Commit e8d548d5 authored by Kuninori Morimoto's avatar Kuninori Morimoto Committed by Greg Kroah-Hartman

usb: renesas_usbhs: fifo became independent from pipe.

Current renesas_usbhs has PIO data transfer mode which controls CFIFO.
And it was implemented in pipe.c.
But, fifo control method needs more flexible implementation
to support DMAEngine.
This patch create fifo.c, and it became independent from pipe.c.
Signed-off-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent ad6f2a8b
......@@ -4,6 +4,6 @@
obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs.o
renesas_usbhs-y := common.o mod.o pipe.o
renesas_usbhs-y := common.o mod.o pipe.o fifo.o
renesas_usbhs-$(CONFIG_USB_RENESAS_USBHS_UDC) += mod_gadget.o
......@@ -24,6 +24,7 @@ struct usbhs_priv;
#include "./mod.h"
#include "./pipe.h"
#include "./fifo.h"
/*
*
......
/*
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* 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 <linux/delay.h>
#include <linux/io.h>
#include "./common.h"
#include "./pipe.h"
/*
* FIFO ctrl
*/
static void usbhsf_send_terminator(struct usbhs_pipe *pipe)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
usbhs_bset(priv, CFIFOCTR, BVAL, BVAL);
}
static int usbhsf_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 void usbhsf_fifo_clear(struct usbhs_pipe *pipe)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
if (!usbhs_pipe_is_dcp(pipe))
usbhsf_fifo_barrier(priv);
usbhs_write(priv, CFIFOCTR, BCLR);
}
static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv)
{
return usbhs_read(priv, CFIFOCTR) & DTLN_MASK;
}
static int usbhsf_fifo_select(struct usbhs_pipe *pipe, int write)
{
struct usbhs_priv *priv = usbhs_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 (usbhs_pipe_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;
}
/*
* PIO fifo functions
*/
int usbhs_fifo_prepare_write(struct usbhs_pipe *pipe)
{
return usbhsf_fifo_select(pipe, 1);
}
int usbhs_fifo_write(struct usbhs_pipe *pipe, u8 *buf, int len)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
void __iomem *addr = priv->base + CFIFO;
int maxp = usbhs_pipe_get_maxpacket(pipe);
int total_len;
int i, ret;
ret = usbhs_pipe_is_accessible(pipe);
if (ret < 0)
return ret;
ret = usbhsf_fifo_select(pipe, 1);
if (ret < 0)
return ret;
ret = usbhsf_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)
usbhsf_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 = usbhsf_fifo_select(pipe, 0);
if (ret < 0)
return ret;
usbhs_pipe_enable(pipe);
return ret;
}
int usbhs_fifo_read(struct usbhs_pipe *pipe, u8 *buf, int len)
{
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
void __iomem *addr = priv->base + CFIFO;
int rcv_len;
int i, ret;
int total_len;
u32 data = 0;
ret = usbhsf_fifo_select(pipe, 0);
if (ret < 0)
return ret;
ret = usbhsf_fifo_barrier(priv);
if (ret < 0)
return ret;
rcv_len = usbhsf_fifo_rcv_len(priv);
/*
* Buffer clear if Zero-Length packet
*
* see
* "Operation" - "FIFO Buffer Memory" - "FIFO Port Function"
*/
if (0 == rcv_len) {
usbhsf_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;
}
/*
* Renesas USB driver
*
* Copyright (C) 2011 Renesas Solutions Corp.
* Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
*
* 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 RENESAS_USB_FIFO_H
#define RENESAS_USB_FIFO_H
#include "common.h"
/*
* fifo
*/
int usbhs_fifo_write(struct usbhs_pipe *pipe, u8 *buf, int len);
int usbhs_fifo_read(struct usbhs_pipe *pipe, u8 *buf, int len);
int usbhs_fifo_prepare_write(struct usbhs_pipe *pipe);
int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe);
#endif /* RENESAS_USB_FIFO_H */
......@@ -376,7 +376,7 @@ static int usbhsg_try_run_send_packet(struct usbhsg_uep *uep,
* - after callback_update,
* - before queue_pop / stage_end
*/
usbhs_fifo_enable(pipe);
usbhs_pipe_enable(pipe);
/*
* all data were sent ?
......@@ -454,7 +454,7 @@ static int usbhsg_try_run_receive_packet(struct usbhsg_uep *uep,
int disable = 0;
uep->handler->irq_mask(uep, disable);
usbhs_fifo_disable(pipe);
usbhs_pipe_disable(pipe);
usbhsg_queue_pop(uep, ureq, 0);
}
......@@ -546,9 +546,9 @@ static int usbhsg_recip_handler_std_clear_endpoint(struct usbhs_priv *priv,
struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
if (!usbhsg_status_has(gpriv, USBHSG_STATUS_WEDGE)) {
usbhs_fifo_disable(pipe);
usbhs_pipe_disable(pipe);
usbhs_pipe_clear_sequence(pipe);
usbhs_fifo_enable(pipe);
usbhs_pipe_enable(pipe);
}
usbhsg_recip_handler_std_control_done(priv, uep, ctrl);
......@@ -695,7 +695,7 @@ static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv,
ret = gpriv->driver->setup(&gpriv->gadget, &ctrl);
if (ret < 0)
usbhs_fifo_stall(pipe);
usbhs_pipe_stall(pipe);
return ret;
}
......@@ -803,7 +803,7 @@ static int usbhsg_pipe_disable(struct usbhsg_uep *uep)
********* assume under spin lock *********
*/
usbhs_fifo_disable(pipe);
usbhs_pipe_disable(pipe);
/*
* disable pipe irq
......@@ -1016,9 +1016,9 @@ static int __usbhsg_ep_set_halt_wedge(struct usb_ep *ep, int halt, int wedge)
halt, usbhs_pipe_number(pipe));
if (halt)
usbhs_fifo_stall(pipe);
usbhs_pipe_stall(pipe);
else
usbhs_fifo_disable(pipe);
usbhs_pipe_disable(pipe);
if (halt && wedge)
usbhsg_status_set(gpriv, USBHSG_STATUS_WEDGE);
......
This diff is collapsed.
......@@ -56,25 +56,9 @@ struct usbhs_pipe_info {
__usbhs_for_each_pipe(0, pos, &((priv)->pipe_info), i)
/*
* pipe module probe / remove
* data
*/
int usbhs_pipe_probe(struct usbhs_priv *priv);
void usbhs_pipe_remove(struct usbhs_priv *priv);
/*
* cfifo
*/
int usbhs_fifo_write(struct usbhs_pipe *pipe, u8 *buf, int len);
int usbhs_fifo_read(struct usbhs_pipe *pipe, u8 *buf, int len);
int usbhs_fifo_prepare_write(struct usbhs_pipe *pipe);
int usbhs_fifo_prepare_read(struct usbhs_pipe *pipe);
void usbhs_fifo_enable(struct usbhs_pipe *pipe);
void usbhs_fifo_disable(struct usbhs_pipe *pipe);
void usbhs_fifo_stall(struct usbhs_pipe *pipe);
void usbhs_fifo_send_terminator(struct usbhs_pipe *pipe);
#define usbhs_priv_to_pipeinfo(pr) (&(pr)->pipe_info)
/*
* usb request
......@@ -88,14 +72,21 @@ void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req);
struct usbhs_pipe
*usbhs_pipe_malloc(struct usbhs_priv *priv,
const struct usb_endpoint_descriptor *desc);
int usbhs_pipe_probe(struct usbhs_priv *priv);
void usbhs_pipe_remove(struct usbhs_priv *priv);
int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe);
int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe);
void usbhs_pipe_init(struct usbhs_priv *priv);
int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe);
void usbhs_pipe_clear_sequence(struct usbhs_pipe *pipe);
int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe);
void usbhs_pipe_enable(struct usbhs_pipe *pipe);
void usbhs_pipe_disable(struct usbhs_pipe *pipe);
void usbhs_pipe_stall(struct usbhs_pipe *pipe);
#define usbhs_pipe_to_priv(p) ((p)->priv)
#define usbhs_pipe_number(p) (int)((p) - (p)->priv->pipe_info.pipe)
#define usbhs_pipe_is_dcp(p) ((p)->priv->pipe_info.pipe == (p))
/*
* dcp control
......
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