aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinaro CI <ci_notify@linaro.org>2022-02-08 18:13:51 +0000
committerLinaro CI <ci_notify@linaro.org>2022-02-08 18:13:51 +0000
commite25e36bf6d19526b522d9574e2a845c9b42bd99c (patch)
treebf38a6a4ed28067211bde7ff6ffcaf79ec0c8281
parentca074ccfa44fade2d74512a396863c29cc69c130 (diff)
parent8b4561ee07948f9342e3586efad1a4bd59477537 (diff)
Merge remote-tracking branch 'sm8450-drivers/tracking-qcomlt-sm8450-drivers' into integration-linux-qcomlt
-rw-r--r--Documentation/devicetree/bindings/pci/qcom,pcie.txt22
-rw-r--r--drivers/base/arch_topology.c3
-rw-r--r--drivers/cpufreq/qcom-cpufreq-hw.c2
-rw-r--r--drivers/pci/controller/dwc/pcie-qcom.c227
-rw-r--r--drivers/spmi/spmi-pmic-arb.c233
-rw-r--r--drivers/thermal/qcom/tsens.c5
6 files changed, 341 insertions, 151 deletions
diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.txt b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
index a0ae024c2d0c..0adb56d5645e 100644
--- a/Documentation/devicetree/bindings/pci/qcom,pcie.txt
+++ b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
@@ -15,6 +15,8 @@
- "qcom,pcie-sc8180x" for sc8180x
- "qcom,pcie-sdm845" for sdm845
- "qcom,pcie-sm8250" for sm8250
+ - "qcom,pcie-sm8450-pcie0" for PCIe0 on sm8450
+ - "qcom,pcie-sm8450-pcie1" for PCIe1 on sm8450
- "qcom,pcie-ipq6018" for ipq6018
- reg:
@@ -169,6 +171,24 @@
- "ddrss_sf_tbu" PCIe SF TBU clock
- "pipe" PIPE clock
+- clock-names:
+ Usage: required for sm8450-pcie0 and sm8450-pcie1
+ Value type: <stringlist>
+ Definition: Should contain the following entries
+ - "aux" Auxiliary clock
+ - "cfg" Configuration clock
+ - "bus_master" Master AXI clock
+ - "bus_slave" Slave AXI clock
+ - "slave_q2a" Slave Q2A clock
+ - "tbu" PCIe TBU clock
+ - "ddrss_sf_tbu" PCIe SF TBU clock
+ - "pipe" PIPE clock
+ - "pipe_mux" PIPE MUX
+ - "phy_pipe" PIPE output clock
+ - "ref" REFERENCE clock
+ - "aggre0" Aggre NoC PCIe0 AXI clock, only for sm8450-pcie0
+ - "aggre1" Aggre NoC PCIe1 AXI clock
+
- resets:
Usage: required
Value type: <prop-encoded-array>
@@ -246,7 +266,7 @@
- "ahb" AHB reset
- reset-names:
- Usage: required for sc8180x, sdm845 and sm8250
+ Usage: required for sc8180x, sdm845, sm8250 and sm8450
Value type: <stringlist>
Definition: Should contain the following entries
- "pci" PCIe core reset
diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index 976154140f0b..6560a0c3b969 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -177,6 +177,9 @@ void topology_update_thermal_pressure(const struct cpumask *cpus,
u32 max_freq;
int cpu;
+ if (WARN_ON(cpumask_empty(cpus)))
+ return;
+
cpu = cpumask_first(cpus);
max_capacity = arch_scale_cpu_capacity(cpu);
max_freq = per_cpu(freq_factor, cpu);
diff --git a/drivers/cpufreq/qcom-cpufreq-hw.c b/drivers/cpufreq/qcom-cpufreq-hw.c
index 05f3d7876e44..866fba3ac6fc 100644
--- a/drivers/cpufreq/qcom-cpufreq-hw.c
+++ b/drivers/cpufreq/qcom-cpufreq-hw.c
@@ -297,7 +297,7 @@ static void qcom_lmh_dcvs_notify(struct qcom_cpufreq_data *data)
throttled_freq = freq_hz / HZ_PER_KHZ;
/* Update thermal pressure (the boost frequencies are accepted) */
- arch_update_thermal_pressure(policy->related_cpus, throttled_freq);
+ arch_update_thermal_pressure(policy->cpus, throttled_freq);
/*
* In the unlikely case policy is unregistered do not enable
diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
index 03e766f6937e..0f6ba725962e 100644
--- a/drivers/pci/controller/dwc/pcie-qcom.c
+++ b/drivers/pci/controller/dwc/pcie-qcom.c
@@ -12,6 +12,7 @@
#include <linux/crc8.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
+#include <linux/interconnect.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
@@ -128,7 +129,6 @@ struct qcom_pcie_resources_2_3_2 {
struct clk *master_clk;
struct clk *slave_clk;
struct clk *cfg_clk;
- struct clk *pipe_clk;
struct regulator_bulk_data supplies[QCOM_PCIE_2_3_2_MAX_SUPPLY];
};
@@ -161,14 +161,14 @@ struct qcom_pcie_resources_2_3_3 {
/* 6 clocks typically, 7 for sm8250 */
struct qcom_pcie_resources_2_7_0 {
- struct clk_bulk_data clks[7];
+ struct clk_bulk_data clks[9];
int num_clks;
struct regulator_bulk_data supplies[2];
struct reset_control *pci_reset;
- struct clk *pipe_clk;
struct clk *pipe_clk_src;
struct clk *phy_pipe_clk;
struct clk *ref_clk_src;
+ struct icc_path *path;
};
union qcom_pcie_resources {
@@ -185,9 +185,7 @@ struct qcom_pcie;
struct qcom_pcie_ops {
int (*get_resources)(struct qcom_pcie *pcie);
int (*init)(struct qcom_pcie *pcie);
- int (*post_init)(struct qcom_pcie *pcie);
void (*deinit)(struct qcom_pcie *pcie);
- void (*post_deinit)(struct qcom_pcie *pcie);
void (*ltssm_enable)(struct qcom_pcie *pcie);
int (*config_sid)(struct qcom_pcie *pcie);
};
@@ -195,6 +193,10 @@ struct qcom_pcie_ops {
struct qcom_pcie_cfg {
const struct qcom_pcie_ops *ops;
unsigned int pipe_clk_need_muxing:1;
+ unsigned int has_tbu_clk:1;
+ unsigned int has_ddrss_sf_tbu_clk:1;
+ unsigned int has_aggre0_clk:1;
+ unsigned int has_aggre1_clk:1;
};
struct qcom_pcie {
@@ -204,8 +206,7 @@ struct qcom_pcie {
union qcom_pcie_resources res;
struct phy *phy;
struct gpio_desc *reset;
- const struct qcom_pcie_ops *ops;
- unsigned int pipe_clk_need_muxing:1;
+ const struct qcom_pcie_cfg *cfg;
};
#define to_qcom_pcie(x) dev_get_drvdata((x)->dev)
@@ -229,8 +230,8 @@ static int qcom_pcie_start_link(struct dw_pcie *pci)
struct qcom_pcie *pcie = to_qcom_pcie(pci);
/* Enable Link Training state machine */
- if (pcie->ops->ltssm_enable)
- pcie->ops->ltssm_enable(pcie);
+ if (pcie->cfg->ops->ltssm_enable)
+ pcie->cfg->ops->ltssm_enable(pcie);
return 0;
}
@@ -591,11 +592,7 @@ static int qcom_pcie_get_resources_2_3_2(struct qcom_pcie *pcie)
return PTR_ERR(res->master_clk);
res->slave_clk = devm_clk_get(dev, "bus_slave");
- if (IS_ERR(res->slave_clk))
- return PTR_ERR(res->slave_clk);
-
- res->pipe_clk = devm_clk_get(dev, "pipe");
- return PTR_ERR_OR_ZERO(res->pipe_clk);
+ return PTR_ERR_OR_ZERO(res->slave_clk);
}
static void qcom_pcie_deinit_2_3_2(struct qcom_pcie *pcie)
@@ -610,13 +607,6 @@ static void qcom_pcie_deinit_2_3_2(struct qcom_pcie *pcie)
regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
}
-static void qcom_pcie_post_deinit_2_3_2(struct qcom_pcie *pcie)
-{
- struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
-
- clk_disable_unprepare(res->pipe_clk);
-}
-
static int qcom_pcie_init_2_3_2(struct qcom_pcie *pcie)
{
struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
@@ -691,22 +681,6 @@ err_aux_clk:
return ret;
}
-static int qcom_pcie_post_init_2_3_2(struct qcom_pcie *pcie)
-{
- struct qcom_pcie_resources_2_3_2 *res = &pcie->res.v2_3_2;
- struct dw_pcie *pci = pcie->pci;
- struct device *dev = pci->dev;
- int ret;
-
- ret = clk_prepare_enable(res->pipe_clk);
- if (ret) {
- dev_err(dev, "cannot prepare/enable pipe clock\n");
- return ret;
- }
-
- return 0;
-}
-
static int qcom_pcie_get_resources_2_4_0(struct qcom_pcie *pcie)
{
struct qcom_pcie_resources_2_4_0 *res = &pcie->res.v2_4_0;
@@ -1146,12 +1120,17 @@ static int qcom_pcie_get_resources_2_7_0(struct qcom_pcie *pcie)
struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
struct dw_pcie *pci = pcie->pci;
struct device *dev = pci->dev;
+ unsigned int idx;
int ret;
res->pci_reset = devm_reset_control_get_exclusive(dev, "pci");
if (IS_ERR(res->pci_reset))
return PTR_ERR(res->pci_reset);
+ res->path = devm_of_icc_get(dev, "pci");
+ if (IS_ERR(res->path))
+ return PTR_ERR(res->path);
+
res->supplies[0].supply = "vdda";
res->supplies[1].supply = "vddpe-3v3";
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(res->supplies),
@@ -1159,24 +1138,28 @@ static int qcom_pcie_get_resources_2_7_0(struct qcom_pcie *pcie)
if (ret)
return ret;
- res->clks[0].id = "aux";
- res->clks[1].id = "cfg";
- res->clks[2].id = "bus_master";
- res->clks[3].id = "bus_slave";
- res->clks[4].id = "slave_q2a";
- res->clks[5].id = "tbu";
- if (of_device_is_compatible(dev->of_node, "qcom,pcie-sm8250")) {
- res->clks[6].id = "ddrss_sf_tbu";
- res->num_clks = 7;
- } else {
- res->num_clks = 6;
- }
+ idx = 0;
+ res->clks[idx++].id = "aux";
+ res->clks[idx++].id = "cfg";
+ res->clks[idx++].id = "bus_master";
+ res->clks[idx++].id = "bus_slave";
+ res->clks[idx++].id = "slave_q2a";
+ if (pcie->cfg->has_tbu_clk)
+ res->clks[idx++].id = "tbu";
+ if (pcie->cfg->has_ddrss_sf_tbu_clk)
+ res->clks[idx++].id = "ddrss_sf_tbu";
+ if (pcie->cfg->has_aggre0_clk)
+ res->clks[idx++].id = "aggre0";
+ if (pcie->cfg->has_aggre1_clk)
+ res->clks[idx++].id = "aggre1";
+
+ res->num_clks = idx;
ret = devm_clk_bulk_get(dev, res->num_clks, res->clks);
if (ret < 0)
return ret;
- if (pcie->pipe_clk_need_muxing) {
+ if (pcie->cfg->pipe_clk_need_muxing) {
res->pipe_clk_src = devm_clk_get(dev, "pipe_mux");
if (IS_ERR(res->pipe_clk_src))
return PTR_ERR(res->pipe_clk_src);
@@ -1188,10 +1171,12 @@ static int qcom_pcie_get_resources_2_7_0(struct qcom_pcie *pcie)
res->ref_clk_src = devm_clk_get(dev, "ref");
if (IS_ERR(res->ref_clk_src))
return PTR_ERR(res->ref_clk_src);
+
+ /* Ensure that the TCXO is a clock source for pcie_pipe_clk_src */
+ clk_set_parent(res->pipe_clk_src, res->ref_clk_src);
}
- res->pipe_clk = devm_clk_get(dev, "pipe");
- return PTR_ERR_OR_ZERO(res->pipe_clk);
+ return 0;
}
static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie)
@@ -1208,9 +1193,12 @@ static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie)
return ret;
}
- /* Set TCXO as clock source for pcie_pipe_clk_src */
- if (pcie->pipe_clk_need_muxing)
- clk_set_parent(res->pipe_clk_src, res->ref_clk_src);
+ /* Set pipe clock as clock source for pcie_pipe_clk_src */
+ if (pcie->cfg->pipe_clk_need_muxing)
+ clk_set_parent(res->pipe_clk_src, res->phy_pipe_clk);
+
+ if (res->path)
+ icc_set_bw(res->path, 500, 800);
ret = clk_bulk_prepare_enable(res->num_clks, res->clks);
if (ret < 0)
@@ -1230,11 +1218,8 @@ static int qcom_pcie_init_2_7_0(struct qcom_pcie *pcie)
goto err_disable_clocks;
}
- ret = clk_prepare_enable(res->pipe_clk);
- if (ret) {
- dev_err(dev, "cannot prepare/enable pipe clock\n");
- goto err_disable_clocks;
- }
+ /* Wait for reset to complete, required on SM8450 */
+ usleep_range(1000, 1500);
/* configure PCIe to RC mode */
writel(DEVICE_TYPE_RC, pcie->parf + PCIE20_PARF_DEVICE_TYPE);
@@ -1276,25 +1261,14 @@ static void qcom_pcie_deinit_2_7_0(struct qcom_pcie *pcie)
struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
clk_bulk_disable_unprepare(res->num_clks, res->clks);
- regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
-}
-
-static int qcom_pcie_post_init_2_7_0(struct qcom_pcie *pcie)
-{
- struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
-
- /* Set pipe clock as clock source for pcie_pipe_clk_src */
- if (pcie->pipe_clk_need_muxing)
- clk_set_parent(res->pipe_clk_src, res->phy_pipe_clk);
-
- return clk_prepare_enable(res->pipe_clk);
-}
+ if (res->path)
+ icc_set_bw(res->path, 0, 0);
-static void qcom_pcie_post_deinit_2_7_0(struct qcom_pcie *pcie)
-{
- struct qcom_pcie_resources_2_7_0 *res = &pcie->res.v2_7_0;
+ /* Set TCXO as clock source for pcie_pipe_clk_src */
+ if (pcie->cfg->pipe_clk_need_muxing)
+ clk_set_parent(res->pipe_clk_src, res->ref_clk_src);
- clk_disable_unprepare(res->pipe_clk);
+ regulator_bulk_disable(ARRAY_SIZE(res->supplies), res->supplies);
}
static int qcom_pcie_link_up(struct dw_pcie *pci)
@@ -1384,7 +1358,7 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
qcom_ep_reset_assert(pcie);
- ret = pcie->ops->init(pcie);
+ ret = pcie->cfg->ops->init(pcie);
if (ret)
return ret;
@@ -1392,16 +1366,10 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
if (ret)
goto err_deinit;
- if (pcie->ops->post_init) {
- ret = pcie->ops->post_init(pcie);
- if (ret)
- goto err_disable_phy;
- }
-
qcom_ep_reset_deassert(pcie);
- if (pcie->ops->config_sid) {
- ret = pcie->ops->config_sid(pcie);
+ if (pcie->cfg->ops->config_sid) {
+ ret = pcie->cfg->ops->config_sid(pcie);
if (ret)
goto err;
}
@@ -1410,12 +1378,9 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
err:
qcom_ep_reset_assert(pcie);
- if (pcie->ops->post_deinit)
- pcie->ops->post_deinit(pcie);
-err_disable_phy:
phy_power_off(pcie->phy);
err_deinit:
- pcie->ops->deinit(pcie);
+ pcie->cfg->ops->deinit(pcie);
return ret;
}
@@ -1444,9 +1409,7 @@ static const struct qcom_pcie_ops ops_1_0_0 = {
static const struct qcom_pcie_ops ops_2_3_2 = {
.get_resources = qcom_pcie_get_resources_2_3_2,
.init = qcom_pcie_init_2_3_2,
- .post_init = qcom_pcie_post_init_2_3_2,
.deinit = qcom_pcie_deinit_2_3_2,
- .post_deinit = qcom_pcie_post_deinit_2_3_2,
.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
};
@@ -1472,8 +1435,6 @@ static const struct qcom_pcie_ops ops_2_7_0 = {
.init = qcom_pcie_init_2_7_0,
.deinit = qcom_pcie_deinit_2_7_0,
.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
- .post_init = qcom_pcie_post_init_2_7_0,
- .post_deinit = qcom_pcie_post_deinit_2_7_0,
};
/* Qcom IP rev.: 1.9.0 */
@@ -1482,8 +1443,6 @@ static const struct qcom_pcie_ops ops_1_9_0 = {
.init = qcom_pcie_init_2_7_0,
.deinit = qcom_pcie_deinit_2_7_0,
.ltssm_enable = qcom_pcie_2_3_2_ltssm_enable,
- .post_init = qcom_pcie_post_init_2_7_0,
- .post_deinit = qcom_pcie_post_deinit_2_7_0,
.config_sid = qcom_pcie_config_sid_sm8250,
};
@@ -1509,14 +1468,33 @@ static const struct qcom_pcie_cfg ipq4019_cfg = {
static const struct qcom_pcie_cfg sdm845_cfg = {
.ops = &ops_2_7_0,
+ .has_tbu_clk = true,
};
static const struct qcom_pcie_cfg sm8250_cfg = {
.ops = &ops_1_9_0,
+ .has_tbu_clk = true,
+ .has_ddrss_sf_tbu_clk = true,
+};
+
+static const struct qcom_pcie_cfg sm8450_pcie0_cfg = {
+ .ops = &ops_1_9_0,
+ .has_ddrss_sf_tbu_clk = true,
+ .pipe_clk_need_muxing = true,
+ .has_aggre0_clk = true,
+ .has_aggre1_clk = true,
+};
+
+static const struct qcom_pcie_cfg sm8450_pcie1_cfg = {
+ .ops = &ops_1_9_0,
+ .has_ddrss_sf_tbu_clk = true,
+ .pipe_clk_need_muxing = true,
+ .has_aggre1_clk = true,
};
static const struct qcom_pcie_cfg sc7280_cfg = {
.ops = &ops_1_9_0,
+ .has_tbu_clk = true,
.pipe_clk_need_muxing = true,
};
@@ -1531,15 +1509,8 @@ static int qcom_pcie_probe(struct platform_device *pdev)
struct pcie_port *pp;
struct dw_pcie *pci;
struct qcom_pcie *pcie;
- const struct qcom_pcie_cfg *pcie_cfg;
int ret;
- pcie_cfg = of_device_get_match_data(dev);
- if (!pcie_cfg || !pcie_cfg->ops) {
- dev_err(dev, "Invalid platform data\n");
- return -EINVAL;
- }
-
pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
if (!pcie)
return -ENOMEM;
@@ -1548,11 +1519,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
if (!pci)
return -ENOMEM;
- pm_runtime_enable(dev);
- ret = pm_runtime_get_sync(dev);
- if (ret < 0)
- goto err_pm_runtime_put;
-
pci->dev = dev;
pci->ops = &dw_pcie_ops;
pp = &pci->pp;
@@ -1560,42 +1526,41 @@ static int qcom_pcie_probe(struct platform_device *pdev)
pcie->pci = pci;
- pcie->ops = pcie_cfg->ops;
- pcie->pipe_clk_need_muxing = pcie_cfg->pipe_clk_need_muxing;
+ pcie->cfg = of_device_get_match_data(dev);
+ if (!pcie->cfg || !pcie->cfg->ops) {
+ dev_err(dev, "Invalid platform data\n");
+ return -EINVAL;
+ }
pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_HIGH);
- if (IS_ERR(pcie->reset)) {
- ret = PTR_ERR(pcie->reset);
- goto err_pm_runtime_put;
- }
+ if (IS_ERR(pcie->reset))
+ return PTR_ERR(pcie->reset);
pcie->parf = devm_platform_ioremap_resource_byname(pdev, "parf");
- if (IS_ERR(pcie->parf)) {
- ret = PTR_ERR(pcie->parf);
- goto err_pm_runtime_put;
- }
+ if (IS_ERR(pcie->parf))
+ return PTR_ERR(pcie->parf);
pcie->elbi = devm_platform_ioremap_resource_byname(pdev, "elbi");
- if (IS_ERR(pcie->elbi)) {
- ret = PTR_ERR(pcie->elbi);
- goto err_pm_runtime_put;
- }
+ if (IS_ERR(pcie->elbi))
+ return PTR_ERR(pcie->elbi);
pcie->phy = devm_phy_optional_get(dev, "pciephy");
- if (IS_ERR(pcie->phy)) {
- ret = PTR_ERR(pcie->phy);
- goto err_pm_runtime_put;
- }
+ if (IS_ERR(pcie->phy))
+ return PTR_ERR(pcie->phy);
- ret = pcie->ops->get_resources(pcie);
+ ret = pcie->cfg->ops->get_resources(pcie);
if (ret)
- goto err_pm_runtime_put;
+ return ret;
+
+ pm_runtime_enable(dev);
+ ret = pm_runtime_resume_and_get(dev);
+ if (ret < 0)
+ goto err_pm_runtime_disable;
pp->ops = &qcom_pcie_dw_ops;
ret = phy_init(pcie->phy);
if (ret) {
- pm_runtime_disable(&pdev->dev);
goto err_pm_runtime_put;
}
@@ -1604,7 +1569,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
ret = dw_pcie_host_init(pp);
if (ret) {
dev_err(dev, "cannot initialize host\n");
- pm_runtime_disable(&pdev->dev);
goto err_pm_runtime_put;
}
@@ -1612,6 +1576,7 @@ static int qcom_pcie_probe(struct platform_device *pdev)
err_pm_runtime_put:
pm_runtime_put(dev);
+err_pm_runtime_disable:
pm_runtime_disable(dev);
return ret;
@@ -1629,6 +1594,8 @@ static const struct of_device_id qcom_pcie_match[] = {
{ .compatible = "qcom,pcie-sdm845", .data = &sdm845_cfg },
{ .compatible = "qcom,pcie-sm8250", .data = &sm8250_cfg },
{ .compatible = "qcom,pcie-sc8180x", .data = &sm8250_cfg },
+ { .compatible = "qcom,pcie-sm8450-pcie0", .data = &sm8450_pcie0_cfg },
+ { .compatible = "qcom,pcie-sm8450-pcie1", .data = &sm8450_pcie1_cfg },
{ .compatible = "qcom,pcie-sc7280", .data = &sc7280_cfg },
{ }
};
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index 2113be40b5a9..f4d54e7785a8 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -22,8 +22,14 @@
#define PMIC_ARB_VERSION_V2_MIN 0x20010000
#define PMIC_ARB_VERSION_V3_MIN 0x30000000
#define PMIC_ARB_VERSION_V5_MIN 0x50000000
+#define PMIC_ARB_VERSION_V7_MIN 0x70000000
#define PMIC_ARB_INT_EN 0x0004
+#define PMIC_ARB_FEATURES 0x0004
+#define PMIC_ARB_FEATURES_PERIPH_MASK GENMASK(10, 0)
+
+#define PMIC_ARB_FEATURES1 0x0008
+
/* PMIC Arbiter channel registers offsets */
#define PMIC_ARB_CMD 0x00
#define PMIC_ARB_CONFIG 0x04
@@ -48,7 +54,6 @@
#define INVALID_EE 0xFF
/* Ownership Table */
-#define SPMI_OWNERSHIP_TABLE_REG(N) (0x0700 + (4 * (N)))
#define SPMI_OWNERSHIP_PERIPH2OWNER(X) ((X) & 0x7)
/* Channel Status fields */
@@ -91,6 +96,7 @@ enum pmic_arb_channel {
/* Maximum number of support PMIC peripherals */
#define PMIC_ARB_MAX_PERIPHS 512
+#define PMIC_ARB_MAX_PERIPHS_V7 1024
#define PMIC_ARB_TIMEOUT_US 100
#define PMIC_ARB_MAX_TRANS_BYTES (8)
@@ -104,12 +110,12 @@ enum pmic_arb_channel {
((((slave_id) & 0xF) << 28) | \
(((periph_id) & 0xFF) << 20) | \
(((irq_id) & 0x7) << 16) | \
- (((apid) & 0x1FF) << 0))
+ (((apid) & 0x3FF) << 0))
#define hwirq_to_sid(hwirq) (((hwirq) >> 28) & 0xF)
#define hwirq_to_per(hwirq) (((hwirq) >> 20) & 0xFF)
#define hwirq_to_irq(hwirq) (((hwirq) >> 16) & 0x7)
-#define hwirq_to_apid(hwirq) (((hwirq) >> 0) & 0x1FF)
+#define hwirq_to_apid(hwirq) (((hwirq) >> 0) & 0x3FF)
struct pmic_arb_ver_ops;
@@ -137,6 +143,8 @@ struct apid_data {
* @spmic: SPMI controller object
* @ver_ops: version dependent operations.
* @ppid_to_apid in-memory copy of PPID -> APID mapping table.
+ * @apid_data: Table of data for all APIDs
+ * @max_periphs: Number of elements in apid_data[]
*/
struct spmi_pmic_arb {
void __iomem *rd_base;
@@ -149,8 +157,11 @@ struct spmi_pmic_arb {
u8 channel;
int irq;
u8 ee;
+ u32 bus_instance;
u16 min_apid;
u16 max_apid;
+ u16 base_apid;
+ int apid_count;
u32 *mapping_table;
DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS);
struct irq_domain *domain;
@@ -158,7 +169,8 @@ struct spmi_pmic_arb {
const struct pmic_arb_ver_ops *ver_ops;
u16 *ppid_to_apid;
u16 last_apid;
- struct apid_data apid_data[PMIC_ARB_MAX_PERIPHS];
+ struct apid_data *apid_data;
+ int max_periphs;
};
/**
@@ -180,6 +192,7 @@ struct spmi_pmic_arb {
* @irq_clear: on v1 address of PMIC_ARB_SPMI_PIC_IRQ_CLEARn
* on v2 address of SPMI_PIC_IRQ_CLEARn.
* @apid_map_offset: offset of PMIC_ARB_REG_CHNLn
+ * @apid_owner: on v2 and later address of SPMI_PERIPHn_2OWNER_TABLE_REG
*/
struct pmic_arb_ver_ops {
const char *ver_str;
@@ -196,6 +209,7 @@ struct pmic_arb_ver_ops {
void __iomem *(*irq_status)(struct spmi_pmic_arb *pmic_arb, u16 n);
void __iomem *(*irq_clear)(struct spmi_pmic_arb *pmic_arb, u16 n);
u32 (*apid_map_offset)(u16 n);
+ void __iomem *(*apid_owner)(struct spmi_pmic_arb *pmic_arb, u16 n);
};
static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb,
@@ -631,6 +645,11 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
struct irq_chip *chip = irq_desc_get_chip(desc);
int first = pmic_arb->min_apid >> 5;
int last = pmic_arb->max_apid >> 5;
+ /*
+ * acc_offset will be non-zero for the secondary SPMI bus instance on
+ * v7 controllers.
+ */
+ int acc_offset = pmic_arb->base_apid >> 5;
u8 ee = pmic_arb->ee;
u32 status, enable;
int i, id, apid;
@@ -638,8 +657,7 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
chained_irq_enter(chip, desc);
for (i = first; i <= last; ++i) {
- status = readl_relaxed(
- ver_ops->owner_acc_status(pmic_arb, ee, i));
+ status = readl_relaxed(ver_ops->owner_acc_status(pmic_arb, ee, i - acc_offset));
while (status) {
id = ffs(status) - 1;
status &= ~BIT(id);
@@ -944,8 +962,8 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pmic_arb, u16 ppid)
if (offset >= pmic_arb->core_size)
break;
- regval = readl_relaxed(pmic_arb->cnfg +
- SPMI_OWNERSHIP_TABLE_REG(apid));
+ regval = readl_relaxed(pmic_arb->ver_ops->apid_owner(pmic_arb,
+ apid));
apidd->irq_ee = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
apidd->write_ee = apidd->irq_ee;
@@ -981,20 +999,29 @@ static int pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pmic_arb, u16 ppid)
static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pmic_arb)
{
- struct apid_data *apidd = pmic_arb->apid_data;
+ struct apid_data *apidd;
struct apid_data *prev_apidd;
- u16 i, apid, ppid;
+ u16 i, apid, ppid, apid_max;
bool valid, is_irq_ee;
u32 regval, offset;
/*
* In order to allow multiple EEs to write to a single PPID in arbiter
- * version 5, there is more than one APID mapped to each PPID.
+ * version 5 and 7, there is more than one APID mapped to each PPID.
* The owner field for each of these mappings specifies the EE which is
* allowed to write to the APID. The owner of the last (highest) APID
* for a given PPID will receive interrupts from the PPID.
+ *
+ * In arbiter version 7, the APID numbering space is divided between
+ * the primary bus (0) and secondary bus (1) such that:
+ * APID = 0 to N-1 are assigned to the primary bus
+ * APID = N to N+M-1 are assigned to the secondary bus
+ * where N = number of APIDs supported by the primary bus and
+ * M = number of APIDs supported by the secondary bus
*/
- for (i = 0; ; i++, apidd++) {
+ apidd = &pmic_arb->apid_data[pmic_arb->base_apid];
+ apid_max = pmic_arb->base_apid + pmic_arb->apid_count;
+ for (i = pmic_arb->base_apid; i < apid_max; i++, apidd++) {
offset = pmic_arb->ver_ops->apid_map_offset(i);
if (offset >= pmic_arb->core_size)
break;
@@ -1005,8 +1032,8 @@ static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pmic_arb)
ppid = (regval >> 8) & PMIC_ARB_PPID_MASK;
is_irq_ee = PMIC_ARB_CHAN_IS_IRQ_OWNER(regval);
- regval = readl_relaxed(pmic_arb->cnfg +
- SPMI_OWNERSHIP_TABLE_REG(i));
+ regval = readl_relaxed(pmic_arb->ver_ops->apid_owner(pmic_arb,
+ i));
apidd->write_ee = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
apidd->irq_ee = is_irq_ee ? apidd->write_ee : INVALID_EE;
@@ -1100,6 +1127,40 @@ static int pmic_arb_offset_v5(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
return offset;
}
+/*
+ * v7 offset per ee and per apid for observer channels and per apid for
+ * read/write channels.
+ */
+static int pmic_arb_offset_v7(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
+ enum pmic_arb_channel ch_type)
+{
+ u16 apid;
+ int rc;
+ u32 offset = 0;
+ u16 ppid = (sid << 8) | (addr >> 8);
+
+ rc = pmic_arb->ver_ops->ppid_to_apid(pmic_arb, ppid);
+ if (rc < 0)
+ return rc;
+
+ apid = rc;
+ switch (ch_type) {
+ case PMIC_ARB_CHANNEL_OBS:
+ offset = 0x8000 * pmic_arb->ee + 0x20 * apid;
+ break;
+ case PMIC_ARB_CHANNEL_RW:
+ if (pmic_arb->apid_data[apid].write_ee != pmic_arb->ee) {
+ dev_err(&pmic_arb->spmic->dev, "disallowed SPMI write to sid=%u, addr=0x%04X\n",
+ sid, addr);
+ return -EPERM;
+ }
+ offset = 0x1000 * apid;
+ break;
+ }
+
+ return offset;
+}
+
static u32 pmic_arb_fmt_cmd_v1(u8 opc, u8 sid, u16 addr, u8 bc)
{
return (opc << 27) | ((sid & 0xf) << 20) | (addr << 4) | (bc & 0x7);
@@ -1135,6 +1196,12 @@ pmic_arb_owner_acc_status_v5(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
}
static void __iomem *
+pmic_arb_owner_acc_status_v7(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
+{
+ return pmic_arb->intr + 0x1000 * m + 0x4 * n;
+}
+
+static void __iomem *
pmic_arb_acc_enable_v1(struct spmi_pmic_arb *pmic_arb, u16 n)
{
return pmic_arb->intr + 0x200 + 0x4 * n;
@@ -1153,6 +1220,12 @@ pmic_arb_acc_enable_v5(struct spmi_pmic_arb *pmic_arb, u16 n)
}
static void __iomem *
+pmic_arb_acc_enable_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
+{
+ return pmic_arb->wr_base + 0x100 + 0x1000 * n;
+}
+
+static void __iomem *
pmic_arb_irq_status_v1(struct spmi_pmic_arb *pmic_arb, u16 n)
{
return pmic_arb->intr + 0x600 + 0x4 * n;
@@ -1171,6 +1244,12 @@ pmic_arb_irq_status_v5(struct spmi_pmic_arb *pmic_arb, u16 n)
}
static void __iomem *
+pmic_arb_irq_status_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
+{
+ return pmic_arb->wr_base + 0x104 + 0x1000 * n;
+}
+
+static void __iomem *
pmic_arb_irq_clear_v1(struct spmi_pmic_arb *pmic_arb, u16 n)
{
return pmic_arb->intr + 0xA00 + 0x4 * n;
@@ -1188,6 +1267,12 @@ pmic_arb_irq_clear_v5(struct spmi_pmic_arb *pmic_arb, u16 n)
return pmic_arb->wr_base + 0x108 + 0x10000 * n;
}
+static void __iomem *
+pmic_arb_irq_clear_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
+{
+ return pmic_arb->wr_base + 0x108 + 0x1000 * n;
+}
+
static u32 pmic_arb_apid_map_offset_v2(u16 n)
{
return 0x800 + 0x4 * n;
@@ -1198,6 +1283,28 @@ static u32 pmic_arb_apid_map_offset_v5(u16 n)
return 0x900 + 0x4 * n;
}
+static u32 pmic_arb_apid_map_offset_v7(u16 n)
+{
+ return 0x2000 + 0x4 * n;
+}
+
+static void __iomem *
+pmic_arb_apid_owner_v2(struct spmi_pmic_arb *pmic_arb, u16 n)
+{
+ return pmic_arb->cnfg + 0x700 + 0x4 * n;
+}
+
+/*
+ * For arbiter version 7, APID ownership table registers have independent
+ * numbering space for each SPMI bus instance, so each is indexed starting from
+ * 0.
+ */
+static void __iomem *
+pmic_arb_apid_owner_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
+{
+ return pmic_arb->cnfg + 0x4 * (n - pmic_arb->base_apid);
+}
+
static const struct pmic_arb_ver_ops pmic_arb_v1 = {
.ver_str = "v1",
.ppid_to_apid = pmic_arb_ppid_to_apid_v1,
@@ -1209,6 +1316,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v1 = {
.irq_status = pmic_arb_irq_status_v1,
.irq_clear = pmic_arb_irq_clear_v1,
.apid_map_offset = pmic_arb_apid_map_offset_v2,
+ .apid_owner = pmic_arb_apid_owner_v2,
};
static const struct pmic_arb_ver_ops pmic_arb_v2 = {
@@ -1222,6 +1330,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v2 = {
.irq_status = pmic_arb_irq_status_v2,
.irq_clear = pmic_arb_irq_clear_v2,
.apid_map_offset = pmic_arb_apid_map_offset_v2,
+ .apid_owner = pmic_arb_apid_owner_v2,
};
static const struct pmic_arb_ver_ops pmic_arb_v3 = {
@@ -1235,6 +1344,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v3 = {
.irq_status = pmic_arb_irq_status_v2,
.irq_clear = pmic_arb_irq_clear_v2,
.apid_map_offset = pmic_arb_apid_map_offset_v2,
+ .apid_owner = pmic_arb_apid_owner_v2,
};
static const struct pmic_arb_ver_ops pmic_arb_v5 = {
@@ -1248,6 +1358,21 @@ static const struct pmic_arb_ver_ops pmic_arb_v5 = {
.irq_status = pmic_arb_irq_status_v5,
.irq_clear = pmic_arb_irq_clear_v5,
.apid_map_offset = pmic_arb_apid_map_offset_v5,
+ .apid_owner = pmic_arb_apid_owner_v2,
+};
+
+static const struct pmic_arb_ver_ops pmic_arb_v7 = {
+ .ver_str = "v7",
+ .ppid_to_apid = pmic_arb_ppid_to_apid_v5,
+ .non_data_cmd = pmic_arb_non_data_cmd_v2,
+ .offset = pmic_arb_offset_v7,
+ .fmt_cmd = pmic_arb_fmt_cmd_v2,
+ .owner_acc_status = pmic_arb_owner_acc_status_v7,
+ .acc_enable = pmic_arb_acc_enable_v7,
+ .irq_status = pmic_arb_irq_status_v7,
+ .irq_clear = pmic_arb_irq_clear_v7,
+ .apid_map_offset = pmic_arb_apid_map_offset_v7,
+ .apid_owner = pmic_arb_apid_owner_v7,
};
static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
@@ -1274,8 +1399,18 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
pmic_arb = spmi_controller_get_drvdata(ctrl);
pmic_arb->spmic = ctrl;
+ /*
+ * Please don't replace this with devm_platform_ioremap_resource() or
+ * devm_ioremap_resource(). These both result in a call to
+ * devm_request_mem_region() which prevents multiple mappings of this
+ * register address range. SoCs with PMIC arbiter v7 may define two
+ * arbiter devices, for the two physical SPMI interfaces, which share
+ * some register address ranges (i.e. "core", "obsrvr", and "chnls").
+ * Ensure that both devices probe successfully by calling devm_ioremap()
+ * which does not result in a devm_request_mem_region() call.
+ */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
- core = devm_ioremap_resource(&ctrl->dev, res);
+ core = devm_ioremap(&ctrl->dev, res->start, resource_size(res));
if (IS_ERR(core)) {
err = PTR_ERR(core);
goto err_put_ctrl;
@@ -1304,12 +1439,15 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
pmic_arb->ver_ops = &pmic_arb_v2;
else if (hw_ver < PMIC_ARB_VERSION_V5_MIN)
pmic_arb->ver_ops = &pmic_arb_v3;
- else
+ else if (hw_ver < PMIC_ARB_VERSION_V7_MIN)
pmic_arb->ver_ops = &pmic_arb_v5;
+ else
+ pmic_arb->ver_ops = &pmic_arb_v7;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"obsrvr");
- pmic_arb->rd_base = devm_ioremap_resource(&ctrl->dev, res);
+ pmic_arb->rd_base = devm_ioremap(&ctrl->dev, res->start,
+ resource_size(res));
if (IS_ERR(pmic_arb->rd_base)) {
err = PTR_ERR(pmic_arb->rd_base);
goto err_put_ctrl;
@@ -1317,13 +1455,70 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"chnls");
- pmic_arb->wr_base = devm_ioremap_resource(&ctrl->dev, res);
+ pmic_arb->wr_base = devm_ioremap(&ctrl->dev, res->start,
+ resource_size(res));
if (IS_ERR(pmic_arb->wr_base)) {
err = PTR_ERR(pmic_arb->wr_base);
goto err_put_ctrl;
}
}
+ pmic_arb->max_periphs = PMIC_ARB_MAX_PERIPHS;
+
+ if (hw_ver >= PMIC_ARB_VERSION_V7_MIN) {
+ pmic_arb->max_periphs = PMIC_ARB_MAX_PERIPHS_V7;
+ /* Optional property for v7: */
+ of_property_read_u32(pdev->dev.of_node, "qcom,bus-id",
+ &pmic_arb->bus_instance);
+ if (pmic_arb->bus_instance > 1) {
+ err = -EINVAL;
+ dev_err(&pdev->dev, "invalid bus instance (%u) specified\n",
+ pmic_arb->bus_instance);
+ goto err_put_ctrl;
+ }
+
+ if (pmic_arb->bus_instance == 0) {
+ pmic_arb->base_apid = 0;
+ pmic_arb->apid_count =
+ readl_relaxed(core + PMIC_ARB_FEATURES) &
+ PMIC_ARB_FEATURES_PERIPH_MASK;
+ } else {
+ pmic_arb->base_apid =
+ readl_relaxed(core + PMIC_ARB_FEATURES) &
+ PMIC_ARB_FEATURES_PERIPH_MASK;
+ pmic_arb->apid_count =
+ readl_relaxed(core + PMIC_ARB_FEATURES1) &
+ PMIC_ARB_FEATURES_PERIPH_MASK;
+ }
+
+ if (pmic_arb->base_apid + pmic_arb->apid_count >
+ pmic_arb->max_periphs) {
+ err = -EINVAL;
+ dev_err(&pdev->dev, "Unsupported APID count %d detected\n",
+ pmic_arb->base_apid + pmic_arb->apid_count);
+ goto err_put_ctrl;
+ }
+ } else if (hw_ver >= PMIC_ARB_VERSION_V5_MIN) {
+ pmic_arb->base_apid = 0;
+ pmic_arb->apid_count = readl_relaxed(core + PMIC_ARB_FEATURES) &
+ PMIC_ARB_FEATURES_PERIPH_MASK;
+
+ if (pmic_arb->apid_count > pmic_arb->max_periphs) {
+ err = -EINVAL;
+ dev_err(&pdev->dev, "Unsupported APID count %d detected\n",
+ pmic_arb->apid_count);
+ goto err_put_ctrl;
+ }
+ }
+
+ pmic_arb->apid_data = devm_kcalloc(&ctrl->dev, pmic_arb->max_periphs,
+ sizeof(*pmic_arb->apid_data),
+ GFP_KERNEL);
+ if (!pmic_arb->apid_data) {
+ err = -ENOMEM;
+ goto err_put_ctrl;
+ }
+
dev_info(&ctrl->dev, "PMIC arbiter version %s (0x%x)\n",
pmic_arb->ver_ops->ver_str, hw_ver);
@@ -1386,7 +1581,7 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
/* Initialize max_apid/min_apid to the opposite bounds, during
* the irq domain translation, we are sure to update these */
pmic_arb->max_apid = 0;
- pmic_arb->min_apid = PMIC_ARB_MAX_PERIPHS - 1;
+ pmic_arb->min_apid = pmic_arb->max_periphs - 1;
platform_set_drvdata(pdev, ctrl);
raw_spin_lock_init(&pmic_arb->lock);
diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c
index 99a8d9f3e03c..c13093e8a642 100644
--- a/drivers/thermal/qcom/tsens.c
+++ b/drivers/thermal/qcom/tsens.c
@@ -19,6 +19,7 @@
#include <linux/slab.h>
#include <linux/thermal.h>
#include "tsens.h"
+#include "../thermal_hwmon.h"
/**
* struct tsens_irq_data - IRQ status and temperature violations
@@ -1060,6 +1061,10 @@ static int tsens_register(struct tsens_priv *priv)
priv->sensor[i].tzd = tzd;
if (priv->ops->enable)
priv->ops->enable(priv, i);
+
+ if (devm_thermal_add_hwmon_sysfs(tzd))
+ dev_warn(priv->dev,
+ "Failed to add hwmon sysfs attributes\n");
}
/* VER_0 require to set MIN and MAX THRESH