Qualcomm driver updates for v5.8
This contains a large set of cleanups, bug fixes, general improvements and documentation fixes for the RPMH driver. It adds a debugfs mechanism for inspecting Command DB. Socinfo got the "soc_id" attribute defines and definitions for a various variants of MSM8939. RPMH, RPMPD and RPMHPD where made possible to build as modules, but RPMH had to be reverted due to a compilation issue when tracing is enabled. RPMHPD gained power-domains for the SM8250 voltage corners. The SCM driver gained fixes for two build warnings and the SMP2P had an unnecessary error print removed. -----BEGIN PGP SIGNATURE----- iQJPBAABCAA5FiEEBd4DzF816k8JZtUlCx85Pw2ZrcUFAl7DZcEbHGJqb3JuLmFu ZGVyc3NvbkBsaW5hcm8ub3JnAAoJEAsfOT8Nma3FEwIQAK1TrENzsRjB23fY4pEW +hN/SkfMjNPsinmyNOHCo03MQzdFIKUl40aNvaHh3foQXaSG4TW12iot9Ul5nsxn /u6dCSzl15FK7pHYj/VQPWTz2WvpANVqsm6G5tf43hBg2TnStbK1AsxgJ6aq47fp QHehMbfeKpF/gltEowv1b+H7xwNFY7eqlQ9O9umYm3hUQh3Bl5mI6PdbkazDdO1j l/vHuQKkZXRdHtD1BxGBfvhPtM4NWDbOPeWWrw8HRFM5muDPgK9mXMRGDcv+fpHq 4I3670xiTWK1Mfz9+FRBMoxLkIWT6zXILg9aNzuZMTOLoNRt3s6VNdne6uf3naND 2Nrcu7t0b+4xWGbdwwpiAFZm8C6l+R1WTCiY4iOJXDychhVvyVwOLzPdZ4i8Pzx9 a4UJDElu8xj2g++oCcjK816IdNwkA46bM7qVz4mkHRUBMkmK9AU7okBA9HQfbP64 MrKPaUljyZuy7zonpJJBBDKLDEFa9a1pI8sehU8p+MUldxYB/4f/iGC3KzyDvv4Q Uzj6AqdP5pjgIxz98YgpOPPl8pwg1c5OgblNLWoHj4yTaqUzT0ZHIRyQO/O/+3Lg HwCrSy+f3+tgzts3DhyVRmOkOXFHfflSdf4rfKtbiq435yB2dz60dt77dJ0jQuBV M9MiF+SE9oASUupPhs47kNte =tkhb -----END PGP SIGNATURE----- Merge tag 'qcom-drivers-for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into arm/drivers Qualcomm driver updates for v5.8 This contains a large set of cleanups, bug fixes, general improvements and documentation fixes for the RPMH driver. It adds a debugfs mechanism for inspecting Command DB. Socinfo got the "soc_id" attribute defines and definitions for a various variants of MSM8939. RPMH, RPMPD and RPMHPD where made possible to build as modules, but RPMH had to be reverted due to a compilation issue when tracing is enabled. RPMHPD gained power-domains for the SM8250 voltage corners. The SCM driver gained fixes for two build warnings and the SMP2P had an unnecessary error print removed. * tag 'qcom-drivers-for-5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux: (42 commits) Revert "soc: qcom: rpmh: Allow RPMH driver to be loaded as a module" soc: qcom: rpmh-rsc: Remove the pm_lock soc: qcom: rpmh-rsc: Simplify locking by eliminating the per-TCS lock kernel/cpu_pm: Fix uninitted local in cpu_pm soc: qcom: rpmh-rsc: We aren't notified of our own failure w/ NOTIFY_BAD soc: qcom: rpmh-rsc: Correctly ignore CPU_CLUSTER_PM notifications firmware: qcom_scm-legacy: Replace zero-length array with flexible-array soc: qcom: rpmh-rsc: Timeout after 1 second in write_tcs_reg_sync() soc: qcom: rpmh-rsc: Factor "tcs_reg_addr" and "tcs_cmd_addr" calculation soc: qcom: socinfo: add msm8936/39 and apq8036/39 soc ids soc: qcom: aoss: Add SM8250 compatible soc: qcom: pdr: Remove impossible error condition soc: qcom: rpmh: Dirt can only make you dirtier, not cleaner soc: qcom: rpmhpd: Add SM8250 power domains firmware: qcom_scm: fix bogous abuse of dma-direct internals dt-bindings: soc: qcom: apr: Use generic node names for APR services firmware: qcom_scm: Remove unneeded conversion to bool soc: qcom: cmd-db: Properly endian swap the slv_id for debugfs soc: qcom: cmd-db: Use 5 digits for printing address soc: qcom: cmd-db: Cast sizeof() to int to silence field width warning ... Link: https://lore.kernel.org/r/20200519052533.1250024-1-bjorn.andersson@linaro.org Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
502afe7f04
@ -23,6 +23,7 @@ properties:
|
||||
- qcom,sc7180-rpmhpd
|
||||
- qcom,sdm845-rpmhpd
|
||||
- qcom,sm8150-rpmhpd
|
||||
- qcom,sm8250-rpmhpd
|
||||
|
||||
'#power-domain-cells':
|
||||
const: 1
|
||||
|
@ -19,6 +19,7 @@ power-domains.
|
||||
"qcom,sc7180-aoss-qmp"
|
||||
"qcom,sdm845-aoss-qmp"
|
||||
"qcom,sm8150-aoss-qmp"
|
||||
"qcom,sm8250-aoss-qmp"
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
|
@ -65,30 +65,30 @@ which uses apr as communication between Apps and QDSP.
|
||||
compatible = "qcom,apr-v2";
|
||||
qcom,apr-domain = <APR_DOMAIN_ADSP>;
|
||||
|
||||
q6core@3 {
|
||||
apr-service@3 {
|
||||
compatible = "qcom,q6core";
|
||||
reg = <APR_SVC_ADSP_CORE>;
|
||||
};
|
||||
|
||||
q6afe@4 {
|
||||
apr-service@4 {
|
||||
compatible = "qcom,q6afe";
|
||||
reg = <APR_SVC_AFE>;
|
||||
|
||||
dais {
|
||||
#sound-dai-cells = <1>;
|
||||
hdmi@1 {
|
||||
reg = <1>;
|
||||
dai@1 {
|
||||
reg = <HDMI_RX>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
q6asm@7 {
|
||||
apr-service@7 {
|
||||
compatible = "qcom,q6asm";
|
||||
reg = <APR_SVC_ASM>;
|
||||
...
|
||||
};
|
||||
|
||||
q6adm@8 {
|
||||
apr-service@8 {
|
||||
compatible = "qcom,q6adm";
|
||||
reg = <APR_SVC_ADM>;
|
||||
...
|
||||
@ -106,26 +106,26 @@ have no such dependency.
|
||||
qcom,glink-channels = "apr_audio_svc";
|
||||
qcom,apr-domain = <APR_DOMAIN_ADSP>;
|
||||
|
||||
q6core {
|
||||
apr-service@3 {
|
||||
compatible = "qcom,q6core";
|
||||
reg = <APR_SVC_ADSP_CORE>;
|
||||
};
|
||||
|
||||
q6afe: q6afe {
|
||||
q6afe: apr-service@4 {
|
||||
compatible = "qcom,q6afe";
|
||||
reg = <APR_SVC_AFE>;
|
||||
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
|
||||
...
|
||||
};
|
||||
|
||||
q6asm: q6asm {
|
||||
q6asm: apr-service@7 {
|
||||
compatible = "qcom,q6asm";
|
||||
reg = <APR_SVC_ASM>;
|
||||
qcom,protection-domain = "tms/servreg", "msm/slpi/sensor_pd";
|
||||
...
|
||||
};
|
||||
|
||||
q6adm: q6adm {
|
||||
q6adm: apr-service@8 {
|
||||
compatible = "qcom,q6adm";
|
||||
reg = <APR_SVC_ADM>;
|
||||
qcom,protection-domain = "avs/audio", "msm/adsp/audio_pd";
|
||||
|
@ -56,7 +56,7 @@ struct scm_legacy_command {
|
||||
__le32 buf_offset;
|
||||
__le32 resp_hdr_offset;
|
||||
__le32 id;
|
||||
__le32 buf[0];
|
||||
__le32 buf[];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/dma-direct.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
@ -806,8 +805,7 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
|
||||
struct qcom_scm_mem_map_info *mem_to_map;
|
||||
phys_addr_t mem_to_map_phys;
|
||||
phys_addr_t dest_phys;
|
||||
phys_addr_t ptr_phys;
|
||||
dma_addr_t ptr_dma;
|
||||
dma_addr_t ptr_phys;
|
||||
size_t mem_to_map_sz;
|
||||
size_t dest_sz;
|
||||
size_t src_sz;
|
||||
@ -824,10 +822,9 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
|
||||
ptr_sz = ALIGN(src_sz, SZ_64) + ALIGN(mem_to_map_sz, SZ_64) +
|
||||
ALIGN(dest_sz, SZ_64);
|
||||
|
||||
ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_dma, GFP_KERNEL);
|
||||
ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_phys, GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
ptr_phys = dma_to_phys(__scm->dev, ptr_dma);
|
||||
|
||||
/* Fill source vmid detail */
|
||||
src = ptr;
|
||||
@ -855,7 +852,7 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
|
||||
|
||||
ret = __qcom_scm_assign_mem(__scm->dev, mem_to_map_phys, mem_to_map_sz,
|
||||
ptr_phys, src_sz, dest_phys, dest_sz);
|
||||
dma_free_coherent(__scm->dev, ptr_sz, ptr, ptr_dma);
|
||||
dma_free_coherent(__scm->dev, ptr_sz, ptr, ptr_phys);
|
||||
if (ret) {
|
||||
dev_err(__scm->dev,
|
||||
"Assign memory protection call failed %d\n", ret);
|
||||
@ -943,7 +940,7 @@ bool qcom_scm_hdcp_available(void)
|
||||
|
||||
qcom_scm_clk_disable();
|
||||
|
||||
return ret > 0 ? true : false;
|
||||
return ret > 0;
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_scm_hdcp_available);
|
||||
|
||||
|
@ -117,7 +117,7 @@ config QCOM_RPMH
|
||||
help apply the aggregated state on the resource.
|
||||
|
||||
config QCOM_RPMHPD
|
||||
bool "Qualcomm RPMh Power domain driver"
|
||||
tristate "Qualcomm RPMh Power domain driver"
|
||||
depends on QCOM_RPMH && QCOM_COMMAND_DB
|
||||
help
|
||||
QCOM RPMh Power domain driver to support power-domains with
|
||||
@ -126,8 +126,8 @@ config QCOM_RPMHPD
|
||||
for the voltage rail.
|
||||
|
||||
config QCOM_RPMPD
|
||||
bool "Qualcomm RPM Power domain driver"
|
||||
depends on QCOM_SMD_RPM=y
|
||||
tristate "Qualcomm RPM Power domain driver"
|
||||
depends on QCOM_SMD_RPM
|
||||
help
|
||||
QCOM RPM Power domain driver to support power-domains with
|
||||
performance states. The driver communicates a performance state
|
||||
|
@ -1,12 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. */
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <soc/qcom/cmd-db.h>
|
||||
@ -236,6 +237,77 @@ enum cmd_db_hw_type cmd_db_read_slave_id(const char *id)
|
||||
}
|
||||
EXPORT_SYMBOL(cmd_db_read_slave_id);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
static int cmd_db_debugfs_dump(struct seq_file *seq, void *p)
|
||||
{
|
||||
int i, j;
|
||||
const struct rsc_hdr *rsc;
|
||||
const struct entry_header *ent;
|
||||
const char *name;
|
||||
u16 len, version;
|
||||
u8 major, minor;
|
||||
|
||||
seq_puts(seq, "Command DB DUMP\n");
|
||||
|
||||
for (i = 0; i < MAX_SLV_ID; i++) {
|
||||
rsc = &cmd_db_header->header[i];
|
||||
if (!rsc->slv_id)
|
||||
break;
|
||||
|
||||
switch (le16_to_cpu(rsc->slv_id)) {
|
||||
case CMD_DB_HW_ARC:
|
||||
name = "ARC";
|
||||
break;
|
||||
case CMD_DB_HW_VRM:
|
||||
name = "VRM";
|
||||
break;
|
||||
case CMD_DB_HW_BCM:
|
||||
name = "BCM";
|
||||
break;
|
||||
default:
|
||||
name = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
version = le16_to_cpu(rsc->version);
|
||||
major = version >> 8;
|
||||
minor = version;
|
||||
|
||||
seq_printf(seq, "Slave %s (v%u.%u)\n", name, major, minor);
|
||||
seq_puts(seq, "-------------------------\n");
|
||||
|
||||
ent = rsc_to_entry_header(rsc);
|
||||
for (j = 0; j < le16_to_cpu(rsc->cnt); j++, ent++) {
|
||||
seq_printf(seq, "0x%05x: %*pEp", le32_to_cpu(ent->addr),
|
||||
(int)sizeof(ent->id), ent->id);
|
||||
|
||||
len = le16_to_cpu(ent->len);
|
||||
if (len) {
|
||||
seq_printf(seq, " [%*ph]",
|
||||
len, rsc_offset(rsc, ent));
|
||||
}
|
||||
seq_putc(seq, '\n');
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int open_cmd_db_debugfs(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, cmd_db_debugfs_dump, inode->i_private);
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct file_operations cmd_db_debugfs_ops = {
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
.open = open_cmd_db_debugfs,
|
||||
#endif
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int cmd_db_dev_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct reserved_mem *rmem;
|
||||
@ -259,12 +331,14 @@ static int cmd_db_dev_probe(struct platform_device *pdev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
debugfs_create_file("cmd-db", 0400, NULL, NULL, &cmd_db_debugfs_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id cmd_db_match_table[] = {
|
||||
{ .compatible = "qcom,cmd-db" },
|
||||
{ },
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct platform_driver cmd_db_dev_driver = {
|
||||
|
@ -155,10 +155,6 @@ static int pdr_register_listener(struct pdr_handle *pdr,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((int)resp.curr_state < INT_MIN || (int)resp.curr_state > INT_MAX)
|
||||
pr_err("PDR: %s notification state invalid: 0x%x\n",
|
||||
pds->service_path, resp.curr_state);
|
||||
|
||||
pds->state = resp.curr_state;
|
||||
|
||||
return 0;
|
||||
|
@ -599,6 +599,7 @@ static const struct of_device_id qmp_dt_match[] = {
|
||||
{ .compatible = "qcom,sc7180-aoss-qmp", },
|
||||
{ .compatible = "qcom,sdm845-aoss-qmp", },
|
||||
{ .compatible = "qcom,sm8150-aoss-qmp", },
|
||||
{ .compatible = "qcom,sm8250-aoss-qmp", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, qmp_dt_match);
|
||||
|
@ -22,16 +22,23 @@ struct rsc_drv;
|
||||
* struct tcs_group: group of Trigger Command Sets (TCS) to send state requests
|
||||
* to the controller
|
||||
*
|
||||
* @drv: the controller
|
||||
* @type: type of the TCS in this group - active, sleep, wake
|
||||
* @mask: mask of the TCSes relative to all the TCSes in the RSC
|
||||
* @offset: start of the TCS group relative to the TCSes in the RSC
|
||||
* @num_tcs: number of TCSes in this type
|
||||
* @ncpt: number of commands in each TCS
|
||||
* @lock: lock for synchronizing this TCS writes
|
||||
* @req: requests that are sent from the TCS
|
||||
* @cmd_cache: flattened cache of cmds in sleep/wake TCS
|
||||
* @slots: indicates which of @cmd_addr are occupied
|
||||
* @drv: The controller.
|
||||
* @type: Type of the TCS in this group - active, sleep, wake.
|
||||
* @mask: Mask of the TCSes relative to all the TCSes in the RSC.
|
||||
* @offset: Start of the TCS group relative to the TCSes in the RSC.
|
||||
* @num_tcs: Number of TCSes in this type.
|
||||
* @ncpt: Number of commands in each TCS.
|
||||
* @req: Requests that are sent from the TCS; only used for ACTIVE_ONLY
|
||||
* transfers (could be on a wake/sleep TCS if we are borrowing for
|
||||
* an ACTIVE_ONLY transfer).
|
||||
* Start: grab drv->lock, set req, set tcs_in_use, drop drv->lock,
|
||||
* trigger
|
||||
* End: get irq, access req,
|
||||
* grab drv->lock, clear tcs_in_use, drop drv->lock
|
||||
* @slots: Indicates which of @cmd_addr are occupied; only used for
|
||||
* SLEEP / WAKE TCSs. Things are tightly packed in the
|
||||
* case that (ncpt < MAX_CMDS_PER_TCS). That is if ncpt = 2 and
|
||||
* MAX_CMDS_PER_TCS = 16 then bit[2] = the first bit in 2nd TCS.
|
||||
*/
|
||||
struct tcs_group {
|
||||
struct rsc_drv *drv;
|
||||
@ -40,9 +47,7 @@ struct tcs_group {
|
||||
u32 offset;
|
||||
int num_tcs;
|
||||
int ncpt;
|
||||
spinlock_t lock;
|
||||
const struct tcs_request *req[MAX_TCS_PER_TYPE];
|
||||
u32 *cmd_cache;
|
||||
DECLARE_BITMAP(slots, MAX_TCS_SLOTS);
|
||||
};
|
||||
|
||||
@ -84,20 +89,32 @@ struct rpmh_ctrlr {
|
||||
* struct rsc_drv: the Direct Resource Voter (DRV) of the
|
||||
* Resource State Coordinator controller (RSC)
|
||||
*
|
||||
* @name: controller identifier
|
||||
* @tcs_base: start address of the TCS registers in this controller
|
||||
* @id: instance id in the controller (Direct Resource Voter)
|
||||
* @num_tcs: number of TCSes in this DRV
|
||||
* @tcs: TCS groups
|
||||
* @tcs_in_use: s/w state of the TCS
|
||||
* @lock: synchronize state of the controller
|
||||
* @client: handle to the DRV's client.
|
||||
* @name: Controller identifier.
|
||||
* @tcs_base: Start address of the TCS registers in this controller.
|
||||
* @id: Instance id in the controller (Direct Resource Voter).
|
||||
* @num_tcs: Number of TCSes in this DRV.
|
||||
* @rsc_pm: CPU PM notifier for controller.
|
||||
* Used when solver mode is not present.
|
||||
* @cpus_in_pm: Number of CPUs not in idle power collapse.
|
||||
* Used when solver mode is not present.
|
||||
* @tcs: TCS groups.
|
||||
* @tcs_in_use: S/W state of the TCS; only set for ACTIVE_ONLY
|
||||
* transfers, but might show a sleep/wake TCS in use if
|
||||
* it was borrowed for an active_only transfer. You
|
||||
* must hold the lock in this struct (AKA drv->lock) in
|
||||
* order to update this.
|
||||
* @lock: Synchronize state of the controller. If RPMH's cache
|
||||
* lock will also be held, the order is: drv->lock then
|
||||
* cache_lock.
|
||||
* @client: Handle to the DRV's client.
|
||||
*/
|
||||
struct rsc_drv {
|
||||
const char *name;
|
||||
void __iomem *tcs_base;
|
||||
int id;
|
||||
int num_tcs;
|
||||
struct notifier_block rsc_pm;
|
||||
atomic_t cpus_in_pm;
|
||||
struct tcs_group tcs[TCS_TYPE_NR];
|
||||
DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR);
|
||||
spinlock_t lock;
|
||||
@ -107,7 +124,7 @@ struct rsc_drv {
|
||||
int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg);
|
||||
int rpmh_rsc_write_ctrl_data(struct rsc_drv *drv,
|
||||
const struct tcs_request *msg);
|
||||
int rpmh_rsc_invalidate(struct rsc_drv *drv);
|
||||
void rpmh_rsc_invalidate(struct rsc_drv *drv);
|
||||
|
||||
void rpmh_tx_done(const struct tcs_request *msg, int r);
|
||||
int rpmh_flush(struct rpmh_ctrlr *ctrlr);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,7 @@
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
@ -119,6 +120,7 @@ static struct cache_req *cache_rpm_request(struct rpmh_ctrlr *ctrlr,
|
||||
{
|
||||
struct cache_req *req;
|
||||
unsigned long flags;
|
||||
u32 old_sleep_val, old_wake_val;
|
||||
|
||||
spin_lock_irqsave(&ctrlr->cache_lock, flags);
|
||||
req = __find_req(ctrlr, cmd->addr);
|
||||
@ -133,26 +135,27 @@ static struct cache_req *cache_rpm_request(struct rpmh_ctrlr *ctrlr,
|
||||
|
||||
req->addr = cmd->addr;
|
||||
req->sleep_val = req->wake_val = UINT_MAX;
|
||||
INIT_LIST_HEAD(&req->list);
|
||||
list_add_tail(&req->list, &ctrlr->cache);
|
||||
|
||||
existing:
|
||||
old_sleep_val = req->sleep_val;
|
||||
old_wake_val = req->wake_val;
|
||||
|
||||
switch (state) {
|
||||
case RPMH_ACTIVE_ONLY_STATE:
|
||||
if (req->sleep_val != UINT_MAX)
|
||||
req->wake_val = cmd->data;
|
||||
break;
|
||||
case RPMH_WAKE_ONLY_STATE:
|
||||
req->wake_val = cmd->data;
|
||||
break;
|
||||
case RPMH_SLEEP_STATE:
|
||||
req->sleep_val = cmd->data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ctrlr->dirty = true;
|
||||
ctrlr->dirty |= (req->sleep_val != old_sleep_val ||
|
||||
req->wake_val != old_wake_val) &&
|
||||
req->sleep_val != UINT_MAX &&
|
||||
req->wake_val != UINT_MAX;
|
||||
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
|
||||
|
||||
@ -287,6 +290,7 @@ static void cache_batch(struct rpmh_ctrlr *ctrlr, struct batch_cache_req *req)
|
||||
|
||||
spin_lock_irqsave(&ctrlr->cache_lock, flags);
|
||||
list_add_tail(&req->list, &ctrlr->batch_cache);
|
||||
ctrlr->dirty = true;
|
||||
spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
|
||||
}
|
||||
|
||||
@ -294,12 +298,10 @@ static int flush_batch(struct rpmh_ctrlr *ctrlr)
|
||||
{
|
||||
struct batch_cache_req *req;
|
||||
const struct rpmh_request *rpm_msg;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
/* Send Sleep/Wake requests to the controller, expect no response */
|
||||
spin_lock_irqsave(&ctrlr->cache_lock, flags);
|
||||
list_for_each_entry(req, &ctrlr->batch_cache, list) {
|
||||
for (i = 0; i < req->count; i++) {
|
||||
rpm_msg = req->rpm_msgs + i;
|
||||
@ -309,23 +311,10 @@ static int flush_batch(struct rpmh_ctrlr *ctrlr)
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void invalidate_batch(struct rpmh_ctrlr *ctrlr)
|
||||
{
|
||||
struct batch_cache_req *req, *tmp;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ctrlr->cache_lock, flags);
|
||||
list_for_each_entry_safe(req, tmp, &ctrlr->batch_cache, list)
|
||||
kfree(req);
|
||||
INIT_LIST_HEAD(&ctrlr->batch_cache);
|
||||
spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* rpmh_write_batch: Write multiple sets of RPMH commands and wait for the
|
||||
* batch to finish.
|
||||
@ -442,36 +431,42 @@ static int send_single(struct rpmh_ctrlr *ctrlr, enum rpmh_state state,
|
||||
}
|
||||
|
||||
/**
|
||||
* rpmh_flush: Flushes the buffered active and sleep sets to TCS
|
||||
* rpmh_flush() - Flushes the buffered sleep and wake sets to TCSes
|
||||
*
|
||||
* @ctrlr: controller making request to flush cached data
|
||||
* @ctrlr: Controller making request to flush cached data
|
||||
*
|
||||
* Return: -EBUSY if the controller is busy, probably waiting on a response
|
||||
* to a RPMH request sent earlier.
|
||||
*
|
||||
* This function is always called from the sleep code from the last CPU
|
||||
* that is powering down the entire system. Since no other RPMH API would be
|
||||
* executing at this time, it is safe to run lockless.
|
||||
* Return:
|
||||
* * 0 - Success
|
||||
* * Error code - Otherwise
|
||||
*/
|
||||
int rpmh_flush(struct rpmh_ctrlr *ctrlr)
|
||||
{
|
||||
struct cache_req *p;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
lockdep_assert_irqs_disabled();
|
||||
|
||||
/*
|
||||
* Currently rpmh_flush() is only called when we think we're running
|
||||
* on the last processor. If the lock is busy it means another
|
||||
* processor is up and it's better to abort than spin.
|
||||
*/
|
||||
if (!spin_trylock(&ctrlr->cache_lock))
|
||||
return -EBUSY;
|
||||
|
||||
if (!ctrlr->dirty) {
|
||||
pr_debug("Skipping flush, TCS has latest data.\n");
|
||||
return 0;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Invalidate the TCSes first to avoid stale data */
|
||||
rpmh_rsc_invalidate(ctrlr_to_drv(ctrlr));
|
||||
|
||||
/* First flush the cached batch requests */
|
||||
ret = flush_batch(ctrlr);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto exit;
|
||||
|
||||
/*
|
||||
* Nobody else should be calling this function other than system PM,
|
||||
* hence we can run without locks.
|
||||
*/
|
||||
list_for_each_entry(p, &ctrlr->cache, list) {
|
||||
if (!is_req_valid(p)) {
|
||||
pr_debug("%s: skipping RPMH req: a:%#x s:%#x w:%#x",
|
||||
@ -481,38 +476,40 @@ int rpmh_flush(struct rpmh_ctrlr *ctrlr)
|
||||
ret = send_single(ctrlr, RPMH_SLEEP_STATE, p->addr,
|
||||
p->sleep_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto exit;
|
||||
ret = send_single(ctrlr, RPMH_WAKE_ONLY_STATE, p->addr,
|
||||
p->wake_val);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ctrlr->dirty = false;
|
||||
|
||||
return 0;
|
||||
exit:
|
||||
spin_unlock(&ctrlr->cache_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* rpmh_invalidate: Invalidate all sleep and active sets
|
||||
* sets.
|
||||
* rpmh_invalidate: Invalidate sleep and wake sets in batch_cache
|
||||
*
|
||||
* @dev: The device making the request
|
||||
*
|
||||
* Invalidate the sleep and active values in the TCS blocks.
|
||||
* Invalidate the sleep and wake values in batch_cache.
|
||||
*/
|
||||
int rpmh_invalidate(const struct device *dev)
|
||||
{
|
||||
struct rpmh_ctrlr *ctrlr = get_rpmh_ctrlr(dev);
|
||||
int ret;
|
||||
struct batch_cache_req *req, *tmp;
|
||||
unsigned long flags;
|
||||
|
||||
invalidate_batch(ctrlr);
|
||||
spin_lock_irqsave(&ctrlr->cache_lock, flags);
|
||||
list_for_each_entry_safe(req, tmp, &ctrlr->batch_cache, list)
|
||||
kfree(req);
|
||||
INIT_LIST_HEAD(&ctrlr->batch_cache);
|
||||
ctrlr->dirty = true;
|
||||
spin_unlock_irqrestore(&ctrlr->cache_lock, flags);
|
||||
|
||||
do {
|
||||
ret = rpmh_rsc_invalidate(ctrlr_to_drv(ctrlr));
|
||||
} while (ret == -EAGAIN);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rpmh_invalidate);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/slab.h>
|
||||
@ -166,6 +167,24 @@ static const struct rpmhpd_desc sm8150_desc = {
|
||||
.num_pds = ARRAY_SIZE(sm8150_rpmhpds),
|
||||
};
|
||||
|
||||
static struct rpmhpd *sm8250_rpmhpds[] = {
|
||||
[SM8250_CX] = &sdm845_cx,
|
||||
[SM8250_CX_AO] = &sdm845_cx_ao,
|
||||
[SM8250_EBI] = &sdm845_ebi,
|
||||
[SM8250_GFX] = &sdm845_gfx,
|
||||
[SM8250_LCX] = &sdm845_lcx,
|
||||
[SM8250_LMX] = &sdm845_lmx,
|
||||
[SM8250_MMCX] = &sm8150_mmcx,
|
||||
[SM8250_MMCX_AO] = &sm8150_mmcx_ao,
|
||||
[SM8250_MX] = &sdm845_mx,
|
||||
[SM8250_MX_AO] = &sdm845_mx_ao,
|
||||
};
|
||||
|
||||
static const struct rpmhpd_desc sm8250_desc = {
|
||||
.rpmhpds = sm8250_rpmhpds,
|
||||
.num_pds = ARRAY_SIZE(sm8250_rpmhpds),
|
||||
};
|
||||
|
||||
/* SC7180 RPMH powerdomains */
|
||||
static struct rpmhpd *sc7180_rpmhpds[] = {
|
||||
[SC7180_CX] = &sdm845_cx,
|
||||
@ -187,8 +206,10 @@ static const struct of_device_id rpmhpd_match_table[] = {
|
||||
{ .compatible = "qcom,sc7180-rpmhpd", .data = &sc7180_desc },
|
||||
{ .compatible = "qcom,sdm845-rpmhpd", .data = &sdm845_desc },
|
||||
{ .compatible = "qcom,sm8150-rpmhpd", .data = &sm8150_desc },
|
||||
{ .compatible = "qcom,sm8250-rpmhpd", .data = &sm8250_desc },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rpmhpd_match_table);
|
||||
|
||||
static int rpmhpd_send_corner(struct rpmhpd *pd, int state,
|
||||
unsigned int corner, bool sync)
|
||||
@ -460,3 +481,6 @@ static int __init rpmhpd_init(void)
|
||||
return platform_driver_register(&rpmhpd_driver);
|
||||
}
|
||||
core_initcall(rpmhpd_init);
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPMh Power Domain Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/of.h>
|
||||
@ -226,6 +227,7 @@ static const struct of_device_id rpmpd_match_table[] = {
|
||||
{ .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rpmpd_match_table);
|
||||
|
||||
static int rpmpd_send_enable(struct rpmpd *pd, bool enable)
|
||||
{
|
||||
@ -422,3 +424,6 @@ static int __init rpmpd_init(void)
|
||||
return platform_driver_register(&rpmpd_driver);
|
||||
}
|
||||
core_initcall(rpmpd_init);
|
||||
|
||||
MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPM Power Domain Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -474,10 +474,8 @@ static int qcom_smp2p_probe(struct platform_device *pdev)
|
||||
goto report_read_failure;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "unable to acquire smp2p interrupt\n");
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
}
|
||||
|
||||
smp2p->mbox_client.dev = &pdev->dev;
|
||||
smp2p->mbox_client.knows_txdone = true;
|
||||
|
@ -188,6 +188,10 @@ static const struct soc_id soc_id[] = {
|
||||
{ 216, "MSM8674PRO" },
|
||||
{ 217, "MSM8974-AA" },
|
||||
{ 218, "MSM8974-AB" },
|
||||
{ 233, "MSM8936" },
|
||||
{ 239, "MSM8939" },
|
||||
{ 240, "APQ8036" },
|
||||
{ 241, "APQ8039" },
|
||||
{ 246, "MSM8996" },
|
||||
{ 247, "APQ8016" },
|
||||
{ 248, "MSM8216" },
|
||||
@ -430,6 +434,8 @@ static int qcom_socinfo_probe(struct platform_device *pdev)
|
||||
qs->attr.family = "Snapdragon";
|
||||
qs->attr.machine = socinfo_machine(&pdev->dev,
|
||||
le32_to_cpu(info->id));
|
||||
qs->attr.soc_id = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%u",
|
||||
le32_to_cpu(info->id));
|
||||
qs->attr.revision = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%u.%u",
|
||||
SOCINFO_MAJOR(le32_to_cpu(info->ver)),
|
||||
SOCINFO_MINOR(le32_to_cpu(info->ver)));
|
||||
|
@ -28,6 +28,18 @@
|
||||
#define SM8150_MMCX 9
|
||||
#define SM8150_MMCX_AO 10
|
||||
|
||||
/* SM8250 Power Domain Indexes */
|
||||
#define SM8250_CX 0
|
||||
#define SM8250_CX_AO 1
|
||||
#define SM8250_EBI 2
|
||||
#define SM8250_GFX 3
|
||||
#define SM8250_LCX 4
|
||||
#define SM8250_LMX 5
|
||||
#define SM8250_MMCX 6
|
||||
#define SM8250_MMCX_AO 7
|
||||
#define SM8250_MX 8
|
||||
#define SM8250_MX_AO 9
|
||||
|
||||
/* SC7180 Power Domain Indexes */
|
||||
#define SC7180_CX 0
|
||||
#define SC7180_CX_AO 1
|
||||
|
@ -4,6 +4,7 @@
|
||||
#ifndef __QCOM_COMMAND_DB_H__
|
||||
#define __QCOM_COMMAND_DB_H__
|
||||
|
||||
#include <linux/err.h>
|
||||
|
||||
enum cmd_db_hw_type {
|
||||
CMD_DB_HW_INVALID = 0,
|
||||
|
@ -80,7 +80,7 @@ EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier);
|
||||
*/
|
||||
int cpu_pm_enter(void)
|
||||
{
|
||||
int nr_calls;
|
||||
int nr_calls = 0;
|
||||
int ret = 0;
|
||||
|
||||
ret = cpu_pm_notify(CPU_PM_ENTER, -1, &nr_calls);
|
||||
@ -131,7 +131,7 @@ EXPORT_SYMBOL_GPL(cpu_pm_exit);
|
||||
*/
|
||||
int cpu_cluster_pm_enter(void)
|
||||
{
|
||||
int nr_calls;
|
||||
int nr_calls = 0;
|
||||
int ret = 0;
|
||||
|
||||
ret = cpu_pm_notify(CPU_CLUSTER_PM_ENTER, -1, &nr_calls);
|
||||
|
Loading…
Reference in New Issue
Block a user