Loading include/linux/sde_rsc.h +2 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _SDE_RSC_H_ Loading @@ -12,6 +12,7 @@ #define SDE_RSC_INDEX 0 #define MAX_RSC_CLIENT_NAME_LEN 128 #define NUM_RSC_PROFILING_COUNTERS 3 /* DRM Object IDs are numbered excluding 0, use 0 to indicate invalid CRTC */ #define SDE_RSC_INVALID_CRTC_ID 0 Loading msm/sde_rsc.c +187 −4 Original line number Diff line number Diff line Loading @@ -543,6 +543,13 @@ static int sde_rsc_switch_to_cmd(struct sde_rsc_priv *rsc, } } /* vsync wait not needed during VID->CMD switch (rev 4+ HW only) */ if (rsc->current_state == SDE_RSC_VID_STATE && rsc->version >= SDE_RSC_REV_4) { rc = 0; goto end; } vsync_wait: /* indicate wait for vsync for vid to cmd state switch & cfg update */ if (!rc && (rsc->current_state == SDE_RSC_VID_STATE || Loading Loading @@ -682,13 +689,20 @@ static int sde_rsc_switch_to_vid(struct sde_rsc_priv *rsc, rc = rsc->hw_ops.state_update(rsc, SDE_RSC_VID_STATE); if (!rc) { rpmh_mode_solver_set(rsc->rpmh_dev, rsc->version == SDE_RSC_REV_3 ? true : false); rsc->version >= SDE_RSC_REV_3); sde_rsc_set_data_bus_mode(&rsc->phandle, rsc->version == SDE_RSC_REV_3 ? rsc->version >= SDE_RSC_REV_3 ? QCOM_ICC_TAG_WAKE : QCOM_ICC_TAG_AMC); } } /* vsync wait not needed during CMD->VID switch (rev 4+ HW only) */ if (rsc->current_state == SDE_RSC_CMD_STATE && rsc->version >= SDE_RSC_REV_4) { rc = 0; goto end; } vsync_wait: /* indicate wait for vsync for vid to cmd state switch & cfg update */ if (!rc && (rsc->current_state == SDE_RSC_VID_STATE || Loading Loading @@ -1176,6 +1190,49 @@ static int _sde_debugfs_status_open(struct inode *inode, struct file *file) return single_open(file, _sde_debugfs_status_show, inode->i_private); } static int _sde_debugfs_counters_show(struct seq_file *s, void *data) { struct sde_rsc_priv *rsc = s->private; u32 counters[NUM_RSC_PROFILING_COUNTERS]; int i, ret; if (!rsc) return -EINVAL; if (!rsc->hw_ops.get_counters) { seq_puts(s, "counters are not supported on this target\n"); return 0; } memset(counters, 0, sizeof(counters)); mutex_lock(&rsc->client_lock); if (rsc->current_state == SDE_RSC_IDLE_STATE) { pr_debug("counters are not supported during idle state\n"); seq_puts(s, "no access to counters during idle pc\n"); goto end; } ret = rsc->hw_ops.get_counters(rsc, counters); if (ret) { pr_err("sde rsc: get_counters failed ret:%d\n", ret); seq_puts(s, "failed to retrieve counts!\n"); goto end; } seq_puts(s, "rsc profiling counters:\n"); for (i = 0; i < NUM_RSC_PROFILING_COUNTERS; ++i) seq_printf(s, "\tmode[%d] = 0x%08x:\n", i, counters[i]); end: mutex_unlock(&rsc->client_lock); return 0; } static int _sde_debugfs_counters_open(struct inode *inode, struct file *file) { return single_open(file, _sde_debugfs_counters_show, inode->i_private); } static int _sde_debugfs_generic_noseek_open(struct inode *inode, struct file *file) { Loading @@ -1184,6 +1241,108 @@ static int _sde_debugfs_generic_noseek_open(struct inode *inode, return nonseekable_open(inode, file); } static ssize_t _sde_debugfs_profiling_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct sde_rsc_priv *rsc = file->private_data; size_t max_size = min_t(size_t, count, MAX_BUFFER_SIZE); char buffer[MAX_BUFFER_SIZE]; int blen = 0; if (*ppos || !rsc) return 0; if (!rsc->hw_ops.setup_counters) { blen += scnprintf(&buffer[blen], max_size - blen, "counters are not supported on this target\n"); goto end; } mutex_lock(&rsc->client_lock); if (rsc->current_state == SDE_RSC_IDLE_STATE) { pr_debug("counters are not supported during idle state\n"); blen += scnprintf(&buffer[blen], max_size - blen, "no access to counters during idle pc\n"); goto unlock; } blen += scnprintf(&buffer[blen], max_size - blen, "%s\n", rsc->profiling_en ? "Y" : "N"); unlock: mutex_unlock(&rsc->client_lock); end: if (copy_to_user(buf, buffer, blen)) return -EFAULT; *ppos += blen; return blen; } static ssize_t _sde_debugfs_profiling_write(struct file *file, const char __user *p, size_t count, loff_t *ppos) { struct sde_rsc_priv *rsc = file->private_data; bool input_valid, input_value; char *input; int rc; if (!rsc || !rsc->hw_ops.setup_counters || !count || count > MAX_COUNT_SIZE_SUPPORTED) return 0; input = kmalloc(count + 1, GFP_KERNEL); if (!input) return -ENOMEM; if (copy_from_user(input, p, count)) { kfree(input); return -EFAULT; } input[count] = '\0'; switch (input[0]) { case 'y': case 'Y': case '1': input_valid = true; input_value = true; break; case 'n': case 'N': case '0': input_valid = true; input_value = false; break; default: input_valid = false; count = 0; break; } mutex_lock(&rsc->client_lock); if (rsc->current_state == SDE_RSC_IDLE_STATE) { pr_debug("debug node is not supported during idle state\n"); count = 0; goto end; } pr_debug("input %s, profiling_en: %d\n", input_valid ? "valid" : "invalid", rsc->profiling_en); if (input_valid) { rsc->profiling_en = input_value; rc = rsc->hw_ops.setup_counters(rsc, rsc->profiling_en); if (rc) pr_err("setup_counters failed, rc:%d\n", rc); } end: mutex_unlock(&rsc->client_lock); kfree(input); return count; } static ssize_t _sde_debugfs_mode_ctrl_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { Loading Loading @@ -1380,6 +1539,19 @@ static const struct file_operations vsync_status_fops = { .write = _sde_debugfs_vsync_mode_write, }; static const struct file_operations profiling_enable_fops = { .open = _sde_debugfs_generic_noseek_open, .read = _sde_debugfs_profiling_read, .write = _sde_debugfs_profiling_write, }; static const struct file_operations profiling_counts_fops = { .open = _sde_debugfs_counters_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static void _sde_rsc_init_debugfs(struct sde_rsc_priv *rsc, char *name) { rsc->debugfs_root = debugfs_create_dir(name, NULL); Loading @@ -1393,6 +1565,14 @@ static void _sde_rsc_init_debugfs(struct sde_rsc_priv *rsc, char *name) &mode_control_fops); debugfs_create_file("vsync_mode", 0600, rsc->debugfs_root, rsc, &vsync_status_fops); if (rsc->profiling_supp) { debugfs_create_file("profiling_en", 0600, rsc->debugfs_root, rsc, &profiling_enable_fops); debugfs_create_file("profiling_counts", 0400, rsc->debugfs_root, rsc, &profiling_counts_fops); } debugfs_create_x32("debug_mode", 0600, rsc->debugfs_root, &rsc->debug_mode); } Loading Loading @@ -1515,12 +1695,12 @@ static int sde_rsc_probe(struct platform_device *pdev) of_property_read_u32(pdev->dev.of_node, "qcom,sde-rsc-version", &rsc->version); if (rsc->version == SDE_RSC_REV_2) if (rsc->version >= SDE_RSC_REV_2) rsc->single_tcs_execution_time = SINGLE_TCS_EXECUTION_TIME_V2; else rsc->single_tcs_execution_time = SINGLE_TCS_EXECUTION_TIME_V1; if (rsc->version == SDE_RSC_REV_3) { if (rsc->version >= SDE_RSC_REV_3) { rsc->time_slot_0_ns = rsc->single_tcs_execution_time + RSC_MODE_INSTRUCTION_TIME; rsc->backoff_time_ns = RSC_MODE_INSTRUCTION_TIME; Loading @@ -1534,6 +1714,9 @@ static int sde_rsc_probe(struct platform_device *pdev) + RSC_MODE_THRESHOLD_OVERHEAD; } if (rsc->version >= SDE_RSC_REV_4) rsc->profiling_supp = true; ret = sde_power_resource_init(pdev, &rsc->phandle); if (ret) { pr_err("sde rsc:power resource init failed ret:%d\n", ret); Loading msm/sde_rsc_hw.h +5 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _SDE_RSC_HW_H_ Loading Loading @@ -65,6 +65,10 @@ #define SDE_RSCC_TCS_DRV0_CONTROL 0x1c14 #define SDE_RSCC_LPM_PROFILING_COUNTER0_EN_DRV0 0x4d00 #define SDE_RSCC_LPM_PROFILING_COUNTER0_CLR_DRV0 0x4d04 #define SDE_RSCC_LPM_PROFILING_COUNTER0_STATUS_DRV0 0x4d08 #define SDE_RSCC_WRAPPER_CTRL 0x000 #define SDE_RSCC_WRAPPER_OVERRIDE_CTRL 0x004 #define SDE_RSCC_WRAPPER_STATIC_WAKEUP_0 0x008 Loading msm/sde_rsc_hw_v3.c +49 −1 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "[sde_rsc_hw:%s:%d]: " fmt, __func__, __LINE__ Loading Loading @@ -561,6 +561,50 @@ int rsc_hw_bwi_status_v3(struct sde_rsc_priv *rsc, bool bw_indication) return rc; } static int rsc_hw_profiling_counter_ctrl(struct sde_rsc_priv *rsc, bool enable) { int i; if (!rsc) { pr_debug("invalid input param\n"); return -EINVAL; } for (i = 0; i < NUM_RSC_PROFILING_COUNTERS; ++i) { dss_reg_w(&rsc->drv_io, SDE_RSCC_LPM_PROFILING_COUNTER0_EN_DRV0 + (0x20 * i), enable ? 1 : 0, rsc->debug_mode); dss_reg_w(&rsc->drv_io, SDE_RSCC_LPM_PROFILING_COUNTER0_CLR_DRV0 + (0x20 * i), 1, rsc->debug_mode); } wmb(); /* make sure counters are cleared now */ pr_debug("rsc profiling counters %s and cleared\n", enable ? "enabled" : "disabled"); return 0; } static int rsc_hw_get_profiling_counter_status(struct sde_rsc_priv *rsc, u32 *counters) { int i; if (!rsc || !counters) { pr_debug("invalid input param, %d %d\n", rsc ? 0 : 1, counters ? 0 : 1); return -EINVAL; } for (i = 0; i < NUM_RSC_PROFILING_COUNTERS; ++i) counters[i] = dss_reg_r(&rsc->drv_io, SDE_RSCC_LPM_PROFILING_COUNTER0_STATUS_DRV0 + (0x20 * i), rsc->debug_mode); return 0; } static int rsc_hw_timer_update_v3(struct sde_rsc_priv *rsc) { if (!rsc) { Loading Loading @@ -620,6 +664,10 @@ int sde_rsc_hw_register_v3(struct sde_rsc_priv *rsc) rsc->hw_ops.debug_show = sde_rsc_debug_show; rsc->hw_ops.mode_ctrl = rsc_hw_mode_ctrl; rsc->hw_ops.debug_dump = rsc_hw_debug_dump; if (rsc->profiling_supp) { rsc->hw_ops.setup_counters = rsc_hw_profiling_counter_ctrl; rsc->hw_ops.get_counters = rsc_hw_get_profiling_counter_status; } return 0; } msm/sde_rsc_priv.h +11 −2 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _SDE_RSC_PRIV_H_ Loading @@ -27,6 +27,7 @@ #define SDE_RSC_REV_1 0x1 #define SDE_RSC_REV_2 0x2 #define SDE_RSC_REV_3 0x3 #define SDE_RSC_REV_4 0x4 #define SDE_RSC_HW_MAJOR_MINOR_STEP(major, minor, step) \ (((major & 0xff) << 16) |\ Loading Loading @@ -78,8 +79,10 @@ enum rsc_vsync_req { * @debug_dump: dump debug bus registers or enable debug bus * @state_update: Enable/override the solver based on rsc state * status (command/video) * @mode_show: shows current mode status, mode0/1/2 * @debug_show: Show current debug status. * @mode_ctrl: shows current mode status, mode0/1/2 * @setup_counters: Enable/disable RSC profiling counters * @get_counters: Get current status of profiling counters */ struct sde_rsc_hw_ops { Loading @@ -96,6 +99,8 @@ struct sde_rsc_hw_ops { int (*debug_show)(struct seq_file *s, struct sde_rsc_priv *rsc); int (*mode_ctrl)(struct sde_rsc_priv *rsc, enum rsc_mode_req request, char *buffer, int buffer_size, u32 mode); int (*setup_counters)(struct sde_rsc_priv *rsc, bool enable); int (*get_counters)(struct sde_rsc_priv *rsc, u32 *counters); }; /** Loading Loading @@ -186,6 +191,8 @@ struct sde_rsc_bw_config { * bw_config: check sde_rsc_bw_config structure description. * dev: rsc device node * resource_refcount: Track rsc resource refcount * profiling_supp: Indicates if HW has support for profiling counters * profiling_en: Flag for rsc lpm profiling counters, true=enabled */ struct sde_rsc_priv { u32 version; Loading Loading @@ -227,6 +234,8 @@ struct sde_rsc_priv { struct sde_rsc_bw_config bw_config; struct device *dev; atomic_t resource_refcount; bool profiling_supp; bool profiling_en; }; /** Loading Loading
include/linux/sde_rsc.h +2 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _SDE_RSC_H_ Loading @@ -12,6 +12,7 @@ #define SDE_RSC_INDEX 0 #define MAX_RSC_CLIENT_NAME_LEN 128 #define NUM_RSC_PROFILING_COUNTERS 3 /* DRM Object IDs are numbered excluding 0, use 0 to indicate invalid CRTC */ #define SDE_RSC_INVALID_CRTC_ID 0 Loading
msm/sde_rsc.c +187 −4 Original line number Diff line number Diff line Loading @@ -543,6 +543,13 @@ static int sde_rsc_switch_to_cmd(struct sde_rsc_priv *rsc, } } /* vsync wait not needed during VID->CMD switch (rev 4+ HW only) */ if (rsc->current_state == SDE_RSC_VID_STATE && rsc->version >= SDE_RSC_REV_4) { rc = 0; goto end; } vsync_wait: /* indicate wait for vsync for vid to cmd state switch & cfg update */ if (!rc && (rsc->current_state == SDE_RSC_VID_STATE || Loading Loading @@ -682,13 +689,20 @@ static int sde_rsc_switch_to_vid(struct sde_rsc_priv *rsc, rc = rsc->hw_ops.state_update(rsc, SDE_RSC_VID_STATE); if (!rc) { rpmh_mode_solver_set(rsc->rpmh_dev, rsc->version == SDE_RSC_REV_3 ? true : false); rsc->version >= SDE_RSC_REV_3); sde_rsc_set_data_bus_mode(&rsc->phandle, rsc->version == SDE_RSC_REV_3 ? rsc->version >= SDE_RSC_REV_3 ? QCOM_ICC_TAG_WAKE : QCOM_ICC_TAG_AMC); } } /* vsync wait not needed during CMD->VID switch (rev 4+ HW only) */ if (rsc->current_state == SDE_RSC_CMD_STATE && rsc->version >= SDE_RSC_REV_4) { rc = 0; goto end; } vsync_wait: /* indicate wait for vsync for vid to cmd state switch & cfg update */ if (!rc && (rsc->current_state == SDE_RSC_VID_STATE || Loading Loading @@ -1176,6 +1190,49 @@ static int _sde_debugfs_status_open(struct inode *inode, struct file *file) return single_open(file, _sde_debugfs_status_show, inode->i_private); } static int _sde_debugfs_counters_show(struct seq_file *s, void *data) { struct sde_rsc_priv *rsc = s->private; u32 counters[NUM_RSC_PROFILING_COUNTERS]; int i, ret; if (!rsc) return -EINVAL; if (!rsc->hw_ops.get_counters) { seq_puts(s, "counters are not supported on this target\n"); return 0; } memset(counters, 0, sizeof(counters)); mutex_lock(&rsc->client_lock); if (rsc->current_state == SDE_RSC_IDLE_STATE) { pr_debug("counters are not supported during idle state\n"); seq_puts(s, "no access to counters during idle pc\n"); goto end; } ret = rsc->hw_ops.get_counters(rsc, counters); if (ret) { pr_err("sde rsc: get_counters failed ret:%d\n", ret); seq_puts(s, "failed to retrieve counts!\n"); goto end; } seq_puts(s, "rsc profiling counters:\n"); for (i = 0; i < NUM_RSC_PROFILING_COUNTERS; ++i) seq_printf(s, "\tmode[%d] = 0x%08x:\n", i, counters[i]); end: mutex_unlock(&rsc->client_lock); return 0; } static int _sde_debugfs_counters_open(struct inode *inode, struct file *file) { return single_open(file, _sde_debugfs_counters_show, inode->i_private); } static int _sde_debugfs_generic_noseek_open(struct inode *inode, struct file *file) { Loading @@ -1184,6 +1241,108 @@ static int _sde_debugfs_generic_noseek_open(struct inode *inode, return nonseekable_open(inode, file); } static ssize_t _sde_debugfs_profiling_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct sde_rsc_priv *rsc = file->private_data; size_t max_size = min_t(size_t, count, MAX_BUFFER_SIZE); char buffer[MAX_BUFFER_SIZE]; int blen = 0; if (*ppos || !rsc) return 0; if (!rsc->hw_ops.setup_counters) { blen += scnprintf(&buffer[blen], max_size - blen, "counters are not supported on this target\n"); goto end; } mutex_lock(&rsc->client_lock); if (rsc->current_state == SDE_RSC_IDLE_STATE) { pr_debug("counters are not supported during idle state\n"); blen += scnprintf(&buffer[blen], max_size - blen, "no access to counters during idle pc\n"); goto unlock; } blen += scnprintf(&buffer[blen], max_size - blen, "%s\n", rsc->profiling_en ? "Y" : "N"); unlock: mutex_unlock(&rsc->client_lock); end: if (copy_to_user(buf, buffer, blen)) return -EFAULT; *ppos += blen; return blen; } static ssize_t _sde_debugfs_profiling_write(struct file *file, const char __user *p, size_t count, loff_t *ppos) { struct sde_rsc_priv *rsc = file->private_data; bool input_valid, input_value; char *input; int rc; if (!rsc || !rsc->hw_ops.setup_counters || !count || count > MAX_COUNT_SIZE_SUPPORTED) return 0; input = kmalloc(count + 1, GFP_KERNEL); if (!input) return -ENOMEM; if (copy_from_user(input, p, count)) { kfree(input); return -EFAULT; } input[count] = '\0'; switch (input[0]) { case 'y': case 'Y': case '1': input_valid = true; input_value = true; break; case 'n': case 'N': case '0': input_valid = true; input_value = false; break; default: input_valid = false; count = 0; break; } mutex_lock(&rsc->client_lock); if (rsc->current_state == SDE_RSC_IDLE_STATE) { pr_debug("debug node is not supported during idle state\n"); count = 0; goto end; } pr_debug("input %s, profiling_en: %d\n", input_valid ? "valid" : "invalid", rsc->profiling_en); if (input_valid) { rsc->profiling_en = input_value; rc = rsc->hw_ops.setup_counters(rsc, rsc->profiling_en); if (rc) pr_err("setup_counters failed, rc:%d\n", rc); } end: mutex_unlock(&rsc->client_lock); kfree(input); return count; } static ssize_t _sde_debugfs_mode_ctrl_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { Loading Loading @@ -1380,6 +1539,19 @@ static const struct file_operations vsync_status_fops = { .write = _sde_debugfs_vsync_mode_write, }; static const struct file_operations profiling_enable_fops = { .open = _sde_debugfs_generic_noseek_open, .read = _sde_debugfs_profiling_read, .write = _sde_debugfs_profiling_write, }; static const struct file_operations profiling_counts_fops = { .open = _sde_debugfs_counters_open, .read = seq_read, .llseek = seq_lseek, .release = single_release, }; static void _sde_rsc_init_debugfs(struct sde_rsc_priv *rsc, char *name) { rsc->debugfs_root = debugfs_create_dir(name, NULL); Loading @@ -1393,6 +1565,14 @@ static void _sde_rsc_init_debugfs(struct sde_rsc_priv *rsc, char *name) &mode_control_fops); debugfs_create_file("vsync_mode", 0600, rsc->debugfs_root, rsc, &vsync_status_fops); if (rsc->profiling_supp) { debugfs_create_file("profiling_en", 0600, rsc->debugfs_root, rsc, &profiling_enable_fops); debugfs_create_file("profiling_counts", 0400, rsc->debugfs_root, rsc, &profiling_counts_fops); } debugfs_create_x32("debug_mode", 0600, rsc->debugfs_root, &rsc->debug_mode); } Loading Loading @@ -1515,12 +1695,12 @@ static int sde_rsc_probe(struct platform_device *pdev) of_property_read_u32(pdev->dev.of_node, "qcom,sde-rsc-version", &rsc->version); if (rsc->version == SDE_RSC_REV_2) if (rsc->version >= SDE_RSC_REV_2) rsc->single_tcs_execution_time = SINGLE_TCS_EXECUTION_TIME_V2; else rsc->single_tcs_execution_time = SINGLE_TCS_EXECUTION_TIME_V1; if (rsc->version == SDE_RSC_REV_3) { if (rsc->version >= SDE_RSC_REV_3) { rsc->time_slot_0_ns = rsc->single_tcs_execution_time + RSC_MODE_INSTRUCTION_TIME; rsc->backoff_time_ns = RSC_MODE_INSTRUCTION_TIME; Loading @@ -1534,6 +1714,9 @@ static int sde_rsc_probe(struct platform_device *pdev) + RSC_MODE_THRESHOLD_OVERHEAD; } if (rsc->version >= SDE_RSC_REV_4) rsc->profiling_supp = true; ret = sde_power_resource_init(pdev, &rsc->phandle); if (ret) { pr_err("sde rsc:power resource init failed ret:%d\n", ret); Loading
msm/sde_rsc_hw.h +5 −1 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _SDE_RSC_HW_H_ Loading Loading @@ -65,6 +65,10 @@ #define SDE_RSCC_TCS_DRV0_CONTROL 0x1c14 #define SDE_RSCC_LPM_PROFILING_COUNTER0_EN_DRV0 0x4d00 #define SDE_RSCC_LPM_PROFILING_COUNTER0_CLR_DRV0 0x4d04 #define SDE_RSCC_LPM_PROFILING_COUNTER0_STATUS_DRV0 0x4d08 #define SDE_RSCC_WRAPPER_CTRL 0x000 #define SDE_RSCC_WRAPPER_OVERRIDE_CTRL 0x004 #define SDE_RSCC_WRAPPER_STATIC_WAKEUP_0 0x008 Loading
msm/sde_rsc_hw_v3.c +49 −1 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #define pr_fmt(fmt) "[sde_rsc_hw:%s:%d]: " fmt, __func__, __LINE__ Loading Loading @@ -561,6 +561,50 @@ int rsc_hw_bwi_status_v3(struct sde_rsc_priv *rsc, bool bw_indication) return rc; } static int rsc_hw_profiling_counter_ctrl(struct sde_rsc_priv *rsc, bool enable) { int i; if (!rsc) { pr_debug("invalid input param\n"); return -EINVAL; } for (i = 0; i < NUM_RSC_PROFILING_COUNTERS; ++i) { dss_reg_w(&rsc->drv_io, SDE_RSCC_LPM_PROFILING_COUNTER0_EN_DRV0 + (0x20 * i), enable ? 1 : 0, rsc->debug_mode); dss_reg_w(&rsc->drv_io, SDE_RSCC_LPM_PROFILING_COUNTER0_CLR_DRV0 + (0x20 * i), 1, rsc->debug_mode); } wmb(); /* make sure counters are cleared now */ pr_debug("rsc profiling counters %s and cleared\n", enable ? "enabled" : "disabled"); return 0; } static int rsc_hw_get_profiling_counter_status(struct sde_rsc_priv *rsc, u32 *counters) { int i; if (!rsc || !counters) { pr_debug("invalid input param, %d %d\n", rsc ? 0 : 1, counters ? 0 : 1); return -EINVAL; } for (i = 0; i < NUM_RSC_PROFILING_COUNTERS; ++i) counters[i] = dss_reg_r(&rsc->drv_io, SDE_RSCC_LPM_PROFILING_COUNTER0_STATUS_DRV0 + (0x20 * i), rsc->debug_mode); return 0; } static int rsc_hw_timer_update_v3(struct sde_rsc_priv *rsc) { if (!rsc) { Loading Loading @@ -620,6 +664,10 @@ int sde_rsc_hw_register_v3(struct sde_rsc_priv *rsc) rsc->hw_ops.debug_show = sde_rsc_debug_show; rsc->hw_ops.mode_ctrl = rsc_hw_mode_ctrl; rsc->hw_ops.debug_dump = rsc_hw_debug_dump; if (rsc->profiling_supp) { rsc->hw_ops.setup_counters = rsc_hw_profiling_counter_ctrl; rsc->hw_ops.get_counters = rsc_hw_get_profiling_counter_status; } return 0; }
msm/sde_rsc_priv.h +11 −2 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. */ #ifndef _SDE_RSC_PRIV_H_ Loading @@ -27,6 +27,7 @@ #define SDE_RSC_REV_1 0x1 #define SDE_RSC_REV_2 0x2 #define SDE_RSC_REV_3 0x3 #define SDE_RSC_REV_4 0x4 #define SDE_RSC_HW_MAJOR_MINOR_STEP(major, minor, step) \ (((major & 0xff) << 16) |\ Loading Loading @@ -78,8 +79,10 @@ enum rsc_vsync_req { * @debug_dump: dump debug bus registers or enable debug bus * @state_update: Enable/override the solver based on rsc state * status (command/video) * @mode_show: shows current mode status, mode0/1/2 * @debug_show: Show current debug status. * @mode_ctrl: shows current mode status, mode0/1/2 * @setup_counters: Enable/disable RSC profiling counters * @get_counters: Get current status of profiling counters */ struct sde_rsc_hw_ops { Loading @@ -96,6 +99,8 @@ struct sde_rsc_hw_ops { int (*debug_show)(struct seq_file *s, struct sde_rsc_priv *rsc); int (*mode_ctrl)(struct sde_rsc_priv *rsc, enum rsc_mode_req request, char *buffer, int buffer_size, u32 mode); int (*setup_counters)(struct sde_rsc_priv *rsc, bool enable); int (*get_counters)(struct sde_rsc_priv *rsc, u32 *counters); }; /** Loading Loading @@ -186,6 +191,8 @@ struct sde_rsc_bw_config { * bw_config: check sde_rsc_bw_config structure description. * dev: rsc device node * resource_refcount: Track rsc resource refcount * profiling_supp: Indicates if HW has support for profiling counters * profiling_en: Flag for rsc lpm profiling counters, true=enabled */ struct sde_rsc_priv { u32 version; Loading Loading @@ -227,6 +234,8 @@ struct sde_rsc_priv { struct sde_rsc_bw_config bw_config; struct device *dev; atomic_t resource_refcount; bool profiling_supp; bool profiling_en; }; /** Loading