Add samsung specific changes

This commit is contained in:
2025-08-11 14:29:00 +02:00
parent c66122e619
commit 4d134a1294
2688 changed files with 1127995 additions and 11475 deletions

View File

@@ -11,6 +11,16 @@ menuconfig INTERCONNECT
if INTERCONNECT
menuconfig INTERCONNECT_TEST
tristate "Debugfs test"
depends on DEBUG_FS
help
Expose the interconnect API to userspace for testing purposes. This
will create /sys/kernel/debug/interconnect-test to allow requesting
bandwidth between endpoints.
If unsure, say no.
source "drivers/interconnect/imx/Kconfig"
source "drivers/interconnect/qcom/Kconfig"
source "drivers/interconnect/samsung/Kconfig"

View File

@@ -2,8 +2,10 @@
CFLAGS_core.o := -I$(src)
icc-core-objs := core.o bulk.o debugfs-client.o
icc-test-objs := debugfs-test.o
obj-$(CONFIG_INTERCONNECT) += icc-core.o
obj-$(CONFIG_INTERCONNECT_TEST) += icc-test.o
obj-$(CONFIG_INTERCONNECT_IMX) += imx/
obj-$(CONFIG_INTERCONNECT_QCOM) += qcom/
obj-$(CONFIG_INTERCONNECT_SAMSUNG) += samsung/

View File

@@ -0,0 +1,115 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2017, Linaro Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/interconnect.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
static struct platform_device *icc_pdev;
static struct dentry *debugfs_dir;
static struct icc_path *path;
static u32 src_port;
static u32 dst_port;
static u32 avg_bw;
static u32 peak_bw;
static ssize_t get_write_op(struct file *file, char const __user *buf,
size_t count, loff_t *ppos)
{
unsigned long val;
int ret;
ret = kstrtoul_from_user(buf, count, 10, &val);
if (ret)
return ret;
path = icc_get(&icc_pdev->dev, src_port, dst_port);
if (IS_ERR(path))
return PTR_ERR(path);
*ppos += count;
return count;
}
static const struct file_operations get_fops = {
.owner = THIS_MODULE,
.write = get_write_op
};
static ssize_t commit_write_op(struct file *file, char const __user *buf,
size_t count, loff_t *ppos)
{
unsigned long val;
int ret;
ret = kstrtoul_from_user(buf, count, 10, &val);
if (ret)
return ret;
if (IS_ERR(path))
return PTR_ERR(path);
ret = icc_set_bw(path, avg_bw, peak_bw);
if (ret)
return ret;
*ppos += count;
return count;
}
static const struct file_operations commit_fops = {
.owner = THIS_MODULE,
.write = commit_write_op
};
static void __exit icc_test_exit(void)
{
if (!IS_ERR(path))
icc_put(path);
debugfs_remove_recursive(debugfs_dir);
platform_device_del(icc_pdev);
platform_device_put(icc_pdev);
}
static int __init icc_test_init(void)
{
icc_pdev = platform_device_alloc("icc-test", PLATFORM_DEVID_AUTO);
platform_device_add(icc_pdev);
debugfs_dir = debugfs_create_dir("interconnect-test", NULL);
if (!debugfs_dir)
pr_err("interconnect: error creating debugfs directory\n");
debugfs_create_u32("src_port", 0600, debugfs_dir, &src_port);
debugfs_create_u32("dst_port", 0600, debugfs_dir, &dst_port);
debugfs_create_file("get", 0200, debugfs_dir, NULL, &get_fops);
debugfs_create_u32("avg_bw", 0600, debugfs_dir, &avg_bw);
debugfs_create_u32("peak_bw", 0600, debugfs_dir, &peak_bw);
debugfs_create_file("commit", 0200, debugfs_dir, NULL, &commit_fops);
return 0;
}
module_init(icc_test_init);
module_exit(icc_test_exit);
MODULE_LICENSE("GPL");
#endif

View File

@@ -8,6 +8,21 @@ config INTERCONNECT_QCOM
config INTERCONNECT_QCOM_BCM_VOTER
tristate
config INTERCONNECT_QCOM_QOS_RPM
tristate
config INTERCONNECT_QCOM_MONACO
tristate "MONACO interconnect driver"
depends on INTERCONNECT_QCOM
depends on MSM_RPM_SMD
select INTERCONNECT_QCOM_RPM
select INTERCONNECT_QCOM_QOS_RPM
help
This is a driver for the Qualcomm Technologies, Inc. Network-on-Chip
on monaco-based platforms. The interconnect provider collects and
aggreagates the cosumer bandwidth requests to satisfy constraints
placed on Network-on-Chip performance states.
config INTERCONNECT_QCOM_MSM8916
tristate "Qualcomm MSM8916 interconnect driver"
depends on INTERCONNECT_QCOM
@@ -182,6 +197,19 @@ config INTERCONNECT_QCOM_SDX65
This is a driver for the Qualcomm Network-on-Chip on sdx65-based
platforms.
config INTERCONNECT_QCOM_SDX75
tristate "SDX75 interconnect driver"
depends on INTERCONNECT_QCOM
depends on OF
select INTERCONNECT_QCOM_BCM_VOTER
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_QOS
help
This is a driver for the Qualcomm Technologies, Inc. Network-on-Chip
on sdx75-based platforms. Interconnect driver provides interfaces
for setting bandwidth between two endpoints (path). It also used to
configure NOC QoS settings (Quality of Service).
config INTERCONNECT_QCOM_SM6350
tristate "Qualcomm SM6350 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
@@ -227,6 +255,45 @@ config INTERCONNECT_QCOM_SM8450
This is a driver for the Qualcomm Network-on-Chip on SM8450-based
platforms.
config INTERCONNECT_QCOM_SUN
tristate "SUN interconnect driver"
depends on INTERCONNECT_QCOM
depends on OF
select INTERCONNECT_QCOM_BCM_VOTER
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_QOS
help
This is a driver for the Qualcomm Technologies, Inc. Network-on-Chip
on Sun-based platforms. Interconnect driver provides interfaces
for setting bandwidth between two endpoints (path). It also used to
configure NOC QoS settings (Quality of Service).
config INTERCONNECT_QCOM_TUNA
tristate "TUNA interconnect driver"
depends on INTERCONNECT_QCOM
depends on OF
select INTERCONNECT_QCOM_BCM_VOTER
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_QOS
help
This is a driver for the Qualcomm Technologies, Inc. Network-on-Chip
on Tuna-based platforms. Interconnect driver provides interfaces
for setting bandwidth between two endpoints (path). It also used to
configure NOC QoS settings (Quality of Service).
config INTERCONNECT_QCOM_PINEAPPLE
tristate "PINEAPPLE interconnect driver"
depends on INTERCONNECT_QCOM
depends on OF
select INTERCONNECT_QCOM_BCM_VOTER
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_QOS
help
This is a driver for the Qualcomm Technologies, Inc. Network-on-Chip
on Pineapple-based platforms. Interconnect driver provides interfaces
for setting bandwidth between two endpoints (path). It also used to
configure NOC QoS settings (Quality of Service).
config INTERCONNECT_QCOM_SM8550
tristate "Qualcomm SM8550 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
@@ -236,5 +303,46 @@ config INTERCONNECT_QCOM_SM8550
This is a driver for the Qualcomm Network-on-Chip on SM8550-based
platforms.
config INTERCONNECT_QCOM_PARROT
tristate "PARROT interconnect driver"
depends on INTERCONNECT_QCOM
depends on QCOM_RPMH && QCOM_COMMAND_DB && OF
select INTERCONNECT_QCOM_BCM_VOTER
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_QOS
help
This is a driver for the Qualcomm Technologies, Inc. Network-on-Chip
on Parrot-based platforms. Interconnect driver provides interfaces
for setting bandwidth between two endpoints (path). It also used to
configure NOC QoS settings (Quality of Service).
config INTERCONNECT_QCOM_RPM
tristate
config INTERCONNECT_QCOM_SMD_RPM
tristate
config INTERCONNECT_QCOM_QOS
tristate
config INTERCONNECT_QCOM_DEBUG
tristate "QCOM-specific interconnect debug features"
depends on INTERCONNECT_QCOM
help
This driver provides debug features specific to
Qualcomm Technologies, Inc. interconnect drivers. These features
include optionally printing all enabled interconnect votes when
entering suspend.
config INTERCONNECT_QCOM_RAVELIN
tristate "RAVELIN interconnect driver"
depends on INTERCONNECT_QCOM
depends on QCOM_RPMH && QCOM_COMMAND_DB && OF
select INTERCONNECT_QCOM_BCM_VOTER
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_QOS
help
This is a driver for the Qualcomm Technologies, Inc. Network-on-Chip
on Ravelin-based platforms. Interconnect driver provides interfaces
for setting bandwidth between two endpoints (path). It also used to
configure NOC QoS settings (Quality of Service).

View File

@@ -9,10 +9,12 @@ qnoc-msm8939-objs := msm8939.o
qnoc-msm8974-objs := msm8974.o
qnoc-msm8996-objs := msm8996.o
icc-osm-l3-objs := osm-l3.o
qnoc-monaco-objs := monaco.o
qnoc-qcm2290-objs := qcm2290.o
qnoc-qcs404-objs := qcs404.o
qnoc-qdu1000-objs := qdu1000.o
icc-rpmh-obj := icc-rpmh.o
icc-rpm-obj := icc-rpm.o
qnoc-sa8775p-objs := sa8775p.o
qnoc-sc7180-objs := sc7180.o
qnoc-sc7280-objs := sc7280.o
@@ -23,13 +25,21 @@ qnoc-sdm670-objs := sdm670.o
qnoc-sdm845-objs := sdm845.o
qnoc-sdx55-objs := sdx55.o
qnoc-sdx65-objs := sdx65.o
qnoc-sdx75-objs := sdx75.o
qnoc-sm6350-objs := sm6350.o
qnoc-sm8150-objs := sm8150.o
qnoc-sm8250-objs := sm8250.o
qnoc-sm8350-objs := sm8350.o
qnoc-sm8450-objs := sm8450.o
qnoc-sun-objs := sun.o
qnoc-tuna-objs := tuna.o
qnoc-pineapple-objs := pineapple.o
qnoc-sm8550-objs := sm8550.o
icc-smd-rpm-objs := smd-rpm.o icc-rpm.o icc-rpm-clocks.o
qnoc-parrot-objs := parrot.o
qnoc-ravelin-objs := ravelin.o
icc-smd-rpm-objs := smd-rpm.o
qnoc-qos-rpm-obj := qnoc-qos-rpm.o
qnoc-qos-obj := qnoc-qos.o
obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o
@@ -37,10 +47,12 @@ obj-$(CONFIG_INTERCONNECT_QCOM_MSM8939) += qnoc-msm8939.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8974) += qnoc-msm8974.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8996) += qnoc-msm8996.o
obj-$(CONFIG_INTERCONNECT_QCOM_OSM_L3) += icc-osm-l3.o
obj-$(CONFIG_INTERCONNECT_QCOM_MONACO) += qnoc-monaco.o
obj-$(CONFIG_INTERCONNECT_QCOM_QCM2290) += qnoc-qcm2290.o
obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o
obj-$(CONFIG_INTERCONNECT_QCOM_QDU1000) += qnoc-qdu1000.o
obj-$(CONFIG_INTERCONNECT_QCOM_RPMH) += icc-rpmh.o
obj-$(CONFIG_INTERCONNECT_QCOM_RPM) += icc-rpm.o
obj-$(CONFIG_INTERCONNECT_QCOM_SA8775P) += qnoc-sa8775p.o
obj-$(CONFIG_INTERCONNECT_QCOM_SC7180) += qnoc-sc7180.o
obj-$(CONFIG_INTERCONNECT_QCOM_SC7280) += qnoc-sc7280.o
@@ -51,10 +63,19 @@ obj-$(CONFIG_INTERCONNECT_QCOM_SDM670) += qnoc-sdm670.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDM845) += qnoc-sdm845.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDX55) += qnoc-sdx55.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDX65) += qnoc-sdx65.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDX75) += qnoc-sdx75.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM6350) += qnoc-sm6350.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8150) += qnoc-sm8150.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8250) += qnoc-sm8250.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8350) += qnoc-sm8350.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8450) += qnoc-sm8450.o
obj-$(CONFIG_INTERCONNECT_QCOM_SUN) += qnoc-sun.o
obj-$(CONFIG_INTERCONNECT_QCOM_TUNA) += qnoc-tuna.o
obj-$(CONFIG_INTERCONNECT_QCOM_PINEAPPLE) += qnoc-pineapple.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8550) += qnoc-sm8550.o
obj-$(CONFIG_INTERCONNECT_QCOM_PARROT) += qnoc-parrot.o
obj-$(CONFIG_INTERCONNECT_QCOM_RAVELIN) += qnoc-ravelin.o
obj-$(CONFIG_INTERCONNECT_QCOM_SMD_RPM) += icc-smd-rpm.o
obj-$(CONFIG_INTERCONNECT_QCOM_QOS) += qnoc-qos.o
obj-$(CONFIG_INTERCONNECT_QCOM_QOS_RPM) += qnoc-qos-rpm.o
obj-$(CONFIG_INTERCONNECT_QCOM_DEBUG) += icc-debug.o

View File

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <asm/div64.h>
@@ -16,6 +17,9 @@
#include "bcm-voter.h"
#include "icc-rpmh.h"
#define CREATE_TRACE_POINTS
#include "trace.h"
static LIST_HEAD(bcm_voters);
static DEFINE_MUTEX(bcm_voter_lock);
@@ -28,15 +32,18 @@ static DEFINE_MUTEX(bcm_voter_lock);
* @ws_list: list containing bcms that have different wake/sleep votes
* @voter_node: list of bcm voters
* @tcs_wait: mask for which buckets require TCS completion
* @has_amc: flag to determine if this voter supports AMC
*/
struct bcm_voter {
struct device *dev;
struct device_node *np;
struct qcom_icc_crm_voter *crm;
struct mutex lock;
struct list_head commit_list;
struct list_head ws_list;
struct list_head voter_node;
u32 tcs_wait;
bool has_amc;
};
static int cmp_vcd(void *priv, const struct list_head *a, const struct list_head *b)
@@ -72,19 +79,17 @@ static void bcm_aggregate_mask(struct qcom_icc_bcm *bcm)
node = bcm->nodes[i];
/* If any vote in this bucket exists, keep the BCM enabled */
if (node->sum_avg[bucket] || node->max_peak[bucket]) {
bcm->vote_x[bucket] = 0;
bcm->vote_y[bucket] = bcm->enable_mask;
break;
}
if (node->sum_avg[bucket] || node->max_peak[bucket])
bcm->vote_y[bucket] |= bcm->enable_mask;
if (node->perf_mode[bucket])
bcm->vote_y[bucket] |= bcm->perf_mode_mask;
}
}
if (bcm->keepalive) {
bcm->vote_x[QCOM_ICC_BUCKET_AMC] = bcm->enable_mask;
bcm->vote_x[QCOM_ICC_BUCKET_WAKE] = bcm->enable_mask;
bcm->vote_y[QCOM_ICC_BUCKET_AMC] = bcm->enable_mask;
bcm->vote_y[QCOM_ICC_BUCKET_WAKE] = bcm->enable_mask;
bcm->vote_y[QCOM_ICC_BUCKET_AMC] |= bcm->enable_mask;
bcm->vote_y[QCOM_ICC_BUCKET_WAKE] |= bcm->enable_mask;
}
}
@@ -240,6 +245,31 @@ struct bcm_voter *of_bcm_voter_get(struct device *dev, const char *name)
}
EXPORT_SYMBOL_GPL(of_bcm_voter_get);
/**
* qcom_icc_bcm_voter_exist - checks if the bcm voter exists
* @voter: voter that needs to checked against available bcm voters
*
* Returns true incase bcm_voter exists else false
*/
static bool qcom_icc_bcm_voter_exist(struct bcm_voter *voter)
{
bool exists = false;
struct bcm_voter *temp;
if (voter) {
mutex_lock(&bcm_voter_lock);
list_for_each_entry(temp, &bcm_voters, voter_node) {
if (temp == voter) {
exists = true;
break;
}
}
mutex_unlock(&bcm_voter_lock);
}
return exists;
}
/**
* qcom_icc_bcm_voter_add - queues up the bcm nodes that require updates
* @voter: voter that the bcms are being added to
@@ -250,6 +280,9 @@ void qcom_icc_bcm_voter_add(struct bcm_voter *voter, struct qcom_icc_bcm *bcm)
if (!voter)
return;
if (!qcom_icc_bcm_voter_exist(voter))
return;
mutex_lock(&voter->lock);
if (list_empty(&bcm->list))
list_add_tail(&bcm->list, &voter->commit_list);
@@ -261,6 +294,194 @@ void qcom_icc_bcm_voter_add(struct bcm_voter *voter, struct qcom_icc_bcm *bcm)
}
EXPORT_SYMBOL_GPL(qcom_icc_bcm_voter_add);
static void qcom_icc_bcm_log(struct bcm_voter *voter, enum rpmh_state state,
const struct tcs_cmd *cmd, const u32 *commit_idx)
{
static const char * const rpmh_state[] = {
"RPMH_SLEEP_STATE",
"RPMH_WAKE_ONLY_STATE",
"RPMH_ACTIVE_ONLY_STATE"
};
int i, count = 0;
if (!cmd || !commit_idx)
return;
while (commit_idx[count] > 0)
count++;
if (!count)
return;
for (i = 0; i < count; i++)
trace_bcm_voter_commit(rpmh_state[state], cmd);
}
static int commit_rpmh(struct bcm_voter *voter)
{
struct qcom_icc_bcm *bcm;
struct qcom_icc_bcm *bcm_tmp;
int commit_idx[MAX_VCD + 1];
struct tcs_cmd cmds[MAX_BCMS];
int ret = 0;
if (voter->has_amc) {
/*
* Pre sort the BCMs based on VCD for ease of generating a command list
* that groups the BCMs with the same VCD together. VCDs are numbered
* with lowest being the most expensive time wise, ensuring that
* those commands are being sent the earliest in the queue. This needs
* to be sorted every commit since we can't guarantee the order in which
* the BCMs are added to the list.
*/
list_sort(NULL, &voter->commit_list, cmp_vcd);
/*
* Construct the command list based on a pre ordered list of BCMs
* based on VCD.
*/
tcs_list_gen(voter, QCOM_ICC_BUCKET_AMC, cmds, commit_idx);
if (!commit_idx[0])
goto out;
qcom_icc_bcm_log(voter, RPMH_ACTIVE_ONLY_STATE, cmds, commit_idx);
ret = rpmh_write_batch(voter->dev, RPMH_ACTIVE_ONLY_STATE,
cmds, commit_idx);
/*
* Ignore -EBUSY for AMC requests, since this can only happen for AMC
* requests when the RSC is in solver mode. We can only be in solver
* mode at the time of request for secondary RSCs (e.g. Display RSC),
* since the primary Apps RSC is only in solver mode while
* entering/exiting power collapse when SW isn't running. The -EBUSY
* response is expected in solver and is a non-issue, since we just
* want the request to apply to the WAKE set in that case instead.
* Interconnect doesn't know when the RSC is in solver, so just always
* send AMC and ignore the harmless error response.
*/
if (ret && ret != -EBUSY) {
pr_err("Error sending AMC RPMH requests (%d)\n", ret);
goto out;
}
}
rpmh_invalidate(voter->dev);
list_for_each_entry_safe(bcm, bcm_tmp, &voter->commit_list, list)
list_del_init(&bcm->list);
list_for_each_entry_safe(bcm, bcm_tmp, &voter->ws_list, ws_list) {
/*
* Only generate WAKE and SLEEP commands if a resource's
* requirements change as the execution environment transitions
* between different power states.
*/
if (!voter->has_amc ||
bcm->vote_x[QCOM_ICC_BUCKET_WAKE] != bcm->vote_x[QCOM_ICC_BUCKET_SLEEP] ||
bcm->vote_y[QCOM_ICC_BUCKET_WAKE] != bcm->vote_y[QCOM_ICC_BUCKET_SLEEP])
list_add_tail(&bcm->list, &voter->commit_list);
else
list_del_init(&bcm->ws_list);
}
if (list_empty(&voter->commit_list))
goto out;
list_sort(NULL, &voter->commit_list, cmp_vcd);
tcs_list_gen(voter, QCOM_ICC_BUCKET_WAKE, cmds, commit_idx);
qcom_icc_bcm_log(voter, RPMH_WAKE_ONLY_STATE, cmds, commit_idx);
ret = rpmh_write_batch(voter->dev, RPMH_WAKE_ONLY_STATE, cmds, commit_idx);
if (ret) {
pr_err("Error sending WAKE RPMH requests (%d)\n", ret);
goto out;
}
tcs_list_gen(voter, QCOM_ICC_BUCKET_SLEEP, cmds, commit_idx);
qcom_icc_bcm_log(voter, RPMH_SLEEP_STATE, cmds, commit_idx);
ret = rpmh_write_batch(voter->dev, RPMH_SLEEP_STATE, cmds, commit_idx);
if (ret) {
pr_err("Error sending SLEEP RPMH requests (%d)\n", ret);
goto out;
}
out:
return ret;
}
static int map_crm_pwr_state(enum crm_drv_type client_type, u32 bucket)
{
if (client_type == CRM_HW_DRV)
return bucket;
switch (bucket) {
case QCOM_ICC_BUCKET_AMC: return CRM_ACTIVE_STATE;
case QCOM_ICC_BUCKET_WAKE: return CRM_WAKE_STATE;
case QCOM_ICC_BUCKET_SLEEP: return CRM_SLEEP_STATE;
}
return -EINVAL;
}
static int crm_cmd_gen(struct crm_cmd *cmd, enum crm_drv_type client_type,
u32 bucket, u32 node, u64 vote_x, u64 vote_y)
{
int pwr_state;
if (!cmd)
return -EINVAL;
memset(cmd, 0, sizeof(*cmd));
if (vote_x > BCM_TCS_CMD_VOTE_MASK)
vote_x = BCM_TCS_CMD_VOTE_MASK;
if (vote_y > BCM_TCS_CMD_VOTE_MASK)
vote_y = BCM_TCS_CMD_VOTE_MASK;
pwr_state = map_crm_pwr_state(client_type, bucket);
if (pwr_state < 0)
return pwr_state;
cmd->pwr_state.hw = pwr_state;
cmd->resource_idx = node;
cmd->data = BCM_TCS_CMD(true, true, vote_x, vote_y);
cmd->wait = true;
return 0;
}
static int commit_crm(struct bcm_voter *voter)
{
struct list_head *bcm_list = &voter->commit_list;
struct qcom_icc_crm_voter *crm = voter->crm;
struct qcom_icc_bcm *bcm;
struct crm_cmd crm_cmd;
int ret, i;
list_for_each_entry(bcm, bcm_list, list) {
for (i = 0; i < crm->pwr_states; i++) {
ret = crm_cmd_gen(&crm_cmd, crm->client_type, i, bcm->crm_node,
bcm->vote_x[i], bcm->vote_y[i]);
if (ret) {
pr_err("Error generating crm_cmd: ret=%d\n", ret);
return ret;
}
ret = crm_write_bw_pt_vote(crm->dev, crm->client_type,
crm->client_idx, &crm_cmd);
if (ret) {
pr_err("Error writing crm bw: ret=%d\n", ret);
return ret;
}
}
}
return 0;
}
/**
* qcom_icc_bcm_voter_commit - generates and commits tcs cmds based on bcms
* @voter: voter that needs flushing
@@ -277,88 +498,28 @@ int qcom_icc_bcm_voter_commit(struct bcm_voter *voter)
{
struct qcom_icc_bcm *bcm;
struct qcom_icc_bcm *bcm_tmp;
int commit_idx[MAX_VCD + 1];
struct tcs_cmd cmds[MAX_BCMS];
int ret = 0;
int ret;
if (!voter)
return 0;
if (!qcom_icc_bcm_voter_exist(voter))
return -ENODEV;
mutex_lock(&voter->lock);
list_for_each_entry(bcm, &voter->commit_list, list) {
if (bcm->enable_mask)
if (bcm->type == QCOM_ICC_BCM_TYPE_MASK || bcm->enable_mask)
bcm_aggregate_mask(bcm);
else
bcm_aggregate(bcm);
}
/*
* Pre sort the BCMs based on VCD for ease of generating a command list
* that groups the BCMs with the same VCD together. VCDs are numbered
* with lowest being the most expensive time wise, ensuring that
* those commands are being sent the earliest in the queue. This needs
* to be sorted every commit since we can't guarantee the order in which
* the BCMs are added to the list.
*/
list_sort(NULL, &voter->commit_list, cmp_vcd);
if (voter->crm)
ret = commit_crm(voter);
else
ret = commit_rpmh(voter);
/*
* Construct the command list based on a pre ordered list of BCMs
* based on VCD.
*/
tcs_list_gen(voter, QCOM_ICC_BUCKET_AMC, cmds, commit_idx);
if (!commit_idx[0])
goto out;
rpmh_invalidate(voter->dev);
ret = rpmh_write_batch(voter->dev, RPMH_ACTIVE_ONLY_STATE,
cmds, commit_idx);
if (ret) {
pr_err("Error sending AMC RPMH requests (%d)\n", ret);
goto out;
}
list_for_each_entry_safe(bcm, bcm_tmp, &voter->commit_list, list)
list_del_init(&bcm->list);
list_for_each_entry_safe(bcm, bcm_tmp, &voter->ws_list, ws_list) {
/*
* Only generate WAKE and SLEEP commands if a resource's
* requirements change as the execution environment transitions
* between different power states.
*/
if (bcm->vote_x[QCOM_ICC_BUCKET_WAKE] !=
bcm->vote_x[QCOM_ICC_BUCKET_SLEEP] ||
bcm->vote_y[QCOM_ICC_BUCKET_WAKE] !=
bcm->vote_y[QCOM_ICC_BUCKET_SLEEP])
list_add_tail(&bcm->list, &voter->commit_list);
else
list_del_init(&bcm->ws_list);
}
if (list_empty(&voter->commit_list))
goto out;
list_sort(NULL, &voter->commit_list, cmp_vcd);
tcs_list_gen(voter, QCOM_ICC_BUCKET_WAKE, cmds, commit_idx);
ret = rpmh_write_batch(voter->dev, RPMH_WAKE_ONLY_STATE, cmds, commit_idx);
if (ret) {
pr_err("Error sending WAKE RPMH requests (%d)\n", ret);
goto out;
}
tcs_list_gen(voter, QCOM_ICC_BUCKET_SLEEP, cmds, commit_idx);
ret = rpmh_write_batch(voter->dev, RPMH_SLEEP_STATE, cmds, commit_idx);
if (ret) {
pr_err("Error sending SLEEP RPMH requests (%d)\n", ret);
goto out;
}
out:
list_for_each_entry_safe(bcm, bcm_tmp, &voter->commit_list, list)
list_del_init(&bcm->list);
@@ -370,7 +531,10 @@ EXPORT_SYMBOL_GPL(qcom_icc_bcm_voter_commit);
static int qcom_icc_bcm_voter_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct qcom_icc_crm_voter *crm;
struct bcm_voter *voter;
const char *crm_name;
int ret;
voter = devm_kzalloc(&pdev->dev, sizeof(*voter), GFP_KERNEL);
if (!voter)
@@ -378,6 +542,7 @@ static int qcom_icc_bcm_voter_probe(struct platform_device *pdev)
voter->dev = &pdev->dev;
voter->np = np;
voter->has_amc = !of_property_read_bool(np, "qcom,no-amc");
if (of_property_read_u32(np, "qcom,tcs-wait", &voter->tcs_wait))
voter->tcs_wait = QCOM_ICC_TAG_ACTIVE_ONLY;
@@ -386,6 +551,42 @@ static int qcom_icc_bcm_voter_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&voter->commit_list);
INIT_LIST_HEAD(&voter->ws_list);
ret = of_property_read_string(np, "qcom,crm-name", &crm_name);
if (!ret) {
crm = devm_kzalloc(&pdev->dev, sizeof(*crm), GFP_KERNEL);
if (!crm)
return -ENOMEM;
crm->dev = crm_get_device(crm_name);
if (IS_ERR(crm->dev)) {
if (PTR_ERR(crm->dev) == -ENODEV) {
dev_err(&pdev->dev, "crm_name=%s unavailable=%d\n",
crm_name, -EPROBE_DEFER);
return -EPROBE_DEFER;
}
return PTR_ERR(crm->dev);
}
if (of_property_read_bool(np, "qcom,crm-sw-client"))
crm->client_type = CRM_SW_DRV;
else
crm->client_type = CRM_HW_DRV;
ret = of_property_read_u32(np, "qcom,crm-client-idx", &crm->client_idx);
if (ret) {
dev_err(&pdev->dev, "Error getting crm-client-idx, ret=%d\n", ret);
return ret;
}
ret = of_property_read_u32(np, "qcom,crm-pwr-states", &crm->pwr_states);
if (ret) {
dev_err(&pdev->dev, "Error getting crm-pwr-states, ret=%d\n", ret);
return ret;
}
voter->crm = crm;
}
mutex_lock(&bcm_voter_lock);
list_add_tail(&voter->voter_node, &bcm_voters);
mutex_unlock(&bcm_voter_lock);
@@ -393,6 +594,23 @@ static int qcom_icc_bcm_voter_probe(struct platform_device *pdev)
return 0;
}
static int qcom_icc_bcm_voter_remove(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct bcm_voter *voter, *temp;
mutex_lock(&bcm_voter_lock);
list_for_each_entry_safe(voter, temp, &bcm_voters, voter_node) {
if (voter->np == np) {
list_del(&voter->voter_node);
break;
}
}
mutex_unlock(&bcm_voter_lock);
return 0;
}
static const struct of_device_id bcm_voter_of_match[] = {
{ .compatible = "qcom,bcm-voter" },
{ }
@@ -401,12 +619,18 @@ MODULE_DEVICE_TABLE(of, bcm_voter_of_match);
static struct platform_driver qcom_icc_bcm_voter_driver = {
.probe = qcom_icc_bcm_voter_probe,
.remove = qcom_icc_bcm_voter_remove,
.driver = {
.name = "bcm_voter",
.of_match_table = bcm_voter_of_match,
},
};
module_platform_driver(qcom_icc_bcm_voter_driver);
static int __init qcom_icc_bcm_voter_driver_init(void)
{
return platform_driver_register(&qcom_icc_bcm_voter_driver);
}
module_init(qcom_icc_bcm_voter_driver_init);
MODULE_AUTHOR("David Dai <daidavid1@codeaurora.org>");
MODULE_DESCRIPTION("Qualcomm BCM Voter interconnect driver");

View File

@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef __DRIVERS_INTERCONNECT_QCOM_BCM_VOTER_H__

View File

@@ -0,0 +1,175 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2021, The Linux Foundation. All rights reserved. */
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/interconnect-provider.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <trace/events/power.h>
#include "../internal.h"
static LIST_HEAD(icc_providers);
static DEFINE_MUTEX(debug_lock);
static struct dentry *dentry_suspend;
static bool debug_suspend;
struct qcom_icc_debug_provider {
struct list_head list;
struct icc_provider *provider;
};
static int icc_print_enabled(void)
{
struct qcom_icc_debug_provider *dp;
struct icc_provider *provider;
struct icc_node *n;
struct icc_req *r;
u32 avg_bw, peak_bw;
pr_info(" node tag avg peak\n");
pr_info("--------------------------------------------------------------------\n");
list_for_each_entry(dp, &icc_providers, list) {
provider = dp->provider;
list_for_each_entry(n, &provider->nodes, node_list) {
if (!n->avg_bw && !n->peak_bw)
continue;
pr_info("%-42s %12u %12u\n",
n->name, n->avg_bw, n->peak_bw);
hlist_for_each_entry(r, &n->req_list, req_node) {
if (!r->dev)
continue;
if (r->enabled) {
avg_bw = r->avg_bw;
peak_bw = r->peak_bw;
} else {
avg_bw = 0;
peak_bw = 0;
}
if (avg_bw || peak_bw)
pr_info(" %-27s %12u %12u %12u\n",
dev_name(r->dev), r->tag, avg_bw, peak_bw);
}
}
}
return 0;
}
static int icc_debug_suspend_get(void *data, u64 *val)
{
*val = debug_suspend;
return 0;
}
static void icc_debug_suspend_trace_probe(void *unused, const char *action,
int val, bool start)
{
if (start && val > 0 && !strcmp("machine_suspend", action)) {
pr_info("Enabled interconnect votes:\n");
icc_print_enabled();
}
}
static int icc_debug_suspend_set(void *data, u64 val)
{
int ret;
val = !!val;
if (val == debug_suspend)
return 0;
if (val)
ret = register_trace_suspend_resume(icc_debug_suspend_trace_probe, NULL);
else
ret = unregister_trace_suspend_resume(icc_debug_suspend_trace_probe, NULL);
if (ret) {
pr_err("%s: Failed to %sregister suspend trace callback, ret=%d\n",
__func__, val ? "" : "un", ret);
return ret;
}
debug_suspend = val;
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(icc_debug_suspend_fops, icc_debug_suspend_get,
icc_debug_suspend_set, "%llu\n");
int qcom_icc_debug_register(struct icc_provider *provider)
{
struct qcom_icc_debug_provider *dp;
dp = kzalloc(sizeof(*dp), GFP_KERNEL);
if (!dp)
return -ENOMEM;
dp->provider = provider;
mutex_lock(&debug_lock);
list_add_tail(&dp->list, &icc_providers);
mutex_unlock(&debug_lock);
return 0;
}
EXPORT_SYMBOL(qcom_icc_debug_register);
int qcom_icc_debug_unregister(struct icc_provider *provider)
{
struct qcom_icc_debug_provider *dp, *temp;
mutex_lock(&debug_lock);
list_for_each_entry_safe(dp, temp, &icc_providers, list) {
if (dp->provider == provider) {
list_del(&dp->list);
kfree(dp);
}
}
mutex_unlock(&debug_lock);
return 0;
}
EXPORT_SYMBOL(qcom_icc_debug_unregister);
static int __init qcom_icc_debug_init(void)
{
static struct dentry *dir;
int ret;
dir = debugfs_lookup("interconnect", NULL);
if (IS_ERR_OR_NULL(dir)) {
ret = PTR_ERR(dir);
pr_err("%s: unable to find root interconnect debugfs directory, ret=%d\n",
__func__, ret);
return 0;
}
dentry_suspend = debugfs_create_file_unsafe("debug_suspend",
0644, dir, NULL,
&icc_debug_suspend_fops);
return 0;
}
module_init(qcom_icc_debug_init);
static void __exit qcom_icc_debug_exit(void)
{
debugfs_remove(dentry_suspend);
if (debug_suspend)
unregister_trace_suspend_resume(icc_debug_suspend_trace_probe, NULL);
}
module_exit(qcom_icc_debug_exit);
MODULE_DESCRIPTION("QCOM ICC debug library");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (c) 2021, The Linux Foundation. All rights reserved. */
#ifndef __QCOM_ICC_DEBUG_H__
#define __QCOM_ICC_DEBUG_H__
#include <linux/interconnect-provider.h>
int qcom_icc_debug_register(struct icc_provider *provider);
int qcom_icc_debug_unregister(struct icc_provider *provider);
#endif

View File

@@ -1,266 +1,68 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 Linaro Ltd
* Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved.
*
*/
#include <linux/device.h>
#include <asm/div64.h>
#include <linux/clk.h>
#include <linux/interconnect-provider.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <dt-bindings/interconnect/qcom,icc.h>
#include "icc-common.h"
#include "icc-rpm.h"
#include "qnoc-qos-rpm.h"
/* QNOC QoS */
#define QNOC_QOS_MCTL_LOWn_ADDR(n) (0x8 + (n * 0x1000))
#define QNOC_QOS_MCTL_DFLT_PRIO_MASK 0x70
#define QNOC_QOS_MCTL_DFLT_PRIO_SHIFT 4
#define QNOC_QOS_MCTL_URGFWD_EN_MASK 0x8
#define QNOC_QOS_MCTL_URGFWD_EN_SHIFT 3
/* BIMC QoS */
#define M_BKE_REG_BASE(n) (0x300 + (0x4000 * n))
#define M_BKE_EN_ADDR(n) (M_BKE_REG_BASE(n))
#define M_BKE_HEALTH_CFG_ADDR(i, n) (M_BKE_REG_BASE(n) + 0x40 + (0x4 * i))
#define M_BKE_HEALTH_CFG_LIMITCMDS_MASK 0x80000000
#define M_BKE_HEALTH_CFG_AREQPRIO_MASK 0x300
#define M_BKE_HEALTH_CFG_PRIOLVL_MASK 0x3
#define M_BKE_HEALTH_CFG_AREQPRIO_SHIFT 0x8
#define M_BKE_HEALTH_CFG_LIMITCMDS_SHIFT 0x1f
#define M_BKE_EN_EN_BMASK 0x1
/* NoC QoS */
#define NOC_QOS_PRIORITYn_ADDR(n) (0x8 + (n * 0x1000))
#define NOC_QOS_PRIORITY_P1_MASK 0xc
#define NOC_QOS_PRIORITY_P0_MASK 0x3
#define NOC_QOS_PRIORITY_P1_SHIFT 0x2
#define NOC_QOS_MODEn_ADDR(n) (0xc + (n * 0x1000))
#define NOC_QOS_MODEn_MASK 0x3
#define NOC_QOS_MODE_FIXED_VAL 0x0
#define NOC_QOS_MODE_BYPASS_VAL 0x2
#define ICC_BUS_CLK_MIN_RATE 19200ULL /* kHz */
static int qcom_icc_set_qnoc_qos(struct icc_node *src)
static int qcom_icc_rpm_smd_send_msg(int ctx, int rsc_type, int rpm_id, u64 val)
{
struct icc_provider *provider = src->provider;
struct qcom_icc_provider *qp = to_qcom_provider(provider);
struct qcom_icc_node *qn = src->data;
struct qcom_icc_qos *qos = &qn->qos;
int rc;
int ret;
struct msm_rpm_kvp rpm_kvp;
rc = regmap_update_bits(qp->regmap,
qp->qos_offset + QNOC_QOS_MCTL_LOWn_ADDR(qos->qos_port),
QNOC_QOS_MCTL_DFLT_PRIO_MASK,
qos->areq_prio << QNOC_QOS_MCTL_DFLT_PRIO_SHIFT);
if (rc)
return rc;
rpm_kvp.length = sizeof(uint64_t);
rpm_kvp.key = RPM_MASTER_FIELD_BW;
rpm_kvp.data = (uint8_t *)&val;
return regmap_update_bits(qp->regmap,
qp->qos_offset + QNOC_QOS_MCTL_LOWn_ADDR(qos->qos_port),
QNOC_QOS_MCTL_URGFWD_EN_MASK,
!!qos->urg_fwd_en << QNOC_QOS_MCTL_URGFWD_EN_SHIFT);
}
ret = msm_rpm_send_message(ctx, rsc_type, rpm_id, &rpm_kvp, 1);
static int qcom_icc_bimc_set_qos_health(struct qcom_icc_provider *qp,
struct qcom_icc_qos *qos,
int regnum)
{
u32 val;
u32 mask;
val = qos->prio_level;
mask = M_BKE_HEALTH_CFG_PRIOLVL_MASK;
val |= qos->areq_prio << M_BKE_HEALTH_CFG_AREQPRIO_SHIFT;
mask |= M_BKE_HEALTH_CFG_AREQPRIO_MASK;
/* LIMITCMDS is not present on M_BKE_HEALTH_3 */
if (regnum != 3) {
val |= qos->limit_commands << M_BKE_HEALTH_CFG_LIMITCMDS_SHIFT;
mask |= M_BKE_HEALTH_CFG_LIMITCMDS_MASK;
}
return regmap_update_bits(qp->regmap,
qp->qos_offset + M_BKE_HEALTH_CFG_ADDR(regnum, qos->qos_port),
mask, val);
}
static int qcom_icc_set_bimc_qos(struct icc_node *src)
{
struct qcom_icc_provider *qp;
struct qcom_icc_node *qn;
struct icc_provider *provider;
u32 mode = NOC_QOS_MODE_BYPASS;
u32 val = 0;
int i, rc = 0;
qn = src->data;
provider = src->provider;
qp = to_qcom_provider(provider);
if (qn->qos.qos_mode != NOC_QOS_MODE_INVALID)
mode = qn->qos.qos_mode;
/* QoS Priority: The QoS Health parameters are getting considered
* only if we are NOT in Bypass Mode.
*/
if (mode != NOC_QOS_MODE_BYPASS) {
for (i = 3; i >= 0; i--) {
rc = qcom_icc_bimc_set_qos_health(qp,
&qn->qos, i);
if (rc)
return rc;
}
/* Set BKE_EN to 1 when Fixed, Regulator or Limiter Mode */
val = 1;
}
return regmap_update_bits(qp->regmap,
qp->qos_offset + M_BKE_EN_ADDR(qn->qos.qos_port),
M_BKE_EN_EN_BMASK, val);
}
static int qcom_icc_noc_set_qos_priority(struct qcom_icc_provider *qp,
struct qcom_icc_qos *qos)
{
u32 val;
int rc;
/* Must be updated one at a time, P1 first, P0 last */
val = qos->areq_prio << NOC_QOS_PRIORITY_P1_SHIFT;
rc = regmap_update_bits(qp->regmap,
qp->qos_offset + NOC_QOS_PRIORITYn_ADDR(qos->qos_port),
NOC_QOS_PRIORITY_P1_MASK, val);
if (rc)
return rc;
return regmap_update_bits(qp->regmap,
qp->qos_offset + NOC_QOS_PRIORITYn_ADDR(qos->qos_port),
NOC_QOS_PRIORITY_P0_MASK, qos->prio_level);
}
static int qcom_icc_set_noc_qos(struct icc_node *src)
{
struct qcom_icc_provider *qp;
struct qcom_icc_node *qn;
struct icc_provider *provider;
u32 mode = NOC_QOS_MODE_BYPASS_VAL;
int rc = 0;
qn = src->data;
provider = src->provider;
qp = to_qcom_provider(provider);
if (qn->qos.qos_port < 0) {
dev_dbg(src->provider->dev,
"NoC QoS: Skipping %s: vote aggregated on parent.\n",
qn->name);
return 0;
}
if (qn->qos.qos_mode == NOC_QOS_MODE_FIXED) {
dev_dbg(src->provider->dev, "NoC QoS: %s: Set Fixed mode\n", qn->name);
mode = NOC_QOS_MODE_FIXED_VAL;
rc = qcom_icc_noc_set_qos_priority(qp, &qn->qos);
if (rc)
return rc;
} else if (qn->qos.qos_mode == NOC_QOS_MODE_BYPASS) {
dev_dbg(src->provider->dev, "NoC QoS: %s: Set Bypass mode\n", qn->name);
mode = NOC_QOS_MODE_BYPASS_VAL;
} else {
/* How did we get here? */
}
return regmap_update_bits(qp->regmap,
qp->qos_offset + NOC_QOS_MODEn_ADDR(qn->qos.qos_port),
NOC_QOS_MODEn_MASK, mode);
}
static int qcom_icc_qos_set(struct icc_node *node)
{
struct qcom_icc_provider *qp = to_qcom_provider(node->provider);
struct qcom_icc_node *qn = node->data;
dev_dbg(node->provider->dev, "Setting QoS for %s\n", qn->name);
switch (qp->type) {
case QCOM_ICC_BIMC:
return qcom_icc_set_bimc_qos(node);
case QCOM_ICC_QNOC:
return qcom_icc_set_qnoc_qos(node);
default:
return qcom_icc_set_noc_qos(node);
}
}
static int qcom_icc_rpm_set(struct qcom_icc_node *qn, u64 *bw)
{
int ret, rpm_ctx = 0;
u64 bw_bps;
if (qn->qos.ap_owned)
return 0;
for (rpm_ctx = 0; rpm_ctx < QCOM_SMD_RPM_STATE_NUM; rpm_ctx++) {
bw_bps = icc_units_to_bps(bw[rpm_ctx]);
if (qn->mas_rpm_id != -1) {
ret = qcom_icc_rpm_smd_send(rpm_ctx,
RPM_BUS_MASTER_REQ,
qn->mas_rpm_id,
bw_bps);
if (ret) {
pr_err("qcom_icc_rpm_smd_send mas %d error %d\n",
qn->mas_rpm_id, ret);
return ret;
}
}
if (qn->slv_rpm_id != -1) {
ret = qcom_icc_rpm_smd_send(rpm_ctx,
RPM_BUS_SLAVE_REQ,
qn->slv_rpm_id,
bw_bps);
if (ret) {
pr_err("qcom_icc_rpm_smd_send slv %d error %d\n",
qn->slv_rpm_id, ret);
return ret;
}
}
}
return 0;
return ret;
}
/**
* qcom_icc_pre_bw_aggregate - cleans up values before re-aggregate requests
* qcom_icc_get_bw_stub - initializes the bw values to zero
* @node: icc node to operate on
* @avg_bw: initial bw to sum aggregate
* @peak_bw: initial bw to max aggregate
*/
int qcom_icc_get_bw_stub(struct icc_node *node, u32 *avg, u32 *peak)
{
*avg = 0;
*peak = 0;
return 0;
}
EXPORT_SYMBOL_GPL(qcom_icc_get_bw_stub);
/**
* qcom_icc_rpm_pre_aggregate - cleans up stale values from prior icc_set
* @node: icc node to operate on
*/
static void qcom_icc_pre_bw_aggregate(struct icc_node *node)
void qcom_icc_rpm_pre_aggregate(struct icc_node *node)
{
struct qcom_icc_node *qn;
size_t i;
struct qcom_icc_node *qn;
qn = node->data;
for (i = 0; i < QCOM_SMD_RPM_STATE_NUM; i++) {
for (i = 0; i < RPM_NUM_CXT; i++) {
qn->sum_avg[i] = 0;
qn->max_peak[i] = 0;
}
}
EXPORT_SYMBOL_GPL(qcom_icc_rpm_pre_aggregate);
/**
* qcom_icc_bw_aggregate - aggregate bw for buckets indicated by tag
* qcom_icc_rpm_aggregate - aggregate bw for buckets indicated by tag
* @node: node to aggregate
* @tag: tag to indicate which buckets to aggregate
* @avg_bw: new bw to sum aggregate
@@ -268,18 +70,20 @@ static void qcom_icc_pre_bw_aggregate(struct icc_node *node)
* @agg_avg: existing aggregate avg bw val
* @agg_peak: existing aggregate peak bw val
*/
static int qcom_icc_bw_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
int qcom_icc_rpm_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
{
size_t i;
struct qcom_icc_node *qn;
qn = node->data;
if (!tag)
tag = RPM_ALWAYS_TAG;
if (tag && !(tag & QCOM_ICC_TAG_SLEEP))
tag = BIT(RPM_ACTIVE_CXT);
else
tag = BIT(RPM_SLEEP_CXT) | BIT(RPM_ACTIVE_CXT);
for (i = 0; i < QCOM_SMD_RPM_STATE_NUM; i++) {
for (i = 0; i < RPM_NUM_CXT; i++) {
if (tag & BIT(i)) {
qn->sum_avg[i] += avg_bw;
qn->max_peak[i] = max_t(u32, qn->max_peak[i], peak_bw);
@@ -288,301 +92,144 @@ static int qcom_icc_bw_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
*agg_avg += avg_bw;
*agg_peak = max_t(u32, *agg_peak, peak_bw);
qn->dirty = true;
return 0;
}
EXPORT_SYMBOL_GPL(qcom_icc_rpm_aggregate);
/**
* qcom_icc_bus_aggregate - calculate bus clock rates by traversing all nodes
* @provider: generic interconnect provider
* @agg_clk_rate: array containing the aggregated clock rates in kHz
* qcom_icc_rpm_set - set the constraints based on path
* @src: source node for the path to set constraints on
* @dst: destination node for the path to set constraints on
*
* Return: 0 on success, or an error code otherwise
*/
static void qcom_icc_bus_aggregate(struct icc_provider *provider, u64 *agg_clk_rate)
int qcom_icc_rpm_set(struct icc_node *src, struct icc_node *dst)
{
u64 agg_avg_rate, agg_rate;
struct qcom_icc_node *qn;
struct icc_node *node;
int i;
/*
* Iterate nodes on the provider, aggregate bandwidth requests for
* every bucket and convert them into bus clock rates.
*/
list_for_each_entry(node, &provider->nodes, node_list) {
qn = node->data;
for (i = 0; i < QCOM_SMD_RPM_STATE_NUM; i++) {
if (qn->channels)
agg_avg_rate = div_u64(qn->sum_avg[i], qn->channels);
else
agg_avg_rate = qn->sum_avg[i];
agg_rate = max_t(u64, agg_avg_rate, qn->max_peak[i]);
do_div(agg_rate, qn->buswidth);
agg_clk_rate[i] = max_t(u64, agg_clk_rate[i], agg_rate);
}
}
}
static int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
{
struct qcom_icc_node *src_qn = NULL, *dst_qn = NULL;
u64 agg_clk_rate[QCOM_SMD_RPM_STATE_NUM] = { 0 };
struct icc_provider *provider;
struct qcom_icc_provider *qp;
u64 active_rate, sleep_rate;
int ret;
struct qcom_icc_node *qn;
struct icc_node *n, *node;
struct icc_provider *provider;
int ret, i;
int rpm_ctx;
u64 clk_rate, sum_avg, max_peak;
u64 bus_clk_rate[RPM_NUM_CXT] = {0, 0};
src_qn = src->data;
if (dst)
dst_qn = dst->data;
provider = src->provider;
qp = to_qcom_provider(provider);
if (!src)
node = dst;
else
node = src;
qcom_icc_bus_aggregate(provider, agg_clk_rate);
active_rate = agg_clk_rate[QCOM_SMD_RPM_ACTIVE_STATE];
sleep_rate = agg_clk_rate[QCOM_SMD_RPM_SLEEP_STATE];
qp = to_qcom_provider(node->provider);
qn = node->data;
ret = qcom_icc_rpm_set(src_qn, src_qn->sum_avg);
if (ret)
return ret;
if (dst_qn) {
ret = qcom_icc_rpm_set(dst_qn, dst_qn->sum_avg);
if (ret)
return ret;
}
/* Some providers don't have a bus clock to scale */
if (!qp->bus_clk_desc && !qp->bus_clk)
if (!qn->dirty)
return 0;
/*
* Downstream checks whether the requested rate is zero, but it makes little sense
* to vote for a value that's below the lower threshold, so let's not do so.
*/
if (qp->keep_alive)
active_rate = max(ICC_BUS_CLK_MIN_RATE, active_rate);
provider = node->provider;
/* Some providers have a non-RPM-owned bus clock - convert kHz->Hz for the CCF */
if (qp->bus_clk) {
active_rate = max_t(u64, active_rate, sleep_rate);
/* ARM32 caps clk_set_rate arg to u32.. Nothing we can do about that! */
active_rate = min_t(u64, 1000ULL * active_rate, ULONG_MAX);
return clk_set_rate(qp->bus_clk, active_rate);
}
list_for_each_entry(n, &provider->nodes, node_list) {
qn = n->data;
for (i = 0; i < RPM_NUM_CXT; i++) {
sum_avg = icc_units_to_bps(qn->sum_avg[i]);
/* RPM only accepts <=INT_MAX rates */
active_rate = min_t(u64, active_rate, INT_MAX);
sleep_rate = min_t(u64, sleep_rate, INT_MAX);
sum_avg *= qp->util_factor;
do_div(sum_avg, DEFAULT_UTIL_FACTOR);
if (active_rate != qp->bus_clk_rate[QCOM_SMD_RPM_ACTIVE_STATE]) {
ret = qcom_icc_rpm_set_bus_rate(qp->bus_clk_desc, QCOM_SMD_RPM_ACTIVE_STATE,
active_rate);
if (ret)
return ret;
do_div(sum_avg, qn->channels);
max_peak = icc_units_to_bps(qn->max_peak[i]);
/* Cache the rate after we've successfully commited it to RPM */
qp->bus_clk_rate[QCOM_SMD_RPM_ACTIVE_STATE] = active_rate;
}
clk_rate = max(sum_avg, max_peak);
do_div(clk_rate, qn->buswidth);
if (sleep_rate != qp->bus_clk_rate[QCOM_SMD_RPM_SLEEP_STATE]) {
ret = qcom_icc_rpm_set_bus_rate(qp->bus_clk_desc, QCOM_SMD_RPM_SLEEP_STATE,
sleep_rate);
if (ret)
return ret;
bus_clk_rate[i] = max(bus_clk_rate[i], clk_rate);
/* Cache the rate after we've successfully commited it to RPM */
qp->bus_clk_rate[QCOM_SMD_RPM_SLEEP_STATE] = sleep_rate;
}
return 0;
}
int qnoc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct qcom_icc_desc *desc;
struct icc_onecell_data *data;
struct icc_provider *provider;
struct qcom_icc_node * const *qnodes;
struct qcom_icc_provider *qp;
struct icc_node *node;
size_t num_nodes, i;
const char * const *cds = NULL;
int cd_num;
int ret;
/* wait for the RPM proxy */
if (!qcom_icc_rpm_smd_available())
return -EPROBE_DEFER;
desc = of_device_get_match_data(dev);
if (!desc)
return -EINVAL;
qnodes = desc->nodes;
num_nodes = desc->num_nodes;
if (desc->num_intf_clocks) {
cds = desc->intf_clocks;
cd_num = desc->num_intf_clocks;
} else {
/* 0 intf clocks is perfectly fine */
cd_num = 0;
}
qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL);
if (!qp)
return -ENOMEM;
qp->intf_clks = devm_kcalloc(dev, cd_num, sizeof(*qp->intf_clks), GFP_KERNEL);
if (!qp->intf_clks)
return -ENOMEM;
if (desc->bus_clk_desc) {
qp->bus_clk_desc = devm_kzalloc(dev, sizeof(*qp->bus_clk_desc),
GFP_KERNEL);
if (!qp->bus_clk_desc)
return -ENOMEM;
qp->bus_clk_desc = desc->bus_clk_desc;
} else {
/* Some older SoCs may have a single non-RPM-owned bus clock. */
qp->bus_clk = devm_clk_get_optional(dev, "bus");
if (IS_ERR(qp->bus_clk))
return PTR_ERR(qp->bus_clk);
}
data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes),
GFP_KERNEL);
if (!data)
return -ENOMEM;
qp->num_intf_clks = cd_num;
for (i = 0; i < cd_num; i++)
qp->intf_clks[i].id = cds[i];
qp->keep_alive = desc->keep_alive;
qp->type = desc->type;
qp->qos_offset = desc->qos_offset;
if (desc->regmap_cfg) {
struct resource *res;
void __iomem *mmio;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
/* Try parent's regmap */
qp->regmap = dev_get_regmap(dev->parent, NULL);
if (qp->regmap)
goto regmap_done;
return -ENODEV;
}
mmio = devm_ioremap_resource(dev, res);
if (IS_ERR(mmio))
return PTR_ERR(mmio);
qp->regmap = devm_regmap_init_mmio(dev, mmio, desc->regmap_cfg);
if (IS_ERR(qp->regmap)) {
dev_err(dev, "Cannot regmap interconnect bus resource\n");
return PTR_ERR(qp->regmap);
if (bus_clk_rate[i] > RPM_CLK_MAX_LEVEL)
bus_clk_rate[i] = RPM_CLK_MAX_LEVEL;
}
}
regmap_done:
ret = clk_prepare_enable(qp->bus_clk);
if (ret)
return ret;
for (i = 0; i < RPM_NUM_CXT; i++) {
if (qp->bus_clk_cur_rate[i] != bus_clk_rate[i]) {
if (qp->keepalive && i == RPM_ACTIVE_CXT) {
if (qp->init)
ret = clk_set_rate(qp->bus_clks[i].clk,
RPM_CLK_MAX_LEVEL);
else if (bus_clk_rate[i] == 0)
ret = clk_set_rate(qp->bus_clks[i].clk,
RPM_CLK_MIN_LEVEL);
else
ret = clk_set_rate(qp->bus_clks[i].clk,
bus_clk_rate[i]);
} else {
ret = clk_set_rate(qp->bus_clks[i].clk,
bus_clk_rate[i]);
}
ret = devm_clk_bulk_get(dev, qp->num_intf_clks, qp->intf_clks);
if (ret)
goto err_disable_unprepare_clk;
provider = &qp->provider;
provider->dev = dev;
provider->set = qcom_icc_set;
provider->pre_aggregate = qcom_icc_pre_bw_aggregate;
provider->aggregate = qcom_icc_bw_aggregate;
provider->xlate_extended = qcom_icc_xlate_extended;
provider->data = data;
icc_provider_init(provider);
/* If this fails, bus accesses will crash the platform! */
ret = clk_bulk_prepare_enable(qp->num_intf_clks, qp->intf_clks);
if (ret)
goto err_disable_unprepare_clk;
for (i = 0; i < num_nodes; i++) {
size_t j;
node = icc_node_create(qnodes[i]->id);
if (IS_ERR(node)) {
clk_bulk_disable_unprepare(qp->num_intf_clks,
qp->intf_clks);
ret = PTR_ERR(node);
goto err_remove_nodes;
}
node->name = qnodes[i]->name;
node->data = qnodes[i];
icc_node_add(node, provider);
for (j = 0; j < qnodes[i]->num_links; j++)
icc_link_create(node, qnodes[i]->links[j]);
/* Set QoS registers (we only need to do it once, generally) */
if (qnodes[i]->qos.ap_owned &&
qnodes[i]->qos.qos_mode != NOC_QOS_MODE_INVALID) {
ret = qcom_icc_qos_set(node);
if (ret) {
clk_bulk_disable_unprepare(qp->num_intf_clks,
qp->intf_clks);
goto err_remove_nodes;
pr_err("%s clk_set_rate error: %d\n",
qp->bus_clks[i].id, ret);
return ret;
}
qp->bus_clk_cur_rate[i] = bus_clk_rate[i];
}
}
list_for_each_entry(n, &provider->nodes, node_list) {
qn = n->data;
if (!qn->dirty)
continue;
qn->dirty = false;
if ((qn->mas_rpm_id == -1) && (qn->slv_rpm_id == -1))
continue;
/* send bandwidth request message to the RPM processor */
for (i = 0; i < RPM_NUM_CXT; i++) {
if (qn->last_sum_avg[i] != qn->sum_avg[i]) {
rpm_ctx = (i == RPM_SLEEP_CXT) ?
RPM_SLEEP_SET : RPM_ACTIVE_SET;
sum_avg = icc_units_to_bps(qn->sum_avg[i]);
if (qn->mas_rpm_id != -1) {
ret = qcom_icc_rpm_smd_send_msg(
rpm_ctx,
RPM_BUS_MASTER_REQ,
qn->mas_rpm_id,
sum_avg);
if (ret) {
pr_err("qcom_icc_rpm_smd_send_msg mas %d error %d\n",
qn->mas_rpm_id, ret);
return ret;
}
}
if (qn->slv_rpm_id != -1) {
ret = qcom_icc_rpm_smd_send_msg(
rpm_ctx,
RPM_BUS_SLAVE_REQ,
qn->slv_rpm_id,
sum_avg);
if (ret) {
pr_err("qcom_icc_rpm_smd_send_msg slv %d error %d\n",
qn->slv_rpm_id, ret);
return ret;
}
}
qn->last_sum_avg[i] = qn->sum_avg[i];
}
}
data->nodes[i] = node;
}
data->num_nodes = num_nodes;
clk_bulk_disable_unprepare(qp->num_intf_clks, qp->intf_clks);
ret = icc_provider_register(provider);
if (ret)
goto err_remove_nodes;
platform_set_drvdata(pdev, qp);
/* Populate child NoC devices if any */
if (of_get_child_count(dev->of_node) > 0) {
ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
if (ret)
goto err_deregister_provider;
}
return 0;
err_deregister_provider:
icc_provider_deregister(provider);
err_remove_nodes:
icc_nodes_remove(provider);
err_disable_unprepare_clk:
clk_disable_unprepare(qp->bus_clk);
return ret;
}
EXPORT_SYMBOL(qnoc_probe);
EXPORT_SYMBOL_GPL(qcom_icc_rpm_set);
int qnoc_remove(struct platform_device *pdev)
{
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
icc_provider_deregister(&qp->provider);
icc_nodes_remove(&qp->provider);
clk_disable_unprepare(qp->bus_clk);
return 0;
}
EXPORT_SYMBOL(qnoc_remove);
MODULE_LICENSE("GPL");

View File

@@ -1,88 +1,69 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2020 Linaro Ltd
* Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef __DRIVERS_INTERCONNECT_QCOM_ICC_RPM_H
#define __DRIVERS_INTERCONNECT_QCOM_ICC_RPM_H
#include <linux/soc/qcom/smd-rpm.h>
#include <dt-bindings/interconnect/qcom,rpm-icc.h>
#include <linux/clk.h>
#include <linux/interconnect-provider.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <soc/qcom/rpm-smd.h>
#define RPM_BUS_MASTER_REQ 0x73616d62
#define RPM_BUS_SLAVE_REQ 0x766c7362
#define QCOM_MAX_LINKS 128
#define RPM_SLEEP_SET MSM_RPM_CTX_SLEEP_SET
#define RPM_ACTIVE_SET MSM_RPM_CTX_ACTIVE_SET
#define RPM_CLK_MAX_LEVEL INT_MAX
#define RPM_CLK_MIN_LEVEL 19200000
#define DEFAULT_UTIL_FACTOR 100
#define to_qcom_provider(_provider) \
container_of(_provider, struct qcom_icc_provider, provider)
enum qcom_icc_type {
QCOM_ICC_NOC,
QCOM_ICC_BIMC,
QCOM_ICC_QNOC,
enum qcom_icc_rpm_mas_field_type {
RPM_MASTER_FIELD_BW = 0x00007762,
RPM_MASTER_FIELD_BW_T0 = 0x30747762,
RPM_MASTER_FIELD_BW_T1 = 0x31747762,
RPM_MASTER_FIELD_BW_T2 = 0x32747762,
};
/**
* struct rpm_clk_resource - RPM bus clock resource
* @resource_type: RPM resource type of the clock resource
* @clock_id: index of the clock resource of a specific resource type
* @branch: whether the resource represents a branch clock
*/
struct rpm_clk_resource {
u32 resource_type;
u32 clock_id;
bool branch;
enum qcom_icc_rpm_context {
RPM_SLEEP_CXT,
RPM_ACTIVE_CXT,
RPM_NUM_CXT
};
/**
* struct qcom_icc_provider - Qualcomm specific interconnect provider
* @provider: generic interconnect provider
* @num_intf_clks: the total number of intf_clks clk_bulk_data entries
* @type: the ICC provider type
* @regmap: regmap for QoS registers read/write access
* @qos_offset: offset to QoS registers
* @bus_clk_rate: bus clock rate in Hz
* @bus_clk_desc: a pointer to a rpm_clk_resource description of bus clocks
* @bus_clk: a pointer to a HLOS-owned bus clock
* @intf_clks: a clk_bulk_data array of interface clocks
* @keep_alive: whether to always keep a minimum vote on the bus clocks
* @is_on: whether the bus is powered on
* @dev: reference to the NoC device
* @qos_clks: the clk_bulk_data table of QoS clocks
* @num_qos_clks: the total number of clk_bulk_data entries
* @bus_clks: the clk_bulk_data table of bus clocks
* @num_clks: the total number of clk_bulk_data entries
* @bus_clk_cur_rate: current frequency of bus clock
* @keepalive: flag used to indicate whether a keepalive is required
* @init: flag to determine when init has completed.
*/
struct qcom_icc_provider {
struct icc_provider provider;
int num_intf_clks;
enum qcom_icc_type type;
struct device *dev;
struct regmap *regmap;
unsigned int qos_offset;
u32 bus_clk_rate[QCOM_SMD_RPM_STATE_NUM];
const struct rpm_clk_resource *bus_clk_desc;
struct clk *bus_clk;
struct clk_bulk_data *intf_clks;
bool keep_alive;
bool is_on;
};
/**
* struct qcom_icc_qos - Qualcomm specific interconnect QoS parameters
* @areq_prio: node requests priority
* @prio_level: priority level for bus communication
* @limit_commands: activate/deactivate limiter mode during runtime
* @ap_owned: indicates if the node is owned by the AP or by the RPM
* @qos_mode: default qos mode for this node
* @qos_port: qos port number for finding qos registers of this node
* @urg_fwd_en: enable urgent forwarding
*/
struct qcom_icc_qos {
u32 areq_prio;
u32 prio_level;
bool limit_commands;
bool ap_owned;
int qos_mode;
int qos_port;
bool urg_fwd_en;
struct list_head probe_list;
struct clk_bulk_data *qos_clks;
int num_qos_clks;
struct clk_bulk_data *bus_clks;
int num_clks;
u32 util_factor;
u64 bus_clk_cur_rate[RPM_NUM_CXT];
bool keepalive;
bool init;
};
/**
@@ -91,65 +72,43 @@ struct qcom_icc_qos {
* @id: a unique node identifier
* @links: an array of nodes where we can go next while traversing
* @num_links: the total number of @links
* @channels: number of channels at this node (e.g. DDR channels)
* @channels: num of channels at this node
* @buswidth: width of the interconnect between a node and the bus (bytes)
* @last_sum_avg: aggregated average bandwidth from previous aggregation
* @sum_avg: current sum aggregate value of all avg bw requests
* @max_peak: current max aggregate value of all peak bw requests
* @mas_rpm_id: RPM id for devices that are bus masters
* @slv_rpm_id: RPM id for devices that are bus slaves
* @qos: NoC QoS setting parameters
* @rate: current bus clock rate in Hz
* @dirty: flag used to indicate whether the node needs to be committed
*/
struct qcom_icc_node {
unsigned char *name;
u16 id;
const u16 *links;
u16 links[QCOM_MAX_LINKS];
u16 num_links;
u16 channels;
u16 buswidth;
u64 sum_avg[QCOM_SMD_RPM_STATE_NUM];
u64 max_peak[QCOM_SMD_RPM_STATE_NUM];
u64 last_sum_avg[RPM_NUM_CXT];
u64 sum_avg[RPM_NUM_CXT];
u64 max_peak[RPM_NUM_CXT];
int mas_rpm_id;
int slv_rpm_id;
struct qcom_icc_qos qos;
u64 rate;
struct regmap *regmap;
struct qcom_icc_qosbox *qosbox;
const struct qcom_icc_noc_ops *noc_ops;
bool dirty;
};
struct qcom_icc_desc {
struct qcom_icc_node * const *nodes;
struct qcom_icc_node **nodes;
size_t num_nodes;
const struct rpm_clk_resource *bus_clk_desc;
const char * const *intf_clocks;
size_t num_intf_clocks;
bool keep_alive;
enum qcom_icc_type type;
const struct regmap_config *regmap_cfg;
unsigned int qos_offset;
};
/* Valid for all bus types */
enum qos_mode {
NOC_QOS_MODE_INVALID = 0,
NOC_QOS_MODE_FIXED,
NOC_QOS_MODE_BYPASS,
};
extern const struct rpm_clk_resource aggre1_clk;
extern const struct rpm_clk_resource aggre2_clk;
extern const struct rpm_clk_resource bimc_clk;
extern const struct rpm_clk_resource bus_0_clk;
extern const struct rpm_clk_resource bus_1_clk;
extern const struct rpm_clk_resource bus_2_clk;
extern const struct rpm_clk_resource mmaxi_0_clk;
extern const struct rpm_clk_resource mmaxi_1_clk;
extern const struct rpm_clk_resource qup_clk;
extern const struct rpm_clk_resource aggre1_branch_clk;
extern const struct rpm_clk_resource aggre2_branch_clk;
int qnoc_probe(struct platform_device *pdev);
int qnoc_remove(struct platform_device *pdev);
bool qcom_icc_rpm_smd_available(void);
int qcom_icc_rpm_smd_send(int ctx, int rsc_type, int id, u32 val);
int qcom_icc_rpm_set_bus_rate(const struct rpm_clk_resource *clk, int ctx, u32 rate);
int qcom_icc_rpm_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
u32 peak_bw, u32 *agg_avg, u32 *agg_peak);
int qcom_icc_rpm_set(struct icc_node *src, struct icc_node *dst);
void qcom_icc_rpm_pre_aggregate(struct icc_node *node);
int qcom_icc_get_bw_stub(struct icc_node *node, u32 *avg, u32 *peak);
#endif

View File

@@ -1,18 +1,23 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/clk.h>
#include <linux/interconnect.h>
#include <linux/interconnect-provider.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/slab.h>
#include <soc/qcom/socinfo.h>
#include "bcm-voter.h"
#include "icc-common.h"
#include "icc-debug.h"
#include "icc-rpmh.h"
#include "qnoc-qos.h"
/**
* qcom_icc_pre_aggregate - cleans up stale values from prior icc_set
@@ -30,13 +35,19 @@ void qcom_icc_pre_aggregate(struct icc_node *node)
for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) {
qn->sum_avg[i] = 0;
qn->max_peak[i] = 0;
qn->perf_mode[i] = false;
}
for (i = 0; i < qn->num_bcms; i++)
qcom_icc_bcm_voter_add(qp->voter, qn->bcms[i]);
qcom_icc_bcm_voter_add(qp->voters[qn->bcms[i]->voter_idx],
qn->bcms[i]);
}
EXPORT_SYMBOL_GPL(qcom_icc_pre_aggregate);
static void qcom_icc_pre_aggregate_stub(struct icc_node *node)
{
}
/**
* qcom_icc_aggregate - aggregate bw for buckets indicated by tag
* @node: node to aggregate
@@ -61,6 +72,8 @@ int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
if (tag & BIT(i)) {
qn->sum_avg[i] += avg_bw;
qn->max_peak[i] = max_t(u32, qn->max_peak[i], peak_bw);
if (tag & QCOM_ICC_TAG_PERF_MODE && (avg_bw || peak_bw))
qn->perf_mode[i] = true;
}
if (node->init_avg || node->init_peak) {
@@ -76,6 +89,13 @@ int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
}
EXPORT_SYMBOL_GPL(qcom_icc_aggregate);
int qcom_icc_aggregate_stub(struct icc_node *node, u32 tag, u32 avg_bw,
u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
{
return 0;
}
EXPORT_SYMBOL(qcom_icc_aggregate_stub);
/**
* qcom_icc_set - set the constraints based on path
* @src: source node for the path to set constraints on
@@ -87,6 +107,9 @@ int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
{
struct qcom_icc_provider *qp;
struct icc_node *node;
struct qcom_icc_node *qn;
u64 clk_rate;
int i, ret;
if (!src)
node = dst;
@@ -94,13 +117,78 @@ int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
node = src;
qp = to_qcom_provider(node->provider);
qn = node->data;
qcom_icc_bcm_voter_commit(qp->voter);
if (qn->bw_scale_numerator && qn->bw_scale_denominator) {
node->avg_bw *= qn->bw_scale_numerator;
do_div(node->avg_bw, qn->bw_scale_denominator);
node->peak_bw *= qn->bw_scale_numerator;
do_div(node->peak_bw, qn->bw_scale_denominator);
}
if (qn->clk) {
/*
* Multiply by 1000 to convert the unit of bandwidth from KBps
* to Bps, then divide by the bandwidth to get the clk rate in Hz.
*/
clk_rate = (u64)max(node->avg_bw, node->peak_bw) * 1000 / qn->buswidth;
clk_rate = clk_rate > U32_MAX ? U32_MAX : clk_rate;
if (clk_rate > 0) {
ret = clk_set_rate(qn->clk, clk_rate);
if (ret)
dev_warn(qp->dev, "Failed to set %s rate to %llu for %s\n",
qn->clk_name, clk_rate, qn->name);
if (qn->toggle_clk && !qn->clk_enabled) {
ret = clk_prepare_enable(qn->clk);
if (ret) {
dev_err(qp->dev, "Failed to enable %s for %s\n",
qn->clk_name, qn->name);
return ret;
}
qn->clk_enabled = true;
}
} else if (qn->toggle_clk && qn->clk_enabled) {
clk_disable_unprepare(qn->clk);
qn->clk_enabled = false;
}
}
for (i = 0; i < qp->num_voters; i++)
qcom_icc_bcm_voter_commit(qp->voters[i]);
return 0;
}
EXPORT_SYMBOL_GPL(qcom_icc_set);
int qcom_icc_set_stub(struct icc_node *src, struct icc_node *dst)
{
return 0;
}
EXPORT_SYMBOL(qcom_icc_set_stub);
int qcom_icc_get_bw_stub(struct icc_node *node, u32 *avg, u32 *peak)
{
*avg = 0;
*peak = 0;
return 0;
}
EXPORT_SYMBOL(qcom_icc_get_bw_stub);
int qcom_icc_get_bw(struct icc_node *node, u32 *avg, u32 *peak)
{
struct qcom_icc_node *qn = node->data;
*peak = qn->init_peak;
*avg = qn->init_avg;
return 0;
}
/**
* qcom_icc_bcm_init - populates bcm aux data and connect qnodes
* @bcm: bcm to be initialized
@@ -108,15 +196,17 @@ EXPORT_SYMBOL_GPL(qcom_icc_set);
*
* Return: 0 on success, or an error code otherwise
*/
int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev)
int qcom_icc_bcm_init(struct qcom_icc_provider *qp, struct qcom_icc_bcm *bcm,
struct device *dev)
{
struct qcom_icc_node *qn;
const struct bcm_db *data;
struct bcm_voter *voter;
size_t data_count;
int i;
/* BCM is already initialised*/
if (bcm->addr)
if (bcm->disabled || bcm->addr)
return 0;
bcm->addr = cmd_db_read_addr(bcm->name);
@@ -138,8 +228,8 @@ int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev)
return -EINVAL;
}
bcm->aux_data.unit = le32_to_cpu(data->unit);
bcm->aux_data.width = le16_to_cpu(data->width);
bcm->aux_data.unit = max_t(u32, 1, le32_to_cpu(data->unit));
bcm->aux_data.width = max_t(u16, 1, le16_to_cpu(data->width));
bcm->aux_data.vcd = data->vcd;
bcm->aux_data.reserved = data->reserved;
INIT_LIST_HEAD(&bcm->list);
@@ -155,10 +245,188 @@ int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev)
qn->num_bcms++;
}
if (bcm->keepalive) {
/*
* Default vote for keepalive BCMs, use the first node as proxy node
*/
qn = bcm->nodes[0];
qn->init_avg = INT_MAX;
qn->init_peak = INT_MAX;
voter = qp->voters[bcm->voter_idx];
qcom_icc_bcm_voter_add(voter, bcm);
}
return 0;
}
EXPORT_SYMBOL_GPL(qcom_icc_bcm_init);
static bool bcm_needs_qos_proxy(struct qcom_icc_bcm *bcm)
{
int i;
if (bcm->qos_proxy)
return true;
if (bcm->voter_idx == 0)
for (i = 0; i < bcm->num_nodes; i++)
if (bcm->nodes[i]->qosbox)
return true;
return false;
}
static int enable_qos_deps(struct qcom_icc_provider *qp)
{
struct qcom_icc_bcm *bcm;
struct bcm_voter *voter;
bool keepalive;
int ret, i;
for (i = 0; i < qp->num_bcms; i++) {
bcm = qp->bcms[i];
if (bcm_needs_qos_proxy(bcm)) {
keepalive = bcm->keepalive;
bcm->keepalive = true;
voter = qp->voters[bcm->voter_idx];
qcom_icc_bcm_voter_add(voter, bcm);
ret = qcom_icc_bcm_voter_commit(voter);
bcm->keepalive = keepalive;
if (ret) {
dev_err(qp->dev, "failed to vote BW to %s for QoS\n",
bcm->name);
return ret;
}
}
}
ret = clk_bulk_prepare_enable(qp->num_clks, qp->clks);
if (ret) {
dev_err(qp->dev, "failed to enable clocks for QoS\n");
return ret;
}
return 0;
}
static void disable_qos_deps(struct qcom_icc_provider *qp)
{
struct qcom_icc_bcm *bcm;
struct bcm_voter *voter;
int i;
clk_bulk_disable_unprepare(qp->num_clks, qp->clks);
for (i = 0; i < qp->num_bcms; i++) {
bcm = qp->bcms[i];
if (bcm_needs_qos_proxy(bcm)) {
voter = qp->voters[bcm->voter_idx];
qcom_icc_bcm_voter_add(voter, bcm);
qcom_icc_bcm_voter_commit(voter);
}
}
}
int qcom_icc_rpmh_configure_qos(struct qcom_icc_provider *qp)
{
struct qcom_icc_node *qnode;
size_t i;
int ret;
ret = enable_qos_deps(qp);
if (ret)
return ret;
for (i = 0; i < qp->num_nodes; i++) {
qnode = qp->nodes[i];
if (!qnode)
continue;
if (qnode->qosbox)
qnode->noc_ops->set_qos(qnode);
}
disable_qos_deps(qp);
return ret;
}
EXPORT_SYMBOL(qcom_icc_rpmh_configure_qos);
static struct regmap *qcom_icc_rpmh_map(struct platform_device *pdev,
const struct qcom_icc_desc *desc)
{
void __iomem *base;
struct resource *res;
struct device *dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return NULL;
base = devm_ioremap(dev, res->start, resource_size(res));
if (IS_ERR(base))
return ERR_CAST(base);
return devm_regmap_init_mmio(dev, base, desc->config);
}
static bool is_voter_disabled(struct device *dev, char *voter)
{
struct device_node *np = dev->of_node;
int idx = 0;
if (!voter || !np)
return true;
idx = of_property_match_string(np, "qcom,disabled-voters", voter);
if (idx >= 0)
return true;
if ((strnstr(voter, "disp", strlen(voter)) && socinfo_get_part_info(PART_DISPLAY)) ||
(strnstr(voter, "cam", strlen(voter)) && socinfo_get_part_info(PART_CAMERA)))
return true;
return false;
}
static int qcom_icc_init_disabled_parts(struct qcom_icc_provider *qp)
{
struct qcom_icc_bcm *bcm;
struct qcom_icc_node * const *qnodes, *qn;
const struct qcom_icc_desc *desc;
int voter_idx, i, j;
char *voter_name;
desc = of_device_get_match_data(qp->dev);
if (!desc)
return -EINVAL;
for (i = 0; i < qp->num_bcms; i++) {
bcm = qp->bcms[i];
voter_idx = bcm->voter_idx;
voter_name = desc->voters[voter_idx];
/* Disable BCMs incase of NO display or No Camera */
if (is_voter_disabled(qp->dev, voter_name)) {
bcm->disabled = true;
qnodes = qp->nodes;
for (j = 0; j < qp->num_nodes; j++) {
qn = qnodes[j];
if (!qn)
continue;
if (strnstr(qn->name, voter_name, strlen(qn->name)))
qn->disabled = true;
}
}
}
return 0;
}
int qcom_icc_rpmh_probe(struct platform_device *pdev)
{
const struct qcom_icc_desc *desc;
@@ -187,38 +455,90 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
return -ENOMEM;
data->num_nodes = num_nodes;
qp->stub = of_property_read_bool(pdev->dev.of_node, "qcom,stub");
qp->skip_qos = of_property_read_bool(pdev->dev.of_node, "qcom,skip-qos");
provider = &qp->provider;
provider->dev = dev;
provider->set = qcom_icc_set;
provider->pre_aggregate = qcom_icc_pre_aggregate;
provider->aggregate = qcom_icc_aggregate;
provider->xlate_extended = qcom_icc_xlate_extended;
provider->data = data;
provider->get_bw = qcom_icc_get_bw;
if (qp->stub) {
provider->set = qcom_icc_set_stub;
provider->pre_aggregate = qcom_icc_pre_aggregate_stub;
provider->aggregate = qcom_icc_aggregate_stub;
}
icc_provider_init(provider);
qp->dev = dev;
qp->bcms = desc->bcms;
qp->num_bcms = desc->num_bcms;
qp->nodes = desc->nodes;
qp->num_nodes = desc->num_nodes;
qp->voter = of_bcm_voter_get(qp->dev, NULL);
if (IS_ERR(qp->voter))
return PTR_ERR(qp->voter);
if (!qp->stub) {
qp->num_bcms = desc->num_bcms;
qp->num_voters = desc->num_voters;
qp->voters = devm_kcalloc(&pdev->dev, qp->num_voters,
sizeof(*qp->voters), GFP_KERNEL);
if (!qp->voters)
return -ENOMEM;
ret = qcom_icc_init_disabled_parts(qp);
if (ret)
return ret;
for (i = 0; i < qp->num_voters; i++) {
if (desc->voters[i] && !is_voter_disabled(qp->dev, desc->voters[i])) {
qp->voters[i] = of_bcm_voter_get(qp->dev, desc->voters[i]);
if (IS_ERR(qp->voters[i]))
return PTR_ERR(qp->voters[i]);
}
}
}
qp->regmap = qcom_icc_rpmh_map(pdev, desc);
if (IS_ERR(qp->regmap))
return PTR_ERR(qp->regmap);
qp->num_clks = devm_clk_bulk_get_all(qp->dev, &qp->clks);
if (qp->num_clks < 0)
return qp->num_clks;
for (i = 0; i < qp->num_bcms; i++)
qcom_icc_bcm_init(qp->bcms[i], dev);
qcom_icc_bcm_init(qp, qp->bcms[i], dev);
for (i = 0; i < num_nodes; i++) {
qn = qnodes[i];
if (!qn)
if (!qn || qn->disabled)
continue;
qn->regmap = dev_get_regmap(qp->dev, NULL);
node = icc_node_create(qn->id);
if (IS_ERR(node)) {
ret = PTR_ERR(node);
goto err_remove_nodes;
}
if (qn->clk_name) {
qn->clk = devm_clk_get(qp->dev, qn->clk_name);
if (IS_ERR(qn->clk)) {
ret = PTR_ERR(qn->clk);
if (ret != -EPROBE_DEFER)
dev_err(qp->dev, "failed to get %s, err:(%d)\n",
qn->clk_name, ret);
goto err_remove_nodes;
}
}
node->name = qn->name;
node->data = qn;
icc_node_add(node, provider);
@@ -229,6 +549,12 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
data->nodes[i] = node;
}
if (!qp->skip_qos) {
ret = qcom_icc_rpmh_configure_qos(qp);
if (ret)
goto err_remove_nodes;
}
ret = icc_provider_register(provider);
if (ret)
goto err_remove_nodes;
@@ -242,6 +568,8 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
goto err_deregister_provider;
}
qcom_icc_debug_register(provider);
return 0;
err_deregister_provider:
@@ -257,6 +585,9 @@ int qcom_icc_rpmh_remove(struct platform_device *pdev)
{
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
qcom_icc_debug_unregister(&qp->provider);
clk_bulk_put_all(qp->num_clks, qp->clks);
icc_provider_deregister(&qp->provider);
icc_nodes_remove(&qp->provider);

View File

@@ -1,12 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef __DRIVERS_INTERCONNECT_QCOM_ICC_RPMH_H__
#define __DRIVERS_INTERCONNECT_QCOM_ICC_RPMH_H__
#include <dt-bindings/interconnect/qcom,icc.h>
#include <linux/regmap.h>
#include <linux/platform_device.h>
#include <soc/qcom/crm.h>
#define to_qcom_provider(_provider) \
container_of(_provider, struct qcom_icc_provider, provider)
@@ -24,7 +29,16 @@ struct qcom_icc_provider {
struct device *dev;
struct qcom_icc_bcm * const *bcms;
size_t num_bcms;
struct bcm_voter *voter;
struct qcom_icc_node * const *nodes;
size_t num_nodes;
struct list_head probe_list;
struct regmap *regmap;
struct clk_bulk_data *clks;
int num_clks;
struct bcm_voter **voters;
size_t num_voters;
bool stub;
bool skip_qos;
};
/**
@@ -46,6 +60,14 @@ struct bcm_db {
#define MAX_BCM_PER_NODE 3
#define MAX_VCD 10
struct qcom_icc_crm_voter {
const char *name;
const struct device *dev;
enum crm_drv_type client_type;
u32 client_idx;
u32 pwr_states;
};
/**
* struct qcom_icc_node - Qualcomm specific interconnect nodes
* @name: the node name used in debugfs
@@ -56,8 +78,16 @@ struct bcm_db {
* @buswidth: width of the interconnect between a node and the bus
* @sum_avg: current sum aggregate value of all avg bw requests
* @max_peak: current max aggregate value of all peak bw requests
* @perf_mode: current OR aggregate value of all QCOM_ICC_TAG_PERF_MODE votes
* @bcms: list of bcms associated with this logical node
* @num_bcms: num of @bcms
* @clk: the local clock at this node
* @clk_name: the local clock name at this node
* @toggle_clk: flag used to indicate whether local clock can be enabled/disabled
* @clk_enabled: flag used to indicate whether local clock have been enabled
* @bw_scale_numerator: the numerator of the bandwidth scale factor
* @bw_scale_denominator: the denominator of the bandwidth scale factor
* @disabled : flag used to indicate state of icc node
*/
struct qcom_icc_node {
const char *name;
@@ -68,22 +98,51 @@ struct qcom_icc_node {
u16 buswidth;
u64 sum_avg[QCOM_ICC_NUM_BUCKETS];
u64 max_peak[QCOM_ICC_NUM_BUCKETS];
bool perf_mode[QCOM_ICC_NUM_BUCKETS];
u32 init_avg;
u32 init_peak;
struct qcom_icc_bcm *bcms[MAX_BCM_PER_NODE];
size_t num_bcms;
struct regmap *regmap;
struct qcom_icc_qosbox *qosbox;
const struct qcom_icc_noc_ops *noc_ops;
struct clk *clk;
const char *clk_name;
bool toggle_clk;
bool clk_enabled;
u16 bw_scale_numerator;
u16 bw_scale_denominator;
bool disabled;
};
/**
* enum qcom_icc_bcm_type - The type of aggregation used by a BCM
*
* @QCOM_ICC_BCM_TYPE_BW: Aggregates SUM of vote_x and MAX of vote_y
* @QCOM_ICC_BCM_TYPE_MASK: Aggregates bitwise OR of vote_y
*/
enum qcom_icc_bcm_type {
QCOM_ICC_BCM_TYPE_BW,
QCOM_ICC_BCM_TYPE_MASK,
};
/**
* struct qcom_icc_bcm - Qualcomm specific hardware accelerator nodes
* known as Bus Clock Manager (BCM)
* @name: the bcm node name used to fetch BCM data from command db
* @type: latency or bandwidth bcm
* @type: aggregation strategy used by this BCM
* @addr: address offsets used when voting to RPMH
* @vote_x: aggregated threshold values, represents sum_bw when @type is bw bcm
* @vote_y: aggregated threshold values, represents peak_bw when @type is bw bcm
* @vote_scale: scaling factor for vote_x and vote_y
* @enable_mask: optional mask to send as vote instead of vote_x/vote_y
* @perf_mode_mask: mask to OR with enable_mask when QCOM_ICC_TAG_PERF_MODE is set
* @dirty: flag used to indicate whether the bcm needs to be committed
* @keepalive: flag used to indicate whether a keepalive is required
* @keepalive_early: keepalive only prior to sync-state
* @qos_proxy: flag used to indicate whether a proxy vote needed as part of
* qos configuration
* @disabled: flag used to indicate state of bcm node
* @aux_data: auxiliary data used when calculating threshold values and
* communicating with RPMh
* @list: used to link to other bcms when compiling lists for commit
@@ -93,17 +152,23 @@ struct qcom_icc_node {
*/
struct qcom_icc_bcm {
const char *name;
u32 type;
enum qcom_icc_bcm_type type;
u32 addr;
u64 vote_x[QCOM_ICC_NUM_BUCKETS];
u64 vote_y[QCOM_ICC_NUM_BUCKETS];
u64 vote_scale;
u32 enable_mask;
u32 perf_mode_mask;
bool dirty;
bool keepalive;
bool keepalive_early;
bool qos_proxy;
bool disabled;
struct bcm_db aux_data;
struct list_head list;
struct list_head ws_list;
int voter_idx;
u8 crm_node;
size_t num_nodes;
struct qcom_icc_node *nodes[];
};
@@ -115,17 +180,24 @@ struct qcom_icc_fabric {
struct qcom_icc_desc {
struct qcom_icc_node * const *nodes;
const struct regmap_config *config;
size_t num_nodes;
struct qcom_icc_bcm * const *bcms;
size_t num_bcms;
char **voters;
size_t num_voters;
};
int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
u32 peak_bw, u32 *agg_avg, u32 *agg_peak);
int qcom_icc_aggregate_stub(struct icc_node *node, u32 tag, u32 avg_bw,
u32 peak_bw, u32 *agg_avg, u32 *agg_peak);
int qcom_icc_set(struct icc_node *src, struct icc_node *dst);
int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev);
int qcom_icc_set_stub(struct icc_node *src, struct icc_node *dst);
int qcom_icc_bcm_init(struct qcom_icc_provider *qp, struct qcom_icc_bcm *bcm, struct device *dev);
void qcom_icc_pre_aggregate(struct icc_node *node);
int qcom_icc_rpmh_probe(struct platform_device *pdev);
int qcom_icc_rpmh_remove(struct platform_device *pdev);
int qcom_icc_get_bw_stub(struct icc_node *node, u32 *avg, u32 *peak);
int qcom_icc_rpmh_configure_qos(struct qcom_icc_provider *qp);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@
* Qualcomm MSM8996 Network-on-Chip (NoC) QoS driver
*
* Copyright (c) 2021 Yassine Oudjana <y.oudjana@protonmail.com>
* Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/device.h>
@@ -2117,12 +2118,6 @@ static int __init qnoc_driver_init(void)
}
core_initcall(qnoc_driver_init);
static void __exit qnoc_driver_exit(void)
{
platform_driver_unregister(&qnoc_driver);
}
module_exit(qnoc_driver_exit);
MODULE_AUTHOR("Yassine Oudjana <y.oudjana@protonmail.com>");
MODULE_DESCRIPTION("Qualcomm MSM8996 NoC driver");
MODULE_LICENSE("GPL v2");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
*
*/
@@ -1059,11 +1059,5 @@ static int __init qnoc_driver_init(void)
}
core_initcall(qnoc_driver_init);
static void __exit qnoc_driver_exit(void)
{
platform_driver_unregister(&qnoc_driver);
}
module_exit(qnoc_driver_exit);
MODULE_DESCRIPTION("QDU1000 NoC driver");
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,125 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/interconnect.h>
#include <linux/interconnect-provider.h>
#include <linux/module.h>
#include "icc-rpm.h"
#include "qnoc-qos-rpm.h"
#define QOSGEN_MAINCTL_LO(p, qp) ((p)->offsets[qp] + \
(p)->regs[QOSGEN_OFF_MAINCTL_LO])
#define QOS_SLV_URG_MSG_EN_SHFT 3
#define QOS_DFLT_PRIO_MASK 0x7
#define QOS_DFLT_PRIO_SHFT 4
#define QOS_DISABLE_SHIFT 24
#define QOSGEN_M_BKE_HEALTH(p, qp, n) ((p)->offsets[qp] + ((n) * 4) + \
(p)->regs[QOSGEN_OFF_MPORT_BKE_HEALTH])
#define QOS_PRIOLVL_MASK 0x7
#define QOS_PRIOLVL_SHFT 0x0
#define QOS_AREQPRIO_MASK 0x70
#define QOS_AREQPRIO_SHFT 0x8
#define QOSGEN_M_BKE_EN(p, qp) ((p)->offsets[qp] + \
(p)->regs[QOSGEN_OFF_MPORT_BKE_EN])
#define QOS_BKE_EN_MASK 0x1
#define QOS_BKE_EN_SHFT 0x0
#define NUM_BKE_HEALTH_LEVELS 4
const u8 icc_qnoc_qos_regs[][QOSGEN_OFF_MAX_REGS] = {
[ICC_QNOC_QOSGEN_TYPE_RPMH] = {
[QOSGEN_OFF_MAINCTL_LO] = 0x8,
[QOSGEN_OFF_LIMITBW_LO] = 0x18,
[QOSGEN_OFF_SHAPING_LO] = 0x20,
[QOSGEN_OFF_SHAPING_HI] = 0x24,
[QOSGEN_OFF_REGUL0CTL_LO] = 0x40,
[QOSGEN_OFF_REGUL0BW_LO] = 0x48,
},
};
EXPORT_SYMBOL_GPL(icc_qnoc_qos_regs);
const u8 icc_bimc_qos_regs[][QOSGEN_OFF_MAX_REGS] = {
[ICC_QNOC_QOSGEN_TYPE_RPMH] = {
[QOSGEN_OFF_MPORT_BKE_EN] = 0x0,
[QOSGEN_OFF_MPORT_BKE_HEALTH] = 0x40,
},
};
EXPORT_SYMBOL_GPL(icc_bimc_qos_regs);
/**
* qcom_icc_set_qos - initialize static QoS configurations
* @node: qcom icc node to operate on
*/
static void qcom_icc_set_qos(struct qcom_icc_node *node)
{
struct qcom_icc_qosbox *qos = node->qosbox;
int port;
if (!node->regmap)
return;
if (!qos)
return;
for (port = 0; port < qos->num_ports; port++) {
regmap_update_bits(node->regmap, QOSGEN_MAINCTL_LO(qos, port),
BIT(QOS_DISABLE_SHIFT),
qos->config->prio_fwd_disable << QOS_DISABLE_SHIFT);
regmap_update_bits(node->regmap, QOSGEN_MAINCTL_LO(qos, port),
QOS_DFLT_PRIO_MASK << QOS_DFLT_PRIO_SHFT,
qos->config->prio << QOS_DFLT_PRIO_SHFT);
regmap_update_bits(node->regmap, QOSGEN_MAINCTL_LO(qos, port),
BIT(QOS_SLV_URG_MSG_EN_SHFT),
qos->config->urg_fwd << QOS_SLV_URG_MSG_EN_SHFT);
}
}
const struct qcom_icc_noc_ops qcom_qnoc4_ops = {
.set_qos = qcom_icc_set_qos,
};
EXPORT_SYMBOL_GPL(qcom_qnoc4_ops);
/**
* qcom_icc_set_bimc_qos - initialize static QoS configurations
* @node: qcom icc node to operate on
*/
static void qcom_icc_set_bimc_qos(struct qcom_icc_node *node)
{
struct qcom_icc_qosbox *qos = node->qosbox;
int port, i;
if (!node->regmap)
return;
if (!qos)
return;
for (port = 0; port < qos->num_ports; port++) {
for (i = 0; i < NUM_BKE_HEALTH_LEVELS; i++) {
regmap_update_bits(node->regmap,
QOSGEN_M_BKE_HEALTH(qos, port, i),
((qos->config->prio << QOS_PRIOLVL_SHFT) |
(qos->config->prio << QOS_AREQPRIO_SHFT)),
(QOS_PRIOLVL_MASK | QOS_AREQPRIO_MASK));
}
regmap_update_bits(node->regmap,
QOSGEN_M_BKE_EN(qos, port),
qos->config->bke_enable << QOS_BKE_EN_SHFT,
QOS_BKE_EN_MASK);
}
}
const struct qcom_icc_noc_ops qcom_bimc_ops = {
.set_qos = qcom_icc_set_bimc_qos,
};
EXPORT_SYMBOL_GPL(qcom_bimc_ops);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#ifndef __DRIVERS_INTERCONNECT_QCOM_QNOC_QOS_RPM_H__
#define __DRIVERS_INTERCONNECT_QCOM_QNOC_QOS_RPM_H__
#define QOSGEN_OFF_MAX_REGS 6
#define ICC_QNOC_QOS_MAX_TYPE 1
enum {
ICC_QNOC_QOSGEN_TYPE_RPMH,
};
enum {
QOSGEN_OFF_MAINCTL_LO,
QOSGEN_OFF_LIMITBW_LO,
QOSGEN_OFF_SHAPING_LO,
QOSGEN_OFF_SHAPING_HI,
QOSGEN_OFF_REGUL0CTL_LO,
QOSGEN_OFF_REGUL0BW_LO,
};
enum {
QOSGEN_OFF_MPORT_BKE_HEALTH,
QOSGEN_OFF_MPORT_BKE_EN,
};
extern const u8 icc_qnoc_qos_regs[ICC_QNOC_QOS_MAX_TYPE][QOSGEN_OFF_MAX_REGS];
extern const u8 icc_bimc_qos_regs[ICC_QNOC_QOS_MAX_TYPE][QOSGEN_OFF_MAX_REGS];
struct qcom_icc_noc_ops {
void (*set_qos)(struct qcom_icc_node *node);
};
struct qos_config {
u32 prio;
u32 urg_fwd;
bool prio_fwd_disable;
u32 bke_enable;
};
struct qcom_icc_qosbox {
u32 num_ports;
const u8 *regs;
bool initialized;
struct qos_config *config;
u32 offsets[];
};
extern const struct qcom_icc_noc_ops qcom_qnoc4_ops;
extern const struct qcom_icc_noc_ops qcom_bimc_ops;
#endif

View File

@@ -0,0 +1,69 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*
*/
#include <linux/interconnect.h>
#include <linux/interconnect-provider.h>
#include <linux/module.h>
#include "icc-rpmh.h"
#include "qnoc-qos.h"
#define QOSGEN_MAINCTL_LO(p, qp) ((p)->offsets[qp] + \
(p)->regs[QOSGEN_OFF_MAINCTL_LO])
#define QOS_SLV_URG_MSG_EN_SHFT 3
# define QOS_DFLT_PRIO_MASK 0x7
# define QOS_DFLT_PRIO_SHFT 4
#define QOS_DISABLE_SHIFT 24
const u8 icc_qnoc_qos_regs[][QOSGEN_OFF_MAX_REGS] = {
[ICC_QNOC_QOSGEN_TYPE_RPMH] = {
[QOSGEN_OFF_MAINCTL_LO] = 0x8,
[QOSGEN_OFF_LIMITBW_LO] = 0x18,
[QOSGEN_OFF_SHAPING_LO] = 0x20,
[QOSGEN_OFF_SHAPING_HI] = 0x24,
[QOSGEN_OFF_REGUL0CTL_LO] = 0x40,
[QOSGEN_OFF_REGUL0BW_LO] = 0x48,
},
};
EXPORT_SYMBOL(icc_qnoc_qos_regs);
/**
* qcom_icc_set_qos - initialize static QoS configurations
* @node: qcom icc node to operate on
*/
static void qcom_icc_set_qos(struct qcom_icc_node *node)
{
struct qcom_icc_qosbox *qos = node->qosbox;
int port;
if (!node->regmap)
return;
if (!qos)
return;
for (port = 0; port < qos->num_ports; port++) {
regmap_update_bits(node->regmap, QOSGEN_MAINCTL_LO(qos, port),
BIT(QOS_DISABLE_SHIFT),
qos->config->prio_fwd_disable << QOS_DISABLE_SHIFT);
regmap_update_bits(node->regmap, QOSGEN_MAINCTL_LO(qos, port),
QOS_DFLT_PRIO_MASK << QOS_DFLT_PRIO_SHFT,
qos->config->prio << QOS_DFLT_PRIO_SHFT);
regmap_update_bits(node->regmap, QOSGEN_MAINCTL_LO(qos, port),
BIT(QOS_SLV_URG_MSG_EN_SHFT),
qos->config->urg_fwd << QOS_SLV_URG_MSG_EN_SHFT);
}
}
const struct qcom_icc_noc_ops qcom_qnoc4_ops = {
.set_qos = qcom_icc_set_qos,
};
EXPORT_SYMBOL(qcom_qnoc4_ops);
MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,59 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*
*/
#ifndef __DRIVERS_INTERCONNECT_QCOM_QNOC_QOS_H__
#define __DRIVERS_INTERCONNECT_QCOM_QNOC_QOS_H__
#define QOSGEN_OFF_MAX_REGS 6
#define ICC_QNOC_QOS_MAX_TYPE 1
enum {
ICC_QNOC_QOSGEN_TYPE_RPMH,
};
enum {
QOSGEN_OFF_MAINCTL_LO,
QOSGEN_OFF_LIMITBW_LO,
QOSGEN_OFF_SHAPING_LO,
QOSGEN_OFF_SHAPING_HI,
QOSGEN_OFF_REGUL0CTL_LO,
QOSGEN_OFF_REGUL0BW_LO,
};
extern const u8 icc_qnoc_qos_regs[ICC_QNOC_QOS_MAX_TYPE][QOSGEN_OFF_MAX_REGS];
struct qcom_icc_noc_ops {
void (*set_qos)(struct qcom_icc_node *node);
};
struct qos_config {
u32 prio;
u32 urg_fwd;
bool prio_fwd_disable;
};
struct qcom_icc_qosbox {
u32 num_ports;
const u8 *regs;
struct qos_config *config;
u32 offsets[];
};
#define DEFINE_QNODE_QOS(_name, _prio, _urg_fwd, _num_ports, ...) \
static struct qos_config _name##_qos_cfg = { \
.prio = _prio, \
.urg_fwd = _urg_fwd, \
}; \
static struct qcom_icc_qosbox _name##_qos = { \
.num_ports = _num_ports, \
.config = &_name##_qos_cfg, \
.regs = icc_qnoc_qos_regs[ICC_QNOC_QOSGEN_TYPE_RPMH], \
.offsets = {__VA_ARGS__}, \
} \
extern const struct qcom_icc_noc_ops qcom_qnoc4_ops;
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,486 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved.
*
*/
#ifndef __DRIVERS_INTERCONNECT_QCOM_RPM_IDS_H__
#define __DRIVERS_INTERCONNECT_QCOM_RPM_IDS_H__
/*
* ID's used in RPM messages
*/
#define ICBID_MASTER_APPSS_PROC 0
#define ICBID_MASTER_MSS_PROC 1
#define ICBID_MASTER_MNOC_BIMC 2
#define ICBID_MASTER_SNOC_BIMC 3
#define ICBID_MASTER_SNOC_BIMC_0 ICBID_MASTER_SNOC_BIMC
#define ICBID_MASTER_CNOC_MNOC_MMSS_CFG 4
#define ICBID_MASTER_CNOC_MNOC_CFG 5
#define ICBID_MASTER_GFX3D 6
#define ICBID_MASTER_JPEG 7
#define ICBID_MASTER_MDP 8
#define ICBID_MASTER_MDP0 ICBID_MASTER_MDP
#define ICBID_MASTER_MDPS ICBID_MASTER_MDP
#define ICBID_MASTER_VIDEO 9
#define ICBID_MASTER_VIDEO_P0 ICBID_MASTER_VIDEO
#define ICBID_MASTER_VIDEO_P1 10
#define ICBID_MASTER_VFE 11
#define ICBID_MASTER_VFE0 ICBID_MASTER_VFE
#define ICBID_MASTER_CNOC_ONOC_CFG 12
#define ICBID_MASTER_JPEG_OCMEM 13
#define ICBID_MASTER_MDP_OCMEM 14
#define ICBID_MASTER_VIDEO_P0_OCMEM 15
#define ICBID_MASTER_VIDEO_P1_OCMEM 16
#define ICBID_MASTER_VFE_OCMEM 17
#define ICBID_MASTER_LPASS_AHB 18
#define ICBID_MASTER_QDSS_BAM 19
#define ICBID_MASTER_SNOC_CFG 20
#define ICBID_MASTER_BIMC_SNOC 21
#define ICBID_MASTER_BIMC_SNOC_0 ICBID_MASTER_BIMC_SNOC
#define ICBID_MASTER_CNOC_SNOC 22
#define ICBID_MASTER_CRYPTO 23
#define ICBID_MASTER_CRYPTO_CORE0 ICBID_MASTER_CRYPTO
#define ICBID_MASTER_CRYPTO_CORE1 24
#define ICBID_MASTER_LPASS_PROC 25
#define ICBID_MASTER_MSS 26
#define ICBID_MASTER_MSS_NAV 27
#define ICBID_MASTER_OCMEM_DMA 28
#define ICBID_MASTER_PNOC_SNOC 29
#define ICBID_MASTER_WCSS 30
#define ICBID_MASTER_QDSS_ETR 31
#define ICBID_MASTER_USB3 32
#define ICBID_MASTER_USB3_0 ICBID_MASTER_USB3
#define ICBID_MASTER_SDCC_1 33
#define ICBID_MASTER_EMMC ICBID_MASTER_SDCC_1
#define ICBID_MASTER_SDCC_3 34
#define ICBID_MASTER_SDCC_2 35
#define ICBID_MASTER_SDCC_4 36
#define ICBID_MASTER_TSIF 37
#define ICBID_MASTER_BAM_DMA 38
#define ICBID_MASTER_BLSP_2 39
#define ICBID_MASTER_USB_HSIC 40
#define ICBID_MASTER_BLSP_1 41
#define ICBID_MASTER_QUP_1 ICBID_MASTER_BLSP_1
#define ICBID_MASTER_USB_HS 42
#define ICBID_MASTER_USB_HS1 ICBID_MASTER_USB_HS
#define ICBID_MASTER_PNOC_CFG 43
#define ICBID_MASTER_SNOC_PNOC 44
#define ICBID_MASTER_RPM_INST 45
#define ICBID_MASTER_RPM_DATA 46
#define ICBID_MASTER_RPM_SYS 47
#define ICBID_MASTER_DEHR 48
#define ICBID_MASTER_QDSS_DAP 49
#define ICBID_MASTER_SPDM 50
#define ICBID_MASTER_TIC 51
#define ICBID_MASTER_SNOC_CNOC 52
#define ICBID_MASTER_GFX3D_OCMEM 53
#define ICBID_MASTER_GFX3D_GMEM ICBID_MASTER_GFX3D_OCMEM
#define ICBID_MASTER_OVIRT_SNOC 54
#define ICBID_MASTER_SNOC_OVIRT 55
#define ICBID_MASTER_SNOC_GVIRT ICBID_MASTER_SNOC_OVIRT
#define ICBID_MASTER_ONOC_OVIRT 56
#define ICBID_MASTER_USB_HS2 57
#define ICBID_MASTER_QPIC 58
#define ICBID_MASTER_IPA 59
#define ICBID_MASTER_DSI 60
#define ICBID_MASTER_MDP1 61
#define ICBID_MASTER_MDPE ICBID_MASTER_MDP1
#define ICBID_MASTER_VPU_PROC 62
#define ICBID_MASTER_VPU 63
#define ICBID_MASTER_VPU0 ICBID_MASTER_VPU
#define ICBID_MASTER_CRYPTO_CORE2 64
#define ICBID_MASTER_PCIE_0 65
#define ICBID_MASTER_PCIE_1 66
#define ICBID_MASTER_SATA 67
#define ICBID_MASTER_UFS 68
#define ICBID_MASTER_USB3_1 69
#define ICBID_MASTER_VIDEO_OCMEM 70
#define ICBID_MASTER_VPU1 71
#define ICBID_MASTER_VCAP 72
#define ICBID_MASTER_EMAC 73
#define ICBID_MASTER_BCAST 74
#define ICBID_MASTER_MMSS_PROC 75
#define ICBID_MASTER_SNOC_BIMC_1 76
#define ICBID_MASTER_SNOC_PCNOC 77
#define ICBID_MASTER_AUDIO 78
#define ICBID_MASTER_MM_INT_0 79
#define ICBID_MASTER_MM_INT_1 80
#define ICBID_MASTER_MM_INT_2 81
#define ICBID_MASTER_MM_INT_BIMC 82
#define ICBID_MASTER_MSS_INT 83
#define ICBID_MASTER_PCNOC_CFG 84
#define ICBID_MASTER_PCNOC_INT_0 85
#define ICBID_MASTER_PCNOC_INT_1 86
#define ICBID_MASTER_PCNOC_M_0 87
#define ICBID_MASTER_PCNOC_M_1 88
#define ICBID_MASTER_PCNOC_S_0 89
#define ICBID_MASTER_PCNOC_S_1 90
#define ICBID_MASTER_PCNOC_S_2 91
#define ICBID_MASTER_PCNOC_S_3 92
#define ICBID_MASTER_PCNOC_S_4 93
#define ICBID_MASTER_PCNOC_S_6 94
#define ICBID_MASTER_PCNOC_S_7 95
#define ICBID_MASTER_PCNOC_S_8 96
#define ICBID_MASTER_PCNOC_S_9 97
#define ICBID_MASTER_QDSS_INT 98
#define ICBID_MASTER_SNOC_INT_0 99
#define ICBID_MASTER_SNOC_INT_1 100
#define ICBID_MASTER_SNOC_INT_BIMC 101
#define ICBID_MASTER_TCU_0 102
#define ICBID_MASTER_TCU_1 103
#define ICBID_MASTER_BIMC_INT_0 104
#define ICBID_MASTER_BIMC_INT_1 105
#define ICBID_MASTER_CAMERA 106
#define ICBID_MASTER_RICA 107
#define ICBID_MASTER_SNOC_BIMC_2 108
#define ICBID_MASTER_BIMC_SNOC_1 109
#define ICBID_MASTER_A0NOC_SNOC 110
#define ICBID_MASTER_ANOC_SNOC ICBID_MASTER_A0NOC_SNOC
#define ICBID_MASTER_A1NOC_SNOC 111
#define ICBID_MASTER_A2NOC_SNOC 112
#define ICBID_MASTER_PIMEM 113
#define ICBID_MASTER_SNOC_VMEM 114
#define ICBID_MASTER_CPP 115
#define ICBID_MASTER_CNOC_A1NOC 116
#define ICBID_MASTER_PNOC_A1NOC 117
#define ICBID_MASTER_HMSS 118
#define ICBID_MASTER_PCIE_2 119
#define ICBID_MASTER_ROTATOR 120
#define ICBID_MASTER_VENUS_VMEM 121
#define ICBID_MASTER_DCC 122
#define ICBID_MASTER_MCDMA 123
#define ICBID_MASTER_PCNOC_INT_2 124
#define ICBID_MASTER_PCNOC_INT_3 125
#define ICBID_MASTER_PCNOC_INT_4 126
#define ICBID_MASTER_PCNOC_INT_5 127
#define ICBID_MASTER_PCNOC_INT_6 128
#define ICBID_MASTER_PCNOC_S_5 129
#define ICBID_MASTER_SENSORS_AHB 130
#define ICBID_MASTER_SENSORS_PROC 131
#define ICBID_MASTER_QSPI 132
#define ICBID_MASTER_VFE1 133
#define ICBID_MASTER_SNOC_INT_2 134
#define ICBID_MASTER_SMMNOC_BIMC 135
#define ICBID_MASTER_CRVIRT_A1NOC 136
#define ICBID_MASTER_XM_USB_HS1 137
#define ICBID_MASTER_XI_USB_HS1 138
#define ICBID_MASTER_PCNOC_BIMC_1 139
#define ICBID_MASTER_BIMC_PCNOC 140
#define ICBID_MASTER_XI_HSIC 141
#define ICBID_MASTER_SGMII 142
#define ICBID_MASTER_SPMI_FETCHER 143
#define ICBID_MASTER_GNOC_BIMC 144
#define ICBID_MASTER_CRVIRT_A2NOC 145
#define ICBID_MASTER_CNOC_A2NOC 146
#define ICBID_MASTER_WLAN 147
#define ICBID_MASTER_MSS_CE 148
#define ICBID_MASTER_CDSP_PROC 149
#define ICBID_MASTER_GNOC_SNOC 150
#define ICBID_MASTER_MODEM_WRAPPER 151
#define ICBID_MASTER_SDIO 152
#define ICBID_MASTER_BIMC_SNOC_PCIE 153
#define ICBID_MASTER_WLAN_PROC 154
#define ICBID_MASTER_CRVIRT_PCNOC 155
#define ICBID_MASTER_WLAN_INT 156
#define ICBID_MASTER_PCNOC_S_10 157
#define ICBID_MASTER_PCNOC_S_11 158
#define ICBID_MASTER_LPASS_LPAIF 159
#define ICBID_MASTER_LPASS_LEC 160
#define ICBID_MASTER_LPASS_ANOC_BIMC 161
#define ICBID_MASTER_SNOC_BIMC_RT 163
#define ICBID_MASTER_SNOC_BIMC_NRT 164
#define ICBID_MASTER_GPU_CDSP_PROC 165
#define ICBID_MASTER_QUP_0 166
#define ICBID_MASTER_UFS_MEM 167
#define ICBID_MASTER_VIDEO_PROC 168
#define ICBID_MASTER_QUP_CORE_0 170
#define ICBID_MASTER_QUP_CORE_1 171
#define ICBID_MASTER_CAMNOC_SF 172
#define ICBID_MASTER_CAMNOC_HF 173
#define ICBID_SLAVE_EBI1 0
#define ICBID_SLAVE_APPSS_L2 1
#define ICBID_SLAVE_BIMC_SNOC 2
#define ICBID_SLAVE_BIMC_SNOC_0 ICBID_SLAVE_BIMC_SNOC
#define ICBID_SLAVE_CAMERA_CFG 3
#define ICBID_SLAVE_DISPLAY_CFG 4
#define ICBID_SLAVE_OCMEM_CFG 5
#define ICBID_SLAVE_CPR_CFG 6
#define ICBID_SLAVE_CPR_XPU_CFG 7
#define ICBID_SLAVE_MISC_CFG 8
#define ICBID_SLAVE_MISC_XPU_CFG 9
#define ICBID_SLAVE_VENUS_CFG 10
#define ICBID_SLAVE_GFX3D_CFG 11
#define ICBID_SLAVE_MMSS_CLK_CFG 12
#define ICBID_SLAVE_MMSS_CLK_XPU_CFG 13
#define ICBID_SLAVE_MNOC_MPU_CFG 14
#define ICBID_SLAVE_ONOC_MPU_CFG 15
#define ICBID_SLAVE_MNOC_BIMC 16
#define ICBID_SLAVE_SERVICE_MNOC 17
#define ICBID_SLAVE_OCMEM 18
#define ICBID_SLAVE_GMEM ICBID_SLAVE_OCMEM
#define ICBID_SLAVE_SERVICE_ONOC 19
#define ICBID_SLAVE_APPSS 20
#define ICBID_SLAVE_LPASS 21
#define ICBID_SLAVE_USB3 22
#define ICBID_SLAVE_USB3_0 ICBID_SLAVE_USB3
#define ICBID_SLAVE_WCSS 23
#define ICBID_SLAVE_SNOC_BIMC 24
#define ICBID_SLAVE_SNOC_BIMC_0 ICBID_SLAVE_SNOC_BIMC
#define ICBID_SLAVE_SNOC_CNOC 25
#define ICBID_SLAVE_IMEM 26
#define ICBID_SLAVE_OCIMEM ICBID_SLAVE_IMEM
#define ICBID_SLAVE_SNOC_OVIRT 27
#define ICBID_SLAVE_SNOC_GVIRT ICBID_SLAVE_SNOC_OVIRT
#define ICBID_SLAVE_SNOC_PNOC 28
#define ICBID_SLAVE_SNOC_PCNOC ICBID_SLAVE_SNOC_PNOC
#define ICBID_SLAVE_SERVICE_SNOC 29
#define ICBID_SLAVE_QDSS_STM 30
#define ICBID_SLAVE_SDCC_1 31
#define ICBID_SLAVE_EMMC_CFG ICBID_SLAVE_SDCC_1
#define ICBID_SLAVE_SDCC_3 32
#define ICBID_SLAVE_SDCC_2 33
#define ICBID_SLAVE_SDCC_4 34
#define ICBID_SLAVE_TSIF 35
#define ICBID_SLAVE_BAM_DMA 36
#define ICBID_SLAVE_BLSP_2 37
#define ICBID_SLAVE_USB_HSIC 38
#define ICBID_SLAVE_BLSP_1 39
#define ICBID_SLAVE_QUP_1 ICBID_SLAVE_BLSP_1
#define ICBID_SLAVE_USB_HS 40
#define ICBID_SLAVE_USB_HS1 ICBID_SLAVE_USB_HS
#define ICBID_SLAVE_PDM 41
#define ICBID_SLAVE_PERIPH_APU_CFG 42
#define ICBID_SLAVE_PNOC_MPU_CFG 43
#define ICBID_SLAVE_PRNG 44
#define ICBID_SLAVE_PNOC_SNOC 45
#define ICBID_SLAVE_PCNOC_SNOC ICBID_SLAVE_PNOC_SNOC
#define ICBID_SLAVE_SERVICE_PNOC 46
#define ICBID_SLAVE_CLK_CTL 47
#define ICBID_SLAVE_CNOC_MSS 48
#define ICBID_SLAVE_PCNOC_MSS ICBID_SLAVE_CNOC_MSS
#define ICBID_SLAVE_SECURITY 49
#define ICBID_SLAVE_TCSR 50
#define ICBID_SLAVE_TLMM 51
#define ICBID_SLAVE_CRYPTO_0_CFG 52
#define ICBID_SLAVE_CRYPTO_1_CFG 53
#define ICBID_SLAVE_IMEM_CFG 54
#define ICBID_SLAVE_MESSAGE_RAM 55
#define ICBID_SLAVE_BIMC_CFG 56
#define ICBID_SLAVE_BOOT_ROM 57
#define ICBID_SLAVE_CNOC_MNOC_MMSS_CFG 58
#define ICBID_SLAVE_PMIC_ARB 59
#define ICBID_SLAVE_SPDM_WRAPPER 60
#define ICBID_SLAVE_DEHR_CFG 61
#define ICBID_SLAVE_MPM 62
#define ICBID_SLAVE_QDSS_CFG 63
#define ICBID_SLAVE_RBCPR_CFG 64
#define ICBID_SLAVE_RBCPR_CX_CFG ICBID_SLAVE_RBCPR_CFG
#define ICBID_SLAVE_RBCPR_QDSS_APU_CFG 65
#define ICBID_SLAVE_CNOC_MNOC_CFG 66
#define ICBID_SLAVE_SNOC_MPU_CFG 67
#define ICBID_SLAVE_CNOC_ONOC_CFG 68
#define ICBID_SLAVE_PNOC_CFG 69
#define ICBID_SLAVE_SNOC_CFG 70
#define ICBID_SLAVE_EBI1_DLL_CFG 71
#define ICBID_SLAVE_PHY_APU_CFG 72
#define ICBID_SLAVE_EBI1_PHY_CFG 73
#define ICBID_SLAVE_RPM 74
#define ICBID_SLAVE_CNOC_SNOC 75
#define ICBID_SLAVE_SERVICE_CNOC 76
#define ICBID_SLAVE_OVIRT_SNOC 77
#define ICBID_SLAVE_OVIRT_OCMEM 78
#define ICBID_SLAVE_USB_HS2 79
#define ICBID_SLAVE_QPIC 80
#define ICBID_SLAVE_IPS_CFG 81
#define ICBID_SLAVE_DSI_CFG 82
#define ICBID_SLAVE_USB3_1 83
#define ICBID_SLAVE_PCIE_0 84
#define ICBID_SLAVE_PCIE_1 85
#define ICBID_SLAVE_PSS_SMMU_CFG 86
#define ICBID_SLAVE_CRYPTO_2_CFG 87
#define ICBID_SLAVE_PCIE_0_CFG 88
#define ICBID_SLAVE_PCIE_1_CFG 89
#define ICBID_SLAVE_SATA_CFG 90
#define ICBID_SLAVE_SPSS_GENI_IR 91
#define ICBID_SLAVE_UFS_CFG 92
#define ICBID_SLAVE_AVSYNC_CFG 93
#define ICBID_SLAVE_VPU_CFG 94
#define ICBID_SLAVE_USB_PHY_CFG 95
#define ICBID_SLAVE_RBCPR_MX_CFG 96
#define ICBID_SLAVE_PCIE_PARF 97
#define ICBID_SLAVE_VCAP_CFG 98
#define ICBID_SLAVE_EMAC_CFG 99
#define ICBID_SLAVE_BCAST_CFG 100
#define ICBID_SLAVE_KLM_CFG 101
#define ICBID_SLAVE_DISPLAY_PWM 102
#define ICBID_SLAVE_GENI 103
#define ICBID_SLAVE_SNOC_BIMC_1 104
#define ICBID_SLAVE_AUDIO 105
#define ICBID_SLAVE_CATS_0 106
#define ICBID_SLAVE_CATS_1 107
#define ICBID_SLAVE_MM_INT_0 108
#define ICBID_SLAVE_MM_INT_1 109
#define ICBID_SLAVE_MM_INT_2 110
#define ICBID_SLAVE_MM_INT_BIMC 111
#define ICBID_SLAVE_MMU_MODEM_XPU_CFG 112
#define ICBID_SLAVE_MSS_INT 113
#define ICBID_SLAVE_PCNOC_INT_0 114
#define ICBID_SLAVE_PCNOC_INT_1 115
#define ICBID_SLAVE_PCNOC_M_0 116
#define ICBID_SLAVE_PCNOC_M_1 117
#define ICBID_SLAVE_PCNOC_S_0 118
#define ICBID_SLAVE_PCNOC_S_1 119
#define ICBID_SLAVE_PCNOC_S_2 120
#define ICBID_SLAVE_PCNOC_S_3 121
#define ICBID_SLAVE_PCNOC_S_4 122
#define ICBID_SLAVE_PCNOC_S_6 123
#define ICBID_SLAVE_PCNOC_S_7 124
#define ICBID_SLAVE_PCNOC_S_8 125
#define ICBID_SLAVE_PCNOC_S_9 126
#define ICBID_SLAVE_PRNG_XPU_CFG 127
#define ICBID_SLAVE_QDSS_INT 128
#define ICBID_SLAVE_RPM_XPU_CFG 129
#define ICBID_SLAVE_SNOC_INT_0 130
#define ICBID_SLAVE_SNOC_INT_1 131
#define ICBID_SLAVE_SNOC_INT_BIMC 132
#define ICBID_SLAVE_TCU 133
#define ICBID_SLAVE_BIMC_INT_0 134
#define ICBID_SLAVE_BIMC_INT_1 135
#define ICBID_SLAVE_RICA_CFG 136
#define ICBID_SLAVE_SNOC_BIMC_2 137
#define ICBID_SLAVE_BIMC_SNOC_1 138
#define ICBID_SLAVE_PNOC_A1NOC 139
#define ICBID_SLAVE_SNOC_VMEM 140
#define ICBID_SLAVE_A0NOC_SNOC 141
#define ICBID_SLAVE_ANOC_SNOC ICBID_SLAVE_A0NOC_SNOC
#define ICBID_SLAVE_A1NOC_SNOC 142
#define ICBID_SLAVE_A2NOC_SNOC 143
#define ICBID_SLAVE_A0NOC_CFG 144
#define ICBID_SLAVE_A0NOC_MPU_CFG 145
#define ICBID_SLAVE_A0NOC_SMMU_CFG 146
#define ICBID_SLAVE_A1NOC_CFG 147
#define ICBID_SLAVE_A1NOC_MPU_CFG 148
#define ICBID_SLAVE_A1NOC_SMMU_CFG 149
#define ICBID_SLAVE_A2NOC_CFG 150
#define ICBID_SLAVE_A2NOC_MPU_CFG 151
#define ICBID_SLAVE_A2NOC_SMMU_CFG 152
#define ICBID_SLAVE_AHB2PHY 153
#define ICBID_SLAVE_CAMERA_THROTTLE_CFG 154
#define ICBID_SLAVE_DCC_CFG 155
#define ICBID_SLAVE_DISPLAY_THROTTLE_CFG 156
#define ICBID_SLAVE_DSA_CFG 157
#define ICBID_SLAVE_DSA_MPU_CFG 158
#define ICBID_SLAVE_SSC_MPU_CFG 159
#define ICBID_SLAVE_HMSS_L3 160
#define ICBID_SLAVE_LPASS_SMMU_CFG 161
#define ICBID_SLAVE_MMAGIC_CFG 162
#define ICBID_SLAVE_PCIE20_AHB2PHY 163
#define ICBID_SLAVE_PCIE_2 164
#define ICBID_SLAVE_PCIE_2_CFG 165
#define ICBID_SLAVE_PIMEM 166
#define ICBID_SLAVE_PIMEM_CFG 167
#define ICBID_SLAVE_QDSS_RBCPR_APU_CFG 168
#define ICBID_SLAVE_RBCPR_CX 169
#define ICBID_SLAVE_RBCPR_MX 170
#define ICBID_SLAVE_SMMU_CPP_CFG 171
#define ICBID_SLAVE_SMMU_JPEG_CFG 172
#define ICBID_SLAVE_SMMU_MDP_CFG 173
#define ICBID_SLAVE_SMMU_ROTATOR_CFG 174
#define ICBID_SLAVE_SMMU_VENUS_CFG 175
#define ICBID_SLAVE_SMMU_VFE_CFG 176
#define ICBID_SLAVE_SSC_CFG 177
#define ICBID_SLAVE_VENUS_THROTTLE_CFG 178
#define ICBID_SLAVE_VMEM 179
#define ICBID_SLAVE_VMEM_CFG 180
#define ICBID_SLAVE_QDSS_MPU_CFG 181
#define ICBID_SLAVE_USB3_PHY_CFG 182
#define ICBID_SLAVE_IPA_CFG 183
#define ICBID_SLAVE_PCNOC_INT_2 184
#define ICBID_SLAVE_PCNOC_INT_3 185
#define ICBID_SLAVE_PCNOC_INT_4 186
#define ICBID_SLAVE_PCNOC_INT_5 187
#define ICBID_SLAVE_PCNOC_INT_6 188
#define ICBID_SLAVE_PCNOC_S_5 189
#define ICBID_SLAVE_QSPI 190
#define ICBID_SLAVE_A1NOC_MS_MPU_CFG 191
#define ICBID_SLAVE_A2NOC_MS_MPU_CFG 192
#define ICBID_SLAVE_MODEM_Q6_SMMU_CFG 193
#define ICBID_SLAVE_MSS_MPU_CFG 194
#define ICBID_SLAVE_MSS_PROC_MS_MPU_CFG 195
#define ICBID_SLAVE_SKL 196
#define ICBID_SLAVE_SNOC_INT_2 197
#define ICBID_SLAVE_SMMNOC_BIMC 198
#define ICBID_SLAVE_CRVIRT_A1NOC 199
#define ICBID_SLAVE_SGMII 200
#define ICBID_SLAVE_QHS4_APPS 201
#define ICBID_SLAVE_BIMC_PCNOC 202
#define ICBID_SLAVE_PCNOC_BIMC_1 203
#define ICBID_SLAVE_SPMI_FETCHER 204
#define ICBID_SLAVE_MMSS_SMMU_CFG 205
#define ICBID_SLAVE_WLAN 206
#define ICBID_SLAVE_CRVIRT_A2NOC 207
#define ICBID_SLAVE_CNOC_A2NOC 208
#define ICBID_SLAVE_GLM 209
#define ICBID_SLAVE_GNOC_BIMC 210
#define ICBID_SLAVE_GNOC_SNOC 211
#define ICBID_SLAVE_QM_CFG 212
#define ICBID_SLAVE_TLMM_EAST 213
#define ICBID_SLAVE_TLMM_NORTH 214
#define ICBID_SLAVE_TLMM_WEST 215
#define ICBID_SLAVE_TLMM_SOUTH 216
#define ICBID_SLAVE_TLMM_CENTER 217
#define ICBID_SLAVE_MSS_NAV_CE_MPU_CFG 218
#define ICBID_SLAVE_A2NOC_THROTTLE_CFG 219
#define ICBID_SLAVE_CDSP 220
#define ICBID_SLAVE_CDSP_SMMU_CFG 221
#define ICBID_SLAVE_LPASS_MPU_CFG 222
#define ICBID_SLAVE_CSI_PHY_CFG 223
#define ICBID_SLAVE_DDRSS_CFG 224
#define ICBID_SLAVE_DDRSS_MPU_CFG 225
#define ICBID_SLAVE_SNOC_MSS_XPU_CFG 226
#define ICBID_SLAVE_BIMC_MSS_XPU_CFG 227
#define ICBID_SLAVE_MSS_SNOC_MPU_CFG 228
#define ICBID_SLAVE_MSS 229
#define ICBID_SLAVE_SDIO 230
#define ICBID_SLAVE_QM_MPU_CFG 231
#define ICBID_SLAVE_BIMC_SNOC_PCIE 232
#define ICBID_SLAVE_BOOTIMEM 233
#define ICBID_SLAVE_CDSP_CFG 234
#define ICBID_SLAVE_WLAN_DSP_CFG 235
#define ICBID_SLAVE_GENIR_XPU_CFG 236
#define ICBID_SLAVE_BOOTIMEM_MPU 237
#define ICBID_SLAVE_CRVIRT_PCNOC 238
#define ICBID_SLAVE_WLAN_INT 239
#define ICBID_SLAVE_WLAN_MPU_CFG 240
#define ICBID_SLAVE_LPASS_AGNOC_CFG 241
#define ICBID_SLAVE_LPASS_AGNOC_XPU_CFG 242
#define ICBID_SLAVE_PLL_BIAS_CFG 243
#define ICBID_SLAVE_EMAC 244
#define ICBID_SLAVE_PCNOC_S_10 245
#define ICBID_SLAVE_PCNOC_S_11 246
#define ICBID_SLAVE_LPASS_ANOC_BIMC 247
#define ICBID_SLAVE_SNOC_BIMC_NRT 259
#define ICBID_SLAVE_SNOC_BIMC_RT 260
#define ICBID_SLAVE_QUP_0 261
#define ICBID_SLAVE_UFS_MEM_CFG 262
#define ICBID_SLAVE_VSENSE_CTRL_CFG 263
#define ICBID_SLAVE_QUP_CORE_0 264
#define ICBID_SLAVE_QUP_CORE_1 265
#define ICBID_SLAVE_GPU_CDSP_BIMC 266
#define ICBID_SLAVE_AHB2PHY_USB 268
#define ICBID_SLAVE_APSS_THROTTLE_CFG 270
#define ICBID_SLAVE_CAMERA_NRT_THROTTLE_CFG 271
#define ICBID_SLAVE_CDSP_THROTTLE_CFG 272
#define ICBID_SLAVE_DDR_PHY_CFG 273
#define ICBID_SLAVE_DDR_SS_CFG 274
#define ICBID_SLAVE_GPU_CFG 275
#define ICBID_SLAVE_GPU_THROTTLE_CFG 276
#define ICBID_SLAVE_MAPSS 277
#define ICBID_SLAVE_MDSP_MPU_CFG 278
#define ICBID_SLAVE_CAMERA_RT_THROTTLE_CFG 279
#define ICBID_SLAVE_HWKM 280
#define ICBID_SLAVE_PKA_WRAPPER 281
#endif

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2021-2023, Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2023, Linaro Limited
*/
@@ -2533,11 +2533,5 @@ static int __init qnoc_driver_init(void)
}
core_initcall(qnoc_driver_init);
static void __exit qnoc_driver_exit(void)
{
platform_driver_unregister(&qnoc_driver);
}
module_exit(qnoc_driver_exit);
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. SA8775P NoC driver");
MODULE_LICENSE("GPL");

View File

@@ -2,6 +2,7 @@
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022, Linaro Ltd
* Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/device.h>
@@ -2405,11 +2406,5 @@ static int __init qnoc_driver_init(void)
}
core_initcall(qnoc_driver_init);
static void __exit qnoc_driver_exit(void)
{
platform_driver_unregister(&qnoc_driver);
}
module_exit(qnoc_driver_exit);
MODULE_DESCRIPTION("Qualcomm SC8280XP NoC driver");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,7 @@
/*
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2021, Linaro Limited
* Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/device.h>
@@ -1898,11 +1899,5 @@ static int __init qnoc_driver_init(void)
}
core_initcall(qnoc_driver_init);
static void __exit qnoc_driver_exit(void)
{
platform_driver_unregister(&qnoc_driver);
}
module_exit(qnoc_driver_exit);
MODULE_DESCRIPTION("sm8450 NoC driver");
MODULE_LICENSE("GPL v2");

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2022, Linaro Limited
*
*/
@@ -2233,11 +2233,5 @@ static int __init qnoc_driver_init(void)
}
core_initcall(qnoc_driver_init);
static void __exit qnoc_driver_exit(void)
{
platform_driver_unregister(&qnoc_driver);
}
module_exit(qnoc_driver_exit);
MODULE_DESCRIPTION("sm8550 NoC driver");
MODULE_LICENSE("GPL");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#undef TRACE_SYSTEM
#define TRACE_SYSTEM interconnect_qcom
#if !defined(_TRACE_INTERCONNECT_QCOM_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_INTERCONNECT_QCOM_H
#include <soc/qcom/tcs.h>
#include <linux/tracepoint.h>
TRACE_EVENT(bcm_voter_commit,
TP_PROTO(const char *rpmh_state, const struct tcs_cmd *cmd),
TP_ARGS(rpmh_state, cmd),
TP_STRUCT__entry(
__string(state_name, rpmh_state)
__field(u32, addr)
__field(u32, data)
__field(u32, wait)
),
TP_fast_assign(
__assign_str(state_name, rpmh_state);
__entry->addr = cmd->addr;
__entry->data = cmd->data;
__entry->wait = cmd->wait;
),
TP_printk("%s cmd_addr=0x%x cmd_data=0x%x cmd_wait=%u",
__get_str(state_name),
__entry->addr,
__entry->data,
__entry->wait)
);
#endif /* _TRACE_INTERCONNECT_QCOM_H */
/* This part must be outside protection */
#undef TRACE_INCLUDE_PATH
#define TRACE_INCLUDE_PATH .
#undef TRACE_INCLUDE_FILE
#define TRACE_INCLUDE_FILE trace
#include <trace/define_trace.h>

File diff suppressed because it is too large Load Diff