summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2021-08-18 15:33:01 +0200
committerArnd Bergmann <arnd@arndb.de>2021-08-18 15:33:02 +0200
commit5c785014b67fb25d8e2a36d24940dad0c416a005 (patch)
tree1306292cb72edf705eee701222a23c4cf8694b02 /drivers
parent63db5acb4adf3a61c42b387c9c79799b86d25e7f (diff)
parente3d4571955050736bbf3eda0a9538a09d9fcfce8 (diff)
Merge tag 'qcom-drivers-for-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into arm/drivers
Qualcomm driver updates for v5.15 This fixes the "shared memory state machine" (SMSM) interrupt logic to avoid missing transitions happening while the interrupts are masked. SM6115 support is added to smd-rpm and rpmpd. The Qualcomm SCM firmware driver is once again made possible to compile and load as a kernel module. An out-of-bounds error related to the cooling devices of the AOSS driver is corrected. The binding is converted to YAML and a generic compatible is introduced to reduce the driver churn. The GENI wrapper gains a helper function used in I2C and SPI for switching the serial engine hardware to use the wrapper's DMA-engine. Lastly it contains a number of cleanups and smaller fixes for rpmhpd, socinfo, CPR, mdt_loader and the GENI DT binding. * tag 'qcom-drivers-for-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux: soc: qcom: smsm: Fix missed interrupts if state changes while masked soc: qcom: smsm: Implement support for get_irqchip_state soc: qcom: mdt_loader: be more informative on errors dt-bindings: qcom: geni-se: document iommus soc: qcom: smd-rpm: Add SM6115 compatible soc: qcom: geni: Add support for gpi dma soc: qcom: geni: move GENI_IF_DISABLE_RO to common header PM: AVS: qcom-cpr: Use nvmem_cell_read_variable_le_u32() drivers: soc: qcom: rpmpd: Add SM6115 RPM Power Domains dt-bindings: power: rpmpd: Add SM6115 to rpmpd binding dt-bindings: soc: qcom: smd-rpm: Add SM6115 compatible soc: qcom: aoss: Fix the out of bound usage of cooling_devs firmware: qcom_scm: Allow qcom_scm driver to be loadable as a permenent module soc: qcom: socinfo: Don't print anything if nothing found soc: qcom: rpmhpd: Use corner in power_off soc: qcom: aoss: Add generic compatible dt-bindings: soc: qcom: aoss: Convert to YAML dt-bindings: soc: qcom: aoss: Add SC8180X and generic compatible firmware: qcom_scm: remove a duplicative condition firmware: qcom_scm: Mark string array const Link: https://lore.kernel.org/r/20210816214840.581244-1-bjorn.andersson@linaro.org Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/firmware/Kconfig2
-rw-r--r--drivers/firmware/Makefile3
-rw-r--r--drivers/firmware/qcom_scm.c8
-rw-r--r--drivers/iommu/Kconfig2
-rw-r--r--drivers/net/wireless/ath/ath10k/Kconfig1
-rw-r--r--drivers/soc/qcom/cpr.c43
-rw-r--r--drivers/soc/qcom/mdt_loader.c18
-rw-r--r--drivers/soc/qcom/qcom-geni-se.c30
-rw-r--r--drivers/soc/qcom/qcom_aoss.c9
-rw-r--r--drivers/soc/qcom/rpmhpd.c5
-rw-r--r--drivers/soc/qcom/rpmpd.c28
-rw-r--r--drivers/soc/qcom/smd-rpm.c1
-rw-r--r--drivers/soc/qcom/smsm.c28
-rw-r--r--drivers/soc/qcom/socinfo.c4
14 files changed, 122 insertions, 60 deletions
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 8d41f73f5395..77fe6d0f55c6 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -203,7 +203,7 @@ config INTEL_STRATIX10_RSU
Say Y here if you want Intel RSU support.
config QCOM_SCM
- bool
+ tristate "Qcom SCM driver"
depends on ARM || ARM64
depends on HAVE_ARM_SMCCC
select RESET_CONTROLLER
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 546ac8e7f6d0..3c2af2e98def 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -17,7 +17,8 @@ obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.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-smc.o qcom_scm-legacy.o
+obj-$(CONFIG_QCOM_SCM) += qcom-scm.o
+qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index 47ea2bd42b10..ced1964faf42 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -71,7 +71,7 @@ static struct qcom_scm_wb_entry qcom_scm_wb[] = {
{ .flag = QCOM_SCM_FLAG_WARMBOOT_CPU3 },
};
-static const char *qcom_scm_convention_names[] = {
+static const char * const qcom_scm_convention_names[] = {
[SMC_CONVENTION_UNKNOWN] = "unknown",
[SMC_CONVENTION_ARM_32] = "smc arm 32",
[SMC_CONVENTION_ARM_64] = "smc arm 64",
@@ -331,7 +331,7 @@ int qcom_scm_set_cold_boot_addr(void *entry, const cpumask_t *cpus)
.owner = ARM_SMCCC_OWNER_SIP,
};
- if (!cpus || (cpus && cpumask_empty(cpus)))
+ if (!cpus || cpumask_empty(cpus))
return -EINVAL;
for_each_cpu(cpu, cpus) {
@@ -1299,6 +1299,7 @@ static const struct of_device_id qcom_scm_dt_match[] = {
{ .compatible = "qcom,scm" },
{}
};
+MODULE_DEVICE_TABLE(of, qcom_scm_dt_match);
static struct platform_driver qcom_scm_driver = {
.driver = {
@@ -1315,3 +1316,6 @@ static int __init qcom_scm_init(void)
return platform_driver_register(&qcom_scm_driver);
}
subsys_initcall(qcom_scm_init);
+
+MODULE_DESCRIPTION("Qualcomm Technologies, Inc. SCM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 07b7c25cbed8..f61516c17589 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -253,6 +253,7 @@ config SPAPR_TCE_IOMMU
config ARM_SMMU
tristate "ARM Ltd. System MMU (SMMU) Support"
depends on ARM64 || ARM || (COMPILE_TEST && !GENERIC_ATOMIC64)
+ depends on QCOM_SCM || !QCOM_SCM #if QCOM_SCM=m this can't be =y
select IOMMU_API
select IOMMU_IO_PGTABLE_LPAE
select ARM_DMA_USE_IOMMU if ARM
@@ -382,6 +383,7 @@ config QCOM_IOMMU
# Note: iommu drivers cannot (yet?) be built as modules
bool "Qualcomm IOMMU Support"
depends on ARCH_QCOM || (COMPILE_TEST && !GENERIC_ATOMIC64)
+ depends on QCOM_SCM=y
select IOMMU_API
select IOMMU_IO_PGTABLE_LPAE
select ARM_DMA_USE_IOMMU
diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig
index 40f91bc8514d..741289e385d5 100644
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
@@ -44,6 +44,7 @@ config ATH10K_SNOC
tristate "Qualcomm ath10k SNOC support"
depends on ATH10K
depends on ARCH_QCOM || COMPILE_TEST
+ depends on QCOM_SCM || !QCOM_SCM #if QCOM_SCM=m this can't be =y
select QCOM_QMI_HELPERS
help
This module adds support for integrated WCN3990 chip connected
diff --git a/drivers/soc/qcom/cpr.c b/drivers/soc/qcom/cpr.c
index b24cc77d1889..4ce8e816154f 100644
--- a/drivers/soc/qcom/cpr.c
+++ b/drivers/soc/qcom/cpr.c
@@ -801,38 +801,6 @@ unlock:
return ret;
}
-static int cpr_read_efuse(struct device *dev, const char *cname, u32 *data)
-{
- struct nvmem_cell *cell;
- ssize_t len;
- char *ret;
- int i;
-
- *data = 0;
-
- cell = nvmem_cell_get(dev, cname);
- if (IS_ERR(cell)) {
- if (PTR_ERR(cell) != -EPROBE_DEFER)
- dev_err(dev, "undefined cell %s\n", cname);
- return PTR_ERR(cell);
- }
-
- ret = nvmem_cell_read(cell, &len);
- nvmem_cell_put(cell);
- if (IS_ERR(ret)) {
- dev_err(dev, "can't read cell %s\n", cname);
- return PTR_ERR(ret);
- }
-
- for (i = 0; i < len; i++)
- *data |= ret[i] << (8 * i);
-
- kfree(ret);
- dev_dbg(dev, "efuse read(%s) = %x, bytes %zd\n", cname, *data, len);
-
- return 0;
-}
-
static int
cpr_populate_ring_osc_idx(struct cpr_drv *drv)
{
@@ -843,8 +811,7 @@ cpr_populate_ring_osc_idx(struct cpr_drv *drv)
int ret;
for (; fuse < end; fuse++, fuses++) {
- ret = cpr_read_efuse(drv->dev, fuses->ring_osc,
- &data);
+ ret = nvmem_cell_read_variable_le_u32(drv->dev, fuses->ring_osc, &data);
if (ret)
return ret;
fuse->ring_osc_idx = data;
@@ -863,7 +830,7 @@ static int cpr_read_fuse_uV(const struct cpr_desc *desc,
u32 bits = 0;
int ret;
- ret = cpr_read_efuse(drv->dev, init_v_efuse, &bits);
+ ret = nvmem_cell_read_variable_le_u32(drv->dev, init_v_efuse, &bits);
if (ret)
return ret;
@@ -932,7 +899,7 @@ static int cpr_fuse_corner_init(struct cpr_drv *drv)
}
/* Populate target quotient by scaling */
- ret = cpr_read_efuse(drv->dev, fuses->quotient, &fuse->quot);
+ ret = nvmem_cell_read_variable_le_u32(drv->dev, fuses->quotient, &fuse->quot);
if (ret)
return ret;
@@ -1001,7 +968,7 @@ static int cpr_calculate_scaling(const char *quot_offset,
prev_fuse = fuse - 1;
if (quot_offset) {
- ret = cpr_read_efuse(drv->dev, quot_offset, &quot_diff);
+ ret = nvmem_cell_read_variable_le_u32(drv->dev, quot_offset, &quot_diff);
if (ret)
return ret;
@@ -1701,7 +1668,7 @@ static int cpr_probe(struct platform_device *pdev)
* initialized after attaching to the power domain,
* since it depends on the CPU's OPP table.
*/
- ret = cpr_read_efuse(dev, "cpr_fuse_revision", &cpr_rev);
+ ret = nvmem_cell_read_variable_le_u32(dev, "cpr_fuse_revision", &cpr_rev);
if (ret)
return ret;
diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
index eba7f76f9d61..bda170d7b4a2 100644
--- a/drivers/soc/qcom/mdt_loader.c
+++ b/drivers/soc/qcom/mdt_loader.c
@@ -166,6 +166,8 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
metadata = qcom_mdt_read_metadata(fw, &metadata_len);
if (IS_ERR(metadata)) {
ret = PTR_ERR(metadata);
+ dev_err(dev, "error %d reading firmware %s metadata\n",
+ ret, fw_name);
goto out;
}
@@ -173,7 +175,9 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
kfree(metadata);
if (ret) {
- dev_err(dev, "invalid firmware metadata\n");
+ /* Invalid firmware metadata */
+ dev_err(dev, "error %d initializing firmware %s\n",
+ ret, fw_name);
goto out;
}
}
@@ -199,7 +203,9 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
ret = qcom_scm_pas_mem_setup(pas_id, mem_phys,
max_addr - min_addr);
if (ret) {
- dev_err(dev, "unable to setup relocation\n");
+ /* Unable to set up relocation */
+ dev_err(dev, "error %d setting up firmware %s\n",
+ ret, fw_name);
goto out;
}
}
@@ -243,9 +249,8 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
if (phdr->p_filesz && phdr->p_offset < fw->size) {
/* Firmware is large enough to be non-split */
if (phdr->p_offset + phdr->p_filesz > fw->size) {
- dev_err(dev,
- "failed to load segment %d from truncated file %s\n",
- i, firmware);
+ dev_err(dev, "file %s segment %d would be truncated\n",
+ fw_name, i);
ret = -EINVAL;
break;
}
@@ -257,7 +262,8 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
ret = request_firmware_into_buf(&seg_fw, fw_name, dev,
ptr, phdr->p_filesz);
if (ret) {
- dev_err(dev, "failed to load %s\n", fw_name);
+ dev_err(dev, "error %d loading %s\n",
+ ret, fw_name);
break;
}
diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c
index 5bdfb1565c14..7d649d2cf31e 100644
--- a/drivers/soc/qcom/qcom-geni-se.c
+++ b/drivers/soc/qcom/qcom-geni-se.c
@@ -104,7 +104,6 @@ static const char * const icc_path_names[] = {"qup-core", "qup-config",
#define GENI_OUTPUT_CTRL 0x24
#define GENI_CGC_CTRL 0x28
#define GENI_CLK_CTRL_RO 0x60
-#define GENI_IF_DISABLE_RO 0x64
#define GENI_FW_S_REVISION_RO 0x6c
#define SE_GENI_BYTE_GRAN 0x254
#define SE_GENI_TX_PACKING_CFG0 0x260
@@ -322,6 +321,30 @@ static void geni_se_select_dma_mode(struct geni_se *se)
writel_relaxed(val, se->base + SE_GENI_DMA_MODE_EN);
}
+static void geni_se_select_gpi_mode(struct geni_se *se)
+{
+ u32 val;
+
+ geni_se_irq_clear(se);
+
+ writel(0, se->base + SE_IRQ_EN);
+
+ val = readl(se->base + SE_GENI_S_IRQ_EN);
+ val &= ~S_CMD_DONE_EN;
+ writel(val, se->base + SE_GENI_S_IRQ_EN);
+
+ val = readl(se->base + SE_GENI_M_IRQ_EN);
+ val &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN |
+ M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN);
+ writel(val, se->base + SE_GENI_M_IRQ_EN);
+
+ writel(GENI_DMA_MODE_EN, se->base + SE_GENI_DMA_MODE_EN);
+
+ val = readl(se->base + SE_GSI_EVENT_EN);
+ val |= (DMA_RX_EVENT_EN | DMA_TX_EVENT_EN | GENI_M_EVENT_EN | GENI_S_EVENT_EN);
+ writel(val, se->base + SE_GSI_EVENT_EN);
+}
+
/**
* geni_se_select_mode() - Select the serial engine transfer mode
* @se: Pointer to the concerned serial engine.
@@ -329,7 +352,7 @@ static void geni_se_select_dma_mode(struct geni_se *se)
*/
void geni_se_select_mode(struct geni_se *se, enum geni_se_xfer_mode mode)
{
- WARN_ON(mode != GENI_SE_FIFO && mode != GENI_SE_DMA);
+ WARN_ON(mode != GENI_SE_FIFO && mode != GENI_SE_DMA && mode != GENI_GPI_DMA);
switch (mode) {
case GENI_SE_FIFO:
@@ -338,6 +361,9 @@ void geni_se_select_mode(struct geni_se *se, enum geni_se_xfer_mode mode)
case GENI_SE_DMA:
geni_se_select_dma_mode(se);
break;
+ case GENI_GPI_DMA:
+ geni_se_select_gpi_mode(se);
+ break;
case GENI_SE_INVALID:
default:
break;
diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c
index 934fcc4d2b05..536c3e4114fb 100644
--- a/drivers/soc/qcom/qcom_aoss.c
+++ b/drivers/soc/qcom/qcom_aoss.c
@@ -476,12 +476,12 @@ static int qmp_cooling_device_add(struct qmp *qmp,
static int qmp_cooling_devices_register(struct qmp *qmp)
{
struct device_node *np, *child;
- int count = QMP_NUM_COOLING_RESOURCES;
+ int count = 0;
int ret;
np = qmp->dev->of_node;
- qmp->cooling_devs = devm_kcalloc(qmp->dev, count,
+ qmp->cooling_devs = devm_kcalloc(qmp->dev, QMP_NUM_COOLING_RESOURCES,
sizeof(*qmp->cooling_devs),
GFP_KERNEL);
@@ -497,12 +497,16 @@ static int qmp_cooling_devices_register(struct qmp *qmp)
goto unroll;
}
+ if (!count)
+ devm_kfree(qmp->dev, qmp->cooling_devs);
+
return 0;
unroll:
while (--count >= 0)
thermal_cooling_device_unregister
(qmp->cooling_devs[count].cdev);
+ devm_kfree(qmp->dev, qmp->cooling_devs);
return ret;
}
@@ -602,6 +606,7 @@ static const struct of_device_id qmp_dt_match[] = {
{ .compatible = "qcom,sm8150-aoss-qmp", },
{ .compatible = "qcom,sm8250-aoss-qmp", },
{ .compatible = "qcom,sm8350-aoss-qmp", },
+ { .compatible = "qcom,aoss-qmp", },
{}
};
MODULE_DEVICE_TABLE(of, qmp_dt_match);
diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c
index 2daa17ba54a3..fa209b479ab3 100644
--- a/drivers/soc/qcom/rpmhpd.c
+++ b/drivers/soc/qcom/rpmhpd.c
@@ -403,12 +403,11 @@ static int rpmhpd_power_on(struct generic_pm_domain *domain)
static int rpmhpd_power_off(struct generic_pm_domain *domain)
{
struct rpmhpd *pd = domain_to_rpmhpd(domain);
- int ret = 0;
+ int ret;
mutex_lock(&rpmhpd_lock);
- ret = rpmhpd_aggregate_corner(pd, pd->level[0]);
-
+ ret = rpmhpd_aggregate_corner(pd, 0);
if (!ret)
pd->enabled = false;
diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c
index 0b532a892d60..dbf494e92574 100644
--- a/drivers/soc/qcom/rpmpd.c
+++ b/drivers/soc/qcom/rpmpd.c
@@ -346,6 +346,33 @@ static const struct rpmpd_desc sdm660_desc = {
.max_state = RPM_SMD_LEVEL_TURBO,
};
+/* sm4250/6115 RPM Power domains */
+DEFINE_RPMPD_PAIR(sm6115, vddcx, vddcx_ao, RWCX, LEVEL, 0);
+DEFINE_RPMPD_VFL(sm6115, vddcx_vfl, RWCX, 0);
+
+DEFINE_RPMPD_PAIR(sm6115, vddmx, vddmx_ao, RWMX, LEVEL, 0);
+DEFINE_RPMPD_VFL(sm6115, vddmx_vfl, RWMX, 0);
+
+DEFINE_RPMPD_LEVEL(sm6115, vdd_lpi_cx, RWLC, 0);
+DEFINE_RPMPD_LEVEL(sm6115, vdd_lpi_mx, RWLM, 0);
+
+static struct rpmpd *sm6115_rpmpds[] = {
+ [SM6115_VDDCX] = &sm6115_vddcx,
+ [SM6115_VDDCX_AO] = &sm6115_vddcx_ao,
+ [SM6115_VDDCX_VFL] = &sm6115_vddcx_vfl,
+ [SM6115_VDDMX] = &sm6115_vddmx,
+ [SM6115_VDDMX_AO] = &sm6115_vddmx_ao,
+ [SM6115_VDDMX_VFL] = &sm6115_vddmx_vfl,
+ [SM6115_VDD_LPI_CX] = &sm6115_vdd_lpi_cx,
+ [SM6115_VDD_LPI_MX] = &sm6115_vdd_lpi_mx,
+};
+
+static const struct rpmpd_desc sm6115_desc = {
+ .rpmpds = sm6115_rpmpds,
+ .num_pds = ARRAY_SIZE(sm6115_rpmpds),
+ .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
+};
+
static const struct of_device_id rpmpd_match_table[] = {
{ .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc },
{ .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc },
@@ -356,6 +383,7 @@ static const struct of_device_id rpmpd_match_table[] = {
{ .compatible = "qcom,msm8998-rpmpd", .data = &msm8998_desc },
{ .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc },
{ .compatible = "qcom,sdm660-rpmpd", .data = &sdm660_desc },
+ { .compatible = "qcom,sm6115-rpmpd", .data = &sm6115_desc },
{ }
};
MODULE_DEVICE_TABLE(of, rpmpd_match_table);
diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c
index bc0be1d4be5f..dfdd4f20f5fd 100644
--- a/drivers/soc/qcom/smd-rpm.c
+++ b/drivers/soc/qcom/smd-rpm.c
@@ -242,6 +242,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = {
{ .compatible = "qcom,rpm-msm8996" },
{ .compatible = "qcom,rpm-msm8998" },
{ .compatible = "qcom,rpm-sdm660" },
+ { .compatible = "qcom,rpm-sm6115" },
{ .compatible = "qcom,rpm-sm6125" },
{ .compatible = "qcom,rpm-qcs404" },
{}
diff --git a/drivers/soc/qcom/smsm.c b/drivers/soc/qcom/smsm.c
index 1d3d5e3ec2b0..ef15d014c03a 100644
--- a/drivers/soc/qcom/smsm.c
+++ b/drivers/soc/qcom/smsm.c
@@ -109,7 +109,7 @@ struct smsm_entry {
DECLARE_BITMAP(irq_enabled, 32);
DECLARE_BITMAP(irq_rising, 32);
DECLARE_BITMAP(irq_falling, 32);
- u32 last_value;
+ unsigned long last_value;
u32 *remote_state;
u32 *subscription;
@@ -204,8 +204,7 @@ static irqreturn_t smsm_intr(int irq, void *data)
u32 val;
val = readl(entry->remote_state);
- changed = val ^ entry->last_value;
- entry->last_value = val;
+ changed = val ^ xchg(&entry->last_value, val);
for_each_set_bit(i, entry->irq_enabled, 32) {
if (!(changed & BIT(i)))
@@ -264,6 +263,12 @@ static void smsm_unmask_irq(struct irq_data *irqd)
struct qcom_smsm *smsm = entry->smsm;
u32 val;
+ /* Make sure our last cached state is up-to-date */
+ if (readl(entry->remote_state) & BIT(irq))
+ set_bit(irq, &entry->last_value);
+ else
+ clear_bit(irq, &entry->last_value);
+
set_bit(irq, entry->irq_enabled);
if (entry->subscription) {
@@ -299,11 +304,28 @@ static int smsm_set_irq_type(struct irq_data *irqd, unsigned int type)
return 0;
}
+static int smsm_get_irqchip_state(struct irq_data *irqd,
+ enum irqchip_irq_state which, bool *state)
+{
+ struct smsm_entry *entry = irq_data_get_irq_chip_data(irqd);
+ irq_hw_number_t irq = irqd_to_hwirq(irqd);
+ u32 val;
+
+ if (which != IRQCHIP_STATE_LINE_LEVEL)
+ return -EINVAL;
+
+ val = readl(entry->remote_state);
+ *state = !!(val & BIT(irq));
+
+ return 0;
+}
+
static struct irq_chip smsm_irq_chip = {
.name = "smsm",
.irq_mask = smsm_mask_irq,
.irq_unmask = smsm_unmask_irq,
.irq_set_type = smsm_set_irq_type,
+ .irq_get_irqchip_state = smsm_get_irqchip_state,
};
/**
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index b2f049faa3df..9faf48302f4b 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -417,8 +417,8 @@ QCOM_OPEN(chip_id, qcom_show_chip_id);
static int show_image_##type(struct seq_file *seq, void *p) \
{ \
struct smem_image_version *image_version = seq->private; \
- seq_puts(seq, image_version->type); \
- seq_putc(seq, '\n'); \
+ if (image_version->type[0] != '\0') \
+ seq_printf(seq, "%s\n", image_version->type); \
return 0; \
} \
static int open_image_##type(struct inode *inode, struct file *file) \