diff options
| author | Arnd Bergmann <arnd@arndb.de> | 2026-01-21 16:45:49 +0100 |
|---|---|---|
| committer | Arnd Bergmann <arnd@arndb.de> | 2026-01-21 16:45:49 +0100 |
| commit | 733f0303c2a7282750fa283b0458ffad3b6ba8ee (patch) | |
| tree | 63c0d3e13b54009dae418872ebe074bdb3abf18a /drivers/soc | |
| parent | 599efa093ffcc342b8ec18e9c77a8c959efd4b9b (diff) | |
| parent | fe099c387e06b566840449ac21008db1b25ad1f4 (diff) | |
Merge tag 'qcom-drivers-for-6.20' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux into soc/drivers
Qualcomm driver updates for v6.20
Support multiple wait queues in the SCM firmware interface and provide
discovery of the wait queue interrupt to deal with the cases where
bootloader didn't patch the DeviceTree with the IRQ information.
Refactor the MDT loader and the SCM driver's peripheral authentication
service interface and introduce support for passing a remoteproc
resource table to the firmware. The remoteproc patches that uses this
and uses this to configure the IOMMU are included here due to
bidirectional dependencies. The end result is remoteproc support on the
Glymur platform.
Enable QSEECOM and thereby UEFI variable access, on the Surface Pro 11.
Make the QMI interface endianness aware, to support ath1Xk on big endian
machines.
Add the Glymur support in LLCC driver.
* tag 'qcom-drivers-for-6.20' of https://git.kernel.org/pub/scm/linux/kernel/git/qcom/linux: (33 commits)
soc: qcom: preserve CPU endianness for QMI_DATA_LEN
soc: qcom: fix QMI encoding/decoding for basic elements
soc: qcom: check QMI basic element error codes
soc: qcom: ubwc: add missing include
remoteproc: qcom: pas: Enable Secure PAS support with IOMMU managed by Linux
remoteproc: pas: Extend parse_fw callback to fetch resources via SMC call
firmware: qcom_scm: Add qcom_scm_pas_get_rsc_table() to get resource table
firmware: qcom_scm: Add SHM bridge handling for PAS when running without QHEE
firmware: qcom_scm: Refactor qcom_scm_pas_init_image()
firmware: qcom_scm: Add a prep version of auth_and_reset function
soc: qcom: mdtloader: Remove qcom_mdt_pas_init() from exported symbols
soc: qcom: mdtloader: Add PAS context aware qcom_mdt_pas_load() function
remoteproc: pas: Replace metadata context with PAS context structure
firmware: qcom_scm: Introduce PAS context allocator helper function
firmware: qcom_scm: Rename peripheral as pas_id
firmware: qcom_scm: Remove redundant piece of code
dt-bindings: remoteproc: qcom,pas: Add iommus property
soc: qcom: cmd-db: Use devm_memremap() to fix memory leak in cmd_db_dev_probe
soc: qcom: pmic_glink_altmode: Consume TBT3/USB4 mode notifications
dt-bindings: qcom,pdc: document the Milos Power Domain Controller
...
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/soc')
| -rw-r--r-- | drivers/soc/qcom/cmd-db.c | 7 | ||||
| -rw-r--r-- | drivers/soc/qcom/llcc-qcom.c | 207 | ||||
| -rw-r--r-- | drivers/soc/qcom/mdt_loader.c | 51 | ||||
| -rw-r--r-- | drivers/soc/qcom/pmic_glink_altmode.c | 188 | ||||
| -rw-r--r-- | drivers/soc/qcom/qmi_encdec.c | 137 | ||||
| -rw-r--r-- | drivers/soc/qcom/smem.c | 4 |
6 files changed, 532 insertions, 62 deletions
diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c index ae66c2623d25..84a75d8c4b70 100644 --- a/drivers/soc/qcom/cmd-db.c +++ b/drivers/soc/qcom/cmd-db.c @@ -349,15 +349,16 @@ static int cmd_db_dev_probe(struct platform_device *pdev) return -EINVAL; } - cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WC); - if (!cmd_db_header) { - ret = -ENOMEM; + cmd_db_header = devm_memremap(&pdev->dev, rmem->base, rmem->size, MEMREMAP_WC); + if (IS_ERR(cmd_db_header)) { + ret = PTR_ERR(cmd_db_header); cmd_db_header = NULL; return ret; } if (!cmd_db_magic_matches(cmd_db_header)) { dev_err(&pdev->dev, "Invalid Command DB Magic\n"); + cmd_db_header = NULL; return -EINVAL; } diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 13e174267294..1abfda7a58f2 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -182,6 +182,197 @@ enum llcc_reg_offset { LLCC_TRP_WRS_CACHEABLE_EN, }; +static const struct llcc_slice_config glymur_data[] = { + { + .usecase_id = LLCC_CPUSS, + .slice_id = 1, + .max_cap = 7680, + .priority = 1, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .vict_prio = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_VIDSC0, + .slice_id = 2, + .max_cap = 512, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .vict_prio = true, + }, { + .usecase_id = LLCC_AUDIO, + .slice_id = 6, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .vict_prio = true, + }, { + .usecase_id = LLCC_VIDSC1, + .slice_id = 4, + .max_cap = 512, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .vict_prio = true, + }, { + .usecase_id = LLCC_CMPT, + .slice_id = 10, + .max_cap = 7680, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .vict_prio = true, + }, { + .usecase_id = LLCC_GPUHTW, + .slice_id = 11, + .max_cap = 512, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .vict_prio = true, + }, { + .usecase_id = LLCC_GPU, + .slice_id = 9, + .max_cap = 7680, + .priority = 1, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .write_scid_en = true, + .write_scid_cacheable_en = true, + .stale_en = true, + .vict_prio = true, + }, { + .usecase_id = LLCC_MMUHWT, + .slice_id = 18, + .max_cap = 768, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .vict_prio = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_AUDHW, + .slice_id = 22, + .max_cap = 1024, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .vict_prio = true, + }, { + .usecase_id = LLCC_CVP, + .slice_id = 8, + .max_cap = 64, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .vict_prio = true, + }, { + .usecase_id = LLCC_WRCACHE, + .slice_id = 31, + .max_cap = 1536, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .vict_prio = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_CMPTHCP, + .slice_id = 17, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .vict_prio = true, + }, { + .usecase_id = LLCC_LCPDARE, + .slice_id = 30, + .max_cap = 768, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .alloc_oneway_en = true, + .vict_prio = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_AENPU, + .slice_id = 3, + .max_cap = 3072, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .cache_mode = 2, + .vict_prio = true, + }, { + .usecase_id = LLCC_ISLAND1, + .slice_id = 12, + .max_cap = 5632, + .priority = 7, + .fixed_size = true, + .bonus_ways = 0x0, + .res_ways = 0x7FF, + .vict_prio = true, + }, { + .usecase_id = LLCC_VIDVSP, + .slice_id = 28, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .vict_prio = true, + }, { + .usecase_id = LLCC_OOBM_NS, + .slice_id = 5, + .max_cap = 512, + .priority = 1, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .vict_prio = true, + }, { + .usecase_id = LLCC_CPUSS_OPP, + .slice_id = 32, + .max_cap = 0, + .fixed_size = true, + .bonus_ways = 0x0, + .res_ways = 0x0, + .vict_prio = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_PCIE_TCU, + .slice_id = 19, + .max_cap = 256, + .priority = 1, + .fixed_size = true, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .vict_prio = true, + .activate_on_init = true, + }, { + .usecase_id = LLCC_VIDSC_VSP1, + .slice_id = 29, + .max_cap = 256, + .priority = 3, + .fixed_size = true, + .bonus_ways = 0xFFF, + .res_ways = 0x0, + .vict_prio = true, + } +}; + static const struct llcc_slice_config ipq5424_data[] = { { .usecase_id = LLCC_CPUSS, @@ -3872,6 +4063,16 @@ static const struct qcom_llcc_config kaanapali_cfg[] = { }, }; +static const struct qcom_llcc_config glymur_cfg[] = { + { + .sct_data = glymur_data, + .size = ARRAY_SIZE(glymur_data), + .reg_offset = llcc_v6_reg_offset, + .edac_reg_offset = &llcc_v2_1_edac_reg_offset, + .no_edac = true, + }, +}; + static const struct qcom_llcc_config qcs615_cfg[] = { { .sct_data = qcs615_data, @@ -4103,6 +4304,11 @@ static const struct qcom_sct_config kaanapali_cfgs = { .num_config = ARRAY_SIZE(kaanapali_cfg), }; +static const struct qcom_sct_config glymur_cfgs = { + .llcc_config = glymur_cfg, + .num_config = ARRAY_SIZE(glymur_cfg), +}; + static const struct qcom_sct_config qcs615_cfgs = { .llcc_config = qcs615_cfg, .num_config = ARRAY_SIZE(qcs615_cfg), @@ -4941,6 +5147,7 @@ err: } static const struct of_device_id qcom_llcc_of_match[] = { + { .compatible = "qcom,glymur-llcc", .data = &glymur_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/mdt_loader.c b/drivers/soc/qcom/mdt_loader.c index c239107cb930..c004d444d698 100644 --- a/drivers/soc/qcom/mdt_loader.c +++ b/drivers/soc/qcom/mdt_loader.c @@ -227,20 +227,9 @@ void *qcom_mdt_read_metadata(const struct firmware *fw, size_t *data_len, } EXPORT_SYMBOL_GPL(qcom_mdt_read_metadata); -/** - * qcom_mdt_pas_init() - initialize PAS region for firmware loading - * @dev: device handle to associate resources with - * @fw: firmware object for the mdt file - * @fw_name: name of the firmware, for construction of segment file names - * @pas_id: PAS identifier - * @mem_phys: physical address of allocated memory region - * @ctx: PAS metadata context, to be released by caller - * - * Returns 0 on success, negative errno otherwise. - */ -int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, - const char *fw_name, int pas_id, phys_addr_t mem_phys, - struct qcom_scm_pas_metadata *ctx) +static int __qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, + const char *fw_name, int pas_id, phys_addr_t mem_phys, + struct qcom_scm_pas_context *ctx) { const struct elf32_phdr *phdrs; const struct elf32_phdr *phdr; @@ -302,7 +291,6 @@ int qcom_mdt_pas_init(struct device *dev, const struct firmware *fw, out: return ret; } -EXPORT_SYMBOL_GPL(qcom_mdt_pas_init); static bool qcom_mdt_bins_are_split(const struct firmware *fw) { @@ -469,7 +457,7 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, { int ret; - ret = qcom_mdt_pas_init(dev, fw, fw_name, pas_id, mem_phys, NULL); + ret = __qcom_mdt_pas_init(dev, fw, fw_name, pas_id, mem_phys, NULL); if (ret) return ret; @@ -478,5 +466,36 @@ int qcom_mdt_load(struct device *dev, const struct firmware *fw, } EXPORT_SYMBOL_GPL(qcom_mdt_load); +/** + * qcom_mdt_pas_load - Loads and authenticates the metadata of the firmware + * (typically contained in the .mdt file), followed by loading the actual + * firmware segments (e.g., .bXX files). Authentication of the segments done + * by a separate call. + * + * The PAS context must be initialized using qcom_scm_pas_context_init() + * prior to invoking this function. + * + * @ctx: Pointer to the PAS (Peripheral Authentication Service) context + * @fw: Firmware object representing the .mdt file + * @firmware: Name of the firmware used to construct segment file names + * @mem_region: Memory region allocated for loading the firmware + * @reloc_base: Physical address adjusted after relocation + * + * Return: 0 on success or a negative error code on failure. + */ +int qcom_mdt_pas_load(struct qcom_scm_pas_context *ctx, const struct firmware *fw, + const char *firmware, void *mem_region, phys_addr_t *reloc_base) +{ + int ret; + + ret = __qcom_mdt_pas_init(ctx->dev, fw, firmware, ctx->pas_id, ctx->mem_phys, ctx); + if (ret) + return ret; + + return qcom_mdt_load_no_init(ctx->dev, fw, firmware, mem_region, ctx->mem_phys, + ctx->mem_size, reloc_base); +} +EXPORT_SYMBOL_GPL(qcom_mdt_pas_load); + MODULE_DESCRIPTION("Firmware parser for Qualcomm MDT format"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c index 7f11acd33323..d0afdcb96ee1 100644 --- a/drivers/soc/qcom/pmic_glink_altmode.c +++ b/drivers/soc/qcom/pmic_glink_altmode.c @@ -14,10 +14,12 @@ #include <linux/soc/qcom/pdr.h> #include <drm/bridge/aux-bridge.h> +#include <linux/usb/pd.h> #include <linux/usb/typec_altmode.h> #include <linux/usb/typec_dp.h> #include <linux/usb/typec_mux.h> #include <linux/usb/typec_retimer.h> +#include <linux/usb/typec_tbt.h> #include <linux/soc/qcom/pmic_glink.h> @@ -37,11 +39,38 @@ struct usbc_write_req { __le32 reserved; }; -#define NOTIFY_PAYLOAD_SIZE 16 +struct usbc_sc8280x_dp_data { + u8 pin_assignment : 6; + u8 hpd_state : 1; + u8 hpd_irq : 1; + u8 res[7]; +}; + +/* Used for both TBT and USB4 notifications */ +struct usbc_sc8280x_tbt_data { + u8 usb_speed : 3; + u8 cable_type : 3; + /* This field is NOP on USB4, all cables support rounded rates by spec */ + u8 rounded_cable : 1; + u8 power_limited : 1; + u8 res[11]; +}; + struct usbc_notify { struct pmic_glink_hdr hdr; - char payload[NOTIFY_PAYLOAD_SIZE]; - u32 reserved; + u8 port_idx; + u8 orientation; + u8 mux_ctrl; +#define MUX_CTRL_STATE_NO_CONN 0 +#define MUX_CTRL_STATE_TUNNELING 4 + + u8 res; + __le16 vid; + __le16 svid; + union usbc_sc8280x_extended_data { + struct usbc_sc8280x_dp_data dp; + struct usbc_sc8280x_tbt_data tbt; + } extended_data; }; struct usbc_sc8180x_notify { @@ -74,6 +103,7 @@ struct pmic_glink_altmode_port { struct typec_retimer *typec_retimer; struct typec_retimer_state retimer_state; struct typec_altmode dp_alt; + struct typec_altmode tbt_alt; struct work_struct work; @@ -81,10 +111,12 @@ struct pmic_glink_altmode_port { enum typec_orientation orientation; u16 svid; + struct usbc_sc8280x_tbt_data tbt_data; u8 dp_data; u8 mode; u8 hpd_state; u8 hpd_irq; + u8 mux_ctrl; }; #define work_to_altmode(w) container_of((w), struct pmic_glink_altmode, enable_work) @@ -170,6 +202,102 @@ static void pmic_glink_altmode_enable_dp(struct pmic_glink_altmode *altmode, dev_err(altmode->dev, "failed to setup retimer to DP: %d\n", ret); } +static void pmic_glink_altmode_enable_tbt(struct pmic_glink_altmode *altmode, + struct pmic_glink_altmode_port *port) +{ + struct usbc_sc8280x_tbt_data *tbt = &port->tbt_data; + struct typec_thunderbolt_data tbt_data = {}; + u32 cable_speed; + int ret; + + /* Device Discover Mode VDO */ + tbt_data.device_mode = TBT_MODE; + tbt_data.device_mode |= TBT_SET_ADAPTER(TBT_ADAPTER_TBT3); + + /* Cable Discover Mode VDO */ + tbt_data.cable_mode = TBT_MODE; + + if (tbt->usb_speed == 0) { + cable_speed = TBT_CABLE_USB3_PASSIVE; + } else if (tbt->usb_speed == 1) { + cable_speed = TBT_CABLE_10_AND_20GBPS; + } else { + dev_err(altmode->dev, + "Got illegal TBT3 cable speed value (%u), falling back to passive\n", + tbt->usb_speed); + cable_speed = TBT_CABLE_USB3_PASSIVE; + } + tbt_data.cable_mode |= TBT_SET_CABLE_SPEED(cable_speed); + + if (tbt->cable_type) { + tbt_data.cable_mode |= TBT_CABLE_ACTIVE_PASSIVE; + tbt_data.cable_mode |= TBT_SET_CABLE_ROUNDED(tbt->rounded_cable); + } + + /* Enter Mode VDO */ + tbt_data.enter_vdo |= TBT_MODE; + tbt_data.enter_vdo |= TBT_ENTER_MODE_CABLE_SPEED(cable_speed); + + if (tbt->cable_type) { + tbt_data.enter_vdo |= TBT_CABLE_ACTIVE_PASSIVE; + tbt_data.enter_vdo |= TBT_SET_CABLE_ROUNDED(tbt->rounded_cable); + } + + port->state.alt = &port->tbt_alt; + port->state.data = &tbt_data; + port->state.mode = TYPEC_MODAL_STATE(port->mode); + + ret = typec_mux_set(port->typec_mux, &port->state); + if (ret) + dev_err(altmode->dev, "failed to switch mux to USB: %d\n", ret); + + port->retimer_state.alt = &port->tbt_alt; + port->retimer_state.data = &tbt_data; + port->retimer_state.mode = TYPEC_MODAL_STATE(port->mode); + + ret = typec_retimer_set(port->typec_retimer, &port->retimer_state); + if (ret) + dev_err(altmode->dev, "failed to setup retimer to USB: %d\n", ret); +} + +static void pmic_glink_altmode_enable_usb4(struct pmic_glink_altmode *altmode, + struct pmic_glink_altmode_port *port) +{ + struct usbc_sc8280x_tbt_data *tbt = &port->tbt_data; + struct enter_usb_data data = {}; + int ret; + + data.eudo = FIELD_PREP(EUDO_USB_MODE_MASK, EUDO_USB_MODE_USB4); + + if (tbt->usb_speed == 0) { + data.eudo |= FIELD_PREP(EUDO_CABLE_SPEED_MASK, EUDO_CABLE_SPEED_USB4_GEN2); + } else if (tbt->usb_speed == 1) { + data.eudo |= FIELD_PREP(EUDO_CABLE_SPEED_MASK, EUDO_CABLE_SPEED_USB4_GEN3); + } else { + pr_err("Got illegal USB4 cable speed value (%u), falling back to G2\n", + tbt->usb_speed); + data.eudo |= FIELD_PREP(EUDO_CABLE_SPEED_MASK, EUDO_CABLE_SPEED_USB4_GEN2); + } + + data.eudo |= FIELD_PREP(EUDO_CABLE_TYPE_MASK, tbt->cable_type); + + port->state.alt = NULL; + port->state.data = &data; + port->state.mode = TYPEC_MODE_USB4; + + ret = typec_mux_set(port->typec_mux, &port->state); + if (ret) + dev_err(altmode->dev, "failed to switch mux to USB: %d\n", ret); + + port->retimer_state.alt = NULL; + port->retimer_state.data = &data; + port->retimer_state.mode = TYPEC_MODE_USB4; + + ret = typec_retimer_set(port->typec_retimer, &port->retimer_state); + if (ret) + dev_err(altmode->dev, "failed to setup retimer to USB: %d\n", ret); +} + static void pmic_glink_altmode_enable_usb(struct pmic_glink_altmode *altmode, struct pmic_glink_altmode_port *port) { @@ -222,15 +350,15 @@ static void pmic_glink_altmode_worker(struct work_struct *work) typec_switch_set(alt_port->typec_switch, alt_port->orientation); - 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); - } + if (alt_port->mux_ctrl == MUX_CTRL_STATE_NO_CONN) { + pmic_glink_altmode_safe(altmode, alt_port); + } else if (alt_port->svid == USB_TYPEC_TBT_SID) { + pmic_glink_altmode_enable_tbt(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); if (alt_port->hpd_state) conn_status = connector_status_connected; @@ -238,6 +366,8 @@ static void pmic_glink_altmode_worker(struct work_struct *work) conn_status = connector_status_disconnected; drm_aux_hpd_bridge_notify(&alt_port->bridge->dev, conn_status); + } else if (alt_port->mux_ctrl == MUX_CTRL_STATE_TUNNELING) { + pmic_glink_altmode_enable_usb4(altmode, alt_port); } else { pmic_glink_altmode_enable_usb(altmode, alt_port); } @@ -314,11 +444,10 @@ static void pmic_glink_altmode_sc8280xp_notify(struct pmic_glink_altmode *altmod u16 svid, const void *data, size_t len) { struct pmic_glink_altmode_port *alt_port; + const struct usbc_sc8280x_tbt_data *tbt; + const struct usbc_sc8280x_dp_data *dp; const struct usbc_notify *notify; u8 orientation; - u8 hpd_state; - u8 hpd_irq; - u8 mode; u8 port; if (len != sizeof(*notify)) { @@ -329,11 +458,8 @@ static void pmic_glink_altmode_sc8280xp_notify(struct pmic_glink_altmode *altmod notify = data; - port = notify->payload[0]; - orientation = notify->payload[1]; - mode = FIELD_GET(SC8280XP_DPAM_MASK, notify->payload[8]) - DPAM_HPD_A; - hpd_state = FIELD_GET(SC8280XP_HPD_STATE_MASK, notify->payload[8]); - hpd_irq = FIELD_GET(SC8280XP_HPD_IRQ_MASK, notify->payload[8]); + port = notify->port_idx; + orientation = notify->orientation; if (port >= ARRAY_SIZE(altmode->ports) || !altmode->ports[port].altmode) { dev_dbg(altmode->dev, "notification on undefined port %d\n", port); @@ -343,9 +469,21 @@ static void pmic_glink_altmode_sc8280xp_notify(struct pmic_glink_altmode *altmod alt_port = &altmode->ports[port]; alt_port->orientation = pmic_glink_altmode_orientation(orientation); alt_port->svid = svid; - alt_port->mode = mode; - alt_port->hpd_state = hpd_state; - alt_port->hpd_irq = hpd_irq; + alt_port->mux_ctrl = notify->mux_ctrl; + + if (svid == USB_TYPEC_DP_SID) { + dp = ¬ify->extended_data.dp; + + alt_port->mode = dp->pin_assignment - DPAM_HPD_A; + alt_port->hpd_state = dp->hpd_state; + alt_port->hpd_irq = dp->hpd_irq; + } else if (alt_port->mux_ctrl == MUX_CTRL_STATE_TUNNELING) { + /* Valid for both USB4 and TBT3 */ + tbt = ¬ify->extended_data.tbt; + + alt_port->tbt_data = *tbt; + } + schedule_work(&alt_port->work); } @@ -471,6 +609,10 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev, alt_port->dp_alt.mode = USB_TYPEC_DP_MODE; alt_port->dp_alt.active = 1; + alt_port->tbt_alt.svid = USB_TYPEC_TBT_SID; + alt_port->tbt_alt.mode = TYPEC_TBT_MODE; + alt_port->tbt_alt.active = 1; + alt_port->typec_mux = fwnode_typec_mux_get(fwnode); if (IS_ERR(alt_port->typec_mux)) { fwnode_handle_put(fwnode); diff --git a/drivers/soc/qcom/qmi_encdec.c b/drivers/soc/qcom/qmi_encdec.c index 7660a960fb45..28ce6f130b6a 100644 --- a/drivers/soc/qcom/qmi_encdec.c +++ b/drivers/soc/qcom/qmi_encdec.c @@ -23,18 +23,60 @@ *p_length |= ((u8)*p_src) << 8; \ } while (0) -#define QMI_ENCDEC_ENCODE_N_BYTES(p_dst, p_src, size) \ +#define QMI_ENCDEC_ENCODE_U8(p_dst, p_src) \ do { \ - memcpy(p_dst, p_src, size); \ - p_dst = (u8 *)p_dst + size; \ - p_src = (u8 *)p_src + size; \ + memcpy(p_dst, p_src, sizeof(u8)); \ + p_dst = (u8 *)p_dst + sizeof(u8); \ + p_src = (u8 *)p_src + sizeof(u8); \ } while (0) -#define QMI_ENCDEC_DECODE_N_BYTES(p_dst, p_src, size) \ +#define QMI_ENCDEC_ENCODE_U16(p_dst, p_src) \ do { \ - memcpy(p_dst, p_src, size); \ - p_dst = (u8 *)p_dst + size; \ - p_src = (u8 *)p_src + size; \ + *(__le16 *)p_dst = __cpu_to_le16(*(u16 *)p_src); \ + p_dst = (u8 *)p_dst + sizeof(u16); \ + p_src = (u8 *)p_src + sizeof(u16); \ +} while (0) + +#define QMI_ENCDEC_ENCODE_U32(p_dst, p_src) \ +do { \ + *(__le32 *)p_dst = __cpu_to_le32(*(u32 *)p_src); \ + p_dst = (u8 *)p_dst + sizeof(u32); \ + p_src = (u8 *)p_src + sizeof(u32); \ +} while (0) + +#define QMI_ENCDEC_ENCODE_U64(p_dst, p_src) \ +do { \ + *(__le64 *)p_dst = __cpu_to_le64(*(u64 *)p_src); \ + p_dst = (u8 *)p_dst + sizeof(u64); \ + p_src = (u8 *)p_src + sizeof(u64); \ +} while (0) + +#define QMI_ENCDEC_DECODE_U8(p_dst, p_src) \ +do { \ + memcpy(p_dst, p_src, sizeof(u8)); \ + p_dst = (u8 *)p_dst + sizeof(u8); \ + p_src = (u8 *)p_src + sizeof(u8); \ +} while (0) + +#define QMI_ENCDEC_DECODE_U16(p_dst, p_src) \ +do { \ + *(u16 *)p_dst = __le16_to_cpu(*(__le16 *)p_src); \ + p_dst = (u8 *)p_dst + sizeof(u16); \ + p_src = (u8 *)p_src + sizeof(u16); \ +} while (0) + +#define QMI_ENCDEC_DECODE_U32(p_dst, p_src) \ +do { \ + *(u32 *)p_dst = __le32_to_cpu(*(__le32 *)p_src); \ + p_dst = (u8 *)p_dst + sizeof(u32); \ + p_src = (u8 *)p_src + sizeof(u32); \ +} while (0) + +#define QMI_ENCDEC_DECODE_U64(p_dst, p_src) \ +do { \ + *(u64 *)p_dst = __le64_to_cpu(*(__le64 *)p_src); \ + p_dst = (u8 *)p_dst + sizeof(u64); \ + p_src = (u8 *)p_src + sizeof(u64); \ } while (0) #define UPDATE_ENCODE_VARIABLES(temp_si, buf_dst, \ @@ -161,7 +203,8 @@ static int qmi_calc_min_msg_len(const struct qmi_elem_info *ei_array, * of primary data type which include u8 - u64 or similar. This * function returns the number of bytes of encoded information. * - * Return: The number of bytes of encoded information. + * Return: The number of bytes of encoded information on success or negative + * errno on error. */ static int qmi_encode_basic_elem(void *buf_dst, const void *buf_src, u32 elem_len, u32 elem_size) @@ -169,7 +212,24 @@ static int qmi_encode_basic_elem(void *buf_dst, const void *buf_src, u32 i, rc = 0; for (i = 0; i < elem_len; i++) { - QMI_ENCDEC_ENCODE_N_BYTES(buf_dst, buf_src, elem_size); + switch (elem_size) { + case sizeof(u8): + QMI_ENCDEC_ENCODE_U8(buf_dst, buf_src); + break; + case sizeof(u16): + QMI_ENCDEC_ENCODE_U16(buf_dst, buf_src); + break; + case sizeof(u32): + QMI_ENCDEC_ENCODE_U32(buf_dst, buf_src); + break; + case sizeof(u64): + QMI_ENCDEC_ENCODE_U64(buf_dst, buf_src); + break; + default: + pr_err("%s: Unrecognized element size\n", __func__); + return -EINVAL; + } + rc += elem_size; } @@ -267,11 +327,15 @@ static int qmi_encode_string_elem(const struct qmi_elem_info *ei_array, } rc = qmi_encode_basic_elem(buf_dst, &string_len, 1, string_len_sz); + if (rc < 0) + return rc; encoded_bytes += rc; } rc = qmi_encode_basic_elem(buf_dst + encoded_bytes, buf_src, string_len, temp_ei->elem_size); + if (rc < 0) + return rc; encoded_bytes += rc; return encoded_bytes; @@ -333,6 +397,8 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf, case QMI_OPT_FLAG: rc = qmi_encode_basic_elem(&opt_flag_value, buf_src, 1, sizeof(u8)); + if (rc < 0) + return rc; if (opt_flag_value) temp_ei = temp_ei + 1; else @@ -340,6 +406,7 @@ 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, sizeof(u32)); data_len_sz = temp_ei->elem_size == sizeof(u8) ? sizeof(u8) : sizeof(u16); /* Check to avoid out of range buffer access */ @@ -350,15 +417,17 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf, return -ETOOSMALL; } if (data_len_sz == sizeof(u8)) { - val8 = *(u8 *)buf_src; - data_len_value = (u32)val8; + val8 = data_len_value; rc = qmi_encode_basic_elem(buf_dst, &val8, 1, data_len_sz); + if (rc < 0) + return rc; } else { - val16 = *(u16 *)buf_src; - data_len_value = (u32)le16_to_cpu(val16); + val16 = data_len_value; rc = qmi_encode_basic_elem(buf_dst, &val16, 1, data_len_sz); + if (rc < 0) + return rc; } UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst, encoded_bytes, tlv_len, @@ -386,6 +455,8 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf, rc = qmi_encode_basic_elem(buf_dst, buf_src, data_len_value, temp_ei->elem_size); + if (rc < 0) + return rc; UPDATE_ENCODE_VARIABLES(temp_ei, buf_dst, encoded_bytes, tlv_len, encode_tlv, rc); @@ -444,7 +515,8 @@ static int qmi_encode(const struct qmi_elem_info *ei_array, void *out_buf, * of primary data type which include u8 - u64 or similar. This * function returns the number of bytes of decoded information. * - * Return: The total size of the decoded data elements, in bytes. + * Return: The total size of the decoded data elements, in bytes, on success or + * negative errno on error. */ static int qmi_decode_basic_elem(void *buf_dst, const void *buf_src, u32 elem_len, u32 elem_size) @@ -452,7 +524,24 @@ static int qmi_decode_basic_elem(void *buf_dst, const void *buf_src, u32 i, rc = 0; for (i = 0; i < elem_len; i++) { - QMI_ENCDEC_DECODE_N_BYTES(buf_dst, buf_src, elem_size); + switch (elem_size) { + case sizeof(u8): + QMI_ENCDEC_DECODE_U8(buf_dst, buf_src); + break; + case sizeof(u16): + QMI_ENCDEC_DECODE_U16(buf_dst, buf_src); + break; + case sizeof(u32): + QMI_ENCDEC_DECODE_U32(buf_dst, buf_src); + break; + case sizeof(u64): + QMI_ENCDEC_DECODE_U64(buf_dst, buf_src); + break; + default: + pr_err("%s: Unrecognized element size\n", __func__); + return -EINVAL; + } + rc += elem_size; } @@ -544,10 +633,14 @@ static int qmi_decode_string_elem(const struct qmi_elem_info *ei_array, if (string_len_sz == sizeof(u8)) { rc = qmi_decode_basic_elem(&val8, buf_src, 1, string_len_sz); + if (rc < 0) + return rc; string_len = (u32)val8; } else { rc = qmi_decode_basic_elem(&val16, buf_src, 1, string_len_sz); + if (rc < 0) + return rc; string_len = (u32)val16; } decoded_bytes += rc; @@ -565,6 +658,8 @@ static int qmi_decode_string_elem(const struct qmi_elem_info *ei_array, rc = qmi_decode_basic_elem(buf_dst, buf_src + decoded_bytes, string_len, temp_ei->elem_size); + if (rc < 0) + return rc; *((char *)buf_dst + string_len) = '\0'; decoded_bytes += rc; @@ -625,7 +720,6 @@ static int qmi_decode(const struct qmi_elem_info *ei_array, void *out_c_struct, int rc; u8 val8; u16 val16; - u32 val32; while (decoded_bytes < in_buf_len) { if (dec_level >= 2 && temp_ei->data_type == QMI_EOTI) @@ -667,14 +761,17 @@ static int qmi_decode(const struct qmi_elem_info *ei_array, void *out_c_struct, if (data_len_sz == sizeof(u8)) { rc = qmi_decode_basic_elem(&val8, buf_src, 1, data_len_sz); + if (rc < 0) + return rc; data_len_value = (u32)val8; } else { rc = qmi_decode_basic_elem(&val16, buf_src, 1, data_len_sz); + if (rc < 0) + return rc; data_len_value = (u32)val16; } - val32 = cpu_to_le32(data_len_value); - memcpy(buf_dst, &val32, sizeof(u32)); + memcpy(buf_dst, &data_len_value, sizeof(u32)); temp_ei = temp_ei + 1; buf_dst = out_c_struct + temp_ei->offset; tlv_len -= data_len_sz; @@ -701,6 +798,8 @@ static int qmi_decode(const struct qmi_elem_info *ei_array, void *out_c_struct, rc = qmi_decode_basic_elem(buf_dst, buf_src, data_len_value, temp_ei->elem_size); + if (rc < 0) + return rc; UPDATE_DECODE_VARIABLES(buf_src, decoded_bytes, rc); break; diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index fef840b54574..088b2bbee9e6 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -1219,7 +1219,9 @@ static int qcom_smem_probe(struct platform_device *pdev) smem->item_count = qcom_smem_get_item_count(smem); break; case SMEM_GLOBAL_HEAP_VERSION: - qcom_smem_map_global(smem, size); + ret = qcom_smem_map_global(smem, size); + if (ret < 0) + return ret; smem->item_count = SMEM_ITEM_COUNT; break; default: |
