2020-12-04 15:53:41 +08:00
/* 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
2022-07-12 09:59:28 +08:00
# include <dt-bindings/interconnect/qcom,icc.h>
2020-12-04 15:53:41 +08:00
# 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 )
2021-12-15 08:23:20 +08:00
enum qcom_icc_type {
QCOM_ICC_NOC ,
QCOM_ICC_BIMC ,
2021-12-15 08:23:21 +08:00
QCOM_ICC_QNOC ,
2021-12-15 08:23:20 +08:00
} ;
2020-12-04 15:53:41 +08:00
/**
* struct qcom_icc_provider - Qualcomm specific interconnect provider
* @ provider : generic interconnect provider
* @ bus_clks : the clk_bulk_data table of bus clocks
* @ num_clks : the total number of clk_bulk_data entries
2021-12-15 08:23:20 +08:00
* @ type : the ICC provider type
2021-09-04 02:24:15 +03:00
* @ qos_offset : offset to QoS registers
2021-09-04 02:24:14 +03:00
* @ regmap : regmap for QoS registers read / write access
interconnect: qcom: icc-rpm: Fix for cached clock rate
All nodes within an interconnect bus share interconnect bus clocks, but
every node has its own cached clock rate values, this can lead to
unexpected clock rate setting.
Let's see an example shown in below, in this case, a bus have two nodes
A and B, and its buswidth is 8:
step1: vote bandwidth 1600M for node(A):
aggregated(bw) = 1600M
qcom_icc_node(A)->rate = 1600M / 8 = 200MHz
step2: vote bandwidth 1600M for node(B):
aggregated(bw) = 1600M + 1600M = 3200M
qcom_icc_node(B)->rate = 3200M / 8 = 400MHz
step3: unvote bandwidth 1600M for node(A)
aggregated(bw) = 3200M - 1600M = 1600M
target_clock = 1600M / 8 = 200MHz
The problem is in step 3, the calculated target clock rate is 200MHz,
which equals to the cached clock rate in node(A) (See step 1),
unfortunately, qcom_icc_set() skips to set the new clock rate 200MHz in
this case, so the bus clock rate will continue to stay at 400MHz.
To resolve the issue, one possible solution is to invoke clk_get_rate()
to retrieve the clock rates on the fly, thus we can totally remove the
cached clock rates. But after review the code, many bus clock has set
the flag CLK_GET_RATE_NOCACHE, this results in the retrieving bus clock
rate is time cost for iterating parent clock nodes, and even challenges
bus clock drivers to provide recalc_rate() callbacks.
So this patch moves the cached rates into structure qcom_icc_provider,
we use it as a central place to maintain bus clock handlers and cached
clock rate, therefore, it can smoothly dismiss the mismatching problem.
Signed-off-by: Leo Yan <leo.yan@linaro.org>
Link: https://lore.kernel.org/r/20220416031029.693211-2-leo.yan@linaro.org
Signed-off-by: Georgi Djakov <djakov@kernel.org>
2022-05-04 10:46:18 +03:00
* @ bus_clk_rate : bus clock rate in Hz
2020-12-04 15:53:41 +08:00
*/
struct qcom_icc_provider {
struct icc_provider provider ;
int num_clks ;
2021-12-15 08:23:20 +08:00
enum qcom_icc_type type ;
2021-09-04 02:24:14 +03:00
struct regmap * regmap ;
2021-09-04 02:24:15 +03:00
unsigned int qos_offset ;
2022-05-04 10:46:18 +03:00
u64 * bus_clk_rate ;
2021-09-04 02:24:11 +03:00
struct clk_bulk_data bus_clks [ ] ;
2020-12-04 15:53:41 +08:00
} ;
2021-09-04 02:24:14 +03:00
/**
* 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
2021-12-15 08:23:21 +08:00
* @ urg_fwd_en : enable urgent forwarding
2021-09-04 02:24:14 +03:00
*/
struct qcom_icc_qos {
u32 areq_prio ;
u32 prio_level ;
bool limit_commands ;
bool ap_owned ;
int qos_mode ;
int qos_port ;
2021-12-15 08:23:21 +08:00
bool urg_fwd_en ;
2021-09-04 02:24:14 +03:00
} ;
2020-12-04 15:53:41 +08:00
/**
* 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
* @ buswidth : width of the interconnect between a node and the bus ( bytes )
2022-07-12 09:59:28 +08:00
* @ sum_avg : current sum aggregate value of all avg bw requests
* @ max_peak : current max aggregate value of all peak bw requests
2020-12-04 15:53:41 +08:00
* @ mas_rpm_id : RPM id for devices that are bus masters
* @ slv_rpm_id : RPM id for devices that are bus slaves
2021-09-04 02:24:14 +03:00
* @ qos : NoC QoS setting parameters
2020-12-04 15:53:41 +08:00
*/
struct qcom_icc_node {
unsigned char * name ;
u16 id ;
2021-09-04 02:24:14 +03:00
const u16 * links ;
2020-12-04 15:53:41 +08:00
u16 num_links ;
u16 buswidth ;
2022-07-12 09:59:28 +08:00
u64 sum_avg [ QCOM_ICC_NUM_BUCKETS ] ;
u64 max_peak [ QCOM_ICC_NUM_BUCKETS ] ;
2020-12-04 15:53:41 +08:00
int mas_rpm_id ;
int slv_rpm_id ;
2021-09-04 02:24:14 +03:00
struct qcom_icc_qos qos ;
2020-12-04 15:53:41 +08:00
} ;
struct qcom_icc_desc {
2022-04-12 12:26:22 +02:00
struct qcom_icc_node * const * nodes ;
2020-12-04 15:53:41 +08:00
size_t num_nodes ;
2021-09-04 02:24:14 +03:00
const char * const * clocks ;
size_t num_clocks ;
2021-10-21 13:24:42 +00:00
bool has_bus_pd ;
2021-12-15 08:23:20 +08:00
enum qcom_icc_type type ;
2021-09-04 02:24:14 +03:00
const struct regmap_config * regmap_cfg ;
2021-09-04 02:24:15 +03:00
unsigned int qos_offset ;
2020-12-04 15:53:41 +08:00
} ;
2021-09-04 02:24:14 +03:00
/* Valid for both NoC and BIMC */
# define NOC_QOS_MODE_INVALID -1
# define NOC_QOS_MODE_FIXED 0x0
# define NOC_QOS_MODE_BYPASS 0x2
2020-12-04 15:53:41 +08:00
2021-09-04 02:24:11 +03:00
int qnoc_probe ( struct platform_device * pdev ) ;
2020-12-04 15:53:41 +08:00
int qnoc_remove ( struct platform_device * pdev ) ;
# endif