Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ struct usbhs_priv;

#include "./mod.h"
#include "./pipe.h"
#include "./fifo.h"

/*
 *
+211 −0
Original line number Diff line number Diff line
/*
 * 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;
}
+30 −0
Original line number Diff line number Diff line
/*
 * 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 */
+8 −8
Original line number Diff line number Diff line
@@ -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);
Loading