Loading drivers/usb/dwc3/dwc3-msm.c +20 −45 Original line number Diff line number Diff line Loading @@ -373,34 +373,9 @@ static inline void dwc3_msm_write_reg_field(void __iomem *base, u32 offset, tmp &= ~mask; /* clear written bits */ val = tmp | (val << shift); iowrite32(val, base + offset); } /** * Write register and read back masked value to confirm it is written * * @base - DWC3 base virtual address. * @offset - register offset. * @mask - register bitmask specifying what should be updated * @val - value to write. * */ static inline void dwc3_msm_write_readback(void __iomem *base, u32 offset, const u32 mask, u32 val) { u32 write_val, tmp = ioread32(base + offset); tmp &= ~mask; /* retain other bits */ write_val = tmp | val; iowrite32(write_val, base + offset); /* Read back to see if val was written */ tmp = ioread32(base + offset); tmp &= mask; /* clear other bits */ if (tmp != val) pr_err("%s: write: %x to QSCRATCH: %x FAILED\n", __func__, val, offset); /* Read back to make sure that previous write goes through */ ioread32(base + offset); } static bool dwc3_msm_is_ss_rhport_connected(struct dwc3_msm *mdwc) Loading Loading @@ -952,21 +927,24 @@ static void gsi_store_ringbase_dbl_info(struct usb_ep *ep, GSI_RING_BASE_ADDR_L(mdwc->gsi_reg[RING_BASE_ADDR_L], (n)), dwc3_trb_dma_offset(dep, &dep->trb_pool[0])); if (request->mapped_db_reg_phs_addr_lsb) dma_unmap_resource(dwc->sysdev, request->mapped_db_reg_phs_addr_lsb, if (!request->mapped_db_reg_phs_addr_lsb) { request->mapped_db_reg_phs_addr_lsb = dma_map_resource(dwc->sysdev, (phys_addr_t)request->db_reg_phs_addr_lsb, PAGE_SIZE, DMA_BIDIRECTIONAL, 0); request->mapped_db_reg_phs_addr_lsb = dma_map_resource(dwc->sysdev, (phys_addr_t)request->db_reg_phs_addr_lsb, PAGE_SIZE, DMA_BIDIRECTIONAL, 0); if (dma_mapping_error(dwc->sysdev, request->mapped_db_reg_phs_addr_lsb)) if (dma_mapping_error(dwc->sysdev, request->mapped_db_reg_phs_addr_lsb)) dev_err(mdwc->dev, "mapping error for db_reg_phs_addr_lsb\n"); } dev_dbg(mdwc->dev, "ep:%s dbl_addr_lsb:%x mapped_dbl_addr_lsb:%llx\n", ep->name, request->db_reg_phs_addr_lsb, (unsigned long long)request->mapped_db_reg_phs_addr_lsb); dbg_log_string("ep:%s dbl_addr_lsb:%x mapped_addr:%llx\n", ep->name, request->db_reg_phs_addr_lsb, (unsigned long long)request->mapped_db_reg_phs_addr_lsb); dwc3_msm_write_reg(mdwc->base, GSI_DBL_ADDR_L(mdwc->gsi_reg[DBL_ADDR_L], (n)), (u32)request->mapped_db_reg_phs_addr_lsb); Loading Loading @@ -4033,17 +4011,14 @@ static void dwc3_override_vbus_status(struct dwc3_msm *mdwc, bool vbus_present) struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); /* Update OTG VBUS Valid from HSPHY to controller */ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, vbus_present ? UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL : UTMI_OTG_VBUS_VALID, vbus_present ? UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL : 0); dwc3_msm_write_reg_field(mdwc->base, HS_PHY_CTRL_REG, UTMI_OTG_VBUS_VALID, !!vbus_present); /* Update only if Super Speed is supported */ if (dwc->maximum_speed >= USB_SPEED_SUPER) { /* Update VBUS Valid from SSPHY to controller */ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, LANE0_PWR_PRESENT, vbus_present ? LANE0_PWR_PRESENT : 0); dwc3_msm_write_reg_field(mdwc->base, SS_PHY_CTRL_REG, LANE0_PWR_PRESENT, !!vbus_present); } } Loading Loading @@ -4145,7 +4120,7 @@ static int dwc3_usb_blocking_sync(struct notifier_block *nb, dbg_event(0xFF, "fw_blocksync", 0); flush_work(&mdwc->resume_work); flush_delayed_work(&mdwc->sm_work); drain_workqueue(mdwc->sm_usb_wq); if (!mdwc->in_host_mode && !mdwc->in_device_mode) { dbg_event(0xFF, "lpm_state", atomic_read(&dwc->in_lpm)); Loading drivers/usb/pd/policy_engine.c +49 −32 Original line number Diff line number Diff line Loading @@ -230,7 +230,7 @@ static void *usbpd_ipc_log; #define PS_HARD_RESET_TIME 25 #define PS_SOURCE_ON 400 #define PS_SOURCE_OFF 750 #define FIRST_SOURCE_CAP_TIME 200 #define FIRST_SOURCE_CAP_TIME 100 #define VDM_BUSY_TIME 50 #define VCONN_ON_TIME 100 Loading Loading @@ -344,8 +344,6 @@ static void *usbpd_ipc_log; #define ID_HDR_PRODUCT_PER 2 #define ID_HDR_PRODUCT_AMA 5 #define ID_HDR_PRODUCT_VPD 6 #define ID_HDR_VID 0x05c6 /* qcom */ #define PROD_VDO_PID 0x0a00 /* TBD */ #define PD_MIN_SINK_CURRENT 900 Loading Loading @@ -668,14 +666,29 @@ static inline void pd_reset_protocol(struct usbpd *pd) static int pd_send_msg(struct usbpd *pd, u8 msg_type, const u32 *data, size_t num_data, enum pd_sop_type sop) { unsigned long flags; int ret; u16 hdr; if (pd->hard_reset_recvd) return -EBUSY; if (sop == SOP_MSG) hdr = PD_MSG_HDR(msg_type, pd->current_dr, pd->current_pr, pd->tx_msgid[sop], num_data, pd->spec_rev); else /* sending SOP'/SOP'' to a cable, PR/DR fields should be 0 */ hdr = PD_MSG_HDR(msg_type, 0, 0, pd->tx_msgid[sop], num_data, pd->spec_rev); /* bail out and try again later if a message just arrived */ spin_lock_irqsave(&pd->rx_lock, flags); if (!list_empty(&pd->rx_q)) { spin_unlock_irqrestore(&pd->rx_lock, flags); usbpd_dbg(&pd->dev, "Abort send due to pending RX\n"); return -EBUSY; } spin_unlock_irqrestore(&pd->rx_lock, flags); ret = pd_phy_write(hdr, (u8 *)data, num_data * sizeof(u32), sop); if (ret) { Loading Loading @@ -820,10 +833,6 @@ static int pd_eval_src_caps(struct usbpd *pd) power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED, &val); /* First time connecting to a PD source and it supports USB data */ if (pd->peer_usb_comm && pd->current_dr == DR_UFP && !pd->pd_connected) start_usb_peripheral(pd); /* Check for PPS APDOs */ if (pd->spec_rev == USBPD_REV_30) { for (i = 1; i < PD_MAX_DATA_OBJ; i++) { Loading @@ -846,6 +855,10 @@ static int pd_eval_src_caps(struct usbpd *pd) power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_ACTIVE, &val); /* First time connecting to a PD source and it supports USB data */ if (pd->peer_usb_comm && pd->current_dr == DR_UFP && !pd->pd_connected) start_usb_peripheral(pd); /* Select the first PDO (vSafe5V) immediately. */ pd_select_pdo(pd, 1, 0, 0); Loading Loading @@ -1452,18 +1465,7 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) /* Standard Discovery or unhandled messages go here */ switch (cmd_type) { case SVDM_CMD_TYPE_INITIATOR: if (svid == USBPD_SID && cmd == USBPD_SVDM_DISCOVER_IDENTITY) { u32 tx_vdos[3] = { ID_HDR_USB_HOST | ID_HDR_USB_DEVICE | ID_HDR_PRODUCT_PER_MASK | ID_HDR_VID, 0x0, /* TBD: Cert Stat VDO */ (PROD_VDO_PID << 16), /* TBD: Get these from gadget */ }; usbpd_send_svdm(pd, USBPD_SID, cmd, SVDM_CMD_TYPE_RESP_ACK, 0, tx_vdos, 3); } else if (cmd != USBPD_SVDM_ATTENTION) { if (cmd != USBPD_SVDM_ATTENTION) { usbpd_send_svdm(pd, svid, cmd, SVDM_CMD_TYPE_RESP_NAK, SVDM_HDR_OBJ_POS(vdm_hdr), NULL, 0); } Loading Loading @@ -1509,20 +1511,11 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) static void handle_vdm_tx(struct usbpd *pd, enum pd_sop_type sop_type) { int ret; unsigned long flags; /* only send one VDM at a time */ if (pd->vdm_tx) { u32 vdm_hdr = pd->vdm_tx->data[0]; /* bail out and try again later if a message just arrived */ spin_lock_irqsave(&pd->rx_lock, flags); if (!list_empty(&pd->rx_q)) { spin_unlock_irqrestore(&pd->rx_lock, flags); return; } spin_unlock_irqrestore(&pd->rx_lock, flags); ret = pd_send_msg(pd, MSG_VDM, pd->vdm_tx->data, pd->vdm_tx->size, sop_type); if (ret) { Loading Loading @@ -1598,6 +1591,9 @@ static void dr_swap(struct usbpd *pd) start_usb_host(pd, true); pd->current_dr = DR_DFP; /* ensure host is started before allowing DP */ extcon_blocking_sync(pd->extcon, EXTCON_USB_HOST, 0); usbpd_send_svdm(pd, USBPD_SID, USBPD_SVDM_DISCOVER_IDENTITY, SVDM_CMD_TYPE_INITIATOR, 0, NULL, 0); } Loading Loading @@ -1919,6 +1915,16 @@ static void handle_state_src_send_capabilities(struct usbpd *pd, ret = pd_send_msg(pd, MSG_SOURCE_CAPABILITIES, default_src_caps, ARRAY_SIZE(default_src_caps), SOP_MSG); if (ret) { if (pd->pd_connected) { usbpd_set_state(pd, PE_SEND_SOFT_RESET); break; } /* * Technically this is PE_SRC_Discovery, but we can * handle it by setting a timer to come back to the * same state for the next retry. */ pd->caps_count++; if (pd->caps_count >= PD_CAPS_COUNT) { usbpd_dbg(&pd->dev, "Src CapsCounter exceeded, disabling PD\n"); Loading Loading @@ -2206,9 +2212,19 @@ static void enter_state_snk_startup(struct usbpd *pd) }; union power_supply_propval val = {0}; if (pd->current_dr == DR_NONE || pd->current_dr == DR_UFP) if (pd->current_dr == DR_NONE || pd->current_dr == DR_UFP) { pd->current_dr = DR_UFP; ret = power_supply_get_property(pd->usb_psy, POWER_SUPPLY_PROP_REAL_TYPE, &val); if (!ret) { usbpd_dbg(&pd->dev, "type:%d\n", val.intval); if (val.intval == POWER_SUPPLY_TYPE_USB || val.intval == POWER_SUPPLY_TYPE_USB_CDP) start_usb_peripheral(pd); } } dual_role_instance_changed(pd->dual_role); /* Loading Loading @@ -3186,7 +3202,8 @@ static void usbpd_sm(struct work_struct *w) /* Disconnect? */ if (pd->current_pr == PR_NONE) { if (pd->current_state == PE_UNKNOWN) if (pd->current_state == PE_UNKNOWN && pd->current_dr == DR_NONE) goto sm_done; handle_disconnect(pd); Loading drivers/usb/pd/qpnp-pdphy.c +9 −1 Original line number Diff line number Diff line Loading @@ -473,13 +473,16 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, enum pd_sop_type sop) u8 val; int ret; size_t total_len = data_len + USB_PDPHY_MSG_HDR_LEN; struct usb_pdphy *pdphy; struct usb_pdphy *pdphy = __pdphy; unsigned int msg_rx_cnt; if (!pdphy) { pr_err("%s: pdphy not found\n", __func__); return -ENODEV; } msg_rx_cnt = pdphy->msg_rx_cnt; if (!pdphy->is_opened) { dev_dbg(pdphy->dev, "%s: pdphy disabled\n", __func__); return -ENODEV; Loading Loading @@ -537,6 +540,11 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, enum pd_sop_type sop) else val |= TX_CONTROL_RETRY_COUNT(3); if (msg_rx_cnt != pdphy->msg_rx_cnt) { dev_err(pdphy->dev, "%s: RX message arrived\n", __func__); return -EBUSY; } ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val); if (ret) return ret; Loading drivers/usb/phy/phy-msm-ssusb-qmp.c +111 −14 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ #include <linux/regulator/consumer.h> #include <linux/usb/phy.h> #include <linux/clk.h> #include <linux/extcon.h> #include <linux/reset.h> #include <linux/hrtimer.h> Loading Loading @@ -70,6 +71,7 @@ enum core_ldo_levels { /* USB3_DP_COM_PHY_MODE_CTRL bits */ #define USB3_MODE BIT(0) /* enables USB3 mode */ #define DP_MODE BIT(1) /* enables DP mode */ #define USB3_DP_COMBO_MODE (USB3_MODE | DP_MODE) /*enables combo mode */ /* USB3 Gen2 link training indicator */ #define RX_EQUALIZATION_IN_PROGRESS BIT(3) Loading @@ -82,6 +84,9 @@ enum qmp_phy_rev_reg { USB3_PHY_SW_RESET, USB3_PHY_START, /* TypeC port select configuration (optional) */ USB3_PHY_PCS_MISC_TYPEC_CTRL, /* USB DP Combo PHY related */ USB3_DP_DP_PHY_PD_CTL, USB3_DP_COM_POWER_DOWN_CTRL, Loading @@ -94,8 +99,6 @@ enum qmp_phy_rev_reg { USB3_DP_PCS_PCS_STATUS2, USB3_DP_PCS_INSIG_SW_CTRL3, USB3_DP_PCS_INSIG_MX_CTRL3, /* TypeC port select configuration (optional) */ USB3_PHY_PCS_MISC_TYPEC_CTRL, USB3_PHY_REG_MAX, }; Loading Loading @@ -126,6 +129,8 @@ struct msm_ssphy_qmp { struct reset_control *phy_reset; struct reset_control *phy_phy_reset; struct reset_control *global_phy_reset; struct extcon_dev *extcon_dp; struct notifier_block dp_nb; bool power_enabled; bool clk_enabled; bool cable_connected; Loading Loading @@ -335,6 +340,18 @@ static int configure_phy_regs(struct usb_phy *uphy, return 0; } static void msm_ssphy_qmp_setmode(struct msm_ssphy_qmp *phy, u32 mode) { mode = mode & USB3_DP_COMBO_MODE; writel_relaxed(mode, phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]); /* flush the write by reading it */ readl_relaxed(phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]); } static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy) { int val; Loading @@ -352,9 +369,11 @@ static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy) switch (phy->phy.type) { case USB_PHY_TYPE_USB3_AND_DP: /* override hardware control for reset of qmp phy */ if (!(phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE)) writel_relaxed(SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET, phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]); phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]); /* update port select */ if (val > 0) { Loading @@ -364,12 +383,13 @@ static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy) phy->phy_reg[USB3_DP_COM_TYPEC_CTRL]); } writel_relaxed(USB3_MODE | DP_MODE, phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]); if (!(phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE)) { msm_ssphy_qmp_setmode(phy, USB3_DP_COMBO_MODE); /* bring both QMP USB and QMP DP PHYs PCS block out of reset */ writel_relaxed(0x00, phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]); /* bring both USB and DP PHYs PCS block out of reset */ writel_relaxed(0x00, phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]); } break; case USB_PHY_TYPE_USB3_OR_DP: if (val > 0) { Loading Loading @@ -457,7 +477,8 @@ static int msm_ssphy_qmp_init(struct usb_phy *uphy) } /* perform software reset of PHY common logic */ if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP) if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP && !(phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE)) writel_relaxed(0x00, phy->base + phy->phy_reg[USB3_DP_COM_SW_RESET]); Loading Loading @@ -495,6 +516,25 @@ static int msm_ssphy_qmp_dp_combo_reset(struct usb_phy *uphy) phy); int ret = 0; if (phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE) { dev_dbg(uphy->dev, "Resetting USB part of QMP phy\n"); /* Assert USB3 PHY CSR reset */ ret = reset_control_assert(phy->phy_reset); if (ret) { dev_err(uphy->dev, "phy_reset assert failed\n"); goto exit; } /* Deassert USB3 PHY CSR reset */ ret = reset_control_deassert(phy->phy_reset); if (ret) { dev_err(uphy->dev, "phy_reset deassert failed\n"); goto exit; } return 0; } dev_dbg(uphy->dev, "Global reset of QMP DP combo phy\n"); /* Assert global PHY reset */ ret = reset_control_assert(phy->global_phy_reset); Loading Loading @@ -627,11 +667,14 @@ static int msm_ssphy_qmp_set_suspend(struct usb_phy *uphy, int suspend) } if (suspend) { if (phy->cable_connected) if (phy->cable_connected) { msm_ssusb_qmp_enable_autonomous(phy, 1); else } else { if (uphy->type == USB_PHY_TYPE_USB3_AND_DP) msm_ssphy_qmp_setmode(phy, USB3_MODE); writel_relaxed(0x00, phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); } /* Make sure above write completed with PHY */ wmb(); Loading Loading @@ -758,6 +801,56 @@ static int msm_ssphy_qmp_notify_disconnect(struct usb_phy *uphy, return 0; } static int msm_ssphy_qmp_vbus_notifier(struct notifier_block *nb, unsigned long event, void *ptr) { return 0; } static int msm_ssphy_qmp_dp_notifier(struct notifier_block *nb, unsigned long dp_lane, void *ptr) { struct msm_ssphy_qmp *phy = container_of(nb, struct msm_ssphy_qmp, dp_nb); if (dp_lane == 2 || dp_lane == 4) phy->phy.flags |= PHY_USB_DP_CONCURRENT_MODE; else phy->phy.flags &= ~PHY_USB_DP_CONCURRENT_MODE; return 0; } static int msm_ssphy_qmp_extcon_register(struct msm_ssphy_qmp *phy, struct device *dev) { struct device_node *node = dev->of_node; struct extcon_dev *edev; int ret = 0; if (!of_property_read_bool(node, "extcon")) return 0; edev = extcon_get_edev_by_phandle(dev, 0); if (IS_ERR(edev)) { dev_err(dev, "failed to get phandle for msm_ssphy_qmp\n"); return PTR_ERR(edev); } phy->extcon_dp = edev; phy->phy.vbus_nb.notifier_call = msm_ssphy_qmp_vbus_notifier; phy->dp_nb.notifier_call = msm_ssphy_qmp_dp_notifier; ret = extcon_register_blocking_notifier(edev, EXTCON_DISP_DP, &phy->dp_nb); if (ret < 0) { dev_err(dev, "failed to register blocking notifier\n"); return ret; } return 0; } static int msm_ssphy_qmp_get_clks(struct msm_ssphy_qmp *phy, struct device *dev) { int ret = 0; Loading Loading @@ -877,7 +970,7 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) phy->phy.type = USB_PHY_TYPE_USB3_AND_DP; if (of_device_is_compatible(dev->of_node, "qcom,usb-ssphy-qmp-usb-or-dp")) "qcom,usb-ssphy-qmp-usb3-or-dp")) phy->phy.type = USB_PHY_TYPE_USB3_OR_DP; ret = msm_ssphy_qmp_get_clks(phy, dev); Loading Loading @@ -1069,6 +1162,10 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) else phy->phy.reset = msm_ssphy_qmp_reset; ret = msm_ssphy_qmp_extcon_register(phy, dev); if (ret) goto err; ret = usb_add_phy_dev(&phy->phy); err: Loading include/linux/usb/phy.h +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #define PHY_LANE_B BIT(7) #define PHY_HSFS_MODE BIT(8) #define PHY_LS_MODE BIT(9) #define PHY_USB_DP_CONCURRENT_MODE BIT(10) enum usb_phy_interface { USBPHY_INTERFACE_MODE_UNKNOWN, Loading Loading
drivers/usb/dwc3/dwc3-msm.c +20 −45 Original line number Diff line number Diff line Loading @@ -373,34 +373,9 @@ static inline void dwc3_msm_write_reg_field(void __iomem *base, u32 offset, tmp &= ~mask; /* clear written bits */ val = tmp | (val << shift); iowrite32(val, base + offset); } /** * Write register and read back masked value to confirm it is written * * @base - DWC3 base virtual address. * @offset - register offset. * @mask - register bitmask specifying what should be updated * @val - value to write. * */ static inline void dwc3_msm_write_readback(void __iomem *base, u32 offset, const u32 mask, u32 val) { u32 write_val, tmp = ioread32(base + offset); tmp &= ~mask; /* retain other bits */ write_val = tmp | val; iowrite32(write_val, base + offset); /* Read back to see if val was written */ tmp = ioread32(base + offset); tmp &= mask; /* clear other bits */ if (tmp != val) pr_err("%s: write: %x to QSCRATCH: %x FAILED\n", __func__, val, offset); /* Read back to make sure that previous write goes through */ ioread32(base + offset); } static bool dwc3_msm_is_ss_rhport_connected(struct dwc3_msm *mdwc) Loading Loading @@ -952,21 +927,24 @@ static void gsi_store_ringbase_dbl_info(struct usb_ep *ep, GSI_RING_BASE_ADDR_L(mdwc->gsi_reg[RING_BASE_ADDR_L], (n)), dwc3_trb_dma_offset(dep, &dep->trb_pool[0])); if (request->mapped_db_reg_phs_addr_lsb) dma_unmap_resource(dwc->sysdev, request->mapped_db_reg_phs_addr_lsb, if (!request->mapped_db_reg_phs_addr_lsb) { request->mapped_db_reg_phs_addr_lsb = dma_map_resource(dwc->sysdev, (phys_addr_t)request->db_reg_phs_addr_lsb, PAGE_SIZE, DMA_BIDIRECTIONAL, 0); request->mapped_db_reg_phs_addr_lsb = dma_map_resource(dwc->sysdev, (phys_addr_t)request->db_reg_phs_addr_lsb, PAGE_SIZE, DMA_BIDIRECTIONAL, 0); if (dma_mapping_error(dwc->sysdev, request->mapped_db_reg_phs_addr_lsb)) if (dma_mapping_error(dwc->sysdev, request->mapped_db_reg_phs_addr_lsb)) dev_err(mdwc->dev, "mapping error for db_reg_phs_addr_lsb\n"); } dev_dbg(mdwc->dev, "ep:%s dbl_addr_lsb:%x mapped_dbl_addr_lsb:%llx\n", ep->name, request->db_reg_phs_addr_lsb, (unsigned long long)request->mapped_db_reg_phs_addr_lsb); dbg_log_string("ep:%s dbl_addr_lsb:%x mapped_addr:%llx\n", ep->name, request->db_reg_phs_addr_lsb, (unsigned long long)request->mapped_db_reg_phs_addr_lsb); dwc3_msm_write_reg(mdwc->base, GSI_DBL_ADDR_L(mdwc->gsi_reg[DBL_ADDR_L], (n)), (u32)request->mapped_db_reg_phs_addr_lsb); Loading Loading @@ -4033,17 +4011,14 @@ static void dwc3_override_vbus_status(struct dwc3_msm *mdwc, bool vbus_present) struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); /* Update OTG VBUS Valid from HSPHY to controller */ dwc3_msm_write_readback(mdwc->base, HS_PHY_CTRL_REG, vbus_present ? UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL : UTMI_OTG_VBUS_VALID, vbus_present ? UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL : 0); dwc3_msm_write_reg_field(mdwc->base, HS_PHY_CTRL_REG, UTMI_OTG_VBUS_VALID, !!vbus_present); /* Update only if Super Speed is supported */ if (dwc->maximum_speed >= USB_SPEED_SUPER) { /* Update VBUS Valid from SSPHY to controller */ dwc3_msm_write_readback(mdwc->base, SS_PHY_CTRL_REG, LANE0_PWR_PRESENT, vbus_present ? LANE0_PWR_PRESENT : 0); dwc3_msm_write_reg_field(mdwc->base, SS_PHY_CTRL_REG, LANE0_PWR_PRESENT, !!vbus_present); } } Loading Loading @@ -4145,7 +4120,7 @@ static int dwc3_usb_blocking_sync(struct notifier_block *nb, dbg_event(0xFF, "fw_blocksync", 0); flush_work(&mdwc->resume_work); flush_delayed_work(&mdwc->sm_work); drain_workqueue(mdwc->sm_usb_wq); if (!mdwc->in_host_mode && !mdwc->in_device_mode) { dbg_event(0xFF, "lpm_state", atomic_read(&dwc->in_lpm)); Loading
drivers/usb/pd/policy_engine.c +49 −32 Original line number Diff line number Diff line Loading @@ -230,7 +230,7 @@ static void *usbpd_ipc_log; #define PS_HARD_RESET_TIME 25 #define PS_SOURCE_ON 400 #define PS_SOURCE_OFF 750 #define FIRST_SOURCE_CAP_TIME 200 #define FIRST_SOURCE_CAP_TIME 100 #define VDM_BUSY_TIME 50 #define VCONN_ON_TIME 100 Loading Loading @@ -344,8 +344,6 @@ static void *usbpd_ipc_log; #define ID_HDR_PRODUCT_PER 2 #define ID_HDR_PRODUCT_AMA 5 #define ID_HDR_PRODUCT_VPD 6 #define ID_HDR_VID 0x05c6 /* qcom */ #define PROD_VDO_PID 0x0a00 /* TBD */ #define PD_MIN_SINK_CURRENT 900 Loading Loading @@ -668,14 +666,29 @@ static inline void pd_reset_protocol(struct usbpd *pd) static int pd_send_msg(struct usbpd *pd, u8 msg_type, const u32 *data, size_t num_data, enum pd_sop_type sop) { unsigned long flags; int ret; u16 hdr; if (pd->hard_reset_recvd) return -EBUSY; if (sop == SOP_MSG) hdr = PD_MSG_HDR(msg_type, pd->current_dr, pd->current_pr, pd->tx_msgid[sop], num_data, pd->spec_rev); else /* sending SOP'/SOP'' to a cable, PR/DR fields should be 0 */ hdr = PD_MSG_HDR(msg_type, 0, 0, pd->tx_msgid[sop], num_data, pd->spec_rev); /* bail out and try again later if a message just arrived */ spin_lock_irqsave(&pd->rx_lock, flags); if (!list_empty(&pd->rx_q)) { spin_unlock_irqrestore(&pd->rx_lock, flags); usbpd_dbg(&pd->dev, "Abort send due to pending RX\n"); return -EBUSY; } spin_unlock_irqrestore(&pd->rx_lock, flags); ret = pd_phy_write(hdr, (u8 *)data, num_data * sizeof(u32), sop); if (ret) { Loading Loading @@ -820,10 +833,6 @@ static int pd_eval_src_caps(struct usbpd *pd) power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED, &val); /* First time connecting to a PD source and it supports USB data */ if (pd->peer_usb_comm && pd->current_dr == DR_UFP && !pd->pd_connected) start_usb_peripheral(pd); /* Check for PPS APDOs */ if (pd->spec_rev == USBPD_REV_30) { for (i = 1; i < PD_MAX_DATA_OBJ; i++) { Loading @@ -846,6 +855,10 @@ static int pd_eval_src_caps(struct usbpd *pd) power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_ACTIVE, &val); /* First time connecting to a PD source and it supports USB data */ if (pd->peer_usb_comm && pd->current_dr == DR_UFP && !pd->pd_connected) start_usb_peripheral(pd); /* Select the first PDO (vSafe5V) immediately. */ pd_select_pdo(pd, 1, 0, 0); Loading Loading @@ -1452,18 +1465,7 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) /* Standard Discovery or unhandled messages go here */ switch (cmd_type) { case SVDM_CMD_TYPE_INITIATOR: if (svid == USBPD_SID && cmd == USBPD_SVDM_DISCOVER_IDENTITY) { u32 tx_vdos[3] = { ID_HDR_USB_HOST | ID_HDR_USB_DEVICE | ID_HDR_PRODUCT_PER_MASK | ID_HDR_VID, 0x0, /* TBD: Cert Stat VDO */ (PROD_VDO_PID << 16), /* TBD: Get these from gadget */ }; usbpd_send_svdm(pd, USBPD_SID, cmd, SVDM_CMD_TYPE_RESP_ACK, 0, tx_vdos, 3); } else if (cmd != USBPD_SVDM_ATTENTION) { if (cmd != USBPD_SVDM_ATTENTION) { usbpd_send_svdm(pd, svid, cmd, SVDM_CMD_TYPE_RESP_NAK, SVDM_HDR_OBJ_POS(vdm_hdr), NULL, 0); } Loading Loading @@ -1509,20 +1511,11 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) static void handle_vdm_tx(struct usbpd *pd, enum pd_sop_type sop_type) { int ret; unsigned long flags; /* only send one VDM at a time */ if (pd->vdm_tx) { u32 vdm_hdr = pd->vdm_tx->data[0]; /* bail out and try again later if a message just arrived */ spin_lock_irqsave(&pd->rx_lock, flags); if (!list_empty(&pd->rx_q)) { spin_unlock_irqrestore(&pd->rx_lock, flags); return; } spin_unlock_irqrestore(&pd->rx_lock, flags); ret = pd_send_msg(pd, MSG_VDM, pd->vdm_tx->data, pd->vdm_tx->size, sop_type); if (ret) { Loading Loading @@ -1598,6 +1591,9 @@ static void dr_swap(struct usbpd *pd) start_usb_host(pd, true); pd->current_dr = DR_DFP; /* ensure host is started before allowing DP */ extcon_blocking_sync(pd->extcon, EXTCON_USB_HOST, 0); usbpd_send_svdm(pd, USBPD_SID, USBPD_SVDM_DISCOVER_IDENTITY, SVDM_CMD_TYPE_INITIATOR, 0, NULL, 0); } Loading Loading @@ -1919,6 +1915,16 @@ static void handle_state_src_send_capabilities(struct usbpd *pd, ret = pd_send_msg(pd, MSG_SOURCE_CAPABILITIES, default_src_caps, ARRAY_SIZE(default_src_caps), SOP_MSG); if (ret) { if (pd->pd_connected) { usbpd_set_state(pd, PE_SEND_SOFT_RESET); break; } /* * Technically this is PE_SRC_Discovery, but we can * handle it by setting a timer to come back to the * same state for the next retry. */ pd->caps_count++; if (pd->caps_count >= PD_CAPS_COUNT) { usbpd_dbg(&pd->dev, "Src CapsCounter exceeded, disabling PD\n"); Loading Loading @@ -2206,9 +2212,19 @@ static void enter_state_snk_startup(struct usbpd *pd) }; union power_supply_propval val = {0}; if (pd->current_dr == DR_NONE || pd->current_dr == DR_UFP) if (pd->current_dr == DR_NONE || pd->current_dr == DR_UFP) { pd->current_dr = DR_UFP; ret = power_supply_get_property(pd->usb_psy, POWER_SUPPLY_PROP_REAL_TYPE, &val); if (!ret) { usbpd_dbg(&pd->dev, "type:%d\n", val.intval); if (val.intval == POWER_SUPPLY_TYPE_USB || val.intval == POWER_SUPPLY_TYPE_USB_CDP) start_usb_peripheral(pd); } } dual_role_instance_changed(pd->dual_role); /* Loading Loading @@ -3186,7 +3202,8 @@ static void usbpd_sm(struct work_struct *w) /* Disconnect? */ if (pd->current_pr == PR_NONE) { if (pd->current_state == PE_UNKNOWN) if (pd->current_state == PE_UNKNOWN && pd->current_dr == DR_NONE) goto sm_done; handle_disconnect(pd); Loading
drivers/usb/pd/qpnp-pdphy.c +9 −1 Original line number Diff line number Diff line Loading @@ -473,13 +473,16 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, enum pd_sop_type sop) u8 val; int ret; size_t total_len = data_len + USB_PDPHY_MSG_HDR_LEN; struct usb_pdphy *pdphy; struct usb_pdphy *pdphy = __pdphy; unsigned int msg_rx_cnt; if (!pdphy) { pr_err("%s: pdphy not found\n", __func__); return -ENODEV; } msg_rx_cnt = pdphy->msg_rx_cnt; if (!pdphy->is_opened) { dev_dbg(pdphy->dev, "%s: pdphy disabled\n", __func__); return -ENODEV; Loading Loading @@ -537,6 +540,11 @@ int pd_phy_write(u16 hdr, const u8 *data, size_t data_len, enum pd_sop_type sop) else val |= TX_CONTROL_RETRY_COUNT(3); if (msg_rx_cnt != pdphy->msg_rx_cnt) { dev_err(pdphy->dev, "%s: RX message arrived\n", __func__); return -EBUSY; } ret = pdphy_reg_write(pdphy, USB_PDPHY_TX_CONTROL, val); if (ret) return ret; Loading
drivers/usb/phy/phy-msm-ssusb-qmp.c +111 −14 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ #include <linux/regulator/consumer.h> #include <linux/usb/phy.h> #include <linux/clk.h> #include <linux/extcon.h> #include <linux/reset.h> #include <linux/hrtimer.h> Loading Loading @@ -70,6 +71,7 @@ enum core_ldo_levels { /* USB3_DP_COM_PHY_MODE_CTRL bits */ #define USB3_MODE BIT(0) /* enables USB3 mode */ #define DP_MODE BIT(1) /* enables DP mode */ #define USB3_DP_COMBO_MODE (USB3_MODE | DP_MODE) /*enables combo mode */ /* USB3 Gen2 link training indicator */ #define RX_EQUALIZATION_IN_PROGRESS BIT(3) Loading @@ -82,6 +84,9 @@ enum qmp_phy_rev_reg { USB3_PHY_SW_RESET, USB3_PHY_START, /* TypeC port select configuration (optional) */ USB3_PHY_PCS_MISC_TYPEC_CTRL, /* USB DP Combo PHY related */ USB3_DP_DP_PHY_PD_CTL, USB3_DP_COM_POWER_DOWN_CTRL, Loading @@ -94,8 +99,6 @@ enum qmp_phy_rev_reg { USB3_DP_PCS_PCS_STATUS2, USB3_DP_PCS_INSIG_SW_CTRL3, USB3_DP_PCS_INSIG_MX_CTRL3, /* TypeC port select configuration (optional) */ USB3_PHY_PCS_MISC_TYPEC_CTRL, USB3_PHY_REG_MAX, }; Loading Loading @@ -126,6 +129,8 @@ struct msm_ssphy_qmp { struct reset_control *phy_reset; struct reset_control *phy_phy_reset; struct reset_control *global_phy_reset; struct extcon_dev *extcon_dp; struct notifier_block dp_nb; bool power_enabled; bool clk_enabled; bool cable_connected; Loading Loading @@ -335,6 +340,18 @@ static int configure_phy_regs(struct usb_phy *uphy, return 0; } static void msm_ssphy_qmp_setmode(struct msm_ssphy_qmp *phy, u32 mode) { mode = mode & USB3_DP_COMBO_MODE; writel_relaxed(mode, phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]); /* flush the write by reading it */ readl_relaxed(phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]); } static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy) { int val; Loading @@ -352,9 +369,11 @@ static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy) switch (phy->phy.type) { case USB_PHY_TYPE_USB3_AND_DP: /* override hardware control for reset of qmp phy */ if (!(phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE)) writel_relaxed(SW_DPPHY_RESET_MUX | SW_DPPHY_RESET | SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET, phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]); phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]); /* update port select */ if (val > 0) { Loading @@ -364,12 +383,13 @@ static void usb_qmp_update_portselect_phymode(struct msm_ssphy_qmp *phy) phy->phy_reg[USB3_DP_COM_TYPEC_CTRL]); } writel_relaxed(USB3_MODE | DP_MODE, phy->base + phy->phy_reg[USB3_DP_COM_PHY_MODE_CTRL]); if (!(phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE)) { msm_ssphy_qmp_setmode(phy, USB3_DP_COMBO_MODE); /* bring both QMP USB and QMP DP PHYs PCS block out of reset */ writel_relaxed(0x00, phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]); /* bring both USB and DP PHYs PCS block out of reset */ writel_relaxed(0x00, phy->base + phy->phy_reg[USB3_DP_COM_RESET_OVRD_CTRL]); } break; case USB_PHY_TYPE_USB3_OR_DP: if (val > 0) { Loading Loading @@ -457,7 +477,8 @@ static int msm_ssphy_qmp_init(struct usb_phy *uphy) } /* perform software reset of PHY common logic */ if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP) if (phy->phy.type == USB_PHY_TYPE_USB3_AND_DP && !(phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE)) writel_relaxed(0x00, phy->base + phy->phy_reg[USB3_DP_COM_SW_RESET]); Loading Loading @@ -495,6 +516,25 @@ static int msm_ssphy_qmp_dp_combo_reset(struct usb_phy *uphy) phy); int ret = 0; if (phy->phy.flags & PHY_USB_DP_CONCURRENT_MODE) { dev_dbg(uphy->dev, "Resetting USB part of QMP phy\n"); /* Assert USB3 PHY CSR reset */ ret = reset_control_assert(phy->phy_reset); if (ret) { dev_err(uphy->dev, "phy_reset assert failed\n"); goto exit; } /* Deassert USB3 PHY CSR reset */ ret = reset_control_deassert(phy->phy_reset); if (ret) { dev_err(uphy->dev, "phy_reset deassert failed\n"); goto exit; } return 0; } dev_dbg(uphy->dev, "Global reset of QMP DP combo phy\n"); /* Assert global PHY reset */ ret = reset_control_assert(phy->global_phy_reset); Loading Loading @@ -627,11 +667,14 @@ static int msm_ssphy_qmp_set_suspend(struct usb_phy *uphy, int suspend) } if (suspend) { if (phy->cable_connected) if (phy->cable_connected) { msm_ssusb_qmp_enable_autonomous(phy, 1); else } else { if (uphy->type == USB_PHY_TYPE_USB3_AND_DP) msm_ssphy_qmp_setmode(phy, USB3_MODE); writel_relaxed(0x00, phy->base + phy->phy_reg[USB3_PHY_POWER_DOWN_CONTROL]); } /* Make sure above write completed with PHY */ wmb(); Loading Loading @@ -758,6 +801,56 @@ static int msm_ssphy_qmp_notify_disconnect(struct usb_phy *uphy, return 0; } static int msm_ssphy_qmp_vbus_notifier(struct notifier_block *nb, unsigned long event, void *ptr) { return 0; } static int msm_ssphy_qmp_dp_notifier(struct notifier_block *nb, unsigned long dp_lane, void *ptr) { struct msm_ssphy_qmp *phy = container_of(nb, struct msm_ssphy_qmp, dp_nb); if (dp_lane == 2 || dp_lane == 4) phy->phy.flags |= PHY_USB_DP_CONCURRENT_MODE; else phy->phy.flags &= ~PHY_USB_DP_CONCURRENT_MODE; return 0; } static int msm_ssphy_qmp_extcon_register(struct msm_ssphy_qmp *phy, struct device *dev) { struct device_node *node = dev->of_node; struct extcon_dev *edev; int ret = 0; if (!of_property_read_bool(node, "extcon")) return 0; edev = extcon_get_edev_by_phandle(dev, 0); if (IS_ERR(edev)) { dev_err(dev, "failed to get phandle for msm_ssphy_qmp\n"); return PTR_ERR(edev); } phy->extcon_dp = edev; phy->phy.vbus_nb.notifier_call = msm_ssphy_qmp_vbus_notifier; phy->dp_nb.notifier_call = msm_ssphy_qmp_dp_notifier; ret = extcon_register_blocking_notifier(edev, EXTCON_DISP_DP, &phy->dp_nb); if (ret < 0) { dev_err(dev, "failed to register blocking notifier\n"); return ret; } return 0; } static int msm_ssphy_qmp_get_clks(struct msm_ssphy_qmp *phy, struct device *dev) { int ret = 0; Loading Loading @@ -877,7 +970,7 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) phy->phy.type = USB_PHY_TYPE_USB3_AND_DP; if (of_device_is_compatible(dev->of_node, "qcom,usb-ssphy-qmp-usb-or-dp")) "qcom,usb-ssphy-qmp-usb3-or-dp")) phy->phy.type = USB_PHY_TYPE_USB3_OR_DP; ret = msm_ssphy_qmp_get_clks(phy, dev); Loading Loading @@ -1069,6 +1162,10 @@ static int msm_ssphy_qmp_probe(struct platform_device *pdev) else phy->phy.reset = msm_ssphy_qmp_reset; ret = msm_ssphy_qmp_extcon_register(phy, dev); if (ret) goto err; ret = usb_add_phy_dev(&phy->phy); err: Loading
include/linux/usb/phy.h +1 −0 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #define PHY_LANE_B BIT(7) #define PHY_HSFS_MODE BIT(8) #define PHY_LS_MODE BIT(9) #define PHY_USB_DP_CONCURRENT_MODE BIT(10) enum usb_phy_interface { USBPHY_INTERFACE_MODE_UNKNOWN, Loading