Commit 385903a7 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'soc-drivers-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc

Pull SoC driver updates from Arnd Bergmann:
 "The highlights for the driver support this time are

   - Qualcomm platforms gain support for the Qualcomm Secure Execution
     Environment firmware interface to access EFI variables on certain
     devices, and new features for multiple platform and firmware
     drivers.

   - Arm FF-A firmware support gains support for v1.1 specification
     features, in particular notification and memory transaction
     descriptor changes.

   - SCMI firmware support now support v3.2 features for clock and DVFS
     configuration and a new transport for Qualcomm platforms.

   - Minor cleanups and bugfixes are added to pretty much all the active
     platforms: qualcomm, broadcom, dove, ti-k3, rockchip, sifive,
     amlogic, atmel, tegra, aspeed, vexpress, mediatek, samsung and
     more.

     In particular, this contains portions of the treewide conversion to
     use __counted_by annotations and the device_get_match_data helper"

* tag 'soc-drivers-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (156 commits)
  soc: qcom: pmic_glink_altmode: Print return value on error
  firmware: qcom: scm: remove unneeded 'extern' specifiers
  firmware: qcom: scm: add a missing forward declaration for struct device
  firmware: qcom: move Qualcomm code into its own directory
  soc: samsung: exynos-chipid: Convert to platform remove callback returning void
  soc: qcom: apr: Add __counted_by for struct apr_rx_buf and use struct_size()
  soc: qcom: pmic_glink: fix connector type to be DisplayPort
  soc: ti: k3-socinfo: Avoid overriding return value
  soc: ti: k3-socinfo: Fix typo in bitfield documentation
  soc: ti: knav_qmss_queue: Use device_get_match_data()
  firmware: ti_sci: Use device_get_match_data()
  firmware: qcom: qseecom: add missing include guards
  soc/pxa: ssp: Convert to platform remove callback returning void
  soc/mediatek: mtk-mmsys: Convert to platform remove callback returning void
  soc/mediatek: mtk-devapc: Convert to platform remove callback returning void
  soc/loongson: loongson2_guts: Convert to platform remove callback returning void
  soc/litex: litex_soc_ctrl: Convert to platform remove callback returning void
  soc/ixp4xx: ixp4xx-qmgr: Convert to platform remove callback returning void
  soc/ixp4xx: ixp4xx-npe: Convert to platform remove callback returning void
  soc/hisilicon: kunpeng_hccs: Convert to platform remove callback returning void
  ...
parents c035f026 dfae9478
......@@ -309,7 +309,9 @@ properties:
power-domains property.
For PSCI based platforms, the name corresponding to the index of the PSCI
PM domain provider, must be "psci".
PM domain provider, must be "psci". For SCMI based platforms, the name
corresponding to the index of an SCMI performance domain provider, must be
"perf".
qcom,saw:
$ref: /schemas/types.yaml#/definitions/phandle
......
......@@ -20,6 +20,7 @@ description: |
properties:
compatible:
enum:
- qcom,qdu1000-llcc
- qcom,sc7180-llcc
- qcom,sc7280-llcc
- qcom,sc8180x-llcc
......@@ -44,6 +45,14 @@ properties:
interrupts:
maxItems: 1
nvmem-cells:
items:
- description: Reference to an nvmem node for multi channel DDR
nvmem-cell-names:
items:
- const: multi-chan-ddr
required:
- compatible
- reg
......@@ -92,6 +101,7 @@ allOf:
compatible:
contains:
enum:
- qcom,qdu1000-llcc
- qcom,sc8180x-llcc
- qcom,sc8280xp-llcc
then:
......
......@@ -38,6 +38,9 @@ properties:
with shmem address(4KB-page, offset) as parameters
items:
- const: arm,scmi-smc-param
- description: SCMI compliant firmware with Qualcomm SMC/HVC transport
items:
- const: qcom,scmi-smc
- description: SCMI compliant firmware with SCMI Virtio transport.
The virtio transport only supports a single device.
items:
......@@ -149,8 +152,15 @@ properties:
'#clock-cells':
const: 1
required:
- '#clock-cells'
'#power-domain-cells':
const: 1
oneOf:
- required:
- '#clock-cells'
- required:
- '#power-domain-cells'
protocol@14:
$ref: '#/$defs/protocol-node'
......@@ -306,6 +316,7 @@ else:
enum:
- arm,scmi-smc
- arm,scmi-smc-param
- qcom,scmi-smc
then:
required:
- arm,smc-id
......
......@@ -24,6 +24,7 @@ properties:
- qcom,scm-apq8064
- qcom,scm-apq8084
- qcom,scm-ipq4019
- qcom,scm-ipq5018
- qcom,scm-ipq5332
- qcom,scm-ipq6018
- qcom,scm-ipq806x
......@@ -56,6 +57,7 @@ properties:
- qcom,scm-sm6125
- qcom,scm-sm6350
- qcom,scm-sm6375
- qcom,scm-sm7150
- qcom,scm-sm8150
- qcom,scm-sm8250
- qcom,scm-sm8350
......@@ -89,6 +91,14 @@ properties:
protocol to handle sleeping SCM calls.
maxItems: 1
qcom,sdi-enabled:
description:
Indicates that the SDI (Secure Debug Image) has been enabled by TZ
by default and it needs to be disabled.
If not disabled WDT assertion or reboot will cause the board to hang
in the debug mode.
type: boolean
qcom,dload-mode:
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
......
......@@ -40,6 +40,7 @@ patternProperties:
".*@[0-9]+$":
type: object
$ref: mc-peripheral-props.yaml#
additionalProperties: true
required:
- compatible
......
......@@ -80,6 +80,8 @@ properties:
patternProperties:
"flash@[0-9a-f]+$":
type: object
additionalProperties: true
properties:
compatible:
contains:
......
......@@ -130,7 +130,7 @@ patternProperties:
bus. The device can be a NAND chip, SRAM device, NOR device
or an ASIC.
$ref: ti,gpmc-child.yaml
additionalProperties: true
required:
- compatible
......
......@@ -13,8 +13,9 @@ maintainers:
description: |+
System on chip designs are often divided into multiple PM domains that can be
used for power gating of selected IP blocks for power saving by reduced leakage
current.
used for power gating of selected IP blocks for power saving by reduced
leakage current. Moreover, in some cases the similar PM domains may also be
capable of scaling performance for a group of IP blocks.
This device tree binding can be used to bind PM domain consumer devices with
their PM domains provided by PM domain providers. A PM domain provider can be
......@@ -25,7 +26,7 @@ description: |+
properties:
$nodename:
pattern: "^(power-controller|power-domain)([@-].*)?$"
pattern: "^(power-controller|power-domain|performance-domain)([@-].*)?$"
domain-idle-states:
$ref: /schemas/types.yaml#/definitions/phandle-array
......@@ -44,11 +45,11 @@ properties:
operating-points-v2:
description:
Phandles to the OPP tables of power domains provided by a power domain
provider. If the provider provides a single power domain only or all
the power domains provided by the provider have identical OPP tables,
then this shall contain a single phandle. Refer to ../opp/opp-v2-base.yaml
for more information.
Phandles to the OPP tables of power domains that are capable of scaling
performance, provided by a power domain provider. If the provider provides
a single power domain only or all the power domains provided by the
provider have identical OPP tables, then this shall contain a single
phandle. Refer to ../opp/opp-v2-base.yaml for more information.
"#power-domain-cells":
description:
......
......@@ -26,6 +26,17 @@ properties:
description: >
identifier of the client to use this region for buffers
qcom,use-guard-pages:
type: boolean
description: >
Indicates that the firmware, or hardware, does not gracefully handle
memory protection of this region when placed adjacent to other protected
memory regions, and that padding around the used portion of the memory
region is necessary.
When this is set, the first and last page should be left unused, and the
effective size of the region will thereby shrink with two pages.
qcom,vmid:
$ref: /schemas/types.yaml#/definitions/uint32-array
description: >
......
......@@ -22,6 +22,7 @@ properties:
compatible:
enum:
- mediatek,mt8183-svs
- mediatek,mt8188-svs
- mediatek,mt8192-svs
reg:
......
......@@ -52,6 +52,8 @@ properties:
iommus:
maxItems: 1
dma-coherent: true
required:
- compatible
- reg
......
......@@ -17894,6 +17894,18 @@ S: Maintained
F: Documentation/devicetree/bindings/mtd/qcom,nandc.yaml
F: drivers/mtd/nand/raw/qcom_nandc.c
QUALCOMM QSEECOM DRIVER
M: Maximilian Luz <luzmaximilian@gmail.com>
L: linux-arm-msm@vger.kernel.org
S: Maintained
F: drivers/firmware/qcom/qcom_qseecom.c
QUALCOMM QSEECOM UEFISECAPP DRIVER
M: Maximilian Luz <luzmaximilian@gmail.com>
L: linux-arm-msm@vger.kernel.org
S: Maintained
F: drivers/firmware/qcom/qcom_qseecom_uefisecapp.c
QUALCOMM RMNET DRIVER
M: Subash Abhinov Kasiviswanathan <quic_subashab@quicinc.com>
M: Sean Tranchetti <quic_stranche@quicinc.com>
......@@ -21003,6 +21015,7 @@ F: drivers/clk/clk-sc[mp]i.c
F: drivers/cpufreq/sc[mp]i-cpufreq.c
F: drivers/firmware/arm_scmi/
F: drivers/firmware/arm_scpi.c
F: drivers/pmdomain/arm/
F: drivers/powercap/arm_scmi_powercap.c
F: drivers/regulator/scmi-regulator.c
F: drivers/reset/reset-scmi.c
......
......@@ -423,6 +423,7 @@ static __always_inline void do_ffa_mem_xfer(const u64 func_id,
DECLARE_REG(u32, fraglen, ctxt, 2);
DECLARE_REG(u64, addr_mbz, ctxt, 3);
DECLARE_REG(u32, npages_mbz, ctxt, 4);
struct ffa_mem_region_attributes *ep_mem_access;
struct ffa_composite_mem_region *reg;
struct ffa_mem_region *buf;
u32 offset, nr_ranges;
......@@ -452,7 +453,9 @@ static __always_inline void do_ffa_mem_xfer(const u64 func_id,
buf = hyp_buffers.tx;
memcpy(buf, host_buffers.tx, fraglen);
offset = buf->ep_mem_access[0].composite_off;
ep_mem_access = (void *)buf +
ffa_mem_desc_offset(buf, 0, FFA_VERSION_1_0);
offset = ep_mem_access->composite_off;
if (!offset || buf->ep_count != 1 || buf->sender_id != HOST_FFA_ID) {
ret = FFA_RET_INVALID_PARAMETERS;
goto out_unlock;
......@@ -504,6 +507,7 @@ static void do_ffa_mem_reclaim(struct arm_smccc_res *res,
DECLARE_REG(u32, handle_lo, ctxt, 1);
DECLARE_REG(u32, handle_hi, ctxt, 2);
DECLARE_REG(u32, flags, ctxt, 3);
struct ffa_mem_region_attributes *ep_mem_access;
struct ffa_composite_mem_region *reg;
u32 offset, len, fraglen, fragoff;
struct ffa_mem_region *buf;
......@@ -528,7 +532,9 @@ static void do_ffa_mem_reclaim(struct arm_smccc_res *res,
len = res->a1;
fraglen = res->a2;
offset = buf->ep_mem_access[0].composite_off;
ep_mem_access = (void *)buf +
ffa_mem_desc_offset(buf, 0, FFA_VERSION_1_0);
offset = ep_mem_access->composite_off;
/*
* We can trust the SPMD to get this right, but let's at least
* check that we end up with something that doesn't look _completely_
......
......@@ -34,6 +34,7 @@ config SOC_STARFIVE
bool "StarFive SoCs"
select PINCTRL
select RESET_CONTROLLER
select ARM_AMBA
help
This enables support for StarFive SoC platform hardware.
......
......@@ -130,6 +130,7 @@ static const struct genpd_lock_ops genpd_spin_ops = {
#define genpd_is_active_wakeup(genpd) (genpd->flags & GENPD_FLAG_ACTIVE_WAKEUP)
#define genpd_is_cpu_domain(genpd) (genpd->flags & GENPD_FLAG_CPU_DOMAIN)
#define genpd_is_rpm_always_on(genpd) (genpd->flags & GENPD_FLAG_RPM_ALWAYS_ON)
#define genpd_is_opp_table_fw(genpd) (genpd->flags & GENPD_FLAG_OPP_TABLE_FW)
static inline bool irq_safe_dev_in_sleep_domain(struct device *dev,
const struct generic_pm_domain *genpd)
......@@ -2337,7 +2338,7 @@ int of_genpd_add_provider_simple(struct device_node *np,
genpd->dev.of_node = np;
/* Parse genpd OPP table */
if (genpd->set_performance_state) {
if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) {
ret = dev_pm_opp_of_add_table(&genpd->dev);
if (ret)
return dev_err_probe(&genpd->dev, ret, "Failed to add OPP table\n");
......@@ -2352,7 +2353,7 @@ int of_genpd_add_provider_simple(struct device_node *np,
ret = genpd_add_provider(np, genpd_xlate_simple, genpd);
if (ret) {
if (genpd->set_performance_state) {
if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) {
dev_pm_opp_put_opp_table(genpd->opp_table);
dev_pm_opp_of_remove_table(&genpd->dev);
}
......@@ -2396,7 +2397,7 @@ int of_genpd_add_provider_onecell(struct device_node *np,
genpd->dev.of_node = np;
/* Parse genpd OPP table */
if (genpd->set_performance_state) {
if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) {
ret = dev_pm_opp_of_add_table_indexed(&genpd->dev, i);
if (ret) {
dev_err_probe(&genpd->dev, ret,
......@@ -2432,7 +2433,7 @@ int of_genpd_add_provider_onecell(struct device_node *np,
genpd->provider = NULL;
genpd->has_provider = false;
if (genpd->set_performance_state) {
if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) {
dev_pm_opp_put_opp_table(genpd->opp_table);
dev_pm_opp_of_remove_table(&genpd->dev);
}
......@@ -2464,7 +2465,7 @@ void of_genpd_del_provider(struct device_node *np)
if (gpd->provider == &np->fwnode) {
gpd->has_provider = false;
if (!gpd->set_performance_state)
if (genpd_is_opp_table_fw(gpd) || !gpd->set_performance_state)
continue;
dev_pm_opp_put_opp_table(gpd->opp_table);
......
......@@ -31,7 +31,7 @@ config ARM_INTEGRATOR_LM
config BRCMSTB_GISB_ARB
tristate "Broadcom STB GISB bus arbiter"
depends on ARM || ARM64 || MIPS
depends on ARCH_BRCMSTB || BMIPS_GENERIC
default ARCH_BRCMSTB || BMIPS_GENERIC
help
Driver for the Broadcom Set Top Box System-on-a-chip internal bus
......
......@@ -54,7 +54,7 @@ struct vexpress_syscfg_func {
struct vexpress_syscfg *syscfg;
struct regmap *regmap;
int num_templates;
u32 template[]; /* Keep it last! */
u32 template[] __counted_by(num_templates); /* Keep it last! */
};
struct vexpress_config_bridge_ops {
......
......@@ -13,13 +13,18 @@
#include <linux/scmi_protocol.h>
#include <asm/div64.h>
#define NOT_ATOMIC false
#define ATOMIC true
static const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
struct scmi_clk {
u32 id;
struct device *dev;
struct clk_hw hw;
const struct scmi_clock_info *info;
const struct scmi_protocol_handle *ph;
struct clk_parent_data *parent_data;
};
#define to_scmi_clk(clk) container_of(clk, struct scmi_clk, hw)
......@@ -74,38 +79,89 @@ static int scmi_clk_set_rate(struct clk_hw *hw, unsigned long rate,
return scmi_proto_clk_ops->rate_set(clk->ph, clk->id, rate);
}
static int scmi_clk_set_parent(struct clk_hw *hw, u8 parent_index)
{
struct scmi_clk *clk = to_scmi_clk(hw);
return scmi_proto_clk_ops->parent_set(clk->ph, clk->id, parent_index);
}
static u8 scmi_clk_get_parent(struct clk_hw *hw)
{
struct scmi_clk *clk = to_scmi_clk(hw);
u32 parent_id, p_idx;
int ret;
ret = scmi_proto_clk_ops->parent_get(clk->ph, clk->id, &parent_id);
if (ret)
return 0;
for (p_idx = 0; p_idx < clk->info->num_parents; p_idx++) {
if (clk->parent_data[p_idx].index == parent_id)
break;
}
if (p_idx == clk->info->num_parents)
return 0;
return p_idx;
}
static int scmi_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
{
/*
* Suppose all the requested rates are supported, and let firmware
* to handle the left work.
*/
return 0;
}
static int scmi_clk_enable(struct clk_hw *hw)
{
struct scmi_clk *clk = to_scmi_clk(hw);
return scmi_proto_clk_ops->enable(clk->ph, clk->id);
return scmi_proto_clk_ops->enable(clk->ph, clk->id, NOT_ATOMIC);
}
static void scmi_clk_disable(struct clk_hw *hw)
{
struct scmi_clk *clk = to_scmi_clk(hw);
scmi_proto_clk_ops->disable(clk->ph, clk->id);
scmi_proto_clk_ops->disable(clk->ph, clk->id, NOT_ATOMIC);
}
static int scmi_clk_atomic_enable(struct clk_hw *hw)
{
struct scmi_clk *clk = to_scmi_clk(hw);
return scmi_proto_clk_ops->enable_atomic(clk->ph, clk->id);
return scmi_proto_clk_ops->enable(clk->ph, clk->id, ATOMIC);
}
static void scmi_clk_atomic_disable(struct clk_hw *hw)
{
struct scmi_clk *clk = to_scmi_clk(hw);
scmi_proto_clk_ops->disable_atomic(clk->ph, clk->id);
scmi_proto_clk_ops->disable(clk->ph, clk->id, ATOMIC);
}
static int scmi_clk_atomic_is_enabled(struct clk_hw *hw)
{
int ret;
bool enabled = false;
struct scmi_clk *clk = to_scmi_clk(hw);
ret = scmi_proto_clk_ops->state_get(clk->ph, clk->id, &enabled, ATOMIC);
if (ret)
dev_warn(clk->dev,
"Failed to get state for clock ID %d\n", clk->id);
return !!enabled;
}
/*
* We can provide enable/disable atomic callbacks only if the underlying SCMI
* transport for an SCMI instance is configured to handle SCMI commands in an
* atomic manner.
* We can provide enable/disable/is_enabled atomic callbacks only if the
* underlying SCMI transport for an SCMI instance is configured to handle
* SCMI commands in an atomic manner.
*
* When no SCMI atomic transport support is available we instead provide only
* the prepare/unprepare API, as allowed by the clock framework when atomic
......@@ -121,6 +177,9 @@ static const struct clk_ops scmi_clk_ops = {
.set_rate = scmi_clk_set_rate,
.prepare = scmi_clk_enable,
.unprepare = scmi_clk_disable,
.set_parent = scmi_clk_set_parent,
.get_parent = scmi_clk_get_parent,
.determine_rate = scmi_clk_determine_rate,
};
static const struct clk_ops scmi_atomic_clk_ops = {
......@@ -129,6 +188,10 @@ static const struct clk_ops scmi_atomic_clk_ops = {
.set_rate = scmi_clk_set_rate,
.enable = scmi_clk_atomic_enable,
.disable = scmi_clk_atomic_disable,
.is_enabled = scmi_clk_atomic_is_enabled,
.set_parent = scmi_clk_set_parent,
.get_parent = scmi_clk_get_parent,
.determine_rate = scmi_clk_determine_rate,
};
static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk,
......@@ -139,9 +202,10 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk,
struct clk_init_data init = {
.flags = CLK_GET_RATE_NOCACHE,
.num_parents = 0,
.num_parents = sclk->info->num_parents,
.ops = scmi_ops,
.name = sclk->info->name,
.parent_data = sclk->parent_data,
};
sclk->hw.init = &init;
......@@ -213,11 +277,13 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
sclk->info = scmi_proto_clk_ops->info_get(ph, idx);
if (!sclk->info) {
dev_dbg(dev, "invalid clock info for idx %d\n", idx);
devm_kfree(dev, sclk);
continue;
}
sclk->id = idx;
sclk->ph = ph;
sclk->dev = dev;
/*
* Note that when transport is atomic but SCMI protocol did not
......@@ -230,9 +296,23 @@ static int scmi_clocks_probe(struct scmi_device *sdev)
else
scmi_ops = &scmi_clk_ops;
/* Initialize clock parent data. */
if (sclk->info->num_parents > 0) {
sclk->parent_data = devm_kcalloc(dev, sclk->info->num_parents,
sizeof(*sclk->parent_data), GFP_KERNEL);
if (!sclk->parent_data)
return -ENOMEM;
for (int i = 0; i < sclk->info->num_parents; i++) {
sclk->parent_data[i].index = sclk->info->parents[i];
sclk->parent_data[i].hw = hws[sclk->info->parents[i]];
}
}
err = scmi_clk_ops_init(dev, sclk, scmi_ops);
if (err) {
dev_err(dev, "failed to register clock %d\n", idx);
devm_kfree(dev, sclk->parent_data);
devm_kfree(dev, sclk);
hws[idx] = NULL;
} else {
......
......@@ -70,16 +70,36 @@ static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy,
return 0;
}
static int scmi_cpu_domain_id(struct device *cpu_dev)
{
struct device_node *np = cpu_dev->of_node;
struct of_phandle_args domain_id;
int index;
if (of_parse_phandle_with_args(np, "clocks", "#clock-cells", 0,
&domain_id)) {
/* Find the corresponding index for power-domain "perf". */
index = of_property_match_string(np, "power-domain-names",
"perf");
if (index < 0)
return -EINVAL;
if (of_parse_phandle_with_args(np, "power-domains",
"#power-domain-cells", index,
&domain_id))
return -EINVAL;
}
return domain_id.args[0];
}
static int
scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
scmi_get_sharing_cpus(struct device *cpu_dev, int domain,
struct cpumask *cpumask)
{
int cpu, domain, tdomain;
int cpu, tdomain;
struct device *tcpu_dev;
domain = perf_ops->device_domain_id(cpu_dev);
if (domain < 0)
return domain;
for_each_possible_cpu(cpu) {
if (cpu == cpu_dev->id)
continue;
......@@ -88,7 +108,7 @@ scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
if (!tcpu_dev)
continue;
tdomain = perf_ops->device_domain_id(tcpu_dev);
tdomain = scmi_cpu_domain_id(tcpu_dev);
if (tdomain == domain)
cpumask_set_cpu(cpu, cpumask);
}
......@@ -104,7 +124,7 @@ scmi_get_cpu_power(struct device *cpu_dev, unsigned long *power,
unsigned long Hz;
int ret, domain;
domain = perf_ops->device_domain_id(cpu_dev);
domain = scmi_cpu_domain_id(cpu_dev);
if (domain < 0)
return domain;
......@@ -126,7 +146,7 @@ scmi_get_cpu_power(struct device *cpu_dev, unsigned long *power,
static int scmi_cpufreq_init(struct cpufreq_policy *policy)
{
int ret, nr_opp;
int ret, nr_opp, domain;
unsigned int latency;
struct device *cpu_dev;
struct scmi_data *priv;
......@@ -138,6 +158,10 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
return -ENODEV;
}
domain = scmi_cpu_domain_id(cpu_dev);
if (domain < 0)
return domain;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
......@@ -148,7 +172,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
}
/* Obtain CPUs that share SCMI performance controls */
ret = scmi_get_sharing_cpus(cpu_dev, policy->cpus);
ret = scmi_get_sharing_cpus(cpu_dev, domain, policy->cpus);
if (ret) {
dev_warn(cpu_dev, "failed to get sharing cpumask\n");
goto out_free_cpumask;
......@@ -176,7 +200,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
*/
nr_opp = dev_pm_opp_get_opp_count(cpu_dev);
if (nr_opp <= 0) {
ret = perf_ops->device_opps_add(ph, cpu_dev);
ret = perf_ops->device_opps_add(ph, cpu_dev, domain);
if (ret) {
dev_warn(cpu_dev, "failed to add opps to the device\n");
goto out_free_cpumask;
......@@ -209,7 +233,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
}
priv->cpu_dev = cpu_dev;
priv->domain_id = perf_ops->device_domain_id(cpu_dev);
priv->domain_id = domain;
policy->driver_data = priv;
policy->freq_table = freq_table;
......@@ -217,14 +241,14 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy)
/* SCMI allows DVFS request for any domain from any CPU */
policy->dvfs_possible_from_any_cpu = true;
latency = perf_ops->transition_latency_get(ph, cpu_dev);
latency = perf_ops->transition_latency_get(ph, domain);
if (!latency)
latency = CPUFREQ_ETERNAL;
policy->cpuinfo.transition_latency = latency;
policy->fast_switch_possible =
perf_ops->fast_switch_possible(ph, cpu_dev);
perf_ops->fast_switch_possible(ph, domain);
return 0;
......
......@@ -212,20 +212,6 @@ config MTK_ADSP_IPC
ADSP exists on some mtk processors.
Client might use shared memory to exchange information with ADSP.
config QCOM_SCM
tristate
config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
bool "Qualcomm download mode enabled by default"
depends on QCOM_SCM
help
A device with "download mode" enabled will upon an unexpected
warm-restart enter a special debug mode that allows the user to
"download" memory content over USB for offline postmortem analysis.
The feature can be enabled/disabled on the kernel command line.
Say Y here to enable "download mode" by default.
config SYSFB
bool
select BOOT_VESA_SUPPORT
......@@ -311,6 +297,7 @@ source "drivers/firmware/efi/Kconfig"
source "drivers/firmware/imx/Kconfig"
source "drivers/firmware/meson/Kconfig"
source "drivers/firmware/psci/Kconfig"
source "drivers/firmware/qcom/Kconfig"
source "drivers/firmware/smccc/Kconfig"
source "drivers/firmware/tegra/Kconfig"
source "drivers/firmware/xilinx/Kconfig"
......
......@@ -18,8 +18,6 @@ obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
obj-$(CONFIG_MTK_ADSP_IPC) += mtk-adsp-ipc.o
obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o
obj-$(CONFIG_QCOM_SCM) += qcom-scm.o
qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
obj-$(CONFIG_SYSFB) += sysfb.o
obj-$(CONFIG_SYSFB_SIMPLEFB) += sysfb_simplefb.o
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
......@@ -35,6 +33,7 @@ obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
obj-y += efi/
obj-y += imx/
obj-y += psci/
obj-y += qcom/
obj-y += smccc/
obj-y += tegra/
obj-y += xilinx/
......@@ -15,6 +15,8 @@
#include "common.h"
#define SCMI_UEVENT_MODALIAS_FMT "arm_ffa:%04x:%pUb"
static DEFINE_IDA(ffa_bus_id);
static int ffa_device_match(struct device *dev, struct device_driver *drv)
......@@ -63,10 +65,20 @@ static int ffa_device_uevent(const struct device *dev, struct kobj_uevent_env *e
{
const struct ffa_device *ffa_dev = to_ffa_dev(dev);
return add_uevent_var(env, "MODALIAS=arm_ffa:%04x:%pUb",
return add_uevent_var(env, "MODALIAS=" SCMI_UEVENT_MODALIAS_FMT,
ffa_dev->vm_id, &ffa_dev->uuid);
}
static ssize_t modalias_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ffa_device *ffa_dev = to_ffa_dev(dev);
return sysfs_emit(buf, SCMI_UEVENT_MODALIAS_FMT, ffa_dev->vm_id,
&ffa_dev->uuid);
}
static DEVICE_ATTR_RO(modalias);
static ssize_t partition_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
......@@ -88,6 +100,7 @@ static DEVICE_ATTR_RO(uuid);
static struct attribute *ffa_device_attributes_attrs[] = {
&dev_attr_partition_id.attr,
&dev_attr_uuid.attr,
&dev_attr_modalias.attr,
NULL,
};
ATTRIBUTE_GROUPS(ffa_device_attributes);
......@@ -193,6 +206,7 @@ struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id,
dev->release = ffa_release_device;
dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id);
ffa_dev->id = id;
ffa_dev->vm_id = vm_id;
ffa_dev->ops = ops;
uuid_copy(&ffa_dev->uuid, uuid);
......
This diff is collapsed.
......@@ -181,6 +181,18 @@ config ARM_SCMI_POWER_DOMAIN
will be called scmi_pm_domain. Note this may needed early in boot
before rootfs may be available.
config ARM_SCMI_PERF_DOMAIN
tristate "SCMI performance domain driver"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
default y
select PM_GENERIC_DOMAINS if PM
help
This enables support for the SCMI performance domains which can be
enabled or disabled via the SCP firmware.
This driver can also be built as a module. If so, the module will be
called scmi_perf_domain.
config ARM_SCMI_POWER_CONTROL
tristate "SCMI system power control driver"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
......
......@@ -16,7 +16,6 @@ scmi-module-objs := $(scmi-driver-y) $(scmi-protocols-y) $(scmi-transport-y)
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
obj-$(CONFIG_ARM_SCMI_POWER_CONTROL) += scmi_power_control.o
ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy)
......
This diff is collapsed.
......@@ -2915,6 +2915,7 @@ static const struct of_device_id scmi_of_match[] = {
#ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC
{ .compatible = "arm,scmi-smc", .data = &scmi_smc_desc},
{ .compatible = "arm,scmi-smc-param", .data = &scmi_smc_desc},
{ .compatible = "qcom,scmi-smc", .data = &scmi_smc_desc},
#endif
#ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO
{ .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc},
......
......@@ -145,7 +145,6 @@ struct scmi_msg_resp_perf_describe_levels_v4 {
struct perf_dom_info {
u32 id;
bool set_limits;
bool set_perf;
bool perf_limit_notify;
bool perf_level_notify;
bool perf_fastchannels;
......@@ -154,7 +153,7 @@ struct perf_dom_info {
u32 sustained_freq_khz;
u32 sustained_perf_level;
u32 mult_factor;
char name[SCMI_MAX_STR_SIZE];
struct scmi_perf_domain_info info;
struct scmi_opp opp[MAX_OPPS];
struct scmi_fc_info *fc_info;
struct xarray opps_by_idx;
......@@ -257,7 +256,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
flags = le32_to_cpu(attr->flags);
dom_info->set_limits = SUPPORTS_SET_LIMITS(flags);
dom_info->set_perf = SUPPORTS_SET_PERF_LVL(flags);
dom_info->info.set_perf = SUPPORTS_SET_PERF_LVL(flags);
dom_info->perf_limit_notify = SUPPORTS_PERF_LIMIT_NOTIFY(flags);
dom_info->perf_level_notify = SUPPORTS_PERF_LEVEL_NOTIFY(flags);
dom_info->perf_fastchannels = SUPPORTS_PERF_FASTCHANNELS(flags);
......@@ -276,7 +275,8 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
dom_info->mult_factor =
(dom_info->sustained_freq_khz * 1000) /
dom_info->sustained_perf_level;
strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
strscpy(dom_info->info.name, attr->name,
SCMI_SHORT_NAME_MAX_SIZE);
}
ph->xops->xfer_put(ph, t);
......@@ -288,7 +288,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph,
if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 &&
SUPPORTS_EXTENDED_NAMES(flags))
ph->hops->extended_name_get(ph, PERF_DOMAIN_NAME_GET,
dom_info->id, dom_info->name,
dom_info->id, dom_info->info.name,
SCMI_MAX_STR_SIZE);
if (dom_info->level_indexing_mode) {
......@@ -423,6 +423,36 @@ scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph,
return ret;
}
static int scmi_perf_num_domains_get(const struct scmi_protocol_handle *ph)
{
struct scmi_perf_info *pi = ph->get_priv(ph);
return pi->num_domains;
}
static inline struct perf_dom_info *
scmi_perf_domain_lookup(const struct scmi_protocol_handle *ph, u32 domain)
{
struct scmi_perf_info *pi = ph->get_priv(ph);
if (domain >= pi->num_domains)
return ERR_PTR(-EINVAL);
return pi->dom_info + domain;
}
static const struct scmi_perf_domain_info *
scmi_perf_info_get(const struct scmi_protocol_handle *ph, u32 domain)
{
struct perf_dom_info *dom;
dom = scmi_perf_domain_lookup(ph, domain);
if (IS_ERR(dom))
return ERR_PTR(-EINVAL);
return &dom->info;
}
static int scmi_perf_msg_limits_set(const struct scmi_protocol_handle *ph,
u32 domain, u32 max_perf, u32 min_perf)
{
......@@ -446,17 +476,6 @@ static int scmi_perf_msg_limits_set(const struct scmi_protocol_handle *ph,
return ret;
}
static inline struct perf_dom_info *
scmi_perf_domain_lookup(const struct scmi_protocol_handle *ph, u32 domain)
{
struct scmi_perf_info *pi = ph->get_priv(ph);
if (domain >= pi->num_domains)
return ERR_PTR(-EINVAL);
return pi->dom_info + domain;
}
static int __scmi_perf_limits_set(const struct scmi_protocol_handle *ph,
struct perf_dom_info *dom, u32 max_perf,
u32 min_perf)
......@@ -763,71 +782,46 @@ static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph,
*p_fc = fc;
}
/* Device specific ops */
static int scmi_dev_domain_id(struct device *dev)
{
struct of_phandle_args clkspec;
if (of_parse_phandle_with_args(dev->of_node, "clocks", "#clock-cells",
0, &clkspec))
return -EINVAL;
return clkspec.args[0];
}
static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph,
struct device *dev)
struct device *dev, u32 domain)
{
int idx, ret, domain;
int idx, ret;
unsigned long freq;
struct scmi_opp *opp;
struct dev_pm_opp_data data = {};
struct perf_dom_info *dom;
domain = scmi_dev_domain_id(dev);
if (domain < 0)
return -EINVAL;
dom = scmi_perf_domain_lookup(ph, domain);
if (IS_ERR(dom))
return PTR_ERR(dom);
for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) {
for (idx = 0; idx < dom->opp_count; idx++) {
if (!dom->level_indexing_mode)
freq = opp->perf * dom->mult_factor;
freq = dom->opp[idx].perf * dom->mult_factor;
else
freq = opp->indicative_freq * 1000;
freq = dom->opp[idx].indicative_freq * 1000;
data.level = dom->opp[idx].perf;
data.freq = freq;
ret = dev_pm_opp_add(dev, freq, 0);
ret = dev_pm_opp_add_dynamic(dev, &data);
if (ret) {
dev_warn(dev, "failed to add opp %luHz\n", freq);
while (idx-- > 0) {
if (!dom->level_indexing_mode)
freq = (--opp)->perf * dom->mult_factor;
else
freq = (--opp)->indicative_freq * 1000;
dev_pm_opp_remove(dev, freq);
}
dev_pm_opp_remove_all_dynamic(dev);
return ret;
}
dev_dbg(dev, "[%d][%s]:: Registered OPP[%d] %lu\n",
domain, dom->name, idx, freq);
domain, dom->info.name, idx, freq);
}
return 0;
}
static int
scmi_dvfs_transition_latency_get(const struct scmi_protocol_handle *ph,
struct device *dev)
u32 domain)
{
int domain;
struct perf_dom_info *dom;
domain = scmi_dev_domain_id(dev);
if (domain < 0)
return -EINVAL;
dom = scmi_perf_domain_lookup(ph, domain);
if (IS_ERR(dom))
return PTR_ERR(dom);
......@@ -923,15 +917,10 @@ static int scmi_dvfs_est_power_get(const struct scmi_protocol_handle *ph,
}
static bool scmi_fast_switch_possible(const struct scmi_protocol_handle *ph,
struct device *dev)
u32 domain)
{
int domain;
struct perf_dom_info *dom;
domain = scmi_dev_domain_id(dev);
if (domain < 0)
return false;
dom = scmi_perf_domain_lookup(ph, domain);
if (IS_ERR(dom))
return false;
......@@ -948,11 +937,12 @@ scmi_power_scale_get(const struct scmi_protocol_handle *ph)
}
static const struct scmi_perf_proto_ops perf_proto_ops = {
.num_domains_get = scmi_perf_num_domains_get,
.info_get = scmi_perf_info_get,
.limits_set = scmi_perf_limits_set,
.limits_get = scmi_perf_limits_get,
.level_set = scmi_perf_level_set,
.level_get = scmi_perf_level_get,
.device_domain_id = scmi_dev_domain_id,
.transition_latency_get = scmi_dvfs_transition_latency_get,
.device_opps_add = scmi_dvfs_device_opps_add,
.freq_set = scmi_dvfs_freq_set,
......
......@@ -360,8 +360,8 @@ static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
msg = t->tx.buf;
msg->domain = cpu_to_le32(pc->id);
msg->flags =
cpu_to_le32(FIELD_PREP(CAP_SET_ASYNC, !!pc->async_powercap_cap_set) |
FIELD_PREP(CAP_SET_IGNORE_DRESP, !!ignore_dresp));
cpu_to_le32(FIELD_PREP(CAP_SET_ASYNC, pc->async_powercap_cap_set) |
FIELD_PREP(CAP_SET_IGNORE_DRESP, ignore_dresp));
msg->value = cpu_to_le32(power_cap);
if (!pc->async_powercap_cap_set || ignore_dresp) {
......
......@@ -15,6 +15,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/limits.h>
#include <linux/processor.h>
#include <linux/slab.h>
......@@ -50,6 +51,8 @@
* @func_id: smc/hvc call function id
* @param_page: 4K page number of the shmem channel
* @param_offset: Offset within the 4K page of the shmem channel
* @cap_id: smc/hvc doorbell's capability id to be used on Qualcomm virtual
* platforms
*/
struct scmi_smc {
......@@ -60,9 +63,10 @@ struct scmi_smc {
struct mutex shmem_lock;
#define INFLIGHT_NONE MSG_TOKEN_MAX
atomic_t inflight;
u32 func_id;
u32 param_page;
u32 param_offset;
unsigned long func_id;
unsigned long param_page;
unsigned long param_offset;
unsigned long cap_id;
};
static irqreturn_t smc_msg_done_isr(int irq, void *data)
......@@ -124,6 +128,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
bool tx)
{
struct device *cdev = cinfo->dev;
unsigned long cap_id = ULONG_MAX;
struct scmi_smc *scmi_info;
resource_size_t size;
struct resource res;
......@@ -162,6 +167,18 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
if (ret < 0)
return ret;
if (of_device_is_compatible(dev->of_node, "qcom,scmi-smc")) {
void __iomem *ptr = (void __iomem *)scmi_info->shmem + size - 8;
/* The capability-id is kept in last 8 bytes of shmem.
* +-------+ <-- 0
* | shmem |
* +-------+ <-- size - 8
* | capId |
* +-------+ <-- size
*/
memcpy_fromio(&cap_id, ptr, sizeof(cap_id));
}
if (of_device_is_compatible(dev->of_node, "arm,scmi-smc-param")) {
scmi_info->param_page = SHMEM_PAGE(res.start);
scmi_info->param_offset = SHMEM_OFFSET(res.start);
......@@ -184,6 +201,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev,
}
scmi_info->func_id = func_id;
scmi_info->cap_id = cap_id;
scmi_info->cinfo = cinfo;
smc_channel_lock_init(scmi_info);
cinfo->transport_info = scmi_info;
......@@ -211,8 +229,6 @@ static int smc_send_message(struct scmi_chan_info *cinfo,
{
struct scmi_smc *scmi_info = cinfo->transport_info;
struct arm_smccc_res res;
unsigned long page = scmi_info->param_page;
unsigned long offset = scmi_info->param_offset;
/*
* Channel will be released only once response has been
......@@ -222,8 +238,13 @@ static int smc_send_message(struct scmi_chan_info *cinfo,
shmem_tx_prepare(scmi_info->shmem, xfer, cinfo);
arm_smccc_1_1_invoke(scmi_info->func_id, page, offset, 0, 0, 0, 0, 0,
&res);
if (scmi_info->cap_id != ULONG_MAX)
arm_smccc_1_1_invoke(scmi_info->func_id, scmi_info->cap_id, 0,
0, 0, 0, 0, 0, &res);
else
arm_smccc_1_1_invoke(scmi_info->func_id, scmi_info->param_page,
scmi_info->param_offset, 0, 0, 0, 0, 0,
&res);
/* Only SMCCC_RET_NOT_SUPPORTED is valid error code */
if (res.a0) {
......
......@@ -26,9 +26,12 @@
#include <linux/list.h>
#include <linux/mailbox_client.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/printk.h>
#include <linux/property.h>
#include <linux/pm_opp.h>
#include <linux/scpi_protocol.h>
#include <linux/slab.h>
......@@ -894,11 +897,6 @@ static int scpi_alloc_xfer_list(struct device *dev, struct scpi_chan *ch)
return 0;
}
static const struct of_device_id legacy_scpi_of_match[] = {
{.compatible = "arm,scpi-pre-1.0"},
{},
};
static const struct of_device_id shmem_of_match[] __maybe_unused = {
{ .compatible = "amlogic,meson-gxbb-scp-shmem", },
{ .compatible = "amlogic,meson-axg-scp-shmem", },
......@@ -919,8 +917,7 @@ static int scpi_probe(struct platform_device *pdev)
if (!scpi_drvinfo)
return -ENOMEM;
if (of_match_device(legacy_scpi_of_match, &pdev->dev))
scpi_drvinfo->is_legacy = true;
scpi_drvinfo->is_legacy = !!device_get_match_data(dev);
count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells");
if (count < 0) {
......@@ -1038,7 +1035,7 @@ static int scpi_probe(struct platform_device *pdev)
static const struct of_device_id scpi_of_match[] = {
{.compatible = "arm,scpi"},
{.compatible = "arm,scpi-pre-1.0"},
{.compatible = "arm,scpi-pre-1.0", .data = (void *)1UL },
{},
};
......
......@@ -13,9 +13,10 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/printk.h>
#include <linux/property.h>
#include <linux/types.h>
#include <linux/sizes.h>
#include <linux/slab.h>
......@@ -67,7 +68,7 @@ static u32 meson_sm_get_cmd(const struct meson_sm_chip *chip,
return cmd->smc_id;
}
static u32 __meson_sm_call(u32 cmd, u32 arg0, u32 arg1, u32 arg2,
static s32 __meson_sm_call(u32 cmd, u32 arg0, u32 arg1, u32 arg2,
u32 arg3, u32 arg4)
{
struct arm_smccc_res res;
......@@ -102,9 +103,10 @@ static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size)
* Return: 0 on success, a negative value on error
*/
int meson_sm_call(struct meson_sm_firmware *fw, unsigned int cmd_index,
u32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
s32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4)
{
u32 cmd, lret;
u32 cmd;
s32 lret;
if (!fw->chip)
return -ENOENT;
......@@ -143,7 +145,7 @@ int meson_sm_call_read(struct meson_sm_firmware *fw, void *buffer,
unsigned int bsize, unsigned int cmd_index, u32 arg0,
u32 arg1, u32 arg2, u32 arg3, u32 arg4)
{
u32 size;
s32 size;
int ret;
if (!fw->chip)
......@@ -158,11 +160,16 @@ int meson_sm_call_read(struct meson_sm_firmware *fw, void *buffer,
if (meson_sm_call(fw, cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0)
return -EINVAL;
if (size > bsize)
if (size < 0 || size > bsize)
return -EINVAL;
ret = size;
/* In some cases (for example GET_CHIP_ID command),
* SMC doesn't return the number of bytes read, even
* though the bytes were actually read into sm_shmem_out.
* So this check is needed.
*/
if (!size)
size = bsize;
......@@ -192,7 +199,7 @@ int meson_sm_call_write(struct meson_sm_firmware *fw, void *buffer,
unsigned int size, unsigned int cmd_index, u32 arg0,
u32 arg1, u32 arg2, u32 arg3, u32 arg4)
{
u32 written;
s32 written;
if (!fw->chip)
return -ENOENT;
......@@ -208,7 +215,7 @@ int meson_sm_call_write(struct meson_sm_firmware *fw, void *buffer,
if (meson_sm_call(fw, cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0)
return -EINVAL;
if (!written)
if (written <= 0 || written > size)
return -EINVAL;
return written;
......@@ -291,7 +298,7 @@ static int __init meson_sm_probe(struct platform_device *pdev)
if (!fw)
return -ENOMEM;
chip = of_match_device(meson_sm_ids, dev)->data;
chip = device_get_match_data(dev);
if (!chip)
return -EINVAL;
......
# SPDX-License-Identifier: GPL-2.0-only
#
# For a description of the syntax of this configuration file,
# see Documentation/kbuild/kconfig-language.rst.
#
menu "Qualcomm firmware drivers"
config QCOM_SCM
tristate
config QCOM_SCM_DOWNLOAD_MODE_DEFAULT
bool "Qualcomm download mode enabled by default"
depends on QCOM_SCM
help
A device with "download mode" enabled will upon an unexpected
warm-restart enter a special debug mode that allows the user to
"download" memory content over USB for offline postmortem analysis.
The feature can be enabled/disabled on the kernel command line.
Say Y here to enable "download mode" by default.
config QCOM_QSEECOM
bool "Qualcomm QSEECOM interface driver"
depends on QCOM_SCM=y
select AUXILIARY_BUS
help
Various Qualcomm SoCs have a Secure Execution Environment (SEE) running
in the Trust Zone. This module provides an interface to that via the
QSEECOM mechanism, using SCM calls.
The QSEECOM interface allows, among other things, access to applications
running in the SEE. An example of such an application is 'uefisecapp',
which is required to access UEFI variables on certain systems. If
selected, the interface will also attempt to detect and register client
devices for supported applications.
Select Y here to enable the QSEECOM interface driver.
config QCOM_QSEECOM_UEFISECAPP
bool "Qualcomm SEE UEFI Secure App client driver"
depends on QCOM_QSEECOM
depends on EFI
help
Various Qualcomm SoCs do not allow direct access to EFI variables.
Instead, these need to be accessed via the UEFI Secure Application
(uefisecapp), residing in the Secure Execution Environment (SEE).
This module provides a client driver for uefisecapp, installing efivar
operations to allow the kernel accessing EFI variables, and via that also
provide user-space with access to EFI variables via efivarfs.
Select Y here to provide access to EFI variables on the aforementioned
platforms.
endmenu
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the linux kernel.
#
obj-$(CONFIG_QCOM_SCM) += qcom-scm.o
qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o
obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Driver for Qualcomm Secure Execution Environment (SEE) interface (QSEECOM).
* Responsible for setting up and managing QSEECOM client devices.
*
* Copyright (C) 2023 Maximilian Luz <luzmaximilian@gmail.com>
*/
#include <linux/auxiliary_bus.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/firmware/qcom/qcom_qseecom.h>
#include <linux/firmware/qcom/qcom_scm.h>
struct qseecom_app_desc {
const char *app_name;
const char *dev_name;
};
static void qseecom_client_release(struct device *dev)
{
struct qseecom_client *client;
client = container_of(dev, struct qseecom_client, aux_dev.dev);
kfree(client);
}
static void qseecom_client_remove(void *data)
{
struct qseecom_client *client = data;
auxiliary_device_delete(&client->aux_dev);
auxiliary_device_uninit(&client->aux_dev);
}
static int qseecom_client_register(struct platform_device *qseecom_dev,
const struct qseecom_app_desc *desc)
{
struct qseecom_client *client;
u32 app_id;
int ret;
/* Try to find the app ID, skip device if not found */
ret = qcom_scm_qseecom_app_get_id(desc->app_name, &app_id);
if (ret)
return ret == -ENOENT ? 0 : ret;
dev_info(&qseecom_dev->dev, "setting up client for %s\n", desc->app_name);
/* Allocate and set-up the client device */
client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client)
return -ENOMEM;
client->aux_dev.name = desc->dev_name;
client->aux_dev.dev.parent = &qseecom_dev->dev;
client->aux_dev.dev.release = qseecom_client_release;
client->app_id = app_id;
ret = auxiliary_device_init(&client->aux_dev);
if (ret) {
kfree(client);
return ret;
}
ret = auxiliary_device_add(&client->aux_dev);
if (ret) {
auxiliary_device_uninit(&client->aux_dev);
return ret;
}
ret = devm_add_action_or_reset(&qseecom_dev->dev, qseecom_client_remove, client);
if (ret)
return ret;
return 0;
}
/*
* List of supported applications. One client device will be created per entry,
* assuming the app has already been loaded (usually by firmware bootloaders)
* and its ID can be queried successfully.
*/
static const struct qseecom_app_desc qcom_qseecom_apps[] = {
{ "qcom.tz.uefisecapp", "uefisecapp" },
};
static int qcom_qseecom_probe(struct platform_device *qseecom_dev)
{
int ret;
int i;
/* Set up client devices for each base application */
for (i = 0; i < ARRAY_SIZE(qcom_qseecom_apps); i++) {
ret = qseecom_client_register(qseecom_dev, &qcom_qseecom_apps[i]);
if (ret)
return ret;
}
return 0;
}
static struct platform_driver qcom_qseecom_driver = {
.driver = {
.name = "qcom_qseecom",
},
.probe = qcom_qseecom_probe,
};
static int __init qcom_qseecom_init(void)
{
return platform_driver_register(&qcom_qseecom_driver);
}
subsys_initcall(qcom_qseecom_init);
MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
MODULE_DESCRIPTION("Driver for the Qualcomm SEE (QSEECOM) interface");
MODULE_LICENSE("GPL");
This diff is collapsed.
......@@ -4,6 +4,8 @@
#ifndef __QCOM_SCM_INT_H
#define __QCOM_SCM_INT_H
struct device;
enum qcom_scm_convention {
SMC_CONVENTION_UNKNOWN,
SMC_CONVENTION_LEGACY,
......@@ -64,22 +66,22 @@ int qcom_scm_wait_for_wq_completion(u32 wq_ctx);
int scm_get_wq_ctx(u32 *wq_ctx, u32 *flags, u32 *more_pending);
#define SCM_SMC_FNID(s, c) ((((s) & 0xFF) << 8) | ((c) & 0xFF))
extern int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
enum qcom_scm_convention qcom_convention,
struct qcom_scm_res *res, bool atomic);
int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
enum qcom_scm_convention qcom_convention,
struct qcom_scm_res *res, bool atomic);
#define scm_smc_call(dev, desc, res, atomic) \
__scm_smc_call((dev), (desc), qcom_scm_convention, (res), (atomic))
#define SCM_LEGACY_FNID(s, c) (((s) << 10) | ((c) & 0x3ff))
extern int scm_legacy_call_atomic(struct device *dev,
const struct qcom_scm_desc *desc,
struct qcom_scm_res *res);
extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
int scm_legacy_call_atomic(struct device *dev, const struct qcom_scm_desc *desc,
struct qcom_scm_res *res);
int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc,
struct qcom_scm_res *res);
#define QCOM_SCM_SVC_BOOT 0x01
#define QCOM_SCM_BOOT_SET_ADDR 0x01
#define QCOM_SCM_BOOT_TERMINATE_PC 0x02
#define QCOM_SCM_BOOT_SDI_CONFIG 0x09
#define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10
#define QCOM_SCM_BOOT_SET_ADDR_MC 0x11
#define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a
......
......@@ -378,6 +378,7 @@ EXPORT_SYMBOL_GPL(rpi_firmware_get);
/**
* devm_rpi_firmware_get - Get pointer to rpi_firmware structure.
* @dev: The firmware device structure
* @firmware_node: Pointer to the firmware Device Tree node.
*
* Returns NULL is the firmware device is not ready.
......
......@@ -313,6 +313,8 @@ static ssize_t tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel,
return __tegra_bpmp_channel_write(channel, mrq, flags, data, size);
}
static int __maybe_unused tegra_bpmp_resume(struct device *dev);
int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp,
struct tegra_bpmp_message *msg)
{
......@@ -325,6 +327,14 @@ int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp,
if (!tegra_bpmp_message_valid(msg))
return -EINVAL;
if (bpmp->suspended) {
/* Reset BPMP IPC channels during resume based on flags passed */
if (msg->flags & TEGRA_BPMP_MESSAGE_RESET)
tegra_bpmp_resume(bpmp->dev);
else
return -EAGAIN;
}
channel = bpmp->tx_channel;
spin_lock(&bpmp->atomic_tx_lock);
......@@ -364,6 +374,14 @@ int tegra_bpmp_transfer(struct tegra_bpmp *bpmp,
if (!tegra_bpmp_message_valid(msg))
return -EINVAL;
if (bpmp->suspended) {
/* Reset BPMP IPC channels during resume based on flags passed */
if (msg->flags & TEGRA_BPMP_MESSAGE_RESET)
tegra_bpmp_resume(bpmp->dev);
else
return -EAGAIN;
}
channel = tegra_bpmp_write_threaded(bpmp, msg->mrq, msg->tx.data,
msg->tx.size);
if (IS_ERR(channel))
......@@ -796,10 +814,21 @@ static int tegra_bpmp_probe(struct platform_device *pdev)
return err;
}
static int __maybe_unused tegra_bpmp_suspend(struct device *dev)
{
struct tegra_bpmp *bpmp = dev_get_drvdata(dev);
bpmp->suspended = true;
return 0;
}
static int __maybe_unused tegra_bpmp_resume(struct device *dev)
{
struct tegra_bpmp *bpmp = dev_get_drvdata(dev);
bpmp->suspended = false;
if (bpmp->soc->ops->resume)
return bpmp->soc->ops->resume(bpmp);
else
......@@ -807,6 +836,7 @@ static int __maybe_unused tegra_bpmp_resume(struct device *dev)
}
static const struct dev_pm_ops tegra_bpmp_pm_ops = {
.suspend_noirq = tegra_bpmp_suspend,
.resume_noirq = tegra_bpmp_resume,
};
......
......@@ -16,7 +16,10 @@
#include <linux/kernel.h>
#include <linux/mailbox_client.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/semaphore.h>
#include <linux/slab.h>
#include <linux/soc/ti/ti-msgmgr.h>
......@@ -190,19 +193,6 @@ static int ti_sci_debugfs_create(struct platform_device *pdev,
return 0;
}
/**
* ti_sci_debugfs_destroy() - clean up log debug file
* @pdev: platform device pointer
* @info: Pointer to SCI entity information
*/
static void ti_sci_debugfs_destroy(struct platform_device *pdev,
struct ti_sci_info *info)
{
if (IS_ERR(info->debug_region))
return;
debugfs_remove(info->d);
}
#else /* CONFIG_DEBUG_FS */
static inline int ti_sci_debugfs_create(struct platform_device *dev,
struct ti_sci_info *info)
......@@ -485,7 +475,7 @@ static int ti_sci_cmd_get_revision(struct ti_sci_info *info)
ver->abi_major = rev_info->abi_major;
ver->abi_minor = rev_info->abi_minor;
ver->firmware_revision = rev_info->firmware_revision;
strncpy(ver->firmware_description, rev_info->firmware_description,
strscpy(ver->firmware_description, rev_info->firmware_description,
sizeof(ver->firmware_description));
fail:
......@@ -2886,7 +2876,6 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
const struct ti_sci_handle *ti_sci_get_handle(struct device *dev)
{
struct device_node *ti_sci_np;
struct list_head *p;
struct ti_sci_handle *handle = NULL;
struct ti_sci_info *info;
......@@ -2901,8 +2890,7 @@ const struct ti_sci_handle *ti_sci_get_handle(struct device *dev)
}
mutex_lock(&ti_sci_list_mutex);
list_for_each(p, &ti_sci_list) {
info = list_entry(p, struct ti_sci_info, node);
list_for_each_entry(info, &ti_sci_list, node) {
if (ti_sci_np == info->dev->of_node) {
handle = &info->handle;
info->users++;
......@@ -3012,7 +3000,6 @@ const struct ti_sci_handle *ti_sci_get_by_phandle(struct device_node *np,
struct ti_sci_handle *handle = NULL;
struct device_node *ti_sci_np;
struct ti_sci_info *info;
struct list_head *p;
if (!np) {
pr_err("I need a device pointer\n");
......@@ -3024,8 +3011,7 @@ const struct ti_sci_handle *ti_sci_get_by_phandle(struct device_node *np,
return ERR_PTR(-ENODEV);
mutex_lock(&ti_sci_list_mutex);
list_for_each(p, &ti_sci_list) {
info = list_entry(p, struct ti_sci_info, node);
list_for_each_entry(info, &ti_sci_list, node) {
if (ti_sci_np == info->dev->of_node) {
handle = &info->handle;
info->users++;
......@@ -3310,7 +3296,6 @@ MODULE_DEVICE_TABLE(of, ti_sci_of_match);
static int ti_sci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
const struct of_device_id *of_id;
const struct ti_sci_desc *desc;
struct ti_sci_xfer *xfer;
struct ti_sci_info *info = NULL;
......@@ -3321,12 +3306,7 @@ static int ti_sci_probe(struct platform_device *pdev)
int reboot = 0;
u32 h_id;
of_id = of_match_device(ti_sci_of_match, dev);
if (!of_id) {
dev_err(dev, "OF data missing\n");
return -EINVAL;
}
desc = of_id->data;
desc = device_get_match_data(dev);
info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
if (!info)
......@@ -3449,43 +3429,12 @@ static int ti_sci_probe(struct platform_device *pdev)
return ret;
}
static int ti_sci_remove(struct platform_device *pdev)
{
struct ti_sci_info *info;
struct device *dev = &pdev->dev;
int ret = 0;
of_platform_depopulate(dev);
info = platform_get_drvdata(pdev);
if (info->nb.notifier_call)
unregister_restart_handler(&info->nb);
mutex_lock(&ti_sci_list_mutex);
if (info->users)
ret = -EBUSY;
else
list_del(&info->node);
mutex_unlock(&ti_sci_list_mutex);
if (!ret) {
ti_sci_debugfs_destroy(pdev, info);
/* Safe to free channels since no more users */
mbox_free_channel(info->chan_tx);
mbox_free_channel(info->chan_rx);
}
return ret;
}
static struct platform_driver ti_sci_driver = {
.probe = ti_sci_probe,
.remove = ti_sci_remove,
.driver = {
.name = "ti-sci",
.of_match_table = of_match_ptr(ti_sci_of_match),
.suppress_bind_attrs = true,
},
};
module_platform_driver(ti_sci_driver);
......
......@@ -12,7 +12,10 @@
#include <linux/mfd/syscon/atmel-matrix.h>
#include <linux/mfd/syscon/atmel-smc.h>
#include <linux/init.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <soc/at91/atmel-sfr.h>
......@@ -30,7 +33,7 @@ struct atmel_ebi_dev {
struct atmel_ebi *ebi;
u32 mode;
int numcs;
struct atmel_ebi_dev_config configs[];
struct atmel_ebi_dev_config configs[] __counted_by(numcs);
};
struct atmel_ebi_caps {
......@@ -515,16 +518,11 @@ static int atmel_ebi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *child, *np = dev->of_node, *smc_np;
const struct of_device_id *match;
struct atmel_ebi *ebi;
int ret, reg_cells;
struct clk *clk;
u32 val;
match = of_match_device(atmel_ebi_id_table, dev);
if (!match || !match->data)
return -EINVAL;
ebi = devm_kzalloc(dev, sizeof(*ebi), GFP_KERNEL);
if (!ebi)
return -ENOMEM;
......@@ -532,7 +530,9 @@ static int atmel_ebi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ebi);
INIT_LIST_HEAD(&ebi->devs);
ebi->caps = match->data;
ebi->caps = device_get_match_data(dev);
if (!ebi->caps)
return -EINVAL;
ebi->dev = dev;
clk = devm_clk_get(dev, NULL);
......
......@@ -8,8 +8,9 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#define REG_MEMC_CNTRLR_CONFIG 0x00
#define CNTRLR_CONFIG_LPDDR4_SHIFT 5
......@@ -121,12 +122,9 @@ static struct attribute_group dev_attr_group = {
.attrs = dev_attrs,
};
static const struct of_device_id brcmstb_memc_of_match[];
static int brcmstb_memc_probe(struct platform_device *pdev)
{
const struct brcmstb_memc_data *memc_data;
const struct of_device_id *of_id;
struct device *dev = &pdev->dev;
struct brcmstb_memc *memc;
int ret;
......@@ -137,8 +135,7 @@ static int brcmstb_memc_probe(struct platform_device *pdev)
dev_set_drvdata(dev, memc);
of_id = of_match_device(brcmstb_memc_of_match, dev);
memc_data = of_id->data;
memc_data = device_get_match_data(dev);
memc->srpd_offset = memc_data->srpd_offset;
memc->ddr_ctrl = devm_platform_ioremap_resource(pdev, 0);
......
......@@ -10,10 +10,8 @@
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/property.h>
enum ccf_version {
CCF1,
......@@ -172,14 +170,9 @@ static irqreturn_t ccf_irq(int irq, void *dev_id)
static int ccf_probe(struct platform_device *pdev)
{
struct ccf_private *ccf;
const struct of_device_id *match;
u32 errinten;
int ret, irq;
match = of_match_device(ccf_matches, &pdev->dev);
if (WARN_ON(!match))
return -ENODEV;
ccf = devm_kzalloc(&pdev->dev, sizeof(*ccf), GFP_KERNEL);
if (!ccf)
return -ENOMEM;
......@@ -189,7 +182,7 @@ static int ccf_probe(struct platform_device *pdev)
return PTR_ERR(ccf->regs);
ccf->dev = &pdev->dev;
ccf->info = match->data;
ccf->info = device_get_match_data(&pdev->dev);
ccf->err_regs = ccf->regs + ccf->info->err_reg_offs;
if (ccf->info->has_brr) {
......
......@@ -449,6 +449,18 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
.security = 0x38c,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_VIW,
.name = "viw",
.bpmp_id = TEGRA_ICC_BPMP_VI,
.type = TEGRA_ICC_ISO_VI,
.sid = TEGRA234_SID_ISO_VI,
.regs = {
.sid = {
.override = 0x390,
.security = 0x394,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_NVDECSRD,
.name = "nvdecsrd",
......@@ -621,6 +633,30 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
.security = 0x50c,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_VIFALR,
.name = "vifalr",
.bpmp_id = TEGRA_ICC_BPMP_VIFAL,
.type = TEGRA_ICC_ISO_VIFAL,
.sid = TEGRA234_SID_ISO_VIFALC,
.regs = {
.sid = {
.override = 0x5e0,
.security = 0x5e4,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_VIFALW,
.name = "vifalw",
.bpmp_id = TEGRA_ICC_BPMP_VIFAL,
.type = TEGRA_ICC_ISO_VIFAL,
.sid = TEGRA234_SID_ISO_VIFALC,
.regs = {
.sid = {
.override = 0x5e8,
.security = 0x5ec,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_DLA0RDA,
.name = "dla0rda",
......@@ -701,6 +737,30 @@ static const struct tegra_mc_client tegra234_mc_clients[] = {
.security = 0x62c,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_RCER,
.name = "rcer",
.bpmp_id = TEGRA_ICC_BPMP_RCE,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_RCE,
.regs = {
.sid = {
.override = 0x690,
.security = 0x694,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_RCEW,
.name = "rcew",
.bpmp_id = TEGRA_ICC_BPMP_RCE,
.type = TEGRA_ICC_NISO,
.sid = TEGRA234_SID_RCE,
.regs = {
.sid = {
.override = 0x698,
.security = 0x69c,
},
},
}, {
.id = TEGRA234_MEMORY_CLIENT_PCIE0R,
.name = "pcie0r",
......@@ -986,6 +1046,10 @@ static int tegra234_mc_icc_set(struct icc_node *src, struct icc_node *dst)
msg.rx.data = &bwmgr_resp;
msg.rx.size = sizeof(bwmgr_resp);
if (pclient->bpmp_id >= TEGRA_ICC_BPMP_CPU_CLUSTER0 &&
pclient->bpmp_id <= TEGRA_ICC_BPMP_CPU_CLUSTER2)
msg.flags = TEGRA_BPMP_MESSAGE_RESET;
ret = tegra_bpmp_transfer(mc->bpmp, &msg);
if (ret < 0) {
dev_err(mc->dev, "BPMP transfer failed: %d\n", ret);
......
......@@ -2,6 +2,7 @@
obj-y += actions/
obj-y += amlogic/
obj-y += apple/
obj-y += arm/
obj-y += bcm/
obj-y += imx/
obj-y += mediatek/
......
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_ARM_SCMI_PERF_DOMAIN) += scmi_perf_domain.o
obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o
// SPDX-License-Identifier: GPL-2.0
/*
* SCMI performance domain support.
*
* Copyright (C) 2023 Linaro Ltd.
*/
#include <linux/err.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/pm_domain.h>
#include <linux/pm_opp.h>
#include <linux/scmi_protocol.h>
#include <linux/slab.h>
struct scmi_perf_domain {
struct generic_pm_domain genpd;
const struct scmi_perf_proto_ops *perf_ops;
const struct scmi_protocol_handle *ph;
const struct scmi_perf_domain_info *info;
u32 domain_id;
};
#define to_scmi_pd(pd) container_of(pd, struct scmi_perf_domain, genpd)
static int
scmi_pd_set_perf_state(struct generic_pm_domain *genpd, unsigned int state)
{
struct scmi_perf_domain *pd = to_scmi_pd(genpd);
int ret;
if (!pd->info->set_perf)
return 0;
if (!state)
return -EINVAL;
ret = pd->perf_ops->level_set(pd->ph, pd->domain_id, state, true);
if (ret)
dev_warn(&genpd->dev, "Failed with %d when trying to set %d perf level",
ret, state);
return ret;
}
static int
scmi_pd_attach_dev(struct generic_pm_domain *genpd, struct device *dev)
{
struct scmi_perf_domain *pd = to_scmi_pd(genpd);
int ret;
/*
* Allow the device to be attached, but don't add the OPP table unless
* the performance level can be changed.
*/
if (!pd->info->set_perf)
return 0;
ret = pd->perf_ops->device_opps_add(pd->ph, dev, pd->domain_id);
if (ret)
dev_warn(dev, "failed to add OPPs for the device\n");
return ret;
}
static void
scmi_pd_detach_dev(struct generic_pm_domain *genpd, struct device *dev)
{
struct scmi_perf_domain *pd = to_scmi_pd(genpd);
if (!pd->info->set_perf)
return;
dev_pm_opp_remove_all_dynamic(dev);
}
static int scmi_perf_domain_probe(struct scmi_device *sdev)
{
struct device *dev = &sdev->dev;
const struct scmi_handle *handle = sdev->handle;
const struct scmi_perf_proto_ops *perf_ops;
struct scmi_protocol_handle *ph;
struct scmi_perf_domain *scmi_pd;
struct genpd_onecell_data *scmi_pd_data;
struct generic_pm_domain **domains;
int num_domains, i, ret = 0;
if (!handle)
return -ENODEV;
/* The OF node must specify us as a power-domain provider. */
if (!of_find_property(dev->of_node, "#power-domain-cells", NULL))
return 0;
perf_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_PERF, &ph);
if (IS_ERR(perf_ops))
return PTR_ERR(perf_ops);
num_domains = perf_ops->num_domains_get(ph);
if (num_domains < 0) {
dev_warn(dev, "Failed with %d when getting num perf domains\n",
num_domains);
return num_domains;
} else if (!num_domains) {
return 0;
}
scmi_pd = devm_kcalloc(dev, num_domains, sizeof(*scmi_pd), GFP_KERNEL);
if (!scmi_pd)
return -ENOMEM;
scmi_pd_data = devm_kzalloc(dev, sizeof(*scmi_pd_data), GFP_KERNEL);
if (!scmi_pd_data)
return -ENOMEM;
domains = devm_kcalloc(dev, num_domains, sizeof(*domains), GFP_KERNEL);
if (!domains)
return -ENOMEM;
for (i = 0; i < num_domains; i++, scmi_pd++) {
scmi_pd->info = perf_ops->info_get(ph, i);
scmi_pd->domain_id = i;
scmi_pd->perf_ops = perf_ops;
scmi_pd->ph = ph;
scmi_pd->genpd.name = scmi_pd->info->name;
scmi_pd->genpd.flags = GENPD_FLAG_ALWAYS_ON |
GENPD_FLAG_OPP_TABLE_FW;
scmi_pd->genpd.set_performance_state = scmi_pd_set_perf_state;
scmi_pd->genpd.attach_dev = scmi_pd_attach_dev;
scmi_pd->genpd.detach_dev = scmi_pd_detach_dev;
ret = pm_genpd_init(&scmi_pd->genpd, NULL, false);
if (ret)
goto err;
domains[i] = &scmi_pd->genpd;
}
scmi_pd_data->domains = domains;
scmi_pd_data->num_domains = num_domains;
ret = of_genpd_add_provider_onecell(dev->of_node, scmi_pd_data);
if (ret)
goto err;
dev_set_drvdata(dev, scmi_pd_data);
dev_info(dev, "Initialized %d performance domains", num_domains);
return 0;
err:
for (i--; i >= 0; i--)
pm_genpd_remove(domains[i]);
return ret;
}
static void scmi_perf_domain_remove(struct scmi_device *sdev)
{
struct device *dev = &sdev->dev;
struct genpd_onecell_data *scmi_pd_data = dev_get_drvdata(dev);
int i;
of_genpd_del_provider(dev->of_node);
for (i = 0; i < scmi_pd_data->num_domains; i++)
pm_genpd_remove(scmi_pd_data->domains[i]);
}
static const struct scmi_device_id scmi_id_table[] = {
{ SCMI_PROTOCOL_PERF, "perf" },
{ },
};
MODULE_DEVICE_TABLE(scmi, scmi_id_table);
static struct scmi_driver scmi_perf_domain_driver = {
.name = "scmi-perf-domain",
.probe = scmi_perf_domain_probe,
.remove = scmi_perf_domain_remove,
.id_table = scmi_id_table,
};
module_scmi_driver(scmi_perf_domain_driver);
MODULE_AUTHOR("Ulf Hansson <ulf.hansson@linaro.org>");
MODULE_DESCRIPTION("ARM SCMI perf domain driver");
MODULE_LICENSE("GPL v2");
......@@ -332,14 +332,12 @@ static int aspeed_lpc_ctrl_probe(struct platform_device *pdev)
return rc;
}
static int aspeed_lpc_ctrl_remove(struct platform_device *pdev)
static void aspeed_lpc_ctrl_remove(struct platform_device *pdev)
{
struct aspeed_lpc_ctrl *lpc_ctrl = dev_get_drvdata(&pdev->dev);
misc_deregister(&lpc_ctrl->miscdev);
clk_disable_unprepare(lpc_ctrl->clk);
return 0;
}
static const struct of_device_id aspeed_lpc_ctrl_match[] = {
......@@ -355,7 +353,7 @@ static struct platform_driver aspeed_lpc_ctrl_driver = {
.of_match_table = aspeed_lpc_ctrl_match,
},
.probe = aspeed_lpc_ctrl_probe,
.remove = aspeed_lpc_ctrl_remove,
.remove_new = aspeed_lpc_ctrl_remove,
};
module_platform_driver(aspeed_lpc_ctrl_driver);
......
......@@ -331,7 +331,7 @@ static int aspeed_lpc_snoop_probe(struct platform_device *pdev)
return rc;
}
static int aspeed_lpc_snoop_remove(struct platform_device *pdev)
static void aspeed_lpc_snoop_remove(struct platform_device *pdev)
{
struct aspeed_lpc_snoop *lpc_snoop = dev_get_drvdata(&pdev->dev);
......@@ -340,8 +340,6 @@ static int aspeed_lpc_snoop_remove(struct platform_device *pdev)
aspeed_lpc_disable_snoop(lpc_snoop, 1);
clk_disable_unprepare(lpc_snoop->clk);
return 0;
}
static const struct aspeed_lpc_snoop_model_data ast2400_model_data = {
......@@ -368,7 +366,7 @@ static struct platform_driver aspeed_lpc_snoop_driver = {
.of_match_table = aspeed_lpc_snoop_match,
},
.probe = aspeed_lpc_snoop_probe,
.remove = aspeed_lpc_snoop_remove,
.remove_new = aspeed_lpc_snoop_remove,
};
module_platform_driver(aspeed_lpc_snoop_driver);
......
......@@ -383,13 +383,11 @@ static int aspeed_p2a_ctrl_probe(struct platform_device *pdev)
return rc;
}
static int aspeed_p2a_ctrl_remove(struct platform_device *pdev)
static void aspeed_p2a_ctrl_remove(struct platform_device *pdev)
{
struct aspeed_p2a_ctrl *p2a_ctrl = dev_get_drvdata(&pdev->dev);
misc_deregister(&p2a_ctrl->miscdev);
return 0;
}
#define SCU2C_DRAM BIT(25)
......@@ -433,7 +431,7 @@ static struct platform_driver aspeed_p2a_ctrl_driver = {
.of_match_table = aspeed_p2a_ctrl_match,
},
.probe = aspeed_p2a_ctrl_probe,
.remove = aspeed_p2a_ctrl_remove,
.remove_new = aspeed_p2a_ctrl_remove,
};
module_platform_driver(aspeed_p2a_ctrl_driver);
......
......@@ -565,14 +565,12 @@ static int aspeed_uart_routing_probe(struct platform_device *pdev)
return 0;
}
static int aspeed_uart_routing_remove(struct platform_device *pdev)
static void aspeed_uart_routing_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct aspeed_uart_routing *uart_routing = platform_get_drvdata(pdev);
sysfs_remove_group(&dev->kobj, uart_routing->attr_grp);
return 0;
}
static const struct of_device_id aspeed_uart_routing_table[] = {
......@@ -591,7 +589,7 @@ static struct platform_driver aspeed_uart_routing_driver = {
.of_match_table = aspeed_uart_routing_table,
},
.probe = aspeed_uart_routing_probe,
.remove = aspeed_uart_routing_remove,
.remove_new = aspeed_uart_routing_remove,
};
module_platform_driver(aspeed_uart_routing_driver);
......
......@@ -3,7 +3,7 @@ menu "Broadcom SoC drivers"
config SOC_BRCMSTB
bool "Broadcom STB SoC drivers"
depends on ARM || ARM64 || BMIPS_GENERIC || COMPILE_TEST
depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
select SOC_BUS
help
Enables drivers for the Broadcom Set-Top Box (STB) series of chips.
......
......@@ -410,13 +410,16 @@ int __init dove_init_pmu(void)
struct pmu_domain *domain;
domain = kzalloc(sizeof(*domain), GFP_KERNEL);
if (!domain)
if (!domain) {
of_node_put(np);
break;
}
domain->pmu = pmu;
domain->base.name = kasprintf(GFP_KERNEL, "%pOFn", np);
if (!domain->base.name) {
kfree(domain);
of_node_put(np);
break;
}
......
......@@ -300,12 +300,10 @@ static int dpaa2_console_probe(struct platform_device *pdev)
return error;
}
static int dpaa2_console_remove(struct platform_device *pdev)
static void dpaa2_console_remove(struct platform_device *pdev)
{
misc_deregister(&dpaa2_mc_console_dev);
misc_deregister(&dpaa2_aiop_console_dev);
return 0;
}
static const struct of_device_id dpaa2_console_match_table[] = {
......@@ -322,7 +320,7 @@ static struct platform_driver dpaa2_console_driver = {
.of_match_table = dpaa2_console_match_table,
},
.probe = dpaa2_console_probe,
.remove = dpaa2_console_remove,
.remove_new = dpaa2_console_remove,
};
module_platform_driver(dpaa2_console_driver);
......
......@@ -1415,7 +1415,7 @@ static int qmc_probe(struct platform_device *pdev)
return ret;
}
static int qmc_remove(struct platform_device *pdev)
static void qmc_remove(struct platform_device *pdev)
{
struct qmc *qmc = platform_get_drvdata(pdev);
......@@ -1427,8 +1427,6 @@ static int qmc_remove(struct platform_device *pdev)
/* Disconnect the serial from TSA */
tsa_serial_disconnect(qmc->tsa_serial);
return 0;
}
static const struct of_device_id qmc_id_table[] = {
......@@ -1443,7 +1441,7 @@ static struct platform_driver qmc_driver = {
.of_match_table = of_match_ptr(qmc_id_table),
},
.probe = qmc_probe,
.remove = qmc_remove,
.remove_new = qmc_remove,
};
module_platform_driver(qmc_driver);
......
......@@ -706,7 +706,7 @@ static int tsa_probe(struct platform_device *pdev)
return 0;
}
static int tsa_remove(struct platform_device *pdev)
static void tsa_remove(struct platform_device *pdev)
{
struct tsa *tsa = platform_get_drvdata(pdev);
int i;
......@@ -729,7 +729,6 @@ static int tsa_remove(struct platform_device *pdev)
clk_put(tsa->tdm[i].l1rclk_clk);
}
}
return 0;
}
static const struct of_device_id tsa_id_table[] = {
......@@ -744,7 +743,7 @@ static struct platform_driver tsa_driver = {
.of_match_table = of_match_ptr(tsa_id_table),
},
.probe = tsa_probe,
.remove = tsa_remove,
.remove_new = tsa_remove,
};
module_platform_driver(tsa_driver);
......
......@@ -116,7 +116,7 @@ static int a64fx_diag_probe(struct platform_device *pdev)
return 0;
}
static int a64fx_diag_remove(struct platform_device *pdev)
static void a64fx_diag_remove(struct platform_device *pdev)
{
struct a64fx_diag_priv *priv = platform_get_drvdata(pdev);
......@@ -127,8 +127,6 @@ static int a64fx_diag_remove(struct platform_device *pdev)
free_nmi(priv->irq, NULL);
else
free_irq(priv->irq, NULL);
return 0;
}
static const struct acpi_device_id a64fx_diag_acpi_match[] = {
......@@ -144,7 +142,7 @@ static struct platform_driver a64fx_diag_driver = {
.acpi_match_table = ACPI_PTR(a64fx_diag_acpi_match),
},
.probe = a64fx_diag_probe,
.remove = a64fx_diag_remove,
.remove_new = a64fx_diag_remove,
};
module_platform_driver(a64fx_diag_driver);
......
......@@ -1240,14 +1240,12 @@ static int hccs_probe(struct platform_device *pdev)
return rc;
}
static int hccs_remove(struct platform_device *pdev)
static void hccs_remove(struct platform_device *pdev)
{
struct hccs_dev *hdev = platform_get_drvdata(pdev);
hccs_remove_topo_dirs(hdev);
hccs_unregister_pcc_channel(hdev);
return 0;
}
static const struct acpi_device_id hccs_acpi_match[] = {
......@@ -1258,7 +1256,7 @@ MODULE_DEVICE_TABLE(acpi, hccs_acpi_match);
static struct platform_driver hccs_driver = {
.probe = hccs_probe,
.remove = hccs_remove,
.remove_new = hccs_remove,
.driver = {
.name = "kunpeng_hccs",
.acpi_match_table = hccs_acpi_match,
......
This diff is collapsed.
......@@ -442,11 +442,10 @@ static int ixp4xx_qmgr_probe(struct platform_device *pdev)
return 0;
}
static int ixp4xx_qmgr_remove(struct platform_device *pdev)
static void ixp4xx_qmgr_remove(struct platform_device *pdev)
{
synchronize_irq(qmgr_irq_1);
synchronize_irq(qmgr_irq_2);
return 0;
}
static const struct of_device_id ixp4xx_qmgr_of_match[] = {
......@@ -462,7 +461,7 @@ static struct platform_driver ixp4xx_qmgr_driver = {
.of_match_table = ixp4xx_qmgr_of_match,
},
.probe = ixp4xx_qmgr_probe,
.remove = ixp4xx_qmgr_remove,
.remove_new = ixp4xx_qmgr_remove,
};
module_platform_driver(ixp4xx_qmgr_driver);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment