diff options
Diffstat (limited to 'drivers/usb/renesas_usbhs/pipe.c')
-rw-r--r-- | drivers/usb/renesas_usbhs/pipe.c | 298 |
1 files changed, 72 insertions, 226 deletions
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index bc4521c54261..1b14cae45704 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -15,7 +15,6 @@ * */ #include <linux/delay.h> -#include <linux/io.h> #include <linux/slab.h> #include "./common.h" #include "./pipe.h" @@ -23,13 +22,8 @@ /* * macros */ -#define usbhsp_priv_to_pipeinfo(pr) (&(pr)->pipe_info) -#define usbhsp_pipe_to_priv(p) ((p)->priv) - #define usbhsp_addr_offset(p) ((usbhs_pipe_number(p) - 1) * 2) -#define usbhsp_is_dcp(p) ((p)->priv->pipe_info.pipe == (p)) - #define usbhsp_flags_set(p, f) ((p)->flags |= USBHS_PIPE_FLAGS_##f) #define usbhsp_flags_clr(p, f) ((p)->flags &= ~USBHS_PIPE_FLAGS_##f) #define usbhsp_flags_has(p, f) ((p)->flags & USBHS_PIPE_FLAGS_##f) @@ -77,10 +71,10 @@ void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req) */ static void usbhsp_pipectrl_set(struct usbhs_pipe *pipe, u16 mask, u16 val) { - struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe); + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); int offset = usbhsp_addr_offset(pipe); - if (usbhsp_is_dcp(pipe)) + if (usbhs_pipe_is_dcp(pipe)) usbhs_bset(priv, DCPCTR, mask, val); else usbhs_bset(priv, PIPEnCTR + offset, mask, val); @@ -88,10 +82,10 @@ static void usbhsp_pipectrl_set(struct usbhs_pipe *pipe, u16 mask, u16 val) static u16 usbhsp_pipectrl_get(struct usbhs_pipe *pipe) { - struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe); + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); int offset = usbhsp_addr_offset(pipe); - if (usbhsp_is_dcp(pipe)) + if (usbhs_pipe_is_dcp(pipe)) return usbhs_read(priv, DCPCTR); else return usbhs_read(priv, PIPEnCTR + offset); @@ -104,9 +98,9 @@ static void __usbhsp_pipe_xxx_set(struct usbhs_pipe *pipe, u16 dcp_reg, u16 pipe_reg, u16 mask, u16 val) { - struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe); + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - if (usbhsp_is_dcp(pipe)) + if (usbhs_pipe_is_dcp(pipe)) usbhs_bset(priv, dcp_reg, mask, val); else usbhs_bset(priv, pipe_reg, mask, val); @@ -115,9 +109,9 @@ static void __usbhsp_pipe_xxx_set(struct usbhs_pipe *pipe, static u16 __usbhsp_pipe_xxx_get(struct usbhs_pipe *pipe, u16 dcp_reg, u16 pipe_reg) { - struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe); + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); - if (usbhsp_is_dcp(pipe)) + if (usbhs_pipe_is_dcp(pipe)) return usbhs_read(priv, dcp_reg); else return usbhs_read(priv, pipe_reg); @@ -136,7 +130,7 @@ static void usbhsp_pipe_cfg_set(struct usbhs_pipe *pipe, u16 mask, u16 val) */ static void usbhsp_pipe_buf_set(struct usbhs_pipe *pipe, u16 mask, u16 val) { - if (usbhsp_is_dcp(pipe)) + if (usbhs_pipe_is_dcp(pipe)) return; __usbhsp_pipe_xxx_set(pipe, 0, PIPEBUF, mask, val); @@ -160,7 +154,7 @@ static u16 usbhsp_pipe_maxp_get(struct usbhs_pipe *pipe) */ static void usbhsp_pipe_select(struct usbhs_pipe *pipe) { - struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe); + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); /* * On pipe, this is necessary before @@ -182,7 +176,7 @@ static void usbhsp_pipe_select(struct usbhs_pipe *pipe) static int usbhsp_pipe_barrier(struct usbhs_pipe *pipe) { - struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe); + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); int timeout = 1024; u16 val; @@ -205,7 +199,7 @@ static int usbhsp_pipe_barrier(struct usbhs_pipe *pipe) * - "Pipe Control Registers Switching Procedure" */ usbhs_write(priv, CFIFOSEL, 0); - usbhs_fifo_disable(pipe); + usbhs_pipe_disable(pipe); do { val = usbhsp_pipectrl_get(pipe); @@ -220,7 +214,7 @@ static int usbhsp_pipe_barrier(struct usbhs_pipe *pipe) return -EBUSY; } -static int usbhsp_pipe_is_accessible(struct usbhs_pipe *pipe) +int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe) { u16 val; @@ -253,7 +247,7 @@ static void __usbhsp_pid_try_nak_if_stall(struct usbhs_pipe *pipe) } } -void usbhs_fifo_disable(struct usbhs_pipe *pipe) +void usbhs_pipe_disable(struct usbhs_pipe *pipe) { int timeout = 1024; u16 val; @@ -273,7 +267,7 @@ void usbhs_fifo_disable(struct usbhs_pipe *pipe) } while (timeout--); } -void usbhs_fifo_enable(struct usbhs_pipe *pipe) +void usbhs_pipe_enable(struct usbhs_pipe *pipe) { /* see "Pipe n Control Register" - "PID" */ __usbhsp_pid_try_nak_if_stall(pipe); @@ -281,7 +275,7 @@ void usbhs_fifo_enable(struct usbhs_pipe *pipe) usbhsp_pipectrl_set(pipe, PID_MASK, PID_BUF); } -void usbhs_fifo_stall(struct usbhs_pipe *pipe) +void usbhs_pipe_stall(struct usbhs_pipe *pipe) { u16 pid = usbhsp_pipectrl_get(pipe); @@ -302,191 +296,6 @@ void usbhs_fifo_stall(struct usbhs_pipe *pipe) } /* - * CFIFO ctrl - */ -void usbhs_fifo_send_terminator(struct usbhs_pipe *pipe) -{ - struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe); - - usbhs_bset(priv, CFIFOCTR, BVAL, BVAL); -} - -static void usbhsp_fifo_clear(struct usbhs_pipe *pipe) -{ - struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe); - - usbhs_write(priv, CFIFOCTR, BCLR); -} - -static int usbhsp_fifo_barrier(struct usbhs_priv *priv) -{ - int timeout = 1024; - - do { - /* The FIFO port is accessible */ - if (usbhs_read(priv, CFIFOCTR) & FRDY) - return 0; - - udelay(10); - } while (timeout--); - - return -EBUSY; -} - -static int usbhsp_fifo_rcv_len(struct usbhs_priv *priv) -{ - return usbhs_read(priv, CFIFOCTR) & DTLN_MASK; -} - -static int usbhsp_fifo_select(struct usbhs_pipe *pipe, int write) -{ - struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe); - struct device *dev = usbhs_priv_to_dev(priv); - int timeout = 1024; - u16 mask = ((1 << 5) | 0xF); /* mask of ISEL | CURPIPE */ - u16 base = usbhs_pipe_number(pipe); /* CURPIPE */ - - if (usbhsp_is_dcp(pipe)) - base |= (1 == write) << 5; /* ISEL */ - - /* "base" will be used below */ - usbhs_write(priv, CFIFOSEL, base | MBW_32); - - /* check ISEL and CURPIPE value */ - while (timeout--) { - if (base == (mask & usbhs_read(priv, CFIFOSEL))) - return 0; - udelay(10); - } - - dev_err(dev, "fifo select error\n"); - - return -EIO; -} - -int usbhs_fifo_prepare_write(struct usbhs_pipe *pipe) -{ - return usbhsp_fifo_select(pipe, 1); -} - -int usbhs_fifo_write(struct usbhs_pipe *pipe, u8 *buf, int len) -{ - struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe); - void __iomem *addr = priv->base + CFIFO; - int maxp = usbhs_pipe_get_maxpacket(pipe); - int total_len; - int i, ret; - - ret = usbhsp_pipe_is_accessible(pipe); - if (ret < 0) - return ret; - - ret = usbhsp_fifo_select(pipe, 1); - if (ret < 0) - return ret; - - ret = usbhsp_fifo_barrier(priv); - if (ret < 0) - return ret; - - len = min(len, maxp); - total_len = len; - - /* - * FIXME - * - * 32-bit access only - */ - if (len >= 4 && - !((unsigned long)buf & 0x03)) { - iowrite32_rep(addr, buf, len / 4); - len %= 4; - buf += total_len - len; - } - - /* the rest operation */ - for (i = 0; i < len; i++) - iowrite8(buf[i], addr + (0x03 - (i & 0x03))); - - if (total_len < maxp) - usbhs_fifo_send_terminator(pipe); - - return total_len; -} - -int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe) -{ - int ret; - - /* - * select pipe and enable it to prepare packet receive - */ - ret = usbhsp_fifo_select(pipe, 0); - if (ret < 0) - return ret; - - usbhs_fifo_enable(pipe); - - return ret; -} - -int usbhs_fifo_read(struct usbhs_pipe *pipe, u8 *buf, int len) -{ - struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe); - void __iomem *addr = priv->base + CFIFO; - int rcv_len; - int i, ret; - int total_len; - u32 data = 0; - - ret = usbhsp_fifo_select(pipe, 0); - if (ret < 0) - return ret; - - ret = usbhsp_fifo_barrier(priv); - if (ret < 0) - return ret; - - rcv_len = usbhsp_fifo_rcv_len(priv); - - /* - * Buffer clear if Zero-Length packet - * - * see - * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function" - */ - if (0 == rcv_len) { - usbhsp_fifo_clear(pipe); - return 0; - } - - len = min(rcv_len, len); - total_len = len; - - /* - * FIXME - * - * 32-bit access only - */ - if (len >= 4 && - !((unsigned long)buf & 0x03)) { - ioread32_rep(addr, buf, len / 4); - len %= 4; - buf += rcv_len - len; - } - - /* the rest operation */ - for (i = 0; i < len; i++) { - if (!(i & 0x03)) - data = ioread32(addr); - - buf[i] = (data >> ((i & 0x03) * 8)) & 0xff; - } - - return total_len; -} - -/* * pipe setup */ static int usbhsp_possible_double_buffer(struct usbhs_pipe *pipe) @@ -519,7 +328,7 @@ static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe, }; int is_double = usbhsp_possible_double_buffer(pipe); - if (usbhsp_is_dcp(pipe)) + if (usbhs_pipe_is_dcp(pipe)) return -EINVAL; /* @@ -550,12 +359,15 @@ static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe, /* DIR */ if (usb_endpoint_dir_in(desc)) - usbhsp_flags_set(pipe, IS_DIR_IN); + usbhsp_flags_set(pipe, IS_DIR_HOST); if ((is_host && usb_endpoint_dir_out(desc)) || (!is_host && usb_endpoint_dir_in(desc))) dir |= DIR_OUT; + if (!dir) + usbhsp_flags_set(pipe, IS_DIR_IN); + /* SHTNAK */ if (usbhsp_type_is(pipe, USB_ENDPOINT_XFER_BULK) && !dir) @@ -587,8 +399,8 @@ static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe, const struct usb_endpoint_descriptor *desc, int is_host) { - struct usbhs_priv *priv = usbhsp_pipe_to_priv(pipe); - struct usbhs_pipe_info *info = usbhsp_priv_to_pipeinfo(priv); + struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); + struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); struct device *dev = usbhs_priv_to_dev(priv); int pipe_num = usbhs_pipe_number(pipe); int is_double = usbhsp_possible_double_buffer(pipe); @@ -666,7 +478,7 @@ static u16 usbhsp_setup_pipebuff(struct usbhs_pipe *pipe, */ int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe) { - u16 mask = usbhsp_is_dcp(pipe) ? DCP_MAXP_MASK : PIPE_MAXP_MASK; + u16 mask = usbhs_pipe_is_dcp(pipe) ? DCP_MAXP_MASK : PIPE_MAXP_MASK; usbhsp_pipe_select(pipe); @@ -678,11 +490,22 @@ int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe) return usbhsp_flags_has(pipe, IS_DIR_IN); } +int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe) +{ + return usbhsp_flags_has(pipe, IS_DIR_HOST); +} + void usbhs_pipe_clear_sequence(struct usbhs_pipe *pipe) { usbhsp_pipectrl_set(pipe, SQCLR, SQCLR); } +void usbhs_pipe_clear(struct usbhs_pipe *pipe) +{ + usbhsp_pipectrl_set(pipe, ACLRM, ACLRM); + usbhsp_pipectrl_set(pipe, ACLRM, 0); +} + static struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type) { struct usbhs_pipe *pos, *pipe; @@ -714,12 +537,20 @@ static struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type) return pipe; } -void usbhs_pipe_init(struct usbhs_priv *priv) +void usbhs_pipe_init(struct usbhs_priv *priv, + void (*done)(struct usbhs_pkt *pkt), + int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map)) { - struct usbhs_pipe_info *info = usbhsp_priv_to_pipeinfo(priv); + struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); + struct device *dev = usbhs_priv_to_dev(priv); struct usbhs_pipe *pipe; int i; + if (!done) { + dev_err(dev, "no done function\n"); + return; + } + /* * FIXME * @@ -738,10 +569,16 @@ void usbhs_pipe_init(struct usbhs_priv *priv) info->bufnmb_last++; usbhsp_flags_init(pipe); + pipe->fifo = NULL; pipe->mod_private = NULL; + INIT_LIST_HEAD(&pipe->list); - usbhsp_fifo_clear(pipe); + /* pipe force init */ + usbhs_pipe_clear(pipe); } + + info->done = done; + info->dma_map_ctrl = dma_map_ctrl; } struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, @@ -761,7 +598,9 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, return NULL; } - usbhs_fifo_disable(pipe); + INIT_LIST_HEAD(&pipe->list); + + usbhs_pipe_disable(pipe); /* make sure pipe is not busy */ ret = usbhsp_pipe_barrier(pipe); @@ -774,11 +613,6 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, pipebuf = usbhsp_setup_pipebuff(pipe, desc, is_host); pipemaxp = usbhsp_setup_pipemaxp(pipe, desc, is_host); - /* buffer clear - * see PIPECFG :: BFRE */ - usbhsp_pipectrl_set(pipe, ACLRM, ACLRM); - usbhsp_pipectrl_set(pipe, ACLRM, 0); - usbhsp_pipe_select(pipe); usbhsp_pipe_cfg_set(pipe, 0xFFFF, pipecfg); usbhsp_pipe_buf_set(pipe, 0xFFFF, pipebuf); @@ -794,6 +628,18 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, return pipe; } +void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo) +{ + if (pipe->fifo) + pipe->fifo->pipe = NULL; + + pipe->fifo = fifo; + + if (fifo) + fifo->pipe = pipe; +} + + /* * dcp control */ @@ -813,25 +659,25 @@ struct usbhs_pipe *usbhs_dcp_malloc(struct usbhs_priv *priv) usbhsp_pipe_select(pipe); usbhs_pipe_clear_sequence(pipe); + INIT_LIST_HEAD(&pipe->list); return pipe; } void usbhs_dcp_control_transfer_done(struct usbhs_pipe *pipe) { - WARN_ON(!usbhsp_is_dcp(pipe)); + WARN_ON(!usbhs_pipe_is_dcp(pipe)); - usbhs_fifo_enable(pipe); + usbhs_pipe_enable(pipe); usbhsp_pipectrl_set(pipe, CCPL, CCPL); } - /* * pipe module function */ int usbhs_pipe_probe(struct usbhs_priv *priv) { - struct usbhs_pipe_info *info = usbhsp_priv_to_pipeinfo(priv); + struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); struct usbhs_pipe *pipe; struct device *dev = usbhs_priv_to_dev(priv); u32 *pipe_type = usbhs_get_dparam(priv, pipe_type); @@ -868,7 +714,7 @@ int usbhs_pipe_probe(struct usbhs_priv *priv) void usbhs_pipe_remove(struct usbhs_priv *priv) { - struct usbhs_pipe_info *info = usbhsp_priv_to_pipeinfo(priv); + struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv); kfree(info->pipe); } |