X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fusb%2Fdwc3%2Fcore.c;h=56e2a046bf060177a7751aef31011f52f8a0c14f;hb=5ebc7c7e27780ce9a16289eeb87290eebd248ea9;hp=58c3bfdbfed6deff4bb803f40068a13f6e392552;hpb=8e1906a81f9e98ed538da393e839d6784b8b87fd;p=oweals%2Fu-boot.git diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 58c3bfdbfe..56e2a046bf 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /** * core.c - DesignWare USB3 DRD Controller Core file * @@ -10,8 +11,6 @@ * to uboot. * * commit cd72f890d2 : usb: dwc3: core: enable phy suspend quirk on non-FPGA - * - * SPDX-License-Identifier: GPL-2.0 */ #include @@ -19,7 +18,8 @@ #include #include #include - +#include +#include #include #include @@ -29,10 +29,10 @@ #include "linux-compat.h" -struct dwc3 *dwc; +static LIST_HEAD(dwc3_list); /* -------------------------------------------------------------------------- */ -void dwc3_set_mode(struct dwc3 *dwc, u32 mode) +static void dwc3_set_mode(struct dwc3 *dwc, u32 mode) { u32 reg; @@ -111,7 +111,8 @@ static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, { struct dwc3_event_buffer *evt; - evt = devm_kzalloc(dwc->dev, sizeof(*evt), GFP_KERNEL); + evt = devm_kzalloc((struct udevice *)dwc->dev, sizeof(*evt), + GFP_KERNEL); if (!evt) return ERR_PTR(-ENOMEM); @@ -122,6 +123,8 @@ static struct dwc3_event_buffer *dwc3_alloc_one_event_buffer(struct dwc3 *dwc, if (!evt->buf) return ERR_PTR(-ENOMEM); + dwc3_flush_cache((uintptr_t)evt->buf, evt->length); + return evt; } @@ -157,8 +160,8 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length) num = DWC3_NUM_INT(dwc->hwparams.hwparams1); dwc->num_event_buffers = num; - dwc->ev_buffs = devm_kzalloc(dwc->dev, sizeof(*dwc->ev_buffs) * num, - GFP_KERNEL); + dwc->ev_buffs = memalign(CONFIG_SYS_CACHELINE_SIZE, + sizeof(*dwc->ev_buffs) * num); if (!dwc->ev_buffs) return -ENOMEM; @@ -281,7 +284,7 @@ static int dwc3_setup_scratch_buffers(struct dwc3 *dwc) return 0; err1: - dma_unmap_single((void *)dwc->scratch_addr, dwc->nr_scratch * + dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); err0: @@ -296,7 +299,7 @@ static void dwc3_free_scratch_buffers(struct dwc3 *dwc) if (!dwc->nr_scratch) return; - dma_unmap_single((void *)dwc->scratch_addr, dwc->nr_scratch * + dma_unmap_single((void *)(uintptr_t)dwc->scratch_addr, dwc->nr_scratch * DWC3_SCRATCHBUF_SIZE, DMA_BIDIRECTIONAL); kfree(dwc->scratchbuf); } @@ -612,7 +615,8 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc) */ int dwc3_uboot_init(struct dwc3_device *dwc3_dev) { - struct device *dev; + struct dwc3 *dwc; + struct device *dev = NULL; u8 lpm_nyet_threshold; u8 tx_de_emphasis; u8 hird_threshold; @@ -621,14 +625,16 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev) void *mem; - mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL); + 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 = (int *)(dwc3_dev->base + DWC3_GLOBALS_REGS_START); + dwc->regs = (void *)(uintptr_t)(dwc3_dev->base + + DWC3_GLOBALS_REGS_START); /* default to highest possible threshold */ lpm_nyet_threshold = 0xff; @@ -678,6 +684,8 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev) dwc->hird_threshold = hird_threshold | (dwc->is_utmi_l1_suspend << 4); + dwc->index = dwc3_dev->index; + dwc3_cache_hwparams(dwc); ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE); @@ -710,6 +718,8 @@ int dwc3_uboot_init(struct dwc3_device *dwc3_dev) if (ret) goto err2; + list_add_tail(&dwc->list, &dwc3_list); + return 0; err2: @@ -729,20 +739,190 @@ err0: * @index: index of this controller * * Performs cleanup of memory allocated in dwc3_uboot_init and other misc - * cleanups (equivalent to dwc3_remove in linux). + * 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() +void dwc3_uboot_exit(int index) { - dwc3_core_exit_mode(dwc); - dwc3_event_buffers_cleanup(dwc); - dwc3_free_event_buffers(dwc); - dwc3_core_exit(dwc); - kfree(dwc->mem); + 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; + } +} + +/** + * dwc3_uboot_handle_interrupt - handle dwc3 core interrupt + * @index: index of this controller + * + * Invokes dwc3 gadget interrupts. + * + * Generally called from board file. + */ +void dwc3_uboot_handle_interrupt(int index) +{ + struct dwc3 *dwc = NULL; + + list_for_each_entry(dwc, &dwc3_list, list) { + if (dwc->index != index) + continue; + + dwc3_gadget_uboot_handle_interrupt(dwc); + break; + } } MODULE_ALIAS("platform:dwc3"); MODULE_AUTHOR("Felipe Balbi "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); + +#if CONFIG_IS_ENABLED(PHY) && CONFIG_IS_ENABLED(DM_USB) +int dwc3_setup_phy(struct udevice *dev, struct phy **array, int *num_phys) +{ + int i, ret, count; + struct phy *usb_phys; + + /* Return if no phy declared */ + if (!dev_read_prop(dev, "phys", NULL)) + return 0; + count = dev_count_phandle_with_args(dev, "phys", "#phy-cells"); + if (count <= 0) + return count; + + usb_phys = devm_kcalloc(dev, count, sizeof(struct phy), + GFP_KERNEL); + if (!usb_phys) + return -ENOMEM; + + for (i = 0; i < count; i++) { + ret = generic_phy_get_by_index(dev, i, &usb_phys[i]); + if (ret && ret != -ENOENT) { + pr_err("Failed to get USB PHY%d for %s\n", + i, dev->name); + return ret; + } + } + + for (i = 0; i < count; i++) { + ret = generic_phy_init(&usb_phys[i]); + if (ret) { + pr_err("Can't init USB PHY%d for %s\n", + i, dev->name); + goto phys_init_err; + } + } + + for (i = 0; i < count; i++) { + ret = generic_phy_power_on(&usb_phys[i]); + if (ret) { + pr_err("Can't power USB PHY%d for %s\n", + i, dev->name); + goto phys_poweron_err; + } + } + + *array = usb_phys; + *num_phys = count; + return 0; + +phys_poweron_err: + for (i = count - 1; i >= 0; i--) + generic_phy_power_off(&usb_phys[i]); + + for (i = 0; i < count; i++) + generic_phy_exit(&usb_phys[i]); + + return ret; + +phys_init_err: + for (; i >= 0; i--) + generic_phy_exit(&usb_phys[i]); + + return ret; +} + +int dwc3_shutdown_phy(struct udevice *dev, struct phy *usb_phys, int num_phys) +{ + int i, ret; + + for (i = 0; i < num_phys; i++) { + if (!generic_phy_valid(&usb_phys[i])) + continue; + + ret = generic_phy_power_off(&usb_phys[i]); + ret |= generic_phy_exit(&usb_phys[i]); + if (ret) { + pr_err("Can't shutdown USB PHY%d for %s\n", + i, dev->name); + } + } + + return 0; +} +#endif + +#if CONFIG_IS_ENABLED(DM_USB_GADGET) +int dwc3_init(struct dwc3 *dwc) +{ + int ret; + + 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(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; + } + + 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_exit(dwc); + kfree(dwc->mem); +} +#endif