summaryrefslogtreecommitdiff
path: root/drivers/soc/qcom
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc/qcom')
-rw-r--r--drivers/soc/qcom/Kconfig8
-rw-r--r--drivers/soc/qcom/Makefile1
-rw-r--r--drivers/soc/qcom/llcc-qcom.c497
-rw-r--r--drivers/soc/qcom/mdt_loader.c63
-rw-r--r--drivers/soc/qcom/pmic_glink.c13
-rw-r--r--drivers/soc/qcom/pmic_glink_altmode.c30
-rw-r--r--drivers/soc/qcom/qcom-geni-se.c13
-rw-r--r--drivers/soc/qcom/qcom_pd_mapper.c11
-rw-r--r--drivers/soc/qcom/qcom_stats.c133
-rw-r--r--drivers/soc/qcom/qmi_encdec.c52
-rw-r--r--drivers/soc/qcom/qmi_interface.c6
-rw-r--r--drivers/soc/qcom/rpmh-rsc.c2
-rw-r--r--drivers/soc/qcom/smem.c2
-rw-r--r--drivers/soc/qcom/smp2p.c2
-rw-r--r--drivers/soc/qcom/socinfo.c14
-rw-r--r--drivers/soc/qcom/ubwc_config.c282
16 files changed, 1075 insertions, 54 deletions
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 58e63cf0036b..2caadbbcf830 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -296,3 +296,11 @@ config QCOM_PBS
PBS trigger event to the PBS RAM.
endmenu
+
+config QCOM_UBWC_CONFIG
+ tristate
+ help
+ Most Qualcomm SoCs feature a number of Universal Bandwidth Compression
+ (UBWC) engines across various IP blocks, which need to be initialized
+ with coherent configuration data. This module functions as a single
+ source of truth for that information.
diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile
index acbca2ab5cc2..b7f1d2a57367 100644
--- a/drivers/soc/qcom/Makefile
+++ b/drivers/soc/qcom/Makefile
@@ -39,3 +39,4 @@ obj-$(CONFIG_QCOM_ICC_BWMON) += icc-bwmon.o
qcom_ice-objs += ice.o
obj-$(CONFIG_QCOM_INLINE_CRYPTO_ENGINE) += qcom_ice.o
obj-$(CONFIG_QCOM_PBS) += qcom-pbs.o
+obj-$(CONFIG_QCOM_UBWC_CONFIG) += ubwc_config.o
diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c
index 56823b6a2fac..192edc3f64dc 100644
--- a/drivers/soc/qcom/llcc-qcom.c
+++ b/drivers/soc/qcom/llcc-qcom.c
@@ -35,6 +35,11 @@
#define ATTR0_RES_WAYS_MASK GENMASK(15, 0)
#define ATTR0_BONUS_WAYS_MASK GENMASK(31, 16)
#define ATTR0_BONUS_WAYS_SHIFT 16
+#define ATTR2_PROBE_TARGET_WAYS_MASK BIT(4)
+#define ATTR2_FIXED_SIZE_MASK BIT(8)
+#define ATTR2_PRIORITY_MASK GENMASK(14, 12)
+#define ATTR2_PARENT_SCID_MASK GENMASK(21, 16)
+#define ATTR2_IN_A_GROUP_MASK BIT(24)
#define LLCC_STATUS_READ_DELAY 100
#define CACHE_LINE_SIZE_SHIFT 6
@@ -49,6 +54,10 @@
#define LLCC_TRP_ATTR0_CFGn(n) (0x21000 + SZ_8 * n)
#define LLCC_TRP_ATTR1_CFGn(n) (0x21004 + SZ_8 * n)
#define LLCC_TRP_ATTR2_CFGn(n) (0x21100 + SZ_4 * n)
+#define LLCC_V6_TRP_ATTR0_CFGn(n) (cfg->reg_offset[LLCC_TRP_ATTR0_CFG] + SZ_64 * (n))
+#define LLCC_V6_TRP_ATTR1_CFGn(n) (cfg->reg_offset[LLCC_TRP_ATTR1_CFG] + SZ_64 * (n))
+#define LLCC_V6_TRP_ATTR2_CFGn(n) (cfg->reg_offset[LLCC_TRP_ATTR2_CFG] + SZ_64 * (n))
+#define LLCC_V6_TRP_ATTR3_CFGn(n) (cfg->reg_offset[LLCC_TRP_ATTR3_CFG] + SZ_64 * (n))
#define LLCC_TRP_SCID_DIS_CAP_ALLOC 0x21f00
#define LLCC_TRP_PCB_ACT 0x21f04
@@ -66,6 +75,7 @@
#define LLCC_VERSION_2_0_0_0 0x02000000
#define LLCC_VERSION_2_1_0_0 0x02010000
#define LLCC_VERSION_4_1_0_0 0x04010000
+#define LLCC_VERSION_6_0_0_0 0X06000000
/**
* struct llcc_slice_config - Data associated with the llcc slice
@@ -106,6 +116,7 @@
* ovcap_en.
* @vict_prio: When current scid is under-capacity, allocate over other
* lower-than victim priority-line threshold scid.
+ * @parent_slice_id: For grouped slices, specifies the slice id of the parent.
*/
struct llcc_slice_config {
u32 usecase_id;
@@ -130,6 +141,7 @@ struct llcc_slice_config {
bool ovcap_en;
bool ovcap_prio;
bool vict_prio;
+ u32 parent_slice_id;
};
struct qcom_llcc_config {
@@ -153,6 +165,21 @@ struct qcom_sct_config {
enum llcc_reg_offset {
LLCC_COMMON_HW_INFO,
LLCC_COMMON_STATUS0,
+ LLCC_TRP_ATTR0_CFG,
+ LLCC_TRP_ATTR1_CFG,
+ LLCC_TRP_ATTR2_CFG,
+ LLCC_TRP_ATTR3_CFG,
+ LLCC_TRP_SID_DIS_CAP_ALLOC,
+ LLCC_TRP_ALGO_STALE_EN,
+ LLCC_TRP_ALGO_STALE_CAP_EN,
+ LLCC_TRP_ALGO_MRU0,
+ LLCC_TRP_ALGO_MRU1,
+ LLCC_TRP_ALGO_ALLOC0,
+ LLCC_TRP_ALGO_ALLOC1,
+ LLCC_TRP_ALGO_ALLOC2,
+ LLCC_TRP_ALGO_ALLOC3,
+ LLCC_TRP_WRS_EN,
+ LLCC_TRP_WRS_CACHEABLE_EN,
};
static const struct llcc_slice_config ipq5424_data[] = {
@@ -2662,6 +2689,263 @@ static const struct llcc_slice_config sm8650_data[] = {
},
};
+static const struct llcc_slice_config sm8750_data[] = {
+ {
+ .usecase_id = LLCC_CPUSS,
+ .slice_id = 1,
+ .max_cap = 5120,
+ .priority = 1,
+ .bonus_ways = 0xffffffff,
+ .activate_on_init = true,
+ .write_scid_en = true,
+ }, {
+ .usecase_id = LLCC_MDMHPFX,
+ .slice_id = 24,
+ .max_cap = 1024,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_VIDSC0,
+ .slice_id = 2,
+ .max_cap = 512,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_AUDIO,
+ .slice_id = 35,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_MDMHPGRW,
+ .slice_id = 25,
+ .max_cap = 1024,
+ .priority = 5,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_MODHW,
+ .slice_id = 26,
+ .max_cap = 1024,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_CMPT,
+ .slice_id = 34,
+ .max_cap = 4096,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_GPUHTW,
+ .slice_id = 11,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_GPU,
+ .slice_id = 9,
+ .max_cap = 5632,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .write_scid_en = true,
+ .write_scid_cacheable_en = true
+ }, {
+ .usecase_id = LLCC_MMUHWT,
+ .slice_id = 18,
+ .max_cap = 768,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_DISP,
+ .slice_id = 16,
+ .max_cap = 7168,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .cache_mode = 2,
+ .stale_en = true,
+ }, {
+ .usecase_id = LLCC_VIDFW,
+ .slice_id = 17,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_CAMFW,
+ .slice_id = 20,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_MDMPNG,
+ .slice_id = 27,
+ .max_cap = 256,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xf0000000,
+ }, {
+ .usecase_id = LLCC_AUDHW,
+ .slice_id = 22,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_CVP,
+ .slice_id = 8,
+ .max_cap = 800,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .vict_prio = true,
+ }, {
+ .usecase_id = LLCC_MODPE,
+ .slice_id = 29,
+ .max_cap = 256,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xf0000000,
+ .alloc_oneway_en = true,
+ }, {
+ .usecase_id = LLCC_WRCACHE,
+ .slice_id = 31,
+ .max_cap = 512,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .activate_on_init = true,
+ }, {
+ .usecase_id = LLCC_CVPFW,
+ .slice_id = 19,
+ .max_cap = 64,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_CMPTHCP,
+ .slice_id = 15,
+ .max_cap = 256,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_LCPDARE,
+ .slice_id = 30,
+ .max_cap = 128,
+ .priority = 5,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .activate_on_init = true,
+ .alloc_oneway_en = true,
+ }, {
+ .usecase_id = LLCC_AENPU,
+ .slice_id = 3,
+ .max_cap = 3072,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .cache_mode = 2,
+ }, {
+ .usecase_id = LLCC_ISLAND1,
+ .slice_id = 12,
+ .max_cap = 7936,
+ .priority = 7,
+ .fixed_size = true,
+ .bonus_ways = 0x7fffffff,
+ }, {
+ .usecase_id = LLCC_DISP_WB,
+ .slice_id = 23,
+ .max_cap = 512,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_VIDVSP,
+ .slice_id = 4,
+ .max_cap = 256,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ }, {
+ .usecase_id = LLCC_VIDDEC,
+ .slice_id = 5,
+ .max_cap = 6144,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .cache_mode = 2,
+ .ovcap_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CAMOFE,
+ .slice_id = 33,
+ .max_cap = 6144,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .stale_en = true,
+ .ovcap_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CAMRTIP,
+ .slice_id = 13,
+ .max_cap = 1024,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .stale_en = true,
+ .ovcap_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CAMSRTIP,
+ .slice_id = 14,
+ .max_cap = 6144,
+ .priority = 4,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .stale_en = true,
+ .ovcap_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CAMRTRF,
+ .slice_id = 7,
+ .max_cap = 3584,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .stale_en = true,
+ .ovcap_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CAMSRTRF,
+ .slice_id = 21,
+ .max_cap = 6144,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .stale_en = true,
+ .ovcap_prio = true,
+ .parent_slice_id = 33,
+ }, {
+ .usecase_id = LLCC_CPUSSMPAM,
+ .slice_id = 6,
+ .max_cap = 2048,
+ .priority = 1,
+ .fixed_size = true,
+ .bonus_ways = 0xffffffff,
+ .activate_on_init = true,
+ .write_scid_en = true,
+ },
+};
+
static const struct llcc_slice_config qcs615_data[] = {
{
.usecase_id = LLCC_CPUSS,
@@ -3161,6 +3445,33 @@ static const struct llcc_edac_reg_offset llcc_v2_1_edac_reg_offset = {
.drp_ecc_db_err_syn0 = 0x52120,
};
+static const struct llcc_edac_reg_offset llcc_v6_edac_reg_offset = {
+ .trp_ecc_error_status0 = 0x47448,
+ .trp_ecc_error_status1 = 0x47450,
+ .trp_ecc_sb_err_syn0 = 0x47490,
+ .trp_ecc_db_err_syn0 = 0x474d0,
+ .trp_ecc_error_cntr_clear = 0x47444,
+ .trp_interrupt_0_status = 0x47600,
+ .trp_interrupt_0_clear = 0x47604,
+ .trp_interrupt_0_enable = 0x47608,
+
+ /* LLCC Common registers */
+ .cmn_status0 = 0x6400c,
+ .cmn_interrupt_0_enable = 0x6401c,
+ .cmn_interrupt_2_enable = 0x6403c,
+
+ /* LLCC DRP registers */
+ .drp_ecc_error_cfg = 0x80000,
+ .drp_ecc_error_cntr_clear = 0x80004,
+ .drp_interrupt_status = 0x80020,
+ .drp_interrupt_clear = 0x80028,
+ .drp_interrupt_enable = 0x8002c,
+ .drp_ecc_error_status0 = 0x820f4,
+ .drp_ecc_error_status1 = 0x820f8,
+ .drp_ecc_sb_err_syn0 = 0x820fc,
+ .drp_ecc_db_err_syn0 = 0x82120,
+};
+
/* LLCC register offset starting from v1.0.0 */
static const u32 llcc_v1_reg_offset[] = {
[LLCC_COMMON_HW_INFO] = 0x00030000,
@@ -3173,6 +3484,27 @@ static const u32 llcc_v2_1_reg_offset[] = {
[LLCC_COMMON_STATUS0] = 0x0003400c,
};
+/* LLCC register offset starting from v6.0.0 */
+static const u32 llcc_v6_reg_offset[] = {
+ [LLCC_COMMON_HW_INFO] = 0x00064000,
+ [LLCC_COMMON_STATUS0] = 0x0006400c,
+ [LLCC_TRP_ATTR0_CFG] = 0x00041000,
+ [LLCC_TRP_ATTR1_CFG] = 0x00041008,
+ [LLCC_TRP_ATTR2_CFG] = 0x00041010,
+ [LLCC_TRP_ATTR3_CFG] = 0x00041014,
+ [LLCC_TRP_SID_DIS_CAP_ALLOC] = 0x00042000,
+ [LLCC_TRP_ALGO_STALE_EN] = 0x00042008,
+ [LLCC_TRP_ALGO_STALE_CAP_EN] = 0x00042010,
+ [LLCC_TRP_ALGO_MRU0] = 0x00042018,
+ [LLCC_TRP_ALGO_MRU1] = 0x00042020,
+ [LLCC_TRP_ALGO_ALLOC0] = 0x00042028,
+ [LLCC_TRP_ALGO_ALLOC1] = 0x00042030,
+ [LLCC_TRP_ALGO_ALLOC2] = 0x00042038,
+ [LLCC_TRP_ALGO_ALLOC3] = 0x00042040,
+ [LLCC_TRP_WRS_EN] = 0x00042080,
+ [LLCC_TRP_WRS_CACHEABLE_EN] = 0x00042088,
+};
+
static const struct qcom_llcc_config qcs615_cfg[] = {
{
.sct_data = qcs615_data,
@@ -3379,6 +3711,16 @@ static const struct qcom_llcc_config sm8650_cfg[] = {
},
};
+static const struct qcom_llcc_config sm8750_cfg[] = {
+ {
+ .sct_data = sm8750_data,
+ .size = ARRAY_SIZE(sm8750_data),
+ .skip_llcc_cfg = false,
+ .reg_offset = llcc_v6_reg_offset,
+ .edac_reg_offset = &llcc_v6_edac_reg_offset,
+ },
+};
+
static const struct qcom_llcc_config x1e80100_cfg[] = {
{
.sct_data = x1e80100_data,
@@ -3489,6 +3831,11 @@ static const struct qcom_sct_config sm8650_cfgs = {
.num_config = ARRAY_SIZE(sm8650_cfg),
};
+static const struct qcom_sct_config sm8750_cfgs = {
+ .llcc_config = sm8750_cfg,
+ .num_config = ARRAY_SIZE(sm8750_cfg),
+};
+
static const struct qcom_sct_config x1e80100_cfgs = {
.llcc_config = x1e80100_cfg,
.num_config = ARRAY_SIZE(x1e80100_cfg),
@@ -3869,6 +4216,139 @@ static int _qcom_llcc_cfg_program(const struct llcc_slice_config *config,
return ret;
}
+static int _qcom_llcc_cfg_program_v6(const struct llcc_slice_config *config,
+ const struct qcom_llcc_config *cfg)
+{
+ u32 stale_en, stale_cap_en, mru_uncap_en, mru_rollover;
+ u32 alloc_oneway_en, ovcap_en, ovcap_prio, vict_prio;
+ u32 attr0_cfg, attr1_cfg, attr2_cfg, attr3_cfg;
+ u32 attr0_val, attr1_val, attr2_val, attr3_val;
+ u32 slice_offset, reg_offset;
+ struct llcc_slice_desc *desc;
+ u32 wren, wr_cache_en;
+ int ret;
+
+ attr0_cfg = LLCC_V6_TRP_ATTR0_CFGn(config->slice_id);
+ attr1_cfg = LLCC_V6_TRP_ATTR1_CFGn(config->slice_id);
+ attr2_cfg = LLCC_V6_TRP_ATTR2_CFGn(config->slice_id);
+ attr3_cfg = LLCC_V6_TRP_ATTR3_CFGn(config->slice_id);
+
+ attr0_val = config->res_ways;
+ attr1_val = config->bonus_ways;
+ attr2_val = config->cache_mode;
+ attr2_val |= FIELD_PREP(ATTR2_PROBE_TARGET_WAYS_MASK, config->probe_target_ways);
+ attr2_val |= FIELD_PREP(ATTR2_FIXED_SIZE_MASK, config->fixed_size);
+ attr2_val |= FIELD_PREP(ATTR2_PRIORITY_MASK, config->priority);
+
+ if (config->parent_slice_id && config->fixed_size) {
+ attr2_val |= FIELD_PREP(ATTR2_PARENT_SCID_MASK, config->parent_slice_id);
+ attr2_val |= ATTR2_IN_A_GROUP_MASK;
+ }
+
+ attr3_val = MAX_CAP_TO_BYTES(config->max_cap);
+ attr3_val /= drv_data->num_banks;
+ attr3_val >>= CACHE_LINE_SIZE_SHIFT;
+
+ ret = regmap_write(drv_data->bcast_regmap, attr0_cfg, attr0_val);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(drv_data->bcast_regmap, attr1_cfg, attr1_val);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(drv_data->bcast_regmap, attr2_cfg, attr2_val);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(drv_data->bcast_regmap, attr3_cfg, attr3_val);
+ if (ret)
+ return ret;
+
+ slice_offset = config->slice_id % 32;
+ reg_offset = (config->slice_id / 32) * 4;
+
+ wren = config->write_scid_en << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_WRS_EN] + reg_offset,
+ BIT(slice_offset), wren);
+ if (ret)
+ return ret;
+
+ wr_cache_en = config->write_scid_cacheable_en << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_WRS_CACHEABLE_EN] + reg_offset,
+ BIT(slice_offset), wr_cache_en);
+ if (ret)
+ return ret;
+
+ stale_en = config->stale_en << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_ALGO_STALE_EN] + reg_offset,
+ BIT(slice_offset), stale_en);
+ if (ret)
+ return ret;
+
+ stale_cap_en = config->stale_cap_en << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_ALGO_STALE_CAP_EN] + reg_offset,
+ BIT(slice_offset), stale_cap_en);
+ if (ret)
+ return ret;
+
+ mru_uncap_en = config->mru_uncap_en << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_ALGO_MRU0] + reg_offset,
+ BIT(slice_offset), mru_uncap_en);
+ if (ret)
+ return ret;
+
+ mru_rollover = config->mru_rollover << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_ALGO_MRU1] + reg_offset,
+ BIT(slice_offset), mru_rollover);
+ if (ret)
+ return ret;
+
+ alloc_oneway_en = config->alloc_oneway_en << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_ALGO_ALLOC0] + reg_offset,
+ BIT(slice_offset), alloc_oneway_en);
+ if (ret)
+ return ret;
+
+ ovcap_en = config->ovcap_en << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_ALGO_ALLOC1] + reg_offset,
+ BIT(slice_offset), ovcap_en);
+ if (ret)
+ return ret;
+
+ ovcap_prio = config->ovcap_prio << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_ALGO_ALLOC2] + reg_offset,
+ BIT(slice_offset), ovcap_prio);
+ if (ret)
+ return ret;
+
+ vict_prio = config->vict_prio << slice_offset;
+ ret = regmap_update_bits(drv_data->bcast_regmap,
+ cfg->reg_offset[LLCC_TRP_ALGO_ALLOC3] + reg_offset,
+ BIT(slice_offset), vict_prio);
+ if (ret)
+ return ret;
+
+ if (config->activate_on_init) {
+ desc = llcc_slice_getd(config->usecase_id);
+ if (PTR_ERR_OR_ZERO(desc))
+ return -EINVAL;
+
+ ret = llcc_slice_activate(desc);
+ }
+
+ return ret;
+}
+
static int qcom_llcc_cfg_program(struct platform_device *pdev,
const struct qcom_llcc_config *cfg)
{
@@ -3880,10 +4360,18 @@ 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++) {
- ret = _qcom_llcc_cfg_program(&llcc_table[i], cfg);
- if (ret)
- return ret;
+ 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);
+ if (ret)
+ return ret;
+ }
+ } else {
+ for (i = 0; i < sz; i++) {
+ ret = _qcom_llcc_cfg_program(&llcc_table[i], cfg);
+ if (ret)
+ return ret;
+ }
}
return ret;
@@ -4102,6 +4590,7 @@ static const struct of_device_id qcom_llcc_of_match[] = {
{ .compatible = "qcom,sm8450-llcc", .data = &sm8450_cfgs },
{ .compatible = "qcom,sm8550-llcc", .data = &sm8550_cfgs },
{ .compatible = "qcom,sm8650-llcc", .data = &sm8650_cfgs },
+ { .compatible = "qcom,sm8750-llcc", .data = &sm8750_cfgs },
{ .compatible = "qcom,x1e80100-llcc", .data = &x1e80100_cfgs },
{ }
};
diff --git a/drivers/soc/qcom/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c
index b2c0fb55d4ae..0ca268bdf1f8 100644
--- a/drivers/soc/qcom/mdt_loader.c
+++ b/drivers/soc/qcom/mdt_loader.c
@@ -18,7 +18,38 @@
#include <linux/slab.h>
#include <linux/soc/qcom/mdt_loader.h>
-static bool mdt_phdr_valid(const struct elf32_phdr *phdr)
+static bool mdt_header_valid(const struct firmware *fw)
+{
+ const struct elf32_hdr *ehdr;
+ size_t phend;
+ size_t shend;
+
+ if (fw->size < sizeof(*ehdr))
+ return false;
+
+ ehdr = (struct elf32_hdr *)fw->data;
+
+ if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG))
+ return false;
+
+ if (ehdr->e_phentsize != sizeof(struct elf32_phdr))
+ return false;
+
+ phend = size_add(size_mul(sizeof(struct elf32_phdr), ehdr->e_phnum), ehdr->e_phoff);
+ if (phend > fw->size)
+ return false;
+
+ if (ehdr->e_shentsize != sizeof(struct elf32_shdr))
+ return false;
+
+ shend = size_add(size_mul(sizeof(struct elf32_shdr), ehdr->e_shnum), ehdr->e_shoff);
+ if (shend > fw->size)
+ return false;
+
+ return true;
+}
+
+static bool mdt_phdr_loadable(const struct elf32_phdr *phdr)
{
if (phdr->p_type != PT_LOAD)
return false;
@@ -82,13 +113,16 @@ ssize_t qcom_mdt_get_size(const struct firmware *fw)
phys_addr_t max_addr = 0;
int i;
+ if (!mdt_header_valid(fw))
+ return -EINVAL;
+
ehdr = (struct elf32_hdr *)fw->data;
- phdrs = (struct elf32_phdr *)(ehdr + 1);
+ phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff);
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
- if (!mdt_phdr_valid(phdr))
+ if (!mdt_phdr_loadable(phdr))
continue;
if (phdr->p_paddr < min_addr)
@@ -134,8 +168,11 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len,
ssize_t ret;
void *data;
+ if (!mdt_header_valid(fw))
+ return ERR_PTR(-EINVAL);
+
ehdr = (struct elf32_hdr *)fw->data;
- phdrs = (struct elf32_phdr *)(ehdr + 1);
+ phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff);
if (ehdr->e_phnum < 2)
return ERR_PTR(-EINVAL);
@@ -214,13 +251,16 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw,
int ret;
int i;
+ if (!mdt_header_valid(fw))
+ return -EINVAL;
+
ehdr = (struct elf32_hdr *)fw->data;
- phdrs = (struct elf32_phdr *)(ehdr + 1);
+ phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff);
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
- if (!mdt_phdr_valid(phdr))
+ if (!mdt_phdr_loadable(phdr))
continue;
if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
@@ -270,7 +310,7 @@ static bool qcom_mdt_bins_are_split(const struct firmware *fw, const char *fw_na
int i;
ehdr = (struct elf32_hdr *)fw->data;
- phdrs = (struct elf32_phdr *)(ehdr + 1);
+ phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff);
for (i = 0; i < ehdr->e_phnum; i++) {
/*
@@ -310,14 +350,17 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
if (!fw || !mem_region || !mem_phys || !mem_size)
return -EINVAL;
+ if (!mdt_header_valid(fw))
+ return -EINVAL;
+
is_split = qcom_mdt_bins_are_split(fw, fw_name);
ehdr = (struct elf32_hdr *)fw->data;
- phdrs = (struct elf32_phdr *)(ehdr + 1);
+ phdrs = (struct elf32_phdr *)(fw->data + ehdr->e_phoff);
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
- if (!mdt_phdr_valid(phdr))
+ if (!mdt_phdr_loadable(phdr))
continue;
if (phdr->p_flags & QCOM_MDT_RELOCATABLE)
@@ -344,7 +387,7 @@ static int __qcom_mdt_load(struct device *dev, const struct firmware *fw,
for (i = 0; i < ehdr->e_phnum; i++) {
phdr = &phdrs[i];
- if (!mdt_phdr_valid(phdr))
+ if (!mdt_phdr_loadable(phdr))
continue;
offset = phdr->p_paddr - mem_reloc;
diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c
index cde19cdfd3c7..c0a4be5df926 100644
--- a/drivers/soc/qcom/pmic_glink.c
+++ b/drivers/soc/qcom/pmic_glink.c
@@ -167,7 +167,10 @@ static int pmic_glink_rpmsg_callback(struct rpmsg_device *rpdev, void *data,
return 0;
}
-static void pmic_glink_aux_release(struct device *dev) {}
+static void pmic_glink_aux_release(struct device *dev)
+{
+ of_node_put(dev->of_node);
+}
static int pmic_glink_add_aux_device(struct pmic_glink *pg,
struct auxiliary_device *aux,
@@ -181,8 +184,10 @@ static int pmic_glink_add_aux_device(struct pmic_glink *pg,
aux->dev.release = pmic_glink_aux_release;
device_set_of_node_from_dev(&aux->dev, parent);
ret = auxiliary_device_init(aux);
- if (ret)
+ if (ret) {
+ of_node_put(aux->dev.of_node);
return ret;
+ }
ret = auxiliary_device_add(aux);
if (ret)
@@ -371,15 +376,11 @@ static void pmic_glink_remove(struct platform_device *pdev)
__pmic_glink = NULL;
}
-static const unsigned long pmic_glink_sc8280xp_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) |
- BIT(PMIC_GLINK_CLIENT_ALTMODE);
-
static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) |
BIT(PMIC_GLINK_CLIENT_ALTMODE) |
BIT(PMIC_GLINK_CLIENT_UCSI);
static const struct of_device_id pmic_glink_of_match[] = {
- { .compatible = "qcom,sc8280xp-pmic-glink", .data = &pmic_glink_sc8280xp_client_mask },
{ .compatible = "qcom,pmic-glink", .data = &pmic_glink_sm8450_client_mask },
{}
};
diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c
index bd06ce161804..7f11acd33323 100644
--- a/drivers/soc/qcom/pmic_glink_altmode.c
+++ b/drivers/soc/qcom/pmic_glink_altmode.c
@@ -218,21 +218,29 @@ static void pmic_glink_altmode_worker(struct work_struct *work)
{
struct pmic_glink_altmode_port *alt_port = work_to_altmode_port(work);
struct pmic_glink_altmode *altmode = alt_port->altmode;
+ enum drm_connector_status conn_status;
typec_switch_set(alt_port->typec_switch, alt_port->orientation);
- if (alt_port->svid == USB_TYPEC_DP_SID && alt_port->mode == 0xff)
- pmic_glink_altmode_safe(altmode, alt_port);
- else if (alt_port->svid == USB_TYPEC_DP_SID)
- pmic_glink_altmode_enable_dp(altmode, alt_port, alt_port->mode,
- alt_port->hpd_state, alt_port->hpd_irq);
- else
- pmic_glink_altmode_enable_usb(altmode, alt_port);
+ if (alt_port->svid == USB_TYPEC_DP_SID) {
+ if (alt_port->mode == 0xff) {
+ pmic_glink_altmode_safe(altmode, alt_port);
+ } else {
+ pmic_glink_altmode_enable_dp(altmode, alt_port,
+ alt_port->mode,
+ alt_port->hpd_state,
+ alt_port->hpd_irq);
+ }
- drm_aux_hpd_bridge_notify(&alt_port->bridge->dev,
- alt_port->hpd_state ?
- connector_status_connected :
- connector_status_disconnected);
+ if (alt_port->hpd_state)
+ conn_status = connector_status_connected;
+ else
+ conn_status = connector_status_disconnected;
+
+ drm_aux_hpd_bridge_notify(&alt_port->bridge->dev, conn_status);
+ } else {
+ pmic_glink_altmode_enable_usb(altmode, alt_port);
+ }
pmic_glink_altmode_request(altmode, ALTMODE_PAN_ACK, alt_port->index);
}
diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c
index 4cb959106efa..3c3b796333a6 100644
--- a/drivers/soc/qcom/qcom-geni-se.c
+++ b/drivers/soc/qcom/qcom-geni-se.c
@@ -895,6 +895,7 @@ static int geni_se_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct geni_wrapper *wrapper;
+ const struct geni_se_desc *desc;
int ret;
wrapper = devm_kzalloc(dev, sizeof(*wrapper), GFP_KERNEL);
@@ -906,13 +907,10 @@ static int geni_se_probe(struct platform_device *pdev)
if (IS_ERR(wrapper->base))
return PTR_ERR(wrapper->base);
- if (!has_acpi_companion(&pdev->dev)) {
- const struct geni_se_desc *desc;
- int i;
+ desc = device_get_match_data(&pdev->dev);
- desc = device_get_match_data(&pdev->dev);
- if (!desc)
- return -EINVAL;
+ if (!has_acpi_companion(&pdev->dev) && desc->num_clks) {
+ int i;
wrapper->num_clks = min_t(unsigned int, desc->num_clks, MAX_CLKS);
@@ -953,6 +951,8 @@ static const struct geni_se_desc qup_desc = {
.num_clks = ARRAY_SIZE(qup_clks),
};
+static const struct geni_se_desc sa8255p_qup_desc = {};
+
static const char * const i2c_master_hub_clks[] = {
"s-ahb",
};
@@ -965,6 +965,7 @@ static const struct geni_se_desc i2c_master_hub_desc = {
static const struct of_device_id geni_se_dt_match[] = {
{ .compatible = "qcom,geni-se-qup", .data = &qup_desc },
{ .compatible = "qcom,geni-se-i2c-master-hub", .data = &i2c_master_hub_desc },
+ { .compatible = "qcom,sa8255p-geni-se-qup", .data = &sa8255p_qup_desc },
{}
};
MODULE_DEVICE_TABLE(of, geni_se_dt_match);
diff --git a/drivers/soc/qcom/qcom_pd_mapper.c b/drivers/soc/qcom/qcom_pd_mapper.c
index 1d1c438be3e7..3abea241b1c4 100644
--- a/drivers/soc/qcom/qcom_pd_mapper.c
+++ b/drivers/soc/qcom/qcom_pd_mapper.c
@@ -488,6 +488,16 @@ static const struct qcom_pdm_domain_data *sm6350_domains[] = {
NULL,
};
+static const struct qcom_pdm_domain_data *sm7150_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 *sm8150_domains[] = {
&adsp_audio_pd,
&adsp_root_pd,
@@ -565,6 +575,7 @@ static const struct of_device_id qcom_pdm_domains[] __maybe_unused = {
{ .compatible = "qcom,sm4250", .data = sm6115_domains, },
{ .compatible = "qcom,sm6115", .data = sm6115_domains, },
{ .compatible = "qcom,sm6350", .data = sm6350_domains, },
+ { .compatible = "qcom,sm7150", .data = sm7150_domains, },
{ .compatible = "qcom,sm7225", .data = sm6350_domains, },
{ .compatible = "qcom,sm7325", .data = sc7280_domains, },
{ .compatible = "qcom,sm8150", .data = sm8150_domains, },
diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c
index 5de99cf59b9f..2e380faf9080 100644
--- a/drivers/soc/qcom/qcom_stats.c
+++ b/drivers/soc/qcom/qcom_stats.c
@@ -1,8 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2011-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022-2025, Qualcomm Innovation Center, Inc. All rights reserved.
*/
+#include <linux/bitfield.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/io.h>
@@ -11,6 +13,7 @@
#include <linux/platform_device.h>
#include <linux/seq_file.h>
+#include <linux/soc/qcom/qcom_aoss.h>
#include <linux/soc/qcom/smem.h>
#include <clocksource/arm_arch_timer.h>
@@ -24,6 +27,19 @@
#define ACCUMULATED_OFFSET 0x18
#define CLIENT_VOTES_OFFSET 0x20
+#define DDR_STATS_MAGIC_KEY 0xA1157A75
+#define DDR_STATS_MAX_NUM_MODES 20
+#define DDR_STATS_MAGIC_KEY_ADDR 0x0
+#define DDR_STATS_NUM_MODES_ADDR 0x4
+#define DDR_STATS_ENTRY_START_ADDR 0x8
+
+#define DDR_STATS_CP_IDX(data) FIELD_GET(GENMASK(4, 0), data)
+#define DDR_STATS_LPM_NAME(data) FIELD_GET(GENMASK(7, 0), data)
+#define DDR_STATS_TYPE(data) FIELD_GET(GENMASK(15, 8), data)
+#define DDR_STATS_FREQ(data) FIELD_GET(GENMASK(31, 16), data)
+
+static struct qmp *qcom_stats_qmp;
+
struct subsystem_data {
const char *name;
u32 smem_item;
@@ -48,12 +64,19 @@ static const struct subsystem_data subsystems[] = {
struct stats_config {
size_t stats_offset;
+ size_t ddr_stats_offset;
size_t num_records;
bool appended_stats_avail;
bool dynamic_offset;
bool subsystem_stats_in_smem;
};
+struct ddr_stats_entry {
+ u32 name;
+ u32 count;
+ u64 duration;
+};
+
struct stats_data {
bool appended_stats_avail;
void __iomem *base;
@@ -122,8 +145,101 @@ static int qcom_soc_sleep_stats_show(struct seq_file *s, void *unused)
return 0;
}
+static void qcom_ddr_stats_print(struct seq_file *s, struct ddr_stats_entry *data)
+{
+ u32 cp_idx;
+
+ /*
+ * DDR statistic have two different types of details encoded.
+ * (1) DDR LPM Stats
+ * (2) DDR Frequency Stats
+ *
+ * The name field have details like which type of DDR stat (bits 8:15)
+ * along with other details as explained below
+ *
+ * In case of DDR LPM stat, name field will be encoded as,
+ * Bits - Meaning
+ * 0:7 - DDR LPM name, can be of 0xd4, 0xd3, 0x11 and 0xd0.
+ * 8:15 - 0x0 (indicates its a LPM stat)
+ * 16:31 - Unused
+ *
+ * In case of DDR FREQ stats, name field will be encoded as,
+ * Bits - Meaning
+ * 0:4 - DDR Clock plan index (CP IDX)
+ * 5:7 - Unused
+ * 8:15 - 0x1 (indicates its Freq stat)
+ * 16:31 - Frequency value in Mhz
+ */
+ switch (DDR_STATS_TYPE(data->name)) {
+ case 0:
+ seq_printf(s, "DDR LPM Stat Name:0x%lx\tcount:%u\tDuration (ticks):%llu\n",
+ DDR_STATS_LPM_NAME(data->name), data->count, data->duration);
+ break;
+ case 1:
+ if (!data->count || !DDR_STATS_FREQ(data->name))
+ return;
+
+ cp_idx = DDR_STATS_CP_IDX(data->name);
+ seq_printf(s, "DDR Freq %luMhz:\tCP IDX:%u\tcount:%u\tDuration (ticks):%llu\n",
+ DDR_STATS_FREQ(data->name), cp_idx, data->count, data->duration);
+ break;
+ }
+}
+
+static int qcom_ddr_stats_show(struct seq_file *s, void *d)
+{
+ struct ddr_stats_entry data[DDR_STATS_MAX_NUM_MODES];
+ void __iomem *reg = (void __iomem *)s->private;
+ u32 entry_count;
+ int i, ret;
+
+ entry_count = readl_relaxed(reg + DDR_STATS_NUM_MODES_ADDR);
+ if (entry_count > DDR_STATS_MAX_NUM_MODES)
+ return -EINVAL;
+
+ if (qcom_stats_qmp) {
+ /*
+ * Recent SoCs (SM8450 onwards) do not have duration field
+ * populated from boot up onwards for both DDR LPM Stats
+ * and DDR Frequency Stats.
+ *
+ * Send QMP message to Always on processor which will
+ * populate duration field into MSG RAM area.
+ *
+ * Sent every time to read latest data.
+ */
+ ret = qmp_send(qcom_stats_qmp, "{class: ddr, action: freqsync}");
+ if (ret)
+ return ret;
+ }
+
+ reg += DDR_STATS_ENTRY_START_ADDR;
+ memcpy_fromio(data, reg, sizeof(struct ddr_stats_entry) * entry_count);
+
+ for (i = 0; i < entry_count; i++)
+ qcom_ddr_stats_print(s, &data[i]);
+
+ return 0;
+}
+
DEFINE_SHOW_ATTRIBUTE(qcom_soc_sleep_stats);
DEFINE_SHOW_ATTRIBUTE(qcom_subsystem_sleep_stats);
+DEFINE_SHOW_ATTRIBUTE(qcom_ddr_stats);
+
+static void qcom_create_ddr_stat_files(struct dentry *root, void __iomem *reg,
+ const struct stats_config *config)
+{
+ u32 key;
+
+ if (!config->ddr_stats_offset)
+ return;
+
+ key = readl_relaxed(reg + config->ddr_stats_offset + DDR_STATS_MAGIC_KEY_ADDR);
+ if (key == DDR_STATS_MAGIC_KEY)
+ debugfs_create_file("ddr_stats", 0400, root,
+ (__force void *)reg + config->ddr_stats_offset,
+ &qcom_ddr_stats_fops);
+}
static void qcom_create_soc_sleep_stat_files(struct dentry *root, void __iomem *reg,
struct stats_data *d,
@@ -207,11 +323,27 @@ static int qcom_stats_probe(struct platform_device *pdev)
for (i = 0; i < config->num_records; i++)
d[i].appended_stats_avail = config->appended_stats_avail;
+ /*
+ * QMP is used for DDR stats syncing to MSG RAM for recent SoCs (SM8450 onwards).
+ * The prior SoCs do not need QMP handle as the required stats are already present
+ * in MSG RAM, provided the DDR_STATS_MAGIC_KEY matches.
+ */
+ qcom_stats_qmp = qmp_get(&pdev->dev);
+ if (IS_ERR(qcom_stats_qmp)) {
+ /* We ignore error if QMP is not defined/needed */
+ if (!of_property_present(pdev->dev.of_node, "qcom,qmp"))
+ qcom_stats_qmp = NULL;
+ else if (PTR_ERR(qcom_stats_qmp) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ else
+ return PTR_ERR(qcom_stats_qmp);
+ }
root = debugfs_create_dir("qcom_stats", NULL);
qcom_create_subsystem_stat_files(root, config);
qcom_create_soc_sleep_stat_files(root, reg, d, config);
+ qcom_create_ddr_stat_files(root, reg, config);
platform_set_drvdata(pdev, root);
@@ -254,6 +386,7 @@ static const struct stats_config rpmh_data_sdm845 = {
static const struct stats_config rpmh_data = {
.stats_offset = 0x48,
+ .ddr_stats_offset = 0xb8,
.num_records = 3,
.appended_stats_avail = false,
.dynamic_offset = false,
diff --git a/drivers/soc/qcom/qmi_encdec.c b/drivers/soc/qcom/qmi_encdec.c
index bb09eff85cff..7660a960fb45 100644
--- a/drivers/soc/qcom/qmi_encdec.c
+++ b/drivers/soc/qcom/qmi_encdec.c
@@ -304,6 +304,8 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf,
const void *buf_src;
int encode_tlv = 0;
int rc;
+ u8 val8;
+ u16 val16;
if (!ei_array)
return 0;
@@ -338,7 +340,6 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf,
break;
case QMI_DATA_LEN:
- memcpy(&data_len_value, buf_src, temp_ei->elem_size);
data_len_sz = temp_ei->elem_size == sizeof(u8) ?
sizeof(u8) : sizeof(u16);
/* Check to avoid out of range buffer access */
@@ -348,8 +349,17 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf,
__func__);
return -ETOOSMALL;
}
- rc = qmi_encode_basic_elem(buf_dst, &data_len_value,
- 1, data_len_sz);
+ if (data_len_sz == sizeof(u8)) {
+ val8 = *(u8 *)buf_src;
+ data_len_value = (u32)val8;
+ rc = qmi_encode_basic_elem(buf_dst, &val8,
+ 1, data_len_sz);
+ } else {
+ val16 = *(u16 *)buf_src;
+ data_len_value = (u32)le16_to_cpu(val16);
+ rc = qmi_encode_basic_elem(buf_dst, &val16,
+ 1, data_len_sz);
+ }
UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst,
encoded_bytes, tlv_len,
encode_tlv, rc);
@@ -523,14 +533,23 @@ static int qmi_decode_string_elem(const struct qmi_elem_info *ei_array,
u32 string_len = 0;
u32 string_len_sz = 0;
const struct qmi_elem_info *temp_ei = ei_array;
+ u8 val8;
+ u16 val16;
if (dec_level == 1) {
string_len = tlv_len;
} else {
string_len_sz = temp_ei->elem_len <= U8_MAX ?
sizeof(u8) : sizeof(u16);
- rc = qmi_decode_basic_elem(&string_len, buf_src,
- 1, string_len_sz);
+ if (string_len_sz == sizeof(u8)) {
+ rc = qmi_decode_basic_elem(&val8, buf_src,
+ 1, string_len_sz);
+ string_len = (u32)val8;
+ } else {
+ rc = qmi_decode_basic_elem(&val16, buf_src,
+ 1, string_len_sz);
+ string_len = (u32)val16;
+ }
decoded_bytes += rc;
}
@@ -604,6 +623,9 @@ static int qmi_decode(const struct qmi_elem_info *ei_array, void *out_c_struct,
u32 decoded_bytes = 0;
const void *buf_src = in_buf;
int rc;
+ u8 val8;
+ u16 val16;
+ u32 val32;
while (decoded_bytes < in_buf_len) {
if (dec_level >= 2 && temp_ei->data_type == QMI_EOTI)
@@ -642,9 +664,17 @@ static int qmi_decode(const struct qmi_elem_info *ei_array, void *out_c_struct,
if (temp_ei->data_type == QMI_DATA_LEN) {
data_len_sz = temp_ei->elem_size == sizeof(u8) ?
sizeof(u8) : sizeof(u16);
- rc = qmi_decode_basic_elem(&data_len_value, buf_src,
- 1, data_len_sz);
- memcpy(buf_dst, &data_len_value, sizeof(u32));
+ if (data_len_sz == sizeof(u8)) {
+ rc = qmi_decode_basic_elem(&val8, buf_src,
+ 1, data_len_sz);
+ data_len_value = (u32)val8;
+ } else {
+ rc = qmi_decode_basic_elem(&val16, buf_src,
+ 1, data_len_sz);
+ data_len_value = (u32)val16;
+ }
+ val32 = cpu_to_le32(data_len_value);
+ memcpy(buf_dst, &val32, sizeof(u32));
temp_ei = temp_ei + 1;
buf_dst = out_c_struct + temp_ei->offset;
tlv_len -= data_len_sz;
@@ -746,9 +776,9 @@ void *qmi_encode_message(int type, unsigned int msg_id, size_t *len,
hdr = msg;
hdr->type = type;
- hdr->txn_id = txn_id;
- hdr->msg_id = msg_id;
- hdr->msg_len = msglen;
+ hdr->txn_id = cpu_to_le16(txn_id);
+ hdr->msg_id = cpu_to_le16(msg_id);
+ hdr->msg_len = cpu_to_le16(msglen);
*len = sizeof(*hdr) + msglen;
diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c
index bc6d6379d8b1..6500f863aae5 100644
--- a/drivers/soc/qcom/qmi_interface.c
+++ b/drivers/soc/qcom/qmi_interface.c
@@ -400,7 +400,7 @@ static void qmi_invoke_handler(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
for (handler = qmi->handlers; handler->fn; handler++) {
if (handler->type == hdr->type &&
- handler->msg_id == hdr->msg_id)
+ handler->msg_id == le16_to_cpu(hdr->msg_id))
break;
}
@@ -488,7 +488,7 @@ static void qmi_handle_message(struct qmi_handle *qmi,
/* If this is a response, find the matching transaction handle */
if (hdr->type == QMI_RESPONSE) {
mutex_lock(&qmi->txn_lock);
- txn = idr_find(&qmi->txns, hdr->txn_id);
+ txn = idr_find(&qmi->txns, le16_to_cpu(hdr->txn_id));
/* Ignore unexpected responses */
if (!txn) {
@@ -514,7 +514,7 @@ static void qmi_handle_message(struct qmi_handle *qmi,
} else {
/* Create a txn based on the txn_id of the incoming message */
memset(&tmp_txn, 0, sizeof(tmp_txn));
- tmp_txn.id = hdr->txn_id;
+ tmp_txn.id = le16_to_cpu(hdr->txn_id);
qmi_invoke_handler(qmi, sq, &tmp_txn, buf, len);
}
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index cb82e887b51d..fdab2b1067db 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -1072,7 +1072,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev)
drv->ver.minor = rsc_id & (MINOR_VER_MASK << MINOR_VER_SHIFT);
drv->ver.minor >>= MINOR_VER_SHIFT;
- if (drv->ver.major == 3)
+ if (drv->ver.major >= 3)
drv->regs = rpmh_rsc_reg_offset_ver_3_0;
else
drv->regs = rpmh_rsc_reg_offset_ver_2_7;
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
index 592819701809..cf425930539e 100644
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -86,7 +86,7 @@
#define SMEM_GLOBAL_HOST 0xfffe
/* Max number of processors/hosts in a system */
-#define SMEM_HOST_COUNT 20
+#define SMEM_HOST_COUNT 25
/**
* struct smem_proc_comm - proc_comm communication struct (legacy)
diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c
index 8c8878bc87f5..cb515c2340c1 100644
--- a/drivers/soc/qcom/smp2p.c
+++ b/drivers/soc/qcom/smp2p.c
@@ -575,7 +575,7 @@ static int qcom_smp2p_probe(struct platform_device *pdev)
smp2p->mbox_client.knows_txdone = true;
smp2p->mbox_chan = mbox_request_channel(&smp2p->mbox_client, 0);
if (IS_ERR(smp2p->mbox_chan)) {
- if (PTR_ERR(smp2p->mbox_chan) != -ENODEV)
+ if (PTR_ERR(smp2p->mbox_chan) != -ENOENT)
return PTR_ERR(smp2p->mbox_chan);
smp2p->mbox_chan = NULL;
diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c
index 18d7f1be9093..963772f45489 100644
--- a/drivers/soc/qcom/socinfo.c
+++ b/drivers/soc/qcom/socinfo.c
@@ -38,6 +38,7 @@
#define SMEM_IMAGE_TABLE_BOOT_INDEX 0
#define SMEM_IMAGE_TABLE_TZ_INDEX 1
#define SMEM_IMAGE_TABLE_RPM_INDEX 3
+#define SMEM_IMAGE_TABLE_APPSBL_INDEX 9
#define SMEM_IMAGE_TABLE_APPS_INDEX 10
#define SMEM_IMAGE_TABLE_MPSS_INDEX 11
#define SMEM_IMAGE_TABLE_ADSP_INDEX 12
@@ -48,6 +49,7 @@
#define SMEM_IMAGE_TABLE_CDSP1_INDEX 19
#define SMEM_IMAGE_TABLE_GPDSP_INDEX 20
#define SMEM_IMAGE_TABLE_GPDSP1_INDEX 21
+#define SMEM_IMAGE_TABLE_TME_INDEX 28
#define SMEM_IMAGE_VERSION_TABLE 469
/*
@@ -55,6 +57,7 @@
*/
static const char *const socinfo_image_names[] = {
[SMEM_IMAGE_TABLE_ADSP_INDEX] = "adsp",
+ [SMEM_IMAGE_TABLE_APPSBL_INDEX] = "appsbl",
[SMEM_IMAGE_TABLE_APPS_INDEX] = "apps",
[SMEM_IMAGE_TABLE_BOOT_INDEX] = "boot",
[SMEM_IMAGE_TABLE_CNSS_INDEX] = "cnss",
@@ -67,6 +70,7 @@ static const char *const socinfo_image_names[] = {
[SMEM_IMAGE_TABLE_CDSP1_INDEX] = "cdsp1",
[SMEM_IMAGE_TABLE_GPDSP_INDEX] = "gpdsp",
[SMEM_IMAGE_TABLE_GPDSP1_INDEX] = "gpdsp1",
+ [SMEM_IMAGE_TABLE_TME_INDEX] = "tme",
};
static const char *const pmic_models[] = {
@@ -126,8 +130,12 @@ static const char *const pmic_models[] = {
[72] = "PMR735D",
[73] = "PM8550",
[74] = "PMK8550",
+ [78] = "PMM8650AU",
+ [79] = "PMM8650AU_PSAIL",
+ [80] = "PM7550",
[82] = "PMC8380",
[83] = "SMB2360",
+ [91] = "PMIV0108",
};
struct socinfo_params {
@@ -444,9 +452,15 @@ static const struct soc_id soc_id[] = {
{ qcom_board_id(IPQ5302) },
{ qcom_board_id(QCS8550) },
{ qcom_board_id(QCM8550) },
+ { qcom_board_id(SM8750) },
{ qcom_board_id(IPQ5300) },
+ { qcom_board_id(SM7635) },
+ { qcom_board_id(SM6650) },
+ { qcom_board_id(SM6650P) },
{ qcom_board_id(IPQ5321) },
{ qcom_board_id(IPQ5424) },
+ { qcom_board_id(QCM6690) },
+ { qcom_board_id(QCS6690) },
{ qcom_board_id(IPQ5404) },
{ qcom_board_id(QCS9100) },
{ qcom_board_id(QCS8300) },
diff --git a/drivers/soc/qcom/ubwc_config.c b/drivers/soc/qcom/ubwc_config.c
new file mode 100644
index 000000000000..bd0a98aad9f3
--- /dev/null
+++ b/drivers/soc/qcom/ubwc_config.c
@@ -0,0 +1,282 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+
+#include <linux/soc/qcom/ubwc.h>
+
+static const struct qcom_ubwc_cfg_data msm8937_data = {
+ .ubwc_enc_version = UBWC_1_0,
+ .ubwc_dec_version = UBWC_1_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL1 |
+ UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 14,
+};
+
+static const struct qcom_ubwc_cfg_data msm8998_data = {
+ .ubwc_enc_version = UBWC_1_0,
+ .ubwc_dec_version = UBWC_1_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL1 |
+ UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 15,
+};
+
+static const struct qcom_ubwc_cfg_data qcm2290_data = {
+ /* no UBWC */
+ .highest_bank_bit = 15,
+};
+
+static const struct qcom_ubwc_cfg_data sa8775p_data = {
+ .ubwc_enc_version = UBWC_4_0,
+ .ubwc_dec_version = UBWC_4_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ .highest_bank_bit = 13,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data sar2130p_data = {
+ .ubwc_enc_version = UBWC_3_0, /* 4.0.2 in hw */
+ .ubwc_dec_version = UBWC_4_3,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ .highest_bank_bit = 13,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data sc7180_data = {
+ .ubwc_enc_version = UBWC_2_0,
+ .ubwc_dec_version = UBWC_2_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ .highest_bank_bit = 14,
+};
+
+static const struct qcom_ubwc_cfg_data sc7280_data = {
+ .ubwc_enc_version = UBWC_3_0,
+ .ubwc_dec_version = UBWC_4_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ .highest_bank_bit = 14,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data sc8180x_data = {
+ .ubwc_enc_version = UBWC_3_0,
+ .ubwc_dec_version = UBWC_3_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 16,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data sc8280xp_data = {
+ .ubwc_enc_version = UBWC_4_0,
+ .ubwc_dec_version = UBWC_4_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ .highest_bank_bit = 16,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data sdm670_data = {
+ .ubwc_enc_version = UBWC_2_0,
+ .ubwc_dec_version = UBWC_2_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 14,
+};
+
+static const struct qcom_ubwc_cfg_data sdm845_data = {
+ .ubwc_enc_version = UBWC_2_0,
+ .ubwc_dec_version = UBWC_2_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 15,
+};
+
+static const struct qcom_ubwc_cfg_data sm6115_data = {
+ .ubwc_enc_version = UBWC_1_0,
+ .ubwc_dec_version = UBWC_2_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL1 |
+ UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ .highest_bank_bit = 14,
+};
+
+static const struct qcom_ubwc_cfg_data sm6125_data = {
+ .ubwc_enc_version = UBWC_1_0,
+ .ubwc_dec_version = UBWC_3_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL1 |
+ UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 14,
+};
+
+static const struct qcom_ubwc_cfg_data sm6150_data = {
+ .ubwc_enc_version = UBWC_2_0,
+ .ubwc_dec_version = UBWC_2_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 14,
+};
+
+static const struct qcom_ubwc_cfg_data sm6350_data = {
+ .ubwc_enc_version = UBWC_2_0,
+ .ubwc_dec_version = UBWC_2_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ .highest_bank_bit = 14,
+};
+
+static const struct qcom_ubwc_cfg_data sm7150_data = {
+ .ubwc_enc_version = UBWC_2_0,
+ .ubwc_dec_version = UBWC_2_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 14,
+};
+
+static const struct qcom_ubwc_cfg_data sm8150_data = {
+ .ubwc_enc_version = UBWC_3_0,
+ .ubwc_dec_version = UBWC_3_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .highest_bank_bit = 15,
+};
+
+static const struct qcom_ubwc_cfg_data sm8250_data = {
+ .ubwc_enc_version = UBWC_4_0,
+ .ubwc_dec_version = UBWC_4_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ /* TODO: highest_bank_bit = 15 for LP_DDR4 */
+ .highest_bank_bit = 16,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data sm8350_data = {
+ .ubwc_enc_version = UBWC_4_0,
+ .ubwc_dec_version = UBWC_4_0,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ /* TODO: highest_bank_bit = 15 for LP_DDR4 */
+ .highest_bank_bit = 16,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data sm8550_data = {
+ .ubwc_enc_version = UBWC_4_0,
+ .ubwc_dec_version = UBWC_4_3,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ /* TODO: highest_bank_bit = 15 for LP_DDR4 */
+ .highest_bank_bit = 16,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data sm8750_data = {
+ .ubwc_enc_version = UBWC_5_0,
+ .ubwc_dec_version = UBWC_5_0,
+ .ubwc_swizzle = 6,
+ .ubwc_bank_spread = true,
+ /* TODO: highest_bank_bit = 15 for LP_DDR4 */
+ .highest_bank_bit = 16,
+ .macrotile_mode = true,
+};
+
+static const struct qcom_ubwc_cfg_data x1e80100_data = {
+ .ubwc_enc_version = UBWC_4_0,
+ .ubwc_dec_version = UBWC_4_3,
+ .ubwc_swizzle = UBWC_SWIZZLE_ENABLE_LVL2 |
+ UBWC_SWIZZLE_ENABLE_LVL3,
+ .ubwc_bank_spread = true,
+ /* TODO: highest_bank_bit = 15 for LP_DDR4 */
+ .highest_bank_bit = 16,
+ .macrotile_mode = true,
+};
+
+static const struct of_device_id qcom_ubwc_configs[] __maybe_unused = {
+ { .compatible = "qcom,apq8096", .data = &msm8998_data },
+ { .compatible = "qcom,msm8917", .data = &msm8937_data },
+ { .compatible = "qcom,msm8937", .data = &msm8937_data },
+ { .compatible = "qcom,msm8953", .data = &msm8937_data },
+ { .compatible = "qcom,msm8956", .data = &msm8937_data },
+ { .compatible = "qcom,msm8976", .data = &msm8937_data },
+ { .compatible = "qcom,msm8996", .data = &msm8998_data },
+ { .compatible = "qcom,msm8998", .data = &msm8998_data },
+ { .compatible = "qcom,qcm2290", .data = &qcm2290_data, },
+ { .compatible = "qcom,qcm6490", .data = &sc7280_data, },
+ { .compatible = "qcom,sa8155p", .data = &sm8150_data, },
+ { .compatible = "qcom,sa8540p", .data = &sc8280xp_data, },
+ { .compatible = "qcom,sa8775p", .data = &sa8775p_data, },
+ { .compatible = "qcom,sar2130p", .data = &sar2130p_data },
+ { .compatible = "qcom,sc7180", .data = &sc7180_data },
+ { .compatible = "qcom,sc7280", .data = &sc7280_data, },
+ { .compatible = "qcom,sc8180x", .data = &sc8180x_data, },
+ { .compatible = "qcom,sc8280xp", .data = &sc8280xp_data, },
+ { .compatible = "qcom,sdm630", .data = &msm8937_data },
+ { .compatible = "qcom,sdm636", .data = &msm8937_data },
+ { .compatible = "qcom,sdm660", .data = &msm8937_data },
+ { .compatible = "qcom,sdm670", .data = &sdm670_data, },
+ { .compatible = "qcom,sdm845", .data = &sdm845_data, },
+ { .compatible = "qcom,sm4250", .data = &sm6115_data, },
+ { .compatible = "qcom,sm6115", .data = &sm6115_data, },
+ { .compatible = "qcom,sm6125", .data = &sm6125_data, },
+ { .compatible = "qcom,sm6150", .data = &sm6150_data, },
+ { .compatible = "qcom,sm6350", .data = &sm6350_data, },
+ { .compatible = "qcom,sm6375", .data = &sm6350_data, },
+ { .compatible = "qcom,sm7125", .data = &sc7180_data },
+ { .compatible = "qcom,sm7150", .data = &sm7150_data, },
+ { .compatible = "qcom,sm8150", .data = &sm8150_data, },
+ { .compatible = "qcom,sm8250", .data = &sm8250_data, },
+ { .compatible = "qcom,sm8350", .data = &sm8350_data, },
+ { .compatible = "qcom,sm8450", .data = &sm8350_data, },
+ { .compatible = "qcom,sm8550", .data = &sm8550_data, },
+ { .compatible = "qcom,sm8650", .data = &sm8550_data, },
+ { .compatible = "qcom,sm8750", .data = &sm8750_data, },
+ { .compatible = "qcom,x1e80100", .data = &x1e80100_data, },
+ { .compatible = "qcom,x1p42100", .data = &x1e80100_data, },
+ { }
+};
+
+const struct qcom_ubwc_cfg_data *qcom_ubwc_config_get_data(void)
+{
+ const struct of_device_id *match;
+ struct device_node *root;
+
+ root = of_find_node_by_path("/");
+ if (!root)
+ return ERR_PTR(-ENODEV);
+
+ match = of_match_node(qcom_ubwc_configs, root);
+ of_node_put(root);
+ if (!match) {
+ pr_err("Couldn't find UBWC config data for this platform!\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ return match->data;
+}
+EXPORT_SYMBOL_GPL(qcom_ubwc_config_get_data);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("UBWC config database for QTI SoCs");