From ac23106a9b9a0f6ed90002ae3d6fe7c14e97e6bf Mon Sep 17 00:00:00 2001 From: Francisco Munoz Ruiz Date: Tue, 7 Apr 2026 14:51:48 -0700 Subject: soc: qcom: llcc-qcom: get SCT descriptors from fw-populated memory Retrieve System Cache Table (SCT) descriptors from a shared memory region populated by firmware. SCT initialization and programming are performed entirely by firmware outside of Linux. The LLCC driver only consumes the pre-initialized descriptor data and does not configure SCT itself. Support this mechanism for future SoCs that provide SCT programming via firmware. Signed-off-by: Francisco Munoz Ruiz Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20260407-external_llcc_changes2set-v2-2-b5017ce2020b@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- include/linux/soc/qcom/llcc-qcom.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/soc/qcom/llcc-qcom.h b/include/linux/soc/qcom/llcc-qcom.h index 227125d84318..b5e917154998 100644 --- a/include/linux/soc/qcom/llcc-qcom.h +++ b/include/linux/soc/qcom/llcc-qcom.h @@ -90,11 +90,13 @@ /** * struct llcc_slice_desc - Cache slice descriptor * @slice_id: llcc slice id + * @uid: Unique ID associated with the llcc device * @slice_size: Size allocated for the llcc slice * @refcount: Atomic counter to track activate/deactivate calls */ struct llcc_slice_desc { u32 slice_id; + u32 uid; size_t slice_size; refcount_t refcount; }; @@ -147,6 +149,7 @@ struct llcc_edac_reg_offset { /** * struct llcc_drv_data - Data associated with the llcc driver + * @dev: device back-pointer for this llcc instance * @regmaps: regmaps associated with the llcc device * @bcast_regmap: regmap associated with llcc broadcast OR offset * @bcast_and_regmap: regmap associated with llcc broadcast AND offset @@ -157,10 +160,11 @@ struct llcc_edac_reg_offset { * @num_banks: Number of llcc banks * @ecc_irq: interrupt for llcc cache error detection and reporting * @ecc_irq_configured: 'True' if firmware has already configured the irq propagation - * @desc: Array pointer of pre-allocated LLCC slice descriptors * @version: Indicates the LLCC version + * @desc: Array pointer of pre-allocated LLCC slice descriptors */ struct llcc_drv_data { + struct device *dev; struct regmap **regmaps; struct regmap *bcast_regmap; struct regmap *bcast_and_regmap; @@ -183,7 +187,7 @@ struct llcc_drv_data { struct llcc_slice_desc *llcc_slice_getd(u32 uid); /** - * llcc_slice_putd - llcc slice descritpor + * llcc_slice_putd - llcc slice descriptor * @desc: Pointer to llcc slice descriptor */ void llcc_slice_putd(struct llcc_slice_desc *desc); -- cgit v1.2.3 From 06a84c2d3ca4b9b54724e79717c2cfd9a59947d9 Mon Sep 17 00:00:00 2001 From: Francisco Munoz Ruiz Date: Tue, 7 Apr 2026 14:51:49 -0700 Subject: soc: qcom: llcc-qcom: Capitalize LLCC/EDAC in comments and diagnostics Capitalize occurrences of the acronym "LLCC" and "EDAC" in comments and diagnostic text to improve consistency and readability. Signed-off-by: Francisco Munoz Ruiz Reviewed-by: Konrad Dybcio Reviewed-by: Mukesh Ojha Link: https://lore.kernel.org/r/20260407-external_llcc_changes2set-v2-3-b5017ce2020b@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/llcc-qcom.c | 32 ++++++++++++++--------------- include/linux/soc/qcom/llcc-qcom.h | 42 +++++++++++++++++++------------------- 2 files changed, 37 insertions(+), 37 deletions(-) (limited to 'include/linux') diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index f8cd35b205eb..dcc08f63e020 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -83,9 +83,9 @@ #define SLC_SCT_SLICE_ACT_ON_BOOT BIT(25) /** - * struct llcc_slice_config - Data associated with the llcc slice + * struct llcc_slice_config - Data associated with the LLCC slice * @usecase_id: Unique id for the client's use case - * @slice_id: llcc slice id for each client + * @slice_id: LLCC slice id for each client * @max_cap: The maximum capacity of the cache slice provided in KB * @priority: Priority of the client used to select victim line for replacement * @fixed_size: Boolean indicating if the slice has a fixed capacity @@ -99,7 +99,7 @@ * slice: normal or TCM(Tightly Coupled Memory) * @probe_target_ways: Determines what ways to probe for access hit. When * configured to 1 only bonus and reserved ways are probed. - * When configured to 0 all ways in llcc are probed. + * When configured to 0 all ways in LLCC are probed. * @dis_cap_alloc: Disable capacity based allocation for a client * @retain_on_pc: If this bit is set and client has maintained active vote * then the ways assigned to this client are not flushed on power @@ -4626,10 +4626,10 @@ static const struct qcom_sct_config x1e80100_cfgs = { static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER; /** - * llcc_slice_getd - get llcc slice descriptor + * llcc_slice_getd - get LLCC slice descriptor * @uid: usecase_id for the client * - * A pointer to llcc slice descriptor will be returned on success + * A pointer to LLCC slice descriptor will be returned on success * and error pointer is returned on failure */ struct llcc_slice_desc *llcc_slice_getd(u32 uid) @@ -4652,8 +4652,8 @@ struct llcc_slice_desc *llcc_slice_getd(u32 uid) EXPORT_SYMBOL_GPL(llcc_slice_getd); /** - * llcc_slice_putd - llcc slice descriptor - * @desc: Pointer to llcc slice descriptor + * llcc_slice_putd - LLCC slice descriptor + * @desc: Pointer to LLCC slice descriptor */ void llcc_slice_putd(struct llcc_slice_desc *desc) { @@ -4716,8 +4716,8 @@ static int llcc_update_act_ctrl(u32 sid, } /** - * llcc_slice_activate - Activate the llcc slice - * @desc: Pointer to llcc slice descriptor + * llcc_slice_activate - Activate the LLCC slice + * @desc: Pointer to LLCC slice descriptor * * A value of zero will be returned on success and a negative errno will * be returned in error cases @@ -4752,8 +4752,8 @@ int llcc_slice_activate(struct llcc_slice_desc *desc) EXPORT_SYMBOL_GPL(llcc_slice_activate); /** - * llcc_slice_deactivate - Deactivate the llcc slice - * @desc: Pointer to llcc slice descriptor + * llcc_slice_deactivate - Deactivate the LLCC slice + * @desc: Pointer to LLCC slice descriptor * * A value of zero will be returned on success and a negative errno will * be returned in error cases @@ -4789,7 +4789,7 @@ EXPORT_SYMBOL_GPL(llcc_slice_deactivate); /** * llcc_get_slice_id - return the slice id - * @desc: Pointer to llcc slice descriptor + * @desc: Pointer to LLCC slice descriptor */ int llcc_get_slice_id(struct llcc_slice_desc *desc) { @@ -4802,7 +4802,7 @@ EXPORT_SYMBOL_GPL(llcc_get_slice_id); /** * llcc_get_slice_size - return the slice id - * @desc: Pointer to llcc slice descriptor + * @desc: Pointer to LLCC slice descriptor */ size_t llcc_get_slice_size(struct llcc_slice_desc *desc) { @@ -4836,9 +4836,9 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config, /* * LLCC instances can vary for each target. * The SW writes to broadcast register which gets propagated - * to each llcc instance (llcc0,.. llccN). + * to each LLCC instance (llcc0,.. llccN). * Since the size of the memory is divided equally amongst the - * llcc instances, we need to configure the max cap accordingly. + * LLCC instances, we need to configure the max cap accordingly. */ max_cap_cacheline = max_cap_cacheline / drv_data->num_banks; max_cap_cacheline >>= CACHE_LINE_SIZE_SHIFT; @@ -5424,7 +5424,7 @@ static int qcom_llcc_probe(struct platform_device *pdev) "qcom_llcc_edac", -1, drv_data, sizeof(*drv_data)); if (IS_ERR(llcc_edac)) - dev_err(dev, "Failed to register llcc edac driver\n"); + dev_err(dev, "Failed to register LLCC EDAC driver\n"); } platform_set_drvdata(pdev, drv_data); diff --git a/include/linux/soc/qcom/llcc-qcom.h b/include/linux/soc/qcom/llcc-qcom.h index b5e917154998..f3ed63e475ab 100644 --- a/include/linux/soc/qcom/llcc-qcom.h +++ b/include/linux/soc/qcom/llcc-qcom.h @@ -89,9 +89,9 @@ /** * struct llcc_slice_desc - Cache slice descriptor - * @slice_id: llcc slice id - * @uid: Unique ID associated with the llcc device - * @slice_size: Size allocated for the llcc slice + * @slice_id: LLCC slice id + * @uid: Unique ID associated with the LLCC device + * @slice_size: Size allocated for the LLCC slice * @refcount: Atomic counter to track activate/deactivate calls */ struct llcc_slice_desc { @@ -102,7 +102,7 @@ struct llcc_slice_desc { }; /** - * struct llcc_edac_reg_data - llcc edac registers data for each error type + * struct llcc_edac_reg_data - LLCC EDAC registers data for each error type * @name: Name of the error * @reg_cnt: Number of registers * @count_mask: Mask value to get the error count @@ -148,17 +148,17 @@ struct llcc_edac_reg_offset { }; /** - * struct llcc_drv_data - Data associated with the llcc driver - * @dev: device back-pointer for this llcc instance - * @regmaps: regmaps associated with the llcc device - * @bcast_regmap: regmap associated with llcc broadcast OR offset - * @bcast_and_regmap: regmap associated with llcc broadcast AND offset + * struct llcc_drv_data - Data associated with the LLCC driver + * @dev: device back-pointer for this LLCC instance + * @regmaps: regmaps associated with the LLCC device + * @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 * @cfg_size: size of the config data table - * @num_banks: Number of llcc banks - * @ecc_irq: interrupt for llcc cache error detection and reporting + * @num_banks: Number of LLCC banks + * @ecc_irq: interrupt for LLCC cache error detection and reporting * @ecc_irq_configured: 'True' if firmware has already configured the irq propagation * @version: Indicates the LLCC version * @desc: Array pointer of pre-allocated LLCC slice descriptors @@ -181,38 +181,38 @@ struct llcc_drv_data { #if IS_ENABLED(CONFIG_QCOM_LLCC) /** - * llcc_slice_getd - get llcc slice descriptor + * llcc_slice_getd - get LLCC slice descriptor * @uid: usecase_id of the client */ struct llcc_slice_desc *llcc_slice_getd(u32 uid); /** - * llcc_slice_putd - llcc slice descriptor - * @desc: Pointer to llcc slice descriptor + * llcc_slice_putd - LLCC slice descriptor + * @desc: Pointer to LLCC slice descriptor */ void llcc_slice_putd(struct llcc_slice_desc *desc); /** * llcc_get_slice_id - get slice id - * @desc: Pointer to llcc slice descriptor + * @desc: Pointer to LLCC slice descriptor */ int llcc_get_slice_id(struct llcc_slice_desc *desc); /** - * llcc_get_slice_size - llcc slice size - * @desc: Pointer to llcc slice descriptor + * llcc_get_slice_size - LLCC slice size + * @desc: Pointer to LLCC slice descriptor */ size_t llcc_get_slice_size(struct llcc_slice_desc *desc); /** - * llcc_slice_activate - Activate the llcc slice - * @desc: Pointer to llcc slice descriptor + * llcc_slice_activate - Activate the LLCC slice + * @desc: Pointer to LLCC slice descriptor */ int llcc_slice_activate(struct llcc_slice_desc *desc); /** - * llcc_slice_deactivate - Deactivate the llcc slice - * @desc: Pointer to llcc slice descriptor + * llcc_slice_deactivate - Deactivate the LLCC slice + * @desc: Pointer to LLCC slice descriptor */ int llcc_slice_deactivate(struct llcc_slice_desc *desc); -- cgit v1.2.3 From ab7e4d7cf6f8efd37a675a85eb0aef3d6a4954ba Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 7 May 2026 16:02:58 +0300 Subject: soc: qcom: ubwc: define UBWC 3.1 Follow the comment for the macrotile_mode and introduce separate revision for UBWC 3.0 + 8-channel macrotiling mode. It is not used by the database (since the drivers are not yet changed to handle it yet). Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20260507-ubwc-rework-v4-2-c19593d20c1d@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- include/linux/soc/qcom/ubwc.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/soc/qcom/ubwc.h b/include/linux/soc/qcom/ubwc.h index f5d0e2341261..319caed88775 100644 --- a/include/linux/soc/qcom/ubwc.h +++ b/include/linux/soc/qcom/ubwc.h @@ -50,6 +50,7 @@ struct qcom_ubwc_cfg_data { #define UBWC_1_0 0x10000000 #define UBWC_2_0 0x20000000 #define UBWC_3_0 0x30000000 +#define UBWC_3_1 0x30010000 /* UBWC 3.0 + Macrotile mode */ #define UBWC_4_0 0x40000000 #define UBWC_4_3 0x40030000 #define UBWC_5_0 0x50000000 -- cgit v1.2.3 From b5f7365c44d8fd58ef0224bf4111805c4fea0a1e Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 7 May 2026 16:02:59 +0300 Subject: soc: qcom: ubwc: define helper for MDSS and Adreno drivers Define special helper returning version setting for MDSS and A8xx drivers. Reviewed-by: Konrad Dybcio Signed-off-by: Dmitry Baryshkov Link: https://lore.kernel.org/r/20260507-ubwc-rework-v4-3-c19593d20c1d@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- include/linux/soc/qcom/ubwc.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'include/linux') diff --git a/include/linux/soc/qcom/ubwc.h b/include/linux/soc/qcom/ubwc.h index 319caed88775..8355ffe40f88 100644 --- a/include/linux/soc/qcom/ubwc.h +++ b/include/linux/soc/qcom/ubwc.h @@ -100,4 +100,20 @@ static inline u32 qcom_ubwc_swizzle(const struct qcom_ubwc_cfg_data *cfg) return cfg->ubwc_swizzle; } +static inline u32 qcom_ubwc_version_tag(const struct qcom_ubwc_cfg_data *cfg) +{ + if (cfg->ubwc_enc_version >= UBWC_6_0) + return 5; + if (cfg->ubwc_enc_version >= UBWC_5_0) + return 4; + if (cfg->ubwc_enc_version >= UBWC_4_3) + return 3; + if (cfg->ubwc_enc_version >= UBWC_4_0) + return 2; + if (cfg->ubwc_enc_version >= UBWC_3_0) + return 1; + + return 0; +} + #endif /* __QCOM_UBWC_H__ */ -- cgit v1.2.3 From c5e3f2a3abcb925f0364df09abfd759ff0590454 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Thu, 7 May 2026 16:03:00 +0300 Subject: soc: qcom: ubwc: add helper controlling AMSBC enablement Adreno and MDSS drivers need to know whether to enable AMSBC. Add separate helper, describing that feature. Signed-off-by: Dmitry Baryshkov Reviewed-by: Konrad Dybcio Link: https://lore.kernel.org/r/20260507-ubwc-rework-v4-4-c19593d20c1d@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- include/linux/soc/qcom/ubwc.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include/linux') diff --git a/include/linux/soc/qcom/ubwc.h b/include/linux/soc/qcom/ubwc.h index 8355ffe40f88..83d2c2a7116c 100644 --- a/include/linux/soc/qcom/ubwc.h +++ b/include/linux/soc/qcom/ubwc.h @@ -116,4 +116,9 @@ static inline u32 qcom_ubwc_version_tag(const struct qcom_ubwc_cfg_data *cfg) return 0; } +static inline bool qcom_ubwc_enable_amsbc(const struct qcom_ubwc_cfg_data *cfg) +{ + return cfg->ubwc_enc_version >= UBWC_3_0; +} + #endif /* __QCOM_UBWC_H__ */ -- cgit v1.2.3 From f746fedb892872cbcee698696303609f0ea76fd7 Mon Sep 17 00:00:00 2001 From: Praveen Talari Date: Fri, 27 Feb 2026 11:45:33 +0530 Subject: soc: qcom: geni-se: Add geni_icc_set_bw_ab() function Add a new function geni_icc_set_bw_ab() that allows callers to set average bandwidth values for all ICC (Interconnect) paths in a single call. This function takes separate parameters for core, config, and DDR average bandwidth values and applies them to the respective ICC paths. This provides a more convenient API for drivers that need to configure specific average bandwidth values. Co-developed-by: Konrad Dybcio Signed-off-by: Konrad Dybcio Signed-off-by: Praveen Talari Tested-by: Mattijs Korpershoek Link: https://lore.kernel.org/r/20260227061544.1785978-3-praveen.talari@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom-geni-se.c | 22 ++++++++++++++++++++++ include/linux/soc/qcom/geni-se.h | 1 + 2 files changed, 23 insertions(+) (limited to 'include/linux') diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index b6167b968ef6..b0542f836453 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -946,6 +946,28 @@ int geni_icc_set_bw(struct geni_se *se) } EXPORT_SYMBOL_GPL(geni_icc_set_bw); +/** + * geni_icc_set_bw_ab() - Set average bandwidth for all ICC paths and apply + * @se: Pointer to the concerned serial engine. + * @core_ab: Average bandwidth in kBps for GENI_TO_CORE path. + * @cfg_ab: Average bandwidth in kBps for CPU_TO_GENI path. + * @ddr_ab: Average bandwidth in kBps for GENI_TO_DDR path. + * + * Sets bandwidth values for all ICC paths and applies them. DDR path is + * optional and only set if it exists. + * + * Return: 0 on success, negative error code on failure. + */ +int geni_icc_set_bw_ab(struct geni_se *se, u32 core_ab, u32 cfg_ab, u32 ddr_ab) +{ + se->icc_paths[GENI_TO_CORE].avg_bw = core_ab; + se->icc_paths[CPU_TO_GENI].avg_bw = cfg_ab; + se->icc_paths[GENI_TO_DDR].avg_bw = ddr_ab; + + return geni_icc_set_bw(se); +} +EXPORT_SYMBOL_GPL(geni_icc_set_bw_ab); + void geni_icc_set_tag(struct geni_se *se, u32 tag) { int i; diff --git a/include/linux/soc/qcom/geni-se.h b/include/linux/soc/qcom/geni-se.h index 0a984e2579fe..980aabea2157 100644 --- a/include/linux/soc/qcom/geni-se.h +++ b/include/linux/soc/qcom/geni-se.h @@ -528,6 +528,7 @@ void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len); int geni_icc_get(struct geni_se *se, const char *icc_ddr); int geni_icc_set_bw(struct geni_se *se); +int geni_icc_set_bw_ab(struct geni_se *se, u32 core_ab, u32 cfg_ab, u32 ddr_ab); void geni_icc_set_tag(struct geni_se *se, u32 tag); int geni_icc_enable(struct geni_se *se); -- cgit v1.2.3 From 5b8a39dcf909a4723a58e424ae1b0595d6f5032d Mon Sep 17 00:00:00 2001 From: Praveen Talari Date: Fri, 27 Feb 2026 11:45:34 +0530 Subject: soc: qcom: geni-se: Introduce helper API for resource initialization The GENI Serial Engine drivers (I2C, SPI, and SERIAL) currently duplicate code for initializing shared resources such as clocks and interconnect paths. Introduce a new helper API, geni_se_resources_init(), to centralize this initialization logic, improving modularity and simplifying the probe function. Reviewed-by: Konrad Dybcio Signed-off-by: Praveen Talari Tested-by: Mattijs Korpershoek Link: https://lore.kernel.org/r/20260227061544.1785978-4-praveen.talari@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom-geni-se.c | 47 ++++++++++++++++++++++++++++++++++++++++ include/linux/soc/qcom/geni-se.h | 6 +++++ 2 files changed, 53 insertions(+) (limited to 'include/linux') diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index b0542f836453..75e722cd1a94 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -19,6 +19,7 @@ #include #include #include +#include #include /** @@ -1012,6 +1013,52 @@ int geni_icc_disable(struct geni_se *se) } EXPORT_SYMBOL_GPL(geni_icc_disable); +/** + * geni_se_resources_init() - Initialize resources for a GENI SE device. + * @se: Pointer to the geni_se structure representing the GENI SE device. + * + * This function initializes various resources required by the GENI Serial Engine + * (SE) device, including clock resources (core and SE clocks), interconnect + * paths for communication. + * It retrieves optional and mandatory clock resources, adds an OF-based + * operating performance point (OPP) table, and sets up interconnect paths + * with default bandwidths. The function also sets a flag (`has_opp`) to + * indicate whether OPP support is available for the device. + * + * Return: 0 on success, or a negative errno on failure. + */ +int geni_se_resources_init(struct geni_se *se) +{ + int ret; + + se->core_clk = devm_clk_get_optional(se->dev, "core"); + if (IS_ERR(se->core_clk)) + return dev_err_probe(se->dev, PTR_ERR(se->core_clk), + "Failed to get optional core clk\n"); + + se->clk = devm_clk_get(se->dev, "se"); + if (IS_ERR(se->clk) && !has_acpi_companion(se->dev)) + return dev_err_probe(se->dev, PTR_ERR(se->clk), + "Failed to get SE clk\n"); + + ret = devm_pm_opp_set_clkname(se->dev, "se"); + if (ret) + return ret; + + ret = devm_pm_opp_of_add_table(se->dev); + if (ret && ret != -ENODEV) + return dev_err_probe(se->dev, ret, "Failed to add OPP table\n"); + + se->has_opp = (ret == 0); + + ret = geni_icc_get(se, "qup-memory"); + if (ret) + return ret; + + return geni_icc_set_bw_ab(se, GENI_DEFAULT_BW, GENI_DEFAULT_BW, GENI_DEFAULT_BW); +} +EXPORT_SYMBOL_GPL(geni_se_resources_init); + /** * geni_find_protocol_fw() - Locate and validate SE firmware for a protocol. * @dev: Pointer to the device structure. diff --git a/include/linux/soc/qcom/geni-se.h b/include/linux/soc/qcom/geni-se.h index 980aabea2157..c182dd0f0bde 100644 --- a/include/linux/soc/qcom/geni-se.h +++ b/include/linux/soc/qcom/geni-se.h @@ -60,18 +60,22 @@ struct geni_icc_path { * @dev: Pointer to the Serial Engine device * @wrapper: Pointer to the parent QUP Wrapper core * @clk: Handle to the core serial engine clock + * @core_clk: Auxiliary clock, which may be required by a protocol * @num_clk_levels: Number of valid clock levels in clk_perf_tbl * @clk_perf_tbl: Table of clock frequency input to serial engine clock * @icc_paths: Array of ICC paths for SE + * @has_opp: Indicates if OPP is supported */ struct geni_se { void __iomem *base; struct device *dev; struct geni_wrapper *wrapper; struct clk *clk; + struct clk *core_clk; unsigned int num_clk_levels; unsigned long *clk_perf_tbl; struct geni_icc_path icc_paths[3]; + bool has_opp; }; /* Common SE registers */ @@ -535,6 +539,8 @@ int geni_icc_enable(struct geni_se *se); int geni_icc_disable(struct geni_se *se); +int geni_se_resources_init(struct geni_se *se); + int geni_load_se_firmware(struct geni_se *se, enum geni_se_protocol_type protocol); #endif #endif -- cgit v1.2.3 From 8f4ce470ff8c0d7d820d319f64f05ed9a239a240 Mon Sep 17 00:00:00 2001 From: Praveen Talari Date: Fri, 27 Feb 2026 11:45:36 +0530 Subject: soc: qcom: geni-se: Add resources activation/deactivation helpers The GENI SE protocol drivers (I2C, SPI, UART) implement similar resource activation/deactivation sequences independently, leading to code duplication. Introduce geni_se_resources_activate()/geni_se_resources_deactivate() to power on/off resources.The activate function enables ICC, clocks, and TLMM whereas the deactivate function disables resources in reverse order including OPP rate reset, clocks, ICC and TLMM. Signed-off-by: Praveen Talari Reviewed-by: Konrad Dybcio Tested-by: Mattijs Korpershoek Link: https://lore.kernel.org/r/20260227061544.1785978-6-praveen.talari@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom-geni-se.c | 70 ++++++++++++++++++++++++++++++++++++++++ include/linux/soc/qcom/geni-se.h | 4 +++ 2 files changed, 74 insertions(+) (limited to 'include/linux') diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index 2e41595ff912..6e58568701b0 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -1025,6 +1025,76 @@ int geni_icc_disable(struct geni_se *se) } EXPORT_SYMBOL_GPL(geni_icc_disable); +/** + * geni_se_resources_deactivate() - Deactivate GENI SE device resources + * @se: Pointer to the geni_se structure + * + * Deactivates device resources for power saving: OPP rate to 0, pin control + * to sleep state, turns off clocks, and disables interconnect. Skips ACPI devices. + * + * Return: 0 on success, negative error code on failure + */ +int geni_se_resources_deactivate(struct geni_se *se) +{ + int ret; + + if (has_acpi_companion(se->dev)) + return 0; + + if (se->has_opp) + dev_pm_opp_set_rate(se->dev, 0); + + ret = pinctrl_pm_select_sleep_state(se->dev); + if (ret) + return ret; + + geni_se_clks_off(se); + + return geni_icc_disable(se); +} +EXPORT_SYMBOL_GPL(geni_se_resources_deactivate); + +/** + * geni_se_resources_activate() - Activate GENI SE device resources + * @se: Pointer to the geni_se structure + * + * Activates device resources for operation: enables interconnect, prepares clocks, + * and sets pin control to default state. Includes error cleanup. Skips ACPI devices. + * + * Unlike geni_se_resources_deactivate(), this function doesn't alter the + * connected genpds' performance states, which must be additionally handled. + * + * Return: 0 on success, negative error code on failure + */ +int geni_se_resources_activate(struct geni_se *se) +{ + int ret; + + if (has_acpi_companion(se->dev)) + return 0; + + ret = geni_icc_enable(se); + if (ret) + return ret; + + ret = geni_se_clks_on(se); + if (ret) + goto out_icc_disable; + + ret = pinctrl_pm_select_default_state(se->dev); + if (ret) { + geni_se_clks_off(se); + goto out_icc_disable; + } + + return 0; + +out_icc_disable: + geni_icc_disable(se); + return ret; +} +EXPORT_SYMBOL_GPL(geni_se_resources_activate); + /** * geni_se_resources_init() - Initialize resources for a GENI SE device. * @se: Pointer to the geni_se structure representing the GENI SE device. diff --git a/include/linux/soc/qcom/geni-se.h b/include/linux/soc/qcom/geni-se.h index c182dd0f0bde..36a68149345c 100644 --- a/include/linux/soc/qcom/geni-se.h +++ b/include/linux/soc/qcom/geni-se.h @@ -541,6 +541,10 @@ int geni_icc_disable(struct geni_se *se); int geni_se_resources_init(struct geni_se *se); +int geni_se_resources_activate(struct geni_se *se); + +int geni_se_resources_deactivate(struct geni_se *se); + int geni_load_se_firmware(struct geni_se *se, enum geni_se_protocol_type protocol); #endif #endif -- cgit v1.2.3 From f1a325d2812797166c744ff7ffb2ccbafbac20ad Mon Sep 17 00:00:00 2001 From: Praveen Talari Date: Fri, 27 Feb 2026 11:45:37 +0530 Subject: soc: qcom: geni-se: Introduce helper API for attaching power domains The GENI Serial Engine drivers (I2C, SPI, and SERIAL) currently handle the attachment of power domains. This often leads to duplicated code logic across different driver probe functions. Introduce a new helper API, geni_se_domain_attach(), to centralize the logic for attaching "power" and "perf" domains to the GENI SE device. Signed-off-by: Praveen Talari Reviewed-by: Konrad Dybcio Tested-by: Mattijs Korpershoek Link: https://lore.kernel.org/r/20260227061544.1785978-7-praveen.talari@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom-geni-se.c | 31 +++++++++++++++++++++++++++++++ include/linux/soc/qcom/geni-se.h | 4 ++++ 2 files changed, 35 insertions(+) (limited to 'include/linux') diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index 6e58568701b0..13ad3a51b58c 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -1095,6 +1096,36 @@ out_icc_disable: } EXPORT_SYMBOL_GPL(geni_se_resources_activate); +/** + * geni_se_domain_attach() - Attach power domains to a GENI SE device. + * @se: Pointer to the geni_se structure representing the GENI SE device. + * + * This function attaches the power domains ("power" and "perf") required + * in the SCMI auto-VM environment to the GENI Serial Engine device. It + * initializes se->pd_list with the attached domains. + * + * Return: 0 on success, or a negative error code on failure. + */ +int geni_se_domain_attach(struct geni_se *se) +{ + struct dev_pm_domain_attach_data pd_data = { + .pd_flags = PD_FLAG_DEV_LINK_ON, + .pd_names = (const char*[]) { "power", "perf" }, + .num_pd_names = 2, + }; + int ret; + + ret = devm_pm_domain_attach_list(se->dev, + &pd_data, &se->pd_list); + if (ret == 0) + return -ENODEV; + else if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL_GPL(geni_se_domain_attach); + /** * geni_se_resources_init() - Initialize resources for a GENI SE device. * @se: Pointer to the geni_se structure representing the GENI SE device. diff --git a/include/linux/soc/qcom/geni-se.h b/include/linux/soc/qcom/geni-se.h index 36a68149345c..5f75159c5531 100644 --- a/include/linux/soc/qcom/geni-se.h +++ b/include/linux/soc/qcom/geni-se.h @@ -64,6 +64,7 @@ struct geni_icc_path { * @num_clk_levels: Number of valid clock levels in clk_perf_tbl * @clk_perf_tbl: Table of clock frequency input to serial engine clock * @icc_paths: Array of ICC paths for SE + * @pd_list: Power domain list for managing power domains * @has_opp: Indicates if OPP is supported */ struct geni_se { @@ -75,6 +76,7 @@ struct geni_se { unsigned int num_clk_levels; unsigned long *clk_perf_tbl; struct geni_icc_path icc_paths[3]; + struct dev_pm_domain_list *pd_list; bool has_opp; }; @@ -546,5 +548,7 @@ int geni_se_resources_activate(struct geni_se *se); int geni_se_resources_deactivate(struct geni_se *se); int geni_load_se_firmware(struct geni_se *se, enum geni_se_protocol_type protocol); + +int geni_se_domain_attach(struct geni_se *se); #endif #endif -- cgit v1.2.3 From c012e28e9a4a84b0fe7bf9ef7db334a9a4f31687 Mon Sep 17 00:00:00 2001 From: Praveen Talari Date: Fri, 27 Feb 2026 11:45:38 +0530 Subject: soc: qcom: geni-se: Introduce helper APIs for performance control The GENI Serial Engine (SE) drivers (I2C, SPI, and SERIAL) currently manage performance levels and operating points directly. This resulting in code duplication across drivers. such as configuring a specific level or find and apply an OPP based on a clock frequency. Introduce two new helper APIs, geni_se_set_perf_level() and geni_se_set_perf_opp(), addresses this issue by providing a streamlined method for the GENI Serial Engine (SE) drivers to find and set the OPP based on the desired performance level, thereby eliminating redundancy. Signed-off-by: Praveen Talari Reviewed-by: Konrad Dybcio Tested-by: Mattijs Korpershoek Link: https://lore.kernel.org/r/20260227061544.1785978-8-praveen.talari@oss.qualcomm.com Signed-off-by: Bjorn Andersson --- drivers/soc/qcom/qcom-geni-se.c | 50 ++++++++++++++++++++++++++++++++++++++++ include/linux/soc/qcom/geni-se.h | 4 ++++ 2 files changed, 54 insertions(+) (limited to 'include/linux') diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index 13ad3a51b58c..15636a8dc907 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -282,6 +282,12 @@ struct se_fw_hdr { #define geni_setbits32(_addr, _v) writel(readl(_addr) | (_v), _addr) #define geni_clrbits32(_addr, _v) writel(readl(_addr) & ~(_v), _addr) +enum domain_idx { + DOMAIN_IDX_POWER, + DOMAIN_IDX_PERF, + DOMAIN_IDX_MAX +}; + /** * geni_se_get_qup_hw_version() - Read the QUP wrapper Hardware version * @se: Pointer to the corresponding serial engine. @@ -1096,6 +1102,50 @@ out_icc_disable: } EXPORT_SYMBOL_GPL(geni_se_resources_activate); +/** + * geni_se_set_perf_level() - Set performance level for GENI SE. + * @se: Pointer to the struct geni_se instance. + * @level: The desired performance level. + * + * Sets the performance level by directly calling dev_pm_opp_set_level + * on the performance device associated with the SE. + * + * Return: 0 on success, or a negative error code on failure. + */ +int geni_se_set_perf_level(struct geni_se *se, unsigned long level) +{ + return dev_pm_opp_set_level(se->pd_list->pd_devs[DOMAIN_IDX_PERF], level); +} +EXPORT_SYMBOL_GPL(geni_se_set_perf_level); + +/** + * geni_se_set_perf_opp() - Set performance OPP for GENI SE by frequency. + * @se: Pointer to the struct geni_se instance. + * @clk_freq: The requested clock frequency. + * + * Finds the nearest operating performance point (OPP) for the given + * clock frequency and applies it to the SE's performance device. + * + * Return: 0 on success, or a negative error code on failure. + */ +int geni_se_set_perf_opp(struct geni_se *se, unsigned long clk_freq) +{ + struct device *perf_dev = se->pd_list->pd_devs[DOMAIN_IDX_PERF]; + struct dev_pm_opp *opp; + int ret; + + opp = dev_pm_opp_find_freq_floor(perf_dev, &clk_freq); + if (IS_ERR(opp)) { + dev_err(se->dev, "failed to find opp for freq %lu\n", clk_freq); + return PTR_ERR(opp); + } + + ret = dev_pm_opp_set_opp(perf_dev, opp); + dev_pm_opp_put(opp); + return ret; +} +EXPORT_SYMBOL_GPL(geni_se_set_perf_opp); + /** * geni_se_domain_attach() - Attach power domains to a GENI SE device. * @se: Pointer to the geni_se structure representing the GENI SE device. diff --git a/include/linux/soc/qcom/geni-se.h b/include/linux/soc/qcom/geni-se.h index 5f75159c5531..c5e6ab85df09 100644 --- a/include/linux/soc/qcom/geni-se.h +++ b/include/linux/soc/qcom/geni-se.h @@ -550,5 +550,9 @@ int geni_se_resources_deactivate(struct geni_se *se); int geni_load_se_firmware(struct geni_se *se, enum geni_se_protocol_type protocol); int geni_se_domain_attach(struct geni_se *se); + +int geni_se_set_perf_level(struct geni_se *se, unsigned long level); + +int geni_se_set_perf_opp(struct geni_se *se, unsigned long clk_freq); #endif #endif -- cgit v1.2.3