The Linux core.c has no U-Boot entry points like dwc3_uboot_init() and dwc3_init(). Copy them back unchanged from the core.c we had before "usb: dwc3: restore to original v3.19-rc1 kernel import", with the struct members and prototypes they use.
A diff against that old core.c shows no change for them. What they need for the resynced core comes in the next commit. Co-developed-by: Jerome Forissier <[email protected]> Signed-off-by: Jerome Forissier <[email protected]> Co-developed-by: Jens Wiklander <[email protected]> Signed-off-by: Jens Wiklander <[email protected]> Signed-off-by: Anders Roxell <[email protected]> --- drivers/usb/dwc3/core.c | 420 ++++++++++++++++++++++++++++++++++++++++ drivers/usb/dwc3/core.h | 11 ++ 2 files changed, 431 insertions(+) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index dee68745b94a..8db1dd2c29a1 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -45,6 +45,8 @@ #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ +static LIST_HEAD(dwc3_list); + void dwc3_enable_susphy(struct dwc3 *dwc, bool enable) { u32 reg; @@ -1315,6 +1317,14 @@ static int dwc3_core_init_mode(struct dwc3 *dwc) return 0; } +static void dwc3_core_stop(struct dwc3 *dwc) +{ + u32 reg; + + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + dwc3_writel(dwc->regs, DWC3_DCTL, reg & ~(DWC3_DCTL_RUN_STOP)); +} + static void dwc3_core_exit_mode(struct dwc3 *dwc) { switch (dwc->dr_mode) { @@ -1336,6 +1346,8 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc) dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, true); } +#define DWC3_ALIGN_MASK (16 - 1) + /* check whether the core supports IMOD */ bool dwc3_has_imod(struct dwc3 *dwc) { @@ -1392,3 +1404,411 @@ static int dwc3_get_num_ports(struct dwc3 *dwc) return 0; } + +#if CONFIG_IS_ENABLED(PHY) && CONFIG_IS_ENABLED(DM_USB) +int dwc3_setup_phy(struct udevice *dev, struct phy_bulk *phys) +{ + int ret; + + ret = generic_phy_get_bulk(dev, phys); + if (ret) + return ret; + + ret = generic_phy_init_bulk(phys); + if (ret) + return ret; + + ret = generic_phy_power_on_bulk(phys); + if (ret) + generic_phy_exit_bulk(phys); + + return ret; +} + +int dwc3_shutdown_phy(struct udevice *dev, struct phy_bulk *phys) +{ + int ret; + + ret = generic_phy_power_off_bulk(phys); + ret |= generic_phy_exit_bulk(phys); + return ret; +} +#endif + +#if CONFIG_IS_ENABLED(DM_USB) +void dwc3_of_parse(struct dwc3 *dwc) +{ + const u8 *tmp; + struct udevice *dev = dwc->dev; + u8 lpm_nyet_threshold; + u8 tx_de_emphasis; + u8 hird_threshold; + u32 val; + int i; + + /* 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->hsphy_mode = usb_get_phy_mode(dev_ofnode(dev)); + + dwc->has_lpm_erratum = dev_read_bool(dev, + "snps,has-lpm-erratum"); + tmp = dev_read_u8_array_ptr(dev, "snps,lpm-nyet-threshold", 1); + if (tmp) + lpm_nyet_threshold = *tmp; + + dwc->is_utmi_l1_suspend = dev_read_bool(dev, + "snps,is-utmi-l1-suspend"); + tmp = dev_read_u8_array_ptr(dev, "snps,hird-threshold", 1); + if (tmp) + hird_threshold = *tmp; + + dwc->disable_scramble_quirk = dev_read_bool(dev, + "snps,disable_scramble_quirk"); + dwc->u2exit_lfps_quirk = dev_read_bool(dev, + "snps,u2exit_lfps_quirk"); + dwc->u2ss_inp3_quirk = dev_read_bool(dev, + "snps,u2ss_inp3_quirk"); + dwc->req_p1p2p3_quirk = dev_read_bool(dev, + "snps,req_p1p2p3_quirk"); + dwc->del_p1p2p3_quirk = dev_read_bool(dev, + "snps,del_p1p2p3_quirk"); + dwc->del_phy_power_chg_quirk = dev_read_bool(dev, + "snps,del_phy_power_chg_quirk"); + dwc->lfps_filter_quirk = dev_read_bool(dev, + "snps,lfps_filter_quirk"); + dwc->rx_detect_poll_quirk = dev_read_bool(dev, + "snps,rx_detect_poll_quirk"); + dwc->dis_u3_susphy_quirk = dev_read_bool(dev, + "snps,dis_u3_susphy_quirk"); + dwc->dis_u2_susphy_quirk = dev_read_bool(dev, + "snps,dis_u2_susphy_quirk"); + dwc->dis_del_phy_power_chg_quirk = dev_read_bool(dev, + "snps,dis-del-phy-power-chg-quirk"); + dwc->dis_tx_ipgap_linecheck_quirk = dev_read_bool(dev, + "snps,dis-tx-ipgap-linecheck-quirk"); + dwc->dis_enblslpm_quirk = dev_read_bool(dev, + "snps,dis_enblslpm_quirk"); + dwc->dis_u2_freeclk_exists_quirk = dev_read_bool(dev, + "snps,dis-u2-freeclk-exists-quirk"); + dwc->tx_de_emphasis_quirk = dev_read_bool(dev, + "snps,tx_de_emphasis_quirk"); + tmp = dev_read_u8_array_ptr(dev, "snps,tx_de_emphasis", 1); + if (tmp) + tx_de_emphasis = *tmp; + + 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); + + dev_read_u32(dev, "snps,quirk-frame-length-adjustment", &dwc->fladj); + + /* + * Handle property "snps,incr-burst-type-adjustment". + * Get the number of value from this property: + * result <= 0, means this property is not supported. + * result = 1, means INCRx burst mode supported. + * result > 1, means undefined length burst mode supported. + */ + dwc->incrx_mode = INCRX_BURST_MODE; + dwc->incrx_size = 0; + for (i = 0; i < 8; i++) { + if (dev_read_u32_index(dev, "snps,incr-burst-type-adjustment", + i, &val)) + break; + + dwc->incrx_mode = INCRX_UNDEF_LENGTH_BURST_MODE; + dwc->incrx_size = max(dwc->incrx_size, val); + } +} + +int dwc3_init(struct dwc3 *dwc) +{ + int ret; + u32 reg; + + dwc3_cache_hwparams(dwc); + + ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); + if (ret) { + dev_err(dwc->dev, "failed to allocate event buffers\n"); + return -ENOMEM; + } + + ret = dwc3_core_init(dwc); + if (ret) { + dev_err(dwc->dev, "failed to initialize core\n"); + goto core_fail; + } + + ret = dwc3_event_buffers_setup(dwc); + if (ret) { + dev_err(dwc->dev, "failed to setup event buffers\n"); + goto event_fail; + } + + 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); + + reg |= DWC3_GUCTL_HSTINAUTORETRY; + + dwc3_writel(dwc->regs, DWC3_GUCTL, reg); + } + + ret = dwc3_core_init_mode(dwc); + if (ret) + goto mode_fail; + + return 0; + +mode_fail: + dwc3_event_buffers_cleanup(dwc); + +event_fail: + dwc3_core_exit(dwc); + +core_fail: + dwc3_free_event_buffers(dwc); + + return ret; +} + +void dwc3_remove(struct dwc3 *dwc) +{ + dwc3_core_exit_mode(dwc); + dwc3_event_buffers_cleanup(dwc); + dwc3_free_event_buffers(dwc); + dwc3_core_stop(dwc); + dwc3_core_exit(dwc); + kfree(dwc->mem); +} +#endif + +/** + * dwc3_uboot_init - dwc3 core uboot initialization code + * @dwc3_dev: struct dwc3_device containing initialization data + * + * Entry point for dwc3 driver (equivalent to dwc3_probe in linux + * kernel driver). Pointer to dwc3_device should be passed containing + * base address and other initialization data. Returns '0' on success and + * a negative value on failure. + * + * Generally called from board_usb_init() implemented in board file. + */ +int dwc3_uboot_init(struct dwc3_device *dwc3_dev) +{ + struct dwc3 *dwc; + struct device *dev = NULL; + u8 lpm_nyet_threshold; + u8 tx_de_emphasis; + u8 hird_threshold; + + int ret; + + void *mem; + + mem = devm_kzalloc((struct udevice *)dev, + sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); + if (!mem) + return -ENOMEM; + + dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); + dwc->mem = mem; + + dwc->regs = (void *)(uintptr_t)(dwc3_dev->base + + DWC3_GLOBALS_REGS_START); + + /* 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 = dwc3_dev->maximum_speed; + dwc->has_lpm_erratum = dwc3_dev->has_lpm_erratum; + if (dwc3_dev->lpm_nyet_threshold) + lpm_nyet_threshold = dwc3_dev->lpm_nyet_threshold; + dwc->is_utmi_l1_suspend = dwc3_dev->is_utmi_l1_suspend; + if (dwc3_dev->hird_threshold) + hird_threshold = dwc3_dev->hird_threshold; + + dwc->needs_fifo_resize = dwc3_dev->tx_fifo_resize; + dwc->dr_mode = dwc3_dev->dr_mode; + + dwc->disable_scramble_quirk = dwc3_dev->disable_scramble_quirk; + dwc->u2exit_lfps_quirk = dwc3_dev->u2exit_lfps_quirk; + dwc->u2ss_inp3_quirk = dwc3_dev->u2ss_inp3_quirk; + dwc->req_p1p2p3_quirk = dwc3_dev->req_p1p2p3_quirk; + dwc->del_p1p2p3_quirk = dwc3_dev->del_p1p2p3_quirk; + dwc->del_phy_power_chg_quirk = dwc3_dev->del_phy_power_chg_quirk; + dwc->lfps_filter_quirk = dwc3_dev->lfps_filter_quirk; + dwc->rx_detect_poll_quirk = dwc3_dev->rx_detect_poll_quirk; + dwc->dis_u3_susphy_quirk = dwc3_dev->dis_u3_susphy_quirk; + dwc->dis_u2_susphy_quirk = dwc3_dev->dis_u2_susphy_quirk; + dwc->dis_del_phy_power_chg_quirk = dwc3_dev->dis_del_phy_power_chg_quirk; + dwc->dis_tx_ipgap_linecheck_quirk = dwc3_dev->dis_tx_ipgap_linecheck_quirk; + dwc->dis_enblslpm_quirk = dwc3_dev->dis_enblslpm_quirk; + dwc->dis_u2_freeclk_exists_quirk = dwc3_dev->dis_u2_freeclk_exists_quirk; + + dwc->tx_de_emphasis_quirk = dwc3_dev->tx_de_emphasis_quirk; + if (dwc3_dev->tx_de_emphasis) + tx_de_emphasis = dwc3_dev->tx_de_emphasis; + + /* default to superspeed if no maximum_speed passed */ + if (dwc->maximum_speed == USB_SPEED_UNKNOWN) + dwc->maximum_speed = USB_SPEED_SUPER; + + 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); + + dwc->hsphy_mode = dwc3_dev->hsphy_mode; + + dwc->index = dwc3_dev->index; + + dwc3_cache_hwparams(dwc); + + ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); + if (ret) { + dev_err(dwc->dev, "failed to allocate event buffers\n"); + return -ENOMEM; + } + + if (!IS_ENABLED(CONFIG_USB_DWC3_GADGET)) + dwc->dr_mode = USB_DR_MODE_HOST; + else if (!IS_ENABLED(CONFIG_USB_HOST)) + 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(dwc->dev, "failed to initialize core\n"); + goto err0; + } + + ret = dwc3_event_buffers_setup(dwc); + if (ret) { + dev_err(dwc->dev, "failed to setup event buffers\n"); + goto err1; + } + + ret = dwc3_core_init_mode(dwc); + if (ret) + goto err2; + + list_add_tail(&dwc->list, &dwc3_list); + + return 0; + +err2: + dwc3_event_buffers_cleanup(dwc); + +err1: + dwc3_core_exit(dwc); + +err0: + dwc3_free_event_buffers(dwc); + + return ret; +} + +/** + * dwc3_uboot_exit - dwc3 core uboot cleanup code + * @index: index of this controller + * + * Performs cleanup of memory allocated in dwc3_uboot_init and other misc + * cleanups (equivalent to dwc3_remove in linux). index of _this_ controller + * should be passed and should match with the index passed in + * dwc3_device during init. + * + * Generally called from board file. + */ +void dwc3_uboot_exit(int index) +{ + struct dwc3 *dwc; + + list_for_each_entry(dwc, &dwc3_list, list) { + if (dwc->index != index) + continue; + + dwc3_core_exit_mode(dwc); + dwc3_event_buffers_cleanup(dwc); + dwc3_free_event_buffers(dwc); + dwc3_core_exit(dwc); + list_del(&dwc->list); + kfree(dwc->mem); + break; + } +} + +#if !CONFIG_IS_ENABLED(DM_USB_GADGET) +__weak int dwc3_uboot_interrupt_status(struct udevice *dev) +{ + return 1; +} + +/** + * dm_usb_gadget_handle_interrupts - handle dwc3 core interrupt + * @dev: device of this controller + * + * Invokes dwc3 gadget interrupts. + * + * Generally called from board file. + */ +int dm_usb_gadget_handle_interrupts(struct udevice *dev) +{ + struct dwc3 *dwc = NULL; + + if (!dwc3_uboot_interrupt_status(dev)) + return 0; + + list_for_each_entry(dwc, &dwc3_list, list) { + if (dwc->dev != dev) + continue; + + dwc3_gadget_uboot_handle_interrupt(dwc); + break; + } + + return 0; +} +#endif + diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 036a1440c8e8..4c4d7bae2e5f 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -418,6 +418,7 @@ /* Global User Control Register*/ #define DWC3_GUCTL_REFCLKPER_MASK 0xffc00000 #define DWC3_GUCTL_REFCLKPER_SEL 22 +#define DWC3_GUCTL_HSTINAUTORETRY BIT(14) /* Global User Control Register 2 */ #define DWC3_GUCTL2_RST_ACTBITLATER BIT(14) @@ -1232,6 +1233,8 @@ struct dwc3 { enum usb_dr_mode role_switch_default_mode; u32 fladj; + u8 incrx_mode; + u32 incrx_size; u32 ref_clk_per; u32 irq_gadget; u32 otg_irq; @@ -1313,6 +1316,8 @@ struct dwc3 { u8 num_eps; + void *mem; + struct dwc3_hwparams hwparams; struct debugfs_regset32 *regset; @@ -1398,6 +1403,9 @@ struct dwc3 { struct dentry *debug_root; u32 gsbuscfg0_reqinfo; u32 wakeup_pending_funcs; + + int index; + struct list_head list; }; #define INCRX_BURST_MODE 0 @@ -1564,6 +1572,9 @@ struct dwc3_gadget_ep_cmd_params { /* prototypes */ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy); u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type); +void dwc3_of_parse(struct dwc3 *dwc); +int dwc3_init(struct dwc3 *dwc); +void dwc3_remove(struct dwc3 *dwc); #define DWC3_IP_IS(_ip) \ (dwc->ip == _ip##_IP) -- 2.53.0
