This commit is contained in:
		
						commit
						54f683dbfb
					
				
							
								
								
									
										1
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										1
									
								
								Makefile
								
								
								
								
							|  | @ -847,6 +847,7 @@ libs-y += drivers/usb/host/ | ||||||
| libs-y += drivers/usb/mtu3/ | libs-y += drivers/usb/mtu3/ | ||||||
| libs-y += drivers/usb/musb/ | libs-y += drivers/usb/musb/ | ||||||
| libs-y += drivers/usb/musb-new/ | libs-y += drivers/usb/musb-new/ | ||||||
|  | libs-y += drivers/usb/isp1760/ | ||||||
| libs-y += drivers/usb/phy/ | libs-y += drivers/usb/phy/ | ||||||
| libs-y += drivers/usb/ulpi/ | libs-y += drivers/usb/ulpi/ | ||||||
| ifdef CONFIG_POST | ifdef CONFIG_POST | ||||||
|  |  | ||||||
|  | @ -810,7 +810,6 @@ config ARCH_KEYSTONE | ||||||
| 	select CMD_POWEROFF | 	select CMD_POWEROFF | ||||||
| 	select CPU_V7A | 	select CPU_V7A | ||||||
| 	select DDR_SPD | 	select DDR_SPD | ||||||
| 	select GPIO_EXTRA_HEADER |  | ||||||
| 	select SUPPORT_SPL | 	select SUPPORT_SPL | ||||||
| 	select SYS_ARCH_TIMER | 	select SYS_ARCH_TIMER | ||||||
| 	select SYS_THUMB_BUILD | 	select SYS_THUMB_BUILD | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ static int spl_sdp_load_image(struct spl_image_info *spl_image, | ||||||
| 
 | 
 | ||||||
| 	usb_gadget_initialize(controller_index); | 	usb_gadget_initialize(controller_index); | ||||||
| 
 | 
 | ||||||
| 	board_usb_init(0, USB_INIT_DEVICE); | 	board_usb_init(controller_index, USB_INIT_DEVICE); | ||||||
| 
 | 
 | ||||||
| 	g_dnl_clear_detach(); | 	g_dnl_clear_detach(); | ||||||
| 	ret = g_dnl_register("usb_dnl_sdp"); | 	ret = g_dnl_register("usb_dnl_sdp"); | ||||||
|  |  | ||||||
|  | @ -47,6 +47,8 @@ | ||||||
| #define HUB_SHORT_RESET_TIME	20 | #define HUB_SHORT_RESET_TIME	20 | ||||||
| #define HUB_LONG_RESET_TIME	200 | #define HUB_LONG_RESET_TIME	200 | ||||||
| 
 | 
 | ||||||
|  | #define HUB_DEBOUNCE_TIMEOUT	1000 | ||||||
|  | 
 | ||||||
| #define PORT_OVERCURRENT_MAX_SCAN_COUNT		3 | #define PORT_OVERCURRENT_MAX_SCAN_COUNT		3 | ||||||
| 
 | 
 | ||||||
| struct usb_device_scan { | struct usb_device_scan { | ||||||
|  | @ -208,10 +210,10 @@ static void usb_hub_power_on(struct usb_hub_device *hub) | ||||||
| 	 * will be done based on this value in the USB port loop in | 	 * will be done based on this value in the USB port loop in | ||||||
| 	 * usb_hub_configure() later. | 	 * usb_hub_configure() later. | ||||||
| 	 */ | 	 */ | ||||||
| 	hub->connect_timeout = hub->query_delay + 1000; | 	hub->connect_timeout = hub->query_delay + HUB_DEBOUNCE_TIMEOUT; | ||||||
| 	debug("devnum=%d poweron: query_delay=%d connect_timeout=%d\n", | 	debug("devnum=%d poweron: query_delay=%d connect_timeout=%d\n", | ||||||
| 	      dev->devnum, max(100, (int)pgood_delay), | 	      dev->devnum, max(100, (int)pgood_delay), | ||||||
| 	      max(100, (int)pgood_delay) + 1000); | 	      max(100, (int)pgood_delay) + HUB_DEBOUNCE_TIMEOUT); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #if !CONFIG_IS_ENABLED(DM_USB) | #if !CONFIG_IS_ENABLED(DM_USB) | ||||||
|  |  | ||||||
|  | @ -581,14 +581,14 @@ static int probe_usb_keyboard(struct usb_device *dev) | ||||||
| 
 | 
 | ||||||
| 	stdinname = env_get("stdin"); | 	stdinname = env_get("stdin"); | ||||||
| #if CONFIG_IS_ENABLED(CONSOLE_MUX) | #if CONFIG_IS_ENABLED(CONSOLE_MUX) | ||||||
|  | 	if (strstr(stdinname, DEVNAME) != NULL) { | ||||||
| 		error = iomux_doenv(stdin, stdinname); | 		error = iomux_doenv(stdin, stdinname); | ||||||
| 		if (error) | 		if (error) | ||||||
| 			return error; | 			return error; | ||||||
|  | 	} | ||||||
| #else | #else | ||||||
| 	/* Check if this is the standard input device. */ | 	/* Check if this is the standard input device. */ | ||||||
| 	if (strcmp(stdinname, DEVNAME)) | 	if (!strcmp(stdinname, DEVNAME)) { | ||||||
| 		return 1; |  | ||||||
| 
 |  | ||||||
| 		/* Reassign the console */ | 		/* Reassign the console */ | ||||||
| 		if (overwrite_console()) | 		if (overwrite_console()) | ||||||
| 			return 1; | 			return 1; | ||||||
|  | @ -596,6 +596,7 @@ static int probe_usb_keyboard(struct usb_device *dev) | ||||||
| 		error = console_assign(stdin, DEVNAME); | 		error = console_assign(stdin, DEVNAME); | ||||||
| 		if (error) | 		if (error) | ||||||
| 			return error; | 			return error; | ||||||
|  | 	} | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|  | @ -28,6 +28,8 @@ CONFIG_SYS_BOOTM_LEN=0x800000 | ||||||
| # CONFIG_CMD_XIMG is not set | # CONFIG_CMD_XIMG is not set | ||||||
| CONFIG_CMD_LOADM=y | CONFIG_CMD_LOADM=y | ||||||
| # CONFIG_CMD_LOADS is not set | # CONFIG_CMD_LOADS is not set | ||||||
|  | CONFIG_CMD_MMC=y | ||||||
|  | CONFIG_CMD_USB=y | ||||||
| # CONFIG_CMD_SETEXPR is not set | # CONFIG_CMD_SETEXPR is not set | ||||||
| # CONFIG_CMD_NFS is not set | # CONFIG_CMD_NFS is not set | ||||||
| CONFIG_CMD_CACHE=y | CONFIG_CMD_CACHE=y | ||||||
|  | @ -50,4 +52,5 @@ CONFIG_DM_RTC=y | ||||||
| CONFIG_RTC_EMULATION=y | CONFIG_RTC_EMULATION=y | ||||||
| CONFIG_DM_SERIAL=y | CONFIG_DM_SERIAL=y | ||||||
| CONFIG_USB=y | CONFIG_USB=y | ||||||
|  | CONFIG_USB_ISP1760=y | ||||||
| CONFIG_ERRNO_STR=y | CONFIG_ERRNO_STR=y | ||||||
|  |  | ||||||
|  | @ -68,6 +68,8 @@ config SPL_DM_USB_GADGET | ||||||
| 
 | 
 | ||||||
| source "drivers/usb/host/Kconfig" | source "drivers/usb/host/Kconfig" | ||||||
| 
 | 
 | ||||||
|  | source "drivers/usb/isp1760/Kconfig" | ||||||
|  | 
 | ||||||
| source "drivers/usb/cdns3/Kconfig" | source "drivers/usb/cdns3/Kconfig" | ||||||
| 
 | 
 | ||||||
| source "drivers/usb/dwc3/Kconfig" | source "drivers/usb/dwc3/Kconfig" | ||||||
|  |  | ||||||
|  | @ -4,5 +4,9 @@ | ||||||
| #
 | #
 | ||||||
| 
 | 
 | ||||||
| obj-$(CONFIG_$(SPL_)DM_USB) += common.o | obj-$(CONFIG_$(SPL_)DM_USB) += common.o | ||||||
|  | obj-$(CONFIG_USB_ISP1760) += usb_urb.o | ||||||
|  | obj-$(CONFIG_USB_MUSB_HOST) += usb_urb.o | ||||||
|  | obj-$(CONFIG_USB_MUSB_GADGET) += usb_urb.o | ||||||
|  | obj-$(CONFIG_USB_R8A66597_HCD) += usb_urb.o | ||||||
| obj-$(CONFIG_USB_EHCI_FSL) += fsl-dt-fixup.o fsl-errata.o | obj-$(CONFIG_USB_EHCI_FSL) += fsl-dt-fixup.o fsl-errata.o | ||||||
| obj-$(CONFIG_USB_XHCI_FSL) += fsl-dt-fixup.o fsl-errata.o | obj-$(CONFIG_USB_XHCI_FSL) += fsl-dt-fixup.o fsl-errata.o | ||||||
|  |  | ||||||
|  | @ -0,0 +1,160 @@ | ||||||
|  | // SPDX-License-Identifier: GPL-2.0
 | ||||||
|  | /*
 | ||||||
|  |  * Common code for usb urb handling, based on the musb-new code | ||||||
|  |  * | ||||||
|  |  * Copyright 2021 Linaro, Rui Miguel Silva <rui.silva@linaro.org> | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <dm/device.h> | ||||||
|  | #include <dm/device_compat.h> | ||||||
|  | #include <linux/usb/usb_urb_compat.h> | ||||||
|  | 
 | ||||||
|  | #include <time.h> | ||||||
|  | #include <usb.h> | ||||||
|  | 
 | ||||||
|  | #if CONFIG_IS_ENABLED(DM_USB) | ||||||
|  | struct usb_device *usb_dev_get_parent(struct usb_device *udev) | ||||||
|  | { | ||||||
|  | 	struct udevice *parent = udev->dev->parent; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * When called from usb-uclass.c: usb_scan_device() udev->dev points | ||||||
|  | 	 * to the parent udevice, not the actual udevice belonging to the | ||||||
|  | 	 * udev as the device is not instantiated yet. | ||||||
|  | 	 * | ||||||
|  | 	 * If dev is an usb-bus, then we are called from usb_scan_device() for | ||||||
|  | 	 * an usb-device plugged directly into the root port, return NULL. | ||||||
|  | 	 */ | ||||||
|  | 	if (device_get_uclass_id(udev->dev) == UCLASS_USB) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * If these 2 are not the same we are being called from | ||||||
|  | 	 * usb_scan_device() and udev itself is the parent. | ||||||
|  | 	 */ | ||||||
|  | 	if (dev_get_parent_priv(udev->dev) != udev) | ||||||
|  | 		return udev; | ||||||
|  | 
 | ||||||
|  | 	/* We are being called normally, use the parent pointer */ | ||||||
|  | 	if (device_get_uclass_id(parent) == UCLASS_USB_HUB) | ||||||
|  | 		return dev_get_parent_priv(parent); | ||||||
|  | 
 | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | #else | ||||||
|  | struct usb_device *usb_dev_get_parent(struct usb_device *udev) | ||||||
|  | { | ||||||
|  | 	return udev->parent; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | static void usb_urb_complete(struct urb *urb) | ||||||
|  | { | ||||||
|  | 	urb->dev->status &= ~USB_ST_NOT_PROC; | ||||||
|  | 	urb->dev->act_len = urb->actual_length; | ||||||
|  | 
 | ||||||
|  | 	if (urb->status == -EINPROGRESS) | ||||||
|  | 		urb->status = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void usb_urb_fill(struct urb *urb, struct usb_host_endpoint *hep, | ||||||
|  | 		  struct usb_device *dev, int endpoint_type, | ||||||
|  | 		  unsigned long pipe, void *buffer, int len, | ||||||
|  | 		  struct devrequest *setup, int interval) | ||||||
|  | { | ||||||
|  | 	int epnum = usb_pipeendpoint(pipe); | ||||||
|  | 	int is_in = usb_pipein(pipe); | ||||||
|  | 	u16 maxpacketsize = is_in ? dev->epmaxpacketin[epnum] : | ||||||
|  | 					dev->epmaxpacketout[epnum]; | ||||||
|  | 
 | ||||||
|  | 	memset(urb, 0, sizeof(struct urb)); | ||||||
|  | 	memset(hep, 0, sizeof(struct usb_host_endpoint)); | ||||||
|  | 	INIT_LIST_HEAD(&hep->urb_list); | ||||||
|  | 	INIT_LIST_HEAD(&urb->urb_list); | ||||||
|  | 	urb->ep = hep; | ||||||
|  | 	urb->complete = usb_urb_complete; | ||||||
|  | 	urb->status = -EINPROGRESS; | ||||||
|  | 	urb->dev = dev; | ||||||
|  | 	urb->pipe = pipe; | ||||||
|  | 	urb->transfer_buffer = buffer; | ||||||
|  | 	urb->transfer_dma = (unsigned long)buffer; | ||||||
|  | 	urb->transfer_buffer_length = len; | ||||||
|  | 	urb->setup_packet = (unsigned char *)setup; | ||||||
|  | 
 | ||||||
|  | 	urb->ep->desc.wMaxPacketSize = __cpu_to_le16(maxpacketsize); | ||||||
|  | 	urb->ep->desc.bmAttributes = endpoint_type; | ||||||
|  | 	urb->ep->desc.bEndpointAddress = ((is_in ? USB_DIR_IN : USB_DIR_OUT) | | ||||||
|  | 					  epnum); | ||||||
|  | 	urb->ep->desc.bInterval = interval; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int usb_urb_submit(struct usb_hcd *hcd, struct urb *urb) | ||||||
|  | { | ||||||
|  | 	const struct usb_urb_ops *ops = hcd->urb_ops; | ||||||
|  | 	unsigned long timeout; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	if (!ops) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	ret = ops->urb_enqueue(hcd, urb, 0); | ||||||
|  | 	if (ret < 0) { | ||||||
|  | 		printf("Failed to enqueue URB to controller\n"); | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	timeout = get_timer(0) + USB_TIMEOUT_MS(urb->pipe); | ||||||
|  | 	do { | ||||||
|  | 		if (ctrlc()) | ||||||
|  | 			return -EIO; | ||||||
|  | 		ops->isr(0, hcd); | ||||||
|  | 	} while (urb->status == -EINPROGRESS && get_timer(0) < timeout); | ||||||
|  | 
 | ||||||
|  | 	if (urb->status == -EINPROGRESS) | ||||||
|  | 		ops->urb_dequeue(hcd, urb, -ETIME); | ||||||
|  | 
 | ||||||
|  | 	return urb->status; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int usb_urb_submit_control(struct usb_hcd *hcd, struct urb *urb, | ||||||
|  | 			   struct usb_host_endpoint *hep, | ||||||
|  | 			   struct usb_device *dev, unsigned long pipe, | ||||||
|  | 			   void *buffer, int len, struct devrequest *setup, | ||||||
|  | 			   int interval, enum usb_device_speed speed) | ||||||
|  | { | ||||||
|  | 	const struct usb_urb_ops *ops = hcd->urb_ops; | ||||||
|  | 
 | ||||||
|  | 	usb_urb_fill(urb, hep, dev, USB_ENDPOINT_XFER_CONTROL, pipe, buffer, | ||||||
|  | 		     len, setup, 0); | ||||||
|  | 
 | ||||||
|  | 	/* Fix speed for non hub-attached devices */ | ||||||
|  | 	if (!usb_dev_get_parent(dev)) { | ||||||
|  | 		dev->speed = speed; | ||||||
|  | 		if (ops->hub_control) | ||||||
|  | 			return ops->hub_control(hcd, dev, pipe, buffer, len, | ||||||
|  | 						setup); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return usb_urb_submit(hcd, urb); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int usb_urb_submit_bulk(struct usb_hcd *hcd, struct urb *urb, | ||||||
|  | 			struct usb_host_endpoint *hep, struct usb_device *dev, | ||||||
|  | 			unsigned long pipe, void *buffer, int len) | ||||||
|  | { | ||||||
|  | 	usb_urb_fill(urb, hep, dev, USB_ENDPOINT_XFER_BULK, pipe, buffer, len, | ||||||
|  | 		     NULL, 0); | ||||||
|  | 
 | ||||||
|  | 	return usb_urb_submit(hcd, urb); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int usb_urb_submit_irq(struct usb_hcd *hcd, struct urb *urb, | ||||||
|  | 		       struct usb_host_endpoint *hep, struct usb_device *dev, | ||||||
|  | 		       unsigned long pipe, void *buffer, int len, int interval) | ||||||
|  | { | ||||||
|  | 	usb_urb_fill(urb, hep, dev, USB_ENDPOINT_XFER_INT, pipe, buffer, len, | ||||||
|  | 		     NULL, interval); | ||||||
|  | 
 | ||||||
|  | 	return usb_urb_submit(hcd, urb); | ||||||
|  | } | ||||||
|  | @ -26,6 +26,7 @@ | ||||||
| #include <reset.h> | #include <reset.h> | ||||||
| #include <clk.h> | #include <clk.h> | ||||||
| #include <usb/xhci.h> | #include <usb/xhci.h> | ||||||
|  | #include <asm/gpio.h> | ||||||
| 
 | 
 | ||||||
| struct dwc3_glue_data { | struct dwc3_glue_data { | ||||||
| 	struct clk_bulk		clks; | 	struct clk_bulk		clks; | ||||||
|  | @ -43,6 +44,7 @@ struct dwc3_generic_priv { | ||||||
| 	void *base; | 	void *base; | ||||||
| 	struct dwc3 dwc3; | 	struct dwc3 dwc3; | ||||||
| 	struct phy_bulk phys; | 	struct phy_bulk phys; | ||||||
|  | 	struct gpio_desc ulpi_reset; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct dwc3_generic_host_priv { | struct dwc3_generic_host_priv { | ||||||
|  | @ -78,6 +80,27 @@ static int dwc3_generic_probe(struct udevice *dev, | ||||||
| 	if (rc && rc != -ENOTSUPP) | 	if (rc && rc != -ENOTSUPP) | ||||||
| 		return rc; | 		return rc; | ||||||
| 
 | 
 | ||||||
|  | 	if (CONFIG_IS_ENABLED(DM_GPIO) && | ||||||
|  | 	    device_is_compatible(dev->parent, "xlnx,zynqmp-dwc3")) { | ||||||
|  | 		rc = gpio_request_by_name(dev->parent, "reset-gpios", 0, | ||||||
|  | 					  &priv->ulpi_reset, GPIOD_ACTIVE_LOW); | ||||||
|  | 		if (rc) | ||||||
|  | 			return rc; | ||||||
|  | 
 | ||||||
|  | 		/* Toggle ulpi to reset the phy. */ | ||||||
|  | 		rc = dm_gpio_set_value(&priv->ulpi_reset, 1); | ||||||
|  | 		if (rc) | ||||||
|  | 			return rc; | ||||||
|  | 
 | ||||||
|  | 		mdelay(5); | ||||||
|  | 
 | ||||||
|  | 		rc = dm_gpio_set_value(&priv->ulpi_reset, 0); | ||||||
|  | 		if (rc) | ||||||
|  | 			return rc; | ||||||
|  | 
 | ||||||
|  | 		mdelay(5); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if (device_is_compatible(dev->parent, "rockchip,rk3399-dwc3")) | 	if (device_is_compatible(dev->parent, "rockchip,rk3399-dwc3")) | ||||||
| 		reset_deassert_bulk(&glue->resets); | 		reset_deassert_bulk(&glue->resets); | ||||||
| 
 | 
 | ||||||
|  | @ -99,6 +122,13 @@ static int dwc3_generic_remove(struct udevice *dev, | ||||||
| { | { | ||||||
| 	struct dwc3 *dwc3 = &priv->dwc3; | 	struct dwc3 *dwc3 = &priv->dwc3; | ||||||
| 
 | 
 | ||||||
|  | 	if (CONFIG_IS_ENABLED(DM_GPIO) && | ||||||
|  | 	    device_is_compatible(dev->parent, "xlnx,zynqmp-dwc3")) { | ||||||
|  | 		struct gpio_desc *ulpi_reset = &priv->ulpi_reset; | ||||||
|  | 
 | ||||||
|  | 		dm_gpio_free(ulpi_reset->dev, ulpi_reset); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	dwc3_remove(dwc3); | 	dwc3_remove(dwc3); | ||||||
| 	dwc3_shutdown_phy(dev, &priv->phys); | 	dwc3_shutdown_phy(dev, &priv->phys); | ||||||
| 	unmap_physmem(dwc3->regs, MAP_NOCACHE); | 	unmap_physmem(dwc3->regs, MAP_NOCACHE); | ||||||
|  |  | ||||||
|  | @ -14,6 +14,7 @@ | ||||||
| #include <dm/device_compat.h> | #include <dm/device_compat.h> | ||||||
| #include <linux/delay.h> | #include <linux/delay.h> | ||||||
| #include <linux/iopoll.h> | #include <linux/iopoll.h> | ||||||
|  | #include <linux/usb/usb_urb_compat.h> | ||||||
| #include <power/regulator.h> | #include <power/regulator.h> | ||||||
| 
 | 
 | ||||||
| #include "r8a66597.h" | #include "r8a66597.h" | ||||||
|  | @ -24,35 +25,6 @@ | ||||||
| #define R8A66597_DPRINT(...) | #define R8A66597_DPRINT(...) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| static inline struct usb_device *usb_dev_get_parent(struct usb_device *udev) |  | ||||||
| { |  | ||||||
| 	struct udevice *parent = udev->dev->parent; |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * When called from usb-uclass.c: usb_scan_device() udev->dev points |  | ||||||
| 	 * to the parent udevice, not the actual udevice belonging to the |  | ||||||
| 	 * udev as the device is not instantiated yet. |  | ||||||
| 	 * |  | ||||||
| 	 * If dev is an usb-bus, then we are called from usb_scan_device() for |  | ||||||
| 	 * an usb-device plugged directly into the root port, return NULL. |  | ||||||
| 	 */ |  | ||||||
| 	if (device_get_uclass_id(udev->dev) == UCLASS_USB) |  | ||||||
| 		return NULL; |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * If these 2 are not the same we are being called from |  | ||||||
| 	 * usb_scan_device() and udev itself is the parent. |  | ||||||
| 	 */ |  | ||||||
| 	if (dev_get_parent_priv(udev->dev) != udev) |  | ||||||
| 		return udev; |  | ||||||
| 
 |  | ||||||
| 	/* We are being called normally, use the parent pointer */ |  | ||||||
| 	if (device_get_uclass_id(parent) == UCLASS_USB_HUB) |  | ||||||
| 		return dev_get_parent_priv(parent); |  | ||||||
| 
 |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void get_hub_data(struct usb_device *dev, u16 *hub_devnum, u16 *hubport) | static void get_hub_data(struct usb_device *dev, u16 *hub_devnum, u16 *hubport) | ||||||
| { | { | ||||||
| 	struct usb_device *parent = usb_dev_get_parent(dev); | 	struct usb_device *parent = usb_dev_get_parent(dev); | ||||||
|  |  | ||||||
|  | @ -0,0 +1,12 @@ | ||||||
|  | # SPDX-License-Identifier: GPL-2.0 | ||||||
|  | 
 | ||||||
|  | config USB_ISP1760 | ||||||
|  | 	tristate "NXP ISP 1760/1761/1763 support" | ||||||
|  | 	select DM_USB | ||||||
|  | 	select USB_HOST | ||||||
|  | 	help | ||||||
|  | 	  Say Y or M here if your system as an ISP1760/1761/1763 USB host | ||||||
|  | 	  controller. | ||||||
|  | 
 | ||||||
|  | 	  This USB controller is usually attached to a non-DMA-Master | ||||||
|  | 	  capable bus. | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | # SPDX-License-Identifier: GPL-2.0
 | ||||||
|  | isp1760-y := isp1760-core.o isp1760-if.o isp1760-uboot.o isp1760-hcd.o | ||||||
|  | 
 | ||||||
|  | #isp1760-hcd.o
 | ||||||
|  | 
 | ||||||
|  | obj-$(CONFIG_USB_ISP1760) += isp1760.o | ||||||
|  | @ -0,0 +1,380 @@ | ||||||
|  | // SPDX-License-Identifier: GPL-2.0
 | ||||||
|  | /*
 | ||||||
|  |  * Driver for the NXP ISP1760 chip | ||||||
|  |  * | ||||||
|  |  * Copyright 2022 Linaro, Rui Miguel Silva <rui.silva@linaro.org> | ||||||
|  |  * | ||||||
|  |  * This is based on linux kernel driver, original developed: | ||||||
|  |  * Copyright 2014 Laurent Pinchart | ||||||
|  |  * Copyright 2007 Sebastian Siewior | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <dm.h> | ||||||
|  | #include <dm/device-internal.h> | ||||||
|  | #include <dm/device_compat.h> | ||||||
|  | #include <dm/devres.h> | ||||||
|  | #include <linux/compat.h> | ||||||
|  | #include <linux/delay.h> | ||||||
|  | #include <linux/io.h> | ||||||
|  | #include <linux/kernel.h> | ||||||
|  | #include <regmap.h> | ||||||
|  | #include <usb.h> | ||||||
|  | 
 | ||||||
|  | #include "isp1760-core.h" | ||||||
|  | #include "isp1760-hcd.h" | ||||||
|  | #include "isp1760-regs.h" | ||||||
|  | 
 | ||||||
|  | #define msleep(a) udelay((a) * 1000) | ||||||
|  | 
 | ||||||
|  | static int isp1760_init_core(struct isp1760_device *isp) | ||||||
|  | { | ||||||
|  | 	struct isp1760_hcd *hcd = &isp->hcd; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Reset the host controller, including the CPU interface | ||||||
|  | 	 * configuration. | ||||||
|  | 	 */ | ||||||
|  | 	isp1760_field_set(hcd->fields, SW_RESET_RESET_ALL); | ||||||
|  | 	msleep(100); | ||||||
|  | 
 | ||||||
|  | 	/* Setup HW Mode Control: This assumes a level active-low interrupt */ | ||||||
|  | 	if ((isp->devflags & ISP1760_FLAG_ANALOG_OC) && hcd->is_isp1763) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_16) | ||||||
|  | 		isp1760_field_clear(hcd->fields, HW_DATA_BUS_WIDTH); | ||||||
|  | 	if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_8) | ||||||
|  | 		isp1760_field_set(hcd->fields, HW_DATA_BUS_WIDTH); | ||||||
|  | 	if (isp->devflags & ISP1760_FLAG_ANALOG_OC) | ||||||
|  | 		isp1760_field_set(hcd->fields, HW_ANA_DIGI_OC); | ||||||
|  | 	if (isp->devflags & ISP1760_FLAG_DACK_POL_HIGH) | ||||||
|  | 		isp1760_field_set(hcd->fields, HW_DACK_POL_HIGH); | ||||||
|  | 	if (isp->devflags & ISP1760_FLAG_DREQ_POL_HIGH) | ||||||
|  | 		isp1760_field_set(hcd->fields, HW_DREQ_POL_HIGH); | ||||||
|  | 	if (isp->devflags & ISP1760_FLAG_INTR_POL_HIGH) | ||||||
|  | 		isp1760_field_set(hcd->fields, HW_INTR_HIGH_ACT); | ||||||
|  | 	if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG) | ||||||
|  | 		isp1760_field_set(hcd->fields, HW_INTR_EDGE_TRIG); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * The ISP1761 has a dedicated DC IRQ line but supports sharing the HC | ||||||
|  | 	 * IRQ line for both the host and device controllers. Hardcode IRQ | ||||||
|  | 	 * sharing for now and disable the DC interrupts globally to avoid | ||||||
|  | 	 * spurious interrupts during HCD registration. | ||||||
|  | 	 */ | ||||||
|  | 	if (isp->devflags & ISP1760_FLAG_ISP1761) { | ||||||
|  | 		isp1760_reg_write(hcd->regs, ISP176x_DC_MODE, 0); | ||||||
|  | 		isp1760_field_set(hcd->fields, HW_COMN_IRQ); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * PORT 1 Control register of the ISP1760 is the OTG control register | ||||||
|  | 	 * on ISP1761. | ||||||
|  | 	 * | ||||||
|  | 	 * TODO: Really support OTG. For now we configure port 1 in device mode | ||||||
|  | 	 */ | ||||||
|  | 	if (((isp->devflags & ISP1760_FLAG_ISP1761) || | ||||||
|  | 	     (isp->devflags & ISP1760_FLAG_ISP1763)) && | ||||||
|  | 	    (isp->devflags & ISP1760_FLAG_PERIPHERAL_EN)) { | ||||||
|  | 		isp1760_field_set(hcd->fields, HW_DM_PULLDOWN); | ||||||
|  | 		isp1760_field_set(hcd->fields, HW_DP_PULLDOWN); | ||||||
|  | 		isp1760_field_set(hcd->fields, HW_OTG_DISABLE); | ||||||
|  | 	} else { | ||||||
|  | 		isp1760_field_set(hcd->fields, HW_SW_SEL_HC_DC); | ||||||
|  | 		isp1760_field_set(hcd->fields, HW_VBUS_DRV); | ||||||
|  | 		isp1760_field_set(hcd->fields, HW_SEL_CP_EXT); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	printf("%s bus width: %u, oc: %s\n", | ||||||
|  | 	       hcd->is_isp1763 ? "isp1763" : "isp1760", | ||||||
|  | 	       isp->devflags & ISP1760_FLAG_BUS_WIDTH_8 ? 8 : | ||||||
|  | 	       isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32, | ||||||
|  | 	       hcd->is_isp1763 ? "not available" : | ||||||
|  | 	       isp->devflags & ISP1760_FLAG_ANALOG_OC ? "analog" : "digital"); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void isp1760_set_pullup(struct isp1760_device *isp, bool enable) | ||||||
|  | { | ||||||
|  | 	struct isp1760_hcd *hcd = &isp->hcd; | ||||||
|  | 
 | ||||||
|  | 	if (enable) | ||||||
|  | 		isp1760_field_set(hcd->fields, HW_DP_PULLUP); | ||||||
|  | 	else | ||||||
|  | 		isp1760_field_set(hcd->fields, HW_DP_PULLUP_CLEAR); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * ISP1760/61: | ||||||
|  |  * | ||||||
|  |  * 60kb divided in: | ||||||
|  |  * - 32 blocks @ 256  bytes | ||||||
|  |  * - 20 blocks @ 1024 bytes | ||||||
|  |  * -  4 blocks @ 8192 bytes | ||||||
|  |  */ | ||||||
|  | static const struct isp1760_memory_layout isp176x_memory_conf = { | ||||||
|  | 	.blocks[0]		= 32, | ||||||
|  | 	.blocks_size[0]		= 256, | ||||||
|  | 	.blocks[1]		= 20, | ||||||
|  | 	.blocks_size[1]		= 1024, | ||||||
|  | 	.blocks[2]		= 4, | ||||||
|  | 	.blocks_size[2]		= 8192, | ||||||
|  | 
 | ||||||
|  | 	.slot_num		= 32, | ||||||
|  | 	.payload_blocks		= 32 + 20 + 4, | ||||||
|  | 	.payload_area_size	= 0xf000, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * ISP1763: | ||||||
|  |  * | ||||||
|  |  * 20kb divided in: | ||||||
|  |  * - 8 blocks @ 256  bytes | ||||||
|  |  * - 2 blocks @ 1024 bytes | ||||||
|  |  * - 4 blocks @ 4096 bytes | ||||||
|  |  */ | ||||||
|  | static const struct isp1760_memory_layout isp1763_memory_conf = { | ||||||
|  | 	.blocks[0]		= 8, | ||||||
|  | 	.blocks_size[0]		= 256, | ||||||
|  | 	.blocks[1]		= 2, | ||||||
|  | 	.blocks_size[1]		= 1024, | ||||||
|  | 	.blocks[2]		= 4, | ||||||
|  | 	.blocks_size[2]		= 4096, | ||||||
|  | 
 | ||||||
|  | 	.slot_num		= 16, | ||||||
|  | 	.payload_blocks		= 8 + 2 + 4, | ||||||
|  | 	.payload_area_size	= 0x5000, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct regmap_config isp1760_hc_regmap_conf = { | ||||||
|  | 	.width = REGMAP_SIZE_16, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct reg_field isp1760_hc_reg_fields[] = { | ||||||
|  | 	[HCS_PPC]		= REG_FIELD(ISP176x_HC_HCSPARAMS, 4, 4), | ||||||
|  | 	[HCS_N_PORTS]		= REG_FIELD(ISP176x_HC_HCSPARAMS, 0, 3), | ||||||
|  | 	[HCC_ISOC_CACHE]	= REG_FIELD(ISP176x_HC_HCCPARAMS, 7, 7), | ||||||
|  | 	[HCC_ISOC_THRES]	= REG_FIELD(ISP176x_HC_HCCPARAMS, 4, 6), | ||||||
|  | 	[CMD_LRESET]		= REG_FIELD(ISP176x_HC_USBCMD, 7, 7), | ||||||
|  | 	[CMD_RESET]		= REG_FIELD(ISP176x_HC_USBCMD, 1, 1), | ||||||
|  | 	[CMD_RUN]		= REG_FIELD(ISP176x_HC_USBCMD, 0, 0), | ||||||
|  | 	[STS_PCD]		= REG_FIELD(ISP176x_HC_USBSTS, 2, 2), | ||||||
|  | 	[HC_FRINDEX]		= REG_FIELD(ISP176x_HC_FRINDEX, 0, 13), | ||||||
|  | 	[FLAG_CF]		= REG_FIELD(ISP176x_HC_CONFIGFLAG, 0, 0), | ||||||
|  | 	[HC_ISO_PTD_DONEMAP]	= REG_FIELD(ISP176x_HC_ISO_PTD_DONEMAP, 0, 31), | ||||||
|  | 	[HC_ISO_PTD_SKIPMAP]	= REG_FIELD(ISP176x_HC_ISO_PTD_SKIPMAP, 0, 31), | ||||||
|  | 	[HC_ISO_PTD_LASTPTD]	= REG_FIELD(ISP176x_HC_ISO_PTD_LASTPTD, 0, 31), | ||||||
|  | 	[HC_INT_PTD_DONEMAP]	= REG_FIELD(ISP176x_HC_INT_PTD_DONEMAP, 0, 31), | ||||||
|  | 	[HC_INT_PTD_SKIPMAP]	= REG_FIELD(ISP176x_HC_INT_PTD_SKIPMAP, 0, 31), | ||||||
|  | 	[HC_INT_PTD_LASTPTD]	= REG_FIELD(ISP176x_HC_INT_PTD_LASTPTD, 0, 31), | ||||||
|  | 	[HC_ATL_PTD_DONEMAP]	= REG_FIELD(ISP176x_HC_ATL_PTD_DONEMAP, 0, 31), | ||||||
|  | 	[HC_ATL_PTD_SKIPMAP]	= REG_FIELD(ISP176x_HC_ATL_PTD_SKIPMAP, 0, 31), | ||||||
|  | 	[HC_ATL_PTD_LASTPTD]	= REG_FIELD(ISP176x_HC_ATL_PTD_LASTPTD, 0, 31), | ||||||
|  | 	[PORT_OWNER]		= REG_FIELD(ISP176x_HC_PORTSC1, 13, 13), | ||||||
|  | 	[PORT_POWER]		= REG_FIELD(ISP176x_HC_PORTSC1, 12, 12), | ||||||
|  | 	[PORT_LSTATUS]		= REG_FIELD(ISP176x_HC_PORTSC1, 10, 11), | ||||||
|  | 	[PORT_RESET]		= REG_FIELD(ISP176x_HC_PORTSC1, 8, 8), | ||||||
|  | 	[PORT_SUSPEND]		= REG_FIELD(ISP176x_HC_PORTSC1, 7, 7), | ||||||
|  | 	[PORT_RESUME]		= REG_FIELD(ISP176x_HC_PORTSC1, 6, 6), | ||||||
|  | 	[PORT_PE]		= REG_FIELD(ISP176x_HC_PORTSC1, 2, 2), | ||||||
|  | 	[PORT_CSC]		= REG_FIELD(ISP176x_HC_PORTSC1, 1, 1), | ||||||
|  | 	[PORT_CONNECT]		= REG_FIELD(ISP176x_HC_PORTSC1, 0, 0), | ||||||
|  | 	[ALL_ATX_RESET]		= REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 31, 31), | ||||||
|  | 	[HW_ANA_DIGI_OC]	= REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 15, 15), | ||||||
|  | 	[HW_COMN_IRQ]		= REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 10, 10), | ||||||
|  | 	[HW_DATA_BUS_WIDTH]	= REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 8, 8), | ||||||
|  | 	[HW_DACK_POL_HIGH]	= REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 6, 6), | ||||||
|  | 	[HW_DREQ_POL_HIGH]	= REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 5, 5), | ||||||
|  | 	[HW_INTR_HIGH_ACT]	= REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 2, 2), | ||||||
|  | 	[HW_INTR_EDGE_TRIG]	= REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 1, 1), | ||||||
|  | 	[HW_GLOBAL_INTR_EN]	= REG_FIELD(ISP176x_HC_HW_MODE_CTRL, 0, 0), | ||||||
|  | 	[HC_CHIP_REV]		= REG_FIELD(ISP176x_HC_CHIP_ID, 16, 31), | ||||||
|  | 	[HC_CHIP_ID_HIGH]	= REG_FIELD(ISP176x_HC_CHIP_ID, 8, 15), | ||||||
|  | 	[HC_CHIP_ID_LOW]	= REG_FIELD(ISP176x_HC_CHIP_ID, 0, 7), | ||||||
|  | 	[HC_SCRATCH]		= REG_FIELD(ISP176x_HC_SCRATCH, 0, 31), | ||||||
|  | 	[SW_RESET_RESET_ALL]	= REG_FIELD(ISP176x_HC_RESET, 0, 0), | ||||||
|  | 	[ISO_BUF_FILL]		= REG_FIELD(ISP176x_HC_BUFFER_STATUS, 2, 2), | ||||||
|  | 	[INT_BUF_FILL]		= REG_FIELD(ISP176x_HC_BUFFER_STATUS, 1, 1), | ||||||
|  | 	[ATL_BUF_FILL]		= REG_FIELD(ISP176x_HC_BUFFER_STATUS, 0, 0), | ||||||
|  | 	[MEM_BANK_SEL]		= REG_FIELD(ISP176x_HC_MEMORY, 16, 17), | ||||||
|  | 	[MEM_START_ADDR]	= REG_FIELD(ISP176x_HC_MEMORY, 0, 15), | ||||||
|  | 	[HC_INTERRUPT]		= REG_FIELD(ISP176x_HC_INTERRUPT, 0, 9), | ||||||
|  | 	[HC_ATL_IRQ_ENABLE]	= REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 8, 8), | ||||||
|  | 	[HC_INT_IRQ_ENABLE]	= REG_FIELD(ISP176x_HC_INTERRUPT_ENABLE, 7, 7), | ||||||
|  | 	[HC_ISO_IRQ_MASK_OR]	= REG_FIELD(ISP176x_HC_ISO_IRQ_MASK_OR, 0, 31), | ||||||
|  | 	[HC_INT_IRQ_MASK_OR]	= REG_FIELD(ISP176x_HC_INT_IRQ_MASK_OR, 0, 31), | ||||||
|  | 	[HC_ATL_IRQ_MASK_OR]	= REG_FIELD(ISP176x_HC_ATL_IRQ_MASK_OR, 0, 31), | ||||||
|  | 	[HC_ISO_IRQ_MASK_AND]	= REG_FIELD(ISP176x_HC_ISO_IRQ_MASK_AND, 0, 31), | ||||||
|  | 	[HC_INT_IRQ_MASK_AND]	= REG_FIELD(ISP176x_HC_INT_IRQ_MASK_AND, 0, 31), | ||||||
|  | 	[HC_ATL_IRQ_MASK_AND]	= REG_FIELD(ISP176x_HC_ATL_IRQ_MASK_AND, 0, 31), | ||||||
|  | 	[HW_OTG_DISABLE]	= REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 10, 10), | ||||||
|  | 	[HW_SW_SEL_HC_DC]	= REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 7, 7), | ||||||
|  | 	[HW_VBUS_DRV]		= REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 4, 4), | ||||||
|  | 	[HW_SEL_CP_EXT]		= REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 3, 3), | ||||||
|  | 	[HW_DM_PULLDOWN]	= REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 2, 2), | ||||||
|  | 	[HW_DP_PULLDOWN]	= REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 1, 1), | ||||||
|  | 	[HW_DP_PULLUP]		= REG_FIELD(ISP176x_HC_OTG_CTRL_SET, 0, 0), | ||||||
|  | 	[HW_OTG_DISABLE_CLEAR]	= REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 10, 10), | ||||||
|  | 	[HW_SW_SEL_HC_DC_CLEAR]	= REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 7, 7), | ||||||
|  | 	[HW_VBUS_DRV_CLEAR]	= REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 4, 4), | ||||||
|  | 	[HW_SEL_CP_EXT_CLEAR]	= REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 3, 3), | ||||||
|  | 	[HW_DM_PULLDOWN_CLEAR]	= REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 2, 2), | ||||||
|  | 	[HW_DP_PULLDOWN_CLEAR]	= REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 1, 1), | ||||||
|  | 	[HW_DP_PULLUP_CLEAR]	= REG_FIELD(ISP176x_HC_OTG_CTRL_CLEAR, 0, 0), | ||||||
|  | 	/* Make sure the array is sized properly during compilation */ | ||||||
|  | 	[HC_FIELD_MAX]		= {}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct regmap_config isp1763_hc_regmap_conf = { | ||||||
|  | 	.width = REGMAP_SIZE_16, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static const struct reg_field isp1763_hc_reg_fields[] = { | ||||||
|  | 	[CMD_LRESET]		= REG_FIELD(ISP1763_HC_USBCMD, 7, 7), | ||||||
|  | 	[CMD_RESET]		= REG_FIELD(ISP1763_HC_USBCMD, 1, 1), | ||||||
|  | 	[CMD_RUN]		= REG_FIELD(ISP1763_HC_USBCMD, 0, 0), | ||||||
|  | 	[STS_PCD]		= REG_FIELD(ISP1763_HC_USBSTS, 2, 2), | ||||||
|  | 	[HC_FRINDEX]		= REG_FIELD(ISP1763_HC_FRINDEX, 0, 13), | ||||||
|  | 	[FLAG_CF]		= REG_FIELD(ISP1763_HC_CONFIGFLAG, 0, 0), | ||||||
|  | 	[HC_ISO_PTD_DONEMAP]	= REG_FIELD(ISP1763_HC_ISO_PTD_DONEMAP, 0, 15), | ||||||
|  | 	[HC_ISO_PTD_SKIPMAP]	= REG_FIELD(ISP1763_HC_ISO_PTD_SKIPMAP, 0, 15), | ||||||
|  | 	[HC_ISO_PTD_LASTPTD]	= REG_FIELD(ISP1763_HC_ISO_PTD_LASTPTD, 0, 15), | ||||||
|  | 	[HC_INT_PTD_DONEMAP]	= REG_FIELD(ISP1763_HC_INT_PTD_DONEMAP, 0, 15), | ||||||
|  | 	[HC_INT_PTD_SKIPMAP]	= REG_FIELD(ISP1763_HC_INT_PTD_SKIPMAP, 0, 15), | ||||||
|  | 	[HC_INT_PTD_LASTPTD]	= REG_FIELD(ISP1763_HC_INT_PTD_LASTPTD, 0, 15), | ||||||
|  | 	[HC_ATL_PTD_DONEMAP]	= REG_FIELD(ISP1763_HC_ATL_PTD_DONEMAP, 0, 15), | ||||||
|  | 	[HC_ATL_PTD_SKIPMAP]	= REG_FIELD(ISP1763_HC_ATL_PTD_SKIPMAP, 0, 15), | ||||||
|  | 	[HC_ATL_PTD_LASTPTD]	= REG_FIELD(ISP1763_HC_ATL_PTD_LASTPTD, 0, 15), | ||||||
|  | 	[PORT_OWNER]		= REG_FIELD(ISP1763_HC_PORTSC1, 13, 13), | ||||||
|  | 	[PORT_POWER]		= REG_FIELD(ISP1763_HC_PORTSC1, 12, 12), | ||||||
|  | 	[PORT_LSTATUS]		= REG_FIELD(ISP1763_HC_PORTSC1, 10, 11), | ||||||
|  | 	[PORT_RESET]		= REG_FIELD(ISP1763_HC_PORTSC1, 8, 8), | ||||||
|  | 	[PORT_SUSPEND]		= REG_FIELD(ISP1763_HC_PORTSC1, 7, 7), | ||||||
|  | 	[PORT_RESUME]		= REG_FIELD(ISP1763_HC_PORTSC1, 6, 6), | ||||||
|  | 	[PORT_PE]		= REG_FIELD(ISP1763_HC_PORTSC1, 2, 2), | ||||||
|  | 	[PORT_CSC]		= REG_FIELD(ISP1763_HC_PORTSC1, 1, 1), | ||||||
|  | 	[PORT_CONNECT]		= REG_FIELD(ISP1763_HC_PORTSC1, 0, 0), | ||||||
|  | 	[HW_DATA_BUS_WIDTH]	= REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 4, 4), | ||||||
|  | 	[HW_DACK_POL_HIGH]	= REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 6, 6), | ||||||
|  | 	[HW_DREQ_POL_HIGH]	= REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 5, 5), | ||||||
|  | 	[HW_INTF_LOCK]		= REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 3, 3), | ||||||
|  | 	[HW_INTR_HIGH_ACT]	= REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 2, 2), | ||||||
|  | 	[HW_INTR_EDGE_TRIG]	= REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 1, 1), | ||||||
|  | 	[HW_GLOBAL_INTR_EN]	= REG_FIELD(ISP1763_HC_HW_MODE_CTRL, 0, 0), | ||||||
|  | 	[SW_RESET_RESET_ATX]	= REG_FIELD(ISP1763_HC_RESET, 3, 3), | ||||||
|  | 	[SW_RESET_RESET_ALL]	= REG_FIELD(ISP1763_HC_RESET, 0, 0), | ||||||
|  | 	[HC_CHIP_ID_HIGH]	= REG_FIELD(ISP1763_HC_CHIP_ID, 0, 15), | ||||||
|  | 	[HC_CHIP_ID_LOW]	= REG_FIELD(ISP1763_HC_CHIP_REV, 8, 15), | ||||||
|  | 	[HC_CHIP_REV]		= REG_FIELD(ISP1763_HC_CHIP_REV, 0, 7), | ||||||
|  | 	[HC_SCRATCH]		= REG_FIELD(ISP1763_HC_SCRATCH, 0, 15), | ||||||
|  | 	[ISO_BUF_FILL]		= REG_FIELD(ISP1763_HC_BUFFER_STATUS, 2, 2), | ||||||
|  | 	[INT_BUF_FILL]		= REG_FIELD(ISP1763_HC_BUFFER_STATUS, 1, 1), | ||||||
|  | 	[ATL_BUF_FILL]		= REG_FIELD(ISP1763_HC_BUFFER_STATUS, 0, 0), | ||||||
|  | 	[MEM_START_ADDR]	= REG_FIELD(ISP1763_HC_MEMORY, 0, 15), | ||||||
|  | 	[HC_DATA]		= REG_FIELD(ISP1763_HC_DATA, 0, 15), | ||||||
|  | 	[HC_INTERRUPT]		= REG_FIELD(ISP1763_HC_INTERRUPT, 0, 10), | ||||||
|  | 	[HC_ATL_IRQ_ENABLE]	= REG_FIELD(ISP1763_HC_INTERRUPT_ENABLE, 8, 8), | ||||||
|  | 	[HC_INT_IRQ_ENABLE]	= REG_FIELD(ISP1763_HC_INTERRUPT_ENABLE, 7, 7), | ||||||
|  | 	[HC_ISO_IRQ_MASK_OR]	= REG_FIELD(ISP1763_HC_ISO_IRQ_MASK_OR, 0, 15), | ||||||
|  | 	[HC_INT_IRQ_MASK_OR]	= REG_FIELD(ISP1763_HC_INT_IRQ_MASK_OR, 0, 15), | ||||||
|  | 	[HC_ATL_IRQ_MASK_OR]	= REG_FIELD(ISP1763_HC_ATL_IRQ_MASK_OR, 0, 15), | ||||||
|  | 	[HC_ISO_IRQ_MASK_AND]	= REG_FIELD(ISP1763_HC_ISO_IRQ_MASK_AND, 0, 15), | ||||||
|  | 	[HC_INT_IRQ_MASK_AND]	= REG_FIELD(ISP1763_HC_INT_IRQ_MASK_AND, 0, 15), | ||||||
|  | 	[HC_ATL_IRQ_MASK_AND]	= REG_FIELD(ISP1763_HC_ATL_IRQ_MASK_AND, 0, 15), | ||||||
|  | 	[HW_HC_2_DIS]		= REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 15, 15), | ||||||
|  | 	[HW_OTG_DISABLE]	= REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 10, 10), | ||||||
|  | 	[HW_SW_SEL_HC_DC]	= REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 7, 7), | ||||||
|  | 	[HW_VBUS_DRV]		= REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 4, 4), | ||||||
|  | 	[HW_SEL_CP_EXT]		= REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 3, 3), | ||||||
|  | 	[HW_DM_PULLDOWN]	= REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 2, 2), | ||||||
|  | 	[HW_DP_PULLDOWN]	= REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 1, 1), | ||||||
|  | 	[HW_DP_PULLUP]		= REG_FIELD(ISP1763_HC_OTG_CTRL_SET, 0, 0), | ||||||
|  | 	[HW_HC_2_DIS_CLEAR]	= REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 15, 15), | ||||||
|  | 	[HW_OTG_DISABLE_CLEAR]	= REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 10, 10), | ||||||
|  | 	[HW_SW_SEL_HC_DC_CLEAR]	= REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 7, 7), | ||||||
|  | 	[HW_VBUS_DRV_CLEAR]	= REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 4, 4), | ||||||
|  | 	[HW_SEL_CP_EXT_CLEAR]	= REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 3, 3), | ||||||
|  | 	[HW_DM_PULLDOWN_CLEAR]	= REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 2, 2), | ||||||
|  | 	[HW_DP_PULLDOWN_CLEAR]	= REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 1, 1), | ||||||
|  | 	[HW_DP_PULLUP_CLEAR]	= REG_FIELD(ISP1763_HC_OTG_CTRL_CLEAR, 0, 0), | ||||||
|  | 	/* Make sure the array is sized properly during compilation */ | ||||||
|  | 	[HC_FIELD_MAX]		= {}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | int isp1760_register(struct isp1760_device *isp, struct resource *mem, int irq, | ||||||
|  | 		     unsigned long irqflags) | ||||||
|  | { | ||||||
|  | 	const struct regmap_config *hc_regmap; | ||||||
|  | 	const struct reg_field *hc_reg_fields; | ||||||
|  | 	struct isp1760_hcd *hcd; | ||||||
|  | 	struct regmap_field *f; | ||||||
|  | 	unsigned int devflags; | ||||||
|  | 	struct udevice *dev; | ||||||
|  | 	int ret; | ||||||
|  | 	int i; | ||||||
|  | 
 | ||||||
|  | 	hcd = &isp->hcd; | ||||||
|  | 	devflags = isp->devflags; | ||||||
|  | 	dev = isp->dev; | ||||||
|  | 
 | ||||||
|  | 	hcd->is_isp1763 = !!(devflags & ISP1760_FLAG_ISP1763); | ||||||
|  | 
 | ||||||
|  | 	if (!hcd->is_isp1763 && (devflags & ISP1760_FLAG_BUS_WIDTH_8)) { | ||||||
|  | 		dev_err(dev, "isp1760/61 do not support data width 8\n"); | ||||||
|  | 		return -EINVAL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (hcd->is_isp1763) { | ||||||
|  | 		hc_regmap = &isp1763_hc_regmap_conf; | ||||||
|  | 		hc_reg_fields = &isp1763_hc_reg_fields[0]; | ||||||
|  | 	} else { | ||||||
|  | 		hc_regmap = &isp1760_hc_regmap_conf; | ||||||
|  | 		hc_reg_fields = &isp1760_hc_reg_fields[0]; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	hcd->base = devm_ioremap(dev, mem->start, resource_size(mem)); | ||||||
|  | 	if (IS_ERR(hcd->base)) | ||||||
|  | 		return PTR_ERR(hcd->base); | ||||||
|  | 
 | ||||||
|  | 	hcd->regs = devm_regmap_init(dev, NULL, NULL, hc_regmap); | ||||||
|  | 	if (IS_ERR(hcd->regs)) | ||||||
|  | 		return PTR_ERR(hcd->regs); | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < HC_FIELD_MAX; i++) { | ||||||
|  | 		f = devm_regmap_field_alloc(dev, hcd->regs, hc_reg_fields[i]); | ||||||
|  | 		if (IS_ERR(f)) | ||||||
|  | 			return PTR_ERR(f); | ||||||
|  | 
 | ||||||
|  | 		hcd->fields[i] = f; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (hcd->is_isp1763) | ||||||
|  | 		hcd->memory_layout = &isp1763_memory_conf; | ||||||
|  | 	else | ||||||
|  | 		hcd->memory_layout = &isp176x_memory_conf; | ||||||
|  | 
 | ||||||
|  | 	ret = isp1760_init_core(isp); | ||||||
|  | 	if (ret < 0) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	hcd->dev = dev; | ||||||
|  | 
 | ||||||
|  | 	ret = isp1760_hcd_register(hcd, mem, irq, irqflags, dev); | ||||||
|  | 	if (ret < 0) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	ret = isp1760_hcd_lowlevel_init(hcd); | ||||||
|  | 	if (ret < 0) | ||||||
|  | 		return ret; | ||||||
|  | 
 | ||||||
|  | 	dev_set_drvdata(dev, isp); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void isp1760_unregister(struct isp1760_device *isp) | ||||||
|  | { | ||||||
|  | 	isp1760_hcd_unregister(&isp->hcd); | ||||||
|  | } | ||||||
|  | @ -0,0 +1,96 @@ | ||||||
|  | /* SPDX-License-Identifier: GPL-2.0 */ | ||||||
|  | /*
 | ||||||
|  |  * Driver for the NXP ISP1760 chip | ||||||
|  |  * | ||||||
|  |  * Copyright 2021 Linaro, Rui Miguel Silva | ||||||
|  |  * Copyright 2014 Laurent Pinchart | ||||||
|  |  * Copyright 2007 Sebastian Siewior | ||||||
|  |  * | ||||||
|  |  * Contacts: | ||||||
|  |  *	Sebastian Siewior <bigeasy@linutronix.de> | ||||||
|  |  *	Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||||||
|  |  *	Rui Miguel Silva <rui.silva@linaro.org> | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef _ISP1760_CORE_H_ | ||||||
|  | #define _ISP1760_CORE_H_ | ||||||
|  | 
 | ||||||
|  | #include <linux/compat.h> | ||||||
|  | #include <linux/ioport.h> | ||||||
|  | #include <regmap.h> | ||||||
|  | 
 | ||||||
|  | #include "isp1760-hcd.h" | ||||||
|  | 
 | ||||||
|  | struct device; | ||||||
|  | struct gpio_desc; | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Device flags that can vary from board to board.  All of these | ||||||
|  |  * indicate the most "atypical" case, so that a devflags of 0 is | ||||||
|  |  * a sane default configuration. | ||||||
|  |  */ | ||||||
|  | #define ISP1760_FLAG_BUS_WIDTH_16	0x00000002 /* 16-bit data bus width */ | ||||||
|  | #define ISP1760_FLAG_PERIPHERAL_EN	0x00000004 /* Port 1 supports Peripheral mode*/ | ||||||
|  | #define ISP1760_FLAG_ANALOG_OC		0x00000008 /* Analog overcurrent */ | ||||||
|  | #define ISP1760_FLAG_DACK_POL_HIGH	0x00000010 /* DACK active high */ | ||||||
|  | #define ISP1760_FLAG_DREQ_POL_HIGH	0x00000020 /* DREQ active high */ | ||||||
|  | #define ISP1760_FLAG_ISP1761		0x00000040 /* Chip is ISP1761 */ | ||||||
|  | #define ISP1760_FLAG_INTR_POL_HIGH	0x00000080 /* Interrupt polarity active high */ | ||||||
|  | #define ISP1760_FLAG_INTR_EDGE_TRIG	0x00000100 /* Interrupt edge triggered */ | ||||||
|  | #define ISP1760_FLAG_ISP1763		0x00000200 /* Chip is ISP1763 */ | ||||||
|  | #define ISP1760_FLAG_BUS_WIDTH_8	0x00000400 /* 8-bit data bus width */ | ||||||
|  | 
 | ||||||
|  | struct isp1760_device { | ||||||
|  | 	struct udevice *dev; | ||||||
|  | 
 | ||||||
|  | 	unsigned int devflags; | ||||||
|  | 	struct gpio_desc *rst_gpio; | ||||||
|  | 
 | ||||||
|  | 	struct isp1760_hcd hcd; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | int isp1760_register(struct isp1760_device *isp, struct resource *mem, int irq, | ||||||
|  | 		     unsigned long irqflags); | ||||||
|  | void isp1760_unregister(struct isp1760_device *isp); | ||||||
|  | 
 | ||||||
|  | void isp1760_set_pullup(struct isp1760_device *isp, bool enable); | ||||||
|  | 
 | ||||||
|  | static inline u32 isp1760_field_read(struct regmap_field **fields, u32 field) | ||||||
|  | { | ||||||
|  | 	unsigned int val; | ||||||
|  | 
 | ||||||
|  | 	regmap_field_read(fields[field], &val); | ||||||
|  | 
 | ||||||
|  | 	return val; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void isp1760_field_write(struct regmap_field **fields, u32 field, | ||||||
|  | 				       u32 val) | ||||||
|  | { | ||||||
|  | 	regmap_field_write(fields[field], val); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void isp1760_field_set(struct regmap_field **fields, u32 field) | ||||||
|  | { | ||||||
|  | 	isp1760_field_write(fields, field, 0xFFFFFFFF); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void isp1760_field_clear(struct regmap_field **fields, u32 field) | ||||||
|  | { | ||||||
|  | 	isp1760_field_write(fields, field, 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline u32 isp1760_reg_read(struct regmap *regs, u32 reg) | ||||||
|  | { | ||||||
|  | 	unsigned int val; | ||||||
|  | 
 | ||||||
|  | 	regmap_read(regs, reg, &val); | ||||||
|  | 
 | ||||||
|  | 	return val; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline void isp1760_reg_write(struct regmap *regs, u32 reg, u32 val) | ||||||
|  | { | ||||||
|  | 	regmap_write(regs, reg, val); | ||||||
|  | } | ||||||
|  | #endif | ||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -0,0 +1,81 @@ | ||||||
|  | /* SPDX-License-Identifier: GPL-2.0 */ | ||||||
|  | #ifndef _ISP1760_HCD_H_ | ||||||
|  | #define _ISP1760_HCD_H_ | ||||||
|  | 
 | ||||||
|  | #include <regmap.h> | ||||||
|  | 
 | ||||||
|  | #include "isp1760-regs.h" | ||||||
|  | 
 | ||||||
|  | struct isp1760_qh; | ||||||
|  | struct isp1760_qtd; | ||||||
|  | struct resource; | ||||||
|  | struct usb_hcd; | ||||||
|  | 
 | ||||||
|  | struct isp1760_slotinfo { | ||||||
|  | 	struct isp1760_qh *qh; | ||||||
|  | 	struct isp1760_qtd *qtd; | ||||||
|  | 	unsigned long timestamp; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* chip memory management */ | ||||||
|  | #define ISP176x_BLOCK_MAX (32 + 20 + 4) | ||||||
|  | #define ISP176x_BLOCK_NUM 3 | ||||||
|  | 
 | ||||||
|  | struct isp1760_memory_layout { | ||||||
|  | 	unsigned int blocks[ISP176x_BLOCK_NUM]; | ||||||
|  | 	unsigned int blocks_size[ISP176x_BLOCK_NUM]; | ||||||
|  | 
 | ||||||
|  | 	unsigned int slot_num; | ||||||
|  | 	unsigned int payload_blocks; | ||||||
|  | 	unsigned int payload_area_size; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct isp1760_memory_chunk { | ||||||
|  | 	unsigned int start; | ||||||
|  | 	unsigned int size; | ||||||
|  | 	unsigned int free; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | enum isp1760_queue_head_types { | ||||||
|  | 	QH_CONTROL, | ||||||
|  | 	QH_BULK, | ||||||
|  | 	QH_INTERRUPT, | ||||||
|  | 	QH_END | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct isp1760_hcd { | ||||||
|  | 	struct usb_hcd		*hcd; | ||||||
|  | 	struct udevice		*dev; | ||||||
|  | 
 | ||||||
|  | 	void __iomem		*base; | ||||||
|  | 
 | ||||||
|  | 	struct regmap		*regs; | ||||||
|  | 	struct regmap_field	*fields[HC_FIELD_MAX]; | ||||||
|  | 
 | ||||||
|  | 	bool			is_isp1763; | ||||||
|  | 	const struct isp1760_memory_layout	*memory_layout; | ||||||
|  | 
 | ||||||
|  | 	struct isp1760_slotinfo	*atl_slots; | ||||||
|  | 	int			atl_done_map; | ||||||
|  | 	struct isp1760_slotinfo	*int_slots; | ||||||
|  | 	int			int_done_map; | ||||||
|  | 	struct isp1760_memory_chunk memory_pool[ISP176x_BLOCK_MAX]; | ||||||
|  | 	struct list_head	qh_list[QH_END]; | ||||||
|  | 
 | ||||||
|  | 	/* periodic schedule support */ | ||||||
|  | #define	DEFAULT_I_TDPS		1024 | ||||||
|  | 	unsigned int		periodic_size; | ||||||
|  | 	unsigned int		i_thresh; | ||||||
|  | 	unsigned long		reset_done; | ||||||
|  | 	unsigned long		next_statechange; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | int isp1760_hcd_register(struct isp1760_hcd *priv, struct resource *mem, | ||||||
|  | 			 int irq, unsigned long irqflags, struct udevice *dev); | ||||||
|  | void isp1760_hcd_unregister(struct isp1760_hcd *priv); | ||||||
|  | int isp1760_hcd_lowlevel_init(struct isp1760_hcd *priv); | ||||||
|  | 
 | ||||||
|  | int isp1760_init_kmem_once(void); | ||||||
|  | void isp1760_deinit_kmem_cache(void); | ||||||
|  | 
 | ||||||
|  | #endif /* _ISP1760_HCD_H_ */ | ||||||
|  | @ -0,0 +1,125 @@ | ||||||
|  | // SPDX-License-Identifier: GPL-2.0
 | ||||||
|  | /*
 | ||||||
|  |  * Copyright 2021 Linaro, Rui Miguel Silva <rui.silva@linaro.org> | ||||||
|  |  * | ||||||
|  |  * based on original code from: | ||||||
|  |  * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de> | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <common.h> | ||||||
|  | #include <dm.h> | ||||||
|  | #include <dm/device-internal.h> | ||||||
|  | #include <dm/device_compat.h> | ||||||
|  | #include <dm/devres.h> | ||||||
|  | #include <dm/lists.h> | ||||||
|  | #include <linux/bug.h> | ||||||
|  | #include <linux/io.h> | ||||||
|  | #include <linux/kernel.h> | ||||||
|  | #include <linux/usb/otg.h> | ||||||
|  | #include <log.h> | ||||||
|  | #include <usb.h> | ||||||
|  | 
 | ||||||
|  | #include "isp1760-core.h" | ||||||
|  | #include "isp1760-regs.h" | ||||||
|  | #include "isp1760-uboot.h" | ||||||
|  | 
 | ||||||
|  | static int isp1760_of_to_plat(struct udevice *dev) | ||||||
|  | { | ||||||
|  | 	struct isp1760_device *isp = dev_get_plat(dev); | ||||||
|  | 	unsigned int devflags = 0; | ||||||
|  | 	u32 bus_width = 0; | ||||||
|  | 	ofnode dp; | ||||||
|  | 
 | ||||||
|  | 	if (!dev_has_ofnode(dev)) { | ||||||
|  | 		/* select isp1763 as the default device */ | ||||||
|  | 		devflags = ISP1760_FLAG_ISP1763 | ISP1760_FLAG_BUS_WIDTH_16; | ||||||
|  | 		pr_err("isp1760: no platform data\n"); | ||||||
|  | 		goto isp_setup; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	dp = dev_ofnode(dev); | ||||||
|  | 
 | ||||||
|  | 	if (ofnode_device_is_compatible(dp, "nxp,usb-isp1761")) | ||||||
|  | 		devflags |= ISP1760_FLAG_ISP1761; | ||||||
|  | 
 | ||||||
|  | 	if (ofnode_device_is_compatible(dp, "nxp,usb-isp1763")) | ||||||
|  | 		devflags |= ISP1760_FLAG_ISP1763; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Some systems wire up only 8 of 16 data lines or | ||||||
|  | 	 * 16 of the 32 data lines | ||||||
|  | 	 */ | ||||||
|  | 	bus_width = ofnode_read_u32_default(dp, "bus-width", 16); | ||||||
|  | 	if (bus_width == 16) | ||||||
|  | 		devflags |= ISP1760_FLAG_BUS_WIDTH_16; | ||||||
|  | 	else if (bus_width == 8) | ||||||
|  | 		devflags |= ISP1760_FLAG_BUS_WIDTH_8; | ||||||
|  | 
 | ||||||
|  | 	if (usb_get_dr_mode(dev_ofnode(dev)) == USB_DR_MODE_PERIPHERAL) | ||||||
|  | 		devflags |= ISP1760_FLAG_PERIPHERAL_EN; | ||||||
|  | 
 | ||||||
|  | 	if (ofnode_read_bool(dp, "analog-oc")) | ||||||
|  | 		devflags |= ISP1760_FLAG_ANALOG_OC; | ||||||
|  | 
 | ||||||
|  | 	if (ofnode_read_bool(dp, "dack-polarity")) | ||||||
|  | 		devflags |= ISP1760_FLAG_DACK_POL_HIGH; | ||||||
|  | 
 | ||||||
|  | 	if (ofnode_read_bool(dp, "dreq-polarity")) | ||||||
|  | 		devflags |= ISP1760_FLAG_DREQ_POL_HIGH; | ||||||
|  | 
 | ||||||
|  | isp_setup: | ||||||
|  | 	isp->devflags = devflags; | ||||||
|  | 	isp->dev = dev; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int isp1760_plat_probe(struct udevice *dev) | ||||||
|  | { | ||||||
|  | 	struct isp1760_device *isp = dev_get_plat(dev); | ||||||
|  | 	struct resource mem_res; | ||||||
|  | 	struct resource irq_res; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	dev_read_resource(dev, 0, &mem_res); | ||||||
|  | 	dev_read_resource(dev, 1, &irq_res); | ||||||
|  | 
 | ||||||
|  | 	isp1760_init_kmem_once(); | ||||||
|  | 
 | ||||||
|  | 	ret = isp1760_register(isp, &mem_res, irq_res.start, irq_res.flags); | ||||||
|  | 	if (ret < 0) { | ||||||
|  | 		isp1760_deinit_kmem_cache(); | ||||||
|  | 		return ret; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int isp1760_plat_remove(struct udevice *dev) | ||||||
|  | { | ||||||
|  | 	struct isp1760_device *isp = dev_get_plat(dev); | ||||||
|  | 
 | ||||||
|  | 	isp1760_deinit_kmem_cache(); | ||||||
|  | 	isp1760_unregister(isp); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static const struct udevice_id isp1760_ids[] = { | ||||||
|  | 	{ .compatible = "nxp,usb-isp1760", }, | ||||||
|  | 	{ .compatible = "nxp,usb-isp1761", }, | ||||||
|  | 	{ .compatible = "nxp,usb-isp1763", }, | ||||||
|  | 	{ }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | U_BOOT_DRIVER(isp1760) = { | ||||||
|  | 	.name		= "isp1760", | ||||||
|  | 	.id		= UCLASS_USB, | ||||||
|  | 	.of_match	= isp1760_ids, | ||||||
|  | 	.of_to_plat	= isp1760_of_to_plat, | ||||||
|  | 	.ops		= &isp1760_usb_ops, | ||||||
|  | 	.probe		= isp1760_plat_probe, | ||||||
|  | 	.remove		= isp1760_plat_remove, | ||||||
|  | 	.plat_auto	= sizeof(struct isp1760_device), | ||||||
|  | 	.priv_auto	= sizeof(struct isp1760_host_data), | ||||||
|  | }; | ||||||
|  | @ -0,0 +1,292 @@ | ||||||
|  | /* SPDX-License-Identifier: GPL-2.0 */ | ||||||
|  | /*
 | ||||||
|  |  * Driver for the NXP ISP1760 chip | ||||||
|  |  * | ||||||
|  |  * Copyright 2021 Linaro, Rui Miguel Silva | ||||||
|  |  * Copyright 2014 Laurent Pinchart | ||||||
|  |  * Copyright 2007 Sebastian Siewior | ||||||
|  |  * | ||||||
|  |  * Contacts: | ||||||
|  |  *     Sebastian Siewior <bigeasy@linutronix.de> | ||||||
|  |  *     Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||||||
|  |  *     Rui Miguel Silva <rui.silva@linaro.org> | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef _ISP176x_REGS_H_ | ||||||
|  | #define _ISP176x_REGS_H_ | ||||||
|  | 
 | ||||||
|  | /* -----------------------------------------------------------------------------
 | ||||||
|  |  * Host Controller | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | /* ISP1760/31 */ | ||||||
|  | /* EHCI capability registers */ | ||||||
|  | #define ISP176x_HC_VERSION		0x002 | ||||||
|  | #define ISP176x_HC_HCSPARAMS		0x004 | ||||||
|  | #define ISP176x_HC_HCCPARAMS		0x008 | ||||||
|  | 
 | ||||||
|  | /* EHCI operational registers */ | ||||||
|  | #define ISP176x_HC_USBCMD		0x020 | ||||||
|  | #define ISP176x_HC_USBSTS		0x024 | ||||||
|  | #define ISP176x_HC_FRINDEX		0x02c | ||||||
|  | 
 | ||||||
|  | #define ISP176x_HC_CONFIGFLAG		0x060 | ||||||
|  | #define ISP176x_HC_PORTSC1		0x064 | ||||||
|  | 
 | ||||||
|  | #define ISP176x_HC_ISO_PTD_DONEMAP	0x130 | ||||||
|  | #define ISP176x_HC_ISO_PTD_SKIPMAP	0x134 | ||||||
|  | #define ISP176x_HC_ISO_PTD_LASTPTD	0x138 | ||||||
|  | #define ISP176x_HC_INT_PTD_DONEMAP	0x140 | ||||||
|  | #define ISP176x_HC_INT_PTD_SKIPMAP	0x144 | ||||||
|  | #define ISP176x_HC_INT_PTD_LASTPTD	0x148 | ||||||
|  | #define ISP176x_HC_ATL_PTD_DONEMAP	0x150 | ||||||
|  | #define ISP176x_HC_ATL_PTD_SKIPMAP	0x154 | ||||||
|  | #define ISP176x_HC_ATL_PTD_LASTPTD	0x158 | ||||||
|  | 
 | ||||||
|  | /* Configuration Register */ | ||||||
|  | #define ISP176x_HC_HW_MODE_CTRL		0x300 | ||||||
|  | #define ISP176x_HC_CHIP_ID		0x304 | ||||||
|  | #define ISP176x_HC_SCRATCH		0x308 | ||||||
|  | #define ISP176x_HC_RESET		0x30c | ||||||
|  | #define ISP176x_HC_BUFFER_STATUS	0x334 | ||||||
|  | #define ISP176x_HC_MEMORY		0x33c | ||||||
|  | 
 | ||||||
|  | /* Interrupt Register */ | ||||||
|  | #define ISP176x_HC_INTERRUPT		0x310 | ||||||
|  | #define ISP176x_HC_INTERRUPT_ENABLE	0x314 | ||||||
|  | #define ISP176x_HC_ISO_IRQ_MASK_OR	0x318 | ||||||
|  | #define ISP176x_HC_INT_IRQ_MASK_OR	0x31c | ||||||
|  | #define ISP176x_HC_ATL_IRQ_MASK_OR	0x320 | ||||||
|  | #define ISP176x_HC_ISO_IRQ_MASK_AND	0x324 | ||||||
|  | #define ISP176x_HC_INT_IRQ_MASK_AND	0x328 | ||||||
|  | #define ISP176x_HC_ATL_IRQ_MASK_AND	0x32c | ||||||
|  | 
 | ||||||
|  | #define ISP176x_HC_OTG_CTRL_SET		0x374 | ||||||
|  | #define ISP176x_HC_OTG_CTRL_CLEAR	0x376 | ||||||
|  | 
 | ||||||
|  | enum isp176x_host_controller_fields { | ||||||
|  | 	/* HC_PORTSC1 */ | ||||||
|  | 	PORT_OWNER, PORT_POWER, PORT_LSTATUS, PORT_RESET, PORT_SUSPEND, | ||||||
|  | 	PORT_RESUME, PORT_PE, PORT_CSC, PORT_CONNECT, | ||||||
|  | 	/* HC_HCSPARAMS */ | ||||||
|  | 	HCS_PPC, HCS_N_PORTS, | ||||||
|  | 	/* HC_HCCPARAMS */ | ||||||
|  | 	HCC_ISOC_CACHE, HCC_ISOC_THRES, | ||||||
|  | 	/* HC_USBCMD */ | ||||||
|  | 	CMD_LRESET, CMD_RESET, CMD_RUN, | ||||||
|  | 	/* HC_USBSTS */ | ||||||
|  | 	STS_PCD, | ||||||
|  | 	/* HC_FRINDEX */ | ||||||
|  | 	HC_FRINDEX, | ||||||
|  | 	/* HC_CONFIGFLAG */ | ||||||
|  | 	FLAG_CF, | ||||||
|  | 	/* ISO/INT/ATL PTD */ | ||||||
|  | 	HC_ISO_PTD_DONEMAP, HC_ISO_PTD_SKIPMAP, HC_ISO_PTD_LASTPTD, | ||||||
|  | 	HC_INT_PTD_DONEMAP, HC_INT_PTD_SKIPMAP, HC_INT_PTD_LASTPTD, | ||||||
|  | 	HC_ATL_PTD_DONEMAP, HC_ATL_PTD_SKIPMAP, HC_ATL_PTD_LASTPTD, | ||||||
|  | 	/* HC_HW_MODE_CTRL */ | ||||||
|  | 	ALL_ATX_RESET, HW_ANA_DIGI_OC, HW_DEV_DMA, HW_COMN_IRQ, HW_COMN_DMA, | ||||||
|  | 	HW_DATA_BUS_WIDTH, HW_DACK_POL_HIGH, HW_DREQ_POL_HIGH, HW_INTR_HIGH_ACT, | ||||||
|  | 	HW_INTF_LOCK, HW_INTR_EDGE_TRIG, HW_GLOBAL_INTR_EN, | ||||||
|  | 	/* HC_CHIP_ID */ | ||||||
|  | 	HC_CHIP_ID_HIGH, HC_CHIP_ID_LOW, HC_CHIP_REV, | ||||||
|  | 	/* HC_SCRATCH */ | ||||||
|  | 	HC_SCRATCH, | ||||||
|  | 	/* HC_RESET */ | ||||||
|  | 	SW_RESET_RESET_ATX, SW_RESET_RESET_HC, SW_RESET_RESET_ALL, | ||||||
|  | 	/* HC_BUFFER_STATUS */ | ||||||
|  | 	ISO_BUF_FILL, INT_BUF_FILL, ATL_BUF_FILL, | ||||||
|  | 	/* HC_MEMORY */ | ||||||
|  | 	MEM_BANK_SEL, MEM_START_ADDR, | ||||||
|  | 	/* HC_DATA */ | ||||||
|  | 	HC_DATA, | ||||||
|  | 	/* HC_INTERRUPT */ | ||||||
|  | 	HC_INTERRUPT, | ||||||
|  | 	/* HC_INTERRUPT_ENABLE */ | ||||||
|  | 	HC_INT_IRQ_ENABLE, HC_ATL_IRQ_ENABLE, | ||||||
|  | 	/* INTERRUPT MASKS */ | ||||||
|  | 	HC_ISO_IRQ_MASK_OR, HC_INT_IRQ_MASK_OR, HC_ATL_IRQ_MASK_OR, | ||||||
|  | 	HC_ISO_IRQ_MASK_AND, HC_INT_IRQ_MASK_AND, HC_ATL_IRQ_MASK_AND, | ||||||
|  | 	/* HW_OTG_CTRL_SET */ | ||||||
|  | 	HW_OTG_DISABLE, HW_SW_SEL_HC_DC, HW_VBUS_DRV, HW_SEL_CP_EXT, | ||||||
|  | 	HW_DM_PULLDOWN, HW_DP_PULLDOWN, HW_DP_PULLUP, HW_HC_2_DIS, | ||||||
|  | 	/* HW_OTG_CTRL_CLR */ | ||||||
|  | 	HW_OTG_DISABLE_CLEAR, HW_SW_SEL_HC_DC_CLEAR, HW_VBUS_DRV_CLEAR, | ||||||
|  | 	HW_SEL_CP_EXT_CLEAR, HW_DM_PULLDOWN_CLEAR, HW_DP_PULLDOWN_CLEAR, | ||||||
|  | 	HW_DP_PULLUP_CLEAR, HW_HC_2_DIS_CLEAR, | ||||||
|  | 	/* Last element */ | ||||||
|  | 	HC_FIELD_MAX, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* ISP1763 */ | ||||||
|  | /* EHCI operational registers */ | ||||||
|  | #define ISP1763_HC_USBCMD		0x8c | ||||||
|  | #define ISP1763_HC_USBSTS		0x90 | ||||||
|  | #define ISP1763_HC_FRINDEX		0x98 | ||||||
|  | 
 | ||||||
|  | #define ISP1763_HC_CONFIGFLAG		0x9c | ||||||
|  | #define ISP1763_HC_PORTSC1		0xa0 | ||||||
|  | 
 | ||||||
|  | #define ISP1763_HC_ISO_PTD_DONEMAP	0xa4 | ||||||
|  | #define ISP1763_HC_ISO_PTD_SKIPMAP	0xa6 | ||||||
|  | #define ISP1763_HC_ISO_PTD_LASTPTD	0xa8 | ||||||
|  | #define ISP1763_HC_INT_PTD_DONEMAP	0xaa | ||||||
|  | #define ISP1763_HC_INT_PTD_SKIPMAP	0xac | ||||||
|  | #define ISP1763_HC_INT_PTD_LASTPTD	0xae | ||||||
|  | #define ISP1763_HC_ATL_PTD_DONEMAP	0xb0 | ||||||
|  | #define ISP1763_HC_ATL_PTD_SKIPMAP	0xb2 | ||||||
|  | #define ISP1763_HC_ATL_PTD_LASTPTD	0xb4 | ||||||
|  | 
 | ||||||
|  | /* Configuration Register */ | ||||||
|  | #define ISP1763_HC_HW_MODE_CTRL		0xb6 | ||||||
|  | #define ISP1763_HC_CHIP_REV		0x70 | ||||||
|  | #define ISP1763_HC_CHIP_ID		0x72 | ||||||
|  | #define ISP1763_HC_SCRATCH		0x78 | ||||||
|  | #define ISP1763_HC_RESET		0xb8 | ||||||
|  | #define ISP1763_HC_BUFFER_STATUS	0xba | ||||||
|  | #define ISP1763_HC_MEMORY		0xc4 | ||||||
|  | #define ISP1763_HC_DATA			0xc6 | ||||||
|  | 
 | ||||||
|  | /* Interrupt Register */ | ||||||
|  | #define ISP1763_HC_INTERRUPT		0xd4 | ||||||
|  | #define ISP1763_HC_INTERRUPT_ENABLE	0xd6 | ||||||
|  | #define ISP1763_HC_ISO_IRQ_MASK_OR	0xd8 | ||||||
|  | #define ISP1763_HC_INT_IRQ_MASK_OR	0xda | ||||||
|  | #define ISP1763_HC_ATL_IRQ_MASK_OR	0xdc | ||||||
|  | #define ISP1763_HC_ISO_IRQ_MASK_AND	0xde | ||||||
|  | #define ISP1763_HC_INT_IRQ_MASK_AND	0xe0 | ||||||
|  | #define ISP1763_HC_ATL_IRQ_MASK_AND	0xe2 | ||||||
|  | 
 | ||||||
|  | #define ISP1763_HC_OTG_CTRL_SET		0xe4 | ||||||
|  | #define ISP1763_HC_OTG_CTRL_CLEAR	0xe6 | ||||||
|  | 
 | ||||||
|  | /* -----------------------------------------------------------------------------
 | ||||||
|  |  * Peripheral Controller | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #define DC_IEPTX(n)			(1 << (11 + 2 * (n))) | ||||||
|  | #define DC_IEPRX(n)			(1 << (10 + 2 * (n))) | ||||||
|  | #define DC_IEPRXTX(n)			(3 << (10 + 2 * (n))) | ||||||
|  | 
 | ||||||
|  | #define ISP176x_DC_CDBGMOD_ACK		BIT(6) | ||||||
|  | #define ISP176x_DC_DDBGMODIN_ACK	BIT(4) | ||||||
|  | #define ISP176x_DC_DDBGMODOUT_ACK	BIT(2) | ||||||
|  | 
 | ||||||
|  | #define ISP176x_DC_IEP0SETUP		BIT(8) | ||||||
|  | #define ISP176x_DC_IEVBUS		BIT(7) | ||||||
|  | #define ISP176x_DC_IEHS_STA		BIT(5) | ||||||
|  | #define ISP176x_DC_IERESM		BIT(4) | ||||||
|  | #define ISP176x_DC_IESUSP		BIT(3) | ||||||
|  | #define ISP176x_DC_IEBRST		BIT(0) | ||||||
|  | 
 | ||||||
|  | #define ISP176x_DC_ENDPTYP_ISOC		0x01 | ||||||
|  | #define ISP176x_DC_ENDPTYP_BULK		0x02 | ||||||
|  | #define ISP176x_DC_ENDPTYP_INTERRUPT	0x03 | ||||||
|  | 
 | ||||||
|  | /* Initialization Registers */ | ||||||
|  | #define ISP176x_DC_ADDRESS		0x0200 | ||||||
|  | #define ISP176x_DC_MODE			0x020c | ||||||
|  | #define ISP176x_DC_INTCONF		0x0210 | ||||||
|  | #define ISP176x_DC_DEBUG		0x0212 | ||||||
|  | #define ISP176x_DC_INTENABLE		0x0214 | ||||||
|  | 
 | ||||||
|  | /* Data Flow Registers */ | ||||||
|  | #define ISP176x_DC_EPMAXPKTSZ		0x0204 | ||||||
|  | #define ISP176x_DC_EPTYPE		0x0208 | ||||||
|  | 
 | ||||||
|  | #define ISP176x_DC_BUFLEN		0x021c | ||||||
|  | #define ISP176x_DC_BUFSTAT		0x021e | ||||||
|  | #define ISP176x_DC_DATAPORT		0x0220 | ||||||
|  | 
 | ||||||
|  | #define ISP176x_DC_CTRLFUNC		0x0228 | ||||||
|  | #define ISP176x_DC_EPINDEX		0x022c | ||||||
|  | 
 | ||||||
|  | /* DMA Registers */ | ||||||
|  | #define ISP176x_DC_DMACMD		0x0230 | ||||||
|  | #define ISP176x_DC_DMATXCOUNT		0x0234 | ||||||
|  | #define ISP176x_DC_DMACONF		0x0238 | ||||||
|  | #define ISP176x_DC_DMAHW		0x023c | ||||||
|  | #define ISP176x_DC_DMAINTREASON		0x0250 | ||||||
|  | #define ISP176x_DC_DMAINTEN		0x0254 | ||||||
|  | #define ISP176x_DC_DMAEP		0x0258 | ||||||
|  | #define ISP176x_DC_DMABURSTCOUNT	0x0264 | ||||||
|  | 
 | ||||||
|  | /* General Registers */ | ||||||
|  | #define ISP176x_DC_INTERRUPT		0x0218 | ||||||
|  | #define ISP176x_DC_CHIPID		0x0270 | ||||||
|  | #define ISP176x_DC_FRAMENUM		0x0274 | ||||||
|  | #define ISP176x_DC_SCRATCH		0x0278 | ||||||
|  | #define ISP176x_DC_UNLOCKDEV		0x027c | ||||||
|  | #define ISP176x_DC_INTPULSEWIDTH	0x0280 | ||||||
|  | #define ISP176x_DC_TESTMODE		0x0284 | ||||||
|  | 
 | ||||||
|  | enum isp176x_device_controller_fields { | ||||||
|  | 	/* DC_ADDRESS */ | ||||||
|  | 	DC_DEVEN, DC_DEVADDR, | ||||||
|  | 	/* DC_MODE */ | ||||||
|  | 	DC_VBUSSTAT, DC_SFRESET, DC_GLINTENA, | ||||||
|  | 	/* DC_INTCONF */ | ||||||
|  | 	DC_CDBGMOD_ACK, DC_DDBGMODIN_ACK, DC_DDBGMODOUT_ACK, DC_INTPOL, | ||||||
|  | 	/* DC_INTENABLE */ | ||||||
|  | 	DC_IEPRXTX_7, DC_IEPRXTX_6, DC_IEPRXTX_5, DC_IEPRXTX_4, DC_IEPRXTX_3, | ||||||
|  | 	DC_IEPRXTX_2, DC_IEPRXTX_1, DC_IEPRXTX_0, | ||||||
|  | 	DC_IEP0SETUP, DC_IEVBUS, DC_IEHS_STA, DC_IERESM, DC_IESUSP, DC_IEBRST, | ||||||
|  | 	/* DC_EPINDEX */ | ||||||
|  | 	DC_EP0SETUP, DC_ENDPIDX, DC_EPDIR, | ||||||
|  | 	/* DC_CTRLFUNC */ | ||||||
|  | 	DC_CLBUF, DC_VENDP, DC_DSEN, DC_STATUS, DC_STALL, | ||||||
|  | 	/* DC_BUFLEN */ | ||||||
|  | 	DC_BUFLEN, | ||||||
|  | 	/* DC_EPMAXPKTSZ */ | ||||||
|  | 	DC_FFOSZ, | ||||||
|  | 	/* DC_EPTYPE */ | ||||||
|  | 	DC_EPENABLE, DC_ENDPTYP, | ||||||
|  | 	/* DC_FRAMENUM */ | ||||||
|  | 	DC_FRAMENUM, DC_UFRAMENUM, | ||||||
|  | 	/* DC_CHIP_ID */ | ||||||
|  | 	DC_CHIP_ID_HIGH, DC_CHIP_ID_LOW, | ||||||
|  | 	/* DC_SCRATCH */ | ||||||
|  | 	DC_SCRATCH, | ||||||
|  | 	/* Last element */ | ||||||
|  | 	DC_FIELD_MAX, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /* ISP1763 */ | ||||||
|  | /* Initialization Registers */ | ||||||
|  | #define ISP1763_DC_ADDRESS		0x00 | ||||||
|  | #define ISP1763_DC_MODE			0x0c | ||||||
|  | #define ISP1763_DC_INTCONF		0x10 | ||||||
|  | #define ISP1763_DC_INTENABLE		0x14 | ||||||
|  | 
 | ||||||
|  | /* Data Flow Registers */ | ||||||
|  | #define ISP1763_DC_EPMAXPKTSZ		0x04 | ||||||
|  | #define ISP1763_DC_EPTYPE		0x08 | ||||||
|  | 
 | ||||||
|  | #define ISP1763_DC_BUFLEN		0x1c | ||||||
|  | #define ISP1763_DC_BUFSTAT		0x1e | ||||||
|  | #define ISP1763_DC_DATAPORT		0x20 | ||||||
|  | 
 | ||||||
|  | #define ISP1763_DC_CTRLFUNC		0x28 | ||||||
|  | #define ISP1763_DC_EPINDEX		0x2c | ||||||
|  | 
 | ||||||
|  | /* DMA Registers */ | ||||||
|  | #define ISP1763_DC_DMACMD		0x30 | ||||||
|  | #define ISP1763_DC_DMATXCOUNT		0x34 | ||||||
|  | #define ISP1763_DC_DMACONF		0x38 | ||||||
|  | #define ISP1763_DC_DMAHW		0x3c | ||||||
|  | #define ISP1763_DC_DMAINTREASON		0x50 | ||||||
|  | #define ISP1763_DC_DMAINTEN		0x54 | ||||||
|  | #define ISP1763_DC_DMAEP		0x58 | ||||||
|  | #define ISP1763_DC_DMABURSTCOUNT	0x64 | ||||||
|  | 
 | ||||||
|  | /* General Registers */ | ||||||
|  | #define ISP1763_DC_INTERRUPT		0x18 | ||||||
|  | #define ISP1763_DC_CHIPID_LOW		0x70 | ||||||
|  | #define ISP1763_DC_CHIPID_HIGH		0x72 | ||||||
|  | #define ISP1763_DC_FRAMENUM		0x74 | ||||||
|  | #define ISP1763_DC_SCRATCH		0x78 | ||||||
|  | #define ISP1763_DC_UNLOCKDEV		0x7c | ||||||
|  | #define ISP1763_DC_INTPULSEWIDTH	0x80 | ||||||
|  | #define ISP1763_DC_TESTMODE		0x84 | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | @ -0,0 +1,75 @@ | ||||||
|  | // SPDX-License-Identifier: GPL-2.0
 | ||||||
|  | /*
 | ||||||
|  |  * Driver for the NXP ISP1760 chip | ||||||
|  |  * | ||||||
|  |  * Copyright 2021 Linaro, Rui Miguel Silva <rui.silva@linaro.org> | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <common.h> | ||||||
|  | #include <dm.h> | ||||||
|  | #include <dm/device-internal.h> | ||||||
|  | #include <dm/device_compat.h> | ||||||
|  | #include <dm/devres.h> | ||||||
|  | #include <dm/lists.h> | ||||||
|  | #include <linux/bug.h> | ||||||
|  | #include <linux/io.h> | ||||||
|  | #include <linux/kernel.h> | ||||||
|  | #include <linux/usb/otg.h> | ||||||
|  | #include <linux/usb/usb_urb_compat.h> | ||||||
|  | #include <log.h> | ||||||
|  | #include <usb.h> | ||||||
|  | 
 | ||||||
|  | #include "isp1760-core.h" | ||||||
|  | #include "isp1760-hcd.h" | ||||||
|  | #include "isp1760-regs.h" | ||||||
|  | #include "isp1760-uboot.h" | ||||||
|  | 
 | ||||||
|  | static int isp1760_msg_submit_control(struct udevice *dev, | ||||||
|  | 				      struct usb_device *udev, | ||||||
|  | 				      unsigned long pipe, void *buffer, | ||||||
|  | 				      int length, struct devrequest *setup) | ||||||
|  | { | ||||||
|  | 	struct isp1760_host_data *host = dev_get_priv(dev); | ||||||
|  | 
 | ||||||
|  | 	return usb_urb_submit_control(&host->hcd, &host->urb, &host->hep, udev, | ||||||
|  | 				      pipe, buffer, length, setup, 0, | ||||||
|  | 				      host->host_speed); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int isp1760_msg_submit_bulk(struct udevice *dev, struct usb_device *udev, | ||||||
|  | 				   unsigned long pipe, void *buffer, int length) | ||||||
|  | { | ||||||
|  | 	struct isp1760_host_data *host = dev_get_priv(dev); | ||||||
|  | 
 | ||||||
|  | 	return usb_urb_submit_bulk(&host->hcd, &host->urb, &host->hep, udev, | ||||||
|  | 				   pipe, buffer, length); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int isp1760_msg_submit_irq(struct udevice *dev, struct usb_device *udev, | ||||||
|  | 				  unsigned long pipe, void *buffer, int length, | ||||||
|  | 				  int interval, bool nonblock) | ||||||
|  | { | ||||||
|  | 	struct isp1760_host_data *host = dev_get_priv(dev); | ||||||
|  | 
 | ||||||
|  | 	return usb_urb_submit_irq(&host->hcd, &host->urb, &host->hep, udev, | ||||||
|  | 				  pipe, buffer, length, interval); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int isp1760_get_max_xfer_size(struct udevice *dev, size_t *size) | ||||||
|  | { | ||||||
|  | 	struct isp1760_host_data *host = dev_get_priv(dev); | ||||||
|  | 	struct isp1760_hcd *priv = host->hcd.hcd_priv; | ||||||
|  | 	const struct isp1760_memory_layout *mem = priv->memory_layout; | ||||||
|  | 
 | ||||||
|  | 	*size = mem->blocks_size[ISP176x_BLOCK_NUM - 1]; | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | struct dm_usb_ops isp1760_usb_ops = { | ||||||
|  | 	.control		= isp1760_msg_submit_control, | ||||||
|  | 	.bulk			= isp1760_msg_submit_bulk, | ||||||
|  | 	.interrupt		= isp1760_msg_submit_irq, | ||||||
|  | 	.get_max_xfer_size	= isp1760_get_max_xfer_size, | ||||||
|  | }; | ||||||
|  | @ -0,0 +1,27 @@ | ||||||
|  | /* SPDX-License-Identifier: GPL-2.0 */ | ||||||
|  | /*
 | ||||||
|  |  * Driver for the NXP ISP1760 chip | ||||||
|  |  * | ||||||
|  |  * Copyright 2021 Linaro, Rui Miguel Silva <rui.silva@linaro.org> | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef __ISP1760_UBOOT_H__ | ||||||
|  | #define __ISP1760_UBOOT_H__ | ||||||
|  | 
 | ||||||
|  | #include <linux/usb/usb_urb_compat.h> | ||||||
|  | #include <usb.h> | ||||||
|  | 
 | ||||||
|  | #include "isp1760-core.h" | ||||||
|  | 
 | ||||||
|  | struct isp1760_host_data { | ||||||
|  | 	struct isp1760_hcd *priv; | ||||||
|  | 	struct usb_hcd hcd; | ||||||
|  | 	enum usb_device_speed host_speed; | ||||||
|  | 	struct usb_host_endpoint hep; | ||||||
|  | 	struct urb urb; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | extern struct dm_usb_ops isp1760_usb_ops; | ||||||
|  | 
 | ||||||
|  | #endif | ||||||
|  | @ -89,9 +89,9 @@ | ||||||
| #include <linux/usb/ch9.h> | #include <linux/usb/ch9.h> | ||||||
| #include <linux/usb/gadget.h> | #include <linux/usb/gadget.h> | ||||||
| #include <linux/usb/musb.h> | #include <linux/usb/musb.h> | ||||||
|  | #include <linux/usb/usb_urb_compat.h> | ||||||
| #include <asm/io.h> | #include <asm/io.h> | ||||||
| #include "linux-compat.h" | #include "linux-compat.h" | ||||||
| #include "usb-compat.h" |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #include "musb_core.h" | #include "musb_core.h" | ||||||
|  |  | ||||||
|  | @ -26,8 +26,8 @@ | ||||||
| #include <dm/device_compat.h> | #include <dm/device_compat.h> | ||||||
| #include <usb.h> | #include <usb.h> | ||||||
| #include <linux/bug.h> | #include <linux/bug.h> | ||||||
|  | #include <linux/usb/usb_urb_compat.h> | ||||||
| #include "linux-compat.h" | #include "linux-compat.h" | ||||||
| #include "usb-compat.h" |  | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #include "musb_core.h" | #include "musb_core.h" | ||||||
|  |  | ||||||
|  | @ -10,7 +10,7 @@ | ||||||
| #ifndef _MUSB_HOST_H | #ifndef _MUSB_HOST_H | ||||||
| #define _MUSB_HOST_H | #define _MUSB_HOST_H | ||||||
| #ifdef __UBOOT__ | #ifdef __UBOOT__ | ||||||
| #include "usb-compat.h" | #include <linux/usb/usb_urb_compat.h> | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| static inline struct usb_hcd *musb_to_hcd(struct musb *musb) | static inline struct usb_hcd *musb_to_hcd(struct musb *musb) | ||||||
|  |  | ||||||
|  | @ -8,10 +8,10 @@ | ||||||
| #include <linux/errno.h> | #include <linux/errno.h> | ||||||
| #include <linux/usb/ch9.h> | #include <linux/usb/ch9.h> | ||||||
| #include <linux/usb/gadget.h> | #include <linux/usb/gadget.h> | ||||||
|  | #include <linux/usb/usb_urb_compat.h> | ||||||
| 
 | 
 | ||||||
| #include <usb.h> | #include <usb.h> | ||||||
| #include "linux-compat.h" | #include "linux-compat.h" | ||||||
| #include "usb-compat.h" |  | ||||||
| #include "musb_core.h" | #include "musb_core.h" | ||||||
| #include "musb_host.h" | #include "musb_host.h" | ||||||
| #include "musb_gadget.h" | #include "musb_gadget.h" | ||||||
|  | @ -453,39 +453,3 @@ struct musb *musb_register(struct musb_hdrc_platform_data *plat, void *bdata, | ||||||
| 
 | 
 | ||||||
| 	return *musbp; | 	return *musbp; | ||||||
| } | } | ||||||
| 
 |  | ||||||
| #if CONFIG_IS_ENABLED(DM_USB) |  | ||||||
| struct usb_device *usb_dev_get_parent(struct usb_device *udev) |  | ||||||
| { |  | ||||||
| 	struct udevice *parent = udev->dev->parent; |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * When called from usb-uclass.c: usb_scan_device() udev->dev points |  | ||||||
| 	 * to the parent udevice, not the actual udevice belonging to the |  | ||||||
| 	 * udev as the device is not instantiated yet. |  | ||||||
| 	 * |  | ||||||
| 	 * If dev is an usb-bus, then we are called from usb_scan_device() for |  | ||||||
| 	 * an usb-device plugged directly into the root port, return NULL. |  | ||||||
| 	 */ |  | ||||||
| 	if (device_get_uclass_id(udev->dev) == UCLASS_USB) |  | ||||||
| 		return NULL; |  | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * If these 2 are not the same we are being called from |  | ||||||
| 	 * usb_scan_device() and udev itself is the parent. |  | ||||||
| 	 */ |  | ||||||
| 	if (dev_get_parent_priv(udev->dev) != udev) |  | ||||||
| 		return udev; |  | ||||||
| 
 |  | ||||||
| 	/* We are being called normally, use the parent pointer */ |  | ||||||
| 	if (device_get_uclass_id(parent) == UCLASS_USB_HUB) |  | ||||||
| 		return dev_get_parent_priv(parent); |  | ||||||
| 
 |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
| #else |  | ||||||
| struct usb_device *usb_dev_get_parent(struct usb_device *udev) |  | ||||||
| { |  | ||||||
| 	return udev->parent; |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
|  | @ -8,8 +8,8 @@ | ||||||
| #define __MUSB_UBOOT_H__ | #define __MUSB_UBOOT_H__ | ||||||
| 
 | 
 | ||||||
| #include <usb.h> | #include <usb.h> | ||||||
|  | #include <linux/usb/usb_urb_compat.h> | ||||||
| #include "linux-compat.h" | #include "linux-compat.h" | ||||||
| #include "usb-compat.h" |  | ||||||
| #include "musb_core.h" | #include "musb_core.h" | ||||||
| 
 | 
 | ||||||
| struct musb_host_data { | struct musb_host_data { | ||||||
|  |  | ||||||
|  | @ -24,4 +24,10 @@ | ||||||
| 
 | 
 | ||||||
| #define CONFIG_SYS_SDRAM_BASE	PHYS_SDRAM_1 | #define CONFIG_SYS_SDRAM_BASE	PHYS_SDRAM_1 | ||||||
| 
 | 
 | ||||||
|  | #define BOOT_TARGET_DEVICES(func) \ | ||||||
|  | 	func(USB, usb, 0) | ||||||
|  | 
 | ||||||
|  | #include <config_distro_bootcmd.h> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -1,12 +1,28 @@ | ||||||
| #ifndef __USB_COMPAT_H__ | /* SPDX-License-Identifier: GPL-2.0+ */ | ||||||
| #define __USB_COMPAT_H__ |  | ||||||
| 
 | 
 | ||||||
| #include "usb.h" | #ifndef __USB_URB_COMPAT_H__ | ||||||
|  | #define __USB_URB_COMPAT_H__ | ||||||
|  | 
 | ||||||
|  | #include <linux/compat.h> | ||||||
|  | #include <usb.h> | ||||||
| 
 | 
 | ||||||
| struct udevice; | struct udevice; | ||||||
|  | struct urb; | ||||||
|  | struct usb_hcd; | ||||||
|  | 
 | ||||||
|  | struct usb_urb_ops { | ||||||
|  | 	int (*urb_enqueue)(struct usb_hcd *hcd, struct urb *urb, | ||||||
|  | 			   gfp_t mem_flags); | ||||||
|  | 	int (*urb_dequeue)(struct usb_hcd *hcd, struct urb *urb, int status); | ||||||
|  | 	int (*hub_control)(struct usb_hcd *hcd, struct usb_device *dev, | ||||||
|  | 			   unsigned long pipe, void *buffer, int len, | ||||||
|  | 			   struct devrequest *setup); | ||||||
|  | 	irqreturn_t (*isr)(int irq, void *priv); | ||||||
|  | }; | ||||||
| 
 | 
 | ||||||
| struct usb_hcd { | struct usb_hcd { | ||||||
| 	void *hcd_priv; | 	void *hcd_priv; | ||||||
|  | 	const struct usb_urb_ops *urb_ops; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| struct usb_host_endpoint { | struct usb_host_endpoint { | ||||||
|  | @ -23,8 +39,6 @@ struct usb_host_endpoint { | ||||||
| #define URB_SHORT_NOT_OK	0x0001	/* report short reads as errors */ | #define URB_SHORT_NOT_OK	0x0001	/* report short reads as errors */ | ||||||
| #define URB_ZERO_PACKET		0x0040	/* Finish bulk OUT with short packet */ | #define URB_ZERO_PACKET		0x0040	/* Finish bulk OUT with short packet */ | ||||||
| 
 | 
 | ||||||
| struct urb; |  | ||||||
| 
 |  | ||||||
| typedef void (*usb_complete_t)(struct urb *); | typedef void (*usb_complete_t)(struct urb *); | ||||||
| 
 | 
 | ||||||
| struct urb { | struct urb { | ||||||
|  | @ -76,4 +90,25 @@ static inline int usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, | ||||||
|  */ |  */ | ||||||
| struct usb_device *usb_dev_get_parent(struct usb_device *udev); | struct usb_device *usb_dev_get_parent(struct usb_device *udev); | ||||||
| 
 | 
 | ||||||
|  | int usb_urb_submit_control(struct usb_hcd *hcd, struct urb *urb, | ||||||
|  | 			   struct usb_host_endpoint *hep, | ||||||
|  | 			   struct usb_device *dev, unsigned long pipe, | ||||||
|  | 			   void *buffer, int len, struct devrequest *setup, | ||||||
|  | 			   int interval, enum usb_device_speed speed); | ||||||
|  | 
 | ||||||
|  | int usb_urb_submit_bulk(struct usb_hcd *hcd, struct urb *urb, | ||||||
|  | 			struct usb_host_endpoint *hep, struct usb_device *dev, | ||||||
|  | 			unsigned long pipe, void *buffer, int len); | ||||||
|  | 
 | ||||||
|  | int usb_urb_submit_irq(struct usb_hcd *hcd, struct urb *urb, | ||||||
|  | 		       struct usb_host_endpoint *hep, struct usb_device *dev, | ||||||
|  | 		       unsigned long pipe, void *buffer, int len, int interval); | ||||||
|  | 
 | ||||||
|  | void usb_urb_fill(struct urb *urb, struct usb_host_endpoint *hep, | ||||||
|  | 		  struct usb_device *dev, int endpoint_type, | ||||||
|  | 		  unsigned long pipe, void *buffer, int len, | ||||||
|  | 		  struct devrequest *setup, int interval); | ||||||
|  | 
 | ||||||
|  | int usb_urb_submit(struct usb_hcd *hcd, struct urb *urb); | ||||||
|  | 
 | ||||||
| #endif /* __USB_COMPAT_H__ */ | #endif /* __USB_COMPAT_H__ */ | ||||||
|  | @ -81,6 +81,32 @@ | ||||||
| #define EndpointOutRequest \ | #define EndpointOutRequest \ | ||||||
| 	((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8) | 	((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8) | ||||||
| 
 | 
 | ||||||
|  | /* class requests from the USB 2.0 hub spec, table 11-15 */ | ||||||
|  | #define HUB_CLASS_REQ(dir, type, request) ((((dir) | (type)) << 8) | (request)) | ||||||
|  | /* GetBusState and SetHubDescriptor are optional, omitted */ | ||||||
|  | #define ClearHubFeature		HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_HUB, \ | ||||||
|  | 					      USB_REQ_CLEAR_FEATURE) | ||||||
|  | #define ClearPortFeature	HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, \ | ||||||
|  | 					      USB_REQ_CLEAR_FEATURE) | ||||||
|  | #define GetHubDescriptor	HUB_CLASS_REQ(USB_DIR_IN, USB_RT_HUB, \ | ||||||
|  | 					      USB_REQ_GET_DESCRIPTOR) | ||||||
|  | #define GetHubStatus		HUB_CLASS_REQ(USB_DIR_IN, USB_RT_HUB, \ | ||||||
|  | 					      USB_REQ_GET_STATUS) | ||||||
|  | #define GetPortStatus		HUB_CLASS_REQ(USB_DIR_IN, USB_RT_PORT, \ | ||||||
|  | 					      USB_REQ_GET_STATUS) | ||||||
|  | #define SetHubFeature		HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_HUB, \ | ||||||
|  | 					      USB_REQ_SET_FEATURE) | ||||||
|  | #define SetPortFeature		HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, \ | ||||||
|  | 					      USB_REQ_SET_FEATURE) | ||||||
|  | #define ClearTTBuffer		HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, \ | ||||||
|  | 					      HUB_CLEAR_TT_BUFFER) | ||||||
|  | #define ResetTT			HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, \ | ||||||
|  | 					      HUB_RESET_TT) | ||||||
|  | #define GetTTState		HUB_CLASS_REQ(USB_DIR_IN, USB_RT_PORT, \ | ||||||
|  | 					      HUB_GET_TT_STATE) | ||||||
|  | #define StopTT			HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, \ | ||||||
|  | 					      HUB_STOP_TT) | ||||||
|  | 
 | ||||||
| /* Descriptor types */ | /* Descriptor types */ | ||||||
| #define USB_DT_DEVICE        0x01 | #define USB_DT_DEVICE        0x01 | ||||||
| #define USB_DT_CONFIG        0x02 | #define USB_DT_CONFIG        0x02 | ||||||
|  | @ -289,10 +315,16 @@ | ||||||
| #define USB_SS_PORT_STAT_C_CONFIG_ERROR	0x0080 | #define USB_SS_PORT_STAT_C_CONFIG_ERROR	0x0080 | ||||||
| 
 | 
 | ||||||
| /* wHubCharacteristics (masks) */ | /* wHubCharacteristics (masks) */ | ||||||
|  | #define HUB_CHAR_COMMON_OCPM        0x0000 /* All ports Over-Current reporting */ | ||||||
|  | #define HUB_CHAR_INDV_PORT_LPSM     0x0001 /* per-port power control */ | ||||||
|  | #define HUB_CHAR_NO_LPSM            0x0002 /* no power switching */ | ||||||
| #define HUB_CHAR_LPSM               0x0003 | #define HUB_CHAR_LPSM               0x0003 | ||||||
| #define HUB_CHAR_COMPOUND           0x0004 | #define HUB_CHAR_COMPOUND           0x0004 | ||||||
|  | #define HUB_CHAR_INDV_PORT_OCPM     0x0008 /* per-port Over-current reporting */ | ||||||
|  | #define HUB_CHAR_NO_OCPM            0x0010 /* No Over-current Protection support */ | ||||||
| #define HUB_CHAR_OCPM               0x0018 | #define HUB_CHAR_OCPM               0x0018 | ||||||
| #define HUB_CHAR_TTTT               0x0060 /* TT Think Time mask */ | #define HUB_CHAR_TTTT               0x0060 /* TT Think Time mask */ | ||||||
|  | #define HUB_CHAR_PORTIND            0x0080 /* per-port indicators (LEDs) */ | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Hub Status & Hub Change bit masks |  * Hub Status & Hub Change bit masks | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue