From 01e84cef1a988834b444b7bebba15f5268873d35 Mon Sep 17 00:00:00 2001
From: Florian Fainelli <florian@openwrt.org>
Date: Sun, 8 Apr 2007 10:15:17 +0000
Subject: Rename mipsIRQ.S to int-handler to match the kernel naming
 convention, implement basic board detection, rewrite usb HCD driver (to be
 tested)

SVN-Revision: 6893
---
 target/linux/adm5120-2.6/config/default            |  25 +++-
 .../adm5120-2.6/files/arch/mips/adm5120/Makefile   |   2 +-
 .../files/arch/mips/adm5120/adm5120_info.c         |  11 +-
 .../files/arch/mips/adm5120/int-handler.S          | 135 ++++++++++++++++++
 .../adm5120-2.6/files/arch/mips/adm5120/mipsIRQ.S  | 135 ------------------
 .../files/drivers/usb/host/adm5120-hcd.c           | 151 ++++++++++++++-------
 6 files changed, 271 insertions(+), 188 deletions(-)
 create mode 100644 target/linux/adm5120-2.6/files/arch/mips/adm5120/int-handler.S
 delete mode 100644 target/linux/adm5120-2.6/files/arch/mips/adm5120/mipsIRQ.S

diff --git a/target/linux/adm5120-2.6/config/default b/target/linux/adm5120-2.6/config/default
index 5cd765276d..f4d1208eb1 100644
--- a/target/linux/adm5120-2.6/config/default
+++ b/target/linux/adm5120-2.6/config/default
@@ -7,6 +7,10 @@ CONFIG_BASE_SMALL=0
 CONFIG_BAYCOM_SER_FDX=m
 CONFIG_BAYCOM_SER_HDX=m
 CONFIG_BINFMT_MISC=m
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIUSB is not set
 CONFIG_CIFS_DEBUG2=y
 CONFIG_CIFS_EXPERIMENTAL=y
 CONFIG_CIFS_STATS2=y
@@ -225,6 +229,7 @@ CONFIG_SERIO_SERPORT=y
 # CONFIG_SIBYTE_RHONE is not set
 # CONFIG_SIBYTE_SENTOSA is not set
 # CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SND_USB_AUDIO is not set
 CONFIG_SOFT_WATCHDOG=m
 # CONFIG_SPARSEMEM_STATIC is not set
 CONFIG_SYN_COOKIES=y
@@ -238,5 +243,23 @@ CONFIG_TMPFS_POSIX_ACL=y
 # CONFIG_TOSHIBA_RBTX4938 is not set
 CONFIG_TRAD_SIGNALS=y
 # CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_USB is not set
+CONFIG_USB=y
+# CONFIG_USBPCWATCHDOG is not set
+# CONFIG_USB_ACM is not set
+CONFIG_USB_ADM5120_HCD=y
+# CONFIG_USB_ATM is not set
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_SERIAL is not set
+# CONFIG_USB_STORAGE is not set
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_USBNET_MII is not set
+# CONFIG_USB_ZD1201 is not set
 CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_ZD1211RW is not set
diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile b/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile
index a68b4a1451..7ea82a1309 100644
--- a/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile
+++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/Makefile
@@ -2,6 +2,6 @@
 # Makefile for the ADMtek ADM5120 SoC specific parts of the kernel
 #
 
-obj-y  := setup.o prom.o irq.o memory.o mipsIRQ.o adm5120_info.o
+obj-y  := setup.o prom.o irq.o memory.o int-handler.o adm5120_info.o
 
 EXTRA_AFLAGS := $(CFLAGS)
diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/adm5120_info.c b/target/linux/adm5120-2.6/files/arch/mips/adm5120/adm5120_info.c
index 9e39730a4f..1780a5bb8a 100644
--- a/target/linux/adm5120-2.6/files/arch/mips/adm5120/adm5120_info.c
+++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/adm5120_info.c
@@ -162,7 +162,16 @@ static int __init detect_bootloader(void)
  */
 static void __init detect_board_type(void)
 {
-	/* FIXME: not yet implemented */
+	switch(adm5120_info.boot_loader) {
+		case BOOT_LOADER_CFE:
+			adm5120_info.board_type = BOARD_TYPE_WP54G_WRT;
+			adm5120_info.iface_num = 2;
+			adm5120_info.has_usb = 0;
+			printk("Board is a Compex WP54G-WRT\n");
+		default:
+			adm5120_info.board_type = BOARD_TYPE_UNKNOWN;
+			printk("Board type is unknown\n");
+	}
 }
 
 void __init adm5120_info_show(void)
diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/int-handler.S b/target/linux/adm5120-2.6/files/arch/mips/adm5120/int-handler.S
new file mode 100644
index 0000000000..f118fb402b
--- /dev/null
+++ b/target/linux/adm5120-2.6/files/arch/mips/adm5120/int-handler.S
@@ -0,0 +1,135 @@
+/*
+ * Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 1999, 2000 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * ########################################################################
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope 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.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * ########################################################################
+ *
+ * Interrupt exception dispatch code.
+ *
+ */
+#include <linux/autoconf.h>
+
+#include <asm/asm.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+
+#define STATUS_IE	0x00000001
+
+/* A lot of complication here is taken away because:
+ *
+ * 1) We handle one interrupt and return, sitting in a loop and moving across
+ *    all the pending IRQ bits in the cause register is _NOT_ the answer, the
+ *    common case is one pending IRQ so optimize in that direction.
+ *
+ * 2) We need not check against bits in the status register IRQ mask, that
+ *    would make this routine slow as hell.
+ *
+ * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
+ *    between like BSD spl() brain-damage.
+ *
+ * Furthermore, the IRQs on the MIPS board look basically (barring software
+ * IRQs which we don't use at all and all external interrupt sources are
+ * combined together on hardware interrupt 0 (MIPS IRQ 2)) like:
+ *
+ *	MIPS IRQ	Source
+ *      --------        ------
+ *             0	Software (ignored)
+ *             1        Software (ignored)
+ *             2        Combined hardware interrupt (hw0)
+ *             3        Hardware (ignored)
+ *             4        Hardware (ignored)
+ *             5        Hardware (ignored)
+ *             6        Hardware (ignored)
+ *             7        R4k timer (what we use)
+ *
+ * Note: On the SEAD board thing are a little bit different.
+ *       Here IRQ 2 (hw0) is wired to the UART0 and IRQ 3 (hw1) is wired
+ *       wired to UART1.
+ *	
+ * We handle the IRQ according to _our_ priority which is:
+ *
+ * Highest ----     R4k Timer
+ * Lowest  ----     Combined hardware interrupt
+ *
+ * then we just return, if multiple IRQs are pending then we will just take
+ * another exception, big deal.
+ */
+
+	.text
+	.set	noreorder
+	.set	noat
+	.align	5
+
+NESTED(mipsIRQ, PT_SIZE, sp)
+	SAVE_ALL
+	CLI
+	.set	at
+
+	mfc0	s0, CP0_CAUSE		
+	mfc0	s1, CP0_STATUS
+	and     s0, s0, s1
+	
+	/* First we check for r4k counter/timer IRQ. */
+	andi	a0, s0, CAUSEF_IP7
+	beq		a0, zero, 1f
+	nop
+
+	move	a0, sp
+	jal		mips_timer_interrupt
+	nop
+
+	j		ret_from_irq
+	nop				
+
+1:
+	andi	a0, s0, CAUSEF_IP2
+	beq		a0, zero, 1f	
+	nop
+	
+	move	a0, sp			
+	jal		adm5120_hw0_irqdispatch	 
+	nop
+1:
+	j		ret_from_irq
+	nop							
+
+END(mipsIRQ)
+
+
+LEAF(mips_int_lock)
+	.set noreorder
+	mfc0	v0, CP0_STATUS
+	li		v1, ~STATUS_IE
+	and		v1, v1, v0
+	mtc0	v1, CP0_STATUS
+	j		ra
+	and		v0, v0, STATUS_IE
+	.set reorder
+END(mips_int_lock)
+
+
+LEAF(mips_int_unlock)
+	mfc0	v0, CP0_STATUS
+	and		a0, a0, STATUS_IE
+	or		v0, v0, a0
+	mtc0	v0, CP0_STATUS
+	j		ra
+	nop
+END(mips_int_unlock)
+
diff --git a/target/linux/adm5120-2.6/files/arch/mips/adm5120/mipsIRQ.S b/target/linux/adm5120-2.6/files/arch/mips/adm5120/mipsIRQ.S
deleted file mode 100644
index f118fb402b..0000000000
--- a/target/linux/adm5120-2.6/files/arch/mips/adm5120/mipsIRQ.S
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999, 2000 MIPS Technologies, Inc.  All rights reserved.
- *
- * ########################################################################
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope 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.,
- *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * ########################################################################
- *
- * Interrupt exception dispatch code.
- *
- */
-#include <linux/autoconf.h>
-
-#include <asm/asm.h>
-#include <asm/mipsregs.h>
-#include <asm/regdef.h>
-#include <asm/stackframe.h>
-
-#define STATUS_IE	0x00000001
-
-/* A lot of complication here is taken away because:
- *
- * 1) We handle one interrupt and return, sitting in a loop and moving across
- *    all the pending IRQ bits in the cause register is _NOT_ the answer, the
- *    common case is one pending IRQ so optimize in that direction.
- *
- * 2) We need not check against bits in the status register IRQ mask, that
- *    would make this routine slow as hell.
- *
- * 3) Linux only thinks in terms of all IRQs on or all IRQs off, nothing in
- *    between like BSD spl() brain-damage.
- *
- * Furthermore, the IRQs on the MIPS board look basically (barring software
- * IRQs which we don't use at all and all external interrupt sources are
- * combined together on hardware interrupt 0 (MIPS IRQ 2)) like:
- *
- *	MIPS IRQ	Source
- *      --------        ------
- *             0	Software (ignored)
- *             1        Software (ignored)
- *             2        Combined hardware interrupt (hw0)
- *             3        Hardware (ignored)
- *             4        Hardware (ignored)
- *             5        Hardware (ignored)
- *             6        Hardware (ignored)
- *             7        R4k timer (what we use)
- *
- * Note: On the SEAD board thing are a little bit different.
- *       Here IRQ 2 (hw0) is wired to the UART0 and IRQ 3 (hw1) is wired
- *       wired to UART1.
- *	
- * We handle the IRQ according to _our_ priority which is:
- *
- * Highest ----     R4k Timer
- * Lowest  ----     Combined hardware interrupt
- *
- * then we just return, if multiple IRQs are pending then we will just take
- * another exception, big deal.
- */
-
-	.text
-	.set	noreorder
-	.set	noat
-	.align	5
-
-NESTED(mipsIRQ, PT_SIZE, sp)
-	SAVE_ALL
-	CLI
-	.set	at
-
-	mfc0	s0, CP0_CAUSE		
-	mfc0	s1, CP0_STATUS
-	and     s0, s0, s1
-	
-	/* First we check for r4k counter/timer IRQ. */
-	andi	a0, s0, CAUSEF_IP7
-	beq		a0, zero, 1f
-	nop
-
-	move	a0, sp
-	jal		mips_timer_interrupt
-	nop
-
-	j		ret_from_irq
-	nop				
-
-1:
-	andi	a0, s0, CAUSEF_IP2
-	beq		a0, zero, 1f	
-	nop
-	
-	move	a0, sp			
-	jal		adm5120_hw0_irqdispatch	 
-	nop
-1:
-	j		ret_from_irq
-	nop							
-
-END(mipsIRQ)
-
-
-LEAF(mips_int_lock)
-	.set noreorder
-	mfc0	v0, CP0_STATUS
-	li		v1, ~STATUS_IE
-	and		v1, v1, v0
-	mtc0	v1, CP0_STATUS
-	j		ra
-	and		v0, v0, STATUS_IE
-	.set reorder
-END(mips_int_lock)
-
-
-LEAF(mips_int_unlock)
-	mfc0	v0, CP0_STATUS
-	and		a0, a0, STATUS_IE
-	or		v0, v0, a0
-	mtc0	v0, CP0_STATUS
-	j		ra
-	nop
-END(mips_int_unlock)
-
diff --git a/target/linux/adm5120-2.6/files/drivers/usb/host/adm5120-hcd.c b/target/linux/adm5120-2.6/files/drivers/usb/host/adm5120-hcd.c
index b4a1899d1d..6f0df78c3a 100644
--- a/target/linux/adm5120-2.6/files/drivers/usb/host/adm5120-hcd.c
+++ b/target/linux/adm5120-2.6/files/drivers/usb/host/adm5120-hcd.c
@@ -8,14 +8,22 @@
  *	Which again was based on the ohci and uhci drivers.
  */
 
-#include <linux/autoconf.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include <linux/errno.h>
-#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/list.h>
 #include <linux/usb.h>
 #include <linux/platform_device.h>
 
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+#include <asm/mach-adm5120/adm5120_info.h>
+
 #include "../core/hcd.h"
 
 MODULE_DESCRIPTION("ADM5120 USB Host Controller Driver");
@@ -137,13 +145,33 @@ static int admhcd_td_err[16] = {
 #define ED(ed)	((struct admhcd_ed *)(((u32)(ed)) & ~0xf))
 
 struct admhcd {
+	spinlock_t	lock;
+	
+	void __iomem *addr_reg;
+	void __iomem *data_reg;
+	/* Root hub registers */
+	u32 rhdesca;
+	u32 rhdescb;
+	u32 rhstatus;
+	u32 rhport[2];
+
+	/* async schedule: control, bulk */
+	struct list_head async;
 	u32		base;
 	u32		dma_en;
-	spinlock_t	lock;
 	unsigned long	flags;
+	
 };
 
-#define hcd_to_admhcd(hcd) ((struct admhcd *)(hcd)->hcd_priv)
+static inline struct admhcd *hcd_to_admhcd(struct usb_hcd *hcd)
+{
+	return (struct admhcd *)(hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *admhcd_to_hcd(struct admhcd *admhcd)
+{
+	return container_of((void *)admhcd, struct usb_hcd, hcd_priv);
+}
 
 static char hcd_name[] = "adm5120-hcd";
 
@@ -670,46 +698,69 @@ static struct hc_driver adm5120_hc_driver = {
 	.hub_control =		admhcd_hub_control,
 };
 
+#define resource_len(r) (((r)->end - (r)->start) + 1)
+
 static int __init adm5120hcd_probe(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd;
 	struct admhcd *ahcd;
 	struct usb_device *udev;
-	int err = 0;
+	struct resource *addr, *data;
+	void __iomem *addr_reg;
+	void __iomem *data_reg;	
+	int irq, err = 0;
 
-	if (!request_mem_region(pdev->resource[0].start,
-	    pdev->resource[0].end - pdev->resource[0].start, hcd_name)) {
-		pr_debug("couldn't request mem\n");
-		err = -EBUSY;
+	if (pdev->num_resources < 3) {
+		err = -ENODEV;
 		goto out;
 	}
 
-	//hcd = usb_create_hcd(&adm5120_hc_driver, pdev, pdev->bus_id);
-	if (!hcd)
-		goto out_mem;
+	data = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	addr = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	irq = platform_get_irq(pdev, 0);
 
-	ahcd = hcd_to_admhcd(hcd);
-	dev_set_drvdata(pdev, ahcd);
-	hcd->self.controller = pdev;
-	//hcd->self.bus_name = pdev->bus_id;
-	hcd->irq = pdev->resource[1].start;
-	hcd->regs = (void *)pdev->resource[0].start;
-	hcd->product_desc = hcd_name;
-	ahcd->base = pdev->resource[0].start;
-
-	if (request_irq(pdev->resource[1].start, adm5120hcd_irq, 0, hcd_name,
-	    hcd)) {
-		pr_debug("couldn't request irq\n");
+	if (!addr || !data || irq < 0) {
+		err = -ENODEV;
+		goto out;
+	}
+
+	if (pdev->dev.dma_mask) {
+		printk(KERN_DEBUG "DMA not supported\n");
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (!request_mem_region(addr->start, 2, hcd_name)) {
+		err = -EBUSY;
+		goto out;
+	}
+	addr_reg = ioremap(addr->start, resource_len(addr));
+	if (addr_reg == NULL) {
+		err = -ENOMEM;
+		goto out_mem;
+	}
+	if (!request_mem_region(data->start, 2, hcd_name)) {
 		err = -EBUSY;
-		goto out_hcd;
+		goto out_unmap;
+	}
+	data_reg = ioremap(data->start, resource_len(data));
+	if (data_reg == NULL) {
+		err = -ENOMEM;
+		goto out_mem;
 	}
+								
 
-	//err = usb_register_bus(&hcd->self);
-	//if (err < 0)
-	//	goto out_irq;
+	hcd = usb_create_hcd(&adm5120_hc_driver, &pdev->dev, pdev->dev.bus_id);
+	if (!hcd)
+		goto out_mem;
 
+	ahcd = hcd_to_admhcd(hcd);
+	ahcd->data_reg = data_reg;
+	ahcd->addr_reg = addr_reg;
 	spin_lock_init(&ahcd->lock);
+	INIT_LIST_HEAD(&ahcd->async);
 
+	/* Initialise the HCD registers */
 	admhcd_reg_set(ahcd, ADMHCD_REG_INTENABLE, 0);
 	mdelay(10);
 	admhcd_reg_set(ahcd, ADMHCD_REG_CONTROL, ADMHCD_SW_RESET);
@@ -727,41 +778,39 @@ static int __init adm5120hcd_probe(struct platform_device *pdev)
 	admhcd_reg_set(ahcd, ADMHCD_REG_RHDESCR, ADMHCD_NPS | ADMHCD_LPSC);
 	admhcd_reg_set(ahcd, ADMHCD_REG_HOSTCONTROL, ADMHCD_STATE_OP);
 
-	udev = usb_alloc_dev(NULL, &hcd->self, 0);
-	if (!udev) {
-		err = -ENOMEM;
-		goto out_bus;
-	}
-
-	udev->speed = USB_SPEED_FULL;
-	hcd->state = HC_STATE_RUNNING;
-
-	//err = hcd_register_root(udev, hcd);
-	//if (err != 0) {
-	//	usb_put_dev(udev);
-	//	goto out_dev;
-	//}
+	err = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+	if (err)
+		goto out_dev;
 
 	return 0;
 
 out_dev:
-	usb_put_dev(udev);
-out_bus:
-	//usb_deregister_bus(&hcd->self);
+	usb_put_hcd(hcd);
 out_irq:
 	free_irq(pdev->resource[1].start, hcd);
+out_unmap:
+	iounmap(addr_reg);
 out_hcd:
 	usb_put_hcd(hcd);
 out_mem:
-	release_mem_region(pdev->resource[0].start,
-	    pdev->resource[0].end - pdev->resource[0].start);
+	release_mem_region(addr->start, 2);
 out:
 	return err;
 }
 
 static int __init_or_module adm5120hcd_remove(struct platform_device *pdev)
 {
-	device_init_wakeup(&pdev->dev, 0);
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+	struct admhcd *ahcd;
+	struct resource *res;
+
+	if (!hcd)
+		return 0;
+	ahcd = hcd_to_admhcd(hcd);
+	usb_remove_hcd(hcd);
+
+	usb_put_hcd(hcd);
+	return 0;
 }
 
 static struct platform_driver adm5120hcd_driver = {
@@ -777,6 +826,8 @@ static int __init adm5120hcd_init(void)
 {
 	if (usb_disabled())
 		return -ENODEV;
+	if (!adm5120_info.has_usb)
+		return -ENODEV;
 
 	return platform_driver_register(&adm5120hcd_driver);
 }
-- 
cgit v1.2.3