static int dwc3_remove(struct platform_device *pdev) { struct dwc3 *dwc = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pm_runtime_get_sync(&pdev->dev); /* * restore res->start back to its original value so that, in case the * probe is deferred, we don't end up getting error in request the * memory region the next time probe is called. */ res->start -= DWC3_GLOBALS_REGS_START; dwc3_debugfs_exit(dwc); dwc3_core_exit_mode(dwc); dwc3_core_exit(dwc); dwc3_ulpi_exit(dwc); pm_runtime_put_sync(&pdev->dev); pm_runtime_allow(&pdev->dev); pm_runtime_disable(&pdev->dev); dwc3_free_event_buffers(dwc); dwc3_free_scratch_buffers(dwc); return 0; }
static int dwc3_remove(struct platform_device *pdev) { struct dwc3 *dwc = platform_get_drvdata(pdev); pm_runtime_get_sync(&pdev->dev); dwc3_debugfs_exit(dwc); dwc3_core_exit_mode(dwc); dwc3_event_buffers_cleanup(dwc); dwc3_core_exit(dwc); dwc3_ulpi_exit(dwc); pm_runtime_put_sync(&pdev->dev); pm_runtime_allow(&pdev->dev); pm_runtime_disable(&pdev->dev); dwc3_free_event_buffers(dwc); dwc3_free_scratch_buffers(dwc); clk_bulk_put(dwc->num_clks, dwc->clks); return 0; }
static int dwc3_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct resource *res; struct dwc3 *dwc; int ret; void __iomem *regs; dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL); if (!dwc) return -ENOMEM; dwc->dev = dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "missing memory resource\n"); return -ENODEV; } dwc->xhci_resources[0].start = res->start; dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + DWC3_XHCI_REGS_END; dwc->xhci_resources[0].flags = res->flags; dwc->xhci_resources[0].name = res->name; res->start += DWC3_GLOBALS_REGS_START; /* * Request memory region but exclude xHCI regs, * since it will be requested by the xhci-plat driver. */ regs = devm_ioremap_resource(dev, res); if (IS_ERR(regs)) { ret = PTR_ERR(regs); goto err0; } dwc->regs = regs; dwc->regs_size = resource_size(res); dwc3_get_properties(dwc); platform_set_drvdata(pdev, dwc); dwc3_cache_hwparams(dwc); ret = dwc3_core_get_phy(dwc); if (ret) goto err0; spin_lock_init(&dwc->lock); pm_runtime_set_active(dev); pm_runtime_use_autosuspend(dev); pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY); pm_runtime_enable(dev); ret = pm_runtime_get_sync(dev); if (ret < 0) goto err1; pm_runtime_forbid(dev); ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); if (ret) { dev_err(dwc->dev, "failed to allocate event buffers\n"); ret = -ENOMEM; goto err2; } ret = dwc3_get_dr_mode(dwc); if (ret) goto err3; ret = dwc3_alloc_scratch_buffers(dwc); if (ret) goto err3; ret = dwc3_core_init(dwc); if (ret) { dev_err(dev, "failed to initialize core\n"); goto err4; } dwc3_check_params(dwc); ret = dwc3_core_init_mode(dwc); if (ret) goto err5; dwc3_debugfs_init(dwc); pm_runtime_put(dev); return 0; err5: dwc3_event_buffers_cleanup(dwc); err4: dwc3_free_scratch_buffers(dwc); err3: dwc3_free_event_buffers(dwc); dwc3_ulpi_exit(dwc); err2: pm_runtime_allow(&pdev->dev); err1: pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); err0: /* * restore res->start back to its original value so that, in case the * probe is deferred, we don't end up getting error in request the * memory region the next time probe is called. */ res->start -= DWC3_GLOBALS_REGS_START; return ret; }
static int dwc3_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct dwc3_platform_data *pdata = dev_get_platdata(dev); struct resource *res; struct dwc3 *dwc; u8 lpm_nyet_threshold; u8 tx_de_emphasis; u8 hird_threshold; u32 fladj = 0; int ret; void __iomem *regs; void *mem; mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); if (!mem) return -ENOMEM; dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); dwc->mem = mem; dwc->dev = dev; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(dev, "missing IRQ\n"); return -ENODEV; } dwc->xhci_resources[1].start = res->start; dwc->xhci_resources[1].end = res->end; dwc->xhci_resources[1].flags = res->flags; dwc->xhci_resources[1].name = res->name; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "missing memory resource\n"); return -ENODEV; } dwc->xhci_resources[0].start = res->start; dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + DWC3_XHCI_REGS_END; dwc->xhci_resources[0].flags = res->flags; dwc->xhci_resources[0].name = res->name; res->start += DWC3_GLOBALS_REGS_START; /* * Request memory region but exclude xHCI regs, * since it will be requested by the xhci-plat driver. */ regs = devm_ioremap_resource(dev, res); if (IS_ERR(regs)) { ret = PTR_ERR(regs); goto err0; } dwc->regs = regs; dwc->regs_size = resource_size(res); /* default to highest possible threshold */ lpm_nyet_threshold = 0xff; /* default to -3.5dB de-emphasis */ tx_de_emphasis = 1; /* * default to assert utmi_sleep_n and use maximum allowed HIRD * threshold value of 0b1100 */ hird_threshold = 12; dwc->maximum_speed = usb_get_maximum_speed(dev); dwc->dr_mode = usb_get_dr_mode(dev); dwc->has_lpm_erratum = device_property_read_bool(dev, "snps,has-lpm-erratum"); device_property_read_u8(dev, "snps,lpm-nyet-threshold", &lpm_nyet_threshold); dwc->is_utmi_l1_suspend = device_property_read_bool(dev, "snps,is-utmi-l1-suspend"); device_property_read_u8(dev, "snps,hird-threshold", &hird_threshold); dwc->usb3_lpm_capable = device_property_read_bool(dev, "snps,usb3_lpm_capable"); dwc->needs_fifo_resize = device_property_read_bool(dev, "tx-fifo-resize"); dwc->disable_scramble_quirk = device_property_read_bool(dev, "snps,disable_scramble_quirk"); dwc->u2exit_lfps_quirk = device_property_read_bool(dev, "snps,u2exit_lfps_quirk"); dwc->u2ss_inp3_quirk = device_property_read_bool(dev, "snps,u2ss_inp3_quirk"); dwc->req_p1p2p3_quirk = device_property_read_bool(dev, "snps,req_p1p2p3_quirk"); dwc->del_p1p2p3_quirk = device_property_read_bool(dev, "snps,del_p1p2p3_quirk"); dwc->del_phy_power_chg_quirk = device_property_read_bool(dev, "snps,del_phy_power_chg_quirk"); dwc->lfps_filter_quirk = device_property_read_bool(dev, "snps,lfps_filter_quirk"); dwc->rx_detect_poll_quirk = device_property_read_bool(dev, "snps,rx_detect_poll_quirk"); dwc->dis_u3_susphy_quirk = device_property_read_bool(dev, "snps,dis_u3_susphy_quirk"); dwc->dis_u2_susphy_quirk = device_property_read_bool(dev, "snps,dis_u2_susphy_quirk"); dwc->dis_enblslpm_quirk = device_property_read_bool(dev, "snps,dis_enblslpm_quirk"); dwc->tx_de_emphasis_quirk = device_property_read_bool(dev, "snps,tx_de_emphasis_quirk"); device_property_read_u8(dev, "snps,tx_de_emphasis", &tx_de_emphasis); device_property_read_string(dev, "snps,hsphy_interface", &dwc->hsphy_interface); device_property_read_u32(dev, "snps,quirk-frame-length-adjustment", &fladj); if (pdata) { dwc->maximum_speed = pdata->maximum_speed; dwc->has_lpm_erratum = pdata->has_lpm_erratum; if (pdata->lpm_nyet_threshold) lpm_nyet_threshold = pdata->lpm_nyet_threshold; dwc->is_utmi_l1_suspend = pdata->is_utmi_l1_suspend; if (pdata->hird_threshold) hird_threshold = pdata->hird_threshold; dwc->needs_fifo_resize = pdata->tx_fifo_resize; dwc->usb3_lpm_capable = pdata->usb3_lpm_capable; dwc->dr_mode = pdata->dr_mode; dwc->disable_scramble_quirk = pdata->disable_scramble_quirk; dwc->u2exit_lfps_quirk = pdata->u2exit_lfps_quirk; dwc->u2ss_inp3_quirk = pdata->u2ss_inp3_quirk; dwc->req_p1p2p3_quirk = pdata->req_p1p2p3_quirk; dwc->del_p1p2p3_quirk = pdata->del_p1p2p3_quirk; dwc->del_phy_power_chg_quirk = pdata->del_phy_power_chg_quirk; dwc->lfps_filter_quirk = pdata->lfps_filter_quirk; dwc->rx_detect_poll_quirk = pdata->rx_detect_poll_quirk; dwc->dis_u3_susphy_quirk = pdata->dis_u3_susphy_quirk; dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk; dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk; dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk; if (pdata->tx_de_emphasis) tx_de_emphasis = pdata->tx_de_emphasis; dwc->hsphy_interface = pdata->hsphy_interface; fladj = pdata->fladj_value; } dwc->lpm_nyet_threshold = lpm_nyet_threshold; dwc->tx_de_emphasis = tx_de_emphasis; dwc->hird_threshold = hird_threshold | (dwc->is_utmi_l1_suspend << 4); platform_set_drvdata(pdev, dwc); dwc3_cache_hwparams(dwc); ret = dwc3_phy_setup(dwc); if (ret) goto err0; ret = dwc3_core_get_phy(dwc); if (ret) goto err0; spin_lock_init(&dwc->lock); if (!dev->dma_mask) { dev->dma_mask = dev->parent->dma_mask; dev->dma_parms = dev->parent->dma_parms; dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); } pm_runtime_enable(dev); pm_runtime_get_sync(dev); pm_runtime_forbid(dev); ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); if (ret) { dev_err(dwc->dev, "failed to allocate event buffers\n"); ret = -ENOMEM; goto err1; } if (IS_ENABLED(CONFIG_USB_DWC3_HOST)) dwc->dr_mode = USB_DR_MODE_HOST; else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) dwc->dr_mode = USB_DR_MODE_PERIPHERAL; if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) dwc->dr_mode = USB_DR_MODE_OTG; ret = dwc3_core_init(dwc); if (ret) { dev_err(dev, "failed to initialize core\n"); goto err1; } /* Check the maximum_speed parameter */ switch (dwc->maximum_speed) { case USB_SPEED_LOW: case USB_SPEED_FULL: case USB_SPEED_HIGH: case USB_SPEED_SUPER: case USB_SPEED_SUPER_PLUS: break; default: dev_err(dev, "invalid maximum_speed parameter %d\n", dwc->maximum_speed); /* fall through */ case USB_SPEED_UNKNOWN: /* default to superspeed */ dwc->maximum_speed = USB_SPEED_SUPER; /* * default to superspeed plus if we are capable. */ if (dwc3_is_usb31(dwc) && (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) == DWC3_GHWPARAMS3_SSPHY_IFC_GEN2)) dwc->maximum_speed = USB_SPEED_SUPER_PLUS; break; } /* Adjust Frame Length */ dwc3_frame_length_adjustment(dwc, fladj); usb_phy_set_suspend(dwc->usb2_phy, 0); usb_phy_set_suspend(dwc->usb3_phy, 0); ret = phy_power_on(dwc->usb2_generic_phy); if (ret < 0) goto err2; ret = phy_power_on(dwc->usb3_generic_phy); if (ret < 0) goto err3; ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); goto err4; } ret = dwc3_core_init_mode(dwc); if (ret) goto err5; ret = dwc3_debugfs_init(dwc); if (ret) { dev_err(dev, "failed to initialize debugfs\n"); goto err6; } pm_runtime_allow(dev); return 0; err6: dwc3_core_exit_mode(dwc); err5: dwc3_event_buffers_cleanup(dwc); err4: phy_power_off(dwc->usb3_generic_phy); err3: phy_power_off(dwc->usb2_generic_phy); err2: usb_phy_set_suspend(dwc->usb2_phy, 1); usb_phy_set_suspend(dwc->usb3_phy, 1); dwc3_core_exit(dwc); err1: dwc3_free_event_buffers(dwc); dwc3_ulpi_exit(dwc); err0: /* * restore res->start back to its original value so that, in case the * probe is deferred, we don't end up getting error in request the * memory region the next time probe is called. */ res->start -= DWC3_GLOBALS_REGS_START; return ret; }
/** * dwc3_core_init - Low-level initialization of DWC3 Core * @dwc: Pointer to our controller context structure * * Returns 0 on success otherwise negative errno. */ int dwc3_core_init(struct dwc3 *dwc) { u32 reg; int ret; if (!dwc3_core_is_valid(dwc)) { dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); ret = -ENODEV; goto err0; } /* * Write Linux Version Code to our GUID register so it's easy to figure * out which kernel version a bug was found. */ dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE); /* Handle USB2.0-only core configuration */ if (DWC3_GHWPARAMS3_SSPHY_IFC(dwc->hwparams.hwparams3) == DWC3_GHWPARAMS3_SSPHY_IFC_DIS) { if (dwc->maximum_speed == USB_SPEED_SUPER) dwc->maximum_speed = USB_SPEED_HIGH; } ret = dwc3_phy_setup(dwc); if (ret) goto err0; if (!dwc->ulpi_ready) { ret = dwc3_core_ulpi_init(dwc); if (ret) goto err0; dwc->ulpi_ready = true; } if (!dwc->phys_ready) { ret = dwc3_core_get_phy(dwc); if (ret) goto err0a; dwc->phys_ready = true; } ret = dwc3_core_soft_reset(dwc); if (ret) goto err0a; dwc3_core_setup_global_control(dwc); dwc3_core_num_eps(dwc); if (dwc->scratchbuf == NULL) { ret = dwc3_alloc_scratch_buffers(dwc); if (ret) { dev_err(dwc->dev, "Not enough memory for scratch buffers\n"); goto err1; } } ret = dwc3_setup_scratch_buffers(dwc); if (ret) { dev_err(dwc->dev, "Failed to setup scratch buffers: %d\n", ret); goto err1; } /* Adjust Frame Length */ dwc3_frame_length_adjustment(dwc); dwc3_set_incr_burst_type(dwc); ret = dwc3_config_soc_bus(dwc); if (ret) goto err1; usb_phy_set_suspend(dwc->usb2_phy, 0); usb_phy_set_suspend(dwc->usb3_phy, 0); ret = phy_power_on(dwc->usb2_generic_phy); if (ret < 0) goto err2; ret = phy_power_on(dwc->usb3_generic_phy); if (ret < 0) goto err3; ret = dwc3_event_buffers_setup(dwc); if (ret) { dev_err(dwc->dev, "failed to setup event buffers\n"); goto err4; } switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE); break; case USB_DR_MODE_HOST: dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); break; case USB_DR_MODE_OTG: dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG); break; default: dev_warn(dwc->dev, "Unsupported mode %d\n", dwc->dr_mode); break; } /* * ENDXFER polling is available on version 3.10a and later of * the DWC_usb3 controller. It is NOT available in the * DWC_usb31 controller. */ if (!dwc3_is_usb31(dwc) && dwc->revision >= DWC3_REVISION_310A) { reg = dwc3_readl(dwc->regs, DWC3_GUCTL2); reg |= DWC3_GUCTL2_RST_ACTBITLATER; dwc3_writel(dwc->regs, DWC3_GUCTL2, reg); } /* When configured in HOST mode, after issuing U3/L2 exit controller * fails to send proper CRC checksum in CRC5 feild. Because of this * behaviour Transaction Error is generated, resulting in reset and * re-enumeration of usb device attached. Enabling bit 10 of GUCTL1 * will correct this problem */ if (dwc->enable_guctl1_resume_quirk) { reg = dwc3_readl(dwc->regs, DWC3_GUCTL1); reg |= DWC3_GUCTL1_RESUME_QUIRK; dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); } /* SNPS controller when configureed in HOST mode maintains Inter Packet * Delay (IPD) of ~380ns which works with most of the super-speed hubs * except VIA-LAB hubs. When IPD is ~380ns HOST controller fails to * enumerate FS/LS devices when connected behind VIA-LAB hubs. * Enabling bit 9 of GUCTL1 enables the workaround in HW to reduce the * ULPI clock latency by 1 cycle, thus reducing the IPD (~360ns) and * making controller enumerate FS/LS devices connected behind VIA-LAB. */ if (dwc->enable_guctl1_ipd_quirk) { reg = dwc3_readl(dwc->regs, DWC3_GUCTL1); reg |= DWC3_GUCTL1_IPD_QUIRK; dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); } if (dwc->revision >= DWC3_REVISION_250A) { reg = dwc3_readl(dwc->regs, DWC3_GUCTL1); /* * Enable hardware control of sending remote wakeup * in HS when the device is in the L1 state. */ if (dwc->revision >= DWC3_REVISION_290A) reg |= DWC3_GUCTL1_DEV_L1_EXIT_BY_HW; if (dwc->dis_tx_ipgap_linecheck_quirk) reg |= DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS; dwc3_writel(dwc->regs, DWC3_GUCTL1, reg); } if (dwc->dr_mode == USB_DR_MODE_HOST || dwc->dr_mode == USB_DR_MODE_OTG) { reg = dwc3_readl(dwc->regs, DWC3_GUCTL); /* * Enable Auto retry Feature to make the controller operating in * Host mode on seeing transaction errors(CRC errors or internal * overrun scenerios) on IN transfers to reply to the device * with a non-terminating retry ACK (i.e, an ACK transcation * packet with Retry=1 & Nump != 0) */ reg |= DWC3_GUCTL_HSTINAUTORETRY; dwc3_writel(dwc->regs, DWC3_GUCTL, reg); } /* * Must config both number of packets and max burst settings to enable * RX and/or TX threshold. */ if (dwc3_is_usb31(dwc) && dwc->dr_mode == USB_DR_MODE_HOST) { u8 rx_thr_num = dwc->rx_thr_num_pkt_prd; u8 rx_maxburst = dwc->rx_max_burst_prd; u8 tx_thr_num = dwc->tx_thr_num_pkt_prd; u8 tx_maxburst = dwc->tx_max_burst_prd; if (rx_thr_num && rx_maxburst) { reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG); reg |= DWC31_RXTHRNUMPKTSEL_PRD; reg &= ~DWC31_RXTHRNUMPKT_PRD(~0); reg |= DWC31_RXTHRNUMPKT_PRD(rx_thr_num); reg &= ~DWC31_MAXRXBURSTSIZE_PRD(~0); reg |= DWC31_MAXRXBURSTSIZE_PRD(rx_maxburst); dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg); } if (tx_thr_num && tx_maxburst) { reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG); reg |= DWC31_TXTHRNUMPKTSEL_PRD; reg &= ~DWC31_TXTHRNUMPKT_PRD(~0); reg |= DWC31_TXTHRNUMPKT_PRD(tx_thr_num); reg &= ~DWC31_MAXTXBURSTSIZE_PRD(~0); reg |= DWC31_MAXTXBURSTSIZE_PRD(tx_maxburst); dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg); } } return 0; err4: phy_power_off(dwc->usb3_generic_phy); err3: phy_power_off(dwc->usb2_generic_phy); err2: usb_phy_set_suspend(dwc->usb2_phy, 1); usb_phy_set_suspend(dwc->usb3_phy, 1); err1: usb_phy_shutdown(dwc->usb2_phy); usb_phy_shutdown(dwc->usb3_phy); phy_exit(dwc->usb2_generic_phy); phy_exit(dwc->usb3_generic_phy); err0a: dwc3_ulpi_exit(dwc); err0: return ret; }