From: Michael Schmitz <schmitzmic@gmail.com>
To: geert@linux-m68k.org
Cc: linux-m68k@vger.kernel.org, Michael Schmitz <schmitz@debian.org>
Subject: [PATCH 12/12] m68k/atari: USB - add ISP1160 USB host controller support
Date: Sat, 30 Mar 2013 13:27:52 +1300 [thread overview]
Message-ID: <1364603272-8148-13-git-send-email-schmitz@debian.org> (raw)
In-Reply-To: <1364603272-8148-1-git-send-email-schmitz@debian.org>
Add Atari specific quirks to the isp116x-hcd USB driver used for
EtherNAT and NetUSBee.
Debugging of FIFO register access code and NetUSBee support by
David Galvez <dgalvez75@gmail.com> (MiNT driver author)
Signed-off-by: Michael Schmitz <schmitz@debian.org>
---
arch/m68k/Kconfig.bus | 11 ++++
drivers/usb/host/isp116x-hcd.c | 109 +++++++++++++++++++++++++++++++++++++++-
drivers/usb/host/isp116x.h | 41 ++++++++++++---
3 files changed, 150 insertions(+), 11 deletions(-)
diff --git a/arch/m68k/Kconfig.bus b/arch/m68k/Kconfig.bus
index 675b087..efb6aab 100644
--- a/arch/m68k/Kconfig.bus
+++ b/arch/m68k/Kconfig.bus
@@ -55,6 +55,17 @@ config ATARI_ROM_ISA
The only driver currently using this adapter is the EtherNEC
driver for RTL8019AS based NE2000 compatible network cards.
+config ATARI_USB
+ bool "Atari USB host controller support"
+ depends on ATARI
+ select USB_SUPPORT
+ select USB_ARCH_HAS_HCD
+ help
+ This option enables support for USB host controllers contained on
+ the EtherNAT and NetUSBee cards for Atari. You will have to select
+ an appropriate HCD driver in the USB section (the ISP1160 one is
+ the most commonly used one).
+
config GENERIC_ISA_DMA
def_bool ISA
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index b64e661..fce2766 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -82,8 +82,25 @@ MODULE_LICENSE("GPL");
static const char hcd_name[] = "isp116x-hcd";
+#ifdef CONFIG_ATARI
+static unsigned char *enat_cr; /* EtherNAT CPLD control register for USB interrupt enable */
+#endif
+
/*-----------------------------------------------------------------*/
+ /*
+ * 16 bit data bus byte swapped in hardware
+ *
+ * isp116x_write_addr uses raw_readw - hw byte swap takes care of different endianness
+ *
+ * isp116x_write_data16 uses raw_readw - byte swap done in hw so BE data ends up in proper LE format
+ * isp116x_raw_write_data16 uses readw - effectively same endiannes retained, use for LE format data
+ *
+ * reversed semantics of primitives allows to keep the register
+ * access functions unchanged for commands and control data - byte
+ * swap done transparently
+ */
+
/*
Write len bytes to fifo, pad till 32-bit boundary
*/
@@ -100,18 +117,27 @@ static void write_ptddata_to_fifo(struct isp116x *isp116x, void *buf, int len)
if ((unsigned long)dp2 & 1) {
/* not aligned */
+
for (; len > 1; len -= 2) {
w = *dp++;
w |= *dp++ << 8;
isp116x_raw_write_data16(isp116x, w);
}
if (len)
+#ifdef CONFIG_ATARI /* MSch: needs swap */
+ isp116x_raw_write_data16(isp116x, (u16) *dp);
+#else
isp116x_write_data16(isp116x, (u16) * dp);
+#endif
} else {
/* aligned */
for (; len > 1; len -= 2) {
/* Keep byte order ! */
+#ifdef CONFIG_ATARI /* MSch: needs swap */
+ isp116x_write_data16(isp116x, cpu_to_le16(*dp2++));
+#else
isp116x_raw_write_data16(isp116x, cpu_to_le16(*dp2++));
+#endif
}
if (len)
@@ -137,6 +163,7 @@ static void read_ptddata_from_fifo(struct isp116x *isp116x, void *buf, int len)
if ((unsigned long)dp2 & 1) {
/* not aligned */
+
for (; len > 1; len -= 2) {
w = isp116x_raw_read_data16(isp116x);
*dp++ = w & 0xff;
@@ -144,12 +171,20 @@ static void read_ptddata_from_fifo(struct isp116x *isp116x, void *buf, int len)
}
if (len)
+#ifdef CONFIG_ATARI /* MSch: needs swap */
+ *dp = 0xff & isp116x_raw_read_data16(isp116x);
+#else
*dp = 0xff & isp116x_read_data16(isp116x);
+#endif
} else {
/* aligned */
for (; len > 1; len -= 2) {
/* Keep byte order! */
+#ifdef CONFIG_ATARI /* MSch: needs swap */
+ *dp2++ = le16_to_cpu(isp116x_read_data16(isp116x));
+#else
*dp2++ = le16_to_cpu(isp116x_raw_read_data16(isp116x));
+#endif
}
if (len)
@@ -593,6 +628,11 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd)
u16 irqstat;
irqreturn_t ret = IRQ_NONE;
+#ifdef CONFIG_ATARI
+ if ((unsigned long) hcd->rsrc_start >= 0x80000000UL)
+ /* EtherNAT control register, disable interrupt for USB */
+ *enat_cr = (*enat_cr) & 0xFB;
+#endif
spin_lock(&isp116x->lock);
isp116x_write_reg16(isp116x, HCuPINTENB, 0);
irqstat = isp116x_read_reg16(isp116x, HCuPINT);
@@ -636,6 +676,10 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd)
isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb);
done:
spin_unlock(&isp116x->lock);
+#ifdef CONFIG_ATARI
+ if ((unsigned long) hcd->rsrc_start >= 0x80000000UL)
+ *enat_cr = (*enat_cr) | 0x04; /* EtherNAT control register, enable interrupt for USB */
+#endif
return ret;
}
@@ -1259,8 +1303,11 @@ static int isp116x_reset(struct usb_hcd *hcd)
struct isp116x *isp116x = hcd_to_isp116x(hcd);
unsigned long t;
u16 clkrdy = 0;
+#ifdef CONFIG_ATARI
+ int ret, timeout = 200 /* ms */ ;
+#else
int ret, timeout = 15 /* ms */ ;
-
+#endif
ret = isp116x_sw_reset(isp116x);
if (ret)
return ret;
@@ -1291,6 +1338,12 @@ static void isp116x_stop(struct usb_hcd *hcd)
u32 val;
spin_lock_irqsave(&isp116x->lock, flags);
+
+#ifdef CONFIG_ATARI
+ if ((unsigned long) hcd->rsrc_start >= 0x80000000UL)
+ /* EtherNAT control register, disable interrupt for USB */
+ *enat_cr = (*enat_cr) & 0xFB;
+#endif
isp116x_write_reg16(isp116x, HCuPINTENB, 0);
/* Switch off ports' power, some devices don't come up
@@ -1356,6 +1409,12 @@ static int isp116x_start(struct usb_hcd *hcd)
val |= RH_A_PSM;
/* Report overcurrent per port */
val |= RH_A_OCPM;
+#ifdef CONFIG_ATARI
+ /* Galvez: For NetUSBee, Overcurrent protection disable,
+ to stop interrupt storm because OC events */
+ if ((unsigned long) hcd->rsrc_start < 0x80000000UL)
+ val |= (RH_A_NOCP | RH_A_NPS);
+#endif
isp116x_write_reg32(isp116x, HCRHDESCA, val);
isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA);
@@ -1394,6 +1453,10 @@ static int isp116x_start(struct usb_hcd *hcd)
isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS);
isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS);
+#ifdef CONFIG_ATARI
+ if ((unsigned long) hcd->rsrc_start >= 0x80000000UL)
+ *enat_cr = (*enat_cr) | 0x04; /* EtherNAT control register, enable interrupt for USB */
+#endif
isp116x_show_regs_log(isp116x);
spin_unlock_irqrestore(&isp116x->lock, flags);
return 0;
@@ -1539,6 +1602,9 @@ static int isp116x_remove(struct platform_device *pdev)
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct isp116x *isp116x;
struct resource *res;
+#ifdef CONFIG_ATARI
+ unsigned long enat_cr_phys;
+#endif
if (!hcd)
return 0;
@@ -1552,7 +1618,14 @@ static int isp116x_remove(struct platform_device *pdev)
iounmap(isp116x->addr_reg);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, 2);
-
+#ifdef CONFIG_ATARI
+ if ((unsigned long) hcd->rsrc_start >= 0x80000000UL) {
+ iounmap(enat_cr);
+ /* unmap & release EtherNAT CPLD control register - at 0x23 off board base address */
+ enat_cr_phys = (res->start & 0xFFFFFF00) + 0x23;
+ release_mem_region(enat_cr_phys, 2);
+ }
+#endif
usb_put_hcd(hcd);
return 0;
}
@@ -1567,6 +1640,9 @@ static int isp116x_probe(struct platform_device *pdev)
int irq;
int ret = 0;
unsigned long irqflags;
+#ifdef CONFIG_ATARI
+ unsigned long enat_cr_phys;
+#endif
if (usb_disabled())
return -ENODEV;
@@ -1613,6 +1689,26 @@ static int isp116x_probe(struct platform_device *pdev)
goto err4;
}
+#ifdef CONFIG_ATARI
+ if ((unsigned long) data->start >= 0x80000000UL) {
+ /* map EtherNAT CPLD control register - at 0x23 off board base address */
+ enat_cr_phys = (data->start & 0xffffff00) + 0x23;
+ if (!request_mem_region(enat_cr_phys, 2, hcd_name)) {
+ ret = -EBUSY;
+ goto err41;
+ }
+ enat_cr = ioremap(enat_cr_phys, 2);
+ if (enat_cr == NULL) {
+ ret = -ENOMEM;
+ goto err42;
+ }
+ /* Disable USB interrupt in the EtherNat board */
+ *enat_cr = (*enat_cr) & 0xFB;
+ }
+ pr_info("ISP116X probe: data %p virt. %p, addr %p virt. %p\n",
+ (void *)data->start, data_reg, (void *)addr->start, addr_reg);
+#endif
+
/* allocate and initialize hcd */
hcd = usb_create_hcd(&isp116x_hc_driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
@@ -1653,11 +1749,20 @@ static int isp116x_probe(struct platform_device *pdev)
return 0;
+
err7:
usb_remove_hcd(hcd);
err6:
usb_put_hcd(hcd);
err5:
+#ifdef CONFIG_ATARI
+ if ((unsigned long) data->start >= 0x80000000UL)
+ iounmap(enat_cr);
+ err42:
+ if ((unsigned long) data->start >= 0x80000000UL)
+ release_mem_region(enat_cr_phys, 2);
+ err41:
+#endif
iounmap(data_reg);
err4:
release_mem_region(data->start, 2);
diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h
index 9a2c400..6359ccb 100644
--- a/drivers/usb/host/isp116x.h
+++ b/drivers/usb/host/isp116x.h
@@ -364,22 +364,45 @@ struct isp116x_ep {
#define IRQ_TEST() do{}while(0)
#endif
+
+#ifdef CONFIG_ATARI
+ /*
+ * 16 bit data bus byte swapped in hardware on both Atari variants.
+ * EtherNAT variant of ISP1160 integration is memory mapped at 0x800000XX,
+ * and uses regular readw/__raw_readw (but semantics swapped).
+ * NetUSBee variant is hooked up through ROM port and uses ROM port
+ * IO access, with fake IO address of 0x3XX.
+ * Selection of the appropriate accessors relies on ioremapped addresses still
+ * retaining the 0x3XX bit.
+ */
+#define isp_readw(p) ((((unsigned long)(__pa(p)) & 0x00000F00) == 0x00000300UL) ? isa_rom_readw_raw(__pa(p)) : __raw_readw((p)))
+#define isp_writew(v, p) ((((unsigned long)(__pa(p)) & 0x00000F00) == 0x00000300UL) ? isa_rom_writew_raw((v), __pa(p)) : __raw_writew((v), (p)))
+#define isp_raw_readw(p) ((((unsigned long)(__pa(p)) & 0x00000F00) == 0x00000300UL) ? isa_rom_readw(__pa(p)) : readw((p)))
+#define isp_raw_writew(v, p) ((((unsigned long)(__pa(p)) & 0x00000F00) == 0x00000300UL) ? isa_rom_writew((v), __pa(p)) : writew((v), (p)))
+#else
+ /* sane hardware */
+#define isp_readw readw
+#define isp_writew writew
+#define isp_raw_readw __raw_readw
+#define isp_raw_writew __raw_writew
+#endif
+
static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg)
{
IRQ_TEST();
- writew(reg & 0xff, isp116x->addr_reg);
+ isp_writew(reg & 0xff, isp116x->addr_reg);
isp116x_delay(isp116x, 300);
}
static inline void isp116x_write_data16(struct isp116x *isp116x, u16 val)
{
- writew(val, isp116x->data_reg);
+ isp_writew(val, isp116x->data_reg);
isp116x_delay(isp116x, 150);
}
static inline void isp116x_raw_write_data16(struct isp116x *isp116x, u16 val)
{
- __raw_writew(val, isp116x->data_reg);
+ isp_raw_writew(val, isp116x->data_reg);
isp116x_delay(isp116x, 150);
}
@@ -387,7 +410,7 @@ static inline u16 isp116x_read_data16(struct isp116x *isp116x)
{
u16 val;
- val = readw(isp116x->data_reg);
+ val = isp_readw(isp116x->data_reg);
isp116x_delay(isp116x, 150);
return val;
}
@@ -396,16 +419,16 @@ static inline u16 isp116x_raw_read_data16(struct isp116x *isp116x)
{
u16 val;
- val = __raw_readw(isp116x->data_reg);
+ val = isp_raw_readw(isp116x->data_reg);
isp116x_delay(isp116x, 150);
return val;
}
static inline void isp116x_write_data32(struct isp116x *isp116x, u32 val)
{
- writew(val & 0xffff, isp116x->data_reg);
+ isp_writew(val & 0xffff, isp116x->data_reg);
isp116x_delay(isp116x, 150);
- writew(val >> 16, isp116x->data_reg);
+ isp_writew(val >> 16, isp116x->data_reg);
isp116x_delay(isp116x, 150);
}
@@ -413,9 +436,9 @@ static inline u32 isp116x_read_data32(struct isp116x *isp116x)
{
u32 val;
- val = (u32) readw(isp116x->data_reg);
+ val = (u32) isp_readw(isp116x->data_reg);
isp116x_delay(isp116x, 150);
- val |= ((u32) readw(isp116x->data_reg)) << 16;
+ val |= ((u32) isp_readw(isp116x->data_reg)) << 16;
isp116x_delay(isp116x, 150);
return val;
}
--
1.7.0.4
next prev parent reply other threads:[~2013-03-30 0:29 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-03-30 0:27 Atari Ethernet/USB paches for m68k-queue and upstream, refactored timer D interrupt patch Michael Schmitz
2013-03-30 0:27 ` [PATCH 01/12] m68k/atari: ROM port ISA adapter support Michael Schmitz
2013-03-30 0:27 ` [PATCH 02/12] m68k/irq: Add handle_polled_irq() for timer based soft interrupts Michael Schmitz
2013-03-30 0:27 ` [PATCH 03/12] m68k/atari: use dedicated irq_chip for timer D interrupts Michael Schmitz
2013-03-30 0:27 ` [PATCH 04/12] m68k/atari: use polled interrupt handler " Michael Schmitz
2013-03-30 0:27 ` [PATCH 05/12] m68k/atari: EtherNAT - platform device and IRQ support code Michael Schmitz
2013-03-30 0:27 ` [PATCH 06/12] m68k/atari: EtherNEC - add platform device support Michael Schmitz
2013-03-30 0:27 ` [PATCH 07/12] m68k/atari: EtherNAT - ethernet support - new driver (smc91x) Michael Schmitz
2013-03-30 0:27 ` [PATCH 08/12] m68k/atari: EtherNEC - ethernet support - new driver (ne.c) Michael Schmitz
2013-03-30 0:27 ` [PATCH 09/12] m68k/atari: EtherNAT - add interrupt chip definition for CPLD interrupts Michael Schmitz
2013-03-30 0:27 ` [PATCH 10/12] m68k: Implement ndelay() based on the existing udelay() logic Michael Schmitz
2013-03-30 0:27 ` [PATCH 11/12] m68k/atari: USB - add platform devices for EtherNAT/NetUSBee ISP1160 HCD Michael Schmitz
2013-03-30 0:27 ` Michael Schmitz [this message]
-- strict thread matches above, loose matches on Subject: below --
2013-04-06 0:26 [PATCH 0/13] Atari EtherNAT/EtherNEC/NetUSBee support Michael Schmitz
2013-04-06 0:26 ` [PATCH 12/12] m68k/atari: USB - add ISP1160 USB host controller support Michael Schmitz
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=1364603272-8148-13-git-send-email-schmitz@debian.org \
--to=schmitzmic@gmail.com \
--cc=geert@linux-m68k.org \
--cc=linux-m68k@vger.kernel.org \
--cc=schmitz@debian.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox