summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorYoshihiro Shimoda <shimoda.yoshihiro@renesas.com>2008-07-09 21:07:38 +0900
committerMarkus Klotzbuecher <mk@denx.de>2008-08-07 17:37:36 +0200
commitfd0f2f3796ff2a7a32d35deb1b7996e485849df7 (patch)
tree2bdb8ef38517c0ab344103edb04434e31a9acc18 /drivers
parent1d10dcd041aaeae9fd7c821005692898a0303382 (diff)
downloadu-boot-imx-fd0f2f3796ff2a7a32d35deb1b7996e485849df7.zip
u-boot-imx-fd0f2f3796ff2a7a32d35deb1b7996e485849df7.tar.gz
u-boot-imx-fd0f2f3796ff2a7a32d35deb1b7996e485849df7.tar.bz2
usb: add support for R8A66597 usb controller
add support for Renesas R8A66597 usb controller. This patch supports USB Host mode. Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> Signed-off-by: Markus Klotzbuecher <mk@denx.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/Makefile1
-rw-r--r--drivers/usb/r8a66597-hcd.c924
-rw-r--r--drivers/usb/r8a66597.h663
3 files changed, 1588 insertions, 0 deletions
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 252b00e..2bdbb59 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -28,6 +28,7 @@ LIB := $(obj)libusb.a
COBJS-y += isp116x-hcd.o
COBJS-y += sl811_usb.o
COBJS-y += usb_ohci.o
+COBJS-y += r8a66597-hcd.o
COBJS-y += usbdcore.o
COBJS-y += usbdcore_ep0.o
COBJS-y += usbdcore_mpc8xx.o
diff --git a/drivers/usb/r8a66597-hcd.c b/drivers/usb/r8a66597-hcd.c
new file mode 100644
index 0000000..3eb4cb0
--- /dev/null
+++ b/drivers/usb/r8a66597-hcd.c
@@ -0,0 +1,924 @@
+/*
+ * R8A66597 HCD (Host Controller Driver) for u-boot
+ *
+ * Copyright (C) 2008 Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <common.h>
+#include <usb.h>
+#include <asm/io.h>
+
+#include "r8a66597.h"
+
+#if defined(CONFIG_USB_R8A66597_HCD)
+
+#ifdef R8A66597_DEBUG
+#define R8A66597_DPRINT printf
+#else
+#define R8A66597_DPRINT(...)
+#endif
+
+static const char hcd_name[] = "r8a66597_hcd";
+static unsigned short clock = CONFIG_R8A66597_XTAL;
+static unsigned short vif = CONFIG_R8A66597_LDRV;
+static unsigned short endian = CONFIG_R8A66597_ENDIAN;
+static struct r8a66597 gr8a66597;
+
+static void set_devadd_reg(struct r8a66597 *r8a66597, u8 r8a66597_address,
+ u16 usbspd, u8 upphub, u8 hubport, int port)
+{
+ u16 val;
+ unsigned long devadd_reg = get_devadd_addr(r8a66597_address);
+
+ val = (upphub << 11) | (hubport << 8) | (usbspd << 6) | (port & 0x0001);
+ r8a66597_write(r8a66597, val, devadd_reg);
+}
+
+static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
+{
+ u16 tmp;
+ int i = 0;
+
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+ do {
+ r8a66597_write(r8a66597, SCKE, SYSCFG0);
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (i++ > 1000) {
+ printf("register access fail.\n");
+ return -1;
+ }
+ } while ((tmp & SCKE) != SCKE);
+ r8a66597_write(r8a66597, 0x04, 0x02);
+#else
+ do {
+ r8a66597_write(r8a66597, USBE, SYSCFG0);
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (i++ > 1000) {
+ printf("register access fail.\n");
+ return -1;
+ }
+ } while ((tmp & USBE) != USBE);
+ r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+ r8a66597_mdfy(r8a66597, clock, XTAL, SYSCFG0);
+
+ i = 0;
+ r8a66597_bset(r8a66597, XCKE, SYSCFG0);
+ do {
+ udelay(1000);
+ tmp = r8a66597_read(r8a66597, SYSCFG0);
+ if (i++ > 500) {
+ printf("register access fail.\n");
+ return -1;
+ }
+ } while ((tmp & SCKE) != SCKE);
+#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */
+
+ return 0;
+}
+
+static void r8a66597_clock_disable(struct r8a66597 *r8a66597)
+{
+ r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
+ udelay(1);
+#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+ r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
+ r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
+ r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+#endif
+}
+
+static void r8a66597_enable_port(struct r8a66597 *r8a66597, int port)
+{
+ u16 val;
+
+ val = port ? DRPD : DCFM | DRPD;
+ r8a66597_bset(r8a66597, val, get_syscfg_reg(port));
+ r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port));
+
+ r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, get_dmacfg_reg(port));
+}
+
+static void r8a66597_disable_port(struct r8a66597 *r8a66597, int port)
+{
+ u16 val, tmp;
+
+ r8a66597_write(r8a66597, 0, get_intenb_reg(port));
+ r8a66597_write(r8a66597, 0, get_intsts_reg(port));
+
+ r8a66597_port_power(r8a66597, port, 0);
+
+ do {
+ tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS;
+ udelay(640);
+ } while (tmp == EDGESTS);
+
+ val = port ? DRPD : DCFM | DRPD;
+ r8a66597_bclr(r8a66597, val, get_syscfg_reg(port));
+ r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port));
+}
+
+static int enable_controller(struct r8a66597 *r8a66597)
+{
+ int ret, port;
+
+ ret = r8a66597_clock_enable(r8a66597);
+ if (ret < 0)
+ return ret;
+
+ r8a66597_bset(r8a66597, vif & LDRV, PINCFG);
+ r8a66597_bset(r8a66597, USBE, SYSCFG0);
+
+ r8a66597_bset(r8a66597, INTL, SOFCFG);
+ r8a66597_write(r8a66597, 0, INTENB0);
+ r8a66597_write(r8a66597, 0, INTENB1);
+ r8a66597_write(r8a66597, 0, INTENB2);
+
+ r8a66597_bset(r8a66597, endian & BIGEND, CFIFOSEL);
+ r8a66597_bset(r8a66597, endian & BIGEND, D0FIFOSEL);
+ r8a66597_bset(r8a66597, endian & BIGEND, D1FIFOSEL);
+ r8a66597_bset(r8a66597, TRNENSEL, SOFCFG);
+
+ for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+ r8a66597_enable_port(r8a66597, port);
+
+ return 0;
+}
+
+static void disable_controller(struct r8a66597 *r8a66597)
+{
+ int i;
+
+ if (!(r8a66597_read(r8a66597, SYSCFG0) & USBE))
+ return;
+
+ r8a66597_write(r8a66597, 0, INTENB0);
+ r8a66597_write(r8a66597, 0, INTSTS0);
+
+ r8a66597_write(r8a66597, 0, D0FIFOSEL);
+ r8a66597_write(r8a66597, 0, D1FIFOSEL);
+ r8a66597_write(r8a66597, 0, DCPCFG);
+ r8a66597_write(r8a66597, 0x40, DCPMAXP);
+ r8a66597_write(r8a66597, 0, DCPCTR);
+
+ for (i = 0; i <= 10; i++)
+ r8a66597_write(r8a66597, 0, get_devadd_addr(i));
+ for (i = 1; i <= 5; i++) {
+ r8a66597_write(r8a66597, 0, get_pipetre_addr(i));
+ r8a66597_write(r8a66597, 0, get_pipetrn_addr(i));
+ }
+ for (i = 1; i < R8A66597_MAX_NUM_PIPE; i++) {
+ r8a66597_write(r8a66597, 0, get_pipectr_addr(i));
+ r8a66597_write(r8a66597, i, PIPESEL);
+ r8a66597_write(r8a66597, 0, PIPECFG);
+ r8a66597_write(r8a66597, 0, PIPEBUF);
+ r8a66597_write(r8a66597, 0, PIPEMAXP);
+ r8a66597_write(r8a66597, 0, PIPEPERI);
+ }
+
+ for (i = 0; i < R8A66597_MAX_ROOT_HUB; i++)
+ r8a66597_disable_port(r8a66597, i);
+
+ r8a66597_clock_disable(r8a66597);
+}
+
+static void r8a66597_reg_wait(struct r8a66597 *r8a66597, unsigned long reg,
+ u16 mask, u16 loop)
+{
+ u16 tmp;
+ int i = 0;
+
+ do {
+ tmp = r8a66597_read(r8a66597, reg);
+ if (i++ > 1000000) {
+ printf("register%lx, loop %x is timeout\n", reg, loop);
+ break;
+ }
+ } while ((tmp & mask) != loop);
+}
+
+static void pipe_buffer_setting(struct r8a66597 *r8a66597,
+ struct usb_device *dev, unsigned long pipe)
+{
+ u16 val = 0;
+ u16 pipenum, bufnum, maxpacket;
+
+ if (usb_pipein(pipe)) {
+ pipenum = BULK_IN_PIPENUM;
+ bufnum = BULK_IN_BUFNUM;
+ maxpacket = dev->epmaxpacketin[usb_pipeendpoint(pipe)];
+ } else {
+ pipenum = BULK_OUT_PIPENUM;
+ bufnum = BULK_OUT_BUFNUM;
+ maxpacket = dev->epmaxpacketout[usb_pipeendpoint(pipe)];
+ }
+
+ if (r8a66597->pipe_config & (1 << pipenum))
+ return;
+ r8a66597->pipe_config |= (1 << pipenum);
+
+ r8a66597_bset(r8a66597, ACLRM, get_pipectr_addr(pipenum));
+ r8a66597_bclr(r8a66597, ACLRM, get_pipectr_addr(pipenum));
+ r8a66597_write(r8a66597, pipenum, PIPESEL);
+
+ /* FIXME: This driver support bulk transfer only. */
+ if (!usb_pipein(pipe))
+ val |= R8A66597_DIR;
+ else
+ val |= R8A66597_SHTNAK;
+ val |= R8A66597_BULK | R8A66597_DBLB | usb_pipeendpoint(pipe);
+ r8a66597_write(r8a66597, val, PIPECFG);
+
+ r8a66597_write(r8a66597, (8 << 10) | bufnum, PIPEBUF);
+ r8a66597_write(r8a66597, make_devsel(usb_pipedevice(pipe)) |
+ maxpacket, PIPEMAXP);
+ r8a66597_write(r8a66597, 0, PIPEPERI);
+ r8a66597_write(r8a66597, SQCLR, get_pipectr_addr(pipenum));
+}
+
+static int send_setup_packet(struct r8a66597 *r8a66597, struct usb_device *dev,
+ struct devrequest *setup)
+{
+ int i;
+ unsigned short *p = (unsigned short *)setup;
+ unsigned long setup_addr = USBREQ;
+ u16 intsts1;
+ int timeout = 3000;
+ u16 devsel = setup->request == USB_REQ_SET_ADDRESS ? 0 : dev->devnum;
+
+ r8a66597_write(r8a66597, make_devsel(devsel) |
+ (8 << dev->maxpacketsize), DCPMAXP);
+ r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
+
+ for (i = 0; i < 4; i++) {
+ r8a66597_write(r8a66597, le16_to_cpu(p[i]), setup_addr);
+ setup_addr += 2;
+ }
+ r8a66597_write(r8a66597, ~0x0001, BRDYSTS);
+ r8a66597_write(r8a66597, SUREQ, DCPCTR);
+
+ while (1) {
+ intsts1 = r8a66597_read(r8a66597, INTSTS1);
+ if (intsts1 & SACK)
+ break;
+ if (intsts1 & SIGN) {
+ printf("setup packet send error\n");
+ return -1;
+ }
+ if (timeout-- < 0) {
+ printf("setup packet timeout\n");
+ return -1;
+ }
+ udelay(500);
+ }
+
+ return 0;
+}
+
+static int send_bulk_packet(struct r8a66597 *r8a66597, struct usb_device *dev,
+ unsigned long pipe, void *buffer, int transfer_len)
+{
+ u16 tmp, bufsize;
+ u16 *buf;
+ size_t size;
+
+ R8A66597_DPRINT("%s\n", __func__);
+
+ r8a66597_mdfy(r8a66597, MBW | BULK_OUT_PIPENUM,
+ MBW | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, BULK_OUT_PIPENUM);
+ tmp = r8a66597_read(r8a66597, CFIFOCTR);
+ if ((tmp & FRDY) == 0) {
+ printf("%s FRDY is not set (%x)\n", __func__, tmp);
+ return -1;
+ }
+
+ /* prepare parameters */
+ bufsize = dev->epmaxpacketout[usb_pipeendpoint(pipe)];
+ buf = (u16 *)(buffer + dev->act_len);
+ size = min((int)bufsize, transfer_len - dev->act_len);
+
+ /* write fifo */
+ r8a66597_write(r8a66597, ~(1 << BULK_OUT_PIPENUM), BEMPSTS);
+ if (buffer) {
+ r8a66597_write_fifo(r8a66597, CFIFO, buf, size);
+ r8a66597_write(r8a66597, BVAL, CFIFOCTR);
+ }
+
+ /* update parameters */
+ dev->act_len += size;
+
+ r8a66597_mdfy(r8a66597, PID_BUF, PID,
+ get_pipectr_addr(BULK_OUT_PIPENUM));
+
+ while (!(r8a66597_read(r8a66597, BEMPSTS) & (1 << BULK_OUT_PIPENUM)))
+ if (ctrlc())
+ return -1;
+ r8a66597_write(r8a66597, ~(1 << BULK_OUT_PIPENUM), BEMPSTS);
+
+ if (dev->act_len >= transfer_len)
+ r8a66597_mdfy(r8a66597, PID_NAK, PID,
+ get_pipectr_addr(BULK_OUT_PIPENUM));
+
+ return 0;
+}
+
+static int receive_bulk_packet(struct r8a66597 *r8a66597,
+ struct usb_device *dev,
+ unsigned long pipe,
+ void *buffer, int transfer_len)
+{
+ u16 tmp;
+ u16 *buf;
+ const u16 pipenum = BULK_IN_PIPENUM;
+ int rcv_len;
+ int maxpacket = dev->epmaxpacketin[usb_pipeendpoint(pipe)];
+
+ R8A66597_DPRINT("%s\n", __func__);
+
+ /* prepare */
+ if (dev->act_len == 0) {
+ r8a66597_mdfy(r8a66597, PID_NAK, PID,
+ get_pipectr_addr(pipenum));
+ r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS);
+
+ r8a66597_write(r8a66597, TRCLR, get_pipetre_addr(pipenum));
+ r8a66597_write(r8a66597,
+ (transfer_len + maxpacket - 1) / maxpacket,
+ get_pipetrn_addr(pipenum));
+ r8a66597_bset(r8a66597, TRENB, get_pipetre_addr(pipenum));
+
+ r8a66597_mdfy(r8a66597, PID_BUF, PID,
+ get_pipectr_addr(pipenum));
+ }
+
+ r8a66597_mdfy(r8a66597, MBW | pipenum, MBW | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, pipenum);
+
+ while (!(r8a66597_read(r8a66597, BRDYSTS) & (1 << pipenum)))
+ if (ctrlc())
+ return -1;
+ r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS);
+
+ tmp = r8a66597_read(r8a66597, CFIFOCTR);
+ if ((tmp & FRDY) == 0) {
+ printf("%s FRDY is not set. (%x)\n", __func__, tmp);
+ return -1;
+ }
+
+ buf = (u16 *)(buffer + dev->act_len);
+ rcv_len = tmp & DTLN;
+ dev->act_len += rcv_len;
+
+ if (buffer) {
+ if (rcv_len == 0)
+ r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+ else
+ r8a66597_read_fifo(r8a66597, CFIFO, buf, rcv_len);
+ }
+
+ return 0;
+}
+
+static int receive_control_packet(struct r8a66597 *r8a66597,
+ struct usb_device *dev,
+ void *buffer, int transfer_len)
+{
+ u16 tmp;
+ int rcv_len;
+
+ /* FIXME: limit transfer size : 64byte or less */
+
+ r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
+ r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+ r8a66597_bset(r8a66597, SQSET, DCPCTR);
+ r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+ r8a66597_mdfy(r8a66597, PID_BUF, PID, DCPCTR);
+
+ while (!(r8a66597_read(r8a66597, BRDYSTS) & 0x0001))
+ if (ctrlc())
+ return -1;
+ r8a66597_write(r8a66597, ~0x0001, BRDYSTS);
+
+ r8a66597_mdfy(r8a66597, MBW, MBW | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+
+ tmp = r8a66597_read(r8a66597, CFIFOCTR);
+ if ((tmp & FRDY) == 0) {
+ printf("%s FRDY is not set. (%x)\n", __func__, tmp);
+ return -1;
+ }
+
+ rcv_len = tmp & DTLN;
+ dev->act_len += rcv_len;
+
+ r8a66597_mdfy(r8a66597, PID_NAK, PID, DCPCTR);
+
+ if (buffer) {
+ if (rcv_len == 0)
+ r8a66597_write(r8a66597, BCLR, DCPCTR);
+ else
+ r8a66597_read_fifo(r8a66597, CFIFO, buffer, rcv_len);
+ }
+
+ return 0;
+}
+
+static int send_status_packet(struct r8a66597 *r8a66597,
+ unsigned long pipe)
+{
+ r8a66597_bset(r8a66597, SQSET, DCPCTR);
+ r8a66597_mdfy(r8a66597, PID_NAK, PID, DCPCTR);
+
+ if (usb_pipein(pipe)) {
+ r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
+ r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+ r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
+ r8a66597_write(r8a66597, BCLR | BVAL, CFIFOCTR);
+ } else {
+ r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
+ r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
+ r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+ r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+ }
+ r8a66597_mdfy(r8a66597, PID_BUF, PID, DCPCTR);
+
+ while (!(r8a66597_read(r8a66597, BEMPSTS) & 0x0001))
+ if (ctrlc())
+ return -1;
+
+ return 0;
+}
+
+static void r8a66597_check_syssts(struct r8a66597 *r8a66597, int port)
+{
+ int count = R8A66597_MAX_SAMPLING;
+ unsigned short syssts, old_syssts;
+
+ R8A66597_DPRINT("%s\n", __func__);
+
+ old_syssts = r8a66597_read(r8a66597, get_syssts_reg(port) & LNST);
+ while (count > 0) {
+ wait_ms(R8A66597_RH_POLL_TIME);
+
+ syssts = r8a66597_read(r8a66597, get_syssts_reg(port) & LNST);
+ if (syssts == old_syssts) {
+ count--;
+ } else {
+ count = R8A66597_MAX_SAMPLING;
+ old_syssts = syssts;
+ }
+ }
+}
+
+static void r8a66597_bus_reset(struct r8a66597 *r8a66597, int port)
+{
+ wait_ms(10);
+ r8a66597_mdfy(r8a66597, USBRST, USBRST | UACT, get_dvstctr_reg(port));
+ wait_ms(50);
+ r8a66597_mdfy(r8a66597, UACT, USBRST | UACT, get_dvstctr_reg(port));
+ wait_ms(50);
+}
+
+static int check_usb_device_connecting(struct r8a66597 *r8a66597)
+{
+ int timeout = 10000; /* 100usec * 10000 = 1sec */
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ /* check a usb cable connect */
+ while (!(r8a66597_read(r8a66597, INTSTS1) & ATTCH)) {
+ if (timeout-- < 0) {
+ printf("%s timeout.\n", __func__);
+ return -1;
+ }
+ udelay(100);
+ }
+
+ /* check a data line */
+ r8a66597_check_syssts(r8a66597, 0);
+
+ r8a66597_bus_reset(r8a66597, 0);
+ r8a66597->speed = get_rh_usb_speed(r8a66597, 0);
+
+ if (!(r8a66597_read(r8a66597, INTSTS1) & DTCH)) {
+ r8a66597->port_change = USB_PORT_STAT_C_CONNECTION;
+ r8a66597->port_status = USB_PORT_STAT_CONNECTION |
+ USB_PORT_STAT_ENABLE;
+ return 0; /* success */
+ }
+
+ R8A66597_DPRINT("USB device has detached. retry = %d\n", i);
+ r8a66597_write(r8a66597, ~DTCH, INTSTS1);
+ }
+
+ return -1; /* fail */
+}
+
+/* based on usb_ohci.c */
+#define min_t(type, x, y) \
+ ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+/*-------------------------------------------------------------------------*
+ * Virtual Root Hub
+ *-------------------------------------------------------------------------*/
+
+/* Device descriptor */
+static __u8 root_hub_dev_des[] =
+{
+ 0x12, /* __u8 bLength; */
+ 0x01, /* __u8 bDescriptorType; Device */
+ 0x10, /* __u16 bcdUSB; v1.1 */
+ 0x01,
+ 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 bDeviceSubClass; */
+ 0x00, /* __u8 bDeviceProtocol; */
+ 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
+ 0x00, /* __u16 idVendor; */
+ 0x00,
+ 0x00, /* __u16 idProduct; */
+ 0x00,
+ 0x00, /* __u16 bcdDevice; */
+ 0x00,
+ 0x00, /* __u8 iManufacturer; */
+ 0x01, /* __u8 iProduct; */
+ 0x00, /* __u8 iSerialNumber; */
+ 0x01 /* __u8 bNumConfigurations; */
+};
+
+/* Configuration descriptor */
+static __u8 root_hub_config_des[] =
+{
+ 0x09, /* __u8 bLength; */
+ 0x02, /* __u8 bDescriptorType; Configuration */
+ 0x19, /* __u16 wTotalLength; */
+ 0x00,
+ 0x01, /* __u8 bNumInterfaces; */
+ 0x01, /* __u8 bConfigurationValue; */
+ 0x00, /* __u8 iConfiguration; */
+ 0x40, /* __u8 bmAttributes; */
+
+ 0x00, /* __u8 MaxPower; */
+
+ /* interface */
+ 0x09, /* __u8 if_bLength; */
+ 0x04, /* __u8 if_bDescriptorType; Interface */
+ 0x00, /* __u8 if_bInterfaceNumber; */
+ 0x00, /* __u8 if_bAlternateSetting; */
+ 0x01, /* __u8 if_bNumEndpoints; */
+ 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
+ 0x00, /* __u8 if_bInterfaceSubClass; */
+ 0x00, /* __u8 if_bInterfaceProtocol; */
+ 0x00, /* __u8 if_iInterface; */
+
+ /* endpoint */
+ 0x07, /* __u8 ep_bLength; */
+ 0x05, /* __u8 ep_bDescriptorType; Endpoint */
+ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
+ 0x03, /* __u8 ep_bmAttributes; Interrupt */
+ 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
+ 0x00,
+ 0xff /* __u8 ep_bInterval; 255 ms */
+};
+
+static unsigned char root_hub_str_index0[] =
+{
+ 0x04, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 0x09, /* __u8 lang ID */
+ 0x04, /* __u8 lang ID */
+};
+
+static unsigned char root_hub_str_index1[] =
+{
+ 34, /* __u8 bLength; */
+ 0x03, /* __u8 bDescriptorType; String-descriptor */
+ 'R', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ '8', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'A', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ '6', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ '6', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ '5', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ '9', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ '7', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ ' ', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'R', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'o', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 't', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'H', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'u', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+ 'b', /* __u8 Unicode */
+ 0, /* __u8 Unicode */
+};
+
+static int r8a66597_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len, struct devrequest *cmd)
+{
+ struct r8a66597 *r8a66597 = &gr8a66597;
+ int leni = transfer_len;
+ int len = 0;
+ int stat = 0;
+ __u16 bmRType_bReq;
+ __u16 wValue;
+ __u16 wIndex;
+ __u16 wLength;
+ unsigned char data[32];
+
+ R8A66597_DPRINT("%s\n", __func__);
+
+ if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
+ printf("Root-Hub submit IRQ: NOT implemented");
+ return 0;
+ }
+
+ bmRType_bReq = cmd->requesttype | (cmd->request << 8);
+ wValue = cpu_to_le16 (cmd->value);
+ wIndex = cpu_to_le16 (cmd->index);
+ wLength = cpu_to_le16 (cmd->length);
+
+ switch (bmRType_bReq) {
+ case RH_GET_STATUS:
+ *(__u16 *)buffer = cpu_to_le16(1);
+ len = 2;
+ break;
+ case RH_GET_STATUS | RH_INTERFACE:
+ *(__u16 *)buffer = cpu_to_le16(0);
+ len = 2;
+ break;
+ case RH_GET_STATUS | RH_ENDPOINT:
+ *(__u16 *)buffer = cpu_to_le16(0);
+ len = 2;
+ break;
+ case RH_GET_STATUS | RH_CLASS:
+ *(__u32 *)buffer = cpu_to_le32(0);
+ len = 4;
+ break;
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS:
+ *(__u32 *)buffer = cpu_to_le32(r8a66597->port_status |
+ (r8a66597->port_change << 16));
+ len = 4;
+ break;
+ case RH_CLEAR_FEATURE | RH_ENDPOINT:
+ case RH_CLEAR_FEATURE | RH_CLASS:
+ break;
+
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case RH_C_PORT_CONNECTION:
+ r8a66597->port_change &= ~USB_PORT_STAT_C_CONNECTION;
+ break;
+ }
+ break;
+
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case (RH_PORT_SUSPEND):
+ break;
+ case (RH_PORT_RESET):
+ r8a66597_bus_reset(r8a66597, 0);
+ break;
+ case (RH_PORT_POWER):
+ break;
+ case (RH_PORT_ENABLE):
+ break;
+ }
+ break;
+ case RH_SET_ADDRESS:
+ gr8a66597.rh_devnum = wValue;
+ break;
+ case RH_GET_DESCRIPTOR:
+ switch ((wValue & 0xff00) >> 8) {
+ case (0x01): /* device descriptor */
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof(root_hub_dev_des),
+ wLength));
+ memcpy(buffer, root_hub_dev_des, len);
+ break;
+ case (0x02): /* configuration descriptor */
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof(root_hub_config_des),
+ wLength));
+ memcpy(buffer, root_hub_config_des, len);
+ break;
+ case (0x03): /* string descriptors */
+ if (wValue == 0x0300) {
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof(root_hub_str_index0),
+ wLength));
+ memcpy(buffer, root_hub_str_index0, len);
+ }
+ if (wValue == 0x0301) {
+ len = min_t(unsigned int,
+ leni,
+ min_t(unsigned int,
+ sizeof(root_hub_str_index1),
+ wLength));
+ memcpy(buffer, root_hub_str_index1, len);
+ }
+ break;
+ default:
+ stat = USB_ST_STALLED;
+ }
+ break;
+
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ {
+ __u32 temp = 0x00000001;
+
+ data[0] = 9; /* min length; */
+ data[1] = 0x29;
+ data[2] = temp & RH_A_NDP;
+ data[3] = 0;
+ if (temp & RH_A_PSM)
+ data[3] |= 0x1;
+ if (temp & RH_A_NOCP)
+ data[3] |= 0x10;
+ else if (temp & RH_A_OCPM)
+ data[3] |= 0x8;
+
+ /* corresponds to data[4-7] */
+ data[5] = (temp & RH_A_POTPGT) >> 24;
+ data[7] = temp & RH_B_DR;
+ if (data[2] < 7) {
+ data[8] = 0xff;
+ } else {
+ data[0] += 2;
+ data[8] = (temp & RH_B_DR) >> 8;
+ data[10] = data[9] = 0xff;
+ }
+
+ len = min_t(unsigned int, leni,
+ min_t(unsigned int, data[0], wLength));
+ memcpy(buffer, data, len);
+ break;
+ }
+
+ case RH_GET_CONFIGURATION:
+ *(__u8 *) buffer = 0x01;
+ len = 1;
+ break;
+ case RH_SET_CONFIGURATION:
+ break;
+ default:
+ dbg("unsupported root hub command");
+ stat = USB_ST_STALLED;
+ }
+
+ wait_ms(1);
+
+ len = min_t(int, len, leni);
+
+ dev->act_len = len;
+ dev->status = stat;
+
+ return stat;
+}
+
+int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len)
+{
+ struct r8a66597 *r8a66597 = &gr8a66597;
+ int ret = 0;
+
+ R8A66597_DPRINT("%s\n", __func__);
+ R8A66597_DPRINT("pipe = %08x, buffer = %p, len = %d, devnum = %d\n",
+ pipe, buffer, transfer_len, dev->devnum);
+
+ set_devadd_reg(r8a66597, dev->devnum, r8a66597->speed, 0, 0, 0);
+
+ pipe_buffer_setting(r8a66597, dev, pipe);
+
+ dev->act_len = 0;
+ while (dev->act_len < transfer_len && ret == 0) {
+ if (ctrlc())
+ return -1;
+
+ if (usb_pipein(pipe))
+ ret = receive_bulk_packet(r8a66597, dev, pipe, buffer,
+ transfer_len);
+ else
+ ret = send_bulk_packet(r8a66597, dev, pipe, buffer,
+ transfer_len);
+ }
+
+ if (ret == 0)
+ dev->status = 0;
+
+ return ret;
+}
+
+int submit_control_msg(struct usb_device *dev, unsigned long pipe,
+ void *buffer, int transfer_len, struct devrequest *setup)
+{
+ struct r8a66597 *r8a66597 = &gr8a66597;
+ u16 r8a66597_address = setup->request == USB_REQ_SET_ADDRESS ?
+ 0 : dev->devnum;
+
+ R8A66597_DPRINT("%s\n", __func__);
+ if (usb_pipedevice(pipe) == r8a66597->rh_devnum)
+ return r8a66597_submit_rh_msg(dev, pipe, buffer, transfer_len,
+ setup);
+
+ R8A66597_DPRINT("%s: setup\n", __func__);
+ set_devadd_reg(r8a66597, r8a66597_address, r8a66597->speed, 0, 0, 0);
+
+ if (send_setup_packet(r8a66597, dev, setup) < 0) {
+ printf("setup packet send error\n");
+ return -1;
+ }
+
+ if (usb_pipein(pipe))
+ if (receive_control_packet(r8a66597, dev, buffer,
+ transfer_len) < 0)
+ return -1;
+
+ if (send_status_packet(r8a66597, pipe) < 0)
+ return -1;
+
+ dev->status = 0;
+
+ return 0;
+}
+
+int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
+ int transfer_len, int interval)
+{
+ /* no implement */
+ R8A66597_DPRINT("%s\n", __func__);
+ return 0;
+}
+
+void usb_event_poll(void)
+{
+ /* no implement */
+ R8A66597_DPRINT("%s\n", __func__);
+}
+
+int usb_lowlevel_init(void)
+{
+ struct r8a66597 *r8a66597 = &gr8a66597;
+
+ R8A66597_DPRINT("%s\n", __func__);
+
+ memset(r8a66597, 0, sizeof(r8a66597));
+ r8a66597->reg = CONFIG_R8A66597_BASE_ADDR;
+
+ disable_controller(r8a66597);
+ wait_ms(100);
+
+ enable_controller(r8a66597);
+ r8a66597_port_power(r8a66597, 0 , 1);
+
+ /* check usb device */
+ check_usb_device_connecting(r8a66597);
+
+ wait_ms(50);
+
+ return 0;
+}
+
+int usb_lowlevel_stop(void)
+{
+ disable_controller(&gr8a66597);
+
+ return 0;
+}
+
+#endif /* CONFIG_USB_R8A66597_HCD */
+
diff --git a/drivers/usb/r8a66597.h b/drivers/usb/r8a66597.h
new file mode 100644
index 0000000..54a1f26
--- /dev/null
+++ b/drivers/usb/r8a66597.h
@@ -0,0 +1,663 @@
+/*
+ * R8A66597 HCD (Host Controller Driver) for u-boot
+ *
+ * Copyright (C) 2008 Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ *
+ * 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; version 2 of the License.
+ *
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef __R8A66597_H__
+#define __R8A66597_H__
+
+#define SYSCFG0 0x00
+#define SYSCFG1 0x02
+#define SYSSTS0 0x04
+#define SYSSTS1 0x06
+#define DVSTCTR0 0x08
+#define DVSTCTR1 0x0A
+#define TESTMODE 0x0C
+#define PINCFG 0x0E
+#define DMA0CFG 0x10
+#define DMA1CFG 0x12
+#define CFIFO 0x14
+#define D0FIFO 0x18
+#define D1FIFO 0x1C
+#define CFIFOSEL 0x20
+#define CFIFOCTR 0x22
+#define CFIFOSIE 0x24
+#define D0FIFOSEL 0x28
+#define D0FIFOCTR 0x2A
+#define D1FIFOSEL 0x2C
+#define D1FIFOCTR 0x2E
+#define INTENB0 0x30
+#define INTENB1 0x32
+#define INTENB2 0x34
+#define BRDYENB 0x36
+#define NRDYENB 0x38
+#define BEMPENB 0x3A
+#define SOFCFG 0x3C
+#define INTSTS0 0x40
+#define INTSTS1 0x42
+#define INTSTS2 0x44
+#define BRDYSTS 0x46
+#define NRDYSTS 0x48
+#define BEMPSTS 0x4A
+#define FRMNUM 0x4C
+#define UFRMNUM 0x4E
+#define USBADDR 0x50
+#define USBREQ 0x54
+#define USBVAL 0x56
+#define USBINDX 0x58
+#define USBLENG 0x5A
+#define DCPCFG 0x5C
+#define DCPMAXP 0x5E
+#define DCPCTR 0x60
+#define PIPESEL 0x64
+#define PIPECFG 0x68
+#define PIPEBUF 0x6A
+#define PIPEMAXP 0x6C
+#define PIPEPERI 0x6E
+#define PIPE1CTR 0x70
+#define PIPE2CTR 0x72
+#define PIPE3CTR 0x74
+#define PIPE4CTR 0x76
+#define PIPE5CTR 0x78
+#define PIPE6CTR 0x7A
+#define PIPE7CTR 0x7C
+#define PIPE8CTR 0x7E
+#define PIPE9CTR 0x80
+#define PIPE1TRE 0x90
+#define PIPE1TRN 0x92
+#define PIPE2TRE 0x94
+#define PIPE2TRN 0x96
+#define PIPE3TRE 0x98
+#define PIPE3TRN 0x9A
+#define PIPE4TRE 0x9C
+#define PIPE4TRN 0x9E
+#define PIPE5TRE 0xA0
+#define PIPE5TRN 0xA2
+#define DEVADD0 0xD0
+#define DEVADD1 0xD2
+#define DEVADD2 0xD4
+#define DEVADD3 0xD6
+#define DEVADD4 0xD8
+#define DEVADD5 0xDA
+#define DEVADD6 0xDC
+#define DEVADD7 0xDE
+#define DEVADD8 0xE0
+#define DEVADD9 0xE2
+#define DEVADDA 0xE4
+
+/* System Configuration Control Register */
+#define XTAL 0xC000 /* b15-14: Crystal selection */
+#define XTAL48 0x8000 /* 48MHz */
+#define XTAL24 0x4000 /* 24MHz */
+#define XTAL12 0x0000 /* 12MHz */
+#define XCKE 0x2000 /* b13: External clock enable */
+#define PLLC 0x0800 /* b11: PLL control */
+#define SCKE 0x0400 /* b10: USB clock enable */
+#define PCSDIS 0x0200 /* b9: not CS wakeup */
+#define LPSME 0x0100 /* b8: Low power sleep mode */
+#define HSE 0x0080 /* b7: Hi-speed enable */
+#define DCFM 0x0040 /* b6: Controller function select */
+#define DRPD 0x0020 /* b5: D+/- pull down control */
+#define DPRPU 0x0010 /* b4: D+ pull up control */
+#define USBE 0x0001 /* b0: USB module operation enable */
+
+/* System Configuration Status Register */
+#define OVCBIT 0x8000 /* b15-14: Over-current bit */
+#define OVCMON 0xC000 /* b15-14: Over-current monitor */
+#define SOFEA 0x0020 /* b5: SOF monitor */
+#define IDMON 0x0004 /* b3: ID-pin monitor */
+#define LNST 0x0003 /* b1-0: D+, D- line status */
+#define SE1 0x0003 /* SE1 */
+#define FS_KSTS 0x0002 /* Full-Speed K State */
+#define FS_JSTS 0x0001 /* Full-Speed J State */
+#define LS_JSTS 0x0002 /* Low-Speed J State */
+#define LS_KSTS 0x0001 /* Low-Speed K State */
+#define SE0 0x0000 /* SE0 */
+
+/* Device State Control Register */
+#define EXTLP0 0x0400 /* b10: External port */
+#define VBOUT 0x0200 /* b9: VBUS output */
+#define WKUP 0x0100 /* b8: Remote wakeup */
+#define RWUPE 0x0080 /* b7: Remote wakeup sense */
+#define USBRST 0x0040 /* b6: USB reset enable */
+#define RESUME 0x0020 /* b5: Resume enable */
+#define UACT 0x0010 /* b4: USB bus enable */
+#define RHST 0x0007 /* b1-0: Reset handshake status */
+#define HSPROC 0x0004 /* HS handshake is processing */
+#define HSMODE 0x0003 /* Hi-Speed mode */
+#define FSMODE 0x0002 /* Full-Speed mode */
+#define LSMODE 0x0001 /* Low-Speed mode */
+#define UNDECID 0x0000 /* Undecided */
+
+/* Test Mode Register */
+#define UTST 0x000F /* b3-0: Test select */
+#define H_TST_PACKET 0x000C /* HOST TEST Packet */
+#define H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */
+#define H_TST_K 0x000A /* HOST TEST K */
+#define H_TST_J 0x0009 /* HOST TEST J */
+#define H_TST_NORMAL 0x0000 /* HOST Normal Mode */
+#define P_TST_PACKET 0x0004 /* PERI TEST Packet */
+#define P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */
+#define P_TST_K 0x0002 /* PERI TEST K */
+#define P_TST_J 0x0001 /* PERI TEST J */
+#define P_TST_NORMAL 0x0000 /* PERI Normal Mode */
+
+/* Data Pin Configuration Register */
+#define LDRV 0x8000 /* b15: Drive Current Adjust */
+#define VIF1 0x0000 /* VIF = 1.8V */
+#define VIF3 0x8000 /* VIF = 3.3V */
+#define INTA 0x0001 /* b1: USB INT-pin active */
+
+/* DMAx Pin Configuration Register */
+#define DREQA 0x4000 /* b14: Dreq active select */
+#define BURST 0x2000 /* b13: Burst mode */
+#define DACKA 0x0400 /* b10: Dack active select */
+#define DFORM 0x0380 /* b9-7: DMA mode select */
+#define CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */
+#define CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */
+#define CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */
+#define SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */
+#define DENDA 0x0040 /* b6: Dend active select */
+#define PKTM 0x0020 /* b5: Packet mode */
+#define DENDE 0x0010 /* b4: Dend enable */
+#define OBUS 0x0004 /* b2: OUTbus mode */
+
+/* CFIFO/DxFIFO Port Select Register */
+#define RCNT 0x8000 /* b15: Read count mode */
+#define REW 0x4000 /* b14: Buffer rewind */
+#define DCLRM 0x2000 /* b13: DMA buffer clear mode */
+#define DREQE 0x1000 /* b12: DREQ output enable */
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+#define MBW 0x0800
+#else
+#define MBW 0x0400 /* b10: Maximum bit width for FIFO access */
+#endif
+#define MBW_8 0x0000 /* 8bit */
+#define MBW_16 0x0400 /* 16bit */
+#define BIGEND 0x0100 /* b8: Big endian mode */
+#define BYTE_LITTLE 0x0000 /* little dendian */
+#define BYTE_BIG 0x0100 /* big endifan */
+#define ISEL 0x0020 /* b5: DCP FIFO port direction select */
+#define CURPIPE 0x000F /* b2-0: PIPE select */
+
+/* CFIFO/DxFIFO Port Control Register */
+#define BVAL 0x8000 /* b15: Buffer valid flag */
+#define BCLR 0x4000 /* b14: Buffer clear */
+#define FRDY 0x2000 /* b13: FIFO ready */
+#define DTLN 0x0FFF /* b11-0: FIFO received data length */
+
+/* Interrupt Enable Register 0 */
+#define VBSE 0x8000 /* b15: VBUS interrupt */
+#define RSME 0x4000 /* b14: Resume interrupt */
+#define SOFE 0x2000 /* b13: Frame update interrupt */
+#define DVSE 0x1000 /* b12: Device state transition interrupt */
+#define CTRE 0x0800 /* b11: Control transfer stage transition interrupt */
+#define BEMPE 0x0400 /* b10: Buffer empty interrupt */
+#define NRDYE 0x0200 /* b9: Buffer not ready interrupt */
+#define BRDYE 0x0100 /* b8: Buffer ready interrupt */
+
+/* Interrupt Enable Register 1 */
+#define OVRCRE 0x8000 /* b15: Over-current interrupt */
+#define BCHGE 0x4000 /* b14: USB us chenge interrupt */
+#define DTCHE 0x1000 /* b12: Detach sense interrupt */
+#define ATTCHE 0x0800 /* b11: Attach sense interrupt */
+#define EOFERRE 0x0040 /* b6: EOF error interrupt */
+#define SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */
+#define SACKE 0x0010 /* b4: SETUP ACK interrupt */
+
+/* BRDY Interrupt Enable/Status Register */
+#define BRDY9 0x0200 /* b9: PIPE9 */
+#define BRDY8 0x0100 /* b8: PIPE8 */
+#define BRDY7 0x0080 /* b7: PIPE7 */
+#define BRDY6 0x0040 /* b6: PIPE6 */
+#define BRDY5 0x0020 /* b5: PIPE5 */
+#define BRDY4 0x0010 /* b4: PIPE4 */
+#define BRDY3 0x0008 /* b3: PIPE3 */
+#define BRDY2 0x0004 /* b2: PIPE2 */
+#define BRDY1 0x0002 /* b1: PIPE1 */
+#define BRDY0 0x0001 /* b1: PIPE0 */
+
+/* NRDY Interrupt Enable/Status Register */
+#define NRDY9 0x0200 /* b9: PIPE9 */
+#define NRDY8 0x0100 /* b8: PIPE8 */
+#define NRDY7 0x0080 /* b7: PIPE7 */
+#define NRDY6 0x0040 /* b6: PIPE6 */
+#define NRDY5 0x0020 /* b5: PIPE5 */
+#define NRDY4 0x0010 /* b4: PIPE4 */
+#define NRDY3 0x0008 /* b3: PIPE3 */
+#define NRDY2 0x0004 /* b2: PIPE2 */
+#define NRDY1 0x0002 /* b1: PIPE1 */
+#define NRDY0 0x0001 /* b1: PIPE0 */
+
+/* BEMP Interrupt Enable/Status Register */
+#define BEMP9 0x0200 /* b9: PIPE9 */
+#define BEMP8 0x0100 /* b8: PIPE8 */
+#define BEMP7 0x0080 /* b7: PIPE7 */
+#define BEMP6 0x0040 /* b6: PIPE6 */
+#define BEMP5 0x0020 /* b5: PIPE5 */
+#define BEMP4 0x0010 /* b4: PIPE4 */
+#define BEMP3 0x0008 /* b3: PIPE3 */
+#define BEMP2 0x0004 /* b2: PIPE2 */
+#define BEMP1 0x0002 /* b1: PIPE1 */
+#define BEMP0 0x0001 /* b0: PIPE0 */
+
+/* SOF Pin Configuration Register */
+#define TRNENSEL 0x0100 /* b8: Select transaction enable period */
+#define BRDYM 0x0040 /* b6: BRDY clear timing */
+#define INTL 0x0020 /* b5: Interrupt sense select */
+#define EDGESTS 0x0010 /* b4: */
+#define SOFMODE 0x000C /* b3-2: SOF pin select */
+#define SOF_125US 0x0008 /* SOF OUT 125us Frame Signal */
+#define SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */
+#define SOF_DISABLE 0x0000 /* SOF OUT Disable */
+
+/* Interrupt Status Register 0 */
+#define VBINT 0x8000 /* b15: VBUS interrupt */
+#define RESM 0x4000 /* b14: Resume interrupt */
+#define SOFR 0x2000 /* b13: SOF frame update interrupt */
+#define DVST 0x1000 /* b12: Device state transition interrupt */
+#define CTRT 0x0800 /* b11: Control transfer stage transition interrupt */
+#define BEMP 0x0400 /* b10: Buffer empty interrupt */
+#define NRDY 0x0200 /* b9: Buffer not ready interrupt */
+#define BRDY 0x0100 /* b8: Buffer ready interrupt */
+#define VBSTS 0x0080 /* b7: VBUS input port */
+#define DVSQ 0x0070 /* b6-4: Device state */
+#define DS_SPD_CNFG 0x0070 /* Suspend Configured */
+#define DS_SPD_ADDR 0x0060 /* Suspend Address */
+#define DS_SPD_DFLT 0x0050 /* Suspend Default */
+#define DS_SPD_POWR 0x0040 /* Suspend Powered */
+#define DS_SUSP 0x0040 /* Suspend */
+#define DS_CNFG 0x0030 /* Configured */
+#define DS_ADDS 0x0020 /* Address */
+#define DS_DFLT 0x0010 /* Default */
+#define DS_POWR 0x0000 /* Powered */
+#define DVSQS 0x0030 /* b5-4: Device state */
+#define VALID 0x0008 /* b3: Setup packet detected flag */
+#define CTSQ 0x0007 /* b2-0: Control transfer stage */
+#define CS_SQER 0x0006 /* Sequence error */
+#define CS_WRND 0x0005 /* Control write nodata status stage */
+#define CS_WRSS 0x0004 /* Control write status stage */
+#define CS_WRDS 0x0003 /* Control write data stage */
+#define CS_RDSS 0x0002 /* Control read status stage */
+#define CS_RDDS 0x0001 /* Control read data stage */
+#define CS_IDST 0x0000 /* Idle or setup stage */
+
+/* Interrupt Status Register 1 */
+#define OVRCR 0x8000 /* b15: Over-current interrupt */
+#define BCHG 0x4000 /* b14: USB bus chenge interrupt */
+#define DTCH 0x1000 /* b12: Detach sense interrupt */
+#define ATTCH 0x0800 /* b11: Attach sense interrupt */
+#define EOFERR 0x0040 /* b6: EOF-error interrupt */
+#define SIGN 0x0020 /* b5: Setup ignore interrupt */
+#define SACK 0x0010 /* b4: Setup acknowledge interrupt */
+
+/* Frame Number Register */
+#define OVRN 0x8000 /* b15: Overrun error */
+#define CRCE 0x4000 /* b14: Received data error */
+#define FRNM 0x07FF /* b10-0: Frame number */
+
+/* Micro Frame Number Register */
+#define UFRNM 0x0007 /* b2-0: Micro frame number */
+
+/* Default Control Pipe Maxpacket Size Register */
+/* Pipe Maxpacket Size Register */
+#define DEVSEL 0xF000 /* b15-14: Device address select */
+#define MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */
+
+/* Default Control Pipe Control Register */
+#define BSTS 0x8000 /* b15: Buffer status */
+#define SUREQ 0x4000 /* b14: Send USB request */
+#define CSCLR 0x2000 /* b13: complete-split status clear */
+#define CSSTS 0x1000 /* b12: complete-split status */
+#define SUREQCLR 0x0800 /* b11: stop setup request */
+#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define PBUSY 0x0020 /* b5: pipe busy */
+#define PINGE 0x0010 /* b4: ping enable */
+#define CCPL 0x0004 /* b2: Enable control transfer complete */
+#define PID 0x0003 /* b1-0: Response PID */
+#define PID_STALL11 0x0003 /* STALL */
+#define PID_STALL 0x0002 /* STALL */
+#define PID_BUF 0x0001 /* BUF */
+#define PID_NAK 0x0000 /* NAK */
+
+/* Pipe Window Select Register */
+#define PIPENM 0x0007 /* b2-0: Pipe select */
+
+/* Pipe Configuration Register */
+#define R8A66597_TYP 0xC000 /* b15-14: Transfer type */
+#define R8A66597_ISO 0xC000 /* Isochronous */
+#define R8A66597_INT 0x8000 /* Interrupt */
+#define R8A66597_BULK 0x4000 /* Bulk */
+#define R8A66597_BFRE 0x0400 /* b10: Buffer ready interrupt mode select */
+#define R8A66597_DBLB 0x0200 /* b9: Double buffer mode select */
+#define R8A66597_CNTMD 0x0100 /* b8: Continuous transfer mode select */
+#define R8A66597_SHTNAK 0x0080 /* b7: Transfer end NAK */
+#define R8A66597_DIR 0x0010 /* b4: Transfer direction select */
+#define R8A66597_EPNUM 0x000F /* b3-0: Eendpoint number select */
+
+/* Pipe Buffer Configuration Register */
+#define BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */
+#define BUFNMB 0x007F /* b6-0: Pipe buffer number */
+#define PIPE0BUF 256
+#define PIPExBUF 64
+
+/* Pipe Maxpacket Size Register */
+#define MXPS 0x07FF /* b10-0: Maxpacket size */
+
+/* Pipe Cycle Configuration Register */
+#define IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */
+#define IITV 0x0007 /* b2-0: Isochronous interval */
+
+/* Pipex Control Register */
+#define BSTS 0x8000 /* b15: Buffer status */
+#define INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */
+#define CSCLR 0x2000 /* b13: complete-split status clear */
+#define CSSTS 0x1000 /* b12: complete-split status */
+#define ATREPM 0x0400 /* b10: Auto repeat mode */
+#define ACLRM 0x0200 /* b9: Out buffer auto clear mode */
+#define SQCLR 0x0100 /* b8: Sequence toggle bit clear */
+#define SQSET 0x0080 /* b7: Sequence toggle bit set */
+#define SQMON 0x0040 /* b6: Sequence toggle bit monitor */
+#define PBUSY 0x0020 /* b5: pipe busy */
+#define PID 0x0003 /* b1-0: Response PID */
+
+/* PIPExTRE */
+#define TRENB 0x0200 /* b9: Transaction counter enable */
+#define TRCLR 0x0100 /* b8: Transaction counter clear */
+
+/* PIPExTRN */
+#define TRNCNT 0xFFFF /* b15-0: Transaction counter */
+
+/* DEVADDx */
+#define UPPHUB 0x7800
+#define HUBPORT 0x0700
+#define USBSPD 0x00C0
+#define RTPORT 0x0001
+
+#define R8A66597_MAX_NUM_PIPE 10
+#define R8A66597_BUF_BSIZE 8
+#define R8A66597_MAX_DEVICE 10
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+#define R8A66597_MAX_ROOT_HUB 1
+#else
+#define R8A66597_MAX_ROOT_HUB 2
+#endif
+#define R8A66597_MAX_SAMPLING 5
+#define R8A66597_RH_POLL_TIME 10
+
+#define BULK_IN_PIPENUM 3
+#define BULK_IN_BUFNUM 8
+
+#define BULK_OUT_PIPENUM 4
+#define BULK_OUT_BUFNUM 40
+
+#define check_bulk_or_isoc(pipenum) ((pipenum >= 1 && pipenum <= 5))
+#define check_interrupt(pipenum) ((pipenum >= 6 && pipenum <= 9))
+#define make_devsel(addr) (addr << 12)
+
+struct r8a66597 {
+ unsigned long reg;
+ unsigned short pipe_config; /* bit field */
+ unsigned short port_status;
+ unsigned short port_change;
+ u16 speed; /* HSMODE or FSMODE or LSMODE */
+ unsigned char rh_devnum;
+};
+
+static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset)
+{
+ return inw(r8a66597->reg + offset);
+}
+
+static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
+ unsigned long offset, void *buf,
+ int len)
+{
+ int i;
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+ unsigned long fifoaddr = r8a66597->reg + offset;
+ unsigned long count;
+ unsigned long *p = buf;
+
+ count = len / 4;
+ for (i = 0; i < count; i++)
+ inl(p[i], r8a66597->reg + offset);
+
+ if (len & 0x00000003) {
+ unsigned long tmp = inl(fifoaddr);
+ memcpy((unsigned char *)buf + count * 4, &tmp, len & 0x03);
+ }
+#else
+ unsigned short *p = buf;
+
+ len = (len + 1) / 2;
+ for (i = 0; i < len; i++)
+ p[i] = inw(r8a66597->reg + offset);
+#endif
+}
+
+static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
+ unsigned long offset)
+{
+ outw(val, r8a66597->reg + offset);
+}
+
+static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
+ unsigned long offset, void *buf,
+ int len)
+{
+ int i;
+ unsigned long fifoaddr = r8a66597->reg + offset;
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+ unsigned long count;
+ unsigned char *pb;
+ unsigned long *p = buf;
+
+ count = len / 4;
+ for (i = 0; i < count; i++)
+ outl(p[i], fifoaddr);
+
+ if (len & 0x00000003) {
+ pb = (unsigned char *)buf + count * 4;
+ for (i = 0; i < (len & 0x00000003); i++) {
+ if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)
+ outb(pb[i], fifoaddr + i);
+ else
+ outb(pb[i], fifoaddr + 3 - i);
+ }
+ }
+#else
+ int odd = len & 0x0001;
+ unsigned short *p = buf;
+
+ len = len / 2;
+ for (i = 0; i < len; i++)
+ outw(p[i], fifoaddr);
+
+ if (odd) {
+ unsigned char *pb = (unsigned char *)(buf + len);
+ outb(*pb, fifoaddr);
+ }
+#endif
+}
+
+static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
+ u16 val, u16 pat, unsigned long offset)
+{
+ u16 tmp;
+ tmp = r8a66597_read(r8a66597, offset);
+ tmp = tmp & (~pat);
+ tmp = tmp | val;
+ r8a66597_write(r8a66597, tmp, offset);
+}
+
+#define r8a66597_bclr(r8a66597, val, offset) \
+ r8a66597_mdfy(r8a66597, 0, val, offset)
+#define r8a66597_bset(r8a66597, val, offset) \
+ r8a66597_mdfy(r8a66597, val, 0, offset)
+
+static inline unsigned long get_syscfg_reg(int port)
+{
+ return port == 0 ? SYSCFG0 : SYSCFG1;
+}
+
+static inline unsigned long get_syssts_reg(int port)
+{
+ return port == 0 ? SYSSTS0 : SYSSTS1;
+}
+
+static inline unsigned long get_dvstctr_reg(int port)
+{
+ return port == 0 ? DVSTCTR0 : DVSTCTR1;
+}
+
+static inline unsigned long get_dmacfg_reg(int port)
+{
+ return port == 0 ? DMA0CFG : DMA1CFG;
+}
+
+static inline unsigned long get_intenb_reg(int port)
+{
+ return port == 0 ? INTENB1 : INTENB2;
+}
+
+static inline unsigned long get_intsts_reg(int port)
+{
+ return port == 0 ? INTSTS1 : INTSTS2;
+}
+
+static inline u16 get_rh_usb_speed(struct r8a66597 *r8a66597, int port)
+{
+ unsigned long dvstctr_reg = get_dvstctr_reg(port);
+
+ return r8a66597_read(r8a66597, dvstctr_reg) & RHST;
+}
+
+static inline void r8a66597_port_power(struct r8a66597 *r8a66597, int port,
+ int power)
+{
+ unsigned long dvstctr_reg = get_dvstctr_reg(port);
+
+ if (power)
+ r8a66597_bset(r8a66597, VBOUT, dvstctr_reg);
+ else
+ r8a66597_bclr(r8a66597, VBOUT, dvstctr_reg);
+}
+
+#define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2)
+#define get_pipetre_addr(pipenum) (PIPE1TRE + (pipenum - 1) * 4)
+#define get_pipetrn_addr(pipenum) (PIPE1TRN + (pipenum - 1) * 4)
+#define get_devadd_addr(address) (DEVADD0 + address * 2)
+
+
+/* USB HUB CONSTANTS (not OHCI-specific; see hub.h, based on usb_ohci.h) */
+
+/* destination of request */
+#define RH_INTERFACE 0x01
+#define RH_ENDPOINT 0x02
+#define RH_OTHER 0x03
+
+#define RH_CLASS 0x20
+#define RH_VENDOR 0x40
+
+/* Requests: bRequest << 8 | bmRequestType */
+#define RH_GET_STATUS 0x0080
+#define RH_CLEAR_FEATURE 0x0100
+#define RH_SET_FEATURE 0x0300
+#define RH_SET_ADDRESS 0x0500
+#define RH_GET_DESCRIPTOR 0x0680
+#define RH_SET_DESCRIPTOR 0x0700
+#define RH_GET_CONFIGURATION 0x0880
+#define RH_SET_CONFIGURATION 0x0900
+#define RH_GET_STATE 0x0280
+#define RH_GET_INTERFACE 0x0A80
+#define RH_SET_INTERFACE 0x0B00
+#define RH_SYNC_FRAME 0x0C80
+/* Our Vendor Specific Request */
+#define RH_SET_EP 0x2000
+
+
+/* Hub port features */
+#define RH_PORT_CONNECTION 0x00
+#define RH_PORT_ENABLE 0x01
+#define RH_PORT_SUSPEND 0x02
+#define RH_PORT_OVER_CURRENT 0x03
+#define RH_PORT_RESET 0x04
+#define RH_PORT_POWER 0x08
+#define RH_PORT_LOW_SPEED 0x09
+
+#define RH_C_PORT_CONNECTION 0x10
+#define RH_C_PORT_ENABLE 0x11
+#define RH_C_PORT_SUSPEND 0x12
+#define RH_C_PORT_OVER_CURRENT 0x13
+#define RH_C_PORT_RESET 0x14
+
+/* Hub features */
+#define RH_C_HUB_LOCAL_POWER 0x00
+#define RH_C_HUB_OVER_CURRENT 0x01
+
+#define RH_DEVICE_REMOTE_WAKEUP 0x00
+#define RH_ENDPOINT_STALL 0x01
+
+#define RH_ACK 0x01
+#define RH_REQ_ERR -1
+#define RH_NACK 0x00
+
+
+/* OHCI ROOT HUB REGISTER MASKS */
+
+/* roothub.portstatus [i] bits */
+#define RH_PS_CCS 0x00000001 /* current connect status */
+#define RH_PS_PES 0x00000002 /* port enable status*/
+#define RH_PS_PSS 0x00000004 /* port suspend status */
+#define RH_PS_POCI 0x00000008 /* port over current indicator */
+#define RH_PS_PRS 0x00000010 /* port reset status */
+#define RH_PS_PPS 0x00000100 /* port power status */
+#define RH_PS_LSDA 0x00000200 /* low speed device attached */
+#define RH_PS_CSC 0x00010000 /* connect status change */
+#define RH_PS_PESC 0x00020000 /* port enable status change */
+#define RH_PS_PSSC 0x00040000 /* port suspend status change */
+#define RH_PS_OCIC 0x00080000 /* over current indicator change */
+#define RH_PS_PRSC 0x00100000 /* port reset status change */
+
+/* roothub.status bits */
+#define RH_HS_LPS 0x00000001 /* local power status */
+#define RH_HS_OCI 0x00000002 /* over current indicator */
+#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
+#define RH_HS_LPSC 0x00010000 /* local power status change */
+#define RH_HS_OCIC 0x00020000 /* over current indicator change */
+#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
+
+/* roothub.b masks */
+#define RH_B_DR 0x0000ffff /* device removable flags */
+#define RH_B_PPCM 0xffff0000 /* port power control mask */
+
+/* roothub.a masks */
+#define RH_A_NDP (0xff << 0) /* number of downstream ports */
+#define RH_A_PSM (1 << 8) /* power switching mode */
+#define RH_A_NPS (1 << 9) /* no power switching */
+#define RH_A_DT (1 << 10) /* device type (mbz) */
+#define RH_A_OCPM (1 << 11) /* over current protection mode */
+#define RH_A_NOCP (1 << 12) /* no over current protection */
+#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
+
+
+#endif /* __R8A66597_H__ */
+