Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,462 @@
# SPDX-License-Identifier: GPL-2.0-only
config INTERCONNECT_QCOM
tristate "Qualcomm Network-on-Chip interconnect drivers"
depends on ARCH_QCOM
help
Support for Qualcomm's Network-on-Chip interconnect hardware.
config INTERCONNECT_QCOM_BCM_VOTER
tristate
config INTERCONNECT_QCOM_ELIZA
tristate "Qualcomm Eliza interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on Eliza-based
platforms.
config INTERCONNECT_QCOM_GLYMUR
tristate "Qualcomm Glymur interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on glymur-based
platforms.
config INTERCONNECT_QCOM_HAWI
tristate "Qualcomm HAWI interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on hawi-based
platforms.
config INTERCONNECT_QCOM_KAANAPALI
tristate "Qualcomm Kaanapali interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on kaanapali-based
platforms.
config INTERCONNECT_QCOM_MSM8909
tristate "Qualcomm MSM8909 interconnect driver"
depends on INTERCONNECT_QCOM
depends on QCOM_SMD_RPM
depends on ARM || COMPILE_TEST
select INTERCONNECT_QCOM_SMD_RPM
help
This is a driver for the Qualcomm Network-on-Chip on msm8909-based
platforms.
config INTERCONNECT_QCOM_MSM8916
tristate "Qualcomm MSM8916 interconnect driver"
depends on INTERCONNECT_QCOM
depends on QCOM_SMD_RPM
select INTERCONNECT_QCOM_SMD_RPM
help
This is a driver for the Qualcomm Network-on-Chip on msm8916-based
platforms.
config INTERCONNECT_QCOM_MSM8937
tristate "Qualcomm MSM8937 interconnect driver"
depends on INTERCONNECT_QCOM
depends on QCOM_SMD_RPM
select INTERCONNECT_QCOM_SMD_RPM
help
This is a driver for the Qualcomm Network-on-Chip on msm8937-based
platforms.
config INTERCONNECT_QCOM_MSM8939
tristate "Qualcomm MSM8939 interconnect driver"
depends on INTERCONNECT_QCOM
depends on QCOM_SMD_RPM
select INTERCONNECT_QCOM_SMD_RPM
help
This is a driver for the Qualcomm Network-on-Chip on msm8939-based
platforms.
config INTERCONNECT_QCOM_MSM8953
tristate "Qualcomm MSM8953 interconnect driver"
depends on INTERCONNECT_QCOM
depends on QCOM_SMD_RPM
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_SMD_RPM
help
This is a driver for the Qualcomm Network-on-Chip on msm8953-based
platforms.
config INTERCONNECT_QCOM_MSM8974
tristate "Qualcomm MSM8974 interconnect driver"
depends on INTERCONNECT_QCOM
depends on QCOM_SMD_RPM
depends on ARM || COMPILE_TEST
select INTERCONNECT_QCOM_SMD_RPM
help
This is a driver for the Qualcomm Network-on-Chip on msm8974-based
platforms.
config INTERCONNECT_QCOM_MSM8976
tristate "Qualcomm MSM8976 interconnect driver"
depends on INTERCONNECT_QCOM
depends on QCOM_SMD_RPM
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_SMD_RPM
help
This is a driver for the Qualcomm Network-on-Chip on msm8976-based
platforms.
config INTERCONNECT_QCOM_MSM8996
tristate "Qualcomm MSM8996 interconnect driver"
depends on INTERCONNECT_QCOM
depends on QCOM_SMD_RPM
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_SMD_RPM
help
This is a driver for the Qualcomm Network-on-Chip on msm8996-based
platforms.
config INTERCONNECT_QCOM_NORD
tristate "Qualcomm Nord interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on Nord-based
platforms. The topology consists of several NoCs controlled by
the RPMh hardware and communicates via Bus Clock Manager (BCM)
through the Resource State Coordinator (RSC).
config INTERCONNECT_QCOM_OSM_L3
tristate "Qualcomm OSM L3 interconnect driver"
depends on INTERCONNECT_QCOM || COMPILE_TEST
depends on ARM64 || COMPILE_TEST
help
Say y here to support the Operating State Manager (OSM) interconnect
driver which controls the scaling of L3 caches on Qualcomm SoCs.
config INTERCONNECT_QCOM_QCM2290
tristate "Qualcomm QCM2290 interconnect driver"
depends on INTERCONNECT_QCOM
depends on QCOM_SMD_RPM
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_SMD_RPM
help
This is a driver for the Qualcomm Network-on-Chip on qcm2290-based
platforms.
config INTERCONNECT_QCOM_QCS404
tristate "Qualcomm QCS404 interconnect driver"
depends on INTERCONNECT_QCOM
depends on QCOM_SMD_RPM
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_SMD_RPM
help
This is a driver for the Qualcomm Network-on-Chip on qcs404-based
platforms.
config INTERCONNECT_QCOM_QCS615
tristate "Qualcomm QCS615 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on qcs615-based
platforms.
config INTERCONNECT_QCOM_QCS8300
tristate "Qualcomm QCS8300 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Technologies, Inc. Network-on-Chip
on QCS8300-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_QDU1000
tristate "Qualcomm QDU1000/QRU1000 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on QDU1000-based
and QRU1000-based platforms.
config INTERCONNECT_QCOM_RPMH_POSSIBLE
tristate
default INTERCONNECT_QCOM
depends on QCOM_RPMH || (COMPILE_TEST && !QCOM_RPMH)
depends on QCOM_COMMAND_DB || (COMPILE_TEST && !QCOM_COMMAND_DB)
depends on OF
help
Compile-testing RPMH drivers is possible on other platforms,
but in order to avoid link failures, drivers must not be built-in
when QCOM_RPMH or QCOM_COMMAND_DB are loadable modules
config INTERCONNECT_QCOM_RPMH
tristate
config INTERCONNECT_QCOM_SA8775P
tristate "Qualcomm SA8775P interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on sa8775p-based
platforms.
config INTERCONNECT_QCOM_SAR2130P
tristate "Qualcomm SAR2130P interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on SAR2130P-based
platforms.
config INTERCONNECT_QCOM_SC7180
tristate "Qualcomm SC7180 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on sc7180-based
platforms.
config INTERCONNECT_QCOM_SC7280
tristate "Qualcomm SC7280 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on sc7280-based
platforms.
config INTERCONNECT_QCOM_SC8180X
tristate "Qualcomm SC8180X interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on sc8180x-based
platforms.
config INTERCONNECT_QCOM_SC8280XP
tristate "Qualcomm SC8280XP interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on SC8280XP-based
platforms.
config INTERCONNECT_QCOM_SDM660
tristate "Qualcomm SDM660 interconnect driver"
depends on INTERCONNECT_QCOM
depends on ARM64 || COMPILE_TEST
depends on QCOM_SMD_RPM
select INTERCONNECT_QCOM_SMD_RPM
help
This is a driver for the Qualcomm Network-on-Chip on sdm660-based
platforms.
config INTERCONNECT_QCOM_SDM670
tristate "Qualcomm SDM670 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on sdm670-based
platforms.
config INTERCONNECT_QCOM_SDM845
tristate "Qualcomm SDM845 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on sdm845-based
platforms.
config INTERCONNECT_QCOM_SDX55
tristate "Qualcomm SDX55 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on sdx55-based
platforms.
config INTERCONNECT_QCOM_SDX65
tristate "Qualcomm SDX65 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on sdx65-based
platforms.
config INTERCONNECT_QCOM_SDX75
tristate "Qualcomm SDX75 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on sdx75-based
platforms.
config INTERCONNECT_QCOM_SHIKRA
tristate "Qualcomm SHIKRA interconnect driver"
depends on INTERCONNECT_QCOM
depends on QCOM_SMD_RPM
select INTERCONNECT_QCOM_SMD_RPM
help
This is a driver for the Qualcomm Network-on-Chip on shikra-based
platforms.
config INTERCONNECT_QCOM_SM6115
tristate "Qualcomm SM6115 interconnect driver"
depends on INTERCONNECT_QCOM
depends on QCOM_SMD_RPM
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_SMD_RPM
help
This is a driver for the Qualcomm Network-on-Chip on sm6115-based
platforms.
config INTERCONNECT_QCOM_SM6350
tristate "Qualcomm SM6350 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on sm6350-based
platforms.
config INTERCONNECT_QCOM_SM7150
tristate "Qualcomm SM7150 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on sm7150-based
platforms.
config INTERCONNECT_QCOM_MILOS
tristate "Qualcomm Milos interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on Milos-based
platforms.
config INTERCONNECT_QCOM_SM8150
tristate "Qualcomm SM8150 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on sm8150-based
platforms.
config INTERCONNECT_QCOM_SM8250
tristate "Qualcomm SM8250 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on sm8250-based
platforms.
config INTERCONNECT_QCOM_SM8350
tristate "Qualcomm SM8350 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on SM8350-based
platforms.
config INTERCONNECT_QCOM_SM8450
tristate "Qualcomm SM8450 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on SM8450-based
platforms.
config INTERCONNECT_QCOM_SM8550
tristate "Qualcomm SM8550 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on SM8550-based
platforms.
config INTERCONNECT_QCOM_SM8650
tristate "Qualcomm SM8650 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on SM8650-based
platforms.
config INTERCONNECT_QCOM_SM8750
tristate "Qualcomm SM8750 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on SM8750-based
platforms.
config INTERCONNECT_QCOM_X1E80100
tristate "Qualcomm X1E80100 interconnect driver"
depends on INTERCONNECT_QCOM_RPMH_POSSIBLE
depends on ARM64 || COMPILE_TEST
select INTERCONNECT_QCOM_RPMH
select INTERCONNECT_QCOM_BCM_VOTER
help
This is a driver for the Qualcomm Network-on-Chip on X1E80100-based
platforms.
config INTERCONNECT_QCOM_SMD_RPM
tristate
@@ -0,0 +1,100 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_INTERCONNECT_QCOM) += interconnect_qcom.o
interconnect_qcom-y := icc-common.o
icc-bcm-voter-objs := bcm-voter.o
qnoc-eliza-objs := eliza.o
qnoc-glymur-objs := glymur.o
qnoc-hawi-objs := hawi.o
qnoc-kaanapali-objs := kaanapali.o
qnoc-milos-objs := milos.o
qnoc-msm8909-objs := msm8909.o
qnoc-msm8916-objs := msm8916.o
qnoc-msm8937-objs := msm8937.o
qnoc-msm8939-objs := msm8939.o
qnoc-msm8953-objs := msm8953.o
qnoc-msm8974-objs := msm8974.o
qnoc-msm8976-objs := msm8976.o
qnoc-msm8996-objs := msm8996.o
qnoc-nord-objs := nord.o
icc-osm-l3-objs := osm-l3.o
qnoc-qcm2290-objs := qcm2290.o
qnoc-qcs404-objs := qcs404.o
qnoc-qcs615-objs := qcs615.o
qnoc-qcs8300-objs := qcs8300.o
qnoc-qdu1000-objs := qdu1000.o
icc-rpmh-obj := icc-rpmh.o
qnoc-sa8775p-objs := sa8775p.o
qnoc-sar2130p-objs := sar2130p.o
qnoc-sc7180-objs := sc7180.o
qnoc-sc7280-objs := sc7280.o
qnoc-sc8180x-objs := sc8180x.o
qnoc-sc8280xp-objs := sc8280xp.o
qnoc-sdm660-objs := sdm660.o
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-shikra-objs := shikra.o
qnoc-sm6115-objs := sm6115.o
qnoc-sm6350-objs := sm6350.o
qnoc-sm7150-objs := sm7150.o
qnoc-sm8150-objs := sm8150.o
qnoc-sm8250-objs := sm8250.o
qnoc-sm8350-objs := sm8350.o
qnoc-sm8450-objs := sm8450.o
qnoc-sm8550-objs := sm8550.o
qnoc-sm8650-objs := sm8650.o
qnoc-sm8750-objs := sm8750.o
qnoc-x1e80100-objs := x1e80100.o
icc-smd-rpm-objs := smd-rpm.o icc-rpm.o icc-rpm-clocks.o
obj-$(CONFIG_INTERCONNECT_QCOM_BCM_VOTER) += icc-bcm-voter.o
obj-$(CONFIG_INTERCONNECT_QCOM_ELIZA) += qnoc-eliza.o
obj-$(CONFIG_INTERCONNECT_QCOM_GLYMUR) += qnoc-glymur.o
obj-$(CONFIG_INTERCONNECT_QCOM_HAWI) += qnoc-hawi.o
obj-$(CONFIG_INTERCONNECT_QCOM_KAANAPALI) += qnoc-kaanapali.o
obj-$(CONFIG_INTERCONNECT_QCOM_MILOS) += qnoc-milos.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8909) += qnoc-msm8909.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8916) += qnoc-msm8916.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8937) += qnoc-msm8937.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8939) += qnoc-msm8939.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8953) += qnoc-msm8953.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8974) += qnoc-msm8974.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8976) += qnoc-msm8976.o
obj-$(CONFIG_INTERCONNECT_QCOM_MSM8996) += qnoc-msm8996.o
obj-$(CONFIG_INTERCONNECT_QCOM_NORD) += qnoc-nord.o
obj-$(CONFIG_INTERCONNECT_QCOM_OSM_L3) += icc-osm-l3.o
obj-$(CONFIG_INTERCONNECT_QCOM_QCM2290) += qnoc-qcm2290.o
obj-$(CONFIG_INTERCONNECT_QCOM_QCS404) += qnoc-qcs404.o
obj-$(CONFIG_INTERCONNECT_QCOM_QCS615) += qnoc-qcs615.o
obj-$(CONFIG_INTERCONNECT_QCOM_QCS8300) += qnoc-qcs8300.o
obj-$(CONFIG_INTERCONNECT_QCOM_QDU1000) += qnoc-qdu1000.o
obj-$(CONFIG_INTERCONNECT_QCOM_RPMH) += icc-rpmh.o
obj-$(CONFIG_INTERCONNECT_QCOM_SA8775P) += qnoc-sa8775p.o
obj-$(CONFIG_INTERCONNECT_QCOM_SAR2130P) += qnoc-sar2130p.o
obj-$(CONFIG_INTERCONNECT_QCOM_SC7180) += qnoc-sc7180.o
obj-$(CONFIG_INTERCONNECT_QCOM_SC7280) += qnoc-sc7280.o
obj-$(CONFIG_INTERCONNECT_QCOM_SC8180X) += qnoc-sc8180x.o
obj-$(CONFIG_INTERCONNECT_QCOM_SC8280XP) += qnoc-sc8280xp.o
obj-$(CONFIG_INTERCONNECT_QCOM_SDM660) += qnoc-sdm660.o
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_SHIKRA) += qnoc-shikra.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM6115) += qnoc-sm6115.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM6350) += qnoc-sm6350.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM7150) += qnoc-sm7150.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_SM8550) += qnoc-sm8550.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8650) += qnoc-sm8650.o
obj-$(CONFIG_INTERCONNECT_QCOM_SM8750) += qnoc-sm8750.o
obj-$(CONFIG_INTERCONNECT_QCOM_X1E80100) += qnoc-x1e80100.o
obj-$(CONFIG_INTERCONNECT_QCOM_SMD_RPM) += icc-smd-rpm.o
@@ -0,0 +1,413 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
*/
#include <asm/div64.h>
#include <linux/interconnect-provider.h>
#include <linux/list_sort.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <soc/qcom/rpmh.h>
#include <soc/qcom/tcs.h>
#include "bcm-voter.h"
#include "icc-rpmh.h"
static LIST_HEAD(bcm_voters);
static DEFINE_MUTEX(bcm_voter_lock);
/**
* struct bcm_voter - Bus Clock Manager voter
* @dev: reference to the device that communicates with the BCM
* @np: reference to the device node to match bcm voters
* @lock: mutex to protect commit and wake/sleep lists in the voter
* @commit_list: list containing bcms to be committed to hardware
* @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
*/
struct bcm_voter {
struct device *dev;
struct device_node *np;
struct mutex lock;
struct list_head commit_list;
struct list_head ws_list;
struct list_head voter_node;
u32 tcs_wait;
};
static int cmp_vcd(void *priv, const struct list_head *a, const struct list_head *b)
{
const struct qcom_icc_bcm *bcm_a = list_entry(a, struct qcom_icc_bcm, list);
const struct qcom_icc_bcm *bcm_b = list_entry(b, struct qcom_icc_bcm, list);
return bcm_a->aux_data.vcd - bcm_b->aux_data.vcd;
}
static u64 bcm_div(u64 num, u32 base)
{
/* Ensure that small votes aren't lost. */
if (num && num < base)
return 1;
do_div(num, base);
return num;
}
/* BCMs with enable_mask use one-hot-encoding for on/off signaling */
static void bcm_aggregate_mask(struct qcom_icc_bcm *bcm)
{
struct qcom_icc_node *node;
int bucket, i;
for (bucket = 0; bucket < QCOM_ICC_NUM_BUCKETS; bucket++) {
bcm->vote_x[bucket] = 0;
bcm->vote_y[bucket] = 0;
for (i = 0; i < bcm->num_nodes; i++) {
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 (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;
}
}
static void bcm_aggregate(struct qcom_icc_bcm *bcm)
{
struct qcom_icc_node *node;
size_t i, bucket;
u64 agg_avg[QCOM_ICC_NUM_BUCKETS] = {0};
u64 agg_peak[QCOM_ICC_NUM_BUCKETS] = {0};
u64 temp;
for (bucket = 0; bucket < QCOM_ICC_NUM_BUCKETS; bucket++) {
for (i = 0; i < bcm->num_nodes; i++) {
node = bcm->nodes[i];
temp = bcm_div(node->sum_avg[bucket] * bcm->aux_data.width,
node->buswidth * node->channels);
agg_avg[bucket] = max(agg_avg[bucket], temp);
temp = bcm_div(node->max_peak[bucket] * bcm->aux_data.width,
node->buswidth);
agg_peak[bucket] = max(agg_peak[bucket], temp);
}
temp = agg_avg[bucket] * bcm->vote_scale;
bcm->vote_x[bucket] = bcm_div(temp, bcm->aux_data.unit);
temp = agg_peak[bucket] * bcm->vote_scale;
bcm->vote_y[bucket] = bcm_div(temp, bcm->aux_data.unit);
}
if (bcm->keepalive && bcm->vote_x[QCOM_ICC_BUCKET_AMC] == 0 &&
bcm->vote_y[QCOM_ICC_BUCKET_AMC] == 0) {
bcm->vote_x[QCOM_ICC_BUCKET_AMC] = 1;
bcm->vote_x[QCOM_ICC_BUCKET_WAKE] = 1;
bcm->vote_y[QCOM_ICC_BUCKET_AMC] = 1;
bcm->vote_y[QCOM_ICC_BUCKET_WAKE] = 1;
}
}
static inline void tcs_cmd_gen(struct tcs_cmd *cmd, u64 vote_x, u64 vote_y,
u32 addr, bool commit, bool wait)
{
bool valid = true;
if (!cmd)
return;
memset(cmd, 0, sizeof(*cmd));
if (vote_x == 0 && vote_y == 0)
valid = false;
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;
cmd->addr = addr;
cmd->data = BCM_TCS_CMD(commit, valid, vote_x, vote_y);
/*
* Set the wait for completion flag on command that need to be completed
* before the next command.
*/
cmd->wait = wait;
}
static void tcs_list_gen(struct bcm_voter *voter, int bucket,
struct tcs_cmd tcs_list[MAX_VCD],
int n[MAX_VCD + 1])
{
struct list_head *bcm_list = &voter->commit_list;
struct qcom_icc_bcm *bcm;
bool commit, wait;
size_t idx = 0, batch = 0, cur_vcd_size = 0;
memset(n, 0, sizeof(int) * (MAX_VCD + 1));
list_for_each_entry(bcm, bcm_list, list) {
commit = false;
cur_vcd_size++;
if ((list_is_last(&bcm->list, bcm_list)) ||
bcm->aux_data.vcd != list_next_entry(bcm, list)->aux_data.vcd) {
commit = true;
cur_vcd_size = 0;
}
wait = commit && (voter->tcs_wait & BIT(bucket));
tcs_cmd_gen(&tcs_list[idx], bcm->vote_x[bucket],
bcm->vote_y[bucket], bcm->addr, commit, wait);
idx++;
n[batch]++;
/*
* Batch the BCMs in such a way that we do not split them in
* multiple payloads when they are under the same VCD. This is
* to ensure that every BCM is committed since we only set the
* commit bit on the last BCM request of every VCD.
*/
if (n[batch] >= MAX_RPMH_PAYLOAD) {
if (!commit) {
n[batch] -= cur_vcd_size;
n[batch + 1] = cur_vcd_size;
}
batch++;
}
}
}
/**
* of_bcm_voter_get - gets a bcm voter handle from DT node
* @dev: device pointer for the consumer device
* @name: name for the bcm voter device
*
* This function will match a device_node pointer for the phandle
* specified in the device DT and return a bcm_voter handle on success.
*
* Returns bcm_voter pointer or ERR_PTR() on error. EPROBE_DEFER is returned
* when matching bcm voter is yet to be found.
*/
struct bcm_voter *of_bcm_voter_get(struct device *dev, const char *name)
{
struct bcm_voter *voter = ERR_PTR(-EPROBE_DEFER);
struct bcm_voter *temp;
struct device_node *np, *node;
int idx = 0;
if (!dev || !dev->of_node)
return ERR_PTR(-ENODEV);
np = dev->of_node;
if (name) {
idx = of_property_match_string(np, "qcom,bcm-voter-names", name);
if (idx < 0)
return ERR_PTR(idx);
}
node = of_parse_phandle(np, "qcom,bcm-voters", idx);
mutex_lock(&bcm_voter_lock);
list_for_each_entry(temp, &bcm_voters, voter_node) {
if (temp->np == node) {
voter = temp;
break;
}
}
mutex_unlock(&bcm_voter_lock);
of_node_put(node);
return voter;
}
EXPORT_SYMBOL_GPL(of_bcm_voter_get);
/**
* qcom_icc_bcm_voter_add - queues up the bcm nodes that require updates
* @voter: voter that the bcms are being added to
* @bcm: bcm to add to the commit and wake sleep list
*/
void qcom_icc_bcm_voter_add(struct bcm_voter *voter, struct qcom_icc_bcm *bcm)
{
if (!voter)
return;
mutex_lock(&voter->lock);
if (list_empty(&bcm->list))
list_add_tail(&bcm->list, &voter->commit_list);
if (list_empty(&bcm->ws_list))
list_add_tail(&bcm->ws_list, &voter->ws_list);
mutex_unlock(&voter->lock);
}
EXPORT_SYMBOL_GPL(qcom_icc_bcm_voter_add);
/**
* qcom_icc_bcm_voter_commit - generates and commits tcs cmds based on bcms
* @voter: voter that needs flushing
*
* This function generates a set of AMC commands and flushes to the BCM device
* associated with the voter. It conditionally generate WAKE and SLEEP commands
* based on deltas between WAKE/SLEEP requirements. The ws_list persists
* through multiple commit requests and bcm nodes are removed only when the
* requirements for WAKE matches SLEEP.
*
* Returns 0 on success, or an appropriate error code otherwise.
*/
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;
if (!voter)
return 0;
mutex_lock(&voter->lock);
list_for_each_entry(bcm, &voter->commit_list, list) {
if (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);
/*
* 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);
mutex_unlock(&voter->lock);
return ret;
}
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 bcm_voter *voter;
voter = devm_kzalloc(&pdev->dev, sizeof(*voter), GFP_KERNEL);
if (!voter)
return -ENOMEM;
voter->dev = &pdev->dev;
voter->np = np;
if (of_property_read_u32(np, "qcom,tcs-wait", &voter->tcs_wait))
voter->tcs_wait = QCOM_ICC_TAG_ACTIVE_ONLY;
mutex_init(&voter->lock);
INIT_LIST_HEAD(&voter->commit_list);
INIT_LIST_HEAD(&voter->ws_list);
mutex_lock(&bcm_voter_lock);
list_add_tail(&voter->voter_node, &bcm_voters);
mutex_unlock(&bcm_voter_lock);
return 0;
}
static const struct of_device_id bcm_voter_of_match[] = {
{ .compatible = "qcom,bcm-voter" },
{ }
};
MODULE_DEVICE_TABLE(of, bcm_voter_of_match);
static struct platform_driver qcom_icc_bcm_voter_driver = {
.probe = qcom_icc_bcm_voter_probe,
.driver = {
.name = "bcm_voter",
.of_match_table = bcm_voter_of_match,
},
};
module_platform_driver(qcom_icc_bcm_voter_driver);
MODULE_AUTHOR("David Dai <daidavid1@codeaurora.org>");
MODULE_DESCRIPTION("Qualcomm BCM Voter interconnect driver");
MODULE_LICENSE("GPL v2");
@@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#ifndef __DRIVERS_INTERCONNECT_QCOM_BCM_VOTER_H__
#define __DRIVERS_INTERCONNECT_QCOM_BCM_VOTER_H__
#include <soc/qcom/cmd-db.h>
#include <soc/qcom/rpmh.h>
#include <soc/qcom/tcs.h>
#include "icc-rpmh.h"
struct bcm_voter *of_bcm_voter_get(struct device *dev, const char *name);
void qcom_icc_bcm_voter_add(struct bcm_voter *voter, struct qcom_icc_bcm *bcm);
int qcom_icc_bcm_voter_commit(struct bcm_voter *voter);
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,39 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2022 Linaro Ltd.
*/
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/module.h>
#include "icc-common.h"
struct icc_node_data *qcom_icc_xlate_extended(const struct of_phandle_args *spec,
void *data)
{
struct icc_node_data *ndata;
struct icc_node *node;
node = of_icc_xlate_onecell(spec, data);
if (IS_ERR(node))
return ERR_CAST(node);
ndata = kzalloc_obj(*ndata);
if (!ndata)
return ERR_PTR(-ENOMEM);
ndata->node = node;
if (spec->args_count == 2)
ndata->tag = spec->args[1];
if (spec->args_count > 2)
pr_warn("%pOF: Too many arguments, path tag is not parsed\n", spec->np);
return ndata;
}
EXPORT_SYMBOL_GPL(qcom_icc_xlate_extended);
MODULE_DESCRIPTION("Qualcomm interconnect common functions");
MODULE_LICENSE("GPL");
@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2022 Linaro Ltd.
*/
#ifndef __DRIVERS_INTERCONNECT_QCOM_ICC_COMMON_H__
#define __DRIVERS_INTERCONNECT_QCOM_ICC_COMMON_H__
#include <linux/interconnect-provider.h>
struct icc_node_data *qcom_icc_xlate_extended(const struct of_phandle_args *spec,
void *data);
#endif
@@ -0,0 +1,89 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2023 Linaro Ltd
*/
#include <linux/soc/qcom/smd-rpm.h>
#include "icc-rpm.h"
const struct rpm_clk_resource aggre1_clk = {
.resource_type = QCOM_SMD_RPM_AGGR_CLK,
.clock_id = 1,
};
EXPORT_SYMBOL_GPL(aggre1_clk);
const struct rpm_clk_resource aggre2_clk = {
.resource_type = QCOM_SMD_RPM_AGGR_CLK,
.clock_id = 2,
};
EXPORT_SYMBOL_GPL(aggre2_clk);
const struct rpm_clk_resource bimc_clk = {
.resource_type = QCOM_SMD_RPM_MEM_CLK,
.clock_id = 0,
};
EXPORT_SYMBOL_GPL(bimc_clk);
const struct rpm_clk_resource mem_1_clk = {
.resource_type = QCOM_SMD_RPM_MEM_CLK,
.clock_id = 1,
};
EXPORT_SYMBOL_GPL(mem_1_clk);
const struct rpm_clk_resource gpu_mem_2_clk = {
.resource_type = QCOM_SMD_RPM_MEM_CLK,
.clock_id = 2,
};
EXPORT_SYMBOL_GPL(gpu_mem_2_clk);
const struct rpm_clk_resource bus_0_clk = {
.resource_type = QCOM_SMD_RPM_BUS_CLK,
.clock_id = 0,
};
EXPORT_SYMBOL_GPL(bus_0_clk);
const struct rpm_clk_resource bus_1_clk = {
.resource_type = QCOM_SMD_RPM_BUS_CLK,
.clock_id = 1,
};
EXPORT_SYMBOL_GPL(bus_1_clk);
const struct rpm_clk_resource bus_2_clk = {
.resource_type = QCOM_SMD_RPM_BUS_CLK,
.clock_id = 2,
};
EXPORT_SYMBOL_GPL(bus_2_clk);
const struct rpm_clk_resource mmaxi_0_clk = {
.resource_type = QCOM_SMD_RPM_MMAXI_CLK,
.clock_id = 0,
};
EXPORT_SYMBOL_GPL(mmaxi_0_clk);
const struct rpm_clk_resource mmaxi_1_clk = {
.resource_type = QCOM_SMD_RPM_MMAXI_CLK,
.clock_id = 1,
};
EXPORT_SYMBOL_GPL(mmaxi_1_clk);
const struct rpm_clk_resource qup_clk = {
.resource_type = QCOM_SMD_RPM_QUP_CLK,
.clock_id = 0,
};
EXPORT_SYMBOL_GPL(qup_clk);
/* Branch clocks */
const struct rpm_clk_resource aggre1_branch_clk = {
.resource_type = QCOM_SMD_RPM_AGGR_CLK,
.clock_id = 1,
.branch = true,
};
EXPORT_SYMBOL_GPL(aggre1_branch_clk);
const struct rpm_clk_resource aggre2_branch_clk = {
.resource_type = QCOM_SMD_RPM_AGGR_CLK,
.clock_id = 2,
.branch = true,
};
EXPORT_SYMBOL_GPL(aggre2_branch_clk);
@@ -0,0 +1,642 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 Linaro Ltd
*/
#include <linux/device.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 "icc-common.h"
#include "icc-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)
{
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;
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;
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);
}
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, bool ignore_enxio)
{
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);
if (ret != -ENXIO || !ignore_enxio)
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);
if (ret != -ENXIO || !ignore_enxio)
return ret;
}
}
}
return 0;
}
/**
* qcom_icc_pre_bw_aggregate - cleans up values before re-aggregate requests
* @node: icc node to operate on
*/
static void qcom_icc_pre_bw_aggregate(struct icc_node *node)
{
struct qcom_icc_node *qn;
size_t i;
qn = node->data;
for (i = 0; i < QCOM_SMD_RPM_STATE_NUM; i++) {
qn->sum_avg[i] = 0;
qn->max_peak[i] = 0;
}
}
/**
* qcom_icc_bw_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
* @peak_bw: new bw to max aggregate
* @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)
{
size_t i;
struct qcom_icc_node *qn;
qn = node->data;
if (!tag)
tag = RPM_ALWAYS_TAG;
for (i = 0; i < QCOM_SMD_RPM_STATE_NUM; i++) {
if (tag & BIT(i)) {
qn->sum_avg[i] += avg_bw;
qn->max_peak[i] = max_t(u32, qn->max_peak[i], peak_bw);
}
}
*agg_avg += avg_bw;
*agg_peak = max_t(u32, *agg_peak, peak_bw);
return 0;
}
static u64 qcom_icc_calc_rate(struct qcom_icc_provider *qp, struct qcom_icc_node *qn, int ctx)
{
u64 agg_avg_rate, agg_peak_rate, agg_rate;
if (qn->channels)
agg_avg_rate = div_u64(qn->sum_avg[ctx], qn->channels);
else
agg_avg_rate = qn->sum_avg[ctx];
if (qn->ab_coeff) {
agg_avg_rate = agg_avg_rate * qn->ab_coeff;
agg_avg_rate = div_u64(agg_avg_rate, 100);
}
if (qn->ib_coeff) {
agg_peak_rate = qn->max_peak[ctx] * 100;
agg_peak_rate = div_u64(agg_peak_rate, qn->ib_coeff);
} else {
agg_peak_rate = qn->max_peak[ctx];
}
agg_rate = max_t(u64, agg_avg_rate, agg_peak_rate);
return div_u64(agg_rate, qn->buswidth);
}
/**
* 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
*/
static void qcom_icc_bus_aggregate(struct icc_provider *provider, u64 *agg_clk_rate)
{
struct qcom_icc_provider *qp = to_qcom_provider(provider);
struct qcom_icc_node *qn;
struct icc_node *node;
int ctx;
/*
* 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 (ctx = 0; ctx < QCOM_SMD_RPM_STATE_NUM; ctx++) {
agg_clk_rate[ctx] = max_t(u64, agg_clk_rate[ctx],
qcom_icc_calc_rate(qp, qn, ctx));
}
}
}
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;
src_qn = src->data;
if (dst)
dst_qn = dst->data;
provider = src->provider;
qp = to_qcom_provider(provider);
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];
ret = qcom_icc_rpm_set(src_qn, src_qn->sum_avg, qp->ignore_enxio);
if (ret)
return ret;
if (dst_qn) {
ret = qcom_icc_rpm_set(dst_qn, dst_qn->sum_avg, qp->ignore_enxio);
if (ret)
return ret;
}
/* Some providers don't have a bus clock to scale */
if (!qp->bus_clk_desc && !qp->bus_clk)
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);
/* 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);
}
/* RPM only accepts <=INT_MAX rates */
active_rate = min_t(u64, active_rate, INT_MAX);
sleep_rate = min_t(u64, sleep_rate, INT_MAX);
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;
/* Cache the rate after we've successfully commited it to RPM */
qp->bus_clk_rate[QCOM_SMD_RPM_ACTIVE_STATE] = active_rate;
}
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;
/* Cache the rate after we've successfully commited it to RPM */
qp->bus_clk_rate[QCOM_SMD_RPM_SLEEP_STATE] = sleep_rate;
}
/* Handle the node-specific clock */
if (!src_qn->bus_clk_desc)
return 0;
active_rate = qcom_icc_calc_rate(qp, src_qn, QCOM_SMD_RPM_ACTIVE_STATE);
sleep_rate = qcom_icc_calc_rate(qp, src_qn, QCOM_SMD_RPM_SLEEP_STATE);
if (active_rate != src_qn->bus_clk_rate[QCOM_SMD_RPM_ACTIVE_STATE]) {
ret = qcom_icc_rpm_set_bus_rate(src_qn->bus_clk_desc, QCOM_SMD_RPM_ACTIVE_STATE,
active_rate);
if (ret)
return ret;
/* Cache the rate after we've successfully committed it to RPM */
src_qn->bus_clk_rate[QCOM_SMD_RPM_ACTIVE_STATE] = active_rate;
}
if (sleep_rate != src_qn->bus_clk_rate[QCOM_SMD_RPM_SLEEP_STATE]) {
ret = qcom_icc_rpm_set_bus_rate(src_qn->bus_clk_desc, QCOM_SMD_RPM_SLEEP_STATE,
sleep_rate);
if (ret)
return ret;
/* Cache the rate after we've successfully committed it to RPM */
src_qn->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;
data->num_nodes = num_nodes;
qp->num_intf_clks = cd_num;
for (i = 0; i < cd_num; i++)
qp->intf_clks[i].id = cds[i];
qp->ignore_enxio = desc->ignore_enxio;
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);
}
}
regmap_done:
ret = clk_prepare_enable(qp->bus_clk);
if (ret)
return ret;
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;
provider->get_bw = desc->get_bw;
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;
if (!qnodes[i]->ab_coeff)
qnodes[i]->ab_coeff = qp->ab_coeff;
if (!qnodes[i]->ib_coeff)
qnodes[i]->ib_coeff = qp->ib_coeff;
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;
}
}
data->nodes[i] = node;
}
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);
void 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);
}
EXPORT_SYMBOL(qnoc_remove);
@@ -0,0 +1,173 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2020 Linaro Ltd
*/
#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>
#define RPM_BUS_MASTER_REQ 0x73616d62
#define RPM_BUS_SLAVE_REQ 0x766c7362
#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,
};
/**
* 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;
};
/**
* 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
* @ab_coeff: a percentage-based coefficient for compensating the AB calculations
* @ib_coeff: an inverse-percentage-based coefficient for compensating the IB calculations
* @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
* @ignore_enxio: whether to ignore ENXIO errors (for MSM8974)
*/
struct qcom_icc_provider {
struct icc_provider provider;
int num_intf_clks;
enum qcom_icc_type type;
struct regmap *regmap;
unsigned int qos_offset;
u16 ab_coeff;
u16 ib_coeff;
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 ignore_enxio;
};
/**
* 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 qcom_icc_node - Qualcomm specific interconnect nodes
* @name: the node name used in debugfs
* @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)
* @buswidth: width of the interconnect between a node and the bus (bytes)
* @bus_clk_desc: a pointer to a rpm_clk_resource description of bus clocks
* @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
* @ab_coeff: a percentage-based coefficient for compensating the AB calculations
* @ib_coeff: an inverse-percentage-based coefficient for compensating the IB calculations
* @bus_clk_rate: a pointer to an array containing bus clock rates in Hz
*/
struct qcom_icc_node {
unsigned char *name;
u16 id;
const u16 *links;
u16 num_links;
u16 channels;
u16 buswidth;
const struct rpm_clk_resource *bus_clk_desc;
u64 sum_avg[QCOM_SMD_RPM_STATE_NUM];
u64 max_peak[QCOM_SMD_RPM_STATE_NUM];
int mas_rpm_id;
int slv_rpm_id;
struct qcom_icc_qos qos;
u16 ab_coeff;
u16 ib_coeff;
u32 bus_clk_rate[QCOM_SMD_RPM_STATE_NUM];
};
struct qcom_icc_desc {
struct qcom_icc_node * const *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;
u16 ab_coeff;
u16 ib_coeff;
int (*get_bw)(struct icc_node *node, u32 *avg, u32 *peak);
bool ignore_enxio;
};
/* 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 gpu_mem_2_clk;
extern const struct rpm_clk_resource mem_1_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);
void 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);
#endif
@@ -0,0 +1,375 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/bitfield.h>
#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 "bcm-voter.h"
#include "icc-common.h"
#include "icc-rpmh.h"
/* QNOC QoS */
#define QOSGEN_MAINCTL_LO(p, qp) (0x8 + (p->port_offsets[qp]))
#define QOS_SLV_URG_MSG_EN_MASK GENMASK(3, 3)
#define QOS_DFLT_PRIO_MASK GENMASK(6, 4)
#define QOS_DISABLE_MASK GENMASK(24, 24)
/**
* qcom_icc_set_qos - initialize static QoS configurations
* @qp: qcom icc provider to which @node belongs
* @node: qcom icc node to operate on
*/
static void qcom_icc_set_qos(struct qcom_icc_provider *qp,
struct qcom_icc_node *node)
{
const struct qcom_icc_qosbox *qos = node->qosbox;
int port;
for (port = 0; port < qos->num_ports; port++) {
regmap_update_bits(qp->regmap, QOSGEN_MAINCTL_LO(qos, port),
QOS_DISABLE_MASK,
FIELD_PREP(QOS_DISABLE_MASK, qos->prio_fwd_disable));
regmap_update_bits(qp->regmap, QOSGEN_MAINCTL_LO(qos, port),
QOS_DFLT_PRIO_MASK,
FIELD_PREP(QOS_DFLT_PRIO_MASK, qos->prio));
regmap_update_bits(qp->regmap, QOSGEN_MAINCTL_LO(qos, port),
QOS_SLV_URG_MSG_EN_MASK,
FIELD_PREP(QOS_SLV_URG_MSG_EN_MASK, qos->urg_fwd));
}
}
/**
* qcom_icc_pre_aggregate - cleans up stale values from prior icc_set
* @node: icc node to operate on
*/
void qcom_icc_pre_aggregate(struct icc_node *node)
{
size_t i;
struct qcom_icc_node *qn;
struct qcom_icc_provider *qp;
qn = node->data;
qp = to_qcom_provider(node->provider);
for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) {
qn->sum_avg[i] = 0;
qn->max_peak[i] = 0;
}
for (i = 0; i < qn->num_bcms; i++)
qcom_icc_bcm_voter_add(qp->voter, qn->bcms[i]);
}
EXPORT_SYMBOL_GPL(qcom_icc_pre_aggregate);
/**
* qcom_icc_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
* @peak_bw: new bw to max aggregate
* @agg_avg: existing aggregate avg bw val
* @agg_peak: existing aggregate peak bw val
*/
int qcom_icc_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 = QCOM_ICC_TAG_ALWAYS;
for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) {
if (tag & BIT(i)) {
qn->sum_avg[i] += avg_bw;
qn->max_peak[i] = max_t(u32, qn->max_peak[i], peak_bw);
}
if (node->init_avg || node->init_peak) {
qn->sum_avg[i] = max_t(u64, qn->sum_avg[i], node->init_avg);
qn->max_peak[i] = max_t(u64, qn->max_peak[i], node->init_peak);
}
}
*agg_avg += avg_bw;
*agg_peak = max_t(u32, *agg_peak, peak_bw);
return 0;
}
EXPORT_SYMBOL_GPL(qcom_icc_aggregate);
/**
* qcom_icc_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
*/
int qcom_icc_set(struct icc_node *src, struct icc_node *dst)
{
struct qcom_icc_provider *qp;
struct icc_node *node;
if (!src)
node = dst;
else
node = src;
qp = to_qcom_provider(node->provider);
qcom_icc_bcm_voter_commit(qp->voter);
return 0;
}
EXPORT_SYMBOL_GPL(qcom_icc_set);
/**
* qcom_icc_bcm_init - populates bcm aux data and connect qnodes
* @bcm: bcm to be initialized
* @dev: associated provider device
*
* Return: 0 on success, or an error code otherwise
*/
int qcom_icc_bcm_init(struct qcom_icc_bcm *bcm, struct device *dev)
{
struct qcom_icc_node *qn;
const struct bcm_db *data;
size_t data_count;
int i;
/* BCM is already initialised*/
if (bcm->addr)
return 0;
bcm->addr = cmd_db_read_addr(bcm->name);
if (!bcm->addr) {
dev_err(dev, "%s could not find RPMh address\n",
bcm->name);
return -EINVAL;
}
data = cmd_db_read_aux_data(bcm->name, &data_count);
if (IS_ERR(data)) {
dev_err(dev, "%s command db read error (%ld)\n",
bcm->name, PTR_ERR(data));
return PTR_ERR(data);
}
if (!data_count) {
dev_err(dev, "%s command db missing or partial aux data\n",
bcm->name);
return -EINVAL;
}
bcm->aux_data.unit = le32_to_cpu(data->unit);
bcm->aux_data.width = le16_to_cpu(data->width);
bcm->aux_data.vcd = data->vcd;
bcm->aux_data.reserved = data->reserved;
INIT_LIST_HEAD(&bcm->list);
INIT_LIST_HEAD(&bcm->ws_list);
if (!bcm->vote_scale)
bcm->vote_scale = 1000;
/* Link Qnodes to their respective BCMs */
for (i = 0; i < bcm->num_nodes; i++) {
qn = bcm->nodes[i];
qn->bcms[qn->num_bcms] = bcm;
qn->num_bcms++;
}
return 0;
}
EXPORT_SYMBOL_GPL(qcom_icc_bcm_init);
/**
* qcom_icc_rpmh_configure_qos - configure QoS parameters
* @qp: qcom icc provider associated with QoS endpoint nodes
*
* Return: 0 on success, or an error code otherwise
*/
static int qcom_icc_rpmh_configure_qos(struct qcom_icc_provider *qp)
{
struct qcom_icc_node *qnode;
size_t i;
int ret;
ret = clk_bulk_prepare_enable(qp->num_clks, qp->clks);
if (ret)
return ret;
for (i = 0; i < qp->num_nodes; i++) {
qnode = qp->nodes[i];
if (!qnode)
continue;
if (qnode->qosbox)
qcom_icc_set_qos(qp, qnode);
}
clk_bulk_disable_unprepare(qp->num_clks, qp->clks);
return ret;
}
int qcom_icc_rpmh_probe(struct platform_device *pdev)
{
const struct qcom_icc_desc *desc;
struct device *dev = &pdev->dev;
struct icc_onecell_data *data;
struct icc_provider *provider;
struct qcom_icc_node * const *qnodes, *qn;
struct qcom_icc_provider *qp;
struct icc_node *node;
size_t num_nodes, i, j;
int ret;
desc = of_device_get_match_data(dev);
if (!desc)
return -EINVAL;
qnodes = desc->nodes;
num_nodes = desc->num_nodes;
qp = devm_kzalloc(dev, sizeof(*qp), GFP_KERNEL);
if (!qp)
return -ENOMEM;
data = devm_kzalloc(dev, struct_size(data, nodes, num_nodes), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->num_nodes = num_nodes;
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;
icc_provider_init(provider);
qp->dev = dev;
qp->bcms = desc->bcms;
qp->nodes = desc->nodes;
qp->num_bcms = desc->num_bcms;
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);
for (i = 0; i < qp->num_bcms; i++)
qcom_icc_bcm_init(qp->bcms[i], dev);
for (i = 0; i < num_nodes; i++) {
qn = qnodes[i];
if (!qn)
continue;
if (!qn->node)
qn->node = icc_node_create_dyn();
node = qn->node;
if (IS_ERR(node)) {
ret = PTR_ERR(node);
goto err_remove_nodes;
}
ret = icc_node_set_name(node, provider, qn->name);
if (ret) {
icc_node_destroy(node->id);
goto err_remove_nodes;
}
node->data = qn;
icc_node_add(node, provider);
for (j = 0; j < qn->num_links; j++)
icc_link_nodes(node, &qn->link_nodes[j]->node);
data->nodes[i] = node;
}
if (desc->config) {
struct resource *res;
void __iomem *base;
/* Try parent's regmap first */
qp->regmap = dev_get_regmap(dev->parent, NULL);
if (!qp->regmap) {
base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(base))
goto skip_qos_config;
qp->regmap = devm_regmap_init_mmio(dev, base, desc->config);
if (IS_ERR(qp->regmap)) {
dev_info(dev, "Skipping QoS, regmap failed; %ld\n",
PTR_ERR(qp->regmap));
goto skip_qos_config;
}
}
qp->num_clks = devm_clk_bulk_get_all(qp->dev, &qp->clks);
if (qp->num_clks == -EPROBE_DEFER)
return dev_err_probe(dev, qp->num_clks, "Failed to get QoS clocks\n");
if (qp->num_clks < 0 || (!qp->num_clks && desc->qos_requires_clocks)) {
dev_info(dev, "Skipping QoS, failed to get clk: %d\n", qp->num_clks);
goto skip_qos_config;
}
ret = qcom_icc_rpmh_configure_qos(qp);
if (ret)
dev_info(dev, "Failed to program QoS: %d\n", ret);
}
skip_qos_config:
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);
return ret;
}
EXPORT_SYMBOL_GPL(qcom_icc_rpmh_probe);
void qcom_icc_rpmh_remove(struct platform_device *pdev)
{
struct qcom_icc_provider *qp = platform_get_drvdata(pdev);
icc_provider_deregister(&qp->provider);
icc_nodes_remove(&qp->provider);
}
EXPORT_SYMBOL_GPL(qcom_icc_rpmh_remove);
MODULE_DESCRIPTION("Qualcomm RPMh interconnect driver");
MODULE_LICENSE("GPL v2");
@@ -0,0 +1,167 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
* Copyright (c) 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>
#define to_qcom_provider(_provider) \
container_of(_provider, struct qcom_icc_provider, provider)
/**
* struct qcom_icc_provider - Qualcomm specific interconnect provider
* @provider: generic interconnect provider
* @dev: reference to the NoC device
* @bcms: list of bcms that maps to the provider
* @num_bcms: number of @bcms
* @voter: bcm voter targeted by this provider
* @nodes: list of icc nodes that maps to the provider
* @num_nodes: number of @nodes
* @regmap: used for QoS, register access
* @clks : clks required for register access
* @num_clks: number of @clks
*/
struct qcom_icc_provider {
struct icc_provider 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 regmap *regmap;
struct clk_bulk_data *clks;
int num_clks;
};
/**
* struct bcm_db - Auxiliary data pertaining to each Bus Clock Manager (BCM)
* @unit: divisor used to convert bytes/sec bw value to an RPMh msg
* @width: multiplier used to convert bytes/sec bw value to an RPMh msg
* @vcd: virtual clock domain that this bcm belongs to
* @reserved: reserved field
*/
struct bcm_db {
__le32 unit;
__le16 width;
u8 vcd;
u8 reserved;
};
#define MAX_PORTS 4
/**
* struct qcom_icc_qosbox - Qualcomm specific QoS config
* @prio: priority value assigned to requests on the node
* @urg_fwd: whether to forward the urgency promotion issued by master
* (endpoint), or discard
* @prio_fwd_disable: whether to forward the priority driven by master, or
* override by @prio
* @num_ports: number of @ports
* @port_offsets: qos register offsets
*/
struct qcom_icc_qosbox {
const u32 prio;
const bool urg_fwd;
const bool prio_fwd_disable;
const u32 num_ports;
const u32 port_offsets[MAX_PORTS];
};
#define MAX_LINKS 128
#define MAX_BCMS 64
#define MAX_BCM_PER_NODE 3
#define MAX_VCD 10
/**
* struct qcom_icc_node - Qualcomm specific interconnect nodes
* @name: the node name used in debugfs
* @link_nodes: links associated with this node
* @node: icc_node associated with this node
* @num_links: the total number of @links
* @channels: num of channels at this node
* @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
* @bcms: list of bcms associated with this logical node
* @num_bcms: num of @bcms
* @qosbox: QoS config data associated with node
*/
struct qcom_icc_node {
const char *name;
struct icc_node *node;
u16 num_links;
u16 channels;
u16 buswidth;
u64 sum_avg[QCOM_ICC_NUM_BUCKETS];
u64 max_peak[QCOM_ICC_NUM_BUCKETS];
struct qcom_icc_bcm *bcms[MAX_BCM_PER_NODE];
size_t num_bcms;
const struct qcom_icc_qosbox *qosbox;
struct qcom_icc_node *link_nodes[];
};
/**
* 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
* @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
* @dirty: flag used to indicate whether the bcm needs to be committed
* @keepalive: flag used to indicate whether a keepalive is required
* @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
* @ws_list: used to keep track of bcms that may transition between wake/sleep
* @num_nodes: total number of @num_nodes
* @nodes: list of qcom_icc_nodes that this BCM encapsulates
*/
struct qcom_icc_bcm {
const char *name;
u32 type;
u32 addr;
u64 vote_x[QCOM_ICC_NUM_BUCKETS];
u64 vote_y[QCOM_ICC_NUM_BUCKETS];
u64 vote_scale;
u32 enable_mask;
bool dirty;
bool keepalive;
struct bcm_db aux_data;
struct list_head list;
struct list_head ws_list;
size_t num_nodes;
struct qcom_icc_node *nodes[];
};
struct qcom_icc_fabric {
struct qcom_icc_node **nodes;
size_t num_nodes;
};
struct qcom_icc_desc {
const struct regmap_config *config;
struct qcom_icc_node * const *nodes;
size_t num_nodes;
struct qcom_icc_bcm * const *bcms;
size_t num_bcms;
bool qos_requires_clocks;
};
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_set(struct icc_node *src, struct icc_node *dst);
int qcom_icc_bcm_init(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);
void qcom_icc_rpmh_remove(struct platform_device *pdev);
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,149 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Qualcomm MSM8996 interconnect IDs
*
* Copyright (c) 2021 Yassine Oudjana <y.oudjana@protonmail.com>
*/
#ifndef __DRIVERS_INTERCONNECT_QCOM_MSM8996_H__
#define __DRIVERS_INTERCONNECT_QCOM_MSM8996_H__
#define MSM8996_MASTER_PCIE_0 1
#define MSM8996_MASTER_PCIE_1 2
#define MSM8996_MASTER_PCIE_2 3
#define MSM8996_MASTER_CNOC_A1NOC 4
#define MSM8996_MASTER_CRYPTO_CORE0 5
#define MSM8996_MASTER_PNOC_A1NOC 6
#define MSM8996_MASTER_USB3 7
#define MSM8996_MASTER_IPA 8
#define MSM8996_MASTER_UFS 9
#define MSM8996_MASTER_AMPSS_M0 10
#define MSM8996_MASTER_GRAPHICS_3D 11
#define MSM8996_MASTER_MNOC_BIMC 12
#define MSM8996_MASTER_SNOC_BIMC 13
#define MSM8996_MASTER_SNOC_CNOC 14
#define MSM8996_MASTER_QDSS_DAP 15
#define MSM8996_MASTER_CNOC_MNOC_MMSS_CFG 16
#define MSM8996_MASTER_CNOC_MNOC_CFG 17
#define MSM8996_MASTER_CPP 18
#define MSM8996_MASTER_JPEG 19
#define MSM8996_MASTER_MDP_PORT0 20
#define MSM8996_MASTER_MDP_PORT1 21
#define MSM8996_MASTER_ROTATOR 22
#define MSM8996_MASTER_VIDEO_P0 23
#define MSM8996_MASTER_VFE 24
#define MSM8996_MASTER_SNOC_VMEM 25
#define MSM8996_MASTER_VIDEO_P0_OCMEM 26
#define MSM8996_MASTER_SNOC_PNOC 27
#define MSM8996_MASTER_SDCC_1 28
#define MSM8996_MASTER_SDCC_2 29
#define MSM8996_MASTER_SDCC_4 30
#define MSM8996_MASTER_USB_HS 31
#define MSM8996_MASTER_BLSP_1 32
#define MSM8996_MASTER_BLSP_2 33
#define MSM8996_MASTER_TSIF 34
#define MSM8996_MASTER_HMSS 35
#define MSM8996_MASTER_QDSS_BAM 36
#define MSM8996_MASTER_SNOC_CFG 37
#define MSM8996_MASTER_BIMC_SNOC_0 38
#define MSM8996_MASTER_BIMC_SNOC_1 39
#define MSM8996_MASTER_A0NOC_SNOC 40
#define MSM8996_MASTER_A1NOC_SNOC 41
#define MSM8996_MASTER_A2NOC_SNOC 42
#define MSM8996_MASTER_QDSS_ETR 43
#define MSM8996_SLAVE_A0NOC_SNOC 44
#define MSM8996_SLAVE_A1NOC_SNOC 45
#define MSM8996_SLAVE_A2NOC_SNOC 46
#define MSM8996_SLAVE_EBI_CH0 47
#define MSM8996_SLAVE_HMSS_L3 48
#define MSM8996_SLAVE_BIMC_SNOC_0 49
#define MSM8996_SLAVE_BIMC_SNOC_1 50
#define MSM8996_SLAVE_CNOC_A1NOC 51
#define MSM8996_SLAVE_CLK_CTL 52
#define MSM8996_SLAVE_TCSR 53
#define MSM8996_SLAVE_TLMM 54
#define MSM8996_SLAVE_CRYPTO_0_CFG 55
#define MSM8996_SLAVE_MPM 56
#define MSM8996_SLAVE_PIMEM_CFG 57
#define MSM8996_SLAVE_IMEM_CFG 58
#define MSM8996_SLAVE_MESSAGE_RAM 59
#define MSM8996_SLAVE_BIMC_CFG 60
#define MSM8996_SLAVE_PMIC_ARB 61
#define MSM8996_SLAVE_PRNG 62
#define MSM8996_SLAVE_DCC_CFG 63
#define MSM8996_SLAVE_RBCPR_MX 64
#define MSM8996_SLAVE_QDSS_CFG 65
#define MSM8996_SLAVE_RBCPR_CX 66
#define MSM8996_SLAVE_QDSS_RBCPR_APU_CFG 67
#define MSM8996_SLAVE_CNOC_MNOC_CFG 68
#define MSM8996_SLAVE_SNOC_CFG 69
#define MSM8996_SLAVE_SNOC_MPU_CFG 70
#define MSM8996_SLAVE_EBI1_PHY_CFG 71
#define MSM8996_SLAVE_A0NOC_CFG 72
#define MSM8996_SLAVE_PCIE_1_CFG 73
#define MSM8996_SLAVE_PCIE_2_CFG 74
#define MSM8996_SLAVE_PCIE_0_CFG 75
#define MSM8996_SLAVE_PCIE20_AHB2PHY 76
#define MSM8996_SLAVE_A0NOC_MPU_CFG 77
#define MSM8996_SLAVE_UFS_CFG 78
#define MSM8996_SLAVE_A1NOC_CFG 79
#define MSM8996_SLAVE_A1NOC_MPU_CFG 80
#define MSM8996_SLAVE_A2NOC_CFG 81
#define MSM8996_SLAVE_A2NOC_MPU_CFG 82
#define MSM8996_SLAVE_SSC_CFG 83
#define MSM8996_SLAVE_A0NOC_SMMU_CFG 84
#define MSM8996_SLAVE_A1NOC_SMMU_CFG 85
#define MSM8996_SLAVE_A2NOC_SMMU_CFG 86
#define MSM8996_SLAVE_LPASS_SMMU_CFG 87
#define MSM8996_SLAVE_CNOC_MNOC_MMSS_CFG 88
#define MSM8996_SLAVE_MMAGIC_CFG 89
#define MSM8996_SLAVE_CPR_CFG 90
#define MSM8996_SLAVE_MISC_CFG 91
#define MSM8996_SLAVE_VENUS_THROTTLE_CFG 92
#define MSM8996_SLAVE_VENUS_CFG 93
#define MSM8996_SLAVE_VMEM_CFG 94
#define MSM8996_SLAVE_DSA_CFG 95
#define MSM8996_SLAVE_MMSS_CLK_CFG 96
#define MSM8996_SLAVE_DSA_MPU_CFG 97
#define MSM8996_SLAVE_MNOC_MPU_CFG 98
#define MSM8996_SLAVE_DISPLAY_CFG 99
#define MSM8996_SLAVE_DISPLAY_THROTTLE_CFG 100
#define MSM8996_SLAVE_CAMERA_CFG 101
#define MSM8996_SLAVE_CAMERA_THROTTLE_CFG 102
#define MSM8996_SLAVE_GRAPHICS_3D_CFG 103
#define MSM8996_SLAVE_SMMU_MDP_CFG 104
#define MSM8996_SLAVE_SMMU_ROTATOR_CFG 105
#define MSM8996_SLAVE_SMMU_VENUS_CFG 106
#define MSM8996_SLAVE_SMMU_CPP_CFG 107
#define MSM8996_SLAVE_SMMU_JPEG_CFG 108
#define MSM8996_SLAVE_SMMU_VFE_CFG 109
#define MSM8996_SLAVE_MNOC_BIMC 110
#define MSM8996_SLAVE_VMEM 111
#define MSM8996_SLAVE_SERVICE_MNOC 112
#define MSM8996_SLAVE_PNOC_A1NOC 113
#define MSM8996_SLAVE_USB_HS 114
#define MSM8996_SLAVE_SDCC_2 115
#define MSM8996_SLAVE_SDCC_4 116
#define MSM8996_SLAVE_TSIF 117
#define MSM8996_SLAVE_BLSP_2 118
#define MSM8996_SLAVE_SDCC_1 119
#define MSM8996_SLAVE_BLSP_1 120
#define MSM8996_SLAVE_PDM 121
#define MSM8996_SLAVE_AHB2PHY 122
#define MSM8996_SLAVE_APPSS 123
#define MSM8996_SLAVE_LPASS 124
#define MSM8996_SLAVE_USB3 125
#define MSM8996_SLAVE_SNOC_BIMC 126
#define MSM8996_SLAVE_SNOC_CNOC 127
#define MSM8996_SLAVE_OCIMEM 128
#define MSM8996_SLAVE_PIMEM 129
#define MSM8996_SLAVE_SNOC_VMEM 130
#define MSM8996_SLAVE_SNOC_PNOC 131
#define MSM8996_SLAVE_QDSS_STM 132
#define MSM8996_SLAVE_PCIE_0 133
#define MSM8996_SLAVE_PCIE_1 134
#define MSM8996_SLAVE_PCIE_2 135
#define MSM8996_SLAVE_SERVICE_SNOC 136
#endif /* __DRIVERS_INTERCONNECT_QCOM_MSM8996_H__ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,294 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2025 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/args.h>
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/interconnect-provider.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <dt-bindings/interconnect/qcom,osm-l3.h>
#define LUT_MAX_ENTRIES 40U
#define LUT_SRC GENMASK(31, 30)
#define LUT_L_VAL GENMASK(7, 0)
#define CLK_HW_DIV 2
/* OSM Register offsets */
#define REG_ENABLE 0x0
#define OSM_LUT_ROW_SIZE 32
#define OSM_REG_FREQ_LUT 0x110
#define OSM_REG_PERF_STATE 0x920
/* EPSS Register offsets */
#define EPSS_LUT_ROW_SIZE 4
#define EPSS_REG_L3_VOTE 0x90
#define EPSS_REG_FREQ_LUT 0x100
#define EPSS_REG_PERF_STATE 0x320
#define to_osm_l3_provider(_provider) \
container_of(_provider, struct qcom_osm_l3_icc_provider, provider)
struct qcom_osm_l3_icc_provider {
void __iomem *base;
unsigned int max_state;
unsigned int reg_perf_state;
unsigned long lut_tables[LUT_MAX_ENTRIES];
struct icc_provider provider;
};
/**
* struct qcom_osm_l3_node - Qualcomm specific interconnect nodes
* @name: the node name used in debugfs
* @buswidth: width of the interconnect between a node and the bus
*/
struct qcom_osm_l3_node {
const char *name;
u16 buswidth;
};
struct qcom_osm_l3_desc {
const struct qcom_osm_l3_node * const *nodes;
size_t num_nodes;
unsigned int lut_row_size;
unsigned int reg_freq_lut;
unsigned int reg_perf_state;
};
#define DEFINE_QNODE(_name, _buswidth) \
static const struct qcom_osm_l3_node _name = { \
.name = #_name, \
.buswidth = _buswidth, \
}
DEFINE_QNODE(osm_l3_slave, 16);
DEFINE_QNODE(osm_l3_master, 16);
static const struct qcom_osm_l3_node * const osm_l3_nodes[] = {
[MASTER_OSM_L3_APPS] = &osm_l3_master,
[SLAVE_OSM_L3] = &osm_l3_slave,
};
DEFINE_QNODE(epss_l3_slave, 32);
DEFINE_QNODE(epss_l3_master, 32);
static const struct qcom_osm_l3_node * const epss_l3_nodes[] = {
[MASTER_EPSS_L3_APPS] = &epss_l3_master,
[SLAVE_EPSS_L3_SHARED] = &epss_l3_slave,
};
static const struct qcom_osm_l3_desc osm_l3 = {
.nodes = osm_l3_nodes,
.num_nodes = ARRAY_SIZE(osm_l3_nodes),
.lut_row_size = OSM_LUT_ROW_SIZE,
.reg_freq_lut = OSM_REG_FREQ_LUT,
.reg_perf_state = OSM_REG_PERF_STATE,
};
static const struct qcom_osm_l3_desc epss_l3_perf_state = {
.nodes = epss_l3_nodes,
.num_nodes = ARRAY_SIZE(epss_l3_nodes),
.lut_row_size = EPSS_LUT_ROW_SIZE,
.reg_freq_lut = EPSS_REG_FREQ_LUT,
.reg_perf_state = EPSS_REG_PERF_STATE,
};
static const struct qcom_osm_l3_desc epss_l3_l3_vote = {
.nodes = epss_l3_nodes,
.num_nodes = ARRAY_SIZE(epss_l3_nodes),
.lut_row_size = EPSS_LUT_ROW_SIZE,
.reg_freq_lut = EPSS_REG_FREQ_LUT,
.reg_perf_state = EPSS_REG_L3_VOTE,
};
static int qcom_osm_l3_set(struct icc_node *src, struct icc_node *dst)
{
struct qcom_osm_l3_icc_provider *qp;
struct icc_provider *provider;
const struct qcom_osm_l3_node *qn;
unsigned int index;
u64 rate;
qn = src->data;
provider = src->provider;
qp = to_osm_l3_provider(provider);
rate = icc_units_to_bps(dst->peak_bw);
do_div(rate, qn->buswidth);
for (index = 0; index < qp->max_state - 1; index++) {
if (qp->lut_tables[index] >= rate)
break;
}
writel_relaxed(index, qp->base + qp->reg_perf_state);
return 0;
}
static void qcom_osm_l3_remove(struct platform_device *pdev)
{
struct qcom_osm_l3_icc_provider *qp = platform_get_drvdata(pdev);
icc_provider_deregister(&qp->provider);
icc_nodes_remove(&qp->provider);
}
static int qcom_osm_l3_probe(struct platform_device *pdev)
{
u32 info, src, lval, i, prev_freq = 0, freq;
static unsigned long hw_rate, xo_rate;
struct qcom_osm_l3_icc_provider *qp;
const struct qcom_osm_l3_desc *desc;
struct icc_onecell_data *data;
struct icc_provider *provider;
const struct qcom_osm_l3_node * const *qnodes;
struct icc_node *node;
size_t num_nodes;
struct clk *clk;
int ret;
clk = clk_get(&pdev->dev, "xo");
if (IS_ERR(clk))
return PTR_ERR(clk);
xo_rate = clk_get_rate(clk);
clk_put(clk);
clk = clk_get(&pdev->dev, "alternate");
if (IS_ERR(clk))
return PTR_ERR(clk);
hw_rate = clk_get_rate(clk) / CLK_HW_DIV;
clk_put(clk);
qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
if (!qp)
return -ENOMEM;
qp->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(qp->base))
return PTR_ERR(qp->base);
/* HW should be in enabled state to proceed */
if (!(readl_relaxed(qp->base + REG_ENABLE) & 0x1)) {
dev_err(&pdev->dev, "error hardware not enabled\n");
return -ENODEV;
}
desc = device_get_match_data(&pdev->dev);
if (!desc)
return -EINVAL;
qp->reg_perf_state = desc->reg_perf_state;
for (i = 0; i < LUT_MAX_ENTRIES; i++) {
info = readl_relaxed(qp->base + desc->reg_freq_lut +
i * desc->lut_row_size);
src = FIELD_GET(LUT_SRC, info);
lval = FIELD_GET(LUT_L_VAL, info);
if (src)
freq = xo_rate * lval;
else
freq = hw_rate;
/* Two of the same frequencies signify end of table */
if (i > 0 && prev_freq == freq)
break;
dev_dbg(&pdev->dev, "index=%d freq=%d\n", i, freq);
qp->lut_tables[i] = freq;
prev_freq = freq;
}
qp->max_state = i;
qnodes = desc->nodes;
num_nodes = desc->num_nodes;
data = devm_kzalloc(&pdev->dev, struct_size(data, nodes, num_nodes), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->num_nodes = num_nodes;
provider = &qp->provider;
provider->dev = &pdev->dev;
provider->set = qcom_osm_l3_set;
provider->aggregate = icc_std_aggregate;
provider->xlate = of_icc_xlate_onecell;
provider->data = data;
icc_provider_init(provider);
/* Create nodes */
for (i = 0; i < num_nodes; i++) {
node = icc_node_create_dyn();
if (IS_ERR(node)) {
ret = PTR_ERR(node);
goto err;
}
ret = icc_node_set_name(node, provider, qnodes[i]->name);
if (ret) {
icc_node_destroy(node->id);
goto err;
}
/* Cast away const and add it back in qcom_osm_l3_set() */
node->data = (void *)qnodes[i];
icc_node_add(node, provider);
data->nodes[i] = node;
}
/* Create link */
icc_link_nodes(data->nodes[MASTER_OSM_L3_APPS], &data->nodes[SLAVE_OSM_L3]);
ret = icc_provider_register(provider);
if (ret)
goto err;
platform_set_drvdata(pdev, qp);
return 0;
err:
icc_nodes_remove(provider);
return ret;
}
static const struct of_device_id osm_l3_of_match[] = {
{ .compatible = "qcom,epss-l3", .data = &epss_l3_l3_vote },
{ .compatible = "qcom,osm-l3", .data = &osm_l3 },
{ .compatible = "qcom,sa8775p-epss-l3", .data = &epss_l3_perf_state },
{ .compatible = "qcom,sc7180-osm-l3", .data = &osm_l3 },
{ .compatible = "qcom,sc7280-epss-l3", .data = &epss_l3_perf_state },
{ .compatible = "qcom,sdm845-osm-l3", .data = &osm_l3 },
{ .compatible = "qcom,sm8150-osm-l3", .data = &osm_l3 },
{ .compatible = "qcom,sc8180x-osm-l3", .data = &osm_l3 },
{ .compatible = "qcom,sm8250-epss-l3", .data = &epss_l3_perf_state },
{ }
};
MODULE_DEVICE_TABLE(of, osm_l3_of_match);
static struct platform_driver osm_l3_driver = {
.probe = qcom_osm_l3_probe,
.remove = qcom_osm_l3_remove,
.driver = {
.name = "osm-l3",
.of_match_table = osm_l3_of_match,
.sync_state = icc_sync_state,
},
};
module_platform_driver(osm_l3_driver);
MODULE_DESCRIPTION("Qualcomm OSM L3 interconnect 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
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,915 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Qualcomm SDX55 interconnect driver
* Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
*
* Copyright (c) 2021, Linaro Ltd.
*
*/
#include <linux/device.h>
#include <linux/interconnect.h>
#include <linux/interconnect-provider.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <dt-bindings/interconnect/qcom,sdx55.h>
#include "bcm-voter.h"
#include "icc-rpmh.h"
static struct qcom_icc_node llcc_mc;
static struct qcom_icc_node acm_tcu;
static struct qcom_icc_node qnm_snoc_gc;
static struct qcom_icc_node xm_apps_rdwr;
static struct qcom_icc_node qhm_audio;
static struct qcom_icc_node qhm_blsp1;
static struct qcom_icc_node qhm_qdss_bam;
static struct qcom_icc_node qhm_qpic;
static struct qcom_icc_node qhm_snoc_cfg;
static struct qcom_icc_node qhm_spmi_fetcher1;
static struct qcom_icc_node qnm_aggre_noc;
static struct qcom_icc_node qnm_ipa;
static struct qcom_icc_node qnm_memnoc;
static struct qcom_icc_node qnm_memnoc_pcie;
static struct qcom_icc_node qxm_crypto;
static struct qcom_icc_node xm_emac;
static struct qcom_icc_node xm_ipa2pcie_slv;
static struct qcom_icc_node xm_pcie;
static struct qcom_icc_node xm_qdss_etr;
static struct qcom_icc_node xm_sdc1;
static struct qcom_icc_node xm_usb3;
static struct qcom_icc_node ebi;
static struct qcom_icc_node qns_llcc;
static struct qcom_icc_node qns_memnoc_snoc;
static struct qcom_icc_node qns_sys_pcie;
static struct qcom_icc_node qhs_aop;
static struct qcom_icc_node qhs_aoss;
static struct qcom_icc_node qhs_apss;
static struct qcom_icc_node qhs_audio;
static struct qcom_icc_node qhs_blsp1;
static struct qcom_icc_node qhs_clk_ctl;
static struct qcom_icc_node qhs_crypto0_cfg;
static struct qcom_icc_node qhs_ddrss_cfg;
static struct qcom_icc_node qhs_ecc_cfg;
static struct qcom_icc_node qhs_emac_cfg;
static struct qcom_icc_node qhs_imem_cfg;
static struct qcom_icc_node qhs_ipa;
static struct qcom_icc_node qhs_mss_cfg;
static struct qcom_icc_node qhs_pcie_parf;
static struct qcom_icc_node qhs_pdm;
static struct qcom_icc_node qhs_prng;
static struct qcom_icc_node qhs_qdss_cfg;
static struct qcom_icc_node qhs_qpic;
static struct qcom_icc_node qhs_sdc1;
static struct qcom_icc_node qhs_snoc_cfg;
static struct qcom_icc_node qhs_spmi_fetcher;
static struct qcom_icc_node qhs_spmi_vgi_coex;
static struct qcom_icc_node qhs_tcsr;
static struct qcom_icc_node qhs_tlmm;
static struct qcom_icc_node qhs_usb3;
static struct qcom_icc_node qhs_usb3_phy;
static struct qcom_icc_node qns_aggre_noc;
static struct qcom_icc_node qns_snoc_memnoc;
static struct qcom_icc_node qxs_imem;
static struct qcom_icc_node srvc_snoc;
static struct qcom_icc_node xs_pcie;
static struct qcom_icc_node xs_qdss_stm;
static struct qcom_icc_node xs_sys_tcu_cfg;
static struct qcom_icc_node llcc_mc = {
.name = "llcc_mc",
.channels = 4,
.buswidth = 4,
.num_links = 1,
.link_nodes = { &ebi },
};
static struct qcom_icc_node acm_tcu = {
.name = "acm_tcu",
.channels = 1,
.buswidth = 8,
.num_links = 3,
.link_nodes = { &qns_llcc,
&qns_memnoc_snoc,
&qns_sys_pcie },
};
static struct qcom_icc_node qnm_snoc_gc = {
.name = "qnm_snoc_gc",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &qns_llcc },
};
static struct qcom_icc_node xm_apps_rdwr = {
.name = "xm_apps_rdwr",
.channels = 1,
.buswidth = 16,
.num_links = 3,
.link_nodes = { &qns_llcc,
&qns_memnoc_snoc,
&qns_sys_pcie },
};
static struct qcom_icc_node qhm_audio = {
.name = "qhm_audio",
.channels = 1,
.buswidth = 4,
.num_links = 1,
.link_nodes = { &qns_aggre_noc },
};
static struct qcom_icc_node qhm_blsp1 = {
.name = "qhm_blsp1",
.channels = 1,
.buswidth = 4,
.num_links = 1,
.link_nodes = { &qns_aggre_noc },
};
static struct qcom_icc_node qhm_qdss_bam = {
.name = "qhm_qdss_bam",
.channels = 1,
.buswidth = 4,
.num_links = 28,
.link_nodes = { &qhs_snoc_cfg,
&qhs_emac_cfg,
&qhs_usb3,
&qhs_tlmm,
&qhs_spmi_fetcher,
&qhs_qdss_cfg,
&qhs_pdm,
&qns_snoc_memnoc,
&qhs_tcsr,
&qhs_ddrss_cfg,
&qhs_spmi_vgi_coex,
&qhs_qpic,
&qxs_imem,
&qhs_ipa,
&qhs_usb3_phy,
&qhs_aop,
&qhs_blsp1,
&qhs_sdc1,
&qhs_mss_cfg,
&qhs_pcie_parf,
&qhs_ecc_cfg,
&qhs_audio,
&qhs_aoss,
&qhs_prng,
&qhs_crypto0_cfg,
&xs_sys_tcu_cfg,
&qhs_clk_ctl,
&qhs_imem_cfg },
};
static struct qcom_icc_node qhm_qpic = {
.name = "qhm_qpic",
.channels = 1,
.buswidth = 4,
.num_links = 5,
.link_nodes = { &qhs_aoss,
&qhs_ipa,
&qns_aggre_noc,
&qhs_aop,
&qhs_audio },
};
static struct qcom_icc_node qhm_snoc_cfg = {
.name = "qhm_snoc_cfg",
.channels = 1,
.buswidth = 4,
.num_links = 1,
.link_nodes = { &srvc_snoc },
};
static struct qcom_icc_node qhm_spmi_fetcher1 = {
.name = "qhm_spmi_fetcher1",
.channels = 1,
.buswidth = 4,
.num_links = 3,
.link_nodes = { &qhs_aoss,
&qns_aggre_noc,
&qhs_aop },
};
static struct qcom_icc_node qnm_aggre_noc = {
.name = "qnm_aggre_noc",
.channels = 1,
.buswidth = 8,
.num_links = 30,
.link_nodes = { &xs_pcie,
&qhs_snoc_cfg,
&qhs_sdc1,
&qhs_tlmm,
&qhs_spmi_fetcher,
&qhs_qdss_cfg,
&qhs_pdm,
&qns_snoc_memnoc,
&qhs_tcsr,
&qhs_ddrss_cfg,
&qhs_spmi_vgi_coex,
&xs_qdss_stm,
&qhs_qpic,
&qxs_imem,
&qhs_ipa,
&qhs_usb3_phy,
&qhs_aop,
&qhs_blsp1,
&qhs_usb3,
&qhs_mss_cfg,
&qhs_pcie_parf,
&qhs_ecc_cfg,
&qhs_apss,
&qhs_audio,
&qhs_aoss,
&qhs_prng,
&qhs_crypto0_cfg,
&xs_sys_tcu_cfg,
&qhs_clk_ctl,
&qhs_imem_cfg },
};
static struct qcom_icc_node qnm_ipa = {
.name = "qnm_ipa",
.channels = 1,
.buswidth = 8,
.num_links = 27,
.link_nodes = { &qhs_snoc_cfg,
&qhs_emac_cfg,
&qhs_usb3,
&qhs_aoss,
&qhs_spmi_fetcher,
&qhs_qdss_cfg,
&qhs_pdm,
&qns_snoc_memnoc,
&qhs_tcsr,
&qhs_ddrss_cfg,
&xs_qdss_stm,
&qhs_qpic,
&qxs_imem,
&qhs_ipa,
&qhs_usb3_phy,
&qhs_aop,
&qhs_blsp1,
&qhs_sdc1,
&qhs_mss_cfg,
&qhs_pcie_parf,
&qhs_ecc_cfg,
&qhs_audio,
&qhs_tlmm,
&qhs_prng,
&qhs_crypto0_cfg,
&qhs_clk_ctl,
&qhs_imem_cfg },
};
static struct qcom_icc_node qnm_memnoc = {
.name = "qnm_memnoc",
.channels = 1,
.buswidth = 8,
.num_links = 29,
.link_nodes = { &qhs_snoc_cfg,
&qhs_emac_cfg,
&qhs_usb3,
&qhs_tlmm,
&qhs_spmi_fetcher,
&qhs_qdss_cfg,
&qhs_pdm,
&qhs_tcsr,
&qhs_ddrss_cfg,
&qhs_spmi_vgi_coex,
&xs_qdss_stm,
&qhs_qpic,
&qxs_imem,
&qhs_ipa,
&qhs_usb3_phy,
&qhs_aop,
&qhs_blsp1,
&qhs_sdc1,
&qhs_mss_cfg,
&qhs_pcie_parf,
&qhs_ecc_cfg,
&qhs_apss,
&qhs_audio,
&qhs_aoss,
&qhs_prng,
&qhs_crypto0_cfg,
&xs_sys_tcu_cfg,
&qhs_clk_ctl,
&qhs_imem_cfg },
};
static struct qcom_icc_node qnm_memnoc_pcie = {
.name = "qnm_memnoc_pcie",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &xs_pcie },
};
static struct qcom_icc_node qxm_crypto = {
.name = "qxm_crypto",
.channels = 1,
.buswidth = 8,
.num_links = 3,
.link_nodes = { &qhs_aoss,
&qns_aggre_noc,
&qhs_aop },
};
static struct qcom_icc_node xm_emac = {
.name = "xm_emac",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &qns_aggre_noc },
};
static struct qcom_icc_node xm_ipa2pcie_slv = {
.name = "xm_ipa2pcie_slv",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &xs_pcie },
};
static struct qcom_icc_node xm_pcie = {
.name = "xm_pcie",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &qns_aggre_noc },
};
static struct qcom_icc_node xm_qdss_etr = {
.name = "xm_qdss_etr",
.channels = 1,
.buswidth = 8,
.num_links = 28,
.link_nodes = { &qhs_snoc_cfg,
&qhs_emac_cfg,
&qhs_usb3,
&qhs_aoss,
&qhs_spmi_fetcher,
&qhs_qdss_cfg,
&qhs_pdm,
&qns_snoc_memnoc,
&qhs_tcsr,
&qhs_ddrss_cfg,
&qhs_spmi_vgi_coex,
&qhs_qpic,
&qxs_imem,
&qhs_ipa,
&qhs_usb3_phy,
&qhs_aop,
&qhs_blsp1,
&qhs_sdc1,
&qhs_mss_cfg,
&qhs_pcie_parf,
&qhs_ecc_cfg,
&qhs_audio,
&qhs_aoss,
&qhs_prng,
&qhs_crypto0_cfg,
&xs_sys_tcu_cfg,
&qhs_clk_ctl,
&qhs_imem_cfg },
};
static struct qcom_icc_node xm_sdc1 = {
.name = "xm_sdc1",
.channels = 1,
.buswidth = 8,
.num_links = 5,
.link_nodes = { &qhs_aoss,
&qhs_ipa,
&qns_aggre_noc,
&qhs_aop,
&qhs_audio },
};
static struct qcom_icc_node xm_usb3 = {
.name = "xm_usb3",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &qns_aggre_noc },
};
static struct qcom_icc_node ebi = {
.name = "ebi",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qns_llcc = {
.name = "qns_llcc",
.channels = 1,
.buswidth = 16,
.num_links = 1,
.link_nodes = { &ebi },
};
static struct qcom_icc_node qns_memnoc_snoc = {
.name = "qns_memnoc_snoc",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &qnm_memnoc },
};
static struct qcom_icc_node qns_sys_pcie = {
.name = "qns_sys_pcie",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &qnm_memnoc_pcie },
};
static struct qcom_icc_node qhs_aop = {
.name = "qhs_aop",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_aoss = {
.name = "qhs_aoss",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_apss = {
.name = "qhs_apss",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_audio = {
.name = "qhs_audio",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_blsp1 = {
.name = "qhs_blsp1",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_clk_ctl = {
.name = "qhs_clk_ctl",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_crypto0_cfg = {
.name = "qhs_crypto0_cfg",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_ddrss_cfg = {
.name = "qhs_ddrss_cfg",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_ecc_cfg = {
.name = "qhs_ecc_cfg",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_emac_cfg = {
.name = "qhs_emac_cfg",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_imem_cfg = {
.name = "qhs_imem_cfg",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_ipa = {
.name = "qhs_ipa",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_mss_cfg = {
.name = "qhs_mss_cfg",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_pcie_parf = {
.name = "qhs_pcie_parf",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_pdm = {
.name = "qhs_pdm",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_prng = {
.name = "qhs_prng",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_qdss_cfg = {
.name = "qhs_qdss_cfg",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_qpic = {
.name = "qhs_qpic",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_sdc1 = {
.name = "qhs_sdc1",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_snoc_cfg = {
.name = "qhs_snoc_cfg",
.channels = 1,
.buswidth = 4,
.num_links = 1,
.link_nodes = { &qhm_snoc_cfg },
};
static struct qcom_icc_node qhs_spmi_fetcher = {
.name = "qhs_spmi_fetcher",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_spmi_vgi_coex = {
.name = "qhs_spmi_vgi_coex",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_tcsr = {
.name = "qhs_tcsr",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_tlmm = {
.name = "qhs_tlmm",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_usb3 = {
.name = "qhs_usb3",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_usb3_phy = {
.name = "qhs_usb3_phy",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qns_aggre_noc = {
.name = "qns_aggre_noc",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &qnm_aggre_noc },
};
static struct qcom_icc_node qns_snoc_memnoc = {
.name = "qns_snoc_memnoc",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &qnm_snoc_gc },
};
static struct qcom_icc_node qxs_imem = {
.name = "qxs_imem",
.channels = 1,
.buswidth = 8,
};
static struct qcom_icc_node srvc_snoc = {
.name = "srvc_snoc",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node xs_pcie = {
.name = "xs_pcie",
.channels = 1,
.buswidth = 8,
};
static struct qcom_icc_node xs_qdss_stm = {
.name = "xs_qdss_stm",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node xs_sys_tcu_cfg = {
.name = "xs_sys_tcu_cfg",
.channels = 1,
.buswidth = 8,
};
static struct qcom_icc_bcm bcm_mc0 = {
.name = "MC0",
.keepalive = true,
.num_nodes = 1,
.nodes = { &ebi },
};
static struct qcom_icc_bcm bcm_sh0 = {
.name = "SH0",
.keepalive = true,
.num_nodes = 1,
.nodes = { &qns_llcc },
};
static struct qcom_icc_bcm bcm_ce0 = {
.name = "CE0",
.keepalive = false,
.num_nodes = 1,
.nodes = { &qxm_crypto },
};
static struct qcom_icc_bcm bcm_pn0 = {
.name = "PN0",
.keepalive = false,
.num_nodes = 1,
.nodes = { &qhm_snoc_cfg },
};
static struct qcom_icc_bcm bcm_sh3 = {
.name = "SH3",
.keepalive = false,
.num_nodes = 1,
.nodes = { &xm_apps_rdwr },
};
static struct qcom_icc_bcm bcm_sh4 = {
.name = "SH4",
.keepalive = false,
.num_nodes = 2,
.nodes = { &qns_memnoc_snoc, &qns_sys_pcie },
};
static struct qcom_icc_bcm bcm_sn0 = {
.name = "SN0",
.keepalive = true,
.num_nodes = 1,
.nodes = { &qns_snoc_memnoc },
};
static struct qcom_icc_bcm bcm_sn1 = {
.name = "SN1",
.keepalive = false,
.num_nodes = 1,
.nodes = { &qxs_imem },
};
static struct qcom_icc_bcm bcm_pn1 = {
.name = "PN1",
.keepalive = false,
.num_nodes = 1,
.nodes = { &xm_sdc1 },
};
static struct qcom_icc_bcm bcm_pn2 = {
.name = "PN2",
.keepalive = false,
.num_nodes = 2,
.nodes = { &qhm_audio, &qhm_spmi_fetcher1 },
};
static struct qcom_icc_bcm bcm_sn3 = {
.name = "SN3",
.keepalive = false,
.num_nodes = 1,
.nodes = { &xs_qdss_stm },
};
static struct qcom_icc_bcm bcm_pn3 = {
.name = "PN3",
.keepalive = false,
.num_nodes = 2,
.nodes = { &qhm_blsp1, &qhm_qpic },
};
static struct qcom_icc_bcm bcm_sn4 = {
.name = "SN4",
.keepalive = false,
.num_nodes = 1,
.nodes = { &xs_sys_tcu_cfg },
};
static struct qcom_icc_bcm bcm_pn5 = {
.name = "PN5",
.keepalive = false,
.num_nodes = 1,
.nodes = { &qxm_crypto },
};
static struct qcom_icc_bcm bcm_sn6 = {
.name = "SN6",
.keepalive = false,
.num_nodes = 1,
.nodes = { &xs_pcie },
};
static struct qcom_icc_bcm bcm_sn7 = {
.name = "SN7",
.keepalive = false,
.num_nodes = 5,
.nodes = { &qnm_aggre_noc, &xm_emac, &xm_emac, &xm_usb3, &qns_aggre_noc },
};
static struct qcom_icc_bcm bcm_sn8 = {
.name = "SN8",
.keepalive = false,
.num_nodes = 2,
.nodes = { &qhm_qdss_bam, &xm_qdss_etr },
};
static struct qcom_icc_bcm bcm_sn9 = {
.name = "SN9",
.keepalive = false,
.num_nodes = 1,
.nodes = { &qnm_memnoc },
};
static struct qcom_icc_bcm bcm_sn10 = {
.name = "SN10",
.keepalive = false,
.num_nodes = 1,
.nodes = { &qnm_memnoc_pcie },
};
static struct qcom_icc_bcm bcm_sn11 = {
.name = "SN11",
.keepalive = false,
.num_nodes = 2,
.nodes = { &qnm_ipa, &xm_ipa2pcie_slv },
};
static struct qcom_icc_bcm * const mc_virt_bcms[] = {
&bcm_mc0,
};
static struct qcom_icc_node * const mc_virt_nodes[] = {
[MASTER_LLCC] = &llcc_mc,
[SLAVE_EBI_CH0] = &ebi,
};
static const struct qcom_icc_desc sdx55_mc_virt = {
.nodes = mc_virt_nodes,
.num_nodes = ARRAY_SIZE(mc_virt_nodes),
.bcms = mc_virt_bcms,
.num_bcms = ARRAY_SIZE(mc_virt_bcms),
};
static struct qcom_icc_bcm * const mem_noc_bcms[] = {
&bcm_sh0,
&bcm_sh3,
&bcm_sh4,
};
static struct qcom_icc_node * const mem_noc_nodes[] = {
[MASTER_TCU_0] = &acm_tcu,
[MASTER_SNOC_GC_MEM_NOC] = &qnm_snoc_gc,
[MASTER_AMPSS_M0] = &xm_apps_rdwr,
[SLAVE_LLCC] = &qns_llcc,
[SLAVE_MEM_NOC_SNOC] = &qns_memnoc_snoc,
[SLAVE_MEM_NOC_PCIE_SNOC] = &qns_sys_pcie,
};
static const struct qcom_icc_desc sdx55_mem_noc = {
.nodes = mem_noc_nodes,
.num_nodes = ARRAY_SIZE(mem_noc_nodes),
.bcms = mem_noc_bcms,
.num_bcms = ARRAY_SIZE(mem_noc_bcms),
};
static struct qcom_icc_bcm * const system_noc_bcms[] = {
&bcm_ce0,
&bcm_pn0,
&bcm_pn1,
&bcm_pn2,
&bcm_pn3,
&bcm_pn5,
&bcm_sn0,
&bcm_sn1,
&bcm_sn3,
&bcm_sn4,
&bcm_sn6,
&bcm_sn7,
&bcm_sn8,
&bcm_sn9,
&bcm_sn10,
&bcm_sn11,
};
static struct qcom_icc_node * const system_noc_nodes[] = {
[MASTER_AUDIO] = &qhm_audio,
[MASTER_BLSP_1] = &qhm_blsp1,
[MASTER_QDSS_BAM] = &qhm_qdss_bam,
[MASTER_QPIC] = &qhm_qpic,
[MASTER_SNOC_CFG] = &qhm_snoc_cfg,
[MASTER_SPMI_FETCHER] = &qhm_spmi_fetcher1,
[MASTER_ANOC_SNOC] = &qnm_aggre_noc,
[MASTER_IPA] = &qnm_ipa,
[MASTER_MEM_NOC_SNOC] = &qnm_memnoc,
[MASTER_MEM_NOC_PCIE_SNOC] = &qnm_memnoc_pcie,
[MASTER_CRYPTO_CORE_0] = &qxm_crypto,
[MASTER_EMAC] = &xm_emac,
[MASTER_IPA_PCIE] = &xm_ipa2pcie_slv,
[MASTER_PCIE] = &xm_pcie,
[MASTER_QDSS_ETR] = &xm_qdss_etr,
[MASTER_SDCC_1] = &xm_sdc1,
[MASTER_USB3] = &xm_usb3,
[SLAVE_AOP] = &qhs_aop,
[SLAVE_AOSS] = &qhs_aoss,
[SLAVE_APPSS] = &qhs_apss,
[SLAVE_AUDIO] = &qhs_audio,
[SLAVE_BLSP_1] = &qhs_blsp1,
[SLAVE_CLK_CTL] = &qhs_clk_ctl,
[SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg,
[SLAVE_CNOC_DDRSS] = &qhs_ddrss_cfg,
[SLAVE_ECC_CFG] = &qhs_ecc_cfg,
[SLAVE_EMAC_CFG] = &qhs_emac_cfg,
[SLAVE_IMEM_CFG] = &qhs_imem_cfg,
[SLAVE_IPA_CFG] = &qhs_ipa,
[SLAVE_CNOC_MSS] = &qhs_mss_cfg,
[SLAVE_PCIE_PARF] = &qhs_pcie_parf,
[SLAVE_PDM] = &qhs_pdm,
[SLAVE_PRNG] = &qhs_prng,
[SLAVE_QDSS_CFG] = &qhs_qdss_cfg,
[SLAVE_QPIC] = &qhs_qpic,
[SLAVE_SDCC_1] = &qhs_sdc1,
[SLAVE_SNOC_CFG] = &qhs_snoc_cfg,
[SLAVE_SPMI_FETCHER] = &qhs_spmi_fetcher,
[SLAVE_SPMI_VGI_COEX] = &qhs_spmi_vgi_coex,
[SLAVE_TCSR] = &qhs_tcsr,
[SLAVE_TLMM] = &qhs_tlmm,
[SLAVE_USB3] = &qhs_usb3,
[SLAVE_USB3_PHY_CFG] = &qhs_usb3_phy,
[SLAVE_ANOC_SNOC] = &qns_aggre_noc,
[SLAVE_SNOC_MEM_NOC_GC] = &qns_snoc_memnoc,
[SLAVE_OCIMEM] = &qxs_imem,
[SLAVE_SERVICE_SNOC] = &srvc_snoc,
[SLAVE_PCIE_0] = &xs_pcie,
[SLAVE_QDSS_STM] = &xs_qdss_stm,
[SLAVE_TCU] = &xs_sys_tcu_cfg,
};
static const struct qcom_icc_desc sdx55_system_noc = {
.nodes = system_noc_nodes,
.num_nodes = ARRAY_SIZE(system_noc_nodes),
.bcms = system_noc_bcms,
.num_bcms = ARRAY_SIZE(system_noc_bcms),
};
static const struct of_device_id qnoc_of_match[] = {
{ .compatible = "qcom,sdx55-mc-virt",
.data = &sdx55_mc_virt},
{ .compatible = "qcom,sdx55-mem-noc",
.data = &sdx55_mem_noc},
{ .compatible = "qcom,sdx55-system-noc",
.data = &sdx55_system_noc},
{ }
};
MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
.remove = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sdx55",
.of_match_table = qnoc_of_match,
.sync_state = icc_sync_state,
},
};
module_platform_driver(qnoc_driver);
MODULE_DESCRIPTION("Qualcomm SDX55 NoC driver");
MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
MODULE_LICENSE("GPL v2");
@@ -0,0 +1,898 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/device.h>
#include <linux/interconnect.h>
#include <linux/interconnect-provider.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <dt-bindings/interconnect/qcom,sdx65.h>
#include "bcm-voter.h"
#include "icc-rpmh.h"
static struct qcom_icc_node llcc_mc;
static struct qcom_icc_node acm_tcu;
static struct qcom_icc_node qnm_snoc_gc;
static struct qcom_icc_node xm_apps_rdwr;
static struct qcom_icc_node qhm_audio;
static struct qcom_icc_node qhm_blsp1;
static struct qcom_icc_node qhm_qdss_bam;
static struct qcom_icc_node qhm_qpic;
static struct qcom_icc_node qhm_snoc_cfg;
static struct qcom_icc_node qhm_spmi_fetcher1;
static struct qcom_icc_node qnm_aggre_noc;
static struct qcom_icc_node qnm_ipa;
static struct qcom_icc_node qnm_memnoc;
static struct qcom_icc_node qnm_memnoc_pcie;
static struct qcom_icc_node qxm_crypto;
static struct qcom_icc_node xm_ipa2pcie_slv;
static struct qcom_icc_node xm_pcie;
static struct qcom_icc_node xm_qdss_etr;
static struct qcom_icc_node xm_sdc1;
static struct qcom_icc_node xm_usb3;
static struct qcom_icc_node ebi;
static struct qcom_icc_node qns_llcc;
static struct qcom_icc_node qns_memnoc_snoc;
static struct qcom_icc_node qns_sys_pcie;
static struct qcom_icc_node qhs_aoss;
static struct qcom_icc_node qhs_apss;
static struct qcom_icc_node qhs_audio;
static struct qcom_icc_node qhs_blsp1;
static struct qcom_icc_node qhs_clk_ctl;
static struct qcom_icc_node qhs_crypto0_cfg;
static struct qcom_icc_node qhs_ddrss_cfg;
static struct qcom_icc_node qhs_ecc_cfg;
static struct qcom_icc_node qhs_imem_cfg;
static struct qcom_icc_node qhs_ipa;
static struct qcom_icc_node qhs_mss_cfg;
static struct qcom_icc_node qhs_pcie_parf;
static struct qcom_icc_node qhs_pdm;
static struct qcom_icc_node qhs_prng;
static struct qcom_icc_node qhs_qdss_cfg;
static struct qcom_icc_node qhs_qpic;
static struct qcom_icc_node qhs_sdc1;
static struct qcom_icc_node qhs_snoc_cfg;
static struct qcom_icc_node qhs_spmi_fetcher;
static struct qcom_icc_node qhs_spmi_vgi_coex;
static struct qcom_icc_node qhs_tcsr;
static struct qcom_icc_node qhs_tlmm;
static struct qcom_icc_node qhs_usb3;
static struct qcom_icc_node qhs_usb3_phy;
static struct qcom_icc_node qns_aggre_noc;
static struct qcom_icc_node qns_snoc_memnoc;
static struct qcom_icc_node qxs_imem;
static struct qcom_icc_node srvc_snoc;
static struct qcom_icc_node xs_pcie;
static struct qcom_icc_node xs_qdss_stm;
static struct qcom_icc_node xs_sys_tcu_cfg;
static struct qcom_icc_node llcc_mc = {
.name = "llcc_mc",
.channels = 1,
.buswidth = 4,
.num_links = 1,
.link_nodes = { &ebi },
};
static struct qcom_icc_node acm_tcu = {
.name = "acm_tcu",
.channels = 1,
.buswidth = 8,
.num_links = 3,
.link_nodes = { &qns_llcc,
&qns_memnoc_snoc,
&qns_sys_pcie },
};
static struct qcom_icc_node qnm_snoc_gc = {
.name = "qnm_snoc_gc",
.channels = 1,
.buswidth = 16,
.num_links = 1,
.link_nodes = { &qns_llcc },
};
static struct qcom_icc_node xm_apps_rdwr = {
.name = "xm_apps_rdwr",
.channels = 1,
.buswidth = 16,
.num_links = 3,
.link_nodes = { &qns_llcc,
&qns_memnoc_snoc,
&qns_sys_pcie },
};
static struct qcom_icc_node qhm_audio = {
.name = "qhm_audio",
.channels = 1,
.buswidth = 4,
.num_links = 1,
.link_nodes = { &qns_aggre_noc },
};
static struct qcom_icc_node qhm_blsp1 = {
.name = "qhm_blsp1",
.channels = 1,
.buswidth = 4,
.num_links = 1,
.link_nodes = { &qns_aggre_noc },
};
static struct qcom_icc_node qhm_qdss_bam = {
.name = "qhm_qdss_bam",
.channels = 1,
.buswidth = 4,
.num_links = 26,
.link_nodes = { &qhs_aoss,
&qhs_audio,
&qhs_blsp1,
&qhs_clk_ctl,
&qhs_crypto0_cfg,
&qhs_ddrss_cfg,
&qhs_ecc_cfg,
&qhs_imem_cfg,
&qhs_ipa,
&qhs_mss_cfg,
&qhs_pcie_parf,
&qhs_pdm,
&qhs_prng,
&qhs_qdss_cfg,
&qhs_qpic,
&qhs_sdc1,
&qhs_snoc_cfg,
&qhs_spmi_fetcher,
&qhs_spmi_vgi_coex,
&qhs_tcsr,
&qhs_tlmm,
&qhs_usb3,
&qhs_usb3_phy,
&qns_snoc_memnoc,
&qxs_imem,
&xs_sys_tcu_cfg },
};
static struct qcom_icc_node qhm_qpic = {
.name = "qhm_qpic",
.channels = 1,
.buswidth = 4,
.num_links = 4,
.link_nodes = { &qhs_aoss,
&qhs_audio,
&qhs_ipa,
&qns_aggre_noc },
};
static struct qcom_icc_node qhm_snoc_cfg = {
.name = "qhm_snoc_cfg",
.channels = 1,
.buswidth = 4,
.num_links = 1,
.link_nodes = { &srvc_snoc },
};
static struct qcom_icc_node qhm_spmi_fetcher1 = {
.name = "qhm_spmi_fetcher1",
.channels = 1,
.buswidth = 4,
.num_links = 2,
.link_nodes = { &qhs_aoss,
&qns_aggre_noc },
};
static struct qcom_icc_node qnm_aggre_noc = {
.name = "qnm_aggre_noc",
.channels = 1,
.buswidth = 8,
.num_links = 29,
.link_nodes = { &qhs_aoss,
&qhs_apss,
&qhs_audio,
&qhs_blsp1,
&qhs_clk_ctl,
&qhs_crypto0_cfg,
&qhs_ddrss_cfg,
&qhs_ecc_cfg,
&qhs_imem_cfg,
&qhs_ipa,
&qhs_mss_cfg,
&qhs_pcie_parf,
&qhs_pdm,
&qhs_prng,
&qhs_qdss_cfg,
&qhs_qpic,
&qhs_sdc1,
&qhs_snoc_cfg,
&qhs_spmi_fetcher,
&qhs_spmi_vgi_coex,
&qhs_tcsr,
&qhs_tlmm,
&qhs_usb3,
&qhs_usb3_phy,
&qns_snoc_memnoc,
&qxs_imem,
&xs_pcie,
&xs_qdss_stm,
&xs_sys_tcu_cfg },
};
static struct qcom_icc_node qnm_ipa = {
.name = "qnm_ipa",
.channels = 1,
.buswidth = 8,
.num_links = 26,
.link_nodes = { &qhs_aoss,
&qhs_audio,
&qhs_blsp1,
&qhs_clk_ctl,
&qhs_crypto0_cfg,
&qhs_ddrss_cfg,
&qhs_ecc_cfg,
&qhs_imem_cfg,
&qhs_ipa,
&qhs_mss_cfg,
&qhs_pcie_parf,
&qhs_pdm,
&qhs_prng,
&qhs_qdss_cfg,
&qhs_qpic,
&qhs_sdc1,
&qhs_snoc_cfg,
&qhs_spmi_fetcher,
&qhs_tcsr,
&qhs_tlmm,
&qhs_usb3,
&qhs_usb3_phy,
&qns_snoc_memnoc,
&qxs_imem,
&xs_pcie,
&xs_qdss_stm },
};
static struct qcom_icc_node qnm_memnoc = {
.name = "qnm_memnoc",
.channels = 1,
.buswidth = 8,
.num_links = 27,
.link_nodes = { &qhs_aoss,
&qhs_apss,
&qhs_audio,
&qhs_blsp1,
&qhs_clk_ctl,
&qhs_crypto0_cfg,
&qhs_ddrss_cfg,
&qhs_ecc_cfg,
&qhs_imem_cfg,
&qhs_ipa,
&qhs_mss_cfg,
&qhs_pcie_parf,
&qhs_pdm,
&qhs_prng,
&qhs_qdss_cfg,
&qhs_qpic,
&qhs_sdc1,
&qhs_snoc_cfg,
&qhs_spmi_fetcher,
&qhs_spmi_vgi_coex,
&qhs_tcsr,
&qhs_tlmm,
&qhs_usb3,
&qhs_usb3_phy,
&qxs_imem,
&xs_qdss_stm,
&xs_sys_tcu_cfg },
};
static struct qcom_icc_node qnm_memnoc_pcie = {
.name = "qnm_memnoc_pcie",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &xs_pcie },
};
static struct qcom_icc_node qxm_crypto = {
.name = "qxm_crypto",
.channels = 1,
.buswidth = 8,
.num_links = 2,
.link_nodes = { &qhs_aoss,
&qns_aggre_noc },
};
static struct qcom_icc_node xm_ipa2pcie_slv = {
.name = "xm_ipa2pcie_slv",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &xs_pcie },
};
static struct qcom_icc_node xm_pcie = {
.name = "xm_pcie",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &qns_aggre_noc },
};
static struct qcom_icc_node xm_qdss_etr = {
.name = "xm_qdss_etr",
.channels = 1,
.buswidth = 8,
.num_links = 26,
.link_nodes = { &qhs_aoss,
&qhs_audio,
&qhs_blsp1,
&qhs_clk_ctl,
&qhs_crypto0_cfg,
&qhs_ddrss_cfg,
&qhs_ecc_cfg,
&qhs_imem_cfg,
&qhs_ipa,
&qhs_mss_cfg,
&qhs_pcie_parf,
&qhs_pdm,
&qhs_prng,
&qhs_qdss_cfg,
&qhs_qpic,
&qhs_sdc1,
&qhs_snoc_cfg,
&qhs_spmi_fetcher,
&qhs_spmi_vgi_coex,
&qhs_tcsr,
&qhs_tlmm,
&qhs_usb3,
&qhs_usb3_phy,
&qns_snoc_memnoc,
&qxs_imem,
&xs_sys_tcu_cfg },
};
static struct qcom_icc_node xm_sdc1 = {
.name = "xm_sdc1",
.channels = 1,
.buswidth = 8,
.num_links = 4,
.link_nodes = { &qhs_aoss,
&qhs_audio,
&qhs_ipa,
&qns_aggre_noc },
};
static struct qcom_icc_node xm_usb3 = {
.name = "xm_usb3",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &qns_aggre_noc },
};
static struct qcom_icc_node ebi = {
.name = "ebi",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qns_llcc = {
.name = "qns_llcc",
.channels = 1,
.buswidth = 16,
.num_links = 1,
.link_nodes = { &llcc_mc },
};
static struct qcom_icc_node qns_memnoc_snoc = {
.name = "qns_memnoc_snoc",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &qnm_memnoc },
};
static struct qcom_icc_node qns_sys_pcie = {
.name = "qns_sys_pcie",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &qnm_memnoc_pcie },
};
static struct qcom_icc_node qhs_aoss = {
.name = "qhs_aoss",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_apss = {
.name = "qhs_apss",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_audio = {
.name = "qhs_audio",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_blsp1 = {
.name = "qhs_blsp1",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_clk_ctl = {
.name = "qhs_clk_ctl",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_crypto0_cfg = {
.name = "qhs_crypto0_cfg",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_ddrss_cfg = {
.name = "qhs_ddrss_cfg",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_ecc_cfg = {
.name = "qhs_ecc_cfg",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_imem_cfg = {
.name = "qhs_imem_cfg",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_ipa = {
.name = "qhs_ipa",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_mss_cfg = {
.name = "qhs_mss_cfg",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_pcie_parf = {
.name = "qhs_pcie_parf",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_pdm = {
.name = "qhs_pdm",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_prng = {
.name = "qhs_prng",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_qdss_cfg = {
.name = "qhs_qdss_cfg",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_qpic = {
.name = "qhs_qpic",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_sdc1 = {
.name = "qhs_sdc1",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_snoc_cfg = {
.name = "qhs_snoc_cfg",
.channels = 1,
.buswidth = 4,
.num_links = 1,
.link_nodes = { &qhm_snoc_cfg },
};
static struct qcom_icc_node qhs_spmi_fetcher = {
.name = "qhs_spmi_fetcher",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_spmi_vgi_coex = {
.name = "qhs_spmi_vgi_coex",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_tcsr = {
.name = "qhs_tcsr",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_tlmm = {
.name = "qhs_tlmm",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_usb3 = {
.name = "qhs_usb3",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qhs_usb3_phy = {
.name = "qhs_usb3_phy",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node qns_aggre_noc = {
.name = "qns_aggre_noc",
.channels = 1,
.buswidth = 8,
.num_links = 1,
.link_nodes = { &qnm_aggre_noc },
};
static struct qcom_icc_node qns_snoc_memnoc = {
.name = "qns_snoc_memnoc",
.channels = 1,
.buswidth = 16,
.num_links = 1,
.link_nodes = { &qnm_snoc_gc },
};
static struct qcom_icc_node qxs_imem = {
.name = "qxs_imem",
.channels = 1,
.buswidth = 8,
};
static struct qcom_icc_node srvc_snoc = {
.name = "srvc_snoc",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node xs_pcie = {
.name = "xs_pcie",
.channels = 1,
.buswidth = 8,
};
static struct qcom_icc_node xs_qdss_stm = {
.name = "xs_qdss_stm",
.channels = 1,
.buswidth = 4,
};
static struct qcom_icc_node xs_sys_tcu_cfg = {
.name = "xs_sys_tcu_cfg",
.channels = 1,
.buswidth = 8,
};
static struct qcom_icc_bcm bcm_ce0 = {
.name = "CE0",
.keepalive = false,
.num_nodes = 1,
.nodes = { &qxm_crypto },
};
static struct qcom_icc_bcm bcm_mc0 = {
.name = "MC0",
.keepalive = true,
.num_nodes = 1,
.nodes = { &ebi },
};
static struct qcom_icc_bcm bcm_pn0 = {
.name = "PN0",
.keepalive = true,
.num_nodes = 26,
.nodes = { &qhm_snoc_cfg,
&qhs_aoss,
&qhs_apss,
&qhs_audio,
&qhs_blsp1,
&qhs_clk_ctl,
&qhs_crypto0_cfg,
&qhs_ddrss_cfg,
&qhs_ecc_cfg,
&qhs_imem_cfg,
&qhs_ipa,
&qhs_mss_cfg,
&qhs_pcie_parf,
&qhs_pdm,
&qhs_prng,
&qhs_qdss_cfg,
&qhs_qpic,
&qhs_sdc1,
&qhs_snoc_cfg,
&qhs_spmi_fetcher,
&qhs_spmi_vgi_coex,
&qhs_tcsr,
&qhs_tlmm,
&qhs_usb3,
&qhs_usb3_phy,
&srvc_snoc
},
};
static struct qcom_icc_bcm bcm_pn1 = {
.name = "PN1",
.keepalive = false,
.num_nodes = 1,
.nodes = { &xm_sdc1 },
};
static struct qcom_icc_bcm bcm_pn2 = {
.name = "PN2",
.keepalive = false,
.num_nodes = 2,
.nodes = { &qhm_audio, &qhm_spmi_fetcher1 },
};
static struct qcom_icc_bcm bcm_pn3 = {
.name = "PN3",
.keepalive = false,
.num_nodes = 2,
.nodes = { &qhm_blsp1, &qhm_qpic },
};
static struct qcom_icc_bcm bcm_pn4 = {
.name = "PN4",
.keepalive = false,
.num_nodes = 1,
.nodes = { &qxm_crypto },
};
static struct qcom_icc_bcm bcm_sh0 = {
.name = "SH0",
.keepalive = true,
.num_nodes = 1,
.nodes = { &qns_llcc },
};
static struct qcom_icc_bcm bcm_sh1 = {
.name = "SH1",
.keepalive = false,
.num_nodes = 1,
.nodes = { &qns_memnoc_snoc },
};
static struct qcom_icc_bcm bcm_sh3 = {
.name = "SH3",
.keepalive = false,
.num_nodes = 1,
.nodes = { &xm_apps_rdwr },
};
static struct qcom_icc_bcm bcm_sn0 = {
.name = "SN0",
.keepalive = true,
.num_nodes = 1,
.nodes = { &qns_snoc_memnoc },
};
static struct qcom_icc_bcm bcm_sn1 = {
.name = "SN1",
.keepalive = false,
.num_nodes = 1,
.nodes = { &qxs_imem },
};
static struct qcom_icc_bcm bcm_sn2 = {
.name = "SN2",
.keepalive = false,
.num_nodes = 1,
.nodes = { &xs_qdss_stm },
};
static struct qcom_icc_bcm bcm_sn3 = {
.name = "SN3",
.keepalive = false,
.num_nodes = 1,
.nodes = { &xs_sys_tcu_cfg },
};
static struct qcom_icc_bcm bcm_sn5 = {
.name = "SN5",
.keepalive = false,
.num_nodes = 1,
.nodes = { &xs_pcie },
};
static struct qcom_icc_bcm bcm_sn6 = {
.name = "SN6",
.keepalive = false,
.num_nodes = 2,
.nodes = { &qhm_qdss_bam, &xm_qdss_etr },
};
static struct qcom_icc_bcm bcm_sn7 = {
.name = "SN7",
.keepalive = false,
.num_nodes = 4,
.nodes = { &qnm_aggre_noc, &xm_pcie, &xm_usb3, &qns_aggre_noc },
};
static struct qcom_icc_bcm bcm_sn8 = {
.name = "SN8",
.keepalive = false,
.num_nodes = 1,
.nodes = { &qnm_memnoc },
};
static struct qcom_icc_bcm bcm_sn9 = {
.name = "SN9",
.keepalive = false,
.num_nodes = 1,
.nodes = { &qnm_memnoc_pcie },
};
static struct qcom_icc_bcm bcm_sn10 = {
.name = "SN10",
.keepalive = false,
.num_nodes = 2,
.nodes = { &qnm_ipa, &xm_ipa2pcie_slv },
};
static struct qcom_icc_bcm * const mc_virt_bcms[] = {
&bcm_mc0,
};
static struct qcom_icc_node * const mc_virt_nodes[] = {
[MASTER_LLCC] = &llcc_mc,
[SLAVE_EBI1] = &ebi,
};
static const struct qcom_icc_desc sdx65_mc_virt = {
.nodes = mc_virt_nodes,
.num_nodes = ARRAY_SIZE(mc_virt_nodes),
.bcms = mc_virt_bcms,
.num_bcms = ARRAY_SIZE(mc_virt_bcms),
};
static struct qcom_icc_bcm * const mem_noc_bcms[] = {
&bcm_sh0,
&bcm_sh1,
&bcm_sh3,
};
static struct qcom_icc_node * const mem_noc_nodes[] = {
[MASTER_TCU_0] = &acm_tcu,
[MASTER_SNOC_GC_MEM_NOC] = &qnm_snoc_gc,
[MASTER_APPSS_PROC] = &xm_apps_rdwr,
[SLAVE_LLCC] = &qns_llcc,
[SLAVE_MEM_NOC_SNOC] = &qns_memnoc_snoc,
[SLAVE_MEM_NOC_PCIE_SNOC] = &qns_sys_pcie,
};
static const struct qcom_icc_desc sdx65_mem_noc = {
.nodes = mem_noc_nodes,
.num_nodes = ARRAY_SIZE(mem_noc_nodes),
.bcms = mem_noc_bcms,
.num_bcms = ARRAY_SIZE(mem_noc_bcms),
};
static struct qcom_icc_bcm * const system_noc_bcms[] = {
&bcm_ce0,
&bcm_pn0,
&bcm_pn1,
&bcm_pn2,
&bcm_pn3,
&bcm_pn4,
&bcm_sn0,
&bcm_sn1,
&bcm_sn2,
&bcm_sn3,
&bcm_sn5,
&bcm_sn6,
&bcm_sn7,
&bcm_sn8,
&bcm_sn9,
&bcm_sn10,
};
static struct qcom_icc_node * const system_noc_nodes[] = {
[MASTER_AUDIO] = &qhm_audio,
[MASTER_BLSP_1] = &qhm_blsp1,
[MASTER_QDSS_BAM] = &qhm_qdss_bam,
[MASTER_QPIC] = &qhm_qpic,
[MASTER_SNOC_CFG] = &qhm_snoc_cfg,
[MASTER_SPMI_FETCHER] = &qhm_spmi_fetcher1,
[MASTER_ANOC_SNOC] = &qnm_aggre_noc,
[MASTER_IPA] = &qnm_ipa,
[MASTER_MEM_NOC_SNOC] = &qnm_memnoc,
[MASTER_MEM_NOC_PCIE_SNOC] = &qnm_memnoc_pcie,
[MASTER_CRYPTO] = &qxm_crypto,
[MASTER_IPA_PCIE] = &xm_ipa2pcie_slv,
[MASTER_PCIE_0] = &xm_pcie,
[MASTER_QDSS_ETR] = &xm_qdss_etr,
[MASTER_SDCC_1] = &xm_sdc1,
[MASTER_USB3] = &xm_usb3,
[SLAVE_AOSS] = &qhs_aoss,
[SLAVE_APPSS] = &qhs_apss,
[SLAVE_AUDIO] = &qhs_audio,
[SLAVE_BLSP_1] = &qhs_blsp1,
[SLAVE_CLK_CTL] = &qhs_clk_ctl,
[SLAVE_CRYPTO_0_CFG] = &qhs_crypto0_cfg,
[SLAVE_CNOC_DDRSS] = &qhs_ddrss_cfg,
[SLAVE_ECC_CFG] = &qhs_ecc_cfg,
[SLAVE_IMEM_CFG] = &qhs_imem_cfg,
[SLAVE_IPA_CFG] = &qhs_ipa,
[SLAVE_CNOC_MSS] = &qhs_mss_cfg,
[SLAVE_PCIE_PARF] = &qhs_pcie_parf,
[SLAVE_PDM] = &qhs_pdm,
[SLAVE_PRNG] = &qhs_prng,
[SLAVE_QDSS_CFG] = &qhs_qdss_cfg,
[SLAVE_QPIC] = &qhs_qpic,
[SLAVE_SDCC_1] = &qhs_sdc1,
[SLAVE_SNOC_CFG] = &qhs_snoc_cfg,
[SLAVE_SPMI_FETCHER] = &qhs_spmi_fetcher,
[SLAVE_SPMI_VGI_COEX] = &qhs_spmi_vgi_coex,
[SLAVE_TCSR] = &qhs_tcsr,
[SLAVE_TLMM] = &qhs_tlmm,
[SLAVE_USB3] = &qhs_usb3,
[SLAVE_USB3_PHY_CFG] = &qhs_usb3_phy,
[SLAVE_ANOC_SNOC] = &qns_aggre_noc,
[SLAVE_SNOC_MEM_NOC_GC] = &qns_snoc_memnoc,
[SLAVE_IMEM] = &qxs_imem,
[SLAVE_SERVICE_SNOC] = &srvc_snoc,
[SLAVE_PCIE_0] = &xs_pcie,
[SLAVE_QDSS_STM] = &xs_qdss_stm,
[SLAVE_TCU] = &xs_sys_tcu_cfg,
};
static const struct qcom_icc_desc sdx65_system_noc = {
.nodes = system_noc_nodes,
.num_nodes = ARRAY_SIZE(system_noc_nodes),
.bcms = system_noc_bcms,
.num_bcms = ARRAY_SIZE(system_noc_bcms),
};
static const struct of_device_id qnoc_of_match[] = {
{ .compatible = "qcom,sdx65-mc-virt",
.data = &sdx65_mc_virt},
{ .compatible = "qcom,sdx65-mem-noc",
.data = &sdx65_mem_noc},
{ .compatible = "qcom,sdx65-system-noc",
.data = &sdx65_system_noc},
{ }
};
MODULE_DEVICE_TABLE(of, qnoc_of_match);
static struct platform_driver qnoc_driver = {
.probe = qcom_icc_rpmh_probe,
.remove = qcom_icc_rpmh_remove,
.driver = {
.name = "qnoc-sdx65",
.of_match_table = qnoc_of_match,
.sync_state = icc_sync_state,
},
};
module_platform_driver(qnoc_driver);
MODULE_DESCRIPTION("Qualcomm SDX65 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
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,93 @@
// SPDX-License-Identifier: GPL-2.0
/*
* RPM over SMD communication wrapper for interconnects
*
* Copyright (C) 2019 Linaro Ltd
* Author: Georgi Djakov <georgi.djakov@linaro.org>
*/
#include <linux/interconnect-provider.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/soc/qcom/smd-rpm.h>
#include "icc-rpm.h"
#define RPM_KEY_BW 0x00007762
static struct qcom_smd_rpm *icc_smd_rpm;
struct icc_rpm_smd_req {
__le32 key;
__le32 nbytes;
__le32 value;
};
bool qcom_icc_rpm_smd_available(void)
{
return !!icc_smd_rpm;
}
EXPORT_SYMBOL_GPL(qcom_icc_rpm_smd_available);
int qcom_icc_rpm_smd_send(int ctx, int rsc_type, int id, u32 val)
{
struct icc_rpm_smd_req req = {
.key = cpu_to_le32(RPM_KEY_BW),
.nbytes = cpu_to_le32(sizeof(u32)),
.value = cpu_to_le32(val),
};
return qcom_rpm_smd_write(icc_smd_rpm, ctx, rsc_type, id, &req,
sizeof(req));
}
EXPORT_SYMBOL_GPL(qcom_icc_rpm_smd_send);
int qcom_icc_rpm_set_bus_rate(const struct rpm_clk_resource *clk, int ctx, u32 rate)
{
struct clk_smd_rpm_req req = {
.key = cpu_to_le32(QCOM_RPM_SMD_KEY_RATE),
.nbytes = cpu_to_le32(sizeof(u32)),
};
/* Branch clocks are only on/off */
if (clk->branch)
rate = !!rate;
req.value = cpu_to_le32(rate);
return qcom_rpm_smd_write(icc_smd_rpm,
ctx,
clk->resource_type,
clk->clock_id,
&req, sizeof(req));
}
EXPORT_SYMBOL_GPL(qcom_icc_rpm_set_bus_rate);
static void qcom_icc_rpm_smd_remove(struct platform_device *pdev)
{
icc_smd_rpm = NULL;
}
static int qcom_icc_rpm_smd_probe(struct platform_device *pdev)
{
icc_smd_rpm = dev_get_drvdata(pdev->dev.parent);
if (!icc_smd_rpm) {
dev_err(&pdev->dev, "unable to retrieve handle to RPM\n");
return -ENODEV;
}
return 0;
}
static struct platform_driver qcom_interconnect_rpm_smd_driver = {
.driver = {
.name = "icc_smd_rpm",
},
.probe = qcom_icc_rpm_smd_probe,
.remove = qcom_icc_rpm_smd_remove,
};
module_platform_driver(qcom_interconnect_rpm_smd_driver);
MODULE_AUTHOR("Georgi Djakov <georgi.djakov@linaro.org>");
MODULE_DESCRIPTION("Qualcomm SMD RPM interconnect proxy driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:icc_smd_rpm");
File diff suppressed because it is too large Load Diff