SPEAr : usbd driver support for SPEAr SoCs
PATCH v4 6/12 SPEAr : usbd driver support for SPEAr SoCs
SPEAr SoCs contain a synopsys usb device controller. USB Device IP can work in 2 modes
- DMA mode
- Slave mode
The driver adds support only for slave mode operation of usb device IP. This driver is used along with standard USBTTY driver to obtain a tty interface over USB on the host
--- drivers/serial/usbtty.h | 2 + drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/spr_udc.c | 1002 ++++++++++++++++++++++++++++++++++++++++++ include/usb/spr_udc.h | 227 ++++++++++ 4 files changed, 1232 insertions(+), 0 deletions(-)
mode change 100644 => 100755 drivers/serial/usbtty.h mode change 100644 => 100755 drivers/usb/gadget/Makefile create mode 100755 drivers/usb/gadget/spr_udc.c create mode 100755 include/usb/spr_udc.h
<snip>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <usbdevice.h>
+#include "ep0.h"
+#include <usb/spr_udc.h>
+#include <asm/arch/spr_misc.h>
+
+#define UDC_INIT_MDELAY 80 /* Device settle delay */
ws
Some space before the '80'
+
+/* Some kind of debugging output... */
+#ifndef DEBUG_SPRUSBTTY
+#define UDCDBG(str)
+#define UDCDBGA(fmt, args...)
+#else
+#define UDCDBG(str) serial_printf(str "\n") +#define UDCDBGA(fmt, args...) serial_printf(fmt "\n", ##args) +#endif
+
+static struct urb *ep0_urb;
+static struct usb_device_instance *udc_device;
+
+static struct plug_regs *const plug_regs_p =
+ (struct plug_regs * const)CONFIG_SYS_PLUG_BASE;
+static struct udc_regs *const udc_regs_p =
+ (struct udc_regs * const)CONFIG_SYS_USBD_BASE;
+static struct udc_endp_regs *const outep_regs_p =
+ &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->out_regs[0];
+static struct udc_endp_regs *const inep_regs_p =
+ &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->in_regs[0];
+
Similar to other CONFIG_* register bases,
It may be better to move/rename the CONFIG_SYS_PLUG_BASE to an asm/arch header file.
+/*
+ * udc_state_transition - Write the next packet to TxFIFO.
<snip>
*
+ * This function must only be called with interrupts disabled.
+ */
+static void udc_state_transition(usb_device_state_t initial,
+ usb_device_state_t final)
+{
+ if (initial < final) {
+ switch (initial) {
+ case STATE_ATTACHED:
+ usbd_device_event_irq(udc_device,
+ DEVICE_HUB_CONFIGURED, 0);
+ if (final == STATE_POWERED)
+ break;
+ case STATE_POWERED:
+ usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+ if (final == STATE_DEFAULT)
+ break;
+ case STATE_DEFAULT:
+ usbd_device_event_irq(udc_device,
+ DEVICE_ADDRESS_ASSIGNED, 0);
+ if (final == STATE_ADDRESSED)
+ break;
+ case STATE_ADDRESSED:
+ usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
+ case STATE_CONFIGURED:
+ break;
+ default:
+ break;
+ }
+ } else if (initial > final) {
+ switch (initial) {
+ case STATE_CONFIGURED:
+ usbd_device_event_irq(udc_device,
+ DEVICE_DE_CONFIGURED, 0);
+ if (final == STATE_ADDRESSED)
+ break;
+ case STATE_ADDRESSED:
+ usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
+ if (final == STATE_DEFAULT)
+ break;
+ case STATE_DEFAULT:
+ usbd_device_event_irq(udc_device,
+ DEVICE_POWER_INTERRUPTION, 0);
+ if (final == STATE_POWERED)
+ break;
+ case STATE_POWERED:
+ usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0);
+ case STATE_ATTACHED:
+ break;
+ default:
+ break;
+ }
+ }
No panicing if the state transition is the default ? +}
+
<snip>
+static void *get_fifo(int ep_num, int in)
+{
+ u32 *fifo_ptr = (u32 *)CONFIG_SYS_FIFO_BASE;
+
+ switch (ep_num) {
+ case 3:
+ fifo_ptr += readl(&inep_regs_p[1].endp_bsorfn);
+ /* break intentionally left out */
+
+ case 1:
+ fifo_ptr += readl(&inep_regs_p[0].endp_bsorfn);
+ /* break intentionally left out */
+
These EP's should be the #defined UDC_*_ENDPOINT
+ case 0:
+ default:
+ if (in) {
+ fifo_ptr +=
+ readl(&outep_regs_p[2].endp_maxpacksize) >> 16;
+ /* break intentionally left out */
+ } else {
+ break;
+ }
+
+ case 2:
+ fifo_ptr += readl(&outep_regs_p[0].endp_maxpacksize) >> 16;
+ /* break intentionally left out */
+ }
+
+ return (void *)fifo_ptr;
+}
+
+static short usbgetpckfromfifo(int epNum, u8 *bufp, u32 len) +{
+ u8 *fifo_ptr = (u8 *)get_fifo(epNum, 0);
+ u32 i, nw, nb;
+ u32 *wrdp;
+ u8 *bytp;
+
+ if (readl(&udc_regs_p->dev_stat) & DEV_STAT_RXFIFO_EMPTY)
+ return -1;
+
+ nw = len / sizeof(u32);
+ nb = len % sizeof(u32);
+
+ wrdp = (u32 *)bufp;
Does this work when bufp is unaligned ?
+ for (i = 0; i < nw; i++) {
+ writel(readl(fifo_ptr), wrdp);
+ wrdp++;
+ }
+
+ bytp = (u8 *)wrdp;
+ for (i = 0; i < nb; i++) {
+ writeb(readb(fifo_ptr), bytp);
+ fifo_ptr++;
+ bytp++;
+ }
+ readl(&outep_regs_p[epNum].write_done);
+
+ return 0;
The status of this function is never checked. Choosing 'short' is also unusual.
Maybe this should be an int
+}
+
+static void usbputpcktofifo(int epNum, u8 *bufp, u32 len) +{
+ u32 i, nw, nb;
+ u32 *wrdp;
+ u8 *bytp;
+ u8 *fifo_ptr = get_fifo(epNum, 1);
+
+ nw = len / sizeof(int);
+ nb = len % sizeof(int);
+ wrdp = (u32 *)bufp;
+ for (i = 0; i < nw; i++) {
+ writel(*wrdp, fifo_ptr);
+ wrdp++;
+ }
+
+ bytp = (u8 *)wrdp;
+ for (i = 0; i < nb; i++) {
+ writeb(*bytp, fifo_ptr);
+ fifo_ptr++;
+ bytp++;
+ }
+}
<snip>
+/*
+ * Handle TX transaction on non-ISO endpoint.
+ * The ep argument is a physical endpoint number for a non-ISO IN endpoint
+ * in the range 16 to 30.
+ */
+static void spear_udc_epn_tx(int ep)
+{
+ struct usb_endpoint_instance *endpoint = spear_find_ep(ep);
This can return NULL
check if (endpoint)
+
+ /*
+ * We need to transmit a terminating zero-length packet now if
+ * we have sent all of the data in this URB and the transfer
+ * size was an exact multiple of the packet size.
+ */
+ if (endpoint->tx_urb && endpoint->tx_urb->actual_length) {
+ if (endpoint->last == endpoint->tx_packetSize) {
+ /* handle zero length packet here */
+ writel(0x0, &inep_regs_p[ep].write_done);
+ }
+ /* retire the data that was just sent */
+ usbd_tx_complete(endpoint);
+ /*
+ * Check to see if we have more data ready to transmit
+ * now.
+ */
+ if (endpoint->tx_urb && endpoint->tx_urb->actual_length) {
+ /* write data to FIFO */
+ spear_write_noniso_tx_fifo(endpoint);
+ writel(0x0, &inep_regs_p[ep].write_done);
+
+ } else if (endpoint->tx_urb
+ && (endpoint->tx_urb->actual_length == 0)) {
+ /* udc_set_nak(ep); */
+ }
+ }
+}
<snip>
+ writel(val, &outep_regs_p[epid].endp_cntl);
+}
+ +/*******************************************************************
+ * SLAVE MODE ::
+ * Routines to acces RX/TX FIFOs directly.
+ *******************************************************************/ ws
change to proper multi-line comment.
include/usb/spr_udc.h new file +35 -0
@@ -0,0 +1,227 @@ +/* +* (C) Copyright 2009 +* Vipin Kumar, ST Micoelectronics, vipin.kumar at st.com. +* +* See file CREDITS for list of people who contributed to this +* project. +* +* 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. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, +* MA 02111-1307 USA +*/ + +#ifndef __SPR_UDC_H +#define __SPR_UDC_H + +/***************************************************************************** +* Defines for USBD +* +* The udc_ahb controller has three AHB slaves: +* +* 1. THe UDC registers +* 2. The plug detect +* 3. The RX/TX FIFO +*****************************************************************************/
ws
change to proper multi-line comment
+
+#define MAX_ENDPOINTS 16
+
+struct udc_endp_regs {
+ u32 endp_cntl;
+ u32 endp_status;
+ u32 endp_bsorfn;
+ u32 endp_maxpacksize;
+ u32 reserved_1;
+ u32 endp_desc_point;
+ u32 reserved_2;
+ u32 write_done;
+};
+
+/* Endpoint Control Register definitions */
+
+#define ENDP_CNTL_STALL 0x00000001 +#define ENDP_CNTL_FLUSH 0x00000002 +#define ENDP_CNTL_SNOOP 0x00000004 +#define ENDP_CNTL_POLL 0x00000008 +#define ENDP_CNTL_CONTROL 0x00000000 +#define ENDP_CNTL_ISO 0x00000010 +#define ENDP_CNTL_BULK 0x00000020 +#define ENDP_CNTL_INT 0x00000030 +#define ENDP_CNTL_NAK 0x00000040 +#define ENDP_CNTL_SNAK 0x00000080 +#define ENDP_CNTL_CNAK 0x00000100 +#define ENDP_CNTL_RRDY 0x00000200 + +/* Endpoint Satus Register definitions */ + +#define ENDP_STATUS_PIDMSK 0x0000000f +#define ENDP_STATUS_OUTMSK 0x00000030 +#define ENDP_STATUS_OUT_NONE 0x00000000 +#define ENDP_STATUS_OUT_DATA 0x00000010 +#define ENDP_STATUS_OUT_SETUP 0x00000020 +#define ENDP_STATUS_IN 0x00000040 +#define ENDP_STATUS_BUFFNAV 0x00000080 +#define ENDP_STATUS_FATERR 0x00000100 +#define ENDP_STATUS_HOSTBUSERR 0x00000200 +#define ENDP_STATUS_TDC 0x00000400 +#define ENDP_STATUS_RXPKTMSK 0x003ff800
+
+struct udc_regs {
+ struct udc_endp_regs in_regs[MAX_ENDPOINTS];
+ struct udc_endp_regs out_regs[MAX_ENDPOINTS];
+ u32 dev_conf;
+ u32 dev_cntl;
+ u32 dev_stat;
+ u32 dev_int;
+ u32 dev_int_mask;
+ u32 endp_int;
+ u32 endp_int_mask;
+ u32 reserved_3[0x39];
+ u32 reserved_4; /* offset 0x500 */
+ u32 udc_endp_reg[MAX_ENDPOINTS];
+};
+
+/* Device Configuration Register definitions */
+
+#define DEV_CONF_HS_SPEED 0x00000000 +#define DEV_CONF_LS_SPEED 0x00000002 +#define DEV_CONF_FS_SPEED 0x00000003 +#define DEV_CONF_REMWAKEUP 0x00000004 +#define DEV_CONF_SELFPOW 0x00000008 +#define DEV_CONF_SYNCFRAME 0x00000010 +#define DEV_CONF_PHYINT_8 0x00000020 +#define DEV_CONF_PHYINT_16 0x00000000 +#define DEV_CONF_UTMI_BIDIR 0x00000040 +#define DEV_CONF_STATUS_STALL 0x00000080 + +/* Device Control Register definitions */ + +#define DEV_CNTL_RESUME 0x00000001 +#define DEV_CNTL_TFFLUSH 0x00000002 +#define DEV_CNTL_RXDMAEN 0x00000004 +#define DEV_CNTL_TXDMAEN 0x00000008 +#define DEV_CNTL_DESCRUPD 0x00000010 +#define DEV_CNTL_BIGEND 0x00000020 +#define DEV_CNTL_BUFFILL 0x00000040 +#define DEV_CNTL_TSHLDEN 0x00000080 +#define DEV_CNTL_BURSTEN 0x00000100 +#define DEV_CNTL_DMAMODE 0x00000200 +#define DEV_CNTL_SOFTDISCONNECT 0x00000400 +#define DEV_CNTL_SCALEDOWN 0x00000800 +#define DEV_CNTL_BURSTLENU 0x00010000 +#define DEV_CNTL_BURSTLENMSK 0x00ff0000 +#define DEV_CNTL_TSHLDLENU 0x01000000 +#define DEV_CNTL_TSHLDLENMSK 0xff000000 + +/* Device Status Register definitions */ + +#define DEV_STAT_CFG 0x0000000f +#define DEV_STAT_INTF 0x000000f0 +#define DEV_STAT_ALT 0x00000f00 +#define DEV_STAT_SUSP 0x00001000 +#define DEV_STAT_ENUM 0x00006000 +#define DEV_STAT_ENUM_SPEED_HS 0x00000000 +#define DEV_STAT_ENUM_SPEED_FS 0x00002000 +#define DEV_STAT_ENUM_SPEED_LS 0x00004000 +#define DEV_STAT_RXFIFO_EMPTY 0x00008000 +#define DEV_STAT_PHY_ERR 0x00010000 +#define DEV_STAT_TS 0xf0000000 + +/* Device Interrupt Register definitions */ + +#define DEV_INT_MSK 0x0000007f +#define DEV_INT_SETCFG 0x00000001 +#define DEV_INT_SETINTF 0x00000002 +#define DEV_INT_INACTIVE 0x00000004 +#define DEV_INT_USBRESET 0x00000008 +#define DEV_INT_SUSPUSB 0x00000010 +#define DEV_INT_SOF 0x00000020 +#define DEV_INT_ENUM 0x00000040 + +/* Endpoint Interrupt Register definitions */ + +#define ENDP0_INT_CTRLIN 0x00000001 +#define ENDP1_INT_BULKIN 0x00000002 +#define ENDP_INT_NONISOIN_MSK 0x0000AAAA +#define ENDP2_INT_BULKIN 0x00000004 +#define ENDP0_INT_CTRLOUT 0x00010000 +#define ENDP1_INT_BULKOUT 0x00020000 +#define ENDP2_INT_BULKOUT 0x00040000 +#define ENDP_INT_NONISOOUT_MSK 0x55540000 + +/* Endpoint Register definitions */ +#define ENDP_EPDIR_OUT 0x00000000 +#define ENDP_EPDIR_IN 0x00000010 +#define ENDP_EPTYPE_CNTL 0x0 +#define ENDP_EPTYPE_ISO 0x1 +#define ENDP_EPTYPE_BULK 0x2 +#define ENDP_EPTYPE_INT 0x3
+
+/*
+ * Defines for Plug Detect
+ */
+
+struct plug_regs {
+ u32 plug_state;
+ u32 plug_pending;
+};
+
+/* Plug State Register definitions */
+#define PLUG_STATUS_EN 0x1 +#define PLUG_STATUS_ATTACHED 0x2 +#define PLUG_STATUS_PHY_RESET 0x4 +#define PLUG_STATUS_PHY_MODE 0x8
+
+/*
+ * Defines for UDC FIFO (Slave Mode)
+ */
+struct udcfifo_regs {
+ u32 *fifo_p;
+};
+
+/*
+ * USBTTY definitions
+ */
+#define EP0_MAX_PACKET_SIZE 64 +#define UDC_INT_ENDPOINT 1 +#define UDC_INT_PACKET_SIZE 64 +#define UDC_OUT_ENDPOINT 2 +#define UDC_BULK_PACKET_SIZE 64 +#define UDC_IN_ENDPOINT 3 +#define UDC_OUT_PACKET_SIZE 64 +#define UDC_IN_PACKET_SIZE 64
ws
change leading spaces to tabs
+
+/*
+ * Function declarations
+ */
+
+void udc_irq(void);
+
+void udc_set_nak(int epid);
+void udc_unset_nak(int epid);
+
+int udc_endpoint_write(struct usb_endpoint_instance *endpoint); +
+int udc_init(void);
+
+void udc_enable(struct usb_device_instance *device);
+void udc_disable(void);
+
+void udc_connect(void);
+void udc_disconnect(void);
ws
could remove the extra empty line
+
+void udc_startup_events(struct usb_device_instance *device); +void udc_setup_ep(struct usb_device_instance *device, unsigned int ep,
+ struct usb_endpoint_instance *endpoint);
Tom
A message that is not in the archive (sent off-list or not yet received): [email protected]
PATCH v4 6/12 SPEAr : usbd driver support for SPEAr SoCs
Quoted 48 lines · Vipin Kumar
Hello Tom,
Quoted 46 lines
(quoted diff) +46
-0+static void udc_state_transition(usb_device_state_t initial, + usb_device_state_t final) +{ + if (initial < final) { + switch (initial) { + case STATE_ATTACHED: + usbd_device_event_irq(udc_device, + DEVICE_HUB_CONFIGURED, 0); + if (final == STATE_POWERED) + break; + case STATE_POWERED: + usbd_device_event_irq(udc_device, DEVICE_RESET, 0); + if (final == STATE_DEFAULT) + break; + case STATE_DEFAULT: + usbd_device_event_irq(udc_device, + DEVICE_ADDRESS_ASSIGNED, 0); + if (final == STATE_ADDRESSED) + break; + case STATE_ADDRESSED: + usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); + case STATE_CONFIGURED: + break; + default: + break; + } + } else if (initial > final) { + switch (initial) { + case STATE_CONFIGURED: + usbd_device_event_irq(udc_device, + DEVICE_DE_CONFIGURED, 0); + if (final == STATE_ADDRESSED) + break; + case STATE_ADDRESSED: + usbd_device_event_irq(udc_device, DEVICE_RESET, 0); + if (final == STATE_DEFAULT) + break; + case STATE_DEFAULT: + usbd_device_event_irq(udc_device, + DEVICE_POWER_INTERRUPTION, 0); + if (final == STATE_POWERED) + break; + case STATE_POWERED: + usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0); + case STATE_ATTACHED: + break;
Quoted 8 lines
Quoted 5 lines
(quoted diff) +4
-0+ default: + break; + } + }No panicing if the state transition is the default ?
default here is not an error case. The device state may be other than what are written as switch cases
Ok
Tom
Quoted 6 lines
All other review feedbacks are accepted.
Patch set v5 would contain the changesRegards
Vipin