From 85f5656a4f3f188cb950cf8dc88f3f0e4e656bae Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 22 May 2024 13:33:43 +0200 Subject: soc: qcom: socinfo: Update X1E PMICs Assign the correct name to ID 82 and fix the ID of SMB2360. Fixes: e025171d1ab1 ("soc: qcom: socinfo: Add SMB2360 PMIC") Signed-off-by: Konrad Dybcio Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20240522-topic-x1e_pmics_socinfo-v1-1-da8a097e5134@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/socinfo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 277c07a6603d..41342c37916a 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -133,7 +133,8 @@ static const char *const pmic_models[] = { [72] = "PMR735D", [73] = "PM8550", [74] = "PMK8550", - [82] = "SMB2360", + [82] = "PMC8380", + [83] = "SMB2360", }; struct socinfo_params { -- cgit v1.2.3 From a8a313c298b8becc7e2c0bab174df736d1f99450 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Mon, 27 May 2024 11:16:01 +0300 Subject: soc: qcom: pmic_glink: Increase max ports to 3 Up until now, all Qualcomm platforms only had maximum 2 ports. The X Elite (x1e80100) adds a third one. Increase the maximum allowed to 3. Signed-off-by: Abel Vesa Reviewed-by: Neil Armstrong Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240527-x1e80100-soc-qcom-pmic-glink-v1-1-e5c4cda2f745@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/pmic_glink_altmode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c index b3808fc24c69..1e0808b3cb93 100644 --- a/drivers/soc/qcom/pmic_glink_altmode.c +++ b/drivers/soc/qcom/pmic_glink_altmode.c @@ -20,7 +20,7 @@ #include -#define PMIC_GLINK_MAX_PORTS 2 +#define PMIC_GLINK_MAX_PORTS 3 #define USBC_SC8180X_NOTIFY_IND 0x13 #define USBC_CMD_WRITE_REQ 0x15 -- cgit v1.2.3 From 0780c836673b25f5aad306630afcb1172d694cb4 Mon Sep 17 00:00:00 2001 From: Chen Ni Date: Fri, 10 May 2024 16:31:56 +0800 Subject: soc: qcom: pmic_glink: Handle the return value of pmic_glink_init As platform_driver_register() and register_rpmsg_driver() can return error numbers, it should be better to check the return value and deal with the exception. Signed-off-by: Chen Ni Fixes: 58ef4ece1e41 ("soc: qcom: pmic_glink: Introduce base PMIC GLINK driver") Reviewed-by: Bryan O'Donoghue Link: https://lore.kernel.org/r/20240510083156.1996783-1-nichen@iscas.ac.cn Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/pmic_glink.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c index 40fb09d69014..8534a9692c45 100644 --- a/drivers/soc/qcom/pmic_glink.c +++ b/drivers/soc/qcom/pmic_glink.c @@ -369,8 +369,17 @@ static struct platform_driver pmic_glink_driver = { static int pmic_glink_init(void) { - platform_driver_register(&pmic_glink_driver); - register_rpmsg_driver(&pmic_glink_rpmsg_driver); + int ret; + + ret = platform_driver_register(&pmic_glink_driver); + if (ret < 0) + return ret; + + ret = register_rpmsg_driver(&pmic_glink_rpmsg_driver); + if (ret < 0) { + platform_driver_unregister(&pmic_glink_driver); + return ret; + } return 0; } -- cgit v1.2.3 From e43111f52b9ec5c2d700f89a1d61c8d10dc2d9e9 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 9 May 2024 11:41:28 -0700 Subject: soc: qcom: rpmh-rsc: Ensure irqs aren't disabled by rpmh_rsc_send_data() callers Dan pointed out that Smatch is concerned about this code because it uses spin_lock_irqsave() and then calls wait_event_lock_irq() which enables irqs before going to sleep. The comment above the function says it should be called with interrupts enabled, but we simply hope that's true without really confirming that. Let's add a might_sleep() here to confirm that interrupts and preemption aren't disabled. Once we do that, we can change the lock to be non-saving, spin_lock_irq(), to clarify that we don't expect irqs to be disabled. If irqs are disabled by callers they're going to be enabled anyway in the wait_event_lock_irq() call which would be bad. This should make Smatch happier and find bad callers faster with the might_sleep(). We can drop the WARN_ON() in the caller because we have the might_sleep() now, simplifying the code. Reported-by: Dan Carpenter Closes: https://lore.kernel.org/r/911181ed-c430-4592-ad26-4dc948834e08@moroto.mountain Fixes: 2bc20f3c8487 ("soc: qcom: rpmh-rsc: Sleep waiting for tcs slots to be free") Cc: Douglas Anderson Signed-off-by: Stephen Boyd Reviewed-by: Douglas Anderson Link: https://lore.kernel.org/r/20240509184129.3924422-1-swboyd@chromium.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/rpmh-rsc.c | 7 ++++--- drivers/soc/qcom/rpmh.c | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index 561d8037b50a..de86009ecd91 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -646,13 +646,14 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg) { struct tcs_group *tcs; int tcs_id; - unsigned long flags; + + might_sleep(); tcs = get_tcs_for_msg(drv, msg); if (IS_ERR(tcs)) return PTR_ERR(tcs); - spin_lock_irqsave(&drv->lock, flags); + spin_lock_irq(&drv->lock); /* Wait forever for a free tcs. It better be there eventually! */ wait_event_lock_irq(drv->tcs_wait, @@ -670,7 +671,7 @@ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg) write_tcs_reg_sync(drv, drv->regs[RSC_DRV_CMD_ENABLE], tcs_id, 0); enable_tcs_irq(drv, tcs_id, true); } - spin_unlock_irqrestore(&drv->lock, flags); + spin_unlock_irq(&drv->lock); /* * These two can be done after the lock is released because: diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c index 9f26d7f9b9dc..8903ed956312 100644 --- a/drivers/soc/qcom/rpmh.c +++ b/drivers/soc/qcom/rpmh.c @@ -183,7 +183,6 @@ static int __rpmh_write(const struct device *dev, enum rpmh_state state, } if (state == RPMH_ACTIVE_ONLY_STATE) { - WARN_ON(irqs_disabled()); ret = rpmh_rsc_send_data(ctrlr_to_drv(ctrlr), &rpm_msg->msg); } else { /* Clean up our call by spoofing tx_done */ -- cgit v1.2.3 From 8ddfb4a8e093689859184abf52fe15cd2523c6b9 Mon Sep 17 00:00:00 2001 From: Kathiravan Thirumoorthy Date: Mon, 25 Mar 2024 21:19:49 +0530 Subject: soc: qcom: socinfo: Add SoC ID for IPQ5321 Add the SoC ID for IPQ5321, which belong to the family of IPQ5332 SoC. Reviewed-by: Krzysztof Kozlowski Reviewed-by: Mukesh Ojha Signed-off-by: Kathiravan Thirumoorthy Link: https://lore.kernel.org/r/20240325-ipq5321-sku-support-v2-2-f30ce244732f@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/socinfo.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 41342c37916a..4081eda0f398 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -446,6 +446,7 @@ static const struct soc_id soc_id[] = { { qcom_board_id(QCS8550) }, { qcom_board_id(QCM8550) }, { qcom_board_id(IPQ5300) }, + { qcom_board_id(IPQ5321) }, }; static const char *socinfo_machine(struct device *dev, unsigned int id) -- cgit v1.2.3 From a40cf069ac613c0f441b9a9f42b84aa65aada8f7 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Sat, 4 May 2024 21:44:01 +0100 Subject: soc: sunxi: sram: Remove unused list 'claimed_sram' The list 'claimed_sram' seems unused, as far as I can tell it always has been. I think the 'list' member of sunxi_sram_data was intended to be used when it was on that list. Remove them. Build tested only. Signed-off-by: Dr. David Alan Gilbert Link: https://lore.kernel.org/r/20240504204401.198913-1-linux@treblig.org Signed-off-by: Chen-Yu Tsai --- drivers/soc/sunxi/sunxi_sram.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c index 6eb6cf06278e..71cc377b5e24 100644 --- a/drivers/soc/sunxi/sunxi_sram.c +++ b/drivers/soc/sunxi/sunxi_sram.c @@ -33,7 +33,6 @@ struct sunxi_sram_data { u8 offset; u8 width; struct sunxi_sram_func *func; - struct list_head list; }; struct sunxi_sram_desc { @@ -103,7 +102,6 @@ static const struct of_device_id sunxi_sram_dt_ids[] = { }; static struct device *sram_dev; -static LIST_HEAD(claimed_sram); static DEFINE_SPINLOCK(sram_lock); static void __iomem *base; -- cgit v1.2.3 From 48e4da7919bea2f5c0e20b218385ffe8d5492ab2 Mon Sep 17 00:00:00 2001 From: Richard Acayan Date: Thu, 23 May 2024 21:20:26 -0400 Subject: soc: qcom: socinfo: Add SDM670 SoC ID table entry There is support for SDM670 already, but not recognized by the socinfo driver. Add the table entry so SDM670 can be found in sysfs. Signed-off-by: Richard Acayan Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240524012023.318965-7-mailingradian@gmail.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/socinfo.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 4081eda0f398..8087941a7887 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -349,6 +349,7 @@ static const struct soc_id soc_id[] = { { qcom_board_id(SDA630) }, { qcom_board_id(MSM8905) }, { qcom_board_id(SDX202) }, + { qcom_board_id(SDM670) }, { qcom_board_id(SDM450) }, { qcom_board_id(SM8150) }, { qcom_board_id(SDA845) }, -- cgit v1.2.3 From fed15196223785630527320da05edf0b09900706 Mon Sep 17 00:00:00 2001 From: Tengfei Fan Date: Wed, 29 May 2024 18:15:33 +0800 Subject: soc: qcom: llcc: Add llcc configuration support for the SA8775p platform Add llcc configuration support for the SA8775p platform. Signed-off-by: Tengfei Fan Link: https://lore.kernel.org/r/20240529101534.3166507-3-quic_tengfan@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/llcc-qcom.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index cbef0dea1d5d..4379a5f8ddf3 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -150,6 +150,25 @@ enum llcc_reg_offset { LLCC_COMMON_STATUS0, }; +static const struct llcc_slice_config sa8775p_data[] = { + {LLCC_CPUSS, 1, 2048, 1, 0, 0x00FF, 0x0, 0, 0, 0, 1, 1, 0, 0}, + {LLCC_VIDSC0, 2, 512, 3, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, + {LLCC_CPUSS1, 3, 1024, 1, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, + {LLCC_CPUHWT, 5, 512, 1, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, + {LLCC_AUDIO, 6, 1024, 1, 1, 0x00FF, 0x0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CMPT, 10, 4096, 1, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, + {LLCC_GPUHTW, 11, 1024, 1, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, + {LLCC_GPU, 12, 1024, 1, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 1, 0}, + {LLCC_MMUHWT, 13, 1024, 1, 1, 0x00FF, 0x0, 0, 0, 0, 0, 1, 0, 0}, + {LLCC_CMPTDMA, 15, 1024, 1, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, + {LLCC_DISP, 16, 4096, 2, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, + {LLCC_VIDFW, 17, 3072, 1, 0, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, + {LLCC_AUDHW, 22, 1024, 1, 1, 0x00FF, 0x0, 0, 0, 0, 0, 0, 0, 0}, + {LLCC_CVP, 28, 256, 3, 1, 0x00FF, 0x0, 0, 0, 0, 1, 0, 0, 0}, + {LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0xF0, 1, 0, 0, 1, 0, 0, 0}, + {LLCC_WRCACHE, 31, 512, 1, 1, 0x00FF, 0x0, 0, 0, 0, 0, 1, 0, 0}, +}; + static const struct llcc_slice_config sc7180_data[] = { { LLCC_CPUSS, 1, 256, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 1 }, { LLCC_MDM, 8, 128, 1, 0, 0xf, 0x0, 0, 0, 0, 1, 0 }, @@ -552,6 +571,16 @@ static const struct qcom_llcc_config qdu1000_cfg[] = { }, }; +static const struct qcom_llcc_config sa8775p_cfg[] = { + { + .sct_data = sa8775p_data, + .size = ARRAY_SIZE(sa8775p_data), + .need_llcc_cfg = true, + .reg_offset = llcc_v2_1_reg_offset, + .edac_reg_offset = &llcc_v2_1_edac_reg_offset, + }, +}; + static const struct qcom_llcc_config sc7180_cfg[] = { { .sct_data = sc7180_data, @@ -698,6 +727,11 @@ static const struct qcom_sct_config qdu1000_cfgs = { .num_config = ARRAY_SIZE(qdu1000_cfg), }; +static const struct qcom_sct_config sa8775p_cfgs = { + .llcc_config = sa8775p_cfg, + .num_config = ARRAY_SIZE(sa8775p_cfg), +}; + static const struct qcom_sct_config sc7180_cfgs = { .llcc_config = sc7180_cfg, .num_config = ARRAY_SIZE(sc7180_cfg), @@ -1332,6 +1366,7 @@ err: static const struct of_device_id qcom_llcc_of_match[] = { { .compatible = "qcom,qdu1000-llcc", .data = &qdu1000_cfgs}, + { .compatible = "qcom,sa8775p-llcc", .data = &sa8775p_cfgs }, { .compatible = "qcom,sc7180-llcc", .data = &sc7180_cfgs }, { .compatible = "qcom,sc7280-llcc", .data = &sc7280_cfgs }, { .compatible = "qcom,sc8180x-llcc", .data = &sc8180x_cfgs }, -- cgit v1.2.3 From 055afc34fd219c8e2290d736ad186edd58870a9e Mon Sep 17 00:00:00 2001 From: Unnathi Chalicheemala Date: Fri, 31 May 2024 09:45:25 -0700 Subject: soc: qcom: llcc: Add regmap for Broadcast_AND region Until SM8450, there was only one broadcast region (Broadcast_OR) used to broadcast write and check for status bit 0. >From SM8450 onwards another broadcast region (Broadcast_AND) has been added which checks for status bit 1. This hasn't been updated and Broadcast_OR region was wrongly being used to check for status bit 1 all along. Hence define new regmap structure for Broadcast_AND region and initialize this regmap when HW block version is greater than 4.1, otherwise initialize as a NULL pointer for backwards compatibility. Switch from broadcast_OR to broadcast_AND region (when defined in DT) for checking status bit 1 as Broadcast_OR region checks only for bit 0. Signed-off-by: Unnathi Chalicheemala Reviewed-by: Bjorn Andersson Link: https://lore.kernel.org/r/9cf19928a67eaa577ae0f02de5bf86276be34ea2.1717014052.git.quic_uchalich@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/llcc-qcom.c | 16 +++++++++++++++- include/linux/soc/qcom/llcc-qcom.h | 4 +++- 2 files changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 4379a5f8ddf3..110b1f89aa59 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -855,6 +855,7 @@ EXPORT_SYMBOL_GPL(llcc_slice_putd); static int llcc_update_act_ctrl(u32 sid, u32 act_ctrl_reg_val, u32 status) { + struct regmap *regmap; u32 act_ctrl_reg; u32 act_clear_reg; u32 status_reg; @@ -883,7 +884,8 @@ static int llcc_update_act_ctrl(u32 sid, return ret; if (drv_data->version >= LLCC_VERSION_4_1_0_0) { - ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg, + regmap = drv_data->bcast_and_regmap ?: drv_data->bcast_regmap; + ret = regmap_read_poll_timeout(regmap, status_reg, slice_status, (slice_status & ACT_COMPLETE), 0, LLCC_STATUS_READ_DELAY); if (ret) @@ -1318,6 +1320,18 @@ static int qcom_llcc_probe(struct platform_device *pdev) drv_data->version = version; + /* Applicable only when drv_data->version >= 4.1 */ + if (drv_data->version >= LLCC_VERSION_4_1_0_0) { + drv_data->bcast_and_regmap = qcom_llcc_init_mmio(pdev, i + 1, "llcc_broadcast_and_base"); + if (IS_ERR(drv_data->bcast_and_regmap)) { + ret = PTR_ERR(drv_data->bcast_and_regmap); + if (ret == -EINVAL) + drv_data->bcast_and_regmap = NULL; + else + goto err; + } + } + llcc_cfg = cfg->sct_data; sz = cfg->size; diff --git a/include/linux/soc/qcom/llcc-qcom.h b/include/linux/soc/qcom/llcc-qcom.h index 1a886666bbb6..9e9f528b1370 100644 --- a/include/linux/soc/qcom/llcc-qcom.h +++ b/include/linux/soc/qcom/llcc-qcom.h @@ -115,7 +115,8 @@ struct llcc_edac_reg_offset { /** * struct llcc_drv_data - Data associated with the llcc driver * @regmaps: regmaps associated with the llcc device - * @bcast_regmap: regmap associated with llcc broadcast offset + * @bcast_regmap: regmap associated with llcc broadcast OR offset + * @bcast_and_regmap: regmap associated with llcc broadcast AND offset * @cfg: pointer to the data structure for slice configuration * @edac_reg_offset: Offset of the LLCC EDAC registers * @lock: mutex associated with each slice @@ -129,6 +130,7 @@ struct llcc_edac_reg_offset { struct llcc_drv_data { struct regmap **regmaps; struct regmap *bcast_regmap; + struct regmap *bcast_and_regmap; const struct llcc_slice_config *cfg; const struct llcc_edac_reg_offset *edac_reg_offset; struct mutex lock; -- cgit v1.2.3 From 4a95449dd975e2ea6629a034f3e74b46c9634916 Mon Sep 17 00:00:00 2001 From: Jay Buddhabhatti Date: Mon, 8 Apr 2024 04:06:10 -0700 Subject: soc: xilinx: rename cpu_number1 to dummy_cpu_number The per cpu variable cpu_number1 is passed to xlnx_event_handler as argument "dev_id", but it is not used in this function. So drop the initialization of this variable and rename it to dummy_cpu_number. This patch is to fix the following call trace when the kernel option CONFIG_DEBUG_ATOMIC_SLEEP is enabled: BUG: sleeping function called from invalid context at include/linux/sched/mm.h:274 in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 1, name: swapper/0 preempt_count: 1, expected: 0 CPU: 0 PID: 1 Comm: swapper/0 Not tainted 6.1.0 #53 Hardware name: Xilinx Versal vmk180 Eval board rev1.1 (QSPI) (DT) Call trace: dump_backtrace+0xd0/0xe0 show_stack+0x18/0x40 dump_stack_lvl+0x7c/0xa0 dump_stack+0x18/0x34 __might_resched+0x10c/0x140 __might_sleep+0x4c/0xa0 __kmem_cache_alloc_node+0xf4/0x168 kmalloc_trace+0x28/0x38 __request_percpu_irq+0x74/0x138 xlnx_event_manager_probe+0xf8/0x298 platform_probe+0x68/0xd8 Fixes: daed80ed0758 ("soc: xilinx: Fix for call trace due to the usage of smp_processor_id()") Signed-off-by: Jay Buddhabhatti Link: https://lore.kernel.org/r/20240408110610.15676-1-jay.buddhabhatti@amd.com Signed-off-by: Michal Simek --- drivers/soc/xilinx/xlnx_event_manager.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/xilinx/xlnx_event_manager.c b/drivers/soc/xilinx/xlnx_event_manager.c index 253299e4214d..366018f6a0ee 100644 --- a/drivers/soc/xilinx/xlnx_event_manager.c +++ b/drivers/soc/xilinx/xlnx_event_manager.c @@ -3,6 +3,7 @@ * Xilinx Event Management Driver * * Copyright (C) 2021 Xilinx, Inc. + * Copyright (C) 2024 Advanced Micro Devices, Inc. * * Abhyuday Godhasara */ @@ -19,7 +20,7 @@ #include #include -static DEFINE_PER_CPU_READ_MOSTLY(int, cpu_number1); +static DEFINE_PER_CPU_READ_MOSTLY(int, dummy_cpu_number); static int virq_sgi; static int event_manager_availability = -EACCES; @@ -570,7 +571,6 @@ static void xlnx_disable_percpu_irq(void *data) static int xlnx_event_init_sgi(struct platform_device *pdev) { int ret = 0; - int cpu; /* * IRQ related structures are used for the following: * for each SGI interrupt ensure its mapped by GIC IRQ domain @@ -607,11 +607,8 @@ static int xlnx_event_init_sgi(struct platform_device *pdev) sgi_fwspec.param[0] = sgi_num; virq_sgi = irq_create_fwspec_mapping(&sgi_fwspec); - cpu = get_cpu(); - per_cpu(cpu_number1, cpu) = cpu; ret = request_percpu_irq(virq_sgi, xlnx_event_handler, "xlnx_event_mgmt", - &cpu_number1); - put_cpu(); + &dummy_cpu_number); WARN_ON(ret); if (ret) { @@ -627,16 +624,12 @@ static int xlnx_event_init_sgi(struct platform_device *pdev) static void xlnx_event_cleanup_sgi(struct platform_device *pdev) { - int cpu = smp_processor_id(); - - per_cpu(cpu_number1, cpu) = cpu; - cpuhp_remove_state(CPUHP_AP_ONLINE_DYN); on_each_cpu(xlnx_disable_percpu_irq, NULL, 1); irq_clear_status_flags(virq_sgi, IRQ_PER_CPU); - free_percpu_irq(virq_sgi, &cpu_number1); + free_percpu_irq(virq_sgi, &dummy_cpu_number); irq_dispose_mapping(virq_sgi); } -- cgit v1.2.3 From fcf544ac64397776a18246eba5a8ca72a47c4405 Mon Sep 17 00:00:00 2001 From: Jay Buddhabhatti Date: Wed, 24 Apr 2024 05:49:00 -0700 Subject: soc: xilinx: Add cb event for subsystem restart Add support to register subsystem restart events from firmware for Versal and Versal NET platforms. This event is received when firmware requests for subsystem restart. After receiving this event, the kernel needs to be restarted. Signed-off-by: Jay Buddhabhatti Link: https://lore.kernel.org/r/20240424124900.29287-1-jay.buddhabhatti@amd.com Signed-off-by: Michal Simek --- drivers/soc/xilinx/zynqmp_power.c | 151 ++++++++++++++++++++++++---- include/linux/firmware/xlnx-event-manager.h | 10 ++ 2 files changed, 141 insertions(+), 20 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c index 965b1143936a..fced6bedca43 100644 --- a/drivers/soc/xilinx/zynqmp_power.c +++ b/drivers/soc/xilinx/zynqmp_power.c @@ -30,9 +30,27 @@ struct zynqmp_pm_work_struct { u32 args[CB_ARG_CNT]; }; -static struct zynqmp_pm_work_struct *zynqmp_pm_init_suspend_work; +/** + * struct zynqmp_pm_event_info - event related information + * @cb_fun: Function pointer to store the callback function. + * @cb_type: Type of callback from pm_api_cb_id, + * PM_NOTIFY_CB - for Error Events, + * PM_INIT_SUSPEND_CB - for suspend callback. + * @node_id: Node-Id related to event. + * @event: Event Mask for the Error Event. + * @wake: Flag specifying whether the subsystem should be woken upon + * event notification. + */ +struct zynqmp_pm_event_info { + event_cb_func_t cb_fun; + enum pm_api_cb_id cb_type; + u32 node_id; + u32 event; + bool wake; +}; + +static struct zynqmp_pm_work_struct *zynqmp_pm_init_suspend_work, *zynqmp_pm_init_restart_work; static struct mbox_chan *rx_chan; -static bool event_registered; enum pm_suspend_mode { PM_SUSPEND_MODE_FIRST = 0, @@ -54,6 +72,19 @@ static void zynqmp_pm_get_callback_data(u32 *buf) zynqmp_pm_invoke_fn(GET_CALLBACK_DATA, buf, 0); } +static void subsystem_restart_event_callback(const u32 *payload, void *data) +{ + /* First element is callback API ID, others are callback arguments */ + if (work_pending(&zynqmp_pm_init_restart_work->callback_work)) + return; + + /* Copy callback arguments into work's structure */ + memcpy(zynqmp_pm_init_restart_work->args, &payload[0], + sizeof(zynqmp_pm_init_restart_work->args)); + + queue_work(system_unbound_wq, &zynqmp_pm_init_restart_work->callback_work); +} + static void suspend_event_callback(const u32 *payload, void *data) { /* First element is callback API ID, others are callback arguments */ @@ -119,6 +150,37 @@ static void ipi_receive_callback(struct mbox_client *cl, void *data) } } +/** + * zynqmp_pm_subsystem_restart_work_fn - Initiate Subsystem restart + * @work: Pointer to work_struct + * + * Bottom-half of PM callback IRQ handler. + */ +static void zynqmp_pm_subsystem_restart_work_fn(struct work_struct *work) +{ + int ret; + struct zynqmp_pm_work_struct *pm_work = container_of(work, struct zynqmp_pm_work_struct, + callback_work); + + /* First element is callback API ID, others are callback arguments */ + if (pm_work->args[0] == PM_NOTIFY_CB) { + if (pm_work->args[2] == EVENT_SUBSYSTEM_RESTART) { + ret = zynqmp_pm_system_shutdown(ZYNQMP_PM_SHUTDOWN_TYPE_SETSCOPE_ONLY, + ZYNQMP_PM_SHUTDOWN_SUBTYPE_SUBSYSTEM); + if (ret) { + pr_err("unable to set shutdown scope\n"); + return; + } + + kernel_restart(NULL); + } else { + pr_err("%s Unsupported Event - %d\n", __func__, pm_work->args[2]); + } + } else { + pr_err("%s() Unsupported Callback %d\n", __func__, pm_work->args[0]); + } +} + /** * zynqmp_pm_init_suspend_work_fn - Initialize suspend * @work: Pointer to work_struct @@ -184,10 +246,46 @@ static ssize_t suspend_mode_store(struct device *dev, static DEVICE_ATTR_RW(suspend_mode); +static void unregister_event(struct device *dev, void *res) +{ + struct zynqmp_pm_event_info *event_info = res; + + xlnx_unregister_event(event_info->cb_type, event_info->node_id, + event_info->event, event_info->cb_fun, NULL); +} + +static int register_event(struct device *dev, const enum pm_api_cb_id cb_type, const u32 node_id, + const u32 event, const bool wake, event_cb_func_t cb_fun) +{ + int ret; + struct zynqmp_pm_event_info *event_info; + + event_info = devres_alloc(unregister_event, sizeof(struct zynqmp_pm_event_info), + GFP_KERNEL); + if (!event_info) + return -ENOMEM; + + event_info->cb_type = cb_type; + event_info->node_id = node_id; + event_info->event = event; + event_info->wake = wake; + event_info->cb_fun = cb_fun; + + ret = xlnx_register_event(event_info->cb_type, event_info->node_id, + event_info->event, event_info->wake, event_info->cb_fun, NULL); + if (ret) { + devres_free(event_info); + return ret; + } + + devres_add(dev, event_info); + return 0; +} + static int zynqmp_pm_probe(struct platform_device *pdev) { int ret, irq; - u32 pm_api_version; + u32 pm_api_version, pm_family_code, pm_sub_family_code, node_id; struct mbox_client *client; zynqmp_pm_get_api_version(&pm_api_version); @@ -203,21 +301,43 @@ static int zynqmp_pm_probe(struct platform_device *pdev) * is not available to use) or -ENODEV(Xilinx Event Manager not compiled), * then use ipi-mailbox or interrupt method. */ - ret = xlnx_register_event(PM_INIT_SUSPEND_CB, 0, 0, false, - suspend_event_callback, NULL); + ret = register_event(&pdev->dev, PM_INIT_SUSPEND_CB, 0, 0, false, + suspend_event_callback); if (!ret) { zynqmp_pm_init_suspend_work = devm_kzalloc(&pdev->dev, sizeof(struct zynqmp_pm_work_struct), GFP_KERNEL); - if (!zynqmp_pm_init_suspend_work) { - xlnx_unregister_event(PM_INIT_SUSPEND_CB, 0, 0, - suspend_event_callback, NULL); + if (!zynqmp_pm_init_suspend_work) return -ENOMEM; - } - event_registered = true; INIT_WORK(&zynqmp_pm_init_suspend_work->callback_work, zynqmp_pm_init_suspend_work_fn); + + ret = zynqmp_pm_get_family_info(&pm_family_code, &pm_sub_family_code); + if (ret < 0) + return ret; + + if (pm_sub_family_code == VERSALNET_SUB_FAMILY_CODE) + node_id = PM_DEV_ACPU_0_0; + else + node_id = PM_DEV_ACPU_0; + + ret = register_event(&pdev->dev, PM_NOTIFY_CB, node_id, EVENT_SUBSYSTEM_RESTART, + false, subsystem_restart_event_callback); + if (ret) { + dev_err(&pdev->dev, "Failed to Register with Xilinx Event manager %d\n", + ret); + return ret; + } + + zynqmp_pm_init_restart_work = devm_kzalloc(&pdev->dev, + sizeof(struct zynqmp_pm_work_struct), + GFP_KERNEL); + if (!zynqmp_pm_init_restart_work) + return -ENOMEM; + + INIT_WORK(&zynqmp_pm_init_restart_work->callback_work, + zynqmp_pm_subsystem_restart_work_fn); } else if (ret != -EACCES && ret != -ENODEV) { dev_err(&pdev->dev, "Failed to Register with Xilinx Event manager %d\n", ret); return ret; @@ -264,15 +384,8 @@ static int zynqmp_pm_probe(struct platform_device *pdev) } ret = sysfs_create_file(&pdev->dev.kobj, &dev_attr_suspend_mode.attr); - if (ret) { - if (event_registered) { - xlnx_unregister_event(PM_INIT_SUSPEND_CB, 0, 0, suspend_event_callback, - NULL); - event_registered = false; - } - dev_err(&pdev->dev, "unable to create sysfs interface\n"); + if (ret) return ret; - } return 0; } @@ -280,8 +393,6 @@ static int zynqmp_pm_probe(struct platform_device *pdev) static void zynqmp_pm_remove(struct platform_device *pdev) { sysfs_remove_file(&pdev->dev.kobj, &dev_attr_suspend_mode.attr); - if (event_registered) - xlnx_unregister_event(PM_INIT_SUSPEND_CB, 0, 0, suspend_event_callback, NULL); if (!rx_chan) mbox_free_channel(rx_chan); diff --git a/include/linux/firmware/xlnx-event-manager.h b/include/linux/firmware/xlnx-event-manager.h index 82e8254b0f80..645dd34155e6 100644 --- a/include/linux/firmware/xlnx-event-manager.h +++ b/include/linux/firmware/xlnx-event-manager.h @@ -1,4 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 */ +/* + * Xilinx Event Management Driver + * + * Copyright (C) 2024, Advanced Micro Devices, Inc. + */ #ifndef _FIRMWARE_XLNX_EVENT_MANAGER_H_ #define _FIRMWARE_XLNX_EVENT_MANAGER_H_ @@ -7,6 +12,11 @@ #define CB_MAX_PAYLOAD_SIZE (4U) /*In payload maximum 32bytes */ +#define EVENT_SUBSYSTEM_RESTART (4U) + +#define PM_DEV_ACPU_0_0 (0x1810c0afU) +#define PM_DEV_ACPU_0 (0x1810c003U) + /************************** Exported Function *****************************/ typedef void (*event_cb_func_t)(const u32 *payload, void *data); -- cgit v1.2.3 From 494c55a1ec0ab40198cf43f5a41c7c5e0b70e7fc Mon Sep 17 00:00:00 2001 From: Ronak Jain Date: Thu, 25 Apr 2024 02:59:13 -0700 Subject: firmware: xilinx: Move FIRMWARE_VERSION_MASK to xlnx-zynqmp.h Move FIRMWARE_VERSION_MASK macro to xlnx-zynqmp.h so that other drivers can use it for verifying the supported firmware version. Signed-off-by: Ronak Jain Signed-off-by: Anand Ashok Dumbre Signed-off-by: Radhey Shyam Pandey Link: https://lore.kernel.org/r/20240425095913.919390-1-ronak.jain@amd.com Signed-off-by: Michal Simek --- drivers/firmware/xilinx/zynqmp.c | 3 --- drivers/soc/xilinx/xlnx_event_manager.c | 1 - include/linux/firmware/xlnx-zynqmp.h | 3 +++ 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index 9bc45357e1a8..add8acf66a9c 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -41,9 +41,6 @@ /* IOCTL/QUERY feature payload size */ #define FEATURE_PAYLOAD_SIZE 2 -/* Firmware feature check version mask */ -#define FIRMWARE_VERSION_MASK GENMASK(15, 0) - static bool feature_check_enabled; static DEFINE_HASHTABLE(pm_api_features_map, PM_API_FEATURE_CHECK_MAX_ORDER); static u32 ioctl_features[FEATURE_PAYLOAD_SIZE]; diff --git a/drivers/soc/xilinx/xlnx_event_manager.c b/drivers/soc/xilinx/xlnx_event_manager.c index 366018f6a0ee..f529e1346247 100644 --- a/drivers/soc/xilinx/xlnx_event_manager.c +++ b/drivers/soc/xilinx/xlnx_event_manager.c @@ -36,7 +36,6 @@ static int event_manager_availability = -EACCES; #define MAX_BITS (32U) /* Number of bits available for error mask */ -#define FIRMWARE_VERSION_MASK (0xFFFFU) #define REGISTER_NOTIFIER_FIRMWARE_VERSION (2U) static DEFINE_HASHTABLE(reg_driver_map, REGISTERED_DRIVER_MAX_ORDER); diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h index 1a069a56c961..d7d07afc0532 100644 --- a/include/linux/firmware/xlnx-zynqmp.h +++ b/include/linux/firmware/xlnx-zynqmp.h @@ -52,6 +52,9 @@ #define API_ID_MASK GENMASK(7, 0) #define MODULE_ID_MASK GENMASK(11, 8) +/* Firmware feature check version mask */ +#define FIRMWARE_VERSION_MASK 0xFFFFU + /* ATF only commands */ #define TF_A_PM_REGISTER_SGI 0xa04 #define PM_GET_TRUSTZONE_VERSION 0xa03 -- cgit v1.2.3 From 9b003e14801cf85a8cebeddc87bc9fc77100fdce Mon Sep 17 00:00:00 2001 From: Jay Buddhabhatti Date: Wed, 15 May 2024 04:23:45 -0700 Subject: drivers: soc: xilinx: check return status of get_api_version() Currently return status is not getting checked for get_api_version and because of that for x86 arch we are getting below smatch error. CC drivers/soc/xilinx/zynqmp_power.o drivers/soc/xilinx/zynqmp_power.c: In function 'zynqmp_pm_probe': drivers/soc/xilinx/zynqmp_power.c:295:12: warning: 'pm_api_version' is used uninitialized [-Wuninitialized] 295 | if (pm_api_version < ZYNQMP_PM_VERSION) | ^ CHECK drivers/soc/xilinx/zynqmp_power.c drivers/soc/xilinx/zynqmp_power.c:295 zynqmp_pm_probe() error: uninitialized symbol 'pm_api_version'. So, check return status of pm_get_api_version and return error in case of failure to avoid checking uninitialized pm_api_version variable. Fixes: b9b3a8be28b3 ("firmware: xilinx: Remove eemi ops for get_api_version") Signed-off-by: Jay Buddhabhatti Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20240515112345.24673-1-jay.buddhabhatti@amd.com Signed-off-by: Michal Simek --- drivers/soc/xilinx/zynqmp_power.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c index fced6bedca43..411d33f2fb05 100644 --- a/drivers/soc/xilinx/zynqmp_power.c +++ b/drivers/soc/xilinx/zynqmp_power.c @@ -288,7 +288,9 @@ static int zynqmp_pm_probe(struct platform_device *pdev) u32 pm_api_version, pm_family_code, pm_sub_family_code, node_id; struct mbox_client *client; - zynqmp_pm_get_api_version(&pm_api_version); + ret = zynqmp_pm_get_api_version(&pm_api_version); + if (ret) + return ret; /* Check PM API version number */ if (pm_api_version < ZYNQMP_PM_VERSION) -- cgit v1.2.3 From 1b503fa221d144fbb11e2591378429566564a6b8 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Mon, 3 Jun 2024 17:09:34 -0700 Subject: soc: qcom: spm: add missing MODULE_DESCRIPTION() make allmodconfig && make W=1 C=1 warns: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/soc/qcom/spm.o Add the missing MODULE_DESCRIPTION(), using the same description as the underlying QCOM_SPM Kconfig item. Signed-off-by: Jeff Johnson Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240603-md-soc-qcom-spm-v1-1-617730f08d22@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/spm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c index 06e2c4c2a4a8..f75659fff287 100644 --- a/drivers/soc/qcom/spm.c +++ b/drivers/soc/qcom/spm.c @@ -572,4 +572,5 @@ static int __init qcom_spm_init(void) } arch_initcall(qcom_spm_init); +MODULE_DESCRIPTION("Qualcomm Subsystem Power Manager (SPM)"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From d1d0f1f6ff6013211e3ee00237e4cc25ad0cd64b Mon Sep 17 00:00:00 2001 From: Christian Hewitt Date: Tue, 4 Jun 2024 05:07:52 +0000 Subject: soc: amlogic: meson-gx-socinfo: Add S905L ID Add the S905L SoC ID observed in several P271 boards: kernel: soc soc0: Amlogic Meson GXLX (S905L) Revision 26:a (c1:2) Detected Signed-off-by: Christian Hewitt Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20240604050752.3312468-1-christianshewitt@gmail.com Signed-off-by: Neil Armstrong --- drivers/soc/amlogic/meson-gx-socinfo.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc') diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c index 6abb730344ab..7e255acf5430 100644 --- a/drivers/soc/amlogic/meson-gx-socinfo.c +++ b/drivers/soc/amlogic/meson-gx-socinfo.c @@ -64,6 +64,7 @@ static const struct meson_gx_package_id { { "962E", 0x24, 0x20, 0xf0 }, { "A113X", 0x25, 0x37, 0xff }, { "A113D", 0x25, 0x22, 0xff }, + { "S905L", 0x26, 0, 0x0 }, { "S905D2", 0x28, 0x10, 0xf0 }, { "S905Y2", 0x28, 0x30, 0xf0 }, { "S905X2", 0x28, 0x40, 0xf0 }, -- cgit v1.2.3 From 2faaab64de0e89697e01f1a0c5d401ea74d52447 Mon Sep 17 00:00:00 2001 From: Viacheslav Bocharov Date: Tue, 4 Jun 2024 17:04:51 +0300 Subject: soc: amlogic: meson-gx-socinfo: add new A113X SoC id Add new definition for Amlogix A113X SoC found in JetHub D1/D1+ devices: soc soc0: Amlogic Meson AXG (A113X) Revision 25:b (43:2) Detected Signed-off-by: Viacheslav Bocharov Reviewed-by: Neil Armstrong Link: https://lore.kernel.org/r/20240604140612.1179323-1-adeep@lexina.in Signed-off-by: Neil Armstrong --- drivers/soc/amlogic/meson-gx-socinfo.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc') diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c index 7e255acf5430..8809a948201a 100644 --- a/drivers/soc/amlogic/meson-gx-socinfo.c +++ b/drivers/soc/amlogic/meson-gx-socinfo.c @@ -63,6 +63,7 @@ static const struct meson_gx_package_id { { "962X", 0x24, 0x10, 0xf0 }, { "962E", 0x24, 0x20, 0xf0 }, { "A113X", 0x25, 0x37, 0xff }, + { "A113X", 0x25, 0x43, 0xff }, { "A113D", 0x25, 0x22, 0xff }, { "S905L", 0x26, 0, 0x0 }, { "S905D2", 0x28, 0x10, 0xf0 }, -- cgit v1.2.3 From 75287992f58a74271a083fef0356bc81d629f671 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Thu, 6 Jun 2024 21:18:33 +0200 Subject: soc: qcom: smsm: Support using mailbox interface Add support for using the mbox interface instead of manually writing to the syscon. With this change the driver will attempt to get the mailbox first, and if that fails it will fall back to the existing way of using qcom,ipc-* properties and converting to syscon. Reviewed-by: Konrad Dybcio Signed-off-by: Luca Weiss Link: https://lore.kernel.org/r/20240606-smsm-mbox-v2-2-8abe6b5f01da@z3ntu.xyz Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/smsm.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/smsm.c b/drivers/soc/qcom/smsm.c index e7c7e9a640a6..ffe78ae34386 100644 --- a/drivers/soc/qcom/smsm.c +++ b/drivers/soc/qcom/smsm.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -71,6 +72,7 @@ struct smsm_host; * @lock: spinlock for read-modify-write of the outgoing state * @entries: context for each of the entries * @hosts: context for each of the hosts + * @mbox_client: mailbox client handle */ struct qcom_smsm { struct device *dev; @@ -88,6 +90,8 @@ struct qcom_smsm { struct smsm_entry *entries; struct smsm_host *hosts; + + struct mbox_client mbox_client; }; /** @@ -120,11 +124,14 @@ struct smsm_entry { * @ipc_regmap: regmap for outgoing interrupt * @ipc_offset: offset in @ipc_regmap for outgoing interrupt * @ipc_bit: bit in @ipc_regmap + @ipc_offset for outgoing interrupt + * @mbox_chan: apcs ipc mailbox channel handle */ struct smsm_host { struct regmap *ipc_regmap; int ipc_offset; int ipc_bit; + + struct mbox_chan *mbox_chan; }; /** @@ -172,7 +179,13 @@ static int smsm_update_bits(void *data, u32 mask, u32 value) hostp = &smsm->hosts[host]; val = readl(smsm->subscription + host); - if (val & changes && hostp->ipc_regmap) { + if (!(val & changes)) + continue; + + if (hostp->mbox_chan) { + mbox_send_message(hostp->mbox_chan, NULL); + mbox_client_txdone(hostp->mbox_chan, 0); + } else if (hostp->ipc_regmap) { regmap_write(hostp->ipc_regmap, hostp->ipc_offset, BIT(hostp->ipc_bit)); @@ -352,6 +365,28 @@ static const struct irq_domain_ops smsm_irq_ops = { .xlate = irq_domain_xlate_twocell, }; +/** + * smsm_parse_mbox() - requests an mbox channel + * @smsm: smsm driver context + * @host_id: index of the remote host to be resolved + * + * Requests the desired channel using the mbox interface which is needed for + * sending the outgoing interrupts to a remove hosts - identified by @host_id. + */ +static int smsm_parse_mbox(struct qcom_smsm *smsm, unsigned int host_id) +{ + struct smsm_host *host = &smsm->hosts[host_id]; + int ret = 0; + + host->mbox_chan = mbox_request_channel(&smsm->mbox_client, host_id); + if (IS_ERR(host->mbox_chan)) { + ret = PTR_ERR(host->mbox_chan); + host->mbox_chan = NULL; + } + + return ret; +} + /** * smsm_parse_ipc() - parses a qcom,ipc-%d device tree property * @smsm: smsm driver context @@ -521,8 +556,16 @@ static int qcom_smsm_probe(struct platform_device *pdev) "qcom,local-host", &smsm->local_host); + smsm->mbox_client.dev = &pdev->dev; + smsm->mbox_client.knows_txdone = true; + /* Parse the host properties */ for (id = 0; id < smsm->num_hosts; id++) { + /* Try using mbox interface first, otherwise fall back to syscon */ + ret = smsm_parse_mbox(smsm, id); + if (!ret) + continue; + ret = smsm_parse_ipc(smsm, id); if (ret < 0) goto out_put; @@ -609,6 +652,9 @@ unwind_interfaces: qcom_smem_state_unregister(smsm->state); out_put: + for (id = 0; id < smsm->num_hosts; id++) + mbox_free_channel(smsm->hosts[id].mbox_chan); + of_node_put(local_node); return ret; } @@ -622,6 +668,9 @@ static void qcom_smsm_remove(struct platform_device *pdev) if (smsm->entries[id].domain) irq_domain_remove(smsm->entries[id].domain); + for (id = 0; id < smsm->num_hosts; id++) + mbox_free_channel(smsm->hosts[id].mbox_chan); + qcom_smem_state_unregister(smsm->state); } -- cgit v1.2.3 From 9267997fa7aa0b597e8b32cb3fdfe91be1d35a83 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 5 Jun 2024 22:10:14 +0200 Subject: soc: qcom: Move some socinfo defines to the header In preparation for parsing the chip "feature code" (FC) and "product code" (PC) (essentially the parameters that let us conclusively characterize the sillicon we're running on, including various speed bins), move the socinfo version defines to the public header. Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240605-topic-smem_speedbin-v2-1-8989d7e3d176@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/socinfo.c | 8 -------- include/linux/soc/qcom/socinfo.h | 8 ++++++++ 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 277c07a6603d..cf4616a468f2 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -21,14 +21,6 @@ #include -/* - * SoC version type with major number in the upper 16 bits and minor - * number in the lower 16 bits. - */ -#define SOCINFO_MAJOR(ver) (((ver) >> 16) & 0xffff) -#define SOCINFO_MINOR(ver) ((ver) & 0xffff) -#define SOCINFO_VERSION(maj, min) ((((maj) & 0xffff) << 16)|((min) & 0xffff)) - /* Helper macros to create soc_id table */ #define qcom_board_id(id) QCOM_ID_ ## id, __stringify(id) #define qcom_board_id_named(id, name) QCOM_ID_ ## id, (name) diff --git a/include/linux/soc/qcom/socinfo.h b/include/linux/soc/qcom/socinfo.h index e78777bb0f4a..10e0a4c287f4 100644 --- a/include/linux/soc/qcom/socinfo.h +++ b/include/linux/soc/qcom/socinfo.h @@ -12,6 +12,14 @@ #define SMEM_SOCINFO_BUILD_ID_LENGTH 32 #define SMEM_SOCINFO_CHIP_ID_LENGTH 32 +/* + * SoC version type with major number in the upper 16 bits and minor + * number in the lower 16 bits. + */ +#define SOCINFO_MAJOR(ver) (((ver) >> 16) & 0xffff) +#define SOCINFO_MINOR(ver) ((ver) & 0xffff) +#define SOCINFO_VERSION(maj, min) ((((maj) & 0xffff) << 16)|((min) & 0xffff)) + /* Socinfo SMEM item structure */ struct socinfo { __le32 fmt; -- cgit v1.2.3 From 81bbb2b891174da9301fc0d4fe9622bd4cb6a995 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Wed, 5 Jun 2024 22:10:15 +0200 Subject: soc: qcom: smem: Add a feature code getter Recent (SM8550+ ish) Qualcomm SoCs have a new mechanism for precisely identifying the specific SKU and the precise speed bin (in the general meaning of this word, anyway): a pair of values called Product Code and Feature Code. Based on this information, we can deduce the available frequencies for things such as Adreno. In the case of Adreno specifically, Pcode is useless for non-prototype SoCs. Introduce a getter for the feature code and export it. Reviewed-by: Dmitry Baryshkov Signed-off-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240605-topic-smem_speedbin-v2-2-8989d7e3d176@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/smem.c | 33 +++++++++++++++++++++++++++++++++ include/linux/soc/qcom/smem.h | 1 + include/linux/soc/qcom/socinfo.h | 26 ++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 7191fa0c087f..e40aac281b06 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -795,6 +795,39 @@ int qcom_smem_get_soc_id(u32 *id) } EXPORT_SYMBOL_GPL(qcom_smem_get_soc_id); +/** + * qcom_smem_get_feature_code() - return the feature code + * @code: On success, return the feature code here. + * + * Look up the feature code identifier from SMEM and return it. + * + * Return: 0 on success, negative errno on failure. + */ +int qcom_smem_get_feature_code(u32 *code) +{ + struct socinfo *info; + u32 raw_code; + + info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID, NULL); + if (IS_ERR(info)) + return PTR_ERR(info); + + /* This only makes sense for socinfo >= 16 */ + if (__le32_to_cpu(info->fmt) < SOCINFO_VERSION(0, 16)) + return -EOPNOTSUPP; + + raw_code = __le32_to_cpu(info->feature_code); + + /* Ensure the value makes sense */ + if (raw_code > SOCINFO_FC_INT_MAX) + raw_code = SOCINFO_FC_UNKNOWN; + + *code = raw_code; + + return 0; +} +EXPORT_SYMBOL_GPL(qcom_smem_get_feature_code); + static int qcom_smem_get_sbl_version(struct qcom_smem *smem) { struct smem_header *header; diff --git a/include/linux/soc/qcom/smem.h b/include/linux/soc/qcom/smem.h index a36a3b9d4929..0943bf419e11 100644 --- a/include/linux/soc/qcom/smem.h +++ b/include/linux/soc/qcom/smem.h @@ -13,5 +13,6 @@ int qcom_smem_get_free_space(unsigned host); phys_addr_t qcom_smem_virt_to_phys(void *p); int qcom_smem_get_soc_id(u32 *id); +int qcom_smem_get_feature_code(u32 *code); #endif diff --git a/include/linux/soc/qcom/socinfo.h b/include/linux/soc/qcom/socinfo.h index 10e0a4c287f4..608950443eee 100644 --- a/include/linux/soc/qcom/socinfo.h +++ b/include/linux/soc/qcom/socinfo.h @@ -3,6 +3,8 @@ #ifndef __QCOM_SOCINFO_H__ #define __QCOM_SOCINFO_H__ +#include + /* * SMEM item id, used to acquire handles to respective * SMEM region. @@ -82,4 +84,28 @@ struct socinfo { __le32 boot_core; }; +/* Internal feature codes */ +enum qcom_socinfo_feature_code { + /* External feature codes */ + SOCINFO_FC_UNKNOWN = 0x0, + SOCINFO_FC_AA, + SOCINFO_FC_AB, + SOCINFO_FC_AC, + SOCINFO_FC_AD, + SOCINFO_FC_AE, + SOCINFO_FC_AF, + SOCINFO_FC_AG, + SOCINFO_FC_AH, +}; + +/* Internal feature codes */ +/* Valid values: 0 <= n <= 0xf */ +#define SOCINFO_FC_Yn(n) (0xf1 + (n)) +#define SOCINFO_FC_INT_MAX SOCINFO_FC_Yn(0xf) + +/* Product codes */ +#define SOCINFO_PC_UNKNOWN 0 +#define SOCINFO_PCn(n) ((n) + 1) +#define SOCINFO_PC_RESERVE (BIT(31) - 1) + #endif -- cgit v1.2.3 From 24086640ab39396eb1a92d1cb1cd2f31b2677c52 Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Thu, 13 Jun 2024 22:15:06 +0530 Subject: soc: qcom: icc-bwmon: Fix refcount imbalance seen during bwmon_remove The following warning is seen during bwmon_remove due to refcount imbalance, fix this by releasing the OPPs after use. Logs: WARNING: at drivers/opp/core.c:1640 _opp_table_kref_release+0x150/0x158 Hardware name: Qualcomm Technologies, Inc. X1E80100 CRD (DT) ... Call trace: _opp_table_kref_release+0x150/0x158 dev_pm_opp_remove_table+0x100/0x1b4 devm_pm_opp_of_table_release+0x10/0x1c devm_action_release+0x14/0x20 devres_release_all+0xa4/0x104 device_unbind_cleanup+0x18/0x60 device_release_driver_internal+0x1ec/0x228 driver_detach+0x50/0x98 bus_remove_driver+0x6c/0xbc driver_unregister+0x30/0x60 platform_driver_unregister+0x14/0x20 bwmon_driver_exit+0x18/0x524 [icc_bwmon] __arm64_sys_delete_module+0x184/0x264 invoke_syscall+0x48/0x118 el0_svc_common.constprop.0+0xc8/0xe8 do_el0_svc+0x20/0x2c el0_svc+0x34/0xdc el0t_64_sync_handler+0x13c/0x158 el0t_64_sync+0x190/0x194 --[ end trace 0000000000000000 ]--- Fixes: 0276f69f13e2 ("soc: qcom: icc-bwmon: Set default thresholds dynamically") Fixes: b9c2ae6cac40 ("soc: qcom: icc-bwmon: Add bandwidth monitoring driver") Signed-off-by: Sibi Sankar Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240613164506.982068-1-quic_sibis@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/icc-bwmon.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/icc-bwmon.c b/drivers/soc/qcom/icc-bwmon.c index fb323b3364db..ecddb60bd665 100644 --- a/drivers/soc/qcom/icc-bwmon.c +++ b/drivers/soc/qcom/icc-bwmon.c @@ -565,7 +565,7 @@ static void bwmon_start(struct icc_bwmon *bwmon) int window; /* No need to check for errors, as this must have succeeded before. */ - dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_low, 0); + dev_pm_opp_put(dev_pm_opp_find_bw_ceil(bwmon->dev, &bw_low, 0)); bwmon_clear_counters(bwmon, true); @@ -772,11 +772,13 @@ static int bwmon_probe(struct platform_device *pdev) opp = dev_pm_opp_find_bw_floor(dev, &bwmon->max_bw_kbps, 0); if (IS_ERR(opp)) return dev_err_probe(dev, PTR_ERR(opp), "failed to find max peak bandwidth\n"); + dev_pm_opp_put(opp); bwmon->min_bw_kbps = 0; opp = dev_pm_opp_find_bw_ceil(dev, &bwmon->min_bw_kbps, 0); if (IS_ERR(opp)) return dev_err_probe(dev, PTR_ERR(opp), "failed to find min peak bandwidth\n"); + dev_pm_opp_put(opp); bwmon->dev = dev; -- cgit v1.2.3 From 107924c14e3ddd85119ca43c26a4ee1056fa9b84 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 22 Jun 2024 01:03:40 +0300 Subject: soc: qcom: pdr: protect locator_addr with the main mutex If the service locator server is restarted fast enough, the PDR can rewrite locator_addr fields concurrently. Protect them by placing modification of those fields under the main pdr->lock. Fixes: fbe639b44a82 ("soc: qcom: Introduce Protection Domain Restart helpers") Tested-by: Neil Armstrong # on SM8550-QRD Tested-by: Steev Klimaszewski Tested-by: Alexey Minnekhanov Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240622-qcom-pd-mapper-v9-1-a84ee3591c8e@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/pdr_interface.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/pdr_interface.c b/drivers/soc/qcom/pdr_interface.c index a1b6a4081dea..76a62c2ecc58 100644 --- a/drivers/soc/qcom/pdr_interface.c +++ b/drivers/soc/qcom/pdr_interface.c @@ -76,12 +76,12 @@ static int pdr_locator_new_server(struct qmi_handle *qmi, locator_hdl); struct pdr_service *pds; + mutex_lock(&pdr->lock); /* Create a local client port for QMI communication */ pdr->locator_addr.sq_family = AF_QIPCRTR; pdr->locator_addr.sq_node = svc->node; pdr->locator_addr.sq_port = svc->port; - mutex_lock(&pdr->lock); pdr->locator_init_complete = true; mutex_unlock(&pdr->lock); @@ -104,10 +104,10 @@ static void pdr_locator_del_server(struct qmi_handle *qmi, mutex_lock(&pdr->lock); pdr->locator_init_complete = false; - mutex_unlock(&pdr->lock); pdr->locator_addr.sq_node = 0; pdr->locator_addr.sq_port = 0; + mutex_unlock(&pdr->lock); } static const struct qmi_ops pdr_locator_ops = { @@ -365,12 +365,14 @@ static int pdr_get_domain_list(struct servreg_get_domain_list_req *req, if (ret < 0) return ret; + mutex_lock(&pdr->lock); ret = qmi_send_request(&pdr->locator_hdl, &pdr->locator_addr, &txn, SERVREG_GET_DOMAIN_LIST_REQ, SERVREG_GET_DOMAIN_LIST_REQ_MAX_LEN, servreg_get_domain_list_req_ei, req); + mutex_unlock(&pdr->lock); if (ret < 0) { qmi_txn_cancel(&txn); return ret; -- cgit v1.2.3 From 57f20d51f35780f240ecf39d81cda23612800a92 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 22 Jun 2024 01:03:41 +0300 Subject: soc: qcom: pdr: fix parsing of domains lists While parsing the domains list, start offsets from 0 rather than from domains_read. The domains_read is equal to the total count of the domains we have seen, while the domains list in the message starts from offset 0. Fixes: fbe639b44a82 ("soc: qcom: Introduce Protection Domain Restart helpers") Tested-by: Steev Klimaszewski Tested-by: Alexey Minnekhanov Reviewed-by: Chris Lew Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240622-qcom-pd-mapper-v9-2-a84ee3591c8e@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/pdr_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/pdr_interface.c b/drivers/soc/qcom/pdr_interface.c index 76a62c2ecc58..216166e98fae 100644 --- a/drivers/soc/qcom/pdr_interface.c +++ b/drivers/soc/qcom/pdr_interface.c @@ -417,7 +417,7 @@ static int pdr_locate_service(struct pdr_handle *pdr, struct pdr_service *pds) if (ret < 0) goto out; - for (i = domains_read; i < resp->domain_list_len; i++) { + for (i = 0; i < resp->domain_list_len; i++) { entry = &resp->domain_list[i]; if (strnlen(entry->name, sizeof(entry->name)) == sizeof(entry->name)) -- cgit v1.2.3 From 0ac5c7d933de6570e0efa62bb5ef9e440311a6fe Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 22 Jun 2024 01:03:42 +0300 Subject: soc: qcom: pdr: extract PDR message marshalling data The in-kernel PD mapper is going to use same message structures as the QCOM_PDR_HELPERS module. Extract message marshalling data to separate module that can be used by both PDR helpers and by PD mapper. Reviewed-by: Bryan O'Donoghue Tested-by: Steev Klimaszewski Tested-by: Alexey Minnekhanov Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240622-qcom-pd-mapper-v9-3-a84ee3591c8e@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/Kconfig | 4 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/pdr_internal.h | 306 ++------------------------------------ drivers/soc/qcom/qcom_pdr_msg.c | 319 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 334 insertions(+), 296 deletions(-) create mode 100644 drivers/soc/qcom/qcom_pdr_msg.c (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 5af33b0e3470..95973c6b828f 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -75,8 +75,12 @@ config QCOM_OCMEM config QCOM_PDR_HELPERS tristate select QCOM_QMI_HELPERS + select QCOM_PDR_MSG depends on NET +config QCOM_PDR_MSG + tristate + config QCOM_PMIC_PDCHARGER_ULOG tristate "Qualcomm PMIC PDCharger ULOG driver" depends on RPMSG diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index ca0bece0dfff..3110ac3288bc 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o obj-$(CONFIG_QCOM_OCMEM) += ocmem.o obj-$(CONFIG_QCOM_PDR_HELPERS) += pdr_interface.o +obj-$(CONFIG_QCOM_PDR_MSG) += qcom_pdr_msg.o obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink_altmode.o obj-$(CONFIG_QCOM_PMIC_PDCHARGER_ULOG) += pmic_pdcharger_ulog.o diff --git a/drivers/soc/qcom/pdr_internal.h b/drivers/soc/qcom/pdr_internal.h index 03c282b7f17e..7e5bb5a95275 100644 --- a/drivers/soc/qcom/pdr_internal.h +++ b/drivers/soc/qcom/pdr_internal.h @@ -28,83 +28,12 @@ struct servreg_location_entry { u32 instance; }; -static const struct qmi_elem_info servreg_location_entry_ei[] = { - { - .data_type = QMI_STRING, - .elem_len = SERVREG_NAME_LENGTH + 1, - .elem_size = sizeof(char), - .array_type = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct servreg_location_entry, - name), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(u32), - .array_type = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct servreg_location_entry, - instance), - }, - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(u8), - .array_type = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct servreg_location_entry, - service_data_valid), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(u32), - .array_type = NO_ARRAY, - .tlv_type = 0, - .offset = offsetof(struct servreg_location_entry, - service_data), - }, - {} -}; - struct servreg_get_domain_list_req { char service_name[SERVREG_NAME_LENGTH + 1]; u8 domain_offset_valid; u32 domain_offset; }; -static const struct qmi_elem_info servreg_get_domain_list_req_ei[] = { - { - .data_type = QMI_STRING, - .elem_len = SERVREG_NAME_LENGTH + 1, - .elem_size = sizeof(char), - .array_type = NO_ARRAY, - .tlv_type = 0x01, - .offset = offsetof(struct servreg_get_domain_list_req, - service_name), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(u8), - .array_type = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct servreg_get_domain_list_req, - domain_offset_valid), - }, - { - .data_type = QMI_UNSIGNED_4_BYTE, - .elem_len = 1, - .elem_size = sizeof(u32), - .array_type = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct servreg_get_domain_list_req, - domain_offset), - }, - {} -}; - struct servreg_get_domain_list_resp { struct qmi_response_type_v01 resp; u8 total_domains_valid; @@ -116,264 +45,49 @@ struct servreg_get_domain_list_resp { struct servreg_location_entry domain_list[SERVREG_DOMAIN_LIST_LENGTH]; }; -static const struct qmi_elem_info servreg_get_domain_list_resp_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct servreg_get_domain_list_resp, - resp), - .ei_array = qmi_response_type_v01_ei, - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(u8), - .array_type = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct servreg_get_domain_list_resp, - total_domains_valid), - }, - { - .data_type = QMI_UNSIGNED_2_BYTE, - .elem_len = 1, - .elem_size = sizeof(u16), - .array_type = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct servreg_get_domain_list_resp, - total_domains), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(u8), - .array_type = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof(struct servreg_get_domain_list_resp, - db_rev_count_valid), - }, - { - .data_type = QMI_UNSIGNED_2_BYTE, - .elem_len = 1, - .elem_size = sizeof(u16), - .array_type = NO_ARRAY, - .tlv_type = 0x11, - .offset = offsetof(struct servreg_get_domain_list_resp, - db_rev_count), - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(u8), - .array_type = NO_ARRAY, - .tlv_type = 0x12, - .offset = offsetof(struct servreg_get_domain_list_resp, - domain_list_valid), - }, - { - .data_type = QMI_DATA_LEN, - .elem_len = 1, - .elem_size = sizeof(u8), - .array_type = NO_ARRAY, - .tlv_type = 0x12, - .offset = offsetof(struct servreg_get_domain_list_resp, - domain_list_len), - }, - { - .data_type = QMI_STRUCT, - .elem_len = SERVREG_DOMAIN_LIST_LENGTH, - .elem_size = sizeof(struct servreg_location_entry), - .array_type = VAR_LEN_ARRAY, - .tlv_type = 0x12, - .offset = offsetof(struct servreg_get_domain_list_resp, - domain_list), - .ei_array = servreg_location_entry_ei, - }, - {} -}; - struct servreg_register_listener_req { u8 enable; char service_path[SERVREG_NAME_LENGTH + 1]; }; -static const struct qmi_elem_info servreg_register_listener_req_ei[] = { - { - .data_type = QMI_UNSIGNED_1_BYTE, - .elem_len = 1, - .elem_size = sizeof(u8), - .array_type = NO_ARRAY, - .tlv_type = 0x01, - .offset = offsetof(struct servreg_register_listener_req, - enable), - }, - { - .data_type = QMI_STRING, - .elem_len = SERVREG_NAME_LENGTH + 1, - .elem_size = sizeof(char), - .array_type = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct servreg_register_listener_req, - service_path), - }, - {} -}; - struct servreg_register_listener_resp { struct qmi_response_type_v01 resp; u8 curr_state_valid; enum servreg_service_state curr_state; }; -static const struct qmi_elem_info servreg_register_listener_resp_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct servreg_register_listener_resp, - resp), - .ei_array = qmi_response_type_v01_ei, - }, - { - .data_type = QMI_OPT_FLAG, - .elem_len = 1, - .elem_size = sizeof(u8), - .array_type = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct servreg_register_listener_resp, - curr_state_valid), - }, - { - .data_type = QMI_SIGNED_4_BYTE_ENUM, - .elem_len = 1, - .elem_size = sizeof(enum servreg_service_state), - .array_type = NO_ARRAY, - .tlv_type = 0x10, - .offset = offsetof(struct servreg_register_listener_resp, - curr_state), - }, - {} -}; - struct servreg_restart_pd_req { char service_path[SERVREG_NAME_LENGTH + 1]; }; -static const struct qmi_elem_info servreg_restart_pd_req_ei[] = { - { - .data_type = QMI_STRING, - .elem_len = SERVREG_NAME_LENGTH + 1, - .elem_size = sizeof(char), - .array_type = NO_ARRAY, - .tlv_type = 0x01, - .offset = offsetof(struct servreg_restart_pd_req, - service_path), - }, - {} -}; - struct servreg_restart_pd_resp { struct qmi_response_type_v01 resp; }; -static const struct qmi_elem_info servreg_restart_pd_resp_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct servreg_restart_pd_resp, - resp), - .ei_array = qmi_response_type_v01_ei, - }, - {} -}; - struct servreg_state_updated_ind { enum servreg_service_state curr_state; char service_path[SERVREG_NAME_LENGTH + 1]; u16 transaction_id; }; -static const struct qmi_elem_info servreg_state_updated_ind_ei[] = { - { - .data_type = QMI_SIGNED_4_BYTE_ENUM, - .elem_len = 1, - .elem_size = sizeof(u32), - .array_type = NO_ARRAY, - .tlv_type = 0x01, - .offset = offsetof(struct servreg_state_updated_ind, - curr_state), - }, - { - .data_type = QMI_STRING, - .elem_len = SERVREG_NAME_LENGTH + 1, - .elem_size = sizeof(char), - .array_type = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct servreg_state_updated_ind, - service_path), - }, - { - .data_type = QMI_UNSIGNED_2_BYTE, - .elem_len = 1, - .elem_size = sizeof(u16), - .array_type = NO_ARRAY, - .tlv_type = 0x03, - .offset = offsetof(struct servreg_state_updated_ind, - transaction_id), - }, - {} -}; - struct servreg_set_ack_req { char service_path[SERVREG_NAME_LENGTH + 1]; u16 transaction_id; }; -static const struct qmi_elem_info servreg_set_ack_req_ei[] = { - { - .data_type = QMI_STRING, - .elem_len = SERVREG_NAME_LENGTH + 1, - .elem_size = sizeof(char), - .array_type = NO_ARRAY, - .tlv_type = 0x01, - .offset = offsetof(struct servreg_set_ack_req, - service_path), - }, - { - .data_type = QMI_UNSIGNED_2_BYTE, - .elem_len = 1, - .elem_size = sizeof(u16), - .array_type = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct servreg_set_ack_req, - transaction_id), - }, - {} -}; - struct servreg_set_ack_resp { struct qmi_response_type_v01 resp; }; -static const struct qmi_elem_info servreg_set_ack_resp_ei[] = { - { - .data_type = QMI_STRUCT, - .elem_len = 1, - .elem_size = sizeof(struct qmi_response_type_v01), - .array_type = NO_ARRAY, - .tlv_type = 0x02, - .offset = offsetof(struct servreg_set_ack_resp, - resp), - .ei_array = qmi_response_type_v01_ei, - }, - {} -}; +extern const struct qmi_elem_info servreg_location_entry_ei[]; +extern const struct qmi_elem_info servreg_get_domain_list_req_ei[]; +extern const struct qmi_elem_info servreg_get_domain_list_resp_ei[]; +extern const struct qmi_elem_info servreg_register_listener_req_ei[]; +extern const struct qmi_elem_info servreg_register_listener_resp_ei[]; +extern const struct qmi_elem_info servreg_restart_pd_req_ei[]; +extern const struct qmi_elem_info servreg_restart_pd_resp_ei[]; +extern const struct qmi_elem_info servreg_state_updated_ind_ei[]; +extern const struct qmi_elem_info servreg_set_ack_req_ei[]; +extern const struct qmi_elem_info servreg_set_ack_resp_ei[]; #endif diff --git a/drivers/soc/qcom/qcom_pdr_msg.c b/drivers/soc/qcom/qcom_pdr_msg.c new file mode 100644 index 000000000000..9b46f42aa146 --- /dev/null +++ b/drivers/soc/qcom/qcom_pdr_msg.c @@ -0,0 +1,319 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 The Linux Foundation. All rights reserved. + */ + +#include +#include + +#include "pdr_internal.h" + +const struct qmi_elem_info servreg_location_entry_ei[] = { + { + .data_type = QMI_STRING, + .elem_len = SERVREG_NAME_LENGTH + 1, + .elem_size = sizeof(char), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct servreg_location_entry, + name), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct servreg_location_entry, + instance), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct servreg_location_entry, + service_data_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct servreg_location_entry, + service_data), + }, + {} +}; +EXPORT_SYMBOL_GPL(servreg_location_entry_ei); + +const struct qmi_elem_info servreg_get_domain_list_req_ei[] = { + { + .data_type = QMI_STRING, + .elem_len = SERVREG_NAME_LENGTH + 1, + .elem_size = sizeof(char), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct servreg_get_domain_list_req, + service_name), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct servreg_get_domain_list_req, + domain_offset_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct servreg_get_domain_list_req, + domain_offset), + }, + {} +}; +EXPORT_SYMBOL_GPL(servreg_get_domain_list_req_ei); + +const struct qmi_elem_info servreg_get_domain_list_resp_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct servreg_get_domain_list_resp, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct servreg_get_domain_list_resp, + total_domains_valid), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct servreg_get_domain_list_resp, + total_domains), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct servreg_get_domain_list_resp, + db_rev_count_valid), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct servreg_get_domain_list_resp, + db_rev_count), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct servreg_get_domain_list_resp, + domain_list_valid), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct servreg_get_domain_list_resp, + domain_list_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = SERVREG_DOMAIN_LIST_LENGTH, + .elem_size = sizeof(struct servreg_location_entry), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x12, + .offset = offsetof(struct servreg_get_domain_list_resp, + domain_list), + .ei_array = servreg_location_entry_ei, + }, + {} +}; +EXPORT_SYMBOL_GPL(servreg_get_domain_list_resp_ei); + +const struct qmi_elem_info servreg_register_listener_req_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct servreg_register_listener_req, + enable), + }, + { + .data_type = QMI_STRING, + .elem_len = SERVREG_NAME_LENGTH + 1, + .elem_size = sizeof(char), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct servreg_register_listener_req, + service_path), + }, + {} +}; +EXPORT_SYMBOL_GPL(servreg_register_listener_req_ei); + +const struct qmi_elem_info servreg_register_listener_resp_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct servreg_register_listener_resp, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct servreg_register_listener_resp, + curr_state_valid), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum servreg_service_state), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct servreg_register_listener_resp, + curr_state), + }, + {} +}; +EXPORT_SYMBOL_GPL(servreg_register_listener_resp_ei); + +const struct qmi_elem_info servreg_restart_pd_req_ei[] = { + { + .data_type = QMI_STRING, + .elem_len = SERVREG_NAME_LENGTH + 1, + .elem_size = sizeof(char), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct servreg_restart_pd_req, + service_path), + }, + {} +}; +EXPORT_SYMBOL_GPL(servreg_restart_pd_req_ei); + +const struct qmi_elem_info servreg_restart_pd_resp_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct servreg_restart_pd_resp, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; +EXPORT_SYMBOL_GPL(servreg_restart_pd_resp_ei); + +const struct qmi_elem_info servreg_state_updated_ind_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct servreg_state_updated_ind, + curr_state), + }, + { + .data_type = QMI_STRING, + .elem_len = SERVREG_NAME_LENGTH + 1, + .elem_size = sizeof(char), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct servreg_state_updated_ind, + service_path), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct servreg_state_updated_ind, + transaction_id), + }, + {} +}; +EXPORT_SYMBOL_GPL(servreg_state_updated_ind_ei); + +const struct qmi_elem_info servreg_set_ack_req_ei[] = { + { + .data_type = QMI_STRING, + .elem_len = SERVREG_NAME_LENGTH + 1, + .elem_size = sizeof(char), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct servreg_set_ack_req, + service_path), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct servreg_set_ack_req, + transaction_id), + }, + {} +}; +EXPORT_SYMBOL_GPL(servreg_set_ack_req_ei); + +const struct qmi_elem_info servreg_set_ack_resp_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct servreg_set_ack_resp, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; +EXPORT_SYMBOL_GPL(servreg_set_ack_resp_ei); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Qualcomm Protection Domain messages data"); -- cgit v1.2.3 From 1ebcde047c547134e894508468ead0b7bd3b967d Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Sat, 22 Jun 2024 01:03:43 +0300 Subject: soc: qcom: add pd-mapper implementation Existing userspace protection domain mapper implementation has several issue. It doesn't play well with CONFIG_EXTRA_FIRMWARE, it doesn't reread JSON files if firmware location is changed (or if firmware was not available at the time pd-mapper was started but the corresponding directory is mounted later), etc. Provide in-kernel service implementing protection domain mapping required to work with several services, which are provided by the DSP firmware. This module is loaded automatically by the remoteproc drivers when necessary via the symbol dependency. It uses a root node to match a protection domains map for a particular board. It is not possible to implement it as a 'driver' as there is no corresponding device. Tested-by: Steev Klimaszewski Tested-by: Alexey Minnekhanov Reviewed-by: Chris Lew Tested-by: Neil Armstrong # on SM8550-QRD Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240622-qcom-pd-mapper-v9-4-a84ee3591c8e@linaro.org [bjorn: include linux/slab.h] Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/Kconfig | 11 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/pdr_internal.h | 14 + drivers/soc/qcom/qcom_pd_mapper.c | 677 ++++++++++++++++++++++++++++++++++++++ drivers/soc/qcom/qcom_pdr_msg.c | 34 ++ 5 files changed, 737 insertions(+) create mode 100644 drivers/soc/qcom/qcom_pd_mapper.c (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 95973c6b828f..0a2f2bfd7863 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -72,6 +72,17 @@ config QCOM_OCMEM requirements. This is typically used by the GPU, camera/video, and audio components on some Snapdragon SoCs. +config QCOM_PD_MAPPER + tristate "Qualcomm Protection Domain Mapper" + select QCOM_QMI_HELPERS + depends on NET && QRTR + default QCOM_RPROC_COMMON + help + The Protection Domain Mapper maps registered services to the domains + and instances handled by the remote DSPs. This is a kernel-space + implementation of the service. It is a simpler alternative to the + userspace daemon. + config QCOM_PDR_HELPERS tristate select QCOM_QMI_HELPERS diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 3110ac3288bc..d3560f861085 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o obj-$(CONFIG_QCOM_OCMEM) += ocmem.o +obj-$(CONFIG_QCOM_PD_MAPPER) += qcom_pd_mapper.o obj-$(CONFIG_QCOM_PDR_HELPERS) += pdr_interface.o obj-$(CONFIG_QCOM_PDR_MSG) += qcom_pdr_msg.o obj-$(CONFIG_QCOM_PMIC_GLINK) += pmic_glink.o diff --git a/drivers/soc/qcom/pdr_internal.h b/drivers/soc/qcom/pdr_internal.h index 7e5bb5a95275..8d17f7fb79e7 100644 --- a/drivers/soc/qcom/pdr_internal.h +++ b/drivers/soc/qcom/pdr_internal.h @@ -13,6 +13,8 @@ #define SERVREG_SET_ACK_REQ 0x23 #define SERVREG_RESTART_PD_REQ 0x24 +#define SERVREG_LOC_PFR_REQ 0x24 + #define SERVREG_DOMAIN_LIST_LENGTH 32 #define SERVREG_RESTART_PD_REQ_MAX_LEN 67 #define SERVREG_REGISTER_LISTENER_REQ_LEN 71 @@ -20,6 +22,7 @@ #define SERVREG_GET_DOMAIN_LIST_REQ_MAX_LEN 74 #define SERVREG_STATE_UPDATED_IND_MAX_LEN 79 #define SERVREG_GET_DOMAIN_LIST_RESP_MAX_LEN 2389 +#define SERVREG_LOC_PFR_RESP_MAX_LEN 10 struct servreg_location_entry { char name[SERVREG_NAME_LENGTH + 1]; @@ -79,6 +82,15 @@ struct servreg_set_ack_resp { struct qmi_response_type_v01 resp; }; +struct servreg_loc_pfr_req { + char service[SERVREG_NAME_LENGTH + 1]; + char reason[257]; +}; + +struct servreg_loc_pfr_resp { + struct qmi_response_type_v01 rsp; +}; + extern const struct qmi_elem_info servreg_location_entry_ei[]; extern const struct qmi_elem_info servreg_get_domain_list_req_ei[]; extern const struct qmi_elem_info servreg_get_domain_list_resp_ei[]; @@ -89,5 +101,7 @@ extern const struct qmi_elem_info servreg_restart_pd_resp_ei[]; extern const struct qmi_elem_info servreg_state_updated_ind_ei[]; extern const struct qmi_elem_info servreg_set_ack_req_ei[]; extern const struct qmi_elem_info servreg_set_ack_resp_ei[]; +extern const struct qmi_elem_info servreg_loc_pfr_req_ei[]; +extern const struct qmi_elem_info servreg_loc_pfr_resp_ei[]; #endif diff --git a/drivers/soc/qcom/qcom_pd_mapper.c b/drivers/soc/qcom/qcom_pd_mapper.c new file mode 100644 index 000000000000..a4c007080665 --- /dev/null +++ b/drivers/soc/qcom/qcom_pd_mapper.c @@ -0,0 +1,677 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Qualcomm Protection Domain mapper + * + * Copyright (c) 2023 Linaro Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pdr_internal.h" + +#define SERVREG_QMI_VERSION 0x101 +#define SERVREG_QMI_INSTANCE 0 + +#define TMS_SERVREG_SERVICE "tms/servreg" + +struct qcom_pdm_domain_data { + const char *domain; + u32 instance_id; + /* NULL-terminated array */ + const char * services[]; +}; + +struct qcom_pdm_domain { + struct list_head list; + const char *name; + u32 instance_id; +}; + +struct qcom_pdm_service { + struct list_head list; + struct list_head domains; + const char *name; +}; + +struct qcom_pdm_data { + refcount_t refcnt; + struct qmi_handle handle; + struct list_head services; +}; + +static DEFINE_MUTEX(qcom_pdm_mutex); /* protects __qcom_pdm_data */ +static struct qcom_pdm_data *__qcom_pdm_data; + +static struct qcom_pdm_service *qcom_pdm_find(struct qcom_pdm_data *data, + const char *name) +{ + struct qcom_pdm_service *service; + + list_for_each_entry(service, &data->services, list) { + if (!strcmp(service->name, name)) + return service; + } + + return NULL; +} + +static int qcom_pdm_add_service_domain(struct qcom_pdm_data *data, + const char *service_name, + const char *domain_name, + u32 instance_id) +{ + struct qcom_pdm_service *service; + struct qcom_pdm_domain *domain; + + service = qcom_pdm_find(data, service_name); + if (service) { + list_for_each_entry(domain, &service->domains, list) { + if (!strcmp(domain->name, domain_name)) + return -EBUSY; + } + } else { + service = kzalloc(sizeof(*service), GFP_KERNEL); + if (!service) + return -ENOMEM; + + INIT_LIST_HEAD(&service->domains); + service->name = service_name; + + list_add_tail(&service->list, &data->services); + } + + domain = kzalloc(sizeof(*domain), GFP_KERNEL); + if (!domain) { + if (list_empty(&service->domains)) { + list_del(&service->list); + kfree(service); + } + + return -ENOMEM; + } + + domain->name = domain_name; + domain->instance_id = instance_id; + list_add_tail(&domain->list, &service->domains); + + return 0; +} + +static int qcom_pdm_add_domain(struct qcom_pdm_data *data, + const struct qcom_pdm_domain_data *domain) +{ + int ret; + int i; + + ret = qcom_pdm_add_service_domain(data, + TMS_SERVREG_SERVICE, + domain->domain, + domain->instance_id); + if (ret) + return ret; + + for (i = 0; domain->services[i]; i++) { + ret = qcom_pdm_add_service_domain(data, + domain->services[i], + domain->domain, + domain->instance_id); + if (ret) + return ret; + } + + return 0; + +} + +static void qcom_pdm_free_domains(struct qcom_pdm_data *data) +{ + struct qcom_pdm_service *service, *tservice; + struct qcom_pdm_domain *domain, *tdomain; + + list_for_each_entry_safe(service, tservice, &data->services, list) { + list_for_each_entry_safe(domain, tdomain, &service->domains, list) { + list_del(&domain->list); + kfree(domain); + } + + list_del(&service->list); + kfree(service); + } +} + +static void qcom_pdm_get_domain_list(struct qmi_handle *qmi, + struct sockaddr_qrtr *sq, + struct qmi_txn *txn, + const void *decoded) +{ + struct qcom_pdm_data *data = container_of(qmi, struct qcom_pdm_data, handle); + const struct servreg_get_domain_list_req *req = decoded; + struct servreg_get_domain_list_resp *rsp; + struct qcom_pdm_service *service; + u32 offset; + int ret; + + rsp = kzalloc(sizeof(*rsp), GFP_KERNEL); + if (!rsp) + return; + + offset = req->domain_offset_valid ? req->domain_offset : 0; + + rsp->resp.result = QMI_RESULT_SUCCESS_V01; + rsp->resp.error = QMI_ERR_NONE_V01; + + rsp->db_rev_count_valid = true; + rsp->db_rev_count = 1; + + rsp->total_domains_valid = true; + rsp->total_domains = 0; + + mutex_lock(&qcom_pdm_mutex); + + service = qcom_pdm_find(data, req->service_name); + if (service) { + struct qcom_pdm_domain *domain; + + rsp->domain_list_valid = true; + rsp->domain_list_len = 0; + + list_for_each_entry(domain, &service->domains, list) { + u32 i = rsp->total_domains++; + + if (i >= offset && i < SERVREG_DOMAIN_LIST_LENGTH) { + u32 j = rsp->domain_list_len++; + + strscpy(rsp->domain_list[j].name, domain->name, + sizeof(rsp->domain_list[i].name)); + rsp->domain_list[j].instance = domain->instance_id; + + pr_debug("PDM: found %s / %d\n", domain->name, + domain->instance_id); + } + } + } + + pr_debug("PDM: service '%s' offset %d returning %d domains (of %d)\n", req->service_name, + req->domain_offset_valid ? req->domain_offset : -1, rsp->domain_list_len, rsp->total_domains); + + ret = qmi_send_response(qmi, sq, txn, SERVREG_GET_DOMAIN_LIST_REQ, + SERVREG_GET_DOMAIN_LIST_RESP_MAX_LEN, + servreg_get_domain_list_resp_ei, rsp); + if (ret) + pr_err("Error sending servreg response: %d\n", ret); + + mutex_unlock(&qcom_pdm_mutex); + + kfree(rsp); +} + +static void qcom_pdm_pfr(struct qmi_handle *qmi, + struct sockaddr_qrtr *sq, + struct qmi_txn *txn, + const void *decoded) +{ + const struct servreg_loc_pfr_req *req = decoded; + struct servreg_loc_pfr_resp rsp = {}; + int ret; + + pr_warn_ratelimited("PDM: service '%s' crash: '%s'\n", req->service, req->reason); + + rsp.rsp.result = QMI_RESULT_SUCCESS_V01; + rsp.rsp.error = QMI_ERR_NONE_V01; + + ret = qmi_send_response(qmi, sq, txn, SERVREG_LOC_PFR_REQ, + SERVREG_LOC_PFR_RESP_MAX_LEN, + servreg_loc_pfr_resp_ei, &rsp); + if (ret) + pr_err("Error sending servreg response: %d\n", ret); +} + +static const struct qmi_msg_handler qcom_pdm_msg_handlers[] = { + { + .type = QMI_REQUEST, + .msg_id = SERVREG_GET_DOMAIN_LIST_REQ, + .ei = servreg_get_domain_list_req_ei, + .decoded_size = sizeof(struct servreg_get_domain_list_req), + .fn = qcom_pdm_get_domain_list, + }, + { + .type = QMI_REQUEST, + .msg_id = SERVREG_LOC_PFR_REQ, + .ei = servreg_loc_pfr_req_ei, + .decoded_size = sizeof(struct servreg_loc_pfr_req), + .fn = qcom_pdm_pfr, + }, + { }, +}; + +static const struct qcom_pdm_domain_data adsp_audio_pd = { + .domain = "msm/adsp/audio_pd", + .instance_id = 74, + .services = { + "avs/audio", + NULL, + }, +}; + +static const struct qcom_pdm_domain_data adsp_charger_pd = { + .domain = "msm/adsp/charger_pd", + .instance_id = 74, + .services = { NULL }, +}; + +static const struct qcom_pdm_domain_data adsp_root_pd = { + .domain = "msm/adsp/root_pd", + .instance_id = 74, + .services = { NULL }, +}; + +static const struct qcom_pdm_domain_data adsp_root_pd_pdr = { + .domain = "msm/adsp/root_pd", + .instance_id = 74, + .services = { + "tms/pdr_enabled", + NULL, + }, +}; + +static const struct qcom_pdm_domain_data adsp_sensor_pd = { + .domain = "msm/adsp/sensor_pd", + .instance_id = 74, + .services = { NULL }, +}; + +static const struct qcom_pdm_domain_data msm8996_adsp_audio_pd = { + .domain = "msm/adsp/audio_pd", + .instance_id = 4, + .services = { NULL }, +}; + +static const struct qcom_pdm_domain_data msm8996_adsp_root_pd = { + .domain = "msm/adsp/root_pd", + .instance_id = 4, + .services = { NULL }, +}; + +static const struct qcom_pdm_domain_data cdsp_root_pd = { + .domain = "msm/cdsp/root_pd", + .instance_id = 76, + .services = { NULL }, +}; + +static const struct qcom_pdm_domain_data slpi_root_pd = { + .domain = "msm/slpi/root_pd", + .instance_id = 90, + .services = { NULL }, +}; + +static const struct qcom_pdm_domain_data slpi_sensor_pd = { + .domain = "msm/slpi/sensor_pd", + .instance_id = 90, + .services = { NULL }, +}; + +static const struct qcom_pdm_domain_data mpss_root_pd = { + .domain = "msm/modem/root_pd", + .instance_id = 180, + .services = { + NULL, + }, +}; + +static const struct qcom_pdm_domain_data mpss_root_pd_gps = { + .domain = "msm/modem/root_pd", + .instance_id = 180, + .services = { + "gps/gps_service", + NULL, + }, +}; + +static const struct qcom_pdm_domain_data mpss_root_pd_gps_pdr = { + .domain = "msm/modem/root_pd", + .instance_id = 180, + .services = { + "gps/gps_service", + "tms/pdr_enabled", + NULL, + }, +}; + +static const struct qcom_pdm_domain_data msm8996_mpss_root_pd = { + .domain = "msm/modem/root_pd", + .instance_id = 100, + .services = { NULL }, +}; + +static const struct qcom_pdm_domain_data mpss_wlan_pd = { + .domain = "msm/modem/wlan_pd", + .instance_id = 180, + .services = { + "kernel/elf_loader", + "wlan/fw", + NULL, + }, +}; + +static const struct qcom_pdm_domain_data *msm8996_domains[] = { + &msm8996_adsp_audio_pd, + &msm8996_adsp_root_pd, + &msm8996_mpss_root_pd, + NULL, +}; + +static const struct qcom_pdm_domain_data *msm8998_domains[] = { + &mpss_root_pd, + &mpss_wlan_pd, + NULL, +}; + +static const struct qcom_pdm_domain_data *qcm2290_domains[] = { + &adsp_audio_pd, + &adsp_root_pd, + &adsp_sensor_pd, + &mpss_root_pd_gps, + &mpss_wlan_pd, + NULL, +}; + +static const struct qcom_pdm_domain_data *qcs404_domains[] = { + &adsp_audio_pd, + &adsp_root_pd, + &adsp_sensor_pd, + &cdsp_root_pd, + &mpss_root_pd, + &mpss_wlan_pd, + NULL, +}; + +static const struct qcom_pdm_domain_data *sc7180_domains[] = { + &adsp_audio_pd, + &adsp_root_pd_pdr, + &adsp_sensor_pd, + &mpss_root_pd_gps_pdr, + &mpss_wlan_pd, + NULL, +}; + +static const struct qcom_pdm_domain_data *sc7280_domains[] = { + &adsp_audio_pd, + &adsp_root_pd_pdr, + &adsp_charger_pd, + &adsp_sensor_pd, + &cdsp_root_pd, + &mpss_root_pd_gps_pdr, + NULL, +}; + +static const struct qcom_pdm_domain_data *sc8180x_domains[] = { + &adsp_audio_pd, + &adsp_root_pd, + &adsp_charger_pd, + &cdsp_root_pd, + &mpss_root_pd_gps, + &mpss_wlan_pd, + NULL, +}; + +static const struct qcom_pdm_domain_data *sc8280xp_domains[] = { + &adsp_audio_pd, + &adsp_root_pd_pdr, + &adsp_charger_pd, + &cdsp_root_pd, + NULL, +}; + +static const struct qcom_pdm_domain_data *sdm660_domains[] = { + &adsp_audio_pd, + &adsp_root_pd, + &adsp_sensor_pd, + &cdsp_root_pd, + &mpss_root_pd, + &mpss_wlan_pd, + NULL, +}; + +static const struct qcom_pdm_domain_data *sdm670_domains[] = { + &adsp_audio_pd, + &adsp_root_pd, + &cdsp_root_pd, + &mpss_root_pd, + &mpss_wlan_pd, + NULL, +}; + +static const struct qcom_pdm_domain_data *sdm845_domains[] = { + &adsp_audio_pd, + &adsp_root_pd, + &cdsp_root_pd, + &mpss_root_pd, + &mpss_wlan_pd, + &slpi_root_pd, + &slpi_sensor_pd, + NULL, +}; + +static const struct qcom_pdm_domain_data *sm6115_domains[] = { + &adsp_audio_pd, + &adsp_root_pd, + &adsp_sensor_pd, + &cdsp_root_pd, + &mpss_root_pd_gps, + &mpss_wlan_pd, + NULL, +}; + +static const struct qcom_pdm_domain_data *sm6350_domains[] = { + &adsp_audio_pd, + &adsp_root_pd, + &adsp_sensor_pd, + &cdsp_root_pd, + &mpss_wlan_pd, + NULL, +}; + +static const struct qcom_pdm_domain_data *sm8150_domains[] = { + &adsp_audio_pd, + &adsp_root_pd, + &cdsp_root_pd, + &mpss_root_pd_gps, + &mpss_wlan_pd, + NULL, +}; + +static const struct qcom_pdm_domain_data *sm8250_domains[] = { + &adsp_audio_pd, + &adsp_root_pd, + &cdsp_root_pd, + &slpi_root_pd, + &slpi_sensor_pd, + NULL, +}; + +static const struct qcom_pdm_domain_data *sm8350_domains[] = { + &adsp_audio_pd, + &adsp_root_pd_pdr, + &adsp_charger_pd, + &cdsp_root_pd, + &mpss_root_pd_gps, + &slpi_root_pd, + &slpi_sensor_pd, + NULL, +}; + +static const struct qcom_pdm_domain_data *sm8550_domains[] = { + &adsp_audio_pd, + &adsp_root_pd, + &adsp_charger_pd, + &adsp_sensor_pd, + &cdsp_root_pd, + &mpss_root_pd_gps, + NULL, +}; + +static const struct of_device_id qcom_pdm_domains[] = { + { .compatible = "qcom,apq8064", .data = NULL, }, + { .compatible = "qcom,apq8074", .data = NULL, }, + { .compatible = "qcom,apq8084", .data = NULL, }, + { .compatible = "qcom,apq8096", .data = msm8996_domains, }, + { .compatible = "qcom,msm8226", .data = NULL, }, + { .compatible = "qcom,msm8974", .data = NULL, }, + { .compatible = "qcom,msm8996", .data = msm8996_domains, }, + { .compatible = "qcom,msm8998", .data = msm8998_domains, }, + { .compatible = "qcom,qcm2290", .data = qcm2290_domains, }, + { .compatible = "qcom,qcs404", .data = qcs404_domains, }, + { .compatible = "qcom,sc7180", .data = sc7180_domains, }, + { .compatible = "qcom,sc7280", .data = sc7280_domains, }, + { .compatible = "qcom,sc8180x", .data = sc8180x_domains, }, + { .compatible = "qcom,sc8280xp", .data = sc8280xp_domains, }, + { .compatible = "qcom,sda660", .data = sdm660_domains, }, + { .compatible = "qcom,sdm660", .data = sdm660_domains, }, + { .compatible = "qcom,sdm670", .data = sdm670_domains, }, + { .compatible = "qcom,sdm845", .data = sdm845_domains, }, + { .compatible = "qcom,sm4250", .data = sm6115_domains, }, + { .compatible = "qcom,sm6115", .data = sm6115_domains, }, + { .compatible = "qcom,sm6350", .data = sm6350_domains, }, + { .compatible = "qcom,sm8150", .data = sm8150_domains, }, + { .compatible = "qcom,sm8250", .data = sm8250_domains, }, + { .compatible = "qcom,sm8350", .data = sm8350_domains, }, + { .compatible = "qcom,sm8450", .data = sm8350_domains, }, + { .compatible = "qcom,sm8550", .data = sm8550_domains, }, + { .compatible = "qcom,sm8650", .data = sm8550_domains, }, + {}, +}; + +static void qcom_pdm_stop(struct qcom_pdm_data *data) +{ + qcom_pdm_free_domains(data); + + /* The server is removed automatically */ + qmi_handle_release(&data->handle); + + kfree(data); +} + +static struct qcom_pdm_data *qcom_pdm_start(void) +{ + const struct qcom_pdm_domain_data * const *domains; + const struct of_device_id *match; + struct qcom_pdm_data *data; + struct device_node *root; + int ret, i; + + root = of_find_node_by_path("/"); + if (!root) + return ERR_PTR(-ENODEV); + + match = of_match_node(qcom_pdm_domains, root); + of_node_put(root); + if (!match) { + pr_notice("PDM: no support for the platform, userspace daemon might be required.\n"); + return ERR_PTR(-ENODEV); + } + + domains = match->data; + if (!domains) { + pr_debug("PDM: no domains\n"); + return ERR_PTR(-ENODEV); + } + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&data->services); + + ret = qmi_handle_init(&data->handle, SERVREG_GET_DOMAIN_LIST_REQ_MAX_LEN, + NULL, qcom_pdm_msg_handlers); + if (ret) { + kfree(data); + return ERR_PTR(ret); + } + + refcount_set(&data->refcnt, 1); + + for (i = 0; domains[i]; i++) { + ret = qcom_pdm_add_domain(data, domains[i]); + if (ret) + goto err_stop; + } + + ret = qmi_add_server(&data->handle, SERVREG_LOCATOR_SERVICE, + SERVREG_QMI_VERSION, SERVREG_QMI_INSTANCE); + if (ret) { + pr_err("PDM: error adding server %d\n", ret); + goto err_stop; + } + + return data; + +err_stop: + qcom_pdm_stop(data); + + return ERR_PTR(ret); +} + +static int qcom_pdm_probe(struct auxiliary_device *auxdev, + const struct auxiliary_device_id *id) + +{ + struct qcom_pdm_data *data; + int ret = 0; + + mutex_lock(&qcom_pdm_mutex); + + if (!__qcom_pdm_data) { + data = qcom_pdm_start(); + + if (IS_ERR(data)) + ret = PTR_ERR(data); + else + __qcom_pdm_data = data; + } + + auxiliary_set_drvdata(auxdev, __qcom_pdm_data); + + mutex_unlock(&qcom_pdm_mutex); + + return ret; +} + +static void qcom_pdm_remove(struct auxiliary_device *auxdev) +{ + struct qcom_pdm_data *data; + + data = auxiliary_get_drvdata(auxdev); + if (!data) + return; + + if (refcount_dec_and_mutex_lock(&data->refcnt, &qcom_pdm_mutex)) { + __qcom_pdm_data = NULL; + qcom_pdm_stop(data); + mutex_unlock(&qcom_pdm_mutex); + } +} + +static const struct auxiliary_device_id qcom_pdm_table[] = { + { .name = "qcom_common.pd-mapper" }, + {}, +}; +MODULE_DEVICE_TABLE(auxiliary, qcom_pdm_table); + +static struct auxiliary_driver qcom_pdm_drv = { + .name = "qcom-pdm-mapper", + .id_table = qcom_pdm_table, + .probe = qcom_pdm_probe, + .remove = qcom_pdm_remove, +}; +module_auxiliary_driver(qcom_pdm_drv); + +MODULE_DESCRIPTION("Qualcomm Protection Domain Mapper"); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/qcom/qcom_pdr_msg.c b/drivers/soc/qcom/qcom_pdr_msg.c index 9b46f42aa146..bf3e4a47165e 100644 --- a/drivers/soc/qcom/qcom_pdr_msg.c +++ b/drivers/soc/qcom/qcom_pdr_msg.c @@ -315,5 +315,39 @@ const struct qmi_elem_info servreg_set_ack_resp_ei[] = { }; EXPORT_SYMBOL_GPL(servreg_set_ack_resp_ei); +const struct qmi_elem_info servreg_loc_pfr_req_ei[] = { + { + .data_type = QMI_STRING, + .elem_len = SERVREG_NAME_LENGTH + 1, + .elem_size = sizeof(char), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct servreg_loc_pfr_req, service) + }, + { + .data_type = QMI_STRING, + .elem_len = SERVREG_NAME_LENGTH + 1, + .elem_size = sizeof(char), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct servreg_loc_pfr_req, reason) + }, + {} +}; +EXPORT_SYMBOL_GPL(servreg_loc_pfr_req_ei); + +const struct qmi_elem_info servreg_loc_pfr_resp_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof_field(struct servreg_loc_pfr_resp, rsp), + .tlv_type = 0x02, + .offset = offsetof(struct servreg_loc_pfr_resp, rsp), + .ei_array = qmi_response_type_v01_ei, + }, + {} +}; +EXPORT_SYMBOL_GPL(servreg_loc_pfr_resp_ei); + MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Qualcomm Protection Domain messages data"); -- cgit v1.2.3 From dc18836435e7f8dda019db2c618c69194933157f Mon Sep 17 00:00:00 2001 From: Sibi Sankar Date: Mon, 24 Jun 2024 14:52:13 +0530 Subject: soc: qcom: icc-bwmon: Allow for interrupts to be shared across instances The multiple BWMONv4 instances available on the X1E80100 SoC use the same interrupt number. Mark them are shared to allow for re-use across instances. Using IRQF_SHARED coupled with devm_request_threaded_irq implies that the irq can still trigger during/after bwmon_remove due to other active bwmon instances. Handle this race by relying on bwmon_disable to disable the interrupt and coupled with explicit request/free irqs. Signed-off-by: Sibi Sankar Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240624092214.146935-4-quic_sibis@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/icc-bwmon.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/icc-bwmon.c b/drivers/soc/qcom/icc-bwmon.c index ecddb60bd665..e7851974084b 100644 --- a/drivers/soc/qcom/icc-bwmon.c +++ b/drivers/soc/qcom/icc-bwmon.c @@ -783,9 +783,14 @@ static int bwmon_probe(struct platform_device *pdev) bwmon->dev = dev; bwmon_disable(bwmon); - ret = devm_request_threaded_irq(dev, bwmon->irq, bwmon_intr, - bwmon_intr_thread, - IRQF_ONESHOT, dev_name(dev), bwmon); + + /* + * SoCs with multiple cpu-bwmon instances can end up using a shared interrupt + * line. Using the devm_ variant might result in the IRQ handler being executed + * after bwmon_disable in bwmon_remove() + */ + ret = request_threaded_irq(bwmon->irq, bwmon_intr, bwmon_intr_thread, + IRQF_ONESHOT | IRQF_SHARED, dev_name(dev), bwmon); if (ret) return dev_err_probe(dev, ret, "failed to request IRQ\n"); @@ -800,6 +805,7 @@ static void bwmon_remove(struct platform_device *pdev) struct icc_bwmon *bwmon = platform_get_drvdata(pdev); bwmon_disable(bwmon); + free_irq(bwmon->irq, bwmon); } static const struct icc_bwmon_data msm8998_bwmon_data = { -- cgit v1.2.3 From cfcd6c46fec46cac3bf6658838d3ea329aff37aa Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 11 Jun 2024 08:56:03 +0100 Subject: soc/tegra: pmc: Simplify resource lookup Commit 6f4429e21a7f ("soc/tegra: pmc: Update address mapping sequence for PMC apertures") updated the resource lookup code in the PMC driver. Instead of calling platform_get_resource_byname() and devm_ioremap_resource() simplify the code by simply calling devm_platform_ioremap_resource_byname(). Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 91d0ad6ddefc..6c37d6eb8b49 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -2891,15 +2891,11 @@ static int tegra_pmc_probe(struct platform_device *pdev) pmc->aotag = base; pmc->scratch = base; } else { - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "wake"); - pmc->wake = devm_ioremap_resource(&pdev->dev, res); + pmc->wake = devm_platform_ioremap_resource_byname(pdev, "wake"); if (IS_ERR(pmc->wake)) return PTR_ERR(pmc->wake); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "aotag"); - pmc->aotag = devm_ioremap_resource(&pdev->dev, res); + pmc->aotag = devm_platform_ioremap_resource_byname(pdev, "aotag"); if (IS_ERR(pmc->aotag)) return PTR_ERR(pmc->aotag); -- cgit v1.2.3 From 161ee1eb9ab2440553dac55ada8329de704b1ffd Mon Sep 17 00:00:00 2001 From: AngeloGioacchino Del Regno Date: Wed, 19 Jun 2024 12:30:34 +0200 Subject: soc: mediatek: mtk-mutex: Add MDP_TCC0 mod to MT8188 mutex table MT8188's MDP3 is able to use MDP_TCC0, this mutex_mod bit does actually exist and it's the same as MT8195: add it to the table. Fixes: 26bb17dae6fa ("soc: mediatek: mtk-mutex: Add support for MT8188 VPPSYS") Reviewed-by: Fei Shao Link: https://lore.kernel.org/r/20240619103034.110377-1-angelogioacchino.delregno@collabora.com Signed-off-by: AngeloGioacchino Del Regno --- drivers/soc/mediatek/mtk-mutex.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc') diff --git a/drivers/soc/mediatek/mtk-mutex.c b/drivers/soc/mediatek/mtk-mutex.c index b5af1fb5847e..01b129caf1eb 100644 --- a/drivers/soc/mediatek/mtk-mutex.c +++ b/drivers/soc/mediatek/mtk-mutex.c @@ -524,6 +524,7 @@ static const unsigned int mt8188_mdp_mutex_table_mod[MUTEX_MOD_IDX_MAX] = { [MUTEX_MOD_IDX_MDP_PAD0] = MT8195_MUTEX_MOD_MDP_PAD0, [MUTEX_MOD_IDX_MDP_PAD2] = MT8195_MUTEX_MOD_MDP_PAD2, [MUTEX_MOD_IDX_MDP_PAD3] = MT8195_MUTEX_MOD_MDP_PAD3, + [MUTEX_MOD_IDX_MDP_TCC0] = MT8195_MUTEX_MOD_MDP_TCC0, [MUTEX_MOD_IDX_MDP_WROT0] = MT8195_MUTEX_MOD_MDP_WROT0, [MUTEX_MOD_IDX_MDP_WROT2] = MT8195_MUTEX_MOD_MDP_WROT2, [MUTEX_MOD_IDX_MDP_WROT3] = MT8195_MUTEX_MOD_MDP_WROT3, -- cgit v1.2.3 From 7cc069d9286c21e0acb399da26a181bafdca4d7e Mon Sep 17 00:00:00 2001 From: Hsiao Chien Sung Date: Thu, 20 Jun 2024 00:50:24 +0800 Subject: soc: mediatek: Disable 9-bit alpha in ETHDR When 9-bit alpha is enabled, its value will be converted from 0-255 to 0-256 (255 = not defined). This is designed for special HDR related calculation, which should be disabled by default, otherwise, alpha blending will not work correctly. Signed-off-by: Hsiao Chien Sung Reviewed-by: AngeloGioacchino Del Regno Link: https://lore.kernel.org/r/20240620-9bit_alpha-v1-1-13c69daaf29f@mediatek.com Signed-off-by: AngeloGioacchino Del Regno --- drivers/soc/mediatek/mtk-mmsys.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc') diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c index f370f4ec4b88..938240714e54 100644 --- a/drivers/soc/mediatek/mtk-mmsys.c +++ b/drivers/soc/mediatek/mtk-mmsys.c @@ -236,6 +236,7 @@ void mtk_mmsys_mixer_in_config(struct device *dev, int idx, bool alpha_sel, u16 mtk_mmsys_update_bits(mmsys, MT8195_VDO1_MIXER_IN1_ALPHA + (idx - 1) * 4, ~0, alpha << 16 | alpha, cmdq_pkt); + mtk_mmsys_update_bits(mmsys, MT8195_VDO1_HDR_TOP_CFG, BIT(15 + idx), 0, cmdq_pkt); mtk_mmsys_update_bits(mmsys, MT8195_VDO1_HDR_TOP_CFG, BIT(19 + idx), alpha_sel << (19 + idx), cmdq_pkt); mtk_mmsys_update_bits(mmsys, MT8195_VDO1_MIXER_IN1_PAD + (idx - 1) * 4, -- cgit v1.2.3 From 58de63ddd0ecc84548b8fd24c72deb3739365c78 Mon Sep 17 00:00:00 2001 From: "Jason-JH.Lin" Date: Tue, 25 Jun 2024 16:39:57 +0800 Subject: soc: mtk-cmdq: Add cmdq_pkt_logic_command to support math operation Add cmdq_pkt_logic_command to support math operation. cmdq_pkt_logic_command can append logic command to the CMDQ packet, ask GCE to execute a arithmetic calculate instruction, such as add, subtract, multiply, AND, OR and NOT, etc. Note that all arithmetic instructions are unsigned calculations. If there are any overflows, GCE will sent the invalid IRQ to notify CMDQ driver. Signed-off-by: Jason-JH.Lin Signed-off-by: Hsiao Chien Sung Link: https://lore.kernel.org/r/20240625083957.3540-1-jason-jh.lin@mediatek.com Signed-off-by: AngeloGioacchino Del Regno --- drivers/soc/mediatek/mtk-cmdq-helper.c | 34 +++++++++++++++++++++++++++ include/linux/soc/mediatek/mtk-cmdq.h | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c index 046522664dc1..f3cd15387f2d 100644 --- a/drivers/soc/mediatek/mtk-cmdq-helper.c +++ b/drivers/soc/mediatek/mtk-cmdq-helper.c @@ -15,6 +15,7 @@ /* dedicate the last GPR_R15 to assign the register address to be poll */ #define CMDQ_POLL_ADDR_GPR (15) #define CMDQ_EOC_IRQ_EN BIT(0) +#define CMDQ_IMMEDIATE_VALUE 0 #define CMDQ_REG_TYPE 1 #define CMDQ_JUMP_RELATIVE 0 #define CMDQ_JUMP_ABSOLUTE 1 @@ -45,6 +46,16 @@ struct cmdq_instruction { u8 op; }; +static inline u8 cmdq_operand_get_type(struct cmdq_operand *op) +{ + return op->reg ? CMDQ_REG_TYPE : CMDQ_IMMEDIATE_VALUE; +} + +static inline u16 cmdq_operand_get_idx_value(struct cmdq_operand *op) +{ + return op->reg ? op->idx : op->value; +} + int cmdq_dev_get_client_reg(struct device *dev, struct cmdq_client_reg *client_reg, int idx) { @@ -461,6 +472,29 @@ int cmdq_pkt_poll_addr(struct cmdq_pkt *pkt, dma_addr_t addr, u32 value, u32 mas } EXPORT_SYMBOL(cmdq_pkt_poll_addr); +int cmdq_pkt_logic_command(struct cmdq_pkt *pkt, u16 result_reg_idx, + struct cmdq_operand *left_operand, + enum cmdq_logic_op s_op, + struct cmdq_operand *right_operand) +{ + struct cmdq_instruction inst = { {0} }; + + if (!left_operand || !right_operand || s_op >= CMDQ_LOGIC_MAX) + return -EINVAL; + + inst.op = CMDQ_CODE_LOGIC; + inst.dst_t = CMDQ_REG_TYPE; + inst.src_t = cmdq_operand_get_type(left_operand); + inst.arg_c_t = cmdq_operand_get_type(right_operand); + inst.sop = s_op; + inst.reg_dst = result_reg_idx; + inst.src_reg = cmdq_operand_get_idx_value(left_operand); + inst.arg_c = cmdq_operand_get_idx_value(right_operand); + + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_logic_command); + int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value) { struct cmdq_instruction inst = {}; diff --git a/include/linux/soc/mediatek/mtk-cmdq.h b/include/linux/soc/mediatek/mtk-cmdq.h index d4a8e34505e6..5bee6f7fc400 100644 --- a/include/linux/soc/mediatek/mtk-cmdq.h +++ b/include/linux/soc/mediatek/mtk-cmdq.h @@ -25,6 +25,31 @@ struct cmdq_pkt; +enum cmdq_logic_op { + CMDQ_LOGIC_ASSIGN = 0, + CMDQ_LOGIC_ADD = 1, + CMDQ_LOGIC_SUBTRACT = 2, + CMDQ_LOGIC_MULTIPLY = 3, + CMDQ_LOGIC_XOR = 8, + CMDQ_LOGIC_NOT = 9, + CMDQ_LOGIC_OR = 10, + CMDQ_LOGIC_AND = 11, + CMDQ_LOGIC_LEFT_SHIFT = 12, + CMDQ_LOGIC_RIGHT_SHIFT = 13, + CMDQ_LOGIC_MAX, +}; + +struct cmdq_operand { + /* register type */ + bool reg; + union { + /* index */ + u16 idx; + /* value */ + u16 value; + }; +}; + struct cmdq_client_reg { u8 subsys; u16 offset; @@ -272,6 +297,23 @@ int cmdq_pkt_poll(struct cmdq_pkt *pkt, u8 subsys, int cmdq_pkt_poll_mask(struct cmdq_pkt *pkt, u8 subsys, u16 offset, u32 value, u32 mask); +/** + * cmdq_pkt_logic_command() - Append logic command to the CMDQ packet, ask GCE to + * execute an instruction that store the result of logic operation + * with left and right operand into result_reg_idx. + * @pkt: the CMDQ packet + * @result_reg_idx: SPR index that store operation result of left_operand and right_operand + * @left_operand: left operand + * @s_op: the logic operator enum + * @right_operand: right operand + * + * Return: 0 for success; else the error code is returned + */ +int cmdq_pkt_logic_command(struct cmdq_pkt *pkt, u16 result_reg_idx, + struct cmdq_operand *left_operand, + enum cmdq_logic_op s_op, + struct cmdq_operand *right_operand); + /** * cmdq_pkt_assign() - Append logic assign command to the CMDQ packet, ask GCE * to execute an instruction that set a constant value into -- cgit v1.2.3 From a862a3f7b1b7f71211ac0ab7ab6dbb4afd8e50c5 Mon Sep 17 00:00:00 2001 From: Jeff Johnson Date: Tue, 25 Jun 2024 10:04:15 -0700 Subject: soc: add missing MODULE_DESCRIPTION() macros With ARCH=x86, make allmodconfig && make W=1 C=1 reports: WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/soc/imx/soc-imx8m.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/soc/ixp4xx/ixp4xx-qmgr.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/soc/ixp4xx/ixp4xx-npe.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/soc/mediatek/mtk-cmdq-helper.o WARNING: modpost: missing MODULE_DESCRIPTION() in drivers/soc/amlogic/meson-clk-measure.o Add the missing invocations of the MODULE_DESCRIPTION() macro. Reviewed-by: Linus Walleij Acked-by: Shawn Guo Reviewed-by: AngeloGioacchino Del Regno Reviewed-by: Neil Armstrong # for amlogic/meson-clk-measure.c Signed-off-by: Jeff Johnson Link: https://lore.kernel.org/r/20240625-md-drivers-soc-v2-1-8bc7c03e3e69@quicinc.com Signed-off-by: Arnd Bergmann --- drivers/soc/amlogic/meson-clk-measure.c | 1 + drivers/soc/imx/soc-imx8m.c | 1 + drivers/soc/ixp4xx/ixp4xx-npe.c | 1 + drivers/soc/ixp4xx/ixp4xx-qmgr.c | 1 + drivers/soc/mediatek/mtk-cmdq-helper.c | 1 + 5 files changed, 5 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/amlogic/meson-clk-measure.c b/drivers/soc/amlogic/meson-clk-measure.c index 3f3039600357..a6453ffeb753 100644 --- a/drivers/soc/amlogic/meson-clk-measure.c +++ b/drivers/soc/amlogic/meson-clk-measure.c @@ -688,4 +688,5 @@ static struct platform_driver meson_msr_driver = { }, }; module_platform_driver(meson_msr_driver); +MODULE_DESCRIPTION("Amlogic Meson SoC Clock Measure driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/imx/soc-imx8m.c b/drivers/soc/imx/soc-imx8m.c index ec87d9d878f3..fe111bae38c8 100644 --- a/drivers/soc/imx/soc-imx8m.c +++ b/drivers/soc/imx/soc-imx8m.c @@ -252,4 +252,5 @@ free_soc: return ret; } device_initcall(imx8_soc_init); +MODULE_DESCRIPTION("NXP i.MX8M SoC driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/soc/ixp4xx/ixp4xx-npe.c b/drivers/soc/ixp4xx/ixp4xx-npe.c index 35825ee95dff..34a6f187c220 100644 --- a/drivers/soc/ixp4xx/ixp4xx-npe.c +++ b/drivers/soc/ixp4xx/ixp4xx-npe.c @@ -764,6 +764,7 @@ static struct platform_driver ixp4xx_npe_driver = { module_platform_driver(ixp4xx_npe_driver); MODULE_AUTHOR("Krzysztof Halasa"); +MODULE_DESCRIPTION("Intel IXP4xx Network Processor Engine driver"); MODULE_LICENSE("GPL v2"); MODULE_FIRMWARE(NPE_A_FIRMWARE); MODULE_FIRMWARE(NPE_B_FIRMWARE); diff --git a/drivers/soc/ixp4xx/ixp4xx-qmgr.c b/drivers/soc/ixp4xx/ixp4xx-qmgr.c index 244ad8d7e80b..cb112f3643e9 100644 --- a/drivers/soc/ixp4xx/ixp4xx-qmgr.c +++ b/drivers/soc/ixp4xx/ixp4xx-qmgr.c @@ -465,6 +465,7 @@ static struct platform_driver ixp4xx_qmgr_driver = { }; module_platform_driver(ixp4xx_qmgr_driver); +MODULE_DESCRIPTION("Intel IXP4xx Queue Manager driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Krzysztof Halasa"); diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c index 046522664dc1..dd70d4d2bed7 100644 --- a/drivers/soc/mediatek/mtk-cmdq-helper.c +++ b/drivers/soc/mediatek/mtk-cmdq-helper.c @@ -526,4 +526,5 @@ int cmdq_pkt_finalize(struct cmdq_pkt *pkt) } EXPORT_SYMBOL(cmdq_pkt_finalize); +MODULE_DESCRIPTION("MediaTek Command Queue (CMDQ) driver"); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From d77b1befb18ac1fecfdde9110eb1400f0601ca93 Mon Sep 17 00:00:00 2001 From: Vasyl Gomonovych Date: Fri, 17 May 2024 14:29:10 -0700 Subject: soc: ti: pm33xx: Fix missing newlines in log statements Add the missing newline characters to two pm33xx log statements to ensure proper log formatting. Signed-off-by: Vasyl Gomonovych Link: https://lore.kernel.org/r/20240517212930.2019962-1-gomonovych@gmail.com Signed-off-by: Nishanth Menon --- drivers/soc/ti/pm33xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index 8e983c3c4e03..3a56bbf3268a 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c @@ -450,14 +450,14 @@ static int am33xx_pm_rtc_setup(void) rtc_base_virt = of_iomap(np, 0); if (!rtc_base_virt) { - pr_warn("PM: could not iomap rtc"); + pr_warn("PM: could not iomap rtc\n"); error = -ENODEV; goto err_clk_put; } omap_rtc = rtc_class_open("rtc0"); if (!omap_rtc) { - pr_warn("PM: rtc0 not available"); + pr_warn("PM: rtc0 not available\n"); error = -EPROBE_DEFER; goto err_iounmap; } -- cgit v1.2.3 From ca16cb2b9073e2f2a968a04c794275aa21ee1aa3 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Sun, 23 Jun 2024 18:11:31 +0200 Subject: soc: ti: knav_qmss: Constify struct knav_range_ops 'struct knav_range_ops' is not modified in these drivers. Constifying this structure moves some data to a read-only section, so increase overall security. On a x86_64, with allmodconfig: Before: ====== text data bss dec hex filename 7498 1193 0 8691 21f3 drivers/soc/ti/knav_qmss_acc.o After: ===== text data bss dec hex filename 7566 1145 0 8711 2207 drivers/soc/ti/knav_qmss_acc.o Signed-off-by: Christophe JAILLET Link: https://lore.kernel.org/r/a8b4b428f97fc584f38bf45100aa9da241aeb935.1719159074.git.christophe.jaillet@wanadoo.fr Signed-off-by: Nishanth Menon --- drivers/soc/ti/knav_qmss.h | 2 +- drivers/soc/ti/knav_qmss_acc.c | 2 +- drivers/soc/ti/knav_qmss_queue.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/ti/knav_qmss.h b/drivers/soc/ti/knav_qmss.h index a01eda720bf6..9325e8ce2e25 100644 --- a/drivers/soc/ti/knav_qmss.h +++ b/drivers/soc/ti/knav_qmss.h @@ -333,7 +333,7 @@ struct knav_range_info { void *queue_base_inst; unsigned flags; struct list_head list; - struct knav_range_ops *ops; + const struct knav_range_ops *ops; struct knav_acc_info acc_info; struct knav_acc_channel *acc; unsigned num_irqs; diff --git a/drivers/soc/ti/knav_qmss_acc.c b/drivers/soc/ti/knav_qmss_acc.c index 3d388646ed43..269b4e75ae40 100644 --- a/drivers/soc/ti/knav_qmss_acc.c +++ b/drivers/soc/ti/knav_qmss_acc.c @@ -450,7 +450,7 @@ static int knav_acc_free_range(struct knav_range_info *range) return 0; } -static struct knav_range_ops knav_acc_range_ops = { +static const struct knav_range_ops knav_acc_range_ops = { .set_notify = knav_acc_set_notify, .init_queue = knav_acc_init_queue, .open_queue = knav_acc_open_queue, diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index 06fb5505c22c..f2055a76f84c 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -411,7 +411,7 @@ static int knav_gp_close_queue(struct knav_range_info *range, return 0; } -static struct knav_range_ops knav_gp_range_ops = { +static const struct knav_range_ops knav_gp_range_ops = { .set_notify = knav_gp_set_notify, .open_queue = knav_gp_open_queue, .close_queue = knav_gp_close_queue, -- cgit v1.2.3 From e44097c6d535163f28c6106605452a2fdb1d8cba Mon Sep 17 00:00:00 2001 From: Neha Malcom Francis Date: Mon, 24 Jun 2024 12:22:05 +0530 Subject: soc: ti: k3-socinfo: Add J721E SR2.0 Add support to detect J721E SR2.0 Signed-off-by: Neha Malcom Francis Link: https://lore.kernel.org/r/20240624065205.718449-1-n-francis@ti.com Signed-off-by: Nishanth Menon --- drivers/soc/ti/k3-socinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c index 59101bf7cf23..4fb0f0a24828 100644 --- a/drivers/soc/ti/k3-socinfo.c +++ b/drivers/soc/ti/k3-socinfo.c @@ -61,7 +61,7 @@ static const struct k3_soc_id { }; static const char * const j721e_rev_string_map[] = { - "1.0", "1.1", + "1.0", "1.1", "2.0", }; static int -- cgit v1.2.3 From b89c5bc72102469a87f0c6ec0ee7112ef2eba01f Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 26 Jun 2024 22:12:37 +0300 Subject: soc: qcom: add missing pd-mapper dependencies The pd-mapper driver uses auxiliary bus and Qualcomm PDR message format data. Add missing dependencies to the driver's Kconfig entry. Reported-by: Mark Brown Fixes: 1ebcde047c54 ("soc: qcom: add pd-mapper implementation") Signed-off-by: Dmitry Baryshkov Reviewed-by: Chris Lew Link: https://lore.kernel.org/r/20240626-qcom-pd-mapper-fix-deps-v1-1-644678dc4663@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 0a2f2bfd7863..432c85bd8ad4 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -75,6 +75,8 @@ config QCOM_OCMEM config QCOM_PD_MAPPER tristate "Qualcomm Protection Domain Mapper" select QCOM_QMI_HELPERS + select QCOM_PDR_MSG + select AUXILIARY_BUS depends on NET && QRTR default QCOM_RPROC_COMMON help -- cgit v1.2.3 From 05a21e8b5d006177bce7332523eea5e3f2ee23ab Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Fri, 28 Jun 2024 19:30:23 +0200 Subject: soc: qcom: smsm: Add missing mailbox dependency to Kconfig Since the smsm driver got the ability to interact with the mailbox using the mailbox subsystem and not just syscon, we need to add the dependency to kconfig as well to avoid compile errors. Fixes: 75287992f58a ("soc: qcom: smsm: Support using mailbox interface") Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202406180006.Z397C67h-lkp@intel.com/ Signed-off-by: Luca Weiss Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240628-smsm-kconfig-v1-1-117d5af4ba1f@lucaweiss.eu Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 432c85bd8ad4..7f02f0525933 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -211,6 +211,7 @@ config QCOM_SMP2P config QCOM_SMSM tristate "Qualcomm Shared Memory State Machine" + depends on MAILBOX depends on QCOM_SMEM select QCOM_SMEM_STATE select IRQ_DOMAIN -- cgit v1.2.3 From e49380c155940cb47e291a4b3fcb7fdffee6aa4d Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Thu, 27 Jun 2024 16:18:30 +0530 Subject: soc: qcom: smp2p: Use devname for interrupt descriptions When using /proc/interrupts to collect statistics on smp2p interrupt counts, it is hard to distinguish the different instances of smp2p from each other. For example to debug a processor boot issue, the ready and handover interrupts are checked for sanity to ensure the firmware reached a specific initialization stage. Remove "smp2p" string from the irq request so that the irq will default to the device name. Add an .irq_print_chip() callback to print the irq chip name as the device name. These two changes allow for a unique name to be used in /proc/interrupts as shown below. / # cat /proc/interrupts | grep smp2p 18: ... ipcc 196610 Edge smp2p-adsp 20: ... ipcc 131074 Edge smp2p-modem 170: ... smp2p-modem 1 Edge q6v5 ready 178: ... smp2p-adsp 1 Edge q6v5 ready Signed-off-by: Chris Lew Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20240627104831.4176799-2-quic_sudeepgo@quicinc.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/smp2p.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index a21241cbeec7..696c2a8387d0 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -353,11 +354,19 @@ static int smp2p_set_irq_type(struct irq_data *irqd, unsigned int type) return 0; } +static void smp2p_irq_print_chip(struct irq_data *irqd, struct seq_file *p) +{ + struct smp2p_entry *entry = irq_data_get_irq_chip_data(irqd); + + seq_printf(p, " %8s", dev_name(entry->smp2p->dev)); +} + static struct irq_chip smp2p_irq_chip = { .name = "smp2p", .irq_mask = smp2p_mask_irq, .irq_unmask = smp2p_unmask_irq, .irq_set_type = smp2p_set_irq_type, + .irq_print_chip = smp2p_irq_print_chip, }; static int smp2p_irq_map(struct irq_domain *d, @@ -617,7 +626,7 @@ static int qcom_smp2p_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, qcom_smp2p_intr, IRQF_ONESHOT, - "smp2p", (void *)smp2p); + NULL, (void *)smp2p); if (ret) { dev_err(&pdev->dev, "failed to request interrupt\n"); goto unwind_interfaces; -- cgit v1.2.3 From 6e697467c4d1f07839ad934dea322fea6a460e4e Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Wed, 3 Jul 2024 09:01:03 +0200 Subject: soc: qcom: socinfo: Add PM6350 PMIC Add the ID for the PM6350 PMIC found on e.g. SM7225 Fairphone 4. Signed-off-by: Luca Weiss Reviewed-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20240703-socinfo-pm6350-v1-1-e12369af3ed6@fairphone.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/socinfo.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index beb23e292323..d7359a235e3c 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -116,6 +116,7 @@ static const char *const pmic_models[] = { [50] = "PM8350B", [51] = "PMR735A", [52] = "PMR735B", + [54] = "PM6350", [55] = "PM4125", [58] = "PM8450", [65] = "PM8010", -- cgit v1.2.3 From 04e60d7a72b65f8aa45ef04458c818e9c95fe584 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Jul 2024 11:42:36 +0200 Subject: soc: qcom: llcc: simplify with cleanup.h Allocate the memory with scoped/cleanup.h to reduce error handling and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240703-thermal-const-v1-1-6e59e139c65d@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/llcc-qcom.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 110b1f89aa59..37e11e501728 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -1294,16 +1295,13 @@ static int qcom_llcc_probe(struct platform_device *pdev) /* Initialize rest of LLCC bank regmaps */ for (i = 1; i < num_banks; i++) { - char *base = kasprintf(GFP_KERNEL, "llcc%d_base", i); + char *base __free(kfree) = kasprintf(GFP_KERNEL, "llcc%d_base", i); drv_data->regmaps[i] = qcom_llcc_init_mmio(pdev, i, base); if (IS_ERR(drv_data->regmaps[i])) { ret = PTR_ERR(drv_data->regmaps[i]); - kfree(base); goto err; } - - kfree(base); } drv_data->bcast_regmap = qcom_llcc_init_mmio(pdev, i, "llcc_broadcast_base"); -- cgit v1.2.3 From 01dd825d2b54edc90394f297830c63047b424da1 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Jul 2024 11:42:37 +0200 Subject: soc: qcom: mdt_loader: simplify with cleanup.h Allocate the memory with scoped/cleanup.h to reduce error handling and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240703-thermal-const-v1-2-6e59e139c65d@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/mdt_loader.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index 6f177e46fa0f..b2c0fb55d4ae 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -7,6 +7,7 @@ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. */ +#include #include #include #include @@ -37,13 +38,12 @@ static ssize_t mdt_load_split_segment(void *ptr, const struct elf32_phdr *phdrs, { const struct elf32_phdr *phdr = &phdrs[segment]; const struct firmware *seg_fw; - char *seg_name; ssize_t ret; if (strlen(fw_name) < 4) return -EINVAL; - seg_name = kstrdup(fw_name, GFP_KERNEL); + char *seg_name __free(kfree) = kstrdup(fw_name, GFP_KERNEL); if (!seg_name) return -ENOMEM; @@ -52,7 +52,6 @@ static ssize_t mdt_load_split_segment(void *ptr, const struct elf32_phdr *phdrs, ptr, phdr->p_filesz); if (ret) { dev_err(dev, "error %zd loading %s\n", ret, seg_name); - kfree(seg_name); return ret; } @@ -64,7 +63,6 @@ static ssize_t mdt_load_split_segment(void *ptr, const struct elf32_phdr *phdrs, } release_firmware(seg_fw); - kfree(seg_name); return ret; } -- cgit v1.2.3 From 20635bcc12d5feb1b0005d559cf7cf27743045df Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Jul 2024 11:42:38 +0200 Subject: soc: qcom: ocmem: simplify with cleanup.h Allocate the memory with scoped/cleanup.h to reduce error handling (less error paths) and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240703-thermal-const-v1-3-6e59e139c65d@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/ocmem.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c index e8841d247953..6b6dd80cbc0f 100644 --- a/drivers/soc/qcom/ocmem.c +++ b/drivers/soc/qcom/ocmem.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -216,7 +217,6 @@ EXPORT_SYMBOL_GPL(of_get_ocmem); struct ocmem_buf *ocmem_allocate(struct ocmem *ocmem, enum ocmem_client client, unsigned long size) { - struct ocmem_buf *buf; int ret; /* TODO: add support for other clients... */ @@ -229,7 +229,7 @@ struct ocmem_buf *ocmem_allocate(struct ocmem *ocmem, enum ocmem_client client, if (test_and_set_bit_lock(BIT(client), &ocmem->active_allocations)) return ERR_PTR(-EBUSY); - buf = kzalloc(sizeof(*buf), GFP_KERNEL); + struct ocmem_buf *buf __free(kfree) = kzalloc(sizeof(*buf), GFP_KERNEL); if (!buf) { ret = -ENOMEM; goto err_unlock; @@ -247,7 +247,7 @@ struct ocmem_buf *ocmem_allocate(struct ocmem *ocmem, enum ocmem_client client, if (ret) { dev_err(ocmem->dev, "could not lock: %d\n", ret); ret = -EINVAL; - goto err_kfree; + goto err_unlock; } } else { ocmem_write(ocmem, OCMEM_REG_GFX_MPU_START, buf->offset); @@ -258,10 +258,8 @@ struct ocmem_buf *ocmem_allocate(struct ocmem *ocmem, enum ocmem_client client, dev_dbg(ocmem->dev, "using %ldK of OCMEM at 0x%08lx for client %d\n", size / 1024, buf->addr, client); - return buf; + return_ptr(buf); -err_kfree: - kfree(buf); err_unlock: clear_bit_unlock(BIT(client), &ocmem->active_allocations); -- cgit v1.2.3 From 0ed06fcc7a84ea4861564862545dc7805c0f132e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Jul 2024 11:42:39 +0200 Subject: soc: qcom: pdr: simplify with cleanup.h Allocate the memory with scoped/cleanup.h to reduce error handling (less error paths) and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240703-thermal-const-v1-4-6e59e139c65d@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/pdr_interface.c | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/pdr_interface.c b/drivers/soc/qcom/pdr_interface.c index 216166e98fae..328b6153b2be 100644 --- a/drivers/soc/qcom/pdr_interface.c +++ b/drivers/soc/qcom/pdr_interface.c @@ -3,6 +3,7 @@ * Copyright (C) 2020 The Linux Foundation. All rights reserved. */ +#include #include #include #include @@ -396,13 +397,13 @@ static int pdr_get_domain_list(struct servreg_get_domain_list_req *req, static int pdr_locate_service(struct pdr_handle *pdr, struct pdr_service *pds) { - struct servreg_get_domain_list_resp *resp; struct servreg_get_domain_list_req req; struct servreg_location_entry *entry; int domains_read = 0; int ret, i; - resp = kzalloc(sizeof(*resp), GFP_KERNEL); + struct servreg_get_domain_list_resp *resp __free(kfree) = kzalloc(sizeof(*resp), + GFP_KERNEL); if (!resp) return -ENOMEM; @@ -415,7 +416,7 @@ static int pdr_locate_service(struct pdr_handle *pdr, struct pdr_service *pds) req.domain_offset = domains_read; ret = pdr_get_domain_list(&req, resp, pdr); if (ret < 0) - goto out; + return ret; for (i = 0; i < resp->domain_list_len; i++) { entry = &resp->domain_list[i]; @@ -427,7 +428,7 @@ static int pdr_locate_service(struct pdr_handle *pdr, struct pdr_service *pds) pds->service_data_valid = entry->service_data_valid; pds->service_data = entry->service_data; pds->instance = entry->instance; - goto out; + return 0; } } @@ -440,8 +441,7 @@ static int pdr_locate_service(struct pdr_handle *pdr, struct pdr_service *pds) domains_read += resp->domain_list_len; } while (domains_read < resp->total_domains); -out: - kfree(resp); + return ret; } @@ -517,8 +517,7 @@ struct pdr_service *pdr_add_lookup(struct pdr_handle *pdr, const char *service_name, const char *service_path) { - struct pdr_service *pds, *tmp; - int ret; + struct pdr_service *tmp; if (IS_ERR_OR_NULL(pdr)) return ERR_PTR(-EINVAL); @@ -527,7 +526,7 @@ struct pdr_service *pdr_add_lookup(struct pdr_handle *pdr, !service_path || strlen(service_path) > SERVREG_NAME_LENGTH) return ERR_PTR(-EINVAL); - pds = kzalloc(sizeof(*pds), GFP_KERNEL); + struct pdr_service *pds __free(kfree) = kzalloc(sizeof(*pds), GFP_KERNEL); if (!pds) return ERR_PTR(-ENOMEM); @@ -542,8 +541,7 @@ struct pdr_service *pdr_add_lookup(struct pdr_handle *pdr, continue; mutex_unlock(&pdr->list_lock); - ret = -EALREADY; - goto err; + return ERR_PTR(-EALREADY); } list_add(&pds->node, &pdr->lookups); @@ -551,10 +549,7 @@ struct pdr_service *pdr_add_lookup(struct pdr_handle *pdr, schedule_work(&pdr->locator_work); - return pds; -err: - kfree(pds); - return ERR_PTR(ret); + return_ptr(pds); } EXPORT_SYMBOL_GPL(pdr_add_lookup); @@ -651,13 +646,12 @@ struct pdr_handle *pdr_handle_alloc(void (*status)(int state, char *service_path, void *priv), void *priv) { - struct pdr_handle *pdr; int ret; if (!status) return ERR_PTR(-EINVAL); - pdr = kzalloc(sizeof(*pdr), GFP_KERNEL); + struct pdr_handle *pdr __free(kfree) = kzalloc(sizeof(*pdr), GFP_KERNEL); if (!pdr) return ERR_PTR(-ENOMEM); @@ -676,10 +670,8 @@ struct pdr_handle *pdr_handle_alloc(void (*status)(int state, INIT_WORK(&pdr->indack_work, pdr_indack_work); pdr->notifier_wq = create_singlethread_workqueue("pdr_notifier_wq"); - if (!pdr->notifier_wq) { - ret = -ENOMEM; - goto free_pdr_handle; - } + if (!pdr->notifier_wq) + return ERR_PTR(-ENOMEM); pdr->indack_wq = alloc_ordered_workqueue("pdr_indack_wq", WQ_HIGHPRI); if (!pdr->indack_wq) { @@ -704,7 +696,7 @@ struct pdr_handle *pdr_handle_alloc(void (*status)(int state, if (ret < 0) goto release_qmi_handle; - return pdr; + return_ptr(pdr); release_qmi_handle: qmi_handle_release(&pdr->locator_hdl); @@ -712,8 +704,6 @@ destroy_indack: destroy_workqueue(pdr->indack_wq); destroy_notifier: destroy_workqueue(pdr->notifier_wq); -free_pdr_handle: - kfree(pdr); return ERR_PTR(ret); } -- cgit v1.2.3 From b066a2c430f3f8d0aedba44991e0a69e21b512d3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 3 Jul 2024 11:42:40 +0200 Subject: soc: qcom: wcnss: simplify with cleanup.h Allocate the memory with scoped/cleanup.h to reduce error handling (less error paths) and make the code a bit simpler. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240703-thermal-const-v1-5-6e59e139c65d@linaro.org Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/wcnss_ctrl.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c index 148bcbac332d..62b424e90d90 100644 --- a/drivers/soc/qcom/wcnss_ctrl.c +++ b/drivers/soc/qcom/wcnss_ctrl.c @@ -3,6 +3,7 @@ * Copyright (c) 2016, Linaro Ltd. * Copyright (c) 2015, Sony Mobile Communications Inc. */ +#include #include #include #include @@ -198,7 +199,6 @@ static int wcnss_request_version(struct wcnss_ctrl *wcnss) */ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc) { - struct wcnss_download_nv_req *req; const struct firmware *fw; struct device *dev = wcnss->dev; const char *nvbin = NVBIN_FILE; @@ -206,18 +206,19 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc) ssize_t left; int ret; - req = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, GFP_KERNEL); + struct wcnss_download_nv_req *req __free(kfree) = kzalloc(sizeof(*req) + NV_FRAGMENT_SIZE, + GFP_KERNEL); if (!req) return -ENOMEM; ret = of_property_read_string(dev->of_node, "firmware-name", &nvbin); if (ret < 0 && ret != -EINVAL) - goto free_req; + return ret; ret = request_firmware(&fw, nvbin, dev); if (ret < 0) { dev_err(dev, "Failed to load nv file %s: %d\n", nvbin, ret); - goto free_req; + return ret; } data = fw->data; @@ -263,8 +264,6 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc) release_fw: release_firmware(fw); -free_req: - kfree(req); return ret; } -- cgit v1.2.3 From 97c4264f62a73664a2934203346a3e04c109b8ec Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Tue, 2 Jul 2024 08:35:09 +0200 Subject: soc: samsung: exynos-pmu: add support for PMU_ALIVE non atomic registers Not all registers in PMU_ALIVE block support atomic set/clear operations. GS101_SYSIP_DAT0 and GS101_SYSTEM_CONFIGURATION registers are two regs where attempting atomic access fails. As documentation on exactly which registers support atomic operations is not forthcoming. We default to atomic access, unless the register is explicitly added to the tensor_is_atomic() function. Update the comment to reflect this as well. Reviewed-by: Will McVicker Tested-by: Will McVicker Signed-off-by: Peter Griffin Link: https://lore.kernel.org/r/20240628223506.1237523-4-peter.griffin@linaro.org Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20240702063514.6215-2-krzysztof.kozlowski@linaro.org Signed-off-by: Arnd Bergmann --- drivers/soc/samsung/exynos-pmu.c | 22 +++++++++++++++++++--- include/linux/soc/samsung/exynos-regs-pmu.h | 4 ++++ 2 files changed, 23 insertions(+), 3 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c index fd8b6ac06656..a0123070a816 100644 --- a/drivers/soc/samsung/exynos-pmu.c +++ b/drivers/soc/samsung/exynos-pmu.c @@ -129,14 +129,30 @@ static int tensor_set_bits_atomic(void *ctx, unsigned int offset, u32 val, return ret; } -static int tensor_sec_update_bits(void *ctx, unsigned int reg, - unsigned int mask, unsigned int val) +static bool tensor_is_atomic(unsigned int reg) { /* * Use atomic operations for PMU_ALIVE registers (offset 0~0x3FFF) - * as the target registers can be accessed by multiple masters. + * as the target registers can be accessed by multiple masters. SFRs + * that don't support atomic are added to the switch statement below. */ if (reg > PMUALIVE_MASK) + return false; + + switch (reg) { + case GS101_SYSIP_DAT0: + case GS101_SYSTEM_CONFIGURATION: + return false; + default: + return true; + } +} + +static int tensor_sec_update_bits(void *ctx, unsigned int reg, + unsigned int mask, unsigned int val) +{ + + if (!tensor_is_atomic(reg)) return tensor_sec_reg_rmw(ctx, reg, mask, val); return tensor_set_bits_atomic(ctx, reg, val, mask); diff --git a/include/linux/soc/samsung/exynos-regs-pmu.h b/include/linux/soc/samsung/exynos-regs-pmu.h index aa840ed043e1..f411c176536d 100644 --- a/include/linux/soc/samsung/exynos-regs-pmu.h +++ b/include/linux/soc/samsung/exynos-regs-pmu.h @@ -657,4 +657,8 @@ #define EXYNOS5433_PAD_RETENTION_UFS_OPTION (0x3268) #define EXYNOS5433_PAD_RETENTION_FSYSGENIO_OPTION (0x32A8) +/* For Tensor GS101 */ +#define GS101_SYSIP_DAT0 (0x810) +#define GS101_SYSTEM_CONFIGURATION (0x3A00) + #endif /* __LINUX_SOC_EXYNOS_REGS_PMU_H */ -- cgit v1.2.3 From 9bc1e34a7b0c91d790eab2db4eea05175d248c68 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Fri, 5 Jul 2024 12:52:27 +0200 Subject: soc: sunxi: sram: Constify struct regmap_config `sunxi_sram_regmap_config` is not modified and can be declared as const to move its data to a read-only section. Signed-off-by: Javier Carrasco Reviewed-by: Andre Przywara Link: https://lore.kernel.org/r/20240705-sunxi-sram-const-regmap_config-v1-1-1b997cd65d0f@gmail.com Signed-off-by: Chen-Yu Tsai --- drivers/soc/sunxi/sunxi_sram.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c index 71cc377b5e24..2781a091a6a6 100644 --- a/drivers/soc/sunxi/sunxi_sram.c +++ b/drivers/soc/sunxi/sunxi_sram.c @@ -344,7 +344,7 @@ static void sunxi_sram_unlock(void *_lock) spin_unlock(lock); } -static struct regmap_config sunxi_sram_regmap_config = { +static const struct regmap_config sunxi_sram_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, -- cgit v1.2.3