From: Antony Pavlov <antonynpavlov@gmail.com>
To: barebox@lists.infradead.org
Cc: Peter Mamonov <pmamonov@gmail.com>
Subject: [RFC 7/9] usb: ehci: add big-endian registers support
Date: Fri, 28 Aug 2015 01:24:08 +0300 [thread overview]
Message-ID: <1440714250-28080-8-git-send-email-antonynpavlov@gmail.com> (raw)
In-Reply-To: <1440714250-28080-1-git-send-email-antonynpavlov@gmail.com>
Signed-off-by: Antony Pavlov <antonynpavlov@gmail.com>
---
drivers/usb/host/Kconfig | 3 +
drivers/usb/host/ehci-hcd.c | 133 ++++++++++++++++++++++----------------------
drivers/usb/host/ehci.h | 42 +++++++++++++-
include/usb/ehci.h | 1 +
4 files changed, 108 insertions(+), 71 deletions(-)
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 54eaf46..23dcf9c 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -2,6 +2,9 @@ config USB_EHCI
bool "EHCI driver"
depends on HAS_DMA
+config USB_EHCI_BIG_ENDIAN_MMIO
+ bool
+
config USB_EHCI_OMAP
depends on ARCH_OMAP3
depends on USB_TWL4030
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 49af642..dd5f503 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -34,22 +34,6 @@
#include "ehci.h"
-struct ehci_priv {
- int rootdev;
- struct device_d *dev;
- struct ehci_hccr *hccr;
- struct ehci_hcor *hcor;
- struct usb_host host;
- struct QH *qh_list;
- struct qTD *td;
- int portreset;
- unsigned long flags;
-
- int (*init)(void *drvdata);
- int (*post_init)(void *drvdata);
- void *drvdata;
-};
-
#define to_ehci(ptr) container_of(ptr, struct ehci_priv, host)
#define NUM_QH 2
@@ -123,7 +107,8 @@ static struct descriptor {
#define ehci_is_TDI() (ehci->flags & EHCI_HAS_TT)
-static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
+static int handshake(const struct ehci_priv *ehci,
+ uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
{
uint32_t result;
uint64_t start;
@@ -131,7 +116,7 @@ static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
start = get_time_ns();
while (1) {
- result = ehci_readl(ptr);
+ result = ehci_readl(ehci, ptr);
if (result == ~(uint32_t)0)
return -1;
result &= mask;
@@ -149,10 +134,11 @@ static int ehci_reset(struct ehci_priv *ehci)
uint32_t *reg_ptr;
int ret = 0;
- cmd = ehci_readl(&ehci->hcor->or_usbcmd);
+ cmd = ehci_readl(ehci, &ehci->hcor->or_usbcmd);
cmd |= CMD_RESET;
- ehci_writel(&ehci->hcor->or_usbcmd, cmd);
- ret = handshake(&ehci->hcor->or_usbcmd, CMD_RESET, 0, 250 * 1000);
+ ehci_writel(ehci, &ehci->hcor->or_usbcmd, cmd);
+ ret = handshake(ehci, &ehci->hcor->or_usbcmd, CMD_RESET, 0,
+ 250 * 1000);
if (ret < 0) {
dev_err(ehci->dev, "fail to reset\n");
goto out;
@@ -160,9 +146,14 @@ static int ehci_reset(struct ehci_priv *ehci)
if (ehci_is_TDI()) {
reg_ptr = (uint32_t *)((u8 *)ehci->hcor + USBMODE);
- tmp = ehci_readl(reg_ptr);
+ tmp = ehci_readl(ehci, reg_ptr);
tmp |= USBMODE_CM_HC;
- ehci_writel(reg_ptr, tmp);
+ /* FIXME: does not work on AR9331 yet */
+ /*
+ if (ehci_big_endian_mmio(ehci))
+ tmp |= USBMODE_BE;
+ */
+ ehci_writel(ehci, reg_ptr, tmp);
}
out:
return ret;
@@ -333,15 +324,16 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
}
}
- usbsts = ehci_readl(&ehci->hcor->or_usbsts);
- ehci_writel(&ehci->hcor->or_usbsts, (usbsts & 0x3f));
+ usbsts = ehci_readl(ehci, &ehci->hcor->or_usbsts);
+ ehci_writel(ehci, &ehci->hcor->or_usbsts, (usbsts & 0x3f));
/* Enable async. schedule. */
- cmd = ehci_readl(&ehci->hcor->or_usbcmd);
+ cmd = ehci_readl(ehci, &ehci->hcor->or_usbcmd);
cmd |= CMD_ASE;
- ehci_writel(&ehci->hcor->or_usbcmd, cmd);
+ ehci_writel(ehci, &ehci->hcor->or_usbcmd, cmd);
- ret = handshake(&ehci->hcor->or_usbsts, STD_ASS, STD_ASS, 100 * 1000);
+ ret = handshake(ehci, &ehci->hcor->or_usbsts, STD_ASS, STD_ASS,
+ 100 * 1000);
if (ret < 0) {
dev_err(ehci->dev, "fail timeout STD_ASS set\n");
goto fail;
@@ -355,12 +347,13 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
token = hc32_to_cpu(vtd->qt_token);
if (is_timeout(start, timeout_val)) {
/* Disable async schedule. */
- cmd = ehci_readl(&ehci->hcor->or_usbcmd);
+ cmd = ehci_readl(ehci, &ehci->hcor->or_usbcmd);
cmd &= ~CMD_ASE;
- ehci_writel(&ehci->hcor->or_usbcmd, cmd);
+ ehci_writel(ehci, &ehci->hcor->or_usbcmd, cmd);
- ret = handshake(&ehci->hcor->or_usbsts, STD_ASS, 0, 100 * 1000);
- ehci_writel(&qh->qt_token, 0);
+ ret = handshake(ehci, &ehci->hcor->or_usbsts,
+ STD_ASS, 0, 100 * 1000);
+ ehci_writel(ehci, &qh->qt_token, 0);
return -ETIMEDOUT;
}
} while (token & 0x80);
@@ -376,11 +369,11 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
}
/* Disable async schedule. */
- cmd = ehci_readl(&ehci->hcor->or_usbcmd);
+ cmd = ehci_readl(ehci, &ehci->hcor->or_usbcmd);
cmd &= ~CMD_ASE;
- ehci_writel(&ehci->hcor->or_usbcmd, cmd);
+ ehci_writel(ehci, &ehci->hcor->or_usbcmd, cmd);
- ret = handshake(&ehci->hcor->or_usbsts, STD_ASS, 0,
+ ret = handshake(ehci, &ehci->hcor->or_usbsts, STD_ASS, 0,
100 * 1000);
if (ret < 0) {
dev_err(ehci->dev, "fail timeout STD_ASS reset\n");
@@ -420,9 +413,9 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
} else {
dev->act_len = 0;
dev_dbg(ehci->dev, "dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
- dev->devnum, ehci_readl(&ehci->hcor->or_usbsts),
- ehci_readl(&ehci->hcor->or_portsc[0]),
- ehci_readl(&ehci->hcor->or_portsc[1]));
+ dev->devnum, ehci_readl(ehci, &ehci->hcor->or_usbsts),
+ ehci_readl(ehci, &ehci->hcor->or_portsc[0]),
+ ehci_readl(ehci, &ehci->hcor->or_portsc[1]));
}
return (dev->status != USB_ST_NOT_PROC) ? 0 : -1;
@@ -567,7 +560,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
break;
case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
memset(tmpbuf, 0, 4);
- reg = ehci_readl(status_reg);
+ reg = ehci_readl(ehci, status_reg);
if (reg & EHCI_PS_CS)
tmpbuf[0] |= USB_PORT_STAT_CONNECTION;
if (reg & EHCI_PS_PE)
@@ -581,8 +574,9 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
int ret;
/* force reset to complete */
reg = reg & ~(EHCI_PS_PR | EHCI_PS_CLEAR);
- ehci_writel(status_reg, reg);
- ret = handshake(status_reg, EHCI_PS_PR, 0, 2 * 1000);
+ ehci_writel(ehci, status_reg, reg);
+ ret = handshake(ehci, status_reg, EHCI_PS_PR, 0,
+ 2 * 1000);
if (!ret)
tmpbuf[0] |= USB_PORT_STAT_RESET;
else
@@ -621,17 +615,17 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
srclen = 4;
break;
case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
- reg = ehci_readl(status_reg);
+ reg = ehci_readl(ehci, status_reg);
reg &= ~EHCI_PS_CLEAR;
switch (le16_to_cpu(req->value)) {
case USB_PORT_FEAT_ENABLE:
reg |= EHCI_PS_PE;
- ehci_writel(status_reg, reg);
+ ehci_writel(ehci, status_reg, reg);
break;
case USB_PORT_FEAT_POWER:
- if (HCS_PPC(ehci_readl(&ehci->hccr->cr_hcsparams))) {
+ if (HCS_PPC(ehci_readl(ehci, &ehci->hccr->cr_hcsparams))) {
reg |= EHCI_PS_PP;
- ehci_writel(status_reg, reg);
+ ehci_writel(ehci, status_reg, reg);
}
break;
case USB_PORT_FEAT_RESET:
@@ -642,14 +636,14 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
dev_dbg(ehci->dev, "port %d low speed --> companion\n",
port - 1);
reg |= EHCI_PS_PO;
- ehci_writel(status_reg, reg);
+ ehci_writel(ehci, status_reg, reg);
break;
} else {
int ret;
reg |= EHCI_PS_PR;
reg &= ~EHCI_PS_PE;
- ehci_writel(status_reg, reg);
+ ehci_writel(ehci, status_reg, reg);
/*
* caller must wait, then call GetPortStatus
* usb 2.0 specification say 50 ms resets on
@@ -659,13 +653,13 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
mdelay(50);
ehci->portreset |= 1 << port;
/* terminate the reset */
- ehci_writel(status_reg, reg & ~EHCI_PS_PR);
+ ehci_writel(ehci, status_reg, reg & ~EHCI_PS_PR);
/*
* A host controller must terminate the reset
* and stabilize the state of the port within
* 2 milliseconds
*/
- ret = handshake(status_reg, EHCI_PS_PR, 0,
+ ret = handshake(ehci, status_reg, EHCI_PS_PR, 0,
2 * 1000);
if (!ret)
ehci->portreset |=
@@ -681,10 +675,10 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
goto unknown;
}
/* unblock posted writes */
- (void) ehci_readl(&ehci->hcor->or_usbcmd);
+ (void) ehci_readl(ehci, &ehci->hcor->or_usbcmd);
break;
case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
- reg = ehci_readl(status_reg);
+ reg = ehci_readl(ehci, status_reg);
reg &= ~EHCI_PS_CLEAR;
switch (le16_to_cpu(req->value)) {
case USB_PORT_FEAT_ENABLE:
@@ -694,7 +688,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
reg |= EHCI_PS_PEC;
break;
case USB_PORT_FEAT_POWER:
- if (HCS_PPC(ehci_readl(&ehci->hccr->cr_hcsparams)))
+ if (HCS_PPC(ehci_readl(ehci, &ehci->hccr->cr_hcsparams)))
reg &= ~ EHCI_PS_PP;
break;
case USB_PORT_FEAT_C_CONNECTION:
@@ -710,9 +704,9 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
dev_dbg(ehci->dev, "unknown feature %x\n", le16_to_cpu(req->value));
goto unknown;
}
- ehci_writel(status_reg, reg);
+ ehci_writel(ehci, status_reg, reg);
/* unblock posted write */
- (void) ehci_readl(&ehci->hcor->or_usbcmd);
+ (void) ehci_readl(ehci, &ehci->hcor->or_usbcmd);
break;
default:
dev_dbg(ehci->dev, "Unknown request\n");
@@ -743,19 +737,19 @@ unknown:
/* force HC to halt state from unknown (EHCI spec section 2.3) */
static int ehci_halt(struct ehci_priv *ehci)
{
- u32 temp = ehci_readl(&ehci->hcor->or_usbsts);
+ u32 temp = ehci_readl(ehci, &ehci->hcor->or_usbsts);
/* disable any irqs left enabled by previous code */
- ehci_writel(&ehci->hcor->or_usbintr, 0);
+ ehci_writel(ehci, &ehci->hcor->or_usbintr, 0);
if (temp & STS_HALT)
return 0;
- temp = ehci_readl(&ehci->hcor->or_usbcmd);
+ temp = ehci_readl(ehci, &ehci->hcor->or_usbcmd);
temp &= ~CMD_RUN;
- ehci_writel(&ehci->hcor->or_usbcmd, temp);
+ ehci_writel(ehci, &ehci->hcor->or_usbcmd, temp);
- return handshake(&ehci->hcor->or_usbsts,
+ return handshake(ehci, &ehci->hcor->or_usbsts,
STS_HALT, STS_HALT, 16 * 125);
}
@@ -788,10 +782,10 @@ static int ehci_init(struct usb_host *host)
ehci->qh_list->qt_token = cpu_to_hc32(0x40);
/* Set async. queue head pointer. */
- ehci_writel(&ehci->hcor->or_asynclistaddr,
+ ehci_writel(ehci, &ehci->hcor->or_asynclistaddr,
(uint32_t)virt_to_phys(ehci->qh_list));
- reg = ehci_readl(&ehci->hccr->cr_hcsparams);
+ reg = ehci_readl(ehci, &ehci->hccr->cr_hcsparams);
descriptor.hub.bNbrPorts = HCS_N_PORTS(reg);
/* Port Indicators */
@@ -802,21 +796,21 @@ static int ehci_init(struct usb_host *host)
descriptor.hub.wHubCharacteristics |= 0x01;
/* Start the host controller. */
- cmd = ehci_readl(&ehci->hcor->or_usbcmd);
+ cmd = ehci_readl(ehci, &ehci->hcor->or_usbcmd);
/*
* Philips, Intel, and maybe others need CMD_RUN before the
* root hub will detect new devices (why?); NEC doesn't
*/
cmd &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
cmd |= CMD_RUN;
- ehci_writel(&ehci->hcor->or_usbcmd, cmd);
+ ehci_writel(ehci, &ehci->hcor->or_usbcmd, cmd);
/* take control over the ports */
- cmd = ehci_readl(&ehci->hcor->or_configflag);
+ cmd = ehci_readl(ehci, &ehci->hcor->or_configflag);
cmd |= FLAG_CF;
- ehci_writel(&ehci->hcor->or_configflag, cmd);
+ ehci_writel(ehci, &ehci->hcor->or_configflag, cmd);
/* unblock posted write */
- cmd = ehci_readl(&ehci->hcor->or_usbcmd);
+ cmd = ehci_readl(ehci, &ehci->hcor->or_usbcmd);
mdelay(5);
ehci->rootdev = 0;
@@ -890,6 +884,9 @@ int ehci_register(struct device_d *dev, struct ehci_data *data)
host = &ehci->host;
dev->priv = ehci;
ehci->flags = data->flags;
+ if (data->flags & EHCI_BE_MMIO)
+ ehci->big_endian_mmio = 1;
+
ehci->hccr = data->hccr;
ehci->dev = dev;
@@ -897,7 +894,7 @@ int ehci_register(struct device_d *dev, struct ehci_data *data)
ehci->hcor = data->hcor;
else
ehci->hcor = (void __iomem *)ehci->hccr +
- HC_LENGTH(ehci_readl(&ehci->hccr->cr_capbase));
+ HC_LENGTH(ehci_readl(ehci, &ehci->hccr->cr_capbase));
ehci->drvdata = data->drvdata;
ehci->init = data->init;
@@ -922,7 +919,7 @@ int ehci_register(struct device_d *dev, struct ehci_data *data)
usb_register_host(host);
- reg = HC_VERSION(ehci_readl(&ehci->hccr->cr_capbase));
+ reg = HC_VERSION(ehci_readl(ehci, &ehci->hccr->cr_capbase));
dev_info(dev, "USB EHCI %x.%02x\n", reg >> 8, reg & 0xff);
return 0;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index bda669b..e62aca8 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -70,13 +70,49 @@ struct ehci_hcor {
#define USBMODE_CM_HC (3 << 0) /* host controller mode */
#define USBMODE_CM_IDLE (0 << 0) /* idle state */
-static inline void ehci_writel(__u32 __iomem *regs, const unsigned int val)
+struct ehci_priv {
+ int rootdev;
+ struct device_d *dev;
+ struct ehci_hccr *hccr;
+ struct ehci_hcor *hcor;
+ struct usb_host host;
+ struct QH *qh_list;
+ struct qTD *td;
+ int portreset;
+ unsigned long flags;
+ unsigned big_endian_mmio:1;
+
+ int (*init)(void *drvdata);
+ int (*post_init)(void *drvdata);
+ void *drvdata;
+};
+
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+#define ehci_big_endian_mmio(e) ((e)->big_endian_mmio)
+#else
+#define ehci_big_endian_mmio(e) 0
+#endif
+
+static inline void ehci_writel(const struct ehci_priv *ehci,
+ __u32 __iomem *regs, const unsigned int val)
{
- writel(val, regs);
+ if (IS_ENABLED(CONFIG_USB_EHCI_BIG_ENDIAN_MMIO)) {
+ ehci_big_endian_mmio(ehci) ?
+ iowrite32be(val, regs) :
+ writel(val, regs);
+ } else
+ writel(val, regs);
}
-static inline unsigned int ehci_readl(__u32 __iomem *regs)
+static inline unsigned int ehci_readl(const struct ehci_priv *ehci,
+ __u32 __iomem *regs)
{
+ if (IS_ENABLED(CONFIG_USB_EHCI_BIG_ENDIAN_MMIO)) {
+ return ehci_big_endian_mmio(ehci) ?
+ ioread32be(regs) :
+ readl(regs);
+ }
+
return readl(regs);
}
diff --git a/include/usb/ehci.h b/include/usb/ehci.h
index 93f980d..0089a0c 100644
--- a/include/usb/ehci.h
+++ b/include/usb/ehci.h
@@ -2,6 +2,7 @@
#define __USB_EHCI_H
#define EHCI_HAS_TT (1 << 0)
+#define EHCI_BE_MMIO (1 << 1)
struct ehci_platform_data {
unsigned long flags;
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
next prev parent reply other threads:[~2015-08-27 22:24 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-08-27 22:24 [RFC 0/9] ehci-hcd.c: make it works on big-endian mips (AR9331) Antony Pavlov
2015-08-27 22:24 ` [RFC 1/9] WIP: make ehci-hcd.c happy on big-endian MIPS Antony Pavlov
2015-08-27 22:24 ` [RFC 2/9] WIP: fix drivers/usb/core/usb.c Antony Pavlov
2015-08-28 6:11 ` Sascha Hauer
2015-08-28 15:51 ` Antony Pavlov
2015-08-31 6:45 ` Sascha Hauer
2015-08-27 22:24 ` [RFC 3/9] MIPS: add virt_to_phys() and phys_to_virt() Antony Pavlov
2015-08-28 6:34 ` Sascha Hauer
2015-08-28 15:46 ` Antony Pavlov
2015-09-04 6:20 ` Sascha Hauer
2015-09-04 7:27 ` Antony Pavlov
2015-09-04 8:44 ` Sascha Hauer
2015-12-06 14:50 ` Antony Pavlov
2015-12-07 10:27 ` Sascha Hauer
2015-12-08 9:11 ` Antony Pavlov
2015-12-08 11:46 ` Peter Mamonov
2015-12-09 13:03 ` Sascha Hauer
2015-08-27 22:24 ` [RFC 4/9] MIPS: add trivial dma support Antony Pavlov
2015-08-27 22:24 ` [RFC 5/9] ehci-hcd.c: make it works on mips Antony Pavlov
2015-08-27 22:24 ` [RFC 6/9] usb: ehci: drop unusable CONFIG_EHCI_MMIO_BIG_ENDIAN condition Antony Pavlov
2015-08-27 22:24 ` Antony Pavlov [this message]
2015-08-28 6:19 ` [RFC 7/9] usb: ehci: add big-endian registers support Sascha Hauer
2015-08-28 15:49 ` Antony Pavlov
2015-08-27 22:24 ` [RFC 8/9] MIPS: tplink-mr3020: select big-endian EHCI support Antony Pavlov
2015-08-27 22:24 ` [RFC 9/9] MIPS: tplink-mr3020_defconfig: enable usb stuff Antony Pavlov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1440714250-28080-8-git-send-email-antonynpavlov@gmail.com \
--to=antonynpavlov@gmail.com \
--cc=barebox@lists.infradead.org \
--cc=pmamonov@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.