diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2026-05-30 01:02:36 +0300 |
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2026-05-30 01:02:42 +0300 |
| commit | b6a6fae6c542e0e71bbabca653bb97699d2f3b33 (patch) | |
| tree | 1df21ea7ce267f5585e63004912eddab9463fe90 | |
| parent | b1700f8d6c8031948e2b898d2c839dfabe0ba68e (diff) | |
| parent | 23cee0d07a412f1fadb236358e0d834fabf0efcc (diff) | |
| download | linux-b6a6fae6c542e0e71bbabca653bb97699d2f3b33.tar.xz | |
Merge tag 'qcom-drivers-for-7.2' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into soc/drivers
Qualcomm driver updates for v7.2
Enable QSEECOM and with that access to UEFI variables on the Surface Pro
12in laptop.
Refactor the Geni Serial-Engine helper code to allow the serial engine
drivers (such as I2C) to operate on targets where power and performance
is controlled through an SCMI server instead of individual resources in
Linux.
Extend the LLCC driver to support reading its data from a System Cache
Table (SCT) in memory instead of being hard coded per platform in the
driver. Also add support for the Eliza platform.
Add support for the Hawi platform to pd-mapper.
Switch the SMEM driver to track partitions using xarray to handle the
ever growing number of hosts better.
Extend the socinfo driver with knowledge about the Nord, SM7750,
IPQ9650, and Shikra SoCs, as well as PMAU0102, PMC1020H, PMIV0102, and
PMIV0104 PMICs.
Define UBWC 3.1 and add a couple of convenient helpers in the UBWC
library for MDSS and Adreno.
Fix a memory leak in the WCNSS firmware download mechanism.
* tag 'qcom-drivers-for-7.2' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux: (40 commits)
soc: qcom: geni-se: Introduce helper APIs for performance control
soc: qcom: geni-se: Introduce helper API for attaching power domains
soc: qcom: geni-se: Add resources activation/deactivation helpers
soc: qcom: geni-se: Handle core clk in geni_se_clks_off() and geni_se_clks_on()
soc: qcom: geni-se: Introduce helper API for resource initialization
soc: qcom: geni-se: Add geni_icc_set_bw_ab() function
soc: qcom: geni-se: Refactor geni_icc_get() and make qup-memory ICC path optional
soc: qcom: llcc-qcom: Fix NULL vs IS_ERR() bug in qcom_llcc_get_fw_config()
soc: qcom: llcc-qcom: Add support for Eliza
dt-bindings: cache: qcom,llcc: Document Eliza LLCC block
soc: qcom: ubwc: add helper controlling AMSBC enablement
soc: qcom: ubwc: define helper for MDSS and Adreno drivers
soc: qcom: ubwc: define UBWC 3.1
soc: qcom: socinfo: Add SoC ID for Nord SA8797P
dt-bindings: arm: qcom,ids: Add SoC ID for Nord SA8797P
soc: qcom: socinfo: Add SoC ID for SM7750
dt-bindings: arm: qcom,ids: Add SoC ID for SM7750
soc: qcom: socinfo: Add PMIC PMAU0102
soc: qcom: socinfo: Add PMIV0102 & PMIV0104 PMICs
firmware: qcom: scm: Allow QSEECOM on Surface Pro 12in
...
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
| -rw-r--r-- | Documentation/devicetree/bindings/cache/qcom,llcc.yaml | 43 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/firmware/qcom,scm.yaml | 3 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml | 2 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml | 6 | ||||
| -rw-r--r-- | Documentation/devicetree/bindings/soc/qcom/qcom,sa8255p-geni-se-qup.yaml | 31 | ||||
| -rw-r--r-- | drivers/firmware/qcom/qcom_scm.c | 1 | ||||
| -rw-r--r-- | drivers/soc/qcom/llcc-qcom.c | 481 | ||||
| -rw-r--r-- | drivers/soc/qcom/qcom-geni-se.c | 270 | ||||
| -rw-r--r-- | drivers/soc/qcom/qcom_pd_mapper.c | 8 | ||||
| -rw-r--r-- | drivers/soc/qcom/smem.c | 56 | ||||
| -rw-r--r-- | drivers/soc/qcom/socinfo.c | 23 | ||||
| -rw-r--r-- | drivers/soc/qcom/wcnss_ctrl.c | 11 | ||||
| -rw-r--r-- | include/dt-bindings/arm/qcom,ids.h | 11 | ||||
| -rw-r--r-- | include/linux/soc/qcom/geni-se.h | 19 | ||||
| -rw-r--r-- | include/linux/soc/qcom/llcc-qcom.h | 44 | ||||
| -rw-r--r-- | include/linux/soc/qcom/ubwc.h | 22 | ||||
| -rw-r--r-- | include/soc/qcom/qcom-spmi-pmic.h | 15 |
17 files changed, 920 insertions, 126 deletions
diff --git a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml index 995d57815781..34e3a2d78592 100644 --- a/Documentation/devicetree/bindings/cache/qcom,llcc.yaml +++ b/Documentation/devicetree/bindings/cache/qcom,llcc.yaml @@ -20,7 +20,9 @@ description: | properties: compatible: enum: + - qcom,eliza-llcc - qcom,glymur-llcc + - qcom,hawi-llcc - qcom,ipq5424-llcc - qcom,kaanapali-llcc - qcom,qcs615-llcc @@ -35,6 +37,7 @@ properties: - qcom,sc8280xp-llcc - qcom,sdm670-llcc - qcom,sdm845-llcc + - qcom,shikra-llcc - qcom,sm6350-llcc - qcom,sm7150-llcc - qcom,sm8150-llcc @@ -57,6 +60,11 @@ properties: interrupts: maxItems: 1 + memory-region: + maxItems: 1 + description: handle to a reserved-memory node used for firmware-populated + SLC/SCT shared memory. + nvmem-cells: items: - description: Reference to an nvmem node for multi channel DDR @@ -206,6 +214,7 @@ allOf: enum: - qcom,sc7280-llcc - qcom,sdm670-llcc + - qcom,shikra-llcc then: properties: reg: @@ -318,6 +327,7 @@ allOf: contains: enum: - qcom,kaanapali-llcc + - qcom,hawi-llcc - qcom,sm8450-llcc - qcom,sm8550-llcc - qcom,sm8650-llcc @@ -340,6 +350,39 @@ allOf: - const: llcc3_base - const: llcc_broadcast_base - const: llcc_broadcast_and_base + - if: + properties: + compatible: + contains: + enum: + - qcom,hawi-llcc + then: + required: + - memory-region + else: + properties: + memory-region: false + + - if: + properties: + compatible: + contains: + enum: + - qcom,eliza-llcc + then: + properties: + reg: + items: + - description: LLCC0 base register region + - description: LLCC2 base register region + - description: LLCC broadcast OR register region + - description: LLCC broadcast AND register region + reg-names: + items: + - const: llcc0_base + - const: llcc2_base + - const: llcc_broadcast_base + - const: llcc_broadcast_and_base additionalProperties: false diff --git a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml index 7918d31f58b4..25f62bacbc91 100644 --- a/Documentation/devicetree/bindings/firmware/qcom,scm.yaml +++ b/Documentation/devicetree/bindings/firmware/qcom,scm.yaml @@ -25,6 +25,7 @@ properties: - qcom,scm-apq8084 - qcom,scm-eliza - qcom,scm-glymur + - qcom,scm-hawi - qcom,scm-ipq4019 - qcom,scm-ipq5018 - qcom,scm-ipq5210 @@ -49,6 +50,7 @@ properties: - qcom,scm-msm8994 - qcom,scm-msm8996 - qcom,scm-msm8998 + - qcom,scm-nord - qcom,scm-qcm2290 - qcom,scm-qcs615 - qcom,scm-qcs8300 @@ -208,6 +210,7 @@ allOf: contains: enum: - qcom,scm-eliza + - qcom,scm-hawi - qcom,scm-kaanapali - qcom,scm-milos - qcom,scm-sm8450 diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml index c5c1bac2db01..8eaa04431d74 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,aoss-qmp.yaml @@ -25,7 +25,9 @@ properties: compatible: items: - enum: + - qcom,eliza-aoss-qmp - qcom,glymur-aoss-qmp + - qcom,hawi-aoss-qmp - qcom,kaanapali-aoss-qmp - qcom,milos-aoss-qmp - qcom,qcs615-aoss-qmp diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml index ff01d2f3ee5b..2db4288a8a54 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,pmic-glink.yaml @@ -34,11 +34,17 @@ properties: - const: qcom,pmic-glink - items: - enum: + - qcom,hawi-pmic-glink + - const: qcom,kaanapali-pmic-glink + - const: qcom,pmic-glink + - items: + - enum: - qcom,sm7325-pmic-glink - const: qcom,qcm6490-pmic-glink - const: qcom,pmic-glink - items: - enum: + - qcom,eliza-pmic-glink - qcom,milos-pmic-glink - qcom,sm8650-pmic-glink - qcom,sm8750-pmic-glink diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,sa8255p-geni-se-qup.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,sa8255p-geni-se-qup.yaml index 352af3426d34..9c38ba59662b 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,sa8255p-geni-se-qup.yaml +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,sa8255p-geni-se-qup.yaml @@ -19,7 +19,11 @@ description: properties: compatible: - const: qcom,sa8255p-geni-se-qup + oneOf: + - const: qcom,sa8255p-geni-se-qup + - items: + - const: qcom,sa8797p-geni-se-qup + - const: qcom,sa8255p-geni-se-qup reg: description: QUP wrapper common register address and length. @@ -49,7 +53,11 @@ patternProperties: properties: compatible: - const: qcom,sa8255p-geni-spi + oneOf: + - const: qcom,sa8255p-geni-spi + - items: + - const: qcom,sa8797p-geni-spi + - const: qcom,sa8255p-geni-spi "i2c@[0-9a-f]+$": type: object @@ -58,7 +66,11 @@ patternProperties: properties: compatible: - const: qcom,sa8255p-geni-i2c + oneOf: + - const: qcom,sa8255p-geni-i2c + - items: + - const: qcom,sa8797p-geni-i2c + - const: qcom,sa8255p-geni-i2c "serial@[0-9a-f]+$": type: object @@ -67,9 +79,16 @@ patternProperties: properties: compatible: - enum: - - qcom,sa8255p-geni-uart - - qcom,sa8255p-geni-debug-uart + oneOf: + - enum: + - qcom,sa8255p-geni-uart + - qcom,sa8255p-geni-debug-uart + - items: + - const: qcom,sa8797p-geni-uart + - const: qcom,sa8255p-geni-uart + - items: + - const: qcom,sa8797p-geni-debug-uart + - const: qcom,sa8255p-geni-debug-uart required: - compatible diff --git a/drivers/firmware/qcom/qcom_scm.c b/drivers/firmware/qcom/qcom_scm.c index 9b06a69d3a6d..6b601a4b89db 100644 --- a/drivers/firmware/qcom/qcom_scm.c +++ b/drivers/firmware/qcom/qcom_scm.c @@ -2306,6 +2306,7 @@ static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = { { .compatible = "lenovo,yoga-slim7x" }, { .compatible = "medion,sprchrgd14s1" }, { .compatible = "microsoft,arcata", }, + { .compatible = "microsoft,surface-pro-12in", }, { .compatible = "microsoft,blackrock" }, { .compatible = "microsoft,denali", }, { .compatible = "microsoft,romulus13", }, diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 0161ceec8842..8948b5fd42d2 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -5,7 +5,6 @@ */ #include <linux/bitfield.h> -#include <linux/bitops.h> #include <linux/cleanup.h> #include <linux/device.h> #include <linux/io.h> @@ -14,6 +13,7 @@ #include <linux/mutex.h> #include <linux/nvmem-consumer.h> #include <linux/of.h> +#include <linux/of_reserved_mem.h> #include <linux/regmap.h> #include <linux/sizes.h> #include <linux/slab.h> @@ -76,10 +76,16 @@ #define LLCC_VERSION_4_1_0_0 0x04010000 #define LLCC_VERSION_6_0_0_0 0X06000000 +#define SLC_SCT_MEM_LAYOUT_VERSION1 1 /* SCT Memory layout version */ +#define SLC_SCT_DONE 0x00534354444f4e45 /* SCT programming OK */ +#define SLC_SCT_FAIL 0x005343544641494c /* SCT programming failed */ +#define SLC_SCT_NAME_LEN 15 +#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 @@ -93,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 @@ -143,6 +149,87 @@ struct llcc_slice_config { u32 parent_slice_id; }; +/* + * struct slc_sct_error - Represents SCT error + * @code: FW code status + * @param: Holds the SCT programming error + */ +struct slc_sct_error { + __le64 code; + __le64 param; +} __packed; + +/* + * struct slc_sct_status - SCT programming status + * @program_status: Indicates programming success or failure + * @version: SCT mem layout version + * @error: Error enum and its param + */ +struct slc_sct_status { + __le64 program_status; + /* Use the lower 8 bits */ + __le64 version; + struct slc_sct_error error; +} __packed; + +/* + * struct slc_sct_details - SCT details + * @revision: revision of the SCT table + * @name: name of the SCT table + */ +struct slc_sct_details { + u8 revision; + char name[SLC_SCT_NAME_LEN]; +} __packed; + +/* + * struct tcm_mem_info - SC TCM Shared memory details + * @is_present: is TCM region present + * @offset: offset of TCM shared memory details + */ +struct slc_tcm_mem_info { + __le32 is_present; + __le32 offset; +} __packed; + +/* + * struct slc_sct_slice_desc - Slice descriptor definition used in shmem + * @slice_id: SCID of the slice + * @usecase_id: Usecase ID of the slice + * @slice_properties: + * slice_size: Contains the slice descriptor size - 20 bit wide + * rsvd: Reserved space - 4 bit wide + * flags: Flags for descriptors - 3 bit wide + * MPAM SCID: Bit 24 + * Activate on boot: Bit 25 + * Non-HLOS SCID: Bit 26 + * HWMutex: Ensures only one processor (CPU or MCU) at a time can + * access the LLCC hardware resources - 5 bit wide + */ +struct slc_sct_slice_desc { + __le16 slice_id; + __le16 usecase_id; + __le32 slice_properties; +} __packed; + +/* + * struct slc_sct_mem - Shared memory structure + * @sct_status: Status of SCT programming + * @sct_details: Sct revision and name details + * @tcm_mem_info: TCM shared memory presence & offset info + * @slice_descs_count: Number of slice desc present in SCT + * @scid_max: Maximum no. of SCIDs supported + * @slice_descs: Array of SCT slice desc + */ +struct slc_sct_mem { + struct slc_sct_status sct_status; + struct slc_sct_details sct_details; + struct slc_tcm_mem_info tcm_mem_info; + __le32 slice_descs_count; + __le32 scid_max; + struct slc_sct_slice_desc slice_descs[] __counted_by_le(slice_descs_count); +} __packed; + struct qcom_llcc_config { const struct llcc_slice_config *sct_data; const u32 *reg_offset; @@ -181,6 +268,171 @@ enum llcc_reg_offset { LLCC_TRP_WRS_CACHEABLE_EN, }; +static const struct llcc_slice_config eliza_data[] = { + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 896, + .bonus_ways = 0xfff, + .activate_on_init = true, + .write_scid_en = true, + .stale_en = true, + }, + { + .usecase_id = LLCC_MDMHPFX, + .slice_id = 24, + .max_cap = 1024, + .priority = 5, + .fixed_size = true, + .bonus_ways = 0xfff, + }, + { + .usecase_id = LLCC_VIDSC0, + .slice_id = 2, + .max_cap = 128, + .priority = 5, + .fixed_size = true, + .bonus_ways = 0xfff, + }, + { + .usecase_id = LLCC_MDMHPGRW, + .slice_id = 25, + .max_cap = 1024, + .priority = 5, + .bonus_ways = 0xfff, + }, + { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + }, + { + .usecase_id = LLCC_GPU, + .slice_id = 9, + .max_cap = 896, + .priority = 1, + .bonus_ways = 0xfff, + .write_scid_cacheable_en = true, + }, + { + .usecase_id = LLCC_MMUHWT, + .slice_id = 18, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .activate_on_init = true, + }, + { + .usecase_id = LLCC_MDMPNG, + .slice_id = 27, + .max_cap = 256, + .priority = 5, + .fixed_size = true, + .bonus_ways = 0xfff, + }, + { + .usecase_id = LLCC_MODPE, + .slice_id = 29, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xf00, + .alloc_oneway_en = true, + }, + { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .activate_on_init = true, + }, + { + .usecase_id = LLCC_LCPDARE, + .slice_id = 30, + .max_cap = 128, + .priority = 5, + .fixed_size = true, + .bonus_ways = 0xfff, + .activate_on_init = true, + .alloc_oneway_en = true, + }, + { + .usecase_id = LLCC_ISLAND1, + .slice_id = 12, + .max_cap = 1280, + .priority = 7, + .fixed_size = true, + .res_ways = 0x3ff, + }, + { + .usecase_id = LLCC_CAMOFE, + .slice_id = 33, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .stale_en = true, + .parent_slice_id = 13, + }, + { + .usecase_id = LLCC_CAMRTIP, + .slice_id = 13, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .stale_en = true, + .parent_slice_id = 13, + }, + { + .usecase_id = LLCC_CAMSRTIP, + .slice_id = 14, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .stale_en = true, + .parent_slice_id = 13, + }, + { + .usecase_id = LLCC_CAMRTRF, + .slice_id = 7, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .stale_en = true, + .parent_slice_id = 13, + }, + { + .usecase_id = LLCC_CAMSRTRF, + .slice_id = 21, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xfff, + .stale_en = true, + .parent_slice_id = 13, + }, + { + .usecase_id = LLCC_CPUSSMPAM, + .slice_id = 6, + .max_cap = 512, + .priority = 0, + .fixed_size = true, + .bonus_ways = 0xfff, + .activate_on_init = true, + .write_scid_en = true, + .stale_en = true, + }, +}; + static const struct llcc_slice_config glymur_data[] = { { .usecase_id = LLCC_CPUSS, @@ -4141,6 +4393,24 @@ static const u32 llcc_v6_reg_offset[] = { [LLCC_TRP_WRS_CACHEABLE_EN] = 0x00042088, }; +static const struct qcom_llcc_config hawi_sct_cfg[] = { + { + .sct_data = NULL, + .size = 0, + .reg_offset = llcc_v6_reg_offset, + .edac_reg_offset = &llcc_v6_edac_reg_offset, + }, +}; + +static const struct qcom_llcc_config eliza_cfg[] = { + { + .sct_data = eliza_data, + .size = ARRAY_SIZE(eliza_data), + .reg_offset = llcc_v6_reg_offset, + .edac_reg_offset = &llcc_v6_edac_reg_offset, + }, +}; + static const struct qcom_llcc_config kaanapali_cfg[] = { { .sct_data = kaanapali_data, @@ -4397,6 +4667,16 @@ static const struct qcom_llcc_config x1e80100_cfg[] = { }, }; +static const struct qcom_sct_config hawi_sct_cfgs = { + .llcc_config = hawi_sct_cfg, + .num_config = ARRAY_SIZE(hawi_sct_cfg), +}; + +static const struct qcom_sct_config eliza_cfgs = { + .llcc_config = eliza_cfg, + .num_config = ARRAY_SIZE(eliza_cfg), +}; + static const struct qcom_sct_config kaanapali_cfgs = { .llcc_config = kaanapali_cfg, .num_config = ARRAY_SIZE(kaanapali_cfg), @@ -4525,37 +4805,34 @@ 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) { - const struct llcc_slice_config *cfg; - u32 sz, i; - if (IS_ERR(drv_data)) return ERR_CAST(drv_data); - cfg = drv_data->cfg; - sz = drv_data->cfg_size; + if (IS_ERR_OR_NULL(drv_data->desc)) + return ERR_PTR(-ENODEV); - for (i = 0; cfg && i < sz; i++, cfg++) - if (cfg->usecase_id == uid) - break; + for (u32 i = 0; i < drv_data->cfg_size; i++) { + if (uid == drv_data->desc[i].uid) + return &drv_data->desc[i]; + } - if (i == sz) - return ERR_PTR(-ENODEV); + dev_err(drv_data->dev, "Failed to get slice desc for uid: %u\n", uid); - return &drv_data->desc[i]; + return ERR_PTR(-EINVAL); } 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) { @@ -4618,8 +4895,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 @@ -4654,8 +4931,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 @@ -4691,7 +4968,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) { @@ -4704,7 +4981,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) { @@ -4738,9 +5015,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; @@ -5029,6 +5306,12 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev, sz = drv_data->cfg_size; llcc_table = drv_data->cfg; + for (i = 0; i < sz; i++) { + drv_data->desc[i].uid = llcc_table[i].usecase_id; + drv_data->desc[i].slice_id = llcc_table[i].slice_id; + drv_data->desc[i].slice_size = llcc_table[i].max_cap; + } + if (drv_data->version >= LLCC_VERSION_6_0_0_0) { for (i = 0; i < sz; i++) { ret = _qcom_llcc_cfg_program_v6(&llcc_table[i], cfg); @@ -5064,6 +5347,101 @@ static int qcom_llcc_get_cfg_index(struct platform_device *pdev, u8 *cfg_index, return ret; } +static int qcom_llcc_verify_fw_config(struct device *dev, + const struct slc_sct_mem *slc_mem) +{ + u64 program_status; + + program_status = le64_to_cpu(slc_mem->sct_status.program_status); + + if (program_status == SLC_SCT_DONE) { + u32 desc_count = le32_to_cpu(slc_mem->slice_descs_count); + u32 scid_max = le32_to_cpu(slc_mem->scid_max); + + if (desc_count > scid_max) { + dev_err(dev, "Descriptor count above max limit (%u > %u)\n", + desc_count, scid_max); + return -EINVAL; + } + + u8 revision = slc_mem->sct_details.revision; + char name_buf[SLC_SCT_NAME_LEN]; + + memcpy(name_buf, slc_mem->sct_details.name, + SLC_SCT_NAME_LEN - 1); + name_buf[SLC_SCT_NAME_LEN - 1] = '\0'; + + dev_dbg(dev, "SCT init: desc_count=%u, rev=%u, name=%s\n", + desc_count, revision, name_buf); + + return 0; + } else if (program_status == SLC_SCT_FAIL) { + u8 version = (u8)(le64_to_cpu(slc_mem->sct_status.version)); + u64 code = le64_to_cpu(slc_mem->sct_status.error.code); + u64 param = le64_to_cpu(slc_mem->sct_status.error.param); + + if (version == SLC_SCT_MEM_LAYOUT_VERSION1) { + dev_err(dev, "SCT init failed: code = %llu, param = %llu, version = 0x%x\n", + code, param, version); + } else { + dev_err(dev, "Found unsupported version %u\n", version); + } + } else { + dev_err(dev, "Unknown SCT Initialization error\n"); + } + + return -EINVAL; +} + +static int qcom_llcc_get_fw_config(struct platform_device *pdev) +{ + const struct slc_sct_mem *slc_mem = NULL; + const struct slc_sct_slice_desc *memslice; + struct device *dev = &pdev->dev; + u32 slice_properties; + struct resource res; + u32 i, sz; + int ret; + + ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res); + if (ret) { + dev_err(dev, "Unable to locate DT /reserved-memory resource\n"); + return ret; + } + + slc_mem = devm_memremap(dev, res.start, resource_size(&res), MEMREMAP_WB); + if (IS_ERR(slc_mem)) { + dev_err(dev, "Failed to memremap SLC shared memory\n"); + return PTR_ERR(slc_mem); + } + + ret = qcom_llcc_verify_fw_config(dev, slc_mem); + if (ret) + return ret; + + sz = le32_to_cpu(slc_mem->slice_descs_count); + + drv_data->desc = devm_kcalloc(dev, sz, sizeof(struct llcc_slice_desc), + GFP_KERNEL); + if (!drv_data->desc) + return -ENOMEM; + + for (i = 0; i < sz; i++) { + memslice = &slc_mem->slice_descs[i]; + drv_data->desc[i].slice_id = le16_to_cpu(memslice->slice_id); + drv_data->desc[i].uid = le16_to_cpu(memslice->usecase_id); + slice_properties = le32_to_cpu(memslice->slice_properties); + /* Set refcount to 1 if FW already activated this descriptor */ + if (FIELD_GET(SLC_SCT_SLICE_ACT_ON_BOOT, slice_properties)) + refcount_set(&drv_data->desc[i].refcount, 1); + } + + drv_data->cfg = NULL; + drv_data->cfg_size = sz; + + return 0; +} + static void qcom_llcc_remove(struct platform_device *pdev) { /* Set the global pointer to a error code to avoid referencing it */ @@ -5096,8 +5474,6 @@ static int qcom_llcc_probe(struct platform_device *pdev) struct platform_device *llcc_edac; const struct qcom_sct_config *cfgs; const struct qcom_llcc_config *cfg; - const struct llcc_slice_config *llcc_cfg; - u32 sz; u8 cfg_index; u32 version; struct regmap *regmap; @@ -5190,32 +5566,31 @@ static int qcom_llcc_probe(struct platform_device *pdev) } } - llcc_cfg = cfg->sct_data; - sz = cfg->size; - drv_data->desc = devm_kcalloc(dev, sz, sizeof(struct llcc_slice_desc), GFP_KERNEL); - if (!drv_data->desc) { - ret = -ENOMEM; - goto err; - } + mutex_init(&drv_data->lock); + if (!cfg->size) { + ret = qcom_llcc_get_fw_config(pdev); + if (ret) + goto err; + } else { + drv_data->cfg = cfg->sct_data; + drv_data->cfg_size = cfg->size; + drv_data->desc = devm_kcalloc(dev, cfg->size, + sizeof(struct llcc_slice_desc), GFP_KERNEL); - for (i = 0; i < sz; i++) { - drv_data->desc[i].slice_id = llcc_cfg[i].slice_id; - drv_data->desc[i].slice_size = llcc_cfg[i].max_cap; - refcount_set(&drv_data->desc[i].refcount, 0); + if (!drv_data->desc) { + ret = -ENOMEM; + goto err; + } + + ret = qcom_llcc_cfg_program(pdev, cfg); + if (ret) + goto err; } - drv_data->cfg = llcc_cfg; - drv_data->cfg_size = sz; + drv_data->ecc_irq = platform_get_irq_optional(pdev, 0); drv_data->edac_reg_offset = cfg->edac_reg_offset; drv_data->ecc_irq_configured = cfg->irq_configured; - mutex_init(&drv_data->lock); - platform_set_drvdata(pdev, drv_data); - - ret = qcom_llcc_cfg_program(pdev, cfg); - if (ret) - goto err; - - drv_data->ecc_irq = platform_get_irq_optional(pdev, 0); + drv_data->dev = dev; /* * On some platforms, the access to EDAC registers will be locked by @@ -5228,9 +5603,11 @@ 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); + return 0; err: drv_data = ERR_PTR(-ENODEV); @@ -5238,7 +5615,9 @@ err: } static const struct of_device_id qcom_llcc_of_match[] = { + { .compatible = "qcom,eliza-llcc", .data = &eliza_cfgs }, { .compatible = "qcom,glymur-llcc", .data = &glymur_cfgs }, + { .compatible = "qcom,hawi-llcc", .data = &hawi_sct_cfgs }, { .compatible = "qcom,ipq5424-llcc", .data = &ipq5424_cfgs}, { .compatible = "qcom,kaanapali-llcc", .data = &kaanapali_cfgs}, { .compatible = "qcom,qcs615-llcc", .data = &qcs615_cfgs}, diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index cd1779b6a91a..15636a8dc907 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -19,6 +19,8 @@ #include <linux/of_platform.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/pm_opp.h> #include <linux/soc/qcom/geni-se.h> /** @@ -280,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. @@ -582,6 +590,7 @@ static void geni_se_clks_off(struct geni_se *se) clk_disable_unprepare(se->clk); clk_bulk_disable_unprepare(wrapper->num_clks, wrapper->clks); + clk_disable_unprepare(se->core_clk); } /** @@ -618,7 +627,18 @@ static int geni_se_clks_on(struct geni_se *se) ret = clk_prepare_enable(se->clk); if (ret) - clk_bulk_disable_unprepare(wrapper->num_clks, wrapper->clks); + goto err_bulk_clks; + + ret = clk_prepare_enable(se->core_clk); + if (ret) + goto err_se_clk; + + return 0; + +err_se_clk: + clk_disable_unprepare(se->clk); +err_bulk_clks: + clk_bulk_disable_unprepare(wrapper->num_clks, wrapper->clks); return ret; } @@ -899,30 +919,32 @@ EXPORT_SYMBOL_GPL(geni_se_rx_dma_unprep); int geni_icc_get(struct geni_se *se, const char *icc_ddr) { - int i, err; - const char *icc_names[] = {"qup-core", "qup-config", icc_ddr}; + struct geni_icc_path *icc_paths = se->icc_paths; if (has_acpi_companion(se->dev)) return 0; - for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) { - if (!icc_names[i]) - continue; - - se->icc_paths[i].path = devm_of_icc_get(se->dev, icc_names[i]); - if (IS_ERR(se->icc_paths[i].path)) - goto err; + icc_paths[GENI_TO_CORE].path = devm_of_icc_get(se->dev, "qup-core"); + if (IS_ERR(icc_paths[GENI_TO_CORE].path)) + return dev_err_probe(se->dev, PTR_ERR(icc_paths[GENI_TO_CORE].path), + "Failed to get 'qup-core' ICC path\n"); + + icc_paths[CPU_TO_GENI].path = devm_of_icc_get(se->dev, "qup-config"); + if (IS_ERR(icc_paths[CPU_TO_GENI].path)) + return dev_err_probe(se->dev, PTR_ERR(icc_paths[CPU_TO_GENI].path), + "Failed to get 'qup-config' ICC path\n"); + + /* The DDR path is optional, depending on protocol and hw capabilities */ + icc_paths[GENI_TO_DDR].path = devm_of_icc_get(se->dev, "qup-memory"); + if (IS_ERR(icc_paths[GENI_TO_DDR].path)) { + if (PTR_ERR(icc_paths[GENI_TO_DDR].path) == -ENODATA) + icc_paths[GENI_TO_DDR].path = NULL; + else + return dev_err_probe(se->dev, PTR_ERR(icc_paths[GENI_TO_DDR].path), + "Failed to get 'qup-memory' ICC path\n"); } return 0; - -err: - err = PTR_ERR(se->icc_paths[i].path); - if (err != -EPROBE_DEFER) - dev_err_ratelimited(se->dev, "Failed to get ICC path '%s': %d\n", - icc_names[i], err); - return err; - } EXPORT_SYMBOL_GPL(geni_icc_get); @@ -944,6 +966,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; @@ -989,6 +1033,196 @@ 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_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. + * + * 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. + * + * 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. * @fw: Pointer to the firmware image. diff --git a/drivers/soc/qcom/qcom_pd_mapper.c b/drivers/soc/qcom/qcom_pd_mapper.c index 7bb14c20ab5d..b99718e25f2f 100644 --- a/drivers/soc/qcom/qcom_pd_mapper.c +++ b/drivers/soc/qcom/qcom_pd_mapper.c @@ -266,6 +266,12 @@ static const struct qcom_pdm_domain_data adsp_charger_pd = { .services = { NULL }, }; +static const struct qcom_pdm_domain_data adsp_ois_pd = { + .domain = "msm/adsp/ois_pd", + .instance_id = 74, + .services = { NULL, }, +}; + static const struct qcom_pdm_domain_data adsp_root_pd = { .domain = "msm/adsp/root_pd", .instance_id = 74, @@ -370,6 +376,7 @@ static const struct qcom_pdm_domain_data *glymur_domains[] = { static const struct qcom_pdm_domain_data *kaanapali_domains[] = { &adsp_audio_pd, + &adsp_ois_pd, &adsp_root_pd, &adsp_sensor_pd, &cdsp_root_pd, @@ -581,6 +588,7 @@ static const struct of_device_id qcom_pdm_domains[] __maybe_unused = { { .compatible = "qcom,eliza", .data = sm8550_domains, }, { .compatible = "qcom,apq8096", .data = msm8996_domains, }, { .compatible = "qcom,glymur", .data = glymur_domains, }, + { .compatible = "qcom,hawi", .data = kaanapali_domains, }, { .compatible = "qcom,kaanapali", .data = kaanapali_domains, }, { .compatible = "qcom,mahua", .data = glymur_domains, }, { .compatible = "qcom,milos", .data = sm8550_domains, }, diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index d5c94b47f431..afb21a778fe7 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -85,9 +85,6 @@ /* Processor/host identifier for the global partition */ #define SMEM_GLOBAL_HOST 0xfffe -/* Max number of processors/hosts in a system */ -#define SMEM_HOST_COUNT 25 - /** * struct smem_proc_comm - proc_comm communication struct (legacy) * @command: current command to be executed @@ -282,7 +279,7 @@ struct qcom_smem { struct platform_device *socinfo; struct smem_ptable *ptable; struct smem_partition global_partition; - struct smem_partition partitions[SMEM_HOST_COUNT]; + struct xarray partitions; unsigned num_regions; struct smem_region regions[] __counted_by(num_regions); @@ -382,7 +379,7 @@ static struct qcom_smem *__smem = INIT_ERR_PTR(-EPROBE_DEFER); int qcom_smem_bust_hwspin_lock_by_host(unsigned int host) { /* This function is for remote procs, so ignore SMEM_HOST_APPS */ - if (host == SMEM_HOST_APPS || host >= SMEM_HOST_COUNT) + if (host == SMEM_HOST_APPS || !xa_load(&__smem->partitions, host)) return -EINVAL; return hwspin_lock_bust(__smem->hwlock, SMEM_HOST_ID_TO_HWSPINLOCK_ID(host)); @@ -530,8 +527,8 @@ int qcom_smem_alloc(unsigned host, unsigned item, size_t size) if (ret) return ret; - if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) { - part = &__smem->partitions[host]; + part = xa_load(&__smem->partitions, host); + if (part) { ret = qcom_smem_alloc_private(__smem, part, item, size); } else if (__smem->global_partition.virt_base) { part = &__smem->global_partition; @@ -697,8 +694,8 @@ void *qcom_smem_get(unsigned host, unsigned item, size_t *size) if (item >= __smem->item_count) return ERR_PTR(-EINVAL); - if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) { - part = &__smem->partitions[host]; + part = xa_load(&__smem->partitions, host); + if (part) { ptr = qcom_smem_get_private(__smem, part, item, size); } else if (__smem->global_partition.virt_base) { part = &__smem->global_partition; @@ -730,8 +727,8 @@ int qcom_smem_get_free_space(unsigned host) if (IS_ERR(__smem)) return PTR_ERR(__smem); - if (host < SMEM_HOST_COUNT && __smem->partitions[host].virt_base) { - part = &__smem->partitions[host]; + part = xa_load(&__smem->partitions, host); + if (part) { phdr = part->virt_base; ret = le32_to_cpu(phdr->offset_free_cached) - le32_to_cpu(phdr->offset_free_uncached); @@ -774,12 +771,11 @@ phys_addr_t qcom_smem_virt_to_phys(void *p) { struct smem_partition *part; struct smem_region *area; + unsigned long index; u64 offset; u32 i; - for (i = 0; i < SMEM_HOST_COUNT; i++) { - part = &__smem->partitions[i]; - + xa_for_each(&__smem->partitions, index, part) { if (addr_in_range(part->virt_base, part->size, p)) { offset = p - part->virt_base; @@ -1016,16 +1012,20 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host) { struct smem_partition_header *header; + struct smem_partition *part; struct smem_ptable_entry *entry; struct smem_ptable *ptable; u16 remote_host; u16 host0, host1; + int ret; int i; ptable = qcom_smem_get_ptable(smem); if (IS_ERR(ptable)) return PTR_ERR(ptable); + xa_init(&smem->partitions); + for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) { entry = &ptable->entry[i]; if (!le32_to_cpu(entry->offset)) @@ -1042,12 +1042,7 @@ qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host) else continue; - if (remote_host >= SMEM_HOST_COUNT) { - dev_err(smem->dev, "bad host %u\n", remote_host); - return -EINVAL; - } - - if (smem->partitions[remote_host].virt_base) { + if (xa_load(&smem->partitions, remote_host)) { dev_err(smem->dev, "duplicate host %u\n", remote_host); return -EINVAL; } @@ -1056,11 +1051,20 @@ qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host) if (!header) return -EINVAL; - smem->partitions[remote_host].virt_base = (void __iomem *)header; - smem->partitions[remote_host].phys_base = smem->regions[0].aux_base + - le32_to_cpu(entry->offset); - smem->partitions[remote_host].size = le32_to_cpu(entry->size); - smem->partitions[remote_host].cacheline = le32_to_cpu(entry->cacheline); + part = devm_kzalloc(smem->dev, sizeof(struct smem_partition), GFP_KERNEL); + if (!part) + return -ENOMEM; + + part->virt_base = (void __iomem *)header; + part->phys_base = smem->regions[0].aux_base + le32_to_cpu(entry->offset); + part->size = le32_to_cpu(entry->size); + part->cacheline = le32_to_cpu(entry->cacheline); + + ret = xa_insert(&smem->partitions, remote_host, part, GFP_KERNEL); + if (ret) { + dev_err(smem->dev, "fail to insert host %u\n", remote_host); + return ret; + } } return 0; @@ -1229,7 +1233,6 @@ static int qcom_smem_probe(struct platform_device *pdev) return -EINVAL; } - BUILD_BUG_ON(SMEM_HOST_APPS >= SMEM_HOST_COUNT); ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS); if (ret < 0 && ret != -ENOENT) return ret; @@ -1249,6 +1252,7 @@ static void qcom_smem_remove(struct platform_device *pdev) { platform_device_unregister(__smem->socinfo); + xa_destroy(&__smem->partitions); /* Set to -EPROBE_DEFER to signal unprobed state */ __smem = ERR_PTR(-EPROBE_DEFER); } diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 8ffd903ebddb..af418adad7aa 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -188,7 +188,19 @@ static const char *const pmic_models[] = { [80] = "PM7550", [82] = "PMC8380", [83] = "SMB2360", + [86] = "PM8750B", + [87] = "PMD8028", + [88] = "PMC1020H", + [89] = "PMIV0104", + [90] = "PMIV0102", [91] = "PMIV0108", + [92] = "PMK8850", + [93] = "PMH0101", + [94] = "PMAU0102", + [95] = "SMB2370", + [96] = "PMH0104", + [97] = "PMH0110", + [98] = "PMCX0102", }; struct socinfo_params { @@ -519,6 +531,7 @@ static const struct soc_id soc_id[] = { { qcom_board_id(IPQ5424) }, { qcom_board_id(QCM6690) }, { qcom_board_id(QCS6690) }, + { qcom_board_id(SM7750) }, { qcom_board_id(SM8850) }, { qcom_board_id(IPQ5404) }, { qcom_board_id(QCS9100) }, @@ -526,13 +539,23 @@ static const struct soc_id soc_id[] = { { qcom_board_id(QCS8275) }, { qcom_board_id(QCS9075) }, { qcom_board_id(QCS615) }, + { qcom_board_id(SA8797P) }, { qcom_board_id(CQ7790M) }, { qcom_board_id(CQ7790S) }, + { qcom_board_id(CQ2390M) }, + { qcom_board_id(CQ2390S) }, + { qcom_board_id(IQ2390S) }, { qcom_board_id(IPQ5200) }, { qcom_board_id(IPQ5210) }, { qcom_board_id(QCF2200) }, { qcom_board_id(QCF3200) }, { qcom_board_id(QCF3210) }, + { qcom_board_id(IPQ9620) }, + { qcom_board_id(IPQ9650) }, + { qcom_board_id(IPQ9610) }, + { qcom_board_id(IPQ9630) }, + { qcom_board_id(IPQ9640) }, + { qcom_board_id(IPQ9670) }, }; static const char *socinfo_machine(struct device *dev, unsigned int id) diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c index ffb31a049d4a..942e11feba65 100644 --- a/drivers/soc/qcom/wcnss_ctrl.c +++ b/drivers/soc/qcom/wcnss_ctrl.c @@ -221,8 +221,10 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc) left = fw->size; req = kzalloc_flex(*req, fragment, NV_FRAGMENT_SIZE); - if (!req) - return -ENOMEM; + if (!req) { + ret = -ENOMEM; + goto release_fw; + } req->frag_size = NV_FRAGMENT_SIZE; req->hdr.type = WCNSS_DOWNLOAD_NV_REQ; @@ -243,7 +245,7 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc) ret = rpmsg_send(wcnss->channel, req, req->hdr.len); if (ret < 0) { dev_err(dev, "failed to send smd packet\n"); - goto release_fw; + goto release_req; } /* Increment for next fragment */ @@ -262,9 +264,10 @@ static int wcnss_download_nv(struct wcnss_ctrl *wcnss, bool *expect_cbc) ret = 0; } +release_req: + kfree(req); release_fw: release_firmware(fw); - kfree(req); return ret; } diff --git a/include/dt-bindings/arm/qcom,ids.h b/include/dt-bindings/arm/qcom,ids.h index 336f7bb7188a..1af73c0ad41c 100644 --- a/include/dt-bindings/arm/qcom,ids.h +++ b/include/dt-bindings/arm/qcom,ids.h @@ -290,6 +290,7 @@ #define QCOM_ID_IPQ5424 651 #define QCOM_ID_QCM6690 657 #define QCOM_ID_QCS6690 658 +#define QCOM_ID_SM7750 659 #define QCOM_ID_SM8850 660 #define QCOM_ID_IPQ5404 671 #define QCOM_ID_QCS9100 667 @@ -297,13 +298,23 @@ #define QCOM_ID_QCS8275 675 #define QCOM_ID_QCS9075 676 #define QCOM_ID_QCS615 680 +#define QCOM_ID_SA8797P 690 #define QCOM_ID_CQ7790M 731 #define QCOM_ID_CQ7790S 732 +#define QCOM_ID_CQ2390M 756 +#define QCOM_ID_CQ2390S 758 +#define QCOM_ID_IQ2390S 759 #define QCOM_ID_IPQ5200 765 #define QCOM_ID_IPQ5210 766 #define QCOM_ID_QCF2200 767 #define QCOM_ID_QCF3200 768 #define QCOM_ID_QCF3210 769 +#define QCOM_ID_IPQ9620 770 +#define QCOM_ID_IPQ9650 771 +#define QCOM_ID_IPQ9610 778 +#define QCOM_ID_IPQ9630 779 +#define QCOM_ID_IPQ9640 780 +#define QCOM_ID_IPQ9670 781 /* * The board type and revision information, used by Qualcomm bootloaders and diff --git a/include/linux/soc/qcom/geni-se.h b/include/linux/soc/qcom/geni-se.h index 0a984e2579fe..c5e6ab85df09 100644 --- a/include/linux/soc/qcom/geni-se.h +++ b/include/linux/soc/qcom/geni-se.h @@ -60,18 +60,24 @@ 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 + * @pd_list: Power domain list for managing power domains + * @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]; + struct dev_pm_domain_list *pd_list; + bool has_opp; }; /* Common SE registers */ @@ -528,12 +534,25 @@ 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); 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); + +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 diff --git a/include/linux/soc/qcom/llcc-qcom.h b/include/linux/soc/qcom/llcc-qcom.h index 227125d84318..f3ed63e475ab 100644 --- a/include/linux/soc/qcom/llcc-qcom.h +++ b/include/linux/soc/qcom/llcc-qcom.h @@ -89,18 +89,20 @@ /** * struct llcc_slice_desc - Cache slice descriptor - * @slice_id: llcc slice id - * @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 { u32 slice_id; + u32 uid; size_t slice_size; refcount_t refcount; }; /** - * 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 @@ -146,21 +148,23 @@ 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 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 - * @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; @@ -177,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 descritpor - * @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); diff --git a/include/linux/soc/qcom/ubwc.h b/include/linux/soc/qcom/ubwc.h index f5d0e2341261..83d2c2a7116c 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 @@ -99,4 +100,25 @@ 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; +} + +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__ */ diff --git a/include/soc/qcom/qcom-spmi-pmic.h b/include/soc/qcom/qcom-spmi-pmic.h index 2cf9e2d8cd55..997fa18d70fe 100644 --- a/include/soc/qcom/qcom-spmi-pmic.h +++ b/include/soc/qcom/qcom-spmi-pmic.h @@ -50,9 +50,22 @@ #define PMR735B_SUBTYPE 0x34 #define PM6350_SUBTYPE 0x36 #define PM4125_SUBTYPE 0x37 +#define PM8010_SUBTYPE 0x41 +#define PM8550VS_SUBTYPE 0x45 +#define PM8550VE_SUBTYPE 0x46 +#define PMR735D_SUBTYPE 0x48 +#define PM8550_SUBTYPE 0x49 +#define PMK8550_SUBTYPE 0x4a #define PMM8650AU_SUBTYPE 0x4e #define PMM8650AU_PSAIL_SUBTYPE 0x4f - +#define PM8750B_SUBTYPE 0x56 +#define PMD8028_SUBTYPE 0x57 +#define PMK8850_SUBTYPE 0x5c +#define PMH0101_SUBTYPE 0x5d +#define SMB2370_SUBTYPE 0x5f +#define PMH0104_SUBTYPE 0x60 +#define PMH0110_SUBTYPE 0x61 +#define PMCX0102_SUBTYPE 0x62 #define PMI8998_FAB_ID_SMIC 0x11 #define PMI8998_FAB_ID_GF 0x30 |
