mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-24 01:33:10 +02:00
[lantiq] add ltq-hcd
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@34688 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
parent
7185dc2440
commit
1742d60189
51
package/platform/lantiq/ltq-hcd/Makefile
Normal file
51
package/platform/lantiq/ltq-hcd/Makefile
Normal file
@ -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 <blogic@openwrt.org>
|
||||||
|
|
||||||
|
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))
|
104
package/platform/lantiq/ltq-hcd/src/Kconfig
Normal file
104
package/platform/lantiq/ltq-hcd/src/Kconfig
Normal file
@ -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.
|
||||||
|
|
74
package/platform/lantiq/ltq-hcd/src/Makefile
Normal file
74
package/platform/lantiq/ltq-hcd/src/Makefile
Normal file
@ -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__
|
||||||
|
|
2141
package/platform/lantiq/ltq-hcd/src/ifxhcd.c
Normal file
2141
package/platform/lantiq/ltq-hcd/src/ifxhcd.c
Normal file
File diff suppressed because it is too large
Load Diff
758
package/platform/lantiq/ltq-hcd/src/ifxhcd.h
Normal file
758
package/platform/lantiq/ltq-hcd/src/ifxhcd.h
Normal file
@ -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 <linux/list.h>
|
||||||
|
#include <linux/usb.h>
|
||||||
|
|
||||||
|
#include <linux/usb/hcd.h>
|
||||||
|
|
||||||
|
#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__
|
||||||
|
|
599
package/platform/lantiq/ltq-hcd/src/ifxhcd_es.c
Normal file
599
package/platform/lantiq/ltq-hcd/src/ifxhcd_es.c
Normal file
@ -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 <linux/version.h>
|
||||||
|
#include "ifxusb_version.h"
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
|
#include <linux/errno.h>
|
||||||
|
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
|
||||||
|
#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__
|
||||||
|
|
4844
package/platform/lantiq/ltq-hcd/src/ifxhcd_intr.c
Normal file
4844
package/platform/lantiq/ltq-hcd/src/ifxhcd_intr.c
Normal file
File diff suppressed because it is too large
Load Diff
485
package/platform/lantiq/ltq-hcd/src/ifxhcd_queue.c
Normal file
485
package/platform/lantiq/ltq-hcd/src/ifxhcd_queue.c
Normal file
@ -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 <linux/version.h>
|
||||||
|
#include "ifxusb_version.h"
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/moduleparam.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/list.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
1686
package/platform/lantiq/ltq-hcd/src/ifxusb_cif.c
Normal file
1686
package/platform/lantiq/ltq-hcd/src/ifxusb_cif.c
Normal file
File diff suppressed because it is too large
Load Diff
767
package/platform/lantiq/ltq-hcd/src/ifxusb_cif.h
Normal file
767
package/platform/lantiq/ltq-hcd/src/ifxusb_cif.h
Normal file
@ -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 <linux/workqueue.h>
|
||||||
|
|
||||||
|
#include <linux/version.h>
|
||||||
|
#include <asm/param.h>
|
||||||
|
|
||||||
|
#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__)
|
||||||
|
|
535
package/platform/lantiq/ltq-hcd/src/ifxusb_cif_d.c
Normal file
535
package/platform/lantiq/ltq-hcd/src/ifxusb_cif_d.c
Normal file
@ -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 <linux/version.h>
|
||||||
|
#include "ifxusb_version.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <asm/byteorder.h>
|
||||||
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
|
#ifdef __DEBUG__
|
||||||
|
#include <linux/jiffies.h>
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
1599
package/platform/lantiq/ltq-hcd/src/ifxusb_cif_h.c
Normal file
1599
package/platform/lantiq/ltq-hcd/src/ifxusb_cif_h.c
Normal file
File diff suppressed because it is too large
Load Diff
3825
package/platform/lantiq/ltq-hcd/src/ifxusb_ctl.c
Normal file
3825
package/platform/lantiq/ltq-hcd/src/ifxusb_ctl.c
Normal file
File diff suppressed because it is too large
Load Diff
1279
package/platform/lantiq/ltq-hcd/src/ifxusb_driver.c
Normal file
1279
package/platform/lantiq/ltq-hcd/src/ifxusb_driver.c
Normal file
File diff suppressed because it is too large
Load Diff
BIN
package/platform/lantiq/ltq-hcd/src/ifxusb_host.ko
Normal file
BIN
package/platform/lantiq/ltq-hcd/src/ifxusb_host.ko
Normal file
Binary file not shown.
1184
package/platform/lantiq/ltq-hcd/src/ifxusb_plat.h
Normal file
1184
package/platform/lantiq/ltq-hcd/src/ifxusb_plat.h
Normal file
File diff suppressed because it is too large
Load Diff
1471
package/platform/lantiq/ltq-hcd/src/ifxusb_regs.h
Normal file
1471
package/platform/lantiq/ltq-hcd/src/ifxusb_regs.h
Normal file
File diff suppressed because it is too large
Load Diff
5
package/platform/lantiq/ltq-hcd/src/ifxusb_version.h
Normal file
5
package/platform/lantiq/ltq-hcd/src/ifxusb_version.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
#ifndef IFXUSB_VERSION
|
||||||
|
#define IFXUSB_VERSION "3.2 B110801"
|
||||||
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue
Block a user