Commit 9424ea29 authored by Yoshihiro Shimoda's avatar Yoshihiro Shimoda Committed by Greg Kroah-Hartman

USB: r8a66597-hcd: Add support for SH7366 USB host

R8A66597 is similar to SH7366 USB 2.0 Host/Function module. It can
support SH7366 USB host by changing several R8A66597 code.
Signed-off-by: default avatarYoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 29fab0cd
...@@ -260,3 +260,9 @@ config USB_R8A66597_HCD ...@@ -260,3 +260,9 @@ config USB_R8A66597_HCD
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called r8a66597-hcd. module will be called r8a66597-hcd.
config SUPERH_ON_CHIP_R8A66597
boolean "Enable SuperH on-chip USB like the R8A66597"
depends on USB_R8A66597_HCD && CPU_SUBTYPE_SH7366
help
Renesas SuperH processor has USB like the R8A66597.
This driver supported processor is SH7366.
...@@ -51,10 +51,12 @@ MODULE_ALIAS("platform:r8a66597_hcd"); ...@@ -51,10 +51,12 @@ MODULE_ALIAS("platform:r8a66597_hcd");
static const char hcd_name[] = "r8a66597_hcd"; static const char hcd_name[] = "r8a66597_hcd";
/* module parameters */ /* module parameters */
#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
static unsigned short clock = XTAL12; static unsigned short clock = XTAL12;
module_param(clock, ushort, 0644); module_param(clock, ushort, 0644);
MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 " MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
"(default=0)"); "(default=0)");
#endif
static unsigned short vif = LDRV; static unsigned short vif = LDRV;
module_param(vif, ushort, 0644); module_param(vif, ushort, 0644);
...@@ -106,11 +108,22 @@ static void set_devadd_reg(struct r8a66597 *r8a66597, u8 r8a66597_address, ...@@ -106,11 +108,22 @@ static void set_devadd_reg(struct r8a66597 *r8a66597, u8 r8a66597_address,
r8a66597_write(r8a66597, val, devadd_reg); r8a66597_write(r8a66597, val, devadd_reg);
} }
static int enable_controller(struct r8a66597 *r8a66597) static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
{ {
u16 tmp; u16 tmp;
int i = 0; int i = 0;
#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
do {
r8a66597_write(r8a66597, SCKE, SYSCFG0);
tmp = r8a66597_read(r8a66597, SYSCFG0);
if (i++ > 1000) {
err("register access fail.");
return -ENXIO;
}
} while ((tmp & SCKE) != SCKE);
r8a66597_write(r8a66597, 0x04, 0x02);
#else
do { do {
r8a66597_write(r8a66597, USBE, SYSCFG0); r8a66597_write(r8a66597, USBE, SYSCFG0);
tmp = r8a66597_read(r8a66597, SYSCFG0); tmp = r8a66597_read(r8a66597, SYSCFG0);
...@@ -132,13 +145,63 @@ static int enable_controller(struct r8a66597 *r8a66597) ...@@ -132,13 +145,63 @@ static int enable_controller(struct r8a66597 *r8a66597)
return -ENXIO; return -ENXIO;
} }
} while ((tmp & SCKE) != SCKE); } while ((tmp & SCKE) != SCKE);
#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */
r8a66597_bset(r8a66597, DCFM | DRPD, SYSCFG0); return 0;
r8a66597_bset(r8a66597, DRPD, SYSCFG1); }
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));
r8a66597_bclr(r8a66597, DTCHE, get_intenb_reg(port));
r8a66597_bset(r8a66597, ATTCHE, get_intenb_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, vif & LDRV, PINCFG);
r8a66597_bset(r8a66597, HSE, SYSCFG0);
r8a66597_bset(r8a66597, HSE, SYSCFG1);
r8a66597_bset(r8a66597, USBE, SYSCFG0); r8a66597_bset(r8a66597, USBE, SYSCFG0);
r8a66597_bset(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0); r8a66597_bset(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0);
...@@ -146,53 +209,30 @@ static int enable_controller(struct r8a66597 *r8a66597) ...@@ -146,53 +209,30 @@ static int enable_controller(struct r8a66597 *r8a66597)
r8a66597_bset(r8a66597, BRDY0, BRDYENB); r8a66597_bset(r8a66597, BRDY0, BRDYENB);
r8a66597_bset(r8a66597, BEMP0, BEMPENB); r8a66597_bset(r8a66597, BEMP0, BEMPENB);
r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, DMA0CFG);
r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, DMA1CFG);
r8a66597_bset(r8a66597, endian & BIGEND, CFIFOSEL); r8a66597_bset(r8a66597, endian & BIGEND, CFIFOSEL);
r8a66597_bset(r8a66597, endian & BIGEND, D0FIFOSEL); r8a66597_bset(r8a66597, endian & BIGEND, D0FIFOSEL);
r8a66597_bset(r8a66597, endian & BIGEND, D1FIFOSEL); r8a66597_bset(r8a66597, endian & BIGEND, D1FIFOSEL);
r8a66597_bset(r8a66597, TRNENSEL, SOFCFG); r8a66597_bset(r8a66597, TRNENSEL, SOFCFG);
r8a66597_bset(r8a66597, SIGNE | SACKE, INTENB1); r8a66597_bset(r8a66597, SIGNE | SACKE, INTENB1);
r8a66597_bclr(r8a66597, DTCHE, INTENB1);
r8a66597_bset(r8a66597, ATTCHE, INTENB1); for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
r8a66597_bclr(r8a66597, DTCHE, INTENB2); r8a66597_enable_port(r8a66597, port);
r8a66597_bset(r8a66597, ATTCHE, INTENB2);
return 0; return 0;
} }
static void disable_controller(struct r8a66597 *r8a66597) static void disable_controller(struct r8a66597 *r8a66597)
{ {
u16 tmp; int port;
r8a66597_write(r8a66597, 0, INTENB0); r8a66597_write(r8a66597, 0, INTENB0);
r8a66597_write(r8a66597, 0, INTENB1);
r8a66597_write(r8a66597, 0, INTENB2);
r8a66597_write(r8a66597, 0, INTSTS0); r8a66597_write(r8a66597, 0, INTSTS0);
r8a66597_write(r8a66597, 0, INTSTS1);
r8a66597_write(r8a66597, 0, INTSTS2);
r8a66597_port_power(r8a66597, 0, 0);
r8a66597_port_power(r8a66597, 1, 0);
do {
tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS;
udelay(640);
} while (tmp == EDGESTS);
r8a66597_bclr(r8a66597, DCFM | DRPD, SYSCFG0); for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
r8a66597_bclr(r8a66597, DRPD, SYSCFG1); r8a66597_disable_port(r8a66597, port);
r8a66597_bclr(r8a66597, HSE, SYSCFG0);
r8a66597_bclr(r8a66597, HSE, SYSCFG1);
r8a66597_bclr(r8a66597, SCKE, SYSCFG0); r8a66597_clock_disable(r8a66597);
udelay(1);
r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
r8a66597_bclr(r8a66597, USBE, SYSCFG0);
} }
static int get_parent_r8a66597_address(struct r8a66597 *r8a66597, static int get_parent_r8a66597_address(struct r8a66597 *r8a66597,
...@@ -711,6 +751,7 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597, ...@@ -711,6 +751,7 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
struct r8a66597_pipe *pipe, struct r8a66597_pipe *pipe,
struct urb *urb) struct urb *urb)
{ {
#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
int i; int i;
struct r8a66597_pipe_info *info = &pipe->info; struct r8a66597_pipe_info *info = &pipe->info;
...@@ -738,6 +779,7 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597, ...@@ -738,6 +779,7 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
break; break;
} }
} }
#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */
} }
/* this function must be called with interrupt disabled */ /* this function must be called with interrupt disabled */
...@@ -1054,8 +1096,7 @@ static void prepare_status_packet(struct r8a66597 *r8a66597, ...@@ -1054,8 +1096,7 @@ static void prepare_status_packet(struct r8a66597 *r8a66597,
r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL); r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0); r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
r8a66597_write(r8a66597, ~BEMP0, BEMPSTS); r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
r8a66597_write(r8a66597, BCLR, CFIFOCTR); r8a66597_write(r8a66597, BCLR | BVAL, CFIFOCTR);
r8a66597_write(r8a66597, BVAL, CFIFOCTR);
enable_irq_empty(r8a66597, 0); enable_irq_empty(r8a66597, 0);
} else { } else {
r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG); r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
......
...@@ -187,7 +187,11 @@ ...@@ -187,7 +187,11 @@
#define REW 0x4000 /* b14: Buffer rewind */ #define REW 0x4000 /* b14: Buffer rewind */
#define DCLRM 0x2000 /* b13: DMA buffer clear mode */ #define DCLRM 0x2000 /* b13: DMA buffer clear mode */
#define DREQE 0x1000 /* b12: DREQ output enable */ #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 */ #define MBW 0x0400 /* b10: Maximum bit width for FIFO access */
#endif
#define MBW_8 0x0000 /* 8bit */ #define MBW_8 0x0000 /* 8bit */
#define MBW_16 0x0400 /* 16bit */ #define MBW_16 0x0400 /* 16bit */
#define BIGEND 0x0100 /* b8: Big endian mode */ #define BIGEND 0x0100 /* b8: Big endian mode */
...@@ -395,7 +399,11 @@ ...@@ -395,7 +399,11 @@
#define R8A66597_MAX_NUM_PIPE 10 #define R8A66597_MAX_NUM_PIPE 10
#define R8A66597_BUF_BSIZE 8 #define R8A66597_BUF_BSIZE 8
#define R8A66597_MAX_DEVICE 10 #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 #define R8A66597_MAX_ROOT_HUB 2
#endif
#define R8A66597_MAX_SAMPLING 5 #define R8A66597_MAX_SAMPLING 5
#define R8A66597_RH_POLL_TIME 10 #define R8A66597_RH_POLL_TIME 10
#define R8A66597_MAX_DMA_CHANNEL 2 #define R8A66597_MAX_DMA_CHANNEL 2
...@@ -530,8 +538,21 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597, ...@@ -530,8 +538,21 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
unsigned long offset, u16 *buf, unsigned long offset, u16 *buf,
int len) int len)
{ {
#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
unsigned long fifoaddr = r8a66597->reg + offset;
unsigned long count;
count = len / 4;
insl(fifoaddr, buf, count);
if (len & 0x00000003) {
unsigned long tmp = inl(fifoaddr);
memcpy((unsigned char *)buf + count * 4, &tmp, len & 0x03);
}
#else
len = (len + 1) / 2; len = (len + 1) / 2;
insw(r8a66597->reg + offset, buf, len); insw(r8a66597->reg + offset, buf, len);
#endif
} }
static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val, static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
...@@ -545,6 +566,24 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, ...@@ -545,6 +566,24 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
int len) int len)
{ {
unsigned long fifoaddr = r8a66597->reg + offset; unsigned long fifoaddr = r8a66597->reg + offset;
#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
unsigned long count;
unsigned char *pb;
int i;
count = len / 4;
outsl(fifoaddr, buf, count);
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; int odd = len & 0x0001;
len = len / 2; len = len / 2;
...@@ -553,6 +592,7 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597, ...@@ -553,6 +592,7 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
buf = &buf[len]; buf = &buf[len];
outb((unsigned char)*buf, fifoaddr); outb((unsigned char)*buf, fifoaddr);
} }
#endif
} }
static inline void r8a66597_mdfy(struct r8a66597 *r8a66597, static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
...@@ -585,6 +625,11 @@ static inline unsigned long get_dvstctr_reg(int port) ...@@ -585,6 +625,11 @@ static inline unsigned long get_dvstctr_reg(int port)
return port == 0 ? DVSTCTR0 : DVSTCTR1; 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) static inline unsigned long get_intenb_reg(int port)
{ {
return port == 0 ? INTENB1 : INTENB2; return port == 0 ? INTENB1 : INTENB2;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment