From 1742d601891b28f6460dbfda7c29c1275f1b8453 Mon Sep 17 00:00:00 2001 From: blogic Date: Sat, 15 Dec 2012 01:59:53 +0000 Subject: [PATCH] [lantiq] add ltq-hcd git-svn-id: svn://svn.openwrt.org/openwrt/trunk@34688 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- package/platform/lantiq/ltq-hcd/Makefile | 51 + package/platform/lantiq/ltq-hcd/src/Kconfig | 104 + package/platform/lantiq/ltq-hcd/src/Makefile | 74 + package/platform/lantiq/ltq-hcd/src/ifxhcd.c | 2141 +++++++++ package/platform/lantiq/ltq-hcd/src/ifxhcd.h | 758 +++ package/platform/lantiq/ltq-hcd/src/ifxhcd_es.c | 599 +++ package/platform/lantiq/ltq-hcd/src/ifxhcd_intr.c | 4844 ++++++++++++++++++++ package/platform/lantiq/ltq-hcd/src/ifxhcd_queue.c | 485 ++ package/platform/lantiq/ltq-hcd/src/ifxusb_cif.c | 1686 +++++++ package/platform/lantiq/ltq-hcd/src/ifxusb_cif.h | 767 ++++ package/platform/lantiq/ltq-hcd/src/ifxusb_cif_d.c | 535 +++ package/platform/lantiq/ltq-hcd/src/ifxusb_cif_h.c | 1599 +++++++ package/platform/lantiq/ltq-hcd/src/ifxusb_ctl.c | 3825 ++++++++++++++++ .../platform/lantiq/ltq-hcd/src/ifxusb_driver.c | 1279 ++++++ package/platform/lantiq/ltq-hcd/src/ifxusb_host.ko | Bin 0 -> 181257 bytes package/platform/lantiq/ltq-hcd/src/ifxusb_plat.h | 1184 +++++ package/platform/lantiq/ltq-hcd/src/ifxusb_regs.h | 1471 ++++++ .../platform/lantiq/ltq-hcd/src/ifxusb_version.h | 5 + 18 files changed, 21407 insertions(+) create mode 100644 package/platform/lantiq/ltq-hcd/Makefile create mode 100644 package/platform/lantiq/ltq-hcd/src/Kconfig create mode 100644 package/platform/lantiq/ltq-hcd/src/Makefile create mode 100644 package/platform/lantiq/ltq-hcd/src/ifxhcd.c create mode 100644 package/platform/lantiq/ltq-hcd/src/ifxhcd.h create mode 100644 package/platform/lantiq/ltq-hcd/src/ifxhcd_es.c create mode 100644 package/platform/lantiq/ltq-hcd/src/ifxhcd_intr.c create mode 100644 package/platform/lantiq/ltq-hcd/src/ifxhcd_queue.c create mode 100644 package/platform/lantiq/ltq-hcd/src/ifxusb_cif.c create mode 100644 package/platform/lantiq/ltq-hcd/src/ifxusb_cif.h create mode 100644 package/platform/lantiq/ltq-hcd/src/ifxusb_cif_d.c create mode 100644 package/platform/lantiq/ltq-hcd/src/ifxusb_cif_h.c create mode 100644 package/platform/lantiq/ltq-hcd/src/ifxusb_ctl.c create mode 100644 package/platform/lantiq/ltq-hcd/src/ifxusb_driver.c create mode 100644 package/platform/lantiq/ltq-hcd/src/ifxusb_host.ko create mode 100644 package/platform/lantiq/ltq-hcd/src/ifxusb_plat.h create mode 100644 package/platform/lantiq/ltq-hcd/src/ifxusb_regs.h create mode 100644 package/platform/lantiq/ltq-hcd/src/ifxusb_version.h diff --git a/package/platform/lantiq/ltq-hcd/Makefile b/package/platform/lantiq/ltq-hcd/Makefile new file mode 100644 index 0000000000..6f654b4aa4 --- /dev/null +++ b/package/platform/lantiq/ltq-hcd/Makefile @@ -0,0 +1,51 @@ +# Copyright (C) 2012 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. + +include $(TOPDIR)/rules.mk +include $(INCLUDE_DIR)/kernel.mk + +PKG_NAME:=ltq-hcd +PKG_RELEASE:=1 +PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/ltq-hcd-$(BUILD_VARIANT) + +PKG_MAINTAINER:=John Crispin + +include $(INCLUDE_DIR)/package.mk + +define KernelPackage/ltq-hcd-template + SECTION:=sys + CATEGORY:=Kernel modules + SUBMENU:=USB Support + TITLE:=USB driver for $(1) + URL:=http://www.lantiq.com/ + VARIANT:=$(1) + DEPENDS:=@TARGET_lantiq_$(2) +kmod-usb-core + FILES:=$(PKG_BUILD_DIR)/ltq_hcd_$(1).ko + AUTOLOAD:=$(call AutoLoad,50,ltq_hcd_$(1)) +endef + +KernelPackage/ltq-hcd-ase=$(call KernelPackage/ltq-hcd-template,ase,ase) +KernelPackage/ltq-hcd-danube=$(call KernelPackage/ltq-hcd-template,danube,xway) +KernelPackage/ltq-hcd-ar9=$(call KernelPackage/ltq-hcd-template,ar9,xway) +KernelPackage/ltq-hcd-vr9=$(call KernelPackage/ltq-hcd-template,vr9,xway) + +define Build/Prepare + $(INSTALL_DIR) $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile + cd $(LINUX_DIR); \ + ARCH=mips CROSS_COMPILE="$(KERNEL_CROSS)" \ + $(MAKE) BUILD_VARIANT=$(BUILD_VARIANT) M=$(PKG_BUILD_DIR) V=1 modules +endef + +$(eval $(call KernelPackage,ltq-hcd-ase)) +$(eval $(call KernelPackage,ltq-hcd-danube)) +$(eval $(call KernelPackage,ltq-hcd-ar9)) +$(eval $(call KernelPackage,ltq-hcd-vr9)) diff --git a/package/platform/lantiq/ltq-hcd/src/Kconfig b/package/platform/lantiq/ltq-hcd/src/Kconfig new file mode 100644 index 0000000000..2a3a38d3f8 --- /dev/null +++ b/package/platform/lantiq/ltq-hcd/src/Kconfig @@ -0,0 +1,104 @@ + +config USB_HOST_IFX + tristate "Infineon USB Host Controller Driver" + depends on USB + default n + help + Infineon USB Host Controller + +choice + prompt "Infineon USB Host Controller Driver Operation mode" + depends on USB_HOST_IFX && ( AMAZON_S || AR9 || VR9 || AR10 || MIPS_AMAZON_S || MIPS_AR9 || MIPS_VR9 || MIPS_AR10 ) + help + The IFX USB core can be configured as dual-host and single host. + The unused core can be set as Device-mode. + +config USB_HOST_IFX_B + boolean "USB host mode on core 1 and 2" + help + Both cores run as host + +config USB_HOST_IFX_1 + boolean "USB host mode on core 1 only" + help + Core #1 runs as host + +config USB_HOST_IFX_2 + boolean "USB host mode on core 2 only" + help + Core #2 runs as host + +endchoice + +config USB_HOST_IFX_FORCE_USB11 + boolean "Forced USB1.1" + depends on USB_HOST_IFX + default n + help + force to be USB 1.1 + +config USB_HOST_IFX_WITH_HS_ELECT_TST + boolean "With HS_Electrical Test" + depends on USB_HOST_IFX + default n + help + With USBIF HSET routines + +config USB_HOST_IFX_WITH_ISO + boolean "With ISO transfer" + depends on USB_HOST_IFX + default n + help + With USBIF ISO transfer + +config USB_HOST_IFX_COC + boolean "CoC in USB Host" + depends on USB_HOST_IFX + default n + help + With CoC on Host + +choice + prompt "IFX unaligned buffer policy" + depends on USB_HOST_IFX + help + IFX unaligned buffer policy + +config USB_HOST_IFX_UNALIGNED_ADJ + boolean "Adjust" + help + USB_HOST_IFX_UNALIGNED_ADJ + +config USB_HOST_IFX_UNALIGNED_CHK + boolean "Check-only" + help + USB_HOST_IFX_UNALIGNED_CHK + +config USB_HOST_IFX_UNALIGNED_NONE + boolean "No process" + help + USB_HOST_IFX_UNALIGNED_NONE + +endchoice + + +config USB_HOST_IFX_XHCI + tristate "xHCI HCD (USB 3.0) support (EXPERIMENTAL)" + depends on USB && PCI && ( VR9 || MIPS_VR9 || AR10 || MIPS_AR10 ) + ---help--- + The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0 + "SuperSpeed" host controller hardware. + + To compile this driver as a module, choose M here: the + module will be called xhci-hcd. + +config USB_HOST_IFX_XHCI_DEBUGGING + bool "Debugging for the xHCI host controller" + depends on USB_HOST_IFX_XHCI + ---help--- + Say 'Y' to turn on debugging for the xHCI host controller driver. + This will spew debugging output, even in interrupt context. + This should only be used for debugging xHCI driver bugs. + + If unsure, say N. + diff --git a/package/platform/lantiq/ltq-hcd/src/Makefile b/package/platform/lantiq/ltq-hcd/src/Makefile new file mode 100644 index 0000000000..153fd42dc4 --- /dev/null +++ b/package/platform/lantiq/ltq-hcd/src/Makefile @@ -0,0 +1,74 @@ +ltq_hcd_$(BUILD_VARIANT)-objs := ifxusb_driver.o ifxusb_ctl.o ifxusb_cif.o \ + ifxusb_cif_h.o ifxhcd.o ifxhcd_es.o \ + ifxhcd_intr.o ifxhcd_queue.o +obj-m = ltq_hcd_$(BUILD_VARIANT).o + +ifeq ($(BUILD_VARIANT),danube) + EXTRA_CFLAGS += -D__IS_DANUBE__ +endif + +ifeq ($(BUILD_VARIANT),ase) + EXTRA_CFLAGS += -D__IS_AMAZON_SE__ +endif + +ifeq ($(BUILD_VARIANT),ar9) + EXTRA_CFLAGS += -D__IS_AR9__ + EXTRA_CFLAGS += -D__IS_DUAL__ +endif + +ifeq ($(BUILD_VARIANT),vr9) + EXTRA_CFLAGS += -D__IS_VR9__ + EXTRA_CFLAGS += -D__PHY_LONG_PREEMP__ + EXTRA_CFLAGS += -D__PINGSTOP_CTRL__ + EXTRA_CFLAGS += -D__PINGSTOP_BULK__ + EXTRA_CFLAGS += -D__IS_DUAL__ +endif + +ifeq ($(BUILD_VARIANT),ar10) + EXTRA_CFLAGS += -D__IS_AR10__ + EXTRA_CFLAGS += -D__PHY_LONG_PREEMP__ + EXTRA_CFLAGS += -D__PINGSTOP_CTRL__ + EXTRA_CFLAGS += -D__PINGSTOP_BULK__ +endif + +ifeq ($(CONFIG_USB_HOST_IFX_FORCE_USB11),y) + EXTRA_CFLAGS += -D__FORCE_USB11__ +endif +ifeq ($(CONFIG_USB_HOST_IFX_WITH_HS_ELECT_TST),y) + EXTRA_CFLAGS += -D__WITH_HS_ELECT_TST__ +endif +ifeq ($(CONFIG_USB_HOST_IFX_WITH_ISO),y) + EXTRA_CFLAGS += -D__EN_ISOC__ +endif +#ifeq ($(CONFIG_USB_HOST_IFX_UNALIGNED_ADJ),y) + EXTRA_CFLAGS += -D__UNALIGNED_BUF_ADJ__ +#endif +ifeq ($(CONFIG_USB_HOST_IFX_UNALIGNED_CHK),y) + EXTRA_CFLAGS += -D__UNALIGNED_BUF_CHK__ +endif +ifeq ($(CONFIG_USB_HOST_IFX_COC),y) + EXTRA_CFLAGS += -D__HOST_COC__ +endif + +# EXTRA_CFLAGS += -D__IS_FIRST__ +# EXTRA_CFLAGS += -D__IS_SECOND__ + +# EXTRA_CFLAGS += -D__EN_ISOC__ +# EXTRA_CFLAGS += -D__EN_ISOC_SPLIT__ +# EXTRA_CFLAGS += -D__EPQD_DESTROY_TIMEOUT__ +# EXTRA_CFLAGS += -D__INNAKSTOP_CTRL__ + +EXTRA_CFLAGS += -Dlinux -D__LINUX__ +EXTRA_CFLAGS += -D__IS_HOST__ +EXTRA_CFLAGS += -D__KERNEL__ +#EXTRA_CFLAGS += -D__DEBUG__ +#EXTRA_CFLAGS += -D__ENABLE_DUMP__ + +EXTRA_CFLAGS += -D__DYN_SOF_INTR__ +EXTRA_CFLAGS += -D__UEIP__ +EXTRA_CFLAGS += -D__DO_OC_INT__ +EXTRA_CFLAGS += -D__INNAKSTOP_BULK__ + +EXTRA_CFLAGS += -D__INTRNAKRETRY__ +EXTRA_CFLAGS += -D__INTRINCRETRY__ + diff --git a/package/platform/lantiq/ltq-hcd/src/ifxhcd.c b/package/platform/lantiq/ltq-hcd/src/ifxhcd.c new file mode 100644 index 0000000000..6d1551f363 --- /dev/null +++ b/package/platform/lantiq/ltq-hcd/src/ifxhcd.c @@ -0,0 +1,2141 @@ +/***************************************************************************** + ** FILE NAME : ifxhcd.c + ** PROJECT : IFX USB sub-system V3 + ** MODULES : IFX USB sub-system Host and Device driver + ** SRC VERSION : 3.2 + ** DATE : 1/Jan/2011 + ** AUTHOR : Chen, Howard + ** DESCRIPTION : This file contains the structures, constants, and + ** interfaces for the Host Contoller Driver (HCD). + ** + ** The Host Controller Driver (HCD) is responsible for + ** translating requests from the USB Driver into the + ** appropriate actions on the IFXUSB controller. + ** It isolates the USBD from the specifics of the + ** controller by providing an API to the USBD. + ** FUNCTIONS : + ** COMPILER : gcc + ** REFERENCE : Synopsys DWC-OTG Driver 2.7 + ** COPYRIGHT : Copyright (c) 2010 + ** LANTIQ DEUTSCHLAND GMBH, + ** Am Campeon 3, 85579 Neubiberg, Germany + ** + ** This program is free software; you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation; either version 2 of the License, or + ** (at your option) any later version. + ** + ** Version Control Section ** + ** $Author$ + ** $Date$ + ** $Revisions$ + ** $Log$ Revision history + *****************************************************************************/ + +/* + * This file contains code fragments from Synopsys HS OTG Linux Software Driver. + * For this code the following notice is applicable: + * + * ========================================================================== + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +/*! + \file ifxhcd.c + \ingroup IFXUSB_DRIVER_V3 + \brief This file contains the implementation of the HCD. In Linux, + the HCD implements the hc_driver API. +*/ + +#include +#include "ifxusb_version.h" + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + + +#include "ifxusb_plat.h" +#include "ifxusb_regs.h" +#include "ifxusb_cif.h" +#include "ifxhcd.h" + +#include + +#ifdef __DEBUG__ + static void dump_urb_info(struct urb *_urb, char* _fn_name); +#if 0 + static void dump_channel_info(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_epqh_t *_epqh); +#endif +#endif + +static void ifxhcd_complete_urb_sub(ifxhcd_urbd_t *_urbd) +{ + ifxhcd_hcd_t *ifxhcd; + struct urb *urb=NULL; + + if (!list_empty(&_urbd->ql)) + { + list_del_init(&_urbd->ql); + _urbd->epqh->urbd_count--; + } + else + IFX_ERROR("%s: urb(%p) not connect to any epqh\n", + __func__,_urbd); + + ifxhcd=_urbd->epqh->ifxhcd; + urb =_urbd->urb; + if(!urb) + IFX_ERROR("%s: invalid urb\n",__func__); + else if(urb->hcpriv) + { + if(urb->hcpriv != _urbd) + IFX_ERROR("%s: invalid" + " urb(%p)->hcpriv(%p) != _urbd(%p)\n", + __func__, + urb, + urb->hcpriv, + _urbd); + #if defined(__UNALIGNED_BUF_ADJ__) + if(_urbd->is_in && +// _urbd->using_aligned_buf && + _urbd->aligned_buf) + memcpy(_urbd->xfer_buff, + _urbd->aligned_buf, + _urbd->xfer_len); + if(_urbd->aligned_buf) + ifxusb_free_buf_h(_urbd->aligned_buf); + #endif + urb->hcpriv = NULL; + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + urb->status=_urbd->status; + usb_hcd_giveback_urb(ifxhcd_to_syshcd(ifxhcd), urb); + #else + usb_hcd_giveback_urb(ifxhcd_to_syshcd(ifxhcd), urb, + _urbd->status); + #endif + } + kfree(_urbd); +} + +#ifdef __STRICT_ORDER__ + static void ifxhcd_complete_urb_func(unsigned long data) + { + unsigned long flags; + ifxhcd_urbd_t *urbd; + ifxhcd_epqh_t *epqh; + struct list_head *item; + + int count=10; + + epqh=((ifxhcd_epqh_t *)data); + + while (!list_empty(&epqh->release_list) && count) + { + item = epqh->release_list.next; + urbd = list_entry(item, ifxhcd_urbd_t, ql); + if (!urbd) + IFX_ERROR("%s: invalid urbd\n",__func__); + else if (!urbd->epqh) + IFX_ERROR("%s: invalid epqd\n",__func__); + else + { + ifxhcd_epqh_t *epqh2; + epqh2=urbd->epqh; + local_irq_save(flags); + LOCK_URBD_LIST(epqh2); + ifxhcd_complete_urb_sub(urbd); + UNLOCK_URBD_LIST(epqh2); + local_irq_restore (flags); + } + count--; + } + if(!list_empty(&epqh->release_list)) + tasklet_schedule(&epqh->complete_urb_sub); + } + + /*! + \brief Sets the final status of an URB and returns it to the device + driver. Any required cleanup of the URB is performed. + */ + void ifxhcd_complete_urb(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_urbd_t *_urbd, + int _status) + { + unsigned long flags; + + if(!_urbd) + { + IFX_ERROR("%s: invalid urbd\n",__func__); + return; + } + if (!_urbd->epqh) + { + IFX_ERROR("%s: invalid epqh\n",__func__); + return; + } + + local_irq_save(flags); + LOCK_URBD_LIST(_urbd->epqh); + #ifdef __DEBUG__ + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) + { + IFX_PRINT("%s: ehqh %p _urbd %p, urb %p," + " device %d, ep %d %s/%s, status=%d\n", + __func__,_urbd->epqh, + _urbd,_urbd->urb, + (_urbd->urb)?usb_pipedevice(_urbd->urb->pipe):-1, + (_urbd->urb)?usb_pipeendpoint(_urbd->urb->pipe):-1, + (_urbd->urb)?(usb_pipein(_urbd->urb->pipe) ? "IN" : "OUT"):"--", + (_urbd->is_in) ? "IN" : "OUT", + _status); + if ((_urbd->urb)&& _urbd->epqh->ep_type == IFXUSB_EP_TYPE_ISOC) + { + int i; + for (i = 0; i < _urbd->urb->number_of_packets; i++) + IFX_PRINT(" ISO Desc %d status: %d\n", i, _urbd->urb->iso_frame_desc[i].status); + } + } + #endif + _urbd->status = _status; + + if(_urbd->phase!=URBD_FINISHING) + { + if(_urbd->phase!=URBD_DEQUEUEING && _urbd->phase!=URBD_COMPLETING) + printk(KERN_INFO "Warning: %s() Strange URBD PHASE %d\n",__func__,_urbd->phase); + if(_urbd->urb) + { + if( _urbd->status == 0 + && _urbd->phase==URBD_COMPLETING + && in_irq()) + { + list_move_tail(&_urbd->ql,&_urbd->epqh->release_list); + if(!_urbd->epqh->complete_urb_sub.func) + { + _urbd->epqh->complete_urb_sub.next = NULL; + _urbd->epqh->complete_urb_sub.state = 0; + atomic_set( &_urbd->epqh->complete_urb_sub.count, 0); + _urbd->epqh->complete_urb_sub.func = ifxhcd_complete_urb_func; + _urbd->epqh->complete_urb_sub.data = (unsigned long)_urbd->epqh; + } + tasklet_schedule(&_urbd->epqh->complete_urb_sub); + } + else + { + _urbd->phase=URBD_FINISHING; + ifxhcd_complete_urb_sub(_urbd); + } + UNLOCK_URBD_LIST(_urbd->epqh); + } + else + { + UNLOCK_URBD_LIST(_urbd->epqh); + kfree(_urbd); + } + } + else + { + printk(KERN_INFO "Warning: %s() Double Completing \n",__func__); + UNLOCK_URBD_LIST(_urbd->epqh); + } + + local_irq_restore (flags); + } +#else + static void ifxhcd_complete_urb_func(unsigned long data) + { + unsigned long flags; + ifxhcd_urbd_t *urbd; + + urbd=((ifxhcd_urbd_t *)data); + + // local_irq_save(flags); + if (!urbd) + IFX_ERROR("%s: invalid urbd\n",__func__); + else if (!urbd->epqh) + IFX_ERROR("%s: invalid epqd\n",__func__); + else + { + local_irq_save(flags); + LOCK_URBD_LIST(urbd->epqh); + ifxhcd_complete_urb_sub(urbd); + UNLOCK_URBD_LIST(urbd->epqh); + local_irq_restore (flags); + } + // local_irq_restore (flags); + } + + + /*! + \brief Sets the final status of an URB and returns it to the device driver. Any + required cleanup of the URB is performed. + */ + void ifxhcd_complete_urb(ifxhcd_hcd_t *_ifxhcd, ifxhcd_urbd_t *_urbd, int _status) + { + unsigned long flags; + + if(!_urbd) + { + IFX_ERROR("%s: invalid urbd\n",__func__); + return; + } + if (!_urbd->epqh) + { + IFX_ERROR("%s: invalid epqh\n",__func__); + return; + } + + local_irq_save(flags); + LOCK_URBD_LIST(_urbd->epqh); + #ifdef __DEBUG__ + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) + { + IFX_PRINT("%s: ehqh %p _urbd %p, urb %p, device %d, ep %d %s/%s, status=%d\n", + __func__,_urbd->epqh, _urbd,_urbd->urb, + (_urbd->urb)?usb_pipedevice(_urbd->urb->pipe):-1, + (_urbd->urb)?usb_pipeendpoint(_urbd->urb->pipe):-1, + (_urbd->urb)?(usb_pipein(_urbd->urb->pipe) ? "IN" : "OUT"):"--", + (_urbd->is_in) ? "IN" : "OUT", + _status); + if ((_urbd->urb)&& _urbd->epqh->ep_type == IFXUSB_EP_TYPE_ISOC) + { + int i; + for (i = 0; i < _urbd->urb->number_of_packets; i++) + IFX_PRINT(" ISO Desc %d status: %d\n", i, _urbd->urb->iso_frame_desc[i].status); + } + } + #endif + _urbd->status = _status; + + if(_urbd->phase!=URBD_FINISHING) + { + if(_urbd->phase!=URBD_DEQUEUEING && _urbd->phase!=URBD_COMPLETING) + printk(KERN_INFO "Warning: %s() Strange URBD PHASE %d\n",__func__,_urbd->phase); + if(_urbd->urb) + { + if( _urbd->status == 0 + && _urbd->phase==URBD_COMPLETING + && in_irq()) + { + if(_urbd->complete_urb_sub.func) + printk(KERN_INFO "Warning: %s() URBD Tasklet is on already\n",__func__); + _urbd->phase=URBD_FINISHING; + _urbd->complete_urb_sub.next = NULL; + _urbd->complete_urb_sub.state = 0; + atomic_set( &_urbd->complete_urb_sub.count, 0); + _urbd->complete_urb_sub.func = ifxhcd_complete_urb_func; + _urbd->complete_urb_sub.data = (unsigned long)_urbd; + tasklet_schedule(&_urbd->complete_urb_sub); + } + else + { + _urbd->phase=URBD_FINISHING; + ifxhcd_complete_urb_sub(_urbd); + } + } + else + kfree(_urbd); + } + else + printk(KERN_INFO "Warning: %s() Double Completing \n",__func__); + UNLOCK_URBD_LIST(_urbd->epqh); + local_irq_restore (flags); + } +#endif + +/*! + \brief Processes all the URBs in a single EPQHs. Completes them with + status and frees the URBD. + */ +static +void kill_all_urbs_in_epqh(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh, int _status) +{ + struct list_head *item; + struct list_head *next; + ifxhcd_urbd_t *urbd; + + if(!_epqh) + return; + + IFX_DEBUGPL(DBG_HCDV, "%s %p\n",__func__,_epqh); + LOCK_URBD_LIST(_epqh); + list_for_each(item, &_epqh->urbd_list) + { + urbd = list_entry(item, ifxhcd_urbd_t, ql); + if( urbd->phase==URBD_IDLE + || urbd->phase==URBD_ACTIVE +// || urbd->phase==URBD_STARTING + ) + urbd->phase=URBD_DEQUEUEING; + } + list_for_each_safe(item, next, &_epqh->urbd_list) + { + urbd = list_entry(item, ifxhcd_urbd_t, ql); + if(urbd->phase==URBD_DEQUEUEING) + { + urbd->urb->status = _status; + urbd->phase = URBD_FINISHING; + ifxhcd_complete_urb_sub(urbd); + } + else if( urbd->phase==URBD_STARTED + || urbd->phase==URBD_STARTING +// || urbd->phase==URBD_ACTIVE + ) + { + if(ifxhcd_hc_halt(&_ifxhcd->core_if, _epqh->hc, HC_XFER_URB_DEQUEUE)) + { + urbd->urb->status = _status; + urbd->phase=URBD_FINISHING; + ifxhcd_complete_urb_sub(urbd); + } + } + else + IFX_ERROR("%s: invalid urb phase:%d \n",__func__,urbd->phase); + } + UNLOCK_URBD_LIST(_epqh); + IFX_DEBUGPL(DBG_HCDV, "%s %p finish\n",__func__,_epqh); +} + + +/*! + \brief Free all EPS in one Processes all the URBs in a single list of EPQHs. Completes them with + -ETIMEDOUT and frees the URBD. + */ +static +void epqh_list_free_1(ifxhcd_hcd_t *_ifxhcd, struct list_head *_epqh_list) +{ + ifxhcd_epqh_t *epqh; + struct list_head *item; + if (!_ifxhcd) + return; + if (!_epqh_list) + return; + + IFX_DEBUGPL(DBG_HCDV, "%s %p\n",__func__,_epqh_list); + + item = _epqh_list->next; + while(item != _epqh_list && item != item->next) + { + epqh = list_entry(item, ifxhcd_epqh_t, ql); + epqh->phase=EPQH_DISABLING; + item = item->next; + kill_all_urbs_in_epqh(_ifxhcd, epqh, -ETIMEDOUT); + #ifdef __STRICT_ORDER__ + if(list_empty(&epqh->urbd_list) && list_empty(&epqh->release_list)) + #else + if(list_empty(&epqh->urbd_list)) + #endif + ifxhcd_epqh_free(epqh); + } + IFX_DEBUGPL(DBG_HCDV, "%s %p finish\n",__func__,_epqh_list); + /* Ensure there are no URBDs or URBs left. */ +} + +static +void epqh_list_free_2(ifxhcd_hcd_t *_ifxhcd, struct list_head *_epqh_list) +{ + ifxhcd_epqh_t *epqh; + struct list_head *item; + struct list_head *next; + if (!_ifxhcd) + return; + if (!_epqh_list) + return; + + IFX_DEBUGPL(DBG_HCDV, "%s %p\n",__func__,_epqh_list); + list_for_each_safe(item, next, _epqh_list) + { + epqh = list_entry(item, ifxhcd_epqh_t, ql); + if(item == item->next) + { + ifxhcd_epqh_free(epqh); + } + else + { + uint32_t count=0x80000; + #ifdef __STRICT_ORDER__ + for(;(!list_empty(&epqh->urbd_list) || !list_empty(&epqh->release_list))&& count> 0; count--) udelay(1); + #else + for(;!list_empty(&epqh->urbd_list) && count> 0; count--) udelay(1); + #endif + if(!count) + IFX_ERROR("%s: unable to clear urbd in epqh \n",__func__); + ifxhcd_epqh_free(epqh); + } + } + IFX_DEBUGPL(DBG_HCDV, "%s %p finish\n",__func__,_epqh_list); + /* Ensure there are no URBDs or URBs left. */ +} + +static +void epqh_list_free_all_sub(unsigned long data) +{ + ifxhcd_hcd_t *ifxhcd; + + ifxhcd=(ifxhcd_hcd_t *)data; + epqh_list_free_1(ifxhcd, &ifxhcd->epqh_list_np ); + epqh_list_free_1(ifxhcd, &ifxhcd->epqh_list_intr); + #ifdef __EN_ISOC__ + epqh_list_free_1(ifxhcd, &ifxhcd->epqh_list_isoc); + #endif + + epqh_list_free_2(ifxhcd, &ifxhcd->epqh_list_np ); + epqh_list_free_2(ifxhcd, &ifxhcd->epqh_list_intr); + #ifdef __EN_ISOC__ + epqh_list_free_2(ifxhcd, &ifxhcd->epqh_list_isoc); + #endif +} + +static +void epqh_list_free_all(ifxhcd_hcd_t *_ifxhcd) +{ + _ifxhcd->tasklet_free_epqh_list.next = NULL; + _ifxhcd->tasklet_free_epqh_list.state = 0; + atomic_set( &_ifxhcd->tasklet_free_epqh_list.count, 0); + _ifxhcd->tasklet_free_epqh_list.func=epqh_list_free_all_sub; + _ifxhcd->tasklet_free_epqh_list.data = (unsigned long)_ifxhcd; + tasklet_schedule(&_ifxhcd->tasklet_free_epqh_list); +} + + +/*! + \brief This function is called to handle the disconnection of host port. + */ +int32_t ifxhcd_disconnect(ifxhcd_hcd_t *_ifxhcd) +{ + IFX_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _ifxhcd); + + _ifxhcd->disconnecting=1; + /* Set status flags for the hub driver. */ + _ifxhcd->flags.b.port_connect_status_change = 1; + _ifxhcd->flags.b.port_connect_status = 0; + + /* + * Shutdown any transfers in process by clearing the Tx FIFO Empty + * interrupt mask and status bits and disabling subsequent host + * channel interrupts. + */ + { + gint_data_t intr = { .d32 = 0 }; + intr.b.nptxfempty = 1; + intr.b.ptxfempty = 1; + intr.b.hcintr = 1; + ifxusb_mreg (&_ifxhcd->core_if.core_global_regs->gintmsk, intr.d32, 0); + ifxusb_mreg (&_ifxhcd->core_if.core_global_regs->gintsts, intr.d32, 0); + } + + /* Respond with an error status to all URBs in the schedule. */ + epqh_list_free_all(_ifxhcd); + + /* Clean up any host channels that were in use. */ + { + int num_channels; + ifxhcd_hc_t *channel; + ifxusb_hc_regs_t *hc_regs; + hcchar_data_t hcchar; + int i; + + num_channels = _ifxhcd->core_if.params.host_channels; + + for (i = 0; i < num_channels; i++) + { + channel = &_ifxhcd->ifxhc[i]; + hc_regs = _ifxhcd->core_if.hc_regs[i]; + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + if (hcchar.b.chen) + printk(KERN_INFO "Warning: %s() HC still enabled\n",__func__); + ifxhcd_hc_cleanup(&_ifxhcd->core_if, channel); + } + } + IFX_DEBUGPL(DBG_HCDV, "%s(%p) finish\n", __func__, _ifxhcd); + return 1; +} + + +/*! + \brief Frees secondary storage associated with the ifxhcd_hcd structure contained + in the struct usb_hcd field. + */ +static void ifxhcd_freeextra(struct usb_hcd *_syshcd) +{ + ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd(_syshcd); + + IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD FREE\n"); + + /* Free memory for EPQH/URBD lists */ + epqh_list_free_all(ifxhcd); + + /* Free memory for the host channels. */ + ifxusb_free_buf_h(ifxhcd->status_buf); + return; +} + +/*! + \brief Initializes the HCD. This function allocates memory for and initializes the + static parts of the usb_hcd and ifxhcd_hcd structures. It also registers the + USB bus with the core and calls the hc_driver->start() function. It returns + a negative error on failure. + */ +int ifxhcd_init(ifxhcd_hcd_t *_ifxhcd) +{ + int retval = 0; + struct usb_hcd *syshcd = NULL; + + IFX_DEBUGPL(DBG_HCD, "IFX USB HCD INIT\n"); + + INIT_EPQH_LIST_ALL(_ifxhcd); + INIT_EPQH_LIST(_ifxhcd); + + init_timer(&_ifxhcd->autoprobe_timer); + init_timer(&_ifxhcd->host_probe_timer); + _ifxhcd->probe_sec = 5; + _ifxhcd->autoprobe_sec = 30; + + _ifxhcd->hc_driver.description = _ifxhcd->core_if.core_name; + _ifxhcd->hc_driver.product_desc = "IFX USB Controller"; + //_ifxhcd->hc_driver.hcd_priv_size = sizeof(ifxhcd_hcd_t); + _ifxhcd->hc_driver.hcd_priv_size = sizeof(unsigned long); + _ifxhcd->hc_driver.irq = ifxhcd_irq; + _ifxhcd->hc_driver.flags = HCD_MEMORY | HCD_USB2; + _ifxhcd->hc_driver.start = ifxhcd_start; + _ifxhcd->hc_driver.stop = ifxhcd_stop; + //_ifxhcd->hc_driver.reset = + //_ifxhcd->hc_driver.suspend = + //_ifxhcd->hc_driver.resume = + _ifxhcd->hc_driver.urb_enqueue = ifxhcd_urb_enqueue; + _ifxhcd->hc_driver.urb_dequeue = ifxhcd_urb_dequeue; + _ifxhcd->hc_driver.endpoint_disable = ifxhcd_endpoint_disable; + _ifxhcd->hc_driver.get_frame_number = ifxhcd_get_frame_number; + _ifxhcd->hc_driver.hub_status_data = ifxhcd_hub_status_data; + _ifxhcd->hc_driver.hub_control = ifxhcd_hub_control; + //_ifxhcd->hc_driver.hub_suspend = + //_ifxhcd->hc_driver.hub_resume = + _ifxhcd->pkt_remaining_reload_hs=PKT_REMAINING_RELOAD_HS; + _ifxhcd->pkt_remaining_reload_fs=PKT_REMAINING_RELOAD_FS; + _ifxhcd->pkt_remaining_reload_ls=PKT_REMAINING_RELOAD_LS; + _ifxhcd->pkt_count_limit_bo =8; + _ifxhcd->pkt_count_limit_bi =8; + + /* Allocate memory for and initialize the base HCD and */ + //syshcd = usb_create_hcd(&_ifxhcd->hc_driver, _ifxhcd->dev, _ifxhcd->dev->bus_id); + syshcd = usb_create_hcd(&_ifxhcd->hc_driver, _ifxhcd->dev, _ifxhcd->core_if.core_name); + + if (syshcd == NULL) + { + retval = -ENOMEM; + goto error1; + } + + syshcd->rsrc_start = (unsigned long)_ifxhcd->core_if.core_global_regs; + syshcd->regs = (void *)_ifxhcd->core_if.core_global_regs; + syshcd->self.otg_port = 0; + + //*((unsigned long *)(&(syshcd->hcd_priv)))=(unsigned long)_ifxhcd; + //*((unsigned long *)(&(syshcd->hcd_priv[0])))=(unsigned long)_ifxhcd; + syshcd->hcd_priv[0]=(unsigned long)_ifxhcd; + _ifxhcd->syshcd=syshcd; + INIT_LIST_HEAD(&_ifxhcd->epqh_list_all ); + INIT_LIST_HEAD(&_ifxhcd->epqh_list_np ); + INIT_LIST_HEAD(&_ifxhcd->epqh_list_intr ); + #ifdef __EN_ISOC__ + INIT_LIST_HEAD(&_ifxhcd->epqh_list_isoc); + #endif + + /* + * Create a host channel descriptor for each host channel implemented + * in the controller. Initialize the channel descriptor array. + */ + { + int num_channels = _ifxhcd->core_if.params.host_channels; + int i; + for (i = 0; i < num_channels; i++) + { + _ifxhcd->ifxhc[i].hc_num = i; + IFX_DEBUGPL(DBG_HCDV, "HCD Added channel #%d\n", i); + } + } + + /* Set device flags indicating whether the HCD supports DMA. */ + if(_ifxhcd->dev->dma_mask) + *(_ifxhcd->dev->dma_mask) = ~0; + _ifxhcd->dev->coherent_dma_mask = ~0; + + /* + * Finish generic HCD initialization and start the HCD. This function + * allocates the DMA buffer pool, registers the USB bus, requests the + * IRQ line, and calls ifxusb_hcd_start method. + */ + retval = usb_add_hcd(syshcd, _ifxhcd->core_if.irq, 0 + |IRQF_DISABLED + |IRQF_SHARED + ); + if (retval < 0) + goto error2; + + /* + * Allocate space for storing data on status transactions. Normally no + * data is sent, but this space acts as a bit bucket. This must be + * done after usb_add_hcd since that function allocates the DMA buffer + * pool. + */ + _ifxhcd->status_buf = ifxusb_alloc_buf_h(IFXHCD_STATUS_BUF_SIZE, 1); + + if (_ifxhcd->status_buf) + { + IFX_DEBUGPL(DBG_HCD, "IFX USB HCD Initialized, bus=%s, usbbus=%d\n", _ifxhcd->core_if.core_name, syshcd->self.busnum); + return 0; + } + IFX_ERROR("%s: status_buf allocation failed\n", __func__); + + /* Error conditions */ + usb_remove_hcd(syshcd); +error2: + ifxhcd_freeextra(syshcd); + usb_put_hcd(syshcd); +error1: + return retval; +} + +/*! + \brief Removes the HCD. + Frees memory and resources associated with the HCD and deregisters the bus. + */ +void ifxhcd_remove(ifxhcd_hcd_t *_ifxhcd) +{ + struct usb_hcd *syshcd = ifxhcd_to_syshcd(_ifxhcd); + + IFX_DEBUGPL(DBG_HCD, "IFX USB HCD REMOVE\n"); + + /* Turn off all interrupts */ + ifxusb_wreg (&_ifxhcd->core_if.core_global_regs->gintmsk, 0); + ifxusb_mreg (&_ifxhcd->core_if.core_global_regs->gahbcfg, 1, 0); + + usb_remove_hcd(syshcd); + ifxhcd_freeextra(syshcd); + usb_put_hcd(syshcd); + + return; +} + + +/* ========================================================================= + * Linux HC Driver Functions + * ========================================================================= */ + +/*! + \brief Initializes the IFXUSB controller and its root hub and prepares it for host + mode operation. Activates the root port. Returns 0 on success and a negative + error code on failure. + Called by USB stack. + */ +int ifxhcd_start(struct usb_hcd *_syshcd) +{ + ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); + ifxusb_core_if_t *core_if = &ifxhcd->core_if; + struct usb_bus *bus; + + IFX_DEBUGPL(DBG_HCD, "IFX USB HCD START\n"); + + bus = hcd_to_bus(_syshcd); + + /* Initialize the bus state. */ + _syshcd->state = HC_STATE_RUNNING; + + /* Initialize and connect root hub if one is not already attached */ + if (bus->root_hub) + { + IFX_DEBUGPL(DBG_HCD, "IFX USB HCD Has Root Hub\n"); + /* Inform the HUB driver to resume. */ + usb_hcd_resume_root_hub(_syshcd); + } + + ifxhcd->flags.d32 = 0; + + /* Put all channels in the free channel list and clean up channel states.*/ + { + int num_channels = ifxhcd->core_if.params.host_channels; + int i; + for (i = 0; i < num_channels; i++) + { + ifxhcd_hc_t *channel; + channel = &ifxhcd->ifxhc[i]; + ifxhcd_hc_cleanup(&ifxhcd->core_if, channel); + } + } + /* Initialize the USB core for host mode operation. */ + + ifxusb_host_enable_interrupts(core_if); + ifxusb_enable_global_interrupts_h(core_if); + ifxusb_phy_power_on_h (core_if); + + ifxusb_vbus_init(core_if); + + /* Turn on the vbus power. */ + { + hprt0_data_t hprt0; + hprt0.d32 = ifxusb_read_hprt0(core_if); + + IFX_PRINT("Init: Power Port (%d)\n", hprt0.b.prtpwr); + if (hprt0.b.prtpwr == 0 ) + { + hprt0.b.prtpwr = 1; + ifxusb_wreg(core_if->hprt0, hprt0.d32); + ifxusb_vbus_on(core_if); + } + } + return 0; +} + +/*! + \brief Halts the IFXUSB host mode operations in a clean manner. USB transfers are + stopped. + */ + #if defined(__IS_AR10__) +void ifxusb_oc_int_free(int port); + #else +void ifxusb_oc_int_free(void); + #endif + +void ifxhcd_stop(struct usb_hcd *_syshcd) +{ + ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd(_syshcd); + hprt0_data_t hprt0 = { .d32=0 }; + + IFX_DEBUGPL(DBG_HCD, "IFX USB HCD STOP\n"); + + /* Turn off all interrupts. */ + ifxusb_disable_global_interrupts_h(&ifxhcd->core_if ); + ifxusb_host_disable_interrupts(&ifxhcd->core_if ); + + /* + * The root hub should be disconnected before this function is called. + * The disconnect will clear the URBD lists (via ..._hcd_urb_dequeue) + * and the EPQH lists (via ..._hcd_endpoint_disable). + */ + + /* Turn off the vbus power */ + IFX_PRINT("PortPower off\n"); + + ifxusb_vbus_off(&ifxhcd->core_if ); + + + #if defined(__IS_AR10__) + ifxusb_oc_int_free(ifxhcd->core_if.core_no); + #else + ifxusb_oc_int_free(); + #endif + + + ifxusb_vbus_free(&ifxhcd->core_if ); + hprt0.b.prtpwr = 0; + ifxusb_wreg(ifxhcd->core_if.hprt0, hprt0.d32); + return; +} + +/*! + \brief Returns the current frame number + */ +int ifxhcd_get_frame_number(struct usb_hcd *_syshcd) +{ + ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd(_syshcd); + hfnum_data_t hfnum; + + hfnum.d32 = ifxusb_rreg(&ifxhcd->core_if.host_global_regs->hfnum); + + return hfnum.b.frnum; +} + +/*! + \brief Starts processing a USB transfer request specified by a USB Request Block + (URB). mem_flags indicates the type of memory allocation to use while + processing this URB. + */ +int ifxhcd_urb_enqueue( struct usb_hcd *_syshcd, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + struct usb_host_endpoint *_sysep, +#endif + struct urb *_urb, + gfp_t _mem_flags) +{ + ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); + ifxhcd_epqh_t *epqh = NULL; + + #ifdef __DEBUG__ + if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) + dump_urb_info(_urb, "ifxusb_hcd_urb_enqueue"); + #endif //__DEBUG__ + + if (!ifxhcd->flags.b.port_connect_status) /* No longer connected. */ + return -ENODEV; + + #if !defined(__EN_ISOC__) + if(usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) + { + IFX_ERROR("ISOC transfer not supported!!!\n"); + return -ENODEV; + } + #endif + + if(_urb->hcpriv) + { + IFX_WARN("%s() Previous urb->hcpriv exist %p\n",__func__,_urb->hcpriv); + #if 1 + return -ENOSPC; + #endif + } + + epqh=ifxhcd_urbd_create (ifxhcd,_urb); + if (!epqh) + { + IFX_ERROR("IFXUSB HCD URB Enqueue failed creating URBD\n"); + return -ENOSPC; + } + if(epqh->phase==EPQH_DISABLING ) + { + IFX_ERROR("Enqueue to a DISABLING EP!!!\n"); + return -ENODEV; + } + + #ifdef __DYN_SOF_INTR__ + ifxhcd->dyn_sof_count = DYN_SOF_COUNT_DEF; + #endif + //enable_sof(ifxhcd); + { + gint_data_t gintsts; + gintsts.d32=0; + gintsts.b.sofintr = 1; + ifxusb_mreg(&ifxhcd->core_if.core_global_regs->gintmsk, 0,gintsts.d32); + } + + if(epqh->phase==EPQH_IDLE || epqh->phase==EPQH_STDBY ) + { + epqh->phase=EPQH_READY; + #ifdef __EPQD_DESTROY_TIMEOUT__ + del_timer(&epqh->destroy_timer); + #endif + } + select_eps(ifxhcd); + return 0; +} + +/*! + \brief Aborts/cancels a USB transfer request. Always returns 0 to indicate + success. + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) +int ifxhcd_urb_dequeue(struct usb_hcd *_syshcd, struct urb *_urb) +#else +int ifxhcd_urb_dequeue(struct usb_hcd *_syshcd, struct urb *_urb, int status) +#endif +{ + ifxhcd_hcd_t *ifxhcd; + struct usb_host_endpoint *sysep; + ifxhcd_urbd_t *urbd; + ifxhcd_epqh_t *epqh; + + IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD URB Dequeue\n"); + #if !defined(__EN_ISOC__) + if(usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) + return 0; + #endif + + ifxhcd = syshcd_to_ifxhcd(_syshcd); + + urbd = (ifxhcd_urbd_t *) _urb->hcpriv; + if(!urbd) + { + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + _urb->status=-ETIMEDOUT; + usb_hcd_giveback_urb(_syshcd, _urb); + #else +// usb_hcd_giveback_urb(_syshcd, _urb,-ETIMEDOUT); + usb_hcd_giveback_urb(_syshcd, _urb,status); + #endif + return 0; + } + + sysep = ifxhcd_urb_to_endpoint(_urb); + if(sysep) + { + LOCK_EPQH_LIST_ALL(ifxhcd); + epqh = sysep_to_epqh(ifxhcd,sysep); + UNLOCK_EPQH_LIST_ALL(ifxhcd); + if(epqh!=urbd->epqh) + IFX_ERROR("%s inconsistant epqh %p %p\n",__func__,epqh,urbd->epqh); + } + else + epqh = (ifxhcd_epqh_t *) urbd->epqh; + if(!ifxhcd->flags.b.port_connect_status || !epqh) + { + urbd->phase=URBD_DEQUEUEING; + ifxhcd_complete_urb(ifxhcd, urbd, -ENODEV); + } + else + { + LOCK_URBD_LIST(epqh); + if( urbd->phase==URBD_IDLE + || urbd->phase==URBD_ACTIVE +// || urbd->phase==URBD_STARTING + ) + { + urbd->phase=URBD_DEQUEUEING; + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + ifxhcd_complete_urb(ifxhcd, urbd, -ETIMEDOUT); + #else + ifxhcd_complete_urb(ifxhcd, urbd, status); + #endif + } + else if( urbd->phase==URBD_STARTED + || urbd->phase==URBD_STARTING +// || urbd->phase==URBD_ACTIVE + ) + { + if(ifxhcd_hc_halt(&ifxhcd->core_if, epqh->hc, HC_XFER_URB_DEQUEUE)) + { + urbd->phase=URBD_DEQUEUEING; + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) + ifxhcd_complete_urb(ifxhcd, urbd, -ETIMEDOUT); + #else + ifxhcd_complete_urb(ifxhcd, urbd, status); + #endif + ifxhcd_epqh_idle(epqh); + } + } + UNLOCK_URBD_LIST(epqh); + } + return 0; +} + + +/*! + \brief Frees resources in the IFXUSB controller related to a given endpoint. Also + clears state in the HCD related to the endpoint. Any URBs for the endpoint + must already be dequeued. + */ +void ifxhcd_endpoint_disable( struct usb_hcd *_syshcd, + struct usb_host_endpoint *_sysep) +{ + ifxhcd_hcd_t *ifxhcd; + ifxhcd_epqh_t *epqh; + + IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD EP DISABLE: _bEndpointAddress=0x%02x, " + "endpoint=%d\n", _sysep->desc.bEndpointAddress, + ifxhcd_ep_addr_to_endpoint(_sysep->desc.bEndpointAddress)); + + ifxhcd = syshcd_to_ifxhcd(_syshcd); + + LOCK_EPQH_LIST_ALL(ifxhcd); + epqh = sysep_to_epqh(ifxhcd,_sysep); + UNLOCK_EPQH_LIST_ALL(ifxhcd); + + if (!epqh) + { + return; + } + else + { + if (epqh->sysep!=_sysep) + { + IFX_ERROR("%s inconsistant sysep %p %p %p\n",__func__,epqh,epqh->sysep,_sysep); + return; + } + + epqh->phase=EPQH_DISABLING; + kill_all_urbs_in_epqh(ifxhcd, epqh, -ETIMEDOUT); + { + uint32_t count=0x80000; + for(;!list_empty(&epqh->urbd_list) && count> 0; count--) udelay(1); + if(!count) + IFX_ERROR("%s: unable to clear urbd in epqh \n",__func__); + } + ifxhcd_epqh_free(epqh); + } + IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD EP DISABLE: done\n"); +} + + +/*! + \brief Handles host mode interrupts for the IFXUSB controller. Returns IRQ_NONE if + there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid + interrupt. + + This function is called by the USB core when an interrupt occurs + */ +irqreturn_t ifxhcd_irq(struct usb_hcd *_syshcd) +{ + ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); + int32_t retval=0; + + //mask_and_ack_ifx_irq (ifxhcd->core_if.irq); + retval = ifxhcd_handle_intr(ifxhcd); + return IRQ_RETVAL(retval); +} + + + +/*! + \brief Creates Status Change bitmap for the root hub and root port. The bitmap is + returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1 + is the status change indicator for the single root port. Returns 1 if either + change indicator is 1, otherwise returns 0. + */ +int ifxhcd_hub_status_data(struct usb_hcd *_syshcd, char *_buf) +{ + ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); + + _buf[0] = 0; + _buf[0] |= (ifxhcd->flags.b.port_connect_status_change || + ifxhcd->flags.b.port_reset_change || + ifxhcd->flags.b.port_enable_change || + ifxhcd->flags.b.port_suspend_change || + ifxhcd->flags.b.port_over_current_change) << 1; + + #ifdef __DEBUG__ + if (_buf[0]) + { + IFX_DEBUGPL(DBG_HCD, "IFXUSB HCD HUB STATUS DATA:" + " Root port status changed\n"); + IFX_DEBUGPL(DBG_HCDV, " port_connect_status_change: %d\n", + ifxhcd->flags.b.port_connect_status_change); + IFX_DEBUGPL(DBG_HCDV, " port_reset_change: %d\n", + ifxhcd->flags.b.port_reset_change); + IFX_DEBUGPL(DBG_HCDV, " port_enable_change: %d\n", + ifxhcd->flags.b.port_enable_change); + IFX_DEBUGPL(DBG_HCDV, " port_suspend_change: %d\n", + ifxhcd->flags.b.port_suspend_change); + IFX_DEBUGPL(DBG_HCDV, " port_over_current_change: %d\n", + ifxhcd->flags.b.port_over_current_change); + { + hprt0_data_t hprt0; + hprt0.d32 = ifxusb_rreg(ifxhcd->core_if.hprt0); + IFX_DEBUGPL(DBG_HCDV, " port reg :%08X\n",hprt0.d32); + IFX_DEBUGPL(DBG_HCDV, " port reg :connect: %d/%d\n",hprt0.b.prtconnsts,hprt0.b.prtconndet); + IFX_DEBUGPL(DBG_HCDV, " port reg :enable: %d/%d\n",hprt0.b.prtena,hprt0.b.prtenchng); + IFX_DEBUGPL(DBG_HCDV, " port reg :OC: %d/%d\n",hprt0.b.prtovrcurract,hprt0.b.prtovrcurrchng); + IFX_DEBUGPL(DBG_HCDV, " port reg :rsume/suspend/reset: %d/%d/%d\n",hprt0.b.prtres,hprt0.b.prtsusp,hprt0.b.prtrst); + IFX_DEBUGPL(DBG_HCDV, " port reg :port power: %d/\n",hprt0.b.prtpwr); + IFX_DEBUGPL(DBG_HCDV, " port reg :speed: %d/\n",hprt0.b.prtspd); + } + } + #endif //__DEBUG__ + return (_buf[0] != 0); +} + +#ifdef __WITH_HS_ELECT_TST__ + extern void do_setup(ifxusb_core_if_t *_core_if) ; + extern void do_in_ack(ifxusb_core_if_t *_core_if); +#endif //__WITH_HS_ELECT_TST__ + +/*! + \brief Handles hub class-specific requests. + */ +int ifxhcd_hub_control( struct usb_hcd *_syshcd, + u16 _typeReq, + u16 _wValue, + u16 _wIndex, + char *_buf, + u16 _wLength) +{ + int retval = 0; + ifxhcd_hcd_t *ifxhcd = syshcd_to_ifxhcd (_syshcd); + ifxusb_core_if_t *core_if = &ifxhcd->core_if; + struct usb_hub_descriptor *desc; + hprt0_data_t hprt0 = {.d32 = 0}; + + uint32_t port_status; + + switch (_typeReq) + { + case ClearHubFeature: + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "ClearHubFeature 0x%x\n", _wValue); + switch (_wValue) + { + case C_HUB_LOCAL_POWER: + case C_HUB_OVER_CURRENT: + /* Nothing required here */ + break; + default: + retval = -EINVAL; + IFX_ERROR ("IFXUSB HCD - " + "ClearHubFeature request %xh unknown\n", _wValue); + } + break; + case ClearPortFeature: + if (!_wIndex || _wIndex > 1) + goto error; + + switch (_wValue) + { + case USB_PORT_FEAT_ENABLE: + IFX_DEBUGPL (DBG_ANY, "IFXUSB HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_ENABLE\n"); + hprt0.d32 = ifxusb_read_hprt0 (core_if); + hprt0.b.prtena = 1; + ifxusb_wreg(core_if->hprt0, hprt0.d32); + break; + case USB_PORT_FEAT_SUSPEND: + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_SUSPEND\n"); + hprt0.d32 = ifxusb_read_hprt0 (core_if); + hprt0.b.prtres = 1; + ifxusb_wreg(core_if->hprt0, hprt0.d32); + /* Clear Resume bit */ + mdelay (100); + hprt0.b.prtres = 0; + ifxusb_wreg(core_if->hprt0, hprt0.d32); + break; + case USB_PORT_FEAT_POWER: + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_POWER\n"); + #ifdef __IS_DUAL__ + ifxusb_vbus_off(core_if); + #else + ifxusb_vbus_off(core_if); + #endif + hprt0.d32 = ifxusb_read_hprt0 (core_if); + hprt0.b.prtpwr = 0; + ifxusb_wreg(core_if->hprt0, hprt0.d32); + break; + case USB_PORT_FEAT_INDICATOR: + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_INDICATOR\n"); + /* Port inidicator not supported */ + break; + case USB_PORT_FEAT_C_CONNECTION: + /* Clears drivers internal connect status change + * flag */ + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n"); + ifxhcd->flags.b.port_connect_status_change = 0; + break; + case USB_PORT_FEAT_C_RESET: + /* Clears the driver's internal Port Reset Change + * flag */ + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_C_RESET\n"); + ifxhcd->flags.b.port_reset_change = 0; + break; + case USB_PORT_FEAT_C_ENABLE: + /* Clears the driver's internal Port + * Enable/Disable Change flag */ + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n"); + ifxhcd->flags.b.port_enable_change = 0; + break; + case USB_PORT_FEAT_C_SUSPEND: + /* Clears the driver's internal Port Suspend + * Change flag, which is set when resume signaling on + * the host port is complete */ + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n"); + ifxhcd->flags.b.port_suspend_change = 0; + break; + case USB_PORT_FEAT_C_OVER_CURRENT: + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n"); + ifxhcd->flags.b.port_over_current_change = 0; + break; + default: + retval = -EINVAL; + IFX_ERROR ("IFXUSB HCD - " + "ClearPortFeature request %xh " + "unknown or unsupported\n", _wValue); + } + break; + case GetHubDescriptor: + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "GetHubDescriptor\n"); + desc = (struct usb_hub_descriptor *)_buf; + desc->bDescLength = 9; + desc->bDescriptorType = 0x29; + desc->bNbrPorts = 1; + desc->wHubCharacteristics = 0x08; + desc->bPwrOn2PwrGood = 1; + desc->bHubContrCurrent = 0; + + desc->u.hs.DeviceRemovable[0] = 0; + desc->u.hs.DeviceRemovable[1] = 1; + /*desc->bitmap[0] = 0; + desc->bitmap[1] = 0xff;*/ + break; + case GetHubStatus: + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "GetHubStatus\n"); + memset (_buf, 0, 4); + break; + case GetPortStatus: + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "GetPortStatus\n"); + if (!_wIndex || _wIndex > 1) + goto error; + port_status = 0; + if (ifxhcd->flags.b.port_connect_status_change) + port_status |= (1 << USB_PORT_FEAT_C_CONNECTION); + if (ifxhcd->flags.b.port_enable_change) + port_status |= (1 << USB_PORT_FEAT_C_ENABLE); + if (ifxhcd->flags.b.port_suspend_change) + port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); + if (ifxhcd->flags.b.port_reset_change) + port_status |= (1 << USB_PORT_FEAT_C_RESET); + if (ifxhcd->flags.b.port_over_current_change) + { + IFX_ERROR("Device Not Supported\n"); + port_status |= (1 << USB_PORT_FEAT_C_OVER_CURRENT); + } + if (!ifxhcd->flags.b.port_connect_status) + { + /* + * The port is disconnected, which means the core is + * either in device mode or it soon will be. Just + * return 0's for the remainder of the port status + * since the port register can't be read if the core + * is in device mode. + */ + *((u32 *) _buf) = cpu_to_le32(port_status); + break; + } + + hprt0.d32 = ifxusb_rreg(core_if->hprt0); + IFX_DEBUGPL(DBG_HCDV, " HPRT0: 0x%08x\n", hprt0.d32); + if (hprt0.b.prtconnsts) + port_status |= (1 << USB_PORT_FEAT_CONNECTION); + if (hprt0.b.prtena) + { + ifxhcd->disconnecting=0; + port_status |= (1 << USB_PORT_FEAT_ENABLE); + } + if (hprt0.b.prtsusp) + port_status |= (1 << USB_PORT_FEAT_SUSPEND); + if (hprt0.b.prtovrcurract) + port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT); + if (hprt0.b.prtrst) + port_status |= (1 << USB_PORT_FEAT_RESET); + if (hprt0.b.prtpwr) + port_status |= (1 << USB_PORT_FEAT_POWER); +/* if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED) + port_status |= (1 << USB_PORT_FEAT_HIGHSPEED); + else*/ if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_LOW_SPEED) + port_status |= (1 << USB_PORT_FEAT_LOWSPEED); + if (hprt0.b.prttstctl) + port_status |= (1 << USB_PORT_FEAT_TEST); + /* USB_PORT_FEAT_INDICATOR unsupported always 0 */ + *((u32 *) _buf) = cpu_to_le32(port_status); + break; + case SetHubFeature: + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "SetHubFeature\n"); + /* No HUB features supported */ + break; + case SetPortFeature: + if (_wValue != USB_PORT_FEAT_TEST && (!_wIndex || _wIndex > 1)) + goto error; + /* + * The port is disconnected, which means the core is + * either in device mode or it soon will be. Just + * return without doing anything since the port + * register can't be written if the core is in device + * mode. + */ + if (!ifxhcd->flags.b.port_connect_status) + break; + switch (_wValue) + { + case USB_PORT_FEAT_SUSPEND: + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "SetPortFeature - USB_PORT_FEAT_SUSPEND\n"); + hprt0.d32 = ifxusb_read_hprt0 (core_if); + hprt0.b.prtsusp = 1; + ifxusb_wreg(core_if->hprt0, hprt0.d32); + //IFX_PRINT( "SUSPEND: HPRT0=%0x\n", hprt0.d32); + /* Suspend the Phy Clock */ + { + pcgcctl_data_t pcgcctl = {.d32=0}; + pcgcctl.b.stoppclk = 1; + ifxusb_wreg(core_if->pcgcctl, pcgcctl.d32); + } + break; + case USB_PORT_FEAT_POWER: + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "SetPortFeature - USB_PORT_FEAT_POWER\n"); + ifxusb_vbus_on (core_if); + hprt0.d32 = ifxusb_read_hprt0 (core_if); + hprt0.b.prtpwr = 1; + ifxusb_wreg(core_if->hprt0, hprt0.d32); + break; + case USB_PORT_FEAT_RESET: + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "SetPortFeature - USB_PORT_FEAT_RESET\n"); + hprt0.d32 = ifxusb_read_hprt0 (core_if); + hprt0.b.prtrst = 1; + ifxusb_wreg(core_if->hprt0, hprt0.d32); + /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ + MDELAY (60); + hprt0.b.prtrst = 0; + ifxusb_wreg(core_if->hprt0, hprt0.d32); + break; + #ifdef __WITH_HS_ELECT_TST__ + case USB_PORT_FEAT_TEST: + { + uint32_t t; + gint_data_t gintmsk; + t = (_wIndex >> 8); /* MSB wIndex USB */ + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "SetPortFeature - USB_PORT_FEAT_TEST %d\n", t); + warn("USB_PORT_FEAT_TEST %d\n", t); + if (t < 6) + { + hprt0.d32 = ifxusb_read_hprt0 (core_if); + hprt0.b.prttstctl = t; + ifxusb_wreg(core_if->hprt0, hprt0.d32); + } + else if (t == 6) /* HS_HOST_PORT_SUSPEND_RESUME */ + { + /* Save current interrupt mask */ + gintmsk.d32 = ifxusb_rreg(&core_if->core_global_regs->gintmsk); + + /* Disable all interrupts while we muck with + * the hardware directly + */ + ifxusb_wreg(&core_if->core_global_regs->gintmsk, 0); + + /* 15 second delay per the test spec */ + mdelay(15000); + + /* Drive suspend on the root port */ + hprt0.d32 = ifxusb_read_hprt0 (core_if); + hprt0.b.prtsusp = 1; + hprt0.b.prtres = 0; + ifxusb_wreg(core_if->hprt0, hprt0.d32); + + /* 15 second delay per the test spec */ + mdelay(15000); + + /* Drive resume on the root port */ + hprt0.d32 = ifxusb_read_hprt0 (core_if); + hprt0.b.prtsusp = 0; + hprt0.b.prtres = 1; + ifxusb_wreg(core_if->hprt0, hprt0.d32); + mdelay(100); + + /* Clear the resume bit */ + hprt0.b.prtres = 0; + ifxusb_wreg(core_if->hprt0, hprt0.d32); + + /* Restore interrupts */ + ifxusb_wreg(&core_if->core_global_regs->gintmsk, gintmsk.d32); + } + else if (t == 7) /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */ + { + /* Save current interrupt mask */ + gintmsk.d32 = ifxusb_rreg(&core_if->core_global_regs->gintmsk); + + /* Disable all interrupts while we muck with + * the hardware directly + */ + ifxusb_wreg(&core_if->core_global_regs->gintmsk, 0); + + /* 15 second delay per the test spec */ + mdelay(15000); + + /* Send the Setup packet */ + do_setup(core_if); + + /* 15 second delay so nothing else happens for awhile */ + mdelay(15000); + + /* Restore interrupts */ + ifxusb_wreg(&core_if->core_global_regs->gintmsk, gintmsk.d32); + } + + else if (t == 8) /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */ + { + /* Save current interrupt mask */ + gintmsk.d32 = ifxusb_rreg(&core_if->core_global_regs->gintmsk); + + /* Disable all interrupts while we muck with + * the hardware directly + */ + ifxusb_wreg(&core_if->core_global_regs->gintmsk, 0); + + /* Send the Setup packet */ + do_setup(core_if); + + /* 15 second delay so nothing else happens for awhile */ + mdelay(15000); + + /* Send the In and Ack packets */ + do_in_ack(core_if); + + /* 15 second delay so nothing else happens for awhile */ + mdelay(15000); + + /* Restore interrupts */ + ifxusb_wreg(&core_if->core_global_regs->gintmsk, gintmsk.d32); + } + } + break; + #endif //__WITH_HS_ELECT_TST__ + case USB_PORT_FEAT_INDICATOR: + IFX_DEBUGPL (DBG_HCD, "IFXUSB HCD HUB CONTROL - " + "SetPortFeature - USB_PORT_FEAT_INDICATOR\n"); + /* Not supported */ + break; + default: + retval = -EINVAL; + IFX_ERROR ("IFXUSB HCD - " + "SetPortFeature request %xh " + "unknown or unsupported\n", _wValue); + } + break; + default: + error: + retval = -EINVAL; + IFX_WARN ("IFXUSB HCD - " + "Unknown hub control request type or invalid typeReq: %xh wIndex: %xh wValue: %xh\n", + _typeReq, _wIndex, _wValue); + } + return retval; +} + + + + +/*! + \brief This function trigger a data transfer for a host channel and + starts the transfer. + + For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ + register along with a packet count of 1 and the channel is enabled. This + causes a single PING transaction to occur. Other fields in HCTSIZ are + simply set to 0 since no data transfer occurs in this case. + + For a PING transfer in DMA mode, the HCTSIZ register is initialized with + all the information required to perform the subsequent data transfer. In + addition, the Do Ping bit is set in the HCTSIZ register. In this case, the + controller performs the entire PING protocol, then starts the data + transfer. + \param _core_if Pointer of core_if structure + \param _ifxhc Information needed to initialize the host channel. The xfer_len + value may be reduced to accommodate the max widths of the XferSize and + PktCnt fields in the HCTSIZn register. The multi_count value may be changed + to reflect the final xfer_len value. + */ +void ifxhcd_hc_start(ifxhcd_hcd_t *_ifxhcd, ifxhcd_hc_t *_ifxhc) +{ + ifxusb_core_if_t *core_if = &_ifxhcd->core_if; + uint32_t max_hc_xfer_size = core_if->params.max_transfer_size; + uint16_t max_hc_pkt_count = core_if->params.max_packet_count; + ifxusb_hc_regs_t *hc_regs = core_if->hc_regs[_ifxhc->hc_num]; + hfnum_data_t hfnum; + + hprt0_data_t hprt0; + + if(_ifxhc->epqh->urbd->phase==URBD_DEQUEUEING) + return; + + hprt0.d32 = ifxusb_read_hprt0(core_if); + + if(_ifxhcd->pkt_remaining==0) + return; + +#if 0 + if(_ifxhc->phase!=HC_WAITING) + printk(KERN_INFO "%s() line %d: _ifxhc->phase!=HC_WAITING :%d\n",__func__,__LINE__,_ifxhc->phase); + if(_ifxhc->epqh->urbd->phase==URBD_IDLE ) printk(KERN_INFO "%s() line %d: _ifxhc->epqh->urbd->phase==URBD_IDLE\n",__func__,__LINE__); +// if(_ifxhc->epqh->urbd->phase==URBD_ACTIVE ) printk(KERN_INFO "%s() line %d: _ifxhc->epqh->urbd->phase==URBD_ACTIVE\n",__func__,__LINE__); + if(_ifxhc->epqh->urbd->phase==URBD_STARTING ) printk(KERN_INFO "%s() line %d: _ifxhc->epqh->urbd->phase==URBD_STARTING\n",__func__,__LINE__); + if(_ifxhc->epqh->urbd->phase==URBD_STARTED ) printk(KERN_INFO "%s() line %d: _ifxhc->epqh->urbd->phase==URBD_STARTED\n",__func__,__LINE__); + if(_ifxhc->epqh->urbd->phase==URBD_COMPLETING) printk(KERN_INFO "%s() line %d: _ifxhc->epqh->urbd->phase==URBD_COMPLETING\n",__func__,__LINE__); + if(_ifxhc->epqh->urbd->phase==URBD_DEQUEUEING) printk(KERN_INFO "%s() line %d: _ifxhc->epqh->urbd->phase==URBD_DEQUEUEING\n",__func__,__LINE__); + if(_ifxhc->epqh->urbd->phase==URBD_FINISHING ) printk(KERN_INFO "%s() line %d: _ifxhc->epqh->urbd->phase==URBD_FINISHING\n",__func__,__LINE__); +#endif + + if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED) + { + if (_ifxhc->split) + { + if(max_hc_pkt_count > _ifxhcd->pkt_remaining) + max_hc_pkt_count = _ifxhcd->pkt_remaining; + } + else if(_ifxhc->ep_type == IFXUSB_EP_TYPE_BULK) + { + if( _ifxhc->is_in && _ifxhcd->pkt_count_limit_bi && max_hc_pkt_count > _ifxhcd->pkt_count_limit_bi) + max_hc_pkt_count = _ifxhcd->pkt_count_limit_bi; + if(!_ifxhc->is_in && _ifxhcd->pkt_count_limit_bo && max_hc_pkt_count > _ifxhcd->pkt_count_limit_bo) + max_hc_pkt_count = _ifxhcd->pkt_count_limit_bo; + if(max_hc_pkt_count*8 > _ifxhcd->pkt_remaining) + max_hc_pkt_count = _ifxhcd->pkt_remaining/8; + } + else + { + if(max_hc_pkt_count > _ifxhcd->pkt_remaining) + max_hc_pkt_count = _ifxhcd->pkt_remaining; + } + } + else if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_LOW_SPEED) + { + if(max_hc_pkt_count > _ifxhcd->pkt_remaining) + max_hc_pkt_count = _ifxhcd->pkt_remaining; + } + else + { + if(max_hc_pkt_count > _ifxhcd->pkt_remaining) + max_hc_pkt_count = _ifxhcd->pkt_remaining; + } + + if(max_hc_pkt_count==0) + return; + + if(max_hc_pkt_count * _ifxhc->mps < max_hc_xfer_size) + max_hc_xfer_size = max_hc_pkt_count * _ifxhc->mps; + + _ifxhc->epqh->urbd->phase=URBD_STARTING; + + if(_ifxhc->is_in || _ifxhc->speed != IFXUSB_EP_SPEED_HIGH || _ifxhc->xfer_len==0) + _ifxhc->epqh->do_ping=0; + if(_ifxhc->ep_type == IFXUSB_EP_TYPE_INTR || _ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) + _ifxhc->epqh->do_ping=0; + if(_ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL && _ifxhc->control_phase != IFXHCD_CONTROL_DATA ) + _ifxhc->epqh->do_ping=0; + + if (_ifxhc->split > 0) + { + _ifxhc->start_pkt_count = 1; + if(!_ifxhc->is_in && _ifxhc->split>1) // OUT CSPLIT + _ifxhc->xfer_len = 0; + if (_ifxhc->xfer_len > _ifxhc->mps) + _ifxhc->xfer_len = _ifxhc->mps; + if (_ifxhc->xfer_len > 188) + _ifxhc->xfer_len = 188; + } + else if(_ifxhc->is_in) + { + _ifxhc->short_rw = 0; + if (_ifxhc->xfer_len > 0) + { + if (_ifxhc->xfer_len > max_hc_xfer_size) + _ifxhc->xfer_len = max_hc_xfer_size - _ifxhc->mps + 1; + _ifxhc->start_pkt_count = (_ifxhc->xfer_len + _ifxhc->mps - 1) / _ifxhc->mps; + if (_ifxhc->start_pkt_count > max_hc_pkt_count) + _ifxhc->start_pkt_count = max_hc_pkt_count; + } + else /* Need 1 packet for transfer length of 0. */ + _ifxhc->start_pkt_count = 1; + _ifxhc->xfer_len = _ifxhc->start_pkt_count * _ifxhc->mps; + } + else //non-split out + { + if (_ifxhc->xfer_len == 0) + { + if(_ifxhc->short_rw==0) + printk(KERN_INFO "Info: %s() line %d: ZLP write without short_rw set! xfer_count:%d/%d \n",__func__,__LINE__, + _ifxhc->xfer_count, + _ifxhc->epqh->urbd->xfer_len); + _ifxhc->start_pkt_count = 1; + } + else + { + if (_ifxhc->xfer_len > max_hc_xfer_size) + { + _ifxhc->start_pkt_count = (max_hc_xfer_size / _ifxhc->mps); + _ifxhc->xfer_len = _ifxhc->start_pkt_count * _ifxhc->mps; + } + else + { + _ifxhc->start_pkt_count = (_ifxhc->xfer_len+_ifxhc->mps-1) / _ifxhc->mps; +// if(_ifxhc->start_pkt_count * _ifxhc->mps == _ifxhc->xfer_len ) +// _ifxhc->start_pkt_count += _ifxhc->short_rw; + } + } + } + + if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED) + { + if (_ifxhc->split) + { + if( _ifxhcd->pkt_remaining > _ifxhc->start_pkt_count) + _ifxhcd->pkt_remaining -= _ifxhc->start_pkt_count; + else + _ifxhcd->pkt_remaining = 0; + } + else if(_ifxhc->ep_type == IFXUSB_EP_TYPE_BULK) + { + if( _ifxhcd->pkt_remaining*8 > _ifxhc->start_pkt_count) + _ifxhcd->pkt_remaining -= (_ifxhc->start_pkt_count*8); + else + _ifxhcd->pkt_remaining = 0; + } + else + { + if( _ifxhcd->pkt_remaining > _ifxhc->start_pkt_count) + _ifxhcd->pkt_remaining -= _ifxhc->start_pkt_count; + else + _ifxhcd->pkt_remaining = 0; + } + } + else if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_LOW_SPEED) + { + if( _ifxhcd->pkt_remaining > _ifxhc->start_pkt_count) + _ifxhcd->pkt_remaining -= _ifxhc->start_pkt_count; + else + _ifxhcd->pkt_remaining = 0; + } + else + { + if( _ifxhcd->pkt_remaining > _ifxhc->start_pkt_count) + _ifxhcd->pkt_remaining -= _ifxhc->start_pkt_count; + else + _ifxhcd->pkt_remaining = 0; + } + + #ifdef __EN_ISOC__ + if (_ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) + { + /* Set up the initial PID for the transfer. */ + #if 1 + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; + #else + if (_ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + { + if (_ifxhc->is_in) + { + if (_ifxhc->multi_count == 1) + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; + else if (_ifxhc->multi_count == 2) + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; + else + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA2; + } + else + { + if (_ifxhc->multi_count == 1) + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; + else + _ifxhc->data_pid_start = IFXUSB_HC_PID_MDATA; + } + } + else + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; + #endif + } + #endif + + IFX_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, _ifxhc->hc_num); + { + hctsiz_data_t hctsiz= { .d32=0 }; + + hctsiz.b.dopng = _ifxhc->epqh->do_ping; + _ifxhc->epqh->do_ping=0; + + if(_ifxhc->is_in || _ifxhc->speed != IFXUSB_EP_SPEED_HIGH || _ifxhc->xfer_len==0) + hctsiz.b.dopng = 0; + if(_ifxhc->ep_type == IFXUSB_EP_TYPE_INTR || _ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) + hctsiz.b.dopng = 0; + if(_ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL && _ifxhc->control_phase != IFXHCD_CONTROL_DATA ) + hctsiz.b.dopng = 0; + + hctsiz.b.xfersize = _ifxhc->xfer_len; + hctsiz.b.pktcnt = _ifxhc->start_pkt_count; + hctsiz.b.pid = _ifxhc->data_pid_start; + ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); + + IFX_DEBUGPL(DBG_HCDV, " Xfer Size: %d\n", hctsiz.b.xfersize); + IFX_DEBUGPL(DBG_HCDV, " Num Pkts: %d\n" , hctsiz.b.pktcnt); + IFX_DEBUGPL(DBG_HCDV, " Start PID: %d\n", hctsiz.b.pid); + } + IFX_DEBUGPL(DBG_HCDV, " DMA: 0x%08x\n", (uint32_t)(CPHYSADDR( ((uint32_t)(_ifxhc->xfer_buff))+ _ifxhc->xfer_count ))); + ifxusb_wreg(&hc_regs->hcdma, (uint32_t)(CPHYSADDR( ((uint32_t)(_ifxhc->xfer_buff))+ _ifxhc->xfer_count ))); + + /* Start the split */ + if (_ifxhc->split>0) + { + hcsplt_data_t hcsplt; + hcsplt.d32 = ifxusb_rreg (&hc_regs->hcsplt); + hcsplt.b.spltena = 1; + if (_ifxhc->split>1) + hcsplt.b.compsplt = 1; + else + hcsplt.b.compsplt = 0; + + #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) + if (_ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) + hcsplt.b.xactpos = _ifxhc->isoc_xact_pos; + else + #endif + hcsplt.b.xactpos = IFXUSB_HCSPLIT_XACTPOS_ALL;// if not ISO + ifxusb_wreg(&hc_regs->hcsplt, hcsplt.d32); + IFX_DEBUGPL(DBG_HCDV, " SPLIT: XACT_POS:0x%08x\n", hcsplt.d32); + } + + { + hcchar_data_t hcchar; + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); +// hcchar.b.multicnt = _ifxhc->multi_count; + hcchar.b.multicnt = 1; + + if (_ifxhc->ep_type == IFXUSB_EP_TYPE_INTR || _ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) + { + hfnum.d32 = ifxusb_rreg(&core_if->host_global_regs->hfnum); + /* 1 if _next_ frame is odd, 0 if it's even */ + hcchar.b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1; + } + + #ifdef __DEBUG__ + _ifxhc->start_hcchar_val = hcchar.d32; + if (hcchar.b.chdis) + IFX_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", + __func__, _ifxhc->hc_num, hcchar.d32); + #endif + + /* Set host channel enable after all other setup is complete. */ + hcchar.b.chen = 1; + hcchar.b.chdis = 0; + hcchar.b.epdir = _ifxhc->is_in; + _ifxhc->hcchar=hcchar.d32; + } + + IFX_DEBUGPL(DBG_HCDV, " HCCHART: 0x%08x\n", _ifxhc->hcchar); + + _ifxhc->phase=HC_STARTING; +} + +/*! + \brief Attempts to halt a host channel. This function should only be called + to abort a transfer in DMA mode. Under normal circumstances in DMA mode, the + controller halts the channel when the transfer is complete or a condition + occurs that requires application intervention. + + In DMA mode, always sets the Channel Enable and Channel Disable bits of the + HCCHARn register. The controller ensures there is space in the request + queue before submitting the halt request. + + Some time may elapse before the core flushes any posted requests for this + host channel and halts. The Channel Halted interrupt handler completes the + deactivation of the host channel. + */ +int ifxhcd_hc_halt(ifxusb_core_if_t *_core_if, + ifxhcd_hc_t *_ifxhc, + ifxhcd_halt_status_e _halt_status) +{ + hcchar_data_t hcchar; + ifxusb_hc_regs_t *hc_regs; + hc_regs = _core_if->hc_regs[_ifxhc->hc_num]; + + WARN_ON(_halt_status == HC_XFER_NO_HALT_STATUS); + + { + hprt0_data_t hprt0; + hprt0.d32 = ifxusb_rreg(_core_if->hprt0); + if(hprt0.b.prtena == 0) + return -1; + } + + if (_halt_status == HC_XFER_URB_DEQUEUE || + _halt_status == HC_XFER_AHB_ERR) + { + /* + * Disable all channel interrupts except Ch Halted. The URBD + * and EPQH state associated with this transfer has been cleared + * (in the case of URB_DEQUEUE), so the channel needs to be + * shut down carefully to prevent crashes. + */ + hcint_data_t hcintmsk; + hcintmsk.d32 = 0; + hcintmsk.b.chhltd = 1; + ifxusb_wreg(&hc_regs->hcintmsk, hcintmsk.d32); + + /* + * Make sure no other interrupts besides halt are currently + * pending. Handling another interrupt could cause a crash due + * to the URBD and EPQH state. + */ + ifxusb_wreg(&hc_regs->hcint, ~hcintmsk.d32); + + /* + * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR + * even if the channel was already halted for some other + * reason. + */ + _ifxhc->halt_status = _halt_status; + } + + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + if (hcchar.b.chen == 0) + { + /* + * The channel is either already halted or it hasn't + * started yet. In DMA mode, the transfer may halt if + * it finishes normally or a condition occurs that + * requires driver intervention. Don't want to halt + * the channel again. In either Slave or DMA mode, + * it's possible that the transfer has been assigned + * to a channel, but not started yet when an URB is + * dequeued. Don't want to halt a channel that hasn't + * started yet. + */ + _ifxhc->phase=HC_IDLE; + return -1; + } + + if (_ifxhc->phase==HC_STOPPING) + { + /* + * A halt has already been issued for this channel. This might + * happen when a transfer is aborted by a higher level in + * the stack. + */ + #ifdef __DEBUG__ + IFX_PRINT("*** %s: Channel %d, double halt a channel***\n", + __func__, _ifxhc->hc_num); + #endif + return 0; + } + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + hcchar.b.chen = 1; + hcchar.b.chdis = 1; + + ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); + + _ifxhc->halt_status = _halt_status; + _ifxhc->phase=HC_STOPPING; + + IFX_DEBUGPL(DBG_HCDV, "%s: Channel %d\n" , __func__, _ifxhc->hc_num); + IFX_DEBUGPL(DBG_HCDV, " hcchar: 0x%08x\n" , hcchar.d32); + IFX_DEBUGPL(DBG_HCDV, " halt_status: %d\n" , _ifxhc->halt_status); + + return 0; +} + +/*! + \brief Clears a host channel. + */ +void ifxhcd_hc_cleanup(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc) +{ + ifxusb_hc_regs_t *hc_regs; + + _ifxhc->phase=HC_IDLE; + _ifxhc->epqh=0; + + /* + * Clear channel interrupt enables and any unhandled channel interrupt + * conditions. + */ + hc_regs = _core_if->hc_regs[_ifxhc->hc_num]; + ifxusb_wreg(&hc_regs->hcintmsk, 0); + ifxusb_wreg(&hc_regs->hcint, 0xFFFFFFFF); + + #ifdef __DEBUG__ + { + hcchar_data_t hcchar; + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + if (hcchar.b.chdis) + IFX_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n", __func__, _ifxhc->hc_num, hcchar.d32); + } + #endif +} + + + + + +#ifdef __DEBUG__ + static void dump_urb_info(struct urb *_urb, char* _fn_name) + { + IFX_PRINT("%s, urb %p\n" , _fn_name, _urb); + IFX_PRINT(" Device address: %d\n", usb_pipedevice(_urb->pipe)); + IFX_PRINT(" Endpoint: %d, %s\n" , usb_pipeendpoint(_urb->pipe), + (usb_pipein(_urb->pipe) ? "IN" : "OUT")); + IFX_PRINT(" Endpoint type: %s\n", + ({ char *pipetype; + switch (usb_pipetype(_urb->pipe)) { + case PIPE_CONTROL: pipetype = "CONTROL"; break; + case PIPE_BULK: pipetype = "BULK"; break; + case PIPE_INTERRUPT: pipetype = "INTERRUPT"; break; + case PIPE_ISOCHRONOUS: pipetype = "ISOCHRONOUS"; break; + default: pipetype = "UNKNOWN"; break; + }; + pipetype; + })); + IFX_PRINT(" Speed: %s\n", + ({ char *speed; + switch (_urb->dev->speed) { + case USB_SPEED_HIGH: speed = "HIGH"; break; + case USB_SPEED_FULL: speed = "FULL"; break; + case USB_SPEED_LOW: speed = "LOW"; break; + default: speed = "UNKNOWN"; break; + }; + speed; + })); + IFX_PRINT(" Max packet size: %d\n", + usb_maxpacket(_urb->dev, _urb->pipe, usb_pipeout(_urb->pipe))); + IFX_PRINT(" Data buffer length: %d\n", _urb->transfer_buffer_length); + IFX_PRINT(" Transfer buffer: %p, Transfer DMA: %p\n", + _urb->transfer_buffer, (void *)_urb->transfer_dma); + IFX_PRINT(" Setup buffer: %p, Setup DMA: %p\n", + _urb->setup_packet, (void *)_urb->setup_dma); + IFX_PRINT(" Interval: %d\n", _urb->interval); + if (usb_pipetype(_urb->pipe) == PIPE_ISOCHRONOUS) + { + int i; + for (i = 0; i < _urb->number_of_packets; i++) + { + IFX_PRINT(" ISO Desc %d:\n", i); + IFX_PRINT(" offset: %d, length %d\n", + _urb->iso_frame_desc[i].offset, + _urb->iso_frame_desc[i].length); + } + } + } + +#if 0 + static void dump_channel_info(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh) + { + if (_epqh->hc != NULL) + { + ifxhcd_hc_t *hc = _epqh->hc; + struct list_head *item; + ifxhcd_epqh_t *epqh_item; + + ifxusb_hc_regs_t *hc_regs; + + hcchar_data_t hcchar; + hcsplt_data_t hcsplt; + hctsiz_data_t hctsiz; + uint32_t hcdma; + + hc_regs = _ifxhcd->core_if.hc_regs[hc->hc_num]; + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + hcsplt.d32 = ifxusb_rreg(&hc_regs->hcsplt); + hctsiz.d32 = ifxusb_rreg(&hc_regs->hctsiz); + hcdma = ifxusb_rreg(&hc_regs->hcdma); + + IFX_PRINT(" Assigned to channel %d:\n" , hc->hc_num); + IFX_PRINT(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32); + IFX_PRINT(" hctsiz 0x%08x, hcdma 0x%08x\n" , hctsiz.d32, hcdma); + IFX_PRINT(" dev_addr: %d, ep_num: %d, is_in: %d\n", + hc->dev_addr, hc->ep_num, hc->is_in); + IFX_PRINT(" ep_type: %d\n" , hc->ep_type); + IFX_PRINT(" max_packet_size: %d\n", hc->mps); + IFX_PRINT(" data_pid_start: %d\n" , hc->data_pid_start); + IFX_PRINT(" halt_status: %d\n" , hc->halt_status); + IFX_PRINT(" xfer_buff: %p\n" , hc->xfer_buff); + IFX_PRINT(" xfer_len: %d\n" , hc->xfer_len); + IFX_PRINT(" epqh: %p\n" , hc->epqh); + IFX_PRINT(" NP :\n"); + list_for_each(item, &_ifxhcd->epqh_list_np) + { + epqh_item = list_entry(item, ifxhcd_epqh_t, ql); + IFX_PRINT(" %p\n", epqh_item); + } + IFX_PRINT(" INTR :\n"); + list_for_each(item, &_ifxhcd->epqh_list_intr) + { + epqh_item = list_entry(item, ifxhcd_epqh_t, ql); + IFX_PRINT(" %p\n", epqh_item); + } + #ifdef __EN_ISOC__ + IFX_PRINT(" ISOC:\n"); + list_for_each(item, &_ifxhcd->epqh_list_isoc) + { + epqh_item = list_entry(item, ifxhcd_epqh_t, ql); + IFX_PRINT(" %p\n", epqh_item); + } + #endif + } + } +#endif +#endif //__DEBUG__ + + +/*! + \brief This function writes a packet into the Tx FIFO associated with the Host + Channel. For a channel associated with a non-periodic EP, the non-periodic + Tx FIFO is written. For a channel associated with a periodic EP, the + periodic Tx FIFO is written. This function should only be called in Slave + mode. + + Upon return the xfer_buff and xfer_count fields in _hc are incremented by + then number of bytes written to the Tx FIFO. + */ + +#ifdef __ENABLE_DUMP__ + void ifxhcd_dump_state(ifxhcd_hcd_t *_ifxhcd) + { + int num_channels; + int i; + num_channels = _ifxhcd->core_if.params.host_channels; + IFX_PRINT("\n"); + IFX_PRINT("************************************************************\n"); + IFX_PRINT("HCD State:\n"); + IFX_PRINT(" Num channels: %d\n", num_channels); + for (i = 0; i < num_channels; i++) { + ifxhcd_hc_t *hc = &_ifxhcd->ifxhc[i]; + IFX_PRINT(" Channel %d:\n", hc->hc_num); + IFX_PRINT(" dev_addr: %d, ep_num: %d, ep_is_in: %d\n", + hc->dev_addr, hc->ep_num, hc->is_in); + IFX_PRINT(" speed: %d\n" , hc->speed); + IFX_PRINT(" ep_type: %d\n" , hc->ep_type); + IFX_PRINT(" mps: %d\n", hc->mps); + IFX_PRINT(" data_pid_start: %d\n" , hc->data_pid_start); + IFX_PRINT(" xfer_buff: %p\n" , hc->xfer_buff); + IFX_PRINT(" xfer_len: %d\n" , hc->xfer_len); + IFX_PRINT(" xfer_count: %d\n" , hc->xfer_count); + IFX_PRINT(" halt_status: %d\n" , hc->halt_status); + IFX_PRINT(" split: %d\n" , hc->split); + IFX_PRINT(" hub_addr: %d\n" , hc->hub_addr); + IFX_PRINT(" port_addr: %d\n" , hc->port_addr); + #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) + IFX_PRINT(" isoc_xact_pos: %d\n" , hc->isoc_xact_pos); + #endif + + IFX_PRINT(" epqh: %p\n" , hc->epqh); + IFX_PRINT(" short_rw: %d\n" , hc->short_rw); + IFX_PRINT(" control_phase: %d\n" , hc->control_phase); + if(hc->epqh) + { + IFX_PRINT(" do_ping: %d\n" , hc->epqh->do_ping); + } + IFX_PRINT(" start_pkt_count: %d\n" , hc->start_pkt_count); + } + IFX_PRINT("************************************************************\n"); + IFX_PRINT("\n"); + } +#endif //__ENABLE_DUMP__ + diff --git a/package/platform/lantiq/ltq-hcd/src/ifxhcd.h b/package/platform/lantiq/ltq-hcd/src/ifxhcd.h new file mode 100644 index 0000000000..243c5f57e3 --- /dev/null +++ b/package/platform/lantiq/ltq-hcd/src/ifxhcd.h @@ -0,0 +1,758 @@ +/***************************************************************************** + ** FILE NAME : ifxhcd.h + ** PROJECT : IFX USB sub-system V3 + ** MODULES : IFX USB sub-system Host and Device driver + ** SRC VERSION : 3.2 + ** DATE : 1/Jan/2011 + ** AUTHOR : Chen, Howard + ** DESCRIPTION : This file contains the structures, constants, and interfaces for + ** the Host Contoller Driver (HCD). + ** + ** The Host Controller Driver (HCD) is responsible for translating requests + ** from the USB Driver into the appropriate actions on the IFXUSB controller. + ** It isolates the USBD from the specifics of the controller by providing an + ** API to the USBD. + ** FUNCTIONS : + ** COMPILER : gcc + ** REFERENCE : Synopsys DWC-OTG Driver 2.7 + ** COPYRIGHT : Copyright (c) 2010 + ** LANTIQ DEUTSCHLAND GMBH, + ** Am Campeon 3, 85579 Neubiberg, Germany + ** + ** This program is free software; you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation; either version 2 of the License, or + ** (at your option) any later version. + ** + ** Version Control Section ** + ** $Author$ + ** $Date$ + ** $Revisions$ + ** $Log$ Revision history + *****************************************************************************/ + +/* + * This file contains code fragments from Synopsys HS OTG Linux Software Driver. + * For this code the following notice is applicable: + * + * ========================================================================== + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +/*! + \defgroup IFXUSB_HCD HCD Interface + \ingroup IFXUSB_DRIVER_V3 + \brief The Host Controller Driver (HCD) is responsible for translating requests + from the USB Driver into the appropriate actions on the IFXUSB controller. + It isolates the USBD from the specifics of the controller by providing an + API to the USBD. + */ + + +/*! + \file ifxhcd.h + \ingroup IFXUSB_DRIVER_V3 + \brief This file contains the structures, constants, and interfaces for + the Host Contoller Driver (HCD). + */ + +#if !defined(__IFXHCD_H__) +#define __IFXHCD_H__ + + +#define __STRICT_ORDER__ + + +#include +#include + +#include + +#include "ifxusb_cif.h" +#include "ifxusb_plat.h" + + +#undef __INNAKSTOP__ +#if !defined(__INNAKSTOP__) && defined(__INNAKSTOP_CTRL__) + #define __INNAKSTOP__ 1 +#endif +#if !defined(__INNAKSTOP__) && defined(__INNAKSTOP_BULK__) + #define __INNAKSTOP__ 1 +#endif + +#undef __PINGSTOP__ +#if !defined(__PINGSTOP__) && defined(__PINGSTOP_CTRL__) + #define __PINGSTOP__ 1 +#endif +#if !defined(__PINGSTOP__) && defined(__PINGSTOP_BULK__) + #define __PINGSTOP__ 1 +#endif + +#undef __NAKSTOP__ +#if defined(__INNAKSTOP__) || defined(__PINGSTOP__) + #define __NAKSTOP__ 1 +#endif + + +/* Phases for control transfers.*/ +typedef enum ifxhcd_epqh_phase { + EPQH_IDLE=0, + EPQH_DISABLING, +// EPQH_COMPLETING, + EPQH_STDBY, + EPQH_READY, + EPQH_ACTIVE +} ifxhcd_epqh_phase_e; + +/* Phases for control transfers.*/ +typedef enum ifxhcd_urbd_phase { + URBD_IDLE=0, + URBD_ACTIVE, + URBD_STARTING, + URBD_STARTED, + URBD_FINISHING, //URB_Complete already scheduled + URBD_COMPLETING, //To URB_Complete, it's normal finish + URBD_DEQUEUEING, //To URB_Complete, it's abnormal finish +} ifxhcd_urbd_phase_e; + +/* Phases for control transfers.*/ +typedef enum ifxhcd_hc_phase { + HC_IDLE=0, + HC_ASSIGNED, + HC_WAITING, + HC_STARTING, + HC_STARTED, + HC_STOPPING, + HC_STOPPED, +} ifxhcd_hc_phase_e; + +/*! + \addtogroup IFXUSB_HCD + */ +/*@{*/ + +/*! \typedef ifxhcd_control_phase_e + \brief Phases for control transfers. +*/ + +typedef enum ifxhcd_control_phase { + IFXHCD_CONTROL_SETUP, + IFXHCD_CONTROL_DATA, + IFXHCD_CONTROL_STATUS +} ifxhcd_control_phase_e; + +/*! \typedef ifxhcd_halt_status_e + \brief Reasons for halting a host channel. +*/ +typedef enum ifxhcd_halt_status +{ + HC_XFER_NO_HALT_STATUS, // Initial + HC_XFER_COMPLETE, // Xact complete without error, upward + HC_XFER_URB_COMPLETE, // Xfer complete without error, short upward + HC_XFER_STALL, // HC stopped abnormally, upward/downward + HC_XFER_XACT_ERR, // HC stopped abnormally, upward + HC_XFER_FRAME_OVERRUN, // HC stopped abnormally, upward + HC_XFER_BABBLE_ERR, // HC stopped abnormally, upward + HC_XFER_AHB_ERR, // HC stopped abnormally, upward + HC_XFER_DATA_TOGGLE_ERR, + HC_XFER_URB_DEQUEUE, // HC stopper manually, downward + HC_XFER_NO_URB, // HC stopper manually, downward + HC_XFER_NO_EPQH, // HC stopper manually, downward + #ifdef __NAKSTOP__ + HC_XFER_NAK, // HC stopped by nak monitor, downward + #endif + #if defined(__INTRNAKRETRY__) || defined(__INTRINCRETRY__) + HC_XFER_INTR_NAK_RETRY, // HC stopped by nak monitor, downward + #endif +} ifxhcd_halt_status_e; + +struct ifxhcd_urbd; +struct ifxhcd_hc ; +struct ifxhcd_epqh ; +struct ifxhcd_hcd; + +/*! typedef ifxhcd_urbd_t + \brief A URB Descriptor (URBD) holds the state of a bulk, control, + interrupt, or isochronous transfer. A single URBD is created for each URB + (of one of these types) submitted to the HCD. The transfer associated with + a URBD may require one or multiple transactions. + + A URBD is linked to a EP Queue Head, which is entered in either the + isoc, intr or non-periodic schedule for execution. When a URBD is chosen for + execution, some or all of its transactions may be executed. After + execution, the state of the URBD is updated. The URBD may be retired if all + its transactions are complete or if an error occurred. Otherwise, it + remains in the schedule so more transactions can be executed later. + */ +typedef struct ifxhcd_urbd { + ifxhcd_urbd_phase_e phase; + struct list_head ql; // Hook for EPQH->urbd_list + struct urb *urb; /*!< URB for this transfer */ + //struct urb { + // struct list_head urb_list; + // struct list_head anchor_list; + // struct usb_anchor * anchor; + // struct usb_device * dev; + // struct usb_host_endpoint * ep; + // unsigned int pipe; + // int status; + // unsigned int transfer_flags; + // void * transfer_buffer; + // dma_addr_t transfer_dma; + // u32 transfer_buffer_length; + // u32 actual_length; + // unsigned char * setup_packet; + // dma_addr_t setup_dma; + // int start_frame; + // int number_of_packets; + // int interval; + // int error_count; + // void * context; + // usb_complete_t complete; + // struct usb_iso_packet_descriptor iso_frame_desc[0]; + //}; + //urb_list For use by current owner of the URB. + //anchor_list membership in the list of an anchor + //anchor to anchor URBs to a common mooring + //dev Identifies the USB device to perform the request. + //ep Points to the endpoint's data structure. Will + // eventually replace pipe. + //pipe Holds endpoint number, direction, type, and more. + // Create these values with the eight macros available; u + // sb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is + // "ctrl", "bulk", "int" or "iso". For example + // usb_sndbulkpipe or usb_rcvintpipe. Endpoint numbers + // range from zero to fifteen. Note that "in" endpoint two + // is a different endpoint (and pipe) from "out" endpoint + // two. The current configuration controls the existence, + // type, and maximum packet size of any given endpoint. + //status This is read in non-iso completion functions to get + // the status of the particular request. ISO requests + // only use it to tell whether the URB was unlinked; + // detailed status for each frame is in the fields of + // the iso_frame-desc. + //transfer_flags A variety of flags may be used to affect how URB + // submission, unlinking, or operation are handled. + // Different kinds of URB can use different flags. + // URB_SHORT_NOT_OK + // URB_ISO_ASAP + // URB_NO_TRANSFER_DMA_MAP + // URB_NO_SETUP_DMA_MAP + // URB_NO_FSBR + // URB_ZERO_PACKET + // URB_NO_INTERRUPT + //transfer_buffer This identifies the buffer to (or from) which the I/O + // request will be performed (unless URB_NO_TRANSFER_DMA_MAP + // is set). This buffer must be suitable for DMA; allocate it + // with kmalloc or equivalent. For transfers to "in" + // endpoints, contents of this buffer will be modified. This + // buffer is used for the data stage of control transfers. + //transfer_dma When transfer_flags includes URB_NO_TRANSFER_DMA_MAP, the + // device driver is saying that it provided this DMA address, + // which the host controller driver should use in preference + // to the transfer_buffer. + //transfer_buffer_length How big is transfer_buffer. The transfer may be broken + // up into chunks according to the current maximum packet size + // for the endpoint, which is a function of the configuration + // and is encoded in the pipe. When the length is zero, neither + // transfer_buffer nor transfer_dma is used. + //actual_length This is read in non-iso completion functions, and it tells + // how many bytes (out of transfer_buffer_length) were transferred. + // It will normally be the same as requested, unless either an error + // was reported or a short read was performed. The URB_SHORT_NOT_OK + // transfer flag may be used to make such short reads be reported + // as errors. + //setup_packet Only used for control transfers, this points to eight bytes of + // setup data. Control transfers always start by sending this data + // to the device. Then transfer_buffer is read or written, if needed. + //setup_dma For control transfers with URB_NO_SETUP_DMA_MAP set, the device + // driver has provided this DMA address for the setup packet. The + // host controller driver should use this in preference to setup_packet. + //start_frame Returns the initial frame for isochronous transfers. + //number_of_packets Lists the number of ISO transfer buffers. + //interval Specifies the polling interval for interrupt or isochronous transfers. + // The units are frames (milliseconds) for for full and low speed devices, + // and microframes (1/8 millisecond) for highspeed ones. + //error_count Returns the number of ISO transfers that reported errors. + //context For use in completion functions. This normally points to request-specific + // driver context. + //complete Completion handler. This URB is passed as the parameter to the completion + // function. The completion function may then do what it likes with the URB, + // including resubmitting or freeing it. + //iso_frame_desc[0] Used to provide arrays of ISO transfer buffers and to collect the transfer + // status for each buffer. + + struct ifxhcd_epqh *epqh; + // Actual data portion, not SETUP or STATUS in case of CTRL XFER + // DMA adjusted + uint8_t *setup_buff; /*!< Pointer to the entire transfer buffer. (CPU accessable)*/ + uint8_t *xfer_buff; /*!< Pointer to the entire transfer buffer. (CPU accessable)*/ + uint32_t xfer_len; /*!< Total number of bytes to transfer in this xfer. */ + + #if defined(__UNALIGNED_BUF_ADJ__) +// uint8_t using_aligned_setup; + uint8_t *aligned_setup; +// uint8_t using_aligned_buf; + uint8_t *aligned_buf; + unsigned aligned_buf_len : 19; + #endif + #if defined(__UNALIGNED_BUF_ADJ__) || defined(__UNALIGNED_BUF_CHK__) + unsigned aligned_checked : 1; + #endif + unsigned is_in :1; + #ifndef __STRICT_ORDER__ + struct tasklet_struct complete_urb_sub; + #endif + + // For ALL XFER + uint8_t error_count; /*!< Holds the number of bus errors that have occurred for a transaction + within this transfer. + */ + // For ISOC XFER only + #ifdef __EN_ISOC__ + int isoc_frame_index; /*!< Index of the next frame descriptor for an isochronous transfer. A + frame descriptor describes the buffer position and length of the + data to be transferred in the next scheduled (micro)frame of an + isochronous transfer. It also holds status for that transaction. + The frame index starts at 0. + */ + #endif + int status; +} ifxhcd_urbd_t; + +/*! typedef ifxhcd_epqh_t + \brief A EP Queue Head (EPQH) holds the static characteristics of an endpoint and + maintains a list of transfers (URBDs) for that endpoint. A EPQH structure may + be entered in either the isoc, intr or non-periodic schedule. + */ + +typedef struct ifxhcd_epqh { + struct ifxhcd_hcd *ifxhcd; + struct usb_host_endpoint *sysep; + uint8_t devno; + + ifxhcd_epqh_phase_e phase; + struct list_head ql_all; + struct list_head ql; // Hook for EP Queues + struct list_head urbd_list; /*!< List of URBDs for this EPQH. */ + #ifdef __STRICT_ORDER__ + struct list_head release_list; + struct tasklet_struct complete_urb_sub; + #endif + struct ifxhcd_hc *hc; /*!< Host channel currently processing transfers for this EPQH. */ + struct ifxhcd_urbd *urbd; /*!< URBD currently assigned to a host channel for this EPQH. */ + uint8_t ep_type; /*!< Endpoint type. One of the following values: + - IFXUSB_EP_TYPE_CTRL + - IFXUSB_EP_TYPE_ISOC + - IFXUSB_EP_TYPE_BULK + - IFXUSB_EP_TYPE_INTR + */ + uint16_t mps; /*!< wMaxPacketSize Field of Endpoint Descriptor. */ + #ifdef __EPQD_DESTROY_TIMEOUT__ + struct timer_list destroy_timer; + #endif + + unsigned need_split : 1 ; + unsigned do_ping : 1 ; /*!< Set to 1 to indicate that a PING request should be issued on this + channel. If 0, process normally. + */ + unsigned pause : 1; + unsigned period_do : 1; + uint16_t interval; /*!< Interval between transfers in (micro)frames. (for INTR)*/ + uint16_t period_counter; /*!< Interval between transfers in (micro)frames. */ + + #ifdef __EN_ISOC__ + struct tasklet_struct tasklet_next_isoc; + uint8_t isoc_now; + uint32_t isoc_start_frame; + // For SPLITed ISOC XFER only + #ifdef __EN_ISOC_SPLIT__ + uint8_t isoc_split_pos; /*!< Position of the ISOC split on full/low speed */ + uint16_t isoc_split_offset;/*!< Position of the ISOC split in the buffer for the current frame */ + #endif + #endif + spinlock_t urbd_list_lock; + int urbd_count; +} ifxhcd_epqh_t; + + +/*! typedef ifxhcd_hc_t + \brief Host channel descriptor. This structure represents the state of a single + host channel when acting in host mode. It contains the data items needed to + transfer packets to an endpoint via a host channel. + */ +typedef struct ifxhcd_hc +{ + struct ifxhcd_epqh *epqh ; /*!< EP Queue Head for the transfer being processed by this channel. */ + uint8_t hc_num ; /*!< Host channel number used for register address lookup */ + uint8_t *xfer_buff ; /*!< Pointer to the entire transfer buffer. */ + uint32_t xfer_count ; /*!< Number of bytes transferred so far. The offset of the begin of the buf */ + uint32_t xfer_len ; /*!< Total number of bytes to transfer in this xfer. */ + uint16_t start_pkt_count ; /*!< Packet count at start of transfer. Used to calculate the actual xfer size*/ + ifxhcd_halt_status_e halt_status; /*!< Reason for halting the host channel. */ + ifxhcd_hc_phase_e phase; + + unsigned dev_addr : 7; /*!< Device to access */ + unsigned ep_num : 4; /*!< EP to access */ + unsigned is_in : 1; /*!< EP direction. 0: OUT, 1: IN */ + unsigned speed : 2; /*!< EP speed. */ + unsigned ep_type : 2; /*!< Endpoint type. */ + unsigned mps :11; /*!< Max packet size in bytes */ + unsigned data_pid_start : 2; /*!< PID for initial transaction. */ + unsigned short_rw : 1; /*!< When Tx, means termination needed. + When Rx, indicate Short Read */ + /* Split settings for the host channel */ + unsigned split : 2; /*!< Split: 0-Non Split, 1-SSPLIT, 2&3 CSPLIT */ + + unsigned sof_delay :16; + unsigned erron : 1; + + #ifdef __NAKSTOP__ + unsigned stop_on : 1; +// unsigned wait_for_sof_quick : 1; + #endif + + ifxhcd_control_phase_e control_phase; /*!< Current phase for control transfers (Setup, Data, or Status). */ + uint32_t ssplit_out_xfer_count; /*!< How many bytes transferred during SSPLIT OUT */ + #ifdef __DEBUG__ + uint32_t start_hcchar_val; + #endif + uint32_t hcchar; + + /* Split settings for the host channel */ + uint8_t hub_addr; /*!< Address of high speed hub */ + uint8_t port_addr; /*!< Port of the low/full speed device */ + #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) + uint8_t isoc_xact_pos; /*!< Split transaction position */ + #endif +} ifxhcd_hc_t; + + +/*! typedef ifxhcd_hcd_t + \brief This structure holds the state of the HCD, including the non-periodic and + periodic schedules. + */ +typedef struct ifxhcd_hcd +{ + struct device *dev; + struct hc_driver hc_driver; + ifxusb_core_if_t core_if; /*!< Pointer to the core interface structure. */ + struct usb_hcd *syshcd; + + volatile union + { + uint32_t d32; + struct + { + unsigned port_connect_status_change : 1; + unsigned port_connect_status : 1; + unsigned port_reset_change : 1; + unsigned port_enable_change : 1; + unsigned port_suspend_change : 1; + unsigned port_over_current_change : 1; + unsigned reserved : 27; + } b; + } flags; /*!< Internal HCD Flags */ + + struct ifxhcd_hc ifxhc[MAX_EPS_CHANNELS]; /*!< Array of pointers to the host channel descriptors. Allows accessing + a host channel descriptor given the host channel number. This is + useful in interrupt handlers. + */ + uint8_t *status_buf; /*!< Buffer to use for any data received during the status phase of a + control transfer. Normally no data is transferred during the status + phase. This buffer is used as a bit bucket. + */ + #define IFXHCD_STATUS_BUF_SIZE 64 /*!< buffer size of status phase in CTRL xfer */ + + struct list_head epqh_list_all; + struct list_head epqh_list_np; + struct list_head epqh_list_intr; + #ifdef __EN_ISOC__ + struct list_head epqh_list_isoc; + #endif + + uint32_t lastframe; + + uint16_t pkt_remaining; + uint16_t pkt_remaining_reload; + uint16_t pkt_remaining_reload_hs; + uint16_t pkt_remaining_reload_fs; + uint16_t pkt_remaining_reload_ls; + #define PKT_REMAINING_RELOAD_HS 88 + #define PKT_REMAINING_RELOAD_FS 10 + #define PKT_REMAINING_RELOAD_LS 20 + #ifdef __EN_ISOC__ + uint8_t isoc_ep_count; + #endif + + spinlock_t epqh_list_lock; + spinlock_t epqh_list_all_lock; + + struct timer_list host_probe_timer; + struct timer_list autoprobe_timer; + + unsigned power_status; + int probe_sec; + int autoprobe_sec; + #ifdef __DYN_SOF_INTR__ + uint32_t dyn_sof_count; + #define DYN_SOF_COUNT_DEF 40000 + #endif + struct tasklet_struct tasklet_select_eps; /*!< Tasket to do a reset */ + struct tasklet_struct tasklet_free_epqh_list ; /*!< Tasket to do a reset */ + unsigned disconnecting : 1 ; + + uint8_t pkt_count_limit_bo; + uint8_t pkt_count_limit_bi; +} ifxhcd_hcd_t; + +/* Gets the ifxhcd_hcd from a struct usb_hcd */ +static inline ifxhcd_hcd_t *syshcd_to_ifxhcd(struct usb_hcd *syshcd) +{ + return (ifxhcd_hcd_t *)(syshcd->hcd_priv[0]); +} + +/* Gets the struct usb_hcd that contains a ifxhcd_hcd_t. */ +static inline struct usb_hcd *ifxhcd_to_syshcd(ifxhcd_hcd_t *ifxhcd) +{ + return (struct usb_hcd *)(ifxhcd->syshcd); +} + + +extern ifxhcd_epqh_t * sysep_to_epqh(ifxhcd_hcd_t *_ifxhcd, struct usb_host_endpoint *_sysep); + +/* HCD Create/Destroy Functions */ + extern int ifxhcd_init (ifxhcd_hcd_t *_ifxhcd); + extern void ifxhcd_remove(ifxhcd_hcd_t *_ifxhcd); + +/*Linux HC Driver API Functions */ + +extern int ifxhcd_start(struct usb_hcd *hcd); +extern void ifxhcd_stop (struct usb_hcd *hcd); +extern int ifxhcd_get_frame_number(struct usb_hcd *hcd); + + +/*! + \brief This function does the setup for a data transfer for a host channel and + starts the transfer. May be called in either Slave mode or DMA mode. In + Slave mode, the caller must ensure that there is sufficient space in the + request queue and Tx Data FIFO. + + For an OUT transfer in Slave mode, it loads a data packet into the + appropriate FIFO. If necessary, additional data packets will be loaded in + the Host ISR. + + For an IN transfer in Slave mode, a data packet is requested. The data + packets are unloaded from the Rx FIFO in the Host ISR. If necessary, + additional data packets are requested in the Host ISR. + + For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ + register along with a packet count of 1 and the channel is enabled. This + causes a single PING transaction to occur. Other fields in HCTSIZ are + simply set to 0 since no data transfer occurs in this case. + + For a PING transfer in DMA mode, the HCTSIZ register is initialized with + all the information required to perform the subsequent data transfer. In + addition, the Do Ping bit is set in the HCTSIZ register. In this case, the + controller performs the entire PING protocol, then starts the data + transfer. + + @param _ifxhc Information needed to initialize the host channel. The xfer_len + value may be reduced to accommodate the max widths of the XferSize and + PktCnt fields in the HCTSIZn register. The multi_count value may be changed + to reflect the final xfer_len value. + */ +extern void ifxhcd_hc_start(ifxhcd_hcd_t *_ifxhcd, ifxhcd_hc_t *_ifxhc); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) +extern int ifxhcd_urb_enqueue(struct usb_hcd *_syshcd, struct usb_host_endpoint *_sysep, struct urb *_urb, gfp_t mem_flags); +extern int ifxhcd_urb_dequeue(struct usb_hcd *_syshcd, struct urb *_urb); +#else +extern int ifxhcd_urb_enqueue(struct usb_hcd *_syshcd, struct urb *_urb, gfp_t mem_flags); +extern int ifxhcd_urb_dequeue(struct usb_hcd *_syshcd, struct urb *_urb, int status); +#endif +extern irqreturn_t ifxhcd_irq(struct usb_hcd *_syshcd); + +extern void ifxhcd_endpoint_disable(struct usb_hcd *_syshcd, struct usb_host_endpoint *_sysep); + +extern int ifxhcd_hub_status_data(struct usb_hcd *_syshcd, char *_buf); +extern int ifxhcd_hub_control( struct usb_hcd *_syshcd, + u16 _typeReq, + u16 _wValue, + u16 _wIndex, + char *_buf, + u16 _wLength); + +/*@}*/ + +/*! \brief Transaction Execution Functions */ +/*@{*/ +extern void ifxhcd_complete_urb (ifxhcd_hcd_t *_ifxhcd, ifxhcd_urbd_t *_urbd, int _status); + +/*! + \brief Clears the transfer state for a host channel. This function is normally + called after a transfer is done and the host channel is being released. + */ +extern void ifxhcd_hc_cleanup(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc); + +/*! + \brief Attempts to halt a host channel. This function should only be called in + Slave mode or to abort a transfer in either Slave mode or DMA mode. Under + normal circumstances in DMA mode, the controller halts the channel when the + transfer is complete or a condition occurs that requires application + intervention. + + In DMA mode, always sets the Channel Enable and Channel Disable bits of the + HCCHARn register. The controller ensures there is space in the request + queue before submitting the halt request. + + Some time may elapse before the core flushes any posted requests for this + host channel and halts. The Channel Halted interrupt handler completes the + deactivation of the host channel. + */ +extern int ifxhcd_hc_halt(ifxusb_core_if_t *_core_if, + ifxhcd_hc_t *_ifxhc, + ifxhcd_halt_status_e _halt_status); + +/*! + \brief Prepares a host channel for transferring packets to/from a specific + endpoint. The HCCHARn register is set up with the characteristics specified + in _ifxhc. Host channel interrupts that may need to be serviced while this + transfer is in progress are enabled. + */ +extern void ifxhcd_hc_init(ifxusb_core_if_t *_core_if, ifxhcd_hc_t *_ifxhc); + +/*! + \brief This function is called to handle the disconnection of host port. + */ +int32_t ifxhcd_disconnect(ifxhcd_hcd_t *_ifxhcd); +/*@}*/ + +/*! \brief Interrupt Handler Functions */ +/*@{*/ +extern irqreturn_t ifxhcd_oc_irq(int _irq, void *_dev); + +extern int32_t ifxhcd_handle_oc_intr(ifxhcd_hcd_t *_ifxhcd); +extern int32_t ifxhcd_handle_intr (ifxhcd_hcd_t *_ifxhcd); +/*@}*/ + + +/*! \brief Schedule Queue Functions */ +/*@{*/ +extern void ifxhcd_epqh_free (ifxhcd_epqh_t *_epqh); +extern void select_eps (ifxhcd_hcd_t *_ifxhcd); +extern void ifxhcd_epqh_idle(ifxhcd_epqh_t *_epqh); +extern void ifxhcd_epqh_idle_periodic(ifxhcd_epqh_t *_epqh); +extern ifxhcd_epqh_t *ifxhcd_urbd_create (ifxhcd_hcd_t *_ifxhcd,struct urb *_urb); +/*@}*/ + +/*! \brief Gets the usb_host_endpoint associated with an URB. */ +static inline struct usb_host_endpoint *ifxhcd_urb_to_endpoint(struct urb *_urb) +{ + struct usb_device *dev = _urb->dev; + int ep_num = usb_pipeendpoint(_urb->pipe); + + return (usb_pipein(_urb->pipe))?(dev->ep_in[ep_num]):(dev->ep_out[ep_num]); +} + +/*! + * \brief Gets the endpoint number from a _bEndpointAddress argument. The endpoint is + * qualified with its direction (possible 32 endpoints per device). + */ +#define ifxhcd_ep_addr_to_endpoint(_bEndpointAddress_) ((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) | \ + ((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4) + + + +/*! Internal debug function */ +void ifxhcd_dump_state(ifxhcd_hcd_t *_ifxhcd); + +/*@}*//*IFXUSB_HCD*/ + +extern struct usb_device *usb_alloc_dev (struct usb_device *parent, struct usb_bus *, unsigned port); +extern int usb_add_hcd (struct usb_hcd *syshcd, unsigned int irqnum, unsigned long irqflags); +extern void usb_remove_hcd (struct usb_hcd *syshcd); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) +extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, struct device *dev, char *bus_name); +#else +extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, struct device *dev, const char *bus_name); +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32) +extern void usb_hcd_giveback_urb (struct usb_hcd *syshcd, struct urb *urb); +#else +extern void usb_hcd_giveback_urb (struct usb_hcd *syshcd, struct urb *urb,int status); +#endif + +extern void usb_put_hcd (struct usb_hcd *syshcd); +extern long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount); +extern char *syserr(int errno); + + + +static inline void INIT_EPQH_LIST_ALL(ifxhcd_hcd_t *_ifxhcd) +{ + spin_lock_init(&_ifxhcd->epqh_list_all_lock); +} +static inline void LOCK_EPQH_LIST_ALL(ifxhcd_hcd_t *_ifxhcd) +{ + spin_lock(&_ifxhcd->epqh_list_all_lock); +} +static inline void UNLOCK_EPQH_LIST_ALL(ifxhcd_hcd_t *_ifxhcd) +{ + spin_unlock(&_ifxhcd->epqh_list_all_lock); +} + +static inline void INIT_EPQH_LIST(ifxhcd_hcd_t *_ifxhcd) +{ + spin_lock_init(&_ifxhcd->epqh_list_lock); +} +static inline void LOCK_EPQH_LIST(ifxhcd_hcd_t *_ifxhcd) +{ + spin_lock(&_ifxhcd->epqh_list_lock); +} +static inline void UNLOCK_EPQH_LIST(ifxhcd_hcd_t *_ifxhcd) +{ + spin_unlock(&_ifxhcd->epqh_list_lock); +} + +static inline void INIT_URBD_LIST(ifxhcd_epqh_t *_epqh) +{ + spin_lock_init(&_epqh->urbd_list_lock); +} +static inline void LOCK_URBD_LIST(ifxhcd_epqh_t *_epqh) +{ + spin_lock(&_epqh->urbd_list_lock); +} +static inline void UNLOCK_URBD_LIST(ifxhcd_epqh_t *_epqh) +{ + spin_unlock(&_epqh->urbd_list_lock); +} + +#endif // __IFXHCD_H__ + diff --git a/package/platform/lantiq/ltq-hcd/src/ifxhcd_es.c b/package/platform/lantiq/ltq-hcd/src/ifxhcd_es.c new file mode 100644 index 0000000000..a7d18dd7fe --- /dev/null +++ b/package/platform/lantiq/ltq-hcd/src/ifxhcd_es.c @@ -0,0 +1,599 @@ +/***************************************************************************** + ** FILE NAME : ifxhcd_es.c + ** PROJECT : IFX USB sub-system V3 + ** MODULES : IFX USB sub-system Host and Device driver + ** SRC VERSION : 1.0 + ** DATE : 1/Jan/2009 + ** AUTHOR : Chen, Howard + ** DESCRIPTION : The file contain function to enable host mode USB-IF Electrical Test function. + ** FUNCTIONS : + ** COMPILER : gcc + ** REFERENCE : Synopsys DWC-OTG Driver 2.7 + ** COPYRIGHT : Copyright (c) 2010 + ** LANTIQ DEUTSCHLAND GMBH, + ** Am Campeon 3, 85579 Neubiberg, Germany + ** + ** This program is free software; you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation; either version 2 of the License, or + ** (at your option) any later version. + ** + ** Version Control Section ** + ** $Author$ + ** $Date$ + ** $Revisions$ + ** $Log$ Revision history + *****************************************************************************/ + +/* + * This file contains code fragments from Synopsys HS OTG Linux Software Driver. + * For this code the following notice is applicable: + * + * ========================================================================== + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +/*! + \file ifxhcd_es.c + \ingroup IFXUSB_DRIVER_V3 + \brief The file contain function to enable host mode USB-IF Electrical Test function. +*/ + +#include +#include "ifxusb_version.h" + +#include + +#include + +#include + +#include "ifxusb_plat.h" +#include "ifxusb_regs.h" +#include "ifxusb_cif.h" +#include "ifxhcd.h" + + +#ifdef __WITH_HS_ELECT_TST__ + /* + * Quick and dirty hack to implement the HS Electrical Test + * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature. + * + * This code was copied from our userspace app "hset". It sends a + * Get Device Descriptor control sequence in two parts, first the + * Setup packet by itself, followed some time later by the In and + * Ack packets. Rather than trying to figure out how to add this + * functionality to the normal driver code, we just hijack the + * hardware, using these two function to drive the hardware + * directly. + */ + + + void do_setup(ifxusb_core_if_t *_core_if) + { + + ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; + ifxusb_host_global_regs_t *hc_global_regs = _core_if->host_global_regs; + ifxusb_hc_regs_t *hc_regs = _core_if->hc_regs[0]; + uint32_t *data_fifo = _core_if->data_fifo[0]; + + gint_data_t gintsts; + hctsiz_data_t hctsiz; + hcchar_data_t hcchar; + haint_data_t haint; + hcint_data_t hcint; + + + /* Enable HAINTs */ + ifxusb_wreg(&hc_global_regs->haintmsk, 0x0001); + + /* Enable HCINTs */ + ifxusb_wreg(&hc_regs->hcintmsk, 0x04a3); + + /* Read GINTSTS */ + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); + + /* Read HAINT */ + haint.d32 = ifxusb_rreg(&hc_global_regs->haint); + //fprintf(stderr, "HAINT: %08x\n", haint.d32); + + /* Read HCINT */ + hcint.d32 = ifxusb_rreg(&hc_regs->hcint); + //fprintf(stderr, "HCINT: %08x\n", hcint.d32); + + /* Read HCCHAR */ + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); + + /* Clear HCINT */ + ifxusb_wreg(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + ifxusb_wreg(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + ifxusb_wreg(&global_regs->gintsts, gintsts.d32); + + /* Read GINTSTS */ + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); + + /* + * Send Setup packet (Get Device Descriptor) + */ + + /* Make sure channel is disabled */ + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + if (hcchar.b.chen) { + //fprintf(stderr, "Channel already enabled 1, HCCHAR = %08x\n", hcchar.d32); + hcchar.b.chdis = 1; + // hcchar.b.chen = 1; + ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); + //sleep(1); + mdelay(1000); + + /* Read GINTSTS */ + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); + + /* Read HAINT */ + haint.d32 = ifxusb_rreg(&hc_global_regs->haint); + //fprintf(stderr, "HAINT: %08x\n", haint.d32); + + /* Read HCINT */ + hcint.d32 = ifxusb_rreg(&hc_regs->hcint); + //fprintf(stderr, "HCINT: %08x\n", hcint.d32); + + /* Read HCCHAR */ + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); + + /* Clear HCINT */ + ifxusb_wreg(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + ifxusb_wreg(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + ifxusb_wreg(&global_regs->gintsts, gintsts.d32); + + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + //if (hcchar.b.chen) { + // fprintf(stderr, "** Channel _still_ enabled 1, HCCHAR = %08x **\n", hcchar.d32); + //} + } + + /* Set HCTSIZ */ + hctsiz.d32 = 0; + hctsiz.b.xfersize = 8; + hctsiz.b.pktcnt = 1; + hctsiz.b.pid = IFXUSB_HC_PID_SETUP; + ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); + + /* Set HCCHAR */ + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL; + hcchar.b.epdir = 0; + hcchar.b.epnum = 0; + hcchar.b.mps = 8; + hcchar.b.chen = 1; + ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); + + /* Fill FIFO with Setup data for Get Device Descriptor */ + ifxusb_wreg(data_fifo++, 0x01000680); + ifxusb_wreg(data_fifo++, 0x00080000); + + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + //fprintf(stderr, "Waiting for HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32); + + /* Wait for host channel interrupt */ + do { + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + } while (gintsts.b.hcintr == 0); + + //fprintf(stderr, "Got HCINTR intr 1, GINTSTS = %08x\n", gintsts.d32); + + /* Disable HCINTs */ + ifxusb_wreg(&hc_regs->hcintmsk, 0x0000); + + /* Disable HAINTs */ + ifxusb_wreg(&hc_global_regs->haintmsk, 0x0000); + + /* Read HAINT */ + haint.d32 = ifxusb_rreg(&hc_global_regs->haint); + //fprintf(stderr, "HAINT: %08x\n", haint.d32); + + /* Read HCINT */ + hcint.d32 = ifxusb_rreg(&hc_regs->hcint); + //fprintf(stderr, "HCINT: %08x\n", hcint.d32); + + /* Read HCCHAR */ + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); + + /* Clear HCINT */ + ifxusb_wreg(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + ifxusb_wreg(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + ifxusb_wreg(&global_regs->gintsts, gintsts.d32); + + /* Read GINTSTS */ + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); + } + + void do_in_ack(ifxusb_core_if_t *_core_if) + { + + ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; + ifxusb_host_global_regs_t *hc_global_regs = _core_if->host_global_regs; + ifxusb_hc_regs_t *hc_regs = _core_if->hc_regs[0]; + uint32_t *data_fifo = _core_if->data_fifo[0]; + + gint_data_t gintsts; + hctsiz_data_t hctsiz; + hcchar_data_t hcchar; + haint_data_t haint; + hcint_data_t hcint; + grxsts_data_t grxsts; + + /* Enable HAINTs */ + ifxusb_wreg(&hc_global_regs->haintmsk, 0x0001); + + /* Enable HCINTs */ + ifxusb_wreg(&hc_regs->hcintmsk, 0x04a3); + + /* Read GINTSTS */ + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); + + /* Read HAINT */ + haint.d32 = ifxusb_rreg(&hc_global_regs->haint); + //fprintf(stderr, "HAINT: %08x\n", haint.d32); + + /* Read HCINT */ + hcint.d32 = ifxusb_rreg(&hc_regs->hcint); + //fprintf(stderr, "HCINT: %08x\n", hcint.d32); + + /* Read HCCHAR */ + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); + + /* Clear HCINT */ + ifxusb_wreg(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + ifxusb_wreg(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + ifxusb_wreg(&global_regs->gintsts, gintsts.d32); + + /* Read GINTSTS */ + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); + + /* + * Receive Control In packet + */ + + /* Make sure channel is disabled */ + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + if (hcchar.b.chen) { + //fprintf(stderr, "Channel already enabled 2, HCCHAR = %08x\n", hcchar.d32); + hcchar.b.chdis = 1; + hcchar.b.chen = 1; + ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); + //sleep(1); + mdelay(1000); + + /* Read GINTSTS */ + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); + + /* Read HAINT */ + haint.d32 = ifxusb_rreg(&hc_global_regs->haint); + //fprintf(stderr, "HAINT: %08x\n", haint.d32); + + /* Read HCINT */ + hcint.d32 = ifxusb_rreg(&hc_regs->hcint); + //fprintf(stderr, "HCINT: %08x\n", hcint.d32); + + /* Read HCCHAR */ + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); + + /* Clear HCINT */ + ifxusb_wreg(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + ifxusb_wreg(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + ifxusb_wreg(&global_regs->gintsts, gintsts.d32); + + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + //if (hcchar.b.chen) { + // fprintf(stderr, "** Channel _still_ enabled 2, HCCHAR = %08x **\n", hcchar.d32); + //} + } + + /* Set HCTSIZ */ + hctsiz.d32 = 0; + hctsiz.b.xfersize = 8; + hctsiz.b.pktcnt = 1; + hctsiz.b.pid = IFXUSB_HC_PID_DATA1; + ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); + + /* Set HCCHAR */ + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL; + hcchar.b.epdir = 1; + hcchar.b.epnum = 0; + hcchar.b.mps = 8; + hcchar.b.chen = 1; + ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); + + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + //fprintf(stderr, "Waiting for RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32); + + /* Wait for receive status queue interrupt */ + do { + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + } while (gintsts.b.rxstsqlvl == 0); + + //fprintf(stderr, "Got RXSTSQLVL intr 1, GINTSTS = %08x\n", gintsts.d32); + + /* Read RXSTS */ + grxsts.d32 = ifxusb_rreg(&global_regs->grxstsp); + //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32); + + /* Clear RXSTSQLVL in GINTSTS */ + gintsts.d32 = 0; + gintsts.b.rxstsqlvl = 1; + ifxusb_wreg(&global_regs->gintsts, gintsts.d32); + + switch (grxsts.hb.pktsts) { + case IFXUSB_HSTS_DATA_UPDT: + /* Read the data into the host buffer */ + if (grxsts.hb.bcnt > 0) { + int i; + int word_count = (grxsts.hb.bcnt + 3) / 4; + + for (i = 0; i < word_count; i++) { + (void)ifxusb_rreg(data_fifo++); + } + } + + //fprintf(stderr, "Received %u bytes\n", (unsigned)grxsts.hb.bcnt); + break; + + default: + //fprintf(stderr, "** Unexpected GRXSTS packet status 1 **\n"); + break; + } + + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + //fprintf(stderr, "Waiting for RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32); + + /* Wait for receive status queue interrupt */ + do { + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + } while (gintsts.b.rxstsqlvl == 0); + + //fprintf(stderr, "Got RXSTSQLVL intr 2, GINTSTS = %08x\n", gintsts.d32); + + /* Read RXSTS */ + grxsts.d32 = ifxusb_rreg(&global_regs->grxstsp); + //fprintf(stderr, "GRXSTS: %08x\n", grxsts.d32); + + /* Clear RXSTSQLVL in GINTSTS */ + gintsts.d32 = 0; + gintsts.b.rxstsqlvl = 1; + ifxusb_wreg(&global_regs->gintsts, gintsts.d32); + + switch (grxsts.hb.pktsts) { + case IFXUSB_HSTS_XFER_COMP: + break; + + default: + //fprintf(stderr, "** Unexpected GRXSTS packet status 2 **\n"); + break; + } + + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + //fprintf(stderr, "Waiting for HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32); + + /* Wait for host channel interrupt */ + do { + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + } while (gintsts.b.hcintr == 0); + + //fprintf(stderr, "Got HCINTR intr 2, GINTSTS = %08x\n", gintsts.d32); + + /* Read HAINT */ + haint.d32 = ifxusb_rreg(&hc_global_regs->haint); + //fprintf(stderr, "HAINT: %08x\n", haint.d32); + + /* Read HCINT */ + hcint.d32 = ifxusb_rreg(&hc_regs->hcint); + //fprintf(stderr, "HCINT: %08x\n", hcint.d32); + + /* Read HCCHAR */ + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); + + /* Clear HCINT */ + ifxusb_wreg(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + ifxusb_wreg(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + ifxusb_wreg(&global_regs->gintsts, gintsts.d32); + + /* Read GINTSTS */ + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); + + // usleep(100000); + // mdelay(100); + mdelay(1); + + /* + * Send handshake packet + */ + + /* Read HAINT */ + haint.d32 = ifxusb_rreg(&hc_global_regs->haint); + //fprintf(stderr, "HAINT: %08x\n", haint.d32); + + /* Read HCINT */ + hcint.d32 = ifxusb_rreg(&hc_regs->hcint); + //fprintf(stderr, "HCINT: %08x\n", hcint.d32); + + /* Read HCCHAR */ + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); + + /* Clear HCINT */ + ifxusb_wreg(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + ifxusb_wreg(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + ifxusb_wreg(&global_regs->gintsts, gintsts.d32); + + /* Read GINTSTS */ + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); + + /* Make sure channel is disabled */ + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + if (hcchar.b.chen) { + //fprintf(stderr, "Channel already enabled 3, HCCHAR = %08x\n", hcchar.d32); + hcchar.b.chdis = 1; + hcchar.b.chen = 1; + ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); + //sleep(1); + mdelay(1000); + + /* Read GINTSTS */ + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); + + /* Read HAINT */ + haint.d32 = ifxusb_rreg(&hc_global_regs->haint); + //fprintf(stderr, "HAINT: %08x\n", haint.d32); + + /* Read HCINT */ + hcint.d32 = ifxusb_rreg(&hc_regs->hcint); + //fprintf(stderr, "HCINT: %08x\n", hcint.d32); + + /* Read HCCHAR */ + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); + + /* Clear HCINT */ + ifxusb_wreg(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + ifxusb_wreg(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + ifxusb_wreg(&global_regs->gintsts, gintsts.d32); + + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + //if (hcchar.b.chen) { + // fprintf(stderr, "** Channel _still_ enabled 3, HCCHAR = %08x **\n", hcchar.d32); + //} + } + + /* Set HCTSIZ */ + hctsiz.d32 = 0; + hctsiz.b.xfersize = 0; + hctsiz.b.pktcnt = 1; + hctsiz.b.pid = IFXUSB_HC_PID_DATA1; + ifxusb_wreg(&hc_regs->hctsiz, hctsiz.d32); + + /* Set HCCHAR */ + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + hcchar.b.eptype = IFXUSB_EP_TYPE_CTRL; + hcchar.b.epdir = 0; + hcchar.b.epnum = 0; + hcchar.b.mps = 8; + hcchar.b.chen = 1; + ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); + + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + //fprintf(stderr, "Waiting for HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32); + + /* Wait for host channel interrupt */ + do { + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + } while (gintsts.b.hcintr == 0); + + //fprintf(stderr, "Got HCINTR intr 3, GINTSTS = %08x\n", gintsts.d32); + + /* Disable HCINTs */ + ifxusb_wreg(&hc_regs->hcintmsk, 0x0000); + + /* Disable HAINTs */ + ifxusb_wreg(&hc_global_regs->haintmsk, 0x0000); + + /* Read HAINT */ + haint.d32 = ifxusb_rreg(&hc_global_regs->haint); + //fprintf(stderr, "HAINT: %08x\n", haint.d32); + + /* Read HCINT */ + hcint.d32 = ifxusb_rreg(&hc_regs->hcint); + //fprintf(stderr, "HCINT: %08x\n", hcint.d32); + + /* Read HCCHAR */ + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + //fprintf(stderr, "HCCHAR: %08x\n", hcchar.d32); + + /* Clear HCINT */ + ifxusb_wreg(&hc_regs->hcint, hcint.d32); + + /* Clear HAINT */ + ifxusb_wreg(&hc_global_regs->haint, haint.d32); + + /* Clear GINTSTS */ + ifxusb_wreg(&global_regs->gintsts, gintsts.d32); + + /* Read GINTSTS */ + gintsts.d32 = ifxusb_rreg(&global_regs->gintsts); + //fprintf(stderr, "GINTSTS: %08x\n", gintsts.d32); + } +#endif //__WITH_HS_ELECT_TST__ + diff --git a/package/platform/lantiq/ltq-hcd/src/ifxhcd_intr.c b/package/platform/lantiq/ltq-hcd/src/ifxhcd_intr.c new file mode 100644 index 0000000000..27885bb860 --- /dev/null +++ b/package/platform/lantiq/ltq-hcd/src/ifxhcd_intr.c @@ -0,0 +1,4844 @@ +/***************************************************************************** + ** FILE NAME : ifxhcd_intr.c + ** PROJECT : IFX USB sub-system V3 + ** MODULES : IFX USB sub-system Host and Device driver + ** SRC VERSION : 3.2 + ** DATE : 1/Jan/2011 + ** AUTHOR : Chen, Howard + ** DESCRIPTION : This file contains the implementation of the HCD Interrupt handlers. + ** FUNCTIONS : + ** COMPILER : gcc + ** REFERENCE : Synopsys DWC-OTG Driver 2.7 + ** COPYRIGHT : Copyright (c) 2010 + ** LANTIQ DEUTSCHLAND GMBH, + ** Am Campeon 3, 85579 Neubiberg, Germany + ** + ** This program is free software; you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation; either version 2 of the License, or + ** (at your option) any later version. + ** + ** Version Control Section ** + ** $Author$ + ** $Date$ + ** $Revisions$ + ** $Log$ Revision history + *****************************************************************************/ + +/* + * This file contains code fragments from Synopsys HS OTG Linux Software Driver. + * For this code the following notice is applicable: + * + * ========================================================================== + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +/*! + \file ifxhcd_intr.c + \ingroup IFXUSB_DRIVER_V3 + \brief This file contains the implementation of the HCD Interrupt handlers. +*/ + + +#include +#include "ifxusb_version.h" + +#include "ifxusb_plat.h" +#include "ifxusb_regs.h" +#include "ifxusb_cif.h" + +#include "ifxhcd.h" + +/* Macro used to clear one channel interrupt */ +#define clear_hc_int(_hc_regs_,_intr_) \ + do { \ + hcint_data_t hcint_clear = {.d32 = 0}; \ + hcint_clear.b._intr_ = 1; \ + ifxusb_wreg(&((_hc_regs_)->hcint), hcint_clear.d32); \ + } while (0) + +/* + * Macro used to disable one channel interrupt. Channel interrupts are + * disabled when the channel is halted or released by the interrupt handler. + * There is no need to handle further interrupts of that type until the + * channel is re-assigned. In fact, subsequent handling may cause crashes + * because the channel structures are cleaned up when the channel is released. + */ +#define disable_hc_int(_hc_regs_,_intr_) \ + do { \ + hcint_data_t hcintmsk = {.d32 = 0}; \ + hcintmsk.b._intr_ = 1; \ + ifxusb_mreg(&((_hc_regs_)->hcintmsk), hcintmsk.d32, 0); \ + } while (0) + +#define enable_hc_int(_hc_regs_,_intr_) \ + do { \ + hcint_data_t hcintmsk = {.d32 = 0}; \ + hcintmsk.b._intr_ = 1; \ + ifxusb_mreg(&((_hc_regs_)->hcintmsk),0, hcintmsk.d32); \ + } while (0) + +/* + * Save the starting data toggle for the next transfer. The data toggle is + * saved in the QH for non-control transfers and it's saved in the QTD for + * control transfers. + */ +uint8_t read_data_toggle(ifxusb_hc_regs_t *_hc_regs) +{ + hctsiz_data_t hctsiz; + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + return(hctsiz.b.pid); +} + + +static void release_channel_dump(ifxhcd_hc_t *ifxhc, + struct urb *urb, + ifxhcd_epqh_t *epqh, + ifxhcd_urbd_t *urbd, + ifxhcd_halt_status_e halt_status) +{ + #ifdef __DEBUG__ + printk(KERN_INFO); + switch (halt_status) + { + case HC_XFER_NO_HALT_STATUS: + printk("HC_XFER_NO_HALT_STATUS");break; + case HC_XFER_URB_COMPLETE: + printk("HC_XFER_URB_COMPLETE");break; + case HC_XFER_AHB_ERR: + printk("HC_XFER_AHB_ERR");break; + case HC_XFER_STALL: + printk("HC_XFER_STALL");break; + case HC_XFER_BABBLE_ERR: + printk("HC_XFER_BABBLE_ERR");break; + case HC_XFER_XACT_ERR: + printk("HC_XFER_XACT_ERR");break; + case HC_XFER_URB_DEQUEUE: + printk("HC_XFER_URB_DEQUEUE");break; + case HC_XFER_FRAME_OVERRUN: + printk("HC_XFER_FRAME_OVERRUN");break; + case HC_XFER_DATA_TOGGLE_ERR: + printk("HC_XFER_DATA_TOGGLE_ERR");break; + #ifdef __NAKSTOP__ + case HC_XFER_NAK: + printk("HC_XFER_NAK");break; + #endif + case HC_XFER_COMPLETE: + printk("HC_XFER_COMPLETE");break; + default: + printk("KNOWN");break; + } + if(ifxhc) + printk("Ch %d %s%s S%d " , ifxhc->hc_num + ,(ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL)?"CTRL-": + ((ifxhc->ep_type == IFXUSB_EP_TYPE_BULK)?"BULK-": + ((ifxhc->ep_type == IFXUSB_EP_TYPE_INTR)?"INTR-": + ((ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC)?"ISOC-":"????" + ) + ) + ) + ,(ifxhc->is_in)?"IN":"OUT" + ,(ifxhc->split) + ); + else + printk(" [NULL HC] "); + printk("urb=%p epqh=%p urbd=%p\n",urb,epqh,urbd); + + if(urb) + { + printk(KERN_INFO " Device address: %d\n", usb_pipedevice(urb->pipe)); + printk(KERN_INFO " Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe), + (usb_pipein(urb->pipe) ? "IN" : "OUT")); + printk(KERN_INFO " Endpoint type: %s\n", + ({char *pipetype; + switch (usb_pipetype(urb->pipe)) { + case PIPE_CONTROL: pipetype = "CTRL"; break; + case PIPE_BULK: pipetype = "BULK"; break; + case PIPE_INTERRUPT: pipetype = "INTR"; break; + case PIPE_ISOCHRONOUS: pipetype = "ISOC"; break; + default: pipetype = "????"; break; + }; pipetype;})); + printk(KERN_INFO " Speed: %s\n", + ({char *speed; + switch (urb->dev->speed) { + case USB_SPEED_HIGH: speed = "HS"; break; + case USB_SPEED_FULL: speed = "FS"; break; + case USB_SPEED_LOW: speed = "LS"; break; + default: speed = "????"; break; + }; speed;})); + printk(KERN_INFO " Max packet size: %d\n", + usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); + printk(KERN_INFO " Data buffer length: %d/%d\n",urb->actual_length, urb->transfer_buffer_length); + printk(KERN_INFO " Transfer buffer: %p, Transfer DMA: %p\n", + urb->transfer_buffer, (void *)urb->transfer_dma); + printk(KERN_INFO " Setup buffer: %p, Setup DMA: %p\n", + urb->setup_packet, (void *)urb->setup_dma); + printk(KERN_INFO " Interval: %d\n", urb->interval); + } + if(urbd) + { + switch (urbd->status) + { + case HC_XFER_NO_HALT_STATUS: + printk(KERN_INFO " STATUS:HC_XFER_NO_HALT_STATUS\n");break; + case HC_XFER_URB_COMPLETE: + printk(KERN_INFO " STATUS:HC_XFER_URB_COMPLETE\n");break; + case HC_XFER_AHB_ERR: + printk(KERN_INFO " STATUS:HC_XFER_AHB_ERR\n");break; + case HC_XFER_STALL: + printk(KERN_INFO " STATUS:HC_XFER_STALL\n");break; + case HC_XFER_BABBLE_ERR: + printk(KERN_INFO " STATUS:HC_XFER_BABBLE_ERR\n");break; + case HC_XFER_XACT_ERR: + printk(KERN_INFO " STATUS:HC_XFER_XACT_ERR\n");break; + case HC_XFER_URB_DEQUEUE: + printk(KERN_INFO " STATUS:HC_XFER_URB_DEQUEUE\n");break; + case HC_XFER_FRAME_OVERRUN: + printk(KERN_INFO " STATUS:HC_XFER_FRAME_OVERRUN\n");break; + case HC_XFER_DATA_TOGGLE_ERR: + printk(KERN_INFO " STATUS:HC_XFER_DATA_TOGGLE_ERR\n");break; + case HC_XFER_COMPLETE: + printk(KERN_INFO " STATUS:HC_XFER_COMPLETE\n");break; + default: + printk(KERN_INFO " STATUS:UNKKNOWN %d\n",urbd->status);break; + } + } + #endif +} + +/*! + \fn static void release_channel(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxhcd_halt_status_e _halt_status) + \brief Release the halted channel. + \param _ifxhcd Pointer to the sate of HCD structure + \param _ifxhc Pointer to host channel descriptor + \param _halt_status Halt satus + \return None + \ingroup IFXUSB_HCD + */ + +static void release_channel(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxhcd_halt_status_e _halt_status) +{ + ifxusb_hc_regs_t *hc_regs = _ifxhcd->core_if.hc_regs[_ifxhc->hc_num]; + struct urb *urb = NULL; + ifxhcd_epqh_t *epqh = NULL; + ifxhcd_urbd_t *urbd = NULL; + + IFX_DEBUGPL(DBG_HCDV, " %s: channel %d, halt_status %d\n", + __func__, _ifxhc->hc_num, _halt_status); + + epqh=_ifxhc->epqh; + + if(!epqh) + { + if(_halt_status!=HC_XFER_NO_EPQH) + IFX_ERROR("%s epqh=null\n",__func__); + } + else + { + urbd=epqh->urbd; + if(!urbd) + IFX_ERROR("%s urbd=null\n",__func__); + else + { + urb=urbd->urb; + if(!urb) + { + if(_halt_status!=HC_XFER_NO_URB) + IFX_ERROR("%s urb =null\n",__func__); + } + else + { + if (read_data_toggle(hc_regs) == IFXUSB_HCTSIZ_DATA0) + usb_settoggle (urb->dev,usb_pipeendpoint (urb->pipe), (_ifxhc->is_in)?0:1,0); + else if (read_data_toggle(hc_regs) == IFXUSB_HCTSIZ_DATA1) + usb_settoggle (urb->dev,usb_pipeendpoint (urb->pipe), (_ifxhc->is_in)?0:1,1); + } + } + } + + switch (_halt_status) + { + case HC_XFER_NO_HALT_STATUS: + IFX_ERROR("%s: No halt_status, channel %d\n", __func__, _ifxhc->hc_num); +// return; + break; + case HC_XFER_COMPLETE: + IFX_ERROR("%s: Inavalid halt_status HC_XFER_COMPLETE, channel %d\n", __func__, _ifxhc->hc_num); +// return; + break; + case HC_XFER_NO_URB: + break; + case HC_XFER_NO_EPQH: + break; + case HC_XFER_URB_DEQUEUE: + case HC_XFER_AHB_ERR: + case HC_XFER_XACT_ERR: + case HC_XFER_FRAME_OVERRUN: + if(urbd && urb) + { + urbd->phase=URBD_DEQUEUEING; + ifxhcd_complete_urb(_ifxhcd, urbd, urbd->status); + } + else + { + IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); + release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); + } + break; + case HC_XFER_URB_COMPLETE: + if(urbd && urb) + { + urbd->phase=URBD_COMPLETING; + ifxhcd_complete_urb(_ifxhcd, urbd, urbd->status); + } + else + { + IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); + release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); + } + break; + case HC_XFER_STALL: + if(urbd) + { + urbd->phase=URBD_DEQUEUEING; + ifxhcd_complete_urb(_ifxhcd, urbd, -EPIPE); + } + else + { + IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); + release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); + } + if(epqh && urb && urb->dev && urb->pipe) + usb_settoggle(urb->dev, usb_pipeendpoint (urb->pipe), !usb_pipein(urb->pipe), IFXUSB_HC_PID_DATA0); + break; + case HC_XFER_BABBLE_ERR: + case HC_XFER_DATA_TOGGLE_ERR: + if(urbd) + { + urbd->phase=URBD_DEQUEUEING; + ifxhcd_complete_urb(_ifxhcd, urbd, -EOVERFLOW); + } + else + { + IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); + release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); + } + break; + #ifdef __NAKSTOP__ + case HC_XFER_NAK: + if (_ifxhc->is_in) + { + if(urbd && urb) + { + urbd->phase=URBD_COMPLETING; + ifxhcd_complete_urb(_ifxhcd, urbd, 0); + } + else + { + IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); + release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); + } + } + else + { + IFX_WARN("WARNING %s():%d urbd=%p urb=%p\n",__func__,__LINE__,urbd,urb); + release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); + } + break; + #endif + #if defined(__INTRNAKRETRY__) || defined(__INTRINCRETRY__) + case HC_XFER_INTR_NAK_RETRY: + epqh->phase=EPQH_READY; + urbd->phase=URBD_IDLE; + ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc); + select_eps(_ifxhcd); + return; + break; + + #endif + } + if(epqh) + { + ifxhcd_epqh_idle(epqh); + } + else if(_halt_status!=HC_XFER_NO_EPQH) + { + IFX_WARN("WARNING %s():%d epqh=%p\n",__func__,__LINE__,epqh); + release_channel_dump(_ifxhc,urb,epqh,urbd,_halt_status); + } + ifxhcd_hc_cleanup(&_ifxhcd->core_if, _ifxhc); + select_eps(_ifxhcd); +} + +/* + * Updates the state of the URB after a Transfer Complete interrupt on the + * host channel. Updates the actual_length field of the URB based on the + * number of bytes transferred via the host channel. Sets the URB status + * if the data transfer is finished. + * + * @return 1 if the data transfer specified by the URB is completely finished, + * 0 otherwise. + */ +static int update_urb_state_xfer_comp(ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + struct urb *_urb, + ifxhcd_urbd_t *_urbd) +{ + int xfer_done = 0; + + #ifdef __EN_ISOC__ + if(_urbd->epqh->ep_type==IFXUSB_EP_TYPE_ISOC) + { + struct usb_iso_packet_descriptor *frame_desc; + frame_desc = &_urb->iso_frame_desc[_urbd->isoc_frame_index]; + if (_ifxhc->is_in) + { + hctsiz_data_t hctsiz; + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + frame_desc->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); + if ((hctsiz.b.xfersize != 0) || (frame_desc->actual_length >= _urbd->xfer_len)) + { + xfer_done = 1; + frame_desc->status = 0; + #if 0 + if (frame_desc->actual_length < frame_desc->length && _urb->transfer_flags & URB_SHORT_NOT_OK) + frame_desc->status = -EREMOTEIO; + #endif + } + } + else + { + if (_ifxhc->split) + frame_desc->actual_length += _ifxhc->ssplit_out_xfer_count; + else + frame_desc->actual_length += _ifxhc->xfer_len; + if (frame_desc->actual_length >= _urbd->xfer_len) + { + xfer_done = 1; + frame_desc->status = 0; + } + } + } + else + #endif + if (_ifxhc->is_in) + { + hctsiz_data_t hctsiz; + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + _urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); +#ifdef __INTRINCRETRY__ + if(_urbd->epqh->ep_type==IFXUSB_EP_TYPE_INTR) + { + if(_ifxhc->xfer_len != hctsiz.b.xfersize) + { + xfer_done = 1; + _urbd->status = 0; + } + } + else +#endif + if ((hctsiz.b.xfersize != 0) || (_urb->actual_length >= _urb->transfer_buffer_length)) + { + xfer_done = 1; + _urbd->status = 0; + if(_urb->transfer_flags & URB_SHORT_NOT_OK) + { + if (_urb->actual_length < _urb->transfer_buffer_length) + _urbd->status = -EREMOTEIO; + } + } + } + else if(_urb->transfer_buffer_length%_ifxhc->mps) // OUT without ZLP + { + if (_ifxhc->split) + _urb->actual_length += _ifxhc->ssplit_out_xfer_count; + else + _urb->actual_length += _ifxhc->xfer_len; + if (_urb->actual_length >= _urb->transfer_buffer_length) + { + xfer_done = 1; + _urbd->status = 0; + } + } + else if (_urb->actual_length >= _urb->transfer_buffer_length) //OUT with ZLP + { + xfer_done = 1; + _urbd->status = 0; + } + else //OUT without ZLP, unfinished + { + if (_ifxhc->split) + _urb->actual_length += _ifxhc->ssplit_out_xfer_count; + else + _urb->actual_length += _ifxhc->xfer_len; + if (!_ifxhc->short_rw && _urb->actual_length >= _urb->transfer_buffer_length) + { + xfer_done = 1; + _urbd->status = 0; + } + } + + #ifdef __DEBUG__ + { + hctsiz_data_t hctsiz; + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + IFX_DEBUGPL(DBG_HCDV, "IFXUSB: %s: %s, channel %d\n", + __func__, (_ifxhc->is_in ? "IN" : "OUT"), _ifxhc->hc_num); + IFX_DEBUGPL(DBG_HCDV, " hc->xfer_len %d\n", _ifxhc->xfer_len); + IFX_DEBUGPL(DBG_HCDV, " hctsiz.xfersize %d\n", hctsiz.b.xfersize); + #ifdef __EN_ISOC__ + if(_urbd->epqh->ep_type==IFXUSB_EP_TYPE_ISOC) + { + IFX_DEBUGPL(DBG_HCDV, " descritor # %d\n", _urbd->isoc_frame_index); + IFX_DEBUGPL(DBG_HCDV, " buffer_length %d\n", + _urb->iso_frame_desc[_urbd->isoc_frame_index].length); + IFX_DEBUGPL(DBG_HCDV, " actual_length %d\n", _urb->iso_frame_desc[_urbd->isoc_frame_index].actual_length); + } + else + #endif + { + IFX_DEBUGPL(DBG_HCDV, " urb->transfer_buffer_length %d\n", + _urb->transfer_buffer_length); + IFX_DEBUGPL(DBG_HCDV, " urb->actual_length %d\n", _urb->actual_length); + } + } + #endif + return xfer_done; +} + +#ifdef __EN_ISOC__ + static void next_isoc_sub(unsigned long data) + { + ifxhcd_urbd_t *urbd; + ifxhcd_hcd_t *ifxhcd; + + urbd=((ifxhcd_urbd_t *)data); + ifxhcd=urbd->epqh->ifxhcd; + + if (!urbd->epqh) + IFX_ERROR("%s: invalid epqd\n",__func__); + #if defined(__UNALIGNED_BUF_ADJ__) + else + { + if( urbd->aligned_checked && +// urbd->using_aligned_buf && + urbd->xfer_buff && + urbd->is_in) + { + uint8_t *buf; + + buf=urbd->xfer_buff; + buf+=urbd->urb->iso_frame_desc[urbd->isoc_frame_index].offset; + memcpy(buf,urbd->aligned_buf,urbd->urb->iso_frame_desc[urbd->isoc_frame_index].length); + } +// urbd->using_aligned_buf=0; +// urbd->using_aligned_setup=0; + } + #endif + + urbd->isoc_frame_index++; + if(urbd->isoc_frame_index>=urbd->urb->number_of_packets) + release_channel(ifxhcd,urbd->epqh->hc,HC_XFER_URB_COMPLETE); + else + init_hc(urbd->epqh); + } +#endif + +/*! + \fn static void complete_channel(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxhcd_urbd_t *_urbd) + \brief Complete the transaction on the channel. + \param _ifxhcd Pointer to the sate of HCD structure + \param _ifxhc Pointer to host channel descriptor + \param _urbd Pointer to URB descriptor + \return None + \ingroup IFXUSB_HCD + */ +static void complete_channel(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxhcd_urbd_t *_urbd) +{ + ifxusb_hc_regs_t *hc_regs = _ifxhcd->core_if.hc_regs[_ifxhc->hc_num]; + struct urb *urb = NULL; + ifxhcd_epqh_t *epqh = NULL; + int urb_xfer_done; + + IFX_DEBUGPL(DBG_HCD, "--Complete Channel %d : \n", _ifxhc->hc_num); + + if(!_urbd) + { + IFX_ERROR("ERROR %s():%d urbd=%p\n",__func__,__LINE__,_urbd); + return; + } + + urb = _urbd->urb; + epqh = _urbd->epqh; + + if(!epqh) + { + release_channel(_ifxhcd,_ifxhc,HC_XFER_NO_EPQH); + return; + } + if(!urb || (unsigned long)urb->hcpriv!=(unsigned long)_urbd) + { + release_channel(_ifxhcd,_ifxhc,HC_XFER_NO_URB); + return; + } + + if (_ifxhc->split) + _ifxhc->split = 1; + + switch (epqh->ep_type) + { + case IFXUSB_EP_TYPE_CTRL: + switch (_ifxhc->control_phase) + { + case IFXHCD_CONTROL_SETUP: + if (_urbd->xfer_len > 0) + { + _ifxhc->control_phase = IFXHCD_CONTROL_DATA; + IFX_DEBUGPL(DBG_HCDV, " Control setup transaction done Data Stage now\n"); + _ifxhc->is_in = _urbd->is_in; + _ifxhc->xfer_len = _urbd->xfer_len; + #if defined(__UNALIGNED_BUF_ADJ__) + if(_urbd->aligned_buf) + _ifxhc->xfer_buff = _urbd->aligned_buf; + else + #endif + _ifxhc->xfer_buff = _urbd->xfer_buff; + #ifdef __NAKSTOP__ + if(!_ifxhc->split) + { + #ifdef __INNAKSTOP_CTRL__ + if(_ifxhc->is_in) + _ifxhc->stop_on=1; + #endif + #ifdef __PINGSTOP_CTRL__ + if(!_ifxhc->is_in) + _ifxhc->stop_on=1; + #endif + } + #endif + } + else + { + IFX_DEBUGPL(DBG_HCDV, " Control setup transaction done Status Stage now\n"); + _ifxhc->control_phase = IFXHCD_CONTROL_STATUS; + _ifxhc->is_in = 1; + _ifxhc->xfer_len = 0; + _ifxhc->xfer_buff = _ifxhcd->status_buf; + #ifdef __NAKSTOP__ + _ifxhc->stop_on=0; + #endif + } + if(_ifxhc->is_in) + _ifxhc->short_rw =0; + else + _ifxhc->short_rw =(urb->transfer_flags & URB_ZERO_PACKET)?1:0; + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; + _ifxhc->xfer_count = 0; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + break; + case IFXHCD_CONTROL_DATA: + urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); + if (urb_xfer_done) + { + _ifxhc->control_phase = IFXHCD_CONTROL_STATUS; + IFX_DEBUGPL(DBG_HCDV, " Control data transaction done Status Stage now\n"); + _ifxhc->is_in = (_urbd->is_in)?0:1; + _ifxhc->xfer_len = 0; + _ifxhc->xfer_count = 0; + _ifxhc->xfer_buff = _ifxhcd->status_buf; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; + if(_ifxhc->is_in) + _ifxhc->short_rw =0; + else + _ifxhc->short_rw =1; + #ifdef __NAKSTOP__ + _ifxhc->stop_on=0; + #endif + } + else // continue + { + IFX_DEBUGPL(DBG_HCDV, " Control data transaction continue\n"); + _ifxhc->xfer_len = _urbd->xfer_len - urb->actual_length; + _ifxhc->xfer_count = urb->actual_length; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->data_pid_start = read_data_toggle(hc_regs); + } + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + break; + case IFXHCD_CONTROL_STATUS: + IFX_DEBUGPL(DBG_HCDV, " Control status transaction done\n"); + if (_urbd->status == -EINPROGRESS) + _urbd->status = 0; + release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); + break; + } + break; + case IFXUSB_EP_TYPE_BULK: + IFX_DEBUGPL(DBG_HCDV, " Bulk transfer complete\n"); + urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); + if (urb_xfer_done) + release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); + else + { + _ifxhc->xfer_len = _urbd->xfer_len - urb->actual_length; + _ifxhc->xfer_count = urb->actual_length; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->data_pid_start = read_data_toggle(hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + break; + case IFXUSB_EP_TYPE_INTR: + urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); + + #ifdef __INTRINCRETRY__ + if(!urb_xfer_done) + release_channel(_ifxhcd,_ifxhc,HC_XFER_INTR_NAK_RETRY); + else + #endif + release_channel(_ifxhcd,_ifxhc,HC_XFER_URB_COMPLETE); + break; + case IFXUSB_EP_TYPE_ISOC: + #ifdef __EN_ISOC__ + urb_xfer_done = update_urb_state_xfer_comp(_ifxhc, hc_regs, urb, _urbd); + if (urb_xfer_done) + { + #if defined(__UNALIGNED_BUF_ADJ__) + if(in_irq()) + { + if(!epqh->tasklet_next_isoc.func) + { + epqh->tasklet_next_isoc.next = NULL; + epqh->tasklet_next_isoc.state = 0; + atomic_set( &epqh->tasklet_next_isoc.count, 0); + epqh->tasklet_next_isoc.func = next_isoc_sub; + epqh->tasklet_next_isoc.data = (unsigned long)_urbd; + } + tasklet_schedule(&epqh->tasklet_next_isoc); + } + else + #endif + { + next_isoc_sub((unsigned long)_urbd); + } + } + else + { + struct usb_iso_packet_descriptor *frame_desc; + frame_desc = &urb->iso_frame_desc[_urbd->isoc_frame_index]; + _ifxhc->xfer_len = _urbd->xfer_len - frame_desc->actual_length; + _ifxhc->xfer_count = frame_desc->actual_length; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->data_pid_start = read_data_toggle(hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + #endif + break; + } +} + + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_ctrl_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + #ifdef __INNAKSTOP_CTRL__ + if (_ifxhc->halt_status == HC_XFER_NAK) + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + u32 actual_length; + actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize); + + if(_urbd->xfer_len && actual_length >= _urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + else + { + printk(KERN_INFO "Warning: %s() %d Invalid CTRL Phase:%d\n",__func__,__LINE__,_ifxhc->control_phase); + release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); + } + return 1; + } + #endif + + if (hcint.b.xfercomp || hcint.d32 == 0x02) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if (hcint.b.stall) + { + _urbd->error_count =0; + // ZLP shortcut + #if 0 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + #if 0 + if(_ifxhc->control_phase == IFXHCD_CONTROL_STATUS) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + } + return 1; + } + else if (hcint.b.bblerr) + { + _urbd->error_count =0; + + // ZLP shortcut + #if 0 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + #if 0 + if(_ifxhc->control_phase == IFXHCD_CONTROL_STATUS) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + } + return 1; + } + else if (hcint.b.xacterr) + { + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + #if 1 + if(_ifxhc->control_phase == IFXHCD_CONTROL_STATUS) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + #if 1 + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + #else + u32 actual_length; + actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize); + if(actual_length >= _urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->error_count++; + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + if (_urbd->error_count >= 3) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->erron=1; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + #endif + } + else + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + return 1; + } + else if(hcint.b.datatglerr ) + { + #if 0 + #if 1 + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + #else + u32 actual_length; + actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize); + if(actual_length>=_urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->urb->actual_length = actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + } + #endif + #else + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + #endif + return 1; + } + else if(hcint.b.frmovrun ) + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else + { + _urbd->error_count =0; + IFX_ERROR("ERROR %s():%d invalid chhlt condition %08X/%08X %d\n",__func__,__LINE__,hcint.d32,hcintmsk.d32,_ifxhc->halt_status); + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + return 1; + } + + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_ctrl_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + #ifdef __PINGSTOP_CTRL__ + if (_ifxhc->halt_status == HC_XFER_NAK) + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + u32 actual_length; + actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + + if(_urbd->xfer_len && actual_length >= _urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + else + { + printk(KERN_INFO "Warning: %s() %d Invalid CTRL Phase:%d\n",__func__,__LINE__,_ifxhc->control_phase); + release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); + } + return 1; + } + #endif + + + if (hcint.b.xfercomp || hcint.d32 == 0x02) + { + _urbd->error_count =0; + if(_ifxhc->xfer_len==0 && !hcint.b.ack && hcint.b.nak) + { + // Walkaround: When sending ZLP and receive NAK but also issue CMPT intr + // Solution: NoSplit: Resend at next SOF + // Split : Resend at next SOF with SSPLIT + if(hcint.b.nyet) + _ifxhc->epqh->do_ping=1; + + _ifxhc->xfer_len = 0; + _ifxhc->xfer_count = 0; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + else + { + if(hcint.b.nyet) + _ifxhc->epqh->do_ping=1; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + return 1; + } + else if (hcint.b.stall) + { + _urbd->error_count =0; + + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + } + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + } + return 1; + } + else if (hcint.b.xacterr) + { + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + if(_ifxhc->control_phase == IFXHCD_CONTROL_STATUS) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else if(_ifxhc->control_phase == IFXHCD_CONTROL_SETUP) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + #if 0 + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + #else + u32 actual_length; + actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + if(actual_length>=_urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->error_count++; + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + if (_urbd->error_count >= 3) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->erron=1; + _ifxhc->phase=HC_WAITING; + _ifxhc->epqh->do_ping=1; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + #endif + } + else + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + return 1; + } + else if(hcint.b.bblerr ) + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + } + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.nak || hcint.b.nyet) + { + #ifdef __PINGSTOP_CTRL__ + _urbd->error_count =0; + IFX_ERROR("ERROR %s():%d invalid chhlt condition\n",__func__,__LINE__); + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + #else + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + if(_ifxhc->control_phase == IFXHCD_CONTROL_STATUS) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else if(_ifxhc->control_phase == IFXHCD_CONTROL_SETUP) + { + _urbd->error_count =0; + IFX_ERROR("ERROR %s():%d invalid chhlt condition\n",__func__,__LINE__); + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + #if 0 + _ifxhc->epqh->do_ping=1; + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + #else + u32 actual_length; + _ifxhc->epqh->do_ping=1; + actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + if(actual_length>=_urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->erron=1; + _ifxhc->epqh->do_ping=1; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + #endif + } + #endif + return 1; + } + else if(hcint.b.datatglerr ) + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + } + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + return 1; + } + else if(hcint.b.frmovrun ) + { + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + } + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else + { + _urbd->error_count =0; + IFX_ERROR("ERROR %s():%d invalid chhlt condition %08X/%08X %d\n",__func__,__LINE__,hcint.d32,hcintmsk.d32,_ifxhc->halt_status); + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + return 1; + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_bulk_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + #ifdef __INNAKSTOP_BULK__ + if(_ifxhc->halt_status == HC_XFER_NAK) + { + u32 actual_length; + actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize); + + if( + (_urbd->xfer_len && actual_length>=_urbd->xfer_len) + || hctsiz.b.pktcnt==0 + || (hctsiz.b.xfersize % _ifxhc->mps)>0 + ) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + #endif + + if (hcint.b.xfercomp || hcint.d32 == 0x02) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if (hcint.b.stall) + { + _urbd->error_count =0; + // ZLP shortcut + #if 0 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + } + return 1; + } + else if (hcint.b.bblerr) + { + _urbd->error_count =0; + + // ZLP shortcut + #if 0 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + } + return 1; + } + else if (hcint.b.xacterr) + { + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + { + #if 0 + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + #else + u32 actual_length; + actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize); + if(actual_length >= _urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->error_count++; + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + if (_urbd->error_count >= 3) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->erron=1; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + #endif + } + return 1; + } + else if(hcint.b.datatglerr ) + { + #if 0 + #if 1 + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + #else + u32 actual_length; + actual_length = _urbd->urb->actual_length + (_ifxhc->xfer_len - hctsiz.b.xfersize); + if(actual_length >= _urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->urb->actual_length = actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + } + #endif + #else + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + #endif + return 1; + } + else if(hcint.b.frmovrun ) + { +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else + { + _urbd->error_count =0; + IFX_ERROR("ERROR %s():%d invalid chhlt condition %08X/%08X %d sz:%d/%d/%d/%d\n",__func__,__LINE__,hcint.d32,hcintmsk.d32,_ifxhc->halt_status , hctsiz.b.xfersize, _ifxhc->xfer_len-_ifxhc->xfer_len,_ifxhc->xfer_len,_urbd->xfer_len); + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + return 1; + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_bulk_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + int out_nak_enh = 0; + + if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + out_nak_enh = 1; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + #ifdef __PINGSTOP_BULK__ + if (_ifxhc->halt_status == HC_XFER_NAK) + { + u32 actual_length; + actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + + if(_urbd->xfer_len && actual_length >= _urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + #endif + + if (hcint.b.xfercomp || hcint.d32 == 0x02) + { + _urbd->error_count =0; + if(_ifxhc->xfer_len==0 && !hcint.b.ack && hcint.b.nak) + { + // Walkaround: When sending ZLP and receive NAK but also issue CMPT intr + // Solution: NoSplit: Resend at next SOF + // Split : Resend at next SOF with SSPLIT + if(hcint.b.nyet) + _ifxhc->epqh->do_ping=1; + + _ifxhc->xfer_len = 0; + _ifxhc->xfer_count = 0; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + else + { + if(hcint.b.nyet) + _ifxhc->epqh->do_ping=1; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + return 1; + } + else if (hcint.b.stall) + { + _urbd->error_count =0; + + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + if(_urbd->urb->actual_length>_urbd->xfer_len) _urbd->urb->actual_length=_urbd->xfer_len; + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + } + return 1; + } + else if (hcint.b.xacterr) + { + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + { + #if 0 + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + #else + u32 actual_length; + actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + if(actual_length >= _urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->error_count++; + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + if (_urbd->error_count >= 3) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->erron=1; + _ifxhc->phase=HC_WAITING; + _ifxhc->epqh->do_ping=1; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + #endif + } + return 1; + } + else if(hcint.b.bblerr ) + { + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + if(_urbd->urb->actual_length>_urbd->xfer_len) _urbd->urb->actual_length=_urbd->xfer_len; + IFX_ERROR("ERROR %s():%d invalid packet babble\n",__func__,__LINE__); + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.nak || hcint.b.nyet) + { + #ifdef __PINGSTOP_BULK__ + _urbd->error_count =0; + IFX_ERROR("ERROR %s():%d invalid chhlt condition\n",__func__,__LINE__); + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + #else + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + { + #if 0 + _ifxhc->epqh->do_ping=1; + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + #else + u32 actual_length; + _ifxhc->epqh->do_ping=1; + actual_length = _urbd->urb->actual_length + ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + if(actual_length>=_urbd->xfer_len) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _ifxhc->xfer_count = + _urbd->urb->actual_length = actual_length; + _ifxhc->xfer_len = _urbd->xfer_len - actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->erron=1; + _ifxhc->epqh->do_ping=1; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + #endif + } + #endif + return 1; + } + else if(hcint.b.datatglerr ) + { + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + return 1; + } + else if(hcint.b.frmovrun ) + { + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); +// if( _urbd->urb->actual_length > _ifxhc->xfer_len) _urbd->urb->actual_length = _urbd->xfer_len; + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else + { + _urbd->error_count =0; + IFX_ERROR("ERROR %s():%d invalid chhlt condition %08X/%08X %d\n",__func__,__LINE__,hcint.d32,hcintmsk.d32,_ifxhc->halt_status); + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + return 1; + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_intr_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if (hcint.b.xfercomp || hcint.d32 == 0x02) + { + _urbd->error_count =0; + //restart INTR immediately + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if (hcint.b.stall) + { + _urbd->error_count =0; + + // Don't care shortcut + #if 0 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + } + return 1; + } + else if (hcint.b.bblerr) + { + _urbd->error_count =0; + + // Don't care shortcut + #if 0 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + } + return 1; + } + else if (hcint.b.datatglerr || hcint.b.frmovrun) + { + _urbd->error_count =0; + //restart INTR immediately + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if (hcint.b.xacterr) + { + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + { + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + return 1; + } + else if(hcint.b.nyet ) + { + return 1; + } + else if (hcint.b.nak) + { + + #ifdef __INTRNAKRETRY__ + if(hctsiz.b.pktcnt) + { + release_channel(_ifxhcd, _ifxhc, HC_XFER_INTR_NAK_RETRY); + return 1; + } + #endif + _urbd->error_count =0; + //restart INTR immediately + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else + { + _urbd->error_count =0; + //restart INTR immediately + #if 0 + if(hctsiz.b.pktcnt>0) + { + // TODO Re-initialize Channel (in next b_interval - 1 uF/F) + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + else + #endif + { + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + return 1; + } + + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_intr_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + int out_nak_enh = 0; + + if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + out_nak_enh = 1; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + if (hcint.b.xfercomp || hcint.d32 == 0x02) + { + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + _urbd->error_count =0; + //restart INTR immediately + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if (hcint.b.stall) + { + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nyet); + disable_hc_int(_hc_regs,nak); + _urbd->error_count =0; + + // Don't care shortcut + #if 0 + if(hctsiz.b.pktcnt==0) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + #endif + { + if(_ifxhc->xfer_len!=0)// !_ifxhc->is_in + _urbd->urb->actual_length += ((_ifxhc->start_pkt_count - hctsiz.b.pktcnt ) * _ifxhc->mps); + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + } + return 1; + } + else if(hcint.b.nak || hcint.b.frmovrun ) + { + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nyet); + disable_hc_int(_hc_regs,nak); + _urbd->error_count =0; + //restart INTR immediately + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if(hcint.b.xacterr ) + { + // ZLP shortcut + #if 1 + if(hctsiz.b.pktcnt==0) + { + _urbd->error_count =0; + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + #endif + { + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + return 1; + } + else if(hcint.b.bblerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.datatglerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + return 1; + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_isoc_rx_nonsplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + #ifdef __EN_ISOC__ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + if (hcint.b.xfercomp || hcint.b.frmovrun || hcint.d32 == 0x02) + { + _urbd->error_count=0; + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + if (hcint.b.xfercomp) + complete_channel(_ifxhcd, _ifxhc, _urbd); + else + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + } + else if (hcint.b.xacterr || hcint.b.bblerr) + { + #ifndef VR9Skip + if(hctsiz.b.pktcnt==0) + { + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + if (hcint.b.bblerr) + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + else if (hcint.b.xacterr) + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + enable_hc_int(_hc_regs,ack); + enable_hc_int(_hc_regs,nak); + enable_hc_int(_hc_regs,nyet); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + #endif + } + else if(hcint.b.datatglerr ) + { + return 1; + } + else if(hcint.b.stall ) + { + return 1; + } + #endif + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_isoc_tx_nonsplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + #ifdef __EN_ISOC__ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + int out_nak_enh = 0; + + if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + out_nak_enh = 1; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + if (hcint.b.xfercomp || hcint.d32 == 0x02) + { + _urbd->error_count=0; + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if (hcint.b.frmovrun) + { + #ifndef VR9Skip + _urbd->error_count=0; + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + #endif + } + else if(hcint.b.datatglerr ) + { + return 1; + } + else if(hcint.b.bblerr ) + { + #ifndef VR9Skip + if(hctsiz.b.pktcnt==0) + { + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + else + { + _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + } + else + { + enable_hc_int(_hc_regs,ack); + enable_hc_int(_hc_regs,nak); + enable_hc_int(_hc_regs,nyet); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + } + #endif + } + else if(hcint.b.xacterr ) + { + if(hctsiz.b.pktcnt==0) + { + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.stall ) + { + return 1; + } + #endif + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_ctrl_rx_ssplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if (hcint.b.ack) + { + _urbd->error_count=0; + _ifxhc->split=2; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if (hcint.b.nak) + { + _urbd->error_count = 0; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if (hcint.b.xacterr) + { + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.bblerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.stall ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + return 1; + } + else if(hcint.b.datatglerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + return 1; + } + else if(hcint.b.frmovrun ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else if(hcint.b.nyet ) + { + } + else if(hcint.b.xfercomp ) + { + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_ctrl_tx_ssplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + int out_nak_enh = 0; + + if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + out_nak_enh = 1; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if (hcint.b.ack ) + { + _urbd->error_count=0; + if (_ifxhc->control_phase != IFXHCD_CONTROL_SETUP) + _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; + _ifxhc->split=2; + _ifxhc->data_pid_start =read_data_toggle(_hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nyet) + { + _urbd->error_count=0; + if (_ifxhc->control_phase != IFXHCD_CONTROL_SETUP) + _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; + _ifxhc->split=2; + _ifxhc->data_pid_start =read_data_toggle(_hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nak ) + { + _urbd->error_count =0; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.xacterr ) + { + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.datatglerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + return 1; + } + else if(hcint.b.bblerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.stall ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + return 1; + } + else if(hcint.b.frmovrun ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else if(hcint.b.xfercomp ) + { + printk(KERN_INFO "Warning: %s() %d CTRL OUT SPLIT1 COMPLETE\n",__func__,__LINE__); + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_bulk_rx_ssplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if (hcint.b.ack) + { + _urbd->error_count=0; + _ifxhc->split=2; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if (hcint.b.nak) + { + _urbd->error_count = 0; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if (hcint.b.xacterr) + { + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.bblerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.stall ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + return 1; + } + else if(hcint.b.datatglerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + return 1; + } + else if(hcint.b.frmovrun ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else if(hcint.b.nyet ) + { + } + else if(hcint.b.xfercomp ) + { + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_bulk_tx_ssplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + int out_nak_enh = 0; + + if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + out_nak_enh = 1; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if (hcint.b.ack ) + { + _urbd->error_count=0; + _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; + _ifxhc->split=2; + _ifxhc->data_pid_start =read_data_toggle(_hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nyet) + { + _urbd->error_count=0; + _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; + _ifxhc->split=2; + _ifxhc->data_pid_start =read_data_toggle(_hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nak ) + { + _urbd->error_count =0; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.xacterr ) + { + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.datatglerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + return 1; + } + else if(hcint.b.bblerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.stall ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + return 1; + } + else if(hcint.b.frmovrun ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else if(hcint.b.xfercomp ) + { + printk(KERN_INFO "Warning: %s() %d BULK OUT SPLIT1 COMPLETE\n",__func__,__LINE__); + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_intr_rx_ssplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if (hcint.b.ack) + { + _urbd->error_count=0; + _ifxhc->split=2; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nak) + { + _urbd->error_count=0; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.xacterr) + { + hcchar_data_t hcchar; + hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); + _urbd->error_count=hcchar.b.multicnt; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.stall ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + return 1; + } + else if(hcint.b.bblerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.frmovrun ) + { + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.datatglerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + return 1; + } + else if(hcint.b.xfercomp ) + { + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_intr_tx_ssplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + int out_nak_enh = 0; + + if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + out_nak_enh = 1; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if (hcint.b.ack ) + { + _urbd->error_count=0; + _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; + _ifxhc->split=2; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nyet) + { + _urbd->error_count=0; + _ifxhc->ssplit_out_xfer_count = _ifxhc->xfer_len; + _ifxhc->split=2; + _ifxhc->data_pid_start = read_data_toggle(_hc_regs); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nak ) + { + _urbd->error_count =0; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.frmovrun ) + { + _urbd->error_count =0; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.xacterr ) + { + hcchar_data_t hcchar; + hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); + _urbd->error_count=hcchar.b.multicnt; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + enable_hc_int(_hc_regs,ack); + enable_hc_int(_hc_regs,nak); + enable_hc_int(_hc_regs,nyet); + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.datatglerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_DATA_TOGGLE_ERR); + return 1; + } + else if(hcint.b.bblerr ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.stall ) + { + _urbd->error_count =0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + return 1; + } + else if(hcint.b.xfercomp ) + { + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_isoc_rx_ssplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + if (hcint.b.ack ) + { + Do Complete Split + } + else if(hcint.b.frmovrun ) + { + Rewind Buffer Pointers + Retry Start Split (in next b_interval ¡V 1 uF) + } + else if(hcint.b.datatglerr ) + { + //warning + } + else if(hcint.b.bblerr ) + { + //warning + } + else if(hcint.b.xacterr ) + { + //warning + } + else if(hcint.b.stall ) + { + //warning + } + else if(hcint.b.nak ) + { + //warning + } + else if(hcint.b.xfercomp ) + { + //warning + } + else if(hcint.b.nyet) + { + //warning + } + #endif + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_isoc_tx_ssplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + int out_nak_enh = 0; + + if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + out_nak_enh = 1; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + if (hcint.b.ack ) + { + //Do Next Start Split (in next b_interval ¡V 1 uF) + } + else if(hcint.b.frmovrun ) + { + //Do Next Transaction in next frame. + } + else if(hcint.b.datatglerr ) + { + //warning + } + else if(hcint.b.bblerr ) + { + //warning + } + else if(hcint.b.xacterr ) + { + //warning + } + else if(hcint.b.stall ) + { + //warning + } + else if(hcint.b.nak ) + { + //warning + } + else if(hcint.b.xfercomp ) + { + //warning + } + else if(hcint.b.nyet) + { + //warning + } + #endif + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_ctrl_rx_csplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if (hcint.b.xfercomp) + { + _urbd->error_count =0; + _ifxhc->split=1; + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if (hcint.b.nak) + { + _ifxhc->split = 1; + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + } + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nyet) + { + _urbd->error_count=0; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.stall || hcint.b.bblerr ) + { + _urbd->error_count=0; + if (hcint.b.stall) + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + else if(hcint.b.bblerr ) + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.xacterr ) + { + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->split=1; + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + } + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.datatglerr ) + { + if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; + else + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; + _ifxhc->split=1; + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + } + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.frmovrun ) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_ctrl_tx_csplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + int out_nak_enh = 0; + + if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + out_nak_enh = 1; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if(hcint.b.xfercomp ) + { + _urbd->error_count=0; + _ifxhc->split=1; + #if 0 + if(_ifxhc->xfer_len==0 && !hcint.b.ack && (hcint.b.nak || hcint.b.nyet)) + { + // Walkaround: When sending ZLP and receive NYEY or NAK but also issue CMPT intr + // Solution: NoSplit: Resend at next SOF + // Split : Resend at next SOF with SSPLIT + _ifxhc->xfer_len = 0; + _ifxhc->xfer_count = 0; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + else + #endif + { + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + return 1; + } + else if(hcint.b.nak ) + { + _ifxhc->split = 1; + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + } + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nyet) + { + //Retry Complete Split + // Issue Retry instantly on next SOF, without gothrough process_channels + _urbd->error_count=0; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.stall ) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + return 1; + } + else if(hcint.b.xacterr ) + { + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->split=1; + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + } + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.datatglerr ) + { + if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; + else + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; + _ifxhc->split=1; + if(_ifxhc->control_phase == IFXHCD_CONTROL_DATA) + { + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + } + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.frmovrun ) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else if(hcint.b.bblerr ) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_bulk_rx_csplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if (hcint.b.xfercomp) + { + _urbd->error_count =0; + _ifxhc->split=1; + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if (hcint.b.nak) + { + _ifxhc->split = 1; + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nyet) + { + _urbd->error_count=0; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.stall || hcint.b.bblerr ) + { + _urbd->error_count=0; + if (hcint.b.stall) + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + else if(hcint.b.bblerr ) + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + else if(hcint.b.xacterr ) + { + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->split=1; + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.datatglerr ) + { + if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; + else + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; + _ifxhc->split=1; + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.frmovrun ) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_bulk_tx_csplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + int out_nak_enh = 0; + + if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + out_nak_enh = 1; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if(hcint.b.xfercomp ) + { + _urbd->error_count=0; + _ifxhc->split=1; + #if 0 + if(_ifxhc->xfer_len==0 && !hcint.b.ack && (hcint.b.nak || hcint.b.nyet)) + { + // Walkaround: When sending ZLP and receive NYEY or NAK but also issue CMPT intr + // Solution: NoSplit: Resend at next SOF + // Split : Resend at next SOF with SSPLIT + _ifxhc->xfer_len = 0; + _ifxhc->xfer_count = 0; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + else + #endif + { + complete_channel(_ifxhcd, _ifxhc, _urbd); + } + return 1; + } + else if(hcint.b.nak ) + { + _ifxhc->split = 1; + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nyet) + { + //Retry Complete Split + // Issue Retry instantly on next SOF, without gothrough process_channels + _urbd->error_count=0; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.stall ) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + return 1; + } + else if(hcint.b.xacterr ) + { + _urbd->error_count++; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->split=1; + _ifxhc->epqh->do_ping=1; + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.datatglerr ) + { + if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; + else + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; + _ifxhc->split=1; + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.frmovrun ) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else if(hcint.b.bblerr ) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_intr_rx_csplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if (hcint.b.xfercomp ) + { + _urbd->error_count=0; + _ifxhc->split=1; + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if(hcint.b.nak ) + { + _ifxhc->split = 1; + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nyet) + { + _urbd->error_count=0; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.frmovrun || hcint.b.bblerr || hcint.b.stall ) + { + _urbd->error_count=0; + if (hcint.b.stall) + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + else if(hcint.b.bblerr ) + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + else if(hcint.b.frmovrun ) + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else if(hcint.b.xacterr ) + { + hcchar_data_t hcchar; + hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); + _urbd->error_count=hcchar.b.multicnt; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->split=1; + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.datatglerr ) + { + if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; + else + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; + _ifxhc->split=1; + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_intr_tx_csplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + int out_nak_enh = 0; + + if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + out_nak_enh = 1; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + + if(hcint.b.xfercomp ) + { + _urbd->error_count=0; + _ifxhc->split=1; + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if(hcint.b.nak ) + { + _ifxhc->split = 1; + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.nyet) + { + _urbd->error_count=0; + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.stall || hcint.b.frmovrun) + { + _urbd->error_count=0; + if (hcint.b.stall) + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + else if(hcint.b.frmovrun ) + release_channel(_ifxhcd, _ifxhc, HC_XFER_FRAME_OVERRUN); + return 1; + } + else if(hcint.b.xacterr ) + { + hcchar_data_t hcchar; + hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); + _urbd->error_count=hcchar.b.multicnt; + if(_urbd->error_count>=3) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_XACT_ERR); + } + else + { + _ifxhc->split=1; + _ifxhc->epqh->do_ping=1; + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + } + return 1; + } + else if(hcint.b.datatglerr ) + { + if(_ifxhc->data_pid_start == IFXUSB_HC_PID_DATA0) + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA1; + else + _ifxhc->data_pid_start = IFXUSB_HC_PID_DATA0; + _ifxhc->split=1; + _ifxhc->epqh->do_ping=1; + _ifxhc->xfer_len = _urbd->xfer_len - _urbd->urb->actual_length; + _ifxhc->xfer_count = _urbd->urb->actual_length; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.bblerr ) + { + _urbd->error_count=0; + release_channel(_ifxhcd, _ifxhc, HC_XFER_BABBLE_ERR); + return 1; + } + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_isoc_rx_csplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + if(hcint.b.xfercomp ) + { + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + disable_hc_int(_hc_regs,nyet); + _urbd->error_count=0; + _ifxhc->split=1; + complete_channel(_ifxhcd, _ifxhc, _urbd); + return 1; + } + else if(hcint.b.nak ) + { + Retry Start Split (in next b_interval ¡V 1 uF) + } + else if(hcint.b.nyet) + { + //Do Next Complete Split + // Issue Retry instantly on next SOF, without gothrough process_channels + _urbd->error_count=0; + //disable_hc_int(_hc_regs,ack); + //disable_hc_int(_hc_regs,nak); + //disable_hc_int(_hc_regs,datatglerr); + _ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + _ifxhc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, _ifxhc); + return 1; + } + else if(hcint.b.frmovrun || hcint.b.stall || hcint.b.bblerr) + { + _urbd->error_count=0; + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nyet); + disable_hc_int(_hc_regs,nak); + _ifxhc->wait_for_sof = 0; + + //if(hctsiz.b.pktcnt==0) + //{ + // complete_channel(_ifxhcd, _ifxhc, _urbd); + // return 1; + //} + //else + // _urbd->urb->actual_length += (_ifxhc->xfer_len - hctsiz.b.xfersize); + if (hcint.b.stall) + release_channel(_ifxhcd, _ifxhc, HC_XFER_STALL); + else if(hcint.b.frmovrun ) + else if(hcint.b.bblerr ) + return 1; + } + else if(hcint.b.xacterr ) + { + Rewind Buffer Pointers + if (HCCHARn.EC = = 3) // ERR response received + { + Record ERR error + Do Next Start Split (in next frame) + } + else + { + De-allocate Channel + } + } + else if(hcint.b.datatglerr ) + { + warning + } + else if(hcint.b.ack ) + { + warning + } + #endif + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static int32_t chhltd_isoc_tx_csplit(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) + hcint_data_t hcint; + hcint_data_t hcintmsk; + hctsiz_data_t hctsiz; + int out_nak_enh = 0; + + if (_ifxhcd->core_if.snpsid >= 0x4f54271a && _ifxhc->speed == IFXUSB_EP_SPEED_HIGH) + out_nak_enh = 1; + + hcint.d32 = ifxusb_rreg(&_hc_regs->hcint); + hcintmsk.d32 = ifxusb_rreg(&_hc_regs->hcintmsk); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + warning + #endif + return 0; +} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/*! + \fn static int32_t handle_hc_chhltd_intr(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) + \brief This function handles halted interrupts of host channels. + \param _ifxhcd Pointer to the sate of HCD structure + \param _ifxhc Pointer to host channel descriptor + \param _hc_regs Pointer to host channel registers + \param _urbd Pointer to URB descriptor + \return 0 OK + \ingroup IFXUSB_HCD + */ +static +int32_t handle_hc_chhltd_intr(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + IFX_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: Channel Halted--\n", _ifxhc->hc_num); + + _ifxhc->phase = HC_STOPPED; + if(_ifxhc->epqh) + if(_ifxhc->epqh->urbd) + _ifxhc->epqh->urbd->phase=URBD_ACTIVE; + + if (_ifxhc->halt_status == HC_XFER_URB_DEQUEUE || + _ifxhc->halt_status == HC_XFER_AHB_ERR) { + /* + * Just release the channel. A dequeue can happen on a + * transfer timeout. In the case of an AHB Error, the channel + * was forced to halt because there's no way to gracefully + * recover. + */ + if(_ifxhc->epqh) + if(_ifxhc->epqh->urbd) + _ifxhc->epqh->urbd->phase=URBD_DEQUEUEING; + release_channel(_ifxhcd, _ifxhc, _ifxhc->halt_status); + return 1; + } + + if (_ifxhc->ep_type == IFXUSB_EP_TYPE_CTRL) + { + if (_ifxhc->split==0) + { + if(_ifxhc->is_in) + return (chhltd_ctrl_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + else + return (chhltd_ctrl_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + } + else if(_ifxhc->split==1) + { + if(_ifxhc->is_in) + return (chhltd_ctrl_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + else + return (chhltd_ctrl_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + } + else if(_ifxhc->split==2) + { + if(_ifxhc->is_in) + return (chhltd_ctrl_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + else + return (chhltd_ctrl_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + } + } + else if(_ifxhc->ep_type == IFXUSB_EP_TYPE_BULK) + { + if (_ifxhc->split==0) + { + if(_ifxhc->is_in) + return (chhltd_bulk_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + else + return (chhltd_bulk_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + } + else if(_ifxhc->split==1) + { + if(_ifxhc->is_in) + return (chhltd_bulk_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + else + return (chhltd_bulk_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + } + else if(_ifxhc->split==2) + { + if(_ifxhc->is_in) + return (chhltd_bulk_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + else + return (chhltd_bulk_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + } + } + else if(_ifxhc->ep_type == IFXUSB_EP_TYPE_INTR) + { + if (_ifxhc->split==0) + { + if(_ifxhc->is_in) + return (chhltd_intr_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + else + return (chhltd_intr_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + } + else if(_ifxhc->split==1) + { + if(_ifxhc->is_in) + return (chhltd_intr_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + else + return (chhltd_intr_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + } + else if(_ifxhc->split==2) + { + if(_ifxhc->is_in) + return (chhltd_intr_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + else + return (chhltd_intr_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + } + } + else if(_ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) + { + if (_ifxhc->split==0) + { + if(_ifxhc->is_in) + return (chhltd_isoc_rx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + else + return (chhltd_isoc_tx_nonsplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + } + else if(_ifxhc->split==1) + { + if(_ifxhc->is_in) + return (chhltd_isoc_rx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + else + return (chhltd_isoc_tx_ssplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + } + else if(_ifxhc->split==2) + { + if(_ifxhc->is_in) + return (chhltd_isoc_rx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + else + return (chhltd_isoc_tx_csplit(_ifxhcd,_ifxhc,_hc_regs,_urbd)); + } + } + return 0; +} + +/* + * Handles a host channel AHB error interrupt. This handler is only called in + * DMA mode. + */ +static void hc_other_intr_dump(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + #ifdef __DEBUG__ + hcchar_data_t hcchar; + hcsplt_data_t hcsplt; + hctsiz_data_t hctsiz; + uint32_t hcdma; + struct urb *urb = _urbd->urb; + hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); + hcsplt.d32 = ifxusb_rreg(&_hc_regs->hcsplt); + hctsiz.d32 = ifxusb_rreg(&_hc_regs->hctsiz); + hcdma = ifxusb_rreg(&_hc_regs->hcdma); + + IFX_ERROR("Channel %d\n", _ifxhc->hc_num); + IFX_ERROR(" hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32); + IFX_ERROR(" hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma); + IFX_ERROR(" Device address: %d\n", usb_pipedevice(urb->pipe)); + IFX_ERROR(" Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe), + (usb_pipein(urb->pipe) ? "IN" : "OUT")); + IFX_ERROR(" Endpoint type: %s\n", + ({char *pipetype; + switch (usb_pipetype(urb->pipe)) { + case PIPE_CONTROL: pipetype = "CTRL"; break; + case PIPE_BULK: pipetype = "BULK"; break; + case PIPE_INTERRUPT: pipetype = "INTR"; break; + case PIPE_ISOCHRONOUS: pipetype = "ISOC"; break; + default: pipetype = "????"; break; + }; pipetype;})); + IFX_ERROR(" Speed: %s\n", + ({char *speed; + switch (urb->dev->speed) { + case USB_SPEED_HIGH: speed = "HS"; break; + case USB_SPEED_FULL: speed = "FS"; break; + case USB_SPEED_LOW: speed = "LS"; break; + default: speed = "????"; break; + }; speed;})); + IFX_ERROR(" Max packet size: %d\n", + usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe))); + IFX_ERROR(" Data buffer length: %d\n", urb->transfer_buffer_length); + IFX_ERROR(" Transfer buffer: %p, Transfer DMA: %p\n", + urb->transfer_buffer, (void *)urb->transfer_dma); + IFX_ERROR(" Setup buffer: %p, Setup DMA: %p\n", + urb->setup_packet, (void *)urb->setup_dma); + IFX_ERROR(" Interval: %d\n", urb->interval); + #endif //__DEBUG__ +} + +/* + * Handles a host channel ACK interrupt. This interrupt is enabled when + * errors occur, and during Start Split transactions. + */ +static +int32_t handle_hc_ack_intr(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + _urbd->error_count=0; + _ifxhc->erron = 0; + + disable_hc_int(_hc_regs,nyet); + + #ifdef __NAKSTOP__ + if(!_ifxhc->stop_on) + { + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + } + #else + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + #endif + return 1; +} + +/* + * Handles a host channel ACK interrupt. This interrupt is enabled when + * errors occur, and during Start Split transactions. + */ +static +int32_t handle_hc_nak_intr(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + _urbd->error_count=0; + _ifxhc->erron=0; + disable_hc_int(_hc_regs,nyet); + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + #ifdef __NAKSTOP__ + if(_ifxhc->stop_on) + { + hcchar_data_t hcchar; + hcchar.d32 = ifxusb_rreg(&_hc_regs->hcchar); + if(hcchar.b.chen) + { + hcchar.b.chdis = 1; + _ifxhc->halt_status = HC_XFER_NAK; + ifxusb_wreg(&_hc_regs->hcchar, hcchar.d32); + } + } + #endif + return 1; +} + +static +int32_t handle_hc_nyet_intr(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + _urbd->error_count=0; + _ifxhc->erron = 0; + + disable_hc_int(_hc_regs,nyet); + #ifdef __NAKSTOP__ + if(!_ifxhc->stop_on) + { + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + } + #else + disable_hc_int(_hc_regs,ack); + disable_hc_int(_hc_regs,nak); + #endif + return 1; +} + +/* + * Handles a host channel AHB error interrupt. This handler is only called in + * DMA mode. + */ +static int32_t handle_hc_ahberr_intr(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + IFX_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: " + "AHB Error--\n", _ifxhc->hc_num); + hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); + + ifxhcd_hc_halt(&_ifxhcd->core_if, _ifxhc, HC_XFER_AHB_ERR); + return 1; +} + +/* + * Datatoggle + */ +static int32_t handle_hc_datatglerr_intr(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + IFX_ERROR( "--Host Channel %d Interrupt: " + "DATATOGGLE Error--\n", _ifxhc->hc_num); + hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); + disable_hc_int(_hc_regs,datatglerr); + return 1; +} + + +/* + * Interrupts which should not been triggered + */ +static int32_t handle_hc_frmovrun_intr(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + IFX_ERROR( "--Host Channel %d Interrupt: " + "FrameOverRun Error--\n", _ifxhc->hc_num); + hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); + disable_hc_int(_hc_regs,frmovrun); + return 1; +} + +static int32_t handle_hc_bblerr_intr(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + IFX_ERROR( "--Host Channel %d Interrupt: " + "BBL Error--\n", _ifxhc->hc_num); + hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); + disable_hc_int(_hc_regs,bblerr); + return 1; +} + +static int32_t handle_hc_xacterr_intr(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + IFX_ERROR( "--Host Channel %d Interrupt: " + "XACT Error--\n", _ifxhc->hc_num); + hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); + disable_hc_int(_hc_regs,xacterr); + return 1; +} + + +static int32_t handle_hc_stall_intr(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + IFX_ERROR( "--Host Channel %d Interrupt: " + "STALL--\n", _ifxhc->hc_num); + hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); + disable_hc_int(_hc_regs,stall); + return 1; +} + +static int32_t handle_hc_xfercomp_intr(ifxhcd_hcd_t *_ifxhcd, + ifxhcd_hc_t *_ifxhc, + ifxusb_hc_regs_t *_hc_regs, + ifxhcd_urbd_t *_urbd) +{ + IFX_ERROR( "--Host Channel %d Interrupt: " + "XFERCOMP--\n", _ifxhc->hc_num); + hc_other_intr_dump(_ifxhcd,_ifxhc,_hc_regs,_urbd); + disable_hc_int(_hc_regs,xfercomp); + return 1; +} + +/* This interrupt indicates that the specified host channels has a pending + * interrupt. There are multiple conditions that can cause each host channel + * interrupt. This function determines which conditions have occurred for this + * host channel interrupt and handles them appropriately. */ +static int32_t handle_hc_n_intr (ifxhcd_hcd_t *_ifxhcd, uint32_t _num) +{ + uint32_t hcintval,hcintmsk; + hcint_data_t hcint; + ifxhcd_hc_t *ifxhc; + ifxusb_hc_regs_t *hc_regs; + ifxhcd_urbd_t *urbd; + + int retval = 0; + + IFX_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", _num); + + ifxhc = &_ifxhcd->ifxhc[_num]; + hc_regs = _ifxhcd->core_if.hc_regs[_num]; + + hcintval = ifxusb_rreg(&hc_regs->hcint); + hcintmsk = ifxusb_rreg(&hc_regs->hcintmsk); + hcint.d32 = hcintval & hcintmsk; + IFX_DEBUGPL(DBG_HCDV, " 0x%08x & 0x%08x = 0x%08x\n", + hcintval, hcintmsk, hcint.d32); + + urbd = ifxhc->epqh->urbd; + + if (hcint.b.ahberr) + retval |= handle_hc_ahberr_intr(_ifxhcd, ifxhc, hc_regs, urbd); + else if (hcint.b.chhltd) + retval |= handle_hc_chhltd_intr(_ifxhcd, ifxhc, hc_regs, urbd); + else + { + if (hcint.b.datatglerr) + retval |= handle_hc_datatglerr_intr(_ifxhcd, ifxhc, hc_regs, urbd); + if (hcint.b.frmovrun) + retval |= handle_hc_frmovrun_intr(_ifxhcd, ifxhc, hc_regs, urbd); + if (hcint.b.bblerr) + retval |= handle_hc_bblerr_intr(_ifxhcd, ifxhc, hc_regs, urbd); + if (hcint.b.xacterr) + retval |= handle_hc_xacterr_intr(_ifxhcd, ifxhc, hc_regs, urbd); + if (hcint.b.nyet) + retval |= handle_hc_nyet_intr(_ifxhcd, ifxhc, hc_regs, urbd); + if (hcint.b.ack) + retval |= handle_hc_ack_intr(_ifxhcd, ifxhc, hc_regs, urbd); + if (hcint.b.nak) + retval |= handle_hc_nak_intr(_ifxhcd, ifxhc, hc_regs, urbd); + if (hcint.b.stall) + retval |= handle_hc_stall_intr(_ifxhcd, ifxhc, hc_regs, urbd); + if (hcint.b.xfercomp) + retval |= handle_hc_xfercomp_intr(_ifxhcd, ifxhc, hc_regs, urbd); + } + + ifxusb_wreg(&hc_regs->hcint,hcintval); + + return retval; +} + + +static uint8_t update_interval_counter(ifxhcd_epqh_t *_epqh,uint32_t _diff) +{ + if(_diff>=_epqh->period_counter) + { + _epqh->period_do=1; + if(_diff>_epqh->interval) + _epqh->period_counter=1; + else + _epqh->period_counter=_epqh->period_counter+_epqh->interval-_diff; + return 1; + } + _epqh->period_counter=_epqh->period_counter-_diff; + return 0; +} + +static +void process_unaligned( ifxhcd_epqh_t *_epqh, ifxusb_core_if_t *_core_if) +{ + ifxhcd_urbd_t *urbd; + urbd =_epqh->urbd; + + #if defined(__UNALIGNED_BUF_ADJ__) || defined(__UNALIGNED_BUF_CHK__) + if(!urbd->aligned_checked) + { + #if defined(__UNALIGNED_BUF_ADJ__) + uint32_t xfer_len; + xfer_len=urbd->xfer_len; + if(urbd->is_in && xfer_len<_epqh->mps) + xfer_len = _epqh->mps; +// urbd->using_aligned_buf=0; + + if(xfer_len > 0 && ((unsigned long)urbd->xfer_buff) & _core_if->unaligned_mask) + { + if( urbd->aligned_buf + && urbd->aligned_buf_len > 0 + && urbd->aligned_buf_len < xfer_len + ) + { + ifxusb_free_buf_h(urbd->aligned_buf); + urbd->aligned_buf=NULL; + urbd->aligned_buf_len=0; + } + if(! urbd->aligned_buf || ! urbd->aligned_buf_len) + { + urbd->aligned_buf = ifxusb_alloc_buf_h(xfer_len, urbd->is_in); + if(urbd->aligned_buf) + urbd->aligned_buf_len = xfer_len; + } + if(urbd->aligned_buf) + { + if(!urbd->is_in) + memcpy(urbd->aligned_buf, urbd->xfer_buff, xfer_len); +// urbd->using_aligned_buf=1; + _epqh->hc->xfer_buff = urbd->aligned_buf; + } + else + IFX_WARN("%s():%d\n",__func__,__LINE__); + } + if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL) + { +// urbd->using_aligned_setup=0; + if(((unsigned long)urbd->setup_buff) & _core_if->unaligned_mask) + { + if(! urbd->aligned_setup) + urbd->aligned_setup = ifxusb_alloc_buf_h(8,0); + if(urbd->aligned_setup) + { + memcpy(urbd->aligned_setup, urbd->setup_buff, 8); +// urbd->using_aligned_setup=1; + } + else + IFX_WARN("%s():%d\n",__func__,__LINE__); + _epqh->hc->xfer_buff = urbd->aligned_setup; + } + } + #elif defined(__UNALIGNED_BUF_CHK__) + if(_epqh->urbd->is_in) + { + if(_epqh->urbd->xfer_len==0) + IFX_WARN("%s():%d IN xfer while length is zero \n",__func__,__LINE__); + else{ + if(_epqh->urbd->xfer_len < _epqh->mps) + IFX_WARN("%s():%d IN xfer while length < mps \n",__func__,__LINE__); + if(((unsigned long)_epqh->urbd->xfer_buff) & _core_if->unaligned_mask) + IFX_WARN("%s():%d IN xfer Buffer UNALIGNED\n",__func__,__LINE__); + } + } + else + { + if(_epqh->urbd->xfer_len > 0 && (((unsigned long)_epqh->urbd->xfer_buff) & _core_if->unaligned_mask)) + IFX_WARN("%s():%d OUT xfer Buffer UNALIGNED\n",__func__,__LINE__); + } + if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL) + { + if(((unsigned long)_epqh->urbd->setup_buff) & _core_if->unaligned_mask) + IFX_WARN("%s():%d SETUP xfer Buffer UNALIGNED\n",__func__,__LINE__); + } + #endif + } + urbd->aligned_checked=1; + #endif +} + +/*! + \brief Assigns transactions from a URBD to a free host channel and initializes the + host channel to perform the transactions. The host channel is removed from + the free list. + \param _ifxhcd The HCD state structure. + \param _epqh Transactions from the first URBD for this EPQH are selected and assigned to a free host channel. + */ +static +int assign_hc(ifxhcd_hcd_t *_ifxhcd, ifxhcd_epqh_t *_epqh,ifxhcd_urbd_t *_urbd) +{ + ifxhcd_hc_t *ifxhc; + struct urb *urb; + + IFX_DEBUGPL(DBG_HCDV, "%s(%p,%p)\n", __func__, _ifxhcd, _epqh); + + if(_ifxhcd->disconnecting) + { + printk(KERN_INFO "Warning: %s() Port is in discoonection\n",__func__); + return 0; + } + + if(!_epqh) return 0; + if(!_urbd) return 0; + if(!_urbd->urb) return 0; + + { + int i; + int num_channels = _ifxhcd->core_if.params.host_channels; + for(i=0;icore_if.hc_regs[i]; + if(_ifxhcd->ifxhc[i].phase!=HC_IDLE) + { + continue; + } + hcchar.d32 = ifxusb_rreg(&hc_regs->hcchar); + if(hcchar.b.chen || hcchar.b.chdis) + { + continue; + } + break; + } + + if(iifxhc[i]; + ifxhc->phase=HC_ASSIGNED; + } + else + return 0; + } + + urb = _urbd->urb; + _epqh->hc = ifxhc; + _epqh->urbd = _urbd; + ifxhc->epqh = _epqh; + /* + * Use usb_pipedevice to determine device address. This address is + * 0 before the SET_ADDRESS command and the correct address afterward. + */ + ifxhc->dev_addr = usb_pipedevice(urb->pipe); + ifxhc->ep_num = usb_pipeendpoint(urb->pipe); + + if (urb->dev->speed == USB_SPEED_LOW) ifxhc->speed = IFXUSB_EP_SPEED_LOW; + else if (urb->dev->speed == USB_SPEED_FULL) ifxhc->speed = IFXUSB_EP_SPEED_FULL; + else ifxhc->speed = IFXUSB_EP_SPEED_HIGH; + + ifxhc->mps = _epqh->mps; + ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + ifxhc->ep_type = _epqh->ep_type; + + ifxhc->split = 0; + if (_epqh->need_split) + { + ifxhc->split = 1; + ifxhc->hub_addr = urb->dev->tt->hub->devnum; + ifxhc->port_addr = urb->dev->ttport; + } + return 1; +} + +/*! + \brief Assigns transactions from a URBD to a free host channel and initializes the + host channel to perform the transactions. The host channel is removed from + the free list. + \param _ifxhcd The HCD state structure. + \param _epqh Transactions from the first URBD for this EPQH are selected and assigned to a free host channel. + */ +static +void init_hc(ifxhcd_epqh_t *_epqh) +{ + ifxhcd_hc_t *ifxhc; + ifxhcd_urbd_t *urbd; + struct urb *urb; + ifxhcd_hcd_t *ifxhcd; + + IFX_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _epqh); + + ifxhc =_epqh->hc; + urbd =_epqh->urbd; + ifxhcd=_epqh->ifxhcd; + urb = urbd->urb; + #if defined(__UNALIGNED_BUF_ADJ__) || defined(__UNALIGNED_BUF_CHK__) + urbd->aligned_checked=0; + #endif + + ifxhc->halt_status = HC_XFER_NO_HALT_STATUS; + + if(_epqh->ep_type==IFXUSB_EP_TYPE_CTRL) + { + ifxhc->control_phase =IFXHCD_CONTROL_SETUP; + ifxhc->is_in = 0; + ifxhc->data_pid_start = IFXUSB_HC_PID_SETUP; + ifxhc->xfer_buff = urbd->setup_buff; + ifxhc->xfer_len = 8; + ifxhc->xfer_count = 0; + ifxhc->short_rw =(urb->transfer_flags & URB_ZERO_PACKET)?1:0; + ifxhc->sof_delay = 0; + _epqh->do_ping=0; + if(!ifxhc->is_in && ifxhc->split==0) + _epqh->do_ping=1; + } + else if(_epqh->ep_type==IFXUSB_EP_TYPE_ISOC) + { + #ifdef __EN_ISOC__ + struct usb_iso_packet_descriptor *frame_desc; + ifxhc->is_in = urbd->is_in; + frame_desc = &urb->iso_frame_desc[urbd->isoc_frame_index]; + urbd->xfer_len = ifxhc->xfer_len = frame_desc->length; + ifxhc->xfer_buff = urbd->xfer_buff; + ifxhc->xfer_buff += frame_desc->offset; + ifxhc->xfer_count = 0; + ifxhc->sof_delay = 0; + if(usb_gettoggle (urb->dev,usb_pipeendpoint (urb->pipe), (ifxhc->is_in)?0:1)) + ifxhc->data_pid_start = IFXUSB_HCTSIZ_DATA1; + else + ifxhc->data_pid_start = IFXUSB_HCTSIZ_DATA0; + + if(ifxhc->is_in) + ifxhc->short_rw =0; + else + ifxhc->short_rw =(urb->transfer_flags & URB_ZERO_PACKET)?1:0; + #ifdef __EN_ISOC_SPLIT__ + ifxhc->isoc_xact_pos = IFXUSB_HCSPLIT_XACTPOS_ALL; + #endif + + _epqh->isoc_frame_index=0; + _epqh->isoc_now=0; + _epqh->isoc_start_frame=0; + if(_urb->transfer_flags && URB_ISO_ASAP) + _epqh->isoc_now=1; + else + _epqh->isoc_start_frame=_urb->start_frame; + #ifdef __EN_ISOC_SPLIT__ + _epqh->isoc_split_pos =0; + _epqh->isoc_split_offset=0; + #endif + _epqh->do_ping=0; + #endif + } + else + { + ifxhc->is_in = urbd->is_in; + ifxhc->xfer_buff = urbd->xfer_buff; + ifxhc->xfer_len = urbd->xfer_len; + ifxhc->xfer_count = 0; + ifxhc->sof_delay = 0; +// if(ifxhc->xfer_len==13 && ifxhc->is_in && _epqh->ep_type==IFXUSB_EP_TYPE_BULK && ifxhc->split==0) +// ifxhc->sof_delay = 8; + if(usb_gettoggle (urb->dev,usb_pipeendpoint (urb->pipe), (ifxhc->is_in)?0:1)) + ifxhc->data_pid_start = IFXUSB_HCTSIZ_DATA1; + else + ifxhc->data_pid_start = IFXUSB_HCTSIZ_DATA0; + if(ifxhc->is_in) + ifxhc->short_rw =0; + else + ifxhc->short_rw =(urb->transfer_flags & URB_ZERO_PACKET)?1:0; + _epqh->do_ping=0; + if(!ifxhc->is_in && ifxhc->split==0) + { + if(_epqh->ep_type==IFXUSB_EP_TYPE_BULK) _epqh->do_ping=1; + } + } + + { + hcint_data_t hc_intr_mask; + uint8_t hc_num = ifxhc->hc_num; + ifxusb_hc_regs_t *hc_regs = ifxhcd->core_if.hc_regs[hc_num]; + + /* Clear old interrupt conditions for this host channel. */ + hc_intr_mask.d32 = 0xFFFFFFFF; + hc_intr_mask.b.reserved = 0; + ifxusb_wreg(&hc_regs->hcint, hc_intr_mask.d32); + + /* Enable channel interrupts required for this transfer. */ + hc_intr_mask.d32 = 0; + hc_intr_mask.b.chhltd = 1; + hc_intr_mask.b.ahberr = 1; + + ifxusb_wreg(&hc_regs->hcintmsk, hc_intr_mask.d32); + + /* Enable the top level host channel interrupt. */ + { + uint32_t intr_enable; + intr_enable = (1 << hc_num); + ifxusb_mreg(&ifxhcd->core_if.host_global_regs->haintmsk, 0, intr_enable); + } + + /* Make sure host channel interrupts are enabled. */ + { + gint_data_t gintmsk ={.d32 = 0}; + gintmsk.b.hcintr = 1; + ifxusb_mreg(&ifxhcd->core_if.core_global_regs->gintmsk, 0, gintmsk.d32); + } + + /* + * Program the HCCHARn register with the endpoint characteristics for + * the current transfer. + */ + { + hcchar_data_t hcchar; + + hcchar.d32 = 0; + hcchar.b.devaddr = ifxhc->dev_addr; + hcchar.b.epnum = ifxhc->ep_num; + hcchar.b.lspddev = (ifxhc->speed == IFXUSB_EP_SPEED_LOW); + hcchar.b.eptype = ifxhc->ep_type; + hcchar.b.mps = ifxhc->mps; + ifxusb_wreg(&hc_regs->hcchar, hcchar.d32); + + IFX_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, ifxhc->hc_num); + IFX_DEBUGPL(DBG_HCDV, " Dev Addr: %d\n" , hcchar.b.devaddr); + IFX_DEBUGPL(DBG_HCDV, " Ep Num: %d\n" , hcchar.b.epnum); + IFX_DEBUGPL(DBG_HCDV, " Is Low Speed: %d\n", hcchar.b.lspddev); + IFX_DEBUGPL(DBG_HCDV, " Ep Type: %d\n" , hcchar.b.eptype); + IFX_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n" , hcchar.b.mps); + IFX_DEBUGPL(DBG_HCDV, " Multi Cnt: %d\n" , hcchar.b.multicnt); + } + /* Program the HCSPLIT register for SPLITs */ + { + hcsplt_data_t hcsplt; + + hcsplt.d32 = 0; + if (ifxhc->split) + { + IFX_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n", ifxhc->hc_num, + (ifxhc->split==2) ? "CSPLIT" : "SSPLIT"); + hcsplt.b.spltena = 1; + hcsplt.b.compsplt = (ifxhc->split==2); + #if defined(__EN_ISOC__) && defined(__EN_ISOC_SPLIT__) + if(_epqh->ep_type==IFXUSB_EP_TYPE_ISOC) + hcsplt.b.xactpos = ifxhc->isoc_xact_pos; + else + #endif + hcsplt.b.xactpos = IFXUSB_HCSPLIT_XACTPOS_ALL; + hcsplt.b.hubaddr = ifxhc->hub_addr; + hcsplt.b.prtaddr = ifxhc->port_addr; + IFX_DEBUGPL(DBG_HCDV, " comp split %d\n" , hcsplt.b.compsplt); + IFX_DEBUGPL(DBG_HCDV, " xact pos %d\n" , hcsplt.b.xactpos); + IFX_DEBUGPL(DBG_HCDV, " hub addr %d\n" , hcsplt.b.hubaddr); + IFX_DEBUGPL(DBG_HCDV, " port addr %d\n" , hcsplt.b.prtaddr); + IFX_DEBUGPL(DBG_HCDV, " is_in %d\n" , ifxhc->is_in); + IFX_DEBUGPL(DBG_HCDV, " Max Pkt: %d\n" , ifxhc->mps); + IFX_DEBUGPL(DBG_HCDV, " xferlen: %d\n" , ifxhc->xfer_len); + } + ifxusb_wreg(&hc_regs->hcsplt, hcsplt.d32); + } + } + process_unaligned(_epqh,&ifxhcd->core_if); + + + #ifdef __NAKSTOP__ + ifxhc->stop_on=0; + if (!ifxhc->split && ifxhc->ep_type == IFXUSB_EP_TYPE_BULK) + { + #ifdef __INNAKSTOP_BULK__ + if(ifxhc->is_in) + ifxhc->stop_on=1; + #endif + #ifdef __PINGSTOP_BULK__ + if(!ifxhc->is_in) + ifxhc->stop_on=1; + #endif + } + #endif +} + + +static +void select_eps_sub(ifxhcd_hcd_t *_ifxhcd) +{ + struct list_head *epqh_ptr; + ifxhcd_epqh_t *epqh; + struct list_head *urbd_ptr; + unsigned long flags; + ifxhcd_urbd_t *urbd; + + hfnum_data_t hfnum; + uint32_t fndiff; + + if(_ifxhcd->disconnecting) + { +// printk(KERN_INFO "Warning: %s() Port is in discoonection\n",__func__); + return ; + } + + local_irq_save(flags); + LOCK_EPQH_LIST(_ifxhcd); + + hfnum.d32 = ifxusb_rreg(&_ifxhcd->core_if.host_global_regs->hfnum); + fndiff = hfnum.b.frnum; + fndiff+= 0x00004000; + fndiff-= _ifxhcd->lastframe ; + fndiff&= 0x00003FFF; + if(!fndiff) fndiff =1; + + #ifdef __EN_ISOC__ + epqh_ptr = _ifxhcd->epqh_list_isoc.next; + while (epqh_ptr != &_ifxhcd->epqh_list_isoc) + { + epqh = list_entry(epqh_ptr, ifxhcd_epqh_t, ql); + epqh_ptr = epqh_ptr->next; + + #ifdef __DYN_SOF_INTR__ + if (!list_empty(&epqh->urbd_list)) + _ifxhcd->dyn_sof_count = DYN_SOF_COUNT_DEF; + #endif + + if(epqh->pause) + continue; + if(epqh->phase==EPQH_READY) + { + if(update_interval_counter(epqh,fndiff) || epqh->isoc_now) + { + LOCK_URBD_LIST(epqh); + urbd_ptr = epqh->urbd_list.next; + while (urbd_ptr != &epqh->urbd_list) + { + urbd = list_entry(urbd_ptr, ifxhcd_urbd_t, ql); + urbd_ptr=urbd_ptr->next; + if(urbd->phase==URBD_IDLE) + { + if(assign_hc(_ifxhcd, epqh,urbd)) + { + IFX_DEBUGPL(DBG_HCD, " select_eps ISOC\n"); + #ifdef __EPQD_DESTROY_TIMEOUT__ + del_timer(&epqh->destroy_timer); + #endif + epqh->isoc_now=0; + list_del_init (&epqh->ql); + list_add_tail(&epqh->ql, &_ifxhcd->epqh_list_isoc); + init_hc(epqh); + epqh->phase=EPQH_ACTIVE; + urbd->phase==URBD_ACTIVE; + epqh->hc.phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, epqh->hc); + } + break; + } + } + UNLOCK_URBD_LIST(epqh); + } + } + } + #endif //__EN_ISOC__ + + epqh_ptr = _ifxhcd->epqh_list_intr.next; + while (epqh_ptr != &_ifxhcd->epqh_list_intr) + { + epqh = list_entry(epqh_ptr, ifxhcd_epqh_t, ql); + epqh_ptr = epqh_ptr->next; + #ifdef __DYN_SOF_INTR__ + if (!list_empty(&epqh->urbd_list)) + _ifxhcd->dyn_sof_count = DYN_SOF_COUNT_DEF; + #endif + if(epqh->pause) + continue; + if(epqh->phase==EPQH_READY) + { + if(update_interval_counter(epqh,fndiff)) + { + LOCK_URBD_LIST(epqh); + urbd_ptr = epqh->urbd_list.next; + while (urbd_ptr != &epqh->urbd_list) + { + urbd = list_entry(urbd_ptr, ifxhcd_urbd_t, ql); + urbd_ptr=urbd_ptr->next; + if(urbd->phase==URBD_IDLE) + { + if(assign_hc(_ifxhcd, epqh,urbd)) + { + IFX_DEBUGPL(DBG_HCD, " select_eps INTR\n"); + #ifdef __EPQD_DESTROY_TIMEOUT__ + del_timer(&epqh->destroy_timer); + #endif + list_del_init (&epqh->ql); + list_add_tail(&epqh->ql, &_ifxhcd->epqh_list_intr); + init_hc(epqh); + epqh->phase=EPQH_ACTIVE; + urbd->phase=URBD_ACTIVE; + epqh->hc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, epqh->hc); + } + break; + } + } + UNLOCK_URBD_LIST(epqh); + } + } + else if(epqh->phase==EPQH_STDBY) + { + if(epqh->period_counter > 0 ) + epqh->period_counter --; + if(epqh->period_counter == 0) + ifxhcd_epqh_idle_periodic(epqh); + update_interval_counter(epqh,fndiff); + } + else + update_interval_counter(epqh,fndiff); + } + + epqh_ptr = _ifxhcd->epqh_list_np.next; + while (epqh_ptr != &_ifxhcd->epqh_list_np) // may need to preserve at lease one for period + { + epqh = list_entry(epqh_ptr, ifxhcd_epqh_t, ql); + epqh_ptr = epqh_ptr->next; + #ifdef __DYN_SOF_INTR__ + if (!list_empty(&epqh->urbd_list)) + _ifxhcd->dyn_sof_count = DYN_SOF_COUNT_DEF; + #endif + if(epqh->pause) + continue; + if(epqh->phase==EPQH_READY) + { + LOCK_URBD_LIST(epqh); + urbd_ptr = epqh->urbd_list.next; + while (urbd_ptr != &epqh->urbd_list) + { + urbd = list_entry(urbd_ptr, ifxhcd_urbd_t, ql); + urbd_ptr=urbd_ptr->next; + if(urbd->phase==URBD_IDLE) + { + if(assign_hc(_ifxhcd, epqh,urbd)) + { + IFX_DEBUGPL(DBG_HCD, " select_eps Non-Period\n"); + #ifdef __EPQD_DESTROY_TIMEOUT__ + del_timer(&epqh->destroy_timer); + #endif + list_del_init (&epqh->ql); + list_add_tail(&epqh->ql, &_ifxhcd->epqh_list_np); + init_hc(epqh); + epqh->phase=EPQH_ACTIVE; + urbd->phase=URBD_ACTIVE; + epqh->hc->phase=HC_WAITING; + ifxhcd_hc_start(_ifxhcd, epqh->hc); + } + break; + } + } + UNLOCK_URBD_LIST(epqh); + } + } + + _ifxhcd->lastframe=hfnum.b.frnum; + + UNLOCK_EPQH_LIST(_ifxhcd); + local_irq_restore(flags); +} + +static +void select_eps_func(unsigned long data) +{ + ifxhcd_hcd_t *ifxhcd; + ifxhcd=((ifxhcd_hcd_t *)data); + + select_eps_sub(ifxhcd); +} + +/*! + \fn void select_eps(ifxhcd_hcd_t *_ifxhcd) + \brief This function selects transactions from the HCD transfer schedule and assigns them to available host channels. + \param _ifxhcd Pointer to the sate of HCD structure + \ingroup IFXUSB_HCD + */ +void select_eps(ifxhcd_hcd_t *_ifxhcd) +{ + if(in_irq()) + { + if(!_ifxhcd->tasklet_select_eps.func) + { + _ifxhcd->tasklet_select_eps.next = NULL; + _ifxhcd->tasklet_select_eps.state = 0; + atomic_set( &_ifxhcd->tasklet_select_eps.count, 0); + _ifxhcd->tasklet_select_eps.func = select_eps_func; + _ifxhcd->tasklet_select_eps.data = (unsigned long)_ifxhcd; + } + tasklet_schedule(&_ifxhcd->tasklet_select_eps); + } + else + { + select_eps_sub(_ifxhcd); + } +} + +static +void ifxhcd_hc_kickstart(ifxhcd_hcd_t *_ifxhcd) +{ + int num_channels; + ifxusb_hc_regs_t *hc_regs; + int i; + ifxhcd_hc_t *ifxhc; + num_channels = _ifxhcd->core_if.params.host_channels; + + for (i = 0; i < num_channels; i++) + { + ifxhc=&_ifxhcd->ifxhc[i]; + if(ifxhc->phase==HC_STARTING) + { + if(ifxhc->sof_delay) ifxhc->sof_delay--; + if(!ifxhc->sof_delay) + { + hcint_data_t hcint; +// ifxhc->erron=0; + hc_regs = _ifxhcd->core_if.hc_regs[i]; + hcint.d32 =0xFFFFFFFF; + ifxusb_wreg(&hc_regs->hcint, hcint.d32); + hcint.d32 =ifxusb_rreg(&hc_regs->hcintmsk); + hcint.b.nak =0; + hcint.b.ack =0; + hcint.b.nyet=0; + if(ifxhc->erron) + { + hcint.b.ack =1; + hcint.b.nak =1; + hcint.b.nyet =1; + } + #ifdef __NAKSTOP__ + if(ifxhc->stop_on) + { + hcint.b.ack =1; + hcint.b.nak =1; + } + #endif + ifxusb_wreg(&hc_regs->hcintmsk, hcint.d32); + ifxusb_wreg(&hc_regs->hcchar, ifxhc->hcchar); + ifxhc->phase=HC_STARTED; + } + } + } + + for (i = 0; i < num_channels; i++) + { + ifxhc=&_ifxhcd->ifxhc[i]; + if(ifxhc->phase==HC_WAITING && + (ifxhc->ep_type == IFXUSB_EP_TYPE_INTR || ifxhc->ep_type == IFXUSB_EP_TYPE_ISOC) + ) + { + ifxhcd_hc_start(_ifxhcd, ifxhc); + } + } + + for (i = 0; i < num_channels; i++) + { + ifxhc=&_ifxhcd->ifxhc[i]; + if(ifxhc->phase==HC_WAITING) + { + ifxhcd_hc_start(_ifxhcd, ifxhc); + } + } +} + +/* + * Handles the start-of-frame interrupt in host mode. Non-periodic + * transactions may be queued to the DWC_otg controller for the current + * (micro)frame. Periodic transactions may be queued to the controller for the + * next (micro)frame. + */ +static +int32_t handle_sof_intr (ifxhcd_hcd_t *_ifxhcd) +{ + _ifxhcd->pkt_remaining=_ifxhcd->pkt_remaining_reload; + ifxhcd_hc_kickstart(_ifxhcd); + + select_eps(_ifxhcd); + + /* Clear interrupt */ + { + gint_data_t gintsts; + gintsts.d32=0; + gintsts.b.sofintr = 1; + ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); + + #ifdef __DYN_SOF_INTR__ + if(_ifxhcd->dyn_sof_count) + _ifxhcd->dyn_sof_count--; + if(!_ifxhcd->dyn_sof_count) + ifxusb_mreg(&_ifxhcd->core_if.core_global_regs->gintmsk, gintsts.d32,0); + #endif + } + return 1; +} + + + +/* There are multiple conditions that can cause a port interrupt. This function + * determines which interrupt conditions have occurred and handles them + * appropriately. */ +static int32_t handle_port_intr (ifxhcd_hcd_t *_ifxhcd) +{ + int retval = 0; + hprt0_data_t hprt0; + hprt0_data_t hprt0_modify; + + hprt0.d32 = + hprt0_modify.d32 = ifxusb_rreg(_ifxhcd->core_if.hprt0); + + /* Clear appropriate bits in HPRT0 to clear the interrupt bit in + * GINTSTS */ + + hprt0_modify.b.prtena = 0; + hprt0_modify.b.prtconndet = 0; + hprt0_modify.b.prtenchng = 0; + hprt0_modify.b.prtovrcurrchng = 0; + + /* Port Connect Detected + * Set flag and clear if detected */ + if (hprt0.b.prtconndet) { + IFX_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x " + "Port Connect Detected--\n", hprt0.d32); + _ifxhcd->flags.b.port_connect_status_change = 1; + _ifxhcd->flags.b.port_connect_status = 1; + hprt0_modify.b.prtconndet = 1; + + /* The Hub driver asserts a reset when it sees port connect + * status change flag */ + retval |= 1; + } + + /* Port Enable Changed + * Clear if detected - Set internal flag if disabled */ + if (hprt0.b.prtenchng) { + IFX_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " + "Port Enable Changed--\n", hprt0.d32); + hprt0_modify.b.prtenchng = 1; + if (hprt0.b.prtena == 1) + { + /* Port has been enabled set the reset change flag */ + _ifxhcd->flags.b.port_reset_change = 1; + if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED) + _ifxhcd->pkt_remaining_reload=_ifxhcd->pkt_remaining_reload_hs; + else if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_LOW_SPEED) + _ifxhcd->pkt_remaining_reload=_ifxhcd->pkt_remaining_reload_ls; + else + _ifxhcd->pkt_remaining_reload=_ifxhcd->pkt_remaining_reload_fs; + } + else + _ifxhcd->flags.b.port_enable_change = 1; + retval |= 1; + } + + /* Overcurrent Change Interrupt */ + + if (hprt0.b.prtovrcurrchng) { + IFX_DEBUGPL(DBG_HCD, " --Port Interrupt HPRT0=0x%08x " + "Port Overcurrent Changed--\n", hprt0.d32); + _ifxhcd->flags.b.port_over_current_change = 1; + hprt0_modify.b.prtovrcurrchng = 1; + retval |= 1; + } + + /* Clear Port Interrupts */ + ifxusb_wreg(_ifxhcd->core_if.hprt0, hprt0_modify.d32); + return retval; +} + +/* + * This interrupt indicates that SUSPEND state has been detected on + * the USB. + * No Functioning in Host Mode + */ +static int32_t handle_usb_suspend_intr(ifxhcd_hcd_t *_ifxhcd) +{ + gint_data_t gintsts; + IFX_DEBUGP("USB SUSPEND RECEIVED!\n"); + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.usbsuspend = 1; + ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); + return 1; +} + +/* + * This interrupt indicates that the IFXUSB controller has detected a + * resume or remote wakeup sequence. If the IFXUSB controller is in + * low power mode, the handler must brings the controller out of low + * power mode. The controller automatically begins resume + * signaling. The handler schedules a time to stop resume signaling. + */ +static int32_t handle_wakeup_detected_intr(ifxhcd_hcd_t *_ifxhcd) +{ + gint_data_t gintsts; + hprt0_data_t hprt0 = {.d32=0}; + pcgcctl_data_t pcgcctl = {.d32=0}; + ifxusb_core_if_t *core_if = &_ifxhcd->core_if; + + IFX_DEBUGPL(DBG_ANY, "++Resume and Remote Wakeup Detected Interrupt++\n"); + + /* + * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms + * so that OPT tests pass with all PHYs). + */ + /* Restart the Phy Clock */ + pcgcctl.b.stoppclk = 1; + ifxusb_mreg(core_if->pcgcctl, pcgcctl.d32, 0); + UDELAY(10); + + /* Now wait for 70 ms. */ + hprt0.d32 = ifxusb_read_hprt0( core_if ); + IFX_DEBUGPL(DBG_ANY,"Resume: HPRT0=%0x\n", hprt0.d32); + MDELAY(70); + hprt0.b.prtres = 0; /* Resume */ + ifxusb_wreg(core_if->hprt0, hprt0.d32); + IFX_DEBUGPL(DBG_ANY,"Clear Resume: HPRT0=%0x\n", ifxusb_rreg(core_if->hprt0)); + + /* Clear interrupt */ + gintsts.d32 = 0; + gintsts.b.wkupintr = 1; + ifxusb_wreg(&core_if->core_global_regs->gintsts, gintsts.d32); + return 1; +} + +/* + * This interrupt indicates that a device is initiating the Session + * Request Protocol to request the host to turn on bus power so a new + * session can begin. The handler responds by turning on bus power. If + * the DWC_otg controller is in low power mode, the handler brings the + * controller out of low power mode before turning on bus power. + */ +static int32_t handle_session_req_intr(ifxhcd_hcd_t *_ifxhcd) +{ + /* Clear interrupt */ + gint_data_t gintsts = { .d32 = 0 }; + gintsts.b.sessreqintr = 1; + ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); + return 1; +} + +/* + * This interrupt indicates that a device has been disconnected from + * the root port. + */ +static int32_t handle_disconnect_intr(ifxhcd_hcd_t *_ifxhcd) +{ + gint_data_t gintsts; + + ifxhcd_disconnect(_ifxhcd); + + gintsts.d32 = 0; + gintsts.b.disconnect = 1; + ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); + return 1; +} + +/* + * This function handles the Connector ID Status Change Interrupt. It + * reads the OTG Interrupt Register (GOTCTL) to determine whether this + * is a Device to Host Mode transition or a Host Mode to Device + * Transition. + * This only occurs when the cable is connected/removed from the PHY + * connector. + */ +static int32_t handle_conn_id_status_change_intr(ifxhcd_hcd_t *_ifxhcd) +{ + gint_data_t gintsts; + + IFX_WARN("ID Status Change Interrupt: currently in %s mode\n", + ifxusb_mode(&_ifxhcd->core_if) ? "Host" : "Device"); + + gintsts.d32 = 0; + gintsts.b.conidstschng = 1; + ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); + return 1; +} + +static int32_t handle_otg_intr(ifxhcd_hcd_t *_ifxhcd) +{ + ifxusb_core_global_regs_t *global_regs = _ifxhcd->core_if.core_global_regs; + gotgint_data_t gotgint; + gotgint.d32 = ifxusb_rreg( &global_regs->gotgint); + /* Clear GOTGINT */ + ifxusb_wreg (&global_regs->gotgint, gotgint.d32); + return 1; +} + +/** This function will log a debug message */ +static int32_t handle_mode_mismatch_intr(ifxhcd_hcd_t *_ifxhcd) +{ + gint_data_t gintsts; + + IFX_WARN("Mode Mismatch Interrupt: currently in %s mode\n", + ifxusb_mode(&_ifxhcd->core_if) ? "Host" : "Device"); + gintsts.d32 = 0; + gintsts.b.modemismatch = 1; + ifxusb_wreg(&_ifxhcd->core_if.core_global_regs->gintsts, gintsts.d32); + return 1; +} + +/** This function handles interrupts for the HCD. */ +int32_t ifxhcd_handle_intr (ifxhcd_hcd_t *_ifxhcd) +{ + int retval = 0; + + ifxusb_core_if_t *core_if = &_ifxhcd->core_if; + gint_data_t gintsts,gintsts2; + + /* Check if HOST Mode */ + if (ifxusb_is_device_mode(core_if)) + { + IFX_ERROR("%s() CRITICAL! IN DEVICE MODE\n", __func__); + return 0; + } + + gintsts.d32 = ifxusb_read_core_intr(core_if); + gintsts2.d32 = 0; + + if (!gintsts.d32) + return 0; + + //Common INT + if (gintsts.b.modemismatch) + { + retval |= handle_mode_mismatch_intr(_ifxhcd); + gintsts.b.modemismatch=0; + gintsts2.b.modemismatch=1; + } + if (gintsts.b.otgintr) + { + retval |= handle_otg_intr(_ifxhcd); + gintsts.b.otgintr=0; + gintsts2.b.otgintr=1; + } + if (gintsts.b.conidstschng) + { + retval |= handle_conn_id_status_change_intr(_ifxhcd); + gintsts.b.conidstschng=0; + gintsts2.b.conidstschng=1; + } + if (gintsts.b.disconnect) + { + retval |= handle_disconnect_intr(_ifxhcd); + gintsts.b.disconnect=0; + gintsts2.b.disconnect=1; + } + if (gintsts.b.sessreqintr) + { + retval |= handle_session_req_intr(_ifxhcd); + gintsts.b.sessreqintr=0; + gintsts2.b.sessreqintr=1; + } + if (gintsts.b.wkupintr) + { + retval |= handle_wakeup_detected_intr(_ifxhcd); + gintsts.b.wkupintr=0; + gintsts2.b.wkupintr=1; + } + if (gintsts.b.usbsuspend) + { + retval |= handle_usb_suspend_intr(_ifxhcd); + gintsts.b.usbsuspend=0; + gintsts2.b.usbsuspend=1; + } + + //Host Int + if (gintsts.b.sofintr) + { + retval |= handle_sof_intr (_ifxhcd); + gintsts.b.sofintr=0; + gintsts2.b.sofintr=1; + } + if (gintsts.b.portintr) + { + retval |= handle_port_intr (_ifxhcd); + gintsts.b.portintr=0; + gintsts2.b.portintr=1; + } + if (gintsts.b.hcintr) + { + int i; + haint_data_t haint; + haint.d32 = ifxusb_read_host_all_channels_intr(core_if); + for (i=0; iparams.host_channels; i++) + if (haint.b2.chint & (1 << i)) + retval |= handle_hc_n_intr (_ifxhcd, i); + gintsts.b.hcintr=0; + gintsts2.b.hcintr=1; + } + return retval; +} + diff --git a/package/platform/lantiq/ltq-hcd/src/ifxhcd_queue.c b/package/platform/lantiq/ltq-hcd/src/ifxhcd_queue.c new file mode 100644 index 0000000000..a30fcd05e9 --- /dev/null +++ b/package/platform/lantiq/ltq-hcd/src/ifxhcd_queue.c @@ -0,0 +1,485 @@ +/***************************************************************************** + ** FILE NAME : ifxhcd_queue.c + ** PROJECT : IFX USB sub-system V3 + ** MODULES : IFX USB sub-system Host and Device driver + ** SRC VERSION : 3.2 + ** DATE : 1/Jan/2011 + ** AUTHOR : Chen, Howard + ** DESCRIPTION : This file contains the functions to manage Queue Heads and Queue + ** Transfer Descriptors. + ** FUNCTIONS : + ** COMPILER : gcc + ** REFERENCE : Synopsys DWC-OTG Driver 2.7 + ** COPYRIGHT : Copyright (c) 2010 + ** LANTIQ DEUTSCHLAND GMBH, + ** Am Campeon 3, 85579 Neubiberg, Germany + ** + ** This program is free software; you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation; either version 2 of the License, or + ** (at your option) any later version. + ** + ** Version Control Section ** + ** $Author$ + ** $Date$ + ** $Revisions$ + ** $Log$ Revision history + *****************************************************************************/ + +/* + * This file contains code fragments from Synopsys HS OTG Linux Software Driver. + * For this code the following notice is applicable: + * + * ========================================================================== + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +/*! + \file ifxhcd_queue.c + \ingroup IFXUSB_DRIVER_V3 + \brief This file contains the functions to manage Queue Heads and Queue + Transfer Descriptors. +*/ +#include +#include "ifxusb_version.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ifxusb_plat.h" +#include "ifxusb_regs.h" +#include "ifxusb_cif.h" +#include "ifxhcd.h" + +#ifdef __EPQD_DESTROY_TIMEOUT__ + #define epqh_self_destroy_timeout 300 + static void eqph_destroy_func(unsigned long _ptr) + { + ifxhcd_epqh_t *epqh=(ifxhcd_epqh_t *)_ptr; + if(epqh) + { + if(epqh->sysep) + { + epqh->sysep->hcpriv=NULL; + } + ifxhcd_epqh_free (epqh); + } + } +#endif + +/*! + \brief This function allocates and initializes a EPQH. + + \param _ifxhcd The HCD state structure for the USB Host controller. + \param[in] _urb Holds the information about the device/endpoint that we need + to initialize the EPQH. + + \return Returns pointer to the newly allocated EPQH, or NULL on error. + */ +static ifxhcd_epqh_t *ifxhcd_epqh_create (ifxhcd_hcd_t *_ifxhcd, struct urb *_urb) +{ + ifxhcd_epqh_t *epqh; + + hprt0_data_t hprt0; + struct usb_host_endpoint *sysep = ifxhcd_urb_to_endpoint(_urb); + + /* Allocate memory */ +// epqh=(ifxhcd_epqh_t *) kmalloc (sizeof(ifxhcd_epqh_t), GFP_KERNEL); + epqh=(ifxhcd_epqh_t *) kmalloc (sizeof(ifxhcd_epqh_t), GFP_ATOMIC); + + if(epqh == NULL) + return NULL; + + memset (epqh, 0, sizeof (ifxhcd_epqh_t)); + + epqh->sysep=sysep; + + epqh->devno=_urb->dev->devnum; + + epqh->ifxhcd=_ifxhcd; + epqh->phase=EPQH_IDLE; + + /* Initialize EPQH */ + switch (usb_pipetype(_urb->pipe)) + { + case PIPE_CONTROL : epqh->ep_type = IFXUSB_EP_TYPE_CTRL; break; + case PIPE_BULK : epqh->ep_type = IFXUSB_EP_TYPE_BULK; break; + case PIPE_ISOCHRONOUS: epqh->ep_type = IFXUSB_EP_TYPE_ISOC; break; + case PIPE_INTERRUPT : epqh->ep_type = IFXUSB_EP_TYPE_INTR; break; + } + + usb_settoggle(_urb->dev, usb_pipeendpoint (_urb->pipe), !usb_pipein(_urb->pipe), IFXUSB_HC_PID_DATA0); + epqh->mps = usb_maxpacket(_urb->dev, _urb->pipe, !(usb_pipein(_urb->pipe))); + + INIT_LIST_HEAD(&epqh->urbd_list); + #ifdef __STRICT_ORDER__ + INIT_LIST_HEAD(&epqh->release_list); + #endif + INIT_LIST_HEAD(&epqh->ql); + INIT_LIST_HEAD(&epqh->ql_all); + INIT_URBD_LIST(epqh); + + epqh->hc = NULL; + + /* FS/LS Enpoint on HS Hub + * NOT virtual root hub */ + epqh->need_split = 0; + hprt0.d32 = ifxusb_read_hprt0 (&_ifxhcd->core_if); + if (hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED && + ((_urb->dev->speed == USB_SPEED_LOW) || + (_urb->dev->speed == USB_SPEED_FULL)) && + (_urb->dev->tt) && (_urb->dev->tt->hub) && (_urb->dev->tt->hub->devnum != 1)) + { + IFX_DEBUGPL(DBG_HCD, "QH init: EP %d: TT found at hub addr %d, for port %d\n", + usb_pipeendpoint(_urb->pipe), _urb->dev->tt->hub->devnum, + _urb->dev->ttport); + epqh->need_split = 1; + } + + if (epqh->ep_type == IFXUSB_EP_TYPE_INTR || + epqh->ep_type == IFXUSB_EP_TYPE_ISOC) + { + /* Compute scheduling parameters once and save them. */ + epqh->interval = _urb->interval; + if(epqh->need_split) + epqh->interval *= 8; + } + + #ifdef __EN_ISOC__ + if (epqh->ep_type == IFXUSB_EP_TYPE_ISOC) + _ifxhcd->isoc_ep_count++; + #endif + + epqh->period_counter=0; + + #ifdef __EPQD_DESTROY_TIMEOUT__ + /* Start a timer for this transfer. */ + init_timer(&epqh->destroy_timer); + epqh->destroy_timer.function = eqph_destroy_func; + epqh->destroy_timer.data = (unsigned long)(epqh); + #endif + + #ifdef __DEBUG__ + IFX_DEBUGPL(DBG_HCD , "IFXUSB HCD EPQH Initialized\n"); + IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - epqh = %p\n", epqh); + IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - Device Address = %d EP %d, %s\n", + _urb->dev->devnum, + usb_pipeendpoint(_urb->pipe), + usb_pipein(_urb->pipe) == USB_DIR_IN ? "IN" : "OUT"); + IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - Speed = %s\n", + ({ char *speed; switch (_urb->dev->speed) { + case USB_SPEED_LOW: speed = "low" ; break; + case USB_SPEED_FULL: speed = "full"; break; + case USB_SPEED_HIGH: speed = "high"; break; + default: speed = "?"; break; + }; speed;})); + IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - Type = %s\n", + ({ + char *type; switch (epqh->ep_type) + { + case IFXUSB_EP_TYPE_ISOC: type = "isochronous"; break; + case IFXUSB_EP_TYPE_INTR: type = "interrupt" ; break; + case IFXUSB_EP_TYPE_CTRL: type = "control" ; break; + case IFXUSB_EP_TYPE_BULK: type = "bulk" ; break; + default: type = "?"; break; + }; + type; + })); + if (epqh->ep_type == IFXUSB_EP_TYPE_INTR) + IFX_DEBUGPL(DBG_HCDV, "IFXUSB HCD EPQH - interval = %d\n", epqh->interval); + #endif + + LOCK_EPQH_LIST_ALL(_ifxhcd); + list_add_tail(&epqh->ql_all, &_ifxhcd->epqh_list_all); + UNLOCK_EPQH_LIST_ALL(_ifxhcd); + + LOCK_EPQH_LIST(_ifxhcd); + switch (epqh->ep_type) + { + case IFXUSB_EP_TYPE_CTRL: + case IFXUSB_EP_TYPE_BULK: + + list_add_tail(&epqh->ql, &_ifxhcd->epqh_list_np); + break; + case IFXUSB_EP_TYPE_INTR: + list_add_tail(&epqh->ql, &_ifxhcd->epqh_list_intr); + break; + #ifdef __EN_ISOC__ + case IFXUSB_EP_TYPE_ISOC: + list_add_tail(&epqh->ql, &_ifxhcd->epqh_list_isoc); + + break; + #endif + } + UNLOCK_EPQH_LIST(_ifxhcd); + return epqh; +} + + + + + + +/*! + \brief Free the EPQH. EPQH should already be removed from a list. + URBD list should already be empty if called from URB Dequeue. + + \param[in] _epqh The EPQH to free. + */ +void ifxhcd_epqh_free (ifxhcd_epqh_t *_epqh) +{ + unsigned long flags; + if(!_epqh) + return; + + if(_epqh->sysep) _epqh->sysep->hcpriv=NULL; + _epqh->sysep=NULL; + + local_irq_save (flags); + if (!list_empty(&_epqh->urbd_list)) + IFX_WARN("%s() invalid epqh state\n",__func__); + else + { + LOCK_EPQH_LIST_ALL(_epqh->ifxhcd); + if (!list_empty(&_epqh->ql_all)) + list_del_init (&_epqh->ql_all); + UNLOCK_EPQH_LIST_ALL(_epqh->ifxhcd); + + LOCK_EPQH_LIST(_epqh->ifxhcd); + if (!list_empty(&_epqh->ql)) + list_del_init (&_epqh->ql); + UNLOCK_EPQH_LIST(_epqh->ifxhcd); + + #ifdef __EPQD_DESTROY_TIMEOUT__ + del_timer(&_epqh->destroy_timer); + #endif + kfree (_epqh); + } + local_irq_restore (flags); +} + + +void ifxhcd_epqh_idle(ifxhcd_epqh_t *_epqh) +{ + unsigned long flags; + local_irq_save(flags); + LOCK_URBD_LIST(_epqh); + if (list_empty(&_epqh->urbd_list)) + { + if(_epqh->ep_type == IFXUSB_EP_TYPE_ISOC || _epqh->ep_type == IFXUSB_EP_TYPE_INTR) + _epqh->phase=EPQH_STDBY; + else + { + _epqh->phase=EPQH_IDLE; + #ifdef __EPQD_DESTROY_TIMEOUT__ + del_timer(&_epqh->destroy_timer); + _epqh->destroy_timer.expires = jiffies + (HZ*epqh_self_destroy_timeout); + add_timer(&_epqh->destroy_timer ); + #endif + } + } + else + { + _epqh->phase=EPQH_READY; + #ifdef __EPQD_DESTROY_TIMEOUT__ + del_timer(&_epqh->destroy_timer); + #endif + } + UNLOCK_URBD_LIST(_epqh); + local_irq_restore(flags); +} + + +void ifxhcd_epqh_idle_periodic(ifxhcd_epqh_t *_epqh) +{ + unsigned long flags; + if(_epqh->ep_type != IFXUSB_EP_TYPE_ISOC && _epqh->ep_type != IFXUSB_EP_TYPE_INTR && _epqh->phase!=EPQH_STDBY) + return; + + local_irq_save(flags); + LOCK_URBD_LIST(_epqh); + if (!list_empty(&_epqh->urbd_list)) + IFX_WARN("%s() invalid epqh state(not empty)\n",__func__); + + _epqh->phase=EPQH_IDLE; + + #ifdef __EPQD_DESTROY_TIMEOUT__ + del_timer(&_epqh->destroy_timer); + _epqh->destroy_timer.expires = jiffies + (HZ*epqh_self_destroy_timeout); + add_timer(&_epqh->destroy_timer ); + #endif + + #ifdef __EN_ISOC__ + if (_epqh->ep_type == IFXUSB_EP_TYPE_ISOC) + _epqh->ifxhcd->isoc_ep_count--; + #endif + UNLOCK_URBD_LIST(_epqh); + local_irq_restore(flags); +} + + +ifxhcd_epqh_t *ifxhcd_urbd_create (ifxhcd_hcd_t *_ifxhcd,struct urb *_urb) +{ + ifxhcd_urbd_t *urbd; + struct usb_host_endpoint *sysep; + ifxhcd_epqh_t *epqh=NULL; + unsigned long flags; + + local_irq_save(flags); + + sysep = ifxhcd_urb_to_endpoint(_urb); + + LOCK_EPQH_LIST_ALL(_ifxhcd); + epqh = sysep_to_epqh(_ifxhcd, sysep); + + if (!epqh) + { + sysep->hcpriv = NULL; + epqh = ifxhcd_epqh_create (_ifxhcd, _urb); + } + UNLOCK_EPQH_LIST_ALL(_ifxhcd); + + if (!epqh) + { + IFX_ERROR("EPQH Error alloc\n"); + local_irq_restore (flags); + return (ifxhcd_epqh_t *)NULL; + } + if(epqh->phase==EPQH_DISABLING) + { + IFX_ERROR("EPQH Error alloc while disabling\n"); + local_irq_restore (flags); + return (ifxhcd_epqh_t *)NULL; + } + sysep->hcpriv = epqh; + + if(_urb->hcpriv) + { + IFX_WARN("%s() Previous urb->hcpriv exist %p\n",__func__,_urb->hcpriv); + #if 1 + local_irq_restore (flags); + return (ifxhcd_epqh_t *)NULL; + #else + urbd = _urb->hcpriv; + if(urbd->epqh!=epqh) + IFX_WARN("%s() Previous urb->hcpriv exist %p and epqh not the same %p %p\n",__func__,_urb->hcpriv,urbd->epqh,epqh); + #endif + } + else + { + urbd = (ifxhcd_urbd_t *) kmalloc (sizeof(ifxhcd_urbd_t), GFP_ATOMIC); + if (!urbd) + { + local_irq_restore (flags); + return (ifxhcd_epqh_t *)NULL; + } + memset (urbd, 0, sizeof (ifxhcd_urbd_t)); + INIT_LIST_HEAD(&urbd->ql); + } + + _urb->hcpriv = urbd; + urbd->urb = _urb; + urbd->epqh = epqh; + urbd->status= -EINPROGRESS; + + urbd->is_in=usb_pipein(_urb->pipe) ? 1 : 0; +#define URB_NO_SETUP_DMA_MAP 0 + #ifdef __EN_ISOC__ + if(epqh->ep_type == IFXUSB_EP_TYPE_ISOC) + { + if(_urb->transfer_flags && URB_NO_TRANSFER_DMA_MAP) + urbd->xfer_buff = (uint8_t *) (KSEG1ADDR((uint32_t *)_urb->transfer_dma)); + else + urbd->xfer_buff = (uint8_t *) _urb->transfer_buffer; + } + else + #endif + { + urbd->xfer_len=_urb->transfer_buffer_length; + if(urbd->xfer_len>0) + { + if(_urb->transfer_flags && URB_NO_TRANSFER_DMA_MAP) + urbd->xfer_buff = (uint8_t *) (KSEG1ADDR((uint32_t *)_urb->transfer_dma)); + else + urbd->xfer_buff = (uint8_t *) _urb->transfer_buffer; + } + } + + #if 1 // cache write-back, so DMA engine can get correct content. Precaution + if(urbd->xfer_len) + dma_cache_wback_inv((unsigned long)urbd->xfer_buff, urbd->xfer_len); + #endif + + if(epqh->ep_type == IFXUSB_EP_TYPE_CTRL) + { + if(_urb->transfer_flags && URB_NO_SETUP_DMA_MAP) + urbd->setup_buff = (uint8_t *) (KSEG1ADDR((uint32_t *)_urb->setup_dma)); + else + urbd->setup_buff = (uint8_t *) _urb->setup_packet; + #if 1 // cache write-back, so DMA engine can get correct content. Precaution + dma_cache_wback_inv((unsigned long)urbd->setup_buff, 16); + #endif + } + + LOCK_URBD_LIST(epqh); + if (!list_empty(&urbd->ql)) + list_del_init(&urbd->ql); + list_add_tail(&urbd->ql, &epqh->urbd_list); + epqh->urbd_count++; + UNLOCK_URBD_LIST(epqh); + + local_irq_restore (flags); + return epqh; +} + + + +ifxhcd_epqh_t * sysep_to_epqh(ifxhcd_hcd_t *_ifxhcd, struct usb_host_endpoint *_sysep) +{ + ifxhcd_epqh_t *epqh; + + LOCK_EPQH_LIST_ALL(_ifxhcd); + list_for_each_entry( epqh, &_ifxhcd->epqh_list_all, ql_all) + { + if(epqh->sysep==_sysep) + { + UNLOCK_EPQH_LIST_ALL(_ifxhcd); + return epqh; + } + } + UNLOCK_EPQH_LIST_ALL(_ifxhcd); + return NULL; +} + diff --git a/package/platform/lantiq/ltq-hcd/src/ifxusb_cif.c b/package/platform/lantiq/ltq-hcd/src/ifxusb_cif.c new file mode 100644 index 0000000000..9f0262578e --- /dev/null +++ b/package/platform/lantiq/ltq-hcd/src/ifxusb_cif.c @@ -0,0 +1,1686 @@ +/***************************************************************************** + ** FILE NAME : ifxusb_cif.c + ** PROJECT : IFX USB sub-system V3 + ** MODULES : IFX USB sub-system Host and Device driver + ** SRC VERSION : 1.0 + ** SRC VERSION : 3.2 + ** DATE : 1/Jan/2011 + ** DESCRIPTION : The Core Interface provides basic services for accessing and + ** managing the IFX USB hardware. These services are used by both the + ** Host Controller Driver and the Peripheral Controller Driver. + ** FUNCTIONS : + ** COMPILER : gcc + ** REFERENCE : Synopsys DWC-OTG Driver 2.7 + ** COPYRIGHT : Copyright (c) 2010 + ** LANTIQ DEUTSCHLAND GMBH, + ** Am Campeon 3, 85579 Neubiberg, Germany + ** + ** This program is free software; you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation; either version 2 of the License, or + ** (at your option) any later version. + ** + ** Version Control Section ** + ** $Author$ + ** $Date$ + ** $Revisions$ + ** $Log$ Revision history + *****************************************************************************/ + +/* + * This file contains code fragments from Synopsys HS OTG Linux Software Driver. + * For this code the following notice is applicable: + * + * ========================================================================== + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +/*! + \file ifxusb_cif.c + \ingroup IFXUSB_DRIVER_V3 + \brief This file contains the interface to the IFX USB Core. +*/ + +#include +#include "ifxusb_version.h" + +#include +#include + +#ifdef __DEBUG__ + #include +#include +#include +#include +#endif + + +#include "ifxusb_plat.h" +#include "ifxusb_regs.h" +#include "ifxusb_cif.h" + + +#ifdef __IS_DEVICE__ + #include "ifxpcd.h" +#endif + +#ifdef __IS_HOST__ + #include "ifxhcd.h" +#endif + +#include + +#include + +#include + +#if defined(__UEIP__) + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) + #ifndef USB_CTRL_PMU_SETUP + #define USB_CTRL_PMU_SETUP(__x) USB0_CTRL_PMU_SETUP(__x) + #endif + #ifndef USB_PHY_PMU_SETUP + #define USB_PHY_PMU_SETUP(__x) USB0_PHY_PMU_SETUP(__x) + #endif + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) +#endif // defined(__UEIP__) + +/*! + \brief This function is called to allocate buffer of specified size. + The allocated buffer is mapped into DMA accessable address. + \param size Size in BYTE to be allocated + \param clear 0: don't do clear after buffer allocated, other: do clear to zero + \return 0/NULL: Fail; uncached pointer of allocated buffer + */ +#ifdef __IS_HOST__ +void *ifxusb_alloc_buf_h(size_t size, int clear) +#else +void *ifxusb_alloc_buf_d(size_t size, int clear) +#endif +{ + uint32_t *cached,*uncached; + uint32_t totalsize,page; + + if(!size) + return 0; + + size=(size+3)&0xFFFFFFFC; + totalsize=size + 12; + page=get_order(totalsize); + + cached = (void *) __get_free_pages(( GFP_ATOMIC | GFP_DMA), page); + + if(!cached) + { + IFX_PRINT("%s Allocation Failed size:%d\n",__func__,size); + return NULL; + } + + uncached = (uint32_t *)(KSEG1ADDR(cached)); + if(clear) + memset(uncached, 0, totalsize); + + *(uncached+0)=totalsize; + *(uncached+1)=page; + *(uncached+2)=(uint32_t)cached; + return (void *)(uncached+3); +} + + +/*! + \brief This function is called to free allocated buffer. + \param vaddr the uncached pointer of the buffer + */ +#ifdef __IS_HOST__ +void ifxusb_free_buf_h(void *vaddr) +#else +void ifxusb_free_buf_d(void *vaddr) +#endif +{ + uint32_t totalsize,page; + uint32_t *cached,*uncached; + + if(vaddr != NULL) + { + uncached=vaddr; + uncached-=3; + totalsize=*(uncached+0); + page=*(uncached+1); + cached=(uint32_t *)(*(uncached+2)); + if(totalsize && page==get_order(totalsize) && cached==(uint32_t *)(KSEG0ADDR(uncached))) + { + free_pages((unsigned long)cached, page); + return; + } + // the memory is not allocated by ifxusb_alloc_buf. Allowed but must be careful. + return; + } +} + + + +/*! + \brief This function is called to initialize the IFXUSB CSR data + structures. The register addresses in the device and host + structures are initialized from the base address supplied by the + caller. The calling function must make the OS calls to get the + base address of the IFXUSB controller registers. + + \param _core_if Pointer of core_if structure + \param _irq irq number + \param _reg_base_addr Base address of IFXUSB core registers + \param _fifo_base_addr Fifo base address + \param _fifo_dbg_addr Fifo debug address + \return 0: success; + */ +#ifdef __IS_HOST__ +int ifxusb_core_if_init_h(ifxusb_core_if_t *_core_if, +#else +int ifxusb_core_if_init_d(ifxusb_core_if_t *_core_if, +#endif + int _irq, + uint32_t _reg_base_addr, + uint32_t _fifo_base_addr, + uint32_t _fifo_dbg_addr) +{ + int retval = 0; + uint32_t *reg_base =NULL; + uint32_t *fifo_base =NULL; + uint32_t *fifo_dbg =NULL; + + int i; + + IFX_DEBUGPL(DBG_CILV, "%s(%p,%d,0x%08X,0x%08X,0x%08X)\n", __func__, + _core_if, + _irq, + _reg_base_addr, + _fifo_base_addr, + _fifo_dbg_addr); + + if( _core_if == NULL) + { + IFX_ERROR("%s() invalid _core_if\n", __func__); + retval = -ENOMEM; + goto fail; + } + + //memset(_core_if, 0, sizeof(ifxusb_core_if_t)); + + _core_if->irq=_irq; + + reg_base =ioremap_nocache(_reg_base_addr , IFXUSB_IOMEM_SIZE ); + fifo_base =ioremap_nocache(_fifo_base_addr, IFXUSB_FIFOMEM_SIZE); + fifo_dbg =ioremap_nocache(_fifo_dbg_addr , IFXUSB_FIFODBG_SIZE); + if( reg_base == NULL || fifo_base == NULL || fifo_dbg == NULL) + { + IFX_ERROR("%s() usb ioremap() failed\n", __func__); + retval = -ENOMEM; + goto fail; + } + + _core_if->core_global_regs = (ifxusb_core_global_regs_t *)reg_base; + + /* + * Attempt to ensure this device is really a IFXUSB Controller. + * Read and verify the SNPSID register contents. The value should be + * 0x45F42XXX + */ + { + int32_t snpsid; + snpsid = ifxusb_rreg(&_core_if->core_global_regs->gsnpsid); + if ((snpsid & 0xFFFFF000) != 0x4F542000) + { + IFX_ERROR("%s() snpsid error(0x%08x) failed\n", __func__,snpsid); + retval = -EINVAL; + goto fail; + } + _core_if->snpsid=snpsid; + } + + #ifdef __IS_HOST__ + _core_if->host_global_regs = (ifxusb_host_global_regs_t *) + ((uint32_t)reg_base + IFXUSB_HOST_GLOBAL_REG_OFFSET); + _core_if->hprt0 = (uint32_t*)((uint32_t)reg_base + IFXUSB_HOST_PORT_REGS_OFFSET); + + for (i=0; ihc_regs[i] = (ifxusb_hc_regs_t *) + ((uint32_t)reg_base + IFXUSB_HOST_CHAN_REGS_OFFSET + + (i * IFXUSB_CHAN_REGS_OFFSET)); + IFX_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n", + i, &_core_if->hc_regs[i]->hcchar); + } + #endif //__IS_HOST__ + + #ifdef __IS_DEVICE__ + _core_if->dev_global_regs = + (ifxusb_device_global_regs_t *)((uint32_t)reg_base + IFXUSB_DEV_GLOBAL_REG_OFFSET); + + for (i=0; iin_ep_regs[i] = (ifxusb_dev_in_ep_regs_t *) + ((uint32_t)reg_base + IFXUSB_DEV_IN_EP_REG_OFFSET + + (i * IFXUSB_EP_REG_OFFSET)); + _core_if->out_ep_regs[i] = (ifxusb_dev_out_ep_regs_t *) + ((uint32_t)reg_base + IFXUSB_DEV_OUT_EP_REG_OFFSET + + (i * IFXUSB_EP_REG_OFFSET)); + IFX_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p/%p %p/0x%08X/0x%08X\n", + i, &_core_if->in_ep_regs[i]->diepctl, _core_if->in_ep_regs[i], + reg_base,IFXUSB_DEV_IN_EP_REG_OFFSET,(i * IFXUSB_EP_REG_OFFSET) + ); + IFX_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p/%p %p/0x%08X/0x%08X\n", + i, &_core_if->out_ep_regs[i]->doepctl, _core_if->out_ep_regs[i], + reg_base,IFXUSB_DEV_OUT_EP_REG_OFFSET,(i * IFXUSB_EP_REG_OFFSET) + ); + } + #endif //__IS_DEVICE__ + + /* Setting the FIFO and other Address. */ + for (i=0; idata_fifo[i] = fifo_base + (i * IFXUSB_DATA_FIFO_SIZE); + IFX_DEBUGPL(DBG_CILV, "data_fifo[%d]=0x%08x\n", + i, (unsigned)_core_if->data_fifo[i]); + } + + _core_if->data_fifo_dbg = fifo_dbg; + _core_if->pcgcctl = (uint32_t*)(((uint32_t)reg_base) + IFXUSB_PCGCCTL_OFFSET); + + /* + * Store the contents of the hardware configuration registers here for + * easy access later. + */ + _core_if->hwcfg1.d32 = ifxusb_rreg(&_core_if->core_global_regs->ghwcfg1); + _core_if->hwcfg2.d32 = ifxusb_rreg(&_core_if->core_global_regs->ghwcfg2); + _core_if->hwcfg3.d32 = ifxusb_rreg(&_core_if->core_global_regs->ghwcfg3); + _core_if->hwcfg4.d32 = ifxusb_rreg(&_core_if->core_global_regs->ghwcfg4); + + IFX_DEBUGPL(DBG_CILV,"hwcfg1=%08x\n",_core_if->hwcfg1.d32); + IFX_DEBUGPL(DBG_CILV,"hwcfg2=%08x\n",_core_if->hwcfg2.d32); + IFX_DEBUGPL(DBG_CILV,"hwcfg3=%08x\n",_core_if->hwcfg3.d32); + IFX_DEBUGPL(DBG_CILV,"hwcfg4=%08x\n",_core_if->hwcfg4.d32); + + + #ifdef __DED_FIFO__ + { + unsigned int countdown=0xFFFF; + IFX_PRINT("Waiting for PHY Clock Lock!\n"); + while(--countdown && !( ifxusb_rreg(&_core_if->core_global_regs->grxfsiz) & (1<<9))) + { + UDELAY(1); + } + if(countdown) + IFX_PRINT("PHY Clock Locked!\n"); + else + IFX_PRINT("PHY Clock Not Locked! %08X\n",ifxusb_rreg(&_core_if->core_global_regs->grxfsiz)); + } + #endif + + /* Create new workqueue and init works */ +#if 0 + _core_if->wq_usb = create_singlethread_workqueue(_core_if->core_name); + + if(_core_if->wq_usb == 0) + { + IFX_DEBUGPL(DBG_CIL, "Creation of wq_usb failed\n"); + retval = -EINVAL; + goto fail; + } + + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + INIT_WORK(&core_if->w_conn_id, w_conn_id_status_change, core_if); + INIT_WORK(&core_if->w_wkp, w_wakeup_detected, core_if); + #else + INIT_WORK(&core_if->w_conn_id, w_conn_id_status_change); + INIT_DELAYED_WORK(&core_if->w_wkp, w_wakeup_detected); + #endif +#endif + return 0; + +fail: + if( reg_base != NULL) iounmap(reg_base ); + if( fifo_base != NULL) iounmap(fifo_base); + if( fifo_dbg != NULL) iounmap(fifo_dbg ); + return retval; +} + +/*! + \brief This function free the mapped address in the IFXUSB CSR data structures. + \param _core_if Pointer of core_if structure + */ +#ifdef __IS_HOST__ +void ifxusb_core_if_remove_h(ifxusb_core_if_t *_core_if) +#else +void ifxusb_core_if_remove_d(ifxusb_core_if_t *_core_if) +#endif +{ + /* Disable all interrupts */ + if( _core_if->core_global_regs != NULL) + { + gusbcfg_data_t usbcfg ={.d32 = 0}; + usbcfg.d32 = ifxusb_rreg( &_core_if->core_global_regs->gusbcfg); + usbcfg.b.ForceDevMode=0; + usbcfg.b.ForceHstMode=0; + ifxusb_wreg( &_core_if->core_global_regs->gusbcfg,usbcfg.d32); + ifxusb_mreg( &_core_if->core_global_regs->gahbcfg, 1, 0); + ifxusb_wreg( &_core_if->core_global_regs->gintmsk, 0); + } + + if( _core_if->core_global_regs != NULL) iounmap(_core_if->core_global_regs ); + if( _core_if->data_fifo[0] != NULL) iounmap(_core_if->data_fifo[0] ); + if( _core_if->data_fifo_dbg != NULL) iounmap(_core_if->data_fifo_dbg ); + +#if 0 + if (_core_if->wq_usb) + destroy_workqueue(_core_if->wq_usb); +#endif + memset(_core_if, 0, sizeof(ifxusb_core_if_t)); +} + + + + +/*! + \brief This function enbles the controller's Global Interrupt in the AHB Config register. + \param _core_if Pointer of core_if structure + */ +#ifdef __IS_HOST__ +void ifxusb_enable_global_interrupts_h( ifxusb_core_if_t *_core_if ) +#else +void ifxusb_enable_global_interrupts_d( ifxusb_core_if_t *_core_if ) +#endif +{ + gahbcfg_data_t ahbcfg ={ .d32 = 0}; + ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ + ifxusb_mreg(&_core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32); +} + +/*! + \brief This function disables the controller's Global Interrupt in the AHB Config register. + \param _core_if Pointer of core_if structure + */ +#ifdef __IS_HOST__ +void ifxusb_disable_global_interrupts_h( ifxusb_core_if_t *_core_if ) +#else +void ifxusb_disable_global_interrupts_d( ifxusb_core_if_t *_core_if ) +#endif +{ + gahbcfg_data_t ahbcfg ={ .d32 = 0}; + ahbcfg.b.glblintrmsk = 1; /* Enable interrupts */ + ifxusb_mreg(&_core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0); +} + + + + +/*! + \brief Flush Tx and Rx FIFO. + \param _core_if Pointer of core_if structure + */ +#ifdef __IS_HOST__ +void ifxusb_flush_both_fifo_h( ifxusb_core_if_t *_core_if ) +#else +void ifxusb_flush_both_fifo_d( ifxusb_core_if_t *_core_if ) +#endif +{ + ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; + volatile grstctl_t greset ={ .d32 = 0}; + int count = 0; + + IFX_DEBUGPL((DBG_CIL|DBG_PCDV), "%s\n", __func__); + greset.b.rxfflsh = 1; + greset.b.txfflsh = 1; + greset.b.txfnum = 0x10; + greset.b.intknqflsh=1; + greset.b.hstfrm=1; + ifxusb_wreg( &global_regs->grstctl, greset.d32 ); + + do + { + greset.d32 = ifxusb_rreg( &global_regs->grstctl); + if (++count > 10000) + { + IFX_WARN("%s() HANG! GRSTCTL=%0x\n", __func__, greset.d32); + break; + } + } while (greset.b.rxfflsh == 1 || greset.b.txfflsh == 1); + /* Wait for 3 PHY Clocks*/ + UDELAY(1); +} + +/*! + \brief Flush a Tx FIFO. + \param _core_if Pointer of core_if structure + \param _num Tx FIFO to flush. ( 0x10 for ALL TX FIFO ) + */ +#ifdef __IS_HOST__ +void ifxusb_flush_tx_fifo_h( ifxusb_core_if_t *_core_if, const int _num ) +#else +void ifxusb_flush_tx_fifo_d( ifxusb_core_if_t *_core_if, const int _num ) +#endif +{ + ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; + volatile grstctl_t greset ={ .d32 = 0}; + int count = 0; + + IFX_DEBUGPL((DBG_CIL|DBG_PCDV), "Flush Tx FIFO %d\n", _num); + + greset.b.intknqflsh=1; + greset.b.txfflsh = 1; + greset.b.txfnum = _num; + ifxusb_wreg( &global_regs->grstctl, greset.d32 ); + + do + { + greset.d32 = ifxusb_rreg( &global_regs->grstctl); + if (++count > 10000&&(_num==0 ||_num==0x10)) + { + IFX_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n", + __func__, greset.d32, + ifxusb_rreg( &global_regs->gnptxsts)); + break; + } + } while (greset.b.txfflsh == 1); + /* Wait for 3 PHY Clocks*/ + UDELAY(1); +} + + +/*! + \brief Flush Rx FIFO. + \param _core_if Pointer of core_if structure + */ +#ifdef __IS_HOST__ +void ifxusb_flush_rx_fifo_h( ifxusb_core_if_t *_core_if ) +#else +void ifxusb_flush_rx_fifo_d( ifxusb_core_if_t *_core_if ) +#endif +{ + ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; + volatile grstctl_t greset ={ .d32 = 0}; + int count = 0; + + IFX_DEBUGPL((DBG_CIL|DBG_PCDV), "%s\n", __func__); + greset.b.rxfflsh = 1; + ifxusb_wreg( &global_regs->grstctl, greset.d32 ); + + do + { + greset.d32 = ifxusb_rreg( &global_regs->grstctl); + if (++count > 10000) + { + IFX_WARN("%s() HANG! GRSTCTL=%0x\n", __func__, greset.d32); + break; + } + } while (greset.b.rxfflsh == 1); + /* Wait for 3 PHY Clocks*/ + UDELAY(1); +} + + +#define SOFT_RESET_DELAY 100 /*!< Delay in msec of detection after soft-reset of usb core */ + +/*! + \brief Do a soft reset of the core. Be careful with this because it + resets all the internal state machines of the core. + \param _core_if Pointer of core_if structure + */ +#ifdef __IS_HOST__ +int ifxusb_core_soft_reset_h(ifxusb_core_if_t *_core_if) +#else +int ifxusb_core_soft_reset_d(ifxusb_core_if_t *_core_if) +#endif +{ + ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; + volatile grstctl_t greset ={ .d32 = 0}; + int count = 0; + + IFX_DEBUGPL(DBG_CILV, "%s\n", __func__); + /* Wait for AHB master IDLE state. */ + do + { + UDELAY(10); + greset.d32 = ifxusb_rreg( &global_regs->grstctl); + if (++count > 100000) + { + IFX_WARN("%s() HANG! AHB Idle GRSTCTL=%0x %x\n", __func__, + greset.d32, greset.b.ahbidle); + break; + } + } while (greset.b.ahbidle == 0); + + UDELAY(1); + + /* Core Soft Reset */ + count = 0; + greset.b.csftrst = 1; + ifxusb_wreg( &global_regs->grstctl, greset.d32 ); + + #ifdef SOFT_RESET_DELAY + MDELAY(SOFT_RESET_DELAY); + #endif + + do + { + UDELAY(10); + greset.d32 = ifxusb_rreg( &global_regs->grstctl); + if (++count > 100000) + { + IFX_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n", __func__, greset.d32); + return -1; + } + } while (greset.b.csftrst == 1); + + #ifdef SOFT_RESET_DELAY + MDELAY(SOFT_RESET_DELAY); + #endif + + // This is to reset the PHY of VR9 + #if defined(__IS_VR9__) + if(_core_if->core_no==0) + { + set_bit (4, VR9_RCU_USBRESET2); + MDELAY(50); + clear_bit (4, VR9_RCU_USBRESET2); + } + else + { + set_bit (5, VR9_RCU_USBRESET2); + MDELAY(50); + clear_bit (5, VR9_RCU_USBRESET2); + } + MDELAY(50); + #endif //defined(__IS_VR9__) + + IFX_PRINT("USB core #%d soft-reset\n",_core_if->core_no); + + return 0; +} + +/*! + \brief Turn on the USB Core Power + \param _core_if Pointer of core_if structure +*/ +#ifdef __IS_HOST__ +void ifxusb_power_on_h (ifxusb_core_if_t *_core_if) +#else +void ifxusb_power_on_d (ifxusb_core_if_t *_core_if) +#endif +{ + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + #if defined(__UEIP__) + + // set clock gating + #if defined(__IS_TWINPASS) || defined(__IS_DANUBE__) + set_bit (4, (volatile unsigned long *)DANUBE_CGU_IFCCR); + set_bit (5, (volatile unsigned long *)DANUBE_CGU_IFCCR); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + // clear_bit (4, (volatile unsigned long *)AMAZON_SE_CGU_IFCCR); + clear_bit (5, (volatile unsigned long *)AMAZON_SE_CGU_IFCCR); + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + set_bit (0, (volatile unsigned long *)AR9_CGU_IFCCR); + set_bit (1, (volatile unsigned long *)AR9_CGU_IFCCR); + #endif //defined(__IS_AR9__) + #if defined(__IS_VR9__) +// set_bit (0, (volatile unsigned long *)VR9_CGU_IFCCR); +// set_bit (1, (volatile unsigned long *)VR9_CGU_IFCCR); + #endif //defined(__IS_VR9__) + #if defined(__IS_AR10__) +// set_bit (0, (volatile unsigned long *)VR9_CGU_IFCCR); +// set_bit (1, (volatile unsigned long *)VR9_CGU_IFCCR); + #endif //defined(__IS_AR10__) + + MDELAY(50); +#define PMU_AHBM BIT(15) +#define PMU_USB0 BIT(6) +#define PMU_USB1 BIT(27) +#define PMU_USB0_P BIT(0) +#define PMU_USB1_P BIT(26) + // set power + ltq_pmu_enable(PMU_AHBM); + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) + ltq_pmu_enable(PMU_USB0); + //#if defined(__IS_TWINPASS__) + // ifxusb_enable_afe_oc(); + //#endif + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) || defined(__IS_VR9__) + if(_core_if->core_no==0) + ltq_pmu_enable(PMU_USB0); + else + ltq_pmu_enable(PMU_USB1); + #endif //defined(__IS_AR9__) || defined(__IS_VR9__) + #if defined(__IS_AR10__) + //if(_core_if->core_no==0) + // USB0_CTRL_PMU_SETUP(IFX_PMU_ENABLE); + //else + // USB1_CTRL_PMU_SETUP(IFX_PMU_ENABLE); + #endif //defined(__IS_AR10__) + + MDELAY(50); + + if(_core_if->pcgcctl) + { + pcgcctl_data_t pcgcctl = {.d32=0}; + pcgcctl.b.gatehclk = 1; + ifxusb_mreg(_core_if->pcgcctl, pcgcctl.d32, 0); + } + + + if(_core_if->core_global_regs) + { + // PHY configurations. + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AR9__) + #if defined(__IS_VR9__) + //ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_VR9__) + #if defined(__IS_AR10__) + //ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AR10__) + } + #else //defined(__UEIP__) + // set clock gating + #if defined(__IS_TWINPASS) || defined(__IS_DANUBE__) + set_bit (4, (volatile unsigned long *)DANUBE_CGU_IFCCR); + set_bit (5, (volatile unsigned long *)DANUBE_CGU_IFCCR); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + // clear_bit (4, (volatile unsigned long *)AMAZON_SE_CGU_IFCCR); + clear_bit (5, (volatile unsigned long *)AMAZON_SE_CGU_IFCCR); + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + set_bit (0, (volatile unsigned long *)AMAZON_S_CGU_IFCCR); + set_bit (1, (volatile unsigned long *)AMAZON_S_CGU_IFCCR); + #endif //defined(__IS_AR9__) + + MDELAY(50); + + // set power + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + clear_bit (6, (volatile unsigned long *)DANUBE_PMU_PWDCR);//USB + clear_bit (9, (volatile unsigned long *)DANUBE_PMU_PWDCR);//DSL + clear_bit (15, (volatile unsigned long *)DANUBE_PMU_PWDCR);//AHB + #if defined(__IS_TWINPASS__) + ifxusb_enable_afe_oc(); + #endif + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + clear_bit (6, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR); + clear_bit (9, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR); + clear_bit (15, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR); + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + if(_core_if->core_no==0) + clear_bit (6, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//USB + else + clear_bit (27, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//USB + clear_bit (9, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//DSL + clear_bit (15, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//AHB + #endif //defined(__IS_AR9__) + + if(_core_if->core_global_regs) + { + // PHY configurations. + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AR9__) + } + + #endif //defined(__UEIP__) +} + +/*! + \brief Turn off the USB Core Power + \param _core_if Pointer of core_if structure +*/ +#ifdef __IS_HOST__ +void ifxusb_power_off_h (ifxusb_core_if_t *_core_if) +#else +void ifxusb_power_off_d (ifxusb_core_if_t *_core_if) +#endif + +{ + #ifdef __IS_HOST__ + ifxusb_phy_power_off_h (_core_if); + #else + ifxusb_phy_power_off_d (_core_if); + #endif + + #if defined(__UEIP__) + //AHBM_PMU_SETUP(IFX_PMU_DISABLE); + // set power + if(_core_if->pcgcctl) + { + pcgcctl_data_t pcgcctl = {.d32=0}; + pcgcctl.b.gatehclk = 1; + pcgcctl.b.stoppclk = 1; + ifxusb_mreg(_core_if->pcgcctl, 0, pcgcctl.d32); + } + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) + //USB_CTRL_PMU_SETUP(IFX_PMU_DISABLE); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) || defined(__IS_VR9__) + /* if(_core_if->core_no==0) + USB0_CTRL_PMU_SETUP(IFX_PMU_DISABLE); + else + USB1_CTRL_PMU_SETUP(IFX_PMU_DISABLE);*/ + #endif //defined(__IS_AR9__) || defined(__IS_VR9__) + #if defined(__IS_AR10__) + //if(_core_if->core_no==0) + // USB0_CTRL_PMU_SETUP(IFX_PMU_DISABLE); + //else + // USB1_CTRL_PMU_SETUP(IFX_PMU_DISABLE); + #endif //defined(__IS_AR10__) + #else //defined(__UEIP__) + // set power + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + set_bit (6, (volatile unsigned long *)DANUBE_PMU_PWDCR);//USB + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + set_bit (6, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR);//USB + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + if(_core_if->core_no==0) + set_bit (6, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//USB + else + set_bit (27, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//USB + #endif //defined(__IS_AR9__) + #endif //defined(__UEIP__) +} + +/*! + \brief Turn on the USB PHY Power + \param _core_if Pointer of core_if structure +*/ +#ifdef __IS_HOST__ +void ifxusb_phy_power_on_h (ifxusb_core_if_t *_core_if) +#else +void ifxusb_phy_power_on_d (ifxusb_core_if_t *_core_if) +#endif +{ + #if defined(__UEIP__) + if(_core_if->core_global_regs) + { + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AR9__) + #if ( defined(__IS_VR9__) || defined(__IS_AR10__)) && defined(__PHY_LONG_PREEMP__) + if(_core_if->core_no==0) + set_bit (0, VR9_RCU_USB_ANA_CFG1A); + else + set_bit (0, VR9_RCU_USB_ANA_CFG1B); + #endif //( defined(__IS_VR9__) || defined(__IS_AR10__)) && defined(__PHY_LONG_PREEMP__) + + if(_core_if->pcgcctl) + { + pcgcctl_data_t pcgcctl = {.d32=0}; + pcgcctl.b.stoppclk = 1; + ifxusb_mreg(_core_if->pcgcctl, pcgcctl.d32, 0); + } + } + + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) + ltq_pmu_enable(PMU_USB0_P); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) || defined(__IS_VR9__) || defined(__IS_AR10__) + if(_core_if->core_no==0) + ltq_pmu_enable(PMU_USB0_P); + else + ltq_pmu_enable(PMU_USB1_P); + #endif //defined(__IS_AR9__) || defined(__IS_VR9__) + + // PHY configurations. + if(_core_if->core_global_regs) + { + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AR9__) + #if ( defined(__IS_VR9__) || defined(__IS_AR10__)) && defined(__PHY_LONG_PREEMP__) + if(_core_if->core_no==0) + set_bit (0, VR9_RCU_USB_ANA_CFG1A); + else + set_bit (0, VR9_RCU_USB_ANA_CFG1B); + #endif //( defined(__IS_VR9__) || defined(__IS_AR10__)) && defined(__PHY_LONG_PREEMP__) + } + #else //defined(__UEIP__) + // PHY configurations. + if(_core_if->core_global_regs) + { + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AR9__) + } + + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + clear_bit (0, (volatile unsigned long *)DANUBE_PMU_PWDCR);//PHY + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + clear_bit (0, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR); + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + if(_core_if->core_no==0) + clear_bit (0, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//PHY + else + clear_bit (26, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//PHY + #endif //defined(__IS_AR9__) + + // PHY configurations. + if(_core_if->core_global_regs) + { + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AR9__) + } + #endif //defined(__UEIP__) +} + + +/*! + \brief Turn off the USB PHY Power + \param _core_if Pointer of core_if structure +*/ +#ifdef __IS_HOST__ +void ifxusb_phy_power_off_h (ifxusb_core_if_t *_core_if) +#else +void ifxusb_phy_power_off_d (ifxusb_core_if_t *_core_if) +#endif +{ + #if defined(__UEIP__) + if(_core_if->pcgcctl) + { + pcgcctl_data_t pcgcctl = {.d32=0}; + pcgcctl.b.stoppclk = 1; + ifxusb_mreg(_core_if->pcgcctl, 0, pcgcctl.d32); + } + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) + //USB_PHY_PMU_SETUP(IFX_PMU_DISABLE); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) || defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) || defined(__IS_VR9__) || defined(__IS_AR10__) +/* if(_core_if->core_no==0) + USB0_PHY_PMU_SETUP(IFX_PMU_DISABLE); + else + USB1_PHY_PMU_SETUP(IFX_PMU_DISABLE);*/ + #endif // defined(__IS_AR9__) || defined(__IS_VR9__) + #else //defined(__UEIP__) + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + set_bit (0, (volatile unsigned long *)DANUBE_PMU_PWDCR);//PHY + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + set_bit (0, (volatile unsigned long *)AMAZON_SE_PMU_PWDCR);//PHY + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + if(_core_if->core_no==0) + set_bit (0, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//PHY + else + set_bit (26, (volatile unsigned long *)AMAZON_S_PMU_PWDCR);//PHY + #endif //defined(__IS_AR9__) + #endif //defined(__UEIP__) +} + + +/*! + \brief Reset on the USB Core RCU + \param _core_if Pointer of core_if structure + */ +#if defined(__IS_VR9__) || defined(__IS_AR10__) +static int CheckAlready(void) +{ + gusbcfg_data_t usbcfg ={.d32 = 0}; + usbcfg.d32 = ifxusb_rreg((volatile uint32_t *)0xBE10100C); + if(usbcfg.b.ForceDevMode) + return 1; + if(usbcfg.b.ForceHstMode) + return 1; + usbcfg.d32 = ifxusb_rreg((volatile uint32_t *)0xBE10600C); + if(usbcfg.b.ForceDevMode) + return 1; + if(usbcfg.b.ForceHstMode) + return 1; + return 0; +} +#endif + +#ifdef __IS_HOST__ + void ifxusb_hard_reset_h(ifxusb_core_if_t *_core_if) +#else + void ifxusb_hard_reset_d(ifxusb_core_if_t *_core_if) +#endif +{ + #if defined(__UEIP__) + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined (__IS_HOST__) + clear_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); + #elif defined (__IS_DEVICE__) + set_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); + #endif + #endif //defined(__IS_AMAZON_SE__) + + #if defined(__IS_AMAZON_SE__) + #if defined (__IS_HOST__) + clear_bit (AMAZON_SE_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); + #elif defined (__IS_DEVICE__) + set_bit (AMAZON_SE_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); + #endif + #endif //defined(__IS_AMAZON_SE__) + + #if defined(__IS_AR9__) + if(_core_if->core_no==0) + { + #if defined (__IS_HOST__) + clear_bit (AR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR9_RCU_USB1CFG); + #elif defined (__IS_DEVICE__) + set_bit (AR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR9_RCU_USB1CFG); + #endif + } + else + { + #if defined (__IS_HOST__) + clear_bit (AR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR9_RCU_USB2CFG); + #elif defined (__IS_DEVICE__) + set_bit (AR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR9_RCU_USB2CFG); + #endif + } + #endif //defined(__IS_AR9__) + + #if defined(__IS_VR9__) + if(!CheckAlready()) + { + #if defined (__IS_HOST__) + #if defined (__IS_DUAL__) + clear_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); + clear_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); + #elif defined (__IS_FIRST__) + clear_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); + set_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); + #elif defined (__IS_SECOND__) + set_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); + clear_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); + #endif + #endif + #if defined (__IS_DEVICE__) + #if defined (__IS_FIRST__) + set_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); + clear_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); + #elif defined (__IS_SECOND__) + clear_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); + set_bit (VR9_USBCFG_HDSEL_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); + #endif + #endif + } + #endif //defined(__IS_VR9__) + + #if defined(__IS_AR10__) + if(!CheckAlready()) + { + #if defined (__IS_HOST__) + #if defined (__IS_DUAL__) + clear_bit (AR10_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR10_RCU_USB1CFG); + clear_bit (AR10_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR10_RCU_USB2CFG); + #elif defined (__IS_FIRST__) + clear_bit (AR10_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR10_RCU_USB1CFG); + set_bit (AR10_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR10_RCU_USB2CFG); + #elif defined (__IS_SECOND__) + set_bit (AR10_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR10_RCU_USB1CFG); + clear_bit (AR10_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR10_RCU_USB2CFG); + #endif + #endif + #if defined (__IS_DEVICE__) + #if defined (__IS_FIRST__) + set_bit (AR10_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR10_RCU_USB1CFG); + clear_bit (AR10_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR10_RCU_USB2CFG); + #elif defined (__IS_SECOND__) + clear_bit (AR10_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR10_RCU_USB1CFG); + set_bit (AR10_USBCFG_HDSEL_BIT, (volatile unsigned long *)AR10_RCU_USB2CFG); + #endif + #endif + } + #endif //defined(__IS_AR10__) + + // set the HC's byte-order to big-endian + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + set_bit (DANUBE_USBCFG_HOST_END_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); + clear_bit (DANUBE_USBCFG_SLV_END_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + set_bit (AMAZON_SE_USBCFG_HOST_END_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); + clear_bit (AMAZON_SE_USBCFG_SLV_END_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + if(_core_if->core_no==0) + { + set_bit (AR9_USBCFG_HOST_END_BIT, (volatile unsigned long *)AR9_RCU_USB1CFG); + clear_bit (AR9_USBCFG_SLV_END_BIT, (volatile unsigned long *)AR9_RCU_USB1CFG); + } + else + { + set_bit (AR9_USBCFG_HOST_END_BIT, (volatile unsigned long *)AR9_RCU_USB2CFG); + clear_bit (AR9_USBCFG_SLV_END_BIT, (volatile unsigned long *)AR9_RCU_USB2CFG); + } + #endif //defined(__IS_AR9__) + #if defined(__IS_VR9__) + if(_core_if->core_no==0) + { + set_bit (VR9_USBCFG_HOST_END_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); + clear_bit (VR9_USBCFG_SLV_END_BIT, (volatile unsigned long *)VR9_RCU_USB1CFG); + } + else + { + set_bit (VR9_USBCFG_HOST_END_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); + clear_bit (VR9_USBCFG_SLV_END_BIT, (volatile unsigned long *)VR9_RCU_USB2CFG); + } + #endif //defined(__IS_VR9__) + #if defined(__IS_AR10__) + if(_core_if->core_no==0) + { + set_bit (AR10_USBCFG_HOST_END_BIT, (volatile unsigned long *)AR10_RCU_USB1CFG); + clear_bit (AR10_USBCFG_SLV_END_BIT, (volatile unsigned long *)AR10_RCU_USB1CFG); + } + else + { + set_bit (AR10_USBCFG_HOST_END_BIT, (volatile unsigned long *)AR10_RCU_USB2CFG); + clear_bit (AR10_USBCFG_SLV_END_BIT, (volatile unsigned long *)AR10_RCU_USB2CFG); + } + #endif //defined(__IS_AR10__) + + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + set_bit (4, DANUBE_RCU_RESET); + MDELAY(50); + clear_bit (4, DANUBE_RCU_RESET); + MDELAY(50); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + + #if defined(__IS_AMAZON_SE__) + set_bit (4, AMAZON_SE_RCU_RESET); + MDELAY(50); + clear_bit (4, AMAZON_SE_RCU_RESET); + MDELAY(50); + #endif //defined(__IS_AMAZON_SE__) + + #if defined(__IS_AR9__) + if(_core_if->core_no==0) + { + set_bit (4, AR9_RCU_USBRESET); + MDELAY(50); + clear_bit (4, AR9_RCU_USBRESET); + } + else + { + set_bit (28, AR9_RCU_USBRESET); + MDELAY(50); + clear_bit (28, AR9_RCU_USBRESET); + } + MDELAY(50); + #endif //defined(__IS_AR9__) + #if defined(__IS_VR9__) + if(!CheckAlready()) + { + set_bit (4, VR9_RCU_USBRESET); + MDELAY(50); + clear_bit (4, VR9_RCU_USBRESET); + MDELAY(50); + } + #endif //defined(__IS_VR9__) + #if defined(__IS_AR10__) + if(!CheckAlready()) + { + set_bit (4, AR10_RCU_USBRESET); + MDELAY(50); + clear_bit (4, AR10_RCU_USBRESET); + MDELAY(50); + } + #endif //defined(__IS_AR10__) + + #if defined(__IS_TWINPASS__) + ifxusb_enable_afe_oc(); + #endif + + if(_core_if->core_global_regs) + { + // PHY configurations. + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AR9__) + #if defined(__IS_VR9__) + // ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_VR9__) + #if defined(__IS_AR10__) + // ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AR10__) + } + #else //defined(__UEIP__) + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined (__IS_HOST__) + clear_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); + #elif defined (__IS_DEVICE__) + set_bit (DANUBE_USBCFG_HDSEL_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); + #endif + #endif //defined(__IS_AMAZON_SE__) + + #if defined(__IS_AMAZON_SE__) + #if defined (__IS_HOST__) + clear_bit (AMAZON_SE_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); + #elif defined (__IS_DEVICE__) + set_bit (AMAZON_SE_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); + #endif + #endif //defined(__IS_AMAZON_SE__) + + #if defined(__IS_AR9__) + if(_core_if->core_no==0) + { + #if defined (__IS_HOST__) + clear_bit (AMAZON_S_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB1CFG); + #elif defined (__IS_DEVICE__) + set_bit (AMAZON_S_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB1CFG); + #endif + } + else + { + #if defined (__IS_HOST__) + clear_bit (AMAZON_S_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB2CFG); + #elif defined (__IS_DEVICE__) + set_bit (AMAZON_S_USBCFG_HDSEL_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB2CFG); + #endif + } + #endif //defined(__IS_AR9__) + + // set the HC's byte-order to big-endian + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + set_bit (DANUBE_USBCFG_HOST_END_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); + clear_bit (DANUBE_USBCFG_SLV_END_BIT, (volatile unsigned long *)DANUBE_RCU_USBCFG); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + set_bit (AMAZON_SE_USBCFG_HOST_END_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); + clear_bit (AMAZON_SE_USBCFG_SLV_END_BIT, (volatile unsigned long *)AMAZON_SE_RCU_USBCFG); + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + if(_core_if->core_no==0) + { + set_bit (AMAZON_S_USBCFG_HOST_END_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB1CFG); + clear_bit (AMAZON_S_USBCFG_SLV_END_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB1CFG); + } + else + { + set_bit (AMAZON_S_USBCFG_HOST_END_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB2CFG); + clear_bit (AMAZON_S_USBCFG_SLV_END_BIT, (volatile unsigned long *)AMAZON_S_RCU_USB2CFG); + } + #endif //defined(__IS_AR9__) + + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + set_bit (4, DANUBE_RCU_RESET); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + set_bit (4, AMAZON_SE_RCU_RESET); + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + if(_core_if->core_no==0) + { + set_bit (4, AMAZON_S_RCU_USBRESET); + } + else + { + set_bit (28, AMAZON_S_RCU_USBRESET); + } + #endif //defined(__IS_AR9__) + + MDELAY(50); + + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + clear_bit (4, DANUBE_RCU_RESET); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + clear_bit (4, AMAZON_SE_RCU_RESET); + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + if(_core_if->core_no==0) + { + clear_bit (4, AMAZON_S_RCU_USBRESET); + } + else + { + clear_bit (28, AMAZON_S_RCU_USBRESET); + } + #endif //defined(__IS_AR9__) + + MDELAY(50); + + #if defined(__IS_TWINPASS__) + ifxusb_enable_afe_oc(); + #endif + + if(_core_if->core_global_regs) + { + // PHY configurations. + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + ifxusb_wreg (&_core_if->core_global_regs->guid,0x14014); + #endif //defined(__IS_AR9__) + } + #endif //defined(__UEIP__) +} + +#if defined(__GADGET_LED__) || defined(__HOST_LED__) + #if defined(__UEIP__) + static void *g_usb_led_trigger = NULL; + #endif + + void ifxusb_led_init(ifxusb_core_if_t *_core_if) + { + #if defined(__UEIP__) + #if defined(IFX_LEDGPIO_USB_LED) || defined(IFX_LEDLED_USB_LED) + if ( !g_usb_led_trigger ) + { + ifx_led_trigger_register("usb_link", &g_usb_led_trigger); + if ( g_usb_led_trigger != NULL ) + { + struct ifx_led_trigger_attrib attrib = {0}; + attrib.delay_on = 250; + attrib.delay_off = 250; + attrib.timeout = 2000; + attrib.def_value = 1; + attrib.flags = IFX_LED_TRIGGER_ATTRIB_DELAY_ON | IFX_LED_TRIGGER_ATTRIB_DELAY_OFF | IFX_LED_TRIGGER_ATTRIB_TIMEOUT | IFX_LED_TRIGGER_ATTRIB_DEF_VALUE; + IFX_DEBUGP("Reg USB LED!!\n"); + ifx_led_trigger_set_attrib(g_usb_led_trigger, &attrib); + } + } + #endif + #endif //defined(__UEIP__) + } + + void ifxusb_led_free(ifxusb_core_if_t *_core_if) + { + #if defined(__UEIP__) + if ( g_usb_led_trigger ) + { + ifx_led_trigger_deregister(g_usb_led_trigger); + g_usb_led_trigger = NULL; + } + #endif //defined(__UEIP__) + } + + /*! + \brief Turn off the USB 5V VBus Power + \param _core_if Pointer of core_if structure + */ + void ifxusb_led(ifxusb_core_if_t *_core_if) + { + #if defined(__UEIP__) + if(g_usb_led_trigger) + ifx_led_trigger_activate(g_usb_led_trigger); + #else + #endif //defined(__UEIP__) + } +#endif // defined(__GADGET_LED__) || defined(__HOST_LED__) + + + +/*! + \brief internal routines for debugging + */ +#ifdef __IS_HOST__ +void ifxusb_dump_msg_h(const u8 *buf, unsigned int length) +#else +void ifxusb_dump_msg_d(const u8 *buf, unsigned int length) +#endif +{ +#ifdef __DEBUG__ + unsigned int start, num, i; + char line[52], *p; + + if (length >= 512) + return; + start = 0; + while (length > 0) + { + num = min(length, 16u); + p = line; + for (i = 0; i < num; ++i) + { + if (i == 8) + *p++ = ' '; + sprintf(p, " %02x", buf[i]); + p += 3; + } + *p = 0; + IFX_PRINT( "%6x: %s\n", start, line); + buf += num; + start += num; + length -= num; + } +#endif +} + +/*! + \brief internal routines for debugging, reads the SPRAM and prints its content + */ +#ifdef __IS_HOST__ +void ifxusb_dump_spram_h(ifxusb_core_if_t *_core_if) +#else +void ifxusb_dump_spram_d(ifxusb_core_if_t *_core_if) +#endif +{ +#ifdef __ENABLE_DUMP__ + volatile uint8_t *addr, *start_addr, *end_addr; + uint32_t size; + IFX_PRINT("SPRAM Data:\n"); + start_addr = (void*)_core_if->core_global_regs; + IFX_PRINT("Base Address: 0x%8X\n", (uint32_t)start_addr); + + start_addr = (void*)_core_if->data_fifo_dbg; + IFX_PRINT("Starting Address: 0x%8X\n", (uint32_t)start_addr); + + size=_core_if->hwcfg3.b.dfifo_depth; + size<<=2; + size+=0x200; + size&=0x0003FFFC; + + end_addr = (void*)_core_if->data_fifo_dbg; + end_addr += size; + + for(addr = start_addr; addr < end_addr; addr+=16) + { + IFX_PRINT("0x%8X: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X \n", (uint32_t)addr, + addr[ 0], addr[ 1], addr[ 2], addr[ 3], + addr[ 4], addr[ 5], addr[ 6], addr[ 7], + addr[ 8], addr[ 9], addr[10], addr[11], + addr[12], addr[13], addr[14], addr[15] + ); + } + return; +#endif //__ENABLE_DUMP__ +} + +/*! + \brief internal routines for debugging, reads the core global registers and prints them + */ +#ifdef __IS_HOST__ +void ifxusb_dump_registers_h(ifxusb_core_if_t *_core_if) +#else +void ifxusb_dump_registers_d(ifxusb_core_if_t *_core_if) +#endif +{ +#ifdef __ENABLE_DUMP__ + int i; + volatile uint32_t *addr; + #ifdef __IS_DEVICE__ + volatile uint32_t *addri,*addro; + #endif + + IFX_PRINT("Core #%d\n",_core_if->core_no); + IFX_PRINT("========================================\n"); + IFX_PRINT("Core Global Registers\n"); + addr=&_core_if->core_global_regs->gotgctl; + IFX_PRINT(" GOTGCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->core_global_regs->gotgint; + IFX_PRINT(" GOTGINT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->core_global_regs->gahbcfg; + IFX_PRINT(" GAHBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->core_global_regs->gusbcfg; + IFX_PRINT(" GUSBCFG @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->core_global_regs->grstctl; + IFX_PRINT(" GRSTCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->core_global_regs->gintsts; + IFX_PRINT(" GINTSTS @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->core_global_regs->gintmsk; + IFX_PRINT(" GINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->core_global_regs->gi2cctl; + IFX_PRINT(" GI2CCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->core_global_regs->gpvndctl; + IFX_PRINT(" GPVNDCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->core_global_regs->ggpio; + IFX_PRINT(" GGPIO @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->core_global_regs->guid; + IFX_PRINT(" GUID @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->core_global_regs->gsnpsid; + IFX_PRINT(" GSNPSID @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->core_global_regs->ghwcfg1; + IFX_PRINT(" GHWCFG1 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->core_global_regs->ghwcfg2; + IFX_PRINT(" GHWCFG2 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->core_global_regs->ghwcfg3; + IFX_PRINT(" GHWCFG3 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->core_global_regs->ghwcfg4; + IFX_PRINT(" GHWCFG4 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + + addr=_core_if->pcgcctl; + IFX_PRINT(" PCGCCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + + addr=&_core_if->core_global_regs->grxfsiz; + IFX_PRINT(" GRXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + + #ifdef __IS_HOST__ + addr=&_core_if->core_global_regs->gnptxfsiz; + IFX_PRINT(" GNPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->core_global_regs->hptxfsiz; + IFX_PRINT(" HPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + #endif //__IS_HOST__ + + #ifdef __IS_DEVICE__ + #ifdef __DED_FIFO__ + addr=&_core_if->core_global_regs->gnptxfsiz; + IFX_PRINT(" GNPTXFSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + for (i=0; i<= _core_if->hwcfg4.b.num_in_eps; i++) + { + addr=&_core_if->core_global_regs->dptxfsiz_dieptxf[i]; + IFX_PRINT(" DPTXFSIZ[%d] @0x%08X : 0x%08X\n",i,(uint32_t)addr,ifxusb_rreg(addr)); + } + #else + addr=&_core_if->core_global_regs->gnptxfsiz; + IFX_PRINT(" TXFSIZ[00] @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + for (i=0; i< _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) + { + addr=&_core_if->core_global_regs->dptxfsiz_dieptxf[i]; + IFX_PRINT(" TXFSIZ[%02d] @0x%08X : 0x%08X\n",i+1,(uint32_t)addr,ifxusb_rreg(addr)); + } + #endif + #endif //__IS_DEVICE__ + + #ifdef __IS_HOST__ + IFX_PRINT(" Host Global Registers\n"); + addr=&_core_if->host_global_regs->hcfg; + IFX_PRINT(" HCFG @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->host_global_regs->hfir; + IFX_PRINT(" HFIR @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->host_global_regs->hfnum; + IFX_PRINT(" HFNUM @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->host_global_regs->hptxsts; + IFX_PRINT(" HPTXSTS @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->host_global_regs->haint; + IFX_PRINT(" HAINT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->host_global_regs->haintmsk; + IFX_PRINT(" HAINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr= _core_if->hprt0; + IFX_PRINT(" HPRT0 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + + for (i=0; ihc_regs[i]->hcchar; + IFX_PRINT(" Host Channel %d Specific Registers\n", i); + IFX_PRINT(" HCCHAR @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->hc_regs[i]->hcsplt; + IFX_PRINT(" HCSPLT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->hc_regs[i]->hcint; + IFX_PRINT(" HCINT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->hc_regs[i]->hcintmsk; + IFX_PRINT(" HCINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->hc_regs[i]->hctsiz; + IFX_PRINT(" HCTSIZ @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->hc_regs[i]->hcdma; + IFX_PRINT(" HCDMA @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + } + #endif //__IS_HOST__ + + #ifdef __IS_DEVICE__ + IFX_PRINT(" Device Global Registers\n"); + addr=&_core_if->dev_global_regs->dcfg; + IFX_PRINT(" DCFG @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->dev_global_regs->dctl; + IFX_PRINT(" DCTL @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->dev_global_regs->dsts; + IFX_PRINT(" DSTS @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->dev_global_regs->diepmsk; + IFX_PRINT(" DIEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->dev_global_regs->doepmsk; + IFX_PRINT(" DOEPMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->dev_global_regs->daintmsk; + IFX_PRINT(" DAINTMSK @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->dev_global_regs->daint; + IFX_PRINT(" DAINT @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->dev_global_regs->dvbusdis; + IFX_PRINT(" DVBUSID @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + addr=&_core_if->dev_global_regs->dvbuspulse; + IFX_PRINT(" DVBUSPULS @0x%08X : 0x%08X\n", (uint32_t)addr,ifxusb_rreg(addr)); + + addr=&_core_if->dev_global_regs->dtknqr1; + IFX_PRINT(" DTKNQR1 @0x%08X : 0x%08X\n",(uint32_t)addr,ifxusb_rreg(addr)); + if (_core_if->hwcfg2.b.dev_token_q_depth > 6) { + addr=&_core_if->dev_global_regs->dtknqr2; + IFX_PRINT(" DTKNQR2 @0x%08X : 0x%08X\n", (uint32_t)addr,ifxusb_rreg(addr)); + } + + if (_core_if->hwcfg2.b.dev_token_q_depth > 14) + { + addr=&_core_if->dev_global_regs->dtknqr3_dthrctl; + IFX_PRINT(" DTKNQR3_DTHRCTL @0x%08X : 0x%08X\n", (uint32_t)addr, ifxusb_rreg(addr)); + } + + if (_core_if->hwcfg2.b.dev_token_q_depth > 22) + { + addr=&_core_if->dev_global_regs->dtknqr4_fifoemptymsk; + IFX_PRINT(" DTKNQR4 @0x%08X : 0x%08X\n", (uint32_t)addr, ifxusb_rreg(addr)); + } + + //for (i=0; i<= MAX_EPS_CHANNELS; i++) + //for (i=0; i<= 10; i++) + for (i=0; i<= 3; i++) + { + IFX_PRINT(" Device EP %d Registers\n", i); + addri=&_core_if->in_ep_regs[i]->diepctl;addro=&_core_if->out_ep_regs[i]->doepctl; + IFX_PRINT(" DEPCTL I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); + addro=&_core_if->out_ep_regs[i]->doepfn; + IFX_PRINT(" DEPFN I: O: 0x%08X\n",ifxusb_rreg(addro)); + addri=&_core_if->in_ep_regs[i]->diepint;addro=&_core_if->out_ep_regs[i]->doepint; + IFX_PRINT(" DEPINT I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); + addri=&_core_if->in_ep_regs[i]->dieptsiz;addro=&_core_if->out_ep_regs[i]->doeptsiz; + IFX_PRINT(" DETSIZ I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); + addri=&_core_if->in_ep_regs[i]->diepdma;addro=&_core_if->out_ep_regs[i]->doepdma; + IFX_PRINT(" DEPDMA I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); + addri=&_core_if->in_ep_regs[i]->dtxfsts; + IFX_PRINT(" DTXFSTS I: 0x%08X\n",ifxusb_rreg(addri) ); + addri=&_core_if->in_ep_regs[i]->diepdmab;addro=&_core_if->out_ep_regs[i]->doepdmab; + IFX_PRINT(" DEPDMAB I: 0x%08X O: 0x%08X\n",ifxusb_rreg(addri),ifxusb_rreg(addro)); + } + #endif //__IS_DEVICE__ +#endif //__ENABLE_DUMP__ +} + +#ifdef __IS_HOST__ +void do_suspend_h(ifxusb_core_if_t *core_if) +{ + ifxusb_vbus_off(core_if); + mdelay(100); + ifxusb_power_off_h(core_if); +} +void do_resume_h(ifxusb_core_if_t *core_if) +{ + ifxusb_vbus_on(core_if); + mdelay(100); + ifxusb_power_on_h(core_if); + ifxusb_phy_power_on_h(core_if); +} +#endif +#ifdef __IS_DEVICE__ +void do_suspend_d(ifxusb_core_if_t *core_if) +{ + ifxusb_power_off_d(core_if); +} +void do_resume_d(ifxusb_core_if_t *core_if) +{ + dctl_data_t dctl = {.d32=0}; + + ifxusb_power_on_d(core_if); + ifxusb_phy_power_on_d(core_if); + dctl.d32=ifxusb_rreg(&core_if->dev_global_regs->dctl); + dctl.b.sftdiscon=1; + ifxusb_wreg(&core_if->dev_global_regs->dctl,dctl.d32); + mdelay(50); + dctl.b.sftdiscon=0; + ifxusb_wreg(&core_if->dev_global_regs->dctl,dctl.d32); +} +#endif + diff --git a/package/platform/lantiq/ltq-hcd/src/ifxusb_cif.h b/package/platform/lantiq/ltq-hcd/src/ifxusb_cif.h new file mode 100644 index 0000000000..5af988f91f --- /dev/null +++ b/package/platform/lantiq/ltq-hcd/src/ifxusb_cif.h @@ -0,0 +1,767 @@ +/***************************************************************************** + ** FILE NAME : ifxusb_cif.h + ** PROJECT : IFX USB sub-system V3 + ** MODULES : IFX USB sub-system Host and Device driver + ** SRC VERSION : 3.2 + ** DATE : 1/Jan/2011 + ** AUTHOR : Chen, Howard + ** DESCRIPTION : The Core Interface provides basic services for accessing and + ** managing the IFX USB hardware. These services are used by both the + ** Host Controller Driver and the Peripheral Controller Driver. + ** FUNCTIONS : + ** COMPILER : gcc + ** REFERENCE : Synopsys DWC-OTG Driver 2.7 + ** COPYRIGHT : Copyright (c) 2010 + ** LANTIQ DEUTSCHLAND GMBH, + ** Am Campeon 3, 85579 Neubiberg, Germany + ** + ** This program is free software; you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation; either version 2 of the License, or + ** (at your option) any later version. + ** + ** Version Control Section ** + ** $Author$ + ** $Date$ + ** $Revisions$ + ** $Log$ Revision history + *****************************************************************************/ + +/* + * This file contains code fragments from Synopsys HS OTG Linux Software Driver. + * For this code the following notice is applicable: + * + * ========================================================================== + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +/*! + \defgroup IFXUSB_DRIVER_V3 IFX USB SS Project + \brief IFX USB subsystem V3.x + */ + +/*! + \defgroup IFXUSB_CIF Core Interface APIs + \ingroup IFXUSB_DRIVER_V3 + \brief The Core Interface provides basic services for accessing and + managing the IFXUSB hardware. These services are used by both the + Host Controller Driver and the Peripheral Controller Driver. + */ + + +/*! + \file ifxusb_cif.h + \ingroup IFXUSB_DRIVER_V3 + \brief This file contains the interface to the IFX USB Core. + */ + +#if !defined(__IFXUSB_CIF_H__) +#define __IFXUSB_CIF_H__ + +#include + +#include +#include + +#include "ifxusb_plat.h" +#include "ifxusb_regs.h" + +#ifdef __DEBUG__ + #include "linux/timer.h" +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define IFXUSB_PARAM_SPEED_HIGH 0 /*!< Build stage parameter: High Speed */ +#define IFXUSB_PARAM_SPEED_FULL 1 /*!< Build stage parameter: Full Speed */ + +#define IFXUSB_EP_SPEED_LOW 0 /*!< Run-Time Status: High Speed */ +#define IFXUSB_EP_SPEED_FULL 1 /*!< Run-Time Status: Full Speed */ +#define IFXUSB_EP_SPEED_HIGH 2 /*!< Run-Time Status: Low Speed */ + +#define IFXUSB_EP_TYPE_CTRL 0 /*!< Run-Time Status: CTRL */ +#define IFXUSB_EP_TYPE_ISOC 1 /*!< Run-Time Status: ISOC */ +#define IFXUSB_EP_TYPE_BULK 2 /*!< Run-Time Status: BULK */ +#define IFXUSB_EP_TYPE_INTR 3 /*!< Run-Time Status: INTR */ + +#define IFXUSB_HC_PID_DATA0 0 /*!< Run-Time Data Toggle: Data 0 */ +#define IFXUSB_HC_PID_DATA2 1 /*!< Run-Time Data Toggle: Data 2 */ +#define IFXUSB_HC_PID_DATA1 2 /*!< Run-Time Data Toggle: Data 1 */ +#define IFXUSB_HC_PID_MDATA 3 /*!< Run-Time Data Toggle: MData */ +#define IFXUSB_HC_PID_SETUP 3 /*!< Run-Time Data Toggle: Setup */ + + +/*! + \addtogroup IFXUSB_CIF + */ +/*@{*/ + +/*! typedef ifxusb_params_t + \brief IFXUSB Parameters structure. + This structure is used for both importing from insmod stage and run-time storage. + These parameters define how the IFXUSB controller should be configured. + */ +typedef struct ifxusb_params +{ + int32_t dma_burst_size; /*!< The DMA Burst size (applicable only for Internal DMA + Mode). 0(for single), 1(incr), 4(incr4), 8(incr8) 16(incr16) + */ + /* Translate this to GAHBCFG values */ + int32_t speed; /*!< Specifies the maximum speed of operation in host and device mode. + The actual speed depends on the speed of the attached device and + the value of phy_type. The actual speed depends on the speed of the + attached device. + 0 - High Speed (default) + 1 - Full Speed + */ + + int32_t data_fifo_size; /*!< Total number of dwords in the data FIFO memory. This + memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic + Tx FIFOs. + 32 to 32768 + */ + #ifdef __IS_DEVICE__ + int32_t rx_fifo_size; /*!< Number of dwords in the Rx FIFO in device mode. + 16 to 32768 + */ + + + int32_t tx_fifo_size[MAX_EPS_CHANNELS]; /*!< Number of dwords in each of the Tx FIFOs in device mode. + 4 to 768 + */ + #ifdef __DED_FIFO__ + int32_t thr_ctl; /*!< Threshold control on/off */ + int32_t tx_thr_length; /*!< Threshold length for Tx */ + int32_t rx_thr_length; /*!< Threshold length for Rx*/ + #endif + #else //__IS_HOST__ + int32_t host_channels; /*!< The number of host channel registers to use. + 1 to 16 + */ + + int32_t rx_fifo_size; /*!< Number of dwords in the Rx FIFO in host mode. + 16 to 32768 + */ + + int32_t nperio_tx_fifo_size;/*!< Number of dwords in the non-periodic Tx FIFO in host mode. + 16 to 32768 + */ + + int32_t perio_tx_fifo_size; /*!< Number of dwords in the host periodic Tx FIFO. + 16 to 32768 + */ + #endif //__IS_HOST__ + + int32_t max_transfer_size; /*!< The maximum transfer size supported in bytes. + 2047 to 65,535 + */ + + int32_t max_packet_count; /*!< The maximum number of packets in a transfer. + 15 to 511 (default 511) + */ + int32_t phy_utmi_width; /*!< Specifies the UTMI+ Data Width. + 8 or 16 bits (default 16) + */ + + int32_t turn_around_time_hs; /*!< Specifies the Turn-Around time at HS*/ + int32_t turn_around_time_fs; /*!< Specifies the Turn-Around time at FS*/ + + int32_t timeout_cal_hs; /*!< Specifies the Timeout_Calibration at HS*/ + int32_t timeout_cal_fs; /*!< Specifies the Timeout_Calibration at FS*/ +} ifxusb_params_t; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/*! typedef ifxusb_core_if_t + \brief The ifx_core_if structure contains information needed to manage + the IFX USB controller acting in either host or device mode. It + represents the programming view of the controller as a whole. + */ +typedef struct ifxusb_core_if +{ + ifxusb_params_t params; /*!< Run-time Parameters */ + + uint8_t core_no; /*!< core number (used as id when multi-core case */ + char *core_name; /*!< core name used for registration and informative purpose*/ + int irq; /*!< irq number this core is hooked */ + + /***************************************************************** + * Structures and pointers to physical register interface. + *****************************************************************/ + /** Core Global registers starting at offset 000h. */ + ifxusb_core_global_regs_t *core_global_regs; /*!< pointer to Core Global Registers, offset at 000h */ + + /** Host-specific registers */ + #ifdef __IS_HOST__ + /** Host Global Registers starting at offset 400h.*/ + ifxusb_host_global_regs_t *host_global_regs; /*!< pointer to Host Global Registers, offset at 400h */ + #define IFXUSB_HOST_GLOBAL_REG_OFFSET 0x400 + /** Host Port 0 Control and Status Register */ + volatile uint32_t *hprt0; /*!< pointer to HPRT0 Registers, offset at 440h */ + #define IFXUSB_HOST_PORT_REGS_OFFSET 0x440 + /** Host Channel Specific Registers at offsets 500h-5FCh. */ + ifxusb_hc_regs_t *hc_regs[MAX_EPS_CHANNELS]; /*!< pointer to Host-Channel n Registers, offset at 500h */ + #define IFXUSB_HOST_CHAN_REGS_OFFSET 0x500 + #define IFXUSB_CHAN_REGS_OFFSET 0x20 + #endif + + /** Device-specific registers */ + #ifdef __IS_DEVICE__ + /** Device Global Registers starting at offset 800h */ + ifxusb_device_global_regs_t *dev_global_regs; /*!< pointer to Device Global Registers, offset at 800h */ + #define IFXUSB_DEV_GLOBAL_REG_OFFSET 0x800 + + /** Device Logical IN Endpoint-Specific Registers 900h-AFCh */ + ifxusb_dev_in_ep_regs_t *in_ep_regs[MAX_EPS_CHANNELS]; /*!< pointer to Device IN-EP Registers, offset at 900h */ + #define IFXUSB_DEV_IN_EP_REG_OFFSET 0x900 + #define IFXUSB_EP_REG_OFFSET 0x20 + /** Device Logical OUT Endpoint-Specific Registers B00h-CFCh */ + ifxusb_dev_out_ep_regs_t *out_ep_regs[MAX_EPS_CHANNELS];/*!< pointer to Device OUT-EP Registers, offset at 900h */ + #define IFXUSB_DEV_OUT_EP_REG_OFFSET 0xB00 + #endif + + /** Power and Clock Gating Control Register */ + volatile uint32_t *pcgcctl; /*!< pointer to Power and Clock Gating Control Registers, offset at E00h */ + #define IFXUSB_PCGCCTL_OFFSET 0xE00 + + /** Push/pop addresses for endpoints or host channels.*/ + uint32_t *data_fifo[MAX_EPS_CHANNELS]; /*!< pointer to FIFO access windows, offset at 1000h */ + #define IFXUSB_DATA_FIFO_OFFSET 0x1000 + #define IFXUSB_DATA_FIFO_SIZE 0x1000 + + uint32_t *data_fifo_dbg; /*!< pointer to FIFO debug windows, offset at 1000h */ + + /** Hardware Configuration -- stored here for convenience.*/ + hwcfg1_data_t hwcfg1; /*!< preserved Hardware Configuration 1 */ + hwcfg2_data_t hwcfg2; /*!< preserved Hardware Configuration 2 */ + hwcfg3_data_t hwcfg3; /*!< preserved Hardware Configuration 3 */ + hwcfg4_data_t hwcfg4; /*!< preserved Hardware Configuration 3 */ + uint32_t snpsid; /*!< preserved SNPSID */ + + /***************************************************************** + * Run-time informations. + *****************************************************************/ + /* Set to 1 if the core PHY interface bits in USBCFG have been initialized. */ + uint8_t phy_init_done; /*!< indicated PHY is initialized. */ + + #ifdef __IS_HOST__ + uint8_t queuing_high_bandwidth; /*!< Host mode, Queueing High Bandwidth. */ + #endif + + #if defined(__UNALIGNED_BUF_ADJ__) || defined(__UNALIGNED_BUF_CHK__) + uint32_t unaligned_mask; + #endif +} ifxusb_core_if_t; + +/*@}*//*IFXUSB_CIF*/ + + +/*! + \fn void *ifxusb_alloc_buf(size_t size, int clear) + \brief This function is called to allocate buffer of specified size. + The allocated buffer is mapped into DMA accessable address. + \param size Size in BYTE to be allocated + \param clear 0: don't do clear after buffer allocated, other: do clear to zero + \return 0/NULL: Fail; uncached pointer of allocated buffer + \ingroup IFXUSB_CIF + */ +#ifdef __IS_HOST__ +extern void *ifxusb_alloc_buf_h(size_t size, int clear); +#else +extern void *ifxusb_alloc_buf_d(size_t size, int clear); +#endif + + +/*! + \fn void ifxusb_free_buf(void *vaddr) + \brief This function is called to free allocated buffer. + \param vaddr the uncached pointer of the buffer + \ingroup IFXUSB_CIF + */ +#ifdef __IS_HOST__ +extern void ifxusb_free_buf_h(void *vaddr); +#else +extern void ifxusb_free_buf_d(void *vaddr); +#endif + +/*! + \fn int ifxusb_core_if_init(ifxusb_core_if_t *_core_if, + int _irq, + uint32_t _reg_base_addr, + uint32_t _fifo_base_addr, + uint32_t _fifo_dbg_addr) + \brief This function is called to initialize the IFXUSB CSR data + structures. The register addresses in the device and host + structures are initialized from the base address supplied by the + caller. The calling function must make the OS calls to get the + base address of the IFXUSB controller registers. + \param _core_if Pointer of core_if structure + \param _irq irq number + \param _reg_base_addr Base address of IFXUSB core registers + \param _fifo_base_addr Fifo base address + \param _fifo_dbg_addr Fifo debug address + \return 0: success; + \ingroup IFXUSB_CIF + */ +#ifdef __IS_HOST__ +extern int ifxusb_core_if_init_h(ifxusb_core_if_t *_core_if, +#else +extern int ifxusb_core_if_init_d(ifxusb_core_if_t *_core_if, +#endif + int _irq, + uint32_t _reg_base_addr, + uint32_t _fifo_base_addr, + uint32_t _fifo_dbg_addr); + + +/*! + \fn void ifxusb_core_if_remove(ifxusb_core_if_t *_core_if) + \brief This function free the mapped address in the IFXUSB CSR data structures. + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ +#ifdef __IS_HOST__ +extern void ifxusb_core_if_remove_h(ifxusb_core_if_t *_core_if); +#else +extern void ifxusb_core_if_remove_d(ifxusb_core_if_t *_core_if); +#endif + +/*! + \fn void ifxusb_enable_global_interrupts( ifxusb_core_if_t *_core_if ) + \brief This function enbles the controller's Global Interrupt in the AHB Config register. + \param _core_if Pointer of core_if structure + */ +#ifdef __IS_HOST__ +extern void ifxusb_enable_global_interrupts_h( ifxusb_core_if_t *_core_if ); +#else +extern void ifxusb_enable_global_interrupts_d( ifxusb_core_if_t *_core_if ); +#endif + +/*! + \fn void ifxusb_disable_global_interrupts( ifxusb_core_if_t *_core_if ) + \brief This function disables the controller's Global Interrupt in the AHB Config register. + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ +#ifdef __IS_HOST__ +extern void ifxusb_disable_global_interrupts_h( ifxusb_core_if_t *_core_if ); +#else +extern void ifxusb_disable_global_interrupts_d( ifxusb_core_if_t *_core_if ); +#endif + +/*! + \fn void ifxusb_flush_tx_fifo( ifxusb_core_if_t *_core_if, const int _num ) + \brief Flush a Tx FIFO. + \param _core_if Pointer of core_if structure + \param _num Tx FIFO to flush. ( 0x10 for ALL TX FIFO ) + \ingroup IFXUSB_CIF + */ +#ifdef __IS_HOST__ +extern void ifxusb_flush_tx_fifo_h( ifxusb_core_if_t *_core_if, const int _num ); +#else +extern void ifxusb_flush_tx_fifo_d( ifxusb_core_if_t *_core_if, const int _num ); +#endif + +/*! + \fn void ifxusb_flush_rx_fifo( ifxusb_core_if_t *_core_if ) + \brief Flush Rx FIFO. + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ +#ifdef __IS_HOST__ +extern void ifxusb_flush_rx_fifo_h( ifxusb_core_if_t *_core_if ); +#else +extern void ifxusb_flush_rx_fifo_d( ifxusb_core_if_t *_core_if ); +#endif + +/*! + \fn void ifxusb_flush_both_fifo( ifxusb_core_if_t *_core_if ) + \brief Flush ALL Rx and Tx FIFO. + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ +#ifdef __IS_HOST__ +extern void ifxusb_flush_both_fifo_h( ifxusb_core_if_t *_core_if ); +#else +extern void ifxusb_flush_both_fifo_d( ifxusb_core_if_t *_core_if ); +#endif + + +/*! + \fn int ifxusb_core_soft_reset(ifxusb_core_if_t *_core_if) + \brief Do core a soft reset of the core. Be careful with this because it + resets all the internal state machines of the core. + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ +#ifdef __IS_HOST__ +extern int ifxusb_core_soft_reset_h(ifxusb_core_if_t *_core_if); +#else +extern int ifxusb_core_soft_reset_d(ifxusb_core_if_t *_core_if); +#endif + + +/*! + \brief Turn on the USB Core Power + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF +*/ +#ifdef __IS_HOST__ + extern void ifxusb_power_on_h (ifxusb_core_if_t *_core_if); +#else + extern void ifxusb_power_on_d (ifxusb_core_if_t *_core_if); +#endif + +/*! + \fn void ifxusb_power_off (ifxusb_core_if_t *_core_if) + \brief Turn off the USB Core Power + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF +*/ +#ifdef __IS_HOST__ + extern void ifxusb_power_off_h (ifxusb_core_if_t *_core_if); +#else + extern void ifxusb_power_off_d (ifxusb_core_if_t *_core_if); +#endif + +/*! + \fn void ifxusb_phy_power_on (ifxusb_core_if_t *_core_if) + \brief Turn on the USB PHY Power + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF +*/ +#ifdef __IS_HOST__ + extern void ifxusb_phy_power_on_h (ifxusb_core_if_t *_core_if); +#else + extern void ifxusb_phy_power_on_d (ifxusb_core_if_t *_core_if); +#endif + + +/*! + \fn void ifxusb_phy_power_off (ifxusb_core_if_t *_core_if) + \brief Turn off the USB PHY Power + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF +*/ +#ifdef __IS_HOST__ + extern void ifxusb_phy_power_off_h (ifxusb_core_if_t *_core_if); +#else + extern void ifxusb_phy_power_off_d (ifxusb_core_if_t *_core_if); +#endif + +/*! + \fn void ifxusb_hard_reset(ifxusb_core_if_t *_core_if) + \brief Reset on the USB Core RCU + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ +#ifdef __IS_HOST__ + extern void ifxusb_hard_reset_h(ifxusb_core_if_t *_core_if); +#else + extern void ifxusb_hard_reset_d(ifxusb_core_if_t *_core_if); +#endif + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +#ifdef __IS_HOST__ + /*! + \fn void ifxusb_host_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) + \brief This function initializes the IFXUSB controller registers for Host mode. + This function flushes the Tx and Rx FIFOs and it flushes any entries in the + request queues. + \param _core_if Pointer of core_if structure + \param _params parameters to be set + \ingroup IFXUSB_CIF + */ + extern void ifxusb_host_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params); + + /*! + \fn void ifxusb_host_enable_interrupts(ifxusb_core_if_t *_core_if) + \brief This function enables the Host mode interrupts. + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ + extern void ifxusb_host_enable_interrupts(ifxusb_core_if_t *_core_if); + + /*! + \fn void ifxusb_host_disable_interrupts(ifxusb_core_if_t *_core_if) + \brief This function disables the Host mode interrupts. + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ + extern void ifxusb_host_disable_interrupts(ifxusb_core_if_t *_core_if); + + #if defined(__IS_TWINPASS__) + extern void ifxusb_enable_afe_oc(void); + #endif + + /*! + \fn void ifxusb_vbus_init(ifxusb_core_if_t *_core_if) + \brief This function init the VBUS control. + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ + extern void ifxusb_vbus_init(ifxusb_core_if_t *_core_if); + + /*! + \fn void ifxusb_vbus_free(ifxusb_core_if_t *_core_if) + \brief This function free the VBUS control. + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ + extern void ifxusb_vbus_free(ifxusb_core_if_t *_core_if); + + /*! + \fn void ifxusb_vbus_on(ifxusb_core_if_t *_core_if) + \brief Turn on the USB 5V VBus Power + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ + extern void ifxusb_vbus_on(ifxusb_core_if_t *_core_if); + + /*! + \fn void ifxusb_vbus_off(ifxusb_core_if_t *_core_if) + \brief Turn off the USB 5V VBus Power + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ + extern void ifxusb_vbus_off(ifxusb_core_if_t *_core_if); + + /*! + \fn int ifxusb_vbus(ifxusb_core_if_t *_core_if) + \brief Read Current VBus status + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ + extern int ifxusb_vbus(ifxusb_core_if_t *_core_if); +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + +#ifdef __IS_DEVICE__ + /*! + \fn void ifxusb_dev_enable_interrupts(ifxusb_core_if_t *_core_if) + \brief This function enables the Device mode interrupts. + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ + extern void ifxusb_dev_enable_interrupts(ifxusb_core_if_t *_core_if); + + /*! + \fn uint32_t ifxusb_dev_get_frame_number(ifxusb_core_if_t *_core_if) + \brief Gets the current USB frame number. This is the frame number from the last SOF packet. + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ + extern uint32_t ifxusb_dev_get_frame_number(ifxusb_core_if_t *_core_if); + + /*! + \fn void ifxusb_dev_ep_set_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _is_in) + \brief Set the EP STALL. + \param _core_if Pointer of core_if structure + \param _epno EP number + \param _is_in 1: is IN transfer + \ingroup IFXUSB_CIF + */ + extern void ifxusb_dev_ep_set_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _is_in); + + /*! + \fn void ifxusb_dev_ep_clear_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _ep_type, uint8_t _is_in) + \brief Set the EP STALL. + \param _core_if Pointer of core_if structure + \param _epno EP number + \param _ep_type EP Type + \ingroup IFXUSB_CIF + */ + extern void ifxusb_dev_ep_clear_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _ep_type, uint8_t _is_in); + + /*! + \fn void ifxusb_dev_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) + \brief This function initializes the IFXUSB controller registers for Device mode. + This function flushes the Tx and Rx FIFOs and it flushes any entries in the + request queues. + This function validate the imported parameters and store the result in the CIF structure. + After + \param _core_if Pointer of core_if structure + \param _params structure of inported parameters + \ingroup IFXUSB_CIF + */ + extern void ifxusb_dev_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params); +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if defined(__GADGET_LED__) || defined(__HOST_LED__) + /*! + \fn void ifxusb_led_init(ifxusb_core_if_t *_core_if) + \brief This function init the LED control. + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ + extern void ifxusb_led_init(ifxusb_core_if_t *_core_if); + + /*! + \fn void ifxusb_led_free(ifxusb_core_if_t *_core_if) + \brief This function free the LED control. + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ + extern void ifxusb_led_free(ifxusb_core_if_t *_core_if); + + /*! + \fn void ifxusb_led(ifxusb_core_if_t *_core_if) + \brief This function trigger the LED access. + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ + extern void ifxusb_led(ifxusb_core_if_t *_core_if); +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/* internal routines for debugging */ +#ifdef __IS_HOST__ + extern void ifxusb_dump_msg_h(const u8 *buf, unsigned int length); + extern void ifxusb_dump_spram_h(ifxusb_core_if_t *_core_if); + extern void ifxusb_dump_registers_h(ifxusb_core_if_t *_core_if); +#else + extern void ifxusb_dump_msg_d(const u8 *buf, unsigned int length); + extern void ifxusb_dump_spram_d(ifxusb_core_if_t *_core_if); + extern void ifxusb_dump_registers_d(ifxusb_core_if_t *_core_if); +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static inline uint32_t ifxusb_read_core_intr(ifxusb_core_if_t *_core_if) +{ + return (ifxusb_rreg(&_core_if->core_global_regs->gintsts) & + ifxusb_rreg(&_core_if->core_global_regs->gintmsk)); +} + +static inline uint32_t ifxusb_read_otg_intr (ifxusb_core_if_t *_core_if) +{ + return (ifxusb_rreg (&_core_if->core_global_regs->gotgint)); +} + +static inline uint32_t ifxusb_mode(ifxusb_core_if_t *_core_if) +{ + return (ifxusb_rreg( &_core_if->core_global_regs->gintsts ) & 0x1); +} +static inline uint8_t ifxusb_is_device_mode(ifxusb_core_if_t *_core_if) +{ + return (ifxusb_mode(_core_if) != 1); +} +static inline uint8_t ifxusb_is_host_mode(ifxusb_core_if_t *_core_if) +{ + return (ifxusb_mode(_core_if) == 1); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef __IS_HOST__ + static inline uint32_t ifxusb_read_hprt0(ifxusb_core_if_t *_core_if) + { + hprt0_data_t hprt0; + hprt0.d32 = ifxusb_rreg(_core_if->hprt0); + hprt0.b.prtena = 0; + hprt0.b.prtconndet = 0; + hprt0.b.prtenchng = 0; + hprt0.b.prtovrcurrchng = 0; + return hprt0.d32; + } + + static inline uint32_t ifxusb_read_host_all_channels_intr (ifxusb_core_if_t *_core_if) + { + return (ifxusb_rreg (&_core_if->host_global_regs->haint)); + } + + static inline uint32_t ifxusb_read_host_channel_intr (ifxusb_core_if_t *_core_if, int hc_num) + { + return (ifxusb_rreg (&_core_if->hc_regs[hc_num]->hcint)); + } +#endif + +#ifdef __IS_DEVICE__ + static inline uint32_t ifxusb_read_dev_all_in_ep_intr(ifxusb_core_if_t *_core_if) + { + uint32_t v; + v = ifxusb_rreg(&_core_if->dev_global_regs->daint) & + ifxusb_rreg(&_core_if->dev_global_regs->daintmsk); + return (v & 0xffff); + } + + static inline uint32_t ifxusb_read_dev_all_out_ep_intr(ifxusb_core_if_t *_core_if) + { + uint32_t v; + v = ifxusb_rreg(&_core_if->dev_global_regs->daint) & + ifxusb_rreg(&_core_if->dev_global_regs->daintmsk); + return ((v & 0xffff0000) >> 16); + } + + static inline uint32_t ifxusb_read_dev_in_ep_intr(ifxusb_core_if_t *_core_if, int _ep_num) + { + uint32_t v; + v = ifxusb_rreg(&_core_if->in_ep_regs[_ep_num]->diepint) & + ifxusb_rreg(&_core_if->dev_global_regs->diepmsk); + return v; + } + + static inline uint32_t ifxusb_read_dev_out_ep_intr(ifxusb_core_if_t *_core_if, int _ep_num) + { + uint32_t v; + v = ifxusb_rreg(&_core_if->out_ep_regs[_ep_num]->doepint) & + ifxusb_rreg(&_core_if->dev_global_regs->doepmsk); + return v; + } + +#endif + +#ifdef __IS_HOST__ +extern void ifxusb_attr_create_h (void *_dev); +extern void ifxusb_attr_remove_h (void *_dev); +#else +extern void ifxusb_attr_create_d (void *_dev); +extern void ifxusb_attr_remove_d (void *_dev); +#endif + +#ifdef __IS_HOST__ +extern void do_suspend_h(ifxusb_core_if_t *core_if); +extern void do_resume_h(ifxusb_core_if_t *_core_if); +#else +extern void do_suspend_d(ifxusb_core_if_t *core_if); +extern void do_resume_d(ifxusb_core_if_t *_core_if); +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#endif // !defined(__IFXUSB_CIF_H__) + diff --git a/package/platform/lantiq/ltq-hcd/src/ifxusb_cif_d.c b/package/platform/lantiq/ltq-hcd/src/ifxusb_cif_d.c new file mode 100644 index 0000000000..19f7650410 --- /dev/null +++ b/package/platform/lantiq/ltq-hcd/src/ifxusb_cif_d.c @@ -0,0 +1,535 @@ +/***************************************************************************** + ** FILE NAME : ifxusb_cif_d.c + ** PROJECT : IFX USB sub-system V3 + ** MODULES : IFX USB sub-system Host and Device driver + ** SRC VERSION : 3.2 + ** DATE : 1/Jan/2011 + ** AUTHOR : Chen, Howard + ** DESCRIPTION : The Core Interface provides basic services for accessing and + ** managing the IFX USB hardware. These services are used by the + ** Peripheral Controller Driver only. + ** FUNCTIONS : + ** COMPILER : gcc + ** REFERENCE : Synopsys DWC-OTG Driver 2.7 + ** COPYRIGHT : Copyright (c) 2010 + ** LANTIQ DEUTSCHLAND GMBH, + ** Am Campeon 3, 85579 Neubiberg, Germany + ** + ** This program is free software; you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation; either version 2 of the License, or + ** (at your option) any later version. + ** + ** Version Control Section ** + ** $Author$ + ** $Date$ + ** $Revisions$ + ** $Log$ Revision history + *****************************************************************************/ + +/* + * This file contains code fragments from Synopsys HS OTG Linux Software Driver. + * For this code the following notice is applicable: + * + * ========================================================================== + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +/*! + \file ifxusb_cif_d.c + \ingroup IFXUSB_DRIVER_V3 + \brief This file contains the interface to the IFX USB Core. +*/ + +#include +#include "ifxusb_version.h" + + +#include +#include + +#ifdef __DEBUG__ + #include +#endif + +#include "ifxusb_plat.h" +#include "ifxusb_regs.h" +#include "ifxusb_cif.h" + +#include "ifxpcd.h" + + + +/*! + \brief Initializes the DevSpd field of the DCFG register depending on the PHY type + and the enumeration speed of the device. + \param _core_if Pointer of core_if structure + */ +void ifxusb_dev_init_spd(ifxusb_core_if_t *_core_if) +{ + uint32_t val; + dcfg_data_t dcfg; + + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + if (_core_if->params.speed == IFXUSB_PARAM_SPEED_FULL) + /* High speed PHY running at full speed */ + val = 0x1; + else + /* High speed PHY running at high speed and full speed*/ + val = 0x0; + + IFX_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val); + dcfg.d32 = ifxusb_rreg(&_core_if->dev_global_regs->dcfg); + dcfg.b.devspd = val; + ifxusb_wreg(&_core_if->dev_global_regs->dcfg, dcfg.d32); +} + + +/*! + \brief This function enables the Device mode interrupts. + \param _core_if Pointer of core_if structure + */ +void ifxusb_dev_enable_interrupts(ifxusb_core_if_t *_core_if) +{ + gint_data_t intr_mask ={ .d32 = 0}; + ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; + + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + IFX_DEBUGPL(DBG_CIL, "%s()\n", __func__); + + /* Clear any pending OTG Interrupts */ + ifxusb_wreg( &global_regs->gotgint, 0xFFFFFFFF); + + /* Clear any pending interrupts */ + ifxusb_wreg( &global_regs->gintsts, 0xFFFFFFFF); + + /* Enable the interrupts in the GINTMSK.*/ + intr_mask.b.modemismatch = 1; + intr_mask.b.conidstschng = 1; + intr_mask.b.wkupintr = 1; + intr_mask.b.disconnect = 1; + intr_mask.b.usbsuspend = 1; + + intr_mask.b.usbreset = 1; + intr_mask.b.enumdone = 1; + intr_mask.b.inepintr = 1; + intr_mask.b.outepintr = 1; + intr_mask.b.erlysuspend = 1; + #ifndef __DED_FIFO__ + #ifndef __DED_INTR__ + intr_mask.b.epmismatch = 1; + #endif + #endif + + ifxusb_mreg( &global_regs->gintmsk, intr_mask.d32, intr_mask.d32); + IFX_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__, ifxusb_rreg( &global_regs->gintmsk)); +} + +/*! + \brief Gets the current USB frame number. This is the frame number from the last SOF packet. + \param _core_if Pointer of core_if structure + */ +uint32_t ifxusb_dev_get_frame_number(ifxusb_core_if_t *_core_if) +{ + dsts_data_t dsts; + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + dsts.d32 = ifxusb_rreg(&_core_if->dev_global_regs->dsts); + /* read current frame/microfreme number from DSTS register */ + return dsts.b.soffn; +} + + +/*! + \brief Set the EP STALL. + */ +void ifxusb_dev_ep_set_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _is_in) +{ + depctl_data_t depctl; + volatile uint32_t *depctl_addr; + + IFX_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _epno, (_is_in?"IN":"OUT")); + + depctl_addr = (_is_in)? (&(_core_if->in_ep_regs [_epno]->diepctl)): + (&(_core_if->out_ep_regs[_epno]->doepctl)); + depctl.d32 = ifxusb_rreg(depctl_addr); + depctl.b.stall = 1; + + if (_is_in && depctl.b.epena) + depctl.b.epdis = 1; + + ifxusb_wreg(depctl_addr, depctl.d32); + IFX_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",ifxusb_rreg(depctl_addr)); + return; +} + +/*! +\brief Clear the EP STALL. + */ +void ifxusb_dev_ep_clear_stall(ifxusb_core_if_t *_core_if, uint8_t _epno, uint8_t _ep_type, uint8_t _is_in) +{ + depctl_data_t depctl; + volatile uint32_t *depctl_addr; + + IFX_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, _epno, (_is_in?"IN":"OUT")); + + depctl_addr = (_is_in)? (&(_core_if->in_ep_regs [_epno]->diepctl)): + (&(_core_if->out_ep_regs[_epno]->doepctl)); + + depctl.d32 = ifxusb_rreg(depctl_addr); + /* clear the stall bits */ + depctl.b.stall = 0; + + /* + * USB Spec 9.4.5: For endpoints using data toggle, regardless + * of whether an endpoint has the Halt feature set, a + * ClearFeature(ENDPOINT_HALT) request always results in the + * data toggle being reinitialized to DATA0. + */ + if (_ep_type == IFXUSB_EP_TYPE_INTR || _ep_type == IFXUSB_EP_TYPE_BULK) + depctl.b.setd0pid = 1; /* DATA0 */ + + ifxusb_wreg(depctl_addr, depctl.d32); + IFX_DEBUGPL(DBG_PCD,"DEPCTL=%0x\n",ifxusb_rreg(depctl_addr)); + return; +} + +/*! + \brief This function initializes the IFXUSB controller registers for Device mode. + This function flushes the Tx and Rx FIFOs and it flushes any entries in the + request queues. + \param _core_if Pointer of core_if structure + \param _params parameters to be set + */ +void ifxusb_dev_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) +{ + ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; + + gusbcfg_data_t usbcfg ={.d32 = 0}; + gahbcfg_data_t ahbcfg ={.d32 = 0}; + dcfg_data_t dcfg ={.d32 = 0}; + grstctl_t resetctl ={.d32 = 0}; + gotgctl_data_t gotgctl ={.d32 = 0}; + + uint32_t dir; + int i; + + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + IFX_DEBUGPL(DBG_CILV, "%s(%p)\n",__func__,_core_if); + + /* Copy Params */ + _core_if->params.dma_burst_size = _params->dma_burst_size; + _core_if->params.speed = _params->speed; + if(_params->max_transfer_size < 2048 || _params->max_transfer_size > ((1 << (_core_if->hwcfg3.b.xfer_size_cntr_width + 11)) - 1) ) + _core_if->params.max_transfer_size = ((1 << (_core_if->hwcfg3.b.xfer_size_cntr_width + 11)) - 1); + else + _core_if->params.max_transfer_size = _params->max_transfer_size; + + if(_params->max_packet_count < 16 || _params->max_packet_count > ((1 << (_core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1) ) + _core_if->params.max_packet_count= ((1 << (_core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1); + else + _core_if->params.max_packet_count= _params->max_packet_count; + _core_if->params.phy_utmi_width = _params->phy_utmi_width; + _core_if->params.turn_around_time_hs = _params->turn_around_time_hs; + _core_if->params.turn_around_time_fs = _params->turn_around_time_fs; + _core_if->params.timeout_cal_hs = _params->timeout_cal_hs; + _core_if->params.timeout_cal_fs = _params->timeout_cal_fs; + + #ifdef __DED_FIFO__ + _core_if->params.thr_ctl = _params->thr_ctl; + _core_if->params.tx_thr_length = _params->tx_thr_length; + _core_if->params.rx_thr_length = _params->rx_thr_length; + #endif + + /* Reset the Controller */ + do + { + while(ifxusb_core_soft_reset_d( _core_if )) + ifxusb_hard_reset_d(_core_if); + } while (ifxusb_is_host_mode(_core_if)); + + usbcfg.d32 = ifxusb_rreg(&global_regs->gusbcfg); + + usbcfg.b.ForceDevMode = 1; + usbcfg.b.ForceHstMode = 0; + + usbcfg.b.term_sel_dl_pulse = 0; + ifxusb_wreg (&global_regs->gusbcfg, usbcfg.d32); + + /* This programming sequence needs to happen in FS mode before any other + * programming occurs */ + /* High speed PHY. */ + if (!_core_if->phy_init_done) + { + _core_if->phy_init_done = 1; + /* HS PHY parameters. These parameters are preserved + * during soft reset so only program the first time. Do + * a soft reset immediately after setting phyif. */ + usbcfg.b.ulpi_utmi_sel = 0; //UTMI+ + usbcfg.b.phyif = ( _core_if->params.phy_utmi_width == 16)?1:0; + ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); + /* Reset after setting the PHY parameters */ + ifxusb_core_soft_reset_d( _core_if ); + } + + /* Program the GAHBCFG Register.*/ + switch (_core_if->params.dma_burst_size) + { + case 0 : + ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_SINGLE; + break; + case 1 : + ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR; + break; + case 4 : + ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR4; + break; + case 8 : + ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR8; + break; + case 16: + ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR16; + break; + } + #if defined(__UNALIGNED_BUF_ADJ__) || defined(__UNALIGNED_BUF_CHK__) + _core_if->unaligned_mask=3; + #if defined(__UNALIGNED_BUF_BURST__) + switch (_core_if->params.dma_burst_size) + { + case 4 : + _core_if->unaligned_mask=15; + break; + case 8 : + _core_if->unaligned_mask=31; + break; + case 16: + _core_if->unaligned_mask=63; + break; + case 0 : + case 1 : + break; + } + #endif //defined(__UNALIGNED_BUF_BURST__) + #endif //defined(__UNALIGNED_BUF_ADJ__) || defined(__UNALIGNED_BUF_CHK__) + ahbcfg.b.dmaenable = 1; + ifxusb_wreg(&global_regs->gahbcfg, ahbcfg.d32); + + /* Program the GUSBCFG register. */ + usbcfg.d32 = ifxusb_rreg( &global_regs->gusbcfg ); + usbcfg.b.hnpcap = 0; + usbcfg.b.srpcap = 0; + ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); + + { + dctl_data_t dctl = {.d32=0}; + dctl.d32=ifxusb_rreg(&_core_if->dev_global_regs->dctl); + dctl.b.sftdiscon=1; + ifxusb_wreg(&_core_if->dev_global_regs->dctl,dctl.d32); + } + + /* Restart the Phy Clock */ + ifxusb_wreg(_core_if->pcgcctl, 0); + + /* Device configuration register */ + ifxusb_dev_init_spd(_core_if); + dcfg.d32 = ifxusb_rreg( &_core_if->dev_global_regs->dcfg); + dcfg.b.perfrint = IFXUSB_DCFG_FRAME_INTERVAL_80; + #if defined(__DED_FIFO__) + #if defined(__DESC_DMA__) + dcfg.b.descdma = 1; + #else + dcfg.b.descdma = 0; + #endif + #endif + + ifxusb_wreg( &_core_if->dev_global_regs->dcfg, dcfg.d32 ); + + /* Configure data FIFO sizes */ + _core_if->params.data_fifo_size = _core_if->hwcfg3.b.dfifo_depth; + _core_if->params.rx_fifo_size = ifxusb_rreg(&global_regs->grxfsiz); + IFX_DEBUGPL(DBG_CIL, "Initial: FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); + IFX_DEBUGPL(DBG_CIL, " Rx FIFO Size=0x%06X\n", _core_if->params.rx_fifo_size); + + _core_if->params.tx_fifo_size[0]= ifxusb_rreg(&global_regs->gnptxfsiz) >> 16; + + #ifdef __DED_FIFO__ + for (i=1; i <= _core_if->hwcfg4.b.num_in_eps; i++) + _core_if->params.tx_fifo_size[i] = + ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i-1]) >> 16; + #else + for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) + _core_if->params.tx_fifo_size[i+1] = + ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i]) >> 16; + #endif + + #ifdef __DEBUG__ + #ifdef __DED_FIFO__ + for (i=0; i <= _core_if->hwcfg4.b.num_in_eps; i++) + IFX_DEBUGPL(DBG_CIL, " Tx[%02d] FIFO Size=0x%06X\n",i, _core_if->params.tx_fifo_size[i]); + #else + IFX_DEBUGPL(DBG_CIL, " NPTx FIFO Size=0x%06X\n", _core_if->params.tx_fifo_size[0]); + for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) + IFX_DEBUGPL(DBG_CIL, " PTx[%02d] FIFO Size=0x%06X\n",i, _core_if->params.tx_fifo_size[i+1]); + #endif + #endif + + { + fifosize_data_t txfifosize; + if(_params->data_fifo_size >=0 && _params->data_fifo_size < _core_if->params.data_fifo_size) + _core_if->params.data_fifo_size = _params->data_fifo_size; + + + if(_params->rx_fifo_size >=0 && _params->rx_fifo_size < _core_if->params.rx_fifo_size) + _core_if->params.rx_fifo_size = _params->rx_fifo_size; + if(_core_if->params.data_fifo_size < _core_if->params.rx_fifo_size) + _core_if->params.rx_fifo_size = _core_if->params.data_fifo_size; + ifxusb_wreg( &global_regs->grxfsiz, _core_if->params.rx_fifo_size); + + for (i=0; i < MAX_EPS_CHANNELS; i++) + if(_params->tx_fifo_size[i] >=0 && _params->tx_fifo_size[i] < _core_if->params.tx_fifo_size[i]) + _core_if->params.tx_fifo_size[i] = _params->tx_fifo_size[i]; + + txfifosize.b.startaddr = _core_if->params.rx_fifo_size; + #ifdef __DED_FIFO__ + if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[0] > _core_if->params.data_fifo_size) + _core_if->params.tx_fifo_size[0]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; + txfifosize.b.depth=_core_if->params.tx_fifo_size[0]; + ifxusb_wreg( &global_regs->gnptxfsiz, txfifosize.d32); + txfifosize.b.startaddr += _core_if->params.tx_fifo_size[0]; + for (i=1; i <= _core_if->hwcfg4.b.num_in_eps; i++) + { + if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[i] > _core_if->params.data_fifo_size) + _core_if->params.tx_fifo_size[i]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; + txfifosize.b.depth=_core_if->params.tx_fifo_size[i]; + ifxusb_wreg( &global_regs->dptxfsiz_dieptxf[i-1], txfifosize.d32); + txfifosize.b.startaddr += _core_if->params.tx_fifo_size[i]; + } + #else + if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[0] > _core_if->params.data_fifo_size) + _core_if->params.tx_fifo_size[0]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; + txfifosize.b.depth=_core_if->params.tx_fifo_size[0]; + ifxusb_wreg( &global_regs->gnptxfsiz, txfifosize.d32); + txfifosize.b.startaddr += _core_if->params.tx_fifo_size[0]; + for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) + { + if(txfifosize.b.startaddr + _core_if->params.tx_fifo_size[i+1] > _core_if->params.data_fifo_size) + _core_if->params.tx_fifo_size[i+1]= _core_if->params.data_fifo_size - txfifosize.b.startaddr; + //txfifosize.b.depth=_core_if->params.tx_fifo_size[i+1]; + ifxusb_wreg( &global_regs->dptxfsiz_dieptxf[i], txfifosize.d32); + txfifosize.b.startaddr += _core_if->params.tx_fifo_size[i+1]; + } + #endif + } + + #ifdef __DEBUG__ + { + fifosize_data_t fifosize; + IFX_DEBUGPL(DBG_CIL, "Result : FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); + + IFX_DEBUGPL(DBG_CIL, " Rx FIFO =0x%06X Sz=0x%06X\n", 0,ifxusb_rreg(&global_regs->grxfsiz)); + #ifdef __DED_FIFO__ + fifosize.d32=ifxusb_rreg(&global_regs->gnptxfsiz); + IFX_DEBUGPL(DBG_CIL, " Tx[00] FIFO =0x%06X Sz=0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); + for (i=1; i <= _core_if->hwcfg4.b.num_in_eps; i++) + { + fifosize.d32=ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i-1]); + IFX_DEBUGPL(DBG_CIL, " Tx[%02d] FIFO 0x%06X Sz=0x%06X\n",i, fifosize.b.startaddr,fifosize.b.depth); + } + #else + fifosize.d32=ifxusb_rreg(&global_regs->gnptxfsiz); + IFX_DEBUGPL(DBG_CIL, " NPTx FIFO =0x%06X Sz=0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); + for (i=0; i < _core_if->hwcfg4.b.num_dev_perio_in_ep; i++) + { + fifosize.d32=ifxusb_rreg(&global_regs->dptxfsiz_dieptxf[i]); + IFX_DEBUGPL(DBG_CIL, " PTx[%02d] FIFO 0x%06X Sz=0x%06X\n",i, fifosize.b.startaddr,fifosize.b.depth); + } + #endif + } + #endif + + /* Clear Host Set HNP Enable in the OTG Control Register */ + gotgctl.b.hstsethnpen = 1; + ifxusb_mreg( &global_regs->gotgctl, gotgctl.d32, 0); + + /* Flush the FIFOs */ + ifxusb_flush_tx_fifo_d(_core_if, 0x10); /* all Tx FIFOs */ + ifxusb_flush_rx_fifo_d(_core_if); + + /* Flush the Learning Queue. */ + resetctl.b.intknqflsh = 1; + ifxusb_wreg( &global_regs->grstctl, resetctl.d32); + + /* Clear all pending Device Interrupts */ + ifxusb_wreg( &_core_if->dev_global_regs->diepmsk , 0 ); + ifxusb_wreg( &_core_if->dev_global_regs->doepmsk , 0 ); + ifxusb_wreg( &_core_if->dev_global_regs->daint , 0xFFFFFFFF ); + ifxusb_wreg( &_core_if->dev_global_regs->daintmsk, 0 ); + + dir=_core_if->hwcfg1.d32; + for (i=0; i <= _core_if->hwcfg2.b.num_dev_ep ; i++,dir>>=2) + { + depctl_data_t depctl; + if((dir&0x03)==0 || (dir&0x03) ==1) + { + depctl.d32 = ifxusb_rreg(&_core_if->in_ep_regs[i]->diepctl); + if (depctl.b.epena) + { + depctl.d32 = 0; + depctl.b.epdis = 1; + depctl.b.snak = 1; + } + else + depctl.d32 = 0; + ifxusb_wreg( &_core_if->in_ep_regs[i]->diepctl, depctl.d32); + #ifndef __DESC_DMA__ + ifxusb_wreg( &_core_if->in_ep_regs[i]->dieptsiz, 0); + #endif + ifxusb_wreg( &_core_if->in_ep_regs[i]->diepdma, 0); + ifxusb_wreg( &_core_if->in_ep_regs[i]->diepint, 0xFF); + } + + if((dir&0x03)==0 || (dir&0x03) ==2) + { + depctl.d32 = ifxusb_rreg(&_core_if->out_ep_regs[i]->doepctl); + if (depctl.b.epena) + { + depctl.d32 = 0; + depctl.b.epdis = 1; + depctl.b.snak = 1; + } + else + depctl.d32 = 0; + ifxusb_wreg( &_core_if->out_ep_regs[i]->doepctl, depctl.d32); + #ifndef __DESC_DMA__ + ifxusb_wreg( &_core_if->out_ep_regs[i]->doeptsiz, 0); + #endif + ifxusb_wreg( &_core_if->out_ep_regs[i]->doepdma, 0); + ifxusb_wreg( &_core_if->out_ep_regs[i]->doepint, 0xFF); + } + } +} + diff --git a/package/platform/lantiq/ltq-hcd/src/ifxusb_cif_h.c b/package/platform/lantiq/ltq-hcd/src/ifxusb_cif_h.c new file mode 100644 index 0000000000..e9e67bf43c --- /dev/null +++ b/package/platform/lantiq/ltq-hcd/src/ifxusb_cif_h.c @@ -0,0 +1,1599 @@ +/***************************************************************************** + ** FILE NAME : ifxusb_cif_h.c + ** PROJECT : IFX USB sub-system V3 + ** MODULES : IFX USB sub-system Host and Device driver + ** SRC VERSION : 3.2 + ** DATE : 1/Jan/2011 + ** AUTHOR : Chen, Howard + ** DESCRIPTION : The Core Interface provides basic services for accessing and + ** managing the IFX USB hardware. These services are used by the + ** Host Controller Driver only. + ** FUNCTIONS : + ** COMPILER : gcc + ** REFERENCE : Synopsys DWC-OTG Driver 2.7 + ** COPYRIGHT : Copyright (c) 2010 + ** LANTIQ DEUTSCHLAND GMBH, + ** Am Campeon 3, 85579 Neubiberg, Germany + ** + ** This program is free software; you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation; either version 2 of the License, or + ** (at your option) any later version. + ** + ** Version Control Section ** + ** $Author$ + ** $Date$ + ** $Revisions$ + ** $Log$ Revision history + *****************************************************************************/ + +/* + * This file contains code fragments from Synopsys HS OTG Linux Software Driver. + * For this code the following notice is applicable: + * + * ========================================================================== + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +/*! + \file ifxusb_cif_h.c + \ingroup IFXUSB_DRIVER_V3 + \brief This file contains the interface to the IFX USB Core. +*/ +#include +#include "ifxusb_version.h" + +#include +#include + +#ifdef __DEBUG__ + #include +#endif +#include +#include +#include + +#include "ifxusb_plat.h" +#include "ifxusb_regs.h" +#include "ifxusb_cif.h" + +#include "ifxhcd.h" + +#if !defined(__UEIP__) + #undef __USING_LED_AS_GPIO__ +#endif + + +/*! + \brief This function enables the Host mode interrupts. + \param _core_if Pointer of core_if structure + */ +void ifxusb_host_enable_interrupts(ifxusb_core_if_t *_core_if) +{ + gint_data_t intr_mask ={ .d32 = 0}; + ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; + + IFX_DEBUGPL(DBG_CIL, "%s()\n", __func__); + + /* Clear any pending OTG Interrupts */ + ifxusb_wreg( &global_regs->gotgint, 0xFFFFFFFF); + + /* Clear any pending interrupts */ + ifxusb_wreg( &global_regs->gintsts, 0xFFFFFFFF); + + /* Enable the interrupts in the GINTMSK.*/ + + /* Common interrupts */ + intr_mask.b.modemismatch = 1; + intr_mask.b.conidstschng = 1; + intr_mask.b.wkupintr = 1; + intr_mask.b.disconnect = 1; + intr_mask.b.usbsuspend = 1; + + /* Host interrupts */ + intr_mask.b.sofintr = 1; + intr_mask.b.portintr = 1; + intr_mask.b.hcintr = 1; + + ifxusb_mreg( &global_regs->gintmsk, intr_mask.d32, intr_mask.d32); + IFX_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__, ifxusb_rreg( &global_regs->gintmsk)); +} + +/*! + \brief This function disables the Host mode interrupts. + \param _core_if Pointer of core_if structure + */ +void ifxusb_host_disable_interrupts(ifxusb_core_if_t *_core_if) +{ + ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; + + IFX_DEBUGPL(DBG_CILV, "%s()\n", __func__); + + #if 1 + ifxusb_wreg( &global_regs->gintmsk, 0); + #else + /* Common interrupts */ + { + gint_data_t intr_mask ={.d32 = 0}; + intr_mask.b.modemismatch = 1; + intr_mask.b.rxstsqlvl = 1; + intr_mask.b.conidstschng = 1; + intr_mask.b.wkupintr = 1; + intr_mask.b.disconnect = 1; + intr_mask.b.usbsuspend = 1; + + /* Host interrupts */ + intr_mask.b.sofintr = 1; + intr_mask.b.portintr = 1; + intr_mask.b.hcintr = 1; + intr_mask.b.ptxfempty = 1; + intr_mask.b.nptxfempty = 1; + ifxusb_mreg(&global_regs->gintmsk, intr_mask.d32, 0); + } + #endif +} + +/*! + \brief This function initializes the IFXUSB controller registers for Host mode. + This function flushes the Tx and Rx FIFOs and it flushes any entries in the + request queues. + \param _core_if Pointer of core_if structure + \param _params parameters to be set + */ +void ifxusb_host_core_init(ifxusb_core_if_t *_core_if, ifxusb_params_t *_params) +{ + ifxusb_core_global_regs_t *global_regs = _core_if->core_global_regs; + + gusbcfg_data_t usbcfg ={.d32 = 0}; + gahbcfg_data_t ahbcfg ={.d32 = 0}; + gotgctl_data_t gotgctl ={.d32 = 0}; + + int i; + + IFX_DEBUGPL(DBG_CILV, "%s(%p)\n",__func__,_core_if); + + /* Copy Params */ + + _core_if->params.dma_burst_size = _params->dma_burst_size; + _core_if->params.speed = _params->speed; + if(_params->max_transfer_size < 2048 || _params->max_transfer_size > ((1 << (_core_if->hwcfg3.b.xfer_size_cntr_width + 11)) - 1) ) + _core_if->params.max_transfer_size = ((1 << (_core_if->hwcfg3.b.xfer_size_cntr_width + 11)) - 1); + else + _core_if->params.max_transfer_size = _params->max_transfer_size; + + if(_params->max_packet_count < 16 || _params->max_packet_count > ((1 << (_core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1) ) + _core_if->params.max_packet_count= ((1 << (_core_if->hwcfg3.b.packet_size_cntr_width + 4)) - 1); + else + _core_if->params.max_packet_count= _params->max_packet_count; + _core_if->params.phy_utmi_width = _params->phy_utmi_width; + _core_if->params.turn_around_time_hs = _params->turn_around_time_hs; + _core_if->params.turn_around_time_fs = _params->turn_around_time_fs; + _core_if->params.timeout_cal_hs = _params->timeout_cal_hs; + _core_if->params.timeout_cal_fs = _params->timeout_cal_fs; + usbcfg.d32 = ifxusb_rreg(&global_regs->gusbcfg); +// usbcfg.b.ulpi_ext_vbus_drv = 1; + usbcfg.b.term_sel_dl_pulse = 0; + usbcfg.b.ForceDevMode = 0; + usbcfg.b.ForceHstMode = 1; + ifxusb_wreg (&global_regs->gusbcfg, usbcfg.d32); + /* Reset the Controller */ + do + { + while(ifxusb_core_soft_reset_h( _core_if )) + ifxusb_hard_reset_h(_core_if); + } while (ifxusb_is_device_mode(_core_if)); + + usbcfg.d32 = ifxusb_rreg(&global_regs->gusbcfg); +// usbcfg.b.ulpi_ext_vbus_drv = 1; + usbcfg.b.term_sel_dl_pulse = 0; + ifxusb_wreg (&global_regs->gusbcfg, usbcfg.d32); + + /* This programming sequence needs to happen in FS mode before any other + * programming occurs */ + /* High speed PHY. */ + if (!_core_if->phy_init_done) + { + _core_if->phy_init_done = 1; + /* HS PHY parameters. These parameters are preserved + * during soft reset so only program the first time. Do + * a soft reset immediately after setting phyif. */ + usbcfg.b.ulpi_utmi_sel = 0; //UTMI+ + usbcfg.b.phyif = ( _core_if->params.phy_utmi_width == 16)?1:0; + ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); + /* Reset after setting the PHY parameters */ + ifxusb_core_soft_reset_h( _core_if ); + } + + usbcfg.d32 = ifxusb_rreg(&global_regs->gusbcfg); +// usbcfg.b.ulpi_fsls = 0; +// usbcfg.b.ulpi_clk_sus_m = 0; + usbcfg.b.term_sel_dl_pulse = 0; + usbcfg.b.ForceDevMode = 0; + usbcfg.b.ForceHstMode = 1; + ifxusb_wreg(&global_regs->gusbcfg, usbcfg.d32); + + /* Program the GAHBCFG Register.*/ + switch (_core_if->params.dma_burst_size) + { + case 0 : + ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_SINGLE; + break; + case 1 : + ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR; + break; + case 4 : + ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR4; + break; + case 8 : + ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR8; + break; + case 16: + ahbcfg.b.hburstlen = IFXUSB_GAHBCFG_INT_DMA_BURST_INCR16; + break; + } + #if defined(__UNALIGNED_BUF_ADJ__) || defined(__UNALIGNED_BUF_CHK__) + _core_if->unaligned_mask=3; + #if defined(__UNALIGNED_BUF_BURST__) + switch(_core_if->params.dma_burst_size) + { + case 4 : + _core_if->unaligned_mask=15; + break; + case 8 : + _core_if->unaligned_mask=31; + break; + case 16: + _core_if->unaligned_mask=63; + break; + case 0 : + case 1 : + break; + default: + break; + } + #endif //defined(__UNALIGNED_BUF_BURST__) + #endif //defined(__UNALIGNED_BUF_ADJ__) || defined(__UNALIGNED_BUF_CHK__) + ahbcfg.b.dmaenable = 1; + ifxusb_wreg(&global_regs->gahbcfg, ahbcfg.d32); + + /* Program the GUSBCFG register. */ + usbcfg.d32 = ifxusb_rreg( &global_regs->gusbcfg ); + usbcfg.b.hnpcap = 0; + usbcfg.b.srpcap = 0; + ifxusb_wreg( &global_regs->gusbcfg, usbcfg.d32); + + /* Restart the Phy Clock */ + ifxusb_wreg(_core_if->pcgcctl, 0); + + /* Initialize Host Configuration Register */ + { + hcfg_data_t hcfg; + hcfg.d32 = ifxusb_rreg(&_core_if->host_global_regs->hcfg); + hcfg.b.fslspclksel = IFXUSB_HCFG_30_60_MHZ; + if (_params->speed == IFXUSB_PARAM_SPEED_FULL) + hcfg.b.fslssupp = 1; + ifxusb_wreg(&_core_if->host_global_regs->hcfg, hcfg.d32); + } + + _core_if->params.host_channels=(_core_if->hwcfg2.b.num_host_chan + 1); + + if(_params->host_channels>0 && _params->host_channels < _core_if->params.host_channels) + _core_if->params.host_channels = _params->host_channels; + + /* Configure data FIFO sizes */ + _core_if->params.data_fifo_size = _core_if->hwcfg3.b.dfifo_depth; + _core_if->params.rx_fifo_size = ifxusb_rreg(&global_regs->grxfsiz); + _core_if->params.nperio_tx_fifo_size= ifxusb_rreg(&global_regs->gnptxfsiz) >> 16; + _core_if->params.perio_tx_fifo_size = ifxusb_rreg(&global_regs->hptxfsiz) >> 16; + IFX_DEBUGPL(DBG_CIL, "Initial: FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); + IFX_DEBUGPL(DBG_CIL, " Rx FIFO Size=0x%06X\n", _core_if->params.rx_fifo_size); + IFX_DEBUGPL(DBG_CIL, " NPTx FIFO Size=0x%06X\n", _core_if->params.nperio_tx_fifo_size); + IFX_DEBUGPL(DBG_CIL, " PTx FIFO Size=0x%06X\n", _core_if->params.perio_tx_fifo_size); + + { + fifosize_data_t txfifosize; + if(_params->data_fifo_size >=0 && _params->data_fifo_size < _core_if->params.data_fifo_size) + _core_if->params.data_fifo_size = _params->data_fifo_size; + + if( _params->rx_fifo_size >= 0 && _params->rx_fifo_size < _core_if->params.rx_fifo_size) + _core_if->params.rx_fifo_size = _params->rx_fifo_size; + if( _params->nperio_tx_fifo_size >=0 && _params->nperio_tx_fifo_size < _core_if->params.nperio_tx_fifo_size) + _core_if->params.nperio_tx_fifo_size = _params->nperio_tx_fifo_size; + if( _params->perio_tx_fifo_size >=0 && _params->perio_tx_fifo_size < _core_if->params.perio_tx_fifo_size) + _core_if->params.perio_tx_fifo_size = _params->perio_tx_fifo_size; + + if(_core_if->params.data_fifo_size < _core_if->params.rx_fifo_size) + _core_if->params.rx_fifo_size = _core_if->params.data_fifo_size; + ifxusb_wreg( &global_regs->grxfsiz, _core_if->params.rx_fifo_size); + txfifosize.b.startaddr = _core_if->params.rx_fifo_size; + + if(txfifosize.b.startaddr + _core_if->params.nperio_tx_fifo_size > _core_if->params.data_fifo_size) + _core_if->params.nperio_tx_fifo_size = _core_if->params.data_fifo_size - txfifosize.b.startaddr; + txfifosize.b.depth=_core_if->params.nperio_tx_fifo_size; + ifxusb_wreg( &global_regs->gnptxfsiz, txfifosize.d32); + txfifosize.b.startaddr += _core_if->params.nperio_tx_fifo_size; + + if(txfifosize.b.startaddr + _core_if->params.perio_tx_fifo_size > _core_if->params.data_fifo_size) + _core_if->params.perio_tx_fifo_size = _core_if->params.data_fifo_size - txfifosize.b.startaddr; + txfifosize.b.depth=_core_if->params.perio_tx_fifo_size; + ifxusb_wreg( &global_regs->hptxfsiz, txfifosize.d32); + txfifosize.b.startaddr += _core_if->params.perio_tx_fifo_size; + } + + #ifdef __DEBUG__ + { + fifosize_data_t fifosize; + IFX_DEBUGPL(DBG_CIL, "Result : FIFO Size=0x%06X\n" , _core_if->params.data_fifo_size); + + fifosize.d32=ifxusb_rreg(&global_regs->grxfsiz); + IFX_DEBUGPL(DBG_CIL, " Rx FIFO =0x%06X 0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); + fifosize.d32=ifxusb_rreg(&global_regs->gnptxfsiz); + IFX_DEBUGPL(DBG_CIL, " NPTx FIFO =0x%06X 0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); + fifosize.d32=ifxusb_rreg(&global_regs->hptxfsiz); + IFX_DEBUGPL(DBG_CIL, " PTx FIFO =0x%06X 0x%06X\n", fifosize.b.startaddr,fifosize.b.depth); + } + #endif + + /* Clear Host Set HNP Enable in the OTG Control Register */ + gotgctl.b.hstsethnpen = 1; + ifxusb_mreg( &global_regs->gotgctl, gotgctl.d32, 0); + + /* Flush the FIFOs */ + ifxusb_flush_tx_fifo_h(_core_if, 0x10); /* all Tx FIFOs */ + ifxusb_flush_rx_fifo_h(_core_if); + + for (i = 0; i < _core_if->hwcfg2.b.num_host_chan + 1; i++) + { + hcchar_data_t hcchar; + hcchar.d32 = ifxusb_rreg(&_core_if->hc_regs[i]->hcchar); + hcchar.b.chen = 0; + hcchar.b.chdis = 1; + hcchar.b.epdir = 0; + ifxusb_wreg(&_core_if->hc_regs[i]->hcchar, hcchar.d32); + } + /* Halt all channels to put them into a known state. */ + for (i = 0; i < _core_if->hwcfg2.b.num_host_chan + 1; i++) + { + hcchar_data_t hcchar; + int count = 0; + + hcchar.d32 = ifxusb_rreg(&_core_if->hc_regs[i]->hcchar); + hcchar.b.chen = 1; + hcchar.b.chdis = 1; + hcchar.b.epdir = 0; + ifxusb_wreg(&_core_if->hc_regs[i]->hcchar, hcchar.d32); + + IFX_DEBUGPL(DBG_HCDV, "%s: Halt channel %d\n", __func__, i); + do{ + hcchar.d32 = ifxusb_rreg(&_core_if->hc_regs[i]->hcchar); + if (++count > 1000) + { + IFX_ERROR("%s: Unable to clear halt on channel %d\n", __func__, i); + break; + } + } while (hcchar.b.chen); + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if defined(__UEIP__) + #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) + int ifxusb_vbus_status =-1; + #endif + + #if defined(IFX_GPIO_USB_VBUS1) || defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) + int ifxusb_vbus1_status =-1; + #endif + + #if defined(IFX_GPIO_USB_VBUS2) || defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) + int ifxusb_vbus2_status =-1; + #endif + + #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) + static void *g_usb_vbus_trigger = NULL; + #endif + #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) + static void *g_usb_vbus1_trigger = NULL; + #endif + #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) + static void *g_usb_vbus2_trigger = NULL; + #endif + + #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) + int ifxusb_vbus_gpio_inited=0; + #endif + +#else //defined(__UEIP__) + int ifxusb_vbus_status =-1; + int ifxusb_vbus1_status =-1; + int ifxusb_vbus2_status =-1; + int ifxusb_vbus_gpio_inited=0; +#endif + +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/*! + \fn void ifxusb_vbus_init(ifxusb_core_if_t *_core_if) + \brief This function init the VBUS control. + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ +void ifxusb_vbus_init(ifxusb_core_if_t *_core_if) +{ + #if defined(__UEIP__) + #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) + if ( !g_usb_vbus_trigger ) + { + ifx_led_trigger_register("USB_VBUS", &g_usb_vbus_trigger); + if ( g_usb_vbus_trigger != NULL ) + { + struct ifx_led_trigger_attrib attrib = {0}; + attrib.delay_on = 0; + attrib.delay_off = 0; + attrib.timeout = 0; + attrib.def_value = 0; + attrib.flags = IFX_LED_TRIGGER_ATTRIB_DELAY_ON | IFX_LED_TRIGGER_ATTRIB_DELAY_OFF | IFX_LED_TRIGGER_ATTRIB_TIMEOUT | IFX_LED_TRIGGER_ATTRIB_DEF_VALUE; + IFX_DEBUGP("Reg USB power!!\n"); + ifx_led_trigger_set_attrib(g_usb_vbus_trigger, &attrib); + ifxusb_vbus_status =0; + } + } + #endif + #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) + if(_core_if->core_no==0 && !g_usb_vbus1_trigger ) + { + ifx_led_trigger_register("USB_VBUS1", &g_usb_vbus1_trigger); + if ( g_usb_vbus1_trigger != NULL ) + { + struct ifx_led_trigger_attrib attrib = {0}; + attrib.delay_on = 0; + attrib.delay_off = 0; + attrib.timeout = 0; + attrib.def_value = 0; + attrib.flags = IFX_LED_TRIGGER_ATTRIB_DELAY_ON | IFX_LED_TRIGGER_ATTRIB_DELAY_OFF | IFX_LED_TRIGGER_ATTRIB_TIMEOUT | IFX_LED_TRIGGER_ATTRIB_DEF_VALUE; + IFX_DEBUGP("Reg USB1 power!!\n"); + ifx_led_trigger_set_attrib(g_usb_vbus1_trigger, &attrib); + ifxusb_vbus1_status =0; + } + } + #endif + #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) + if(_core_if->core_no==1 && !g_usb_vbus2_trigger ) + { + ifx_led_trigger_register("USB_VBUS2", &g_usb_vbus2_trigger); + if ( g_usb_vbus2_trigger != NULL ) + { + struct ifx_led_trigger_attrib attrib = {0}; + attrib.delay_on = 0; + attrib.delay_off = 0; + attrib.timeout = 0; + attrib.def_value = 0; + attrib.flags = IFX_LED_TRIGGER_ATTRIB_DELAY_ON | IFX_LED_TRIGGER_ATTRIB_DELAY_OFF | IFX_LED_TRIGGER_ATTRIB_TIMEOUT | IFX_LED_TRIGGER_ATTRIB_DEF_VALUE; + IFX_DEBUGP("Reg USB2 power!!\n"); + ifx_led_trigger_set_attrib(g_usb_vbus2_trigger, &attrib); + ifxusb_vbus2_status =0; + } + } + #endif + + #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) + if(!ifxusb_vbus_gpio_inited) + { + if(!ifx_gpio_register(IFX_GPIO_MODULE_USB)) + { + IFX_DEBUGP("Register USB VBus through GPIO OK!!\n"); + #ifdef IFX_GPIO_USB_VBUS + ifxusb_vbus_status =0; + #endif //IFX_GPIO_USB_VBUS + #ifdef IFX_GPIO_USB_VBUS1 + ifxusb_vbus1_status=0; + #endif //IFX_GPIO_USB_VBUS1 + #ifdef IFX_GPIO_USB_VBUS2 + ifxusb_vbus2_status=0; + #endif //IFX_GPIO_USB_VBUS2 + } + else + IFX_PRINT("Register USB VBus Failed!!\n"); + ifxusb_vbus_gpio_inited=1; + } + #endif //defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) + #endif //defined(__UEIP__) +} + +/*! + \fn void ifxusb_vbus_free(ifxusb_core_if_t *_core_if) + \brief This function free the VBUS control. + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ +void ifxusb_vbus_free(ifxusb_core_if_t *_core_if) +{ + #if defined(__UEIP__) + #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) + if ( g_usb_vbus_trigger ) + { + ifx_led_trigger_deregister(g_usb_vbus_trigger); + g_usb_vbus_trigger = NULL; + ifxusb_vbus_status =-1; + } + #endif + #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) + if(_core_if->core_no==0 && g_usb_vbus1_trigger ) + { + ifx_led_trigger_deregister(g_usb_vbus1_trigger); + g_usb_vbus1_trigger = NULL; + ifxusb_vbus1_status =-1; + } + #endif + #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) + if(_core_if->core_no==1 && g_usb_vbus2_trigger ) + { + ifx_led_trigger_deregister(g_usb_vbus2_trigger); + g_usb_vbus2_trigger = NULL; + ifxusb_vbus2_status =-1; + } + #endif + + #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) + if(ifxusb_vbus_gpio_inited) + { + ifx_gpio_deregister(IFX_GPIO_MODULE_USB); + #ifdef IFX_GPIO_USB_VBUS + ifxusb_vbus_status =-1; + #endif //IFX_GPIO_USB_VBUS + #ifdef IFX_GPIO_USB_VBUS1 + ifxusb_vbus1_status=-1; + #endif //IFX_GPIO_USB_VBUS1 + #ifdef IFX_GPIO_USB_VBUS2 + ifxusb_vbus2_status=-1; + #endif //IFX_GPIO_USB_VBUS2 + ifxusb_vbus_gpio_inited=0; + } + #endif //defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) + #endif //defined(__UEIP__) +} + + +#if defined(__DO_OC_INT__) + +#define OC_Timer_Stable 3 +#define OC_Timer_Sleep 200 +#define OC_Timer_Max 3 + + + #if defined(__IS_AR10__) + #if defined(__IS_DUAL__) + unsigned int oc1_int_installed=0; + unsigned int oc2_int_installed=0; + unsigned int oc1_int_count=0; + unsigned int oc2_int_count=0; + extern ifxhcd_hcd_t *oc1_int_id; + extern ifxhcd_hcd_t *oc2_int_id; + + /*! + \brief Handles host mode Over Current Interrupt + */ + struct timer_list oc1_retry_timer; + struct timer_list oc2_retry_timer; + + void oc_retry_timer_func(unsigned long arg) + { + if(arg==1) + { + if(oc1_int_installed==0) //not installed + { + } + else if(oc1_int_installed==1) //disabled + { + } + else if(oc1_int_installed==2) //stablizing + { + oc1_int_installed=4; + oc1_int_count=0; + } + else if(oc1_int_installed==3) // sleeping + { + mod_timer(&oc1_retry_timer,jiffies + HZ*OC_Timer_Stable); + oc1_int_installed=2; + enable_irq(IFXUSB1_OC_IRQ); + } + else if(oc1_int_installed==4) // + { + oc1_int_count=0; + } + else if(oc1_int_installed==5) // Stable sleeping + { + mod_timer(&oc1_retry_timer,jiffies + HZ*OC_Timer_Stable); + oc1_int_installed=4; + enable_irq(IFXUSB1_OC_IRQ); + } + else + { + } + } + else + { + if(oc2_int_installed==0) //not installed + { + } + else if(oc2_int_installed==1) //disabled + { + } + else if(oc2_int_installed==2) //stablizing + { + oc2_int_installed=4; + oc2_int_count=0; + } + else if(oc2_int_installed==3) // sleeping + { + mod_timer(&oc2_retry_timer,jiffies + HZ*OC_Timer_Stable); + oc2_int_installed=2; + enable_irq(IFXUSB2_OC_IRQ); + } + else if(oc2_int_installed==4) // + { + oc2_int_count=0; + } + else if(oc2_int_installed==5) // Stable sleeping + { + mod_timer(&oc2_retry_timer,jiffies + HZ*OC_Timer_Stable); + oc2_int_installed=4; + enable_irq(IFXUSB2_OC_IRQ); + } + else + { + } + } + } + + irqreturn_t ifxhcd_oc_irq(int _irq , void *_dev) + { + //ifxhcd_hcd_t *ifxhcd= _dev; + int32_t retval=1; + if(_irq==IFXUSB1_OC_IRQ) + { + if(oc1_int_installed==0) //not installed + { + } + else if(oc1_int_installed==1) //disabled + { + } + else if(oc1_int_installed==2) //stablizing + { + disable_irq_nosync(IFXUSB1_OC_IRQ); + mod_timer(&oc1_retry_timer,jiffies + HZ/OC_Timer_Sleep); + oc1_int_installed=3; + } + else if(oc1_int_installed==3) // sleeping + { + } + else if(oc1_int_installed==4) // + { + oc1_int_count++; + if(oc1_int_count>=OC_Timer_Max) + { + IFX_DEBUGP("OC INTERRUPT port #1\n"); + oc1_int_id->flags.b.port_over_current_change = 1; + ifxusb_vbus_off(&oc1_int_id->core_if); + IFX_DEBUGP("Turning off port #1\n"); + } + else + { + disable_irq_nosync(IFXUSB1_OC_IRQ); + mod_timer(&oc1_retry_timer,jiffies + HZ/OC_Timer_Sleep); + oc1_int_installed=5; + } + } + else if(oc1_int_installed==5) // Stable sleeping + { + } + } + else + { + if(oc2_int_installed==0) //not installed + { + } + else if(oc2_int_installed==1) //disabled + { + } + else if(oc2_int_installed==2) //stablizing + { + disable_irq_nosync(IFXUSB2_OC_IRQ); + mod_timer(&oc2_retry_timer,jiffies + HZ/OC_Timer_Sleep); + oc2_int_installed=3; + } + else if(oc2_int_installed==3) // sleeping + { + } + else if(oc2_int_installed==4) // + { + oc2_int_count++; + if(oc2_int_count>=OC_Timer_Max) + { + IFX_DEBUGP("OC INTERRUPT port #2\n"); + oc2_int_id->flags.b.port_over_current_change = 1; + ifxusb_vbus_off(&oc2_int_id->core_if); + IFX_DEBUGP("Turning off port #2\n"); + } + else + { + disable_irq_nosync(IFXUSB2_OC_IRQ); + mod_timer(&oc2_retry_timer,jiffies + HZ/OC_Timer_Sleep); + oc2_int_installed=5; + } + } + else if(oc2_int_installed==5) // Stable sleeping + { + } + } + return IRQ_RETVAL(retval); + } + + void ifxusb_oc_int_on(int port) + { + if(port==1) + IFX_DEBUGPL( DBG_CIL, "registering (overcurrent) handler for port #1 irq%d\n", IFXUSB1_OC_IRQ); + else + IFX_DEBUGPL( DBG_CIL, "registering (overcurrent) handler for port #2 irq%d\n", IFXUSB2_OC_IRQ); + if((port==1&&oc1_int_id) || (port==2&&oc2_int_id) + { + if((port==1&&oc1_int_installed==0)||(port==2&&oc2_int_installed==0)) + { + if(port==1) + { + oc1_int_installed=2; + init_timer(&oc1_retry_timer); + oc1_retry_timer.function = oc_retry_timer_func; + oc1_retry_timer.data=1; + if(request_irq((unsigned int)IFXUSB1_OC_IRQ, &ifxhcd_oc_irq, + IRQF_TRIGGER_NONE + // | IRQF_TRIGGER_RISING + // | IRQF_TRIGGER_FALLING + // | IRQF_TRIGGER_HIGH + // | IRQF_TRIGGER_LOW + // | IRQF_TRIGGER_PROBE + | IRQF_DISABLED + // | IRQF_SAMPLE_RANDOM + // | IRQF_SHARED + | IRQF_PROBE_SHARED + // | IRQF_TIMER + // | IRQF_PERCPU + // | IRQF_NOBALANCING + // | IRQF_IRQPOLL + // | IRQF_ONESHOT + , + "ifxusb1_oc", (void *)oc1_int_id)) + oc1_int_installed=0; + else + mod_timer(&oc1_retry_timer,jiffies + HZ*OC_Timer_Stable); + } + else + { + oc2_int_installed=2; + init_timer(&oc2_retry_timer); + oc2_retry_timer.function = oc_retry_timer_func; + oc2_retry_timer.data=2; + if(request_irq((unsigned int)IFXUSB2_OC_IRQ, &ifxhcd_oc_irq, + IRQF_TRIGGER_NONE + // | IRQF_TRIGGER_RISING + // | IRQF_TRIGGER_FALLING + // | IRQF_TRIGGER_HIGH + // | IRQF_TRIGGER_LOW + // | IRQF_TRIGGER_PROBE + | IRQF_DISABLED + // | IRQF_SAMPLE_RANDOM + // | IRQF_SHARED + | IRQF_PROBE_SHARED + // | IRQF_TIMER + // | IRQF_PERCPU + // | IRQF_NOBALANCING + // | IRQF_IRQPOLL + // | IRQF_ONESHOT + , + "ifxusb2_oc", (void *)oc2_int_id)) + oc2_int_installed=0; + else + mod_timer(&oc2_retry_timer,jiffies + HZ*OC_Timer_Stable); + } + /* Poll the event ring */ + } + else if(port==1 && oc1_int_installed!=2 && oc1_int_installed!=4 ) + { + oc1_int_installed=2; + enable_irq(IFXUSB1_OC_IRQ); + mod_timer(&oc1_retry_timer,jiffies + HZ*OC_Timer_Stable); + } + else if(port==2 && oc2_int_installed!=2 && oc2_int_installed!=4 ) + { + oc2_int_installed=2; + enable_irq(IFXUSB2_OC_IRQ); + mod_timer(&oc2_retry_timer,jiffies + HZ*OC_Timer_Stable); + } + } + } + + void ifxusb_oc_int_off(int port) + { + if(port==1) + { + disable_irq_nosync(IFXUSB1_OC_IRQ); + if(oc1_int_installed) + oc1_int_installed=1; + } + else + { + disable_irq_nosync(IFXUSB2_OC_IRQ); + if(oc2_int_installed) + oc2_int_installed=1; + } + } + + + void ifxusb_oc_int_free(int port) + { + if(port==1) + { + del_timer(&oc1_retry_timer); + disable_irq_nosync(IFXUSB1_OC_IRQ); + free_irq(IFXUSB1_OC_IRQ, (void *)oc1_int_id); + oc1_int_installed=0; + } + else + { + del_timer(&oc1_retry_timer); + disable_irq_nosync(IFXUSB1_OC_IRQ); + free_irq(IFXUSB2_OC_IRQ, (void *)oc2_int_id); + oc2_int_installed=0; + } + } + + #elif defined(__IS_FIRST__) || defined(__IS_SECOND__) + unsigned int oc_int_installed=0; + unsigned int oc_int_count=0; + extern ifxhcd_hcd_t *oc_int_id; + + /*! + \brief Handles host mode Over Current Interrupt + */ + struct timer_list oc_retry_timer; + + void oc_retry_timer_func(void) + { + if(oc_int_installed==0) //not installed + { + } + else if(oc_int_installed==1) //disabled + { + } + else if(oc_int_installed==2) //stablizing + { + oc_int_installed=4; + oc_int_count=0; + } + else if(oc_int_installed==3) // sleeping + { + mod_timer(&oc_retry_timer,jiffies + HZ*OC_Timer_Stable); + oc_int_installed=2; + #if defined(__IS_FIRST__) + enable_irq(IFXUSB1_OC_IRQ); + #else + enable_irq(IFXUSB2_OC_IRQ); + #endif + } + else if(oc_int_installed==4) // + { + oc_int_count=0; + } + else if(oc_int_installed==5) // Stable sleeping + { + mod_timer(&oc_retry_timer,jiffies + HZ*OC_Timer_Stable); + oc_int_installed=4; + #if defined(__IS_FIRST__) + enable_irq(IFXUSB1_OC_IRQ); + #else + enable_irq(IFXUSB2_OC_IRQ); + #endif + } + else + { + } + } + + irqreturn_t ifxhcd_oc_irq(int _irq , void *_dev) + { + //ifxhcd_hcd_t *ifxhcd= _dev; + int32_t retval=1; + if(oc_int_installed==0) //not installed + { + } + else if(oc_int_installed==1) //disabled + { + } + else if(oc_int_installed==2) //stablizing + { + #if defined(__IS_FIRST__) + disable_irq_nosync(IFXUSB1_OC_IRQ); + #else + disable_irq_nosync(IFXUSB2_OC_IRQ); + #endif + mod_timer(&oc_retry_timer,jiffies + HZ/OC_Timer_Sleep); + oc_int_installed=3; + } + else if(oc_int_installed==3) // sleeping + { + } + else if(oc_int_installed==4) // + { + oc_int_count++; + if(oc_int_count>=OC_Timer_Max) + { + #if defined(__IS_FIRST__) + IFX_DEBUGP("OC INTERRUPT port #1\n"); + #else + IFX_DEBUGP("OC INTERRUPT port #2\n"); + #endif + oc_int_id->flags.b.port_over_current_change = 1; + ifxusb_vbus_off(&oc_int_id->core_if); + #if defined(__IS_FIRST__) + IFX_DEBUGP("Turning off port #1\n"); + #else + IFX_DEBUGP("Turning off port #2\n"); + #endif + } + else + { + #if defined(__IS_FIRST__) + disable_irq_nosync(IFXUSB1_OC_IRQ); + #else + disable_irq_nosync(IFXUSB2_OC_IRQ); + #endif + mod_timer(&oc_retry_timer,jiffies + HZ/OC_Timer_Sleep); + oc_int_installed=5; + } + } + else if(oc_int_installed==5) // Stable sleeping + { + } + return IRQ_RETVAL(retval); + } + + void ifxusb_oc_int_on(void) + { + #if defined(__IS_FIRST__) + IFX_DEBUGPL( DBG_CIL, "registering (overcurrent) handler for port #1 irq%d\n", IFXUSB1_OC_IRQ); + #else + IFX_DEBUGPL( DBG_CIL, "registering (overcurrent) handler for port #2 irq%d\n", IFXUSB2_OC_IRQ); + #endif + if(oc_int_id) + { + if(oc_int_installed==0) + { + oc_int_installed=2; + init_timer(&oc_retry_timer); + oc_retry_timer.function = oc_retry_timer_func; + oc_retry_timer.data=1; + #if defined(__IS_FIRST__) + if(request_irq((unsigned int)IFXUSB1_OC_IRQ, &ifxhcd_oc_irq, + #else + if(request_irq((unsigned int)IFXUSB2_OC_IRQ, &ifxhcd_oc_irq, + #endif + IRQF_TRIGGER_NONE + // | IRQF_TRIGGER_RISING + // | IRQF_TRIGGER_FALLING + // | IRQF_TRIGGER_HIGH + // | IRQF_TRIGGER_LOW + // | IRQF_TRIGGER_PROBE + | IRQF_DISABLED + // | IRQF_SAMPLE_RANDOM + // | IRQF_SHARED + | IRQF_PROBE_SHARED + // | IRQF_TIMER + // | IRQF_PERCPU + // | IRQF_NOBALANCING + // | IRQF_IRQPOLL + // | IRQF_ONESHOT + , + "ifxusb_oc", (void *)oc_int_id)) + oc_int_installed=0; + else + mod_timer(&oc1_retry_timer,jiffies + HZ*OC_Timer_Stable); + } + else if(oc_int_installed!=2 && oc_int_installed!=4 ) + { + oc_int_installed=2; + #if defined(__IS_FIRST__) + enable_irq(IFXUSB1_OC_IRQ); + #else + enable_irq(IFXUSB2_OC_IRQ); + #endif + mod_timer(&oc_retry_timer,jiffies + HZ*OC_Timer_Stable); + } + } + } + + void ifxusb_oc_int_off(int port) + { + #if defined(__IS_FIRST__) + disable_irq_nosync(IFXUSB1_OC_IRQ); + #else + disable_irq_nosync(IFXUSB2_OC_IRQ); + #endif + } + void ifxusb_oc_int_free(int port) + { + #if defined(__IS_FIRST__) + free_irq(IFXUSB1_OC_IRQ, (void *)oc_int_id); + #else + free_irq(IFXUSB2_OC_IRQ, (void *)oc_int_id); + #endif + } + #endif + #else //!defined(__IS_AR10__) + unsigned int oc_int_installed=0; + unsigned int oc_int_count=0; + extern ifxhcd_hcd_t *oc_int_id; + #ifdef __IS_DUAL__ + extern ifxhcd_hcd_t *oc_int_id_1; + extern ifxhcd_hcd_t *oc_int_id_2; + #endif + + /*! + \brief Handles host mode Over Current Interrupt + */ + struct timer_list oc_retry_timer; + + void oc_retry_timer_func(unsigned long arg) + { + if(oc_int_installed==0) //not installed + { + } + else if(oc_int_installed==1) //disabled + { + } + else if(oc_int_installed==2) //stablizing + { + oc_int_installed=4; + oc_int_count=0; + } + else if(oc_int_installed==3) // sleeping + { + mod_timer(&oc_retry_timer,jiffies + HZ*OC_Timer_Stable); + oc_int_installed=2; + enable_irq(IFXUSB_OC_IRQ); + } + else if(oc_int_installed==4) // + { + oc_int_count=0; + } + else if(oc_int_installed==5) // Stable sleeping + { + mod_timer(&oc_retry_timer,jiffies + HZ*OC_Timer_Stable); + oc_int_installed=4; + enable_irq(IFXUSB_OC_IRQ); + } + else + { + } + } + + irqreturn_t ifxhcd_oc_irq(int _irq , void *_dev) + { + //ifxhcd_hcd_t *ifxhcd= _dev; + int32_t retval=1; + + if(oc_int_installed==0) //not installed + { + } + else if(oc_int_installed==1) //disabled + { + } + else if(oc_int_installed==2) //stablizing + { + disable_irq_nosync(IFXUSB_OC_IRQ); + mod_timer(&oc_retry_timer,jiffies + HZ/OC_Timer_Sleep); + oc_int_installed=3; + } + else if(oc_int_installed==3) // sleeping + { + } + else if(oc_int_installed==4) // + { + oc_int_count++; + if(oc_int_count>=OC_Timer_Max) + { + IFX_DEBUGP("OC INTERRUPT port #%d\n",oc_int_id->core_if.core_no); + #ifdef __IS_DUAL__ + oc_int_id_1->flags.b.port_over_current_change = 1; + oc_int_id_2->flags.b.port_over_current_change = 1; + ifxusb_vbus_off(&oc_int_id_1->core_if); + IFX_DEBUGP("Turning off port #%d\n",oc_int_id_1->core_if.core_no); + ifxusb_vbus_off(&oc_int_id_2->core_if); + IFX_DEBUGP("Turning off port #%d\n",oc_int_id_2->core_if.core_no); + #else + oc_int_id->flags.b.port_over_current_change = 1; + ifxusb_vbus_off(&oc_int_id->core_if); + IFX_DEBUGP("Turning off port #%d\n",oc_int_id->core_if.core_no); + #endif + } + else + { + disable_irq_nosync(IFXUSB_OC_IRQ); + mod_timer(&oc_retry_timer,jiffies + HZ/OC_Timer_Sleep); + oc_int_installed=5; + } + } + else if(oc_int_installed==5) // Stable sleeping + { + } + + return IRQ_RETVAL(retval); + } + + void ifxusb_oc_int_on(void) + { + IFX_DEBUGPL( DBG_CIL, "registering (overcurrent) handler for irq%d\n", IFXUSB_OC_IRQ); + if(oc_int_id) + { + if(oc_int_installed==0) + { + oc_int_installed=2; + init_timer(&oc_retry_timer); + oc_retry_timer.function = oc_retry_timer_func; + /* Poll the event ring */ + + if(request_irq((unsigned int)IFXUSB_OC_IRQ, &ifxhcd_oc_irq, + IRQF_TRIGGER_NONE + // | IRQF_TRIGGER_RISING + // | IRQF_TRIGGER_FALLING + // | IRQF_TRIGGER_HIGH + // | IRQF_TRIGGER_LOW + // | IRQF_TRIGGER_PROBE + | IRQF_DISABLED + // | IRQF_SAMPLE_RANDOM + // | IRQF_SHARED + // | IRQF_PROBE_SHARED + // | IRQF_TIMER + // | IRQF_PERCPU + // | IRQF_NOBALANCING + // | IRQF_IRQPOLL + // | IRQF_ONESHOT + , + "ifxusb_oc", (void *)oc_int_id)) + oc_int_installed=0; + else + mod_timer(&oc_retry_timer,jiffies + HZ*OC_Timer_Stable); + } + else if(oc_int_installed!=2 && oc_int_installed!=4 ) + { + oc_int_installed=2; + enable_irq(IFXUSB_OC_IRQ); + mod_timer(&oc_retry_timer,jiffies + HZ*OC_Timer_Stable); + } + } + } + + void ifxusb_oc_int_off(void) + { + disable_irq_nosync(IFXUSB_OC_IRQ); + if(oc_int_installed) + oc_int_installed=1; + } + + void ifxusb_oc_int_free(void) + { + del_timer(&oc_retry_timer); + disable_irq_nosync(IFXUSB_OC_IRQ); + if(oc_int_installed) + free_irq(IFXUSB_OC_IRQ, (void *)oc_int_id); + oc_int_installed=0; + } + #endif +#endif + + +/*! + \fn void ifxusb_vbus_on(ifxusb_core_if_t *_core_if) + \brief Turn on the USB 5V VBus Power + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ +void ifxusb_vbus_on(ifxusb_core_if_t *_core_if) +{ + IFX_DEBUGP("SENDING VBus POWER UP\n"); + #if defined(__UEIP__) + #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) + if ( g_usb_vbus_trigger && ifxusb_vbus_status==0) + { + ifx_led_trigger_activate(g_usb_vbus_trigger); + IFX_DEBUGP("Enable USB power!!\n"); + ifxusb_vbus_status=1; + } + #endif + #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) + if(_core_if->core_no==0 && g_usb_vbus1_trigger && ifxusb_vbus1_status==0) + { + ifx_led_trigger_activate(g_usb_vbus1_trigger); + IFX_DEBUGP("Enable USB1 power!!\n"); + ifxusb_vbus1_status=1; + } + #endif + #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) + if(_core_if->core_no==1 && g_usb_vbus2_trigger && ifxusb_vbus2_status==0) + { + ifx_led_trigger_activate(g_usb_vbus2_trigger); + IFX_DEBUGP("Enable USB2 power!!\n"); + ifxusb_vbus2_status=1; + } + #endif + + #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) + if(ifxusb_vbus_gpio_inited) + { + #if defined(IFX_GPIO_USB_VBUS) + if(ifxusb_vbus_status==0) + { + ifx_gpio_output_set(IFX_GPIO_USB_VBUS,IFX_GPIO_MODULE_USB); + ifxusb_vbus_status=1; + } + #endif + #if defined(IFX_GPIO_USB_VBUS1) + if(_core_if->core_no==0 && ifxusb_vbus1_status==0) + { + ifx_gpio_output_set(IFX_GPIO_USB_VBUS1,IFX_GPIO_MODULE_USB); + ifxusb_vbus1_status=1; + } + #endif + #if defined(IFX_GPIO_USB_VBUS2) + if(_core_if->core_no==1 && ifxusb_vbus2_status==0) + { + ifx_gpio_output_set(IFX_GPIO_USB_VBUS2,IFX_GPIO_MODULE_USB); + ifxusb_vbus2_status=1; + } + #endif + } + #endif //defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) + #else + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + ifxusb_vbus_status=1; + //usb_set_vbus_on(); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + set_bit (4, (volatile unsigned long *)AMAZON_SE_GPIO_P0_OUT); + ifxusb_vbus_status=1; + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + if(_core_if->core_no==0) + { + if (bsp_port_reserve_pin(1, 13, PORT_MODULE_USB) != 0) + { + IFX_PRINT("Can't enable USB1 5.5V power!!\n"); + return; + } + bsp_port_clear_altsel0(1, 13, PORT_MODULE_USB); + bsp_port_clear_altsel1(1, 13, PORT_MODULE_USB); + bsp_port_set_dir_out(1, 13, PORT_MODULE_USB); + bsp_port_set_pudsel(1, 13, PORT_MODULE_USB); + bsp_port_set_puden(1, 13, PORT_MODULE_USB); + bsp_port_set_output(1, 13, PORT_MODULE_USB); + IFX_DEBUGP("Enable USB1 power!!\n"); + ifxusb_vbus1_status=1; + } + else + { + if (bsp_port_reserve_pin(3, 4, PORT_MODULE_USB) != 0) + { + IFX_PRINT("Can't enable USB2 5.5V power!!\n"); + return; + } + bsp_port_clear_altsel0(3, 4, PORT_MODULE_USB); + bsp_port_clear_altsel1(3, 4, PORT_MODULE_USB); + bsp_port_set_dir_out(3, 4, PORT_MODULE_USB); + bsp_port_set_pudsel(3, 4, PORT_MODULE_USB); + bsp_port_set_puden(3, 4, PORT_MODULE_USB); + bsp_port_set_output(3, 4, PORT_MODULE_USB); + IFX_DEBUGP("Enable USB2 power!!\n"); + ifxusb_vbus2_status=1; + } + #endif //defined(__IS_AR9__) + #if defined(__IS_VR9__) + if(_core_if->core_no==0) + { + ifxusb_vbus1_status=1; + } + else + { + ifxusb_vbus2_status=1; + } + #endif //defined(__IS_VR9__) + #endif //defined(__UEIP__) + + #if defined(__DO_OC_INT__) + #if defined(__IS_AR10__) && defined(__IS_DUAL__) + if(_core_if->core_no==0) + ifxusb_oc_int_on(1); + else + ifxusb_oc_int_on(2); + #else + ifxusb_oc_int_on(); + #endif + #endif + +} + + +/*! + \fn void ifxusb_vbus_off(ifxusb_core_if_t *_core_if) + \brief Turn off the USB 5V VBus Power + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ +void ifxusb_vbus_off(ifxusb_core_if_t *_core_if) +{ + IFX_DEBUGP("SENDING VBus POWER OFF\n"); + + #if defined(__UEIP__) + #if defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) + if ( g_usb_vbus_trigger && ifxusb_vbus_status==1) + { + ifx_led_trigger_deactivate(g_usb_vbus_trigger); + IFX_DEBUGP("Disable USB power!!\n"); + ifxusb_vbus_status=0; + } + #endif + #if defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) + if(_core_if->core_no==0 && g_usb_vbus1_trigger && ifxusb_vbus1_status==1) + { + ifx_led_trigger_deactivate(g_usb_vbus1_trigger); + IFX_DEBUGP("Disable USB1 power!!\n"); + ifxusb_vbus1_status=0; + } + #endif + #if defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) + if(_core_if->core_no==1 && g_usb_vbus2_trigger && ifxusb_vbus2_status==1) + { + ifx_led_trigger_deactivate(g_usb_vbus2_trigger); + IFX_DEBUGP("Disable USB2 power!!\n"); + ifxusb_vbus2_status=0; + } + #endif + + #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) + if(ifxusb_vbus_gpio_inited) + { + #if defined(IFX_GPIO_USB_VBUS) + if(ifxusb_vbus_status==1) + { + ifx_gpio_output_clear(IFX_GPIO_USB_VBUS,IFX_GPIO_MODULE_USB); + ifxusb_vbus_status=0; + } + #endif + #if defined(IFX_GPIO_USB_VBUS1) + if(_core_if->core_no==0 && ifxusb_vbus1_status==1) + { + ifx_gpio_output_clear(IFX_GPIO_USB_VBUS1,IFX_GPIO_MODULE_USB); + ifxusb_vbus1_status=0; + } + #endif + #if defined(IFX_GPIO_USB_VBUS2) + if(_core_if->core_no==1 && ifxusb_vbus2_status==1) + { + ifx_gpio_output_clear(IFX_GPIO_USB_VBUS2,IFX_GPIO_MODULE_USB); + ifxusb_vbus2_status=0; + } + #endif + } + #endif //defined(IFX_GPIO_USB_VBUS) || defined(IFX_GPIO_USB_VBUS1) || defined(IFX_GPIO_USB_VBUS2) + #else + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + ifxusb_vbus_status=0; + //usb_set_vbus_on(); + #endif //defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #if defined(__IS_AMAZON_SE__) + clear_bit (4, (volatile unsigned long *)AMAZON_SE_GPIO_P0_OUT); + ifxusb_vbus_status=0; + #endif //defined(__IS_AMAZON_SE__) + #if defined(__IS_AR9__) + if(_core_if->core_no==0) + { + if (bsp_port_reserve_pin(1, 13, PORT_MODULE_USB) != 0) { + IFX_PRINT("Can't Disable USB1 5.5V power!!\n"); + return; + } + bsp_port_clear_altsel0(1, 13, PORT_MODULE_USB); + bsp_port_clear_altsel1(1, 13, PORT_MODULE_USB); + bsp_port_set_dir_out(1, 13, PORT_MODULE_USB); + bsp_port_set_pudsel(1, 13, PORT_MODULE_USB); + bsp_port_set_puden(1, 13, PORT_MODULE_USB); + bsp_port_clear_output(1, 13, PORT_MODULE_USB); + IFX_DEBUGP("Disable USB1 power!!\n"); + ifxusb_vbus1_status=0; + } + else + { + if (bsp_port_reserve_pin(3, 4, PORT_MODULE_USB) != 0) { + IFX_PRINT("Can't Disable USB2 5.5V power!!\n"); + return; + } + bsp_port_clear_altsel0(3, 4, PORT_MODULE_USB); + bsp_port_clear_altsel1(3, 4, PORT_MODULE_USB); + bsp_port_set_dir_out(3, 4, PORT_MODULE_USB); + bsp_port_set_pudsel(3, 4, PORT_MODULE_USB); + bsp_port_set_puden(3, 4, PORT_MODULE_USB); + bsp_port_clear_output(3, 4, PORT_MODULE_USB); + IFX_DEBUGP("Disable USB2 power!!\n"); + + ifxusb_vbus2_status=0; + } + #endif //defined(__IS_AR9__) + #if defined(__IS_VR9__) + if(_core_if->core_no==0) + { + ifxusb_vbus1_status=0; + } + else + { + ifxusb_vbus2_status=0; + } + #endif //defined(__IS_VR9__) + #endif //defined(__UEIP__) + #if defined(__DO_OC_INT__) + #if defined(__IS_AR10__) && defined(__IS_DUAL__) + if(_core_if->core_no==0) + ifxusb_oc_int_off(1); + else + ifxusb_oc_int_off(2); + #else + ifxusb_oc_int_off(); + #endif + #endif +} + + +/*! + \fn int ifxusb_vbus(ifxusb_core_if_t *_core_if) + \brief Read Current VBus status + \param _core_if Pointer of core_if structure + \ingroup IFXUSB_CIF + */ +int ifxusb_vbus(ifxusb_core_if_t *_core_if) +{ +#if defined(__UEIP__) + #if defined(IFX_GPIO_USB_VBUS) || defined(IFX_LEDGPIO_USB_VBUS) || defined(IFX_LEDLED_USB_VBUS) + return (ifxusb_vbus_status); + #endif + + #if defined(IFX_GPIO_USB_VBUS1) || defined(IFX_LEDGPIO_USB_VBUS1) || defined(IFX_LEDLED_USB_VBUS1) + if(_core_if->core_no==0) + return (ifxusb_vbus1_status); + #endif + + #if defined(IFX_GPIO_USB_VBUS2) || defined(IFX_LEDGPIO_USB_VBUS2) || defined(IFX_LEDLED_USB_VBUS2) + if(_core_if->core_no==1) + return (ifxusb_vbus2_status); + #endif +#else //defined(__UEIP__) +#endif + return -1; +} + +#if defined(__UEIP__) +#else + #if defined(__IS_TWINPASS__) + #define ADSL_BASE 0x20000 + #define CRI_BASE 0x31F00 + #define CRI_CCR0 CRI_BASE + 0x00 + #define CRI_CCR1 CRI_BASE + 0x01*4 + #define CRI_CDC0 CRI_BASE + 0x02*4 + #define CRI_CDC1 CRI_BASE + 0x03*4 + #define CRI_RST CRI_BASE + 0x04*4 + #define CRI_MASK0 CRI_BASE + 0x05*4 + #define CRI_MASK1 CRI_BASE + 0x06*4 + #define CRI_MASK2 CRI_BASE + 0x07*4 + #define CRI_STATUS0 CRI_BASE + 0x08*4 + #define CRI_STATUS1 CRI_BASE + 0x09*4 + #define CRI_STATUS2 CRI_BASE + 0x0A*4 + #define CRI_AMASK0 CRI_BASE + 0x0B*4 + #define CRI_AMASK1 CRI_BASE + 0x0C*4 + #define CRI_UPDCTL CRI_BASE + 0x0D*4 + #define CRI_MADST CRI_BASE + 0x0E*4 + // 0x0f is missing + #define CRI_EVENT0 CRI_BASE + 0x10*4 + #define CRI_EVENT1 CRI_BASE + 0x11*4 + #define CRI_EVENT2 CRI_BASE + 0x12*4 + + #define IRI_I_ENABLE 0x32000 + #define STY_SMODE 0x3c004 + #define AFE_TCR_0 0x3c0dc + #define AFE_ADDR_ADDR 0x3c0e8 + #define AFE_RDATA_ADDR 0x3c0ec + #define AFE_WDATA_ADDR 0x3c0f0 + #define AFE_CONFIG 0x3c0f4 + #define AFE_SERIAL_CFG 0x3c0fc + + #define DFE_BASE_ADDR 0xBE116000 + //#define DFE_BASE_ADDR 0x9E116000 + + #define MEI_FR_ARCINT_C (DFE_BASE_ADDR + 0x0000001C) + #define MEI_DBG_WADDR_C (DFE_BASE_ADDR + 0x00000024) + #define MEI_DBG_RADDR_C (DFE_BASE_ADDR + 0x00000028) + #define MEI_DBG_DATA_C (DFE_BASE_ADDR + 0x0000002C) + #define MEI_DBG_DECO_C (DFE_BASE_ADDR + 0x00000030) + #define MEI_DBG_MASTER_C (DFE_BASE_ADDR + 0x0000003C) + + static void WriteARCmem(uint32_t addr, uint32_t data) + { + writel(1 ,(volatile uint32_t *)MEI_DBG_MASTER_C); + writel(1 ,(volatile uint32_t *)MEI_DBG_DECO_C ); + writel(addr ,(volatile uint32_t *)MEI_DBG_WADDR_C ); + writel(data ,(volatile uint32_t *)MEI_DBG_DATA_C ); + while( (ifxusb_rreg((volatile uint32_t *)MEI_FR_ARCINT_C) & 0x20) != 0x20 ){}; + writel(0 ,(volatile uint32_t *)MEI_DBG_MASTER_C); + IFX_DEBUGP("WriteARCmem %08x %08x\n",addr,data); + }; + + static uint32_t ReadARCmem(uint32_t addr) + { + u32 data; + writel(1 ,(volatile uint32_t *)MEI_DBG_MASTER_C); + writel(1 ,(volatile uint32_t *)MEI_DBG_DECO_C ); + writel(addr ,(volatile uint32_t *)MEI_DBG_RADDR_C ); + while( (ifxusb_rreg((volatile uint32_t *)MEI_FR_ARCINT_C) & 0x20) != 0x20 ){}; + data = ifxusb_rreg((volatile uint32_t *)MEI_DBG_DATA_C ); + writel(0 ,(volatile uint32_t *)MEI_DBG_MASTER_C); + IFX_DEBUGP("ReadARCmem %08x %08x\n",addr,data); + return data; + }; + + void ifxusb_enable_afe_oc(void) + { + /* Start the clock */ + WriteARCmem(CRI_UPDCTL ,0x00000008); + WriteARCmem(CRI_CCR0 ,0x00000014); + WriteARCmem(CRI_CCR1 ,0x00000500); + WriteARCmem(AFE_CONFIG ,0x000001c8); + WriteARCmem(AFE_SERIAL_CFG,0x00000016); // (DANUBE_PCI_CFG_BASE+(1< +#include "ifxusb_version.h" + + +#include +#include +#include +#include + +#include "ifxusb_plat.h" +#include "ifxusb_regs.h" +#include "ifxusb_cif.h" + +#ifdef __IS_DEVICE__ + #include "ifxpcd.h" + #ifdef __GADGET_COC__ + #include + #include + IFX_PMCU_REGISTER_t pmcuRegisterUSBGadget; + #endif +#endif + +#ifdef __IS_HOST__ + #include "ifxhcd.h" + #ifdef __HOST_COC__ + #include + #include + #ifdef __IS_DUAL__ + IFX_PMCU_REGISTER_t pmcuRegisterUSBHost_1; + IFX_PMCU_REGISTER_t pmcuRegisterUSBHost_2; + #else + IFX_PMCU_REGISTER_t pmcuRegisterUSBHost; + #endif + #endif +#endif + +#include +#include +#include + +#ifdef __IS_HOST__ + extern char ifxusb_hcd_driver_name[]; + + #ifdef __IS_DUAL__ + extern ifxhcd_hcd_t ifxusb_hcd_1; + extern ifxhcd_hcd_t ifxusb_hcd_2; + extern char ifxusb_hcd_name_1[]; + extern char ifxusb_hcd_name_2[]; + #else + extern ifxhcd_hcd_t ifxusb_hcd; + extern char ifxusb_hcd_name[]; + #endif + +#endif + +#ifdef __IS_DEVICE__ + extern char ifxusb_pcd_driver_name[]; + + extern ifxpcd_pcd_t ifxusb_pcd; + extern char ifxusb_pcd_name[]; +#endif + + +//Attributes for sysfs (for 2.6 only) + +#ifdef __IS_HOST__ +extern struct device_attribute dev_attr_version_h; +#else +extern struct device_attribute dev_attr_version_d; +#endif +#ifdef __IS_HOST__ +extern struct device_attribute dev_attr_dbglevel_h; +#else +extern struct device_attribute dev_attr_dbglevel_d; +#endif +#ifdef __IS_HOST__ + #ifdef __IS_DUAL__ + extern struct device_attribute dev_attr_suspend_host_1; + extern struct device_attribute dev_attr_suspend_host_2; + extern struct device_attribute dev_attr_probe_host_1; + extern struct device_attribute dev_attr_probe_host_2; + extern struct device_attribute dev_attr_probe_timer1_val_h; + extern struct device_attribute dev_attr_probe_timer2_val_h; + extern struct device_attribute dev_attr_autoprobe_timer1_val_h; + extern struct device_attribute dev_attr_autoprobe_timer2_val_h; + #else + extern struct device_attribute dev_attr_suspend_host; + extern struct device_attribute dev_attr_probe_host; + extern struct device_attribute dev_attr_probe_timer_val_h; + extern struct device_attribute dev_attr_autoprobe_timer_val_h; + #endif +#endif + +#ifdef __IS_DEVICE__ + extern struct device_attribute dev_attr_suspend_device; + extern struct device_attribute dev_attr_probe_device; + extern struct device_attribute dev_attr_probe_timer_val_d; + extern struct device_attribute dev_attr_autoprobe_timer_val_d; +#endif + +#ifdef __IS_HOST__ + #ifdef __IS_DUAL__ + extern struct device_attribute dev_attr_dump_params_h_1; + extern struct device_attribute dev_attr_dump_params_h_2; + extern struct device_attribute dev_attr_mode_h_1; + extern struct device_attribute dev_attr_mode_h_2; + #else + extern struct device_attribute dev_attr_dump_params_h; + extern struct device_attribute dev_attr_mode_h; + #endif +#else + extern struct device_attribute dev_attr_dump_params_d; + extern struct device_attribute dev_attr_mode_d; +#endif + +#ifdef __IS_HOST__ + #ifdef __IS_DUAL__ + extern struct device_attribute dev_attr_pkt_count_limit_bi_1; + extern struct device_attribute dev_attr_pkt_count_limit_bo_1; + extern struct device_attribute dev_attr_pkt_count_limit_bi_2; + extern struct device_attribute dev_attr_pkt_count_limit_bo_2; + extern struct device_attribute dev_attr_bandwidth_fs_1; + extern struct device_attribute dev_attr_bandwidth_ls_1; + extern struct device_attribute dev_attr_bandwidth_hs_2; + extern struct device_attribute dev_attr_bandwidth_fs_2; + extern struct device_attribute dev_attr_bandwidth_ls_2; + extern struct device_attribute dev_attr_buspower_1; + extern struct device_attribute dev_attr_buspower_2; + extern struct device_attribute dev_attr_bussuspend_1; + extern struct device_attribute dev_attr_bussuspend_2; + extern struct device_attribute dev_attr_busconnected_1; + extern struct device_attribute dev_attr_busconnected_2; + extern struct device_attribute dev_attr_connectspeed_1; + extern struct device_attribute dev_attr_connectspeed_1; + #else + extern struct device_attribute dev_attr_pkt_count_limit_bi; + extern struct device_attribute dev_attr_pkt_count_limit_bo; + extern struct device_attribute dev_attr_bandwidth_hs; + extern struct device_attribute dev_attr_bandwidth_fs; + extern struct device_attribute dev_attr_bandwidth_ls; + extern struct device_attribute dev_attr_buspower; + extern struct device_attribute dev_attr_bussuspend; + extern struct device_attribute dev_attr_busconnected; + extern struct device_attribute dev_attr_connectspeed; + #endif +#endif //__IS_HOST__ + +#ifdef __IS_DEVICE__ + extern struct device_attribute dev_attr_devspeed; + extern struct device_attribute dev_attr_enumspeed; +#endif //__IS_DEVICE__ + +#ifdef __ENABLE_DUMP__ + #ifdef __IS_HOST__ + #ifdef __IS_DUAL__ + extern struct device_attribute dev_attr_dump_reg_h_1; + extern struct device_attribute dev_attr_dump_reg_h_2; + extern struct device_attribute dev_attr_dump_spram_h_1; + extern struct device_attribute dev_attr_dump_spram_h_2; + extern struct device_attribute dev_attr_dump_host_state_1; + extern struct device_attribute dev_attr_dump_host_state_2; + #else + extern struct device_attribute dev_attr_dump_reg_h; + extern struct device_attribute dev_attr_dump_spram_h; + extern struct device_attribute dev_attr_dump_host_state; + #endif + #else + extern struct device_attribute dev_attr_dump_reg_d; + extern struct device_attribute dev_attr_dump_spram_d; + #endif +#endif //__ENABLE_DUMP__ + + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +static ssize_t procfs_version_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) +{ + return sprintf( buf, "%s\n",IFXUSB_VERSION ); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_version_show( struct device *_dev, struct device_attribute *attr,char *buf) +#else + static ssize_t sysfs_version_show( struct device *_dev, char *buf) +#endif +{ + return sprintf( buf, "%s\n",IFXUSB_VERSION ); +} + +#ifdef __IS_HOST__ +DEVICE_ATTR(version_h, S_IRUGO|S_IWUSR, sysfs_version_show, NULL); +#else +DEVICE_ATTR(version_d, S_IRUGO|S_IWUSR, sysfs_version_show, NULL); +#endif + + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +static ssize_t procfs_dbglevel_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) +{ + #ifdef __IS_HOST__ + return sprintf( buf, "%08X\n",h_dbg_lvl ); + #else + return sprintf( buf, "%08X\n",d_dbg_lvl ); + #endif +} + +static ssize_t procfs_dbglevel_store(struct file *file, const char *buffer, unsigned long count, void *data) +{ + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 16); + #ifdef __IS_HOST__ + h_dbg_lvl =value; + #else + d_dbg_lvl =value; + #endif + //turn on and off power + return count; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_dbglevel_show( struct device *_dev, struct device_attribute *attr,char *buf) +#else + static ssize_t sysfs_dbglevel_show( struct device *_dev, char *buf) +#endif +{ + #ifdef __IS_HOST__ + return sprintf( buf, "%08X\n",h_dbg_lvl ); + #else + return sprintf( buf, "%08X\n",d_dbg_lvl ); + #endif +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_dbglevel_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) +#else + static ssize_t sysfs_dbglevel_store( struct device *_dev, const char *buffer, size_t count ) +#endif +{ + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 16); + #ifdef __IS_HOST__ + h_dbg_lvl =value; + #else + d_dbg_lvl =value; + #endif + //turn on and off power + return count; +} + +#ifdef __IS_HOST__ +DEVICE_ATTR(dbglevel_h, S_IRUGO|S_IWUSR, sysfs_dbglevel_show, sysfs_dbglevel_store); +#else +DEVICE_ATTR(dbglevel_d, S_IRUGO|S_IWUSR, sysfs_dbglevel_show, sysfs_dbglevel_store); +#endif + + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +static void ifxusb_dump_params(ifxusb_core_if_t *_core_if); + +#ifdef __IS_DUAL__ + static void dump_params_1(void) + { + ifxusb_dump_params(&ifxusb_hcd_1.core_if); + } + static void dump_params_2(void) + { + ifxusb_dump_params(&ifxusb_hcd_2.core_if); + } + + static ssize_t procfs_dump_params_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + dump_params_1(); + return 0; + } + static ssize_t procfs_dump_params_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + dump_params_2(); + return 0; + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_dump_params_show_1( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_dump_params_show_1( struct device *_dev,char *buf) + #endif + { + dump_params_1(); + return 0; + } + DEVICE_ATTR(dump_params_h_1, S_IRUGO|S_IWUSR, sysfs_dump_params_show_1, NULL); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_dump_params_show_2( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_dump_params_show_2( struct device *_dev,char *buf) + #endif + { + dump_params_2(); + return 0; + } + + DEVICE_ATTR(dump_params_h_2, S_IRUGO|S_IWUSR, sysfs_dump_params_show_2, NULL); +#else + static void dump_params(void) + { + #ifdef __IS_HOST__ + ifxusb_dump_params(&ifxusb_hcd.core_if); + #else + ifxusb_dump_params(&ifxusb_pcd.core_if); + #endif + } + + static ssize_t procfs_dump_params_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + dump_params(); + return 0; + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_dump_params_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_dump_params_show( struct device *_dev,char *buf) + #endif + { + dump_params(); + return 0; + } + + #ifdef __IS_HOST__ + DEVICE_ATTR(dump_params_h, S_IRUGO|S_IWUSR, sysfs_dump_params_show, NULL); + #else + DEVICE_ATTR(dump_params_d, S_IRUGO|S_IWUSR, sysfs_dump_params_show, NULL); + #endif +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef __IS_DUAL__ + static ssize_t mode_show_1(char *buf) + { + if((ifxusb_rreg(&ifxusb_hcd_1.core_if.core_global_regs->gintsts ) & 0x1) == 1) + return sprintf( buf, "HOST\n" ); + else + return sprintf( buf, "DEVICE(INCORRECT!)\n" ); + } + + static ssize_t mode_show_2(char *buf) + { + if((ifxusb_rreg(&ifxusb_hcd_2.core_if.core_global_regs->gintsts ) & 0x1) == 1) + return sprintf( buf, "HOST\n" ); + else + return sprintf( buf, "DEVICE(INCORRECT!)\n" ); + } + + static ssize_t procfs_mode_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return mode_show_1(buf); + } + static ssize_t procfs_mode_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return mode_show_2(buf); + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_mode_show_1( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_mode_show_1( struct device *_dev,char *buf) + #endif + { + return mode_show_1(buf); + } + + DEVICE_ATTR(mode_h_1, S_IRUGO|S_IWUSR, sysfs_mode_show_1, 0); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_mode_show_2( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_mode_show_2( struct device *_dev,char *buf) + #endif + { + return mode_show_2(buf); + } + DEVICE_ATTR(mode_h_2, S_IRUGO|S_IWUSR, sysfs_mode_show_2, NULL); +#else + static ssize_t mode_show(char *buf) + { + #ifdef __IS_HOST__ + if((ifxusb_rreg(&ifxusb_hcd.core_if.core_global_regs->gintsts ) & 0x1) == 1) + return sprintf( buf, "HOST\n" ); + else + return sprintf( buf, "DEVICE(INCORRECT!)\n" ); + #else + if((ifxusb_rreg(&ifxusb_pcd.core_if.core_global_regs->gintsts ) & 0x1) != 1) + return sprintf( buf, "DEVICE\n" ); + else + return sprintf( buf, "HOST(INCORRECT!)\n" ); + #endif + } + static ssize_t procfs_mode_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return mode_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_mode_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_mode_show( struct device *_dev, char *buf) + #endif + { + return mode_show(buf); + } + #ifdef __IS_HOST__ + DEVICE_ATTR(mode_h, S_IRUGO|S_IWUSR, sysfs_mode_show, NULL); + #else + DEVICE_ATTR(mode_d, S_IRUGO|S_IWUSR, sysfs_mode_show, NULL); + #endif +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef __IS_HOST__ +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + #ifdef __IS_DUAL__ + static ssize_t bandwidth_hs_show_1(char *buf) + { + return sprintf( buf, "%d\n",ifxusb_hcd_1.pkt_remaining_reload_hs ); + } + static ssize_t bandwidth_fs_show_1(char *buf) + { + return sprintf( buf, "%d\n",ifxusb_hcd_1.pkt_remaining_reload_fs ); + } + static ssize_t bandwidth_ls_show_1(char *buf) + { + return sprintf( buf, "%d\n",ifxusb_hcd_1.pkt_remaining_reload_ls ); + } + static void bandwidth_hs_store_1(uint32_t value) + { + if(value>16 && value<120) + { + hprt0_data_t hprt0; + ifxusb_hcd_1.pkt_remaining_reload_hs = value; + hprt0.d32 = ifxusb_rreg(ifxusb_hcd_1.core_if.hprt0); + if(hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED) + ifxusb_hcd_1.pkt_remaining_reload=value; + } + } + static void bandwidth_fs_store_1(uint32_t value) + { + if (value>2 && value<30) + { + hprt0_data_t hprt0; + ifxusb_hcd_1.pkt_remaining_reload_fs = value; + hprt0.d32 = ifxusb_rreg(ifxusb_hcd_1.core_if.hprt0); + if(hprt0.b.prtspd != IFXUSB_HPRT0_PRTSPD_LOW_SPEED && hprt0.b.prtspd != IFXUSB_HPRT0_PRTSPD_HIGH_SPEED) + ifxusb_hcd_1.pkt_remaining_reload=value; + } + } + static void bandwidth_ls_store_1(uint32_t value) + { + if (value>2 && value<30) + { + hprt0_data_t hprt0; + ifxusb_hcd_1.pkt_remaining_reload_ls = value; + hprt0.d32 = ifxusb_rreg(ifxusb_hcd_1.core_if.hprt0); + if(hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_LOW_SPEED) + ifxusb_hcd_1.pkt_remaining_reload=value; + } + } + static ssize_t bandwidth_hs_show_2(char *buf) + { + return sprintf( buf, "%d\n",ifxusb_hcd_2.pkt_remaining_reload_hs ); + } + static ssize_t bandwidth_fs_show_2(char *buf) + { + return sprintf( buf, "%d\n",ifxusb_hcd_2.pkt_remaining_reload_fs ); + } + static ssize_t bandwidth_ls_show_2(char *buf) + { + return sprintf( buf, "%d\n",ifxusb_hcd_2.pkt_remaining_reload_ls ); + } + static void bandwidth_hs_store_2(uint32_t value) + { + if(value>16 && value<120) + { + hprt0_data_t hprt0; + ifxusb_hcd_2.pkt_remaining_reload_hs = value; + hprt0.d32 = ifxusb_rreg(ifxusb_hcd_2.core_if.hprt0); + if(hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED) + ifxusb_hcd_2.pkt_remaining_reload=value; + } + } + static void bandwidth_fs_store_2(uint32_t value) + { + if (value>2 && value<30) + { + hprt0_data_t hprt0; + ifxusb_hcd_2.pkt_remaining_reload_fs = value; + hprt0.d32 = ifxusb_rreg(ifxusb_hcd_2.core_if.hprt0); + if(hprt0.b.prtspd != IFXUSB_HPRT0_PRTSPD_LOW_SPEED && hprt0.b.prtspd != IFXUSB_HPRT0_PRTSPD_HIGH_SPEED) + ifxusb_hcd_2.pkt_remaining_reload=value; + } + } + static void bandwidth_ls_store_2(uint32_t value) + { + if (value>2 && value<30) + { + hprt0_data_t hprt0; + ifxusb_hcd_2.pkt_remaining_reload_ls = value; + hprt0.d32 = ifxusb_rreg(ifxusb_hcd_2.core_if.hprt0); + if(hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_LOW_SPEED) + ifxusb_hcd_2.pkt_remaining_reload=value; + } + } + static ssize_t procfs_bandwidth_hs_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return bandwidth_hs_show_1(buf); + } + static ssize_t procfs_bandwidth_fs_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return bandwidth_fs_show_1(buf); + } + static ssize_t procfs_bandwidth_ls_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return bandwidth_ls_show_1(buf); + } + static ssize_t procfs_bandwidth_hs_store_1(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_hs_store_1(value); + return count; + } + static ssize_t procfs_bandwidth_fs_store_1(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_fs_store_1(value); + return count; + } + static ssize_t procfs_bandwidth_ls_store_1(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_ls_store_1(value); + return count; + } + static ssize_t procfs_bandwidth_hs_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return bandwidth_hs_show_2(buf); + } + static ssize_t procfs_bandwidth_fs_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return bandwidth_fs_show_2(buf); + } + static ssize_t procfs_bandwidth_ls_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return bandwidth_ls_show_2(buf); + } + static ssize_t procfs_bandwidth_hs_store_2(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_hs_store_2(value); + return count; + } + static ssize_t procfs_bandwidth_fs_store_2(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_fs_store_2(value); + return count; + } + static ssize_t procfs_bandwidth_ls_store_2(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_ls_store_2(value); + return count; + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_hs_show_1( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_bandwidth_hs_show_1( struct device *_dev,char *buf) + #endif + { + return bandwidth_hs_show_1(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_hs_store_1( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_bandwidth_hs_store_1( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_hs_store_1(value); + return count; + } + DEVICE_ATTR(bandwidth_hs_1, S_IRUGO|S_IWUSR, sysfs_bandwidth_hs_show_1, sysfs_bandwidth_hs_store_1); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_fs_show_1( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_bandwidth_fs_show_1( struct device *_dev,char *buf) + #endif + { + return bandwidth_fs_show_1(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_fs_store_1( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_bandwidth_fs_store_1( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_fs_store_1(value); + return count; + } + DEVICE_ATTR(bandwidth_fs_1, S_IRUGO|S_IWUSR, sysfs_bandwidth_fs_show_1, sysfs_bandwidth_fs_store_1); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_ls_show_1( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_bandwidth_ls_show_1( struct device *_dev,char *buf) + #endif + { + return bandwidth_ls_show_1(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_ls_store_1( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_bandwidth_ls_store_1( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_ls_store_1(value); + return count; + } + DEVICE_ATTR(bandwidth_ls_1, S_IRUGO|S_IWUSR, sysfs_bandwidth_ls_show_1, sysfs_bandwidth_ls_store_1); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_hs_show_2( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_bandwidth_hs_show_2( struct device *_dev,char *buf) + #endif + { + return bandwidth_hs_show_2(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_hs_store_2( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_bandwidth_hs_store_2( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_hs_store_2(value); + return count; + } + DEVICE_ATTR(bandwidth_hs_2, S_IRUGO|S_IWUSR, sysfs_bandwidth_hs_show_2, sysfs_bandwidth_hs_store_2); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_fs_show_2( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_bandwidth_fs_show_2( struct device *_dev,char *buf) + #endif + { + return bandwidth_fs_show_2(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_fs_store_2( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_bandwidth_fs_store_2( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_fs_store_2(value); + return count; + } + DEVICE_ATTR(bandwidth_fs_2, S_IRUGO|S_IWUSR, sysfs_bandwidth_fs_show_2, sysfs_bandwidth_fs_store_2); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_ls_show_2( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_bandwidth_ls_show_2( struct device *_dev,char *buf) + #endif + { + return bandwidth_ls_show_2(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_ls_store_2( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_bandwidth_ls_store_2( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_ls_store_2(value); + return count; + } + DEVICE_ATTR(bandwidth_ls_2, S_IRUGO|S_IWUSR, sysfs_bandwidth_ls_show_2, sysfs_bandwidth_ls_store_2); + #else + static ssize_t bandwidth_hs_show(char *buf) + { + return sprintf( buf, "%d\n",ifxusb_hcd.pkt_remaining_reload_hs ); + } + static ssize_t bandwidth_fs_show(char *buf) + { + return sprintf( buf, "%d\n",ifxusb_hcd.pkt_remaining_reload_fs ); + } + static ssize_t bandwidth_ls_show(char *buf) + { + return sprintf( buf, "%d\n",ifxusb_hcd.pkt_remaining_reload_ls ); + } + static void bandwidth_hs_store(uint32_t value) + { + if (value>16 && value<120) + { + hprt0_data_t hprt0; + ifxusb_hcd.pkt_remaining_reload_hs = value; + hprt0.d32 = ifxusb_rreg(ifxusb_hcd.core_if.hprt0); + if(hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_HIGH_SPEED) + ifxusb_hcd.pkt_remaining_reload=value; + } + } + static void bandwidth_fs_store(uint32_t value) + { + if (value>2 && value<30) + { + hprt0_data_t hprt0; + ifxusb_hcd.pkt_remaining_reload_fs = value; + hprt0.d32 = ifxusb_rreg(ifxusb_hcd.core_if.hprt0); + if(hprt0.b.prtspd != IFXUSB_HPRT0_PRTSPD_LOW_SPEED && hprt0.b.prtspd != IFXUSB_HPRT0_PRTSPD_HIGH_SPEED) + ifxusb_hcd.pkt_remaining_reload=value; + } + } + static void bandwidth_ls_store(uint32_t value) + { + if (value>2 && value<30) + { + hprt0_data_t hprt0; + ifxusb_hcd.pkt_remaining_reload_hs = value; + hprt0.d32 = ifxusb_rreg(ifxusb_hcd.core_if.hprt0); + if(hprt0.b.prtspd == IFXUSB_HPRT0_PRTSPD_LOW_SPEED) + ifxusb_hcd.pkt_remaining_reload=value; + } + } + static ssize_t procfs_bandwidth_hs_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return bandwidth_hs_show(buf); + } + static ssize_t procfs_bandwidth_fs_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return bandwidth_fs_show(buf); + } + static ssize_t procfs_bandwidth_ls_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return bandwidth_ls_show(buf); + } + static ssize_t procfs_bandwidth_hs_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_hs_store(value); + return count; + } + static ssize_t procfs_bandwidth_fs_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_fs_store(value); + return count; + } + static ssize_t procfs_bandwidth_ls_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_ls_store(value); + return count; + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_hs_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_bandwidth_hs_show( struct device *_dev,char *buf) + #endif + { + return bandwidth_hs_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_hs_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_bandwidth_hs_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_hs_store(value); + return count; + } + DEVICE_ATTR(bandwidth_hs, S_IRUGO|S_IWUSR, sysfs_bandwidth_hs_show, sysfs_bandwidth_hs_store); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_fs_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_bandwidth_fs_show( struct device *_dev,char *buf) + #endif + { + return bandwidth_fs_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_fs_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_bandwidth_fs_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_fs_store(value); + return count; + } + DEVICE_ATTR(bandwidth_fs, S_IRUGO|S_IWUSR, sysfs_bandwidth_fs_show, sysfs_bandwidth_fs_store); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_ls_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_bandwidth_ls_show( struct device *_dev,char *buf) + #endif + { + return bandwidth_ls_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bandwidth_ls_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_bandwidth_ls_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + bandwidth_ls_store(value); + return count; + } + DEVICE_ATTR(bandwidth_ls, S_IRUGO|S_IWUSR, sysfs_bandwidth_ls_show, sysfs_bandwidth_ls_store); + #endif + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + #ifdef __IS_DUAL__ + static ssize_t pkt_count_limit_bi_show_1(char *buf) + { + return sprintf( buf, "%d\n",ifxusb_hcd_1.pkt_count_limit_bi ); + } + static ssize_t pkt_count_limit_bo_show_1(char *buf) + { + return sprintf( buf, "%d\n",ifxusb_hcd_1.pkt_count_limit_bo ); + } + static void pkt_count_limit_bi_store_1(uint32_t value) + { + if(value<=13) + ifxusb_hcd_1.pkt_count_limit_bi = value; + } + static void pkt_count_limit_bo_store_1(uint32_t value) + { + if (value<=13) + ifxusb_hcd_1.pkt_count_limit_bo = value; + } + static ssize_t pkt_count_limit_bi_show_2(char *buf) + { + return sprintf( buf, "%d\n",ifxusb_hcd_2.pkt_count_limit_bi ); + } + static ssize_t pkt_count_limit_bo_show_2(char *buf) + { + return sprintf( buf, "%d\n",ifxusb_hcd_2.pkt_count_limit_bo ); + } + static void pkt_count_limit_bi_store_2(uint32_t value) + { + if(value<=13) + ifxusb_hcd_2.pkt_count_limit_bi = value; + } + static void pkt_count_limit_bo_store_2(uint32_t value) + { + if(value<=13) + ifxusb_hcd_2.pkt_count_limit_bo = value; + } + static ssize_t procfs_pkt_count_limit_bi_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return pkt_count_limit_bi_show_1(buf); + } + static ssize_t procfs_pkt_count_limit_bo_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return pkt_count_limit_bo_show_1(buf); + } + static ssize_t procfs_pkt_count_limit_bi_store_1(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + pkt_count_limit_bi_store_1(value); + return count; + } + static ssize_t procfs_pkt_count_limit_bo_store_1(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + pkt_count_limit_bo_store_1(value); + return count; + } + static ssize_t procfs_pkt_count_limit_bi_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return pkt_count_limit_bi_show_2(buf); + } + static ssize_t procfs_pkt_count_limit_bo_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return pkt_count_limit_bo_show_2(buf); + } + static ssize_t procfs_pkt_count_limit_bi_store_2(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + pkt_count_limit_bi_store_2(value); + return count; + } + static ssize_t procfs_pkt_count_limit_bo_store_2(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + pkt_count_limit_bo_store_2(value); + return count; + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_pkt_count_limit_bi_show_1( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_pkt_count_limit_bi_show_1( struct device *_dev,char *buf) + #endif + { + return pkt_count_limit_bi_show_1(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_pkt_count_limit_bi_store_1( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_pkt_count_limit_bi_store_1( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + pkt_count_limit_bi_store_1(value); + return count; + } + DEVICE_ATTR(pkt_count_limit_bi_1, S_IRUGO|S_IWUSR, sysfs_pkt_count_limit_bi_show_1, sysfs_pkt_count_limit_bi_store_1); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_pkt_count_limit_bo_show_1( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_pkt_count_limit_bo_show_1( struct device *_dev,char *buf) + #endif + { + return pkt_count_limit_bo_show_1(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_pkt_count_limit_bo_store_1( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_pkt_count_limit_bo_store_1( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + pkt_count_limit_bo_store_1(value); + return count; + } + DEVICE_ATTR(pkt_count_limit_bo_1, S_IRUGO|S_IWUSR, sysfs_pkt_count_limit_bo_show_1, sysfs_pkt_count_limit_bo_store_1); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_pkt_count_limit_bi_show_2( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_pkt_count_limit_bi_show_2( struct device *_dev,char *buf) + #endif + { + return pkt_count_limit_bi_show_2(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_pkt_count_limit_bi_store_2( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_pkt_count_limit_bi_2( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + pkt_count_limit_bi_store_2(value); + return count; + } + DEVICE_ATTR(pkt_count_limit_bi_2, S_IRUGO|S_IWUSR, sysfs_pkt_count_limit_bi_show_2, sysfs_pkt_count_limit_bi_store_2); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_pkt_count_limit_bo_show_2( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_pkt_count_limit_bo_show_2( struct device *_dev,char *buf) + #endif + { + return pkt_count_limit_bo_show_2(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_pkt_count_limit_bo_store_2( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_pkt_count_limit_bo_store_2( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + pkt_count_limit_bo_store_2(value); + return count; + } + DEVICE_ATTR(pkt_count_limit_bo_2, S_IRUGO|S_IWUSR, sysfs_pkt_count_limit_bo_show_2, sysfs_pkt_count_limit_bo_store_2); + #else + static ssize_t pkt_count_limit_bi_show(char *buf) + { + return sprintf( buf, "%d\n",ifxusb_hcd.pkt_count_limit_bi ); + } + static ssize_t pkt_count_limit_bo_show(char *buf) + { + return sprintf( buf, "%d\n",ifxusb_hcd.pkt_count_limit_bo ); + } + static void pkt_count_limit_bi_store(uint32_t value) + { + if (value<=13) + ifxusb_hcd.pkt_count_limit_bi = value; + } + static void pkt_count_limit_bo_store(uint32_t value) + { + if (value<=13) + ifxusb_hcd.pkt_count_limit_bo = value; + } + static ssize_t procfs_pkt_count_limit_bi_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return pkt_count_limit_bi_show(buf); + } + static ssize_t procfs_pkt_count_limit_bo_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return pkt_count_limit_bo_show(buf); + } + static ssize_t procfs_pkt_count_limit_bi_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + pkt_count_limit_bi_store(value); + return count; + } + static ssize_t procfs_pkt_count_limit_bo_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + pkt_count_limit_bo_store(value); + return count; + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_pkt_count_limit_bi_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_pkt_count_limit_bi_show( struct device *_dev,char *buf) + #endif + { + return pkt_count_limit_bi_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_pkt_count_limit_bi_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_pkt_count_limit_bi_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + pkt_count_limit_bi_store(value); + return count; + } + DEVICE_ATTR(pkt_count_limit_bi, S_IRUGO|S_IWUSR, sysfs_pkt_count_limit_bi_show, sysfs_pkt_count_limit_bi_store); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_pkt_count_limit_bo_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_pkt_count_limit_bo_show( struct device *_dev,char *buf) + #endif + { + return pkt_count_limit_bo_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_pkt_count_limit_bo_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_pkt_count_limit_bo_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + pkt_count_limit_bo_store(value); + return count; + } + DEVICE_ATTR(pkt_count_limit_bo, S_IRUGO|S_IWUSR, sysfs_pkt_count_limit_bo_show, sysfs_pkt_count_limit_bo_store); + #endif + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + + #ifdef __IS_DUAL__ + static ssize_t buspower_show_1(char *buf) + { + if(ifxusb_vbus (&ifxusb_hcd_1.core_if)==1) return sprintf( buf, "1\n" ); + if(ifxusb_vbus (&ifxusb_hcd_1.core_if)==0) return sprintf( buf, "0\n" ); + return sprintf( buf, "UNKNOWN\n" ); + } + static void buspower_store_1(uint32_t value) + { + if (value==1) ifxusb_vbus_on (&ifxusb_hcd_1.core_if); + else if(value==0) ifxusb_vbus_off(&ifxusb_hcd_1.core_if); + } + static ssize_t buspower_show_2(char *buf) + { + if(ifxusb_vbus (&ifxusb_hcd_2.core_if)==1) return sprintf( buf, "1\n" ); + if(ifxusb_vbus (&ifxusb_hcd_2.core_if)==0) return sprintf( buf, "0\n" ); + return sprintf( buf, "UNKNOWN\n" ); + } + static void buspower_store_2(uint32_t value) + { + if (value==1) ifxusb_vbus_on (&ifxusb_hcd_2.core_if); + else if(value==0) ifxusb_vbus_off(&ifxusb_hcd_2.core_if); + } + static ssize_t procfs_buspower_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return buspower_show_1(buf); + } + static ssize_t procfs_buspower_store_1(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + buspower_store_1(value); + return count; + } + static ssize_t procfs_buspower_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return buspower_show_2(buf); + } + static ssize_t procfs_buspower_store_2(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + buspower_store_2(value); + return count; + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_buspower_show_1( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_buspower_show_1( struct device *_dev,char *buf) + #endif + { + return buspower_show_1(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_buspower_store_1( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_buspower_store_1( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + buspower_store_1(value); + return count; + } + DEVICE_ATTR(buspower_1, S_IRUGO|S_IWUSR, sysfs_buspower_show_1, sysfs_buspower_store_1); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_buspower_show_2( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_buspower_show_2( struct device *_dev,char *buf) + #endif + { + return buspower_show_2(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_buspower_store_2( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_buspower_store_2( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + buspower_store_2(value); + return count; + } + DEVICE_ATTR(buspower_2, S_IRUGO|S_IWUSR, sysfs_buspower_show_2, sysfs_buspower_store_2); + #else + static ssize_t buspower_show(char *buf) + { + if(ifxusb_vbus (&ifxusb_hcd.core_if)==1) return sprintf( buf, "1\n" ); + if(ifxusb_vbus (&ifxusb_hcd.core_if)==0) return sprintf( buf, "0\n" ); + return sprintf( buf, "UNKNOWN\n" ); + } + static void buspower_store(uint32_t value) + { + if (value==1) ifxusb_vbus_on (&ifxusb_hcd.core_if); + else if(value==0) ifxusb_vbus_off(&ifxusb_hcd.core_if); + } + static ssize_t procfs_buspower_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return buspower_show(buf); + } + static ssize_t procfs_buspower_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + buspower_store(value); + return count; + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_buspower_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_buspower_show( struct device *_dev, char *buf) + #endif + { + return buspower_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_buspower_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_buspower_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + buspower_store(value); + return count; + } + DEVICE_ATTR(buspower, S_IRUGO|S_IWUSR, sysfs_buspower_show, sysfs_buspower_store); + #endif + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + + + #ifdef __IS_DUAL__ + static ssize_t bussuspend_show_1(char *buf) + { + hprt0_data_t val; + val.d32 = ifxusb_rreg(ifxusb_hcd_1.core_if.hprt0); + return sprintf (buf, "Bus Suspend = 0x%x\n", val.b.prtsusp); + } + static ssize_t bussuspend_show_2(char *buf) + { + hprt0_data_t val; + val.d32 = ifxusb_rreg(ifxusb_hcd_2.core_if.hprt0); + return sprintf (buf, "Bus Suspend = 0x%x\n", val.b.prtsusp); + } + + static ssize_t procfs_bussuspend_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return bussuspend_show_1(buf); + } + static ssize_t procfs_bussuspend_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return bussuspend_show_2(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bussuspend_show_1( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_bussuspend_show_1( struct device *_dev,char *buf) + #endif + { + return bussuspend_show_1(buf); + } + DEVICE_ATTR(bussuspend_1, S_IRUGO|S_IWUSR, sysfs_bussuspend_show_1, 0); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bussuspend_show_2( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_bussuspend_show_2( struct device *_dev,char *buf) + #endif + { + return bussuspend_show_2(buf); + } + DEVICE_ATTR(bussuspend_2, S_IRUGO|S_IWUSR, sysfs_bussuspend_show_2, 0); + #else + static ssize_t bussuspend_show(char *buf) + { + hprt0_data_t val; + val.d32 = ifxusb_rreg(ifxusb_hcd.core_if.hprt0); + return sprintf (buf, "Bus Suspend = 0x%x\n", val.b.prtsusp); + } + static ssize_t procfs_bussuspend_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return bussuspend_show(buf); + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_bussuspend_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_bussuspend_show( struct device *_dev, char *buf) + #endif + { + return bussuspend_show(buf); + } + DEVICE_ATTR(bussuspend, S_IRUGO|S_IWUSR, sysfs_bussuspend_show, 0); + #endif + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + + #ifdef __IS_DUAL__ + static ssize_t busconnected_show_1(char *buf) + { + hprt0_data_t val; + val.d32 = ifxusb_rreg(ifxusb_hcd_1.core_if.hprt0); + return sprintf (buf, "Bus Connected = 0x%x\n", val.b.prtconnsts); + } + static ssize_t busconnected_show_2(char *buf) + { + hprt0_data_t val; + val.d32 = ifxusb_rreg(ifxusb_hcd_2.core_if.hprt0); + return sprintf (buf, "Bus Connected = 0x%x\n", val.b.prtconnsts); + } + + static ssize_t procfs_busconnected_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return busconnected_show_1(buf); + } + static ssize_t procfs_busconnected_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return busconnected_show_2(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_busconnected_show_1( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_busconnected_show_1( struct device *_dev,char *buf) + #endif + { + return busconnected_show_1(buf); + } + DEVICE_ATTR(busconnected_1, S_IRUGO|S_IWUSR, sysfs_busconnected_show_1, 0); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_busconnected_show_2( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_busconnected_show_2( struct device *_dev,char *buf) + #endif + { + return busconnected_show_2(buf); + } + DEVICE_ATTR(busconnected_2, S_IRUGO|S_IWUSR, sysfs_busconnected_show_2, 0); + #else + static ssize_t busconnected_show(char *buf) + { + hprt0_data_t val; + val.d32 = ifxusb_rreg(ifxusb_hcd.core_if.hprt0); + return sprintf (buf, "Bus Connected = 0x%x\n", val.b.prtconnsts); + } + static ssize_t procfs_busconnected_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return busconnected_show(buf); + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_busconnected_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_busconnected_show( struct device *_dev, char *buf) + #endif + { + return busconnected_show(buf); + } + DEVICE_ATTR(busconnected, S_IRUGO|S_IWUSR, sysfs_busconnected_show, 0); + #endif + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + + #ifdef __IS_DUAL__ + static ssize_t connectspeed_show_1(char *buf) + { + hprt0_data_t val; + val.d32 = ifxusb_rreg(ifxusb_hcd_1.core_if.hprt0); + if( val.b.prtspd ==0) return sprintf (buf, "Bus Speed = High (%d)\n", val.b.prtspd); + if( val.b.prtspd ==1) return sprintf (buf, "Bus Speed = Full (%d)\n", val.b.prtspd); + if( val.b.prtspd ==2) return sprintf (buf, "Bus Speed = Low (%d)\n", val.b.prtspd); + return sprintf (buf, "Bus Speed = Unknown (%d)\n", val.b.prtspd); + } + static ssize_t connectspeed_show_2(char *buf) + { + hprt0_data_t val; + val.d32 = ifxusb_rreg(ifxusb_hcd_2.core_if.hprt0); + if( val.b.prtspd ==0) return sprintf (buf, "Bus Speed = High (%d)\n", val.b.prtspd); + if( val.b.prtspd ==1) return sprintf (buf, "Bus Speed = Full (%d)\n", val.b.prtspd); + if( val.b.prtspd ==2) return sprintf (buf, "Bus Speed = Low (%d)\n", val.b.prtspd); + return sprintf (buf, "Bus Speed = Unknown (%d)\n", val.b.prtspd); + } + + static ssize_t procfs_connectspeed_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return connectspeed_show_1(buf); + } + static ssize_t procfs_connectspeed_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return connectspeed_show_2(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_connectspeed_show_1( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_connectspeed_show_1( struct device *_dev,char *buf) + #endif + { + return connectspeed_show_1(buf); + } + DEVICE_ATTR(connectspeed_1, S_IRUGO|S_IWUSR, sysfs_connectspeed_show_1, 0); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_connectspeed_show_2( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_connectspeed_show_2( struct device *_dev,char *buf) + #endif + { + return connectspeed_show_2(buf); + } + DEVICE_ATTR(connectspeed_2, S_IRUGO|S_IWUSR, sysfs_connectspeed_show_2, 0); + #else + static ssize_t connectspeed_show(char *buf) + { + hprt0_data_t val; + val.d32 = ifxusb_rreg(ifxusb_hcd.core_if.hprt0); + if( val.b.prtspd ==0) return sprintf (buf, "Bus Speed = High (%d)\n", val.b.prtspd); + if( val.b.prtspd ==1) return sprintf (buf, "Bus Speed = Full (%d)\n", val.b.prtspd); + if( val.b.prtspd ==2) return sprintf (buf, "Bus Speed = Low (%d)\n", val.b.prtspd); + return sprintf (buf, "Bus Speed = Unknown (%d)\n", val.b.prtspd); + } + + static ssize_t procfs_connectspeed_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return connectspeed_show(buf); + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_connectspeed_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_connectspeed_show( struct device *_dev, char *buf) + #endif + { + return connectspeed_show(buf); + } + DEVICE_ATTR(connectspeed, S_IRUGO|S_IWUSR, sysfs_connectspeed_show, 0); + #endif +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +#endif + + +#ifdef __IS_DEVICE__ +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + static ssize_t devspeed_show(char *buf) + { + dcfg_data_t val; + val.d32 = ifxusb_rreg(&ifxusb_pcd.core_if.dev_global_regs->dcfg); + if( val.b.devspd ==0) return sprintf (buf, "Dev Speed = High (%d)\n", val.b.devspd); + if( val.b.devspd ==1) return sprintf (buf, "Dev Speed = Full (%d)\n", val.b.devspd); + if( val.b.devspd ==3) return sprintf (buf, "Dev Speed = Full (%d)\n", val.b.devspd); + return sprintf (buf, "Dev Speed = Unknown (%d)\n", val.b.devspd); + } + + static ssize_t procfs_devspeed_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return devspeed_show(buf); + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_devspeed_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_devspeed_show( struct device *_dev, char *buf) + #endif + { + return devspeed_show(buf); + } + DEVICE_ATTR(devspeed, S_IRUGO|S_IWUSR, sysfs_devspeed_show, 0); + + static ssize_t enumspeed_show(char *buf) + { + dsts_data_t val; + val.d32 = ifxusb_rreg(&ifxusb_pcd.core_if.dev_global_regs->dsts); + if( val.b.enumspd ==0) return sprintf (buf, "Enum Speed = High (%d)\n", val.b.enumspd); + if( val.b.enumspd ==1) return sprintf (buf, "Enum Speed = Full (%d)\n", val.b.enumspd); + if( val.b.enumspd ==2) return sprintf (buf, "Enum Speed = Low (%d)\n", val.b.enumspd); + return sprintf (buf, "Enum Speed = invalid(%d)\n", val.b.enumspd); + } + + static ssize_t procfs_enumspeed_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return enumspeed_show(buf); + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_enumspeed_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_enumspeed_show( struct device *_dev, char *buf) + #endif + { + return enumspeed_show(buf); + } + DEVICE_ATTR(enumspeed, S_IRUGO|S_IWUSR, sysfs_enumspeed_show, 0); +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +#endif + + +////////////////////////////////////////////////////////////////////////////////// +#ifdef __ENABLE_DUMP__ + + #ifdef __IS_DUAL__ + static void dump_reg_1(void) + { + ifxusb_dump_registers_h(&ifxusb_hcd_1.core_if); + } + static void dump_reg_2(void) + { + ifxusb_dump_registers_h(&ifxusb_hcd_2.core_if); + } + + static ssize_t procfs_dump_reg_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + dump_reg_1(); + return 0; + } + static ssize_t procfs_dump_reg_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + dump_reg_2(); + return 0; + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_dump_reg_show_1( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_dump_reg_show_1( struct device *_dev,char *buf) + #endif + { + dump_reg_1(); + return 0; + } + DEVICE_ATTR(dump_reg_h_1, S_IRUGO|S_IWUSR, sysfs_dump_reg_show_1, 0); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_dump_reg_show_2( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_dump_reg_show_2( struct device *_dev,char *buf) + #endif + { + dump_reg_2(); + return 0; + } + DEVICE_ATTR(dump_reg_h_2, S_IRUGO|S_IWUSR, sysfs_dump_reg_show_2, 0); + #else + static void dump_reg(void) + { + #ifdef __IS_HOST__ + ifxusb_dump_registers_h(&ifxusb_hcd.core_if); + #endif + #ifdef __IS_DEVICE__ + ifxusb_dump_registers_d(&ifxusb_pcd.core_if); + #endif + } + static ssize_t procfs_dump_reg_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + dump_reg(); + return 0; + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_dump_reg_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_dump_reg_show( struct device *_dev,char *buf) + #endif + { + dump_reg(); + return 0; + } + #ifdef __IS_HOST__ + DEVICE_ATTR(dump_reg_h, S_IRUGO|S_IWUSR, sysfs_dump_reg_show, 0); + #else + DEVICE_ATTR(dump_reg_d, S_IRUGO|S_IWUSR, sysfs_dump_reg_show, 0); + #endif + #endif + + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + + #ifdef __IS_DUAL__ + static void dump_spram_1(void) + { + ifxusb_dump_spram_h(&ifxusb_hcd_1.core_if); + } + static void dump_spram_2(void) + { + ifxusb_dump_spram_h(&ifxusb_hcd_2.core_if); + } + + static ssize_t procfs_dump_spram_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + dump_spram_1(); + return 0; + } + static ssize_t procfs_dump_spram_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + dump_spram_2(); + return 0; + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_dump_spram_show_1( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_dump_spram_show_1( struct device *_dev,char *buf) + #endif + { + dump_spram_1(); + return 0; + } + DEVICE_ATTR(dump_spram_h_1, S_IRUGO|S_IWUSR, sysfs_dump_spram_show_1, 0); + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_dump_spram_show_2( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_dump_spram_show_2( struct device *_dev,char *buf) + #endif + { + dump_spram_2(); + return 0; + } + DEVICE_ATTR(dump_spram_h_2, S_IRUGO|S_IWUSR, sysfs_dump_spram_show_2, 0); + #else + static void dump_spram(void) + { + #ifdef __IS_HOST__ + ifxusb_dump_spram_h(&ifxusb_hcd.core_if); + #endif + #ifdef __IS_DEVICE__ + ifxusb_dump_spram_d(&ifxusb_pcd.core_if); + #endif + } + static ssize_t procfs_dump_spram_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + dump_spram(); + return 0; + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_dump_spram_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_dump_spram_show( struct device *_dev,char *buf) + #endif + { + dump_spram(); + return 0; + } + #ifdef __IS_HOST__ + DEVICE_ATTR(dump_spram_h, S_IRUGO|S_IWUSR, sysfs_dump_spram_show, 0); + #else + DEVICE_ATTR(dump_spram_d, S_IRUGO|S_IWUSR, sysfs_dump_spram_show, 0); + #endif + + #endif +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + + #ifdef __IS_HOST__ + #ifdef __IS_DUAL__ + static ssize_t procfs_dump_host_state_show_1(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + ifxhcd_dump_state(&ifxusb_hcd_1); + return 0; + } + static ssize_t procfs_dump_host_state_show_2(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + ifxhcd_dump_state(&ifxusb_hcd_2); + return 0; + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_dump_host_state_show_1( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_dump_host_state_show_1( struct device *_dev,char *buf) + #endif + { + ifxhcd_dump_state(&ifxusb_hcd_1); + return 0; + } + DEVICE_ATTR(dump_host_state_1, S_IRUGO|S_IWUSR, sysfs_dump_host_state_show_1, 0); + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_dump_host_state_show_2( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_dump_host_state_show_2( struct device *_dev,char *buf) + #endif + { + ifxhcd_dump_state(&ifxusb_hcd_2); + return 0; + } + DEVICE_ATTR(dump_host_state_2, S_IRUGO|S_IWUSR, sysfs_dump_host_state_show_2, 0); + #else + static ssize_t procfs_dump_host_state_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + ifxhcd_dump_state(&ifxusb_hcd); + return 0; + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_dump_host_state_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_dump_host_state_show( struct device *_dev,char *buf) + #endif + { + ifxhcd_dump_state(&ifxusb_hcd); + return 0; + } + DEVICE_ATTR(dump_host_state, S_IRUGO|S_IWUSR, sysfs_dump_host_state_show, 0); + #endif + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + + #endif //IS_HOST_ + +#endif //__ENABLE_DUMP__ +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +#ifdef __IS_HOST__ + static void host_probe(unsigned long _ptr) + { + ifxhcd_hcd_t *ifxhcd = (ifxhcd_hcd_t *)_ptr; + + if(ifxhcd->flags.b.port_connect_status) + { + del_timer(&ifxhcd->host_probe_timer); + del_timer(&ifxhcd->autoprobe_timer); + ifxhcd->power_status = 0; + } + else + { + del_timer(&ifxhcd->autoprobe_timer); + ifxhcd->autoprobe_timer.expires = jiffies + (HZ*ifxhcd->autoprobe_sec); + add_timer(&ifxhcd->autoprobe_timer); + ifxhcd->power_status = 2; + del_timer(&ifxhcd->host_probe_timer); + do_suspend_h(&ifxhcd->core_if); + } + } + + static void host_autoprobe(unsigned long _ptr) + { + ifxhcd_hcd_t *ifxhcd = (ifxhcd_hcd_t *)_ptr; + del_timer(&ifxhcd->host_probe_timer); + ifxhcd->host_probe_timer.function = host_probe; + ifxhcd->host_probe_timer.expires = jiffies + (HZ*ifxhcd->probe_sec); + ifxhcd->host_probe_timer.data = (unsigned long)ifxhcd; + add_timer(&ifxhcd->host_probe_timer); + do_resume_h(&ifxhcd->core_if); + } + + static void suspend_host_store(ifxhcd_hcd_t *ifxhcd , uint32_t value) + { + if(value==2) + { + del_timer(&ifxhcd->autoprobe_timer); + ifxhcd->autoprobe_timer.function = host_autoprobe; + ifxhcd->autoprobe_timer.expires = jiffies + (HZ*ifxhcd->autoprobe_sec); + ifxhcd->autoprobe_timer.data = (unsigned long)ifxhcd; + add_timer(&ifxhcd->autoprobe_timer); + ifxhcd->power_status = 2; + } + else if(value==1) + { + do_suspend_h(&ifxhcd->core_if); + ifxhcd->power_status = 1; + del_timer(&ifxhcd->host_probe_timer); + del_timer(&ifxhcd->autoprobe_timer); + } + else if(value==0) + { + do_resume_h(&ifxhcd->core_if); + ifxhcd->power_status = 0; + del_timer(&ifxhcd->host_probe_timer); + del_timer(&ifxhcd->autoprobe_timer); + } + } + #ifdef __IS_DUAL__ + static ssize_t procfs_suspend_host_2_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + suspend_host_store(&ifxusb_hcd_2,value); + return count; + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_suspend_host_2_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_suspend_host_2_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + suspend_host_store(&ifxusb_hcd_2,value); + return count; + } + + static ssize_t procfs_suspend_host_1_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + suspend_host_store(&ifxusb_hcd_1,value); + return count; + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_suspend_host_1_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_suspend_host_1_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + suspend_host_store(&ifxusb_hcd_1,value); + return count; + } + DEVICE_ATTR(suspend_host_2, S_IWUSR,NULL, sysfs_suspend_host_2_store); + DEVICE_ATTR(suspend_host_1, S_IWUSR,NULL, sysfs_suspend_host_1_store); +///////////////////////////////////////////////////////////////////////////////////////////////////// + #else + static ssize_t procfs_suspend_host_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + suspend_host_store(&ifxusb_hcd,value); + return count; + } + + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_suspend_host_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_suspend_host_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + suspend_host_store(&ifxusb_hcd,value); + return count; + } + DEVICE_ATTR(suspend_host, S_IWUSR,NULL, sysfs_suspend_host_store); + #endif +#endif + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +#ifdef __IS_HOST__ + static void probe_host_store(ifxhcd_hcd_t *ifxhcd, uint32_t value) + { + if(ifxhcd->power_status == 1) + { + del_timer(&ifxhcd->host_probe_timer); + ifxhcd->host_probe_timer.function = host_probe; + ifxhcd->host_probe_timer.expires = jiffies + (HZ*ifxhcd->probe_sec); + ifxhcd->host_probe_timer.data = (unsigned long) ifxhcd; + add_timer(&ifxhcd->host_probe_timer); + do_resume_h(&ifxhcd->core_if); + } + } + #ifdef __IS_DUAL__ + static ssize_t probe_host_2_show(char *buf) + { + if(ifxusb_hcd_2.power_status == 0) + return sprintf (buf,"Host 2 power status is ON\n"); + else if(ifxusb_hcd_2.power_status == 1) + return sprintf (buf,"Host 2 power status is Suspend\n"); + else + return sprintf (buf,"Host 2 power status is Auto-probing\n"); + } + static ssize_t probe_host_1_show(char *buf) + { + if(ifxusb_hcd_1.power_status == 0) + return sprintf (buf,"Host 1 power status is ON\n"); + else if(ifxusb_hcd_1.power_status == 1) + return sprintf (buf,"Host 1 power status is Suspend\n"); + else + return sprintf (buf,"Host 1 power status is Auto-probing\n"); + } + static ssize_t procfs_probe_host_2_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + probe_host_store(&ifxusb_hcd_2,value); + return count; + } + static ssize_t procfs_probe_host_2_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return probe_host_2_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_probe_host_2_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_probe_host_2_show( struct device *_dev, char *buf) + #endif + { + return probe_host_2_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_probe_host_2_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_probe_host_2_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + probe_host_store(&ifxusb_hcd_2,value); + return count; + } + + static ssize_t procfs_probe_host_1_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + probe_host_store(&ifxusb_hcd_1,value); + return count; + } + static ssize_t procfs_probe_host_1_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return probe_host_1_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_probe_host_1_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_probe_host_1_show( struct device *_dev, char *buf) + #endif + { + return probe_host_1_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_probe_host_1_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_probe_host_1_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + probe_host_store(&ifxusb_hcd_1,value); + return count; + } + DEVICE_ATTR(probe_host_2, S_IRUGO|S_IWUSR, sysfs_probe_host_2_show, sysfs_probe_host_2_store); + DEVICE_ATTR(probe_host_1, S_IRUGO|S_IWUSR, sysfs_probe_host_1_show, sysfs_probe_host_1_store); +///////////////////////////////////////////////////////////////////////////////////////////////////// + #else + static ssize_t probe_host_show(char *buf) + { + if(ifxusb_hcd.power_status == 0) + return sprintf (buf,"Host power status is ON\n"); + else if(ifxusb_hcd.power_status == 1) + return sprintf (buf,"Host power status is Suspend\n"); + else + return sprintf (buf,"Host power status is Auto-probing\n"); + } + static ssize_t procfs_probe_host_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + probe_host_store(&ifxusb_hcd,value); + return count; + } + static ssize_t procfs_probe_host_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return probe_host_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_probe_host_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_probe_host_show( struct device *_dev, char *buf) + #endif + { + return probe_host_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_probe_host_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_probe_host_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + probe_host_store(&ifxusb_hcd,value); + return count; + } + DEVICE_ATTR(probe_host, S_IRUGO|S_IWUSR, sysfs_probe_host_show, sysfs_probe_host_store); + #endif +#endif +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +#ifdef __IS_DEVICE__ + static void device_probe(unsigned long _ptr) + { + if(ifxusb_pcd.power_status == 2) + { + del_timer(&ifxusb_pcd.device_autoprobe_timer); + ifxusb_pcd.device_autoprobe_timer.expires = jiffies + (HZ*ifxusb_pcd.autoprobe_sec); + add_timer(&ifxusb_pcd.device_autoprobe_timer); + ifxusb_pcd.power_status = 2; + do_suspend_d(&ifxusb_pcd.core_if); + } + else if(ifxusb_pcd.power_status == 1) + { + do_suspend_d(&ifxusb_pcd.core_if); + ifxusb_pcd.power_status = 1; + } + } + static void device_autoprobe(unsigned long _ptr) + { + init_timer(&ifxusb_pcd.device_probe_timer); + ifxusb_pcd.device_probe_timer.function = device_probe; + ifxusb_pcd.device_probe_timer.expires = jiffies + (HZ*ifxusb_pcd.probe_sec); + add_timer(&ifxusb_pcd.device_probe_timer); + do_resume_d(&ifxusb_pcd.core_if); + } + static void suspend_device_store(uint32_t value) + { + if(value==2) + { + del_timer(&ifxusb_pcd.device_autoprobe_timer); + ifxusb_pcd.device_autoprobe_timer.function = device_autoprobe; + ifxusb_pcd.device_autoprobe_timer.expires = jiffies + (HZ*ifxusb_pcd.autoprobe_sec); + add_timer(&ifxusb_pcd.device_autoprobe_timer); + ifxusb_pcd.power_status = 2; + } + else if(value==1) + { + do_suspend_d(&ifxusb_pcd.core_if); + ifxusb_pcd.power_status = 1; + del_timer(&ifxusb_pcd.device_autoprobe_timer); + del_timer(&ifxusb_pcd.device_probe_timer); + } + else if(value==0) + { + do_resume_d(&ifxusb_pcd.core_if); + ifxusb_pcd.power_status = 0; + del_timer(&ifxusb_pcd.device_autoprobe_timer); + del_timer(&ifxusb_pcd.device_probe_timer); + } + } + static ssize_t procfs_suspend_device_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + suspend_device_store(value); + return count; + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_suspend_device_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_suspend_device_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + suspend_device_store(value); + return count; + } + DEVICE_ATTR(suspend_device, S_IWUSR,NULL,sysfs_suspend_device_store); +#endif +///////////////////////////////////////////////////////////////////////////////////////////////////// +#ifdef __IS_DEVICE__ + static ssize_t probe_device_show(char *buf) + { + if(ifxusb_pcd.power_status == 0) + return sprintf (buf,"Device power status is ON\n"); + else if(ifxusb_pcd.power_status == 1) + return sprintf (buf,"Device power status is Suspend\n"); + else + return printk(buf,"Device power status is Auto-probing\n"); + } + static void probe_device_store(uint32_t value) + { + + if(ifxusb_pcd.power_status == 1) + { + del_timer(&ifxusb_pcd.device_probe_timer); + ifxusb_pcd.device_probe_timer.function = device_probe; + ifxusb_pcd.device_probe_timer.expires = jiffies + (HZ*ifxusb_pcd.probe_sec); + add_timer(&ifxusb_pcd.device_probe_timer); + do_resume_d(&ifxusb_pcd.core_if); + } + } + static ssize_t procfs_probe_device_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + probe_device_store(value); + return count; + } + static ssize_t procfs_probe_device_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return probe_device_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_probe_device_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_probe_device_show( struct device *_dev, char *buf) + #endif + { + return probe_device_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_probe_device_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_probe_device_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + probe_device_store(value); + return count; + } + DEVICE_ATTR(probe_device, S_IRUGO|S_IWUSR, sysfs_probe_device_show, sysfs_probe_device_store); +#endif +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +#ifdef __IS_HOST__ + #ifdef __IS_DUAL__ + static ssize_t autoprobe_timer2_val_show(char *buf) + { + return sprintf (buf,"Host 2 auto-probe timer is %d second\n",ifxusb_hcd_2.autoprobe_sec); + } + static ssize_t procfs_autoprobe_timer2_val_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + if((value > 0)&&(value < 300)) + ifxusb_hcd_2.autoprobe_sec = value; + return count; + } + static ssize_t procfs_autoprobe_timer2_val_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return autoprobe_timer2_val_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_autoprobe_timer2_val_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_autoprobe_timer2_val_show( struct device *_dev, char *buf) + #endif + { + return autoprobe_timer2_val_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_autoprobe_timer2_val_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_autoprobe_timer2_val_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + if((value > 0)&&(value < 300)) + ifxusb_hcd_2.autoprobe_sec = value; + return count; + } + + static ssize_t autoprobe_timer1_val_show(char *buf) + { + return sprintf (buf,"Host 1 auto-probe timer is %d second\n",ifxusb_hcd_1.autoprobe_sec); + } + static ssize_t procfs_autoprobe_timer1_val_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + if((value > 0)&&(value < 300)) + ifxusb_hcd_1.autoprobe_sec = value; + return count; + } + static ssize_t procfs_autoprobe_timer1_val_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return autoprobe_timer1_val_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_autoprobe_timer1_val_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_autoprobe_timer1_val_show( struct device *_dev, char *buf) + #endif + { + return autoprobe_timer1_val_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_autoprobe_timer1_val_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_autoautoprobe_timer1_val_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + if((value > 0)&&(value < 300)) + ifxusb_hcd_1.autoprobe_sec = value; + return count; + } + + static ssize_t probe_timer2_val_show(char *buf) + { + return sprintf (buf,"Host 2 probe timer is %d second\n",ifxusb_hcd_2.probe_sec); + } + static ssize_t procfs_probe_timer2_val_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + if((value > 0)&&(value < 10)) + ifxusb_hcd_2.probe_sec = value; + return count; + } + static ssize_t procfs_probe_timer2_val_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return probe_timer2_val_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_probe_timer2_val_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_probe_timer2_val_show( struct device *_dev, char *buf) + #endif + { + return probe_timer2_val_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_probe_timer2_val_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_probe_timer2_val_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + if((value > 0)&&(value < 10)) + ifxusb_hcd_2.probe_sec = value; + return count; + } + + static ssize_t probe_timer1_val_show(char *buf) + { + return sprintf (buf,"Host 1 probe timer is %d second\n",ifxusb_hcd_1.probe_sec); + } + static ssize_t procfs_probe_timer1_val_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + if((value > 0)&&(value < 10)) + ifxusb_hcd_1.probe_sec = value; + return count; + } + static ssize_t procfs_probe_timer1_val_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return probe_timer1_val_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_probe_timer1_val_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_probe_timer1_val_show( struct device *_dev, char *buf) + #endif + { + return probe_timer1_val_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_probe_timer1_val_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_probe_timer1_val_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + if((value > 0)&&(value < 10)) + ifxusb_hcd_1.probe_sec = value; + return count; + } + DEVICE_ATTR(probe_timer1_val_h, S_IRUGO|S_IWUSR, sysfs_probe_timer1_val_show, sysfs_probe_timer1_val_store); + DEVICE_ATTR(probe_timer2_val_h, S_IRUGO|S_IWUSR, sysfs_probe_timer2_val_show, sysfs_probe_timer2_val_store); + DEVICE_ATTR(autoprobe_timer1_val_h, S_IRUGO|S_IWUSR, sysfs_autoprobe_timer1_val_show, sysfs_autoprobe_timer1_val_store); + DEVICE_ATTR(autoprobe_timer2_val_h, S_IRUGO|S_IWUSR, sysfs_autoprobe_timer2_val_show, sysfs_autoprobe_timer2_val_store); + #else + static ssize_t autoprobe_timer_val_show(char *buf) + { + return sprintf (buf,"Host auto-probe timer is %d second\n",ifxusb_hcd.autoprobe_sec); + } + static ssize_t procfs_autoprobe_timer_val_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + if((value > 0)&&(value < 300)) + ifxusb_hcd.autoprobe_sec = value; + return count; + } + static ssize_t procfs_autoprobe_timer_val_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return autoprobe_timer_val_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_autoprobe_timer_val_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_autoprobe_timer_val_show( struct device *_dev, char *buf) + #endif + { + return autoprobe_timer_val_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_autoprobe_timer_val_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_autoautoprobe_timer_val_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + if((value > 0)&&(value < 300)) + ifxusb_hcd.autoprobe_sec = value; + return count; + } + static ssize_t probe_timer_val_show(char *buf) + { + return sprintf (buf,"Host probe timer is %d second\n",ifxusb_hcd.probe_sec); + } + static ssize_t procfs_probe_timer_val_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + if((value > 0)&&(value < 10)) + ifxusb_hcd.probe_sec = value; + return count; + } + static ssize_t procfs_probe_timer_val_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return probe_timer_val_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_probe_timer_val_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_probe_timer_val_show( struct device *_dev, char *buf) + #endif + { + return probe_timer_val_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_probe_timer_val_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_probe_timer_val_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + if((value > 0)&&(value < 10)) + ifxusb_hcd.probe_sec = value; + return count; + } + DEVICE_ATTR(probe_timer_val_h, S_IRUGO|S_IWUSR, sysfs_probe_timer_val_show, sysfs_probe_timer_val_store); + DEVICE_ATTR(autoprobe_timer_val_h, S_IRUGO|S_IWUSR, sysfs_autoprobe_timer_val_show, sysfs_autoprobe_timer_val_store); + #endif +#endif +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// +#ifdef __IS_DEVICE__ + static ssize_t autoprobe_timer_val_show(char *buf) + { + return sprintf (buf,"Device auto-probe timer is %d second\n",ifxusb_pcd.autoprobe_sec); + } + static ssize_t procfs_autoprobe_timer_val_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + if((value > 0)&&(value < 300)) + ifxusb_pcd.autoprobe_sec = value; + return count; + } + static ssize_t procfs_autoprobe_timer_val_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return autoprobe_timer_val_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_autoprobe_timer_val_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_autoprobe_timer_val_show( struct device *_dev, char *buf) + #endif + { + return autoprobe_timer_val_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_autoprobe_timer_val_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_autoautoprobe_timer_val_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + if((value > 0)&&(value < 300)) + ifxusb_pcd.autoprobe_sec = value; + return count; + } + static ssize_t probe_timer_val_show(char *buf) + { + return sprintf (buf,"Device probe timer is %d second\n",ifxusb_pcd.probe_sec); + } + static ssize_t procfs_probe_timer_val_store(struct file *file, const char *buffer, unsigned long count, void *data) + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + if((value > 0)&&(value < 10)) + ifxusb_pcd.probe_sec = value; + return count; + } + static ssize_t procfs_probe_timer_val_show(char *buf, char **start, off_t offset, int count, int *eof, void *data) + { + return probe_timer_val_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_probe_timer_val_show( struct device *_dev, struct device_attribute *attr,char *buf) + #else + static ssize_t sysfs_probe_timer_val_show( struct device *_dev, char *buf) + #endif + { + return probe_timer_val_show(buf); + } + #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + static ssize_t sysfs_probe_timer_val_store( struct device *_dev, struct device_attribute *attr,const char *buffer, size_t count ) + #else + static ssize_t sysfs_probe_timer_val_store( struct device *_dev, const char *buffer, size_t count ) + #endif + { + char buf[10]; + int i = 0; + uint32_t value; + if (copy_from_user(buf, &buffer[i], sizeof("0xFFFFFFFF\n")+1)) + return -EFAULT; + value = simple_strtoul(buf, NULL, 10); + if((value > 0)&&(value < 10)) + ifxusb_pcd.probe_sec = value; + return count; + } + DEVICE_ATTR(probe_timer_val_d, S_IRUGO|S_IWUSR, sysfs_probe_timer_val_show, sysfs_probe_timer_val_store); + DEVICE_ATTR(autoprobe_timer_val_d, S_IRUGO|S_IWUSR, sysfs_autoprobe_timer_val_show, sysfs_autoprobe_timer_val_store); +#endif +////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////// + +static int ifx_proc_addproc(char *funcname, read_proc_t *hookfuncr, write_proc_t *hookfuncw); +static void ifx_proc_delproc(char *funcname); + +////////////////////////////////////////////////////////////////////////////////// + +#if defined(__IS_HOST__) && defined(__HOST_COC__) + #ifdef __IS_DUAL__ + static IFX_PMCU_MODULE_DEP_t depListUSBHost_1= + { + 1, + { + {IFX_PMCU_MODULE_CPU, IFX_PMCU_STATE_D0, IFX_PMCU_STATE_D0D3, IFX_PMCU_STATE_D0D3, IFX_PMCU_STATE_D0D3} + } + }; + static IFX_PMCU_MODULE_DEP_t depListUSBHost_2= + { + 1, + { + {IFX_PMCU_MODULE_CPU, IFX_PMCU_STATE_D0, IFX_PMCU_STATE_D0D3, IFX_PMCU_STATE_D0D3, IFX_PMCU_STATE_D0D3} + } + }; + // This functions returns the current power state of the module + static IFX_PMCU_RETURN_t + ifx_usbhost_stateGet_1(IFX_PMCU_STATE_t *pmcuModState) { + printk(KERN_DEBUG "ifx_usbhost_stateGet_1 is called\n"); + if(ifxusb_hcd_1.power_status == 0){ + printk(KERN_DEBUG "current power state of USB Host #1 is D0\n"); + *pmcuModState = IFX_PMCU_STATE_D0; // set here the right value + } + else if(ifxusb_hcd_1.power_status == 1){ + printk(KERN_DEBUG "current power state of USB Host #1 is D3 (Suspend)\n"); + *pmcuModState = IFX_PMCU_STATE_D3; // set here the right value + } + else if(ifxusb_hcd_1.power_status == 2){ + printk(KERN_DEBUG "current power state of USB Host #1 is D3 (Auto-Probing)\n"); + *pmcuModState = IFX_PMCU_STATE_D3; // set here the right value + } + else{ + printk(KERN_DEBUG "current power state of USB Host #1 is unknown (%d)\n",ifxusb_hcd_1.power_status); + *pmcuModState = IFX_PMCU_STATE_INVALID; // must be set to INVALID + } + return IFX_PMCU_RETURN_SUCCESS; + } + static IFX_PMCU_RETURN_t + ifx_usbhost_stateGet_2(IFX_PMCU_STATE_t *pmcuModState) { + printk(KERN_DEBUG "ifx_usbhost_stateGet_2 is called\n"); + if(ifxusb_hcd_2.power_status == 0){ + printk(KERN_DEBUG "current power state of USB Host #2 is D0\n"); + *pmcuModState = IFX_PMCU_STATE_D0; // set here the right value + } + else if(ifxusb_hcd_2.power_status == 1){ + printk(KERN_DEBUG "current power state of USB Host #2 is D3 (Suspend)\n"); + *pmcuModState = IFX_PMCU_STATE_D3; // set here the right value + } + else if(ifxusb_hcd_2.power_status == 2){ + printk(KERN_DEBUG "current power state of USB Host #2 is D3 (Auto-Probing)\n"); + *pmcuModState = IFX_PMCU_STATE_D3; // set here the right value + } + else{ + printk(KERN_DEBUG "current power state of USB Host #2 is unknown (%d)\n",ifxusb_hcd_2.power_status); + *pmcuModState = IFX_PMCU_STATE_INVALID; // must be set to INVALID + } + return IFX_PMCU_RETURN_SUCCESS; + } + + + // The function should be used to enable/disable the module specific power saving methods + static IFX_PMCU_RETURN_t + ifx_usbhost_pwrFeatureSwitch_1(IFX_PMCU_PWR_STATE_ENA_t pmcuPwrStateEna) + { + if (pmcuPwrStateEna == IFX_PMCU_PWR_STATE_ON) { + suspend_host_store(&ifxusb_hcd_1, 0); + return IFX_PMCU_RETURN_SUCCESS; + } + if (pmcuPwrStateEna == IFX_PMCU_PWR_STATE_OFF) { + suspend_host_store(&ifxusb_hcd_1, 1); + return IFX_PMCU_RETURN_SUCCESS; + } + return IFX_PMCU_RETURN_SUCCESS; + } + static IFX_PMCU_RETURN_t + ifx_usbhost_pwrFeatureSwitch_2(IFX_PMCU_PWR_STATE_ENA_t pmcuPwrStateEna) + { + if (pmcuPwrStateEna == IFX_PMCU_PWR_STATE_ON) { + suspend_host_store(&ifxusb_hcd_2, 0); + return IFX_PMCU_RETURN_SUCCESS; + } + if (pmcuPwrStateEna == IFX_PMCU_PWR_STATE_OFF) { + suspend_host_store(&ifxusb_hcd_2, 1); + return IFX_PMCU_RETURN_SUCCESS; + } + return IFX_PMCU_RETURN_SUCCESS; + } + + // This function should be used to do all the necessary clean-up's before a the real + // power state change is initiated; e.g. flush all serial buffers inside the UART before + // the frequency will be changed. + static IFX_PMCU_RETURN_t + ifx_usbhost_preChange_1(IFX_PMCU_MODULE_t pmcuModule, IFX_PMCU_STATE_t newState, IFX_PMCU_STATE_t oldState) + { + printk(KERN_DEBUG "ifx_usbhost_preChange_1 is called\n"); + return IFX_PMCU_RETURN_SUCCESS; + } + static IFX_PMCU_RETURN_t + ifx_usbhost_preChange_2(IFX_PMCU_MODULE_t pmcuModule, IFX_PMCU_STATE_t newState, IFX_PMCU_STATE_t oldState) + { + printk(KERN_DEBUG "ifx_usbhost_preChange_2 is called\n"); + return IFX_PMCU_RETURN_SUCCESS; + } + + + // This function initiate the real power state change. The module should do all the necessary + // adpations to the new state. + static IFX_PMCU_RETURN_t + ifx_usbhost_stateChange_1(IFX_PMCU_STATE_t newState) + { + printk(KERN_DEBUG "ifx_usbhost_stateChange_1 is called\n"); + if (newState == IFX_PMCU_STATE_D0) { + suspend_host_store(&ifxusb_hcd_1, 0); + return IFX_PMCU_RETURN_SUCCESS; + } + if (newState == IFX_PMCU_STATE_D1) { + suspend_host_store(&ifxusb_hcd_1, 1); + return IFX_PMCU_RETURN_SUCCESS; + } + if (newState == IFX_PMCU_STATE_D2) { + suspend_host_store(&ifxusb_hcd_1, 1); + return IFX_PMCU_RETURN_SUCCESS; + } + if (newState == IFX_PMCU_STATE_D3) { + suspend_host_store(&ifxusb_hcd_1, 1); + return IFX_PMCU_RETURN_SUCCESS; + } + return IFX_PMCU_RETURN_SUCCESS; + } + static IFX_PMCU_RETURN_t + ifx_usbhost_stateChange_2(IFX_PMCU_STATE_t newState) + { + printk(KERN_DEBUG "ifx_usbhost_stateChange_2 is called\n"); + if (newState == IFX_PMCU_STATE_D0) { + suspend_host_store(&ifxusb_hcd_2, 0); + return IFX_PMCU_RETURN_SUCCESS; + } + if (newState == IFX_PMCU_STATE_D1) { + suspend_host_store(&ifxusb_hcd_2, 1); + return IFX_PMCU_RETURN_SUCCESS; + } + if (newState == IFX_PMCU_STATE_D2) { + suspend_host_store(&ifxusb_hcd_2, 1); + return IFX_PMCU_RETURN_SUCCESS; + } + if (newState == IFX_PMCU_STATE_D3) { + suspend_host_store(&ifxusb_hcd_2, 1); + return IFX_PMCU_RETURN_SUCCESS; + } + return IFX_PMCU_RETURN_SUCCESS; + } + + // This function should be used to do all the necessary post processing after a the real + // power state change was initiated. + static IFX_PMCU_RETURN_t + ifx_usbhost_postChange_1(IFX_PMCU_MODULE_t pmcuModule, IFX_PMCU_STATE_t newState, IFX_PMCU_STATE_t oldState) + { + printk(KERN_DEBUG "ifx_usbhost_postChange_1 is called\n"); + return IFX_PMCU_RETURN_SUCCESS; + } + static IFX_PMCU_RETURN_t + ifx_usbhost_postChange_2(IFX_PMCU_MODULE_t pmcuModule, IFX_PMCU_STATE_t newState, IFX_PMCU_STATE_t oldState) + { + printk(KERN_DEBUG "ifx_usbhost_postChange_2 is called\n"); + return IFX_PMCU_RETURN_SUCCESS; + } + #else + static IFX_PMCU_MODULE_DEP_t depListUSBHost= + { + 1, + { + {IFX_PMCU_MODULE_CPU, IFX_PMCU_STATE_D0, IFX_PMCU_STATE_D0D3, IFX_PMCU_STATE_D0D3, IFX_PMCU_STATE_D0D3} + } + }; + // This functions returns the current power state of the module + static IFX_PMCU_RETURN_t + ifx_usbhost_stateGet(IFX_PMCU_STATE_t *pmcuModState) { + printk(KERN_DEBUG "ifx_usbhost_stateGet is called\n"); + if(ifxusb_hcd.power_status == 0){ + printk(KERN_DEBUG "current power state of USB Host is D0\n"); + *pmcuModState = IFX_PMCU_STATE_D0; // set here the right value + } + else if(ifxusb_hcd.power_status == 1){ + printk(KERN_DEBUG "current power state of USB Host is D3 (Suspend)\n"); + *pmcuModState = IFX_PMCU_STATE_D3; // set here the right value + } + else if(ifxusb_hcd.power_status == 2){ + printk(KERN_DEBUG "current power state of USB Host is D3 (Auto-Probing)\n"); + *pmcuModState = IFX_PMCU_STATE_D3; // set here the right value + } + else{ + printk(KERN_DEBUG "current power state of USB Host is unknown (%d)\n",ifxusb_hcd.power_status); + *pmcuModState = IFX_PMCU_STATE_INVALID; // must be set to INVALID + } + return IFX_PMCU_RETURN_SUCCESS; + } + // The function should be used to enable/disable the module specific power saving methods + static IFX_PMCU_RETURN_t + ifx_usbhost_pwrFeatureSwitch(IFX_PMCU_PWR_STATE_ENA_t pmcuPwrStateEna) + { + if (pmcuPwrStateEna == IFX_PMCU_PWR_STATE_ON) { + suspend_host_store(&ifxusb_hcd, 0); + return IFX_PMCU_RETURN_SUCCESS; + } + if (pmcuPwrStateEna == IFX_PMCU_PWR_STATE_OFF) { + suspend_host_store(&ifxusb_hcd, 1); + return IFX_PMCU_RETURN_SUCCESS; + } + return IFX_PMCU_RETURN_SUCCESS; + } + + // This function should be used to do all the necessary clean-up's before a the real + // power state change is initiated; e.g. flush all serial buffers inside the UART before + // the frequency will be changed. + static IFX_PMCU_RETURN_t + ifx_usbhost_preChange(IFX_PMCU_MODULE_t pmcuModule, IFX_PMCU_STATE_t newState, IFX_PMCU_STATE_t oldState) + { + printk(KERN_DEBUG "ifx_usbhost_preChange is called\n"); + return IFX_PMCU_RETURN_SUCCESS; + } + + + // This function initiate the real power state change. The module should do all the necessary + // adpations to the new state. + static IFX_PMCU_RETURN_t + ifx_usbhost_stateChange(IFX_PMCU_STATE_t newState) + { + printk(KERN_DEBUG "ifx_usbhost_stateChange is called\n"); + if (newState == IFX_PMCU_STATE_D0) { + suspend_host_store(&ifxusb_hcd, 0); + return IFX_PMCU_RETURN_SUCCESS; + } + if (newState == IFX_PMCU_STATE_D1) { + suspend_host_store(&ifxusb_hcd, 1); + return IFX_PMCU_RETURN_SUCCESS; + } + if (newState == IFX_PMCU_STATE_D2) { + suspend_host_store(&ifxusb_hcd, 1); + return IFX_PMCU_RETURN_SUCCESS; + } + if (newState == IFX_PMCU_STATE_D3) { + suspend_host_store(&ifxusb_hcd, 1); + return IFX_PMCU_RETURN_SUCCESS; + } + return IFX_PMCU_RETURN_SUCCESS; + } + + // This function should be used to do all the necessary post processing after a the real + // power state change was initiated. + static IFX_PMCU_RETURN_t + ifx_usbhost_postChange(IFX_PMCU_MODULE_t pmcuModule, IFX_PMCU_STATE_t newState, IFX_PMCU_STATE_t oldState) + { + printk(KERN_DEBUG "ifx_usbhost_postChange is called\n"); + return IFX_PMCU_RETURN_SUCCESS; + } + #endif +#endif +#if defined(__IS_DEVICE__) && defined(__GADGET_COC__) + static IFX_PMCU_MODULE_DEP_t depListUSBGadget= + { + 1, + { + {IFX_PMCU_MODULE_CPU, IFX_PMCU_STATE_D0, IFX_PMCU_STATE_D0D3, IFX_PMCU_STATE_D0D3, IFX_PMCU_STATE_D0D3} + } + }; + // This functions returns the current power state of the module + static IFX_PMCU_RETURN_t + ifx_usbgadget_stateGet(IFX_PMCU_STATE_t *pmcuModState) { + printk(KERN_DEBUG "ifx_usbgadget_stateGet is called\n"); + if(ifxusb_pcd.power_status == 0){ + printk(KERN_DEBUG "current power state of USB Gadget is D0\n"); + *pmcuModState = IFX_PMCU_STATE_D0; // set here the right value + } + else if(ifxusb_pcd.power_status == 1){ + printk(KERN_DEBUG "current power state of USB Gadget is D3 (Suspend)\n"); + *pmcuModState = IFX_PMCU_STATE_D3; // set here the right value + } + else if(ifxusb_pcd.power_status == 2){ + printk(KERN_DEBUG "current power state of USB Gadget is D3 (Auto-Probing)\n"); + *pmcuModState = IFX_PMCU_STATE_D3; // set here the right value + } + else{ + printk(KERN_DEBUG "current power state of USB Gadget is unknown (%d)\n",ifxusb_pcd.power_status); + *pmcuModState = IFX_PMCU_STATE_INVALID; // must be set to INVALID + } + return IFX_PMCU_RETURN_SUCCESS; + } + // The function should be used to enable/disable the module specific power saving methods + static IFX_PMCU_RETURN_t + ifx_usbgadget_pwrFeatureSwitch(IFX_PMCU_PWR_STATE_ENA_t pmcuPwrStateEna) + { + if (pmcuPwrStateEna == IFX_PMCU_PWR_STATE_ON) { + suspend_device_store(0); + return IFX_PMCU_RETURN_SUCCESS; + } + if (pmcuPwrStateEna == IFX_PMCU_PWR_STATE_OFF) { + suspend_device_store(1); + return IFX_PMCU_RETURN_SUCCESS; + } + return IFX_PMCU_RETURN_SUCCESS; + } + + // This function should be used to do all the necessary clean-up's before a the real + // power state change is initiated; e.g. flush all serial buffers inside the UART before + // the frequency will be changed. + static IFX_PMCU_RETURN_t + ifx_usbgadget_preChange(IFX_PMCU_MODULE_t pmcuModule, IFX_PMCU_STATE_t newState, IFX_PMCU_STATE_t oldState) + { + printk(KERN_DEBUG "ifx_usbgadget_preChange is called\n"); + return IFX_PMCU_RETURN_SUCCESS; + } + + + // This function initiate the real power state change. The module should do all the necessary + // adpations to the new state. + static IFX_PMCU_RETURN_t + ifx_usbgadget_stateChange(IFX_PMCU_STATE_t newState) + { + printk(KERN_DEBUG "ifx_usbgadget_stateChange is called\n"); + if (newState == IFX_PMCU_STATE_D0) { + suspend_device_store(0); + return IFX_PMCU_RETURN_SUCCESS; + } + if (newState == IFX_PMCU_STATE_D1) { + suspend_device_store(1); + return IFX_PMCU_RETURN_SUCCESS; + } + if (newState == IFX_PMCU_STATE_D2) { + suspend_device_store(1); + return IFX_PMCU_RETURN_SUCCESS; + } + if (newState == IFX_PMCU_STATE_D3) { + suspend_device_store(1); + return IFX_PMCU_RETURN_SUCCESS; + } + return IFX_PMCU_RETURN_SUCCESS; + } + + // This function should be used to do all the necessary post processing after a the real + // power state change was initiated. + static IFX_PMCU_RETURN_t + ifx_usbgadget_postChange(IFX_PMCU_MODULE_t pmcuModule, IFX_PMCU_STATE_t newState, IFX_PMCU_STATE_t oldState) + { + printk(KERN_DEBUG "ifx_usbgadget_postChange is called\n"); + return IFX_PMCU_RETURN_SUCCESS; + } +#endif + + +/*! + \brief This function create the sysfs and procfs entries + \param[in] _dev Pointer of device structure, if applied + */ +#ifdef __IS_HOST__ +void ifxusb_attr_create_h (void *_dev) +#else +void ifxusb_attr_create_d (void *_dev) +#endif +{ + int error; + + struct device *dev = (struct device *) _dev; + + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + + error = ifx_proc_addproc("dbglevel", procfs_dbglevel_show, procfs_dbglevel_store); + #ifdef __IS_HOST__ + error = device_create_file(dev, &dev_attr_dbglevel_h); + #else + error = device_create_file(dev, &dev_attr_dbglevel_d); + #endif + + #ifdef __IS_HOST__ + #ifdef __IS_DUAL__ + error = ifx_proc_addproc("dump_params_1", procfs_dump_params_show_1, NULL); + error = ifx_proc_addproc("dump_params_2", procfs_dump_params_show_2, NULL); + error = device_create_file(dev, &dev_attr_dump_params_h_1); + error = device_create_file(dev, &dev_attr_dump_params_h_2); + + error = ifx_proc_addproc("mode_1", procfs_mode_show_1, NULL); + error = ifx_proc_addproc("mode_2", procfs_mode_show_2, NULL); + error = device_create_file(dev, &dev_attr_mode_h_1); + error = device_create_file(dev, &dev_attr_mode_h_2); + #else + error = ifx_proc_addproc("dump_params", procfs_dump_params_show, NULL); + error = device_create_file(dev, &dev_attr_dump_params_h); + error = ifx_proc_addproc("mode", procfs_mode_show, NULL); + error = device_create_file(dev, &dev_attr_mode_h); + #endif + #else + error = ifx_proc_addproc("dump_params", procfs_dump_params_show, NULL); + error = device_create_file(dev, &dev_attr_dump_params_d); + + error = ifx_proc_addproc("mode", procfs_mode_show, NULL); + error = device_create_file(dev, &dev_attr_mode_d); + #endif + + #ifdef __IS_HOST__ + error = ifx_proc_addproc("version", procfs_version_show, NULL); + error = device_create_file(dev, &dev_attr_version_h); + #else + error = ifx_proc_addproc("version", procfs_version_show, NULL); + error = device_create_file(dev, &dev_attr_version_d); + #endif + + + #ifdef __IS_HOST__ + #ifdef __IS_DUAL__ + error = ifx_proc_addproc("pkt_count_limit_bi_1", procfs_pkt_count_limit_bi_show_1, procfs_pkt_count_limit_bi_store_1); + error = ifx_proc_addproc("pkt_count_limit_bo_1", procfs_pkt_count_limit_bo_show_1, procfs_pkt_count_limit_bo_store_1); + error = ifx_proc_addproc("pkt_count_limit_bi_2", procfs_pkt_count_limit_bi_show_2, procfs_pkt_count_limit_bi_store_2); + error = ifx_proc_addproc("pkt_count_limit_bo_2", procfs_pkt_count_limit_bo_show_2, procfs_pkt_count_limit_bo_store_2); + error = ifx_proc_addproc("bandwidth_hs_1", procfs_bandwidth_hs_show_1, procfs_bandwidth_hs_store_1); + error = ifx_proc_addproc("bandwidth_fs_1", procfs_bandwidth_fs_show_1, procfs_bandwidth_fs_store_1); + error = ifx_proc_addproc("bandwidth_ls_1", procfs_bandwidth_ls_show_1, procfs_bandwidth_ls_store_1); + error = ifx_proc_addproc("bandwidth_hs_2", procfs_bandwidth_hs_show_2, procfs_bandwidth_hs_store_2); + error = ifx_proc_addproc("bandwidth_fs_2", procfs_bandwidth_fs_show_2, procfs_bandwidth_fs_store_2); + error = ifx_proc_addproc("bandwidth_ls_2", procfs_bandwidth_ls_show_2, procfs_bandwidth_ls_store_2); + error = device_create_file(dev, &dev_attr_pkt_count_limit_bi_1); + error = device_create_file(dev, &dev_attr_pkt_count_limit_bo_1); + error = device_create_file(dev, &dev_attr_pkt_count_limit_bi_2); + error = device_create_file(dev, &dev_attr_pkt_count_limit_bo_2); + error = device_create_file(dev, &dev_attr_bandwidth_hs_1); + error = device_create_file(dev, &dev_attr_bandwidth_fs_1); + error = device_create_file(dev, &dev_attr_bandwidth_ls_1); + error = device_create_file(dev, &dev_attr_bandwidth_hs_2); + error = device_create_file(dev, &dev_attr_bandwidth_fs_2); + error = device_create_file(dev, &dev_attr_bandwidth_ls_2); + #else + error = ifx_proc_addproc("pkt_count_limit_bi", procfs_pkt_count_limit_bi_show, procfs_pkt_count_limit_bi_store); + error = ifx_proc_addproc("pkt_count_limit_bo", procfs_pkt_count_limit_bo_show, procfs_pkt_count_limit_bo_store); + error = ifx_proc_addproc("bandwidth_hs", procfs_bandwidth_hs_show, procfs_bandwidth_hs_store); + error = ifx_proc_addproc("bandwidth_fs", procfs_bandwidth_fs_show, procfs_bandwidth_fs_store); + error = ifx_proc_addproc("bandwidth_ls", procfs_bandwidth_ls_show, procfs_bandwidth_ls_store); + error = device_create_file(dev, &dev_attr_pkt_count_limit_bi); + error = device_create_file(dev, &dev_attr_pkt_count_limit_bo); + error = device_create_file(dev, &dev_attr_bandwidth_hs); + error = device_create_file(dev, &dev_attr_bandwidth_fs); + error = device_create_file(dev, &dev_attr_bandwidth_ls); + #endif + + #ifdef __IS_DUAL__ + error = ifx_proc_addproc("buspower_1", procfs_buspower_show_1, procfs_buspower_store_1); + error = ifx_proc_addproc("buspower_2", procfs_buspower_show_2, procfs_buspower_store_2); + error = device_create_file(dev, &dev_attr_buspower_1); + error = device_create_file(dev, &dev_attr_buspower_2); + #else + error = ifx_proc_addproc("buspower", procfs_buspower_show, procfs_buspower_store); + error = device_create_file(dev, &dev_attr_buspower); + #endif + + #ifdef __IS_DUAL__ + error = ifx_proc_addproc("bussuspend_1", procfs_bussuspend_show_1, NULL); + error = ifx_proc_addproc("bussuspend_2", procfs_bussuspend_show_2, NULL); + error = device_create_file(dev, &dev_attr_bussuspend_1); + error = device_create_file(dev, &dev_attr_bussuspend_2); + #else + error = ifx_proc_addproc("bussuspend", procfs_bussuspend_show, NULL); + error = device_create_file(dev, &dev_attr_bussuspend); + #endif + + #ifdef __IS_DUAL__ + error = ifx_proc_addproc("busconnected_1", procfs_busconnected_show_1, NULL); + error = ifx_proc_addproc("busconnected_2", procfs_busconnected_show_2, NULL); + error = device_create_file(dev, &dev_attr_busconnected_1); + error = device_create_file(dev, &dev_attr_busconnected_2); + #else + error = ifx_proc_addproc("busconnected", procfs_busconnected_show, NULL); + error = device_create_file(dev, &dev_attr_busconnected); + #endif + + #ifdef __IS_DUAL__ + error = ifx_proc_addproc("connectspeed_1", procfs_connectspeed_show_1, NULL); + error = ifx_proc_addproc("connectspeed_2", procfs_connectspeed_show_2, NULL); + error = device_create_file(dev, &dev_attr_connectspeed_1); + error = device_create_file(dev, &dev_attr_connectspeed_2); + #else + error = ifx_proc_addproc("connectspeed", procfs_connectspeed_show, NULL); + error = device_create_file(dev, &dev_attr_connectspeed); + #endif + #endif + + #ifdef __IS_DEVICE__ + error = ifx_proc_addproc("devspeed", procfs_devspeed_show, NULL); + error = device_create_file(dev, &dev_attr_devspeed); + error = ifx_proc_addproc("enumspeed", procfs_enumspeed_show, NULL); + error = device_create_file(dev, &dev_attr_enumspeed); + #endif + + ////////////////////////////////////////////////////// + #ifdef __ENABLE_DUMP__ + + #ifdef __IS_HOST__ + #ifdef __IS_DUAL__ + error = ifx_proc_addproc("dump_reg_1", procfs_dump_reg_show_1, NULL); + error = ifx_proc_addproc("dump_reg_2", procfs_dump_reg_show_2, NULL); + error = device_create_file(dev, &dev_attr_dump_reg_h_1); + error = device_create_file(dev, &dev_attr_dump_reg_h_2); + #else + error = ifx_proc_addproc("dump_reg", procfs_dump_reg_show, NULL); + error = device_create_file(dev, &dev_attr_dump_reg_h); + #endif + + #ifdef __IS_DUAL__ + error = ifx_proc_addproc("dump_spram_1", procfs_dump_spram_show_1, NULL); + error = ifx_proc_addproc("dump_spram_2", procfs_dump_spram_show_2, NULL); + error = device_create_file(dev, &dev_attr_dump_spram_h_1); + error = device_create_file(dev, &dev_attr_dump_spram_h_2); + #else + error = ifx_proc_addproc("dump_spram", procfs_dump_spram_show, NULL); + error = device_create_file(dev, &dev_attr_dump_spram_h); + #endif + + #ifdef __IS_DUAL__ + error = ifx_proc_addproc("dump_host_state_1", procfs_dump_host_state_show_1, NULL); + error = ifx_proc_addproc("dump_host_state_2", procfs_dump_host_state_show_2, NULL); + error = device_create_file(dev, &dev_attr_dump_host_state_1); + error = device_create_file(dev, &dev_attr_dump_host_state_2); + #else + error = ifx_proc_addproc("dump_host_state", procfs_dump_host_state_show, NULL); + error = device_create_file(dev, &dev_attr_dump_host_state); + #endif + #else + error = ifx_proc_addproc("dump_reg", procfs_dump_reg_show, NULL); + error = device_create_file(dev, &dev_attr_dump_reg_d); + error = ifx_proc_addproc("dump_spram", procfs_dump_spram_show, NULL); + error = device_create_file(dev, &dev_attr_dump_spram_d); + #endif + #endif //__ENABLE_DUMP__ + ////////////////////////////////////////////////////// +#ifdef __IS_HOST__ + #ifdef __IS_DUAL__ + error = ifx_proc_addproc("suspend_host_1",NULL, procfs_suspend_host_1_store); + error = device_create_file(dev, &dev_attr_suspend_host_1); + + error = ifx_proc_addproc("probe_host_1", procfs_probe_host_1_show, procfs_probe_host_1_store); + error = device_create_file(dev, &dev_attr_probe_host_1); + + error = ifx_proc_addproc("suspend_host_2",NULL, procfs_suspend_host_2_store); + error = device_create_file(dev, &dev_attr_suspend_host_2); + + error = ifx_proc_addproc("probe_host_2", procfs_probe_host_2_show, procfs_probe_host_2_store); + error = device_create_file(dev, &dev_attr_probe_host_2); + + error = ifx_proc_addproc("probe_timer1", procfs_probe_timer1_val_show, procfs_probe_timer1_val_store); + error = device_create_file(dev, &dev_attr_probe_timer1_val_h); + + error = ifx_proc_addproc("probe_timer2", procfs_probe_timer2_val_show, procfs_probe_timer2_val_store); + error = device_create_file(dev, &dev_attr_probe_timer2_val_h); + + error = ifx_proc_addproc("autoprobe_timer1", procfs_autoprobe_timer1_val_show, procfs_autoprobe_timer1_val_store); + error = device_create_file(dev, &dev_attr_autoprobe_timer1_val_h); + + error = ifx_proc_addproc("autoprobe_timer2", procfs_autoprobe_timer2_val_show, procfs_autoprobe_timer2_val_store); + error = device_create_file(dev, &dev_attr_autoprobe_timer2_val_h); + #else + error = ifx_proc_addproc("suspend_host",NULL, procfs_suspend_host_store); + error = device_create_file(dev, &dev_attr_suspend_host); + + error = ifx_proc_addproc("probe_host", procfs_probe_host_show, procfs_probe_host_store); + error = device_create_file(dev, &dev_attr_probe_host); + + error = ifx_proc_addproc("probe_timer", procfs_probe_timer_val_show, procfs_probe_timer_val_store); + error = device_create_file(dev, &dev_attr_probe_timer_val_h); + + error = ifx_proc_addproc("autoprobe_timer", procfs_autoprobe_timer_val_show, procfs_autoprobe_timer_val_store); + error = device_create_file(dev, &dev_attr_autoprobe_timer_val_h); + #endif +#endif + +#ifdef __IS_DEVICE__ + error = ifx_proc_addproc("suspend_device",NULL, procfs_suspend_device_store); + error = device_create_file(dev, &dev_attr_suspend_device); + + error = ifx_proc_addproc("probe_device", procfs_probe_device_show, procfs_probe_device_store); + error = device_create_file(dev, &dev_attr_probe_device); + + error = ifx_proc_addproc("probe_timer", procfs_probe_timer_val_show, procfs_probe_timer_val_store); + error = device_create_file(dev, &dev_attr_probe_timer_val_d); + + error = ifx_proc_addproc("autoprobe_timer", procfs_autoprobe_timer_val_show, procfs_autoprobe_timer_val_store); + error = device_create_file(dev, &dev_attr_autoprobe_timer_val_d); +#endif +#if defined(__IS_HOST__) && defined(__HOST_COC__) + #ifdef __IS_DUAL__ + memset (&pmcuRegisterUSBHost_1, 0, sizeof(pmcuRegisterUSBHost_1)); + memset (&pmcuRegisterUSBHost_2, 0, sizeof(pmcuRegisterUSBHost_2)); + pmcuRegisterUSBHost_1.pmcuModule= + pmcuRegisterUSBHost_2.pmcuModule=IFX_PMCU_MODULE_USB; + pmcuRegisterUSBHost_1.pmcuModuleNr=1; + pmcuRegisterUSBHost_2.pmcuModuleNr=2; + pmcuRegisterUSBHost_1.pmcuModuleDep = &depListUSBHost_1; + pmcuRegisterUSBHost_2.pmcuModuleDep = &depListUSBHost_2; + pmcuRegisterUSBHost_1.pre = ifx_usbhost_preChange_1; + pmcuRegisterUSBHost_2.pre = ifx_usbhost_preChange_2; + pmcuRegisterUSBHost_1.post = ifx_usbhost_postChange_1; + pmcuRegisterUSBHost_2.post = ifx_usbhost_postChange_2; + pmcuRegisterUSBHost_1.ifx_pmcu_state_change = ifx_usbhost_stateChange_1; + pmcuRegisterUSBHost_2.ifx_pmcu_state_change = ifx_usbhost_stateChange_2; + pmcuRegisterUSBHost_1.ifx_pmcu_state_get = ifx_usbhost_stateGet_1; + pmcuRegisterUSBHost_2.ifx_pmcu_state_get = ifx_usbhost_stateGet_2; + pmcuRegisterUSBHost_1.ifx_pmcu_pwr_feature_switch = ifx_usbhost_pwrFeatureSwitch_1; + pmcuRegisterUSBHost_2.ifx_pmcu_pwr_feature_switch = ifx_usbhost_pwrFeatureSwitch_2; + ifx_pmcu_register ( &pmcuRegisterUSBHost_1 ); + ifx_pmcu_register ( &pmcuRegisterUSBHost_2 ); + #else + memset (&pmcuRegisterUSBHost, 0, sizeof(pmcuRegisterUSBHost)); + pmcuRegisterUSBHost.pmcuModule=IFX_PMCU_MODULE_USB; + pmcuRegisterUSBHost.pmcuModuleNr=1; + pmcuRegisterUSBHost.pmcuModuleDep = &depListUSBHost; + pmcuRegisterUSBHost.pre = ifx_usbhost_preChange; + pmcuRegisterUSBHost.post = ifx_usbhost_postChange; + pmcuRegisterUSBHost.ifx_pmcu_state_change = ifx_usbhost_stateChange; + pmcuRegisterUSBHost.ifx_pmcu_state_get = ifx_usbhost_stateGet; + pmcuRegisterUSBHost.ifx_pmcu_pwr_feature_switch = ifx_usbhost_pwrFeatureSwitch; + ifx_pmcu_register ( &pmcuRegisterUSBHost ); + #endif +#endif +#if defined(__IS_DEVICE__) && defined(__GADGET_COC__) + memset (&pmcuRegisterUSBGadget, 0, sizeof(pmcuRegisterUSBGadget)); + pmcuRegisterUSBGadget.pmcuModule=IFX_PMCU_MODULE_USB; + pmcuRegisterUSBGadget.pmcuModuleNr=0; + pmcuRegisterUSBGadget.pmcuModuleDep = &depListUSBGadget; + pmcuRegisterUSBGadget.pre = ifx_usbgadget_preChange; + pmcuRegisterUSBGadget.post = ifx_usbgadget_postChange; + pmcuRegisterUSBGadget.ifx_pmcu_state_change = ifx_usbgadget_stateChange; + pmcuRegisterUSBGadget.ifx_pmcu_state_get = ifx_usbgadget_stateGet; + pmcuRegisterUSBGadget.ifx_pmcu_pwr_feature_switch = ifx_usbgadget_pwrFeatureSwitch; + ifx_pmcu_register ( &pmcuRegisterUSBGadget ); +#endif +} + + +/*! + \brief This function remove the sysfs and procfs entries + \param[in] _dev Pointer of device structure, if applied + */ +#ifdef __IS_HOST__ +void ifxusb_attr_remove_h (void *_dev) +#else +void ifxusb_attr_remove_d (void *_dev) +#endif +{ + struct device *dev = (struct device *) _dev; + + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + ifx_proc_delproc("dbglevel"); + #ifdef __IS_HOST__ + device_remove_file(dev, &dev_attr_dbglevel_h); + #else + device_remove_file(dev, &dev_attr_dbglevel_d); + #endif + + #ifdef __IS_HOST__ + #ifdef __IS_DUAL__ + ifx_proc_delproc("dump_params_1"); + ifx_proc_delproc("dump_params_2"); + device_remove_file(dev, &dev_attr_dump_params_h_1); + device_remove_file(dev, &dev_attr_dump_params_h_2); + #else + ifx_proc_delproc("dump_params"); + device_remove_file(dev, &dev_attr_dump_params_h); + #endif + + #ifdef __IS_DUAL__ + ifx_proc_delproc("mode_1"); + ifx_proc_delproc("mode_2"); + device_remove_file(dev, &dev_attr_mode_h_1); + device_remove_file(dev, &dev_attr_mode_h_2); + #else + ifx_proc_delproc("mode"); + device_remove_file(dev, &dev_attr_mode_h); + #endif + #else + ifx_proc_delproc("dump_params"); + device_remove_file(dev, &dev_attr_dump_params_d); + ifx_proc_delproc("mode"); + device_remove_file(dev, &dev_attr_mode_d); + #endif + + #ifdef __IS_HOST__ + ifx_proc_delproc("version"); + device_remove_file(dev, &dev_attr_version_h); + #else + ifx_proc_delproc("version"); + device_remove_file(dev, &dev_attr_version_d); + #endif + + + #ifdef __IS_HOST__ + #ifdef __IS_DUAL__ + ifx_proc_delproc("pkt_count_limit_bi_1"); + ifx_proc_delproc("pkt_count_limit_bo_1"); + ifx_proc_delproc("pkt_count_limit_bi_2"); + ifx_proc_delproc("pkt_count_limit_bo_2"); + ifx_proc_delproc("bandwidth_hs_1"); + ifx_proc_delproc("bandwidth_fs_1"); + ifx_proc_delproc("bandwidth_ls_1"); + ifx_proc_delproc("bandwidth_hs_2"); + ifx_proc_delproc("bandwidth_fs_2"); + ifx_proc_delproc("bandwidth_ls_2"); + device_remove_file(dev, &dev_attr_pkt_count_limit_bi_1); + device_remove_file(dev, &dev_attr_pkt_count_limit_bo_1); + device_remove_file(dev, &dev_attr_pkt_count_limit_bi_2); + device_remove_file(dev, &dev_attr_pkt_count_limit_bo_2); + device_remove_file(dev, &dev_attr_bandwidth_hs_1); + device_remove_file(dev, &dev_attr_bandwidth_fs_1); + device_remove_file(dev, &dev_attr_bandwidth_ls_1); + device_remove_file(dev, &dev_attr_bandwidth_hs_2); + device_remove_file(dev, &dev_attr_bandwidth_fs_2); + device_remove_file(dev, &dev_attr_bandwidth_ls_2); + #else + ifx_proc_delproc("pkt_count_limit_bi"); + ifx_proc_delproc("pkt_count_limit_bo"); + ifx_proc_delproc("bandwidth_hs"); + ifx_proc_delproc("bandwidth_fs"); + ifx_proc_delproc("bandwidth_ls"); + device_remove_file(dev, &dev_attr_pkt_count_limit_bi); + device_remove_file(dev, &dev_attr_pkt_count_limit_bo); + device_remove_file(dev, &dev_attr_bandwidth_hs); + device_remove_file(dev, &dev_attr_bandwidth_fs); + device_remove_file(dev, &dev_attr_bandwidth_ls); + #endif + #endif + + #ifdef __IS_HOST__ + #ifdef __IS_DUAL__ + ifx_proc_delproc("buspower_1"); + ifx_proc_delproc("buspower_2"); + device_remove_file(dev, &dev_attr_buspower_1); + device_remove_file(dev, &dev_attr_buspower_2); + #else + ifx_proc_delproc("buspower"); + device_remove_file(dev, &dev_attr_buspower); + #endif + + #ifdef __IS_DUAL__ + ifx_proc_delproc("bussuspend_1"); + ifx_proc_delproc("bussuspend_2"); + device_remove_file(dev, &dev_attr_bussuspend_1); + device_remove_file(dev, &dev_attr_bussuspend_2); + #else + ifx_proc_delproc("bussuspend"); + device_remove_file(dev, &dev_attr_bussuspend); + #endif + + #ifdef __IS_DUAL__ + ifx_proc_delproc("busconnected_1"); + ifx_proc_delproc("busconnected_2"); + device_remove_file(dev, &dev_attr_busconnected_1); + device_remove_file(dev, &dev_attr_busconnected_2); + #else + ifx_proc_delproc("busconnected"); + device_remove_file(dev, &dev_attr_busconnected); + #endif + + #ifdef __IS_DUAL__ + ifx_proc_delproc("connectspeed_1"); + ifx_proc_delproc("connectspeed_2"); + device_remove_file(dev, &dev_attr_connectspeed_1); + device_remove_file(dev, &dev_attr_connectspeed_2); + #else + ifx_proc_delproc("connectspeed"); + device_remove_file(dev, &dev_attr_connectspeed); + #endif + #endif + + #ifdef __IS_DEVICE__ + ifx_proc_delproc("devspeed"); + device_remove_file(dev, &dev_attr_devspeed); + ifx_proc_delproc("enumspeed"); + device_remove_file(dev, &dev_attr_enumspeed); + #endif + + #ifdef __ENABLE_DUMP__ + #ifdef __IS_HOST__ + #ifdef __IS_DUAL__ + ifx_proc_delproc("dump_reg_1"); + ifx_proc_delproc("dump_reg_2"); + device_remove_file(dev, &dev_attr_dump_reg_h_1); + device_remove_file(dev, &dev_attr_dump_reg_h_2); + #else + ifx_proc_delproc("dump_reg"); + device_remove_file(dev, &dev_attr_dump_reg_h); + #endif + + #ifdef __IS_DUAL__ + ifx_proc_delproc("dump_spram_1"); + ifx_proc_delproc("dump_spram_2"); + device_remove_file(dev, &dev_attr_dump_spram_h_1); + device_remove_file(dev, &dev_attr_dump_spram_h_2); + #else + ifx_proc_delproc("dump_spram"); + device_remove_file(dev, &dev_attr_dump_spram_h); + #endif + + #ifdef __IS_DUAL__ + ifx_proc_delproc("dump_host_state_1"); + ifx_proc_delproc("dump_host_state_2"); + device_remove_file(dev, &dev_attr_dump_host_state_1); + device_remove_file(dev, &dev_attr_dump_host_state_2); + #else + ifx_proc_delproc("dump_host_state"); + device_remove_file(dev, &dev_attr_dump_host_state); + #endif + #else + ifx_proc_delproc("dump_reg"); + device_remove_file(dev, &dev_attr_dump_reg_d); + ifx_proc_delproc("dump_spram"); + device_remove_file(dev, &dev_attr_dump_spram_d); + #endif + + #ifdef __IS_HOST__ + #endif + #endif //__ENABLE_DUMP__ +#ifdef __IS_HOST__ + #ifdef __IS_DUAL__ + ifx_proc_delproc("suspend_host_1"); + ifx_proc_delproc("probe_host_1"); + device_remove_file(dev, &dev_attr_suspend_host_1); + device_remove_file(dev, &dev_attr_probe_host_1); + ifx_proc_delproc("suspend_host_2"); + ifx_proc_delproc("probe_host_2"); + device_remove_file(dev, &dev_attr_suspend_host_2); + device_remove_file(dev, &dev_attr_probe_host_2); + ifx_proc_delproc("probe_timer1"); + ifx_proc_delproc("autoprobe_timer1"); + device_remove_file(dev, &dev_attr_probe_timer1_val_h); + device_remove_file(dev, &dev_attr_autoprobe_timer1_val_h); + ifx_proc_delproc("probe_timer2"); + ifx_proc_delproc("autoprobe_timer2"); + device_remove_file(dev, &dev_attr_probe_timer2_val_h); + device_remove_file(dev, &dev_attr_autoprobe_timer2_val_h); + #else + ifx_proc_delproc("suspend_host"); + ifx_proc_delproc("probe_host"); + device_remove_file(dev, &dev_attr_suspend_host); + device_remove_file(dev, &dev_attr_probe_host); + ifx_proc_delproc("probe_timer"); + ifx_proc_delproc("autoprobe_timer"); + device_remove_file(dev, &dev_attr_probe_timer_val_h); + device_remove_file(dev, &dev_attr_autoprobe_timer_val_h); + #endif + remove_proc_entry(ifxusb_hcd_driver_name, (void *)0); +#endif + +#ifdef __IS_DEVICE__ + ifx_proc_delproc("suspend_device"); + ifx_proc_delproc("probe_device"); + device_remove_file(dev, &dev_attr_suspend_device); + device_remove_file(dev, &dev_attr_probe_device); + ifx_proc_delproc("probe_timer"); + ifx_proc_delproc("autoprobe_timer"); + device_remove_file(dev, &dev_attr_probe_timer_val_d); + device_remove_file(dev, &dev_attr_autoprobe_timer_val_d); + remove_proc_entry(ifxusb_pcd_driver_name, (void *)0); +#endif +#if defined(__IS_HOST__) && defined(__HOST_COC__) + #ifdef __IS_DUAL__ + ifx_pmcu_unregister ( &pmcuRegisterUSBHost_1 ); + ifx_pmcu_unregister ( &pmcuRegisterUSBHost_2 ); + #else + ifx_pmcu_unregister ( &pmcuRegisterUSBHost ); + #endif +#endif +#if defined(__IS_DEVICE__) && defined(__GADGET_COC__) + ifx_pmcu_unregister ( &pmcuRegisterUSBGadget ); +#endif + +} + +static struct proc_dir_entry * proc_ifx_root = NULL; + +/* initialize the proc file system and make a dir named /proc/[name] */ +static void ifx_proc_init(void) +{ + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); +#ifdef __IS_HOST__ + proc_ifx_root = proc_mkdir(ifxusb_hcd_driver_name, (void *)0); + if (!proc_ifx_root){ + IFX_PRINT("%s proc initialization failed! \n", ifxusb_hcd_driver_name); + return; + } +#else + proc_ifx_root = proc_mkdir(ifxusb_pcd_driver_name, (void *)0); + if (!proc_ifx_root){ + IFX_PRINT("%s proc initialization failed! \n", ifxusb_pcd_driver_name); + return; + } +#endif +} + +/* proc file system add function for debugging. */ +static int ifx_proc_addproc(char *funcname, read_proc_t *hookfuncr, write_proc_t *hookfuncw) +{ + struct proc_dir_entry *pe; + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + if (!proc_ifx_root) + ifx_proc_init(); + + if (hookfuncw == NULL) + { + pe = create_proc_read_entry(funcname, S_IRUGO, proc_ifx_root, hookfuncr, NULL); + if (!pe) + { + IFX_PRINT("ERROR in creating read proc entry (%s)! \n", funcname); + return -1; + } + } + else + { + pe = create_proc_entry(funcname, S_IRUGO | S_IWUGO, proc_ifx_root); + if (pe) + { + pe->read_proc = hookfuncr; + pe->write_proc = hookfuncw; + } + else + { + IFX_PRINT("ERROR in creating proc entry (%s)! \n", funcname); + return -1; + } + } + return 0; +} + + +/* proc file system del function for removing module. */ +static void ifx_proc_delproc(char *funcname) +{ + char pname[30]; + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + sprintf(pname, "%s", funcname); + + remove_proc_entry(pname, proc_ifx_root); + +} + +static void ifxusb_dump_params(ifxusb_core_if_t *_core_if) +{ + ifxusb_params_t *params=&_core_if->params; + + #ifdef __IS_HOST__ + IFX_PRINT("IFXUSB Dump Parameters ( Host Mode) \n"); + #endif //__IS_HOST__ + #ifdef __IS_DEVICE__ + IFX_PRINT("IFXUSB Dump Parameters ( Device Mode) \n"); + #endif //__IS_DEVICE__ + + #ifdef __DESC_DMA__ + IFX_PRINT("DMA: Hermes DMA\n"); + #else + IFX_PRINT("DMA: Non-Desc DMA\n"); + #endif + IFX_PRINT(" Burst size: %d\n",params->dma_burst_size); + + if (params->speed==1) + IFX_PRINT("Full Speed only\n"); + else if(params->speed==0) + IFX_PRINT("Full/Hign Speed\n"); + else + IFX_PRINT("Unkonwn setting (%d) for Speed\n",params->speed); + + IFX_PRINT("Total Data FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", + params->data_fifo_size,params->data_fifo_size, + params->data_fifo_size*4, params->data_fifo_size*4 + ); + + #ifdef __IS_DEVICE__ + IFX_PRINT("Rx FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", + params->rx_fifo_size,params->rx_fifo_size, + params->rx_fifo_size*4, params->rx_fifo_size*4 + ); + { + int i; + for(i=0;itx_fifo_size[i],params->tx_fifo_size[i], + params->tx_fifo_size[i]*4, params->tx_fifo_size[i]*4 + ); + } + } + #ifdef __DED_FIFO__ + IFX_PRINT("Treshold : %s Rx:%d Tx:%d \n", + (params->thr_ctl)?"On":"Off",params->tx_thr_length,params->rx_thr_length); + #endif + #else //__IS_HOST__ + IFX_PRINT("Host Channels: %d\n",params->host_channels); + + IFX_PRINT("Rx FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", + params->data_fifo_size,params->data_fifo_size, + params->data_fifo_size*4, params->data_fifo_size*4 + ); + + IFX_PRINT("NP Tx FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", + params->nperio_tx_fifo_size,params->nperio_tx_fifo_size, + params->nperio_tx_fifo_size*4, params->nperio_tx_fifo_size*4 + ); + + IFX_PRINT(" P Tx FIFO size: %d(0x%06X) DWord, %d(0x%06X) Bytes\n", + params->perio_tx_fifo_size,params->perio_tx_fifo_size, + params->perio_tx_fifo_size*4, params->perio_tx_fifo_size*4 + ); + #endif //__IS_HOST__ + + IFX_PRINT("Max Transfer size: %d(0x%06X) Bytes\n", + params->max_transfer_size,params->max_transfer_size + ); + IFX_PRINT("Max Packet Count: %d(0x%06X)\n", + params->max_packet_count,params->max_packet_count + ); + + IFX_PRINT("PHY UTMI Width: %d\n",params->phy_utmi_width); + + IFX_PRINT("Turn Around Time: HS:%d FS:%d\n",params->turn_around_time_hs,params->turn_around_time_fs); + IFX_PRINT("Timeout Calibration: HS:%d FS:%d\n",params->timeout_cal_hs,params->timeout_cal_fs); + + + IFX_PRINT("==================================================\n"); + IFX_PRINT("End of Parameters Dump\n"); + IFX_PRINT("==================================================\n"); +} + diff --git a/package/platform/lantiq/ltq-hcd/src/ifxusb_driver.c b/package/platform/lantiq/ltq-hcd/src/ifxusb_driver.c new file mode 100644 index 0000000000..b49a197883 --- /dev/null +++ b/package/platform/lantiq/ltq-hcd/src/ifxusb_driver.c @@ -0,0 +1,1279 @@ +/***************************************************************************** + ** FILE NAME : ifxusb_driver.c + ** PROJECT : IFX USB sub-system V3 + ** MODULES : IFX USB sub-system Host and Device driver + ** SRC VERSION : 3.2 + ** DATE : 1/Jan/2011 + ** AUTHOR : Chen, Howard + ** DESCRIPTION : The provides the initialization and cleanup entry + ** points for the IFX USB driver. This module can be + ** dynamically loaded with insmod command or built-in + ** with kernel. When loaded or executed the ifxusb_driver_init + ** function is called. When the module is removed (using rmmod), + ** the ifxusb_driver_cleanup function is called. + ** FUNCTIONS : + ** COMPILER : gcc + ** REFERENCE : Synopsys DWC-OTG Driver 2.7 + ** COPYRIGHT : Copyright (c) 2010 + ** LANTIQ DEUTSCHLAND GMBH, + ** Am Campeon 3, 85579 Neubiberg, Germany + ** + ** This program is free software; you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation; either version 2 of the License, or + ** (at your option) any later version. + ** + ** Version Control Section ** + ** $Author$ + ** $Date$ + ** $Revisions$ + ** $Log$ Revision history + *****************************************************************************/ + +/* + * This file contains code fragments from Synopsys HS OTG Linux Software Driver. + * For this code the following notice is applicable: + * + * ========================================================================== + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + +/*! + \file ifxusb_driver.c + \brief This file contains the loading/unloading interface to the Linux driver. +*/ + +#include +#include "ifxusb_version.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include /* permission constants */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) + #include +#endif + +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + #include +#endif + +#include "ifxusb_plat.h" + +#include "ifxusb_cif.h" + +#ifdef __IS_HOST__ + #include "ifxhcd.h" + + #define USB_DRIVER_DESC "IFX USB HCD driver" + const char ifxusb_hcd_driver_name[] = "ifxusb_hcd"; + #ifdef __IS_DUAL__ + ifxhcd_hcd_t ifxusb_hcd_1; + ifxhcd_hcd_t ifxusb_hcd_2; + const char ifxusb_hcd_name_1[] = "ifxusb_hcd_1"; + const char ifxusb_hcd_name_2[] = "ifxusb_hcd_2"; + #else + ifxhcd_hcd_t ifxusb_hcd; + const char ifxusb_hcd_name[] = "ifxusb_hcd"; + #endif + + #if defined(__DO_OC_INT__) + ifxhcd_hcd_t *oc_int_id=NULL; + #ifdef __IS_DUAL__ + ifxhcd_hcd_t *oc_int_id_1=NULL; + ifxhcd_hcd_t *oc_int_id_2=NULL; + #endif + #endif +#endif + +#ifdef __IS_DEVICE__ + #include "ifxpcd.h" + + #define USB_DRIVER_DESC "IFX USB PCD driver" + const char ifxusb_pcd_driver_name[] = "ifxusb_pcd"; + ifxpcd_pcd_t ifxusb_pcd; + const char ifxusb_pcd_name[] = "ifxusb_pcd"; +#endif + +/* Global Debug Level Mask. */ +#ifdef __IS_HOST__ + uint32_t h_dbg_lvl = 0xff; +#endif + +#ifdef __IS_DEVICE__ + uint32_t d_dbg_lvl = 0x00; +#endif + +#ifdef __IS_HOST__ +ifxusb_params_t ifxusb_module_params_h; +#else +ifxusb_params_t ifxusb_module_params_d; +#endif + +static void parse_parms(void); + + +#if defined(__IS_TWINPASS__) +#warning "Compiled as TWINPASS" +#elif defined(__IS_DANUBE__) +#warning "Compiled as DANUBE" +#elif defined(__IS_AMAZON_SE__) +#warning "Compiled as AMAZON_SE" +#elif defined(__IS_AR9__) +#warning "Compiled as AR9" +#elif defined(__IS_VR9__) +#warning "Compiled as VR9" +#elif defined(__IS_AR10__) +#warning "Compiled as AR10" +#else +#error "No Platform defined" +#endif + + +/* Function to setup the structures to control one usb core running as host*/ +#ifdef __IS_HOST__ +/*! + \brief inlined by ifxusb_driver_probe(), handling host mode probing. Run at each host core. +*/ + static inline int ifxusb_driver_probe_h(ifxhcd_hcd_t *_hcd, + int _irq, + uint32_t _iobase, + uint32_t _fifomem, + uint32_t _fifodbg + ) + { + int retval = 0; + + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + + ifxusb_power_on_h (&_hcd->core_if); + mdelay(50); + ifxusb_phy_power_on_h (&_hcd->core_if); // Test + mdelay(50); + ifxusb_hard_reset_h(&_hcd->core_if); + retval =ifxusb_core_if_init_h(&_hcd->core_if, + _irq, + _iobase, + _fifomem, + _fifodbg); + if(retval) + return retval; + + ifxusb_host_core_init(&_hcd->core_if,&ifxusb_module_params_h); + + ifxusb_disable_global_interrupts_h( &_hcd->core_if); + + /* The driver is now initialized and need to be registered into Linux USB sub-system */ + + retval = ifxhcd_init(_hcd); // hook the hcd into usb ss + + if (retval != 0) + { + IFX_ERROR("_hcd_init failed\n"); + return retval; + } + + //ifxusb_enable_global_interrupts_h( _hcd->core_if ); // this should be done at hcd_start , including hcd_interrupt + return 0; + } +#endif //__IS_HOST__ + +#ifdef __IS_DEVICE__ +/*! + \brief inlined by ifxusb_driver_probe(), handling device mode probing. +*/ + static inline int ifxusb_driver_probe_d(ifxpcd_pcd_t *_pcd, + int _irq, + uint32_t _iobase, + uint32_t _fifomem, + uint32_t _fifodbg + ) + { + int retval = 0; + + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + ifxusb_power_on_d (&_pcd->core_if); + mdelay(50); + ifxusb_phy_power_on_d (&_pcd->core_if); // Test + mdelay(50); + ifxusb_hard_reset_d(&_pcd->core_if); + retval =ifxusb_core_if_init_d(&_pcd->core_if, + _irq, + _iobase, + _fifomem, + _fifodbg); + if(retval) + return retval; + + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + ifxusb_dev_core_init(&_pcd->core_if,&ifxusb_module_params_d); + + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + ifxusb_disable_global_interrupts_d( &_pcd->core_if); + + /* The driver is now initialized and need to be registered into + Linux USB Gadget sub-system + */ + retval = ifxpcd_init(); + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + + if (retval != 0) + { + IFX_ERROR("_pcd_init failed\n"); + return retval; + } + //ifxusb_enable_global_interrupts_d( _pcd->core_if ); // this should be done at gadget bind or start + return 0; + } +#endif //__IS_DEVICE__ + +/*! + \brief This function is called when a driver is unregistered. This happens when + the rmmod command is executed. The device may or may not be electrically + present. If it is present, the driver stops device processing. Any resources + used on behalf of this device are freed. +*/ +static int ifxusb_driver_remove(struct platform_device *_pdev) +{ + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + #ifdef __IS_HOST__ + #if defined(__IS_DUAL__) + ifxhcd_remove(&ifxusb_hcd_1); + ifxusb_core_if_remove_h(&ifxusb_hcd_1.core_if ); + ifxhcd_remove(&ifxusb_hcd_2); + ifxusb_core_if_remove_h(&ifxusb_hcd_2.core_if ); + #else + ifxhcd_remove(&ifxusb_hcd); + ifxusb_core_if_remove_h(&ifxusb_hcd.core_if ); + #endif + #endif + #ifdef __IS_DEVICE__ + ifxpcd_remove(); + ifxusb_core_if_remove_d(&ifxusb_pcd.core_if ); + #endif + /* Remove the device attributes */ + #ifdef __IS_HOST__ + ifxusb_attr_remove_h(&_pdev->dev); + #else + ifxusb_attr_remove_d(&_pdev->dev); + #endif + return 0; +} + +/*! + \brief This function is called by module management in 2.6 kernel or by ifxusb_driver_init with 2.4 kernel + It is to probe and setup IFXUSB core(s). +*/ +static int ifxusb_driver_probe(struct platform_device *_pdev) +{ + int retval = 0; + struct device_node *np; + int gpio_count; +#ifdef __IS_DANUBE__ + np = of_find_compatible_node(NULL, NULL, "lantiq,ifxhcd-danube"); +#elif defined __IS_AMAZON_SE__ + np = of_find_compatible_node(NULL, NULL, "lantiq,ifxhcd-ase"); +#elif defined __IS_AR9__ + np = of_find_compatible_node(NULL, NULL, "lantiq,ifxhcd-arx100"); +#elif defined __IS_VR9__ + np = of_find_compatible_node(NULL, NULL, "lantiq,ifxhcd-xrx200"); +#endif + if (!np) { + dev_err(&_pdev->dev, "failed to find hcd device node\n"); + return -ENODEV; + } + + // Parsing and store the parameters + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + parse_parms(); + + #ifdef __IS_HOST__ + #if defined(__DO_OC_INT__) + if(!oc_int_id) + { + #if defined(__IS_DUAL__) + oc_int_id=&ifxusb_hcd_1; + oc_int_id_1=&ifxusb_hcd_1; + oc_int_id_2=&ifxusb_hcd_2; + #else + oc_int_id=&ifxusb_hcd; + #endif + } + #endif + + #if defined(__IS_DUAL__) + memset(&ifxusb_hcd_1, 0, sizeof(ifxhcd_hcd_t)); + memset(&ifxusb_hcd_2, 0, sizeof(ifxhcd_hcd_t)); + + ifxusb_hcd_1.core_if.core_no=0; + ifxusb_hcd_2.core_if.core_no=1; + ifxusb_hcd_1.core_if.core_name=(char *)ifxusb_hcd_name_1; + ifxusb_hcd_2.core_if.core_name=(char *)ifxusb_hcd_name_2; + + ifxusb_hcd_1.dev=&_pdev->dev; + ifxusb_hcd_2.dev=&_pdev->dev; + + retval = ifxusb_driver_probe_h(&ifxusb_hcd_1, + IFXUSB1_IRQ, + IFXUSB1_IOMEM_BASE, + IFXUSB1_FIFOMEM_BASE, + IFXUSB1_FIFODBG_BASE + ); + if(retval) + goto ifxusb_driver_probe_fail; + + retval = ifxusb_driver_probe_h(&ifxusb_hcd_2, + IFXUSB2_IRQ, + IFXUSB2_IOMEM_BASE, + IFXUSB2_FIFOMEM_BASE, + IFXUSB2_FIFODBG_BASE + ); + if(retval) + goto ifxusb_driver_probe_fail; + + #elif defined(__IS_FIRST__) + memset(&ifxusb_hcd, 0, sizeof(ifxhcd_hcd_t)); + + ifxusb_hcd.core_if.core_no=0; + ifxusb_hcd.core_if.core_name=(char *)ifxusb_hcd_name; + + ifxusb_hcd.dev=&_pdev->dev; + + retval = ifxusb_driver_probe_h(&ifxusb_hcd, + IFXUSB1_IRQ, + IFXUSB1_IOMEM_BASE, + IFXUSB1_FIFOMEM_BASE, + IFXUSB1_FIFODBG_BASE + ); + if(retval) + goto ifxusb_driver_probe_fail; + + #elif defined(__IS_SECOND__) + memset(&ifxusb_hcd, 0, sizeof(ifxhcd_hcd_t)); + + ifxusb_hcd.core_if.core_no=1; + ifxusb_hcd.core_if.core_name=(char *)ifxusb_hcd_name; + + ifxusb_hcd.dev=&_pdev->dev; + + retval = ifxusb_driver_probe_h(&ifxusb_hcd, + IFXUSB2_IRQ, + IFXUSB2_IOMEM_BASE, + IFXUSB2_FIFOMEM_BASE, + IFXUSB2_FIFODBG_BASE + ); + if(retval) + goto ifxusb_driver_probe_fail; + + #else + memset(&ifxusb_hcd, 0, sizeof(ifxhcd_hcd_t)); + + ifxusb_hcd.core_if.core_no=0; + ifxusb_hcd.core_if.core_name=(char *)ifxusb_hcd_name; + + ifxusb_hcd.dev=&_pdev->dev; + + retval = ifxusb_driver_probe_h(&ifxusb_hcd, + IFXUSB_IRQ, + IFXUSB_IOMEM_BASE, + IFXUSB_FIFOMEM_BASE, + IFXUSB_FIFODBG_BASE + ); + if(retval) + goto ifxusb_driver_probe_fail; + #endif + #endif + + #ifdef __IS_DEVICE__ + memset(&ifxusb_pcd, 0, sizeof(ifxpcd_pcd_t)); + ifxusb_pcd.core_if.core_name=(char *)&ifxusb_pcd_name[0]; + + ifxusb_pcd.dev=&_pdev->dev; + + #if defined(__IS_FIRST__) + ifxusb_pcd.core_if.core_no=0; + retval = ifxusb_driver_probe_d(&ifxusb_pcd, + IFXUSB1_IRQ, + IFXUSB1_IOMEM_BASE, + IFXUSB1_FIFOMEM_BASE, + IFXUSB1_FIFODBG_BASE + ); + #elif defined(__IS_SECOND__) + ifxusb_pcd.core_if.core_no=1; + retval = ifxusb_driver_probe_d(&ifxusb_pcd, + IFXUSB2_IRQ, + IFXUSB2_IOMEM_BASE, + IFXUSB2_FIFOMEM_BASE, + IFXUSB2_FIFODBG_BASE + ); + #else + ifxusb_pcd.core_if.core_no=0; + retval = ifxusb_driver_probe_d(&ifxusb_pcd, + IFXUSB_IRQ, + IFXUSB_IOMEM_BASE, + IFXUSB_FIFOMEM_BASE, + IFXUSB_FIFODBG_BASE + ); + #endif + if(retval) + goto ifxusb_driver_probe_fail; + #endif + + #ifdef __IS_HOST__ + ifxusb_attr_create_h(&_pdev->dev); + #else + ifxusb_attr_create_d(&_pdev->dev); + #endif + + gpio_count = of_gpio_count(np); + while (gpio_count) { + enum of_gpio_flags flags; + int gpio = of_get_gpio_flags(np, --gpio_count, &flags); + if (gpio_request(gpio, "usb")) + continue; + dev_info(&_pdev->dev, "requested GPIO %d\n", gpio); + gpio_direction_output(gpio, (flags & OF_GPIO_ACTIVE_LOW) ? (0) : (1)); + } + + + return 0; + +ifxusb_driver_probe_fail: + ifxusb_driver_remove(_pdev); + return retval; +} + +static struct resource ifxusb_device_resources[] = +{ + #if defined(__IS_DUAL__) + [0] = { .start = IFXUSB1_IRQ, + .flags = IORESOURCE_IRQ, + }, + [1] = { .start = IFXUSB1_IOMEM_BASE, + .end = IFXUSB1_IOMEM_BASE + IFXUSB_IOMEM_SIZE-1, + .flags = IORESOURCE_MEM, + }, + [2] = { .start = IFXUSB2_IRQ, + .flags = IORESOURCE_IRQ, + }, + [3] = { .start = IFXUSB2_IOMEM_BASE, + .end = IFXUSB2_IOMEM_BASE + IFXUSB_IOMEM_SIZE-1, + .flags = IORESOURCE_MEM, + }, + [4] = { .start = IFXUSB1_FIFOMEM_BASE, + .end = IFXUSB1_FIFOMEM_BASE + IFXUSB_FIFOMEM_SIZE-1, + .flags = IORESOURCE_MEM, + }, + [5] = { .start = IFXUSB2_FIFOMEM_BASE, + .end = IFXUSB2_FIFOMEM_BASE + IFXUSB_FIFOMEM_SIZE-1, + .flags = IORESOURCE_MEM, + }, + [6] = { .start = IFXUSB1_FIFODBG_BASE, + .end = IFXUSB1_FIFODBG_BASE + IFXUSB_FIFODBG_SIZE-1, + .flags = IORESOURCE_MEM, + }, + [7] = { .start = IFXUSB2_FIFODBG_BASE, + .end = IFXUSB2_FIFODBG_BASE + IFXUSB_FIFODBG_SIZE-1, + .flags = IORESOURCE_MEM, + }, + #elif defined(__IS_FIRST__) + [0] = { .start = IFXUSB1_IRQ, + .flags = IORESOURCE_IRQ, + }, + [1] = { .start = IFXUSB1_IOMEM_BASE, + .end = IFXUSB1_IOMEM_BASE + IFXUSB_IOMEM_SIZE-1, + .flags = IORESOURCE_MEM, + }, + [2] = { .start = IFXUSB1_FIFOMEM_BASE, + .end = IFXUSB1_FIFOMEM_BASE + IFXUSB_FIFOMEM_SIZE-1, + .flags = IORESOURCE_MEM, + }, + [3] = { .start = IFXUSB1_FIFODBG_BASE, + .end = IFXUSB1_FIFODBG_BASE + IFXUSB_FIFODBG_SIZE-1, + .flags = IORESOURCE_MEM, + }, + #elif defined(__IS_SECOND__) + [0] = { .start = IFXUSB2_IRQ, + .flags = IORESOURCE_IRQ, + }, + [1] = { .start = IFXUSB2_IOMEM_BASE, + .end = IFXUSB2_IOMEM_BASE + IFXUSB_IOMEM_SIZE-1, + .flags = IORESOURCE_MEM, + }, + [2] = { .start = IFXUSB2_FIFOMEM_BASE, + .end = IFXUSB2_FIFOMEM_BASE + IFXUSB_FIFOMEM_SIZE-1, + .flags = IORESOURCE_MEM, + }, + [3] = { .start = IFXUSB2_FIFODBG_BASE, + .end = IFXUSB2_FIFODBG_BASE + IFXUSB_FIFODBG_SIZE-1, + .flags = IORESOURCE_MEM, + }, + #else + [0] = { .start = IFXUSB_IRQ, + .flags = IORESOURCE_IRQ, + }, + [1] = { .start = IFXUSB_IOMEM_BASE, + .end = IFXUSB_IOMEM_BASE + IFXUSB_IOMEM_SIZE-1, + .flags = IORESOURCE_MEM, + }, + [2] = { .start = IFXUSB_FIFOMEM_BASE, + .end = IFXUSB_FIFOMEM_BASE+IFXUSB_FIFOMEM_SIZE-1, + .flags = IORESOURCE_MEM, + }, + [3] = { .start = IFXUSB_FIFODBG_BASE, + .end = IFXUSB_FIFODBG_BASE+IFXUSB_FIFODBG_SIZE-1, + .flags = IORESOURCE_MEM, + }, + #endif //__IS_DUAL__ +}; + +static u64 ifxusb_dmamask = (u32)0x1fffffff; + +static void ifxusb_device_release(struct device * dev) +{ + IFX_PRINT("IFX USB platform_dev release\n"); + dev->parent = NULL; +} + +static struct platform_device ifxusb_device = +{ + .id = -1, + .dev = + { + .release = ifxusb_device_release, + .dma_mask = &ifxusb_dmamask, + }, + .resource = ifxusb_device_resources, + .num_resources = ARRAY_SIZE(ifxusb_device_resources), +}; + + +/*! + \brief This function is called when the ifxusb_driver is installed with the insmod command. +*/ +static struct platform_driver ifxusb_driver = { + .probe = ifxusb_driver_probe, + .remove = ifxusb_driver_remove, + .driver ={ + .owner = THIS_MODULE, + #ifdef __IS_HOST__ + .name = ifxusb_hcd_driver_name, + #else + .name = ifxusb_pcd_driver_name, + #endif + }, +}; + +#ifdef __IS_HOST__ + int __init ifxusb_hcd_driver_init(void) +#else + int __init ifxusb_pcd_driver_init(void) +#endif +{ + int retval = 0; + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + #if defined(__IS_HOST__) + IFX_PRINT("%s: version %s\n", ifxusb_hcd_driver_name, IFXUSB_VERSION); + #else + IFX_PRINT("%s: version %s\n", ifxusb_pcd_driver_name, IFXUSB_VERSION); + #endif + + #if 0 + #if defined(__IS_TWINPASS__) + IFX_PRINT(" OPTION: __IS_TWINPASS__\n"); + #elif defined(__IS_DANUBE__) + IFX_PRINT(" OPTION: __IS_DANUBE__\n"); + #elif defined(__IS_AMAZON_SE__) + IFX_PRINT(" OPTION: __IS_AMAZON_SE__\n"); + #elif defined(__IS_AR9__) + IFX_PRINT(" OPTION: __IS_AR9__\n"); + #elif defined(__IS_VR9__) + IFX_PRINT(" OPTION: __IS_VR9__\n"); + #elif defined(__IS_AR10__) + IFX_PRINT(" OPTION: __IS_AR10__\n"); + #else + IFX_PRINT(" OPTION: NO PLATFORM DEFINED\n"); + #endif + + #ifdef __UEIP__ + IFX_PRINT(" OPTION: __UEIP__\n"); + #endif + + #ifdef __PHY_LONG_PREEMP__ + IFX_PRINT(" OPTION: __PHY_LONG_PREEMP__\n"); + #endif + #ifdef __FORCE_USB11__ + IFX_PRINT(" OPTION: __FORCE_USB11__\n"); + #endif + #ifdef __UNALIGNED_BUF_ADJ__ + IFX_PRINT(" OPTION: __UNALIGNED_BUF_ADJ__\n"); + #endif + #ifdef __UNALIGNED_BUF_CHK__ + IFX_PRINT(" OPTION: __UNALIGNED_BUF_CHK__\n"); + #endif + #ifdef __UNALIGNED_BUF_BURST__ + IFX_PRINT(" OPTION: __UNALIGNED_BUF_BURST__\n"); + #endif + #ifdef __DEBUG__ + IFX_PRINT(" OPTION: __DEBUG__\n"); + #endif + #ifdef __ENABLE_DUMP__ + IFX_PRINT(" OPTION: __ENABLE_DUMP__\n"); + #endif + + #ifdef __IS_HOST__ + IFX_PRINT(" OPTION: __IS_HOST__\n"); + #ifdef __IS_DUAL__ + IFX_PRINT(" __IS_DUAL__\n"); + #endif + #ifdef __IS_FIRST__ + IFX_PRINT(" __IS_FIRST__\n"); + #endif + #ifdef __IS_SECOND__ + IFX_PRINT(" __IS_SECOND__\n"); + #endif + #ifdef __WITH_HS_ELECT_TST__ + IFX_PRINT(" __WITH_HS_ELECT_TST__\n"); + #endif + #ifdef __EN_ISOC__ + IFX_PRINT(" __EN_ISOC__\n"); + #endif + #ifdef __EN_ISOC_SPLIT__ + IFX_PRINT(" __EN_ISOC_SPLIT__\n"); + #endif + #ifdef __EPQD_DESTROY_TIMEOUT__ + IFX_PRINT(" __EPQD_DESTROY_TIMEOUT__\n"); + #endif + #ifdef __DYN_SOF_INTR__ + IFX_PRINT(" __DYN_SOF_INTR__\n"); + #endif + #else + IFX_PRINT(" OPTION: __IS_DEVICE__\n"); + #ifdef __DED_INTR__ + IFX_PRINT(" __DED_INTR__\n"); + #endif + #ifdef __DED_FIFO__ + IFX_PRINT(" __DED_FIFO__\n"); + #endif + #ifdef __DESC_DMA__ + IFX_PRINT(" __DESC_DMA__\n"); + #endif + #ifdef __IS_FIRST__ + IFX_PRINT(" __IS_FIRST__\n"); + #endif + #ifdef __IS_SECOND__ + IFX_PRINT(" __IS_SECOND__\n"); + #endif + #ifdef __GADGET_TASKLET_TX__ + IFX_PRINT(" __GADGET_TASKLET_TX__\n"); + #endif + #ifdef __GADGET_TASKLET_RX__ + IFX_PRINT(" __GADGET_TASKLET_RX__\n"); + #endif + #ifdef __GADGET_TASKLET_HIGH__ + IFX_PRINT(" __GADGET_TASKLET_HIGH__\n"); + #endif + #ifdef __DO_PCD_UNLOCK__ + IFX_PRINT(" __DO_PCD_UNLOCK__\n"); + #endif + #ifdef __GADGET_LED__ + IFX_PRINT(" __GADGET_LED__\n"); + #endif + + #ifdef __ECM_NO_INTR__ + IFX_PRINT(" __ECM_NO_INTR__\n"); + #endif + #ifdef __NOSWAPINCTRL__ + IFX_PRINT(" __NOSWAPINCTRL__\n"); + #endif + #ifdef __MAC_ECM_FIX__ + IFX_PRINT(" __MAC_ECM_FIX__\n"); + #endif + #ifdef __RETAIN_BUF_TX__ + IFX_PRINT(" __RETAIN_BUF_TX__\n"); + #endif + #ifdef __RETAIN_BUF_RX__ + IFX_PRINT(" __RETAIN_BUF_RX__\n"); + #endif + #ifdef __QUICKNAK__ + IFX_PRINT(" __QUICKNAK__\n"); + #endif + #endif + #endif + + retval = platform_driver_register(&ifxusb_driver); + + if (retval < 0) { + IFX_ERROR("%s retval=%d\n", __func__, retval); + return retval; + } + + #ifdef __IS_HOST__ + ifxusb_device.name = ifxusb_hcd_driver_name; + #else + ifxusb_device.name = ifxusb_pcd_driver_name; + #endif + + if (ifxusb_device.dev.parent) + retval = -EBUSY; + else + retval = platform_device_register(&ifxusb_device); + + if (retval < 0) + { + IFX_ERROR("%s retval=%d\n", __func__, retval); + platform_driver_unregister(&ifxusb_driver); + return retval; + } + return retval; +} + +#ifdef __IS_HOST__ + module_init(ifxusb_hcd_driver_init); +#else + module_init(ifxusb_pcd_driver_init); +#endif + +/*! + \brief This function is called when the driver is removed from the kernel + with the rmmod command. The driver unregisters itself with its bus + driver. +*/ +#ifdef __IS_HOST__ + void __exit ifxusb_hcd_driver_cleanup(void) + { + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + platform_device_unregister(&ifxusb_device); + platform_driver_unregister(&ifxusb_driver); + IFX_PRINT("%s module removed\n", ifxusb_hcd_driver_name); + } + module_exit(ifxusb_hcd_driver_cleanup); +#else + void __exit ifxusb_pcd_driver_cleanup(void) + { + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + platform_device_unregister(&ifxusb_device); + platform_driver_unregister(&ifxusb_driver); + IFX_PRINT("%s module removed\n", ifxusb_pcd_driver_name); + } + module_exit(ifxusb_pcd_driver_cleanup); +#endif +MODULE_DESCRIPTION(USB_DRIVER_DESC); +MODULE_AUTHOR("Lantiq"); +MODULE_LICENSE("GPL"); + + + +// Parameters set when loaded +//static long dbg_lvl =0xFFFFFFFF; +static long dbg_lvl =0; +static short dma_burst_size =-1; +static short speed =-1; +static long data_fifo_size =-1; +#ifdef __IS_DEVICE__ + static long rx_fifo_size =-1; + #ifdef __DED_FIFO__ + static long tx_fifo_size_00 =-1; + static long tx_fifo_size_01 =-1; + static long tx_fifo_size_02 =-1; + static long tx_fifo_size_03 =-1; + static long tx_fifo_size_04 =-1; + static long tx_fifo_size_05 =-1; + static long tx_fifo_size_06 =-1; + static long tx_fifo_size_07 =-1; + static long tx_fifo_size_08 =-1; + static long tx_fifo_size_09 =-1; + static long tx_fifo_size_10 =-1; + static long tx_fifo_size_11 =-1; + static long tx_fifo_size_12 =-1; + static long tx_fifo_size_13 =-1; + static long tx_fifo_size_14 =-1; + static long tx_fifo_size_15 =-1; + static short thr_ctl=-1; + static long tx_thr_length =-1; + static long rx_thr_length =-1; + #else + static long nperio_tx_fifo_size =-1; + static long perio_tx_fifo_size_01 =-1; + static long perio_tx_fifo_size_02 =-1; + static long perio_tx_fifo_size_03 =-1; + static long perio_tx_fifo_size_04 =-1; + static long perio_tx_fifo_size_05 =-1; + static long perio_tx_fifo_size_06 =-1; + static long perio_tx_fifo_size_07 =-1; + static long perio_tx_fifo_size_08 =-1; + static long perio_tx_fifo_size_09 =-1; + static long perio_tx_fifo_size_10 =-1; + static long perio_tx_fifo_size_11 =-1; + static long perio_tx_fifo_size_12 =-1; + static long perio_tx_fifo_size_13 =-1; + static long perio_tx_fifo_size_14 =-1; + static long perio_tx_fifo_size_15 =-1; + #endif + static short dev_endpoints =-1; +#endif + +#ifdef __IS_HOST__ + static long rx_fifo_size =-1; + static long nperio_tx_fifo_size =-1; + static long perio_tx_fifo_size =-1; + static short host_channels =-1; +#endif + +static long max_transfer_size =-1; +static long max_packet_count =-1; +static long phy_utmi_width =-1; +static long turn_around_time_hs =-1; +static long turn_around_time_fs =-1; +static long timeout_cal_hs =-1; +static long timeout_cal_fs =-1; + +/*! + \brief Parsing the parameters taken when module load +*/ +static void parse_parms(void) +{ + + ifxusb_params_t *params; + IFX_DEBUGPL(DBG_ENTRY, "%s() %d\n", __func__, __LINE__ ); + #ifdef __IS_HOST__ + h_dbg_lvl=dbg_lvl; + params=&ifxusb_module_params_h; + #endif + #ifdef __IS_DEVICE__ + d_dbg_lvl=dbg_lvl; + params=&ifxusb_module_params_d; + #endif + + switch(dma_burst_size) + { + case 0: + case 1: + case 4: + case 8: + case 16: + params->dma_burst_size=dma_burst_size; + break; + default: + #if defined(__IS_VR9__) + { + unsigned int chipid; + unsigned int partnum; + chipid=*((volatile uint32_t *)IFX_MPS_CHIPID); + partnum=(chipid&0x0FFFF000)>>12; + switch(partnum) + { + case 0x000B: //VRX288_A2x + case 0x000E: //VRX282_A2x + case 0x000C: //VRX268_A2x + case 0x000D: //GRX288_A2x + params->dma_burst_size=default_param_dma_burst_size_n; + break; + default: + params->dma_burst_size=default_param_dma_burst_size; + } + printk(KERN_INFO "Chip Version :%04x BurstSize=%d\n",partnum,params->dma_burst_size); + } + #else + params->dma_burst_size=default_param_dma_burst_size; + #endif + } + + if(speed==0 || speed==1) + params->speed=speed; + else + params->speed=default_param_speed; + + if(max_transfer_size>=2048 && max_transfer_size<=65535) + params->max_transfer_size=max_transfer_size; + else + params->max_transfer_size=default_param_max_transfer_size; + + if(max_packet_count>=15 && max_packet_count<=511) + params->max_packet_count=max_packet_count; + else + params->max_packet_count=default_param_max_packet_count; + + switch(phy_utmi_width) + { + case 8: + case 16: + params->phy_utmi_width=phy_utmi_width; + break; + default: + params->phy_utmi_width=default_param_phy_utmi_width; + } + + if(turn_around_time_hs>=0 && turn_around_time_hs<=7) + params->turn_around_time_hs=turn_around_time_hs; + else + params->turn_around_time_hs=default_param_turn_around_time_hs; + + if(turn_around_time_fs>=0 && turn_around_time_fs<=7) + params->turn_around_time_fs=turn_around_time_fs; + else + params->turn_around_time_fs=default_param_turn_around_time_fs; + + if(timeout_cal_hs>=0 && timeout_cal_hs<=7) + params->timeout_cal_hs=timeout_cal_hs; + else + params->timeout_cal_hs=default_param_timeout_cal_hs; + + if(timeout_cal_fs>=0 && timeout_cal_fs<=7) + params->timeout_cal_fs=timeout_cal_fs; + else + params->timeout_cal_fs=default_param_timeout_cal_fs; + + if(data_fifo_size>=32 && data_fifo_size<=32768) + params->data_fifo_size=data_fifo_size; + else + params->data_fifo_size=default_param_data_fifo_size; + + #ifdef __IS_HOST__ + if(host_channels>=1 && host_channels<=16) + params->host_channels=host_channels; + else + params->host_channels=default_param_host_channels; + + if(rx_fifo_size>=16 && rx_fifo_size<=32768) + params->rx_fifo_size=rx_fifo_size; + else + params->rx_fifo_size=default_param_rx_fifo_size; + + if(nperio_tx_fifo_size>=16 && nperio_tx_fifo_size<=32768) + params->nperio_tx_fifo_size=nperio_tx_fifo_size; + else + params->nperio_tx_fifo_size=default_param_nperio_tx_fifo_size; + + if(perio_tx_fifo_size>=16 && perio_tx_fifo_size<=32768) + params->perio_tx_fifo_size=perio_tx_fifo_size; + else + params->perio_tx_fifo_size=default_param_perio_tx_fifo_size; + #endif //__IS_HOST__ + + #ifdef __IS_DEVICE__ + if(rx_fifo_size>=16 && rx_fifo_size<=32768) + params->rx_fifo_size=rx_fifo_size; + else + params->rx_fifo_size=default_param_rx_fifo_size; + #ifdef __DED_FIFO__ + if(tx_fifo_size_00>=16 && tx_fifo_size_00<=32768) + params->tx_fifo_size[ 0]=tx_fifo_size_00; + else + params->tx_fifo_size[ 0]=default_param_tx_fifo_size_00; + if(tx_fifo_size_01>=0 && tx_fifo_size_01<=32768) + params->tx_fifo_size[ 1]=tx_fifo_size_01; + else + params->tx_fifo_size[ 1]=default_param_tx_fifo_size_01; + if(tx_fifo_size_02>=0 && tx_fifo_size_02<=32768) + params->tx_fifo_size[ 2]=tx_fifo_size_02; + else + params->tx_fifo_size[ 2]=default_param_tx_fifo_size_02; + if(tx_fifo_size_03>=0 && tx_fifo_size_03<=32768) + params->tx_fifo_size[ 3]=tx_fifo_size_03; + else + params->tx_fifo_size[ 3]=default_param_tx_fifo_size_03; + if(tx_fifo_size_04>=0 && tx_fifo_size_04<=32768) + params->tx_fifo_size[ 4]=tx_fifo_size_04; + else + params->tx_fifo_size[ 4]=default_param_tx_fifo_size_04; + if(tx_fifo_size_05>=0 && tx_fifo_size_05<=32768) + params->tx_fifo_size[ 5]=tx_fifo_size_05; + else + params->tx_fifo_size[ 5]=default_param_tx_fifo_size_05; + if(tx_fifo_size_06>=0 && tx_fifo_size_06<=32768) + params->tx_fifo_size[ 6]=tx_fifo_size_06; + else + params->tx_fifo_size[ 6]=default_param_tx_fifo_size_06; + if(tx_fifo_size_07>=0 && tx_fifo_size_07<=32768) + params->tx_fifo_size[ 7]=tx_fifo_size_07; + else + params->tx_fifo_size[ 7]=default_param_tx_fifo_size_07; + if(tx_fifo_size_08>=0 && tx_fifo_size_08<=32768) + params->tx_fifo_size[ 8]=tx_fifo_size_08; + else + params->tx_fifo_size[ 8]=default_param_tx_fifo_size_08; + if(tx_fifo_size_09>=0 && tx_fifo_size_09<=32768) + params->tx_fifo_size[ 9]=tx_fifo_size_09; + else + params->tx_fifo_size[ 9]=default_param_tx_fifo_size_09; + if(tx_fifo_size_10>=0 && tx_fifo_size_10<=32768) + params->tx_fifo_size[10]=tx_fifo_size_10; + else + params->tx_fifo_size[10]=default_param_tx_fifo_size_10; + if(tx_fifo_size_11>=0 && tx_fifo_size_11<=32768) + params->tx_fifo_size[11]=tx_fifo_size_11; + else + params->tx_fifo_size[11]=default_param_tx_fifo_size_11; + if(tx_fifo_size_12>=0 && tx_fifo_size_12<=32768) + params->tx_fifo_size[12]=tx_fifo_size_12; + else + params->tx_fifo_size[12]=default_param_tx_fifo_size_12; + if(tx_fifo_size_13>=0 && tx_fifo_size_13<=32768) + params->tx_fifo_size[13]=tx_fifo_size_13; + else + params->tx_fifo_size[13]=default_param_tx_fifo_size_13; + if(tx_fifo_size_14>=0 && tx_fifo_size_14<=32768) + params->tx_fifo_size[14]=tx_fifo_size_14; + else + params->tx_fifo_size[14]=default_param_tx_fifo_size_14; + if(tx_fifo_size_15>=0 && tx_fifo_size_15<=32768) + params->tx_fifo_size[15]=tx_fifo_size_15; + else + params->tx_fifo_size[15]=default_param_tx_fifo_size_15; + if(thr_ctl==0 || thr_ctl==1) + params->thr_ctl=thr_ctl; + else + params->thr_ctl=default_param_thr_ctl; + if(tx_thr_length>=16 && tx_thr_length<=511) + params->tx_thr_length=tx_thr_length; + else + params->tx_thr_length=default_param_tx_thr_length; + if(rx_thr_length>=16 && rx_thr_length<=511) + params->rx_thr_length=rx_thr_length; + else + params->rx_thr_length=default_param_rx_thr_length; + #else //__DED_FIFO__ + if(nperio_tx_fifo_size>=16 && nperio_tx_fifo_size<=32768) + params->tx_fifo_size[ 0]=nperio_tx_fifo_size; + else + params->tx_fifo_size[ 0]=default_param_nperio_tx_fifo_size; + if(perio_tx_fifo_size_01>=0 && perio_tx_fifo_size_01<=32768) + params->tx_fifo_size[ 1]=perio_tx_fifo_size_01; + else + params->tx_fifo_size[ 1]=default_param_perio_tx_fifo_size_01; + if(perio_tx_fifo_size_02>=0 && perio_tx_fifo_size_02<=32768) + params->tx_fifo_size[ 2]=perio_tx_fifo_size_02; + else + params->tx_fifo_size[ 2]=default_param_perio_tx_fifo_size_02; + if(perio_tx_fifo_size_03>=0 && perio_tx_fifo_size_03<=32768) + params->tx_fifo_size[ 3]=perio_tx_fifo_size_03; + else + params->tx_fifo_size[ 3]=default_param_perio_tx_fifo_size_03; + if(perio_tx_fifo_size_04>=0 && perio_tx_fifo_size_04<=32768) + params->tx_fifo_size[ 4]=perio_tx_fifo_size_04; + else + params->tx_fifo_size[ 4]=default_param_perio_tx_fifo_size_04; + if(perio_tx_fifo_size_05>=0 && perio_tx_fifo_size_05<=32768) + params->tx_fifo_size[ 5]=perio_tx_fifo_size_05; + else + params->tx_fifo_size[ 5]=default_param_perio_tx_fifo_size_05; + if(perio_tx_fifo_size_06>=0 && perio_tx_fifo_size_06<=32768) + params->tx_fifo_size[ 6]=perio_tx_fifo_size_06; + else + params->tx_fifo_size[ 6]=default_param_perio_tx_fifo_size_06; + if(perio_tx_fifo_size_07>=0 && perio_tx_fifo_size_07<=32768) + params->tx_fifo_size[ 7]=perio_tx_fifo_size_07; + else + params->tx_fifo_size[ 7]=default_param_perio_tx_fifo_size_07; + if(perio_tx_fifo_size_08>=0 && perio_tx_fifo_size_08<=32768) + params->tx_fifo_size[ 8]=perio_tx_fifo_size_08; + else + params->tx_fifo_size[ 8]=default_param_perio_tx_fifo_size_08; + if(perio_tx_fifo_size_09>=0 && perio_tx_fifo_size_09<=32768) + params->tx_fifo_size[ 9]=perio_tx_fifo_size_09; + else + params->tx_fifo_size[ 9]=default_param_perio_tx_fifo_size_09; + if(perio_tx_fifo_size_10>=0 && perio_tx_fifo_size_10<=32768) + params->tx_fifo_size[10]=perio_tx_fifo_size_10; + else + params->tx_fifo_size[10]=default_param_perio_tx_fifo_size_10; + if(perio_tx_fifo_size_11>=0 && perio_tx_fifo_size_11<=32768) + params->tx_fifo_size[11]=perio_tx_fifo_size_11; + else + params->tx_fifo_size[11]=default_param_perio_tx_fifo_size_11; + if(perio_tx_fifo_size_12>=0 && perio_tx_fifo_size_12<=32768) + params->tx_fifo_size[12]=perio_tx_fifo_size_12; + else + params->tx_fifo_size[12]=default_param_perio_tx_fifo_size_12; + if(perio_tx_fifo_size_13>=0 && perio_tx_fifo_size_13<=32768) + params->tx_fifo_size[13]=perio_tx_fifo_size_13; + else + params->tx_fifo_size[13]=default_param_perio_tx_fifo_size_13; + if(perio_tx_fifo_size_14>=0 && perio_tx_fifo_size_14<=32768) + params->tx_fifo_size[14]=perio_tx_fifo_size_14; + else + params->tx_fifo_size[14]=default_param_perio_tx_fifo_size_14; + if(perio_tx_fifo_size_15>=0 && perio_tx_fifo_size_15<=32768) + params->tx_fifo_size[15]=perio_tx_fifo_size_15; + else + params->tx_fifo_size[15]=default_param_perio_tx_fifo_size_15; + #endif //__DED_FIFO__ + #endif //__IS_DEVICE__ +} + + + + + + + +module_param(dbg_lvl, long, 0444); +MODULE_PARM_DESC(dbg_lvl, "Debug level."); + +module_param(dma_burst_size, short, 0444); +MODULE_PARM_DESC(dma_burst_size, "DMA Burst Size 0, 1, 4, 8, 16"); + +module_param(speed, short, 0444); +MODULE_PARM_DESC(speed, "Speed 0=High Speed 1=Full Speed"); + +module_param(data_fifo_size, long, 0444); +MODULE_PARM_DESC(data_fifo_size, "Total number of words in the data FIFO memory 32-32768"); + +#ifdef __IS_DEVICE__ + module_param(rx_fifo_size, long, 0444); + MODULE_PARM_DESC(rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); + + #ifdef __DED_FIFO__ + module_param(tx_fifo_size_00, long, 0444); + MODULE_PARM_DESC(tx_fifo_size_00, "Number of words in the Tx FIFO #00 16-32768"); + module_param(tx_fifo_size_01, long, 0444); + MODULE_PARM_DESC(tx_fifo_size_01, "Number of words in the Tx FIFO #01 0-32768"); + module_param(tx_fifo_size_02, long, 0444); + MODULE_PARM_DESC(tx_fifo_size_02, "Number of words in the Tx FIFO #02 0-32768"); + module_param(tx_fifo_size_03, long, 0444); + MODULE_PARM_DESC(tx_fifo_size_03, "Number of words in the Tx FIFO #03 0-32768"); + module_param(tx_fifo_size_04, long, 0444); + MODULE_PARM_DESC(tx_fifo_size_04, "Number of words in the Tx FIFO #04 0-32768"); + module_param(tx_fifo_size_05, long, 0444); + MODULE_PARM_DESC(tx_fifo_size_05, "Number of words in the Tx FIFO #05 0-32768"); + module_param(tx_fifo_size_06, long, 0444); + MODULE_PARM_DESC(tx_fifo_size_06, "Number of words in the Tx FIFO #06 0-32768"); + module_param(tx_fifo_size_07, long, 0444); + MODULE_PARM_DESC(tx_fifo_size_07, "Number of words in the Tx FIFO #07 0-32768"); + module_param(tx_fifo_size_08, long, 0444); + MODULE_PARM_DESC(tx_fifo_size_08, "Number of words in the Tx FIFO #08 0-32768"); + module_param(tx_fifo_size_09, long, 0444); + MODULE_PARM_DESC(tx_fifo_size_09, "Number of words in the Tx FIFO #09 0-32768"); + module_param(tx_fifo_size_10, long, 0444); + MODULE_PARM_DESC(tx_fifo_size_10, "Number of words in the Tx FIFO #10 0-32768"); + module_param(tx_fifo_size_11, long, 0444); + MODULE_PARM_DESC(tx_fifo_size_11, "Number of words in the Tx FIFO #11 0-32768"); + module_param(tx_fifo_size_12, long, 0444); + MODULE_PARM_DESC(tx_fifo_size_12, "Number of words in the Tx FIFO #12 0-32768"); + module_param(tx_fifo_size_13, long, 0444); + MODULE_PARM_DESC(tx_fifo_size_13, "Number of words in the Tx FIFO #13 0-32768"); + module_param(tx_fifo_size_14, long, 0444); + MODULE_PARM_DESC(tx_fifo_size_14, "Number of words in the Tx FIFO #14 0-32768"); + module_param(tx_fifo_size_15, long, 0444); + MODULE_PARM_DESC(tx_fifo_size_15, "Number of words in the Tx FIFO #15 0-32768"); + + module_param(thr_ctl, short, 0444); + MODULE_PARM_DESC(thr_ctl, "0=Without 1=With Theshold Ctrl"); + + module_param(tx_thr_length, long, 0444); + MODULE_PARM_DESC(tx_thr_length, "TX Threshold length"); + + module_param(rx_thr_length, long, 0444); + MODULE_PARM_DESC(rx_thr_length, "RX Threshold length"); + + #else + module_param(nperio_tx_fifo_size, long, 0444); + MODULE_PARM_DESC(nperio_tx_fifo_size, "Number of words in the non-periodic Tx FIFO 16-32768"); + + module_param(perio_tx_fifo_size_01, long, 0444); + MODULE_PARM_DESC(perio_tx_fifo_size_01, "Number of words in the periodic Tx FIFO #01 0-32768"); + module_param(perio_tx_fifo_size_02, long, 0444); + MODULE_PARM_DESC(perio_tx_fifo_size_02, "Number of words in the periodic Tx FIFO #02 0-32768"); + module_param(perio_tx_fifo_size_03, long, 0444); + MODULE_PARM_DESC(perio_tx_fifo_size_03, "Number of words in the periodic Tx FIFO #03 0-32768"); + module_param(perio_tx_fifo_size_04, long, 0444); + MODULE_PARM_DESC(perio_tx_fifo_size_04, "Number of words in the periodic Tx FIFO #04 0-32768"); + module_param(perio_tx_fifo_size_05, long, 0444); + MODULE_PARM_DESC(perio_tx_fifo_size_05, "Number of words in the periodic Tx FIFO #05 0-32768"); + module_param(perio_tx_fifo_size_06, long, 0444); + MODULE_PARM_DESC(perio_tx_fifo_size_06, "Number of words in the periodic Tx FIFO #06 0-32768"); + module_param(perio_tx_fifo_size_07, long, 0444); + MODULE_PARM_DESC(perio_tx_fifo_size_07, "Number of words in the periodic Tx FIFO #07 0-32768"); + module_param(perio_tx_fifo_size_08, long, 0444); + MODULE_PARM_DESC(perio_tx_fifo_size_08, "Number of words in the periodic Tx FIFO #08 0-32768"); + module_param(perio_tx_fifo_size_09, long, 0444); + MODULE_PARM_DESC(perio_tx_fifo_size_09, "Number of words in the periodic Tx FIFO #09 0-32768"); + module_param(perio_tx_fifo_size_10, long, 0444); + MODULE_PARM_DESC(perio_tx_fifo_size_10, "Number of words in the periodic Tx FIFO #10 0-32768"); + module_param(perio_tx_fifo_size_11, long, 0444); + MODULE_PARM_DESC(perio_tx_fifo_size_11, "Number of words in the periodic Tx FIFO #11 0-32768"); + module_param(perio_tx_fifo_size_12, long, 0444); + MODULE_PARM_DESC(perio_tx_fifo_size_12, "Number of words in the periodic Tx FIFO #12 0-32768"); + module_param(perio_tx_fifo_size_13, long, 0444); + MODULE_PARM_DESC(perio_tx_fifo_size_13, "Number of words in the periodic Tx FIFO #13 0-32768"); + module_param(perio_tx_fifo_size_14, long, 0444); + MODULE_PARM_DESC(perio_tx_fifo_size_14, "Number of words in the periodic Tx FIFO #14 0-32768"); + module_param(perio_tx_fifo_size_15, long, 0444); + MODULE_PARM_DESC(perio_tx_fifo_size_15, "Number of words in the periodic Tx FIFO #15 0-32768"); + #endif//__DED_FIFO__ + module_param(dev_endpoints, short, 0444); + MODULE_PARM_DESC(dev_endpoints, "The number of endpoints in addition to EP0 available for device mode 1-15"); +#endif + +#ifdef __IS_HOST__ + module_param(rx_fifo_size, long, 0444); + MODULE_PARM_DESC(rx_fifo_size, "Number of words in the Rx FIFO 16-32768"); + + module_param(nperio_tx_fifo_size, long, 0444); + MODULE_PARM_DESC(nperio_tx_fifo_size, "Number of words in the non-periodic Tx FIFO 16-32768"); + + module_param(perio_tx_fifo_size, long, 0444); + MODULE_PARM_DESC(perio_tx_fifo_size, "Number of words in the host periodic Tx FIFO 16-32768"); + + module_param(host_channels, short, 0444); + MODULE_PARM_DESC(host_channels, "The number of host channel registers to use 1-16"); +#endif + +module_param(max_transfer_size, long, 0444); +MODULE_PARM_DESC(max_transfer_size, "The maximum transfer size supported in bytes 2047-65535"); + +module_param(max_packet_count, long, 0444); +MODULE_PARM_DESC(max_packet_count, "The maximum number of packets in a transfer 15-511"); + +module_param(phy_utmi_width, long, 0444); +MODULE_PARM_DESC(phy_utmi_width, "Specifies the UTMI+ Data Width 8 or 16 bits"); + +module_param(turn_around_time_hs, long, 0444); +MODULE_PARM_DESC(turn_around_time_hs, "Turn-Around time for HS"); + +module_param(turn_around_time_fs, long, 0444); +MODULE_PARM_DESC(turn_around_time_fs, "Turn-Around time for FS"); + +module_param(timeout_cal_hs, long, 0444); +MODULE_PARM_DESC(timeout_cal_hs, "Timeout Cal for HS"); + +module_param(timeout_cal_fs, long, 0444); +MODULE_PARM_DESC(timeout_cal_fs, "Timeout Cal for FS"); + diff --git a/package/platform/lantiq/ltq-hcd/src/ifxusb_host.ko b/package/platform/lantiq/ltq-hcd/src/ifxusb_host.ko new file mode 100644 index 0000000000000000000000000000000000000000..1dd25ca0d6f6e80006f5d4e9dbd606c16b6e97b2 GIT binary patch literal 181257 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 +#include +#include +#include +#include + + +#define IFXUSB_IOMEM_SIZE 0x00001000 +#define IFXUSB_FIFOMEM_SIZE 0x00010000 +#define IFXUSB_FIFODBG_SIZE 0x00020000 + + + +/*! + \addtogroup IFXUSB_PLATEFORM_MEM_ADDR + */ +/*@{*/ +#if defined(__UEIP__) + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #define IFXUSB_IRQ 62 + #define IFXUSB_IOMEM_BASE 0x1e101000 + #define IFXUSB_FIFOMEM_BASE 0x1e120000 + #define IFXUSB_FIFODBG_BASE 0x1e140000 + #define IFXUSB_OC_IRQ 159 + + #ifndef DANUBE_RCU_BASE_ADDR + #define DANUBE_RCU_BASE_ADDR (0xBF203000) + #endif + + #ifndef DANUBE_CGU + #define DANUBE_CGU (0xBF103000) + #endif + #ifndef DANUBE_CGU_IFCCR + #define DANUBE_CGU_IFCCR ((volatile unsigned long *)(DANUBE_CGU+ 0x0018)) + #endif + #ifndef DANUBE_PMU + #define DANUBE_PMU (KSEG1+0x1F102000) + #endif + #ifndef DANUBE_PMU_PWDCR + #define DANUBE_PMU_PWDCR ((volatile unsigned long *)(DANUBE_PMU+0x001C)) + #endif + + #ifndef DANUBE_GPIO_P0_OUT + #define DANUBE_GPIO_P0_OUT (0xBF103000+0x10) + #define DANUBE_GPIO_P0_DIR (0xBF103000+0x18) + #define DANUBE_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) + #define DANUBE_GPIO_P0_ALTSEL1 (0xBF103000+0x20) + #define DANUBE_GPIO_P0_OD (0xBF103000+0x24) + #define DANUBE_GPIO_P0_PUDSEL (0xBF103000+0x2C) + #define DANUBE_GPIO_P0_PUDEN (0xBF103000+0x30) + #define DANUBE_GPIO_P1_OUT (0xBF103000+0x40) + #define DANUBE_GPIO_P1_DIR (0xBF103000+0x48) + #define DANUBE_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) + #define DANUBE_GPIO_P1_ALTSEL1 (0xBF103000+0x50) + #define DANUBE_GPIO_P1_OD (0xBF103000+0x54) + #define DANUBE_GPIO_P1_PUDSEL (0xBF103000+0x5C) + #define DANUBE_GPIO_P1_PUDEN (0xBF103000+0x60) + #endif + + #define DANUBE_RCU_USBCFG ((volatile unsigned long *)(DANUBE_RCU_BASE_ADDR + 0x18)) + #define DANUBE_RCU_RESET ((volatile unsigned long *)(DANUBE_RCU_BASE_ADDR + 0x10)) + #define DANUBE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device + #define DANUBE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end + #define DANUBE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end + + #define default_param_dma_burst_size 4 + + #define default_param_speed IFXUSB_PARAM_SPEED_HIGH + + #define default_param_max_transfer_size -1 //(Max, hwcfg) + #define default_param_max_packet_count -1 //(Max, hwcfg) + #define default_param_phy_utmi_width 16 + + #define default_param_turn_around_time_hs 4 + #define default_param_turn_around_time_fs 4 + #define default_param_timeout_cal_hs -1 //(NoChange) + #define default_param_timeout_cal_fs -1 //(NoChange) + + #define default_param_data_fifo_size -1 //(Max, hwcfg) + + #ifdef __IS_HOST__ + #define default_param_host_channels -1 //(Max, hwcfg) + #define default_param_rx_fifo_size 640 + #define default_param_nperio_tx_fifo_size 640 + #define default_param_perio_tx_fifo_size 768 + #endif //__IS_HOST__ + + #ifdef __IS_DEVICE__ + #ifdef __DED_INTR__ +// #define default_param_rx_fifo_size 1024 +// #define default_param_nperio_tx_fifo_size 1016 +// #define default_param_perio_tx_fifo_size_01 8 + #define default_param_rx_fifo_size 1008 + #define default_param_nperio_tx_fifo_size 1008 + #define default_param_perio_tx_fifo_size_01 32 + #else + #define default_param_rx_fifo_size 1024 + #define default_param_nperio_tx_fifo_size 1024 + #define default_param_perio_tx_fifo_size_01 0 + #endif + #define default_param_perio_tx_fifo_size_02 0 + #define default_param_perio_tx_fifo_size_03 0 + #define default_param_perio_tx_fifo_size_04 0 + #define default_param_perio_tx_fifo_size_05 0 + #define default_param_perio_tx_fifo_size_06 0 + #define default_param_perio_tx_fifo_size_07 0 + #define default_param_perio_tx_fifo_size_08 0 + #define default_param_perio_tx_fifo_size_09 0 + #define default_param_perio_tx_fifo_size_10 0 + #define default_param_perio_tx_fifo_size_11 0 + #define default_param_perio_tx_fifo_size_12 0 + #define default_param_perio_tx_fifo_size_13 0 + #define default_param_perio_tx_fifo_size_14 0 + #define default_param_perio_tx_fifo_size_15 0 + #endif //__IS_DEVICE__ + + #elif defined(__IS_AMAZON_SE__) + //#include + //#include + + #define IFXUSB_IRQ 39 + #define IFXUSB_IOMEM_BASE 0x1e101000 + #define IFXUSB_FIFOMEM_BASE 0x1e120000 + #define IFXUSB_FIFODBG_BASE 0x1e140000 + #define IFXUSB_OC_IRQ 20 + + #ifndef AMAZON_SE_RCU_BASE_ADDR + #define AMAZON_SE_RCU_BASE_ADDR (0xBF203000) + #endif + #define AMAZON_SE_RCU_USBCFG ((volatile unsigned long *)(AMAZON_SE_RCU_BASE_ADDR + 0x18)) + #define AMAZON_SE_RCU_RESET ((volatile unsigned long *)(AMAZON_SE_RCU_BASE_ADDR + 0x10)) + #define AMAZON_SE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device + #define AMAZON_SE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end + #define AMAZON_SE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end + + #ifndef AMAZON_SE_GPIO_P0_OUT + #define AMAZON_SE_GPIO_P0_OUT (0xBF103000+0x10) + #define AMAZON_SE_GPIO_P0_DIR (0xBF103000+0x18) + #define AMAZON_SE_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) + #define AMAZON_SE_GPIO_P0_ALTSEL1 (0xBF103000+0x20) + #define AMAZON_SE_GPIO_P0_OD (0xBF103000+0x24) + #define AMAZON_SE_GPIO_P0_PUDSEL (0xBF103000+0x2C) + #define AMAZON_SE_GPIO_P0_PUDEN (0xBF103000+0x30) + #define AMAZON_SE_GPIO_P1_OUT (0xBF103000+0x40) + #define AMAZON_SE_GPIO_P1_DIR (0xBF103000+0x48) + #define AMAZON_SE_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) + #define AMAZON_SE_GPIO_P1_ALTSEL1 (0xBF103000+0x50) + #define AMAZON_SE_GPIO_P1_OD (0xBF103000+0x54) + #define AMAZON_SE_GPIO_P1_PUDSEL (0xBF103000+0x5C) + #define AMAZON_SE_GPIO_P1_PUDEN (0xBF103000+0x60) + #endif + + #ifndef AMAZON_SE_CGU + #define AMAZON_SE_CGU (0xBF103000) + #endif + #ifndef AMAZON_SE_CGU_IFCCR + #define AMAZON_SE_CGU_IFCCR ((volatile unsigned long *)(AMAZON_SE_CGU+ 0x0018)) + #endif + #ifndef AMAZON_SE_PMU + #define AMAZON_SE_PMU (KSEG1+0x1F102000) + #endif + #ifndef AMAZON_SE_PMU_PWDCR + #define AMAZON_SE_PMU_PWDCR ((volatile unsigned long *)(AMAZON_SE_PMU+0x001C)) + #endif + + #define default_param_dma_burst_size 4 + + #define default_param_speed IFXUSB_PARAM_SPEED_HIGH + + #define default_param_max_transfer_size -1 //(Max, hwcfg) + #define default_param_max_packet_count -1 //(Max, hwcfg) + #define default_param_phy_utmi_width 16 + + #define default_param_turn_around_time_hs 4 //(NoChange) + #define default_param_turn_around_time_fs 4 //(NoChange) + #define default_param_timeout_cal_hs -1 //(NoChange) + #define default_param_timeout_cal_fs -1 //(NoChange) + + #define default_param_data_fifo_size -1 //(Max, hwcfg) + + #ifdef __IS_HOST__ + #define default_param_host_channels -1 //(Max, hwcfg) + #define default_param_rx_fifo_size 240 + #define default_param_nperio_tx_fifo_size 240 + #define default_param_perio_tx_fifo_size 32 + #endif //__IS_HOST__ + #ifdef __IS_DEVICE__ + #ifdef __DED_INTR__ +// #define default_param_rx_fifo_size 256 +// #define default_param_nperio_tx_fifo_size 248 +// #define default_param_perio_tx_fifo_size_01 8 + #define default_param_rx_fifo_size 240 + #define default_param_nperio_tx_fifo_size 240 + #define default_param_perio_tx_fifo_size_01 32 + #else + #define default_param_rx_fifo_size 256 + #define default_param_nperio_tx_fifo_size 256 + #define default_param_perio_tx_fifo_size_01 0 + #endif + #define default_param_perio_tx_fifo_size_02 0 + #define default_param_perio_tx_fifo_size_03 0 + #define default_param_perio_tx_fifo_size_04 0 + #define default_param_perio_tx_fifo_size_05 0 + #define default_param_perio_tx_fifo_size_06 0 + #define default_param_perio_tx_fifo_size_07 0 + #define default_param_perio_tx_fifo_size_08 0 + #define default_param_perio_tx_fifo_size_09 0 + #define default_param_perio_tx_fifo_size_10 0 + #define default_param_perio_tx_fifo_size_11 0 + #define default_param_perio_tx_fifo_size_12 0 + #define default_param_perio_tx_fifo_size_13 0 + #define default_param_perio_tx_fifo_size_14 0 + #define default_param_perio_tx_fifo_size_15 0 + #endif //__IS_DEVICE__ + + #elif defined(__IS_AR9__) + #define IFXUSB1_IRQ 62 + #define IFXUSB1_IOMEM_BASE 0x1E101000 + #define IFXUSB1_FIFOMEM_BASE 0x1E120000 + #define IFXUSB1_FIFODBG_BASE 0x1E140000 + + #define IFXUSB2_IRQ 91 + #define IFXUSB2_IOMEM_BASE 0x1E106000 + #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 + #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 + + #define IFXUSB_OC_IRQ 68 + + #ifndef AR9_RCU_BASE_ADDR + #define AR9_RCU_BASE_ADDR (0xBF203000) + #endif + + #ifndef AR9_CGU + #define AR9_CGU (0xBF103000) + #endif + #ifndef AR9_CGU_IFCCR + #define AR9_CGU_IFCCR ((volatile unsigned long *)(AR9_CGU+ 0x0018)) + #endif + + #ifndef AR9_PMU + #define AR9_PMU (KSEG1+0x1F102000) + #endif + #ifndef AR9_PMU_PWDCR + #define AR9_PMU_PWDCR ((volatile unsigned long *)(AR9_PMU+0x001C)) + #endif + + #ifndef AR9_GPIO_P0_OUT + #define AR9_GPIO_P0_OUT (0xBF103000+0x10) + #define AR9_GPIO_P0_DIR (0xBF103000+0x18) + #define AR9_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) + #define AR9_GPIO_P0_ALTSEL1 (0xBF103000+0x20) + #define AR9_GPIO_P0_OD (0xBF103000+0x24) + #define AR9_GPIO_P0_PUDSEL (0xBF103000+0x2C) + #define AR9_GPIO_P0_PUDEN (0xBF103000+0x30) + #define AR9_GPIO_P1_OUT (0xBF103000+0x40) + #define AR9_GPIO_P1_DIR (0xBF103000+0x48) + #define AR9_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) + #define AR9_GPIO_P1_ALTSEL1 (0xBF103000+0x50) + #define AR9_GPIO_P1_OD (0xBF103000+0x54) + #define AR9_GPIO_P1_PUDSEL (0xBF103000+0x5C) + #define AR9_GPIO_P1_PUDEN (0xBF103000+0x60) + #endif + + #define AR9_RCU_USB1CFG ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x18)) + #define AR9_RCU_USB2CFG ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x34)) + #define AR9_RCU_USBRESET ((volatile unsigned long *)(AR9_RCU_BASE_ADDR + 0x10)) + #define AR9_USBCFG_ARB 7 // + #define AR9_USBCFG_HDSEL_BIT 11 // 0:host, 1:device + #define AR9_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end + #define AR9_USBCFG_SLV_END_BIT 17 // 0:little_end, 1:big_end + + #define default_param_dma_burst_size 4 + + #define default_param_speed IFXUSB_PARAM_SPEED_HIGH + + #define default_param_max_transfer_size -1 //(Max, hwcfg) + #define default_param_max_packet_count -1 //(Max, hwcfg) + #define default_param_phy_utmi_width 16 + + #define default_param_turn_around_time_hs 4 //(NoChange) + #define default_param_turn_around_time_fs 4 //(NoChange) + #define default_param_timeout_cal_hs -1 //(NoChange) + #define default_param_timeout_cal_fs -1 //(NoChange) + + #define default_param_data_fifo_size -1 //(Max, hwcfg) + + #ifdef __IS_HOST__ + #define default_param_host_channels -1 //(Max, hwcfg) + #define default_param_rx_fifo_size 240 + #define default_param_nperio_tx_fifo_size 240 + #define default_param_perio_tx_fifo_size 32 + #endif //__IS_HOST__ + #ifdef __IS_DEVICE__ + #ifdef __DED_INTR__ +// #define default_param_rx_fifo_size 256 +// #define default_param_nperio_tx_fifo_size 248 +// #define default_param_perio_tx_fifo_size_01 8 + #define default_param_rx_fifo_size 240 + #define default_param_nperio_tx_fifo_size 240 + #define default_param_perio_tx_fifo_size_01 32 + #else + #define default_param_rx_fifo_size 256 + #define default_param_nperio_tx_fifo_size 256 + #define default_param_perio_tx_fifo_size_01 0 + #endif + #define default_param_perio_tx_fifo_size_02 0 + #define default_param_perio_tx_fifo_size_03 0 + #define default_param_perio_tx_fifo_size_04 0 + #define default_param_perio_tx_fifo_size_05 0 + #define default_param_perio_tx_fifo_size_06 0 + #define default_param_perio_tx_fifo_size_07 0 + #define default_param_perio_tx_fifo_size_08 0 + #define default_param_perio_tx_fifo_size_09 0 + #define default_param_perio_tx_fifo_size_10 0 + #define default_param_perio_tx_fifo_size_11 0 + #define default_param_perio_tx_fifo_size_12 0 + #define default_param_perio_tx_fifo_size_13 0 + #define default_param_perio_tx_fifo_size_14 0 + #define default_param_perio_tx_fifo_size_15 0 + #endif //__IS_DEVICE__ + + #elif defined(__IS_VR9__) + #define IFXUSB1_IRQ 62 + #define IFXUSB1_IOMEM_BASE 0x1E101000 + #define IFXUSB1_FIFOMEM_BASE 0x1E120000 + #define IFXUSB1_FIFODBG_BASE 0x1E140000 + + #define IFXUSB2_IRQ 91 + #define IFXUSB2_IOMEM_BASE 0x1E106000 + #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 + #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 + #define IFXUSB_OC_IRQ 60 + + #ifndef IFX_MPS + #define IFX_MPS (KSEG1+0x1F107000) + #endif + #ifndef IFX_MPS_CHIPID + #define IFX_MPS_CHIPID ((volatile unsigned long *)(IFX_MPS + 0x0344)) + #endif + + #ifndef VR9_RCU_BASE_ADDR + #define VR9_RCU_BASE_ADDR (0xBF203000) + #endif + + #ifndef VR9_CGU + #define VR9_CGU (0xBF103000) + #endif + #ifndef VR9_CGU_IFCCR + #define VR9_CGU_IFCCR ((volatile unsigned long *)(VR9_CGU+ 0x0018)) + #endif + + #ifndef VR9_PMU + #define VR9_PMU (KSEG1+0x1F102000) + #endif + #ifndef VR9_PMU_PWDCR + #define VR9_PMU_PWDCR ((volatile unsigned long *)(VR9_PMU+0x001C)) + #endif + + #ifndef VR9_GPIO_P0_OUT + #define VR9_GPIO_P0_OUT (0xBF103000+0x10) + #define VR9_GPIO_P0_DIR (0xBF103000+0x18) + #define VR9_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) + #define VR9_GPIO_P0_ALTSEL1 (0xBF103000+0x20) + #define VR9_GPIO_P0_OD (0xBF103000+0x24) + #define VR9_GPIO_P0_PUDSEL (0xBF103000+0x2C) + #define VR9_GPIO_P0_PUDEN (0xBF103000+0x30) + #define VR9_GPIO_P1_OUT (0xBF103000+0x40) + #define VR9_GPIO_P1_DIR (0xBF103000+0x48) + #define VR9_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) + #define VR9_GPIO_P1_ALTSEL1 (0xBF103000+0x50) + #define VR9_GPIO_P1_OD (0xBF103000+0x54) + #define VR9_GPIO_P1_PUDSEL (0xBF103000+0x5C) + #define VR9_GPIO_P1_PUDEN (0xBF103000+0x60) + #endif + + #define VR9_RCU_USB1CFG ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x18)) + #define VR9_RCU_USB2CFG ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x34)) + #define VR9_RCU_USB_ANA_CFG1A ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x38)) + #define VR9_RCU_USB_ANA_CFG1B ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x3C)) + #define VR9_RCU_USBRESET ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x10)) + #define VR9_RCU_USBRESET2 ((volatile unsigned long *)(VR9_RCU_BASE_ADDR + 0x48)) + #define VR9_USBCFG_ARB 7 // + #define VR9_USBCFG_HDSEL_BIT 11 // 0:host, 1:device + #define VR9_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end + #define VR9_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end + +// #define default_param_dma_burst_size 4 //(ALL) + //WA for AHB + #define default_param_dma_burst_size 0 //(ALL) + #define default_param_dma_burst_size_n 4 //(ALL) + + #define default_param_speed IFXUSB_PARAM_SPEED_HIGH + + #define default_param_max_transfer_size -1 //(Max, hwcfg) + #define default_param_max_packet_count -1 //(Max, hwcfg) + #define default_param_phy_utmi_width 16 + + #define default_param_turn_around_time_hs 6 //(NoChange) snpsid >= 0x4f54260a + #define default_param_turn_around_time_fs 6 //(NoChange) snpsid >= 0x4f54260a + #define default_param_timeout_cal_hs -1 //(NoChange) + #define default_param_timeout_cal_fs -1 //(NoChange) + + #define default_param_data_fifo_size -1 //(Max, hwcfg) + + #ifdef __IS_HOST__ + #define default_param_host_channels -1 //(Max, hwcfg) + #define default_param_rx_fifo_size 240 + #define default_param_nperio_tx_fifo_size 240 + #define default_param_perio_tx_fifo_size 32 + #endif //__IS_HOST__ + #ifdef __IS_DEVICE__ +#if 0 + #define default_param_rx_fifo_size 256 + #define default_param_tx_fifo_size_00 -1 + #define default_param_tx_fifo_size_01 -1 + #define default_param_tx_fifo_size_02 -1 +#else + #define default_param_rx_fifo_size 256 + #define default_param_tx_fifo_size_00 32 + #define default_param_tx_fifo_size_01 200 + #define default_param_tx_fifo_size_02 8 +#endif + #define default_param_tx_fifo_size_03 -1 + #define default_param_tx_fifo_size_04 -1 + #define default_param_tx_fifo_size_05 -1 + #define default_param_tx_fifo_size_06 -1 + #define default_param_tx_fifo_size_07 -1 + #define default_param_tx_fifo_size_08 -1 + #define default_param_tx_fifo_size_09 -1 + #define default_param_tx_fifo_size_10 -1 + #define default_param_tx_fifo_size_11 -1 + #define default_param_tx_fifo_size_12 -1 + #define default_param_tx_fifo_size_13 -1 + #define default_param_tx_fifo_size_14 -1 + #define default_param_tx_fifo_size_15 -1 + #define default_param_dma_unalgned_tx -1 + #define default_param_dma_unalgned_rx -1 + #define default_param_thr_ctl -1 + #define default_param_tx_thr_length -1 + #define default_param_rx_thr_length -1 + #endif //__IS_DEVICE__ + + #elif defined(__IS_AR10__) + #define IFXUSB1_IRQ 54 + #define IFXUSB1_IOMEM_BASE 0x1E101000 + #define IFXUSB1_FIFOMEM_BASE 0x1E120000 + #define IFXUSB1_FIFODBG_BASE 0x1E140000 + #define IFXUSB1_OC_IRQ 60 + + #define IFXUSB2_IRQ 83 + #define IFXUSB2_IOMEM_BASE 0x1E106000 + #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 + #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 + #define IFXUSB2_OC_IRQ 56 + + #ifndef AR10_RCU_BASE_ADDR + #define AR10_RCU_BASE_ADDR (0xBF203000) + #endif + #ifndef AR10_CGU + #define AR10_CGU (0xBF103000) + #endif + + #ifndef AR10_CGU_IFCCR + #define AR10_CGU_IFCCR ((volatile unsigned long *)(AR10_CGU+ 0x0018)) + #endif + #ifndef AR10_PMU + #define AR10_PMU (KSEG1+0x1F102000) + #endif + #ifndef AR10_PMU_PWDCR + #define AR10_PMU_PWDCR ((volatile unsigned long *)(AR10_PMU+0x0044)) + #endif + + #ifndef AR10_GPIO_P0_OUT + #define AR10_GPIO_P0_OUT (0xBF103000+0x10) + #define AR10_GPIO_P0_DIR (0xBF103000+0x18) + #define AR10_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) + #define AR10_GPIO_P0_ALTSEL1 (0xBF103000+0x20) + #define AR10_GPIO_P0_OD (0xBF103000+0x24) + #define AR10_GPIO_P0_PUDSEL (0xBF103000+0x2C) + #define AR10_GPIO_P0_PUDEN (0xBF103000+0x30) + #define AR10_GPIO_P1_OUT (0xBF103000+0x40) + #define AR10_GPIO_P1_DIR (0xBF103000+0x48) + #define AR10_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) + #define AR10_GPIO_P1_ALTSEL1 (0xBF103000+0x50) + #define AR10_GPIO_P1_OD (0xBF103000+0x54) + #define AR10_GPIO_P1_PUDSEL (0xBF103000+0x5C) + #define AR10_GPIO_P1_PUDEN (0xBF103000+0x60) + #endif + + #define AR10_RCU_USB1CFG ((volatile unsigned long *)(AR10_RCU_BASE_ADDR + 0x18)) + #define AR10_RCU_USB2CFG ((volatile unsigned long *)(AR10_RCU_BASE_ADDR + 0x34)) + #define AR10_RCU_USB_ANA_CFG1A ((volatile unsigned long *)(AR10_RCU_BASE_ADDR + 0x38)) + #define AR10_RCU_USB_ANA_CFG1B ((volatile unsigned long *)(AR10_RCU_BASE_ADDR + 0x3C)) + + #define AR10_RCU_USBRESET ((volatile unsigned long *)(AR10_RCU_BASE_ADDR + 0x10)) + + #define AR10_USBCFG_ARB 7 // + #define AR10_USBCFG_HDSEL_BIT 11 // 0:host, 1:device + #define AR10_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end + #define AR10_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end + +// #define default_param_dma_burst_size 4 //(ALL) + //WA for AHB + #define default_param_dma_burst_size 0 //(ALL) + + #define default_param_speed IFXUSB_PARAM_SPEED_HIGH + + #define default_param_max_transfer_size -1 //(Max, hwcfg) + #define default_param_max_packet_count -1 //(Max, hwcfg) + #define default_param_phy_utmi_width 16 + + #define default_param_turn_around_time_hs 6 //(NoChange) snpsid >= 0x4f54260a + #define default_param_turn_around_time_fs 6 //(NoChange) snpsid >= 0x4f54260a + #define default_param_timeout_cal_hs -1 //(NoChange) + #define default_param_timeout_cal_fs -1 //(NoChange) + + #define default_param_data_fifo_size -1 //(Max, hwcfg) + + #ifdef __IS_HOST__ + #define default_param_host_channels -1 //(Max, hwcfg) + #define default_param_rx_fifo_size 240 + #define default_param_nperio_tx_fifo_size 240 + #define default_param_perio_tx_fifo_size 32 + #endif //__IS_HOST__ + #ifdef __IS_DEVICE__ +#if 0 + #define default_param_rx_fifo_size 256 + #define default_param_tx_fifo_size_00 -1 + #define default_param_tx_fifo_size_01 -1 + #define default_param_tx_fifo_size_02 -1 +#else + #define default_param_rx_fifo_size 256 + #define default_param_tx_fifo_size_00 32 + #define default_param_tx_fifo_size_01 200 + #define default_param_tx_fifo_size_02 8 +#endif + #define default_param_tx_fifo_size_03 -1 + #define default_param_tx_fifo_size_04 -1 + #define default_param_tx_fifo_size_05 -1 + #define default_param_tx_fifo_size_06 -1 + #define default_param_tx_fifo_size_07 -1 + #define default_param_tx_fifo_size_08 -1 + #define default_param_tx_fifo_size_09 -1 + #define default_param_tx_fifo_size_10 -1 + #define default_param_tx_fifo_size_11 -1 + #define default_param_tx_fifo_size_12 -1 + #define default_param_tx_fifo_size_13 -1 + #define default_param_tx_fifo_size_14 -1 + #define default_param_tx_fifo_size_15 -1 + #define default_param_dma_unalgned_tx -1 + #define default_param_dma_unalgned_rx -1 + #define default_param_thr_ctl -1 + #define default_param_tx_thr_length -1 + #define default_param_rx_thr_length -1 + #endif //__IS_DEVICE__ + #else // __IS_AR10__ + #error "Please choose one platform!!" + #endif // __IS_VR9__ + +#else //UEIP + #if defined(__IS_TWINPASS__) || defined(__IS_DANUBE__) + #define IFXUSB_IRQ 54 + #define IFXUSB_IOMEM_BASE 0x1e101000 + #define IFXUSB_FIFOMEM_BASE 0x1e120000 + #define IFXUSB_FIFODBG_BASE 0x1e140000 + #define IFXUSB_OC_IRQ 151 + + + #ifndef DANUBE_RCU_BASE_ADDR + #define DANUBE_RCU_BASE_ADDR (0xBF203000) + #endif + + #ifndef DANUBE_CGU + #define DANUBE_CGU (0xBF103000) + #endif + #ifndef DANUBE_CGU_IFCCR + #define DANUBE_CGU_IFCCR ((volatile unsigned long *)(DANUBE_CGU+ 0x0018)) + #endif + #ifndef DANUBE_PMU + #define DANUBE_PMU (KSEG1+0x1F102000) + #endif + #ifndef DANUBE_PMU_PWDCR + #define DANUBE_PMU_PWDCR ((volatile unsigned long *)(DANUBE_PMU+0x001C)) + #endif + + #ifndef DANUBE_GPIO_P0_OUT + #define DANUBE_GPIO_P0_OUT (0xBF103000+0x10) + #define DANUBE_GPIO_P0_DIR (0xBF103000+0x18) + #define DANUBE_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) + #define DANUBE_GPIO_P0_ALTSEL1 (0xBF103000+0x20) + #define DANUBE_GPIO_P0_OD (0xBF103000+0x24) + #define DANUBE_GPIO_P0_PUDSEL (0xBF103000+0x2C) + #define DANUBE_GPIO_P0_PUDEN (0xBF103000+0x30) + #define DANUBE_GPIO_P1_OUT (0xBF103000+0x40) + #define DANUBE_GPIO_P1_DIR (0xBF103000+0x48) + #define DANUBE_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) + #define DANUBE_GPIO_P1_ALTSEL1 (0xBF103000+0x50) + #define DANUBE_GPIO_P1_OD (0xBF103000+0x54) + #define DANUBE_GPIO_P1_PUDSEL (0xBF103000+0x5C) + #define DANUBE_GPIO_P1_PUDEN (0xBF103000+0x60) + #endif + + + #define DANUBE_RCU_USBCFG ((volatile unsigned long *)(DANUBE_RCU_BASE_ADDR + 0x18)) + #define DANUBE_RCU_RESET ((volatile unsigned long *)(DANUBE_RCU_BASE_ADDR + 0x10)) + #define DANUBE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device + #define DANUBE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end + #define DANUBE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end + + #define default_param_dma_burst_size 4 + + #define default_param_speed IFXUSB_PARAM_SPEED_HIGH + + #define default_param_max_transfer_size -1 //(Max, hwcfg) + #define default_param_max_packet_count -1 //(Max, hwcfg) + #define default_param_phy_utmi_width 16 + + #define default_param_turn_around_time_hs 4 //(NoChange) + #define default_param_turn_around_time_fs 4 //(NoChange) + #define default_param_timeout_cal_hs -1 //(NoChange) + #define default_param_timeout_cal_fs -1 //(NoChange) + + #define default_param_data_fifo_size -1 //(Max, hwcfg) + #ifdef __IS_HOST__ + #define default_param_host_channels -1 //(Max, hwcfg) + #define default_param_rx_fifo_size 640 + #define default_param_nperio_tx_fifo_size 640 + #define default_param_perio_tx_fifo_size 768 + #endif //__IS_HOST__ + + #ifdef __IS_DEVICE__ + #ifdef __DED_INTR__ + #define default_param_rx_fifo_size 1024 + #define default_param_nperio_tx_fifo_size 1016 + #define default_param_perio_tx_fifo_size_01 8 + #else + #define default_param_rx_fifo_size 1024 + #define default_param_nperio_tx_fifo_size 1024 + #define default_param_perio_tx_fifo_size_01 0 + #endif + #define default_param_perio_tx_fifo_size_02 0 + #define default_param_perio_tx_fifo_size_03 0 + #define default_param_perio_tx_fifo_size_04 0 + #define default_param_perio_tx_fifo_size_05 0 + #define default_param_perio_tx_fifo_size_06 0 + #define default_param_perio_tx_fifo_size_07 0 + #define default_param_perio_tx_fifo_size_08 0 + #define default_param_perio_tx_fifo_size_09 0 + #define default_param_perio_tx_fifo_size_10 0 + #define default_param_perio_tx_fifo_size_11 0 + #define default_param_perio_tx_fifo_size_12 0 + #define default_param_perio_tx_fifo_size_13 0 + #define default_param_perio_tx_fifo_size_14 0 + #define default_param_perio_tx_fifo_size_15 0 + #endif //__IS_DEVICE__ + + #elif defined(__IS_AMAZON_SE__) + #include + //#include + + #define IFXUSB_IRQ 31 + #define IFXUSB_IOMEM_BASE 0x1e101000 + #define IFXUSB_FIFOMEM_BASE 0x1e120000 + #define IFXUSB_FIFODBG_BASE 0x1e140000 + #define IFXUSB_OC_IRQ 20 + + #define AMAZON_SE_RCU_USBCFG ((volatile unsigned long *)(AMAZON_SE_RCU_BASE_ADDR + 0x18)) + #define AMAZON_SE_RCU_RESET ((volatile unsigned long *)(AMAZON_SE_RCU_BASE_ADDR + 0x10)) + #define AMAZON_SE_USBCFG_HDSEL_BIT 11 // 0:host, 1:device + #define AMAZON_SE_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end + #define AMAZON_SE_USBCFG_SLV_END_BIT 9 // 0:little_end, 1:big_end + + #ifndef AMAZON_SE_GPIO_P0_OUT + #define AMAZON_SE_GPIO_P0_OUT (0xBF103000+0x10) + #define AMAZON_SE_GPIO_P0_DIR (0xBF103000+0x18) + #define AMAZON_SE_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) + #define AMAZON_SE_GPIO_P0_ALTSEL1 (0xBF103000+0x20) + #define AMAZON_SE_GPIO_P0_OD (0xBF103000+0x24) + #define AMAZON_SE_GPIO_P0_PUDSEL (0xBF103000+0x2C) + #define AMAZON_SE_GPIO_P0_PUDEN (0xBF103000+0x30) + #define AMAZON_SE_GPIO_P1_OUT (0xBF103000+0x40) + #define AMAZON_SE_GPIO_P1_DIR (0xBF103000+0x48) + #define AMAZON_SE_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) + #define AMAZON_SE_GPIO_P1_ALTSEL1 (0xBF103000+0x50) + #define AMAZON_SE_GPIO_P1_OD (0xBF103000+0x54) + #define AMAZON_SE_GPIO_P1_PUDSEL (0xBF103000+0x5C) + #define AMAZON_SE_GPIO_P1_PUDEN (0xBF103000+0x60) + #endif + + + #ifndef AMAZON_SE_CGU + #define AMAZON_SE_CGU (0xBF103000) + #endif + #ifndef AMAZON_SE_CGU_IFCCR + #define AMAZON_SE_CGU_IFCCR ((volatile unsigned long *)(AMAZON_SE_CGU+ 0x0018)) + #endif + #ifndef AMAZON_SE_PMU + #define AMAZON_SE_PMU (KSEG1+0x1F102000) + #endif + #ifndef AMAZON_SE_PMU_PWDCR + #define AMAZON_SE_PMU_PWDCR ((volatile unsigned long *)(AMAZON_SE_PMU+0x001C)) + #endif + + #define default_param_dma_burst_size 4 + + #define default_param_speed IFXUSB_PARAM_SPEED_HIGH + + #define default_param_max_transfer_size -1 //(Max, hwcfg) + #define default_param_max_packet_count -1 //(Max, hwcfg) + #define default_param_phy_utmi_width 16 + + #define default_param_turn_around_time_hs 4 //(NoChange) + #define default_param_turn_around_time_fs 4 //(NoChange) + #define default_param_timeout_cal_hs -1 //(NoChange) + #define default_param_timeout_cal_fs -1 //(NoChange) + + #define default_param_data_fifo_size -1 //(Max, hwcfg) + + #ifdef __IS_HOST__ + #define default_param_host_channels -1 //(Max, hwcfg) + #define default_param_rx_fifo_size 240 + #define default_param_nperio_tx_fifo_size 240 + #define default_param_perio_tx_fifo_size 32 + #endif //__IS_HOST__ + #ifdef __IS_DEVICE__ + #ifdef __DED_INTR__ + #define default_param_rx_fifo_size 256 + #define default_param_nperio_tx_fifo_size 248 + #define default_param_perio_tx_fifo_size_01 8 + #else + #define default_param_rx_fifo_size 256 + #define default_param_nperio_tx_fifo_size 256 + #define default_param_perio_tx_fifo_size_01 0 + #endif + #define default_param_perio_tx_fifo_size_02 0 + #define default_param_perio_tx_fifo_size_03 0 + #define default_param_perio_tx_fifo_size_04 0 + #define default_param_perio_tx_fifo_size_05 0 + #define default_param_perio_tx_fifo_size_06 0 + #define default_param_perio_tx_fifo_size_07 0 + #define default_param_perio_tx_fifo_size_08 0 + #define default_param_perio_tx_fifo_size_09 0 + #define default_param_perio_tx_fifo_size_10 0 + #define default_param_perio_tx_fifo_size_11 0 + #define default_param_perio_tx_fifo_size_12 0 + #define default_param_perio_tx_fifo_size_13 0 + #define default_param_perio_tx_fifo_size_14 0 + #define default_param_perio_tx_fifo_size_15 0 + #endif //__IS_DEVICE__ + + #elif defined(__IS_AR9__) + #define IFXUSB1_IRQ 54 + #define IFXUSB1_IOMEM_BASE 0x1E101000 + #define IFXUSB1_FIFOMEM_BASE 0x1E120000 + #define IFXUSB1_FIFODBG_BASE 0x1E140000 + + #define IFXUSB2_IRQ 83 + #define IFXUSB2_IOMEM_BASE 0x1E106000 + #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 + #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 + + #define IFXUSB_OC_IRQ 60 + + #ifndef AMAZON_S_RCU_BASE_ADDR + #define AMAZON_S_RCU_BASE_ADDR (0xBF203000) + #endif + + #ifndef AMAZON_S_CGU + #define AMAZON_S_CGU (0xBF103000) + #endif + #ifndef AMAZON_S_CGU_IFCCR + #define AMAZON_S_CGU_IFCCR ((volatile unsigned long *)(AMAZON_S_CGU+ 0x0018)) + #endif + + #ifndef AMAZON_S_PMU + #define AMAZON_S_PMU (KSEG1+0x1F102000) + #endif + #ifndef AMAZON_S_PMU_PWDCR + #define AMAZON_S_PMU_PWDCR ((volatile unsigned long *)(AMAZON_S_PMU+0x001C)) + #endif + + #ifndef AMAZON_S_GPIO_P0_OUT + #define AMAZON_S_GPIO_P0_OUT (0xBF103000+0x10) + #define AMAZON_S_GPIO_P0_DIR (0xBF103000+0x18) + #define AMAZON_S_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) + #define AMAZON_S_GPIO_P0_ALTSEL1 (0xBF103000+0x20) + #define AMAZON_S_GPIO_P0_OD (0xBF103000+0x24) + #define AMAZON_S_GPIO_P0_PUDSEL (0xBF103000+0x2C) + #define AMAZON_S_GPIO_P0_PUDEN (0xBF103000+0x30) + #define AMAZON_S_GPIO_P1_OUT (0xBF103000+0x40) + #define AMAZON_S_GPIO_P1_DIR (0xBF103000+0x48) + #define AMAZON_S_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) + #define AMAZON_S_GPIO_P1_ALTSEL1 (0xBF103000+0x50) + #define AMAZON_S_GPIO_P1_OD (0xBF103000+0x54) + #define AMAZON_S_GPIO_P1_PUDSEL (0xBF103000+0x5C) + #define AMAZON_S_GPIO_P1_PUDEN (0xBF103000+0x60) + #endif + + #define AMAZON_S_RCU_USB1CFG ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x18)) + #define AMAZON_S_RCU_USB2CFG ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x34)) + #define AMAZON_S_RCU_USBRESET ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x10)) + #define AMAZON_S_USBCFG_ARB 7 // + #define AMAZON_S_USBCFG_HDSEL_BIT 11 // 0:host, 1:device + #define AMAZON_S_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end + #define AMAZON_S_USBCFG_SLV_END_BIT 17 // 0:little_end, 1:big_end + + #define default_param_dma_burst_size 4 + + #define default_param_speed IFXUSB_PARAM_SPEED_HIGH + + #define default_param_max_transfer_size -1 //(Max, hwcfg) + #define default_param_max_packet_count -1 //(Max, hwcfg) + #define default_param_phy_utmi_width 16 + + #define default_param_turn_around_time_hs 4 //(NoChange) + #define default_param_turn_around_time_fs 4 //(NoChange) + #define default_param_timeout_cal_hs -1 //(NoChange) + #define default_param_timeout_cal_fs -1 //(NoChange) + + #define default_param_data_fifo_size -1 //(Max, hwcfg) + + #ifdef __IS_HOST__ + #define default_param_host_channels -1 //(Max, hwcfg) + #define default_param_rx_fifo_size 240 + #define default_param_nperio_tx_fifo_size 240 + #define default_param_perio_tx_fifo_size 32 + #endif //__IS_HOST__ + #ifdef __IS_DEVICE__ + #ifdef __DED_INTR__ + #define default_param_rx_fifo_size 256 + #define default_param_nperio_tx_fifo_size 248 + #define default_param_perio_tx_fifo_size_01 8 + #else + #define default_param_rx_fifo_size 256 + #define default_param_nperio_tx_fifo_size 256 + #define default_param_perio_tx_fifo_size_01 0 + #endif + #define default_param_perio_tx_fifo_size_02 0 + #define default_param_perio_tx_fifo_size_03 0 + #define default_param_perio_tx_fifo_size_04 0 + #define default_param_perio_tx_fifo_size_05 0 + #define default_param_perio_tx_fifo_size_06 0 + #define default_param_perio_tx_fifo_size_07 0 + #define default_param_perio_tx_fifo_size_08 0 + #define default_param_perio_tx_fifo_size_09 0 + #define default_param_perio_tx_fifo_size_10 0 + #define default_param_perio_tx_fifo_size_11 0 + #define default_param_perio_tx_fifo_size_12 0 + #define default_param_perio_tx_fifo_size_13 0 + #define default_param_perio_tx_fifo_size_14 0 + #define default_param_perio_tx_fifo_size_15 0 + #endif //__IS_DEVICE__ + + #elif defined(__IS_VR9__) + #define IFXUSB1_IRQ 54 + #define IFXUSB1_IOMEM_BASE 0x1E101000 + #define IFXUSB1_FIFOMEM_BASE 0x1E120000 + #define IFXUSB1_FIFODBG_BASE 0x1E140000 + + #define IFXUSB2_IRQ 83 + #define IFXUSB2_IOMEM_BASE 0x1E106000 + #define IFXUSB2_FIFOMEM_BASE 0x1E1E0000 + #define IFXUSB2_FIFODBG_BASE 0x1E1C0000 + #define IFXUSB_OC_IRQ 68 + + #ifndef AMAZON_S_RCU_BASE_ADDR + #define AMAZON_S_RCU_BASE_ADDR (0xBF203000) + #endif + + #ifndef AMAZON_S_CGU + #define AMAZON_S_CGU (0xBF103000) + #endif + #ifndef AMAZON_S_CGU_IFCCR + #define AMAZON_S_CGU_IFCCR ((volatile unsigned long *)(AMAZON_S_CGU+ 0x0018)) + #endif + + #ifndef AMAZON_S_PMU + #define AMAZON_S_PMU (KSEG1+0x1F102000) + #endif + #ifndef AMAZON_S_PMU_PWDCR + #define AMAZON_S_PMU_PWDCR ((volatile unsigned long *)(AMAZON_S_PMU+0x001C)) + #endif + + #ifndef AMAZON_S_GPIO_P0_OUT + #define AMAZON_S_GPIO_P0_OUT (0xBF103000+0x10) + #define AMAZON_S_GPIO_P0_DIR (0xBF103000+0x18) + #define AMAZON_S_GPIO_P0_ALTSEL0 (0xBF103000+0x1C) + #define AMAZON_S_GPIO_P0_ALTSEL1 (0xBF103000+0x20) + #define AMAZON_S_GPIO_P0_OD (0xBF103000+0x24) + #define AMAZON_S_GPIO_P0_PUDSEL (0xBF103000+0x2C) + #define AMAZON_S_GPIO_P0_PUDEN (0xBF103000+0x30) + #define AMAZON_S_GPIO_P1_OUT (0xBF103000+0x40) + #define AMAZON_S_GPIO_P1_DIR (0xBF103000+0x48) + #define AMAZON_S_GPIO_P1_ALTSEL0 (0xBF103000+0x4C) + #define AMAZON_S_GPIO_P1_ALTSEL1 (0xBF103000+0x50) + #define AMAZON_S_GPIO_P1_OD (0xBF103000+0x54) + #define AMAZON_S_GPIO_P1_PUDSEL (0xBF103000+0x5C) + #define AMAZON_S_GPIO_P1_PUDEN (0xBF103000+0x60) + #endif + + #define AMAZON_S_RCU_USB1CFG ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x18)) + #define AMAZON_S_RCU_USB2CFG ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x34)) + #define AMAZON_S_RCU_USBRESET ((volatile unsigned long *)(AMAZON_S_RCU_BASE_ADDR + 0x10)) + #define AMAZON_S_USBCFG_ARB 7 // + #define AMAZON_S_USBCFG_HDSEL_BIT 11 // 0:host, 1:device + #define AMAZON_S_USBCFG_HOST_END_BIT 10 // 0:little_end, 1:big_end + #define AMAZON_S_USBCFG_SLV_END_BIT 17 // 0:little_end, 1:big_end + + #define default_param_dma_burst_size 4 //(ALL) + + #define default_param_speed IFXUSB_PARAM_SPEED_HIGH + + #define default_param_max_transfer_size -1 //(Max, hwcfg) + #define default_param_max_packet_count -1 //(Max, hwcfg) + #define default_param_phy_utmi_width 16 + + #define default_param_turn_around_time_hs 6 //(NoChange) snpsid >= 0x4f54260a + #define default_param_turn_around_time_fs 6 //(NoChange) snpsid >= 0x4f54260a + #define default_param_timeout_cal_hs -1 //(NoChange) + #define default_param_timeout_cal_fs -1 //(NoChange) + + #define default_param_data_fifo_size -1 //(Max, hwcfg) + + #ifdef __IS_HOST__ + #define default_param_host_channels -1 //(Max, hwcfg) + #define default_param_rx_fifo_size 240 + #define default_param_nperio_tx_fifo_size 240 + #define default_param_perio_tx_fifo_size 32 + #endif //__IS_HOST__ + #ifdef __IS_DEVICE__ + #define default_param_rx_fifo_size 256 + #define default_param_tx_fifo_size_00 -1 + #define default_param_tx_fifo_size_01 -1 + #define default_param_tx_fifo_size_02 -1 + #define default_param_tx_fifo_size_03 -1 + #define default_param_tx_fifo_size_04 -1 + #define default_param_tx_fifo_size_05 -1 + #define default_param_tx_fifo_size_06 -1 + #define default_param_tx_fifo_size_07 -1 + #define default_param_tx_fifo_size_08 -1 + #define default_param_tx_fifo_size_09 -1 + #define default_param_tx_fifo_size_10 -1 + #define default_param_tx_fifo_size_11 -1 + #define default_param_tx_fifo_size_12 -1 + #define default_param_tx_fifo_size_13 -1 + #define default_param_tx_fifo_size_14 -1 + #define default_param_tx_fifo_size_15 -1 + #define default_param_dma_unalgned_tx -1 + #define default_param_dma_unalgned_rx -1 + #define default_param_thr_ctl -1 + #define default_param_tx_thr_length -1 + #define default_param_rx_thr_length -1 + #endif //__IS_DEVICE__ + #else // __IS_VR9__ + #error "Please choose one platform!!" + #endif // __IS_VR9__ +#endif //UEIP + +/*@}*//*IFXUSB_PLATEFORM_MEM_ADDR*/ + +///////////////////////////////////////////////////////////////////////// + +#ifdef __IS_HOST__ + #if defined(CONFIG_USB_HOST_IFX_FORCE_USB11) || defined(__FORCE_USB11__) + #undef default_param_speed + #define default_param_speed IFXUSB_PARAM_SPEED_FULL + #endif +#endif +#ifdef __IS_DEVICE__ + #if !defined(CONFIG_USB_GADGET_DUALSPEED) || defined(__FORCE_USB11__) + #undef default_param_speed + #define default_param_speed IFXUSB_PARAM_SPEED_FULL + #endif +#endif + +///////////////////////////////////////////////////////////////////////// + +static __inline__ void UDELAY( const uint32_t _usecs ) +{ + udelay( _usecs ); +} + +static __inline__ void MDELAY( const uint32_t _msecs ) +{ + mdelay( _msecs ); +} + +static __inline__ void SPIN_LOCK( spinlock_t *_lock ) +{ + spin_lock(_lock); +} + +static __inline__ void SPIN_UNLOCK( spinlock_t *_lock ) +{ + spin_unlock(_lock); +} + +#define SPIN_LOCK_IRQSAVE( _l, _f ) \ + { \ + spin_lock_irqsave(_l,_f); \ + } + +#define SPIN_UNLOCK_IRQRESTORE( _l,_f ) \ + { \ + spin_unlock_irqrestore(_l,_f); \ + } + +///////////////////////////////////////////////////////////////////////// +/*! + \addtogroup IFXUSB_DBG_ROUTINE + */ +/*@{*/ +#ifdef __IS_HOST__ + extern uint32_t h_dbg_lvl; +#endif + +#ifdef __IS_DEVICE__ + extern uint32_t d_dbg_lvl; +#endif + +/*! \brief When debug level has the DBG_CIL bit set, display CIL Debug messages. */ +#define DBG_CIL (0x2) +/*! \brief When debug level has the DBG_CILV bit set, display CIL Verbose debug messages */ +#define DBG_CILV (0x20) +/*! \brief When debug level has the DBG_PCD bit set, display PCD (Device) debug messages */ +#define DBG_PCD (0x4) +/*! \brief When debug level has the DBG_PCDV set, display PCD (Device) Verbose debug messages */ +#define DBG_PCDV (0x40) +/*! \brief When debug level has the DBG_HCD bit set, display Host debug messages */ +#define DBG_HCD (0x8) +/*! \brief When debug level has the DBG_HCDV bit set, display Verbose Host debug messages */ +#define DBG_HCDV (0x80) +/*! \brief When debug level has the DBG_HCD_URB bit set, display enqueued URBs in host mode. */ +#define DBG_HCD_URB (0x800) +/*! \brief When debug level has any bit set, display debug messages */ +#define DBG_ANY (0xFF) +/*! \brief All debug messages off */ +#define DBG_OFF 0 + +#define DBG_ENTRY (0x8000) + +#define IFXUSB "IFXUSB: " + +/*! + \fn inline uint32_t SET_DEBUG_LEVEL( const uint32_t _new ) + \brief Set the Debug Level variable. + \param _new 32-bit mask of debug level. + \return previous debug level + */ +static inline uint32_t SET_DEBUG_LEVEL( const uint32_t _new ) +{ + #ifdef __IS_HOST__ + uint32_t old = h_dbg_lvl; + h_dbg_lvl = _new; + #endif + + #ifdef __IS_DEVICE__ + uint32_t old = d_dbg_lvl; + d_dbg_lvl = _new; + #endif + return old; +} + +#ifdef __DEBUG__ + #ifdef __IS_HOST__ + # define IFX_DEBUGPL(lvl, x...) do{ if ((lvl)&h_dbg_lvl)printk( KERN_DEBUG IFXUSB x ); }while(0) + # define CHK_DEBUG_LEVEL(level) ((level) & h_dbg_lvl) + #endif + + #ifdef __IS_DEVICE__ + # define IFX_DEBUGPL(lvl, x...) do{ if ((lvl)&d_dbg_lvl)printk( KERN_DEBUG IFXUSB x ); }while(0) + # define CHK_DEBUG_LEVEL(level) ((level) & d_dbg_lvl) + #endif + + # define IFX_DEBUGP(x...) IFX_DEBUGPL(DBG_ANY, x ) +#else + # define IFX_DEBUGPL(lvl, x...) do{}while(0) + # define IFX_DEBUGP(x...) + # define CHK_DEBUG_LEVEL(level) (0) +#endif //__DEBUG__ + +/* Print an Error message. */ +#define IFX_ERROR(x...) printk( KERN_ERR IFXUSB x ) +/* Print a Warning message. */ +#define IFX_WARN(x...) printk( KERN_WARNING IFXUSB x ) +/* Print a notice (normal but significant message). */ +#define IFX_NOTICE(x...) printk( KERN_NOTICE IFXUSB x ) +/* Basic message printing. */ +#define IFX_PRINT(x...) printk( KERN_INFO IFXUSB x ) + +/*@}*//*IFXUSB_DBG_ROUTINE*/ + + +#endif //__IFXUSB_PLAT_H__ + diff --git a/package/platform/lantiq/ltq-hcd/src/ifxusb_regs.h b/package/platform/lantiq/ltq-hcd/src/ifxusb_regs.h new file mode 100644 index 0000000000..4b43821e9a --- /dev/null +++ b/package/platform/lantiq/ltq-hcd/src/ifxusb_regs.h @@ -0,0 +1,1471 @@ +/***************************************************************************** + ** FILE NAME : ifxusb_regs.h + ** PROJECT : IFX USB sub-system V3 + ** MODULES : IFX USB sub-system Host and Device driver + ** SRC VERSION : 3.2 + ** DATE : 1/Jan/2011 + ** AUTHOR : Chen, Howard + ** DESCRIPTION : This file contains the data structures for accessing the IFXUSB core + ** registers. + ** The application interfaces with the USB core by reading from and + ** writing to the Control and Status Register (CSR) space through the + ** AHB Slave interface. These registers are 32 bits wide, and the + ** addresses are 32-bit-block aligned. + ** CSRs are classified as follows: + ** - Core Global Registers + ** - Device Mode Registers + ** - Device Global Registers + ** - Device Endpoint Specific Registers + ** - Host Mode Registers + ** - Host Global Registers + ** - Host Port CSRs + ** - Host Channel Specific Registers + ** + ** Only the Core Global registers can be accessed in both Device and + ** Host modes. When the USB core is operating in one mode, either + ** Device or Host, the application must not access registers from the + ** other mode. When the core switches from one mode to another, the + ** registers in the new mode of operation must be reprogrammed as they + ** would be after a power-on reset. + ** FUNCTIONS : + ** COMPILER : gcc + ** REFERENCE : Synopsys DWC-OTG Driver 2.7 + ** COPYRIGHT : Copyright (c) 2010 + ** LANTIQ DEUTSCHLAND GMBH, + ** Am Campeon 3, 85579 Neubiberg, Germany + ** + ** This program is free software; you can redistribute it and/or modify + ** it under the terms of the GNU General Public License as published by + ** the Free Software Foundation; either version 2 of the License, or + ** (at your option) any later version. + ** + ** Version Control Section ** + ** $Author$ + ** $Date$ + ** $Revisions$ + ** $Log$ Revision history +*****************************************************************************/ +/****************************************************************************** +** COPYRIGHT : Copyright (c) 2006 +** Infineon Technologies AG +** Am Campeon 1-12, 85579 Neubiberg, Germany +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** HISTORY +** $Date $Author $Comment +** 10 NOV 2008 Wu Qi Ming Initial Version, to comply with COC +*******************************************************************************/ + + +/* + * This file contains code fragments from Synopsys HS OTG Linux Software Driver. + * For this code the following notice is applicable: + * + * ========================================================================== + * + * Synopsys HS OTG Linux Software Driver and documentation (hereinafter, + * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless + * otherwise expressly agreed to in writing between Synopsys and you. + * + * The Software IS NOT an item of Licensed Software or Licensed Product under + * any End User Software License Agreement or Agreement for Licensed Product + * with Synopsys or any supplement thereto. You are permitted to use and + * redistribute this Software in source and binary forms, with or without + * modification, provided that redistributions of source code must retain this + * notice. You may not view, use, disclose, copy or distribute this file or + * any information contained herein except pursuant to this license grant from + * Synopsys. If you do not agree with this notice, including the disclaimer + * below, then you are not authorized to use the Software. + * + * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * ========================================================================== */ + + +/*! + \defgroup IFXUSB_CSR_DEFINITION Control and Status Register bit-map definition + \ingroup IFXUSB_DRIVER_V3 + \brief Data structures for accessing the IFXUSB core registers. + The application interfaces with the USB core by reading from and + writing to the Control and Status Register (CSR) space through the + AHB Slave interface. These registers are 32 bits wide, and the + addresses are 32-bit-block aligned. + CSRs are classified as follows: + - Core Global Registers + - Device Mode Registers + - Device Global Registers + - Device Endpoint Specific Registers + - Host Mode Registers + - Host Global Registers + - Host Port CSRs + - Host Channel Specific Registers + + Only the Core Global registers can be accessed in both Device andHost modes. + When the USB core is operating in one mode, either Device or Host, the + application must not access registers from the other mode. When the core + switches from one mode to another, the registers in the new mode of operation + must be reprogrammed as they would be after a power-on reset. + */ + +/*! + \defgroup IFXUSB_CSR_DEVICE_GLOBAL_REG Device Mode Registers + \ingroup IFXUSB_CSR_DEFINITION + \brief Bit-mapped structure to access Device Mode Global Registers + */ + +/*! + \defgroup IFXUSB_CSR_DEVICE_EP_REG Device Mode EP Registers + \ingroup IFXUSB_CSR_DEFINITION + \brief Bit-mapped structure to access Device Mode EP Registers + There will be one set of endpoint registers per logical endpoint + implemented. + These registers are visible only in Device mode and must not be + accessed in Host mode, as the results are unknown. + */ + +/*! + \defgroup IFXUSB_CSR_DEVICE_DMA_DESC Device mode scatter dma descriptor strusture + \ingroup IFXUSB_CSR_DEFINITION + \brief Bit-mapped structure to DMA descriptor + */ + + +/*! + \defgroup IFXUSB_CSR_HOST_GLOBAL_REG Host Mode Registers + \ingroup IFXUSB_CSR_DEFINITION + \brief Bit-mapped structure to access Host Mode Global Registers + */ + +/*! + \defgroup IFXUSB_CSR_HOST_HC_REG Host Mode HC Registers + \ingroup IFXUSB_CSR_DEFINITION + \brief Bit-mapped structure to access Host Mode Host Channel Registers + There will be one set of endpoint registers per host channel + implemented. + These registers are visible only in Host mode and must not be + accessed in Device mode, as the results are unknown. + */ + +/*! + \defgroup IFXUSB_CSR_PWR_CLK_GATING_REG Power and Clock Gating Control Register + \ingroup IFXUSB_CSR_DEFINITION + \brief Bit-mapped structure to Power and Clock Gating Control Register + */ + +/*! + \defgroup IFXUSB_CSR_CORE_GLOBAL_REG Core Global Registers + \ingroup IFXUSB_CSR_DEFINITION + \brief Bit-mapped structure to access Core Global Registers + */ + +/*! + \defgroup IFXUSB_CSR_CORE_GLOBAL_REG Core Global Registers + \ingroup IFXUSB_CSR_DEFINITION + \brief Bit-mapped structure to access Core Global Registers + */ + + + +/*! + \defgroup IFXUSB_CSR_ACCESS_MACROS Macros to manipulate CSRs + \ingroup IFXUSB_CSR_DEFINITION + \brief Macros to manipulate CSRs + */ + + + + + + +/*! + \file ifxusb_regs.h + \ingroup IFXUSB_DRIVER_V3 + \brief This file contains the data structures for accessing the IFXUSB core registers. + */ + + +#ifndef __IFXUSB_REGS_H__ +#define __IFXUSB_REGS_H__ + +/****************************************************************************/ + +#define MAX_PERIO_FIFOS 15 /** Maximum number of Periodic FIFOs */ +#define MAX_TX_FIFOS 15 /** Maximum number of Periodic FIFOs */ +#define MAX_EPS_CHANNELS 16 /** Maximum number of Endpoints/HostChannels */ + +/****************************************************************************/ + +//#define __RecordRegRW__ + +/*! + \fn static __inline__ uint32_t ifxusb_rreg( volatile uint32_t *_reg) + \brief Reads the content of a register. + \param _reg address of register to read. + \return contents of the register. + \ingroup IFXUSB_CSR_ACCESS_MACROS + */ +static __inline__ uint32_t ifxusb_rreg( volatile uint32_t *_reg) +{ + #ifdef __RecordRegRW__ + uint32_t r; + r=*(_reg); + return (r); + #else + return (*(_reg)); + #endif +}; + + +/*! + \fn static __inline__ void ifxusb_wreg( volatile uint32_t *_reg, const uint32_t _value) + \brief Writes a register with a 32 bit value. + \param _reg address of register to write. + \param _value value to write to _reg. + \ingroup IFXUSB_CSR_ACCESS_MACROS + */ +static __inline__ void ifxusb_wreg( volatile uint32_t *_reg, const uint32_t _value) +{ + #ifdef __RecordRegRW__ + printk(KERN_INFO "[W %p<-%08X]\n",_reg,_value); + #else + *(_reg)=_value; + #endif +}; + +/*! + \fn static __inline__ void ifxusb_mreg( volatile uint32_t *_reg, const uint32_t _clear_mask, const uint32_t _set_mask) + \brief Modifies bit values in a register. Using the + algorithm: (reg_contents & ~clear_mask) | set_mask. + \param _reg address of register to modify. + \param _clear_mask bit mask to be cleared. + \param _set_mask bit mask to be set. + \ingroup IFXUSB_CSR_ACCESS_MACROS + */ +static __inline__ void ifxusb_mreg( volatile uint32_t *_reg, const uint32_t _clear_mask, const uint32_t _set_mask) +{ + uint32_t v; + #ifdef __RecordRegRW__ + uint32_t r; + v= *(_reg); + r=v; + r&=(~_clear_mask); + r|= _set_mask; + *(_reg)=r ; + printk(KERN_INFO "[M %p->%08X+%08X/%08X<-%08X]\n",_reg,r,_clear_mask,_set_mask,r); + #else + v= *(_reg); + v&=(~_clear_mask); + v|= _set_mask; + *(_reg)=v ; + #endif +}; + +/****************************************************************************/ + +/*! + \addtogroup IFXUSB_CSR_CORE_GLOBAL_REG + */ +/*@{*/ + +/*! typedef ifxusb_core_global_regs_t + \brief IFXUSB Core registers . + The ifxusb_core_global_regs structure defines the size + and relative field offsets for the Core Global registers. + */ +typedef struct ifxusb_core_global_regs +{ + volatile uint32_t gotgctl; /*!< 000h OTG Control and Status Register. */ + volatile uint32_t gotgint; /*!< 004h OTG Interrupt Register. */ + volatile uint32_t gahbcfg; /*!< 008h Core AHB Configuration Register. */ + volatile uint32_t gusbcfg; /*!< 00Ch Core USB Configuration Register. */ + volatile uint32_t grstctl; /*!< 010h Core Reset Register. */ + volatile uint32_t gintsts; /*!< 014h Core Interrupt Register. */ + volatile uint32_t gintmsk; /*!< 018h Core Interrupt Mask Register. */ + volatile uint32_t grxstsr; /*!< 01Ch Receive Status Queue Read Register (Read Only). */ + volatile uint32_t grxstsp; /*!< 020h Receive Status Queue Read & POP Register (Read Only). */ + volatile uint32_t grxfsiz; /*!< 024h Receive FIFO Size Register. */ + volatile uint32_t gnptxfsiz; /*!< 028h Non Periodic Transmit FIFO Size Register. */ + volatile uint32_t gnptxsts; /*!< 02Ch Non Periodic Transmit FIFO/Queue Status Register (Read Only). */ + volatile uint32_t gi2cctl; /*!< 030h I2C Access Register. */ + volatile uint32_t gpvndctl; /*!< 034h PHY Vendor Control Register. */ + volatile uint32_t ggpio; /*!< 038h General Purpose Input/Output Register. */ + volatile uint32_t guid; /*!< 03Ch User ID Register. */ + volatile uint32_t gsnpsid; /*!< 040h Synopsys ID Register (Read Only). */ + volatile uint32_t ghwcfg1; /*!< 044h User HW Config1 Register (Read Only). */ + volatile uint32_t ghwcfg2; /*!< 048h User HW Config2 Register (Read Only). */ + volatile uint32_t ghwcfg3; /*!< 04Ch User HW Config3 Register (Read Only). */ + volatile uint32_t ghwcfg4; /*!< 050h User HW Config4 Register (Read Only). */ + volatile uint32_t reserved[43]; /*!< 054h Reserved 054h-0FFh */ + volatile uint32_t hptxfsiz; /*!< 100h Host Periodic Transmit FIFO Size Register. */ + volatile uint32_t dptxfsiz_dieptxf[15];/*!< 104h + (FIFO_Number-1)*04h, 1 <= FIFO Number <= 15. + Device Periodic Transmit FIFO#n Register if dedicated + fifos are disabled, otherwise Device Transmit FIFO#n + Register. + */ +} ifxusb_core_global_regs_t; + +/*! + \brief Bits of the Core OTG Control and Status Register (GOTGCTL). + */ +typedef union gotgctl_data +{ + uint32_t d32; + struct{ + unsigned reserved21_31 : 11; + unsigned currmod : 1 ; /*!< 20 */ + unsigned bsesvld : 1 ; /*!< 19 */ + unsigned asesvld : 1 ; /*!< 18 */ + unsigned reserved17 : 1 ; + unsigned conidsts : 1 ; /*!< 16 */ + unsigned reserved12_15 : 4 ; + unsigned devhnpen : 1 ; /*!< 11 */ + unsigned hstsethnpen : 1 ; /*!< 10 */ + unsigned hnpreq : 1 ; /*!< 09 */ + unsigned hstnegscs : 1 ; /*!< 08 */ + unsigned reserved2_7 : 6 ; + unsigned sesreq : 1 ; /*!< 01 */ + unsigned sesreqscs : 1 ; /*!< 00 */ + } b; +} gotgctl_data_t; + +/*! + \brief Bit fields of the Core OTG Interrupt Register (GOTGINT). + */ +typedef union gotgint_data +{ + uint32_t d32; + struct + { + unsigned reserved31_20 : 12; + unsigned debdone : 1 ; /*!< 19 Debounce Done */ + unsigned adevtoutchng : 1 ; /*!< 18 A-Device Timeout Change */ + unsigned hstnegdet : 1 ; /*!< 17 Host Negotiation Detected */ + unsigned reserver10_16 : 7 ; + unsigned hstnegsucstschng : 1 ; /*!< 09 Host Negotiation Success Status Change */ + unsigned sesreqsucstschng : 1 ; /*!< 08 Session Request Success Status Change */ + unsigned reserved3_7 : 5 ; + unsigned sesenddet : 1 ; /*!< 02 Session End Detected */ + unsigned reserved0_1 : 2 ; + } b; +} gotgint_data_t; + +/*! + \brief Bit fields of the Core AHB Configuration Register (GAHBCFG). + */ +typedef union gahbcfg_data +{ + uint32_t d32; + struct + { + unsigned reserved9_31 : 23; + unsigned ptxfemplvl : 1 ; /*!< 08 Periodic FIFO empty level trigger condition*/ + unsigned nptxfemplvl : 1 ; /*!< 07 Non-Periodic FIFO empty level trigger condition*/ + #define IFXUSB_GAHBCFG_TXFEMPTYLVL_EMPTY 1 + #define IFXUSB_GAHBCFG_TXFEMPTYLVL_HALFEMPTY 0 + unsigned reserved : 1 ; + unsigned dmaenable : 1 ; /*!< 05 DMA enable*/ + #define IFXUSB_GAHBCFG_DMAENABLE 1 + unsigned hburstlen : 4 ; /*!< 01-04 DMA Burst-length*/ + #define IFXUSB_GAHBCFG_INT_DMA_BURST_SINGLE 0 + #define IFXUSB_GAHBCFG_INT_DMA_BURST_INCR 1 + #define IFXUSB_GAHBCFG_INT_DMA_BURST_INCR4 3 + #define IFXUSB_GAHBCFG_INT_DMA_BURST_INCR8 5 + #define IFXUSB_GAHBCFG_INT_DMA_BURST_INCR16 7 + unsigned glblintrmsk : 1 ; /*!< 00 USB Global Interrupt Enable */ + #define IFXUSB_GAHBCFG_GLBINT_ENABLE 1 + } b; +} gahbcfg_data_t; + +/*! + \brief Bit fields of the Core USB Configuration Register (GUSBCFG). +*/ +typedef union gusbcfg_data +{ + uint32_t d32; + struct + { + unsigned reserved31 : 1; + unsigned ForceDevMode : 1; /*!< 30 Force Device Mode */ + unsigned ForceHstMode : 1; /*!< 29 Force Host Mode */ + unsigned TxEndDelay : 1; /*!< 28 Tx End Delay */ + unsigned reserved2723 : 5; + unsigned term_sel_dl_pulse : 1; /*!< 22 TermSel DLine Pulsing Selection */ + unsigned reserved2117 : 5; + unsigned otgutmifssel : 1; /*!< 16 UTMIFS Select */ + unsigned phylpwrclksel : 1; /*!< 15 PHY Low-Power Clock Select */ + unsigned reserved14 : 1; + unsigned usbtrdtim : 4; /*!< 13-10 USB Turnaround Time */ + unsigned hnpcap : 1; /*!< 09 HNP-Capable */ + unsigned srpcap : 1; /*!< 08 SRP-Capable */ + unsigned reserved07 : 1; + unsigned physel : 1; /*!< 06 USB 2.0 High-Speed PHY or + USB 1.1 Full-Speed Serial + Transceiver Select */ + unsigned fsintf : 1; /*!< 05 Full-Speed Serial Interface Select */ + unsigned ulpi_utmi_sel : 1; /*!< 04 ULPI or UTMI+ Select */ + unsigned phyif : 1; /*!< 03 PHY Interface */ + unsigned toutcal : 3; /*!< 00-02 HS/FS Timeout Calibration */ + }b; +} gusbcfg_data_t; + +/*! + \brief Bit fields of the Core Reset Register (GRSTCTL). + */ +typedef union grstctl_data +{ + uint32_t d32; + struct + { + unsigned ahbidle : 1; /*!< 31 AHB Master Idle. Indicates the AHB Master State + Machine is in IDLE condition. */ + unsigned dmareq : 1; /*!< 30 DMA Request Signal. Indicated DMA request is in + probress. Used for debug purpose. */ + unsigned reserved11_29 :19; + unsigned txfnum : 5; /*!< 10-06 TxFIFO Number (TxFNum) to be flushed. + 0x00: Non Periodic TxFIFO Flush or TxFIFO 0 + 0x01-0x0F: Periodic TxFIFO Flush or TxFIFO n + 0x10: Flush all TxFIFO + */ + unsigned txfflsh : 1; /*!< 05 TxFIFO Flush */ + unsigned rxfflsh : 1; /*!< 04 RxFIFO Flush */ + unsigned intknqflsh : 1; /*!< 03 In Token Sequence Learning Queue Flush (Device Only) */ + unsigned hstfrm : 1; /*!< 02 Host Frame Counter Reset (Host Only) */ + unsigned hsftrst : 1; /*!< 01 Hclk Soft Reset */ + + unsigned csftrst : 1; /*!< 00 Core Soft Reset + The application can flush the control logic in the + entire core using this bit. This bit resets the + pipelines in the AHB Clock domain as well as the + PHY Clock domain. + The state machines are reset to an IDLE state, the + control bits in the CSRs are cleared, all the + transmit FIFOs and the receive FIFO are flushed. + The status mask bits that control the generation of + the interrupt, are cleared, to clear the + interrupt. The interrupt status bits are not + cleared, so the application can get the status of + any events that occurred in the core after it has + set this bit. + Any transactions on the AHB are terminated as soon + as possible following the protocol. Any + transactions on the USB are terminated immediately. + The configuration settings in the CSRs are + unchanged, so the software doesn't have to + reprogram these registers (Device + Configuration/Host Configuration/Core System + Configuration/Core PHY Configuration). + The application can write to this bit, any time it + wants to reset the core. This is a self clearing + bit and the core clears this bit after all the + necessary logic is reset in the core, which may + take several clocks, depending on the current state + of the core. + */ + }b; +} grstctl_t; + +/*! + \brief Bit fields of the Core Interrupt Mask Register (GINTMSK) and + Core Interrupt Register (GINTSTS). + */ +typedef union gint_data +{ + uint32_t d32; + #define IFXUSB_SOF_INTR_MASK 0x0008 + struct + { + unsigned wkupintr : 1; /*!< 31 Resume/Remote Wakeup Detected Interrupt */ + unsigned sessreqintr : 1; /*!< 30 Session Request/New Session Detected Interrupt */ + unsigned disconnect : 1; /*!< 29 Disconnect Detected Interrupt */ + unsigned conidstschng : 1; /*!< 28 Connector ID Status Change */ + unsigned reserved27 : 1; + unsigned ptxfempty : 1; /*!< 26 Periodic TxFIFO Empty */ + unsigned hcintr : 1; /*!< 25 Host Channels Interrupt */ + unsigned portintr : 1; /*!< 24 Host Port Interrupt */ + unsigned reserved23 : 1; + unsigned fetsuspmsk : 1; /*!< 22 Data Fetch Suspended */ + unsigned incomplisoout : 1; /*!< 21 Incomplete IsochronousOUT/Period Transfer */ + unsigned incomplisoin : 1; /*!< 20 Incomplete Isochronous IN Transfer */ + unsigned outepintr : 1; /*!< 19 OUT Endpoints Interrupt */ + unsigned inepintr : 1; /*!< 18 IN Endpoints Interrupt */ + unsigned epmismatch : 1; /*!< 17 Endpoint Mismatch Interrupt */ + unsigned reserved16 : 1; + unsigned eopframe : 1; /*!< 15 End of Periodic Frame Interrupt */ + unsigned isooutdrop : 1; /*!< 14 Isochronous OUT Packet Dropped Interrupt */ + unsigned enumdone : 1; /*!< 13 Enumeration Done */ + unsigned usbreset : 1; /*!< 12 USB Reset */ + unsigned usbsuspend : 1; /*!< 11 USB Suspend */ + unsigned erlysuspend : 1; /*!< 10 Early Suspend */ + unsigned i2cintr : 1; /*!< 09 I2C Interrupt */ + unsigned reserved8 : 1; + unsigned goutnakeff : 1; /*!< 07 Global OUT NAK Effective */ + unsigned ginnakeff : 1; /*!< 06 Global Non-periodic IN NAK Effective */ + unsigned nptxfempty : 1; /*!< 05 Non-periodic TxFIFO Empty */ + unsigned rxstsqlvl : 1; /*!< 04 Receive FIFO Non-Empty */ + unsigned sofintr : 1; /*!< 03 Start of (u)Frame */ + unsigned otgintr : 1; /*!< 02 OTG Interrupt */ + unsigned modemismatch : 1; /*!< 01 Mode Mismatch Interrupt */ + unsigned reserved0 : 1; + } b; +} gint_data_t; + +/*! + \brief Bit fields in the Receive Status Read and Pop Registers (GRXSTSR, GRXSTSP) + */ +typedef union grxsts_data +{ + uint32_t d32; + struct + { + unsigned reserved : 7; + unsigned fn : 4; /*!< 24-21 Frame Number */ + unsigned pktsts : 4; /*!< 20-17 Packet Status */ + #define IFXUSB_DSTS_DATA_UPDT 0x2 // OUT Data Packet + #define IFXUSB_DSTS_XFER_COMP 0x3 // OUT Data Transfer Complete + #define IFXUSB_DSTS_GOUT_NAK 0x1 // Global OUT NAK + #define IFXUSB_DSTS_SETUP_COMP 0x4 // Setup Phase Complete + #define IFXUSB_DSTS_SETUP_UPDT 0x6 // SETUP Packet + unsigned dpid : 2; /*!< 16-15 Data PID */ + unsigned bcnt :11; /*!< 14-04 Byte Count */ + unsigned epnum : 4; /*!< 03-00 Endpoint Number */ + } db; + struct + { + unsigned reserved :11; + unsigned pktsts : 4; /*!< 20-17 Packet Status */ + #define IFXUSB_HSTS_DATA_UPDT 0x2 // OUT Data Packet + #define IFXUSB_HSTS_XFER_COMP 0x3 // OUT Data Transfer Complete + #define IFXUSB_HSTS_DATA_TOGGLE_ERR 0x5 // DATA TOGGLE Error + #define IFXUSB_HSTS_CH_HALTED 0x7 // Channel Halted + unsigned dpid : 2; /*!< 16-15 Data PID */ + unsigned bcnt :11; /*!< 14-04 Byte Count */ + unsigned chnum : 4; /*!< 03-00 Channel Number */ + } hb; +} grxsts_data_t; + +/*! + \brief Bit fields in the FIFO Size Registers (HPTXFSIZ, GNPTXFSIZ, DPTXFSIZn). + */ +typedef union fifosize_data +{ + uint32_t d32; + struct + { + unsigned depth : 16; /*!< 31-16 TxFIFO Depth (in DWord)*/ + unsigned startaddr : 16; /*!< 15-00 RAM Starting address */ + } b; +} fifosize_data_t; + +/*! + \brief Bit fields in the Non-Periodic Transmit FIFO/Queue Status Register (GNPTXSTS). + */ + +typedef union gnptxsts_data +{ + uint32_t d32; + struct + { + unsigned reserved : 1; + unsigned nptxqtop_chnep : 4; /*!< 30-27 Channel/EP Number of top of the Non-Periodic + Transmit Request Queue + */ + unsigned nptxqtop_token : 2; /*!< 26-25 Token Type top of the Non-Periodic + Transmit Request Queue + 0 - IN/OUT + 1 - Zero Length OUT + 2 - PING/Complete Split + 3 - Channel Halt + */ + unsigned nptxqtop_terminate : 1; /*!< 24 Terminate (Last entry for the selected + channel/EP)*/ + unsigned nptxqspcavail : 8; /*!< 23-16 Transmit Request Queue Space Available */ + unsigned nptxfspcavail :16; /*!< 15-00 TxFIFO Space Avail (in DWord)*/ + }b; +} gnptxsts_data_t; + + +/*! + \brief Bit fields in the Transmit FIFO Status Register (DTXFSTS). + */ +typedef union dtxfsts_data +{ + uint32_t d32; + struct + { + unsigned reserved : 16; + unsigned txfspcavail : 16; /*!< 15-00 TxFIFO Space Avail (in DWord)*/ + }b; +} dtxfsts_data_t; + + +/*! + \brief Bit fields in the I2C Control Register (I2CCTL). + */ +typedef union gi2cctl_data +{ + uint32_t d32; + struct + { + unsigned bsydne : 1; /*!< 31 I2C Busy/Done*/ + unsigned rw : 1; /*!< 30 Read/Write Indicator */ + unsigned reserved : 2; + unsigned i2cdevaddr : 2; /*!< 27-26 I2C Device Address */ + unsigned i2csuspctl : 1; /*!< 25 I2C Suspend Control */ + unsigned ack : 1; /*!< 24 I2C ACK */ + unsigned i2cen : 1; /*!< 23 I2C Enable */ + unsigned addr : 7; /*!< 22-16 I2C Address */ + unsigned regaddr : 8; /*!< 15-08 I2C Register Addr */ + unsigned rwdata : 8; /*!< I2C Read/Write Data */ + } b; +} gi2cctl_data_t; + + +/*! + \brief Bit fields in the User HW Config1 Register. + */ +typedef union hwcfg1_data +{ + uint32_t d32; + struct + { + unsigned ep_dir15 : 2; /*!< Direction of each EP + 0: BIDIR (IN and OUT) endpoint + 1: IN endpoint + 2: OUT endpoint + 3: Reserved + */ + unsigned ep_dir14 : 2; + unsigned ep_dir13 : 2; + unsigned ep_dir12 : 2; + unsigned ep_dir11 : 2; + unsigned ep_dir10 : 2; + unsigned ep_dir09 : 2; + unsigned ep_dir08 : 2; + unsigned ep_dir07 : 2; + unsigned ep_dir06 : 2; + unsigned ep_dir05 : 2; + unsigned ep_dir04 : 2; + unsigned ep_dir03 : 2; + unsigned ep_dir02 : 2; + unsigned ep_dir01 : 2; + unsigned ep_dir00 : 2; + }b; +} hwcfg1_data_t; + +/*! + \brief Bit fields in the User HW Config2 Register. + */ +typedef union hwcfg2_data +{ + uint32_t d32; + struct + { + unsigned reserved31 : 1; + unsigned dev_token_q_depth : 5; /*!< 30-26 Device Mode IN Token Sequence Learning Queue Depth */ + unsigned host_perio_tx_q_depth : 2; /*!< 25-24 Host Mode Periodic Request Queue Depth */ + unsigned nonperio_tx_q_depth : 2; /*!< 23-22 Non-periodic Request Queue Depth */ + unsigned rx_status_q_depth : 2; /*!< 21-20 Multi Processor Interrupt Enabled */ + unsigned dynamic_fifo : 1; /*!< 19 Dynamic FIFO Sizing Enabled */ + unsigned perio_ep_supported : 1; /*!< 18 Periodic OUT Channels Supported in Host Mode */ + unsigned num_host_chan : 4; /*!< 17-14 Number of Host Channels */ + unsigned num_dev_ep : 4; /*!< 13-10 Number of Device Endpoints */ + unsigned fs_phy_type : 2; /*!< 09-08 Full-Speed PHY Interface Type */ + #define IFXUSB_HWCFG2_FS_PHY_TYPE_NOT_SUPPORTED 0 + #define IFXUSB_HWCFG2_FS_PHY_TYPE_DEDICATE 1 + #define IFXUSB_HWCFG2_FS_PHY_TYPE_UTMI 2 + #define IFXUSB_HWCFG2_FS_PHY_TYPE_ULPI 3 + unsigned hs_phy_type : 2; /*!< 07-06 High-Speed PHY Interface Type */ + #define IFXUSB_HWCFG2_HS_PHY_TYPE_NOT_SUPPORTED 0 + #define IFXUSB_HWCFG2_HS_PHY_TYPE_UTMI 1 + #define IFXUSB_HWCFG2_HS_PHY_TYPE_ULPI 2 + #define IFXUSB_HWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 + unsigned point2point : 1; /*!< 05 Point-to-Point */ + unsigned architecture : 2; /*!< 04-03 Architecture */ + #define IFXUSB_HWCFG2_ARCH_SLAVE_ONLY 0 + #define IFXUSB_HWCFG2_ARCH_EXT_DMA 1 + #define IFXUSB_HWCFG2_ARCH_INT_DMA 2 + unsigned op_mode : 3; /*!< 02-00 Mode of Operation */ + #define IFXUSB_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG 0 + #define IFXUSB_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG 1 + #define IFXUSB_HWCFG2_OP_MODE_NO_HNP_SRP_CAPABLE_OTG 2 + #define IFXUSB_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE 3 + #define IFXUSB_HWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE 4 + #define IFXUSB_HWCFG2_OP_MODE_SRP_CAPABLE_HOST 5 + #define IFXUSB_HWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST 6 + } b; +} hwcfg2_data_t; + +/*! + \brief Bit fields in the User HW Config3 Register. + */ +typedef union hwcfg3_data +{ + uint32_t d32; + struct + { + unsigned dfifo_depth :16; /*!< 31-16 DFIFO Depth */ + unsigned reserved15_12 : 4; + unsigned synch_reset_type : 1; /*!< 11 Reset Style for Clocked always Blocks in RTL */ + unsigned optional_features : 1; /*!< 10 Optional Features Removed */ + unsigned vendor_ctrl_if : 1; /*!< 09 Vendor Control Interface Support */ + unsigned i2c : 1; /*!< 08 I2C Selection */ + unsigned otg_func : 1; /*!< 07 OTG Function Enabled */ + unsigned packet_size_cntr_width : 3; /*!< 06-04 Width of Packet Size Counters */ + unsigned xfer_size_cntr_width : 4; /*!< 03-00 Width of Transfer Size Counters */ + } b; +} hwcfg3_data_t; + +/*! + \brief Bit fields in the User HW Config4 + * Register. Read the register into the d32 element then read + * out the bits using the bit elements. + */ +typedef union hwcfg4_data +{ + uint32_t d32; + struct + { + unsigned desc_dma_dyn : 1; /*!< 31 Scatter/Gather DMA */ + unsigned desc_dma : 1; /*!< 30 Scatter/Gather DMA configuration */ + unsigned num_in_eps : 4; /*!< 29-26 Number of Device Mode IN Endpoints Including Control Endpoints */ + unsigned ded_fifo_en : 1; /*!< 25 Enable Dedicated Transmit FIFO for device IN Endpoints */ + unsigned session_end_filt_en : 1; /*!< 24 session_end Filter Enabled */ + unsigned b_valid_filt_en : 1; /*!< 23 b_valid Filter Enabled */ + unsigned a_valid_filt_en : 1; /*!< 22 a_valid Filter Enabled */ + unsigned vbus_valid_filt_en : 1; /*!< 21 vbus_valid Filter Enabled */ + unsigned iddig_filt_en : 1; /*!< 20 iddig Filter Enable */ + unsigned num_dev_mode_ctrl_ep : 4; /*!< 19-16 Number of Device Mode Control Endpoints in Addition to Endpoint 0 */ + unsigned utmi_phy_data_width : 2; /*!< 15-14 UTMI+ PHY/ULPI-to-Internal UTMI+ Wrapper Data Width */ + unsigned reserved13_06 : 8; + unsigned min_ahb_freq : 1; /*!< 05 Minimum AHB Frequency Less Than 60 MHz */ + unsigned power_optimiz : 1; /*!< 04 Enable Power Optimization? */ + unsigned num_dev_perio_in_ep : 4; /*!< 03-00 Number of Device Mode Periodic IN Endpoints */ + } b; +} hwcfg4_data_t; + +/*@}*//*IFXUSB_CSR_CORE_GLOBAL_REG*/ + +/****************************************************************************/ +/*! + \addtogroup IFXUSB_CSR_DEVICE_GLOBAL_REG + */ +/*@{*/ + +/*! typedef ifxusb_dev_global_regs_t + \brief IFXUSB Device Mode Global registers. Offsets 800h-BFFh + The ifxusb_dev_global_regs structure defines the size + and relative field offsets for the Device Global registers. + These registers are visible only in Device mode and must not be + accessed in Host mode, as the results are unknown. + */ +typedef struct ifxusb_dev_global_regs +{ + volatile uint32_t dcfg; /*!< 800h Device Configuration Register. */ + volatile uint32_t dctl; /*!< 804h Device Control Register. */ + volatile uint32_t dsts; /*!< 808h Device Status Register (Read Only). */ + uint32_t unused; + volatile uint32_t diepmsk; /*!< 810h Device IN Endpoint Common Interrupt Mask Register. */ + volatile uint32_t doepmsk; /*!< 814h Device OUT Endpoint Common Interrupt Mask Register. */ + volatile uint32_t daint; /*!< 818h Device All Endpoints Interrupt Register. */ + volatile uint32_t daintmsk; /*!< 81Ch Device All Endpoints Interrupt Mask Register. */ + volatile uint32_t dtknqr1; /*!< 820h Device IN Token Queue Read Register-1 (Read Only). */ + volatile uint32_t dtknqr2; /*!< 824h Device IN Token Queue Read Register-2 (Read Only). */ + volatile uint32_t dvbusdis; /*!< 828h Device VBUS discharge Register.*/ + volatile uint32_t dvbuspulse; /*!< 82Ch Device VBUS Pulse Register. */ + volatile uint32_t dtknqr3_dthrctl; /*!< 830h Device IN Token Queue Read Register-3 (Read Only). + Device Thresholding control register (Read/Write) + */ + volatile uint32_t dtknqr4_fifoemptymsk; /*!< 834h Device IN Token Queue Read Register-4 (Read Only). + Device IN EPs empty Inr. Mask Register (Read/Write) + */ +} ifxusb_device_global_regs_t; + +/*! + \brief Bit fields in the Device Configuration Register. + */ + +typedef union dcfg_data +{ + uint32_t d32; + struct + { + unsigned reserved31_26 : 6; + unsigned perschintvl : 2; /*!< 25-24 Periodic Scheduling Interval */ + unsigned descdma : 1; /*!< 23 Enable Descriptor DMA in Device mode */ + unsigned epmscnt : 5; /*!< 22-18 In Endpoint Mis-match count */ + unsigned reserved13_17 : 5; + unsigned perfrint : 2; /*!< 12-11 Periodic Frame Interval */ + #define IFXUSB_DCFG_FRAME_INTERVAL_80 0 + #define IFXUSB_DCFG_FRAME_INTERVAL_85 1 + #define IFXUSB_DCFG_FRAME_INTERVAL_90 2 + #define IFXUSB_DCFG_FRAME_INTERVAL_95 3 + unsigned devaddr : 7; /*!< 10-04 Device Addresses */ + unsigned reserved3 : 1; + unsigned nzstsouthshk : 1; /*!< 02 Non Zero Length Status OUT Handshake */ + #define IFXUSB_DCFG_SEND_STALL 1 + unsigned devspd : 2; /*!< 01-00 Device Speed */ + } b; +} dcfg_data_t; + +/*! + \brief Bit fields in the Device Control Register. + */ +typedef union dctl_data +{ + uint32_t d32; + struct + { + unsigned reserved16_31 :16; + unsigned ifrmnum : 1; /*!< 15 Ignore Frame Number for ISOC EPs */ + unsigned gmc : 2; /*!< 14-13 Global Multi Count */ + unsigned gcontbna : 1; /*!< 12 Global Continue on BNA */ + unsigned pwronprgdone : 1; /*!< 11 Power-On Programming Done */ + unsigned cgoutnak : 1; /*!< 10 Clear Global OUT NAK */ + unsigned sgoutnak : 1; /*!< 09 Set Global OUT NAK */ + unsigned cgnpinnak : 1; /*!< 08 Clear Global Non-Periodic IN NAK */ + unsigned sgnpinnak : 1; /*!< 07 Set Global Non-Periodic IN NAK */ + unsigned tstctl : 3; /*!< 06-04 Test Control */ + unsigned goutnaksts : 1; /*!< 03 Global OUT NAK Status */ + unsigned gnpinnaksts : 1; /*!< 02 Global Non-Periodic IN NAK Status */ + unsigned sftdiscon : 1; /*!< 01 Soft Disconnect */ + unsigned rmtwkupsig : 1; /*!< 00 Remote Wakeup */ + } b; +} dctl_data_t; + + +/*! + \brief Bit fields in the Device Status Register. + */ +typedef union dsts_data +{ + uint32_t d32; + struct + { + unsigned reserved22_31 :10; + unsigned soffn :14; /*!< 21-08 Frame or Microframe Number of the received SOF */ + unsigned reserved4_7 : 4; + unsigned errticerr : 1; /*!< 03 Erratic Error */ + unsigned enumspd : 2; /*!< 02-01 Enumerated Speed */ + #define IFXUSB_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ 0 + #define IFXUSB_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ 1 + #define IFXUSB_DSTS_ENUMSPD_LS_PHY_6MHZ 2 + #define IFXUSB_DSTS_ENUMSPD_FS_PHY_48MHZ 3 + unsigned suspsts : 1; /*!< 00 Suspend Status */ + } b; +} dsts_data_t; + +/*! + \brief Bit fields in the Device IN EP Interrupt Register + and the Device IN EP Common Mask Register. + */ +typedef union diepint_data +{ + uint32_t d32; + struct + { + unsigned reserved14_31 :18; + unsigned nakmsk : 1; /*!< 13 NAK interrupt Mask */ + unsigned reserved10_12 : 3; + unsigned bna : 1; /*!< 09 BNA Interrupt mask */ + unsigned txfifoundrn : 1; /*!< 08 Fifo Underrun Mask */ + unsigned emptyintr : 1; /*!< 07 IN Endpoint HAK Effective mask */ + unsigned inepnakeff : 1; /*!< 06 IN Endpoint HAK Effective mask */ + unsigned intknepmis : 1; /*!< 05 IN Token Received with EP mismatch mask */ + unsigned intktxfemp : 1; /*!< 04 IN Token received with TxF Empty mask */ + unsigned timeout : 1; /*!< 03 TimeOUT Handshake mask (non-ISOC EPs) */ + unsigned ahberr : 1; /*!< 02 AHB Error mask */ + unsigned epdisabled : 1; /*!< 01 Endpoint disable mask */ + unsigned xfercompl : 1; /*!< 00 Transfer complete mask */ + } b; +} diepint_data_t; + + +/*! + \brief Bit fields in the Device OUT EP Interrupt Register and + Device OUT EP Common Interrupt Mask Register. + */ +typedef union doepint_data +{ + uint32_t d32; + struct + { + unsigned reserved15_31 :17; + unsigned nyetmsk : 1; /*!< 14 NYET Interrupt */ + unsigned nakmsk : 1; /*!< 13 NAK Interrupt */ + unsigned bbleerrmsk : 1; /*!< 12 Babble Interrupt */ + unsigned reserved10_11 : 2; + unsigned bna : 1; /*!< 09 BNA Interrupt */ + unsigned outpkterr : 1; /*!< 08 OUT packet Error */ + unsigned reserved07 : 1; + unsigned back2backsetup : 1; /*!< 06 Back-to-Back SETUP Packets Received */ + unsigned stsphsercvd : 1; /*!< 05 */ + unsigned outtknepdis : 1; /*!< 04 OUT Token Received when Endpoint Disabled */ + unsigned setup : 1; /*!< 03 Setup Phase Done (contorl EPs) */ + unsigned ahberr : 1; /*!< 02 AHB Error */ + unsigned epdisabled : 1; /*!< 01 Endpoint disable */ + unsigned xfercompl : 1; /*!< 00 Transfer complete */ + } b; +} doepint_data_t; + + +/*! + \brief Bit fields in the Device All EP Interrupt Registers. + */ +typedef union daint_data +{ + uint32_t d32; + struct + { + unsigned out : 16; /*!< 31-16 OUT Endpoint bits */ + unsigned in : 16; /*!< 15-00 IN Endpoint bits */ + } eps; + struct + { + /** OUT Endpoint bits */ + unsigned outep15 : 1; + unsigned outep14 : 1; + unsigned outep13 : 1; + unsigned outep12 : 1; + unsigned outep11 : 1; + unsigned outep10 : 1; + unsigned outep09 : 1; + unsigned outep08 : 1; + unsigned outep07 : 1; + unsigned outep06 : 1; + unsigned outep05 : 1; + unsigned outep04 : 1; + unsigned outep03 : 1; + unsigned outep02 : 1; + unsigned outep01 : 1; + unsigned outep00 : 1; + /** IN Endpoint bits */ + unsigned inep15 : 1; + unsigned inep14 : 1; + unsigned inep13 : 1; + unsigned inep12 : 1; + unsigned inep11 : 1; + unsigned inep10 : 1; + unsigned inep09 : 1; + unsigned inep08 : 1; + unsigned inep07 : 1; + unsigned inep06 : 1; + unsigned inep05 : 1; + unsigned inep04 : 1; + unsigned inep03 : 1; + unsigned inep02 : 1; + unsigned inep01 : 1; + unsigned inep00 : 1; + } ep; +} daint_data_t; + + +/*! + \brief Bit fields in the Device IN Token Queue Read Registers. + */ +typedef union dtknq1_data +{ + uint32_t d32; + struct + { + unsigned epnums0_5 :24; /*!< 31-08 EP Numbers of IN Tokens 0 ... 4 */ + unsigned wrap_bit : 1; /*!< 07 write pointer has wrapped */ + unsigned reserved05_06 : 2; + unsigned intknwptr : 5; /*!< 04-00 In Token Queue Write Pointer */ + }b; +} dtknq1_data_t; + + +/*! + \brief Bit fields in Threshold control Register + */ +typedef union dthrctl_data +{ + uint32_t d32; + struct + { + unsigned reserved26_31 : 6; + unsigned rx_thr_len : 9; /*!< 25-17 Rx Thr. Length */ + unsigned rx_thr_en : 1; /*!< 16 Rx Thr. Enable */ + unsigned reserved11_15 : 5; + unsigned tx_thr_len : 9; /*!< 10-02 Tx Thr. Length */ + unsigned iso_thr_en : 1; /*!< 01 ISO Tx Thr. Enable */ + unsigned non_iso_thr_en : 1; /*!< 00 non ISO Tx Thr. Enable */ + } b; +} dthrctl_data_t; + +/*@}*//*IFXUSB_CSR_DEVICE_GLOBAL_REG*/ + +/****************************************************************************/ + +/*! + \addtogroup IFXUSB_CSR_DEVICE_EP_REG + */ +/*@{*/ + +/*! typedef ifxusb_dev_in_ep_regs_t + \brief Device Logical IN Endpoint-Specific Registers. + There will be one set of endpoint registers per logical endpoint + implemented. + each EP's IN EP Register are offset at : + 900h + * (ep_num * 20h) + */ + +typedef struct ifxusb_dev_in_ep_regs +{ + volatile uint32_t diepctl; /*!< 00h: Endpoint Control Register */ + uint32_t reserved04; /*!< 04h: */ + volatile uint32_t diepint; /*!< 08h: Endpoint Interrupt Register */ + uint32_t reserved0C; /*!< 0Ch: */ + volatile uint32_t dieptsiz; /*!< 10h: Endpoint Transfer Size Register.*/ + volatile uint32_t diepdma; /*!< 14h: Endpoint DMA Address Register. */ + volatile uint32_t dtxfsts; /*!< 18h: Endpoint Transmit FIFO Status Register. */ + volatile uint32_t diepdmab; /*!< 1Ch: Endpoint DMA Buffer Register. */ +} ifxusb_dev_in_ep_regs_t; + +/*! typedef ifxusb_dev_out_ep_regs_t + \brief Device Logical OUT Endpoint-Specific Registers. + There will be one set of endpoint registers per logical endpoint + implemented. + each EP's OUT EP Register are offset at : + B00h + * (ep_num * 20h) + 00h + */ +typedef struct ifxusb_dev_out_ep_regs +{ + volatile uint32_t doepctl; /*!< 00h: Endpoint Control Register */ + volatile uint32_t doepfn; /*!< 04h: Endpoint Frame number Register */ + volatile uint32_t doepint; /*!< 08h: Endpoint Interrupt Register */ + uint32_t reserved0C; /*!< 0Ch: */ + volatile uint32_t doeptsiz; /*!< 10h: Endpoint Transfer Size Register.*/ + volatile uint32_t doepdma; /*!< 14h: Endpoint DMA Address Register. */ + uint32_t reserved18; /*!< 18h: */ + volatile uint32_t doepdmab; /*!< 1Ch: Endpoint DMA Buffer Register. */ +} ifxusb_dev_out_ep_regs_t; + + +/*! + \brief Bit fields in the Device EP Control + Register. + */ +typedef union depctl_data +{ + uint32_t d32; + struct + { + unsigned epena : 1; /*!< 31 Endpoint Enable */ + unsigned epdis : 1; /*!< 30 Endpoint Disable */ + unsigned setd1pid : 1; /*!< 29 Set DATA1 PID (INTR/Bulk IN and OUT endpoints) */ + unsigned setd0pid : 1; /*!< 28 Set DATA0 PID (INTR/Bulk IN and OUT endpoints) */ + unsigned snak : 1; /*!< 27 Set NAK */ + unsigned cnak : 1; /*!< 26 Clear NAK */ + unsigned txfnum : 4; /*!< 25-22 Tx Fifo Number */ + unsigned stall : 1; /*!< 21 Stall Handshake */ + unsigned snp : 1; /*!< 20 Snoop Mode */ + unsigned eptype : 2; /*!< 19-18 Endpoint Type + 0: Control + 1: Isochronous + 2: Bulk + 3: Interrupt + */ + unsigned naksts : 1; /*!< 17 NAK Status */ + unsigned dpid : 1; /*!< 16 Endpoint DPID (INTR/Bulk IN and OUT endpoints) */ + unsigned usbactep : 1; /*!< 15 USB Active Endpoint */ + unsigned nextep : 4; /*!< 14-11 Next Endpoint */ + unsigned mps :11; /*!< 10-00 Maximum Packet Size */ + #define IFXUSB_DEP0CTL_MPS_64 0 + #define IFXUSB_DEP0CTL_MPS_32 1 + #define IFXUSB_DEP0CTL_MPS_16 2 + #define IFXUSB_DEP0CTL_MPS_8 3 + } b; +} depctl_data_t; + + +/*! + \brief Bit fields in the Device EP Transfer Size Register. (EP0 and EPn) + */ +typedef union deptsiz_data +{ + uint32_t d32; + struct + { + unsigned reserved31 : 1; + unsigned supcnt : 2; /*!< 30-29 Setup Packet Count */ + #ifdef __DED_FIFO__ + unsigned reserved21_28 : 8; + unsigned pktcnt : 2; /*!< 19-20 Packet Count */ + #else + unsigned reserved20_28 : 9; + unsigned pktcnt : 1; /*!< 19 Packet Count */ + #endif + unsigned reserved7_18 :12; + unsigned xfersize : 7; /*!< 06-00 Transfer size */ + }b0; + struct + { + unsigned reserved : 1; + unsigned mc : 2; /*!< 30-29 Multi Count */ + unsigned pktcnt :10; /*!< 28-19 Packet Count */ + unsigned xfersize :19; /*!< 18-00 Transfer size */ + } b; +} deptsiz_data_t; + +/*@}*//*IFXUSB_CSR_DEVICE_EP_REG*/ +/****************************************************************************/ + +/*! + \addtogroup IFXUSB_CSR_DEVICE_DMA_DESC + */ +/*@{*/ +/*! + \brief Bit fields in the DMA Descriptor status quadlet. + */ +typedef union desc_sts_data +{ + struct + { + unsigned bs : 2; /*!< 31-30 Buffer Status */ + #define BS_HOST_READY 0x0 + #define BS_DMA_BUSY 0x1 + #define BS_DMA_DONE 0x2 + #define BS_HOST_BUSY 0x3 + unsigned sts : 2; /*!< 29-28 Receive/Trasmit Status */ + #define RTS_SUCCESS 0x0 + #define RTS_BUFFLUSH 0x1 + #define RTS_RESERVED 0x2 + #define RTS_BUFERR 0x3 + unsigned l : 1; /*!< 27 Last */ + unsigned sp : 1; /*!< 26 Short Packet */ + unsigned ioc : 1; /*!< 25 Interrupt On Complete */ + unsigned sr : 1; /*!< 24 Setup Packet received */ + unsigned mtrf : 1; /*!< 23 Multiple Transfer */ + unsigned reserved16_22 : 7; + unsigned bytes :16; /*!< 15-00 Transfer size in bytes */ + } b; + uint32_t d32; /*!< DMA Descriptor data buffer pointer */ +} desc_sts_data_t; + +/*@}*//*IFXUSB_CSR_DEVICE_DMA_DESC*/ +/****************************************************************************/ + +/*! + \addtogroup IFXUSB_CSR_HOST_GLOBAL_REG + */ +/*@{*/ +/*! typedef ifxusb_host_global_regs_t + \brief IFXUSB Host Mode Global registers. Offsets 400h-7FFh + The ifxusb_host_global_regs structure defines the size + and relative field offsets for the Host Global registers. + These registers are visible only in Host mode and must not be + accessed in Device mode, as the results are unknown. + */ +typedef struct ifxusb_host_global_regs +{ + volatile uint32_t hcfg; /*!< 400h Host Configuration Register. */ + volatile uint32_t hfir; /*!< 404h Host Frame Interval Register. */ + volatile uint32_t hfnum; /*!< 408h Host Frame Number / Frame Remaining Register. */ + uint32_t reserved40C; + volatile uint32_t hptxsts; /*!< 410h Host Periodic Transmit FIFO/ Queue Status Register. */ + volatile uint32_t haint; /*!< 414h Host All Channels Interrupt Register. */ + volatile uint32_t haintmsk; /*!< 418h Host All Channels Interrupt Mask Register. */ +} ifxusb_host_global_regs_t; + +/*! + \brief Bit fields in the Host Configuration Register. + */ +typedef union hcfg_data +{ + uint32_t d32; + struct + { + unsigned reserved31_03 :29; + unsigned fslssupp : 1; /*!< 02 FS/LS Only Support */ + unsigned fslspclksel : 2; /*!< 01-00 FS/LS Phy Clock Select */ + #define IFXUSB_HCFG_30_60_MHZ 0 + #define IFXUSB_HCFG_48_MHZ 1 + #define IFXUSB_HCFG_6_MHZ 2 + } b; +} hcfg_data_t; + +/*! + \brief Bit fields in the Host Frame Interval Register. + */ +typedef union hfir_data +{ + uint32_t d32; + struct + { + unsigned reserved : 16; + unsigned frint : 16; /*!< 15-00 Frame Interval */ + } b; +} hfir_data_t; + +/*! + \brief Bit fields in the Host Frame Time Remaing/Number Register. + */ +typedef union hfnum_data +{ + uint32_t d32; + struct + { + unsigned frrem : 16; /*!< 31-16 Frame Time Remaining */ + unsigned frnum : 16; /*!< 15-00 Frame Number*/ + #define IFXUSB_HFNUM_MAX_FRNUM 0x3FFF + } b; +} hfnum_data_t; + +/*! + \brief Bit fields in the Host Periodic Transmit FIFO/Queue Status Register + */ +typedef union hptxsts_data +{ + /** raw register data */ + uint32_t d32; + struct + { + /** Top of the Periodic Transmit Request Queue + * - bit 24 - Terminate (last entry for the selected channel) + */ + unsigned ptxqtop_odd : 1; /*!< 31 Top of the Periodic Transmit Request + Queue Odd/even microframe*/ + unsigned ptxqtop_chnum : 4; /*!< 30-27 Top of the Periodic Transmit Request + Channel Number */ + unsigned ptxqtop_token : 2; /*!< 26-25 Top of the Periodic Transmit Request + Token Type + 0 - Zero length + 1 - Ping + 2 - Disable + */ + unsigned ptxqtop_terminate : 1; /*!< 24 Top of the Periodic Transmit Request + Terminate (last entry for the selected channel)*/ + unsigned ptxqspcavail : 8; /*!< 23-16 Periodic Transmit Request Queue Space Available */ + unsigned ptxfspcavail :16; /*!< 15-00 Periodic Transmit Data FIFO Space Available */ + } b; +} hptxsts_data_t; + +/*! + \brief Bit fields in the Host Port Control and Status Register. + */ +typedef union hprt0_data +{ + uint32_t d32; + struct + { + unsigned reserved19_31 :13; + unsigned prtspd : 2; /*!< 18-17 Port Speed */ + #define IFXUSB_HPRT0_PRTSPD_HIGH_SPEED 0 + #define IFXUSB_HPRT0_PRTSPD_FULL_SPEED 1 + #define IFXUSB_HPRT0_PRTSPD_LOW_SPEED 2 + unsigned prttstctl : 4; /*!< 16-13 Port Test Control */ + unsigned prtpwr : 1; /*!< 12 Port Power */ + unsigned prtlnsts : 2; /*!< 11-10 Port Line Status */ + unsigned reserved9 : 1; + unsigned prtrst : 1; /*!< 08 Port Reset */ + unsigned prtsusp : 1; /*!< 07 Port Suspend */ + unsigned prtres : 1; /*!< 06 Port Resume */ + unsigned prtovrcurrchng : 1; /*!< 05 Port Overcurrent Change */ + unsigned prtovrcurract : 1; /*!< 04 Port Overcurrent Active */ + unsigned prtenchng : 1; /*!< 03 Port Enable/Disable Change */ + unsigned prtena : 1; /*!< 02 Port Enable */ + unsigned prtconndet : 1; /*!< 01 Port Connect Detected */ + unsigned prtconnsts : 1; /*!< 00 Port Connect Status */ + }b; +} hprt0_data_t; + +/*! + \brief Bit fields in the Host All Interrupt Register. + */ +typedef union haint_data +{ + uint32_t d32; + struct + { + unsigned reserved : 16; + unsigned ch15 : 1; + unsigned ch14 : 1; + unsigned ch13 : 1; + unsigned ch12 : 1; + unsigned ch11 : 1; + unsigned ch10 : 1; + unsigned ch09 : 1; + unsigned ch08 : 1; + unsigned ch07 : 1; + unsigned ch06 : 1; + unsigned ch05 : 1; + unsigned ch04 : 1; + unsigned ch03 : 1; + unsigned ch02 : 1; + unsigned ch01 : 1; + unsigned ch00 : 1; + } b; + struct + { + unsigned reserved : 16; + unsigned chint : 16; + } b2; +} haint_data_t; +/*@}*//*IFXUSB_CSR_HOST_GLOBAL_REG*/ +/****************************************************************************/ +/*! + \addtogroup IFXUSB_CSR_HOST_HC_REG + */ +/*@{*/ +/*! typedef ifxusb_hc_regs_t + \brief Host Channel Specific Registers + There will be one set of hc registers per host channelimplemented. + each HC's Register are offset at : + 500h + * (hc_num * 20h) + */ +typedef struct ifxusb_hc_regs +{ + volatile uint32_t hcchar; /*!< 00h Host Channel Characteristic Register.*/ + volatile uint32_t hcsplt; /*!< 04h Host Channel Split Control Register.*/ + volatile uint32_t hcint; /*!< 08h Host Channel Interrupt Register. */ + volatile uint32_t hcintmsk; /*!< 0Ch Host Channel Interrupt Mask Register. */ + volatile uint32_t hctsiz; /*!< 10h Host Channel Transfer Size Register. */ + volatile uint32_t hcdma; /*!< 14h Host Channel DMA Address Register. */ + uint32_t reserved[2]; /*!< 18h Reserved. */ +} ifxusb_hc_regs_t; + + +/*! + \brief Bit fields in the Host Channel Characteristics Register. + */ +typedef union hcchar_data +{ + uint32_t d32; + struct + { + unsigned chen : 1; /*!< 31 Channel enable */ + unsigned chdis : 1; /*!< 30 Channel disable */ + unsigned oddfrm : 1; /*!< 29 Frame to transmit periodic transaction */ + unsigned devaddr : 7; /*!< 28-22 Device address */ + unsigned multicnt : 2; /*!< 21-20 Packets per frame for periodic transfers */ + unsigned eptype : 2; /*!< 19-18 0: Control, 1: Isoc, 2: Bulk, 3: Intr */ + unsigned lspddev : 1; /*!< 17 0: Full/high speed device, 1: Low speed device */ + unsigned reserved : 1; + unsigned epdir : 1; /*!< 15 0: OUT, 1: IN */ + unsigned epnum : 4; /*!< 14-11 Endpoint number */ + unsigned mps :11; /*!< 10-00 Maximum packet size in bytes */ + } b; +} hcchar_data_t; + +/*! + \brief Bit fields in the Host Channel Split Control Register + */ +typedef union hcsplt_data +{ + uint32_t d32; + struct + { + unsigned spltena : 1; /*!< 31 Split Enble */ + unsigned reserved :14; + unsigned compsplt : 1; /*!< 16 Do Complete Split */ + unsigned xactpos : 2; /*!< 15-14 Transaction Position */ + #define IFXUSB_HCSPLIT_XACTPOS_MID 0 + #define IFXUSB_HCSPLIT_XACTPOS_END 1 + #define IFXUSB_HCSPLIT_XACTPOS_BEGIN 2 + #define IFXUSB_HCSPLIT_XACTPOS_ALL 3 + unsigned hubaddr : 7; /*!< 13-07 Hub Address */ + unsigned prtaddr : 7; /*!< 06-00 Port Address */ + } b; +} hcsplt_data_t; + +/*! + \brief Bit fields in the Host Interrupt Register. + */ +typedef union hcint_data +{ + uint32_t d32; + struct + { + unsigned reserved :21; + unsigned datatglerr : 1; /*!< 10 Data Toggle Error */ + unsigned frmovrun : 1; /*!< 09 Frame Overrun */ + unsigned bblerr : 1; /*!< 08 Babble Error */ + unsigned xacterr : 1; /*!< 07 Transaction Err */ + unsigned nyet : 1; /*!< 06 NYET Response Received */ + unsigned ack : 1; /*!< 05 ACK Response Received */ + unsigned nak : 1; /*!< 04 NAK Response Received */ + unsigned stall : 1; /*!< 03 STALL Response Received */ + unsigned ahberr : 1; /*!< 02 AHB Error */ + unsigned chhltd : 1; /*!< 01 Channel Halted */ + unsigned xfercomp : 1; /*!< 00 Channel Halted */ + }b; +} hcint_data_t; + + +/*! + \brief Bit fields in the Host Channel Transfer Size + Register. + */ +typedef union hctsiz_data +{ + uint32_t d32; + struct + { + /** */ + unsigned dopng : 1; /*!< 31 Do PING protocol when 1 */ + /** + * Packet ID for next data packet + * 0: DATA0 + * 1: DATA2 + * 2: DATA1 + * 3: MDATA (non-Control), SETUP (Control) + */ + unsigned pid : 2; /*!< 30-29 Packet ID for next data packet + 0: DATA0 + 1: DATA2 + 2: DATA1 + 3: MDATA (non-Control), SETUP (Control) + */ + #define IFXUSB_HCTSIZ_DATA0 0 + #define IFXUSB_HCTSIZ_DATA1 2 + #define IFXUSB_HCTSIZ_DATA2 1 + #define IFXUSB_HCTSIZ_MDATA 3 + #define IFXUSB_HCTSIZ_SETUP 3 + unsigned pktcnt :10; /*!< 28-19 Data packets to transfer */ + unsigned xfersize :19; /*!< 18-00 Total transfer size in bytes */ + }b; +} hctsiz_data_t; + +/*@}*//*IFXUSB_CSR_HOST_HC_REG*/ + +/****************************************************************************/ + +/*! + \addtogroup IFXUSB_CSR_PWR_CLK_GATING_REG + */ +/*@{*/ +/*! + \brief Bit fields in the Power and Clock Gating Control Register + */ +typedef union pcgcctl_data +{ + uint32_t d32; + struct + { + unsigned reserved : 27; + unsigned physuspended : 1; /*!< 04 PHY Suspended */ + unsigned rstpdwnmodule : 1; /*!< 03 Reset Power Down Modules */ + unsigned pwrclmp : 1; /*!< 02 Power Clamp */ + unsigned gatehclk : 1; /*!< 01 Gate Hclk */ + unsigned stoppclk : 1; /*!< 00 Stop Pclk */ + } b; +} pcgcctl_data_t; +/*@}*//*IFXUSB_CSR_PWR_CLK_GATING_REG*/ + +/****************************************************************************/ + +#endif //__IFXUSB_REGS_H__ diff --git a/package/platform/lantiq/ltq-hcd/src/ifxusb_version.h b/package/platform/lantiq/ltq-hcd/src/ifxusb_version.h new file mode 100644 index 0000000000..11e346e3db --- /dev/null +++ b/package/platform/lantiq/ltq-hcd/src/ifxusb_version.h @@ -0,0 +1,5 @@ + +#ifndef IFXUSB_VERSION +#define IFXUSB_VERSION "3.2 B110801" +#endif + -- 2.11.0