platform: msm: Add snapshot of missing msm_bus driver changes
The msm_bus driver provides offers a means of managing performance levels for the buses, fabrics and NoCs, which connect the peripherals and processes within MSM chipsets. This snapshot is taken to merge missing changes from msm-3.18 to msm-3.10 Change-Id: If6fff441265716632ee2b8d666cbbdaf5974a34e Signed-off-by: Alok Chauhan <alokc@codeaurora.org> Signed-off-by: Kiran Gunda <kgunda@codeaurora.org>
This commit is contained in:
parent
b9161e20e8
commit
23a9665dbc
|
@ -57,14 +57,33 @@ qcom,qos-off: Parameter that represents the delta between QoS register address
|
|||
space for different devices.
|
||||
Typically these optional properties are used for
|
||||
devices that represent fabric devices.
|
||||
qcom,util-fact: Parameter that represents the DDR utilization factor. It is
|
||||
represented as actual util-factor * 100.
|
||||
qcom,agg-scheme: Parameter that represents the aggregation scheme to be used for the
|
||||
node. This parameter defaults to LEGACY scheme. The valid options
|
||||
are LEGACY/SCHEME_1.
|
||||
qcom,util-fact: Parameter that represents the DDR utilization factor to be used in
|
||||
LEGACY scheme. It is represented as actual util-factor * 100.
|
||||
qcom,vrail-comp: Parameter that represents the voltage rail compensation to push
|
||||
the bus to the next level if needed. It is represented as actual
|
||||
vrail-comp * 100.
|
||||
the bus to the next level if needed in LEGACY and SCHEME 1 aggregation
|
||||
schemes. It is represented as actual vrail-comp * 100.
|
||||
qcom,util-levels: Array of tuples that represent a bandwidth threshold and util factor
|
||||
to be used uptil the given threshold.
|
||||
qcom,bus-type: Parameter that represents the bus type such as BIMC or NOC.
|
||||
Typically these optional properties are used for
|
||||
devices that represent fabric devices.
|
||||
bus-gdsc-supply: Optional fabric device parameter that is a reference to the dual
|
||||
context GDSC supply that is needed before clock operations.
|
||||
bus-a-gdsc-supply: Optional fabric device parameter that is a reference to an active
|
||||
only context GDSC supply that is needed before clock operations.
|
||||
bus-qos-gdsc-supply: Optional node or fabric device parameter that is a reference to a GDSC
|
||||
supply that is needed before use of the clock needed to program
|
||||
QoS registers.
|
||||
node-gdsc-supply: Optional node device parameter that is a reference to a GDSC supply
|
||||
that is needed before node-clock operations.
|
||||
qcom,enable-only-clk: Optional property that is represents if the clock doesn't support
|
||||
the clk_set_rate API and should only be enabled/disabled.
|
||||
qcom,setrate-only-clk: Optional property that is indicates that bus driver should only
|
||||
set a rate on a clock handle and not call the enable/disable
|
||||
clock API.
|
||||
clock-names: Optional property that represents the clock name associated
|
||||
with the device "bus_clk", "bus_a_clk";
|
||||
clocks: Property pair that represents the clock controller and the clock
|
||||
|
@ -103,7 +122,6 @@ qcom,blacklist: An array of phandles that represent devices that this de
|
|||
intermediate nodes.
|
||||
qcom,agg-ports: The number of aggregation ports on the bus.
|
||||
|
||||
|
||||
The following properties are optional as collecting data via coresight might
|
||||
and are present on child nodes that represent NOC devices. The documentation
|
||||
for coresight properties can be found in:
|
||||
|
@ -117,6 +135,14 @@ coresight-child-list List of phandles pointing to the children of this
|
|||
component.
|
||||
coresight-child-ports List of input port numbers of the children.
|
||||
|
||||
The following sub-nodes are optional parameters:
|
||||
|
||||
qcom,node-qos-clks: Optional node listing all the clocks and regulators required for programming of
|
||||
QoS registers. Usually these are associated with fabric nodes.
|
||||
clock-names: An array of clock names for QoS programming,
|
||||
clocks: An array of clock phandles corresponding to the clock names listed above.
|
||||
clock-name-gdsc:
|
||||
An optional property listing the regulator associated with a given clock name.
|
||||
|
||||
Example:
|
||||
|
||||
|
@ -130,6 +156,9 @@ Example:
|
|||
label = "fab-snoc";
|
||||
qcom,fab-dev;
|
||||
qcom,bypass-qos-prg;
|
||||
qcom,agg-scheme = <SCHEME_1>;
|
||||
qcom,util-levels = <450000 133>,
|
||||
<750000 154>;
|
||||
qcom,base-name = "snoc-base";
|
||||
qcom,base-offset = <0x7000>;
|
||||
qcom,qos-off = <0x1000>;
|
||||
|
@ -137,11 +166,19 @@ Example:
|
|||
clock-names = "bus_clk", "bus_a_clk";
|
||||
clocks = <&clock_rpm clk_snoc_msmbus_clk>,
|
||||
<&clock_rpm clk_snoc_msmbus_a_clk>;
|
||||
qcom,node-qos-clks {
|
||||
clock-names = "q0-clk", "q1-clk";
|
||||
clocks = <&clock_gcc clk_q0_clk>,
|
||||
<&clock_gcc clk_q1_clk>;
|
||||
q0-clk-supply = <&gdsc_q0_clk>;
|
||||
};
|
||||
};
|
||||
|
||||
mm_int_bimc: mm-int-bimc {
|
||||
cell-id = <10003>;
|
||||
label = "mm-int-bimc";
|
||||
qcom,util-fact = <154>;
|
||||
qcom,vrail-comp = <100>;
|
||||
qcom,ap-owned;
|
||||
qcom,connections = <&snoc_bimc_1_mas>;
|
||||
qcom,bus-dev = <&fab_snoc>;
|
||||
|
|
|
@ -1,24 +1,26 @@
|
|||
#
|
||||
# Makefile for msm-bus driver specific files
|
||||
#
|
||||
obj-y += msm_bus_bimc.o msm_bus_noc.o msm_bus_core.o msm_bus_client_api.o
|
||||
obj-y += msm_bus_core.o msm_bus_client_api.o
|
||||
obj-$(CONFIG_OF) += msm_bus_of.o
|
||||
obj-$(CONFIG_MSM_RPM_SMD) += msm_bus_rpm_smd.o
|
||||
|
||||
ifdef CONFIG_BUS_TOPOLOGY_ADHOC
|
||||
obj-y += msm_bus_fabric_adhoc.o msm_bus_arb_adhoc.o msm_bus_rules.o
|
||||
obj-y += msm_bus_fabric_adhoc.o msm_bus_arb_adhoc.o msm_bus_rules.o \
|
||||
msm_bus_bimc_adhoc.o msm_bus_noc_adhoc.o
|
||||
obj-$(CONFIG_OF) += msm_bus_of_adhoc.o
|
||||
obj-$(CONFIG_DEBUG_BUS_VOTER) += msm_bus_dbg_voter.o
|
||||
obj-$(CONFIG_CORESIGHT) += msm_buspm_coresight_adhoc.o
|
||||
else
|
||||
obj-y += msm_bus_fabric.o msm_bus_config.o msm_bus_arb.o
|
||||
obj-y += msm_bus_fabric.o msm_bus_config.o msm_bus_arb.o \
|
||||
msm_bus_bimc.o msm_bus_noc.o
|
||||
obj-$(CONFIG_CORESIGHT) += msm_buspm_coresight.o
|
||||
endif
|
||||
|
||||
ifdef CONFIG_ARCH_MSM8974
|
||||
obj-$(CONFIG_ARCH_MSM8974) += msm_bus_board_8974.o
|
||||
obj-$(CONFIG_ARCH_MSM8974) += msm_bus_board_8974.o
|
||||
else
|
||||
obj-y += msm_bus_id.o
|
||||
obj-y += msm_bus_id.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_DEBUG_FS) += msm_bus_dbg.o
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -28,6 +28,7 @@ struct link_node {
|
|||
struct device *next_dev;
|
||||
struct list_head link;
|
||||
uint32_t in_use;
|
||||
const char *cl_name;
|
||||
};
|
||||
|
||||
/* New types introduced for adhoc topology */
|
||||
|
@ -46,8 +47,12 @@ struct msm_bus_noc_ops {
|
|||
};
|
||||
|
||||
struct nodebw {
|
||||
uint64_t ab[NUM_CTX];
|
||||
bool dirty;
|
||||
uint64_t sum_ab;
|
||||
uint64_t last_sum_ab;
|
||||
uint64_t max_ib;
|
||||
uint64_t cur_clk_hz;
|
||||
uint32_t util_used;
|
||||
uint32_t vrail_used;
|
||||
};
|
||||
|
||||
struct msm_bus_fab_device_type {
|
||||
|
@ -57,8 +62,6 @@ struct msm_bus_fab_device_type {
|
|||
uint32_t base_offset;
|
||||
uint32_t qos_freq;
|
||||
uint32_t qos_off;
|
||||
uint32_t util_fact;
|
||||
uint32_t vrail_comp;
|
||||
struct msm_bus_noc_ops noc_ops;
|
||||
enum msm_bus_hw_sel bus_type;
|
||||
bool bypass_qos_prg;
|
||||
|
@ -80,6 +83,20 @@ struct qos_params_type {
|
|||
u64 bw_buffer;
|
||||
};
|
||||
|
||||
struct node_util_levels_type {
|
||||
uint64_t threshold;
|
||||
uint32_t util_fact;
|
||||
};
|
||||
|
||||
struct node_agg_params_type {
|
||||
uint32_t agg_scheme;
|
||||
uint32_t num_aggports;
|
||||
unsigned int buswidth;
|
||||
uint32_t vrail_comp;
|
||||
uint32_t num_util_levels;
|
||||
struct node_util_levels_type *util_levels;
|
||||
};
|
||||
|
||||
struct msm_bus_node_info_type {
|
||||
const char *name;
|
||||
unsigned int id;
|
||||
|
@ -100,12 +117,10 @@ struct msm_bus_node_info_type {
|
|||
struct device **black_connections;
|
||||
unsigned int bus_device_id;
|
||||
struct device *bus_device;
|
||||
unsigned int buswidth;
|
||||
struct rule_update_path_info rule;
|
||||
uint64_t lim_bw;
|
||||
uint32_t util_fact;
|
||||
uint32_t vrail_comp;
|
||||
uint32_t num_aggports;
|
||||
bool defer_qos;
|
||||
struct node_agg_params_type agg_params;
|
||||
};
|
||||
|
||||
struct msm_bus_node_device_type {
|
||||
|
@ -113,21 +128,29 @@ struct msm_bus_node_device_type {
|
|||
struct msm_bus_fab_device_type *fabdev;
|
||||
int num_lnodes;
|
||||
struct link_node *lnode_list;
|
||||
uint64_t cur_clk_hz[NUM_CTX];
|
||||
struct nodebw node_ab;
|
||||
struct nodebw node_bw[NUM_CTX];
|
||||
struct list_head link;
|
||||
unsigned int ap_owned;
|
||||
struct nodeclk clk[NUM_CTX];
|
||||
struct nodeclk qos_clk;
|
||||
struct nodeclk bus_qos_clk;
|
||||
uint32_t num_node_qos_clks;
|
||||
struct nodeclk *node_qos_clks;
|
||||
struct device_node *of_node;
|
||||
struct device dev;
|
||||
bool dirty;
|
||||
struct list_head dev_link;
|
||||
struct list_head devlist;
|
||||
};
|
||||
|
||||
static inline struct msm_bus_node_device_type *to_msm_bus_node(struct device *d)
|
||||
{
|
||||
return container_of(d, struct msm_bus_node_device_type, dev);
|
||||
}
|
||||
|
||||
|
||||
int msm_bus_enable_limiter(struct msm_bus_node_device_type *nodedev,
|
||||
int throttle_en, uint64_t lim_bw);
|
||||
int msm_bus_update_clks(struct msm_bus_node_device_type *nodedev,
|
||||
int ctx, int **dirty_nodes, int *num_dirty);
|
||||
int msm_bus_commit_data(int *dirty_nodes, int ctx, int num_dirty);
|
||||
int msm_bus_update_bw(struct msm_bus_node_device_type *nodedev, int ctx,
|
||||
int64_t add_bw, int **dirty_nodes, int *num_dirty);
|
||||
int msm_bus_commit_data(struct list_head *clist);
|
||||
void *msm_bus_realloc_devmem(struct device *dev, void *p, size_t old_size,
|
||||
size_t new_size, gfp_t flags);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,718 @@
|
|||
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "AXI: BIMC: %s(): " fmt, __func__
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/msm-bus-board.h>
|
||||
#include "msm_bus_core.h"
|
||||
#include "msm_bus_bimc.h"
|
||||
#include "msm_bus_adhoc.h"
|
||||
#include <trace/events/trace_msm_bus.h>
|
||||
|
||||
/* M_Generic */
|
||||
|
||||
enum bke_sw {
|
||||
BKE_OFF = 0,
|
||||
BKE_ON = 1,
|
||||
};
|
||||
|
||||
#define M_REG_BASE(b) ((b) + 0x00008000)
|
||||
|
||||
#define M_MODE_ADDR(b, n) \
|
||||
(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000210)
|
||||
enum bimc_m_mode {
|
||||
M_MODE_RMSK = 0xf0000011,
|
||||
M_MODE_WR_GATHER_BEATS_BMSK = 0xf0000000,
|
||||
M_MODE_WR_GATHER_BEATS_SHFT = 0x1c,
|
||||
M_MODE_NARROW_WR_BMSK = 0x10,
|
||||
M_MODE_NARROW_WR_SHFT = 0x4,
|
||||
M_MODE_ORDERING_MODEL_BMSK = 0x1,
|
||||
M_MODE_ORDERING_MODEL_SHFT = 0x0,
|
||||
};
|
||||
|
||||
#define M_PRIOLVL_OVERRIDE_ADDR(b, n) \
|
||||
(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000230)
|
||||
enum bimc_m_priolvl_override {
|
||||
M_PRIOLVL_OVERRIDE_RMSK = 0x301,
|
||||
M_PRIOLVL_OVERRIDE_BMSK = 0x300,
|
||||
M_PRIOLVL_OVERRIDE_SHFT = 0x8,
|
||||
M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_BMSK = 0x1,
|
||||
M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_SHFT = 0x0,
|
||||
};
|
||||
|
||||
#define M_RD_CMD_OVERRIDE_ADDR(b, n) \
|
||||
(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000240)
|
||||
enum bimc_m_read_command_override {
|
||||
M_RD_CMD_OVERRIDE_RMSK = 0x3071f7f,
|
||||
M_RD_CMD_OVERRIDE_AREQPRIO_BMSK = 0x3000000,
|
||||
M_RD_CMD_OVERRIDE_AREQPRIO_SHFT = 0x18,
|
||||
M_RD_CMD_OVERRIDE_AMEMTYPE_BMSK = 0x70000,
|
||||
M_RD_CMD_OVERRIDE_AMEMTYPE_SHFT = 0x10,
|
||||
M_RD_CMD_OVERRIDE_ATRANSIENT_BMSK = 0x1000,
|
||||
M_RD_CMD_OVERRIDE_ATRANSIENT_SHFT = 0xc,
|
||||
M_RD_CMD_OVERRIDE_ASHARED_BMSK = 0x800,
|
||||
M_RD_CMD_OVERRIDE_ASHARED_SHFT = 0xb,
|
||||
M_RD_CMD_OVERRIDE_AREDIRECT_BMSK = 0x400,
|
||||
M_RD_CMD_OVERRIDE_AREDIRECT_SHFT = 0xa,
|
||||
M_RD_CMD_OVERRIDE_AOOO_BMSK = 0x200,
|
||||
M_RD_CMD_OVERRIDE_AOOO_SHFT = 0x9,
|
||||
M_RD_CMD_OVERRIDE_AINNERSHARED_BMSK = 0x100,
|
||||
M_RD_CMD_OVERRIDE_AINNERSHARED_SHFT = 0x8,
|
||||
M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK = 0x40,
|
||||
M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT = 0x6,
|
||||
M_RD_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_BMSK = 0x20,
|
||||
M_RD_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_SHFT = 0x5,
|
||||
M_RD_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_BMSK = 0x10,
|
||||
M_RD_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_SHFT = 0x4,
|
||||
M_RD_CMD_OVERRIDE_OVERRIDE_ASHARED_BMSK = 0x8,
|
||||
M_RD_CMD_OVERRIDE_OVERRIDE_ASHARED_SHFT = 0x3,
|
||||
M_RD_CMD_OVERRIDE_OVERRIDE_AREDIRECT_BMSK = 0x4,
|
||||
M_RD_CMD_OVERRIDE_OVERRIDE_AREDIRECT_SHFT = 0x2,
|
||||
M_RD_CMD_OVERRIDE_OVERRIDE_AOOO_BMSK = 0x2,
|
||||
M_RD_CMD_OVERRIDE_OVERRIDE_AOOO_SHFT = 0x1,
|
||||
M_RD_CMD_OVERRIDE_OVERRIDE_AINNERSHARED_BMSK = 0x1,
|
||||
M_RD_CMD_OVERRIDE_OVERRIDE_AINNERSHARED_SHFT = 0x0,
|
||||
};
|
||||
|
||||
#define M_WR_CMD_OVERRIDE_ADDR(b, n) \
|
||||
(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000250)
|
||||
enum bimc_m_write_command_override {
|
||||
M_WR_CMD_OVERRIDE_RMSK = 0x3071f7f,
|
||||
M_WR_CMD_OVERRIDE_AREQPRIO_BMSK = 0x3000000,
|
||||
M_WR_CMD_OVERRIDE_AREQPRIO_SHFT = 0x18,
|
||||
M_WR_CMD_OVERRIDE_AMEMTYPE_BMSK = 0x70000,
|
||||
M_WR_CMD_OVERRIDE_AMEMTYPE_SHFT = 0x10,
|
||||
M_WR_CMD_OVERRIDE_ATRANSIENT_BMSK = 0x1000,
|
||||
M_WR_CMD_OVERRIDE_ATRANSIENT_SHFT = 0xc,
|
||||
M_WR_CMD_OVERRIDE_ASHARED_BMSK = 0x800,
|
||||
M_WR_CMD_OVERRIDE_ASHARED_SHFT = 0xb,
|
||||
M_WR_CMD_OVERRIDE_AREDIRECT_BMSK = 0x400,
|
||||
M_WR_CMD_OVERRIDE_AREDIRECT_SHFT = 0xa,
|
||||
M_WR_CMD_OVERRIDE_AOOO_BMSK = 0x200,
|
||||
M_WR_CMD_OVERRIDE_AOOO_SHFT = 0x9,
|
||||
M_WR_CMD_OVERRIDE_AINNERSHARED_BMSK = 0x100,
|
||||
M_WR_CMD_OVERRIDE_AINNERSHARED_SHFT = 0x8,
|
||||
M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK = 0x40,
|
||||
M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT = 0x6,
|
||||
M_WR_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_BMSK = 0x20,
|
||||
M_WR_CMD_OVERRIDE_OVERRIDE_ATRANSIENT_SHFT = 0x5,
|
||||
M_WR_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_BMSK = 0x10,
|
||||
M_WR_CMD_OVERRIDE_OVERRIDE_AMEMTYPE_SHFT = 0x4,
|
||||
M_WR_CMD_OVERRIDE_OVERRIDE_ASHARED_BMSK = 0x8,
|
||||
M_WR_CMD_OVERRIDE_OVERRIDE_ASHARED_SHFT = 0x3,
|
||||
M_WR_CMD_OVERRIDE_OVERRIDE_AREDIRECT_BMSK = 0x4,
|
||||
M_WR_CMD_OVERRIDE_OVERRIDE_AREDIRECT_SHFT = 0x2,
|
||||
M_WR_CMD_OVERRIDE_OVERRIDE_AOOO_BMSK = 0x2,
|
||||
M_WR_CMD_OVERRIDE_OVERRIDE_AOOO_SHFT = 0x1,
|
||||
M_WR_CMD_OVERRIDE_OVERRIDE_AINNERSHARED_BMSK = 0x1,
|
||||
M_WR_CMD_OVERRIDE_OVERRIDE_AINNERSHARED_SHFT = 0x0,
|
||||
};
|
||||
|
||||
#define M_BKE_EN_ADDR(b, n) \
|
||||
(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000300)
|
||||
enum bimc_m_bke_en {
|
||||
M_BKE_EN_RMSK = 0x1,
|
||||
M_BKE_EN_EN_BMSK = 0x1,
|
||||
M_BKE_EN_EN_SHFT = 0x0,
|
||||
};
|
||||
|
||||
/* Grant Period registers */
|
||||
#define M_BKE_GP_ADDR(b, n) \
|
||||
(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000304)
|
||||
enum bimc_m_bke_grant_period {
|
||||
M_BKE_GP_RMSK = 0x3ff,
|
||||
M_BKE_GP_GP_BMSK = 0x3ff,
|
||||
M_BKE_GP_GP_SHFT = 0x0,
|
||||
};
|
||||
|
||||
/* Grant count register.
|
||||
* The Grant count register represents a signed 16 bit
|
||||
* value, range 0-0x7fff
|
||||
*/
|
||||
#define M_BKE_GC_ADDR(b, n) \
|
||||
(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000308)
|
||||
enum bimc_m_bke_grant_count {
|
||||
M_BKE_GC_RMSK = 0xffff,
|
||||
M_BKE_GC_GC_BMSK = 0xffff,
|
||||
M_BKE_GC_GC_SHFT = 0x0,
|
||||
};
|
||||
|
||||
/* Threshold High Registers */
|
||||
#define M_BKE_THH_ADDR(b, n) \
|
||||
(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000320)
|
||||
enum bimc_m_bke_thresh_high {
|
||||
M_BKE_THH_RMSK = 0xffff,
|
||||
M_BKE_THH_THRESH_BMSK = 0xffff,
|
||||
M_BKE_THH_THRESH_SHFT = 0x0,
|
||||
};
|
||||
|
||||
/* Threshold Medium Registers */
|
||||
#define M_BKE_THM_ADDR(b, n) \
|
||||
(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000324)
|
||||
enum bimc_m_bke_thresh_medium {
|
||||
M_BKE_THM_RMSK = 0xffff,
|
||||
M_BKE_THM_THRESH_BMSK = 0xffff,
|
||||
M_BKE_THM_THRESH_SHFT = 0x0,
|
||||
};
|
||||
|
||||
/* Threshold Low Registers */
|
||||
#define M_BKE_THL_ADDR(b, n) \
|
||||
(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000328)
|
||||
enum bimc_m_bke_thresh_low {
|
||||
M_BKE_THL_RMSK = 0xffff,
|
||||
M_BKE_THL_THRESH_BMSK = 0xffff,
|
||||
M_BKE_THL_THRESH_SHFT = 0x0,
|
||||
};
|
||||
|
||||
#define M_BKE_HEALTH_0_CONFIG_ADDR(b, n) \
|
||||
(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000340)
|
||||
enum bimc_m_bke_health_0 {
|
||||
M_BKE_HEALTH_0_CONFIG_RMSK = 0x80000303,
|
||||
M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_BMSK = 0x80000000,
|
||||
M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_SHFT = 0x1f,
|
||||
M_BKE_HEALTH_0_CONFIG_AREQPRIO_BMSK = 0x300,
|
||||
M_BKE_HEALTH_0_CONFIG_AREQPRIO_SHFT = 0x8,
|
||||
M_BKE_HEALTH_0_CONFIG_PRIOLVL_BMSK = 0x3,
|
||||
M_BKE_HEALTH_0_CONFIG_PRIOLVL_SHFT = 0x0,
|
||||
};
|
||||
|
||||
#define M_BKE_HEALTH_1_CONFIG_ADDR(b, n) \
|
||||
(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000344)
|
||||
enum bimc_m_bke_health_1 {
|
||||
M_BKE_HEALTH_1_CONFIG_RMSK = 0x80000303,
|
||||
M_BKE_HEALTH_1_CONFIG_LIMIT_CMDS_BMSK = 0x80000000,
|
||||
M_BKE_HEALTH_1_CONFIG_LIMIT_CMDS_SHFT = 0x1f,
|
||||
M_BKE_HEALTH_1_CONFIG_AREQPRIO_BMSK = 0x300,
|
||||
M_BKE_HEALTH_1_CONFIG_AREQPRIO_SHFT = 0x8,
|
||||
M_BKE_HEALTH_1_CONFIG_PRIOLVL_BMSK = 0x3,
|
||||
M_BKE_HEALTH_1_CONFIG_PRIOLVL_SHFT = 0x0,
|
||||
};
|
||||
|
||||
#define M_BKE_HEALTH_2_CONFIG_ADDR(b, n) \
|
||||
(M_REG_BASE(b) + (0x4000 * (n)) + 0x00000348)
|
||||
enum bimc_m_bke_health_2 {
|
||||
M_BKE_HEALTH_2_CONFIG_RMSK = 0x80000303,
|
||||
M_BKE_HEALTH_2_CONFIG_LIMIT_CMDS_BMSK = 0x80000000,
|
||||
M_BKE_HEALTH_2_CONFIG_LIMIT_CMDS_SHFT = 0x1f,
|
||||
M_BKE_HEALTH_2_CONFIG_AREQPRIO_BMSK = 0x300,
|
||||
M_BKE_HEALTH_2_CONFIG_AREQPRIO_SHFT = 0x8,
|
||||
M_BKE_HEALTH_2_CONFIG_PRIOLVL_BMSK = 0x3,
|
||||
M_BKE_HEALTH_2_CONFIG_PRIOLVL_SHFT = 0x0,
|
||||
};
|
||||
|
||||
#define M_BKE_HEALTH_3_CONFIG_ADDR(b, n) \
|
||||
(M_REG_BASE(b) + (0x4000 * (n)) + 0x0000034c)
|
||||
enum bimc_m_bke_health_3 {
|
||||
M_BKE_HEALTH_3_CONFIG_RMSK = 0x303,
|
||||
M_BKE_HEALTH_3_CONFIG_AREQPRIO_BMSK = 0x300,
|
||||
M_BKE_HEALTH_3_CONFIG_AREQPRIO_SHFT = 0x8,
|
||||
M_BKE_HEALTH_3_CONFIG_PRIOLVL_BMSK = 0x3,
|
||||
M_BKE_HEALTH_3_CONFIG_PRIOLVL_SHFT = 0x0,
|
||||
};
|
||||
|
||||
#define BKE_HEALTH_MASK \
|
||||
(M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_BMSK |\
|
||||
M_BKE_HEALTH_0_CONFIG_AREQPRIO_BMSK |\
|
||||
M_BKE_HEALTH_0_CONFIG_PRIOLVL_BMSK)
|
||||
|
||||
#define BKE_HEALTH_VAL(limit, areq, plvl) \
|
||||
((((limit) << M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_SHFT) & \
|
||||
M_BKE_HEALTH_0_CONFIG_LIMIT_CMDS_BMSK) | \
|
||||
(((areq) << M_BKE_HEALTH_0_CONFIG_AREQPRIO_SHFT) & \
|
||||
M_BKE_HEALTH_0_CONFIG_AREQPRIO_BMSK) | \
|
||||
(((plvl) << M_BKE_HEALTH_0_CONFIG_PRIOLVL_SHFT) & \
|
||||
M_BKE_HEALTH_0_CONFIG_PRIOLVL_BMSK))
|
||||
|
||||
#define MAX_GRANT_PERIOD \
|
||||
(M_BKE_GP_GP_BMSK >> \
|
||||
M_BKE_GP_GP_SHFT)
|
||||
|
||||
#define MAX_GC \
|
||||
(M_BKE_GC_GC_BMSK >> \
|
||||
(M_BKE_GC_GC_SHFT + 1))
|
||||
|
||||
static int bimc_div(int64_t *a, uint32_t b)
|
||||
{
|
||||
if ((*a > 0) && (*a < b)) {
|
||||
*a = 0;
|
||||
return 1;
|
||||
} else {
|
||||
return do_div(*a, b);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_qos_mode(void __iomem *baddr, uint32_t index, uint32_t val0,
|
||||
uint32_t val1, uint32_t val2)
|
||||
{
|
||||
uint32_t reg_val, val;
|
||||
|
||||
reg_val = readl_relaxed(M_PRIOLVL_OVERRIDE_ADDR(baddr,
|
||||
index)) & M_PRIOLVL_OVERRIDE_RMSK;
|
||||
val = val0 << M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_SHFT;
|
||||
writel_relaxed(((reg_val & ~(M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_BMSK))
|
||||
| (val & M_PRIOLVL_OVERRIDE_OVERRIDE_PRIOLVL_BMSK)),
|
||||
M_PRIOLVL_OVERRIDE_ADDR(baddr, index));
|
||||
reg_val = readl_relaxed(M_RD_CMD_OVERRIDE_ADDR(baddr, index)) &
|
||||
M_RD_CMD_OVERRIDE_RMSK;
|
||||
val = val1 << M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT;
|
||||
writel_relaxed(((reg_val & ~(M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK
|
||||
)) | (val & M_RD_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK)),
|
||||
M_RD_CMD_OVERRIDE_ADDR(baddr, index));
|
||||
reg_val = readl_relaxed(M_WR_CMD_OVERRIDE_ADDR(baddr, index)) &
|
||||
M_WR_CMD_OVERRIDE_RMSK;
|
||||
val = val2 << M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_SHFT;
|
||||
writel_relaxed(((reg_val & ~(M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK
|
||||
)) | (val & M_WR_CMD_OVERRIDE_OVERRIDE_AREQPRIO_BMSK)),
|
||||
M_WR_CMD_OVERRIDE_ADDR(baddr, index));
|
||||
/* Ensure the priority register writes go through */
|
||||
wmb();
|
||||
}
|
||||
|
||||
static void msm_bus_bimc_set_qos_mode(void __iomem *base,
|
||||
uint32_t mas_index, uint8_t qmode_sel)
|
||||
{
|
||||
uint32_t reg_val, val;
|
||||
|
||||
switch (qmode_sel) {
|
||||
case BIMC_QOS_MODE_FIXED:
|
||||
reg_val = readl_relaxed(M_BKE_EN_ADDR(base,
|
||||
mas_index));
|
||||
writel_relaxed((reg_val & (~M_BKE_EN_EN_BMSK)),
|
||||
M_BKE_EN_ADDR(base, mas_index));
|
||||
/*
|
||||
* Ensure that the book-keeping register writes
|
||||
* go through before setting QoS mode.
|
||||
* QoS mode registers might write beyond 1K
|
||||
* boundary in future
|
||||
*/
|
||||
wmb();
|
||||
set_qos_mode(base, mas_index, 1, 1, 1);
|
||||
break;
|
||||
|
||||
case BIMC_QOS_MODE_BYPASS:
|
||||
reg_val = readl_relaxed(M_BKE_EN_ADDR(base,
|
||||
mas_index));
|
||||
writel_relaxed((reg_val & (~M_BKE_EN_EN_BMSK)),
|
||||
M_BKE_EN_ADDR(base, mas_index));
|
||||
/* Ensure that the book-keeping register writes
|
||||
* go through before setting QoS mode.
|
||||
* QoS mode registers might write beyond 1K
|
||||
* boundary in future
|
||||
*/
|
||||
wmb();
|
||||
set_qos_mode(base, mas_index, 0, 0, 0);
|
||||
break;
|
||||
|
||||
case BIMC_QOS_MODE_REGULATOR:
|
||||
case BIMC_QOS_MODE_LIMITER:
|
||||
set_qos_mode(base, mas_index, 0, 0, 0);
|
||||
reg_val = readl_relaxed(M_BKE_EN_ADDR(base,
|
||||
mas_index));
|
||||
val = 1 << M_BKE_EN_EN_SHFT;
|
||||
/* Ensure that the book-keeping register writes
|
||||
* go through before setting QoS mode.
|
||||
* QoS mode registers might write beyond 1K
|
||||
* boundary in future
|
||||
*/
|
||||
wmb();
|
||||
writel_relaxed(((reg_val & (~M_BKE_EN_EN_BMSK)) | (val &
|
||||
M_BKE_EN_EN_BMSK)), M_BKE_EN_ADDR(base,
|
||||
mas_index));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_qos_prio_rl(void __iomem *addr, uint32_t rmsk,
|
||||
uint8_t index, struct msm_bus_bimc_qos_mode *qmode)
|
||||
{
|
||||
uint32_t reg_val, val0, val;
|
||||
|
||||
/* Note, addr is already passed with right mas_index */
|
||||
reg_val = readl_relaxed(addr) & rmsk;
|
||||
val0 = BKE_HEALTH_VAL(qmode->rl.qhealth[index].limit_commands,
|
||||
qmode->rl.qhealth[index].areq_prio,
|
||||
qmode->rl.qhealth[index].prio_level);
|
||||
val = ((reg_val & (~(BKE_HEALTH_MASK))) | (val0 & BKE_HEALTH_MASK));
|
||||
writel_relaxed(val, addr);
|
||||
/* Ensure that priority for regulator/limiter modes are
|
||||
* set before returning
|
||||
*/
|
||||
wmb();
|
||||
}
|
||||
|
||||
static void msm_bus_bimc_set_qos_prio(void __iomem *base,
|
||||
uint32_t mas_index, uint8_t qmode_sel,
|
||||
struct msm_bus_bimc_qos_mode *qmode)
|
||||
{
|
||||
uint32_t reg_val, val;
|
||||
|
||||
switch (qmode_sel) {
|
||||
case BIMC_QOS_MODE_FIXED:
|
||||
reg_val = readl_relaxed(M_PRIOLVL_OVERRIDE_ADDR(
|
||||
base, mas_index)) & M_PRIOLVL_OVERRIDE_RMSK;
|
||||
val = qmode->fixed.prio_level <<
|
||||
M_PRIOLVL_OVERRIDE_SHFT;
|
||||
writel_relaxed(((reg_val &
|
||||
~(M_PRIOLVL_OVERRIDE_BMSK)) | (val
|
||||
& M_PRIOLVL_OVERRIDE_BMSK)),
|
||||
M_PRIOLVL_OVERRIDE_ADDR(base, mas_index));
|
||||
|
||||
reg_val = readl_relaxed(M_RD_CMD_OVERRIDE_ADDR(
|
||||
base, mas_index)) & M_RD_CMD_OVERRIDE_RMSK;
|
||||
val = qmode->fixed.areq_prio_rd <<
|
||||
M_RD_CMD_OVERRIDE_AREQPRIO_SHFT;
|
||||
writel_relaxed(((reg_val & ~(M_RD_CMD_OVERRIDE_AREQPRIO_BMSK))
|
||||
| (val & M_RD_CMD_OVERRIDE_AREQPRIO_BMSK)),
|
||||
M_RD_CMD_OVERRIDE_ADDR(base, mas_index));
|
||||
|
||||
reg_val = readl_relaxed(M_WR_CMD_OVERRIDE_ADDR(
|
||||
base, mas_index)) & M_WR_CMD_OVERRIDE_RMSK;
|
||||
val = qmode->fixed.areq_prio_wr <<
|
||||
M_WR_CMD_OVERRIDE_AREQPRIO_SHFT;
|
||||
writel_relaxed(((reg_val & ~(M_WR_CMD_OVERRIDE_AREQPRIO_BMSK))
|
||||
| (val & M_WR_CMD_OVERRIDE_AREQPRIO_BMSK)),
|
||||
M_WR_CMD_OVERRIDE_ADDR(base, mas_index));
|
||||
/* Ensure that fixed mode register writes go through
|
||||
* before returning
|
||||
*/
|
||||
wmb();
|
||||
break;
|
||||
|
||||
case BIMC_QOS_MODE_REGULATOR:
|
||||
case BIMC_QOS_MODE_LIMITER:
|
||||
set_qos_prio_rl(M_BKE_HEALTH_3_CONFIG_ADDR(base,
|
||||
mas_index), M_BKE_HEALTH_3_CONFIG_RMSK, 3, qmode);
|
||||
set_qos_prio_rl(M_BKE_HEALTH_2_CONFIG_ADDR(base,
|
||||
mas_index), M_BKE_HEALTH_2_CONFIG_RMSK, 2, qmode);
|
||||
set_qos_prio_rl(M_BKE_HEALTH_1_CONFIG_ADDR(base,
|
||||
mas_index), M_BKE_HEALTH_1_CONFIG_RMSK, 1, qmode);
|
||||
set_qos_prio_rl(M_BKE_HEALTH_0_CONFIG_ADDR(base,
|
||||
mas_index), M_BKE_HEALTH_0_CONFIG_RMSK, 0 , qmode);
|
||||
break;
|
||||
case BIMC_QOS_MODE_BYPASS:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void set_qos_bw_regs(void __iomem *baddr, uint32_t mas_index,
|
||||
int32_t th, int32_t tm, int32_t tl, uint32_t gp,
|
||||
uint32_t gc)
|
||||
{
|
||||
int32_t reg_val, val;
|
||||
int32_t bke_reg_val;
|
||||
int16_t val2;
|
||||
|
||||
/* Disable BKE before writing to registers as per spec */
|
||||
bke_reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index));
|
||||
writel_relaxed((bke_reg_val & ~(M_BKE_EN_EN_BMSK)),
|
||||
M_BKE_EN_ADDR(baddr, mas_index));
|
||||
|
||||
/* Write values of registers calculated */
|
||||
reg_val = readl_relaxed(M_BKE_GP_ADDR(baddr, mas_index))
|
||||
& M_BKE_GP_RMSK;
|
||||
val = gp << M_BKE_GP_GP_SHFT;
|
||||
writel_relaxed(((reg_val & ~(M_BKE_GP_GP_BMSK)) | (val &
|
||||
M_BKE_GP_GP_BMSK)), M_BKE_GP_ADDR(baddr, mas_index));
|
||||
|
||||
reg_val = readl_relaxed(M_BKE_GC_ADDR(baddr, mas_index)) &
|
||||
M_BKE_GC_RMSK;
|
||||
val = gc << M_BKE_GC_GC_SHFT;
|
||||
writel_relaxed(((reg_val & ~(M_BKE_GC_GC_BMSK)) | (val &
|
||||
M_BKE_GC_GC_BMSK)), M_BKE_GC_ADDR(baddr, mas_index));
|
||||
|
||||
reg_val = readl_relaxed(M_BKE_THH_ADDR(baddr, mas_index)) &
|
||||
M_BKE_THH_RMSK;
|
||||
val = th << M_BKE_THH_THRESH_SHFT;
|
||||
writel_relaxed(((reg_val & ~(M_BKE_THH_THRESH_BMSK)) | (val &
|
||||
M_BKE_THH_THRESH_BMSK)), M_BKE_THH_ADDR(baddr, mas_index));
|
||||
|
||||
reg_val = readl_relaxed(M_BKE_THM_ADDR(baddr, mas_index)) &
|
||||
M_BKE_THM_RMSK;
|
||||
val2 = tm << M_BKE_THM_THRESH_SHFT;
|
||||
writel_relaxed(((reg_val & ~(M_BKE_THM_THRESH_BMSK)) | (val2 &
|
||||
M_BKE_THM_THRESH_BMSK)), M_BKE_THM_ADDR(baddr, mas_index));
|
||||
|
||||
reg_val = readl_relaxed(M_BKE_THL_ADDR(baddr, mas_index)) &
|
||||
M_BKE_THL_RMSK;
|
||||
val2 = tl << M_BKE_THL_THRESH_SHFT;
|
||||
writel_relaxed(((reg_val & ~(M_BKE_THL_THRESH_BMSK)) |
|
||||
(val2 & M_BKE_THL_THRESH_BMSK)), M_BKE_THL_ADDR(baddr,
|
||||
mas_index));
|
||||
|
||||
/* Ensure that all bandwidth register writes have completed
|
||||
* before returning
|
||||
*/
|
||||
wmb();
|
||||
}
|
||||
|
||||
static void bke_switch(
|
||||
void __iomem *baddr, uint32_t mas_index, bool req, int mode)
|
||||
{
|
||||
uint32_t reg_val, val, cur_val;
|
||||
|
||||
val = req << M_BKE_EN_EN_SHFT;
|
||||
reg_val = readl_relaxed(M_BKE_EN_ADDR(baddr, mas_index));
|
||||
cur_val = reg_val & M_BKE_EN_RMSK;
|
||||
if (val == cur_val)
|
||||
return;
|
||||
|
||||
if (!req && mode == BIMC_QOS_MODE_FIXED)
|
||||
set_qos_mode(baddr, mas_index, 1, 1, 1);
|
||||
|
||||
writel_relaxed(((reg_val & ~(M_BKE_EN_EN_BMSK)) | (val &
|
||||
M_BKE_EN_EN_BMSK)), M_BKE_EN_ADDR(baddr, mas_index));
|
||||
/* Make sure BKE on/off goes through before changing priorities */
|
||||
wmb();
|
||||
|
||||
if (req)
|
||||
set_qos_mode(baddr, mas_index, 0, 0, 0);
|
||||
}
|
||||
|
||||
static void bimc_set_static_qos_bw(void __iomem *base, unsigned int qos_freq,
|
||||
int mport, struct msm_bus_bimc_qos_bw *qbw)
|
||||
{
|
||||
int32_t bw_mbps, thh = 0, thm, thl, gc;
|
||||
int32_t gp;
|
||||
u64 temp;
|
||||
|
||||
if (qos_freq == 0) {
|
||||
MSM_BUS_DBG("No QoS Frequency.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(qbw->bw && qbw->gp)) {
|
||||
MSM_BUS_DBG("No QoS Bandwidth or Window size\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert bandwidth to MBPS */
|
||||
temp = qbw->bw;
|
||||
bimc_div(&temp, 1000000);
|
||||
bw_mbps = temp;
|
||||
|
||||
/* Grant period in clock cycles
|
||||
* Grant period from bandwidth structure
|
||||
* is in nano seconds, QoS freq is in KHz.
|
||||
* Divide by 1000 to get clock cycles.
|
||||
*/
|
||||
gp = (qos_freq * qbw->gp) / (1000 * NSEC_PER_USEC);
|
||||
|
||||
/* Grant count = BW in MBps * Grant period
|
||||
* in micro seconds
|
||||
*/
|
||||
gc = bw_mbps * (qbw->gp / NSEC_PER_USEC);
|
||||
gc = min(gc, MAX_GC);
|
||||
|
||||
/* Medium threshold = -((Medium Threshold percentage *
|
||||
* Grant count) / 100)
|
||||
*/
|
||||
thm = -((qbw->thmp * gc) / 100);
|
||||
qbw->thm = thm;
|
||||
|
||||
/* Low threshold = -(Grant count) */
|
||||
thl = -gc;
|
||||
qbw->thl = thl;
|
||||
|
||||
MSM_BUS_DBG("%s: BKE parameters: gp %d, gc %d, thm %d thl %d thh %d",
|
||||
__func__, gp, gc, thm, thl, thh);
|
||||
|
||||
trace_bus_bke_params(gc, gp, thl, thm, thl);
|
||||
set_qos_bw_regs(base, mport, thh, thm, thl, gp, gc);
|
||||
}
|
||||
|
||||
static int msm_bus_bimc_limit_mport(struct msm_bus_node_device_type *info,
|
||||
void __iomem *qos_base, uint32_t qos_off,
|
||||
uint32_t qos_delta, uint32_t qos_freq,
|
||||
int enable_lim, u64 lim_bw)
|
||||
{
|
||||
int mode;
|
||||
int i;
|
||||
|
||||
if (ZERO_OR_NULL_PTR(info->node_info->qport)) {
|
||||
MSM_BUS_DBG("No QoS Ports to limit\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((enable_lim == THROTTLE_ON) && lim_bw) {
|
||||
mode = BIMC_QOS_MODE_LIMITER;
|
||||
|
||||
if (!info->node_info->lim_bw) {
|
||||
struct msm_bus_bimc_qos_mode qmode;
|
||||
|
||||
qmode.rl.qhealth[0].limit_commands = 1;
|
||||
qmode.rl.qhealth[1].limit_commands = 0;
|
||||
qmode.rl.qhealth[2].limit_commands = 0;
|
||||
qmode.rl.qhealth[3].limit_commands = 0;
|
||||
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
/* If not in bypass mode, update priority */
|
||||
if (mode != BIMC_QOS_MODE_BYPASS)
|
||||
msm_bus_bimc_set_qos_prio(qos_base,
|
||||
info->node_info->qport[i], mode,
|
||||
&qmode);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
struct msm_bus_bimc_qos_bw qbw;
|
||||
/* If not in fixed mode, update bandwidth */
|
||||
if (info->node_info->lim_bw != lim_bw) {
|
||||
qbw.ws = info->node_info->qos_params.ws;
|
||||
qbw.bw = lim_bw;
|
||||
qbw.gp = info->node_info->qos_params.gp;
|
||||
qbw.thmp = info->node_info->qos_params.thmp;
|
||||
bimc_set_static_qos_bw(qos_base, qos_freq,
|
||||
info->node_info->qport[i], &qbw);
|
||||
}
|
||||
bke_switch(qos_base, info->node_info->qport[i],
|
||||
BKE_ON, mode);
|
||||
}
|
||||
info->node_info->lim_bw = lim_bw;
|
||||
} else {
|
||||
mode = info->node_info->qos_params.mode;
|
||||
for (i = 0; i < info->node_info->num_qports; i++)
|
||||
bke_switch(qos_base, info->node_info->qport[i],
|
||||
BKE_OFF, mode);
|
||||
}
|
||||
info->node_info->qos_params.cur_mode = mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool msm_bus_bimc_update_bw_reg(int mode)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if ((mode == BIMC_QOS_MODE_LIMITER)
|
||||
|| (mode == BIMC_QOS_MODE_REGULATOR))
|
||||
ret = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_bus_bimc_qos_init(struct msm_bus_node_device_type *info,
|
||||
void __iomem *qos_base,
|
||||
uint32_t qos_off, uint32_t qos_delta,
|
||||
uint32_t qos_freq)
|
||||
{
|
||||
int i;
|
||||
struct msm_bus_bimc_qos_mode qmode;
|
||||
|
||||
switch (info->node_info->qos_params.mode) {
|
||||
case BIMC_QOS_MODE_FIXED:
|
||||
qmode.fixed.prio_level = info->node_info->qos_params.prio_lvl;
|
||||
qmode.fixed.areq_prio_rd = info->node_info->qos_params.prio_rd;
|
||||
qmode.fixed.areq_prio_wr = info->node_info->qos_params.prio_wr;
|
||||
break;
|
||||
case BIMC_QOS_MODE_LIMITER:
|
||||
qmode.rl.qhealth[0].limit_commands = 1;
|
||||
qmode.rl.qhealth[1].limit_commands = 0;
|
||||
qmode.rl.qhealth[2].limit_commands = 0;
|
||||
qmode.rl.qhealth[3].limit_commands = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (ZERO_OR_NULL_PTR(info->node_info->qport)) {
|
||||
MSM_BUS_DBG("No QoS Ports to init\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
/* If not in bypass mode, update priority */
|
||||
if (info->node_info->qos_params.mode != BIMC_QOS_MODE_BYPASS)
|
||||
msm_bus_bimc_set_qos_prio(qos_base, info->node_info->
|
||||
qport[i], info->node_info->qos_params.mode,
|
||||
&qmode);
|
||||
|
||||
/* set mode */
|
||||
if (info->node_info->qos_params.mode == BIMC_QOS_MODE_LIMITER)
|
||||
bke_switch(qos_base, info->node_info->qport[i],
|
||||
BKE_OFF, BIMC_QOS_MODE_FIXED);
|
||||
else
|
||||
msm_bus_bimc_set_qos_mode(qos_base,
|
||||
info->node_info->qport[i],
|
||||
info->node_info->qos_params.mode);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_bus_bimc_set_bw(struct msm_bus_node_device_type *dev,
|
||||
void __iomem *qos_base, uint32_t qos_off,
|
||||
uint32_t qos_delta, uint32_t qos_freq)
|
||||
{
|
||||
struct msm_bus_bimc_qos_bw qbw;
|
||||
int i;
|
||||
int64_t bw = 0;
|
||||
int ret = 0;
|
||||
struct msm_bus_node_info_type *info = dev->node_info;
|
||||
|
||||
if (info && info->num_qports &&
|
||||
((info->qos_params.mode == BIMC_QOS_MODE_LIMITER) ||
|
||||
(info->qos_params.mode == BIMC_QOS_MODE_REGULATOR))) {
|
||||
bw = msm_bus_div64(info->num_qports,
|
||||
dev->node_bw[ACTIVE_CTX].sum_ab);
|
||||
|
||||
for (i = 0; i < info->num_qports; i++) {
|
||||
MSM_BUS_DBG("BIMC: Update mas_bw for ID: %d -> %llu\n",
|
||||
info->id, bw);
|
||||
|
||||
if (!info->qport) {
|
||||
MSM_BUS_DBG("No qos ports to update!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
qbw.bw = bw + info->qos_params.bw_buffer;
|
||||
trace_bus_bimc_config_limiter(info->id, bw);
|
||||
|
||||
/* Default to gp of 5us */
|
||||
qbw.gp = (info->qos_params.gp ?
|
||||
info->qos_params.gp : 5000);
|
||||
/* Default to thmp of 50% */
|
||||
qbw.thmp = (info->qos_params.thmp ?
|
||||
info->qos_params.thmp : 50);
|
||||
/*
|
||||
* If the BW vote is 0 then set the QoS mode to
|
||||
* Fixed.
|
||||
*/
|
||||
if (bw) {
|
||||
bimc_set_static_qos_bw(qos_base, qos_freq,
|
||||
info->qport[i], &qbw);
|
||||
bke_switch(qos_base, info->qport[i],
|
||||
BKE_ON, info->qos_params.mode);
|
||||
} else {
|
||||
bke_switch(qos_base, info->qport[i],
|
||||
BKE_OFF, BIMC_QOS_MODE_FIXED);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int msm_bus_bimc_set_ops(struct msm_bus_node_device_type *bus_dev)
|
||||
{
|
||||
if (!bus_dev)
|
||||
return -ENODEV;
|
||||
bus_dev->fabdev->noc_ops.qos_init = msm_bus_bimc_qos_init;
|
||||
bus_dev->fabdev->noc_ops.set_bw = msm_bus_bimc_set_bw;
|
||||
bus_dev->fabdev->noc_ops.limit_mport = msm_bus_bimc_limit_mport;
|
||||
bus_dev->fabdev->noc_ops.update_bw_reg =
|
||||
msm_bus_bimc_update_bw_reg;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_bus_bimc_set_ops);
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -67,6 +67,22 @@ int msm_bus_scale_client_update_request(uint32_t cl, unsigned int index)
|
|||
}
|
||||
EXPORT_SYMBOL(msm_bus_scale_client_update_request);
|
||||
|
||||
/**
|
||||
* msm_bus_scale_client_update_context() - Update the context for a client
|
||||
* cl: Handle to the client
|
||||
* active_only: Bool to indicate dual context or active-only context.
|
||||
* ctx_idx: Voting index to be used when switching contexts.
|
||||
*/
|
||||
int msm_bus_scale_client_update_context(uint32_t cl, bool active_only,
|
||||
unsigned int ctx_idx)
|
||||
{
|
||||
if (arb_ops.update_context)
|
||||
return arb_ops.update_context(cl, active_only, ctx_idx);
|
||||
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_bus_scale_client_update_context);
|
||||
|
||||
/**
|
||||
* msm_bus_scale_unregister_client() - Unregister the client from the bus driver
|
||||
* @cl: Handle to the client
|
||||
|
@ -125,6 +141,28 @@ int msm_bus_scale_update_bw(struct msm_bus_client_handle *cl, u64 ab, u64 ib)
|
|||
}
|
||||
EXPORT_SYMBOL(msm_bus_scale_update_bw);
|
||||
|
||||
/**
|
||||
* msm_bus_scale_change_context() - Update the context for a particular client
|
||||
* cl: Handle to the client
|
||||
* act_ab: The average bandwidth(AB) in Bytes/s to be used in active context.
|
||||
* act_ib: The instantaneous bandwidth(IB) in Bytes/s to be used in active
|
||||
* context.
|
||||
* slp_ib: The average bandwidth(AB) in Bytes/s to be used in dual context.
|
||||
* slp_ab: The instantaneous bandwidth(IB) in Bytes/s to be used in dual
|
||||
* context.
|
||||
*/
|
||||
int
|
||||
msm_bus_scale_update_bw_context(struct msm_bus_client_handle *cl, u64 act_ab,
|
||||
u64 act_ib, u64 slp_ib, u64 slp_ab)
|
||||
{
|
||||
if (arb_ops.update_context)
|
||||
return arb_ops.update_bw_context(cl, act_ab, act_ib,
|
||||
slp_ab, slp_ib);
|
||||
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_bus_scale_update_bw_context);
|
||||
|
||||
/**
|
||||
* msm_bus_scale_unregister() - Update the request for bandwidth
|
||||
* from a particular client
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -17,6 +17,7 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/radix-tree.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/msm-bus-board.h>
|
||||
#include <linux/msm-bus.h>
|
||||
|
||||
|
@ -41,6 +42,7 @@
|
|||
#define INTERLEAVED_VAL(fab_pdata, n) \
|
||||
((fab_pdata->il_flag) ? (n) : 1)
|
||||
#define KBTOB(a) (a * 1000ULL)
|
||||
#define MAX_REG_NAME (50)
|
||||
|
||||
enum msm_bus_dbg_op_type {
|
||||
MSM_BUS_DBG_UNREGISTER = -2,
|
||||
|
@ -57,12 +59,16 @@ enum msm_bus_hw_sel {
|
|||
struct msm_bus_arb_ops {
|
||||
uint32_t (*register_client)(struct msm_bus_scale_pdata *pdata);
|
||||
int (*update_request)(uint32_t cl, unsigned int index);
|
||||
int (*update_context)(uint32_t cl, bool active_only,
|
||||
unsigned int ctx_idx);
|
||||
void (*unregister_client)(uint32_t cl);
|
||||
struct msm_bus_client_handle*
|
||||
(*register_cl)(uint32_t mas, uint32_t slv, char *name,
|
||||
bool active_only);
|
||||
int (*update_bw)(struct msm_bus_client_handle *cl, u64 ab, u64 ib);
|
||||
void (*unregister)(struct msm_bus_client_handle *cl);
|
||||
int (*update_bw_context)(struct msm_bus_client_handle *cl, u64 act_ab,
|
||||
u64 act_ib, u64 slp_ib, u64 slp_ab);
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -139,9 +145,13 @@ struct msm_bus_link_info {
|
|||
|
||||
struct nodeclk {
|
||||
struct clk *clk;
|
||||
struct regulator *reg;
|
||||
uint64_t rate;
|
||||
bool dirty;
|
||||
bool enable_only_clk;
|
||||
bool setrate_only_clk;
|
||||
bool enable;
|
||||
char reg_name[MAX_REG_NAME];
|
||||
};
|
||||
|
||||
struct msm_bus_inode_info {
|
||||
|
@ -270,6 +280,7 @@ struct msm_bus_client {
|
|||
struct msm_bus_scale_pdata *pdata;
|
||||
int *src_pnode;
|
||||
int curr;
|
||||
struct device **src_devs;
|
||||
};
|
||||
|
||||
uint64_t msm_bus_div64(unsigned int width, uint64_t bw);
|
||||
|
@ -333,7 +344,7 @@ static inline void msm_bus_dbg_commit_data(const char *fabname,
|
|||
int op)
|
||||
{
|
||||
}
|
||||
static inline void void msm_bus_dbg_remove_client
|
||||
static inline void msm_bus_dbg_remove_client
|
||||
(const struct msm_bus_client_handle *pdata)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -367,7 +367,7 @@ int msm_bus_dbg_rec_transaction(const struct msm_bus_client_handle *pdata,
|
|||
MSM_BUS_DBG("Client doesn't have a name\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
pr_err("\n%s setting up debugfs %s", __func__, pdata->name);
|
||||
pr_debug("\n%s setting up debugfs %s", __func__, pdata->name);
|
||||
cldata->file = debugfs_create_file(pdata->name, S_IRUGO,
|
||||
clients, (void *)pdata, &client_data_fops);
|
||||
}
|
||||
|
@ -725,6 +725,47 @@ static const struct file_operations msm_bus_dbg_update_request_fops = {
|
|||
.write = msm_bus_dbg_update_request_write,
|
||||
};
|
||||
|
||||
static int msm_bus_dbg_dump_clients_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
file->private_data = inode->i_private;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t msm_bus_dbg_dump_clients_read(struct file *file,
|
||||
char __user *buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
int j, cnt;
|
||||
char msg[50];
|
||||
struct msm_bus_cldata *cldata = NULL;
|
||||
|
||||
cnt = scnprintf(msg, 50,
|
||||
"\nDumping curent client votes to trace log\n");
|
||||
if (*ppos)
|
||||
goto exit_dump_clients_read;
|
||||
list_for_each_entry(cldata, &cl_list, list) {
|
||||
if (IS_ERR_OR_NULL(cldata->pdata))
|
||||
continue;
|
||||
for (j = 0; j < cldata->pdata->usecase->num_paths; j++) {
|
||||
if (cldata->index == -1)
|
||||
continue;
|
||||
trace_bus_client_status(
|
||||
cldata->pdata->name,
|
||||
cldata->pdata->usecase[cldata->index].vectors[j].src,
|
||||
cldata->pdata->usecase[cldata->index].vectors[j].dst,
|
||||
cldata->pdata->usecase[cldata->index].vectors[j].ab,
|
||||
cldata->pdata->usecase[cldata->index].vectors[j].ib,
|
||||
cldata->pdata->active_only);
|
||||
}
|
||||
}
|
||||
exit_dump_clients_read:
|
||||
return simple_read_from_buffer(buf, count, ppos, msg, cnt);
|
||||
}
|
||||
|
||||
static const struct file_operations msm_bus_dbg_dump_clients_fops = {
|
||||
.open = msm_bus_dbg_dump_clients_open,
|
||||
.read = msm_bus_dbg_dump_clients_read,
|
||||
};
|
||||
|
||||
/**
|
||||
* msm_bus_dbg_client_data() - Add debug data for clients
|
||||
* @pdata: Platform data of the client
|
||||
|
@ -860,6 +901,10 @@ static int __init msm_bus_debugfs_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (debugfs_create_file("dump_clients", S_IRUGO | S_IWUSR,
|
||||
clients, NULL, &msm_bus_dbg_dump_clients_fops) == NULL)
|
||||
goto err;
|
||||
|
||||
mutex_lock(&msm_bus_dbg_fablist_lock);
|
||||
list_for_each_entry(fablist, &fabdata_list, list) {
|
||||
fablist->file = debugfs_create_file(fablist->name, S_IRUGO,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
|
||||
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is Mree software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
|
@ -154,36 +154,36 @@ static DEVICE_ATTR(floor_vote_api, S_IRUGO | S_IWUSR,
|
|||
static DEVICE_ATTR(floor_active_only, S_IRUGO | S_IWUSR,
|
||||
bus_floor_active_only_show, bus_floor_active_only_store);
|
||||
|
||||
static int msm_bus_floor_init_dev(struct device *fab_dev,
|
||||
struct device *dev, bool is_master)
|
||||
static struct msm_bus_node_device_type *msm_bus_floor_init_dev(
|
||||
struct device *fab_dev, bool is_master)
|
||||
{
|
||||
struct msm_bus_node_device_type *bus_node = NULL;
|
||||
struct msm_bus_node_device_type *fab_node = NULL;
|
||||
struct msm_bus_node_info_type *node_info = NULL;
|
||||
struct device *dev = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (!(fab_dev && dev)) {
|
||||
ret = -ENXIO;
|
||||
if (!fab_dev) {
|
||||
bus_node = ERR_PTR(-ENXIO);
|
||||
goto exit_init_bus_dev;
|
||||
}
|
||||
|
||||
fab_node = fab_dev->platform_data;
|
||||
fab_node = to_msm_bus_node(fab_dev);
|
||||
|
||||
if (!fab_node) {
|
||||
pr_info("\n%s: Can't create device", __func__);
|
||||
ret = -ENXIO;
|
||||
bus_node = ERR_PTR(-ENXIO);
|
||||
goto exit_init_bus_dev;
|
||||
}
|
||||
|
||||
device_initialize(dev);
|
||||
bus_node = devm_kzalloc(dev,
|
||||
sizeof(struct msm_bus_node_device_type), GFP_KERNEL);
|
||||
|
||||
bus_node = kzalloc(sizeof(struct msm_bus_node_device_type), GFP_KERNEL);
|
||||
if (!bus_node) {
|
||||
pr_err("%s:Bus node alloc failed\n", __func__);
|
||||
ret = -ENOMEM;
|
||||
bus_node = ERR_PTR(-ENOMEM);
|
||||
goto exit_init_bus_dev;
|
||||
}
|
||||
dev = &bus_node->dev;
|
||||
device_initialize(dev);
|
||||
|
||||
node_info = devm_kzalloc(dev,
|
||||
sizeof(struct msm_bus_node_info_type), GFP_KERNEL);
|
||||
|
@ -191,22 +191,22 @@ static int msm_bus_floor_init_dev(struct device *fab_dev,
|
|||
if (!node_info) {
|
||||
pr_err("%s:Bus node info alloc failed\n", __func__);
|
||||
devm_kfree(dev, bus_node);
|
||||
ret = -ENOMEM;
|
||||
bus_node = ERR_PTR(-ENOMEM);
|
||||
goto exit_init_bus_dev;
|
||||
}
|
||||
|
||||
bus_node->node_info = node_info;
|
||||
bus_node->ap_owned = true;
|
||||
bus_node->node_info->bus_device = fab_dev;
|
||||
bus_node->node_info->buswidth = 8;
|
||||
dev->platform_data = bus_node;
|
||||
bus_node->node_info->agg_params.buswidth = 8;
|
||||
dev->bus = &msm_bus_type;
|
||||
list_add_tail(&bus_node->dev_link, &fab_node->devlist);
|
||||
|
||||
bus_node->node_info->id = get_id();
|
||||
if (bus_node->node_info->id < 0) {
|
||||
pr_err("%s: Failed to get id for dev. Bus:%s is_master:%d",
|
||||
__func__, fab_node->node_info->name, is_master);
|
||||
ret = -ENXIO;
|
||||
bus_node = ERR_PTR(-ENXIO);
|
||||
goto exit_init_bus_dev;
|
||||
}
|
||||
|
||||
|
@ -216,11 +216,12 @@ static int msm_bus_floor_init_dev(struct device *fab_dev,
|
|||
ret = device_add(dev);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: Failed to add %s", __func__, dev_name(dev));
|
||||
bus_node = ERR_PTR(ret);
|
||||
goto exit_init_bus_dev;
|
||||
}
|
||||
|
||||
exit_init_bus_dev:
|
||||
return ret;
|
||||
return bus_node;
|
||||
}
|
||||
|
||||
static int msm_bus_floor_show_info(struct device *dev, void *data)
|
||||
|
@ -371,30 +372,22 @@ exit_bus_floor_vote_context:
|
|||
}
|
||||
EXPORT_SYMBOL(msm_bus_floor_vote_context);
|
||||
|
||||
static int msm_bus_floor_setup_dev_conn(struct device *mas, struct device *slv)
|
||||
static int msm_bus_floor_setup_dev_conn(
|
||||
struct msm_bus_node_device_type *mas_node,
|
||||
struct msm_bus_node_device_type *slv_node)
|
||||
{
|
||||
int ret = 0;
|
||||
int slv_id = 0;
|
||||
struct msm_bus_node_device_type *mas_node = NULL;
|
||||
struct msm_bus_node_device_type *slv_node = NULL;
|
||||
|
||||
if (!(mas && slv)) {
|
||||
pr_err("\n%s: Invalid master/slave device", __func__);
|
||||
ret = -ENXIO;
|
||||
goto exit_setup_dev_conn;
|
||||
}
|
||||
|
||||
mas_node = mas->platform_data;
|
||||
slv_node = slv->platform_data;
|
||||
|
||||
if (!(mas_node && slv_node)) {
|
||||
pr_err("\n%s: Invalid master/slave device", __func__);
|
||||
ret = -ENXIO;
|
||||
goto exit_setup_dev_conn;
|
||||
}
|
||||
|
||||
slv_id = slv_node->node_info->id;
|
||||
mas_node->node_info->num_connections = 1;
|
||||
mas_node->node_info->connections = devm_kzalloc(mas,
|
||||
mas_node->node_info->connections = devm_kzalloc(&mas_node->dev,
|
||||
(sizeof(int) * mas_node->node_info->num_connections),
|
||||
GFP_KERNEL);
|
||||
|
||||
|
@ -404,7 +397,7 @@ static int msm_bus_floor_setup_dev_conn(struct device *mas, struct device *slv)
|
|||
goto exit_setup_dev_conn;
|
||||
}
|
||||
|
||||
mas_node->node_info->dev_connections = devm_kzalloc(mas,
|
||||
mas_node->node_info->dev_connections = devm_kzalloc(&mas_node->dev,
|
||||
(sizeof(struct device *) *
|
||||
mas_node->node_info->num_connections),
|
||||
GFP_KERNEL);
|
||||
|
@ -416,7 +409,7 @@ static int msm_bus_floor_setup_dev_conn(struct device *mas, struct device *slv)
|
|||
goto exit_setup_dev_conn;
|
||||
}
|
||||
mas_node->node_info->connections[0] = slv_id;
|
||||
mas_node->node_info->dev_connections[0] = slv;
|
||||
mas_node->node_info->dev_connections[0] = &slv_node->dev;
|
||||
|
||||
exit_setup_dev_conn:
|
||||
return ret;
|
||||
|
@ -499,8 +492,6 @@ err_setup_floor_dev:
|
|||
|
||||
int msm_bus_floor_init(struct device *dev)
|
||||
{
|
||||
struct device *m_dev = NULL;
|
||||
struct device *s_dev = NULL;
|
||||
struct msm_bus_node_device_type *mas_node = NULL;
|
||||
struct msm_bus_node_device_type *slv_node = NULL;
|
||||
struct msm_bus_node_device_type *bus_node = NULL;
|
||||
|
@ -512,7 +503,7 @@ int msm_bus_floor_init(struct device *dev)
|
|||
goto exit_floor_init;
|
||||
}
|
||||
|
||||
bus_node = dev->platform_data;
|
||||
bus_node = to_msm_bus_node(dev);
|
||||
if (!(bus_node && bus_node->node_info->is_fab_dev)) {
|
||||
pr_info("\n%s: Can't create voting client, not a fab device",
|
||||
__func__);
|
||||
|
@ -520,57 +511,27 @@ int msm_bus_floor_init(struct device *dev)
|
|||
goto exit_floor_init;
|
||||
}
|
||||
|
||||
m_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
|
||||
if (!m_dev) {
|
||||
pr_err("%s:Master Device alloc failed\n", __func__);
|
||||
m_dev = NULL;
|
||||
ret = -ENOMEM;
|
||||
goto exit_floor_init;
|
||||
}
|
||||
|
||||
s_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
|
||||
if (!m_dev) {
|
||||
pr_err("%s:Slave Device alloc failed\n", __func__);
|
||||
s_dev = NULL;
|
||||
kfree(m_dev);
|
||||
ret = -ENOMEM;
|
||||
m_dev = NULL;
|
||||
goto exit_floor_init;
|
||||
}
|
||||
|
||||
ret = msm_bus_floor_init_dev(dev, m_dev, true);
|
||||
if (ret) {
|
||||
mas_node = msm_bus_floor_init_dev(dev, true);
|
||||
if (IS_ERR_OR_NULL(mas_node)) {
|
||||
pr_err("\n%s: Error setting up master dev, bus %d",
|
||||
__func__, bus_node->node_info->id);
|
||||
kfree(m_dev);
|
||||
kfree(s_dev);
|
||||
goto exit_floor_init;
|
||||
}
|
||||
|
||||
ret = msm_bus_floor_init_dev(dev, s_dev, false);
|
||||
if (ret) {
|
||||
slv_node = msm_bus_floor_init_dev(dev, false);
|
||||
if (IS_ERR_OR_NULL(slv_node)) {
|
||||
pr_err("\n%s: Error setting up slave dev, bus %d",
|
||||
__func__, bus_node->node_info->id);
|
||||
kfree(m_dev);
|
||||
kfree(s_dev);
|
||||
goto exit_floor_init;
|
||||
}
|
||||
|
||||
ret = msm_bus_floor_setup_dev_conn(m_dev, s_dev);
|
||||
ret = msm_bus_floor_setup_dev_conn(mas_node, slv_node);
|
||||
if (ret) {
|
||||
pr_err("\n%s: Error setting up connections bus %d",
|
||||
__func__, bus_node->node_info->id);
|
||||
goto err_floor_init;
|
||||
}
|
||||
|
||||
mas_node = m_dev->platform_data;
|
||||
slv_node = s_dev->platform_data;
|
||||
if ((!(mas_node && slv_node))) {
|
||||
pr_err("\n%s: Error getting mas/slv nodes bus %d",
|
||||
__func__, bus_node->node_info->id);
|
||||
goto err_floor_init;
|
||||
}
|
||||
|
||||
ret = msm_bus_floor_setup_floor_dev(mas_node, slv_node, bus_node);
|
||||
if (ret) {
|
||||
pr_err("\n%s: Error getting mas/slv nodes bus %d",
|
||||
|
@ -581,9 +542,7 @@ int msm_bus_floor_init(struct device *dev)
|
|||
exit_floor_init:
|
||||
return ret;
|
||||
err_floor_init:
|
||||
device_unregister(m_dev);
|
||||
device_unregister(s_dev);
|
||||
kfree(m_dev);
|
||||
kfree(s_dev);
|
||||
kfree(mas_node);
|
||||
kfree(slv_node);
|
||||
return ret;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -32,28 +32,6 @@
|
|||
|
||||
#define NOC_QOS_REG_BASE(b, o) ((b) + (o))
|
||||
|
||||
#define NOC_QOS_ID_COREIDn_ADDR(b, o, n, d) \
|
||||
(NOC_QOS_REG_BASE(b, o) + (d) * (n))
|
||||
enum noc_qos_id_coreidn {
|
||||
NOC_QOS_ID_COREIDn_RMSK = 0xffffffff,
|
||||
NOC_QOS_ID_COREIDn_MAXn = 32,
|
||||
NOC_QOS_ID_COREIDn_CORECHSUM_BMSK = 0xffffff00,
|
||||
NOC_QOS_ID_COREIDn_CORECHSUM_SHFT = 0x8,
|
||||
NOC_QOS_ID_COREIDn_CORETYPEID_BMSK = 0xff,
|
||||
NOC_QOS_ID_COREIDn_CORETYPEID_SHFT = 0x0,
|
||||
};
|
||||
|
||||
#define NOC_QOS_ID_REVISIONIDn_ADDR(b, o, n, d) \
|
||||
(NOC_QOS_REG_BASE(b, o) + 0x4 + (d) * (n))
|
||||
enum noc_qos_id_revisionidn {
|
||||
NOC_QOS_ID_REVISIONIDn_RMSK = 0xffffffff,
|
||||
NOC_QOS_ID_REVISIONIDn_MAXn = 32,
|
||||
NOC_QOS_ID_REVISIONIDn_FLEXNOCID_BMSK = 0xffffff00,
|
||||
NOC_QOS_ID_REVISIONIDn_FLEXNOCID_SHFT = 0x8,
|
||||
NOC_QOS_ID_REVISIONIDn_USERID_BMSK = 0xff,
|
||||
NOC_QOS_ID_REVISIONIDn_USERID_SHFT = 0x0,
|
||||
};
|
||||
|
||||
#define NOC_QOS_PRIORITYn_ADDR(b, o, n, d) \
|
||||
(NOC_QOS_REG_BASE(b, o) + 0x8 + (d) * (n))
|
||||
enum noc_qos_id_priorityn {
|
||||
|
@ -657,238 +635,6 @@ static int msm_bus_noc_port_unhalt(uint32_t haltid, uint8_t mport)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int msm_bus_noc_qos_init(struct msm_bus_node_device_type *info,
|
||||
void __iomem *qos_base,
|
||||
uint32_t qos_off, uint32_t qos_delta,
|
||||
uint32_t qos_freq)
|
||||
{
|
||||
struct msm_bus_noc_qos_priority prio;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
prio.p1 = info->node_info->qos_params.prio1;
|
||||
prio.p0 = info->node_info->qos_params.prio0;
|
||||
|
||||
if (!info->node_info->qport) {
|
||||
MSM_BUS_DBG("No QoS Ports to init\n");
|
||||
ret = 0;
|
||||
goto err_qos_init;
|
||||
}
|
||||
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
if (info->node_info->qos_params.mode != NOC_QOS_MODE_BYPASS) {
|
||||
noc_set_qos_priority(qos_base, qos_off,
|
||||
info->node_info->qport[i], qos_delta,
|
||||
&prio);
|
||||
|
||||
if (info->node_info->qos_params.mode !=
|
||||
NOC_QOS_MODE_FIXED) {
|
||||
struct msm_bus_noc_qos_bw qbw;
|
||||
qbw.ws = info->node_info->qos_params.ws;
|
||||
qbw.bw = 0;
|
||||
msm_bus_noc_set_qos_bw(qos_base, qos_off,
|
||||
qos_freq,
|
||||
info->node_info->qport[i],
|
||||
qos_delta,
|
||||
info->node_info->qos_params.mode,
|
||||
&qbw);
|
||||
}
|
||||
}
|
||||
|
||||
noc_set_qos_mode(qos_base, qos_off, info->node_info->qport[i],
|
||||
qos_delta, info->node_info->qos_params.mode,
|
||||
(1 << info->node_info->qos_params.mode));
|
||||
}
|
||||
err_qos_init:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_bus_noc_set_bw(struct msm_bus_node_device_type *dev,
|
||||
void __iomem *qos_base,
|
||||
uint32_t qos_off, uint32_t qos_delta,
|
||||
uint32_t qos_freq)
|
||||
{
|
||||
int ret = 0;
|
||||
uint64_t bw = 0;
|
||||
int i;
|
||||
struct msm_bus_node_info_type *info = dev->node_info;
|
||||
|
||||
if (info && info->num_qports &&
|
||||
((info->qos_params.mode == NOC_QOS_MODE_REGULATOR) ||
|
||||
(info->qos_params.mode ==
|
||||
NOC_QOS_MODE_LIMITER))) {
|
||||
struct msm_bus_noc_qos_bw qos_bw;
|
||||
|
||||
bw = msm_bus_div64(info->num_qports,
|
||||
dev->node_ab.ab[DUAL_CTX]);
|
||||
|
||||
for (i = 0; i < info->num_qports; i++) {
|
||||
if (!info->qport) {
|
||||
MSM_BUS_DBG("No qos ports to update!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
qos_bw.bw = bw;
|
||||
qos_bw.ws = info->qos_params.ws;
|
||||
msm_bus_noc_set_qos_bw(qos_base, qos_off, qos_freq,
|
||||
info->qport[i], qos_delta,
|
||||
(1 << info->qos_params.mode), &qos_bw);
|
||||
MSM_BUS_DBG("NOC: QoS: Update mas_bw: ws: %u\n",
|
||||
qos_bw.ws);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_bus_noc_set_lim_mode(struct msm_bus_node_device_type *info,
|
||||
void __iomem *qos_base, uint32_t qos_off,
|
||||
uint32_t qos_delta, uint32_t qos_freq,
|
||||
u64 lim_bw)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (info && info->node_info->num_qports) {
|
||||
struct msm_bus_noc_qos_bw qos_bw;
|
||||
if (lim_bw != info->node_info->lim_bw) {
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
qos_bw.bw = lim_bw;
|
||||
qos_bw.ws = info->node_info->qos_params.ws;
|
||||
msm_bus_noc_set_qos_bw(qos_base,
|
||||
qos_off, qos_freq,
|
||||
info->node_info->qport[i], qos_delta,
|
||||
(1 << NOC_QOS_MODE_LIMITER), &qos_bw);
|
||||
}
|
||||
info->node_info->lim_bw = lim_bw;
|
||||
}
|
||||
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
noc_set_qos_mode(qos_base, qos_off,
|
||||
info->node_info->qport[i],
|
||||
qos_delta,
|
||||
NOC_QOS_MODE_LIMITER,
|
||||
(1 << NOC_QOS_MODE_LIMITER));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_bus_noc_set_reg_mode(struct msm_bus_node_device_type *info,
|
||||
void __iomem *qos_base, uint32_t qos_off,
|
||||
uint32_t qos_delta, uint32_t qos_freq,
|
||||
u64 lim_bw)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (info && info->node_info->num_qports) {
|
||||
struct msm_bus_noc_qos_priority prio;
|
||||
struct msm_bus_noc_qos_bw qos_bw;
|
||||
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
prio.p1 =
|
||||
info->node_info->qos_params.reg_prio1;
|
||||
prio.p0 =
|
||||
info->node_info->qos_params.reg_prio0;
|
||||
noc_set_qos_priority(qos_base, qos_off,
|
||||
info->node_info->qport[i],
|
||||
qos_delta,
|
||||
&prio);
|
||||
}
|
||||
|
||||
if (lim_bw != info->node_info->lim_bw) {
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
qos_bw.bw = lim_bw;
|
||||
qos_bw.ws = info->node_info->qos_params.ws;
|
||||
msm_bus_noc_set_qos_bw(qos_base, qos_off,
|
||||
qos_freq,
|
||||
info->node_info->qport[i], qos_delta,
|
||||
(1 << NOC_QOS_MODE_REGULATOR), &qos_bw);
|
||||
}
|
||||
info->node_info->lim_bw = lim_bw;
|
||||
}
|
||||
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
noc_set_qos_mode(qos_base, qos_off,
|
||||
info->node_info->qport[i],
|
||||
qos_delta,
|
||||
NOC_QOS_MODE_REGULATOR,
|
||||
(1 << NOC_QOS_MODE_REGULATOR));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_bus_noc_set_def_mode(struct msm_bus_node_device_type *info,
|
||||
void __iomem *qos_base, uint32_t qos_off,
|
||||
uint32_t qos_delta, uint32_t qos_freq,
|
||||
u64 lim_bw)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
if (info->node_info->qos_params.mode ==
|
||||
NOC_QOS_MODE_FIXED) {
|
||||
struct msm_bus_noc_qos_priority prio;
|
||||
|
||||
prio.p1 =
|
||||
info->node_info->qos_params.prio1;
|
||||
prio.p0 =
|
||||
info->node_info->qos_params.prio0;
|
||||
noc_set_qos_priority(qos_base, qos_off,
|
||||
info->node_info->qport[i],
|
||||
qos_delta, &prio);
|
||||
}
|
||||
noc_set_qos_mode(qos_base, qos_off,
|
||||
info->node_info->qport[i],
|
||||
qos_delta,
|
||||
info->node_info->qos_params.mode,
|
||||
(1 << info->node_info->qos_params.mode));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_bus_noc_limit_mport(struct msm_bus_node_device_type *info,
|
||||
void __iomem *qos_base, uint32_t qos_off,
|
||||
uint32_t qos_delta, uint32_t qos_freq,
|
||||
int enable_lim, u64 lim_bw)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!(info && info->node_info->num_qports)) {
|
||||
MSM_BUS_ERR("Invalid Node info or no Qports to program");
|
||||
ret = -ENXIO;
|
||||
goto exit_limit_mport;
|
||||
}
|
||||
|
||||
if (lim_bw) {
|
||||
switch (enable_lim) {
|
||||
case THROTTLE_REG:
|
||||
{
|
||||
msm_bus_noc_set_reg_mode(info, qos_base, qos_off,
|
||||
qos_delta, qos_freq, lim_bw);
|
||||
break;
|
||||
}
|
||||
case THROTTLE_ON:
|
||||
{
|
||||
msm_bus_noc_set_lim_mode(info, qos_base, qos_off,
|
||||
qos_delta, qos_freq, lim_bw);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
msm_bus_noc_set_def_mode(info, qos_base, qos_off,
|
||||
qos_delta, qos_freq, lim_bw);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else
|
||||
msm_bus_noc_set_def_mode(info, qos_base, qos_off,
|
||||
qos_delta, qos_freq, lim_bw);
|
||||
|
||||
exit_limit_mport:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int msm_bus_noc_hw_init(struct msm_bus_fabric_registration *pdata,
|
||||
struct msm_bus_hw_algorithm *hw_algo)
|
||||
{
|
||||
|
@ -909,17 +655,3 @@ int msm_bus_noc_hw_init(struct msm_bus_fabric_registration *pdata,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int msm_bus_noc_set_ops(struct msm_bus_node_device_type *bus_dev)
|
||||
{
|
||||
if (!bus_dev)
|
||||
return -ENODEV;
|
||||
else {
|
||||
bus_dev->fabdev->noc_ops.qos_init = msm_bus_noc_qos_init;
|
||||
bus_dev->fabdev->noc_ops.set_bw = msm_bus_noc_set_bw;
|
||||
bus_dev->fabdev->noc_ops.limit_mport = msm_bus_noc_limit_mport;
|
||||
bus_dev->fabdev->noc_ops.update_bw_reg =
|
||||
msm_bus_noc_update_bw_reg;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_bus_noc_set_ops);
|
||||
|
|
|
@ -0,0 +1,590 @@
|
|||
/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "AXI: NOC: %s(): " fmt, __func__
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/msm-bus-board.h>
|
||||
#include "msm_bus_core.h"
|
||||
#include "msm_bus_noc.h"
|
||||
#include "msm_bus_adhoc.h"
|
||||
|
||||
/* NOC_QOS generic */
|
||||
#define __CLZ(x) ((8 * sizeof(uint32_t)) - 1 - __fls(x))
|
||||
#define SAT_SCALE 16 /* 16 bytes minimum for saturation */
|
||||
#define BW_SCALE 256 /* 1/256 byte per cycle unit */
|
||||
#define QOS_DEFAULT_BASEOFFSET 0x00003000
|
||||
#define QOS_DEFAULT_DELTA 0x80
|
||||
#define MAX_BW_FIELD (NOC_QOS_BWn_BW_BMSK >> NOC_QOS_BWn_BW_SHFT)
|
||||
#define MAX_SAT_FIELD (NOC_QOS_SATn_SAT_BMSK >> NOC_QOS_SATn_SAT_SHFT)
|
||||
#define MIN_SAT_FIELD 1
|
||||
#define MIN_BW_FIELD 1
|
||||
|
||||
#define NOC_QOS_REG_BASE(b, o) ((b) + (o))
|
||||
|
||||
#define NOC_QOS_PRIORITYn_ADDR(b, o, n, d) \
|
||||
(NOC_QOS_REG_BASE(b, o) + 0x8 + (d) * (n))
|
||||
enum noc_qos_id_priorityn {
|
||||
NOC_QOS_PRIORITYn_RMSK = 0x0000000f,
|
||||
NOC_QOS_PRIORITYn_MAXn = 32,
|
||||
NOC_QOS_PRIORITYn_P1_BMSK = 0xc,
|
||||
NOC_QOS_PRIORITYn_P1_SHFT = 0x2,
|
||||
NOC_QOS_PRIORITYn_P0_BMSK = 0x3,
|
||||
NOC_QOS_PRIORITYn_P0_SHFT = 0x0,
|
||||
};
|
||||
|
||||
#define NOC_QOS_MODEn_ADDR(b, o, n, d) \
|
||||
(NOC_QOS_REG_BASE(b, o) + 0xC + (d) * (n))
|
||||
enum noc_qos_id_moden_rmsk {
|
||||
NOC_QOS_MODEn_RMSK = 0x00000003,
|
||||
NOC_QOS_MODEn_MAXn = 32,
|
||||
NOC_QOS_MODEn_MODE_BMSK = 0x3,
|
||||
NOC_QOS_MODEn_MODE_SHFT = 0x0,
|
||||
};
|
||||
|
||||
#define NOC_QOS_BWn_ADDR(b, o, n, d) \
|
||||
(NOC_QOS_REG_BASE(b, o) + 0x10 + (d) * (n))
|
||||
enum noc_qos_id_bwn {
|
||||
NOC_QOS_BWn_RMSK = 0x0000ffff,
|
||||
NOC_QOS_BWn_MAXn = 32,
|
||||
NOC_QOS_BWn_BW_BMSK = 0xffff,
|
||||
NOC_QOS_BWn_BW_SHFT = 0x0,
|
||||
};
|
||||
|
||||
/* QOS Saturation registers */
|
||||
#define NOC_QOS_SATn_ADDR(b, o, n, d) \
|
||||
(NOC_QOS_REG_BASE(b, o) + 0x14 + (d) * (n))
|
||||
enum noc_qos_id_saturationn {
|
||||
NOC_QOS_SATn_RMSK = 0x000003ff,
|
||||
NOC_QOS_SATn_MAXn = 32,
|
||||
NOC_QOS_SATn_SAT_BMSK = 0x3ff,
|
||||
NOC_QOS_SATn_SAT_SHFT = 0x0,
|
||||
};
|
||||
|
||||
static int noc_div(uint64_t *a, uint32_t b)
|
||||
{
|
||||
if ((*a > 0) && (*a < b)) {
|
||||
*a = 0;
|
||||
return 1;
|
||||
} else {
|
||||
return do_div(*a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates bw hardware is using from register values
|
||||
* bw returned is in bytes/sec
|
||||
*/
|
||||
static uint64_t noc_bw(uint32_t bw_field, uint32_t qos_freq)
|
||||
{
|
||||
uint64_t res;
|
||||
uint32_t rem, scale;
|
||||
|
||||
res = 2 * qos_freq * bw_field;
|
||||
scale = BW_SCALE * 1000;
|
||||
rem = noc_div(&res, scale);
|
||||
MSM_BUS_DBG("NOC: Calculated bw: %llu\n", res * 1000000ULL);
|
||||
return res * 1000000ULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the max BW in Bytes/s for a given time-base.
|
||||
*/
|
||||
static uint32_t noc_bw_ceil(long int bw_field, uint32_t qos_freq_khz)
|
||||
{
|
||||
uint64_t bw_temp = 2 * qos_freq_khz * bw_field;
|
||||
uint32_t scale = 1000 * BW_SCALE;
|
||||
|
||||
noc_div(&bw_temp, scale);
|
||||
return bw_temp * 1000000;
|
||||
}
|
||||
#define MAX_BW(timebase) noc_bw_ceil(MAX_BW_FIELD, (timebase))
|
||||
|
||||
/**
|
||||
* Calculates ws hardware is using from register values
|
||||
* ws returned is in nanoseconds
|
||||
*/
|
||||
static uint32_t noc_ws(uint64_t bw, uint32_t sat, uint32_t qos_freq)
|
||||
{
|
||||
if (bw && qos_freq) {
|
||||
uint32_t bwf = bw * qos_freq;
|
||||
uint64_t scale = 1000000000000LL * BW_SCALE *
|
||||
SAT_SCALE * sat;
|
||||
noc_div(&scale, bwf);
|
||||
MSM_BUS_DBG("NOC: Calculated ws: %llu\n", scale);
|
||||
return scale;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#define MAX_WS(bw, timebase) noc_ws((bw), MAX_SAT_FIELD, (timebase))
|
||||
|
||||
/* Calculate bandwidth field value for requested bandwidth */
|
||||
static uint32_t noc_bw_field(uint64_t bw_bps, uint32_t qos_freq_khz)
|
||||
{
|
||||
uint32_t bw_field = 0;
|
||||
|
||||
if (bw_bps) {
|
||||
uint32_t rem;
|
||||
uint64_t bw_capped = min_t(uint64_t, bw_bps,
|
||||
MAX_BW(qos_freq_khz));
|
||||
uint64_t bwc = bw_capped * BW_SCALE;
|
||||
uint64_t qf = 2 * qos_freq_khz * 1000;
|
||||
|
||||
rem = noc_div(&bwc, qf);
|
||||
bw_field = (uint32_t)max_t(unsigned long, bwc, MIN_BW_FIELD);
|
||||
bw_field = (uint32_t)min_t(unsigned long, bw_field,
|
||||
MAX_BW_FIELD);
|
||||
}
|
||||
|
||||
MSM_BUS_DBG("NOC: bw_field: %u\n", bw_field);
|
||||
return bw_field;
|
||||
}
|
||||
|
||||
static uint32_t noc_sat_field(uint64_t bw, uint32_t ws, uint32_t qos_freq)
|
||||
{
|
||||
uint32_t sat_field = 0;
|
||||
|
||||
if (bw) {
|
||||
/* Limit to max bw and scale bw to 100 KB increments */
|
||||
uint64_t tbw, tscale;
|
||||
uint64_t bw_scaled = min_t(uint64_t, bw, MAX_BW(qos_freq));
|
||||
uint32_t rem = noc_div(&bw_scaled, 100000);
|
||||
|
||||
/**
|
||||
SATURATION =
|
||||
(BW [MBps] * integration window [us] *
|
||||
time base frequency [MHz]) / (256 * 16)
|
||||
*/
|
||||
tbw = bw_scaled * ws * qos_freq;
|
||||
tscale = BW_SCALE * SAT_SCALE * 1000000LL;
|
||||
rem = noc_div(&tbw, tscale);
|
||||
sat_field = (uint32_t)max_t(unsigned long, tbw, MIN_SAT_FIELD);
|
||||
sat_field = (uint32_t)min_t(unsigned long, sat_field,
|
||||
MAX_SAT_FIELD);
|
||||
}
|
||||
|
||||
MSM_BUS_DBG("NOC: sat_field: %d\n", sat_field);
|
||||
return sat_field;
|
||||
}
|
||||
|
||||
static void noc_set_qos_mode(void __iomem *base, uint32_t qos_off,
|
||||
uint32_t mport, uint32_t qos_delta, uint8_t mode,
|
||||
uint8_t perm_mode)
|
||||
{
|
||||
if (mode < NOC_QOS_MODE_MAX &&
|
||||
((1 << mode) & perm_mode)) {
|
||||
uint32_t reg_val;
|
||||
|
||||
reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(base, qos_off,
|
||||
mport, qos_delta)) & NOC_QOS_MODEn_RMSK;
|
||||
writel_relaxed(((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK))) |
|
||||
(mode & NOC_QOS_MODEn_MODE_BMSK)),
|
||||
NOC_QOS_MODEn_ADDR(base, qos_off, mport, qos_delta));
|
||||
}
|
||||
/* Ensure qos mode is set before exiting */
|
||||
wmb();
|
||||
}
|
||||
|
||||
static void noc_set_qos_priority(void __iomem *base, uint32_t qos_off,
|
||||
uint32_t mport, uint32_t qos_delta,
|
||||
struct msm_bus_noc_qos_priority *priority)
|
||||
{
|
||||
uint32_t reg_val, val;
|
||||
|
||||
reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(base, qos_off, mport,
|
||||
qos_delta)) & NOC_QOS_PRIORITYn_RMSK;
|
||||
val = priority->p1 << NOC_QOS_PRIORITYn_P1_SHFT;
|
||||
writel_relaxed(((reg_val & (~(NOC_QOS_PRIORITYn_P1_BMSK))) |
|
||||
(val & NOC_QOS_PRIORITYn_P1_BMSK)),
|
||||
NOC_QOS_PRIORITYn_ADDR(base, qos_off, mport, qos_delta));
|
||||
|
||||
reg_val = readl_relaxed(NOC_QOS_PRIORITYn_ADDR(base, qos_off, mport,
|
||||
qos_delta))
|
||||
& NOC_QOS_PRIORITYn_RMSK;
|
||||
writel_relaxed(((reg_val & (~(NOC_QOS_PRIORITYn_P0_BMSK))) |
|
||||
(priority->p0 & NOC_QOS_PRIORITYn_P0_BMSK)),
|
||||
NOC_QOS_PRIORITYn_ADDR(base, qos_off, mport, qos_delta));
|
||||
/* Ensure qos priority is set before exiting */
|
||||
wmb();
|
||||
}
|
||||
|
||||
static void msm_bus_noc_set_qos_bw(void __iomem *base, uint32_t qos_off,
|
||||
uint32_t qos_freq, uint32_t mport, uint32_t qos_delta,
|
||||
uint8_t perm_mode, struct msm_bus_noc_qos_bw *qbw)
|
||||
{
|
||||
uint32_t reg_val, val, mode;
|
||||
|
||||
if (!qos_freq) {
|
||||
MSM_BUS_DBG("Zero QoS Freq\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* If Limiter or Regulator modes are not supported, bw not available*/
|
||||
if (perm_mode & (NOC_QOS_PERM_MODE_LIMITER |
|
||||
NOC_QOS_PERM_MODE_REGULATOR)) {
|
||||
uint32_t bw_val = noc_bw_field(qbw->bw, qos_freq);
|
||||
uint32_t sat_val = noc_sat_field(qbw->bw, qbw->ws,
|
||||
qos_freq);
|
||||
|
||||
MSM_BUS_DBG("NOC: BW: perm_mode: %d bw_val: %d, sat_val: %d\n",
|
||||
perm_mode, bw_val, sat_val);
|
||||
/*
|
||||
* If in Limiter/Regulator mode, first go to fixed mode.
|
||||
* Clear QoS accumulator
|
||||
**/
|
||||
mode = readl_relaxed(NOC_QOS_MODEn_ADDR(base, qos_off,
|
||||
mport, qos_delta)) & NOC_QOS_MODEn_MODE_BMSK;
|
||||
if (mode == NOC_QOS_MODE_REGULATOR || mode ==
|
||||
NOC_QOS_MODE_LIMITER) {
|
||||
reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(
|
||||
base, qos_off, mport, qos_delta));
|
||||
val = NOC_QOS_MODE_FIXED;
|
||||
writel_relaxed((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK)))
|
||||
| (val & NOC_QOS_MODEn_MODE_BMSK),
|
||||
NOC_QOS_MODEn_ADDR(base, qos_off, mport,
|
||||
qos_delta));
|
||||
}
|
||||
|
||||
reg_val = readl_relaxed(NOC_QOS_BWn_ADDR(base, qos_off, mport,
|
||||
qos_delta));
|
||||
val = bw_val << NOC_QOS_BWn_BW_SHFT;
|
||||
writel_relaxed(((reg_val & (~(NOC_QOS_BWn_BW_BMSK))) |
|
||||
(val & NOC_QOS_BWn_BW_BMSK)),
|
||||
NOC_QOS_BWn_ADDR(base, qos_off, mport, qos_delta));
|
||||
|
||||
MSM_BUS_DBG("NOC: BW: Wrote value: 0x%x\n", ((reg_val &
|
||||
(~NOC_QOS_BWn_BW_BMSK)) | (val &
|
||||
NOC_QOS_BWn_BW_BMSK)));
|
||||
|
||||
reg_val = readl_relaxed(NOC_QOS_SATn_ADDR(base, qos_off,
|
||||
mport, qos_delta));
|
||||
val = sat_val << NOC_QOS_SATn_SAT_SHFT;
|
||||
writel_relaxed(((reg_val & (~(NOC_QOS_SATn_SAT_BMSK))) |
|
||||
(val & NOC_QOS_SATn_SAT_BMSK)),
|
||||
NOC_QOS_SATn_ADDR(base, qos_off, mport, qos_delta));
|
||||
|
||||
MSM_BUS_DBG("NOC: SAT: Wrote value: 0x%x\n", ((reg_val &
|
||||
(~NOC_QOS_SATn_SAT_BMSK)) | (val &
|
||||
NOC_QOS_SATn_SAT_BMSK)));
|
||||
|
||||
/* Set mode back to what it was initially */
|
||||
reg_val = readl_relaxed(NOC_QOS_MODEn_ADDR(base, qos_off,
|
||||
mport, qos_delta));
|
||||
writel_relaxed((reg_val & (~(NOC_QOS_MODEn_MODE_BMSK)))
|
||||
| (mode & NOC_QOS_MODEn_MODE_BMSK),
|
||||
NOC_QOS_MODEn_ADDR(base, qos_off, mport, qos_delta));
|
||||
/* Ensure that all writes for bandwidth registers have
|
||||
* completed before returning
|
||||
*/
|
||||
wmb();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t msm_bus_noc_get_qos_mode(void __iomem *base, uint32_t qos_off,
|
||||
uint32_t mport, uint32_t qos_delta, uint32_t mode, uint32_t perm_mode)
|
||||
{
|
||||
if (NOC_QOS_MODES_ALL_PERM == perm_mode)
|
||||
return readl_relaxed(NOC_QOS_MODEn_ADDR(base, qos_off,
|
||||
mport, qos_delta)) & NOC_QOS_MODEn_MODE_BMSK;
|
||||
else
|
||||
return 31 - __CLZ(mode &
|
||||
NOC_QOS_MODES_ALL_PERM);
|
||||
}
|
||||
|
||||
void msm_bus_noc_get_qos_priority(void __iomem *base, uint32_t qos_off,
|
||||
uint32_t mport, uint32_t qos_delta,
|
||||
struct msm_bus_noc_qos_priority *priority)
|
||||
{
|
||||
priority->p1 = (readl_relaxed(NOC_QOS_PRIORITYn_ADDR(base, qos_off,
|
||||
mport, qos_delta)) & NOC_QOS_PRIORITYn_P1_BMSK) >>
|
||||
NOC_QOS_PRIORITYn_P1_SHFT;
|
||||
|
||||
priority->p0 = (readl_relaxed(NOC_QOS_PRIORITYn_ADDR(base, qos_off,
|
||||
mport, qos_delta)) & NOC_QOS_PRIORITYn_P0_BMSK) >>
|
||||
NOC_QOS_PRIORITYn_P0_SHFT;
|
||||
}
|
||||
|
||||
void msm_bus_noc_get_qos_bw(void __iomem *base, uint32_t qos_off,
|
||||
uint32_t qos_freq,
|
||||
uint32_t mport, uint32_t qos_delta, uint8_t perm_mode,
|
||||
struct msm_bus_noc_qos_bw *qbw)
|
||||
{
|
||||
if (perm_mode & (NOC_QOS_PERM_MODE_LIMITER |
|
||||
NOC_QOS_PERM_MODE_REGULATOR)) {
|
||||
uint32_t bw_val = readl_relaxed(NOC_QOS_BWn_ADDR(
|
||||
base, qos_off, mport, qos_delta)) & NOC_QOS_BWn_BW_BMSK;
|
||||
uint32_t sat = readl_relaxed(NOC_QOS_SATn_ADDR(
|
||||
base, qos_off, mport, qos_delta))
|
||||
& NOC_QOS_SATn_SAT_BMSK;
|
||||
|
||||
qbw->bw = noc_bw(bw_val, qos_freq);
|
||||
qbw->ws = noc_ws(qbw->bw, sat, qos_freq);
|
||||
} else {
|
||||
qbw->bw = 0;
|
||||
qbw->ws = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static bool msm_bus_noc_update_bw_reg(int mode)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if ((mode == NOC_QOS_MODE_LIMITER) ||
|
||||
(mode == NOC_QOS_MODE_REGULATOR))
|
||||
ret = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_bus_noc_qos_init(struct msm_bus_node_device_type *info,
|
||||
void __iomem *qos_base,
|
||||
uint32_t qos_off, uint32_t qos_delta,
|
||||
uint32_t qos_freq)
|
||||
{
|
||||
struct msm_bus_noc_qos_priority prio;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
prio.p1 = info->node_info->qos_params.prio1;
|
||||
prio.p0 = info->node_info->qos_params.prio0;
|
||||
|
||||
if (!info->node_info->qport) {
|
||||
MSM_BUS_DBG("No QoS Ports to init\n");
|
||||
ret = 0;
|
||||
goto err_qos_init;
|
||||
}
|
||||
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
if (info->node_info->qos_params.mode != NOC_QOS_MODE_BYPASS) {
|
||||
noc_set_qos_priority(qos_base, qos_off,
|
||||
info->node_info->qport[i], qos_delta,
|
||||
&prio);
|
||||
|
||||
if (info->node_info->qos_params.mode !=
|
||||
NOC_QOS_MODE_FIXED) {
|
||||
struct msm_bus_noc_qos_bw qbw;
|
||||
|
||||
qbw.ws = info->node_info->qos_params.ws;
|
||||
qbw.bw = 0;
|
||||
msm_bus_noc_set_qos_bw(qos_base, qos_off,
|
||||
qos_freq,
|
||||
info->node_info->qport[i],
|
||||
qos_delta,
|
||||
info->node_info->qos_params.mode,
|
||||
&qbw);
|
||||
}
|
||||
}
|
||||
|
||||
noc_set_qos_mode(qos_base, qos_off, info->node_info->qport[i],
|
||||
qos_delta, info->node_info->qos_params.mode,
|
||||
(1 << info->node_info->qos_params.mode));
|
||||
}
|
||||
err_qos_init:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_bus_noc_set_bw(struct msm_bus_node_device_type *dev,
|
||||
void __iomem *qos_base,
|
||||
uint32_t qos_off, uint32_t qos_delta,
|
||||
uint32_t qos_freq)
|
||||
{
|
||||
int ret = 0;
|
||||
uint64_t bw = 0;
|
||||
int i;
|
||||
struct msm_bus_node_info_type *info = dev->node_info;
|
||||
|
||||
if (info && info->num_qports &&
|
||||
((info->qos_params.mode == NOC_QOS_MODE_REGULATOR) ||
|
||||
(info->qos_params.mode ==
|
||||
NOC_QOS_MODE_LIMITER))) {
|
||||
struct msm_bus_noc_qos_bw qos_bw;
|
||||
|
||||
bw = msm_bus_div64(info->num_qports,
|
||||
dev->node_bw[ACTIVE_CTX].sum_ab);
|
||||
|
||||
for (i = 0; i < info->num_qports; i++) {
|
||||
if (!info->qport) {
|
||||
MSM_BUS_DBG("No qos ports to update!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
qos_bw.bw = bw;
|
||||
qos_bw.ws = info->qos_params.ws;
|
||||
msm_bus_noc_set_qos_bw(qos_base, qos_off, qos_freq,
|
||||
info->qport[i], qos_delta,
|
||||
(1 << info->qos_params.mode), &qos_bw);
|
||||
MSM_BUS_DBG("NOC: QoS: Update mas_bw: ws: %u\n",
|
||||
qos_bw.ws);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int msm_bus_noc_set_lim_mode(struct msm_bus_node_device_type *info,
|
||||
void __iomem *qos_base, uint32_t qos_off,
|
||||
uint32_t qos_delta, uint32_t qos_freq,
|
||||
u64 lim_bw)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (info && info->node_info->num_qports) {
|
||||
struct msm_bus_noc_qos_bw qos_bw;
|
||||
|
||||
if (lim_bw != info->node_info->lim_bw) {
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
qos_bw.bw = lim_bw;
|
||||
qos_bw.ws = info->node_info->qos_params.ws;
|
||||
msm_bus_noc_set_qos_bw(qos_base,
|
||||
qos_off, qos_freq,
|
||||
info->node_info->qport[i], qos_delta,
|
||||
(1 << NOC_QOS_MODE_LIMITER), &qos_bw);
|
||||
}
|
||||
info->node_info->lim_bw = lim_bw;
|
||||
}
|
||||
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
noc_set_qos_mode(qos_base, qos_off,
|
||||
info->node_info->qport[i],
|
||||
qos_delta,
|
||||
NOC_QOS_MODE_LIMITER,
|
||||
(1 << NOC_QOS_MODE_LIMITER));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_bus_noc_set_reg_mode(struct msm_bus_node_device_type *info,
|
||||
void __iomem *qos_base, uint32_t qos_off,
|
||||
uint32_t qos_delta, uint32_t qos_freq,
|
||||
u64 lim_bw)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (info && info->node_info->num_qports) {
|
||||
struct msm_bus_noc_qos_priority prio;
|
||||
struct msm_bus_noc_qos_bw qos_bw;
|
||||
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
prio.p1 =
|
||||
info->node_info->qos_params.reg_prio1;
|
||||
prio.p0 =
|
||||
info->node_info->qos_params.reg_prio0;
|
||||
noc_set_qos_priority(qos_base, qos_off,
|
||||
info->node_info->qport[i],
|
||||
qos_delta,
|
||||
&prio);
|
||||
}
|
||||
|
||||
if (lim_bw != info->node_info->lim_bw) {
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
qos_bw.bw = lim_bw;
|
||||
qos_bw.ws = info->node_info->qos_params.ws;
|
||||
msm_bus_noc_set_qos_bw(qos_base, qos_off,
|
||||
qos_freq,
|
||||
info->node_info->qport[i], qos_delta,
|
||||
(1 << NOC_QOS_MODE_REGULATOR), &qos_bw);
|
||||
}
|
||||
info->node_info->lim_bw = lim_bw;
|
||||
}
|
||||
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
noc_set_qos_mode(qos_base, qos_off,
|
||||
info->node_info->qport[i],
|
||||
qos_delta,
|
||||
NOC_QOS_MODE_REGULATOR,
|
||||
(1 << NOC_QOS_MODE_REGULATOR));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_bus_noc_set_def_mode(struct msm_bus_node_device_type *info,
|
||||
void __iomem *qos_base, uint32_t qos_off,
|
||||
uint32_t qos_delta, uint32_t qos_freq,
|
||||
u64 lim_bw)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < info->node_info->num_qports; i++) {
|
||||
if (info->node_info->qos_params.mode ==
|
||||
NOC_QOS_MODE_FIXED) {
|
||||
struct msm_bus_noc_qos_priority prio;
|
||||
|
||||
prio.p1 =
|
||||
info->node_info->qos_params.prio1;
|
||||
prio.p0 =
|
||||
info->node_info->qos_params.prio0;
|
||||
noc_set_qos_priority(qos_base, qos_off,
|
||||
info->node_info->qport[i],
|
||||
qos_delta, &prio);
|
||||
}
|
||||
noc_set_qos_mode(qos_base, qos_off,
|
||||
info->node_info->qport[i],
|
||||
qos_delta,
|
||||
info->node_info->qos_params.mode,
|
||||
(1 << info->node_info->qos_params.mode));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_bus_noc_limit_mport(struct msm_bus_node_device_type *info,
|
||||
void __iomem *qos_base, uint32_t qos_off,
|
||||
uint32_t qos_delta, uint32_t qos_freq,
|
||||
int enable_lim, u64 lim_bw)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!(info && info->node_info->num_qports)) {
|
||||
MSM_BUS_ERR("Invalid Node info or no Qports to program");
|
||||
ret = -ENXIO;
|
||||
goto exit_limit_mport;
|
||||
}
|
||||
|
||||
if (lim_bw) {
|
||||
switch (enable_lim) {
|
||||
case THROTTLE_REG:
|
||||
msm_bus_noc_set_reg_mode(info, qos_base, qos_off,
|
||||
qos_delta, qos_freq, lim_bw);
|
||||
break;
|
||||
case THROTTLE_ON:
|
||||
msm_bus_noc_set_lim_mode(info, qos_base, qos_off,
|
||||
qos_delta, qos_freq, lim_bw);
|
||||
break;
|
||||
default:
|
||||
msm_bus_noc_set_def_mode(info, qos_base, qos_off,
|
||||
qos_delta, qos_freq, lim_bw);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
msm_bus_noc_set_def_mode(info, qos_base, qos_off,
|
||||
qos_delta, qos_freq, lim_bw);
|
||||
|
||||
exit_limit_mport:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int msm_bus_noc_set_ops(struct msm_bus_node_device_type *bus_dev)
|
||||
{
|
||||
if (!bus_dev)
|
||||
return -ENODEV;
|
||||
|
||||
bus_dev->fabdev->noc_ops.qos_init = msm_bus_noc_qos_init;
|
||||
bus_dev->fabdev->noc_ops.set_bw = msm_bus_noc_set_bw;
|
||||
bus_dev->fabdev->noc_ops.limit_mport = msm_bus_noc_limit_mport;
|
||||
bus_dev->fabdev->noc_ops.update_bw_reg = msm_bus_noc_update_bw_reg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_bus_noc_set_ops);
|
|
@ -29,6 +29,7 @@
|
|||
#define DEFAULT_QOS_FREQ 19200
|
||||
#define DEFAULT_UTIL_FACT 100
|
||||
#define DEFAULT_VRAIL_COMP 100
|
||||
#define DEFAULT_AGG_SCHEME AGG_SCHEME_LEG
|
||||
|
||||
static int get_qos_mode(struct platform_device *pdev,
|
||||
struct device_node *node, const char *qos_mode)
|
||||
|
@ -148,21 +149,6 @@ static struct msm_bus_fab_device_type *get_fab_device_info(
|
|||
fab_dev->qos_freq = DEFAULT_QOS_FREQ;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(dev_node, "qcom,util-fact",
|
||||
&fab_dev->util_fact);
|
||||
if (ret) {
|
||||
dev_info(&pdev->dev, "Util-fact is missing, default to %d\n",
|
||||
DEFAULT_UTIL_FACT);
|
||||
fab_dev->util_fact = DEFAULT_UTIL_FACT;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(dev_node, "qcom,vrail-comp",
|
||||
&fab_dev->vrail_comp);
|
||||
if (ret) {
|
||||
dev_info(&pdev->dev, "Vrail-comp is missing, default to %d\n",
|
||||
DEFAULT_VRAIL_COMP);
|
||||
fab_dev->vrail_comp = DEFAULT_VRAIL_COMP;
|
||||
}
|
||||
|
||||
return fab_dev;
|
||||
|
||||
|
@ -228,6 +214,159 @@ static void get_qos_params(
|
|||
|
||||
}
|
||||
|
||||
static int msm_bus_of_parse_clk_array(struct device_node *dev_node,
|
||||
struct device_node *gdsc_node,
|
||||
struct platform_device *pdev, struct nodeclk **clk_arr,
|
||||
int *num_clks, int id)
|
||||
{
|
||||
int ret = 0;
|
||||
int idx = 0;
|
||||
struct property *prop;
|
||||
const char *clk_name;
|
||||
int clks = 0;
|
||||
|
||||
clks = of_property_count_strings(dev_node, "clock-names");
|
||||
if (clks < 0) {
|
||||
pr_info("%s: No qos clks node %d\n", __func__, id);
|
||||
ret = clks;
|
||||
goto exit_of_parse_clk_array;
|
||||
}
|
||||
|
||||
*num_clks = clks;
|
||||
*clk_arr = devm_kzalloc(&pdev->dev,
|
||||
(clks * sizeof(struct nodeclk)), GFP_KERNEL);
|
||||
|
||||
if (!(*clk_arr)) {
|
||||
pr_err("%s: Error allocating clk nodes for %d\n", __func__, id);
|
||||
ret = -ENOMEM;
|
||||
*num_clks = 0;
|
||||
goto exit_of_parse_clk_array;
|
||||
}
|
||||
|
||||
of_property_for_each_string(dev_node, "clock-names", prop, clk_name) {
|
||||
char gdsc_string[MAX_REG_NAME];
|
||||
|
||||
(*clk_arr)[idx].clk = of_clk_get_by_name(dev_node, clk_name);
|
||||
|
||||
if (IS_ERR_OR_NULL((*clk_arr)[idx].clk)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to get clk %s for bus%d ", clk_name,
|
||||
id);
|
||||
continue;
|
||||
}
|
||||
if (strnstr(clk_name, "no-rate", strlen(clk_name)))
|
||||
(*clk_arr)[idx].enable_only_clk = true;
|
||||
|
||||
scnprintf(gdsc_string, MAX_REG_NAME, "%s-supply", clk_name);
|
||||
|
||||
if (of_find_property(gdsc_node, gdsc_string, NULL))
|
||||
scnprintf((*clk_arr)[idx].reg_name,
|
||||
MAX_REG_NAME, "%s", clk_name);
|
||||
else
|
||||
scnprintf((*clk_arr)[idx].reg_name,
|
||||
MAX_REG_NAME, "%c", '\0');
|
||||
|
||||
idx++;
|
||||
}
|
||||
exit_of_parse_clk_array:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void get_agg_params(
|
||||
struct device_node * const dev_node,
|
||||
struct platform_device * const pdev,
|
||||
struct msm_bus_node_info_type *node_info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
||||
ret = of_property_read_u32(dev_node, "qcom,buswidth",
|
||||
&node_info->agg_params.buswidth);
|
||||
if (ret) {
|
||||
dev_dbg(&pdev->dev, "Using default 8 bytes %d", node_info->id);
|
||||
node_info->agg_params.buswidth = 8;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(dev_node, "qcom,agg-ports",
|
||||
&node_info->agg_params.num_aggports);
|
||||
if (ret)
|
||||
node_info->agg_params.num_aggports = node_info->num_qports;
|
||||
|
||||
ret = of_property_read_u32(dev_node, "qcom,agg-scheme",
|
||||
&node_info->agg_params.agg_scheme);
|
||||
if (ret) {
|
||||
if (node_info->is_fab_dev)
|
||||
node_info->agg_params.agg_scheme = DEFAULT_AGG_SCHEME;
|
||||
else {
|
||||
node_info->agg_params.agg_scheme = AGG_SCHEME_NONE;
|
||||
goto exit_get_agg_params;
|
||||
}
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(dev_node, "qcom,vrail-comp",
|
||||
&node_info->agg_params.vrail_comp);
|
||||
if (ret) {
|
||||
if (node_info->is_fab_dev)
|
||||
node_info->agg_params.vrail_comp = DEFAULT_VRAIL_COMP;
|
||||
else
|
||||
node_info->agg_params.vrail_comp = 0;
|
||||
}
|
||||
|
||||
if (node_info->agg_params.agg_scheme == AGG_SCHEME_LEG) {
|
||||
node_info->agg_params.num_util_levels = 1;
|
||||
node_info->agg_params.util_levels = devm_kzalloc(&pdev->dev,
|
||||
(node_info->agg_params.num_util_levels *
|
||||
sizeof(struct node_util_levels_type)), GFP_KERNEL);
|
||||
if (IS_ERR_OR_NULL(node_info->agg_params.util_levels))
|
||||
goto err_get_agg_params;
|
||||
|
||||
ret = of_property_read_u32(dev_node, "qcom,util-fact",
|
||||
&node_info->agg_params.util_levels[0].util_fact);
|
||||
if (ret) {
|
||||
if (node_info->is_fab_dev)
|
||||
node_info->agg_params.util_levels[0].util_fact
|
||||
= DEFAULT_UTIL_FACT;
|
||||
}
|
||||
} else if (node_info->agg_params.agg_scheme == AGG_SCHEME_1) {
|
||||
uint32_t len = 0;
|
||||
const uint32_t *util_levels;
|
||||
int i, index = 0;
|
||||
|
||||
util_levels =
|
||||
of_get_property(dev_node, "qcom,util-levels", &len);
|
||||
if (!util_levels)
|
||||
goto err_get_agg_params;
|
||||
|
||||
node_info->agg_params.num_util_levels =
|
||||
len / (sizeof(uint32_t) * 2);
|
||||
node_info->agg_params.util_levels = devm_kzalloc(&pdev->dev,
|
||||
(node_info->agg_params.num_util_levels *
|
||||
sizeof(struct node_util_levels_type)), GFP_KERNEL);
|
||||
|
||||
if (IS_ERR_OR_NULL(node_info->agg_params.util_levels))
|
||||
goto err_get_agg_params;
|
||||
|
||||
for (i = 0; i < node_info->agg_params.num_util_levels; i++) {
|
||||
node_info->agg_params.util_levels[i].threshold =
|
||||
KBTOB(be32_to_cpu(util_levels[index++]));
|
||||
node_info->agg_params.util_levels[i].util_fact =
|
||||
be32_to_cpu(util_levels[index++]);
|
||||
dev_dbg(&pdev->dev, "[%d]:Thresh:%llu util_fact:%d\n",
|
||||
i,
|
||||
node_info->agg_params.util_levels[i].threshold,
|
||||
node_info->agg_params.util_levels[i].util_fact);
|
||||
}
|
||||
} else {
|
||||
dev_err(&pdev->dev, "Agg scheme%d unknown, using default\n",
|
||||
node_info->agg_params.agg_scheme);
|
||||
goto err_get_agg_params;
|
||||
}
|
||||
|
||||
exit_get_agg_params:
|
||||
return;
|
||||
err_get_agg_params:
|
||||
node_info->agg_params.agg_scheme = DEFAULT_AGG_SCHEME;
|
||||
}
|
||||
|
||||
static struct msm_bus_node_info_type *get_node_info_data(
|
||||
struct device_node * const dev_node,
|
||||
|
@ -262,11 +401,6 @@ static struct msm_bus_node_info_type *get_node_info_data(
|
|||
node_info->qport = get_arr(pdev, dev_node, "qcom,qport",
|
||||
&node_info->num_qports);
|
||||
|
||||
ret = of_property_read_u32(dev_node, "qcom,agg-ports",
|
||||
&node_info->num_aggports);
|
||||
if (ret)
|
||||
node_info->num_aggports = node_info->num_qports;
|
||||
|
||||
if (of_get_property(dev_node, "qcom,connections", &size)) {
|
||||
node_info->num_connections = size / sizeof(int);
|
||||
node_info->connections = devm_kzalloc(&pdev->dev, size,
|
||||
|
@ -324,12 +458,6 @@ static struct msm_bus_node_info_type *get_node_info_data(
|
|||
node_info->is_fab_dev = of_property_read_bool(dev_node, "qcom,fab-dev");
|
||||
node_info->virt_dev = of_property_read_bool(dev_node, "qcom,virt-dev");
|
||||
|
||||
ret = of_property_read_u32(dev_node, "qcom,buswidth",
|
||||
&node_info->buswidth);
|
||||
if (ret) {
|
||||
dev_dbg(&pdev->dev, "Using default 8 bytes %d", node_info->id);
|
||||
node_info->buswidth = 8;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(dev_node, "qcom,mas-rpm-id",
|
||||
&node_info->mas_rpm_id);
|
||||
|
@ -344,14 +472,8 @@ static struct msm_bus_node_info_type *get_node_info_data(
|
|||
dev_dbg(&pdev->dev, "slv rpm id is missing\n");
|
||||
node_info->slv_rpm_id = -1;
|
||||
}
|
||||
ret = of_property_read_u32(dev_node, "qcom,util-fact",
|
||||
&node_info->util_fact);
|
||||
if (ret)
|
||||
node_info->util_fact = 0;
|
||||
ret = of_property_read_u32(dev_node, "qcom,vrail-comp",
|
||||
&node_info->vrail_comp);
|
||||
if (ret)
|
||||
node_info->vrail_comp = 0;
|
||||
|
||||
get_agg_params(dev_node, pdev, node_info);
|
||||
get_qos_params(dev_node, pdev, node_info);
|
||||
|
||||
return node_info;
|
||||
|
@ -362,11 +484,14 @@ node_info_err:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned int get_bus_node_device_data(
|
||||
static int get_bus_node_device_data(
|
||||
struct device_node * const dev_node,
|
||||
struct platform_device * const pdev,
|
||||
struct msm_bus_node_device_type * const node_device)
|
||||
{
|
||||
bool enable_only;
|
||||
bool setrate_only;
|
||||
|
||||
node_device->node_info = get_node_info_data(dev_node, pdev);
|
||||
if (IS_ERR_OR_NULL(node_device->node_info)) {
|
||||
dev_err(&pdev->dev, "Error: Node info missing\n");
|
||||
|
@ -376,6 +501,7 @@ static unsigned int get_bus_node_device_data(
|
|||
"qcom,ap-owned");
|
||||
|
||||
if (node_device->node_info->is_fab_dev) {
|
||||
struct device_node *qos_clk_node;
|
||||
dev_err(&pdev->dev, "Dev %d\n", node_device->node_info->id);
|
||||
|
||||
if (!node_device->node_info->virt_dev) {
|
||||
|
@ -388,43 +514,132 @@ static unsigned int get_bus_node_device_data(
|
|||
return -ENODATA;
|
||||
}
|
||||
}
|
||||
|
||||
enable_only = of_property_read_bool(dev_node,
|
||||
"qcom,enable-only-clk");
|
||||
node_device->clk[DUAL_CTX].enable_only_clk = enable_only;
|
||||
node_device->clk[ACTIVE_CTX].enable_only_clk = enable_only;
|
||||
|
||||
/*
|
||||
* Doesn't make sense to have a clk handle you can't enable or
|
||||
* set rate on.
|
||||
*/
|
||||
if (!enable_only) {
|
||||
setrate_only = of_property_read_bool(dev_node,
|
||||
"qcom,setrate-only-clk");
|
||||
node_device->clk[DUAL_CTX].setrate_only_clk =
|
||||
setrate_only;
|
||||
node_device->clk[ACTIVE_CTX].setrate_only_clk =
|
||||
setrate_only;
|
||||
}
|
||||
|
||||
node_device->clk[DUAL_CTX].clk = of_clk_get_by_name(dev_node,
|
||||
"bus_clk");
|
||||
|
||||
if (IS_ERR_OR_NULL(node_device->clk[DUAL_CTX].clk))
|
||||
if (IS_ERR_OR_NULL(node_device->clk[DUAL_CTX].clk)) {
|
||||
int ret;
|
||||
dev_err(&pdev->dev,
|
||||
"%s:Failed to get bus clk for bus%d ctx%d",
|
||||
__func__, node_device->node_info->id,
|
||||
DUAL_CTX);
|
||||
ret = (IS_ERR(node_device->clk[DUAL_CTX].clk) ?
|
||||
PTR_ERR(node_device->clk[DUAL_CTX].clk) : -ENXIO);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (of_find_property(dev_node, "bus-gdsc-supply", NULL))
|
||||
scnprintf(node_device->clk[DUAL_CTX].reg_name,
|
||||
MAX_REG_NAME, "%s", "bus-gdsc");
|
||||
else
|
||||
scnprintf(node_device->clk[DUAL_CTX].reg_name,
|
||||
MAX_REG_NAME, "%c", '\0');
|
||||
|
||||
node_device->clk[ACTIVE_CTX].clk = of_clk_get_by_name(dev_node,
|
||||
"bus_a_clk");
|
||||
if (IS_ERR_OR_NULL(node_device->clk[ACTIVE_CTX].clk))
|
||||
if (IS_ERR_OR_NULL(node_device->clk[ACTIVE_CTX].clk)) {
|
||||
int ret;
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to get bus clk for bus%d ctx%d",
|
||||
node_device->node_info->id, ACTIVE_CTX);
|
||||
ret = (IS_ERR(node_device->clk[DUAL_CTX].clk) ?
|
||||
PTR_ERR(node_device->clk[DUAL_CTX].clk) : -ENXIO);
|
||||
return ret;
|
||||
}
|
||||
|
||||
node_device->qos_clk.clk = of_clk_get_by_name(dev_node,
|
||||
if (of_find_property(dev_node, "bus-a-gdsc-supply", NULL))
|
||||
scnprintf(node_device->clk[ACTIVE_CTX].reg_name,
|
||||
MAX_REG_NAME, "%s", "bus-a-gdsc");
|
||||
else
|
||||
scnprintf(node_device->clk[ACTIVE_CTX].reg_name,
|
||||
MAX_REG_NAME, "%c", '\0');
|
||||
|
||||
node_device->bus_qos_clk.clk = of_clk_get_by_name(dev_node,
|
||||
"bus_qos_clk");
|
||||
|
||||
if (IS_ERR_OR_NULL(node_device->qos_clk.clk))
|
||||
if (IS_ERR_OR_NULL(node_device->bus_qos_clk.clk)) {
|
||||
dev_dbg(&pdev->dev,
|
||||
"%s:Failed to get bus qos clk for %d",
|
||||
__func__, node_device->node_info->id);
|
||||
scnprintf(node_device->bus_qos_clk.reg_name,
|
||||
MAX_REG_NAME, "%c", '\0');
|
||||
} else {
|
||||
if (of_find_property(dev_node, "bus-qos-gdsc-supply",
|
||||
NULL))
|
||||
scnprintf(node_device->bus_qos_clk.reg_name,
|
||||
MAX_REG_NAME, "%s", "bus-qos-gdsc");
|
||||
else
|
||||
scnprintf(node_device->bus_qos_clk.reg_name,
|
||||
MAX_REG_NAME, "%c", '\0');
|
||||
}
|
||||
|
||||
qos_clk_node = of_find_node_by_name(dev_node,
|
||||
"qcom,node-qos-clks");
|
||||
|
||||
if (qos_clk_node)
|
||||
msm_bus_of_parse_clk_array(qos_clk_node, dev_node, pdev,
|
||||
&node_device->node_qos_clks,
|
||||
&node_device->num_node_qos_clks,
|
||||
node_device->node_info->id);
|
||||
|
||||
if (msmbus_coresight_init_adhoc(pdev, dev_node))
|
||||
dev_warn(&pdev->dev,
|
||||
"Coresight support absent for bus: %d\n",
|
||||
node_device->node_info->id);
|
||||
} else {
|
||||
node_device->qos_clk.clk = of_clk_get_by_name(dev_node,
|
||||
node_device->bus_qos_clk.clk = of_clk_get_by_name(dev_node,
|
||||
"bus_qos_clk");
|
||||
|
||||
if (IS_ERR_OR_NULL(node_device->qos_clk.clk))
|
||||
if (IS_ERR_OR_NULL(node_device->bus_qos_clk.clk))
|
||||
dev_dbg(&pdev->dev,
|
||||
"%s:Failed to get bus qos clk for mas%d",
|
||||
__func__, node_device->node_info->id);
|
||||
|
||||
if (of_find_property(dev_node, "bus-qos-gdsc-supply",
|
||||
NULL))
|
||||
scnprintf(node_device->bus_qos_clk.reg_name,
|
||||
MAX_REG_NAME, "%s", "bus-qos-gdsc");
|
||||
else
|
||||
scnprintf(node_device->bus_qos_clk.reg_name,
|
||||
MAX_REG_NAME, "%c", '\0');
|
||||
|
||||
enable_only = of_property_read_bool(dev_node,
|
||||
"qcom,enable-only-clk");
|
||||
node_device->clk[DUAL_CTX].enable_only_clk = enable_only;
|
||||
node_device->bus_qos_clk.enable_only_clk = enable_only;
|
||||
|
||||
/*
|
||||
* Doesn't make sense to have a clk handle you can't enable or
|
||||
* set rate on.
|
||||
*/
|
||||
if (!enable_only) {
|
||||
setrate_only = of_property_read_bool(dev_node,
|
||||
"qcom,setrate-only-clk");
|
||||
node_device->clk[DUAL_CTX].setrate_only_clk =
|
||||
setrate_only;
|
||||
node_device->clk[ACTIVE_CTX].setrate_only_clk =
|
||||
setrate_only;
|
||||
}
|
||||
|
||||
node_device->clk[DUAL_CTX].clk = of_clk_get_by_name(dev_node,
|
||||
"node_clk");
|
||||
|
||||
|
@ -434,6 +649,13 @@ static unsigned int get_bus_node_device_data(
|
|||
__func__, node_device->node_info->id,
|
||||
DUAL_CTX);
|
||||
|
||||
if (of_find_property(dev_node, "node-gdsc-supply", NULL))
|
||||
scnprintf(node_device->clk[DUAL_CTX].reg_name,
|
||||
MAX_REG_NAME, "%s", "node-gdsc");
|
||||
else
|
||||
scnprintf(node_device->clk[DUAL_CTX].reg_name,
|
||||
MAX_REG_NAME, "%c", '\0');
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -482,6 +704,7 @@ struct msm_bus_device_node_registration
|
|||
dev_err(&pdev->dev, "Error: unable to initialize bus nodes\n");
|
||||
goto node_reg_err_1;
|
||||
}
|
||||
pdata->info[i].of_node = child_node;
|
||||
i++;
|
||||
}
|
||||
|
||||
|
@ -493,7 +716,7 @@ struct msm_bus_device_node_registration
|
|||
pdata->info[i].node_info->num_connections);
|
||||
dev_dbg(&pdev->dev, "\nbus_device_id %d\n buswidth %d\n",
|
||||
pdata->info[i].node_info->bus_device_id,
|
||||
pdata->info[i].node_info->buswidth);
|
||||
pdata->info[i].node_info->agg_params.buswidth);
|
||||
for (j = 0; j < pdata->info[i].node_info->num_connections;
|
||||
j++) {
|
||||
dev_dbg(&pdev->dev, "connection[%d]: %d\n", j,
|
||||
|
|
|
@ -13,6 +13,11 @@
|
|||
#ifndef __MSM_BUS_IDS_H
|
||||
#define __MSM_BUS_IDS_H
|
||||
|
||||
/* Aggregation types */
|
||||
#define AGG_SCHEME_NONE 0
|
||||
#define AGG_SCHEME_LEG 1
|
||||
#define AGG_SCHEME_1 2
|
||||
|
||||
/* Topology related enums */
|
||||
#define MSM_BUS_FAB_DEFAULT 0
|
||||
#define MSM_BUS_FAB_APPSS 0
|
||||
|
|
|
@ -71,8 +71,11 @@ struct msm_bus_client_handle {
|
|||
int mas;
|
||||
int slv;
|
||||
int first_hop;
|
||||
u64 cur_ib;
|
||||
u64 cur_ab;
|
||||
struct device *mas_dev;
|
||||
u64 cur_act_ib;
|
||||
u64 cur_act_ab;
|
||||
u64 cur_slp_ib;
|
||||
u64 cur_slp_ab;
|
||||
bool active_only;
|
||||
};
|
||||
|
||||
|
@ -89,12 +92,16 @@ int __init msm_bus_fabric_init_driver(void);
|
|||
uint32_t msm_bus_scale_register_client(struct msm_bus_scale_pdata *pdata);
|
||||
int msm_bus_scale_client_update_request(uint32_t cl, unsigned int index);
|
||||
void msm_bus_scale_unregister_client(uint32_t cl);
|
||||
int msm_bus_scale_client_update_context(uint32_t cl, bool active_only,
|
||||
unsigned int ctx_idx);
|
||||
|
||||
struct msm_bus_client_handle*
|
||||
msm_bus_scale_register(uint32_t mas, uint32_t slv, char *name,
|
||||
bool active_only);
|
||||
void msm_bus_scale_unregister(struct msm_bus_client_handle *cl);
|
||||
int msm_bus_scale_update_bw(struct msm_bus_client_handle *cl, u64 ab, u64 ib);
|
||||
int msm_bus_scale_update_bw_context(struct msm_bus_client_handle *cl,
|
||||
u64 act_ab, u64 act_ib, u64 slp_ib, u64 slp_ab);
|
||||
/* AXI Port configuration APIs */
|
||||
int msm_bus_axi_porthalt(int master_port);
|
||||
int msm_bus_axi_portunhalt(int master_port);
|
||||
|
@ -115,6 +122,13 @@ msm_bus_scale_client_update_request(uint32_t cl, unsigned int index)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
msm_bus_scale_client_update_context(uint32_t cl, bool active_only,
|
||||
unsigned int ctx_idx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
msm_bus_scale_unregister_client(uint32_t cl)
|
||||
{
|
||||
|
@ -147,6 +161,14 @@ msm_bus_scale_update_bw(struct msm_bus_client_handle *cl, u64 ab, u64 ib)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
msm_bus_scale_update_bw_context(struct msm_bus_client_handle *cl, u64 act_ab,
|
||||
u64 act_ib, u64 slp_ib, u64 slp_ab)
|
||||
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_OF) && defined(CONFIG_MSM_BUS_SCALING)
|
||||
|
|
|
@ -25,6 +25,7 @@ struct rule_update_path_info {
|
|||
u64 ab;
|
||||
u64 ib;
|
||||
u64 clk;
|
||||
bool added;
|
||||
struct list_head link;
|
||||
};
|
||||
|
||||
|
|
|
@ -170,6 +170,40 @@ TRACE_EVENT(bus_bke_params,
|
|||
__entry->gc, __entry->gp, __entry->thl, __entry->thm,
|
||||
__entry->thh)
|
||||
);
|
||||
|
||||
TRACE_EVENT(bus_client_status,
|
||||
|
||||
TP_PROTO(const char *name, int src, int dest,
|
||||
unsigned long long ab, unsigned long long ib, int active_only),
|
||||
|
||||
TP_ARGS(name, src, dest, ab, ib, active_only),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(name, name)
|
||||
__field(int, src)
|
||||
__field(int, dest)
|
||||
__field(u64, ab)
|
||||
__field(u64, ib)
|
||||
__field(int, active_only)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(name, name);
|
||||
__entry->src = src;
|
||||
__entry->dest = dest;
|
||||
__entry->ab = ab;
|
||||
__entry->ib = ib;
|
||||
__entry->active_only = active_only;
|
||||
),
|
||||
|
||||
TP_printk("name=%s src=%d dest=%d ab=%llu ib=%llu active_only=%d",
|
||||
__get_str(name),
|
||||
__entry->src,
|
||||
__entry->dest,
|
||||
(unsigned long long)__entry->ab,
|
||||
(unsigned long long)__entry->ib,
|
||||
__entry->active_only)
|
||||
);
|
||||
#endif
|
||||
#define TRACE_INCLUDE_FILE trace_msm_bus
|
||||
#include <trace/define_trace.h>
|
||||
|
|
Loading…
Reference in New Issue