From 8166e88dfa8e0bf336f32a89b729ba4356f41762 Mon Sep 17 00:00:00 2001 From: Wesley Cheng Date: Thu, 23 Jun 2022 15:10:49 -0700 Subject: [PATCH 1/2] usb: dwc3: dwc3-msm-core: Reshuffle DWC3 DTSI node parameter parsing Move OF node parsing for the DWC3 MSM and DWC3 core into its own APIs in an effort to reduce code complexity for the DWC3 MSM probe API. Change-Id: Ibd44dd4252286ee997a3508edff8582a7ecb8b78 Signed-off-by: Wesley Cheng --- drivers/usb/dwc3/dwc3-msm-core.c | 171 +++++++++++++++++-------------- 1 file changed, 93 insertions(+), 78 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-msm-core.c b/drivers/usb/dwc3/dwc3-msm-core.c index 0b6213b68a1b..64b2063920ce 100644 --- a/drivers/usb/dwc3/dwc3-msm-core.c +++ b/drivers/usb/dwc3/dwc3-msm-core.c @@ -5273,6 +5273,7 @@ static int dwc3_msm_core_init(struct dwc3_msm *mdwc) static int dwc3_msm_parse_core_params(struct dwc3_msm *mdwc, struct device_node *dwc3_node) { + struct device_node *phy_node; int ret; const char *prop_string; @@ -5299,16 +5300,101 @@ static int dwc3_msm_parse_core_params(struct dwc3_msm *mdwc, struct device_node disable_irq(mdwc->core_irq); } + phy_node = of_parse_phandle(dwc3_node, "usb-phy", 0); + mdwc->hs_phy = devm_usb_get_phy_by_node(mdwc->dev, phy_node, NULL); + if (IS_ERR(mdwc->hs_phy)) { + dev_err(mdwc->dev, "unable to get hsphy device\n"); + ret = PTR_ERR(mdwc->hs_phy); + return ret; + } + + phy_node = of_parse_phandle(dwc3_node, "usb-phy", 1); + mdwc->ss_phy = devm_usb_get_phy_by_node(mdwc->dev, phy_node, NULL); + if (IS_ERR(mdwc->ss_phy)) { + dev_err(mdwc->dev, "unable to get ssphy device\n"); + ret = PTR_ERR(mdwc->ss_phy); + return ret; + } + return ret; } +static int dwc3_msm_parse_params(struct dwc3_msm *mdwc, struct device_node *node) +{ + struct device *dev = mdwc->dev; + int ret, size = 0, i; + + of_property_read_u32(node, "qcom,num-gsi-evt-buffs", + &mdwc->num_gsi_event_buffers); + + if (mdwc->num_gsi_event_buffers) { + of_get_property(node, "qcom,gsi-reg-offset", &size); + if (size) { + mdwc->gsi_reg = devm_kzalloc(dev, size, GFP_KERNEL); + if (!mdwc->gsi_reg) + return -ENOMEM; + + mdwc->gsi_reg_offset_cnt = + (size / sizeof(*mdwc->gsi_reg)); + if (mdwc->gsi_reg_offset_cnt != GSI_REG_MAX) { + dev_err(dev, "invalid reg offset count\n"); + return -EINVAL; + } + + of_property_read_u32_array(dev->of_node, + "qcom,gsi-reg-offset", mdwc->gsi_reg, + mdwc->gsi_reg_offset_cnt); + } else { + dev_err(dev, "err provide qcom,gsi-reg-offset\n"); + return -EINVAL; + } + } + + mdwc->use_pdc_interrupts = of_property_read_bool(node, + "qcom,use-pdc-interrupts"); + + mdwc->use_eusb2_phy = of_property_read_bool(node, "qcom,use-eusb2-phy"); + mdwc->disable_host_ssphy_powerdown = of_property_read_bool(node, + "qcom,disable-host-ssphy-powerdown"); + + mdwc->dis_sending_cm_l1_quirk = of_property_read_bool(node, + "qcom,dis-sending-cm-l1-quirk"); + + /* use default as nominal bus voting */ + mdwc->default_bus_vote = BUS_VOTE_NOMINAL; + of_property_read_u32(node, "qcom,default-bus-vote", + &mdwc->default_bus_vote); + + if (mdwc->default_bus_vote >= BUS_VOTE_MAX) + mdwc->default_bus_vote = BUS_VOTE_MAX - 1; + else if (mdwc->default_bus_vote < BUS_VOTE_NONE) + mdwc->default_bus_vote = BUS_VOTE_NONE; + + for (i = 0; i < ARRAY_SIZE(mdwc->icc_paths); i++) { + mdwc->icc_paths[i] = of_icc_get(dev, icc_path_names[i]); + if (IS_ERR(mdwc->icc_paths[i])) + mdwc->icc_paths[i] = NULL; + } + + ret = of_property_read_u32(node, "qcom,pm-qos-latency", + &mdwc->pm_qos_latency); + if (ret) { + dev_dbg(dev, "setting pm-qos-latency to zero.\n"); + mdwc->pm_qos_latency = 0; + } + + mdwc->force_gen1 = of_property_read_bool(node, "qcom,force-gen1"); + + return 0; +} + static int dwc3_msm_probe(struct platform_device *pdev) { - struct device_node *node = pdev->dev.of_node, *dwc3_node, *phy_node; + struct device_node *node = pdev->dev.of_node, *dwc3_node; struct device *dev = &pdev->dev; struct dwc3_msm *mdwc; struct resource *res; - int ret = 0, size = 0, i; + int ret = 0, i; u32 val; mdwc = devm_kzalloc(&pdev->dev, sizeof(*mdwc), GFP_KERNEL); @@ -5462,38 +5548,9 @@ static int dwc3_msm_probe(struct platform_device *pdev) } } - ret = of_property_read_u32(node, "qcom,num-gsi-evt-buffs", - &mdwc->num_gsi_event_buffers); - - if (mdwc->num_gsi_event_buffers) { - of_get_property(node, "qcom,gsi-reg-offset", &size); - if (size) { - mdwc->gsi_reg = devm_kzalloc(dev, size, GFP_KERNEL); - if (!mdwc->gsi_reg) - return -ENOMEM; - - mdwc->gsi_reg_offset_cnt = - (size / sizeof(*mdwc->gsi_reg)); - if (mdwc->gsi_reg_offset_cnt != GSI_REG_MAX) { - dev_err(dev, "invalid reg offset count\n"); - return -EINVAL; - } - - of_property_read_u32_array(dev->of_node, - "qcom,gsi-reg-offset", mdwc->gsi_reg, - mdwc->gsi_reg_offset_cnt); - } else { - dev_err(dev, "err provide qcom,gsi-reg-offset\n"); - return -EINVAL; - } - } - - mdwc->use_pdc_interrupts = of_property_read_bool(node, - "qcom,use-pdc-interrupts"); - - mdwc->use_eusb2_phy = of_property_read_bool(node, "qcom,use-eusb2-phy"); - mdwc->disable_host_ssphy_powerdown = of_property_read_bool(node, - "qcom,disable-host-ssphy-powerdown"); + ret = dwc3_msm_parse_params(mdwc, node); + if (ret < 0) + goto err; if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) { dev_err(&pdev->dev, "setting DMA mask to 64 failed.\n"); @@ -5504,9 +5561,6 @@ static int dwc3_msm_probe(struct platform_device *pdev) } } - mdwc->dis_sending_cm_l1_quirk = of_property_read_bool(node, - "qcom,dis-sending-cm-l1-quirk"); - /* Assumes dwc3 is the first DT child of dwc3-msm */ dwc3_node = of_get_next_available_child(node, NULL); if (!dwc3_node) { @@ -5515,39 +5569,9 @@ static int dwc3_msm_probe(struct platform_device *pdev) goto err; } - dwc3_msm_parse_core_params(mdwc, dwc3_node); - - phy_node = of_parse_phandle(dwc3_node, "usb-phy", 0); - mdwc->hs_phy = devm_usb_get_phy_by_node(mdwc->dev, phy_node, NULL); - if (IS_ERR(mdwc->hs_phy)) { - dev_err(mdwc->dev, "unable to get hsphy device\n"); - ret = PTR_ERR(mdwc->hs_phy); + ret = dwc3_msm_parse_core_params(mdwc, dwc3_node); + if (ret < 0) goto err; - } - - phy_node = of_parse_phandle(dwc3_node, "usb-phy", 1); - mdwc->ss_phy = devm_usb_get_phy_by_node(mdwc->dev, phy_node, NULL); - if (IS_ERR(mdwc->ss_phy)) { - dev_err(mdwc->dev, "unable to get ssphy device\n"); - ret = PTR_ERR(mdwc->ss_phy); - goto err; - } - - /* use default as nominal bus voting */ - mdwc->default_bus_vote = BUS_VOTE_NOMINAL; - ret = of_property_read_u32(node, "qcom,default-bus-vote", - &mdwc->default_bus_vote); - - if (mdwc->default_bus_vote >= BUS_VOTE_MAX) - mdwc->default_bus_vote = BUS_VOTE_MAX - 1; - else if (mdwc->default_bus_vote < BUS_VOTE_NONE) - mdwc->default_bus_vote = BUS_VOTE_NONE; - - for (i = 0; i < ARRAY_SIZE(mdwc->icc_paths); i++) { - mdwc->icc_paths[i] = of_icc_get(&pdev->dev, icc_path_names[i]); - if (IS_ERR(mdwc->icc_paths[i])) - mdwc->icc_paths[i] = NULL; - } /* * Clocks and regulators will not be turned on until the first time @@ -5563,18 +5587,9 @@ static int dwc3_msm_probe(struct platform_device *pdev) if (of_property_read_bool(node, "qcom,disable-dev-mode-pm")) pm_runtime_get_noresume(mdwc->dev); - ret = of_property_read_u32(node, "qcom,pm-qos-latency", - &mdwc->pm_qos_latency); - if (ret) { - dev_dbg(&pdev->dev, "setting pm-qos-latency to zero.\n"); - mdwc->pm_qos_latency = 0; - } - mutex_init(&mdwc->suspend_resume_mutex); mutex_init(&mdwc->role_switch_mutex); - mdwc->force_gen1 = of_property_read_bool(node, "qcom,force-gen1"); - if (of_property_read_bool(node, "usb-role-switch")) { struct usb_role_switch_desc role_desc = { .set = dwc3_msm_usb_set_role, From 685398da723a652123aee41ce2f27af3ffd2d000 Mon Sep 17 00:00:00 2001 From: Wesley Cheng Date: Thu, 23 Jun 2022 16:08:32 -0700 Subject: [PATCH 2/2] usb: dwc3: dwc3-msm-core: Add DIAG IMEM management into DWC3 MSM Originally, the PID IMEM field was updated as part of the f_diag driver instance. Since the f_diag, driver has been removed, relocate this logic into DWC3 MSM. Once receiving the pullup enable call, the logic will look up for the diag function, and if present handle writing the PID and device serial number to IMEM. This removes the need for having userspace update/trigger the IMEM update. Change-Id: If6ba232270269001690b3cedd3d0de9bf2d4cebb Signed-off-by: Wesley Cheng --- drivers/usb/dwc3/dwc3-msm-core.c | 89 ++++++++++++++++++++++++++++++++ drivers/usb/dwc3/dwc3-msm-ops.c | 4 ++ include/linux/usb/dwc3-msm.h | 1 + 3 files changed, 94 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-msm-core.c b/drivers/usb/dwc3/dwc3-msm-core.c index 64b2063920ce..86bf95ec3aba 100644 --- a/drivers/usb/dwc3/dwc3-msm-core.c +++ b/drivers/usb/dwc3/dwc3-msm-core.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,7 @@ #include #include #include +#include #include "core.h" #include "gadget.h" @@ -53,6 +55,11 @@ #define NUM_LOG_PAGES 12 +/* dload specific suppot */ +#define PID_MAGIC_ID 0x71432909 +#define SERIAL_NUM_MAGIC_ID 0x61945374 +#define SERIAL_NUMBER_LENGTH 128 + /* time out to wait for USB cable status notification (in ms)*/ #define SM_INIT_TIMEOUT 30000 @@ -291,6 +298,13 @@ enum usb_gsi_reg { GSI_REG_MAX, }; +struct dload_struct { + u32 pid; + char serial_number[SERIAL_NUMBER_LENGTH]; + u32 pid_magic; + u32 serial_magic; +}; + struct dwc3_hw_ep { struct dwc3_ep *dep; enum usb_hw_ep_mode mode; @@ -590,6 +604,8 @@ struct dwc3_msm { /* unfortunately, dwc3 core doesn't manage multiple dwc3 instances for trace */ void *dwc_trace_ipc_log_ctxt; +static struct dload_struct __iomem *diag_dload; + static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc); static inline void dwc3_msm_ep_writel(void __iomem *base, u32 offset, u32 value) @@ -3127,6 +3143,67 @@ static void dwc3_msm_set_clk_sel(struct dwc3_msm *mdwc) dwc3_msm_switch_utmi(mdwc, 1); } +static void *gadget_get_drvdata(struct usb_gadget *g) +{ + return g->ep0->driver_data; +} + +static int is_diag_enabled(struct usb_composite_dev *cdev) +{ + struct usb_configuration *c; + + list_for_each_entry(c, &cdev->configs, list) { + struct usb_function *f; + + f = c->interface[0]; + if (!strcmp(f->fi->group.cg_item.ci_name, "ffs.diag")) + return 1; + } + + return 0; +} + +static void dwc3_msm_update_imem_pid(struct dwc3 *dwc) +{ + struct usb_composite_dev *cdev = NULL; + struct dload_struct local_diag_dload = { 0 }; + + if (!diag_dload || !dwc->gadget) { + pr_err("%s: diag_dload mem region not defined\n", __func__); + return; + } + + cdev = gadget_get_drvdata(dwc->gadget); + + if (cdev->desc.idVendor == 0x05c6 && is_diag_enabled(cdev)) { + struct usb_gadget_string_container *uc; + struct usb_string *s; + + local_diag_dload.pid = cdev->desc.idProduct; + local_diag_dload.pid_magic = PID_MAGIC_ID; + local_diag_dload.serial_magic = SERIAL_NUM_MAGIC_ID; + + list_for_each_entry(uc, &cdev->gstrings, list) { + struct usb_gadget_strings **table; + + table = (struct usb_gadget_strings **)uc->stash; + if (!table) { + pr_err("%s: can't update dload cookie\n", __func__); + return; + } + + for (s = (*table)->strings; s && s->s; s++) { + if (s->id == cdev->desc.iSerialNumber) { + strscpy(local_diag_dload.serial_number, s->s, + SERIAL_NUMBER_LENGTH); + break; + } + } + } + memcpy_toio(diag_dload, &local_diag_dload, sizeof(local_diag_dload)); + } +} + void dwc3_msm_notify_event(struct dwc3 *dwc, enum dwc3_notify_event event, unsigned int value) { @@ -3283,6 +3360,9 @@ void dwc3_msm_notify_event(struct dwc3 *dwc, GSI_EN_MASK, 0); } break; + case DWC3_IMEM_UPDATE_PID: + dwc3_msm_update_imem_pid(dwc); + break; default: dev_dbg(mdwc->dev, "unknown dwc3 event\n"); break; @@ -5321,6 +5401,7 @@ static int dwc3_msm_parse_core_params(struct dwc3_msm *mdwc, struct device_node static int dwc3_msm_parse_params(struct dwc3_msm *mdwc, struct device_node *node) { + struct device_node *diag_node; struct device *dev = mdwc->dev; int ret, size = 0, i; @@ -5385,6 +5466,12 @@ static int dwc3_msm_parse_params(struct dwc3_msm *mdwc, struct device_node *node mdwc->force_gen1 = of_property_read_bool(node, "qcom,force-gen1"); + diag_node = of_find_compatible_node(NULL, NULL, "qcom,msm-imem-diag-dload"); + if (!diag_node) + pr_warn("diag: failed to find diag_dload imem node\n"); + + diag_dload = diag_node ? of_iomap(diag_node, 0) : NULL; + return 0; } @@ -5690,6 +5777,8 @@ static int dwc3_msm_remove(struct platform_device *pdev) struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); int i, ret_pm; + if (diag_dload) + iounmap(diag_dload); usb_role_switch_unregister(mdwc->role_switch); if (mdwc->dpdm_nb.notifier_call) { diff --git a/drivers/usb/dwc3/dwc3-msm-ops.c b/drivers/usb/dwc3/dwc3-msm-ops.c index f0b58df42b66..9ef11bba2554 100644 --- a/drivers/usb/dwc3/dwc3-msm-ops.c +++ b/drivers/usb/dwc3/dwc3-msm-ops.c @@ -112,6 +112,10 @@ static int entry_dwc3_gadget_pullup(struct kretprobe_instance *ri, dwc3_msm_notify_event(data->dwc, DWC3_CONTROLLER_PULLUP_ENTER, data->xi0); + /* Only write PID to IMEM if pullup is being enabled */ + if (data->xi0) + dwc3_msm_notify_event(data->dwc, DWC3_IMEM_UPDATE_PID, 0); + return 0; } diff --git a/include/linux/usb/dwc3-msm.h b/include/linux/usb/dwc3-msm.h index 936692417ed7..ee76735f04bb 100644 --- a/include/linux/usb/dwc3-msm.h +++ b/include/linux/usb/dwc3-msm.h @@ -85,6 +85,7 @@ enum dwc3_notify_event { DWC3_GSI_EVT_BUF_CLEAR, DWC3_GSI_EVT_BUF_FREE, DWC3_CONTROLLER_NOTIFY_CLEAR_DB, + DWC3_IMEM_UPDATE_PID, }; /*