[PATCH 06/11] USB: s3c-hsotg: Add initial detection and setup for dedicated FIFO mode
Maurus Cuelenaere
mcuelenaere at gmail.com
Fri Jun 11 04:54:27 EDT 2010
Op 11-06-10 10:20, Ben Dooks schreef:
> Add support for the dedicated FIFO mode on newer SoCs such as the S5PV210
> partly to improve support and to fix the bug where any non-EP0 IN endpoint
> requires its own FIFO allocation.
>
> To fix this, we ensure that any non-zero IN endpoint is given a TXFIFO
> using the same allocation method as the periodic case (all our current
> hardware has enough FIFOs and FIFO memory for a 1:1 mapping) and ensure
> that the necessary transmission done interrupt is enabled.
>
> The default settings from reset for the core point all EPs at FIFO0,
> used for the control endpoint. However, the controller documentation
> states that all IN endpoints _must_ have a unique FIFO to avoid any
> contention during transmission.
>
> Note, this leaves us with a large IN FIFO for EP0 (which re-uses the
> old NPTXFIFO) for an endpoint which cannot shift more than a pair of
> packets at a time... this is a waste, but it looks like we cannot
> re-allocate space to the individual IN FIFOs as they are already
> maxed out (to be confirmed).
>
> Signed-off-by: Ben Dooks <ben-linux at fluff.org?
Shouldn't this be s/\?/>/ ?
> ---
> .../arm/plat-samsung/include/plat/regs-usb-hsotg.h | 2 +
> drivers/usb/gadget/s3c-hsotg.c | 40 +++++++++++++++++++-
> 2 files changed, 40 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/plat-samsung/include/plat/regs-usb-hsotg.h b/arch/arm/plat-samsung/include/plat/regs-usb-hsotg.h
> index 8d18d9d..dc90f5e 100644
> --- a/arch/arm/plat-samsung/include/plat/regs-usb-hsotg.h
> +++ b/arch/arm/plat-samsung/include/plat/regs-usb-hsotg.h
> @@ -226,6 +226,7 @@
>
> #define S3C_DIEPMSK S3C_HSOTG_REG(0x810)
>
> +#define S3C_DIEPMSK_TxFIFOEmpty (1 << 7)
> #define S3C_DIEPMSK_INEPNakEffMsk (1 << 6)
> #define S3C_DIEPMSK_INTknEPMisMsk (1 << 5)
> #define S3C_DIEPMSK_INTknTXFEmpMsk (1 << 4)
> @@ -371,6 +372,7 @@
>
> #define S3C_DIEPDMA(_a) S3C_HSOTG_REG(0x914 + ((_a) * 0x20))
> #define S3C_DOEPDMA(_a) S3C_HSOTG_REG(0xB14 + ((_a) * 0x20))
> +#define S3C_DTXFSTS(_a) S3C_HSOTG_REG(0x918 + ((_a) * 0x20))
>
> #define S3C_EPFIFO(_a) S3C_HSOTG_REG(0x1000 + ((_a) * 0x1000))
>
> diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
> index 5b61bcf..819e75a 100644
> --- a/drivers/usb/gadget/s3c-hsotg.c
> +++ b/drivers/usb/gadget/s3c-hsotg.c
> @@ -12,6 +12,8 @@
> * published by the Free Software Foundation.
> */
>
> +#define DEBUG
I don't think this is an intended change?
> +
> #include <linux/kernel.h>
> #include <linux/module.h>
> #include <linux/spinlock.h>
> @@ -131,6 +133,7 @@ struct s3c_hsotg_ep {
> * @regs: The memory area mapped for accessing registers.
> * @regs_res: The resource that was allocated when claiming register space.
> * @irq: The IRQ number we are using
> + * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos.
> * @debug_root: root directrory for debugfs.
> * @debug_file: main status file for debugfs.
> * @debug_fifo: FIFO status file for debugfs.
> @@ -149,6 +152,8 @@ struct s3c_hsotg {
> struct resource *regs_res;
> int irq;
>
> + unsigned int dedicated_fifos:1;
> +
> struct dentry *debug_root;
> struct dentry *debug_file;
> struct dentry *debug_fifo;
> @@ -467,7 +472,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
> if (to_write == 0)
> return 0;
>
> - if (periodic) {
> + if (periodic && !hsotg->dedicated_fifos) {
> u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index));
> int size_left;
> int size_done;
> @@ -505,6 +510,11 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg,
> s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp);
> return -ENOSPC;
> }
> + } else if (hsotg->dedicated_fifos && hs_ep->index != 0) {
> + can_write = readl(hsotg->regs + S3C_DTXFSTS(hs_ep->index));
> +
> + can_write &= 0xffff;
> + can_write *= 4;
> } else {
> if (S3C_GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) {
> dev_dbg(hsotg->dev,
> @@ -1830,6 +1840,15 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
> __func__, idx);
> clear |= S3C_DIEPMSK_INTknEPMisMsk;
> }
> +
> + /* FIFO has space or is empty (see GAHBCFG) */
> + if (hsotg->dedicated_fifos &&
> + ints & S3C_DIEPMSK_TxFIFOEmpty) {
> + dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n",
> + __func__, idx);
> + s3c_hsotg_trytx(hsotg, hs_ep);
> + clear |= S3C_DIEPMSK_TxFIFOEmpty;
> + }
> }
>
> writel(clear, hsotg->regs + epint_reg);
> @@ -2281,6 +2300,12 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
> break;
> }
>
> + /* if the hardware has dedicated fifos, we must give each IN EP
> + * a unique tx-fifo even if it is non-periodic.
> + */
> + if (dir_in && hsotg->dedicated_fifos)
> + epctrl |= S3C_DxEPCTL_TxFNum(index);
> +
> /* for non control endpoints, set PID to D0 */
> if (index)
> epctrl |= S3C_DxEPCTL_SetD0PID;
> @@ -2570,7 +2595,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
>
> writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk |
> S3C_DIEPMSK_INTknEPMisMsk |
> - S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk,
> + S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk |
> + ((hsotg->dedicated_fifos) ? S3C_DIEPMSK_TxFIFOEmpty : 0),
> hsotg->regs + S3C_DIEPMSK);
>
> /* don't need XferCompl, we get that from RXFIFO in slave mode. In
> @@ -2797,6 +2823,8 @@ static void s3c_hsotg_otgreset(struct s3c_hsotg *hsotg)
>
> static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
> {
> + u32 cfg4;
> +
> /* unmask subset of endpoint interrupts */
>
> writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk |
> @@ -2832,6 +2860,14 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
>
> writel(using_dma(hsotg) ? S3C_GAHBCFG_DMAEn : 0x0,
> hsotg->regs + S3C_GAHBCFG);
> +
> + /* check hardware configuration */
> +
> + cfg4 = readl(hsotg->regs + 0x50);
> + hsotg->dedicated_fifos = (cfg4 >> 25) & 1;
> +
> + dev_info(hsotg->dev, "%s fifos\n",
> + hsotg->dedicated_fifos ? "dedicated" : "shared");
> }
>
> static void s3c_hsotg_dump(struct s3c_hsotg *hsotg)
More information about the linux-arm-kernel
mailing list