Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions arch/arm64/boot/dts/qcom/sdm630.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,23 @@
};
};

ipa: ipa@14780000 {
compatible = "qcom,ipa-lite-v2.6";
reg = <0x14780000 0x47000>;
clocks = <&rpmcc RPM_SMD_IPA_CLK>;
interrupts = <GIC_SPI 333 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 432 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "ipa", "dma";
interconnects = <&a2noc MASTER_IPA &bimc SLAVE_EBI>,
<&a2noc MASTER_IPA &snoc SLAVE_IMEM>,
<&gnoc MASTER_APSS_PROC &snoc SLAVE_IPA>;
interconnect-names = "ipa-mem", "ipa-imem", "cpu-cfg";
iommus = <&anoc2_smmu 0x19C0>,
<&anoc2_smmu 0x19C2>;
modem-remoteproc = <&remoteproc_mss>;
status = "okay";
};

remoteproc_mss: remoteproc@4080000 {
compatible = "qcom,sdm660-mss-pil";
reg = <0x04080000 0x100>, <0x04180000 0x40>;
Expand Down
3 changes: 2 additions & 1 deletion arch/arm64/configs/sdm660_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,8 @@ CONFIG_RMNET=m
# CONFIG_NET_VENDOR_WANGXUN is not set
# CONFIG_NET_VENDOR_WIZNET is not set
# CONFIG_NET_VENDOR_XILINX is not set
CONFIG_QCOM_IPA=m
CONFIG_QCOM_IPA=n
CONFIG_QCOM_IPA2_LITE=m
CONFIG_PPP=m
CONFIG_PPP_BSDCOMP=m
CONFIG_PPP_DEFLATE=m
Expand Down
20 changes: 20 additions & 0 deletions drivers/clk/clk.c
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,26 @@ void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate,
}
EXPORT_SYMBOL_GPL(clk_hw_set_rate_range);

/*
* Aggregate the rate of all the enabled child nodes and exclude that
* of the child node for which this request was made.
*/
unsigned long clk_aggregate_rate(struct clk_hw *hw,
const struct clk_core *parent)
{
struct clk_core *child;
unsigned long aggre_rate = 0;

hlist_for_each_entry(child, &parent->children, child_node) {
if (child->enable_count &&
strcmp(child->name, hw->init->name))
aggre_rate = max(child->rate, aggre_rate);
}

return aggre_rate;
}
EXPORT_SYMBOL_GPL(clk_aggregate_rate);

/*
* __clk_mux_determine_rate - clk_ops::determine_rate implementation for a mux type clk
* @hw: mux type clk to determine rate on
Expand Down
2 changes: 1 addition & 1 deletion drivers/clk/qcom/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ clk-qcom-y += clk-regmap-mux-div.o
clk-qcom-y += clk-regmap-phy-mux.o
clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o
clk-qcom-y += clk-hfpll.o
clk-qcom-y += reset.o
clk-qcom-y += reset.o clk-voter.o
clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o

# Keep alphabetically sorted by config
Expand Down
2 changes: 2 additions & 0 deletions drivers/clk/qcom/clk-smd-rpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include <linux/platform_device.h>
#include <linux/soc/qcom/smd-rpm.h>

#include "clk-voter.h"

#include <dt-bindings/clock/qcom,rpmcc.h>

#define __DEFINE_CLK_SMD_RPM_PREFIX(_prefix, _name, _active, \
Expand Down
146 changes: 146 additions & 0 deletions drivers/clk/qcom/clk-voter.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2017, 2019, The Linux Foundation. All rights reserved.
*/

#include <linux/clk.h>

#include "clk-voter.h"

static int voter_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
int ret = 0;
struct clk_voter *v = to_clk_voter(hw);
unsigned long cur_rate, new_rate, other_rate = 0;

if (v->is_branch)
return ret;

if (v->enabled) {
struct clk_hw *parent = clk_hw_get_parent(hw);

if (!parent)
return -EINVAL;

/*
* Get the aggregate rate without this clock's vote and update
* if the new rate is different than the current rate.
*/
other_rate = clk_aggregate_rate(hw, parent->core);

cur_rate = max(other_rate, clk_get_rate(hw->clk));
new_rate = max(other_rate, rate);

if (new_rate != cur_rate) {
ret = clk_set_rate(parent->clk, new_rate);
if (ret)
return ret;
}
}
v->rate = rate;

return ret;
}

static int voter_clk_prepare(struct clk_hw *hw)
{
int ret = 0;
unsigned long cur_rate;
struct clk_hw *parent;
struct clk_voter *v = to_clk_voter(hw);

parent = clk_hw_get_parent(hw);
if (!parent)
return -EINVAL;

if (v->is_branch) {
v->enabled = true;
return ret;
}

/*
* Increase the rate if this clock is voting for a higher rate
* than the current rate.
*/
cur_rate = clk_aggregate_rate(hw, parent->core);

if (v->rate > cur_rate) {
ret = clk_set_rate(parent->clk, v->rate);
if (ret)
return ret;
}
v->enabled = true;

return ret;
}

static void voter_clk_unprepare(struct clk_hw *hw)
{
unsigned long cur_rate, new_rate;
struct clk_hw *parent;
struct clk_voter *v = to_clk_voter(hw);


parent = clk_hw_get_parent(hw);
if (!parent)
return;
/*
* Decrease the rate if this clock was the only one voting for
* the highest rate.
*/
v->enabled = false;
if (v->is_branch)
return;

new_rate = clk_aggregate_rate(hw, parent->core);
cur_rate = max(new_rate, v->rate);

if (new_rate < cur_rate)
clk_set_rate(parent->clk, new_rate);
}

static int voter_clk_is_enabled(struct clk_hw *hw)
{
struct clk_voter *v = to_clk_voter(hw);

return v->enabled;
}

static long voter_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
struct clk_hw *parent_hw = clk_hw_get_parent(hw);

if (!parent_hw)
return -EINVAL;

return clk_hw_round_rate(parent_hw, rate);
}

static unsigned long voter_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_voter *v = to_clk_voter(hw);

return v->rate;
}

int voter_clk_handoff(struct clk_hw *hw)
{
struct clk_voter *v = to_clk_voter(hw);

v->enabled = true;

return 0;
}
EXPORT_SYMBOL(voter_clk_handoff);

const struct clk_ops clk_ops_voter = {
.prepare = voter_clk_prepare,
.unprepare = voter_clk_unprepare,
.set_rate = voter_clk_set_rate,
.is_enabled = voter_clk_is_enabled,
.round_rate = voter_clk_round_rate,
.recalc_rate = voter_clk_recalc_rate,
};
43 changes: 43 additions & 0 deletions drivers/clk/qcom/clk-voter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2017, 2019, The Linux Foundation. All rights reserved.
*/

#ifndef __QCOM_CLK_VOTER_H__
#define __QCOM_CLK_VOTER_H__

#include <linux/clk-provider.h>
#include <linux/platform_device.h>

struct clk_voter {
int is_branch;
bool enabled;
struct clk_hw hw;
unsigned long rate;
};

extern const struct clk_ops clk_ops_voter;

#define to_clk_voter(_hw) container_of(_hw, struct clk_voter, hw)

#define __DEFINE_CLK_VOTER(clk_name, _parent_name, _default_rate, _is_branch) \
struct clk_voter clk_name = { \
.is_branch = (_is_branch), \
.rate = _default_rate, \
.hw.init = &(struct clk_init_data){ \
.ops = &clk_ops_voter, \
.name = #clk_name, \
.parent_names = (const char *[]){ #_parent_name }, \
.num_parents = 1, \
}, \
}

#define DEFINE_CLK_VOTER(clk_name, _parent_name, _default_rate) \
__DEFINE_CLK_VOTER(clk_name, _parent_name, _default_rate, 0)

#define DEFINE_CLK_BRANCH_VOTER(clk_name, _parent_name) \
__DEFINE_CLK_VOTER(clk_name, _parent_name, 1000, 1)

int voter_clk_handoff(struct clk_hw *hw);

#endif
2 changes: 2 additions & 0 deletions drivers/net/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,8 @@ source "drivers/net/hippi/Kconfig"

source "drivers/net/ipa/Kconfig"

source "drivers/net/ipa2-lite/Kconfig"

source "drivers/net/phy/Kconfig"

source "drivers/net/pse-pd/Kconfig"
Expand Down
1 change: 1 addition & 0 deletions drivers/net/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ obj-$(CONFIG_FDDI) += fddi/
obj-$(CONFIG_HIPPI) += hippi/
obj-$(CONFIG_HAMRADIO) += hamradio/
obj-$(CONFIG_QCOM_IPA) += ipa/
obj-$(CONFIG_QCOM_IPA2_LITE) += ipa2-lite/
obj-$(CONFIG_PLIP) += plip/
obj-$(CONFIG_PPP) += ppp/
obj-$(CONFIG_PPP_ASYNC) += ppp/
Expand Down
17 changes: 17 additions & 0 deletions drivers/net/ipa2-lite/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
config QCOM_IPA2_LITE
tristate "Qualcomm IPA 2.X support"
depends on NET
depends on ARCH_QCOM || COMPILE_TEST
depends on QCOM_RPROC_COMMON || (QCOM_RPROC_COMMON=n && COMPILE_TEST)
select QCOM_QMI_HELPERS
help
Choose Y or M here to include support for the Qualcomm
IP Abductor (IPA), a hardware block present in some
Qualcomm SoCs. The IPA is a programmable protocol processor
that is capable abducting your IP packets or annihilating
the system if it's not pleased.

Note that if selected, the selection type must match that
of QCOM_Q6V5_COMMON (Y or M).

If unsure, say N.
3 changes: 3 additions & 0 deletions drivers/net/ipa2-lite/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
obj-$(CONFIG_QCOM_IPA2_LITE) += ipa2-lite.o

ipa2-lite-y := ipa.o ipa-qmi.o
Loading
Loading