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

usb: renesas_usbhs: add DMAEngine support

USB DMA was installed on "normal DMAC" when SH7724 or older SuperH,
but the "USB-DMAC" was prepared on recent SuperH.
These 2 DMAC have a little bit different behavior.

This patch add DMAEngine code for "normal DMAC",
but it is still using PIO fifo.
The DMA fifo will be formally supported in the future.

You can enable DMA fifo by local fixup
usbhs_fifo_pio_push_handler -> usbhs_fifo_dma_push_handler
usbhs_fifo_pio_pop_handler  -> usbhs_fifo_dma_pop_handler
on usbhsg_ep_enable.

This DMAEngine was tested by g_file_storage on SH7724 Ecovec board
Signed-off-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 0cb7e61d
......@@ -304,6 +304,8 @@ static int __devinit usbhs_probe(struct platform_device *pdev)
priv->dparam->pipe_type = usbhsc_default_pipe_type;
priv->dparam->pipe_size = ARRAY_SIZE(usbhsc_default_pipe_type);
}
if (!priv->dparam->pio_dma_border)
priv->dparam->pio_dma_border = 64; /* 64byte */
/* FIXME */
/* runtime power control ? */
......
......@@ -36,6 +36,12 @@ struct usbhs_priv;
#define CFIFO 0x0014
#define CFIFOSEL 0x0020
#define CFIFOCTR 0x0022
#define D0FIFO 0x0100
#define D0FIFOSEL 0x0028
#define D0FIFOCTR 0x002A
#define D1FIFO 0x0120
#define D1FIFOSEL 0x002C
#define D1FIFOCTR 0x002E
#define INTENB0 0x0030
#define INTENB1 0x0032
#define BRDYENB 0x0036
......@@ -60,6 +66,30 @@ struct usbhs_priv;
#define PIPEMAXP 0x006C
#define PIPEPERI 0x006E
#define PIPEnCTR 0x0070
#define PIPE1TRE 0x0090
#define PIPE1TRN 0x0092
#define PIPE2TRE 0x0094
#define PIPE2TRN 0x0096
#define PIPE3TRE 0x0098
#define PIPE3TRN 0x009A
#define PIPE4TRE 0x009C
#define PIPE4TRN 0x009E
#define PIPE5TRE 0x00A0
#define PIPE5TRN 0x00A2
#define PIPEBTRE 0x00A4
#define PIPEBTRN 0x00A6
#define PIPECTRE 0x00A8
#define PIPECTRN 0x00AA
#define PIPEDTRE 0x00AC
#define PIPEDTRN 0x00AE
#define PIPEETRE 0x00B0
#define PIPEETRN 0x00B2
#define PIPEFTRE 0x00B4
#define PIPEFTRN 0x00B6
#define PIPE9TRE 0x00B8
#define PIPE9TRN 0x00BA
#define PIPEATRE 0x00BC
#define PIPEATRN 0x00BE
/* SYSCFG */
#define SCKE (1 << 10) /* USB Module Clock Enable */
......@@ -78,6 +108,7 @@ struct usbhs_priv;
#define RHST_HIGH_SPEED 3 /* High-speed connection */
/* CFIFOSEL */
#define DREQE (1 << 12) /* DMA Transfer Request Enable */
#define MBW_32 (0x2 << 10) /* CFIFO Port Access Bit Width */
/* CFIFOCTR */
......@@ -164,6 +195,10 @@ struct usbhs_priv;
#define CCPL (1 << 2) /* Control Transfer End Enable */
/* PIPEnTRE */
#define TRENB (1 << 9) /* Transaction Counter Enable */
#define TRCLR (1 << 8) /* Transaction Counter Clear */
/* FRMNUM */
#define FRNM_MASK (0x7FF)
......
This diff is collapsed.
......@@ -17,18 +17,33 @@
#ifndef RENESAS_USB_FIFO_H
#define RENESAS_USB_FIFO_H
#include <linux/interrupt.h>
#include <linux/sh_dma.h>
#include <asm/dma.h>
#include "pipe.h"
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
struct usbhs_fifo {
char *name;
u32 port; /* xFIFO */
u32 sel; /* xFIFOSEL */
u32 ctr; /* xFIFOCTR */
struct usbhs_pipe *pipe;
struct tasklet_struct tasklet;
struct dma_chan *tx_chan;
struct dma_chan *rx_chan;
struct sh_dmae_slave tx_slave;
struct sh_dmae_slave rx_slave;
};
struct usbhs_fifo_info {
struct usbhs_fifo cfifo;
struct usbhs_fifo d0fifo;
struct usbhs_fifo d1fifo;
};
struct usbhs_pkt_handle;
......@@ -36,8 +51,10 @@ struct usbhs_pkt {
struct list_head node;
struct usbhs_pipe *pipe;
struct usbhs_pkt_handle *handler;
dma_addr_t dma;
void *buf;
int length;
int trans;
int actual;
int zero;
};
......@@ -45,6 +62,7 @@ struct usbhs_pkt {
struct usbhs_pkt_handle {
int (*prepare)(struct usbhs_pkt *pkt, int *is_done);
int (*try_run)(struct usbhs_pkt *pkt, int *is_done);
int (*dma_done)(struct usbhs_pkt *pkt, int *is_done);
};
/*
......@@ -61,12 +79,17 @@ void usbhs_fifo_quit(struct usbhs_priv *priv);
enum {
USBHSF_PKT_PREPARE,
USBHSF_PKT_TRY_RUN,
USBHSF_PKT_DMA_DONE,
};
extern struct usbhs_pkt_handle usbhs_fifo_pio_push_handler;
extern struct usbhs_pkt_handle usbhs_fifo_pio_pop_handler;
extern struct usbhs_pkt_handle usbhs_ctrl_stage_end_handler;
extern struct usbhs_pkt_handle usbhs_fifo_dma_push_handler;
extern struct usbhs_pkt_handle usbhs_fifo_dma_pop_handler;
void usbhs_pkt_init(struct usbhs_pkt *pkt);
void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
struct usbhs_pkt_handle *handler,
......@@ -76,5 +99,6 @@ int __usbhs_pkt_handler(struct usbhs_pipe *pipe, int type);
#define usbhs_pkt_start(p) __usbhs_pkt_handler(p, USBHSF_PKT_PREPARE)
#define usbhs_pkt_run(p) __usbhs_pkt_handler(p, USBHSF_PKT_TRY_RUN)
#define usbhs_pkt_dmadone(p) __usbhs_pkt_handler(p, USBHSF_PKT_DMA_DONE)
#endif /* RENESAS_USB_FIFO_H */
......@@ -160,6 +160,71 @@ static void usbhsg_queue_done(struct usbhs_pkt *pkt)
usbhsg_queue_pop(uep, ureq, 0);
}
static int usbhsg_dma_map(struct device *dev,
struct usbhs_pkt *pkt,
enum dma_data_direction dir)
{
struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt);
struct usb_request *req = &ureq->req;
if (pkt->dma != DMA_ADDR_INVALID) {
dev_err(dev, "dma is already mapped\n");
return -EIO;
}
if (req->dma == DMA_ADDR_INVALID) {
pkt->dma = dma_map_single(dev, pkt->buf, pkt->length, dir);
} else {
dma_sync_single_for_device(dev, req->dma, req->length, dir);
pkt->dma = req->dma;
}
if (dma_mapping_error(dev, pkt->dma)) {
dev_err(dev, "dma mapping error %x\n", pkt->dma);
return -EIO;
}
return 0;
}
static int usbhsg_dma_unmap(struct device *dev,
struct usbhs_pkt *pkt,
enum dma_data_direction dir)
{
struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt);
struct usb_request *req = &ureq->req;
if (pkt->dma == DMA_ADDR_INVALID) {
dev_err(dev, "dma is not mapped\n");
return -EIO;
}
if (req->dma == DMA_ADDR_INVALID)
dma_unmap_single(dev, pkt->dma, pkt->length, dir);
else
dma_sync_single_for_cpu(dev, req->dma, req->length, dir);
pkt->dma = DMA_ADDR_INVALID;
return 0;
}
static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
{
struct usbhs_pipe *pipe = pkt->pipe;
struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe);
struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
struct device *dev = usbhsg_gpriv_to_dev(gpriv);
enum dma_data_direction dir;
dir = usbhs_pipe_is_dir_in(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
if (map)
return usbhsg_dma_map(dev, pkt, dir);
else
return usbhsg_dma_unmap(dev, pkt, dir);
}
/*
* USB_TYPE_STANDARD / clear feature functions
*/
......@@ -434,6 +499,8 @@ static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep,
usbhs_pkt_init(usbhsg_ureq_to_pkt(ureq));
ureq->req.dma = DMA_ADDR_INVALID;
return &ureq->req;
}
......@@ -569,7 +636,8 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status)
* pipe initialize and enable DCP
*/
usbhs_pipe_init(priv,
usbhsg_queue_done);
usbhsg_queue_done,
usbhsg_dma_map_ctrl);
usbhs_fifo_init(priv);
usbhsg_uep_init(gpriv);
......
......@@ -532,7 +532,8 @@ static struct usbhs_pipe *usbhsp_get_pipe(struct usbhs_priv *priv, u32 type)
}
void usbhs_pipe_init(struct usbhs_priv *priv,
void (*done)(struct usbhs_pkt *pkt))
void (*done)(struct usbhs_pkt *pkt),
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map))
{
struct usbhs_pipe_info *info = usbhs_priv_to_pipeinfo(priv);
struct device *dev = usbhs_priv_to_dev(priv);
......@@ -572,6 +573,7 @@ void usbhs_pipe_init(struct usbhs_priv *priv,
}
info->done = done;
info->dma_map_ctrl = dma_map_ctrl;
}
struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv,
......
......@@ -44,6 +44,7 @@ struct usbhs_pipe_info {
int bufnmb_last; /* FIXME : driver needs good allocator */
void (*done)(struct usbhs_pkt *pkt);
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map);
};
/*
......@@ -82,7 +83,8 @@ 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,
void (*done)(struct usbhs_pkt *pkt));
void (*done)(struct usbhs_pkt *pkt),
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map));
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);
......
......@@ -110,6 +110,23 @@ struct renesas_usbhs_driver_param {
* delay time from notify_hotplug callback
*/
int detection_delay;
/*
* option:
*
* dma id for dmaengine
*/
int d0_tx_id;
int d0_rx_id;
int d1_tx_id;
int d1_rx_id;
/*
* option:
*
* pio <--> dma border.
*/
int pio_dma_border; /* default is 64byte */
};
/*
......
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