From David.Daney@caviumnetworks.com Fri Oct  2 01:53:47 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Oct 2009 01:53:54 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:16129 "EHLO
	mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1493807AbZJAXxr (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Fri, 2 Oct 2009 01:53:47 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,5,4,7535)
	id <B4ac540f90006>; Thu, 01 Oct 2009 16:53:29 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.3959);
	 Thu, 1 Oct 2009 16:47:03 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.3959);
	 Thu, 1 Oct 2009 16:47:03 -0700
Message-ID: <4AC53F75.4090902@caviumnetworks.com>
Date:	Thu, 01 Oct 2009 16:47:01 -0700
From:	David Daney <ddaney@caviumnetworks.com>
User-Agent: Thunderbird 2.0.0.21 (X11/20090320)
MIME-Version: 1.0
To:	Ralf Baechle <ralf@linux-mips.org>,
	linux-mips <linux-mips@linux-mips.org>
Subject: [PATCH 0/2] Two Octeon compile errors with 2.6.32-rc1
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
X-OriginalArrivalTime: 01 Oct 2009 23:47:03.0310 (UTC) FILETIME=[79E542E0:01CA42F1]
Return-Path: <David.Daney@caviumnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24122
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ddaney@caviumnetworks.com
Precedence: bulk
X-list: linux-mips

Ralf,

There are a couple of problems I found with 2.6.32-rc1.

Two trivial patches to follow.

David Daney

From David.Daney@caviumnetworks.com Fri Oct  2 01:54:12 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Oct 2009 01:54:19 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:16128 "EHLO
	mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1493804AbZJAXxr (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Fri, 2 Oct 2009 01:53:47 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,5,4,7535)
	id <B4ac540fa0000>; Thu, 01 Oct 2009 16:53:30 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.3959);
	 Thu, 1 Oct 2009 16:47:44 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.3959);
	 Thu, 1 Oct 2009 16:47:44 -0700
Received: from dd1.caveonetworks.com (localhost.localdomain [127.0.0.1])
	by dd1.caveonetworks.com (8.14.2/8.14.2) with ESMTP id n91Nlf4i025438;
	Thu, 1 Oct 2009 16:47:41 -0700
Received: (from ddaney@localhost)
	by dd1.caveonetworks.com (8.14.2/8.14.2/Submit) id n91NlfP4025437;
	Thu, 1 Oct 2009 16:47:41 -0700
From:	David Daney <ddaney@caviumnetworks.com>
To:	linux-mips@linux-mips.org, ralf@linux-mips.org
Cc:	David Daney <ddaney@caviumnetworks.com>
Subject: [PATCH 2/2] MIPS: Octeon: Fix compile error in drivers/staging/octeon/ethernet-mdio.c
Date:	Thu,  1 Oct 2009 16:47:39 -0700
Message-Id: <1254440859-25408-2-git-send-email-ddaney@caviumnetworks.com>
X-Mailer: git-send-email 1.6.0.6
In-Reply-To: <4AC53F75.4090902@caviumnetworks.com>
References: <4AC53F75.4090902@caviumnetworks.com>
X-OriginalArrivalTime: 01 Oct 2009 23:47:44.0107 (UTC) FILETIME=[923663B0:01CA42F1]
Return-Path: <David.Daney@caviumnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24123
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ddaney@caviumnetworks.com
Precedence: bulk
X-list: linux-mips

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---
 drivers/staging/octeon/ethernet-mdio.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c
index 42230e6..31a58e5 100644
--- a/drivers/staging/octeon/ethernet-mdio.c
+++ b/drivers/staging/octeon/ethernet-mdio.c
@@ -170,7 +170,7 @@ static u32 cvm_oct_get_link(struct net_device *dev)
 	return ret;
 }
 
-struct const ethtool_ops cvm_oct_ethtool_ops = {
+const struct ethtool_ops cvm_oct_ethtool_ops = {
 	.get_drvinfo = cvm_oct_get_drvinfo,
 	.get_settings = cvm_oct_get_settings,
 	.set_settings = cvm_oct_set_settings,
-- 
1.6.0.6


From David.Daney@caviumnetworks.com Fri Oct  2 01:54:37 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Oct 2009 01:54:45 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:16130 "EHLO
	mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1493805AbZJAXxr (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Fri, 2 Oct 2009 01:53:47 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,5,4,7535)
	id <B4ac540f90007>; Thu, 01 Oct 2009 16:53:29 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.3959);
	 Thu, 1 Oct 2009 16:47:44 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.3959);
	 Thu, 1 Oct 2009 16:47:44 -0700
Received: from dd1.caveonetworks.com (localhost.localdomain [127.0.0.1])
	by dd1.caveonetworks.com (8.14.2/8.14.2) with ESMTP id n91Nlfuj025434;
	Thu, 1 Oct 2009 16:47:41 -0700
Received: (from ddaney@localhost)
	by dd1.caveonetworks.com (8.14.2/8.14.2/Submit) id n91NldQ6025432;
	Thu, 1 Oct 2009 16:47:39 -0700
From:	David Daney <ddaney@caviumnetworks.com>
To:	linux-mips@linux-mips.org, ralf@linux-mips.org
Cc:	David Daney <ddaney@caviumnetworks.com>
Subject: [PATCH 1/2] MIPS: Octeon: Fix compile error in arch/mips/cavium-octeon/smp.c
Date:	Thu,  1 Oct 2009 16:47:38 -0700
Message-Id: <1254440859-25408-1-git-send-email-ddaney@caviumnetworks.com>
X-Mailer: git-send-email 1.6.0.6
In-Reply-To: <4AC53F75.4090902@caviumnetworks.com>
References: <4AC53F75.4090902@caviumnetworks.com>
X-OriginalArrivalTime: 01 Oct 2009 23:47:44.0107 (UTC) FILETIME=[923663B0:01CA42F1]
Return-Path: <David.Daney@caviumnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24124
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ddaney@caviumnetworks.com
Precedence: bulk
X-list: linux-mips

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---
 arch/mips/cavium-octeon/smp.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c
index 32d51a3..c198efd 100644
--- a/arch/mips/cavium-octeon/smp.c
+++ b/arch/mips/cavium-octeon/smp.c
@@ -65,11 +65,12 @@ void octeon_send_ipi_single(int cpu, unsigned int action)
 	cvmx_write_csr(CVMX_CIU_MBOX_SETX(coreid), action);
 }
 
-static inline void octeon_send_ipi_mask(cpumask_t mask, unsigned int action)
+static inline void octeon_send_ipi_mask(const struct cpumask *mask,
+					unsigned int action)
 {
 	unsigned int i;
 
-	for_each_cpu_mask(i, mask)
+	for_each_cpu_mask(i, *mask)
 		octeon_send_ipi_single(i, action);
 }
 
-- 
1.6.0.6


From w.sang@pengutronix.de Fri Oct  2 12:59:10 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Oct 2009 12:59:16 +0200 (CEST)
Received: from metis.ext.pengutronix.de ([92.198.50.35]:41007 "EHLO
	metis.ext.pengutronix.de" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1493080AbZJBK7K (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Fri, 2 Oct 2009 12:59:10 +0200
Received: from [2001:6f8:1178:2:221:70ff:fe71:1890] (helo=pengutronix.de)
	by metis.ext.pengutronix.de with esmtp (Exim 4.63)
	(envelope-from <w.sang@pengutronix.de>)
	id 1Mtfqp-0006lE-VY; Fri, 02 Oct 2009 12:59:03 +0200
Date:	Fri, 2 Oct 2009 12:59:03 +0200
From:	Wolfram Sang <w.sang@pengutronix.de>
To:	Manuel Lauss <manuel.lauss@googlemail.com>
Cc:	linux-pcmcia <linux-pcmcia@lists.infradead.org>,
	Linux-MIPS <linux-mips@linux-mips.org>,
	Florian Fainelli <florian@openwrt.org>,
	Manuel Lauss <manuel.lauss@gmail.com>
Subject: Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
Message-ID: <20091002105903.GC3179@pengutronix.de>
References: <1254250236-18130-1-git-send-email-manuel.lauss@gmail.com>
MIME-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha1;
	protocol="application/pgp-signature"; boundary="vEao7xgI/oilGqZ+"
Content-Disposition: inline
In-Reply-To: <1254250236-18130-1-git-send-email-manuel.lauss@gmail.com>
User-Agent: Mutt/1.5.18 (2008-05-17)
X-SA-Exim-Connect-IP: 2001:6f8:1178:2:221:70ff:fe71:1890
X-SA-Exim-Mail-From: w.sang@pengutronix.de
X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false
X-PTX-Original-Recipient: linux-mips@linux-mips.org
Return-Path: <w.sang@pengutronix.de>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24125
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: w.sang@pengutronix.de
Precedence: bulk
X-list: linux-mips


--vEao7xgI/oilGqZ+
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable


> Rewritten XXS1500 PCMCIA socket driver, standalone (doesn't
> depend on au1000_generic.c) and added carddetect IRQ support.

I am not familiar with the details here. Why did you choose to drop the gen=
eric
au1000-part for this and the other driver?

--=20
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

--vEao7xgI/oilGqZ+
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAkrF3PcACgkQD27XaX1/VRt2BwCeOFZsajeUyZLnB76UQcDN9hTc
6zYAni04Z9F1asrIMmaG9t/kXKtSDtIN
=aOhh
-----END PGP SIGNATURE-----

--vEao7xgI/oilGqZ+--

From manuel.lauss@googlemail.com Fri Oct  2 13:16:05 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Oct 2009 13:16:12 +0200 (CEST)
Received: from mail-fx0-f221.google.com ([209.85.220.221]:58681 "EHLO
	mail-fx0-f221.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1493054AbZJBLQF (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Fri, 2 Oct 2009 13:16:05 +0200
Received: by fxm21 with SMTP id 21so893780fxm.33
        for <linux-mips@linux-mips.org>; Fri, 02 Oct 2009 04:15:59 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:mime-version:received:in-reply-to:references
         :date:message-id:subject:from:to:cc:content-type;
        bh=H2sHoB9BKG5T1itKZjbNJSqUpnIOI0mPtXxDOJ+SKSw=;
        b=pXYqxY2SgaCpNZYOih/YdM59urKGSRn2n+tZycx8JFH2NllaEE9LvqpSNWZdGoKK7n
         JJisEHllYvuyBZwAKZtnZS3GhUyCMEkJbHcLldpfJrNU7TnEJ+176LMvm8kS63rK8cT3
         rH5VlK4QZpnXn5EwhjwC/IG9XVu4l4zaDzfoA=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type;
        b=xmtByGvP04HKAnulglSYplFqveBf8Dz3aOAYDqig7dEYorgVHzn2YeiVulo2oQEzRm
         oYmPFSd/CfCvg3KPVOdlZZ9f4hpOhfxSXcujeEnT5bLp7yT+8H21lTw23k4XXDVnmgl4
         1c3yCVmlKIMUYDVBEI06aSpZ8jPxT/lOIqNNQ=
MIME-Version: 1.0
Received: by 10.103.76.37 with SMTP id d37mr917394mul.99.1254482159673; Fri, 
	02 Oct 2009 04:15:59 -0700 (PDT)
In-Reply-To: <20091002105903.GC3179@pengutronix.de>
References: <1254250236-18130-1-git-send-email-manuel.lauss@gmail.com>
	 <20091002105903.GC3179@pengutronix.de>
Date:	Fri, 2 Oct 2009 13:15:59 +0200
Message-ID: <f861ec6f0910020415j5125295fn6b5dff7db4bf170e@mail.gmail.com>
Subject: Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Wolfram Sang <w.sang@pengutronix.de>
Cc:	linux-pcmcia <linux-pcmcia@lists.infradead.org>,
	Linux-MIPS <linux-mips@linux-mips.org>,
	Florian Fainelli <florian@openwrt.org>,
	Manuel Lauss <manuel.lauss@gmail.com>
Content-Type: text/plain; charset=ISO-8859-1
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24126
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

Servus Wolfram,

On Fri, Oct 2, 2009 at 12:59 PM, Wolfram Sang <w.sang@pengutronix.de> wrote:
>
>> Rewritten XXS1500 PCMCIA socket driver, standalone (doesn't
>> depend on au1000_generic.c) and added carddetect IRQ support.
>
> I am not familiar with the details here. Why did you choose to drop the generic
> au1000-part for this and the other driver?

I want to get rid of au1000_generic.[ch] eventually or at least all of
its contents
except the static mapping and resource allocation functions, which are board-
independent.  On the other hand these are so short that I opted to
just duplicate
them into the xxs1500_ss.c and db1xxx_ss.c (other patch) files.  The db1xxx_ss
(for the Alchemy demoboards) is supposed to be an example on how to set up
PCMCIA on Alchemy SoCs.

Danke,
        Manuel Lauss

From w.sang@pengutronix.de Fri Oct  2 14:54:31 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Oct 2009 14:54:37 +0200 (CEST)
Received: from metis.ext.pengutronix.de ([92.198.50.35]:37286 "EHLO
	metis.ext.pengutronix.de" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492284AbZJBMyb (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Fri, 2 Oct 2009 14:54:31 +0200
Received: from [2001:6f8:1178:2:221:70ff:fe71:1890] (helo=pengutronix.de)
	by metis.ext.pengutronix.de with esmtp (Exim 4.63)
	(envelope-from <w.sang@pengutronix.de>)
	id 1MtheR-0005lB-Hc; Fri, 02 Oct 2009 14:54:23 +0200
Date:	Fri, 2 Oct 2009 14:54:23 +0200
From:	Wolfram Sang <w.sang@pengutronix.de>
To:	Manuel Lauss <manuel.lauss@googlemail.com>
Cc:	linux-pcmcia <linux-pcmcia@lists.infradead.org>,
	Linux-MIPS <linux-mips@linux-mips.org>,
	Florian Fainelli <florian@openwrt.org>,
	Manuel Lauss <manuel.lauss@gmail.com>
Subject: Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
Message-ID: <20091002125423.GD3179@pengutronix.de>
References: <1254250236-18130-1-git-send-email-manuel.lauss@gmail.com> <20091002105903.GC3179@pengutronix.de> <f861ec6f0910020415j5125295fn6b5dff7db4bf170e@mail.gmail.com>
MIME-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha1;
	protocol="application/pgp-signature"; boundary="PHCdUe6m4AxPMzOu"
Content-Disposition: inline
In-Reply-To: <f861ec6f0910020415j5125295fn6b5dff7db4bf170e@mail.gmail.com>
User-Agent: Mutt/1.5.18 (2008-05-17)
X-SA-Exim-Connect-IP: 2001:6f8:1178:2:221:70ff:fe71:1890
X-SA-Exim-Mail-From: w.sang@pengutronix.de
X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false
X-PTX-Original-Recipient: linux-mips@linux-mips.org
Return-Path: <w.sang@pengutronix.de>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24127
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: w.sang@pengutronix.de
Precedence: bulk
X-list: linux-mips


--PHCdUe6m4AxPMzOu
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable


> >> Rewritten XXS1500 PCMCIA socket driver, standalone (doesn't
> >> depend on au1000_generic.c) and added carddetect IRQ support.
> >
> > I am not familiar with the details here. Why did you choose to drop the=
 generic
> > au1000-part for this and the other driver?
>=20
> I want to get rid of au1000_generic.[ch] eventually or at least all of its
> contents except the static mapping and resource allocation functions, whi=
ch
> are board- independent.  On the other hand these are so short that I opte=
d to
> just duplicate them into the xxs1500_ss.c and db1xxx_ss.c (other patch)
> files.  The db1xxx_ss (for the Alchemy demoboards) is supposed to be an
> example on how to set up PCMCIA on Alchemy SoCs.

Yeah, I saw that you want to remove it, still I don't know why :) Is it fea=
ture
incomplete and updating is impossible? Is the concept outdated? Could you
enlighten me on that?

Regards,

   Wolfram

--=20
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

--PHCdUe6m4AxPMzOu
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAkrF9/8ACgkQD27XaX1/VRurwQCfQAr6lgI3A9GAKmatR/nhjVRz
rkEAoIoEwntfjG6YcwP4JKjdi+V/XKI8
=qhq4
-----END PGP SIGNATURE-----

--PHCdUe6m4AxPMzOu--

From manuel.lauss@googlemail.com Fri Oct  2 16:32:18 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Oct 2009 16:32:24 +0200 (CEST)
Received: from mail-bw0-f208.google.com ([209.85.218.208]:35247 "EHLO
	mail-bw0-f208.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492713AbZJBOcS convert rfc822-to-8bit
	(ORCPT <rfc822;linux-mips@linux-mips.org>);
	Fri, 2 Oct 2009 16:32:18 +0200
Received: by bwz4 with SMTP id 4so1066938bwz.0
        for <linux-mips@linux-mips.org>; Fri, 02 Oct 2009 07:32:11 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:mime-version:received:in-reply-to:references
         :date:message-id:subject:from:to:cc:content-type
         :content-transfer-encoding;
        bh=jGcaZjK99XtaNrUPzqLCxKHSfVzbSKAwn0DaXatuYqs=;
        b=Zk/NIQvMoZYSIEZ6y416eRxQfofvVo/eynCv/v44QkAkSxX/m/6TNtgIW9EjCMp0fM
         3jNUFrzu0xbzxK5z44bae8Er56WtSV0Fb4WAACSch/gLfxc2eZZOydctJioPNHI5HYcR
         lRNRgphAjEkRiAv4yJGED0ai7BDuJxZYtzQqQ=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type:content-transfer-encoding;
        b=TDCWZhOmddN0QTlO+H63fErWZ3UsgGbqn2q6UaA13iebTq3g/v74Kbei/xKPtgt9EQ
         A22fYr2ZdgcsjlMZ1lNXnMRcP0OMKnu7M4yR3k+w2ngbvMs/boa0IyaptHK4GZK0Zg0K
         Fg74tV+J7VXmANIKu1aUx6DPOIG25adsO3hLo=
MIME-Version: 1.0
Received: by 10.102.226.17 with SMTP id y17mr463581mug.67.1254493931746; Fri, 
	02 Oct 2009 07:32:11 -0700 (PDT)
In-Reply-To: <20091002125423.GD3179@pengutronix.de>
References: <1254250236-18130-1-git-send-email-manuel.lauss@gmail.com>
	 <20091002105903.GC3179@pengutronix.de>
	 <f861ec6f0910020415j5125295fn6b5dff7db4bf170e@mail.gmail.com>
	 <20091002125423.GD3179@pengutronix.de>
Date:	Fri, 2 Oct 2009 16:32:11 +0200
Message-ID: <f861ec6f0910020732p2ff76990q1e7a2bca16e52e64@mail.gmail.com>
Subject: Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Wolfram Sang <w.sang@pengutronix.de>
Cc:	linux-pcmcia <linux-pcmcia@lists.infradead.org>,
	Linux-MIPS <linux-mips@linux-mips.org>,
	Florian Fainelli <florian@openwrt.org>,
	Manuel Lauss <manuel.lauss@gmail.com>
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8BIT
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24128
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

On Fri, Oct 2, 2009 at 2:54 PM, Wolfram Sang <w.sang@pengutronix.de> wrote:
>
>> >> Rewritten XXS1500 PCMCIA socket driver, standalone (doesn't
>> >> depend on au1000_generic.c) and added carddetect IRQ support.
>> >
>> > I am not familiar with the details here. Why did you choose to drop the generic
>> > au1000-part for this and the other driver?
>>
>> I want to get rid of au1000_generic.[ch] eventually or at least all of its
>> contents except the static mapping and resource allocation functions, which
>> are board- independent.  On the other hand these are so short that I opted to
>> just duplicate them into the xxs1500_ss.c and db1xxx_ss.c (other patch)
>> files.  The db1xxx_ss (for the Alchemy demoboards) is supposed to be an
>> example on how to set up PCMCIA on Alchemy SoCs.
>
> Yeah, I saw that you want to remove it, still I don't know why :) Is it feature
> incomplete and updating is impossible? Is the concept outdated? Could you
> enlighten me on that?

I started out with the intention to fix its styling issues, add carddetect irq
support, etc.  In the end it was easier to write a quick-and-dirty standalone
full-features socket driver for the DB1200 and extend it to support the
other DB/PB boards. While I was at it I modified my driver for the xxs1500,
that's all.

The only *technical* reason I have is a personal dislike for how the current
one works: it forces every conceivable board to add dozens of cpp macros
for mem/io ranges and gets registered by board-independent code.
Hardly convincing, I know.

        Manuel Lauss

From ralf@linux-mips.org Fri Oct  2 22:33:55 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Fri, 02 Oct 2009 22:33:59 +0200 (CEST)
Received: from localhost.localdomain ([127.0.0.1]:32863 "EHLO h5.dl5rb.org.uk"
	rhost-flags-OK-OK-OK-FAIL) by ftp.linux-mips.org with ESMTP
	id S1493876AbZJBUdz (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Fri, 2 Oct 2009 22:33:55 +0200
Received: from h5.dl5rb.org.uk (localhost.localdomain [127.0.0.1])
	by h5.dl5rb.org.uk (8.14.3/8.14.3) with ESMTP id n92KYudu010272;
	Fri, 2 Oct 2009 22:34:57 +0200
Received: (from ralf@localhost)
	by h5.dl5rb.org.uk (8.14.3/8.14.3/Submit) id n92KYsET010270;
	Fri, 2 Oct 2009 22:34:54 +0200
Date:	Fri, 2 Oct 2009 22:34:54 +0200
From:	Ralf Baechle <ralf@linux-mips.org>
To:	David Daney <ddaney@caviumnetworks.com>
Cc:	linux-mips@linux-mips.org
Subject: Re: [PATCH] MIPS: Don't write ones to reserved entryhi bits.
Message-ID: <20091002203454.GA9138@linux-mips.org>
References: <1241812330-21041-1-git-send-email-ddaney@caviumnetworks.com> <20090527162937.GA9831@linux-mips.org> <4AB129DF.8060200@caviumnetworks.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <4AB129DF.8060200@caviumnetworks.com>
User-Agent: Mutt/1.5.19 (2009-01-05)
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24129
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Wed, Sep 16, 2009 at 11:09:35AM -0700, David Daney wrote:

>>> According to the MIPS64 Privileged Resource Architecture manual, only
>>> values of zero may be written to bits 8..10 of CP0 entryhi.  We need
>>> to add masking by ASID_MASK.
>>
>> Yes, I've silently been relying on the hardware chopping off the excess
>> bits for no better reason that it saving an instruction.  One of the
>> functions you've touched is switch_mm() which is being used in context
>> switches and any changes to it will show up in context switching
>> benchmarks.
>>
>> The patch you did (and along with that some older SMTC changes by Kevin)
>> can be done slightly more elegant because we already have:
>>
>> #define cpu_asid(cpu, mm)       (cpu_context((cpu), (mm)) & ASID_MASK)
>>
>> in <asm/mmu_context.h>.
>>
>> We used to optimize the ASID managment code by code patching even, see
>> mmu_context.h in 78c388aed2b7184182c08428db1de6c872d815f5.
>>
>>   Ralf
>>
>> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
>>
>
> This is nice, but you never committed it.

Waiting for people to test it - thanks!  Committing it now.

  Ralf

From wsa@pengutronix.de Sat Oct  3 12:22:32 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Oct 2009 12:22:38 +0200 (CEST)
Received: from metis.ext.pengutronix.de ([92.198.50.35]:45113 "EHLO
	metis.ext.pengutronix.de" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492313AbZJCKWc (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sat, 3 Oct 2009 12:22:32 +0200
Received: from octopus.hi.pengutronix.de ([2001:6f8:1178:2:215:17ff:fe12:23b0])
	by metis.ext.pengutronix.de with esmtp (Exim 4.63)
	(envelope-from <wsa@pengutronix.de>)
	id 1Mu1ku-0000Jr-6J; Sat, 03 Oct 2009 12:22:24 +0200
Received: from wsa by octopus.hi.pengutronix.de with local (Exim 4.69)
	(envelope-from <wsa@pengutronix.de>)
	id 1Mu1kr-0000Jk-JT; Sat, 03 Oct 2009 12:22:21 +0200
Date:	Sat, 3 Oct 2009 12:22:21 +0200
From:	Wolfram Sang <w.sang@pengutronix.de>
To:	Manuel Lauss <manuel.lauss@googlemail.com>
Cc:	linux-pcmcia <linux-pcmcia@lists.infradead.org>,
	Linux-MIPS <linux-mips@linux-mips.org>,
	Florian Fainelli <florian@openwrt.org>,
	Manuel Lauss <manuel.lauss@gmail.com>
Subject: Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
Message-ID: <20091003102221.GB24206@pengutronix.de>
References: <1254250236-18130-1-git-send-email-manuel.lauss@gmail.com> <20091002105903.GC3179@pengutronix.de> <f861ec6f0910020415j5125295fn6b5dff7db4bf170e@mail.gmail.com> <20091002125423.GD3179@pengutronix.de> <f861ec6f0910020732p2ff76990q1e7a2bca16e52e64@mail.gmail.com>
MIME-Version: 1.0
Content-Type: multipart/signed; micalg=pgp-sha1;
	protocol="application/pgp-signature"; boundary="/WwmFnJnmDyWGHa4"
Content-Disposition: inline
In-Reply-To: <f861ec6f0910020732p2ff76990q1e7a2bca16e52e64@mail.gmail.com>
User-Agent: Mutt/1.5.18 (2008-05-17)
X-SA-Exim-Connect-IP: 2001:6f8:1178:2:215:17ff:fe12:23b0
X-SA-Exim-Mail-From: wsa@pengutronix.de
X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false
X-PTX-Original-Recipient: linux-mips@linux-mips.org
Return-Path: <wsa@pengutronix.de>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24130
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: w.sang@pengutronix.de
Precedence: bulk
X-list: linux-mips


--/WwmFnJnmDyWGHa4
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

> > Yeah, I saw that you want to remove it, still I don't know why :) Is it=
 feature
> > incomplete and updating is impossible? Is the concept outdated? Could y=
ou
> > enlighten me on that?
>=20
> I started out with the intention to fix its styling issues, add carddetec=
t irq
> support, etc.  In the end it was easier to write a quick-and-dirty standa=
lone
> full-features socket driver for the DB1200 and extend it to support the
> other DB/PB boards. While I was at it I modified my driver for the xxs150=
0,
> that's all.

Okay, that explains.

>=20
> The only *technical* reason I have is a personal dislike for how the curr=
ent
> one works: it forces every conceivable board to add dozens of cpp macros
> for mem/io ranges and gets registered by board-independent code.
> Hardly convincing, I know.

Well, you have the (to me) pretty convincing technical argument that your
drivers provide more features and less crashes which is a clear benefit for
users. If we remove the generic au1000-part, then it might even be in the s=
ame
amount in LoC. Okay, we lose a bit of maintainability if a bug is found in a
section which was shared among the former users of generic, as it has to be
updated for each of the three drivers, but well... Are there any plans to
convert pb1x00 as well?

Maybe I find time to look a bit more into it, but I can't test anything, of
course, so the more additional comments/test-reports the better.

Regards,

   Wolfram

--=20
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

--/WwmFnJnmDyWGHa4
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAkrHJd0ACgkQD27XaX1/VRtIlACcDbnPsEWZ4WTlEqP+ow7aoPC9
MxkAniEmjtjOYTdVkajO7oaZ78g+8M4t
=87Vf
-----END PGP SIGNATURE-----

--/WwmFnJnmDyWGHa4--

From manuel.lauss@googlemail.com Sat Oct  3 13:49:48 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Oct 2009 13:49:54 +0200 (CEST)
Received: from mail-fx0-f221.google.com ([209.85.220.221]:59203 "EHLO
	mail-fx0-f221.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492470AbZJCLts convert rfc822-to-8bit
	(ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sat, 3 Oct 2009 13:49:48 +0200
Received: by fxm21 with SMTP id 21so1601410fxm.33
        for <linux-mips@linux-mips.org>; Sat, 03 Oct 2009 04:49:42 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:mime-version:received:in-reply-to:references
         :date:message-id:subject:from:to:cc:content-type
         :content-transfer-encoding;
        bh=9ugZf+IV4IRQ6cyQl4IrZxqO9uG1AxIuMFIONUJMmUs=;
        b=lUY44RrZBbT+Pni+K5GFFBfhUkwqAlvVaclYkWyJABDghJoWkr+ChB6amgWCPRYTqy
         bZYchKRJang7KjcTE4bKbI1yUlPETFMI6d5zHRk3sl8WJiOJw44Y4v4lv1UHBGqok05w
         bC35gDjI51nezrMXf7Y4HDk0/9gBzW+F2Q3cI=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type:content-transfer-encoding;
        b=bm8+74PP2WPQQqGCyswKXUimFGUD0/qgxHkiVpFYMgx08jr1TEbU7R7Wh1W1ZurX+Q
         /ur8WiqTrbGnK5YCCEvDDdPkkNcHwZBUDsoRGqqMVnKUeRdI+g963Q3aBF+GdeOmVKWX
         fb16y1uGINuTBm8FEru1nu2CKoRt+ev9eYOlk=
MIME-Version: 1.0
Received: by 10.103.126.27 with SMTP id d27mr861929mun.56.1254570582081; Sat, 
	03 Oct 2009 04:49:42 -0700 (PDT)
In-Reply-To: <20091003102221.GB24206@pengutronix.de>
References: <1254250236-18130-1-git-send-email-manuel.lauss@gmail.com>
	 <20091002105903.GC3179@pengutronix.de>
	 <f861ec6f0910020415j5125295fn6b5dff7db4bf170e@mail.gmail.com>
	 <20091002125423.GD3179@pengutronix.de>
	 <f861ec6f0910020732p2ff76990q1e7a2bca16e52e64@mail.gmail.com>
	 <20091003102221.GB24206@pengutronix.de>
Date:	Sat, 3 Oct 2009 13:49:42 +0200
Message-ID: <f861ec6f0910030449q635360ct12d6c47cfb24670d@mail.gmail.com>
Subject: Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Wolfram Sang <w.sang@pengutronix.de>
Cc:	linux-pcmcia <linux-pcmcia@lists.infradead.org>,
	Linux-MIPS <linux-mips@linux-mips.org>,
	Florian Fainelli <florian@openwrt.org>,
	Manuel Lauss <manuel.lauss@gmail.com>
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8BIT
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24131
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

On Sat, Oct 3, 2009 at 12:22 PM, Wolfram Sang <w.sang@pengutronix.de> wrote:
>> > Yeah, I saw that you want to remove it, still I don't know why :) Is it feature
>> > incomplete and updating is impossible? Is the concept outdated? Could you
>> > enlighten me on that?
>>
>> I started out with the intention to fix its styling issues, add carddetect irq
>> support, etc.  In the end it was easier to write a quick-and-dirty standalone
>> full-features socket driver for the DB1200 and extend it to support the
>> other DB/PB boards. While I was at it I modified my driver for the xxs1500,
>> that's all.
>
> Okay, that explains.
>
>>
>> The only *technical* reason I have is a personal dislike for how the current
>> one works: it forces every conceivable board to add dozens of cpp macros
>> for mem/io ranges and gets registered by board-independent code.
>> Hardly convincing, I know.
>
> Well, you have the (to me) pretty convincing technical argument that your
> drivers provide more features and less crashes which is a clear benefit for
> users. If we remove the generic au1000-part, then it might even be in the same
> amount in LoC. Okay, we lose a bit of maintainability if a bug is found in a
> section which was shared among the former users of generic, as it has to be
> updated for each of the three drivers, but well... Are there any plans to
> convert pb1x00 as well?

The new db1xxx_ss.c already supports all boards pb1x00 is supposed to,
except for the PB1000 (the very first Alchemy devboard), which has a
rather awkward carddetect irq scheme, so I kept the au1000_pb1x00.c
for it.  Unfortunately I don't have this board to test on, and *if* there are
any linux users with this board, they choose to remain silent (the driver
hasn't built for it in years, so go figure).  I'd rather get rid of
PB1000 support
altogether...


> Maybe I find time to look a bit more into it, but I can't test anything, of
> course, so the more additional comments/test-reports the better.

Thanks.  As I mentioned, the db1xxx_ss part works on my Db1200/Db1300
boards; I don't have any others to test on.

        Manuel Lauss

From ralf@linux-mips.org Sat Oct  3 16:02:51 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Oct 2009 16:02:53 +0200 (CEST)
Received: from localhost.localdomain ([127.0.0.1]:51847 "EHLO h5.dl5rb.org.uk"
	rhost-flags-OK-OK-OK-FAIL) by ftp.linux-mips.org with ESMTP
	id S1492953AbZJCOCv (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sat, 3 Oct 2009 16:02:51 +0200
Received: from h5.dl5rb.org.uk (localhost.localdomain [127.0.0.1])
	by h5.dl5rb.org.uk (8.14.3/8.14.3) with ESMTP id n93E3q3N032212;
	Sat, 3 Oct 2009 16:03:53 +0200
Received: (from ralf@localhost)
	by h5.dl5rb.org.uk (8.14.3/8.14.3/Submit) id n93E3noB032210;
	Sat, 3 Oct 2009 16:03:49 +0200
Date:	Sat, 3 Oct 2009 16:03:49 +0200
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Manuel Lauss <manuel.lauss@googlemail.com>
Cc:	Wolfram Sang <w.sang@pengutronix.de>,
	linux-pcmcia <linux-pcmcia@lists.infradead.org>,
	Linux-MIPS <linux-mips@linux-mips.org>,
	Florian Fainelli <florian@openwrt.org>,
	Manuel Lauss <manuel.lauss@gmail.com>
Subject: Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
Message-ID: <20091003140349.GA11381@linux-mips.org>
References: <1254250236-18130-1-git-send-email-manuel.lauss@gmail.com> <20091002105903.GC3179@pengutronix.de> <f861ec6f0910020415j5125295fn6b5dff7db4bf170e@mail.gmail.com> <20091002125423.GD3179@pengutronix.de> <f861ec6f0910020732p2ff76990q1e7a2bca16e52e64@mail.gmail.com> <20091003102221.GB24206@pengutronix.de> <f861ec6f0910030449q635360ct12d6c47cfb24670d@mail.gmail.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-8859-1
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
In-Reply-To: <f861ec6f0910030449q635360ct12d6c47cfb24670d@mail.gmail.com>
User-Agent: Mutt/1.5.19 (2009-01-05)
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24132
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Sat, Oct 03, 2009 at 01:49:42PM +0200, Manuel Lauss wrote:

> On Sat, Oct 3, 2009 at 12:22 PM, Wolfram Sang <w.sang@pengutronix.de> wrote:
> >> > Yeah, I saw that you want to remove it, still I don't know why :) Is it feature
> >> > incomplete and updating is impossible? Is the concept outdated? Could you
> >> > enlighten me on that?
> >>
> >> I started out with the intention to fix its styling issues, add carddetect irq
> >> support, etc.  In the end it was easier to write a quick-and-dirty standalone
> >> full-features socket driver for the DB1200 and extend it to support the
> >> other DB/PB boards. While I was at it I modified my driver for the xxs1500,
> >> that's all.
> >
> > Okay, that explains.
> >
> >>
> >> The only *technical* reason I have is a personal dislike for how the current
> >> one works: it forces every conceivable board to add dozens of cpp macros
> >> for mem/io ranges and gets registered by board-independent code.
> >> Hardly convincing, I know.
> >
> > Well, you have the (to me) pretty convincing technical argument that your
> > drivers provide more features and less crashes which is a clear benefit for
> > users. If we remove the generic au1000-part, then it might even be in the same
> > amount in LoC. Okay, we lose a bit of maintainability if a bug is found in a
> > section which was shared among the former users of generic, as it has to be
> > updated for each of the three drivers, but well... Are there any plans to
> > convert pb1x00 as well?
> 
> The new db1xxx_ss.c already supports all boards pb1x00 is supposed to,
> except for the PB1000 (the very first Alchemy devboard), which has a
> rather awkward carddetect irq scheme, so I kept the au1000_pb1x00.c
> for it.  Unfortunately I don't have this board to test on, and *if* there are
> any linux users with this board, they choose to remain silent (the driver
> hasn't built for it in years, so go figure).  I'd rather get rid of
> PB1000 support
> altogether...
> 
> 
> > Maybe I find time to look a bit more into it, but I can't test anything, of
> > course, so the more additional comments/test-reports the better.
> 
> Thanks.  As I mentioned, the db1xxx_ss part works on my Db1200/Db1300
> boards; I don't have any others to test on.

Deending on the urgency you assign to these patches I can keep them in
my queue for 2.6.33 and push them upstream for linux-next.

  Ralf

From ralf@linux-mips.org Sat Oct  3 16:33:20 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Oct 2009 16:33:23 +0200 (CEST)
Received: from localhost.localdomain ([127.0.0.1]:41842 "EHLO h5.dl5rb.org.uk"
	rhost-flags-OK-OK-OK-FAIL) by ftp.linux-mips.org with ESMTP
	id S1493063AbZJCOdU (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Sat, 3 Oct 2009 16:33:20 +0200
Received: from h5.dl5rb.org.uk (localhost.localdomain [127.0.0.1])
	by h5.dl5rb.org.uk (8.14.3/8.14.3) with ESMTP id n93EYNBR000846;
	Sat, 3 Oct 2009 16:34:24 +0200
Received: (from ralf@localhost)
	by h5.dl5rb.org.uk (8.14.3/8.14.3/Submit) id n93EYNso000844;
	Sat, 3 Oct 2009 16:34:23 +0200
Date:	Sat, 3 Oct 2009 16:34:23 +0200
From:	Ralf Baechle <ralf@linux-mips.org>
To:	David Daney <ddaney@caviumnetworks.com>
Cc:	linux-mips <linux-mips@linux-mips.org>
Subject: Re: [PATCH 0/2] Two Octeon compile errors with 2.6.32-rc1
Message-ID: <20091003143423.GA839@linux-mips.org>
References: <4AC53F75.4090902@caviumnetworks.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <4AC53F75.4090902@caviumnetworks.com>
User-Agent: Mutt/1.5.19 (2009-01-05)
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24133
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Thu, Oct 01, 2009 at 04:47:01PM -0700, David Daney wrote:

> There are a couple of problems I found with 2.6.32-rc1.
>
> Two trivial patches to follow.

Thanks, both applied.

  Ralf

From manuel.lauss@googlemail.com Sat Oct  3 16:36:22 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Oct 2009 16:36:28 +0200 (CEST)
Received: from mail-bw0-f208.google.com ([209.85.218.208]:49172 "EHLO
	mail-bw0-f208.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S2097287AbZJCOgW (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sat, 3 Oct 2009 16:36:22 +0200
Received: by bwz4 with SMTP id 4so1676734bwz.0
        for <multiple recipients>; Sat, 03 Oct 2009 07:36:16 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:mime-version:received:in-reply-to:references
         :date:message-id:subject:from:to:cc:content-type;
        bh=jQjrYN6MJleuIniaRMJ0hyOg2m1VGHvok9W5B3F6LtA=;
        b=FtS7jAez6jn23rrBFMdlPMwxYtz7oppFZd0Rk5tPb1kHWSjCNfFAqn9WMbPPCCsPw8
         spYesWLElNmiWv+QRGIt+bmEWPx4ecuv/SRTFzpM0vfFiorB2uIJOBC9aqmy3nTQu2r9
         IHzZJ/BnbJSY7SKNohhXopFHb8bGUFT+tL3P0=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type;
        b=x2uKyLn5T91ueS6fW2utTRHHJAwigB1OTv/rwLw/EXOw+VamvX5TX305q5oflVDKPU
         8oH3BmEybEiTFA2cnrDHbyPJZiVwk8jSxn9bF1/CPmWPJqwFMzfxfISGXEa4M8Vd+RkJ
         +r3DiAXSpL7VTSgpSthwhhkphBoQR1FbLg2p4=
MIME-Version: 1.0
Received: by 10.103.126.3 with SMTP id d3mr914588mun.101.1254580576804; Sat, 
	03 Oct 2009 07:36:16 -0700 (PDT)
In-Reply-To: <20091003140349.GA11381@linux-mips.org>
References: <1254250236-18130-1-git-send-email-manuel.lauss@gmail.com>
	 <20091002105903.GC3179@pengutronix.de>
	 <f861ec6f0910020415j5125295fn6b5dff7db4bf170e@mail.gmail.com>
	 <20091002125423.GD3179@pengutronix.de>
	 <f861ec6f0910020732p2ff76990q1e7a2bca16e52e64@mail.gmail.com>
	 <20091003102221.GB24206@pengutronix.de>
	 <f861ec6f0910030449q635360ct12d6c47cfb24670d@mail.gmail.com>
	 <20091003140349.GA11381@linux-mips.org>
Date:	Sat, 3 Oct 2009 16:36:16 +0200
Message-ID: <f861ec6f0910030736m25a230edq4fb8665844237813@mail.gmail.com>
Subject: Re: [PATCH] Alchemy: XXS1500 PCMCIA driver rewrite
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	Wolfram Sang <w.sang@pengutronix.de>,
	linux-pcmcia <linux-pcmcia@lists.infradead.org>,
	Linux-MIPS <linux-mips@linux-mips.org>,
	Florian Fainelli <florian@openwrt.org>,
	Manuel Lauss <manuel.lauss@gmail.com>
Content-Type: text/plain; charset=ISO-8859-1
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24134
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

Hi Ralf,

> Deending on the urgency you assign to these patches I can keep them in
> my queue for 2.6.33 and push them upstream for linux-next.

No hurry; 2.6.33 is fine. I've fixed a few typos and thinkos in them and will
resend soon.  I'd just like to get these in your queue first, so I can base my
DB1300 work on it.

Thanks!
        Manuel Lauss

From manuel.lauss@googlemail.com Sat Oct  3 16:48:19 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 03 Oct 2009 16:48:25 +0200 (CEST)
Received: from mail-bw0-f208.google.com ([209.85.218.208]:54327 "EHLO
	mail-bw0-f208.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492953AbZJCOsT (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sat, 3 Oct 2009 16:48:19 +0200
Received: by bwz4 with SMTP id 4so1680563bwz.0
        for <multiple recipients>; Sat, 03 Oct 2009 07:48:12 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:mime-version:received:date:message-id:subject
         :from:to:content-type;
        bh=FdRNNPhMP/PKLMtu5DWkknzvugHjsqs0w5ArCcHp/+w=;
        b=u+0u1/tl3cHzlL33aRJ2Qc5bs+k8No81E2Tcn/A5DW/ORopYbY1K+kici3IORrYqF7
         dAlF966b89q0+6CUOFZPsj63dSvfw9iZuIi09GnHYp7VbcWY3YP5eM0ArL3IK8lDTyFc
         oEgzT2oCl+QC6dojgEzVxWLaG6otElFQBrqhM=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=mime-version:date:message-id:subject:from:to:content-type;
        b=g8wARAyEZ6THhMFSrm9QEOOcZB93QbVtaEXTiKiKF2P4qemClGbkFHaAjkIws49icp
         PpRXxeFdvjfSSh38ynmsB/lf3E6R1LmdX9j6e+X9Hp/CW3ToyDbbzERVQXdovMcDh0PX
         2fhqYuKrUs0Qc382b1gzl96g0QLOI0AIBcS/s=
MIME-Version: 1.0
Received: by 10.102.226.17 with SMTP id y17mr918559mug.67.1254581292384; Sat, 
	03 Oct 2009 07:48:12 -0700 (PDT)
Date:	Sat, 3 Oct 2009 16:48:12 +0200
Message-ID: <f861ec6f0910030748l396b45bck858f15460354e58e@mail.gmail.com>
Subject: Reason for PIO_MASK?
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Linux-MIPS <linux-mips@linux-mips.org>,
	Ralf Baechle <ralf@linux-mips.org>
Content-Type: text/plain; charset=ISO-8859-1
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24135
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

In arch/mips/lib/iomap.c  there's this "#define PIO_MASK 0x0ffff"
which limits the ability to successfully call ioport_map() to the
first 64kB.  This causes pata_pcmcia to error out on CF card
probe because devm_ioport_map() is called with the remapped
PCMCIA IO area, which is somewhere in MAP_BASE space.

I've temporarily removed the PIO_MASK check and pata_pcmcia
works as expected. Is there any way around this, other than
creating an Alchemy-specific ioport_map() function?

Thanks,
        Manuel Lauss

From toylover@gmail.com Sun Oct  4 08:13:52 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Sun, 04 Oct 2009 08:13:59 +0200 (CEST)
Received: from mail-px0-f187.google.com ([209.85.216.187]:52552 "EHLO
	mail-px0-f187.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492199AbZJDGNw (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sun, 4 Oct 2009 08:13:52 +0200
Received: by pxi17 with SMTP id 17so2925703pxi.21
        for <linux-mips@linux-mips.org>; Sat, 03 Oct 2009 23:13:44 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=domainkey-signature:mime-version:received:date:message-id:subject
         :from:to:content-type;
        bh=btL9sAUhLNYNIfzuegBrCvwT1f/yQZPlm0GAxvnjFsw=;
        b=g9t4HKNbM9CYhRYLJK+iNSddSiSnBcaai4O0s1u12LU7Drs0/JCaKwXPKGn9JfL+Tx
         dyKRIuLtagx1uuDwJm559u4x93qF9f+P81nl0pQU3WVlw5uia34L+EDuuGb661KI3dvp
         o6ovbnAVGlCLJnDeLam6UJ7Ms+p3DTvWdqlIs=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=gamma;
        h=mime-version:date:message-id:subject:from:to:content-type;
        b=HlmGKRzbpLf+3bZd/Vhvi+oodlw2jCqkL7HQ+8PnKK2WOm/Bbrd1Tgw7hx/pgGA4m4
         DkiAI6EPLFJ/Gz7m3oHhzl1GhQm3YrugJPvsz4REEdzZXsl3F4nMtmEAukEKIJdlpPGm
         GjhK0RF2q4mnOUO9Ho+R9kXtb/nNndWomu0As=
MIME-Version: 1.0
Received: by 10.141.28.17 with SMTP id f17mr827049rvj.103.1254636824200; Sat, 
	03 Oct 2009 23:13:44 -0700 (PDT)
Date:	Sun, 4 Oct 2009 14:13:44 +0800
Message-ID: <81f85c130910032313u532c5bdt815f0633269bf79e@mail.gmail.com>
Subject: mipsel-sdelinux-v6.03.01-1.i386.rpm
From:	Toy lover <toylover@gmail.com>
To:	linux-mips@linux-mips.org
Content-Type: multipart/alternative; boundary=000e0cd17a043a8870047515e654
Return-Path: <toylover@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24136
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: toylover@gmail.com
Precedence: bulk
X-list: linux-mips

--000e0cd17a043a8870047515e654
Content-Type: text/plain; charset=ISO-8859-1

I am trying to compile kernel modules for a kernel compiled with
mipsel-sdelinux-v6.03.01-1
but the ftp://ftp.mips.com/
pub/tools/software/sde-for-linux/v6.03.01-1/mipsel-*sdelinux*
-v6.03.01-1.i386.rpm
is no longer available. I am wondering whether any of you can send me a copy
of mipsel-*sdelinux*-v6.03.01-1.i386.rpm
which you might still own.

David

--000e0cd17a043a8870047515e654
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

I am trying to compile kernel modules for a kernel compiled with mipsel-sde=
linux-v6.03.01-1<br>but the <a href=3D"ftp://ftp.mips.com/">ftp://ftp.mips.=
com/</a><span style=3D"visibility: visible;" id=3D"main"><span style=3D"vis=
ibility: visible;" id=3D"search">pub/tools/software/sde-for-linux/v6.03.01-=
1/mipsel-<em>sdelinux</em>-v6.03.01-1.i386.rpm</span></span><br>
is no longer available. I am wondering whether any of you can send me a cop=
y of <span style=3D"visibility: visible;" id=3D"main"><span style=3D"visibi=
lity: visible;" id=3D"search">mipsel-<em>sdelinux</em>-v6.03.01-1.i386.rpm<=
br>which you might still own.<br>
<br>David<br></span></span>

--000e0cd17a043a8870047515e654--

From manuel.lauss@googlemail.com Sun Oct  4 14:55:33 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Sun, 04 Oct 2009 14:55:39 +0200 (CEST)
Received: from ey-out-1920.google.com ([74.125.78.148]:26174 "EHLO
	ey-out-1920.google.com" rhost-flags-OK-OK-OK-OK) by ftp.linux-mips.org
	with ESMTP id S1492478AbZJDMzd (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sun, 4 Oct 2009 14:55:33 +0200
Received: by ey-out-1920.google.com with SMTP id 13so382155eye.52
        for <multiple recipients>; Sun, 04 Oct 2009 05:55:32 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer:in-reply-to:references;
        bh=fq00PyTneMc7YfLfolupzE8iLpWZaNbSbeFB8moNibA=;
        b=SUXIwa5c9FGi9iu6GwPQSWgL+jAvw9y02e4ygwQV+Uec6VKhRjn2IYhZ60HHEOh0x9
         0ZpTqwON1fI3V6kXUaV/Thju1om8PIXmNH2u3Y8Lnp1l9O1+PjlbhA65JrmF6CKurAFb
         tbMYZuBN4sjADYZZLmNo8RwK5wKu0n6fIcOoQ=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        b=TK5HipspVUyrdpLFaU6qcNHf2/xNhDRgleT8zfi7w/orz4fXUsjeuZzVAGKzO59Rmx
         4CXiz19wg4xYPB5yHgo2NXtwO2MKeemJoT0WjfoV8VixIrL+8Ih33GTetO6gfJ2mD6KN
         HIZflqVMfAAd+RbaA8SQs9P8SPiaJLgS0vSQE=
Received: by 10.210.3.21 with SMTP id 21mr1951233ebc.40.1254660932373;
        Sun, 04 Oct 2009 05:55:32 -0700 (PDT)
Received: from localhost.localdomain (fnoeppeil48.netpark.at [217.175.205.176])
        by mx.google.com with ESMTPS id 28sm1555483eyg.4.2009.10.04.05.55.31
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Sun, 04 Oct 2009 05:55:31 -0700 (PDT)
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Linux-MIPS <linux-mips@linux-mips.org>,
	Ralf Baechle <ralf@linux-mips.org>
Cc:	Manuel Lauss <manuel.lauss@gmail.com>
Subject: [PATCH 1/6] Alchemy: devboard register abstraction
Date:	Sun,  4 Oct 2009 14:55:24 +0200
Message-Id: <1254660929-15453-2-git-send-email-manuel.lauss@gmail.com>
X-Mailer: git-send-email 1.6.5.rc2
In-Reply-To: <1254660929-15453-1-git-send-email-manuel.lauss@gmail.com>
References: <1254660929-15453-1-git-send-email-manuel.lauss@gmail.com>
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24137
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

All Alchemy development boards have external CPLDs with a few registers
in them.  They all share an identical register layout with only a few
minor differences (except the PB1000) in bit functions and base
addresses.

This patch
- adds a primitive facility to initialize and use these external
  registers,
- replaces all occurrences of bcsr->xxx accesses with calls to the new
  functions (the pb1200 cascade irq handling code is special).
- collects BCSR register information scattered throughout the board
  headers in a central place.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 arch/mips/alchemy/devboards/Makefile             |    2 +-
 arch/mips/alchemy/devboards/bcsr.c               |   76 +++++++
 arch/mips/alchemy/devboards/db1x00/board_setup.c |   62 +++---
 arch/mips/alchemy/devboards/pb1100/board_setup.c |    7 +-
 arch/mips/alchemy/devboards/pb1200/board_setup.c |   49 ++---
 arch/mips/alchemy/devboards/pb1200/irqmap.c      |   42 +++--
 arch/mips/alchemy/devboards/pb1200/platform.c    |   25 ++-
 arch/mips/alchemy/devboards/pb1500/board_setup.c |    7 +-
 arch/mips/alchemy/devboards/pb1550/board_setup.c |   11 +-
 arch/mips/include/asm/mach-db1x00/bcsr.h         |  235 ++++++++++++++++++++++
 arch/mips/include/asm/mach-db1x00/db1200.h       |  109 +----------
 arch/mips/include/asm/mach-db1x00/db1x00.h       |   92 ---------
 arch/mips/include/asm/mach-pb1x00/pb1100.h       |   49 -----
 arch/mips/include/asm/mach-pb1x00/pb1200.h       |  109 +----------
 arch/mips/include/asm/mach-pb1x00/pb1500.h       |   13 --
 arch/mips/include/asm/mach-pb1x00/pb1550.h       |   89 --------
 drivers/mtd/nand/au1550nd.c                      |    4 +-
 drivers/net/irda/au1k_ir.c                       |   14 +-
 drivers/pcmcia/au1000_db1x00.c                   |   76 ++++----
 19 files changed, 475 insertions(+), 596 deletions(-)
 create mode 100644 arch/mips/alchemy/devboards/bcsr.c
 create mode 100644 arch/mips/include/asm/mach-db1x00/bcsr.h

diff --git a/arch/mips/alchemy/devboards/Makefile b/arch/mips/alchemy/devboards/Makefile
index 730f9f2..adc6717 100644
--- a/arch/mips/alchemy/devboards/Makefile
+++ b/arch/mips/alchemy/devboards/Makefile
@@ -2,7 +2,7 @@
 # Alchemy Develboards
 #
 
-obj-y += prom.o
+obj-y += prom.o bcsr.o
 obj-$(CONFIG_PM)		+= pm.o
 obj-$(CONFIG_MIPS_PB1000)	+= pb1000/
 obj-$(CONFIG_MIPS_PB1100)	+= pb1100/
diff --git a/arch/mips/alchemy/devboards/bcsr.c b/arch/mips/alchemy/devboards/bcsr.c
new file mode 100644
index 0000000..85b7715
--- /dev/null
+++ b/arch/mips/alchemy/devboards/bcsr.c
@@ -0,0 +1,76 @@
+/*
+ * bcsr.h -- Db1xxx/Pb1xxx Devboard CPLD registers ("BCSR") abstraction.
+ *
+ * All Alchemy development boards (except, of course, the weird PB1000)
+ * have a few registers in a CPLD with standardised layout; they mostly
+ * only differ in base address.
+ * All registers are 16bits wide with 32bit spacing.
+ */
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/addrspace.h>
+#include <asm/io.h>
+#include <asm/mach-db1x00/bcsr.h>
+
+static struct bcsr_reg {
+	void __iomem *raddr;
+	spinlock_t lock;
+} bcsr_regs[BCSR_CNT];
+
+void __init bcsr_init(unsigned long bcsr1_phys, unsigned long bcsr2_phys)
+{
+	int i;
+
+	bcsr1_phys = KSEG1ADDR(CPHYSADDR(bcsr1_phys));
+	bcsr2_phys = KSEG1ADDR(CPHYSADDR(bcsr2_phys));
+
+	for (i = 0; i < BCSR_CNT; i++) {
+		if (i >= BCSR_HEXLEDS)
+			bcsr_regs[i].raddr = (void __iomem *)bcsr2_phys +
+					(0x04 * (i - BCSR_HEXLEDS));
+		else
+			bcsr_regs[i].raddr = (void __iomem *)bcsr1_phys +
+					(0x04 * i);
+
+		spin_lock_init(&bcsr_regs[i].lock);
+	}
+}
+
+unsigned short bcsr_read(enum bcsr_id reg)
+{
+	unsigned short r;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bcsr_regs[reg].lock, flags);
+	r = __raw_readw(bcsr_regs[reg].raddr);
+	spin_unlock_irqrestore(&bcsr_regs[reg].lock, flags);
+	return r;
+}
+EXPORT_SYMBOL_GPL(bcsr_read);
+
+void bcsr_write(enum bcsr_id reg, unsigned short val)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&bcsr_regs[reg].lock, flags);
+	__raw_writew(val, bcsr_regs[reg].raddr);
+	wmb();
+	spin_unlock_irqrestore(&bcsr_regs[reg].lock, flags);
+}
+EXPORT_SYMBOL_GPL(bcsr_write);
+
+void bcsr_mod(enum bcsr_id reg, unsigned short clr, unsigned short set)
+{
+	unsigned short r;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bcsr_regs[reg].lock, flags);
+	r = __raw_readw(bcsr_regs[reg].raddr);
+	r &= ~clr;
+	r |= set;
+	__raw_writew(r, bcsr_regs[reg].raddr);
+	wmb();
+	spin_unlock_irqrestore(&bcsr_regs[reg].lock, flags);
+}
+EXPORT_SYMBOL_GPL(bcsr_mod);
diff --git a/arch/mips/alchemy/devboards/db1x00/board_setup.c b/arch/mips/alchemy/devboards/db1x00/board_setup.c
index de30d8e..e713390 100644
--- a/arch/mips/alchemy/devboards/db1x00/board_setup.c
+++ b/arch/mips/alchemy/devboards/db1x00/board_setup.c
@@ -32,12 +32,10 @@
 
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-db1x00/db1x00.h>
+#include <asm/mach-db1x00/bcsr.h>
 
 #include <prom.h>
 
-
-static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
-
 const char *get_system_type(void)
 {
 #ifdef CONFIG_MIPS_BOSPORUS
@@ -49,15 +47,43 @@ const char *get_system_type(void)
 
 void board_reset(void)
 {
-	/* Hit BCSR.SW_RESET[RESET] */
-	bcsr->swreset = 0x0000;
+	bcsr_write(BCSR_SYSTEM, 0);
 }
 
 void __init board_setup(void)
 {
+	unsigned long bcsr1, bcsr2;
 	u32 pin_func = 0;
 	char *argptr;
 
+	bcsr1 = DB1000_BCSR_PHYS_ADDR;
+	bcsr2 = DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS;
+
+#ifdef CONFIG_MIPS_DB1000
+	printk(KERN_INFO "AMD Alchemy Au1000/Db1000 Board\n");
+#endif
+#ifdef CONFIG_MIPS_DB1500
+	printk(KERN_INFO "AMD Alchemy Au1500/Db1500 Board\n");
+#endif
+#ifdef CONFIG_MIPS_DB1100
+	printk(KERN_INFO "AMD Alchemy Au1100/Db1100 Board\n");
+#endif
+#ifdef CONFIG_MIPS_BOSPORUS
+	printk(KERN_INFO "AMD Alchemy Bosporus Board\n");
+#endif
+#ifdef CONFIG_MIPS_MIRAGE
+	printk(KERN_INFO "AMD Alchemy Mirage Board\n");
+#endif
+#ifdef CONFIG_MIPS_DB1550
+	printk(KERN_INFO "AMD Alchemy Au1550/Db1550 Board\n");
+
+	bcsr1 = DB1550_BCSR_PHYS_ADDR;
+	bcsr2 = DB1550_BCSR_PHYS_ADDR + DB1550_BCSR_HEXLED_OFS;
+#endif
+
+	/* initialize board register space */
+	bcsr_init(bcsr1, bcsr2);
+
 	argptr = prom_getcmdline();
 #ifdef CONFIG_SERIAL_8250_CONSOLE
 	argptr = strstr(argptr, "console=");
@@ -89,11 +115,10 @@ void __init board_setup(void)
 	pin_func = au_readl(SYS_PINFUNC) | SYS_PF_IRF;
 	au_writel(pin_func, SYS_PINFUNC);
 	/* Power off until the driver is in use */
-	bcsr->resets &= ~BCSR_RESETS_IRDA_MODE_MASK;
-	bcsr->resets |=  BCSR_RESETS_IRDA_MODE_OFF;
-	au_sync();
+	bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK,
+				BCSR_RESETS_IRDA_MODE_OFF);
 #endif
-	bcsr->pcmcia = 0x0000; /* turn off PCMCIA power */
+	bcsr_write(BCSR_PCMCIA, 0);	/* turn off PCMCIA power */
 
 	/* Enable GPIO[31:0] inputs */
 	alchemy_gpio1_input_enable();
@@ -123,23 +148,4 @@ void __init board_setup(void)
 #endif
 
 	au_sync();
-
-#ifdef CONFIG_MIPS_DB1000
-	printk(KERN_INFO "AMD Alchemy Au1000/Db1000 Board\n");
-#endif
-#ifdef CONFIG_MIPS_DB1500
-	printk(KERN_INFO "AMD Alchemy Au1500/Db1500 Board\n");
-#endif
-#ifdef CONFIG_MIPS_DB1100
-	printk(KERN_INFO "AMD Alchemy Au1100/Db1100 Board\n");
-#endif
-#ifdef CONFIG_MIPS_BOSPORUS
-	printk(KERN_INFO "AMD Alchemy Bosporus Board\n");
-#endif
-#ifdef CONFIG_MIPS_MIRAGE
-	printk(KERN_INFO "AMD Alchemy Mirage Board\n");
-#endif
-#ifdef CONFIG_MIPS_DB1550
-	printk(KERN_INFO "AMD Alchemy Au1550/Db1550 Board\n");
-#endif
 }
diff --git a/arch/mips/alchemy/devboards/pb1100/board_setup.c b/arch/mips/alchemy/devboards/pb1100/board_setup.c
index 6126308..eb749fb 100644
--- a/arch/mips/alchemy/devboards/pb1100/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1100/board_setup.c
@@ -30,6 +30,7 @@
 
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-pb1x00/pb1100.h>
+#include <asm/mach-db1x00/bcsr.h>
 
 #include <prom.h>
 
@@ -49,8 +50,7 @@ const char *get_system_type(void)
 
 void board_reset(void)
 {
-	/* Hit BCSR.RST_VDDI[SOFT_RESET] */
-	au_writel(0x00000000, PB1100_RST_VDDI);
+	bcsr_write(BCSR_SYSTEM, 0);
 }
 
 void __init board_init_irq(void)
@@ -63,6 +63,9 @@ void __init board_setup(void)
 	volatile void __iomem *base = (volatile void __iomem *)0xac000000UL;
 	char *argptr;
 
+	bcsr_init(DB1000_BCSR_PHYS_ADDR,
+		  DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS);
+
 	argptr = prom_getcmdline();
 #ifdef CONFIG_SERIAL_8250_CONSOLE
 	argptr = strstr(argptr, "console=");
diff --git a/arch/mips/alchemy/devboards/pb1200/board_setup.c b/arch/mips/alchemy/devboards/pb1200/board_setup.c
index 94e6b7e..db56380 100644
--- a/arch/mips/alchemy/devboards/pb1200/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1200/board_setup.c
@@ -27,6 +27,8 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 
+#include <asm/mach-db1x00/bcsr.h>
+
 #include <prom.h>
 #include <au1xxx.h>
 
@@ -38,14 +40,25 @@ const char *get_system_type(void)
 
 void board_reset(void)
 {
-	bcsr->resets = 0;
-	bcsr->system = 0;
+	bcsr_write(BCSR_RESETS, 0);
+	bcsr_write(BCSR_SYSTEM, 0);
 }
 
 void __init board_setup(void)
 {
 	char *argptr;
 
+#ifdef CONFIG_MIPS_PB1200
+	printk(KERN_INFO "AMD Alchemy Pb1200 Board\n");
+	bcsr_init(PB1200_BCSR_PHYS_ADDR,
+		  PB1200_BCSR_PHYS_ADDR + PB1200_BCSR_HEXLED_OFS);
+#endif
+#ifdef CONFIG_MIPS_DB1200
+	printk(KERN_INFO "AMD Alchemy Db1200 Board\n");
+	bcsr_init(DB1200_BCSR_PHYS_ADDR,
+		  DB1200_BCSR_PHYS_ADDR + DB1200_BCSR_HEXLED_OFS);
+#endif
+
 	argptr = prom_getcmdline();
 #ifdef CONFIG_SERIAL_8250_CONSOLE
 	argptr = strstr(argptr, "console=");
@@ -82,7 +95,7 @@ void __init board_setup(void)
 		u32 pin_func;
 
 		/* Select SMBus in CPLD */
-		bcsr->resets &= ~BCSR_RESETS_PCS0MUX;
+		bcsr_mod(BCSR_RESETS, BCSR_RESETS_PSC0MUX, 0);
 
 		pin_func = au_readl(SYS_PINFUNC);
 		au_sync();
@@ -116,38 +129,24 @@ void __init board_setup(void)
 
 	/*
 	 * The Pb1200 development board uses external MUX for PSC0 to
-	 * support SMB/SPI. bcsr->resets bit 12: 0=SMB 1=SPI
+	 * support SMB/SPI. bcsr_resets bit 12: 0=SMB 1=SPI
 	 */
 #ifdef CONFIG_I2C_AU1550
-	bcsr->resets &= ~BCSR_RESETS_PCS0MUX;
+	bcsr_mod(BCSR_RESETS, BCSR_RESETS_PSC0MUX, 0);
 #endif
 	au_sync();
-
-#ifdef CONFIG_MIPS_PB1200
-	printk(KERN_INFO "AMD Alchemy Pb1200 Board\n");
-#endif
-#ifdef CONFIG_MIPS_DB1200
-	printk(KERN_INFO "AMD Alchemy Db1200 Board\n");
-#endif
 }
 
 int board_au1200fb_panel(void)
 {
-	BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
-	int p;
-
-	p = bcsr->switches;
-	p >>= 8;
-	p &= 0x0F;
-	return p;
+	return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f;
 }
 
 int board_au1200fb_panel_init(void)
 {
 	/* Apply power */
-	BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
-
-	bcsr->board |= BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD | BCSR_BOARD_LCDBL;
+	bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
+				BCSR_BOARD_LCDBL);
 	/* printk(KERN_DEBUG "board_au1200fb_panel_init()\n"); */
 	return 0;
 }
@@ -155,10 +154,8 @@ int board_au1200fb_panel_init(void)
 int board_au1200fb_panel_shutdown(void)
 {
 	/* Remove power */
-	BCSR *bcsr = (BCSR *)BCSR_KSEG1_ADDR;
-
-	bcsr->board &= ~(BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
-			 BCSR_BOARD_LCDBL);
+	bcsr_mod(BCSR_BOARD, BCSR_BOARD_LCDVEE | BCSR_BOARD_LCDVDD |
+			     BCSR_BOARD_LCDBL, 0);
 	/* printk(KERN_DEBUG "board_au1200fb_panel_shutdown()\n"); */
 	return 0;
 }
diff --git a/arch/mips/alchemy/devboards/pb1200/irqmap.c b/arch/mips/alchemy/devboards/pb1200/irqmap.c
index fe47498..f379b02 100644
--- a/arch/mips/alchemy/devboards/pb1200/irqmap.c
+++ b/arch/mips/alchemy/devboards/pb1200/irqmap.c
@@ -38,11 +38,14 @@
 #define PB1200_INT_END DB1200_INT_END
 #endif
 
+#include <asm/mach-db1x00/bcsr.h>
+
 struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
 	/* This is external interrupt cascade */
 	{ AU1000_GPIO_7, IRQF_TRIGGER_LOW, 0 },
 };
 
+static void __iomem *bcsr_virt;
 
 /*
  * Support for External interrupts on the Pb1200 Development platform.
@@ -50,7 +53,7 @@ struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
 
 static void pb1200_cascade_handler(unsigned int irq, struct irq_desc *d)
 {
-	unsigned short bisr = bcsr->int_status;
+	unsigned short bisr = __raw_readw(bcsr_virt + BCSR_REG_INTSTAT);
 
 	for ( ; bisr; bisr &= bisr - 1)
 		generic_handle_irq(PB1200_INT_BEGIN + __ffs(bisr));
@@ -61,24 +64,27 @@ static void pb1200_cascade_handler(unsigned int irq, struct irq_desc *d)
  */
 static void pb1200_mask_irq(unsigned int irq_nr)
 {
-	bcsr->intclr_mask = 1 << (irq_nr - PB1200_INT_BEGIN);
-	bcsr->intclr = 1 << (irq_nr - PB1200_INT_BEGIN);
-	au_sync();
+	unsigned short v = 1 << (irq_nr - PB1200_INT_BEGIN);
+	__raw_writew(v, bcsr_virt + BCSR_REG_INTCLR);
+	__raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
+	wmb();
 }
 
 static void pb1200_maskack_irq(unsigned int irq_nr)
 {
-	bcsr->intclr_mask = 1 << (irq_nr - PB1200_INT_BEGIN);
-	bcsr->intclr = 1 << (irq_nr - PB1200_INT_BEGIN);
-	bcsr->int_status = 1 << (irq_nr - PB1200_INT_BEGIN);	/* ack */
-	au_sync();
+	unsigned short v = 1 << (irq_nr - PB1200_INT_BEGIN);
+	__raw_writew(v, bcsr_virt + BCSR_REG_INTCLR);
+	__raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
+	__raw_writew(v, bcsr_virt + BCSR_REG_INTSTAT);	/* ack */
+	wmb();
 }
 
 static void pb1200_unmask_irq(unsigned int irq_nr)
 {
-	bcsr->intset = 1 << (irq_nr - PB1200_INT_BEGIN);
-	bcsr->intset_mask = 1 << (irq_nr - PB1200_INT_BEGIN);
-	au_sync();
+	unsigned short v = 1 << (irq_nr - PB1200_INT_BEGIN);
+	__raw_writew(v, bcsr_virt + BCSR_REG_INTSET);
+	__raw_writew(v, bcsr_virt + BCSR_REG_MASKSET);
+	wmb();
 }
 
 static struct irq_chip pb1200_cpld_irq_type = {
@@ -100,8 +106,10 @@ void __init board_init_irq(void)
 	au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
 
 #ifdef CONFIG_MIPS_PB1200
+	bcsr_virt = (void __iomem *)KSEG1ADDR(PB1200_BCSR_PHYS_ADDR);
+
 	/* We have a problem with CPLD rev 3. */
-	if (((bcsr->whoami & BCSR_WHOAMI_CPLD) >> 4) <= 3) {
+	if (BCSR_WHOAMI_CPLD(bcsr_read(BCSR_WHOAMI)) <= 3) {
 		printk(KERN_ERR "WARNING!!!\n");
 		printk(KERN_ERR "WARNING!!!\n");
 		printk(KERN_ERR "WARNING!!!\n");
@@ -119,12 +127,14 @@ void __init board_init_irq(void)
 		printk(KERN_ERR "WARNING!!!\n");
 		panic("Game over.  Your score is 0.");
 	}
+#else
+	bcsr_virt = (void __iomem *)KSEG1ADDR(DB1200_BCSR_PHYS_ADDR);
 #endif
+
 	/* mask & disable & ack all */
-	bcsr->intclr_mask = 0xffff;
-	bcsr->intclr = 0xffff;
-	bcsr->int_status = 0xffff;
-	au_sync();
+	bcsr_write(BCSR_INTCLR, 0xffff);
+	bcsr_write(BCSR_MASKCLR, 0xffff);
+	bcsr_write(BCSR_INTSTAT, 0xffff);
 
 	for (irq = PB1200_INT_BEGIN; irq <= PB1200_INT_END; irq++)
 		set_irq_chip_and_handler_name(irq, &pb1200_cpld_irq_type,
diff --git a/arch/mips/alchemy/devboards/pb1200/platform.c b/arch/mips/alchemy/devboards/pb1200/platform.c
index b93dff4..dfdaabf 100644
--- a/arch/mips/alchemy/devboards/pb1200/platform.c
+++ b/arch/mips/alchemy/devboards/pb1200/platform.c
@@ -26,27 +26,28 @@
 
 #include <asm/mach-au1x00/au1xxx.h>
 #include <asm/mach-au1x00/au1100_mmc.h>
+#include <asm/mach-db1x00/bcsr.h>
 
 static int mmc_activity;
 
 static void pb1200mmc0_set_power(void *mmc_host, int state)
 {
 	if (state)
-		bcsr->board |= BCSR_BOARD_SD0PWR;
+		bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD0PWR);
 	else
-		bcsr->board &= ~BCSR_BOARD_SD0PWR;
+		bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD0PWR, 0);
 
-	au_sync_delay(1);
+	msleep(1);
 }
 
 static int pb1200mmc0_card_readonly(void *mmc_host)
 {
-	return (bcsr->status & BCSR_STATUS_SD0WP) ? 1 : 0;
+	return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD0WP) ? 1 : 0;
 }
 
 static int pb1200mmc0_card_inserted(void *mmc_host)
 {
-	return (bcsr->sig_status & BCSR_INT_SD0INSERT) ? 1 : 0;
+	return (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD0INSERT) ? 1 : 0;
 }
 
 static void pb1200_mmcled_set(struct led_classdev *led,
@@ -54,10 +55,10 @@ static void pb1200_mmcled_set(struct led_classdev *led,
 {
 	if (brightness != LED_OFF) {
 		if (++mmc_activity == 1)
-			bcsr->disk_leds &= ~(1 << 8);
+			bcsr_mod(BCSR_LEDS, BCSR_LEDS_LED0, 0);
 	} else {
 		if (--mmc_activity == 0)
-			bcsr->disk_leds |= (1 << 8);
+			bcsr_mod(BCSR_LEDS, 0, BCSR_LEDS_LED0);
 	}
 }
 
@@ -69,21 +70,21 @@ static struct led_classdev pb1200mmc_led = {
 static void pb1200mmc1_set_power(void *mmc_host, int state)
 {
 	if (state)
-		bcsr->board |= BCSR_BOARD_SD1PWR;
+		bcsr_mod(BCSR_BOARD, 0, BCSR_BOARD_SD1PWR);
 	else
-		bcsr->board &= ~BCSR_BOARD_SD1PWR;
+		bcsr_mod(BCSR_BOARD, BCSR_BOARD_SD1PWR, 0);
 
-	au_sync_delay(1);
+	msleep(1);
 }
 
 static int pb1200mmc1_card_readonly(void *mmc_host)
 {
-	return (bcsr->status & BCSR_STATUS_SD1WP) ? 1 : 0;
+	return (bcsr_read(BCSR_STATUS) & BCSR_STATUS_SD1WP) ? 1 : 0;
 }
 
 static int pb1200mmc1_card_inserted(void *mmc_host)
 {
-	return (bcsr->sig_status & BCSR_INT_SD1INSERT) ? 1 : 0;
+	return (bcsr_read(BCSR_SIGSTAT) & BCSR_INT_SD1INSERT) ? 1 : 0;
 }
 #endif
 
diff --git a/arch/mips/alchemy/devboards/pb1500/board_setup.c b/arch/mips/alchemy/devboards/pb1500/board_setup.c
index d7a5656..c5389e5 100644
--- a/arch/mips/alchemy/devboards/pb1500/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1500/board_setup.c
@@ -30,6 +30,7 @@
 
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-pb1x00/pb1500.h>
+#include <asm/mach-db1x00/bcsr.h>
 
 #include <prom.h>
 
@@ -55,8 +56,7 @@ const char *get_system_type(void)
 
 void board_reset(void)
 {
-	/* Hit BCSR.RST_VDDI[SOFT_RESET] */
-	au_writel(0x00000000, PB1500_RST_VDDI);
+	bcsr_write(BCSR_SYSTEM, 0);
 }
 
 void __init board_init_irq(void)
@@ -70,6 +70,9 @@ void __init board_setup(void)
 	u32 sys_freqctrl, sys_clksrc;
 	char *argptr;
 
+	bcsr_init(DB1000_BCSR_PHYS_ADDR,
+		  DB1000_BCSR_PHYS_ADDR + DB1000_BCSR_HEXLED_OFS);
+
 	argptr = prom_getcmdline();
 #ifdef CONFIG_SERIAL_8250_CONSOLE
 	argptr = strstr(argptr, "console=");
diff --git a/arch/mips/alchemy/devboards/pb1550/board_setup.c b/arch/mips/alchemy/devboards/pb1550/board_setup.c
index b6e9e7d..af7a1b5 100644
--- a/arch/mips/alchemy/devboards/pb1550/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1550/board_setup.c
@@ -32,6 +32,7 @@
 
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-pb1x00/pb1550.h>
+#include <asm/mach-db1x00/bcsr.h>
 
 #include <prom.h>
 
@@ -53,8 +54,7 @@ const char *get_system_type(void)
 
 void board_reset(void)
 {
-	/* Hit BCSR.SYSTEM[RESET] */
-	au_writew(au_readw(0xAF00001C) & ~BCSR_SYSTEM_RESET, 0xAF00001C);
+	bcsr_write(BCSR_SYSTEM, 0);
 }
 
 void __init board_init_irq(void)
@@ -66,6 +66,10 @@ void __init board_setup(void)
 {
 	u32 pin_func;
 
+	bcsr_init(PB1550_BCSR_PHYS_ADDR,
+		  PB1550_BCSR_PHYS_ADDR + PB1550_BCSR_HEXLED_OFS);
+
+
 #ifdef CONFIG_SERIAL_8250_CONSOLE
 	char *argptr;
 	argptr = prom_getcmdline();
@@ -85,8 +89,7 @@ void __init board_setup(void)
 	pin_func |= SYS_PF_MUST_BE_SET | SYS_PF_PSC1_S1;
 	au_writel(pin_func, SYS_PINFUNC);
 
-	au_writel(0, (u32)bcsr | 0x10); /* turn off PCMCIA power */
-	au_sync();
+	bcsr_write(BCSR_PCMCIA, 0);	/* turn off PCMCIA power */
 
 	printk(KERN_INFO "AMD Alchemy Pb1550 Board\n");
 }
diff --git a/arch/mips/include/asm/mach-db1x00/bcsr.h b/arch/mips/include/asm/mach-db1x00/bcsr.h
new file mode 100644
index 0000000..ecbe19e
--- /dev/null
+++ b/arch/mips/include/asm/mach-db1x00/bcsr.h
@@ -0,0 +1,235 @@
+/*
+ * bcsr.h -- Db1xxx/Pb1xxx Devboard CPLD registers ("BCSR") abstraction.
+ *
+ * All Alchemy development boards (except, of course, the weird PB1000)
+ * have a few registers in a CPLD with standardised layout; they mostly
+ * only differ in base address and bit meanings in the RESETS and BOARD
+ * registers.
+ *
+ * All data taken from the official AMD board documentation sheets.
+ */
+
+#ifndef _DB1XXX_BCSR_H_
+#define _DB1XXX_BCSR_H_
+
+
+/* BCSR base addresses on various boards. BCSR base 2 refers to the
+ * physical address of the first HEXLEDS register, which is usually
+ * a variable offset from the WHOAMI register.
+ */
+
+/* DB1000, DB1100, DB1500, PB1100, PB1500 */
+#define DB1000_BCSR_PHYS_ADDR	0x0E000000
+#define DB1000_BCSR_HEXLED_OFS	0x01000000
+
+#define DB1550_BCSR_PHYS_ADDR	0x0F000000
+#define DB1550_BCSR_HEXLED_OFS	0x00400000
+
+#define PB1550_BCSR_PHYS_ADDR	0x0F000000
+#define PB1550_BCSR_HEXLED_OFS	0x00800000
+
+#define DB1200_BCSR_PHYS_ADDR	0x19800000
+#define DB1200_BCSR_HEXLED_OFS	0x00400000
+
+#define PB1200_BCSR_PHYS_ADDR	0x0D800000
+#define PB1200_BCSR_HEXLED_OFS	0x00400000
+
+
+enum bcsr_id {
+	/* BCSR base 1 */
+	BCSR_WHOAMI	= 0,
+	BCSR_STATUS,
+	BCSR_SWITCHES,
+	BCSR_RESETS,
+	BCSR_PCMCIA,
+	BCSR_BOARD,
+	BCSR_LEDS,
+	BCSR_SYSTEM,
+	/* Au1200/1300 based boards */
+	BCSR_INTCLR,
+	BCSR_INTSET,
+	BCSR_MASKCLR,
+	BCSR_MASKSET,
+	BCSR_SIGSTAT,
+	BCSR_INTSTAT,
+
+	/* BCSR base 2 */
+	BCSR_HEXLEDS,
+	BCSR_RSVD1,
+	BCSR_HEXCLEAR,
+
+	BCSR_CNT,
+};
+
+/* register offsets, valid for all Db1xxx/Pb1xxx boards */
+#define BCSR_REG_WHOAMI		0x00
+#define BCSR_REG_STATUS		0x04
+#define BCSR_REG_SWITCHES	0x08
+#define BCSR_REG_RESETS		0x0c
+#define BCSR_REG_PCMCIA		0x10
+#define BCSR_REG_BOARD		0x14
+#define BCSR_REG_LEDS		0x18
+#define BCSR_REG_SYSTEM		0x1c
+/* Au1200/Au1300 based boards: CPLD IRQ muxer */
+#define BCSR_REG_INTCLR		0x20
+#define BCSR_REG_INTSET		0x24
+#define BCSR_REG_MASKCLR	0x28
+#define BCSR_REG_MASKSET	0x2c
+#define BCSR_REG_SIGSTAT	0x30
+#define BCSR_REG_INTSTAT	0x34
+
+/* hexled control, offset from BCSR base 2 */
+#define BCSR_REG_HEXLEDS	0x00
+#define BCSR_REG_HEXCLEAR	0x08
+
+/*
+ * Register Bits and Pieces.
+ */
+#define BCSR_WHOAMI_DCID(x)		((x) & 0xf)
+#define BCSR_WHOAMI_CPLD(x)		(((x) >> 4) & 0xf)
+#define BCSR_WHOAMI_BOARD(x)		(((x) >> 8) & 0xf)
+
+/* register "WHOAMI" bits 11:8 identify the board */
+enum bcsr_whoami_boards {
+	BCSR_WHOAMI_PB1500 = 1,
+	BCSR_WHOAMI_PB1500R2,
+	BCSR_WHOAMI_PB1100,
+	BCSR_WHOAMI_DB1000,
+	BCSR_WHOAMI_DB1100,
+	BCSR_WHOAMI_DB1500,
+	BCSR_WHOAMI_DB1550,
+	BCSR_WHOAMI_PB1550_DDR,
+	BCSR_WHOAMI_PB1550 = BCSR_WHOAMI_PB1550_DDR,
+	BCSR_WHOAMI_PB1550_SDR,
+	BCSR_WHOAMI_PB1200_DDR1,
+	BCSR_WHOAMI_PB1200 = BCSR_WHOAMI_PB1200_DDR1,
+	BCSR_WHOAMI_PB1200_DDR2,
+	BCSR_WHOAMI_DB1200,
+};
+
+/* STATUS reg.  Unless otherwise noted, they're valid on all boards.
+ * PB1200 = DB1200.
+ */
+#define BCSR_STATUS_PC0VS		0x0003
+#define BCSR_STATUS_PC1VS		0x000C
+#define BCSR_STATUS_PC0FI		0x0010
+#define BCSR_STATUS_PC1FI		0x0020
+#define BCSR_STATUS_PB1550_SWAPBOOT	0x0040
+#define BCSR_STATUS_SRAMWIDTH		0x0080
+#define BCSR_STATUS_FLASHBUSY		0x0100
+#define BCSR_STATUS_ROMBUSY		0x0400
+#define BCSR_STATUS_SD0WP		0x0400	/* DB1200 */
+#define BCSR_STATUS_SD1WP		0x0800
+#define BCSR_STATUS_USBOTGID		0x0800	/* PB/DB1550 */
+#define BCSR_STATUS_DB1000_SWAPBOOT	0x2000
+#define BCSR_STATUS_DB1200_SWAPBOOT	0x0040	/* DB1200 */
+#define BCSR_STATUS_IDECBLID		0x0200	/* DB1200 */
+#define BCSR_STATUS_DB1200_U0RXD	0x1000	/* DB1200 */
+#define BCSR_STATUS_DB1200_U1RXD	0x2000	/* DB1200 */
+#define BCSR_STATUS_FLASHDEN		0xC000
+#define BCSR_STATUS_DB1550_U0RXD	0x1000	/* DB1550 */
+#define BCSR_STATUS_DB1550_U3RXD	0x2000	/* DB1550 */
+#define BCSR_STATUS_PB1550_U0RXD	0x1000	/* PB1550 */
+#define BCSR_STATUS_PB1550_U1RXD	0x2000	/* PB1550 */
+#define BCSR_STATUS_PB1550_U3RXD	0x8000	/* PB1550 */
+
+
+/* DB/PB1000,1100,1500,1550 */
+#define BCSR_RESETS_PHY0		0x0001
+#define BCSR_RESETS_PHY1		0x0002
+#define BCSR_RESETS_DC			0x0004
+#define BCSR_RESETS_FIR_SEL		0x2000
+#define BCSR_RESETS_IRDA_MODE_MASK	0xC000
+#define BCSR_RESETS_IRDA_MODE_FULL	0x0000
+#define BCSR_RESETS_PB1550_WSCFSM	0x2000
+#define BCSR_RESETS_IRDA_MODE_OFF	0x4000
+#define BCSR_RESETS_IRDA_MODE_2_3	0x8000
+#define BCSR_RESETS_IRDA_MODE_1_3	0xC000
+#define BCSR_RESETS_DMAREQ		0x8000	/* PB1550 */
+
+#define BCSR_BOARD_PCIM66EN		0x0001
+#define BCSR_BOARD_SD0PWR		0x0040
+#define BCSR_BOARD_SD1PWR		0x0080
+#define BCSR_BOARD_PCIM33		0x0100
+#define BCSR_BOARD_PCIEXTARB		0x0200
+#define BCSR_BOARD_GPIO200RST		0x0400
+#define BCSR_BOARD_PCICLKOUT		0x0800
+#define BCSR_BOARD_PCICFG		0x1000
+#define BCSR_BOARD_SPISEL		0x4000	/* PB/DB1550 */
+#define BCSR_BOARD_SD0WP		0x4000	/* DB1100 */
+#define BCSR_BOARD_SD1WP		0x8000	/* DB1100 */
+
+
+/* DB/PB1200 */
+#define BCSR_RESETS_ETH			0x0001
+#define BCSR_RESETS_CAMERA		0x0002
+#define BCSR_RESETS_DC			0x0004
+#define BCSR_RESETS_IDE			0x0008
+#define BCSR_RESETS_TV			0x0010	/* DB1200 */
+/* Not resets but in the same register */
+#define BCSR_RESETS_PWMR1MUX		0x0800	/* DB1200 */
+#define BCSR_RESETS_PB1200_WSCFSM	0x0800	/* PB1200 */
+#define BCSR_RESETS_PSC0MUX		0x1000
+#define BCSR_RESETS_PSC1MUX		0x2000
+#define BCSR_RESETS_SPISEL		0x4000
+#define BCSR_RESETS_SD1MUX		0x8000	/* PB1200 */
+
+#define BCSR_BOARD_LCDVEE		0x0001
+#define BCSR_BOARD_LCDVDD		0x0002
+#define BCSR_BOARD_LCDBL		0x0004
+#define BCSR_BOARD_CAMSNAP		0x0010
+#define BCSR_BOARD_CAMPWR		0x0020
+#define BCSR_BOARD_SD0PWR		0x0040
+
+
+#define BCSR_SWITCHES_DIP		0x00FF
+#define BCSR_SWITCHES_DIP_1		0x0080
+#define BCSR_SWITCHES_DIP_2		0x0040
+#define BCSR_SWITCHES_DIP_3		0x0020
+#define BCSR_SWITCHES_DIP_4		0x0010
+#define BCSR_SWITCHES_DIP_5		0x0008
+#define BCSR_SWITCHES_DIP_6		0x0004
+#define BCSR_SWITCHES_DIP_7		0x0002
+#define BCSR_SWITCHES_DIP_8		0x0001
+#define BCSR_SWITCHES_ROTARY		0x0F00
+
+
+#define BCSR_PCMCIA_PC0VPP		0x0003
+#define BCSR_PCMCIA_PC0VCC		0x000C
+#define BCSR_PCMCIA_PC0DRVEN		0x0010
+#define BCSR_PCMCIA_PC0RST		0x0080
+#define BCSR_PCMCIA_PC1VPP		0x0300
+#define BCSR_PCMCIA_PC1VCC		0x0C00
+#define BCSR_PCMCIA_PC1DRVEN		0x1000
+#define BCSR_PCMCIA_PC1RST		0x8000
+
+
+#define BCSR_LEDS_DECIMALS		0x0003
+#define BCSR_LEDS_LED0			0x0100
+#define BCSR_LEDS_LED1			0x0200
+#define BCSR_LEDS_LED2			0x0400
+#define BCSR_LEDS_LED3			0x0800
+
+
+#define BCSR_SYSTEM_RESET		0x8000	/* clear to reset */
+#define BCSR_SYSTEM_PWROFF		0x4000	/* set to power off */
+#define BCSR_SYSTEM_VDDI		0x001F	/* PB1xxx boards */
+
+
+
+
+/* initialize BCSR for a board. Provide the PHYSICAL addresses of both
+ * BCSR spaces.
+ */
+void __init bcsr_init(unsigned long bcsr1_phys, unsigned long bcsr2_phys);
+
+/* read a board register */
+unsigned short bcsr_read(enum bcsr_id reg);
+
+/* write to a board register */
+void bcsr_write(enum bcsr_id reg, unsigned short val);
+
+/* modify a register. clear bits set in 'clr', set bits set in 'set' */
+void bcsr_mod(enum bcsr_id reg, unsigned short clr, unsigned short set);
+
+#endif
diff --git a/arch/mips/include/asm/mach-db1x00/db1200.h b/arch/mips/include/asm/mach-db1x00/db1200.h
index 27f2610..2909b83 100644
--- a/arch/mips/include/asm/mach-db1x00/db1200.h
+++ b/arch/mips/include/asm/mach-db1x00/db1200.h
@@ -45,113 +45,6 @@
 #define AC97_PSC_BASE		PSC1_BASE_ADDR
 #define I2S_PSC_BASE		PSC1_BASE_ADDR
 
-#define BCSR_KSEG1_ADDR 	0xB9800000
-
-typedef volatile struct
-{
-	/*00*/	u16 whoami;
-		u16 reserved0;
-	/*04*/	u16 status;
-		u16 reserved1;
-	/*08*/	u16 switches;
-		u16 reserved2;
-	/*0C*/	u16 resets;
-		u16 reserved3;
-
-	/*10*/	u16 pcmcia;
-		u16 reserved4;
-	/*14*/	u16 board;
-		u16 reserved5;
-	/*18*/	u16 disk_leds;
-		u16 reserved6;
-	/*1C*/	u16 system;
-		u16 reserved7;
-
-	/*20*/	u16 intclr;
-		u16 reserved8;
-	/*24*/	u16 intset;
-		u16 reserved9;
-	/*28*/	u16 intclr_mask;
-		u16 reserved10;
-	/*2C*/	u16 intset_mask;
-		u16 reserved11;
-
-	/*30*/	u16 sig_status;
-		u16 reserved12;
-	/*34*/	u16 int_status;
-		u16 reserved13;
-	/*38*/	u16 reserved14;
-		u16 reserved15;
-	/*3C*/	u16 reserved16;
-		u16 reserved17;
-
-} BCSR;
-
-static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
-
-/*
- * Register bit definitions for the BCSRs
- */
-#define BCSR_WHOAMI_DCID	0x000F
-#define BCSR_WHOAMI_CPLD	0x00F0
-#define BCSR_WHOAMI_BOARD	0x0F00
-
-#define BCSR_STATUS_PCMCIA0VS	0x0003
-#define BCSR_STATUS_PCMCIA1VS	0x000C
-#define BCSR_STATUS_SWAPBOOT	0x0040
-#define BCSR_STATUS_FLASHBUSY	0x0100
-#define BCSR_STATUS_IDECBLID	0x0200
-#define BCSR_STATUS_SD0WP	0x0400
-#define BCSR_STATUS_U0RXD	0x1000
-#define BCSR_STATUS_U1RXD	0x2000
-
-#define BCSR_SWITCHES_OCTAL	0x00FF
-#define BCSR_SWITCHES_DIP_1	0x0080
-#define BCSR_SWITCHES_DIP_2	0x0040
-#define BCSR_SWITCHES_DIP_3	0x0020
-#define BCSR_SWITCHES_DIP_4	0x0010
-#define BCSR_SWITCHES_DIP_5	0x0008
-#define BCSR_SWITCHES_DIP_6	0x0004
-#define BCSR_SWITCHES_DIP_7	0x0002
-#define BCSR_SWITCHES_DIP_8	0x0001
-#define BCSR_SWITCHES_ROTARY	0x0F00
-
-#define BCSR_RESETS_ETH		0x0001
-#define BCSR_RESETS_CAMERA	0x0002
-#define BCSR_RESETS_DC		0x0004
-#define BCSR_RESETS_IDE		0x0008
-#define BCSR_RESETS_TV		0x0010
-/* Not resets but in the same register */
-#define BCSR_RESETS_PWMR1MUX	0x0800
-#define BCSR_RESETS_PCS0MUX	0x1000
-#define BCSR_RESETS_PCS1MUX	0x2000
-#define BCSR_RESETS_SPISEL	0x4000
-
-#define BCSR_PCMCIA_PC0VPP	0x0003
-#define BCSR_PCMCIA_PC0VCC	0x000C
-#define BCSR_PCMCIA_PC0DRVEN	0x0010
-#define BCSR_PCMCIA_PC0RST	0x0080
-#define BCSR_PCMCIA_PC1VPP	0x0300
-#define BCSR_PCMCIA_PC1VCC	0x0C00
-#define BCSR_PCMCIA_PC1DRVEN	0x1000
-#define BCSR_PCMCIA_PC1RST	0x8000
-
-#define BCSR_BOARD_LCDVEE	0x0001
-#define BCSR_BOARD_LCDVDD	0x0002
-#define BCSR_BOARD_LCDBL	0x0004
-#define BCSR_BOARD_CAMSNAP	0x0010
-#define BCSR_BOARD_CAMPWR	0x0020
-#define BCSR_BOARD_SD0PWR	0x0040
-
-#define BCSR_LEDS_DECIMALS	0x0003
-#define BCSR_LEDS_LED0		0x0100
-#define BCSR_LEDS_LED1		0x0200
-#define BCSR_LEDS_LED2		0x0400
-#define BCSR_LEDS_LED3		0x0800
-
-#define BCSR_SYSTEM_POWEROFF	0x4000
-#define BCSR_SYSTEM_RESET	0x8000
-
 /* Bit positions for the different interrupt sources */
 #define BCSR_INT_IDE		0x0001
 #define BCSR_INT_ETH		0x0002
@@ -222,7 +115,7 @@ enum external_pb1200_ints {
 
 #define BOARD_PC0_INT	DB1200_PC0_INT
 #define BOARD_PC1_INT	DB1200_PC1_INT
-#define BOARD_CARD_INSERTED(SOCKET) bcsr->sig_status & (1 << (8 + (2 * SOCKET)))
+#define BOARD_CARD_INSERTED(SOCKET) (bcsr_read(BCSR_SIGSTAT) & (1 << (8 + (2 * SOCKET))))
 
 /* NAND chip select */
 #define NAND_CS 1
diff --git a/arch/mips/include/asm/mach-db1x00/db1x00.h b/arch/mips/include/asm/mach-db1x00/db1x00.h
index 1a515b8..cfa6429 100644
--- a/arch/mips/include/asm/mach-db1x00/db1x00.h
+++ b/arch/mips/include/asm/mach-db1x00/db1x00.h
@@ -41,102 +41,10 @@
 #define SMBUS_PSC_BASE		PSC2_BASE_ADDR
 #define I2S_PSC_BASE		PSC3_BASE_ADDR
 
-#define BCSR_KSEG1_ADDR 	0xAF000000
 #define NAND_PHYS_ADDR		0x20000000
 
-#else
-#define BCSR_KSEG1_ADDR 0xAE000000
 #endif
 
-/*
- * Overlay data structure of the DBAu1x00 board registers.
- * Registers are located at physical 0E0000xx, KSEG1 0xAE0000xx.
- */
-typedef volatile struct
-{
-	/*00*/	unsigned short whoami;
-	unsigned short reserved0;
-	/*04*/	unsigned short status;
-	unsigned short reserved1;
-	/*08*/	unsigned short switches;
-	unsigned short reserved2;
-	/*0C*/	unsigned short resets;
-	unsigned short reserved3;
-	/*10*/	unsigned short pcmcia;
-	unsigned short reserved4;
-	/*14*/	unsigned short specific;
-	unsigned short reserved5;
-	/*18*/	unsigned short leds;
-	unsigned short reserved6;
-	/*1C*/	unsigned short swreset;
-	unsigned short reserved7;
-
-} BCSR;
-
-
-/*
- * Register/mask bit definitions for the BCSRs
- */
-#define BCSR_WHOAMI_DCID		0x000F
-#define BCSR_WHOAMI_CPLD		0x00F0
-#define BCSR_WHOAMI_BOARD		0x0F00
-
-#define BCSR_STATUS_PC0VS		0x0003
-#define BCSR_STATUS_PC1VS		0x000C
-#define BCSR_STATUS_PC0FI		0x0010
-#define BCSR_STATUS_PC1FI		0x0020
-#define BCSR_STATUS_FLASHBUSY		0x0100
-#define BCSR_STATUS_ROMBUSY		0x0400
-#define BCSR_STATUS_SWAPBOOT		0x2000
-#define BCSR_STATUS_FLASHDEN		0xC000
-
-#define BCSR_SWITCHES_DIP		0x00FF
-#define BCSR_SWITCHES_DIP_1		0x0080
-#define BCSR_SWITCHES_DIP_2		0x0040
-#define BCSR_SWITCHES_DIP_3		0x0020
-#define BCSR_SWITCHES_DIP_4		0x0010
-#define BCSR_SWITCHES_DIP_5		0x0008
-#define BCSR_SWITCHES_DIP_6		0x0004
-#define BCSR_SWITCHES_DIP_7		0x0002
-#define BCSR_SWITCHES_DIP_8		0x0001
-#define BCSR_SWITCHES_ROTARY		0x0F00
-
-#define BCSR_RESETS_PHY0		0x0001
-#define BCSR_RESETS_PHY1		0x0002
-#define BCSR_RESETS_DC			0x0004
-#define BCSR_RESETS_FIR_SEL		0x2000
-#define BCSR_RESETS_IRDA_MODE_MASK	0xC000
-#define BCSR_RESETS_IRDA_MODE_FULL	0x0000
-#define BCSR_RESETS_IRDA_MODE_OFF	0x4000
-#define BCSR_RESETS_IRDA_MODE_2_3	0x8000
-#define BCSR_RESETS_IRDA_MODE_1_3	0xC000
-
-#define BCSR_PCMCIA_PC0VPP		0x0003
-#define BCSR_PCMCIA_PC0VCC		0x000C
-#define BCSR_PCMCIA_PC0DRVEN		0x0010
-#define BCSR_PCMCIA_PC0RST		0x0080
-#define BCSR_PCMCIA_PC1VPP		0x0300
-#define BCSR_PCMCIA_PC1VCC		0x0C00
-#define BCSR_PCMCIA_PC1DRVEN		0x1000
-#define BCSR_PCMCIA_PC1RST		0x8000
-
-#define BCSR_BOARD_PCIM66EN		0x0001
-#define BCSR_BOARD_SD0_PWR		0x0040
-#define BCSR_BOARD_SD1_PWR		0x0080
-#define BCSR_BOARD_PCIM33		0x0100
-#define BCSR_BOARD_GPIO200RST		0x0400
-#define BCSR_BOARD_PCICFG		0x1000
-#define BCSR_BOARD_SD0_WP		0x4000
-#define BCSR_BOARD_SD1_WP		0x8000
-
-#define BCSR_LEDS_DECIMALS		0x0003
-#define BCSR_LEDS_LED0			0x0100
-#define BCSR_LEDS_LED1			0x0200
-#define BCSR_LEDS_LED2			0x0400
-#define BCSR_LEDS_LED3			0x0800
-
-#define BCSR_SWRESET_RESET		0x0080
-
 /* PCMCIA DBAu1x00 specific defines */
 #define PCMCIA_MAX_SOCK  1
 #define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1100.h b/arch/mips/include/asm/mach-pb1x00/pb1100.h
index b1a60f1..f2bf73a 100644
--- a/arch/mips/include/asm/mach-pb1x00/pb1100.h
+++ b/arch/mips/include/asm/mach-pb1x00/pb1100.h
@@ -26,55 +26,6 @@
 #ifndef __ASM_PB1100_H
 #define __ASM_PB1100_H
 
-#define PB1100_IDENT		0xAE000000
-#define BOARD_STATUS_REG	0xAE000004
-#  define PB1100_ROM_SEL	(1 << 15)
-#  define PB1100_ROM_SIZ	(1 << 14)
-#  define PB1100_SWAP_BOOT	(1 << 13)
-#  define PB1100_FLASH_WP	(1 << 12)
-#  define PB1100_ROM_H_STS	(1 << 11)
-#  define PB1100_ROM_L_STS	(1 << 10)
-#  define PB1100_FLASH_H_STS	(1 << 9)
-#  define PB1100_FLASH_L_STS	(1 << 8)
-#  define PB1100_SRAM_SIZ	(1 << 7)
-#  define PB1100_TSC_BUSY	(1 << 6)
-#  define PB1100_PCMCIA_VS_MASK (3 << 4)
-#  define PB1100_RS232_CD	(1 << 3)
-#  define PB1100_RS232_CTS	(1 << 2)
-#  define PB1100_RS232_DSR	(1 << 1)
-#  define PB1100_RS232_RI	(1 << 0)
-
-#define PB1100_IRDA_RS232	0xAE00000C
-#  define PB1100_IRDA_FULL	(0 << 14)	/* full power		*/
-#  define PB1100_IRDA_SHUTDOWN	(1 << 14)
-#  define PB1100_IRDA_TT	(2 << 14)	/* 2/3 power		*/
-#  define PB1100_IRDA_OT	(3 << 14)	/* 1/3 power		*/
-#  define PB1100_IRDA_FIR	(1 << 13)
-
-#define PCMCIA_BOARD_REG	0xAE000010
-#  define PB1100_SD_WP1_RO	(1 << 15)	/* read only		*/
-#  define PB1100_SD_WP0_RO	(1 << 14)	/* read only		*/
-#  define PB1100_SD_PWR1	(1 << 11)	/* applies power to SD1 */
-#  define PB1100_SD_PWR0	(1 << 10)	/* applies power to SD0 */
-#  define PB1100_SEL_SD_CONN1	(1 << 9)
-#  define PB1100_SEL_SD_CONN0	(1 << 8)
-#  define PC_DEASSERT_RST	(1 << 7)
-#  define PC_DRV_EN		(1 << 4)
-
-#define PB1100_G_CONTROL	0xAE000014	/* graphics control	*/
-
-#define PB1100_RST_VDDI 	0xAE00001C
-#  define PB1100_SOFT_RESET	(1 << 15)	/* clear to reset the board */
-#  define PB1100_VDDI_MASK	0x1F
-
-#define PB1100_LEDS		0xAE000018
-
-/*
- * 11:8 is 4 discreet LEDs. Clearing a bit illuminates the LED.
- * 7:0  is the LED Display's decimal points.
- */
-#define PB1100_HEX_LED		0xAE000018
-
 /* PCMCIA Pb1100 specific defines */
 #define PCMCIA_MAX_SOCK  0
 #define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1200.h b/arch/mips/include/asm/mach-pb1x00/pb1200.h
index c8618df..a51512c 100644
--- a/arch/mips/include/asm/mach-pb1x00/pb1200.h
+++ b/arch/mips/include/asm/mach-pb1x00/pb1200.h
@@ -43,113 +43,8 @@
  * Refer to board documentation.
  */
 #define AC97_PSC_BASE       PSC1_BASE_ADDR
-#define I2S_PSC_BASE		PSC1_BASE_ADDR
+#define I2S_PSC_BASE	PSC1_BASE_ADDR
 
-#define BCSR_KSEG1_ADDR 0xAD800000
-
-typedef volatile struct
-{
-	/*00*/	u16 whoami;
-		u16 reserved0;
-	/*04*/	u16 status;
-		u16 reserved1;
-	/*08*/	u16 switches;
-		u16 reserved2;
-	/*0C*/	u16 resets;
-		u16 reserved3;
-
-	/*10*/	u16 pcmcia;
-		u16 reserved4;
-	/*14*/	u16 board;
-		u16 reserved5;
-	/*18*/	u16 disk_leds;
-		u16 reserved6;
-	/*1C*/	u16 system;
-		u16 reserved7;
-
-	/*20*/	u16 intclr;
-		u16 reserved8;
-	/*24*/	u16 intset;
-		u16 reserved9;
-	/*28*/	u16 intclr_mask;
-		u16 reserved10;
-	/*2C*/	u16 intset_mask;
-		u16 reserved11;
-
-	/*30*/	u16 sig_status;
-		u16 reserved12;
-	/*34*/	u16 int_status;
-		u16 reserved13;
-	/*38*/	u16 reserved14;
-		u16 reserved15;
-	/*3C*/	u16 reserved16;
-		u16 reserved17;
-
-} BCSR;
-
-static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
-
-/*
- * Register bit definitions for the BCSRs
- */
-#define BCSR_WHOAMI_DCID	0x000F
-#define BCSR_WHOAMI_CPLD	0x00F0
-#define BCSR_WHOAMI_BOARD	0x0F00
-
-#define BCSR_STATUS_PCMCIA0VS	0x0003
-#define BCSR_STATUS_PCMCIA1VS	0x000C
-#define BCSR_STATUS_SWAPBOOT	0x0040
-#define BCSR_STATUS_FLASHBUSY	0x0100
-#define BCSR_STATUS_IDECBLID	0x0200
-#define BCSR_STATUS_SD0WP	0x0400
-#define BCSR_STATUS_SD1WP	0x0800
-#define BCSR_STATUS_U0RXD	0x1000
-#define BCSR_STATUS_U1RXD	0x2000
-
-#define BCSR_SWITCHES_OCTAL	0x00FF
-#define BCSR_SWITCHES_DIP_1	0x0080
-#define BCSR_SWITCHES_DIP_2	0x0040
-#define BCSR_SWITCHES_DIP_3	0x0020
-#define BCSR_SWITCHES_DIP_4	0x0010
-#define BCSR_SWITCHES_DIP_5	0x0008
-#define BCSR_SWITCHES_DIP_6	0x0004
-#define BCSR_SWITCHES_DIP_7	0x0002
-#define BCSR_SWITCHES_DIP_8	0x0001
-#define BCSR_SWITCHES_ROTARY	0x0F00
-
-#define BCSR_RESETS_ETH		0x0001
-#define BCSR_RESETS_CAMERA	0x0002
-#define BCSR_RESETS_DC		0x0004
-#define BCSR_RESETS_IDE		0x0008
-/* not resets but in the same register */
-#define BCSR_RESETS_WSCFSM	0x0800
-#define BCSR_RESETS_PCS0MUX	0x1000
-#define BCSR_RESETS_PCS1MUX	0x2000
-#define BCSR_RESETS_SPISEL	0x4000
-#define BCSR_RESETS_SD1MUX	0x8000
-
-#define BCSR_PCMCIA_PC0VPP	0x0003
-#define BCSR_PCMCIA_PC0VCC	0x000C
-#define BCSR_PCMCIA_PC0DRVEN	0x0010
-#define BCSR_PCMCIA_PC0RST	0x0080
-#define BCSR_PCMCIA_PC1VPP	0x0300
-#define BCSR_PCMCIA_PC1VCC	0x0C00
-#define BCSR_PCMCIA_PC1DRVEN	0x1000
-#define BCSR_PCMCIA_PC1RST	0x8000
-
-#define BCSR_BOARD_LCDVEE	0x0001
-#define BCSR_BOARD_LCDVDD	0x0002
-#define BCSR_BOARD_LCDBL	0x0004
-#define BCSR_BOARD_CAMSNAP	0x0010
-#define BCSR_BOARD_CAMPWR	0x0020
-#define BCSR_BOARD_SD0PWR	0x0040
-#define BCSR_BOARD_SD1PWR	0x0080
-
-#define BCSR_LEDS_DECIMALS	0x00FF
-#define BCSR_LEDS_LED0		0x0100
-#define BCSR_LEDS_LED1		0x0200
-#define BCSR_LEDS_LED2		0x0400
-#define BCSR_LEDS_LED3		0x0800
 
 #define BCSR_SYSTEM_VDDI	0x001F
 #define BCSR_SYSTEM_POWEROFF	0x4000
@@ -251,7 +146,7 @@ enum external_pb1200_ints {
 
 #define BOARD_PC0_INT	PB1200_PC0_INT
 #define BOARD_PC1_INT	PB1200_PC1_INT
-#define BOARD_CARD_INSERTED(SOCKET) bcsr->sig_status & (1 << (8 + (2 * SOCKET)))
+#define BOARD_CARD_INSERTED(SOCKET) (bcsr_read(BCSR_SIGSTAT & (1 << (8 + (2 * SOCKET))))
 
 /* NAND chip select */
 #define NAND_CS 1
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1500.h b/arch/mips/include/asm/mach-pb1x00/pb1500.h
index da51a2e..82431a7 100644
--- a/arch/mips/include/asm/mach-pb1x00/pb1500.h
+++ b/arch/mips/include/asm/mach-pb1x00/pb1500.h
@@ -26,19 +26,6 @@
 #ifndef __ASM_PB1500_H
 #define __ASM_PB1500_H
 
-#define IDENT_BOARD_REG 	0xAE000000
-#define BOARD_STATUS_REG	0xAE000004
-#define PCI_BOARD_REG		0xAE000010
-#define PCMCIA_BOARD_REG	0xAE000010
-#  define PC_DEASSERT_RST	      0x80
-#  define PC_DRV_EN		      0x10
-#define PB1500_G_CONTROL	0xAE000014
-#define PB1500_RST_VDDI 	0xAE00001C
-#define PB1500_LEDS		0xAE000018
-
-#define PB1500_HEX_LED		0xAF000004
-#define PB1500_HEX_LED_BLANK	0xAF000008
-
 /* PCMCIA Pb1500 specific defines */
 #define PCMCIA_MAX_SOCK  0
 #define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1550.h b/arch/mips/include/asm/mach-pb1x00/pb1550.h
index 6704a11..306d584 100644
--- a/arch/mips/include/asm/mach-pb1x00/pb1550.h
+++ b/arch/mips/include/asm/mach-pb1x00/pb1550.h
@@ -40,95 +40,6 @@
 #define SMBUS_PSC_BASE		PSC2_BASE_ADDR
 #define I2S_PSC_BASE		PSC3_BASE_ADDR
 
-#define BCSR_PHYS_ADDR 0xAF000000
-
-typedef volatile struct
-{
-	/*00*/	u16 whoami;
-		u16 reserved0;
-	/*04*/	u16 status;
-		u16 reserved1;
-	/*08*/	u16 switches;
-		u16 reserved2;
-	/*0C*/	u16 resets;
-		u16 reserved3;
-	/*10*/	u16 pcmcia;
-		u16 reserved4;
-	/*14*/	u16 pci;
-		u16 reserved5;
-	/*18*/	u16 leds;
-		u16 reserved6;
-	/*1C*/	u16 system;
-		u16 reserved7;
-
-} BCSR;
-
-static BCSR * const bcsr = (BCSR *)BCSR_PHYS_ADDR;
-
-/*
- * Register bit definitions for the BCSRs
- */
-#define BCSR_WHOAMI_DCID	0x000F
-#define BCSR_WHOAMI_CPLD	0x00F0
-#define BCSR_WHOAMI_BOARD	0x0F00
-
-#define BCSR_STATUS_PCMCIA0VS	0x0003
-#define BCSR_STATUS_PCMCIA1VS	0x000C
-#define BCSR_STATUS_PCMCIA0FI	0x0010
-#define BCSR_STATUS_PCMCIA1FI	0x0020
-#define BCSR_STATUS_SWAPBOOT	0x0040
-#define BCSR_STATUS_SRAMWIDTH	0x0080
-#define BCSR_STATUS_FLASHBUSY	0x0100
-#define BCSR_STATUS_ROMBUSY	0x0200
-#define BCSR_STATUS_USBOTGID	0x0800
-#define BCSR_STATUS_U0RXD	0x1000
-#define BCSR_STATUS_U1RXD	0x2000
-#define BCSR_STATUS_U3RXD	0x8000
-
-#define BCSR_SWITCHES_OCTAL	0x00FF
-#define BCSR_SWITCHES_DIP_1	0x0080
-#define BCSR_SWITCHES_DIP_2	0x0040
-#define BCSR_SWITCHES_DIP_3	0x0020
-#define BCSR_SWITCHES_DIP_4	0x0010
-#define BCSR_SWITCHES_DIP_5	0x0008
-#define BCSR_SWITCHES_DIP_6	0x0004
-#define BCSR_SWITCHES_DIP_7	0x0002
-#define BCSR_SWITCHES_DIP_8	0x0001
-#define BCSR_SWITCHES_ROTARY	0x0F00
-
-#define BCSR_RESETS_PHY0	0x0001
-#define BCSR_RESETS_PHY1	0x0002
-#define BCSR_RESETS_DC		0x0004
-#define BCSR_RESETS_WSC		0x2000
-#define BCSR_RESETS_SPISEL	0x4000
-#define BCSR_RESETS_DMAREQ	0x8000
-
-#define BCSR_PCMCIA_PC0VPP	0x0003
-#define BCSR_PCMCIA_PC0VCC	0x000C
-#define BCSR_PCMCIA_PC0DRVEN	0x0010
-#define BCSR_PCMCIA_PC0RST	0x0080
-#define BCSR_PCMCIA_PC1VPP	0x0300
-#define BCSR_PCMCIA_PC1VCC	0x0C00
-#define BCSR_PCMCIA_PC1DRVEN	0x1000
-#define BCSR_PCMCIA_PC1RST	0x8000
-
-#define BCSR_PCI_M66EN		0x0001
-#define BCSR_PCI_M33		0x0100
-#define BCSR_PCI_EXTERNARB	0x0200
-#define BCSR_PCI_GPIO200RST	0x0400
-#define BCSR_PCI_CLKOUT		0x0800
-#define BCSR_PCI_CFGHOST	0x1000
-
-#define BCSR_LEDS_DECIMALS	0x00FF
-#define BCSR_LEDS_LED0		0x0100
-#define BCSR_LEDS_LED1		0x0200
-#define BCSR_LEDS_LED2		0x0400
-#define BCSR_LEDS_LED3		0x0800
-
-#define BCSR_SYSTEM_VDDI	0x001F
-#define BCSR_SYSTEM_POWEROFF	0x4000
-#define BCSR_SYSTEM_RESET	0x8000
-
 #define PCMCIA_MAX_SOCK  1
 #define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
 
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
index 92c334f..43d46e4 100644
--- a/drivers/mtd/nand/au1550nd.c
+++ b/drivers/mtd/nand/au1550nd.c
@@ -19,6 +19,7 @@
 #include <asm/io.h>
 
 #include <asm/mach-au1x00/au1xxx.h>
+#include <asm/mach-db1x00/bcsr.h>
 
 /*
  * MTD structure for NAND controller
@@ -475,7 +476,8 @@ static int __init au1xxx_nand_init(void)
 	/* set gpio206 high */
 	au_writel(au_readl(GPIO2_DIR) & ~(1 << 6), GPIO2_DIR);
 
-	boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) | ((bcsr->status >> 6) & 0x1);
+	boot_swapboot = (au_readl(MEM_STSTAT) & (0x7 << 1)) | ((bcsr_read(BCSR_STATUS) >> 6) & 0x1);
+
 	switch (boot_swapboot) {
 	case 0:
 	case 2:
diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
index eb42468..955f04e 100644
--- a/drivers/net/irda/au1k_ir.c
+++ b/drivers/net/irda/au1k_ir.c
@@ -36,6 +36,7 @@
 #include <asm/pb1000.h>
 #elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
 #include <asm/db1x00.h>
+#include <asm/mach-db1x00/bcsr.h>
 #else 
 #error au1k_ir: unsupported board
 #endif
@@ -66,10 +67,6 @@ static char version[] __devinitdata =
 
 #define RUN_AT(x) (jiffies + (x))
 
-#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
-static BCSR * const bcsr = (BCSR *)0xAE000000;
-#endif
-
 static DEFINE_SPINLOCK(ir_lock);
 
 /*
@@ -282,9 +279,8 @@ static int au1k_irda_net_init(struct net_device *dev)
 
 #if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
 	/* power on */
-	bcsr->resets &= ~BCSR_RESETS_IRDA_MODE_MASK;
-	bcsr->resets |= BCSR_RESETS_IRDA_MODE_FULL;
-	au_sync();
+	bcsr_mod(BCSR_RESETS, BCSR_RESETS_IRDA_MODE_MASK,
+			      BCSR_RESETS_IRDA_MODE_FULL);
 #endif
 
 	return 0;
@@ -720,14 +716,14 @@ au1k_irda_set_speed(struct net_device *dev, int speed)
 
 	if (speed == 4000000) {
 #if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
-		bcsr->resets |= BCSR_RESETS_FIR_SEL;
+		bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_FIR_SEL);
 #else /* Pb1000 and Pb1100 */
 		writel(1<<13, CPLD_AUX1);
 #endif
 	}
 	else {
 #if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100)
-		bcsr->resets &= ~BCSR_RESETS_FIR_SEL;
+		bcsr_mod(BCSR_RESETS, BCSR_RESETS_FIR_SEL, 0);
 #else /* Pb1000 and Pb1100 */
 		writel(readl(CPLD_AUX1) & ~(1<<13), CPLD_AUX1);
 #endif
diff --git a/drivers/pcmcia/au1000_db1x00.c b/drivers/pcmcia/au1000_db1x00.c
index c78d77f..3fdd664 100644
--- a/drivers/pcmcia/au1000_db1x00.c
+++ b/drivers/pcmcia/au1000_db1x00.c
@@ -47,9 +47,9 @@
 	#include <pb1200.h>
 #else
 	#include <asm/mach-db1x00/db1x00.h>
-	static BCSR * const bcsr = (BCSR *)BCSR_KSEG1_ADDR;
 #endif
 
+#include <asm/mach-db1x00/bcsr.h>
 #include "au1000_generic.h"
 
 #if 0
@@ -76,8 +76,8 @@ static int db1x00_pcmcia_hw_init(struct au1000_pcmcia_socket *skt)
 
 static void db1x00_pcmcia_shutdown(struct au1000_pcmcia_socket *skt)
 {
-	bcsr->pcmcia = 0; /* turn off power */
-	au_sync_delay(2);
+	bcsr_write(BCSR_PCMCIA, 0);	/* turn off power */
+	msleep(2);
 }
 
 static void
@@ -93,19 +93,19 @@ db1x00_pcmcia_socket_state(struct au1000_pcmcia_socket *skt, struct pcmcia_state
 
 	switch (skt->nr) {
 	case 0:
-		vs = bcsr->status & 0x3;
+		vs = bcsr_read(BCSR_STATUS) & 0x3;
 #if defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200)
 		inserted = BOARD_CARD_INSERTED(0);
 #else
-		inserted = !(bcsr->status & (1<<4));
+		inserted = !(bcsr_read(BCSR_STATUS) & (1 << 4));
 #endif
 		break;
 	case 1:
-		vs = (bcsr->status & 0xC)>>2;
+		vs = (bcsr_read(BCSR_STATUS) & 0xC) >> 2;
 #if defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200)
 		inserted = BOARD_CARD_INSERTED(1);
 #else
-		inserted = !(bcsr->status & (1<<5));
+		inserted = !(bcsr_read(BCSR_STATUS) & (1<<5));
 #endif
 		break;
 	default:/* should never happen */
@@ -114,7 +114,7 @@ db1x00_pcmcia_socket_state(struct au1000_pcmcia_socket *skt, struct pcmcia_state
 
 	if (inserted)
 		debug("db1x00 socket %d: inserted %d, vs %d pcmcia %x\n",
-				skt->nr, inserted, vs, bcsr->pcmcia);
+				skt->nr, inserted, vs, bcsr_read(BCSR_PCMCIA));
 
 	if (inserted) {
 		switch (vs) {
@@ -136,19 +136,21 @@ db1x00_pcmcia_socket_state(struct au1000_pcmcia_socket *skt, struct pcmcia_state
 		/* if the card was previously inserted and then ejected,
 		 * we should turn off power to it
 		 */
-		if ((skt->nr == 0) && (bcsr->pcmcia & BCSR_PCMCIA_PC0RST)) {
-			bcsr->pcmcia &= ~(BCSR_PCMCIA_PC0RST |
-					BCSR_PCMCIA_PC0DRVEN |
-					BCSR_PCMCIA_PC0VPP |
-					BCSR_PCMCIA_PC0VCC);
-			au_sync_delay(10);
+		if ((skt->nr == 0) &&
+		    (bcsr_read(BCSR_PCMCIA) & BCSR_PCMCIA_PC0RST)) {
+			bcsr_mod(BCSR_PCMCIA, BCSR_PCMCIA_PC0RST   |
+					      BCSR_PCMCIA_PC0DRVEN |
+					      BCSR_PCMCIA_PC0VPP   |
+					      BCSR_PCMCIA_PC0VCC, 0);
+			msleep(10);
 		}
-		else if ((skt->nr == 1) && bcsr->pcmcia & BCSR_PCMCIA_PC1RST) {
-			bcsr->pcmcia &= ~(BCSR_PCMCIA_PC1RST |
-					BCSR_PCMCIA_PC1DRVEN |
-					BCSR_PCMCIA_PC1VPP |
-					BCSR_PCMCIA_PC1VCC);
-			au_sync_delay(10);
+		else if ((skt->nr == 1) &&
+			 (bcsr_read(BCSR_PCMCIA) & BCSR_PCMCIA_PC1RST)) {
+			bcsr_mod(BCSR_PCMCIA, BCSR_PCMCIA_PC1RST   |
+					      BCSR_PCMCIA_PC1DRVEN |
+					      BCSR_PCMCIA_PC1VPP   |
+					      BCSR_PCMCIA_PC1VCC, 0);
+			msleep(10);
 		}
 	}
 
@@ -171,7 +173,7 @@ db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_s
 	 * initializing a socket not to wipe out the settings of the
 	 * other socket.
 	 */
-	pwr = bcsr->pcmcia;
+	pwr = bcsr_read(BCSR_PCMCIA);
 	pwr &= ~(0xf << sock*8); /* clear voltage settings */
 
 	state->Vpp = 0;
@@ -228,37 +230,37 @@ db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_s
 			break;
 	}
 
-	bcsr->pcmcia = pwr;
-	au_sync_delay(300);
+	bcsr_write(BCSR_PCMCIA, pwr);
+	msleep(300);
 
 	if (sock == 0) {
 		if (!(state->flags & SS_RESET)) {
 			pwr |= BCSR_PCMCIA_PC0DRVEN;
-			bcsr->pcmcia = pwr;
-			au_sync_delay(300);
+			bcsr_write(BCSR_PCMCIA, pwr);
+			msleep(300);
 			pwr |= BCSR_PCMCIA_PC0RST;
-			bcsr->pcmcia = pwr;
-			au_sync_delay(100);
+			bcsr_write(BCSR_PCMCIA, pwr);
+			msleep(100);
 		}
 		else {
 			pwr &= ~(BCSR_PCMCIA_PC0RST | BCSR_PCMCIA_PC0DRVEN);
-			bcsr->pcmcia = pwr;
-			au_sync_delay(100);
+			bcsr_write(BCSR_PCMCIA, pwr);
+			msleep(100);
 		}
 	}
 	else {
 		if (!(state->flags & SS_RESET)) {
 			pwr |= BCSR_PCMCIA_PC1DRVEN;
-			bcsr->pcmcia = pwr;
-			au_sync_delay(300);
+			bcsr_write(BCSR_PCMCIA, pwr);
+			msleep(300);
 			pwr |= BCSR_PCMCIA_PC1RST;
-			bcsr->pcmcia = pwr;
-			au_sync_delay(100);
+			bcsr_write(BCSR_PCMCIA, pwr);
+			msleep(100);
 		}
 		else {
 			pwr &= ~(BCSR_PCMCIA_PC1RST | BCSR_PCMCIA_PC1DRVEN);
-			bcsr->pcmcia = pwr;
-			au_sync_delay(100);
+			bcsr_write(BCSR_PCMCIA, pwr);
+			msleep(100);
 		}
 	}
 	return 0;
@@ -298,8 +300,8 @@ struct pcmcia_low_level db1x00_pcmcia_ops = {
 int au1x_board_init(struct device *dev)
 {
 	int ret = -ENODEV;
-	bcsr->pcmcia = 0; /* turn off power, if it's not already off */
-	au_sync_delay(2);
+	bcsr_write(BCSR_PCMCIA, 0); /* turn off power, if it's not already off */
+	msleep(2);
 	ret = au1x00_pcmcia_socket_probe(dev, &db1x00_pcmcia_ops, 0, 2);
 	return ret;
 }
-- 
1.6.5.rc2


From manuel.lauss@googlemail.com Sun Oct  4 14:55:58 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Sun, 04 Oct 2009 14:56:06 +0200 (CEST)
Received: from mail-ew0-f214.google.com ([209.85.219.214]:46395 "EHLO
	mail-ew0-f214.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492490AbZJDMzj (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sun, 4 Oct 2009 14:55:39 +0200
Received: by ewy10 with SMTP id 10so1846480ewy.33
        for <multiple recipients>; Sun, 04 Oct 2009 05:55:31 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer;
        bh=qof7ZKcCo269st5oJasbZZulS7I4jV3DUapHhYkl+MM=;
        b=MZ/j09xEelQ2EieVtFD9c8cpF3T8CDRH5gTODIif/1JyEFvJXEIc9MSFeYSavl3j52
         LTizI2yW/pHE47XFX9d10v93UrCahtS1RB/mrSNBset40t7IpLEPGIt34aI9iK/ff3k8
         grQx4NepKt9sCSmBSaY3OsMK4z04GC0BO/9Fg=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer;
        b=EPakUMX5jr9N/UgW6F4QIyICCGo+YNnFel/RqwlHgYc31Rw1Qn17+Vv2oqnWnYX/Si
         AGnASvJ31zn+CT2yIsg/nYOFAawC6AWURbMaPLW4f2iQk2nTbSY8xqfsROXyv0QB//Sn
         rHBlsG5dzCEKedb4Q7+bpKgf2MSPHSoSOJ8FI=
Received: by 10.211.143.13 with SMTP id v13mr5772854ebn.21.1254660930991;
        Sun, 04 Oct 2009 05:55:30 -0700 (PDT)
Received: from localhost.localdomain (fnoeppeil48.netpark.at [217.175.205.176])
        by mx.google.com with ESMTPS id 28sm1555483eyg.4.2009.10.04.05.55.29
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Sun, 04 Oct 2009 05:55:29 -0700 (PDT)
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Linux-MIPS <linux-mips@linux-mips.org>,
	Ralf Baechle <ralf@linux-mips.org>
Cc:	Manuel Lauss <manuel.lauss@gmail.com>
Subject: [PATCH V2 0/6] Alchemy: devboard and platform updates
Date:	Sun,  4 Oct 2009 14:55:23 +0200
Message-Id: <1254660929-15453-1-git-send-email-manuel.lauss@gmail.com>
X-Mailer: git-send-email 1.6.5.rc2
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24138
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

This is a V2 of the series formerly sent as "BCSR abstraction
and new PCMCIA socket driver".

Changes V1->V2:
- split the pcmcia socket driver patch in a driver-patch and
  board-support patch (#4 / #5);
- fixed typos in #1
- added new patch #3
- added #6 to the series, since it depends on #4 to compile.


#1 adds basic devboard register ("BCSR" space) API and converts
   all "bcsr->" invocations to use the new API.
   The API is slower than direct access but adds locking to register
   modify operations, which patch #3 can take advantage of.
#2 generalizes PB1200's CPLD IRQ controller code; DB1300 can use it
   too.
#3 gets rid of the "board_init_irq" callback in the boards: On all
   currently supported boards it's sufficient to initialize
   GPIO-based interrupts in an arch_initcall through use of standard
   irq functions.

#4 replaces the current devboard PCMCIA socket code.  See patch for
   more details.   While it doesn't really belong to this series
   per-se, it does make use of the functions introduced by #1.
#5 wire up the new pcmcia driver
#6 new pcmcia socket driver for XXS1500 systems (compiled only).


As always, run-tested on the DB1200 where possible;  although testers
for all other boards would be very much appreciated!

Patches 1-3 are more-or-less MIPS-specific, I'd like for them
to get applied while 4-6 await feedback from pcmcia list.


Thanks,
	Manuel Lauss


Manuel Lauss (6):
  Alchemy: devboard register abstraction
  Alchemy: devboards: factor out PB1200 IRQ cascade code.
  Alchemy: remove board_init_irq() function.
  PCMCIA: new socket driver for Au1000 demoboards.
  Alchemy: devboards: wire up new PCMCIA driver.
  Alchemy: XXS1500 PCMCIA driver rewrite

 arch/mips/alchemy/common/irq.c                   |   15 +-
 arch/mips/alchemy/common/platform.c              |    6 -
 arch/mips/alchemy/common/setup.c                 |    3 +-
 arch/mips/alchemy/devboards/Makefile             |    2 +-
 arch/mips/alchemy/devboards/bcsr.c               |  148 +++++
 arch/mips/alchemy/devboards/db1x00/Makefile      |    2 +-
 arch/mips/alchemy/devboards/db1x00/board_setup.c |  109 +++-
 arch/mips/alchemy/devboards/db1x00/irqmap.c      |   90 ---
 arch/mips/alchemy/devboards/db1x00/platform.c    |   84 +++
 arch/mips/alchemy/devboards/pb1000/board_setup.c |   17 +-
 arch/mips/alchemy/devboards/pb1100/Makefile      |    3 +-
 arch/mips/alchemy/devboards/pb1100/board_setup.c |   31 +-
 arch/mips/alchemy/devboards/pb1100/platform.c    |   41 ++
 arch/mips/alchemy/devboards/pb1200/Makefile      |    2 +-
 arch/mips/alchemy/devboards/pb1200/board_setup.c |   91 +++-
 arch/mips/alchemy/devboards/pb1200/irqmap.c      |  134 -----
 arch/mips/alchemy/devboards/pb1200/platform.c    |   80 +++-
 arch/mips/alchemy/devboards/pb1500/Makefile      |    3 +-
 arch/mips/alchemy/devboards/pb1500/board_setup.c |   35 +-
 arch/mips/alchemy/devboards/pb1500/platform.c    |   41 ++
 arch/mips/alchemy/devboards/pb1550/Makefile      |    3 +-
 arch/mips/alchemy/devboards/pb1550/board_setup.c |   38 +-
 arch/mips/alchemy/devboards/pb1550/platform.c    |   63 +++
 arch/mips/alchemy/devboards/platform.c           |   89 +++
 arch/mips/alchemy/devboards/platform.h           |   18 +
 arch/mips/alchemy/mtx-1/Makefile                 |    2 +-
 arch/mips/alchemy/mtx-1/board_setup.c            |   24 +
 arch/mips/alchemy/mtx-1/irqmap.c                 |   56 --
 arch/mips/alchemy/xxs1500/Makefile               |    2 +-
 arch/mips/alchemy/xxs1500/board_setup.c          |   37 +-
 arch/mips/alchemy/xxs1500/irqmap.c               |   52 --
 arch/mips/alchemy/xxs1500/platform.c             |   63 +++
 arch/mips/include/asm/mach-au1x00/au1000.h       |   29 +-
 arch/mips/include/asm/mach-db1x00/bcsr.h         |  238 ++++++++
 arch/mips/include/asm/mach-db1x00/db1200.h       |  123 +-----
 arch/mips/include/asm/mach-db1x00/db1x00.h       |  100 ----
 arch/mips/include/asm/mach-pb1x00/pb1100.h       |   85 ---
 arch/mips/include/asm/mach-pb1x00/pb1200.h       |  122 +----
 arch/mips/include/asm/mach-pb1x00/pb1500.h       |   49 --
 arch/mips/include/asm/mach-pb1x00/pb1550.h       |   96 ----
 drivers/mtd/nand/au1550nd.c                      |    4 +-
 drivers/net/irda/au1k_ir.c                       |   14 +-
 drivers/pcmcia/Kconfig                           |   21 +
 drivers/pcmcia/Makefile                          |   12 +-
 drivers/pcmcia/au1000_db1x00.c                   |  305 -----------
 drivers/pcmcia/au1000_generic.h                  |   12 +-
 drivers/pcmcia/au1000_pb1x00.c                   |  119 +----
 drivers/pcmcia/au1000_xxs1500.c                  |  188 -------
 drivers/pcmcia/db1xxx_ss.c                       |  630 ++++++++++++++++++++++
 drivers/pcmcia/xxs1500_ss.c                      |  357 ++++++++++++
 50 files changed, 2172 insertions(+), 1716 deletions(-)
 create mode 100644 arch/mips/alchemy/devboards/bcsr.c
 delete mode 100644 arch/mips/alchemy/devboards/db1x00/irqmap.c
 create mode 100644 arch/mips/alchemy/devboards/db1x00/platform.c
 create mode 100644 arch/mips/alchemy/devboards/pb1100/platform.c
 delete mode 100644 arch/mips/alchemy/devboards/pb1200/irqmap.c
 create mode 100644 arch/mips/alchemy/devboards/pb1500/platform.c
 create mode 100644 arch/mips/alchemy/devboards/pb1550/platform.c
 create mode 100644 arch/mips/alchemy/devboards/platform.c
 create mode 100644 arch/mips/alchemy/devboards/platform.h
 delete mode 100644 arch/mips/alchemy/mtx-1/irqmap.c
 delete mode 100644 arch/mips/alchemy/xxs1500/irqmap.c
 create mode 100644 arch/mips/alchemy/xxs1500/platform.c
 create mode 100644 arch/mips/include/asm/mach-db1x00/bcsr.h
 delete mode 100644 arch/mips/include/asm/mach-pb1x00/pb1100.h
 delete mode 100644 arch/mips/include/asm/mach-pb1x00/pb1500.h
 delete mode 100644 drivers/pcmcia/au1000_db1x00.c
 delete mode 100644 drivers/pcmcia/au1000_xxs1500.c
 create mode 100644 drivers/pcmcia/db1xxx_ss.c
 create mode 100644 drivers/pcmcia/xxs1500_ss.c


From manuel.lauss@googlemail.com Sun Oct  4 14:56:24 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Sun, 04 Oct 2009 14:56:31 +0200 (CEST)
Received: from mail-ew0-f214.google.com ([209.85.219.214]:56394 "EHLO
	mail-ew0-f214.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492520AbZJDMzm (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sun, 4 Oct 2009 14:55:42 +0200
Received: by ewy10 with SMTP id 10so1846499ewy.33
        for <multiple recipients>; Sun, 04 Oct 2009 05:55:36 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer:in-reply-to:references;
        bh=7xC9w/aAgGCPR6VM7NOWxsIOoAGs+zMHApqop76glMs=;
        b=SNYUCd9y+tuEEEWDPbgcoyb6kqK94PQCqBcGei964SuxBsZ7sYuKntOcQshG/TSnzK
         BANfNeMKcdDN1kOlqroFV3okbSV4h9cMnhZijlfCVh1a3LYk/fTDkcblPMIfcA1aHHNd
         n1VmwzL7KksWJSb8uzIrEIlR3rxqIKRxiJNQk=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        b=upLUgM8q9gKOY/tXxhL4/JK4WvojmQjmCRth5UhynOi4/pnB6X4EvIOoDs6fMA68MD
         G8JQwjPyon1sLLaQX7x69dm+xtdoA2BGwaNSPWosfxoek84fl0XvkeedUpBEuPjB9H8z
         Uz5V4cuvfVtecSG6Ugqnm7ChN9iTc/JDE6Sik=
Received: by 10.211.155.16 with SMTP id h16mr5733380ebo.55.1254660933446;
        Sun, 04 Oct 2009 05:55:33 -0700 (PDT)
Received: from localhost.localdomain (fnoeppeil48.netpark.at [217.175.205.176])
        by mx.google.com with ESMTPS id 28sm1555483eyg.4.2009.10.04.05.55.32
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Sun, 04 Oct 2009 05:55:32 -0700 (PDT)
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Linux-MIPS <linux-mips@linux-mips.org>,
	Ralf Baechle <ralf@linux-mips.org>
Cc:	Manuel Lauss <manuel.lauss@gmail.com>
Subject: [PATCH 2/6] Alchemy: devboards: factor out PB1200 IRQ cascade code.
Date:	Sun,  4 Oct 2009 14:55:25 +0200
Message-Id: <1254660929-15453-3-git-send-email-manuel.lauss@gmail.com>
X-Mailer: git-send-email 1.6.5.rc2
In-Reply-To: <1254660929-15453-2-git-send-email-manuel.lauss@gmail.com>
References: <1254660929-15453-1-git-send-email-manuel.lauss@gmail.com>
 <1254660929-15453-2-git-send-email-manuel.lauss@gmail.com>
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24139
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

Move the PB1200 IRQ cascade code out to the BCSR support code:
upcoming DB1300 support can use it too.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 arch/mips/alchemy/devboards/bcsr.c          |   72 +++++++++++++++++++++++++++
 arch/mips/alchemy/devboards/pb1200/irqmap.c |   71 +--------------------------
 arch/mips/include/asm/mach-db1x00/bcsr.h    |    3 +
 3 files changed, 76 insertions(+), 70 deletions(-)

diff --git a/arch/mips/alchemy/devboards/bcsr.c b/arch/mips/alchemy/devboards/bcsr.c
index 85b7715..3bc4fd2 100644
--- a/arch/mips/alchemy/devboards/bcsr.c
+++ b/arch/mips/alchemy/devboards/bcsr.c
@@ -7,6 +7,7 @@
  * All registers are 16bits wide with 32bit spacing.
  */
 
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <asm/addrspace.h>
@@ -18,6 +19,9 @@ static struct bcsr_reg {
 	spinlock_t lock;
 } bcsr_regs[BCSR_CNT];
 
+static void __iomem *bcsr_virt;	/* KSEG1 addr of BCSR base */
+static int bcsr_csc_base;	/* linux-irq of first cascaded irq */
+
 void __init bcsr_init(unsigned long bcsr1_phys, unsigned long bcsr2_phys)
 {
 	int i;
@@ -25,6 +29,8 @@ void __init bcsr_init(unsigned long bcsr1_phys, unsigned long bcsr2_phys)
 	bcsr1_phys = KSEG1ADDR(CPHYSADDR(bcsr1_phys));
 	bcsr2_phys = KSEG1ADDR(CPHYSADDR(bcsr2_phys));
 
+	bcsr_virt = (void __iomem *)bcsr1_phys;
+
 	for (i = 0; i < BCSR_CNT; i++) {
 		if (i >= BCSR_HEXLEDS)
 			bcsr_regs[i].raddr = (void __iomem *)bcsr2_phys +
@@ -74,3 +80,69 @@ void bcsr_mod(enum bcsr_id reg, unsigned short clr, unsigned short set)
 	spin_unlock_irqrestore(&bcsr_regs[reg].lock, flags);
 }
 EXPORT_SYMBOL_GPL(bcsr_mod);
+
+/*
+ * DB1200/PB1200 CPLD IRQ muxer
+ */
+static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d)
+{
+	unsigned short bisr = __raw_readw(bcsr_virt + BCSR_REG_INTSTAT);
+
+	for ( ; bisr; bisr &= bisr - 1)
+		generic_handle_irq(bcsr_csc_base + __ffs(bisr));
+}
+
+/* NOTE: both the enable and mask bits must be cleared, otherwise the
+ * CPLD generates tons of spurious interrupts (at least on my DB1200).
+ *	-- mlau
+ */
+static void bcsr_irq_mask(unsigned int irq_nr)
+{
+	unsigned short v = 1 << (irq_nr - bcsr_csc_base);
+	__raw_writew(v, bcsr_virt + BCSR_REG_INTCLR);
+	__raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
+	wmb();
+}
+
+static void bcsr_irq_maskack(unsigned int irq_nr)
+{
+	unsigned short v = 1 << (irq_nr - bcsr_csc_base);
+	__raw_writew(v, bcsr_virt + BCSR_REG_INTCLR);
+	__raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
+	__raw_writew(v, bcsr_virt + BCSR_REG_INTSTAT);	/* ack */
+	wmb();
+}
+
+static void bcsr_irq_unmask(unsigned int irq_nr)
+{
+	unsigned short v = 1 << (irq_nr - bcsr_csc_base);
+	__raw_writew(v, bcsr_virt + BCSR_REG_INTSET);
+	__raw_writew(v, bcsr_virt + BCSR_REG_MASKSET);
+	wmb();
+}
+
+static struct irq_chip bcsr_irq_type = {
+	.name		= "CPLD",
+	.mask		= bcsr_irq_mask,
+	.mask_ack	= bcsr_irq_maskack,
+	.unmask		= bcsr_irq_unmask,
+};
+
+void __init bcsr_init_irq(int csc_start, int csc_end, int hook_irq)
+{
+	unsigned int irq;
+
+	/* mask & disable & ack all */
+	__raw_writew(0xffff, bcsr_virt + BCSR_REG_INTCLR);
+	__raw_writew(0xffff, bcsr_virt + BCSR_REG_MASKCLR);
+	__raw_writew(0xffff, bcsr_virt + BCSR_REG_INTSTAT);
+	wmb();
+
+	bcsr_csc_base = csc_start;
+
+	for (irq = csc_start; irq <= csc_end; irq++)
+		set_irq_chip_and_handler_name(irq, &bcsr_irq_type,
+			handle_level_irq, "level");
+
+	set_irq_chained_handler(hook_irq, bcsr_csc_handler);
+}
diff --git a/arch/mips/alchemy/devboards/pb1200/irqmap.c b/arch/mips/alchemy/devboards/pb1200/irqmap.c
index f379b02..3beb804 100644
--- a/arch/mips/alchemy/devboards/pb1200/irqmap.c
+++ b/arch/mips/alchemy/devboards/pb1200/irqmap.c
@@ -45,69 +45,11 @@ struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
 	{ AU1000_GPIO_7, IRQF_TRIGGER_LOW, 0 },
 };
 
-static void __iomem *bcsr_virt;
-
-/*
- * Support for External interrupts on the Pb1200 Development platform.
- */
-
-static void pb1200_cascade_handler(unsigned int irq, struct irq_desc *d)
-{
-	unsigned short bisr = __raw_readw(bcsr_virt + BCSR_REG_INTSTAT);
-
-	for ( ; bisr; bisr &= bisr - 1)
-		generic_handle_irq(PB1200_INT_BEGIN + __ffs(bisr));
-}
-
-/* NOTE: both the enable and mask bits must be cleared, otherwise the
- * CPLD generates tons of spurious interrupts (at least on the DB1200).
- */
-static void pb1200_mask_irq(unsigned int irq_nr)
-{
-	unsigned short v = 1 << (irq_nr - PB1200_INT_BEGIN);
-	__raw_writew(v, bcsr_virt + BCSR_REG_INTCLR);
-	__raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
-	wmb();
-}
-
-static void pb1200_maskack_irq(unsigned int irq_nr)
-{
-	unsigned short v = 1 << (irq_nr - PB1200_INT_BEGIN);
-	__raw_writew(v, bcsr_virt + BCSR_REG_INTCLR);
-	__raw_writew(v, bcsr_virt + BCSR_REG_MASKCLR);
-	__raw_writew(v, bcsr_virt + BCSR_REG_INTSTAT);	/* ack */
-	wmb();
-}
-
-static void pb1200_unmask_irq(unsigned int irq_nr)
-{
-	unsigned short v = 1 << (irq_nr - PB1200_INT_BEGIN);
-	__raw_writew(v, bcsr_virt + BCSR_REG_INTSET);
-	__raw_writew(v, bcsr_virt + BCSR_REG_MASKSET);
-	wmb();
-}
-
-static struct irq_chip pb1200_cpld_irq_type = {
-#ifdef CONFIG_MIPS_PB1200
-	.name = "Pb1200 Ext",
-#endif
-#ifdef CONFIG_MIPS_DB1200
-	.name = "Db1200 Ext",
-#endif
-	.mask		= pb1200_mask_irq,
-	.mask_ack	= pb1200_maskack_irq,
-	.unmask		= pb1200_unmask_irq,
-};
-
 void __init board_init_irq(void)
 {
-	unsigned int irq;
-
 	au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
 
 #ifdef CONFIG_MIPS_PB1200
-	bcsr_virt = (void __iomem *)KSEG1ADDR(PB1200_BCSR_PHYS_ADDR);
-
 	/* We have a problem with CPLD rev 3. */
 	if (BCSR_WHOAMI_CPLD(bcsr_read(BCSR_WHOAMI)) <= 3) {
 		printk(KERN_ERR "WARNING!!!\n");
@@ -127,18 +69,7 @@ void __init board_init_irq(void)
 		printk(KERN_ERR "WARNING!!!\n");
 		panic("Game over.  Your score is 0.");
 	}
-#else
-	bcsr_virt = (void __iomem *)KSEG1ADDR(DB1200_BCSR_PHYS_ADDR);
 #endif
 
-	/* mask & disable & ack all */
-	bcsr_write(BCSR_INTCLR, 0xffff);
-	bcsr_write(BCSR_MASKCLR, 0xffff);
-	bcsr_write(BCSR_INTSTAT, 0xffff);
-
-	for (irq = PB1200_INT_BEGIN; irq <= PB1200_INT_END; irq++)
-		set_irq_chip_and_handler_name(irq, &pb1200_cpld_irq_type,
-					 handle_level_irq, "level");
-
-	set_irq_chained_handler(AU1000_GPIO_7, pb1200_cascade_handler);
+	bcsr_init_irq(PB1200_INT_BEGIN, PB1200_INT_END, AU1000_GPIO_7);
 }
diff --git a/arch/mips/include/asm/mach-db1x00/bcsr.h b/arch/mips/include/asm/mach-db1x00/bcsr.h
index ecbe19e..618d2de 100644
--- a/arch/mips/include/asm/mach-db1x00/bcsr.h
+++ b/arch/mips/include/asm/mach-db1x00/bcsr.h
@@ -232,4 +232,7 @@ void bcsr_write(enum bcsr_id reg, unsigned short val);
 /* modify a register. clear bits set in 'clr', set bits set in 'set' */
 void bcsr_mod(enum bcsr_id reg, unsigned short clr, unsigned short set);
 
+/* install CPLD IRQ demuxer (DB1200/PB1200) */
+void __init bcsr_init_irq(int csc_start, int csc_end, int hook_irq);
+
 #endif
-- 
1.6.5.rc2


From manuel.lauss@googlemail.com Sun Oct  4 14:56:49 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Sun, 04 Oct 2009 14:56:55 +0200 (CEST)
Received: from mail-ew0-f214.google.com ([209.85.219.214]:32847 "EHLO
	mail-ew0-f214.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492532AbZJDMzm (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sun, 4 Oct 2009 14:55:42 +0200
Received: by ewy10 with SMTP id 10so1846514ewy.33
        for <multiple recipients>; Sun, 04 Oct 2009 05:55:36 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer:in-reply-to:references;
        bh=XCYdh6qUXRgLHwtQAlsJk/gSJOvnMa5shBNZXqxbGiY=;
        b=L4eATt808HACarV7tD7LjMdn5MSsOHfp/ZiQec2r6Q9hADgBQnKtsksjiiIghVJk25
         CssIqnjy3TZTzd60uy5qpWnR+8BbNmV2WHXPxlll1whXN6EzwhqXsshLjV9jD+m8UXOB
         FRqQbkVCEZaJxbMITzOapl7IwqMAsqPgy6YYc=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        b=pzrQPk3mmVvcSBtDyAvu9k0sxUQjSYDmU4zYWpvLlWpLWXc5oz7mEZwvEysTrxFcZd
         oe3Ce2+A9UYYHmUuealQQrGQ7UUuUi0rvIWwfhh0pWFeI2A0ptcu97r3rnKQci9Exsdi
         A0u1WpDu0DDBh/jnzbtD6TPyPkYvo94Mc4A54=
Received: by 10.210.6.8 with SMTP id 8mr3840855ebf.80.1254660934428;
        Sun, 04 Oct 2009 05:55:34 -0700 (PDT)
Received: from localhost.localdomain (fnoeppeil48.netpark.at [217.175.205.176])
        by mx.google.com with ESMTPS id 28sm1555483eyg.4.2009.10.04.05.55.33
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Sun, 04 Oct 2009 05:55:33 -0700 (PDT)
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Linux-MIPS <linux-mips@linux-mips.org>,
	Ralf Baechle <ralf@linux-mips.org>
Cc:	Manuel Lauss <manuel.lauss@gmail.com>
Subject: [PATCH 3/6] Alchemy: remove board_init_irq() function.
Date:	Sun,  4 Oct 2009 14:55:26 +0200
Message-Id: <1254660929-15453-4-git-send-email-manuel.lauss@gmail.com>
X-Mailer: git-send-email 1.6.5.rc2
In-Reply-To: <1254660929-15453-3-git-send-email-manuel.lauss@gmail.com>
References: <1254660929-15453-1-git-send-email-manuel.lauss@gmail.com>
 <1254660929-15453-2-git-send-email-manuel.lauss@gmail.com>
 <1254660929-15453-3-git-send-email-manuel.lauss@gmail.com>
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24140
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

remove board_init_irq():  On all in-kernel boards it is sufficient to
initialize board interrupts in an arch_initcall by using the default
linux irq functions.

Some small irqmap.c files have been folded into board_setup files.

Run-tested on DB1200; compile-tested on all other affected boards.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 arch/mips/alchemy/common/irq.c                   |   15 ++--
 arch/mips/alchemy/devboards/db1x00/Makefile      |    2 +-
 arch/mips/alchemy/devboards/db1x00/board_setup.c |   51 ++++++++++++
 arch/mips/alchemy/devboards/db1x00/irqmap.c      |   90 ----------------------
 arch/mips/alchemy/devboards/pb1000/board_setup.c |   17 ++---
 arch/mips/alchemy/devboards/pb1100/board_setup.c |   24 +++---
 arch/mips/alchemy/devboards/pb1200/Makefile      |    2 +-
 arch/mips/alchemy/devboards/pb1200/board_setup.c |   48 +++++++++++-
 arch/mips/alchemy/devboards/pb1200/irqmap.c      |   75 ------------------
 arch/mips/alchemy/devboards/pb1500/board_setup.c |   25 +++---
 arch/mips/alchemy/devboards/pb1550/board_setup.c |   19 ++---
 arch/mips/alchemy/mtx-1/Makefile                 |    2 +-
 arch/mips/alchemy/mtx-1/board_setup.c            |   24 ++++++
 arch/mips/alchemy/mtx-1/irqmap.c                 |   56 -------------
 arch/mips/alchemy/xxs1500/Makefile               |    2 +-
 arch/mips/alchemy/xxs1500/board_setup.c          |   21 +++++
 arch/mips/alchemy/xxs1500/irqmap.c               |   52 -------------
 arch/mips/include/asm/mach-au1x00/au1000.h       |   15 ----
 arch/mips/include/asm/mach-db1x00/db1200.h       |    1 +
 arch/mips/include/asm/mach-pb1x00/pb1200.h       |    1 +
 20 files changed, 194 insertions(+), 348 deletions(-)
 delete mode 100644 arch/mips/alchemy/devboards/db1x00/irqmap.c
 delete mode 100644 arch/mips/alchemy/devboards/pb1200/irqmap.c
 delete mode 100644 arch/mips/alchemy/mtx-1/irqmap.c
 delete mode 100644 arch/mips/alchemy/xxs1500/irqmap.c

diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c
index c88c821..cd264b1 100644
--- a/arch/mips/alchemy/common/irq.c
+++ b/arch/mips/alchemy/common/irq.c
@@ -40,8 +40,11 @@
 static int au1x_ic_settype(unsigned int irq, unsigned int flow_type);
 
 /* per-processor fixed function irqs */
-struct au1xxx_irqmap au1xxx_ic0_map[] __initdata = {
-
+struct au1xxx_irqmap {
+	int im_irq;
+	int im_type;
+	int im_request;
+} au1xxx_ic0_map[] __initdata = {
 #if defined(CONFIG_SOC_AU1000)
 	{ AU1000_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
 	{ AU1000_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
@@ -529,7 +532,7 @@ spurious:
 }
 
 /* setup edge/level and assign request 0/1 */
-void __init au1xxx_setup_irqmap(struct au1xxx_irqmap *map, int count)
+static void __init setup_irqmap(struct au1xxx_irqmap *map, int count)
 {
 	unsigned int bit, irq_nr;
 
@@ -601,11 +604,7 @@ void __init arch_init_irq(void)
 	/*
 	 * Initialize IC0, which is fixed per processor.
 	 */
-	au1xxx_setup_irqmap(au1xxx_ic0_map, ARRAY_SIZE(au1xxx_ic0_map));
-
-	/* Boards can register additional (GPIO-based) IRQs.
-	*/
-	board_init_irq();
+	setup_irqmap(au1xxx_ic0_map, ARRAY_SIZE(au1xxx_ic0_map));
 
 	set_c0_status(IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3);
 }
diff --git a/arch/mips/alchemy/devboards/db1x00/Makefile b/arch/mips/alchemy/devboards/db1x00/Makefile
index 432241a..ce48d58 100644
--- a/arch/mips/alchemy/devboards/db1x00/Makefile
+++ b/arch/mips/alchemy/devboards/db1x00/Makefile
@@ -5,4 +5,4 @@
 # Makefile for the Alchemy Semiconductor DBAu1xx0 boards.
 #
 
-obj-y := board_setup.o irqmap.o
+obj-y := board_setup.o
diff --git a/arch/mips/alchemy/devboards/db1x00/board_setup.c b/arch/mips/alchemy/devboards/db1x00/board_setup.c
index e713390..9a619ae 100644
--- a/arch/mips/alchemy/devboards/db1x00/board_setup.c
+++ b/arch/mips/alchemy/devboards/db1x00/board_setup.c
@@ -29,6 +29,7 @@
 
 #include <linux/gpio.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-db1x00/db1x00.h>
@@ -36,6 +37,37 @@
 
 #include <prom.h>
 
+#ifdef CONFIG_MIPS_DB1500
+char irq_tab_alchemy[][5] __initdata = {
+	[12] = { -1, INTA, INTX, INTX, INTX }, /* IDSEL 12 - HPT371   */
+	[13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot */
+};
+#endif
+
+#ifdef CONFIG_MIPS_BOSPORUS
+char irq_tab_alchemy[][5] __initdata = {
+	[11] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 11 - miniPCI  */
+	[12] = { -1, INTA, INTX, INTX, INTX }, /* IDSEL 12 - SN1741   */
+	[13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot */
+};
+#endif
+
+#ifdef CONFIG_MIPS_MIRAGE
+char irq_tab_alchemy[][5] __initdata = {
+	[11] = { -1, INTD, INTX, INTX, INTX }, /* IDSEL 11 - SMI VGX */
+	[12] = { -1, INTX, INTX, INTC, INTX }, /* IDSEL 12 - PNX1300 */
+	[13] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 13 - miniPCI */
+};
+#endif
+
+#ifdef CONFIG_MIPS_DB1550
+char irq_tab_alchemy[][5] __initdata = {
+	[11] = { -1, INTC, INTX, INTX, INTX }, /* IDSEL 11 - on-board HPT371 */
+	[12] = { -1, INTB, INTC, INTD, INTA }, /* IDSEL 12 - PCI slot 2 (left) */
+	[13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot 1 (right) */
+};
+#endif
+
 const char *get_system_type(void)
 {
 #ifdef CONFIG_MIPS_BOSPORUS
@@ -149,3 +181,22 @@ void __init board_setup(void)
 
 	au_sync();
 }
+
+static int __init db1x00_init_irq(void)
+{
+#if defined(CONFIG_MIPS_MIRAGE)
+	set_irq_type(AU1000_GPIO_7, IRQF_TRIGGER_RISING); /* TS pendown */
+#elif defined(CONFIG_MIPS_DB1550)
+	set_irq_type(AU1000_GPIO_3, IRQF_TRIGGER_LOW);	/* CARD0# */
+	set_irq_type(AU1000_GPIO_5, IRQF_TRIGGER_LOW);	/* CARD1# */
+#else
+	set_irq_type(AU1000_GPIO_0, IRQF_TRIGGER_LOW);	/* CD0# */
+	set_irq_type(AU1000_GPIO_3, IRQF_TRIGGER_LOW);	/* CD1# */
+	set_irq_type(AU1000_GPIO_2, IRQF_TRIGGER_LOW);	/* CARD0# */
+	set_irq_type(AU1000_GPIO_5, IRQF_TRIGGER_LOW);	/* CARD1# */
+	set_irq_type(AU1000_GPIO_1, IRQF_TRIGGER_LOW);	/* STSCHG0# */
+	set_irq_type(AU1000_GPIO_4, IRQF_TRIGGER_LOW);	/* STSCHG1# */
+#endif
+	return 0;
+}
+arch_initcall(db1x00_init_irq);
diff --git a/arch/mips/alchemy/devboards/db1x00/irqmap.c b/arch/mips/alchemy/devboards/db1x00/irqmap.c
deleted file mode 100644
index 0b09025..0000000
--- a/arch/mips/alchemy/devboards/db1x00/irqmap.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- *	Au1xxx irq map table
- *
- * Copyright 2003 Embedded Edge, LLC
- *		dan@embeddededge.com
- *
- *  This program is free software; you can redistribute	 it and/or modify it
- *  under  the terms of	 the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the	License, or (at your
- *  option) any later version.
- *
- *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
- *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
- *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/init.h>
-#include <linux/interrupt.h>
-
-#include <asm/mach-au1x00/au1000.h>
-
-#ifdef CONFIG_MIPS_DB1500
-char irq_tab_alchemy[][5] __initdata = {
-	[12] = { -1, INTA, INTX, INTX, INTX }, /* IDSEL 12 - HPT371   */
-	[13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot */
-};
-#endif
-
-#ifdef CONFIG_MIPS_BOSPORUS
-char irq_tab_alchemy[][5] __initdata = {
-	[11] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 11 - miniPCI  */
-	[12] = { -1, INTA, INTX, INTX, INTX }, /* IDSEL 12 - SN1741   */
-	[13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot */
-};
-#endif
-
-#ifdef CONFIG_MIPS_MIRAGE
-char irq_tab_alchemy[][5] __initdata = {
-	[11] = { -1, INTD, INTX, INTX, INTX }, /* IDSEL 11 - SMI VGX */
-	[12] = { -1, INTX, INTX, INTC, INTX }, /* IDSEL 12 - PNX1300 */
-	[13] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 13 - miniPCI */
-};
-#endif
-
-#ifdef CONFIG_MIPS_DB1550
-char irq_tab_alchemy[][5] __initdata = {
-	[11] = { -1, INTC, INTX, INTX, INTX }, /* IDSEL 11 - on-board HPT371 */
-	[12] = { -1, INTB, INTC, INTD, INTA }, /* IDSEL 12 - PCI slot 2 (left) */
-	[13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot 1 (right) */
-};
-#endif
-
-
-struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
-
-#ifndef CONFIG_MIPS_MIRAGE
-#ifdef CONFIG_MIPS_DB1550
-	{ AU1000_GPIO_3, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 0 IRQ# */
-	{ AU1000_GPIO_5, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 1 IRQ# */
-#else
-	{ AU1000_GPIO_0, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 0 Fully_Interted# */
-	{ AU1000_GPIO_1, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 0 STSCHG# */
-	{ AU1000_GPIO_2, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 0 IRQ# */
-
-	{ AU1000_GPIO_3, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 1 Fully_Interted# */
-	{ AU1000_GPIO_4, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 1 STSCHG# */
-	{ AU1000_GPIO_5, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card 1 IRQ# */
-#endif
-#else
-	{ AU1000_GPIO_7, IRQF_TRIGGER_RISING, 0 }, /* touchscreen pen down */
-#endif
-
-};
-
-void __init board_init_irq(void)
-{
-	au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
-}
diff --git a/arch/mips/alchemy/devboards/pb1000/board_setup.c b/arch/mips/alchemy/devboards/pb1000/board_setup.c
index cd27354..f1cafea 100644
--- a/arch/mips/alchemy/devboards/pb1000/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1000/board_setup.c
@@ -32,11 +32,6 @@
 #include <prom.h>
 
 
-struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
-	{ AU1000_GPIO_15, IRQF_TRIGGER_LOW, 0 },
-};
-
-
 const char *get_system_type(void)
 {
 	return "Alchemy Pb1000";
@@ -46,11 +41,6 @@ void board_reset(void)
 {
 }
 
-void __init board_init_irq(void)
-{
-	au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
-}
-
 void __init board_setup(void)
 {
 	u32 pin_func, static_cfg0;
@@ -193,3 +183,10 @@ void __init board_setup(void)
 		break;
 	}
 }
+
+static int __init pb1000_init_irq(void)
+{
+	set_irq_type(AU1000_GPIO_15, IRQF_TRIGGER_LOW);
+	return 0;
+}
+arch_initcall(pb1000_init_irq);
diff --git a/arch/mips/alchemy/devboards/pb1100/board_setup.c b/arch/mips/alchemy/devboards/pb1100/board_setup.c
index eb749fb..aad424a 100644
--- a/arch/mips/alchemy/devboards/pb1100/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1100/board_setup.c
@@ -35,14 +35,6 @@
 #include <prom.h>
 
 
-struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
-	{ AU1000_GPIO_9,  IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card Fully_Inserted# */
-	{ AU1000_GPIO_10, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card STSCHG# */
-	{ AU1000_GPIO_11, IRQF_TRIGGER_LOW, 0 }, /* PCMCIA Card IRQ# */
-	{ AU1000_GPIO_13, IRQF_TRIGGER_LOW, 0 }, /* DC_IRQ# */
-};
-
-
 const char *get_system_type(void)
 {
 	return "Alchemy Pb1100";
@@ -53,11 +45,6 @@ void board_reset(void)
 	bcsr_write(BCSR_SYSTEM, 0);
 }
 
-void __init board_init_irq(void)
-{
-	au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
-}
-
 void __init board_setup(void)
 {
 	volatile void __iomem *base = (volatile void __iomem *)0xac000000UL;
@@ -158,3 +145,14 @@ void __init board_setup(void)
 		au_sync();
 	}
 }
+
+static int __init pb1100_init_irq(void)
+{
+	set_irq_type(AU1000_GPIO_9,  IRQF_TRIGGER_LOW);	/* PCCD# */
+	set_irq_type(AU1000_GPIO_10, IRQF_TRIGGER_LOW); /* PCSTSCHG# */
+	set_irq_type(AU1000_GPIO_11, IRQF_TRIGGER_LOW); /* PCCard# */
+	set_irq_type(AU1000_GPIO_13, IRQF_TRIGGER_LOW); /* DC_IRQ# */
+
+	return 0;
+}
+arch_initcall(pb1100_init_irq);
diff --git a/arch/mips/alchemy/devboards/pb1200/Makefile b/arch/mips/alchemy/devboards/pb1200/Makefile
index c8c3a99..2ea9b02 100644
--- a/arch/mips/alchemy/devboards/pb1200/Makefile
+++ b/arch/mips/alchemy/devboards/pb1200/Makefile
@@ -2,6 +2,6 @@
 # Makefile for the Alchemy Semiconductor Pb1200/DBAu1200 boards.
 #
 
-obj-y := board_setup.o irqmap.o platform.o
+obj-y := board_setup.o platform.o
 
 EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/alchemy/devboards/pb1200/board_setup.c b/arch/mips/alchemy/devboards/pb1200/board_setup.c
index db56380..76aa652 100644
--- a/arch/mips/alchemy/devboards/pb1200/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1200/board_setup.c
@@ -25,13 +25,25 @@
  */
 
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/sched.h>
 
+#include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-db1x00/bcsr.h>
 
-#include <prom.h>
-#include <au1xxx.h>
+#ifdef CONFIG_MIPS_PB1200
+#include <asm/mach-pb1x00/pb1200.h>
+#endif
+
+#ifdef CONFIG_MIPS_DB1200
+#include <asm/mach-db1x00/db1200.h>
+#define PB1200_INT_BEGIN DB1200_INT_BEGIN
+#define PB1200_INT_END DB1200_INT_END
+#endif
 
+#include <asm/mach-db1x00/bcsr.h>
+
+#include <prom.h>
 
 const char *get_system_type(void)
 {
@@ -137,6 +149,38 @@ void __init board_setup(void)
 	au_sync();
 }
 
+static int __init pb1200_init_irq(void)
+{
+#ifdef CONFIG_MIPS_PB1200
+	/* We have a problem with CPLD rev 3. */
+	if (BCSR_WHOAMI_CPLD(bcsr_read(BCSR_WHOAMI)) <= 3) {
+		printk(KERN_ERR "WARNING!!!\n");
+		printk(KERN_ERR "WARNING!!!\n");
+		printk(KERN_ERR "WARNING!!!\n");
+		printk(KERN_ERR "WARNING!!!\n");
+		printk(KERN_ERR "WARNING!!!\n");
+		printk(KERN_ERR "WARNING!!!\n");
+		printk(KERN_ERR "Pb1200 must be at CPLD rev 4. Please have Pb1200\n");
+		printk(KERN_ERR "updated to latest revision. This software will\n");
+		printk(KERN_ERR "not work on anything less than CPLD rev 4.\n");
+		printk(KERN_ERR "WARNING!!!\n");
+		printk(KERN_ERR "WARNING!!!\n");
+		printk(KERN_ERR "WARNING!!!\n");
+		printk(KERN_ERR "WARNING!!!\n");
+		printk(KERN_ERR "WARNING!!!\n");
+		printk(KERN_ERR "WARNING!!!\n");
+		panic("Game over.  Your score is 0.");
+	}
+#endif
+
+	set_irq_type(AU1000_GPIO_7, IRQF_TRIGGER_LOW);
+	bcsr_init_irq(PB1200_INT_BEGIN, PB1200_INT_END, AU1000_GPIO_7);
+
+	return 0;
+}
+arch_initcall(pb1200_init_irq);
+
+
 int board_au1200fb_panel(void)
 {
 	return (bcsr_read(BCSR_SWITCHES) >> 8) & 0x0f;
diff --git a/arch/mips/alchemy/devboards/pb1200/irqmap.c b/arch/mips/alchemy/devboards/pb1200/irqmap.c
deleted file mode 100644
index 3beb804..0000000
--- a/arch/mips/alchemy/devboards/pb1200/irqmap.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- *	Au1xxx irq map table
- *
- *  This program is free software; you can redistribute	 it and/or modify it
- *  under  the terms of	 the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the	License, or (at your
- *  option) any later version.
- *
- *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
- *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
- *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/init.h>
-#include <linux/interrupt.h>
-
-#include <asm/mach-au1x00/au1000.h>
-
-#ifdef CONFIG_MIPS_PB1200
-#include <asm/mach-pb1x00/pb1200.h>
-#endif
-
-#ifdef CONFIG_MIPS_DB1200
-#include <asm/mach-db1x00/db1200.h>
-#define PB1200_INT_BEGIN DB1200_INT_BEGIN
-#define PB1200_INT_END DB1200_INT_END
-#endif
-
-#include <asm/mach-db1x00/bcsr.h>
-
-struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
-	/* This is external interrupt cascade */
-	{ AU1000_GPIO_7, IRQF_TRIGGER_LOW, 0 },
-};
-
-void __init board_init_irq(void)
-{
-	au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
-
-#ifdef CONFIG_MIPS_PB1200
-	/* We have a problem with CPLD rev 3. */
-	if (BCSR_WHOAMI_CPLD(bcsr_read(BCSR_WHOAMI)) <= 3) {
-		printk(KERN_ERR "WARNING!!!\n");
-		printk(KERN_ERR "WARNING!!!\n");
-		printk(KERN_ERR "WARNING!!!\n");
-		printk(KERN_ERR "WARNING!!!\n");
-		printk(KERN_ERR "WARNING!!!\n");
-		printk(KERN_ERR "WARNING!!!\n");
-		printk(KERN_ERR "Pb1200 must be at CPLD rev 4. Please have Pb1200\n");
-		printk(KERN_ERR "updated to latest revision. This software will\n");
-		printk(KERN_ERR "not work on anything less than CPLD rev 4.\n");
-		printk(KERN_ERR "WARNING!!!\n");
-		printk(KERN_ERR "WARNING!!!\n");
-		printk(KERN_ERR "WARNING!!!\n");
-		printk(KERN_ERR "WARNING!!!\n");
-		printk(KERN_ERR "WARNING!!!\n");
-		printk(KERN_ERR "WARNING!!!\n");
-		panic("Game over.  Your score is 0.");
-	}
-#endif
-
-	bcsr_init_irq(PB1200_INT_BEGIN, PB1200_INT_END, AU1000_GPIO_7);
-}
diff --git a/arch/mips/alchemy/devboards/pb1500/board_setup.c b/arch/mips/alchemy/devboards/pb1500/board_setup.c
index c5389e5..bf8e149 100644
--- a/arch/mips/alchemy/devboards/pb1500/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1500/board_setup.c
@@ -40,14 +40,6 @@ char irq_tab_alchemy[][5] __initdata = {
 	[13] = { -1, INTA, INTB, INTC, INTD },   /* IDSEL 13 - PCI slot */
 };
 
-struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
-	{ AU1500_GPIO_204, IRQF_TRIGGER_HIGH, 0 },
-	{ AU1500_GPIO_201, IRQF_TRIGGER_LOW, 0 },
-	{ AU1500_GPIO_202, IRQF_TRIGGER_LOW, 0 },
-	{ AU1500_GPIO_203, IRQF_TRIGGER_LOW, 0 },
-	{ AU1500_GPIO_205, IRQF_TRIGGER_LOW, 0 },
-};
-
 
 const char *get_system_type(void)
 {
@@ -59,11 +51,6 @@ void board_reset(void)
 	bcsr_write(BCSR_SYSTEM, 0);
 }
 
-void __init board_init_irq(void)
-{
-	au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
-}
-
 void __init board_setup(void)
 {
 	u32 pin_func;
@@ -166,3 +153,15 @@ void __init board_setup(void)
 		au_sync();
 	}
 }
+
+static int __init pb1500_init_irq(void)
+{
+	set_irq_type(AU1500_GPIO_204, IRQF_TRIGGER_HIGH);
+	set_irq_type(AU1500_GPIO_201, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO_202, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO_203, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO_205, IRQF_TRIGGER_LOW);
+
+	return 0;
+}
+arch_initcall(pb1500_init_irq);
diff --git a/arch/mips/alchemy/devboards/pb1550/board_setup.c b/arch/mips/alchemy/devboards/pb1550/board_setup.c
index af7a1b5..64f1ff9 100644
--- a/arch/mips/alchemy/devboards/pb1550/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1550/board_setup.c
@@ -42,11 +42,6 @@ char irq_tab_alchemy[][5] __initdata = {
 	[13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot 1 (right) */
 };
 
-struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
-	{ AU1000_GPIO_0, IRQF_TRIGGER_LOW, 0 },
-	{ AU1000_GPIO_1, IRQF_TRIGGER_LOW, 0 },
-};
-
 const char *get_system_type(void)
 {
 	return "Alchemy Pb1550";
@@ -57,11 +52,6 @@ void board_reset(void)
 	bcsr_write(BCSR_SYSTEM, 0);
 }
 
-void __init board_init_irq(void)
-{
-	au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
-}
-
 void __init board_setup(void)
 {
 	u32 pin_func;
@@ -93,3 +83,12 @@ void __init board_setup(void)
 
 	printk(KERN_INFO "AMD Alchemy Pb1550 Board\n");
 }
+
+static int __init pb1550_init_irq(void)
+{
+	set_irq_type(AU1000_GPIO_0, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1000_GPIO_1, IRQF_TRIGGER_LOW);
+
+	return 0;
+}
+arch_initcall(pb1550_init_irq);
diff --git a/arch/mips/alchemy/mtx-1/Makefile b/arch/mips/alchemy/mtx-1/Makefile
index 7c67b3d..4a53815 100644
--- a/arch/mips/alchemy/mtx-1/Makefile
+++ b/arch/mips/alchemy/mtx-1/Makefile
@@ -6,7 +6,7 @@
 # Makefile for 4G Systems MTX-1 board.
 #
 
-lib-y := init.o board_setup.o irqmap.o
+lib-y := init.o board_setup.o
 obj-y := platform.o
 
 EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/alchemy/mtx-1/board_setup.c b/arch/mips/alchemy/mtx-1/board_setup.c
index cc32c69..568492c 100644
--- a/arch/mips/alchemy/mtx-1/board_setup.c
+++ b/arch/mips/alchemy/mtx-1/board_setup.c
@@ -30,11 +30,23 @@
 
 #include <linux/gpio.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 
 #include <asm/mach-au1x00/au1000.h>
 
 #include <prom.h>
 
+char irq_tab_alchemy[][5] __initdata = {
+	[0] = { -1, INTA, INTA, INTX, INTX }, /* IDSEL 00 - AdapterA-Slot0 (top) */
+	[1] = { -1, INTB, INTA, INTX, INTX }, /* IDSEL 01 - AdapterA-Slot1 (bottom) */
+	[2] = { -1, INTC, INTD, INTX, INTX }, /* IDSEL 02 - AdapterB-Slot0 (top) */
+	[3] = { -1, INTD, INTC, INTX, INTX }, /* IDSEL 03 - AdapterB-Slot1 (bottom) */
+	[4] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 04 - AdapterC-Slot0 (top) */
+	[5] = { -1, INTB, INTA, INTX, INTX }, /* IDSEL 05 - AdapterC-Slot1 (bottom) */
+	[6] = { -1, INTC, INTD, INTX, INTX }, /* IDSEL 06 - AdapterD-Slot0 (top) */
+	[7] = { -1, INTD, INTC, INTX, INTX }, /* IDSEL 07 - AdapterD-Slot1 (bottom) */
+};
+
 extern int (*board_pci_idsel)(unsigned int devsel, int assert);
 int mtx1_pci_idsel(unsigned int devsel, int assert);
 
@@ -110,3 +122,15 @@ mtx1_pci_idsel(unsigned int devsel, int assert)
 	au_sync_udelay(1);
 	return 1;
 }
+
+static int __init mtx1_init_irq(void)
+{
+	set_irq_type(AU1500_GPIO_204, IRQF_TRIGGER_HIGH);
+	set_irq_type(AU1500_GPIO_201, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO_202, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO_203, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO_205, IRQF_TRIGGER_LOW);
+
+	return 0;
+}
+arch_initcall(mtx1_init_irq);
diff --git a/arch/mips/alchemy/mtx-1/irqmap.c b/arch/mips/alchemy/mtx-1/irqmap.c
deleted file mode 100644
index f1ab12a..0000000
--- a/arch/mips/alchemy/mtx-1/irqmap.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- *	Au1xxx irq map table
- *
- * Copyright 2003 Embedded Edge, LLC
- *		dan@embeddededge.com
- *
- *  This program is free software; you can redistribute	 it and/or modify it
- *  under  the terms of	 the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the	License, or (at your
- *  option) any later version.
- *
- *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
- *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
- *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <asm/mach-au1x00/au1000.h>
-
-char irq_tab_alchemy[][5] __initdata = {
-	[0] = { -1, INTA, INTA, INTX, INTX }, /* IDSEL 00 - AdapterA-Slot0 (top) */
-	[1] = { -1, INTB, INTA, INTX, INTX }, /* IDSEL 01 - AdapterA-Slot1 (bottom) */
-	[2] = { -1, INTC, INTD, INTX, INTX }, /* IDSEL 02 - AdapterB-Slot0 (top) */
-	[3] = { -1, INTD, INTC, INTX, INTX }, /* IDSEL 03 - AdapterB-Slot1 (bottom) */
-	[4] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 04 - AdapterC-Slot0 (top) */
-	[5] = { -1, INTB, INTA, INTX, INTX }, /* IDSEL 05 - AdapterC-Slot1 (bottom) */
-	[6] = { -1, INTC, INTD, INTX, INTX }, /* IDSEL 06 - AdapterD-Slot0 (top) */
-	[7] = { -1, INTD, INTC, INTX, INTX }, /* IDSEL 07 - AdapterD-Slot1 (bottom) */
-};
-
-struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
-       { AU1500_GPIO_204, IRQF_TRIGGER_HIGH, 0 },
-       { AU1500_GPIO_201, IRQF_TRIGGER_LOW, 0 },
-       { AU1500_GPIO_202, IRQF_TRIGGER_LOW, 0 },
-       { AU1500_GPIO_203, IRQF_TRIGGER_LOW, 0 },
-       { AU1500_GPIO_205, IRQF_TRIGGER_LOW, 0 },
-};
-
-
-void __init board_init_irq(void)
-{
-	au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
-}
diff --git a/arch/mips/alchemy/xxs1500/Makefile b/arch/mips/alchemy/xxs1500/Makefile
index db3c526..545d8f5 100644
--- a/arch/mips/alchemy/xxs1500/Makefile
+++ b/arch/mips/alchemy/xxs1500/Makefile
@@ -5,4 +5,4 @@
 # Makefile for MyCable XXS1500 board.
 #
 
-lib-y := init.o board_setup.o irqmap.o
+lib-y := init.o board_setup.o
diff --git a/arch/mips/alchemy/xxs1500/board_setup.c b/arch/mips/alchemy/xxs1500/board_setup.c
index 4de2d48..cad14f8 100644
--- a/arch/mips/alchemy/xxs1500/board_setup.c
+++ b/arch/mips/alchemy/xxs1500/board_setup.c
@@ -25,6 +25,7 @@
 
 #include <linux/gpio.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/delay.h>
 
 #include <asm/mach-au1x00/au1000.h>
@@ -92,3 +93,23 @@ void __init board_setup(void)
 #endif
 #endif
 }
+
+static int __init xxs1500_init_irq(void)
+{
+	set_irq_type(AU1500_GPIO_204, IRQF_TRIGGER_HIGH);
+	set_irq_type(AU1500_GPIO_201, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO_202, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO_203, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO_205, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO_207, IRQF_TRIGGER_LOW);
+
+	set_irq_type(AU1000_GPIO_0, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1000_GPIO_1, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1000_GPIO_2, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1000_GPIO_3, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1000_GPIO_4, IRQF_TRIGGER_LOW); /* CF interrupt */
+	set_irq_type(AU1000_GPIO_5, IRQF_TRIGGER_LOW);
+
+	return 0;
+}
+arch_initcall(xxs1500_init_irq);
diff --git a/arch/mips/alchemy/xxs1500/irqmap.c b/arch/mips/alchemy/xxs1500/irqmap.c
deleted file mode 100644
index 0f0f301..0000000
--- a/arch/mips/alchemy/xxs1500/irqmap.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- *	Au1xxx irq map table
- *
- * Copyright 2003 Embedded Edge, LLC
- *		dan@embeddededge.com
- *
- *  This program is free software; you can redistribute	 it and/or modify it
- *  under  the terms of	 the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the	License, or (at your
- *  option) any later version.
- *
- *  THIS  SOFTWARE  IS PROVIDED	  ``AS	IS'' AND   ANY	EXPRESS OR IMPLIED
- *  WARRANTIES,	  INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
- *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
- *  NO	EVENT  SHALL   THE AUTHOR  BE	 LIABLE FOR ANY	  DIRECT, INDIRECT,
- *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *  NOT LIMITED	  TO, PROCUREMENT OF  SUBSTITUTE GOODS	OR SERVICES; LOSS OF
- *  USE, DATA,	OR PROFITS; OR	BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- *  ANY THEORY OF LIABILITY, WHETHER IN	 CONTRACT, STRICT LIABILITY, OR TORT
- *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.,
- *  675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <asm/mach-au1x00/au1000.h>
-
-struct au1xxx_irqmap __initdata au1xxx_irq_map[] = {
-	{ AU1500_GPIO_204, IRQF_TRIGGER_HIGH, 0 },
-	{ AU1500_GPIO_201, IRQF_TRIGGER_LOW, 0 },
-	{ AU1500_GPIO_202, IRQF_TRIGGER_LOW, 0 },
-	{ AU1500_GPIO_203, IRQF_TRIGGER_LOW, 0 },
-	{ AU1500_GPIO_205, IRQF_TRIGGER_LOW, 0 },
-	{ AU1500_GPIO_207, IRQF_TRIGGER_LOW, 0 },
-
-	{ AU1000_GPIO_0, IRQF_TRIGGER_LOW, 0 },
-	{ AU1000_GPIO_1, IRQF_TRIGGER_LOW, 0 },
-	{ AU1000_GPIO_2, IRQF_TRIGGER_LOW, 0 },
-	{ AU1000_GPIO_3, IRQF_TRIGGER_LOW, 0 },
-	{ AU1000_GPIO_4, IRQF_TRIGGER_LOW, 0 }, /* CF interrupt */
-	{ AU1000_GPIO_5, IRQF_TRIGGER_LOW, 0 },
-};
-
-void __init board_init_irq(void)
-{
-	au1xxx_setup_irqmap(au1xxx_irq_map, ARRAY_SIZE(au1xxx_irq_map));
-}
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index 854e95f..0507822 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -143,21 +143,6 @@ void au_sleep(void);
 void save_au1xxx_intctl(void);
 void restore_au1xxx_intctl(void);
 
-/*
- * Every board describes its IRQ mapping with this table.
- */
-struct au1xxx_irqmap {
-	int	im_irq;
-	int	im_type;
-	int	im_request;
-};
-
-/* core calls this function to let boards initialize other IRQ sources */
-void board_init_irq(void);
-
-/* boards call this to register additional (GPIO) interrupts */
-void au1xxx_setup_irqmap(struct au1xxx_irqmap *map, int count);
-
 #endif /* !defined (_LANGUAGE_ASSEMBLY) */
 
 /*
diff --git a/arch/mips/include/asm/mach-db1x00/db1200.h b/arch/mips/include/asm/mach-db1x00/db1200.h
index 2909b83..b7f18e1 100644
--- a/arch/mips/include/asm/mach-db1x00/db1200.h
+++ b/arch/mips/include/asm/mach-db1x00/db1200.h
@@ -25,6 +25,7 @@
 #define __ASM_DB1200_H
 
 #include <linux/types.h>
+#include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1xxx_psc.h>
 
 #define DBDMA_AC97_TX_CHAN	DSCR_CMD0_PSC1_TX
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1200.h b/arch/mips/include/asm/mach-pb1x00/pb1200.h
index a51512c..2458eb4 100644
--- a/arch/mips/include/asm/mach-pb1x00/pb1200.h
+++ b/arch/mips/include/asm/mach-pb1x00/pb1200.h
@@ -25,6 +25,7 @@
 #define __ASM_PB1200_H
 
 #include <linux/types.h>
+#include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-au1x00/au1xxx_psc.h>
 
 #define DBDMA_AC97_TX_CHAN	DSCR_CMD0_PSC1_TX
-- 
1.6.5.rc2


From manuel.lauss@googlemail.com Sun Oct  4 14:57:13 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Sun, 04 Oct 2009 14:57:20 +0200 (CEST)
Received: from mail-ew0-f214.google.com ([209.85.219.214]:42791 "EHLO
	mail-ew0-f214.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492534AbZJDMzn (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sun, 4 Oct 2009 14:55:43 +0200
Received: by ewy10 with SMTP id 10so1846519ewy.33
        for <multiple recipients>; Sun, 04 Oct 2009 05:55:38 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer:in-reply-to:references;
        bh=wYxOGqVaFhWrUnM5OF3u9H4I6WL9VEWm9APBOZOPwFQ=;
        b=HAmwfHoNrhac0PgY1bxD5MseuS8aXCsIy3/y/CKG9K71JP8vS/Lmnz769I+frMyFUD
         hOJCLkD03xe5aq2bZGwE2/81UHH9dHi6jGHr/9+/isLOEJc1OQ27fOSjtk4rluf/DDir
         OFDVR7zaTuiYuhHA52dneLvGc1zJXGXG2+8/g=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        b=JQG4Pisca0wgogUJAeGHewLtnDCwgCvdx0Dq8SAoLfYG3VPt/r7opXfBg4P7Z/qpWj
         UVv0AIjN7ltbi9OFGrZ1MyHzW2Vj8CtWCo9jr6kx2rPAC0vE5ieZCEpdF+CksRhdXoRV
         tPGdbOqGMA2bWLovH32fR+sHS6XbGIBhPBsIE=
Received: by 10.210.7.21 with SMTP id 21mr1972304ebg.66.1254660938278;
        Sun, 04 Oct 2009 05:55:38 -0700 (PDT)
Received: from localhost.localdomain (fnoeppeil48.netpark.at [217.175.205.176])
        by mx.google.com with ESMTPS id 28sm1555483eyg.4.2009.10.04.05.55.37
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Sun, 04 Oct 2009 05:55:37 -0700 (PDT)
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Linux-MIPS <linux-mips@linux-mips.org>,
	Ralf Baechle <ralf@linux-mips.org>
Cc:	Manuel Lauss <manuel.lauss@gmail.com>
Subject: [PATCH 5/6] Alchemy: devboards: wire up new PCMCIA driver.
Date:	Sun,  4 Oct 2009 14:55:28 +0200
Message-Id: <1254660929-15453-6-git-send-email-manuel.lauss@gmail.com>
X-Mailer: git-send-email 1.6.5.rc2
In-Reply-To: <1254660929-15453-5-git-send-email-manuel.lauss@gmail.com>
References: <1254660929-15453-1-git-send-email-manuel.lauss@gmail.com>
 <1254660929-15453-2-git-send-email-manuel.lauss@gmail.com>
 <1254660929-15453-3-git-send-email-manuel.lauss@gmail.com>
 <1254660929-15453-4-git-send-email-manuel.lauss@gmail.com>
 <1254660929-15453-5-git-send-email-manuel.lauss@gmail.com>
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24141
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

Register the PCMCIA driver on all boards supported by it,
get rid of now-unused pcmcia macros in the board headers
(and subsequently empty pb1100/pb1500 ones).

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
V2: split the previous patch in 2 parts; one with the PCMCIA driver,
    the other (this one) to add the socket device registration to the
    various boards.
    Instead of dumping the whole "struct resource" tables for every
    socket into each boards' platform file, they now call a fucntion
    with socket data to setup the whole resource/platform_device stuff;
    saves a lot of lines.

 arch/mips/alchemy/devboards/Makefile             |    2 +-
 arch/mips/alchemy/devboards/db1x00/board_setup.c |    4 +
 arch/mips/alchemy/devboards/db1x00/platform.c    |   84 ++++++++++++++++++++
 arch/mips/alchemy/devboards/pb1100/Makefile      |    3 +-
 arch/mips/alchemy/devboards/pb1100/platform.c    |   41 ++++++++++
 arch/mips/alchemy/devboards/pb1200/platform.c    |   55 +++++++++++++-
 arch/mips/alchemy/devboards/pb1500/Makefile      |    3 +-
 arch/mips/alchemy/devboards/pb1500/board_setup.c |    3 +
 arch/mips/alchemy/devboards/pb1500/platform.c    |   41 ++++++++++
 arch/mips/alchemy/devboards/pb1550/Makefile      |    3 +-
 arch/mips/alchemy/devboards/pb1550/board_setup.c |    8 ++
 arch/mips/alchemy/devboards/pb1550/platform.c    |   63 +++++++++++++++
 arch/mips/alchemy/devboards/platform.c           |   89 ++++++++++++++++++++++
 arch/mips/alchemy/devboards/platform.h           |   18 +++++
 arch/mips/include/asm/mach-db1x00/db1200.h       |   15 ----
 arch/mips/include/asm/mach-db1x00/db1x00.h       |    8 --
 arch/mips/include/asm/mach-pb1x00/pb1100.h       |   36 ---------
 arch/mips/include/asm/mach-pb1x00/pb1200.h       |   14 ----
 arch/mips/include/asm/mach-pb1x00/pb1500.h       |   36 ---------
 arch/mips/include/asm/mach-pb1x00/pb1550.h       |    7 --
 20 files changed, 411 insertions(+), 122 deletions(-)
 create mode 100644 arch/mips/alchemy/devboards/db1x00/platform.c
 create mode 100644 arch/mips/alchemy/devboards/pb1100/platform.c
 create mode 100644 arch/mips/alchemy/devboards/pb1500/platform.c
 create mode 100644 arch/mips/alchemy/devboards/pb1550/platform.c
 create mode 100644 arch/mips/alchemy/devboards/platform.c
 create mode 100644 arch/mips/alchemy/devboards/platform.h
 delete mode 100644 arch/mips/include/asm/mach-pb1x00/pb1100.h
 delete mode 100644 arch/mips/include/asm/mach-pb1x00/pb1500.h

diff --git a/arch/mips/alchemy/devboards/Makefile b/arch/mips/alchemy/devboards/Makefile
index adc6717..cfda972 100644
--- a/arch/mips/alchemy/devboards/Makefile
+++ b/arch/mips/alchemy/devboards/Makefile
@@ -2,7 +2,7 @@
 # Alchemy Develboards
 #
 
-obj-y += prom.o bcsr.o
+obj-y += prom.o bcsr.o platform.o
 obj-$(CONFIG_PM)		+= pm.o
 obj-$(CONFIG_MIPS_PB1000)	+= pb1000/
 obj-$(CONFIG_MIPS_PB1100)	+= pb1100/
diff --git a/arch/mips/alchemy/devboards/db1x00/board_setup.c b/arch/mips/alchemy/devboards/db1x00/board_setup.c
index 9a619ae..3b228a2 100644
--- a/arch/mips/alchemy/devboards/db1x00/board_setup.c
+++ b/arch/mips/alchemy/devboards/db1x00/board_setup.c
@@ -187,8 +187,12 @@ static int __init db1x00_init_irq(void)
 #if defined(CONFIG_MIPS_MIRAGE)
 	set_irq_type(AU1000_GPIO_7, IRQF_TRIGGER_RISING); /* TS pendown */
 #elif defined(CONFIG_MIPS_DB1550)
+	set_irq_type(AU1000_GPIO_0, IRQF_TRIGGER_LOW);	/* CD0# */
+	set_irq_type(AU1000_GPIO_1, IRQF_TRIGGER_LOW);	/* CD1# */
 	set_irq_type(AU1000_GPIO_3, IRQF_TRIGGER_LOW);	/* CARD0# */
 	set_irq_type(AU1000_GPIO_5, IRQF_TRIGGER_LOW);	/* CARD1# */
+	set_irq_type(AU1000_GPIO_21, IRQF_TRIGGER_LOW);	/* STSCHG0# */
+	set_irq_type(AU1000_GPIO_22, IRQF_TRIGGER_LOW);	/* STSCHG1# */
 #else
 	set_irq_type(AU1000_GPIO_0, IRQF_TRIGGER_LOW);	/* CD0# */
 	set_irq_type(AU1000_GPIO_3, IRQF_TRIGGER_LOW);	/* CD1# */
diff --git a/arch/mips/alchemy/devboards/db1x00/platform.c b/arch/mips/alchemy/devboards/db1x00/platform.c
new file mode 100644
index 0000000..b762b79
--- /dev/null
+++ b/arch/mips/alchemy/devboards/db1x00/platform.c
@@ -0,0 +1,84 @@
+/*
+ * DBAu1xxx board platform device registration
+ *
+ * Copyright (C) 2009 Manuel Lauss
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-au1x00/au1xxx.h>
+#include "../platform.h"
+
+#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || \
+    defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550)
+#define DB1XXX_HAS_PCMCIA
+#endif
+
+/* DB1xxx PCMCIA interrupt sources:
+ * CD0/1 	GPIO0/3
+ * STSCHG0/1	GPIO1/4
+ * CARD0/1	GPIO2/5
+ * Db1550:	0/1, 21/22, 3/5
+ */
+#ifndef CONFIG_MIPS_DB1550
+/* Db1000, Db1100, Db1500 */
+#define DB1XXX_PCMCIA_CD0	AU1000_GPIO_0
+#define DB1XXX_PCMCIA_STSCHG0	AU1000_GPIO_1
+#define DB1XXX_PCMCIA_CARD0	AU1000_GPIO_2
+#define DB1XXX_PCMCIA_CD1	AU1000_GPIO_3
+#define DB1XXX_PCMCIA_STSCHG1	AU1000_GPIO_4
+#define DB1XXX_PCMCIA_CARD1	AU1000_GPIO_5
+#else
+#define DB1XXX_PCMCIA_CD0	AU1000_GPIO_0
+#define DB1XXX_PCMCIA_STSCHG0	AU1500_GPIO_21
+#define DB1XXX_PCMCIA_CARD0	AU1000_GPIO_3
+#define DB1XXX_PCMCIA_CD1	AU1000_GPIO_1
+#define DB1XXX_PCMCIA_STSCHG1	AU1500_GPIO_22
+#define DB1XXX_PCMCIA_CARD1	AU1000_GPIO_5
+#endif
+
+static int __init db1xxx_dev_init(void)
+{
+#ifdef DB1XXX_HAS_PCMCIA
+	db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS,
+				    PCMCIA_ATTR_PSEUDO_PHYS + 0x00040000 - 1,
+				    PCMCIA_MEM_PSEUDO_PHYS,
+				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00040000 - 1,
+				    PCMCIA_IO_PSEUDO_PHYS,
+				    PCMCIA_IO_PSEUDO_PHYS   + 0x00001000 - 1,
+				    DB1XXX_PCMCIA_CARD0,
+				    DB1XXX_PCMCIA_CD0,
+				    /*DB1XXX_PCMCIA_STSCHG0*/0,
+				    0,
+				    0);
+
+	db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS + 0x00400000,
+				    PCMCIA_ATTR_PSEUDO_PHYS + 0x00440000 - 1,
+				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00400000,
+				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00440000 - 1,
+				    PCMCIA_IO_PSEUDO_PHYS   + 0x00400000,
+				    PCMCIA_IO_PSEUDO_PHYS   + 0x00401000 - 1,
+				    DB1XXX_PCMCIA_CARD1,
+				    DB1XXX_PCMCIA_CD1,
+				    /*DB1XXX_PCMCIA_STSCHG1*/0,
+				    0,
+				    1);
+#endif
+	return 0;
+}
+device_initcall(db1xxx_dev_init);
diff --git a/arch/mips/alchemy/devboards/pb1100/Makefile b/arch/mips/alchemy/devboards/pb1100/Makefile
index c586dd7..60cf5b9 100644
--- a/arch/mips/alchemy/devboards/pb1100/Makefile
+++ b/arch/mips/alchemy/devboards/pb1100/Makefile
@@ -5,4 +5,5 @@
 # Makefile for the Alchemy Semiconductor Pb1100 board.
 #
 
-obj-y := board_setup.o
+obj-y := board_setup.o platform.o
+
diff --git a/arch/mips/alchemy/devboards/pb1100/platform.c b/arch/mips/alchemy/devboards/pb1100/platform.c
new file mode 100644
index 0000000..8aefecd
--- /dev/null
+++ b/arch/mips/alchemy/devboards/pb1100/platform.c
@@ -0,0 +1,41 @@
+/*
+ * Pb1100 board platform device registration
+ *
+ * Copyright (C) 2009 Manuel Lauss
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/init.h>
+
+#include "../platform.h"
+
+static int __init pb1100_dev_init(void)
+{
+	/* PCMCIA. single socket, identical to Pb1500 */
+	db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS,
+				    PCMCIA_ATTR_PSEUDO_PHYS + 0x00040000 - 1,
+				    PCMCIA_MEM_PSEUDO_PHYS,
+				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00040000 - 1,
+				    PCMCIA_IO_PSEUDO_PHYS,
+				    PCMCIA_IO_PSEUDO_PHYS   + 0x00001000 - 1,
+				    AU1000_GPIO_11,	 /* card */
+				    AU1000_GPIO_9,	 /* insert */
+				    /*AU1000_GPIO_10*/0, /* stschg */
+				    0,			 /* eject */
+				    0);			 /* id */
+	return 0;
+}
+device_initcall(pb1100_dev_init);
diff --git a/arch/mips/alchemy/devboards/pb1200/platform.c b/arch/mips/alchemy/devboards/pb1200/platform.c
index dfdaabf..c8b7ae3 100644
--- a/arch/mips/alchemy/devboards/pb1200/platform.c
+++ b/arch/mips/alchemy/devboards/pb1200/platform.c
@@ -28,6 +28,8 @@
 #include <asm/mach-au1x00/au1100_mmc.h>
 #include <asm/mach-db1x00/bcsr.h>
 
+#include "../platform.h"
+
 static int mmc_activity;
 
 static void pb1200mmc0_set_power(void *mmc_host, int state)
@@ -170,8 +172,57 @@ static struct platform_device *board_platform_devices[] __initdata = {
 
 static int __init board_register_devices(void)
 {
+#ifdef CONFIG_MIPS_PB1200
+	db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS,
+				    PCMCIA_ATTR_PSEUDO_PHYS + 0x00040000 - 1,
+				    PCMCIA_MEM_PSEUDO_PHYS,
+				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00040000 - 1,
+				    PCMCIA_IO_PSEUDO_PHYS,
+				    PCMCIA_IO_PSEUDO_PHYS   + 0x00001000 - 1,
+				    PB1200_PC0_INT,
+				    PB1200_PC0_INSERT_INT,
+				    /*PB1200_PC0_STSCHG_INT*/0,
+				    PB1200_PC0_EJECT_INT,
+				    0);
+
+	db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS + 0x00800000,
+				    PCMCIA_ATTR_PSEUDO_PHYS + 0x00840000 - 1,
+				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00800000,
+				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00840000 - 1,
+				    PCMCIA_IO_PSEUDO_PHYS   + 0x00800000,
+				    PCMCIA_IO_PSEUDO_PHYS   + 0x00801000 - 1,
+				    PB1200_PC1_INT,
+				    PB1200_PC1_INSERT_INT,
+				    /*PB1200_PC1_STSCHG_INT*/0,
+				    PB1200_PC1_EJECT_INT,
+				    1);
+#else
+	db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS,
+				    PCMCIA_ATTR_PSEUDO_PHYS + 0x00040000 - 1,
+				    PCMCIA_MEM_PSEUDO_PHYS,
+				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00040000 - 1,
+				    PCMCIA_IO_PSEUDO_PHYS,
+				    PCMCIA_IO_PSEUDO_PHYS   + 0x00001000 - 1,
+				    DB1200_PC0_INT,
+				    DB1200_PC0_INSERT_INT,
+				    /*DB1200_PC0_STSCHG_INT*/0,
+				    DB1200_PC0_EJECT_INT,
+				    0);
+
+	db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS + 0x00400000,
+				    PCMCIA_ATTR_PSEUDO_PHYS + 0x00440000 - 1,
+				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00400000,
+				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00440000 - 1,
+				    PCMCIA_IO_PSEUDO_PHYS   + 0x00400000,
+				    PCMCIA_IO_PSEUDO_PHYS   + 0x00401000 - 1,
+				    DB1200_PC1_INT,
+				    DB1200_PC1_INSERT_INT,
+				    /*DB1200_PC1_STSCHG_INT*/0,
+				    DB1200_PC1_EJECT_INT,
+				    1);
+#endif
+
 	return platform_add_devices(board_platform_devices,
 				    ARRAY_SIZE(board_platform_devices));
 }
-
-arch_initcall(board_register_devices);
+device_initcall(board_register_devices);
diff --git a/arch/mips/alchemy/devboards/pb1500/Makefile b/arch/mips/alchemy/devboards/pb1500/Makefile
index 173b419..c29545d 100644
--- a/arch/mips/alchemy/devboards/pb1500/Makefile
+++ b/arch/mips/alchemy/devboards/pb1500/Makefile
@@ -5,4 +5,5 @@
 # Makefile for the Alchemy Semiconductor Pb1500 board.
 #
 
-obj-y := board_setup.o
+obj-y := board_setup.o platform.o
+
diff --git a/arch/mips/alchemy/devboards/pb1500/board_setup.c b/arch/mips/alchemy/devboards/pb1500/board_setup.c
index bf8e149..4c4facb 100644
--- a/arch/mips/alchemy/devboards/pb1500/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1500/board_setup.c
@@ -156,6 +156,9 @@ void __init board_setup(void)
 
 static int __init pb1500_init_irq(void)
 {
+	set_irq_type(AU1000_GPIO_9, IRQF_TRIGGER_LOW);	/* CD0# */
+	set_irq_type(AU1000_GPIO_10, IRQF_TRIGGER_LOW);	/* CARD0 */
+	set_irq_type(AU1000_GPIO_11, IRQF_TRIGGER_LOW);	/* STSCHG0# */
 	set_irq_type(AU1500_GPIO_204, IRQF_TRIGGER_HIGH);
 	set_irq_type(AU1500_GPIO_201, IRQF_TRIGGER_LOW);
 	set_irq_type(AU1500_GPIO_202, IRQF_TRIGGER_LOW);
diff --git a/arch/mips/alchemy/devboards/pb1500/platform.c b/arch/mips/alchemy/devboards/pb1500/platform.c
new file mode 100644
index 0000000..beb21e4
--- /dev/null
+++ b/arch/mips/alchemy/devboards/pb1500/platform.c
@@ -0,0 +1,41 @@
+/*
+ * Pb1500 board platform device registration
+ *
+ * Copyright (C) 2009 Manuel Lauss
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/init.h>
+
+#include "../platform.h"
+
+static int __init pb1500_dev_init(void)
+{
+	/* PCMCIA. single socket, identical to Pb1500 */
+	db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS,
+				    PCMCIA_ATTR_PSEUDO_PHYS + 0x00040000 - 1,
+				    PCMCIA_MEM_PSEUDO_PHYS,
+				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00040000 - 1,
+				    PCMCIA_IO_PSEUDO_PHYS,
+				    PCMCIA_IO_PSEUDO_PHYS   + 0x00001000 - 1,
+				    AU1000_GPIO_11,	 /* card */
+				    AU1000_GPIO_9,	 /* insert */
+				    /*AU1000_GPIO_10*/0, /* stschg */
+				    0,			 /* eject */
+				    0);			 /* id */
+	return 0;
+}
+device_initcall(pb1500_dev_init);
diff --git a/arch/mips/alchemy/devboards/pb1550/Makefile b/arch/mips/alchemy/devboards/pb1550/Makefile
index cff95bc..86b410b 100644
--- a/arch/mips/alchemy/devboards/pb1550/Makefile
+++ b/arch/mips/alchemy/devboards/pb1550/Makefile
@@ -5,4 +5,5 @@
 # Makefile for the Alchemy Semiconductor Pb1550 board.
 #
 
-obj-y := board_setup.o
+obj-y := board_setup.o platform.o
+
diff --git a/arch/mips/alchemy/devboards/pb1550/board_setup.c b/arch/mips/alchemy/devboards/pb1550/board_setup.c
index 64f1ff9..64a6fc4 100644
--- a/arch/mips/alchemy/devboards/pb1550/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1550/board_setup.c
@@ -33,6 +33,7 @@
 #include <asm/mach-au1x00/au1000.h>
 #include <asm/mach-pb1x00/pb1550.h>
 #include <asm/mach-db1x00/bcsr.h>
+#include <asm/mach-au1x00/gpio.h>
 
 #include <prom.h>
 
@@ -70,6 +71,8 @@ void __init board_setup(void)
 	}
 #endif
 
+	alchemy_gpio2_enable();
+
 	/*
 	 * Enable PSC1 SYNC for AC'97.  Normaly done in audio driver,
 	 * but it is board specific code, so put it here.
@@ -88,6 +91,11 @@ static int __init pb1550_init_irq(void)
 {
 	set_irq_type(AU1000_GPIO_0, IRQF_TRIGGER_LOW);
 	set_irq_type(AU1000_GPIO_1, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO_201_205, IRQF_TRIGGER_HIGH);
+
+	/* enable both PCMCIA card irqs in the shared line */
+	alchemy_gpio2_enable_int(201);
+	alchemy_gpio2_enable_int(202);
 
 	return 0;
 }
diff --git a/arch/mips/alchemy/devboards/pb1550/platform.c b/arch/mips/alchemy/devboards/pb1550/platform.c
new file mode 100644
index 0000000..aa5016c
--- /dev/null
+++ b/arch/mips/alchemy/devboards/pb1550/platform.c
@@ -0,0 +1,63 @@
+/*
+ * Pb1550 board platform device registration
+ *
+ * Copyright (C) 2009 Manuel Lauss
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/init.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-pb1x00/pb1550.h>
+
+#include "../platform.h"
+
+static int __init pb1550_dev_init(void)
+{
+	/* Pb1550, like all others, also has statuschange irqs; however they're
+	* wired up on one of the Au1550's shared GPIO201_205 line, which also
+	* services the PCMCIA card interrupts.  So we ignore statuschange and
+	* use the GPIO201_205 exclusively for card interrupts, since a) pcmcia
+	* drivers are used to shared irqs and b) statuschange isn't really use-
+	* ful anyway.
+	*/
+	db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS,
+				    PCMCIA_ATTR_PSEUDO_PHYS + 0x00040000 - 1,
+				    PCMCIA_MEM_PSEUDO_PHYS,
+				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00040000 - 1,
+				    PCMCIA_IO_PSEUDO_PHYS,
+				    PCMCIA_IO_PSEUDO_PHYS   + 0x00001000 - 1,
+				    AU1500_GPIO_201_205,
+				    AU1000_GPIO_0,
+				    0,
+				    0,
+				    0);
+
+	db1x_register_pcmcia_socket(PCMCIA_ATTR_PSEUDO_PHYS + 0x00800000,
+				    PCMCIA_ATTR_PSEUDO_PHYS + 0x00840000 - 1,
+				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00800000,
+				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00840000 - 1,
+				    PCMCIA_IO_PSEUDO_PHYS   + 0x00800000,
+				    PCMCIA_IO_PSEUDO_PHYS   + 0x00801000 - 1,
+				    AU1500_GPIO_201_205,
+				    AU1000_GPIO_1,
+				    0,
+				    0,
+				    1);
+
+	return 0;
+}
+device_initcall(pb1550_dev_init);
diff --git a/arch/mips/alchemy/devboards/platform.c b/arch/mips/alchemy/devboards/platform.c
new file mode 100644
index 0000000..48c537c
--- /dev/null
+++ b/arch/mips/alchemy/devboards/platform.c
@@ -0,0 +1,89 @@
+/*
+ * devoard misc stuff.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+
+/* register a pcmcia socket */
+int __init db1x_register_pcmcia_socket(unsigned long pseudo_attr_start,
+				       unsigned long pseudo_attr_end,
+				       unsigned long pseudo_mem_start,
+				       unsigned long pseudo_mem_end,
+				       unsigned long pseudo_io_start,
+				       unsigned long pseudo_io_end,
+				       int card_irq,
+				       int cd_irq,
+				       int stschg_irq,
+				       int eject_irq,
+				       int id)
+{
+	int cnt, i, ret;
+	struct resource *sr;
+	struct platform_device *pd;
+
+	cnt = 5;
+	if (eject_irq)
+		cnt++;
+	if (stschg_irq)
+		cnt++;
+
+	sr = kzalloc(sizeof(struct resource) * cnt, GFP_KERNEL);
+	if (!sr)
+		return -ENOMEM;
+
+	pd = platform_device_alloc("db1xxx_pcmcia", id);
+	if (!pd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	sr[0].name	= "pseudo-attr";
+	sr[0].flags	= IORESOURCE_MEM;
+	sr[0].start	= pseudo_attr_start;
+	sr[0].end	= pseudo_attr_end;
+
+	sr[1].name	= "pseudo-mem";
+	sr[1].flags	= IORESOURCE_MEM;
+	sr[1].start	= pseudo_mem_start;
+	sr[1].end	= pseudo_mem_end;
+
+	sr[2].name	= "pseudo-io";
+	sr[2].flags	= IORESOURCE_MEM;
+	sr[2].start	= pseudo_io_start;
+	sr[2].end	= pseudo_io_end;
+
+	sr[3].name	= "insert";
+	sr[3].flags	= IORESOURCE_IRQ;
+	sr[3].start = sr[3].end = cd_irq;
+
+	sr[4].name	= "card";
+	sr[4].flags	= IORESOURCE_IRQ;
+	sr[4].start = sr[4].end = card_irq;
+
+	i = 5;
+	if (stschg_irq) {
+		sr[i].name	= "insert";
+		sr[i].flags	= IORESOURCE_IRQ;
+		sr[i].start = sr[i].end = cd_irq;
+		i++;
+	}
+	if (eject_irq) {
+		sr[i].name	= "eject";
+		sr[i].flags	= IORESOURCE_IRQ;
+		sr[i].start = sr[i].end = eject_irq;
+	}
+
+	pd->resource = sr;
+	pd->num_resources = cnt;
+
+	ret = platform_device_add(pd);
+	if (!ret)
+		return 0;
+
+	platform_device_put(pd);
+out:
+	kfree(sr);
+	return ret;
+}
diff --git a/arch/mips/alchemy/devboards/platform.h b/arch/mips/alchemy/devboards/platform.h
new file mode 100644
index 0000000..55ecf7e
--- /dev/null
+++ b/arch/mips/alchemy/devboards/platform.h
@@ -0,0 +1,18 @@
+#ifndef _DEVBOARD_PLATFORM_H_
+#define _DEVBOARD_PLATFORM_H_
+
+#include <linux/init.h>
+
+int __init db1x_register_pcmcia_socket(unsigned long pseudo_attr_start,
+				       unsigned long pseudo_attr_len,
+				       unsigned long pseudo_mem_start,
+				       unsigned long pseudo_mem_end,
+				       unsigned long pseudo_io_start,
+				       unsigned long pseudo_io_end,
+				       int card_irq,
+				       int cd_irq,
+				       int stschg_irq,
+				       int eject_irq,
+				       int id);
+
+#endif
diff --git a/arch/mips/include/asm/mach-db1x00/db1200.h b/arch/mips/include/asm/mach-db1x00/db1200.h
index b7f18e1..52b1d84 100644
--- a/arch/mips/include/asm/mach-db1x00/db1200.h
+++ b/arch/mips/include/asm/mach-db1x00/db1200.h
@@ -103,21 +103,6 @@ enum external_pb1200_ints {
 	DB1200_INT_END		= DB1200_INT_BEGIN + 15,
 };
 
-
-/*
- * DBAu1200 specific PCMCIA defines for drivers/pcmcia/au1000_db1x00.c
- */
-#define PCMCIA_MAX_SOCK  1
-#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
-
-/* VPP/VCC */
-#define SET_VCC_VPP(VCC, VPP, SLOT) \
-	((((VCC) << 2) | ((VPP) << 0)) << ((SLOT) * 8))
-
-#define BOARD_PC0_INT	DB1200_PC0_INT
-#define BOARD_PC1_INT	DB1200_PC1_INT
-#define BOARD_CARD_INSERTED(SOCKET) (bcsr_read(BCSR_SIGSTAT) & (1 << (8 + (2 * SOCKET))))
-
 /* NAND chip select */
 #define NAND_CS 1
 
diff --git a/arch/mips/include/asm/mach-db1x00/db1x00.h b/arch/mips/include/asm/mach-db1x00/db1x00.h
index cfa6429..a919dac 100644
--- a/arch/mips/include/asm/mach-db1x00/db1x00.h
+++ b/arch/mips/include/asm/mach-db1x00/db1x00.h
@@ -45,14 +45,6 @@
 
 #endif
 
-/* PCMCIA DBAu1x00 specific defines */
-#define PCMCIA_MAX_SOCK  1
-#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
-
-/* VPP/VCC */
-#define SET_VCC_VPP(VCC, VPP, SLOT)\
-	((((VCC) << 2) | ((VPP) << 0)) << ((SLOT) * 8))
-
 /*
  * NAND defines
  *
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1100.h b/arch/mips/include/asm/mach-pb1x00/pb1100.h
deleted file mode 100644
index f2bf73a..0000000
--- a/arch/mips/include/asm/mach-pb1x00/pb1100.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Alchemy Semi Pb1100 Referrence Board
- *
- * Copyright 2001, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.com>
- *
- * ########################################################################
- *
- *  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.
- *
- * ########################################################################
- *
- *
- */
-#ifndef __ASM_PB1100_H
-#define __ASM_PB1100_H
-
-/* PCMCIA Pb1100 specific defines */
-#define PCMCIA_MAX_SOCK  0
-#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
-
-/* VPP/VCC */
-#define SET_VCC_VPP(VCC, VPP) (((VCC) << 2) | ((VPP) << 0))
-
-#endif /* __ASM_PB1100_H */
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1200.h b/arch/mips/include/asm/mach-pb1x00/pb1200.h
index 2458eb4..962eb55 100644
--- a/arch/mips/include/asm/mach-pb1x00/pb1200.h
+++ b/arch/mips/include/asm/mach-pb1x00/pb1200.h
@@ -135,20 +135,6 @@ enum external_pb1200_ints {
 	PB1200_INT_END		= PB1200_INT_BEGIN + 15
 };
 
-/*
- * Pb1200 specific PCMCIA defines for drivers/pcmcia/au1000_db1x00.c
- */
-#define PCMCIA_MAX_SOCK  1
-#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
-
-/* VPP/VCC */
-#define SET_VCC_VPP(VCC, VPP, SLOT) \
-	((((VCC) << 2) | ((VPP) << 0)) << ((SLOT) * 8))
-
-#define BOARD_PC0_INT	PB1200_PC0_INT
-#define BOARD_PC1_INT	PB1200_PC1_INT
-#define BOARD_CARD_INSERTED(SOCKET) (bcsr_read(BCSR_SIGSTAT & (1 << (8 + (2 * SOCKET))))
-
 /* NAND chip select */
 #define NAND_CS 1
 
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1500.h b/arch/mips/include/asm/mach-pb1x00/pb1500.h
deleted file mode 100644
index 82431a7..0000000
--- a/arch/mips/include/asm/mach-pb1x00/pb1500.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Alchemy Semi Pb1500 Referrence Board
- *
- * Copyright 2001, 2008 MontaVista Software Inc.
- * Author: MontaVista Software, Inc. <source@mvista.com>
- *
- * ########################################################################
- *
- *  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.
- *
- * ########################################################################
- *
- *
- */
-#ifndef __ASM_PB1500_H
-#define __ASM_PB1500_H
-
-/* PCMCIA Pb1500 specific defines */
-#define PCMCIA_MAX_SOCK  0
-#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
-
-/* VPP/VCC */
-#define SET_VCC_VPP(VCC, VPP) (((VCC) << 2) | ((VPP) << 0))
-
-#endif /* __ASM_PB1500_H */
diff --git a/arch/mips/include/asm/mach-pb1x00/pb1550.h b/arch/mips/include/asm/mach-pb1x00/pb1550.h
index 306d584..5879641 100644
--- a/arch/mips/include/asm/mach-pb1x00/pb1550.h
+++ b/arch/mips/include/asm/mach-pb1x00/pb1550.h
@@ -40,13 +40,6 @@
 #define SMBUS_PSC_BASE		PSC2_BASE_ADDR
 #define I2S_PSC_BASE		PSC3_BASE_ADDR
 
-#define PCMCIA_MAX_SOCK  1
-#define PCMCIA_NUM_SOCKS (PCMCIA_MAX_SOCK + 1)
-
-/* VPP/VCC */
-#define SET_VCC_VPP(VCC, VPP, SLOT) \
-	((((VCC) << 2) | ((VPP) << 0)) << ((SLOT) * 8))
-
 #if defined(CONFIG_MTD_PB1550_BOOT) && defined(CONFIG_MTD_PB1550_USER)
 #define PB1550_BOTH_BANKS
 #elif defined(CONFIG_MTD_PB1550_BOOT) && !defined(CONFIG_MTD_PB1550_USER)
-- 
1.6.5.rc2


From manuel.lauss@googlemail.com Sun Oct  4 14:57:38 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Sun, 04 Oct 2009 14:57:45 +0200 (CEST)
Received: from mail-ew0-f214.google.com ([209.85.219.214]:38985 "EHLO
	mail-ew0-f214.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492538AbZJDMzo (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sun, 4 Oct 2009 14:55:44 +0200
Received: by ewy10 with SMTP id 10so1846521ewy.33
        for <multiple recipients>; Sun, 04 Oct 2009 05:55:38 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer:in-reply-to:references;
        bh=ip6vfd6EawsZjNbmsz8EUGsC7QoTnABEK2lHi0JfwqI=;
        b=JWVmdyty7bniXRPhTJBo5JqYJheoF+orqbD1RZVVybvWGW/psHHrUfj+TYA9YvO5l1
         wmNainINBW8KCwjwK86yS6Cr0+PKSGDW3dw9VIU7+w1IiyaosUgyM4y449kI3ni1Xo1O
         Z5PNUpD2zd1ejqe8jukx+iTL1hCwxsq225DWU=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        b=qjk37q9Zb0tWqNY3XjrXY0yS0fHbONX57ipFwLx0xBjJNQnFDoN3OQmZ42QeFdLdLo
         lXZZYEYoRe8LO7YGYfpt7Cyd6iZqMpP3q8GFuUGfUir+dt9G3xkv4dt0cgV3lhDtJUmf
         4YnbOsb5WBIP5ikdoHb9st0hlKekgsbfx9KXM=
Received: by 10.211.172.11 with SMTP id z11mr1992369ebo.93.1254660937388;
        Sun, 04 Oct 2009 05:55:37 -0700 (PDT)
Received: from localhost.localdomain (fnoeppeil48.netpark.at [217.175.205.176])
        by mx.google.com with ESMTPS id 28sm1555483eyg.4.2009.10.04.05.55.36
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Sun, 04 Oct 2009 05:55:36 -0700 (PDT)
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Linux-MIPS <linux-mips@linux-mips.org>,
	Ralf Baechle <ralf@linux-mips.org>
Cc:	Manuel Lauss <manuel.lauss@gmail.com>,
	Linux-PCMCIA <linux-pcmcia@lists.infradead.org>
Subject: [PATCH 4/6] PCMCIA: new socket driver for Au1000 demoboards.
Date:	Sun,  4 Oct 2009 14:55:27 +0200
Message-Id: <1254660929-15453-5-git-send-email-manuel.lauss@gmail.com>
X-Mailer: git-send-email 1.6.5.rc2
In-Reply-To: <1254660929-15453-4-git-send-email-manuel.lauss@gmail.com>
References: <1254660929-15453-1-git-send-email-manuel.lauss@gmail.com>
 <1254660929-15453-2-git-send-email-manuel.lauss@gmail.com>
 <1254660929-15453-3-git-send-email-manuel.lauss@gmail.com>
 <1254660929-15453-4-git-send-email-manuel.lauss@gmail.com>
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24142
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

New PCMCIA socket driver for all Db/Pb1xxx boards (except Pb1000),
which replaces au1000_db1x00.c and (most of) au1000_pb1x00.c.
Notable improvements:
        - supports Db1000, DB/PB1100/1500/1550/1200.
        - support for carddetect and statuschange IRQs.
        - pcmcia socket mem/io/attr areas and irqs passed through
          platform resource information.
        - doesn't freeze system during card insertion/ejection like
          the one it replaces.
        - boardtype is automatically detected using BCSR ID register.

Run-tested on the DB1200.

Cc: Linux-PCMCIA <linux-pcmcia@lists.infradead.org>
Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
V2: split the patch in two, one (this) with the PCMCIA driver part,
    the other (following) adds the board-specific socket device
    registration.
    Fixed a thinko: use bcsr_mod() in socket_configure() function.

 arch/mips/alchemy/common/platform.c        |    6 -
 arch/mips/alchemy/common/setup.c           |    3 +-
 arch/mips/include/asm/mach-au1x00/au1000.h |   14 +
 drivers/pcmcia/Kconfig                     |   11 +
 drivers/pcmcia/Makefile                    |    9 +-
 drivers/pcmcia/au1000_db1x00.c             |  307 --------------
 drivers/pcmcia/au1000_generic.h            |   12 +-
 drivers/pcmcia/au1000_pb1x00.c             |  119 +------
 drivers/pcmcia/db1xxx_ss.c                 |  630 ++++++++++++++++++++++++++++
 9 files changed, 660 insertions(+), 451 deletions(-)
 delete mode 100644 drivers/pcmcia/au1000_db1x00.c
 create mode 100644 drivers/pcmcia/db1xxx_ss.c

diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index 117f99f..2b76a57 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -308,11 +308,6 @@ static struct platform_device au1200_mmc1_device = {
 #endif /* #ifndef CONFIG_MIPS_DB1200 */
 #endif /* #ifdef CONFIG_SOC_AU1200 */
 
-static struct platform_device au1x00_pcmcia_device = {
-	.name 		= "au1x00-pcmcia",
-	.id 		= 0,
-};
-
 /* All Alchemy demoboards with I2C have this #define in their headers */
 #ifdef SMBUS_PSC_BASE
 static struct resource pbdb_smbus_resources[] = {
@@ -334,7 +329,6 @@ static struct platform_device pbdb_smbus_device = {
 static struct platform_device *au1xxx_platform_devices[] __initdata = {
 	&au1xx0_uart_device,
 	&au1xxx_usb_ohci_device,
-	&au1x00_pcmcia_device,
 #ifdef CONFIG_FB_AU1100
 	&au1100_lcd_device,
 #endif
diff --git a/arch/mips/alchemy/common/setup.c b/arch/mips/alchemy/common/setup.c
index 6184baa..375984e 100644
--- a/arch/mips/alchemy/common/setup.c
+++ b/arch/mips/alchemy/common/setup.c
@@ -107,7 +107,8 @@ phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size)
 	 * The pseudo address we use is 0xF400 0000. Any address over
 	 * 0xF400 0000 is a PCMCIA pseudo address.
 	 */
-	if ((phys_addr >= 0xF4000000) && (phys_addr < 0xFFFFFFFF))
+	if ((phys_addr >= PCMCIA_ATTR_PSEUDO_PHYS) &&
+	    (phys_addr < PCMCIA_PSEUDO_END))
 		return (phys_t)(phys_addr << 4);
 
 	/* default nop */
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index 0507822..fceeca8 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -1724,6 +1724,20 @@ enum soc_au1200_ints {
 
 #endif
 
+/*
+ * All Au1xx0 SOCs have a PCMCIA controller.
+ * We setup our 32-bit pseudo addresses to be equal to the
+ * 36-bit addr >> 4, to make it easier to check the address
+ * and fix it.
+ * The PCMCIA socket 0 physical attribute address is 0xF 4000 0000.
+ * The pseudo address we use is 0xF400 0000. Any address over
+ * 0xF400 0000 is a PCMCIA pseudo address.
+ */
+#define PCMCIA_IO_PSEUDO_PHYS	(PCMCIA_IO_PHYS_ADDR >> 4)
+#define PCMCIA_ATTR_PSEUDO_PHYS	(PCMCIA_ATTR_PHYS_ADDR >> 4)
+#define PCMCIA_MEM_PSEUDO_PHYS	(PCMCIA_MEM_PHYS_ADDR >> 4)
+#define PCMCIA_PSEUDO_END	(0xffffffff)
+
 #ifndef _LANGUAGE_ASSEMBLY
 typedef volatile struct {
 	/* 0x0000 */ u32 toytrim;
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 17f38a7..22f6814 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -192,6 +192,17 @@ config PCMCIA_AU1X00
 	tristate "Au1x00 pcmcia support"
 	depends on SOC_AU1X00 && PCMCIA
 
+config PCMCIA_ALCHEMY_DEVBOARD
+	tristate "Alchemy Db/Pb1xxx PCMCIA socket services"
+	depends on SOC_AU1X00 && PCMCIA
+	select 64BIT_PHYS_ADDR
+	help
+	  Enable this driver of you want PCMCIA support on your Alchemy
+	  Db1000, Db/Pb1100, Db/Pb1500, Db/Pb1550, Db/Pb1200 board.
+	  NOT suitable for the PB1000!
+
+	  This driver is also available as a module called db1xxx_ss.ko
+
 config PCMCIA_BCM63XX
 	tristate "bcm63xx pcmcia support"
 	depends on BCM63XX && PCMCIA
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index a03a38a..e58d162 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -34,20 +34,13 @@ obj-$(CONFIG_OMAP_CF)				+= omap_cf.o
 obj-$(CONFIG_BFIN_CFPCMCIA)			+= bfin_cf_pcmcia.o
 obj-$(CONFIG_AT91_CF)				+= at91_cf.o
 obj-$(CONFIG_ELECTRA_CF)			+= electra_cf.o
+obj-$(CONFIG_PCMCIA_ALCHEMY_DEVBOARD)		+= db1xxx_ss.o
 
 sa11xx_core-y					+= soc_common.o sa11xx_base.o
 pxa2xx_core-y					+= soc_common.o pxa2xx_base.o
 
 au1x00_ss-y					+= au1000_generic.o
 au1x00_ss-$(CONFIG_MIPS_PB1000)			+= au1000_pb1x00.o
-au1x00_ss-$(CONFIG_MIPS_PB1100)			+= au1000_pb1x00.o
-au1x00_ss-$(CONFIG_MIPS_PB1200)			+= au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_PB1500)			+= au1000_pb1x00.o
-au1x00_ss-$(CONFIG_MIPS_DB1000)			+= au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_DB1100)			+= au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_DB1200)			+= au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_DB1500)			+= au1000_db1x00.o
-au1x00_ss-$(CONFIG_MIPS_DB1550)			+= au1000_db1x00.o
 au1x00_ss-$(CONFIG_MIPS_XXS1500)		+= au1000_xxs1500.o
 
 sa1111_cs-y					+= sa1111_generic.o
diff --git a/drivers/pcmcia/au1000_db1x00.c b/drivers/pcmcia/au1000_db1x00.c
deleted file mode 100644
index 3fdd664..0000000
--- a/drivers/pcmcia/au1000_db1x00.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- *
- * Alchemy Semi Db1x00 boards specific pcmcia routines.
- *
- * Copyright 2002 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *         	ppopov@mvista.com or source@mvista.com
- *
- * Copyright 2004 Pete Popov, updated the driver to 2.6.
- * Followed the sa11xx API and largely copied many of the hardware
- * independent functions.
- *
- * ########################################################################
- *
- *  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.
- *
- * ########################################################################
- *
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/init.h>
-
-#include <asm/irq.h>
-#include <asm/signal.h>
-#include <asm/mach-au1x00/au1000.h>
-
-#if defined(CONFIG_MIPS_DB1200)
-	#include <db1200.h>
-#elif defined(CONFIG_MIPS_PB1200)
-	#include <pb1200.h>
-#else
-	#include <asm/mach-db1x00/db1x00.h>
-#endif
-
-#include <asm/mach-db1x00/bcsr.h>
-#include "au1000_generic.h"
-
-#if 0
-#define debug(x,args...) printk(KERN_DEBUG "%s: " x, __func__ , ##args)
-#else
-#define debug(x,args...)
-#endif
-
-
-struct au1000_pcmcia_socket au1000_pcmcia_socket[PCMCIA_NUM_SOCKS];
-extern int au1x00_pcmcia_socket_probe(struct device *, struct pcmcia_low_level *, int, int);
-
-static int db1x00_pcmcia_hw_init(struct au1000_pcmcia_socket *skt)
-{
-#ifdef CONFIG_MIPS_DB1550
-	skt->irq = skt->nr ? AU1000_GPIO_5 : AU1000_GPIO_3;
-#elif defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200)
-	skt->irq = skt->nr ? BOARD_PC1_INT : BOARD_PC0_INT;
-#else
-	skt->irq = skt->nr ? AU1000_GPIO_5 : AU1000_GPIO_2;
-#endif
-	return 0;
-}
-
-static void db1x00_pcmcia_shutdown(struct au1000_pcmcia_socket *skt)
-{
-	bcsr_write(BCSR_PCMCIA, 0);	/* turn off power */
-	msleep(2);
-}
-
-static void
-db1x00_pcmcia_socket_state(struct au1000_pcmcia_socket *skt, struct pcmcia_state *state)
-{
-	u32 inserted;
-	unsigned char vs;
-
-	state->ready = 0;
-	state->vs_Xv = 0;
-	state->vs_3v = 0;
-	state->detect = 0;
-
-	switch (skt->nr) {
-	case 0:
-		vs = bcsr_read(BCSR_STATUS) & 0x3;
-#if defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200)
-		inserted = BOARD_CARD_INSERTED(0);
-#else
-		inserted = !(bcsr_read(BCSR_STATUS) & (1 << 4));
-#endif
-		break;
-	case 1:
-		vs = (bcsr_read(BCSR_STATUS) & 0xC) >> 2;
-#if defined(CONFIG_MIPS_DB1200) || defined(CONFIG_MIPS_PB1200)
-		inserted = BOARD_CARD_INSERTED(1);
-#else
-		inserted = !(bcsr_read(BCSR_STATUS) & (1<<5));
-#endif
-		break;
-	default:/* should never happen */
-		return;
-	}
-
-	if (inserted)
-		debug("db1x00 socket %d: inserted %d, vs %d pcmcia %x\n",
-				skt->nr, inserted, vs, bcsr_read(BCSR_PCMCIA));
-
-	if (inserted) {
-		switch (vs) {
-			case 0:
-			case 2:
-				state->vs_3v=1;
-				break;
-			case 3: /* 5V */
-				break;
-			default:
-				/* return without setting 'detect' */
-				printk(KERN_ERR "db1x00 bad VS (%d)\n",
-						vs);
-		}
-		state->detect = 1;
-		state->ready = 1;
-	}
-	else {
-		/* if the card was previously inserted and then ejected,
-		 * we should turn off power to it
-		 */
-		if ((skt->nr == 0) &&
-		    (bcsr_read(BCSR_PCMCIA) & BCSR_PCMCIA_PC0RST)) {
-			bcsr_mod(BCSR_PCMCIA, BCSR_PCMCIA_PC0RST   |
-					      BCSR_PCMCIA_PC0DRVEN |
-					      BCSR_PCMCIA_PC0VPP   |
-					      BCSR_PCMCIA_PC0VCC, 0);
-			msleep(10);
-		}
-		else if ((skt->nr == 1) &&
-			 (bcsr_read(BCSR_PCMCIA) & BCSR_PCMCIA_PC1RST)) {
-			bcsr_mod(BCSR_PCMCIA, BCSR_PCMCIA_PC1RST   |
-					      BCSR_PCMCIA_PC1DRVEN |
-					      BCSR_PCMCIA_PC1VPP   |
-					      BCSR_PCMCIA_PC1VCC, 0);
-			msleep(10);
-		}
-	}
-
-	state->bvd1=1;
-	state->bvd2=1;
-	state->wrprot=0;
-}
-
-static int
-db1x00_pcmcia_configure_socket(struct au1000_pcmcia_socket *skt, struct socket_state_t *state)
-{
-	u16 pwr;
-	int sock = skt->nr;
-
-	debug("config_skt %d Vcc %dV Vpp %dV, reset %d\n",
-			sock, state->Vcc, state->Vpp,
-			state->flags & SS_RESET);
-
-	/* pcmcia reg was set to zero at init time. Be careful when
-	 * initializing a socket not to wipe out the settings of the
-	 * other socket.
-	 */
-	pwr = bcsr_read(BCSR_PCMCIA);
-	pwr &= ~(0xf << sock*8); /* clear voltage settings */
-
-	state->Vpp = 0;
-	switch(state->Vcc){
-		case 0:  /* Vcc 0 */
-			pwr |= SET_VCC_VPP(0,0,sock);
-			break;
-		case 50: /* Vcc 5V */
-			switch(state->Vpp) {
-				case 0:
-					pwr |= SET_VCC_VPP(2,0,sock);
-					break;
-				case 50:
-					pwr |= SET_VCC_VPP(2,1,sock);
-					break;
-				case 12:
-					pwr |= SET_VCC_VPP(2,2,sock);
-					break;
-				case 33:
-				default:
-					pwr |= SET_VCC_VPP(0,0,sock);
-					printk("%s: bad Vcc/Vpp (%d:%d)\n",
-							__func__,
-							state->Vcc,
-							state->Vpp);
-					break;
-			}
-			break;
-		case 33: /* Vcc 3.3V */
-			switch(state->Vpp) {
-				case 0:
-					pwr |= SET_VCC_VPP(1,0,sock);
-					break;
-				case 12:
-					pwr |= SET_VCC_VPP(1,2,sock);
-					break;
-				case 33:
-					pwr |= SET_VCC_VPP(1,1,sock);
-					break;
-				case 50:
-				default:
-					pwr |= SET_VCC_VPP(0,0,sock);
-					printk("%s: bad Vcc/Vpp (%d:%d)\n",
-							__func__,
-							state->Vcc,
-							state->Vpp);
-					break;
-			}
-			break;
-		default: /* what's this ? */
-			pwr |= SET_VCC_VPP(0,0,sock);
-			printk(KERN_ERR "%s: bad Vcc %d\n",
-					__func__, state->Vcc);
-			break;
-	}
-
-	bcsr_write(BCSR_PCMCIA, pwr);
-	msleep(300);
-
-	if (sock == 0) {
-		if (!(state->flags & SS_RESET)) {
-			pwr |= BCSR_PCMCIA_PC0DRVEN;
-			bcsr_write(BCSR_PCMCIA, pwr);
-			msleep(300);
-			pwr |= BCSR_PCMCIA_PC0RST;
-			bcsr_write(BCSR_PCMCIA, pwr);
-			msleep(100);
-		}
-		else {
-			pwr &= ~(BCSR_PCMCIA_PC0RST | BCSR_PCMCIA_PC0DRVEN);
-			bcsr_write(BCSR_PCMCIA, pwr);
-			msleep(100);
-		}
-	}
-	else {
-		if (!(state->flags & SS_RESET)) {
-			pwr |= BCSR_PCMCIA_PC1DRVEN;
-			bcsr_write(BCSR_PCMCIA, pwr);
-			msleep(300);
-			pwr |= BCSR_PCMCIA_PC1RST;
-			bcsr_write(BCSR_PCMCIA, pwr);
-			msleep(100);
-		}
-		else {
-			pwr &= ~(BCSR_PCMCIA_PC1RST | BCSR_PCMCIA_PC1DRVEN);
-			bcsr_write(BCSR_PCMCIA, pwr);
-			msleep(100);
-		}
-	}
-	return 0;
-}
-
-/*
- * Enable card status IRQs on (re-)initialisation.  This can
- * be called at initialisation, power management event, or
- * pcmcia event.
- */
-void db1x00_socket_init(struct au1000_pcmcia_socket *skt)
-{
-	/* nothing to do for now */
-}
-
-/*
- * Disable card status IRQs and PCMCIA bus on suspend.
- */
-void db1x00_socket_suspend(struct au1000_pcmcia_socket *skt)
-{
-	/* nothing to do for now */
-}
-
-struct pcmcia_low_level db1x00_pcmcia_ops = {
-	.owner			= THIS_MODULE,
-
-	.hw_init 		= db1x00_pcmcia_hw_init,
-	.hw_shutdown		= db1x00_pcmcia_shutdown,
-
-	.socket_state		= db1x00_pcmcia_socket_state,
-	.configure_socket	= db1x00_pcmcia_configure_socket,
-
-	.socket_init		= db1x00_socket_init,
-	.socket_suspend		= db1x00_socket_suspend
-};
-
-int au1x_board_init(struct device *dev)
-{
-	int ret = -ENODEV;
-	bcsr_write(BCSR_PCMCIA, 0); /* turn off power, if it's not already off */
-	msleep(2);
-	ret = au1x00_pcmcia_socket_probe(dev, &db1x00_pcmcia_ops, 0, 2);
-	return ret;
-}
diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h
index 13a4fbc..aa743f6 100644
--- a/drivers/pcmcia/au1000_generic.h
+++ b/drivers/pcmcia/au1000_generic.h
@@ -44,22 +44,12 @@
 /* pcmcia socket 1 needs external glue logic so the memory map
  * differs from board to board.
  */
-#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || \
-    defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1550) || \
-    defined(CONFIG_MIPS_PB1200)
+#if defined(CONFIG_MIPS_PB1000)
 #define AU1X_SOCK1_IO        0xF08000000ULL
 #define AU1X_SOCK1_PHYS_ATTR 0xF48000000ULL
 #define AU1X_SOCK1_PHYS_MEM  0xF88000000ULL
 #define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4800000
 #define AU1X_SOCK1_PSEUDO_PHYS_MEM  0xF8800000
-#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || \
-      defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550) || \
-      defined(CONFIG_MIPS_DB1200)
-#define AU1X_SOCK1_IO        0xF04000000ULL
-#define AU1X_SOCK1_PHYS_ATTR 0xF44000000ULL
-#define AU1X_SOCK1_PHYS_MEM  0xF84000000ULL
-#define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4400000
-#define AU1X_SOCK1_PSEUDO_PHYS_MEM  0xF8400000
 #endif
 
 struct pcmcia_state {
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c
index b1984ed..5a979cb 100644
--- a/drivers/pcmcia/au1000_pb1x00.c
+++ b/drivers/pcmcia/au1000_pb1x00.c
@@ -1,6 +1,6 @@
 /*
  *
- * Alchemy Semi Pb1x00 boards specific pcmcia routines.
+ * Alchemy Semi Pb1000 boards specific pcmcia routines.
  *
  * Copyright 2002 MontaVista Software Inc.
  * Author: MontaVista Software, Inc.
@@ -46,20 +46,11 @@
 
 #define debug(fmt, arg...) do { } while (0)
 
-#ifdef CONFIG_MIPS_PB1000
 #include <asm/pb1000.h>
 #define PCMCIA_IRQ AU1000_GPIO_15
-#elif defined (CONFIG_MIPS_PB1500)
-#include <asm/pb1500.h>
-#define PCMCIA_IRQ AU1500_GPIO_203
-#elif defined (CONFIG_MIPS_PB1100)
-#include <asm/pb1100.h>
-#define PCMCIA_IRQ AU1000_GPIO_11
-#endif
 
 static int pb1x00_pcmcia_init(struct pcmcia_init *init)
 {
-#ifdef CONFIG_MIPS_PB1000
 	u16 pcr;
 	pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST;
 
@@ -74,21 +65,10 @@ static int pb1x00_pcmcia_init(struct pcmcia_init *init)
 	au_sync_delay(20);
 	  
 	return PCMCIA_NUM_SOCKS;
-
-#else /* fixme -- take care of the Pb1500 at some point */
-
-	u16 pcr;
-	pcr = au_readw(PCMCIA_BOARD_REG) & ~0xf; /* turn off power */
-	pcr &= ~(PC_DEASSERT_RST | PC_DRV_EN);
-	au_writew(pcr, PCMCIA_BOARD_REG);
-	au_sync_delay(500);
-	return PCMCIA_NUM_SOCKS;
-#endif
 }
 
 static int pb1x00_pcmcia_shutdown(void)
 {
-#ifdef CONFIG_MIPS_PB1000
 	u16 pcr;
 	pcr = PCR_SLOT_0_RST | PCR_SLOT_1_RST;
 	pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,0);
@@ -96,14 +76,6 @@ static int pb1x00_pcmcia_shutdown(void)
 	au_writel(pcr, PB1000_PCR);
 	au_sync_delay(20);
 	return 0;
-#else
-	u16 pcr;
-	pcr = au_readw(PCMCIA_BOARD_REG) & ~0xf; /* turn off power */
-	pcr &= ~(PC_DEASSERT_RST | PC_DRV_EN);
-	au_writew(pcr, PCMCIA_BOARD_REG);
-	au_sync_delay(2);
-	return 0;
-#endif
 }
 
 static int 
@@ -112,21 +84,11 @@ pb1x00_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
 	u32 inserted0, inserted1;
 	u16 vs0, vs1;
 
-#ifdef CONFIG_MIPS_PB1000
 	vs0 = vs1 = (u16)au_readl(PB1000_ACR1);
 	inserted0 = !(vs0 & (ACR1_SLOT_0_CD1 | ACR1_SLOT_0_CD2));
 	inserted1 = !(vs1 & (ACR1_SLOT_1_CD1 | ACR1_SLOT_1_CD2));
 	vs0 = (vs0 >> 4) & 0x3;
 	vs1 = (vs1 >> 12) & 0x3;
-#else
-	vs0 = (au_readw(BOARD_STATUS_REG) >> 4) & 0x3;
-#ifdef CONFIG_MIPS_PB1500
-	inserted0 = !((au_readl(GPIO2_PINSTATE) >> 1) & 0x1); /* gpio 201 */
-#else /* Pb1100 */
-	inserted0 = !((au_readl(SYS_PINSTATERD) >> 9) & 0x1); /* gpio 9 */
-#endif
-	inserted1 = 0;
-#endif
 
 	state->ready = 0;
 	state->vs_Xv = 0;
@@ -203,7 +165,6 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
 
 	if(configure->sock > PCMCIA_MAX_SOCK) return -1;
 
-#ifdef CONFIG_MIPS_PB1000
 	pcr = au_readl(PB1000_PCR);
 
 	if (configure->sock == 0) {
@@ -323,84 +284,6 @@ pb1x00_pcmcia_configure_socket(const struct pcmcia_configure *configure)
 	au_writel(pcr, PB1000_PCR);
 	au_sync_delay(300);
 
-#else
-
-	pcr = au_readw(PCMCIA_BOARD_REG) & ~0xf;
-
-	debug("Vcc %dV Vpp %dV, pcr %x, reset %d\n", 
-			configure->vcc, configure->vpp, pcr, configure->reset);
-
-
-	switch(configure->vcc){
-		case 0:  /* Vcc 0 */
-			pcr |= SET_VCC_VPP(0,0);
-			break;
-		case 50: /* Vcc 5V */
-			switch(configure->vpp) {
-				case 0:
-					pcr |= SET_VCC_VPP(2,0);
-					break;
-				case 50:
-					pcr |= SET_VCC_VPP(2,1);
-					break;
-				case 12:
-					pcr |= SET_VCC_VPP(2,2);
-					break;
-				case 33:
-				default:
-					pcr |= SET_VCC_VPP(0,0);
-					printk("%s: bad Vcc/Vpp (%d:%d)\n", 
-							__func__,
-							configure->vcc, 
-							configure->vpp);
-					break;
-			}
-			break;
-		case 33: /* Vcc 3.3V */
-			switch(configure->vpp) {
-				case 0:
-					pcr |= SET_VCC_VPP(1,0);
-					break;
-				case 12:
-					pcr |= SET_VCC_VPP(1,2);
-					break;
-				case 33:
-					pcr |= SET_VCC_VPP(1,1);
-					break;
-				case 50:
-				default:
-					pcr |= SET_VCC_VPP(0,0);
-					printk("%s: bad Vcc/Vpp (%d:%d)\n", 
-							__func__,
-							configure->vcc, 
-							configure->vpp);
-					break;
-			}
-			break;
-		default: /* what's this ? */
-			pcr |= SET_VCC_VPP(0,0);
-			printk(KERN_ERR "%s: bad Vcc %d\n", 
-					__func__, configure->vcc);
-			break;
-	}
-
-	au_writew(pcr, PCMCIA_BOARD_REG);
-	au_sync_delay(300);
-
-	if (!configure->reset) {
-		pcr |= PC_DRV_EN;
-		au_writew(pcr, PCMCIA_BOARD_REG);
-		au_sync_delay(100);
-		pcr |= PC_DEASSERT_RST;
-		au_writew(pcr, PCMCIA_BOARD_REG);
-		au_sync_delay(100);
-	}
-	else {
-		pcr &= ~(PC_DEASSERT_RST | PC_DRV_EN);
-		au_writew(pcr, PCMCIA_BOARD_REG);
-		au_sync_delay(100);
-	}
-#endif
 	return 0;
 }
 
diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c
new file mode 100644
index 0000000..b35b72b
--- /dev/null
+++ b/drivers/pcmcia/db1xxx_ss.c
@@ -0,0 +1,630 @@
+/*
+ * PCMCIA socket code for the Alchemy Db1xxx/Pb1xxx boards.
+ *
+ * Copyright (c) 2009 Manuel Lauss <manuel.lauss@gmail.com>
+ *
+ */
+
+/* This is a fairly generic PCMCIA socket driver suitable for the
+ * following Alchemy Development boards:
+ *  Db1000, Db/Pb1500, Db/Pb1100, Db/Pb1550, Db/Pb1200.
+ *
+ * The Db1000 is used as a reference:  Per-socket card-, carddetect- and
+ *  statuschange IRQs connected to SoC GPIOs, control and status register
+ *  bits arranged in per-socket groups in an external PLD.  All boards
+ *  listed here use this layout, including bit positions and meanings.
+ *  Of course there are exceptions in later boards:
+ *
+ *	- Pb1100/Pb1500:  single socket only; voltage key bits VS are
+ *			  at STATUS[5:4] (instead of STATUS[1:0]).
+ *	- Au1200-based:	  additional card-eject irqs, irqs not gpios!
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+#include <linux/spinlock.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+
+#include <asm/mach-au1x00/au1000.h>
+#include <asm/mach-db1x00/bcsr.h>
+
+#define MEM_MAP_SIZE	0x400000
+#define IO_MAP_SIZE	0x1000
+
+struct db1x_pcmcia_sock {
+	struct pcmcia_socket	socket;
+	int		nr;		/* socket number */
+	void		*virt_io;
+
+	/* the "pseudo" addresses of the PCMCIA space. */
+	unsigned long	phys_io;
+	unsigned long	phys_attr;
+	unsigned long	phys_mem;
+
+	/* previous flags for set_socket() */
+	unsigned int old_flags;
+
+	/* interrupt sources: linux irq numbers! */
+	int	insert_irq;	/* default carddetect irq */
+	int	stschg_irq;	/* card-status-change irq */
+	int	card_irq;	/* card irq */
+	int	eject_irq;	/* db1200/pb1200 have these */
+
+#define BOARD_TYPE_DEFAULT	0	/* most boards */
+#define BOARD_TYPE_DB1200	1	/* IRQs aren't gpios */
+#define BOARD_TYPE_PB1100	2	/* VS bits slightly different */
+	int	board_type;
+};
+
+#define to_db1x_socket(x) container_of(x, struct db1x_pcmcia_sock, socket)
+
+/* DB/PB1200: check CPLD SIGSTATUS register bit 10/12 */
+static int db1200_card_inserted(struct db1x_pcmcia_sock *sock)
+{
+	unsigned short sigstat;
+
+	sigstat = bcsr_read(BCSR_SIGSTAT);
+	return sigstat & 1 << (8 + 2 * sock->nr);
+}
+
+/* carddetect gpio: low-active */
+static int db1000_card_inserted(struct db1x_pcmcia_sock *sock)
+{
+	return !gpio_get_value(irq_to_gpio(sock->insert_irq));
+}
+
+static int db1x_card_inserted(struct db1x_pcmcia_sock *sock)
+{
+	switch (sock->board_type) {
+	case BOARD_TYPE_DB1200:
+		return db1200_card_inserted(sock);
+	default:
+		return db1000_card_inserted(sock);
+	}
+}
+
+/* STSCHG tends to bounce heavily when cards are inserted/ejected.
+ * To avoid this, the interrupt is normally disabled and only enabled
+ * after reset to a card has been de-asserted.
+ */
+static inline void set_stschg(struct db1x_pcmcia_sock *sock, int en)
+{
+	if (sock->stschg_irq != -1) {
+		if (en)
+			enable_irq(sock->stschg_irq);
+		else
+			disable_irq(sock->stschg_irq);
+	}
+}
+
+static irqreturn_t db1000_pcmcia_cdirq(int irq, void *data)
+{
+	struct db1x_pcmcia_sock *sock = data;
+
+	pcmcia_parse_events(&sock->socket, SS_DETECT);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t db1000_pcmcia_stschgirq(int irq, void *data)
+{
+	struct db1x_pcmcia_sock *sock = data;
+
+	pcmcia_parse_events(&sock->socket, SS_STSCHG);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t db1200_pcmcia_cdirq(int irq, void *data)
+{
+	struct db1x_pcmcia_sock *sock = data;
+
+	/* Db/Pb1200 have separate per-socket insertion and ejection
+	 * interrupts which stay asserted as long as the card is
+	 * inserted/missing.  The one which caused us to be called
+	 * needs to be disabled and the other one enabled.
+	 */
+	if (irq == sock->insert_irq) {
+		disable_irq_nosync(sock->insert_irq);
+		enable_irq(sock->eject_irq);
+	} else {
+		disable_irq_nosync(sock->eject_irq);
+		enable_irq(sock->insert_irq);
+	}
+
+	pcmcia_parse_events(&sock->socket, SS_DETECT);
+
+	return IRQ_HANDLED;
+}
+
+static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
+{
+	int ret;
+	unsigned long flags;
+
+	if (sock->stschg_irq != -1) {
+		ret = request_irq(sock->stschg_irq, db1000_pcmcia_stschgirq,
+				  0, "pcmcia_stschg", sock);
+		if (ret)
+			return ret;
+	}
+
+	/* Db/Pb1200 have separate per-socket insertion and ejection
+	 * interrupts, which should show edge behaviour but don't.
+	 * So interrupts are disabled until both insertion and
+	 * ejection handler have been registered and the currently
+	 * active one disabled.
+	 */
+	if (sock->board_type == BOARD_TYPE_DB1200) {
+		local_irq_save(flags);
+
+		ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq,
+				  IRQF_DISABLED, "pcmcia_insert", sock);
+		if (ret)
+			goto out1;
+
+		ret = request_irq(sock->eject_irq, db1200_pcmcia_cdirq,
+				  IRQF_DISABLED, "pcmcia_eject", sock);
+		if (ret) {
+			free_irq(sock->insert_irq, sock);
+			local_irq_restore(flags);
+			goto out1;
+		}
+
+		/* disable the currently active one */
+		if (db1200_card_inserted(sock))
+			disable_irq_nosync(sock->insert_irq);
+		else
+			disable_irq_nosync(sock->eject_irq);
+
+		local_irq_restore(flags);
+	} else {
+		/* all other (older) Db1x00 boards use a GPIO to show
+		 * card detection status:  use both-edge triggers.
+		 */
+		set_irq_type(sock->insert_irq, IRQ_TYPE_EDGE_BOTH);
+		ret = request_irq(sock->insert_irq, db1000_pcmcia_cdirq,
+				  0, "pcmcia_carddetect", sock);
+
+		if (ret)
+			goto out1;
+	}
+
+	return 0;	/* all done */
+
+out1:
+	if (sock->stschg_irq != -1)
+		free_irq(sock->stschg_irq, sock);
+
+	return ret;
+}
+
+static void db1x_pcmcia_free_irqs(struct db1x_pcmcia_sock *sock)
+{
+	if (sock->stschg_irq != -1)
+		free_irq(sock->stschg_irq, sock);
+
+	free_irq(sock->insert_irq, sock);
+	if (sock->eject_irq != -1)
+		free_irq(sock->eject_irq, sock);
+}
+
+/*
+ * configure a PCMCIA socket on the Db1x00 series of boards (and
+ * compatibles).
+ *
+ * 2 external registers are involved:
+ *   pcmcia_status (offset 0x04): bits [0:1/2:3]: read card voltage id
+ *   pcmcia_control(offset 0x10):
+ *	bits[0:1] set vcc for card
+ *	bits[2:3] set vpp for card
+ *	bit 4:	enable data buffers
+ *	bit 7:	reset# for card
+ *	add 8 for second socket.
+ */
+static int db1x_pcmcia_configure(struct pcmcia_socket *skt,
+				 struct socket_state_t *state)
+{
+	struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
+	unsigned short cr_clr, cr_set;
+	unsigned int changed;
+	int v, p, ret;
+
+	/* card voltage setup */
+	cr_clr = (0xf << (sock->nr * 8)); /* clear voltage settings */
+	cr_set = 0;
+	v = p = ret = 0;
+
+	switch (state->Vcc) {
+	case 50:
+		++v;
+	case 33:
+		++v;
+	case 0:
+		break;
+	default:
+		printk(KERN_INFO "pcmcia%d unsupported Vcc %d\n",
+			sock->nr, state->Vcc);
+	}
+
+	switch (state->Vpp) {
+	case 12:
+		++p;
+	case 33:
+	case 50:
+		++p;
+	case 0:
+		break;
+	default:
+		printk(KERN_INFO "pcmcia%d unsupported Vpp %d\n",
+			sock->nr, state->Vpp);
+	}
+
+	/* sanity check: Vpp must be 0, 12, or Vcc */
+	if (((state->Vcc == 33) && (state->Vpp == 50)) ||
+	    ((state->Vcc == 50) && (state->Vpp == 33))) {
+		printk(KERN_INFO "pcmcia%d bad Vcc/Vpp combo (%d %d)\n",
+			sock->nr, state->Vcc, state->Vpp);
+		v = p = 0;
+		ret = -EINVAL;
+	}
+
+	/* create new voltage code */
+	cr_set |= ((v << 2) | p) << (sock->nr * 8);
+
+	changed = state->flags ^ sock->old_flags;
+
+	if (changed & SS_RESET) {
+		if (state->flags & SS_RESET) {
+			set_stschg(sock, 0);
+			/* assert reset, disable io buffers */
+			cr_clr |= (1 << (7 + (sock->nr * 8)));
+			cr_clr |= (1 << (4 + (sock->nr * 8)));
+		} else {
+			/* de-assert reset, enable io buffers */
+			cr_set |= 1 << (7 + (sock->nr * 8));
+			cr_set |= 1 << (4 + (sock->nr * 8));
+		}
+	}
+
+	/* update PCMCIA configuration */
+	bcsr_mod(BCSR_PCMCIA, cr_clr, cr_set);
+
+	sock->old_flags = state->flags;
+
+	/* reset was taken away: give card time to initialize properly */
+	if ((changed & SS_RESET) && !(state->flags & SS_RESET)) {
+		msleep(500);
+		set_stschg(sock, 1);
+	}
+
+	return ret;
+}
+
+/* VCC bits at [3:2]/[11:10] */
+#define GET_VCC(cr, socknr)		\
+	((((cr) >> 2) >> ((socknr) * 8)) & 3)
+
+/* VS bits at [0:1]/[3:2] */
+#define GET_VS(sr, socknr)		\
+	(((sr) >> (2 * (socknr))) & 3)
+
+/* reset bits at [7]/[15] */
+#define GET_RESET(cr, socknr)		\
+	((cr) & (1 << (7 + (8 * (socknr)))))
+
+static int db1x_pcmcia_get_status(struct pcmcia_socket *skt,
+				  unsigned int *value)
+{
+	struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
+	unsigned short cr, sr;
+	unsigned int status;
+
+	status = db1x_card_inserted(sock) ? SS_DETECT : 0;
+
+	cr = bcsr_read(BCSR_PCMCIA);
+	sr = bcsr_read(BCSR_STATUS);
+
+	/* PB1100/PB1500: voltage key bits are at [5:4] */
+	if (sock->board_type == BOARD_TYPE_PB1100)
+		sr >>= 4;
+
+	/* determine card type */
+	switch (GET_VS(sr, sock->nr)) {
+	case 0:
+	case 2:
+		status |= SS_3VCARD;	/* 3V card */
+	case 3:
+		break;			/* 5V card: set nothing */
+	default:
+		status |= SS_XVCARD;	/* treated as unsupported in core */
+	}
+
+	/* if Vcc is not zero, we have applied power to a card */
+	status |= GET_VCC(cr, sock->nr) ? SS_POWERON : 0;
+
+	/* reset de-asserted? then we're ready */
+	status |= (GET_RESET(cr, sock->nr)) ? SS_READY : SS_RESET;
+
+	*value = status;
+
+	return 0;
+}
+
+static int db1x_pcmcia_sock_init(struct pcmcia_socket *skt)
+{
+	return 0;
+}
+
+static int db1x_pcmcia_sock_suspend(struct pcmcia_socket *skt)
+{
+	return 0;
+}
+
+static int au1x00_pcmcia_set_io_map(struct pcmcia_socket *skt,
+				    struct pccard_io_map *map)
+{
+	struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
+
+	map->start = (u32)sock->virt_io;
+	map->stop = map->start + IO_MAP_SIZE;
+
+	return 0;
+}
+
+static int au1x00_pcmcia_set_mem_map(struct pcmcia_socket *skt,
+				     struct pccard_mem_map *map)
+{
+	struct db1x_pcmcia_sock *sock = to_db1x_socket(skt);
+
+	if (map->flags & MAP_ATTRIB)
+		map->static_start = sock->phys_attr + map->card_start;
+	else
+		map->static_start = sock->phys_mem + map->card_start;
+
+	return 0;
+}
+
+static struct pccard_operations db1x_pcmcia_operations = {
+	.init			= db1x_pcmcia_sock_init,
+	.suspend		= db1x_pcmcia_sock_suspend,
+	.get_status		= db1x_pcmcia_get_status,
+	.set_socket		= db1x_pcmcia_configure,
+	.set_io_map		= au1x00_pcmcia_set_io_map,
+	.set_mem_map		= au1x00_pcmcia_set_mem_map,
+};
+
+static int __devinit db1x_pcmcia_socket_probe(struct platform_device *pdev)
+{
+	struct db1x_pcmcia_sock *sock;
+	struct resource *r;
+	phys_t physio;
+	int ret, bid;
+
+	sock = kzalloc(sizeof(struct db1x_pcmcia_sock), GFP_KERNEL);
+	if (!sock)
+		return -ENOMEM;
+
+	sock->nr = pdev->id;
+
+	bid = BCSR_WHOAMI_BOARD(bcsr_read(BCSR_WHOAMI));
+	switch (bid) {
+	case BCSR_WHOAMI_PB1500:
+	case BCSR_WHOAMI_PB1500R2:
+	case BCSR_WHOAMI_PB1100:
+		sock->board_type = BOARD_TYPE_PB1100;
+		break;
+	case BCSR_WHOAMI_DB1000 ... BCSR_WHOAMI_PB1550_SDR:
+		sock->board_type = BOARD_TYPE_DEFAULT;
+		break;
+	case BCSR_WHOAMI_PB1200 ... BCSR_WHOAMI_DB1200:
+		sock->board_type = BOARD_TYPE_DB1200;
+		break;
+	default:
+		printk(KERN_INFO "db1xxx-ss: unknown board %d!\n", bid);
+		ret = -ENODEV;
+		goto out0;
+	};
+
+	/*
+	 * gather resources necessary and optional nice-to-haves to
+	 * operate a socket:
+	 * This includes IRQs for Carddetection/ejection, the card
+	 *  itself and optional status change detection.
+	 * Also, the memory areas covered by a socket.  For these
+	 *  we require the 32bit "pseudo" addresses (see the au1000.h
+	 *  header for more information).
+	 */
+
+	/* card: irq assigned to the card itself. */
+	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "card");
+	sock->card_irq = r ? r->start : 0;
+
+	/* insert: irq which triggers on card insertion/ejection */
+	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "insert");
+	sock->insert_irq = r ? r->start : -1;
+
+	/* stschg: irq which trigger on card status change (optional) */
+	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "stschg");
+	sock->stschg_irq = r ? r->start : -1;
+
+	/* eject: irq which triggers on ejection (DB1200/PB1200 only) */
+	r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "eject");
+	sock->eject_irq = r ? r->start : -1;
+
+	ret = -ENODEV;
+
+	/*
+	 * pseudo-attr:  The 32bit address of the PCMCIA attribute space
+	 * for this socket (usually the 36bit address shifted 4 to the
+	 * right).
+	 */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-attr");
+	if (!r) {
+		printk(KERN_ERR "pcmcia%d has no 'pseudo-attr' resource!\n",
+			sock->nr);
+		goto out0;
+	}
+	sock->phys_attr = r->start;
+
+	/*
+	 * pseudo-mem:  The 32bit address of the PCMCIA memory space for
+	 * this socket (usually the 36bit address shifted 4 to the right)
+	 */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-mem");
+	if (!r) {
+		printk(KERN_ERR "pcmcia%d has no 'pseudo-mem' resource!\n",
+			sock->nr);
+		goto out0;
+	}
+	sock->phys_mem = r->start;
+
+	/*
+	 * pseudo-io:  The 32bit address of the PCMCIA IO space for this
+	 * socket (usually the 36bit address shifted 4 to the right).
+	 */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-io");
+	if (!r) {
+		printk(KERN_ERR "pcmcia%d has no 'pseudo-io' resource!\n",
+			sock->nr);
+		goto out0;
+	}
+	sock->phys_io = r->start;
+
+
+	/* IO: we must remap the full 36bit address (for reference see
+	 * alchemy/common/setup.c::__fixup_bigphys_addr())
+	 */
+	physio = ((phys_t)sock->phys_io) << 4;
+
+	/*
+	 * PCMCIA client drivers use the inb/outb macros to access
+	 * the IO registers.  Since mips_io_port_base is added
+	 * to the access address of the mips implementation of
+	 * inb/outb, we need to subtract it here because we want
+	 * to access the I/O or MEM address directly, without
+	 * going through this "mips_io_port_base" mechanism.
+	 */
+	sock->virt_io = (void *)(ioremap(physio, IO_MAP_SIZE) -
+				 mips_io_port_base);
+
+	if (!sock->virt_io) {
+		printk(KERN_ERR "pcmcia%d: cannot remap IO area\n",
+			sock->nr);
+		ret = -ENOMEM;
+		goto out0;
+	}
+
+	sock->socket.ops	= &db1x_pcmcia_operations;
+	sock->socket.owner	= THIS_MODULE;
+	sock->socket.pci_irq	= sock->card_irq;
+	sock->socket.features	= SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
+	sock->socket.map_size	= MEM_MAP_SIZE;
+	sock->socket.io_offset	= (unsigned long)sock->virt_io;
+	sock->socket.dev.parent	= &pdev->dev;
+	sock->socket.resource_ops = &pccard_static_ops;
+
+	platform_set_drvdata(pdev, sock);
+
+	ret = db1x_pcmcia_setup_irqs(sock);
+	if (ret) {
+		printk(KERN_ERR "pcmcia%d cannot setup interrupts\n",
+			sock->nr);
+		goto out1;
+	}
+
+	set_stschg(sock, 0);
+
+	ret = pcmcia_register_socket(&sock->socket);
+	if (ret) {
+		printk(KERN_ERR "pcmcia%d failed to register\n", sock->nr);
+		goto out2;
+	}
+
+	printk(KERN_INFO "Alchemy Db/Pb1xxx pcmcia%d @ io/attr/mem %08lx"
+		"(%p) %08lx %08lx  card/insert/stschg/eject irqs @ %d "
+		"%d %d %d\n", sock->nr, sock->phys_io, sock->virt_io,
+		sock->phys_attr, sock->phys_mem, sock->card_irq,
+		sock->insert_irq, sock->stschg_irq, sock->eject_irq);
+
+	return 0;
+
+out2:
+	db1x_pcmcia_free_irqs(sock);
+out1:
+	iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+out0:
+	kfree(sock);
+	return ret;
+}
+
+static int __devexit db1x_pcmcia_socket_remove(struct platform_device *pdev)
+{
+	struct db1x_pcmcia_sock *sock = platform_get_drvdata(pdev);
+
+	db1x_pcmcia_free_irqs(sock);
+	pcmcia_unregister_socket(&sock->socket);
+	iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+	kfree(sock);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int db1x_pcmcia_suspend(struct device *dev)
+{
+	return pcmcia_socket_dev_suspend(dev);
+}
+
+static int db1x_pcmcia_resume(struct device *dev)
+{
+	return pcmcia_socket_dev_resume(dev);
+}
+
+static struct dev_pm_ops db1x_pcmcia_pmops = {
+	.resume		= db1x_pcmcia_resume,
+	.suspend	= db1x_pcmcia_suspend,
+	.thaw		= db1x_pcmcia_resume,
+	.freeze		= db1x_pcmcia_suspend,
+};
+
+#define DB1XXX_SS_PMOPS &db1x_pcmcia_pmops
+
+#else
+
+#define DB1XXX_SS_PMOPS NULL
+
+#endif
+
+static struct platform_driver db1x_pcmcia_socket_driver = {
+	.driver	= {
+		.name	= "db1xxx_pcmcia",
+		.owner	= THIS_MODULE,
+		.pm	= DB1XXX_SS_PMOPS
+	},
+	.probe		= db1x_pcmcia_socket_probe,
+	.remove		= __devexit_p(db1x_pcmcia_socket_remove),
+};
+
+int __init db1x_pcmcia_socket_load(void)
+{
+	return platform_driver_register(&db1x_pcmcia_socket_driver);
+}
+
+void  __exit db1x_pcmcia_socket_unload(void)
+{
+	platform_driver_unregister(&db1x_pcmcia_socket_driver);
+}
+
+module_init(db1x_pcmcia_socket_load);
+module_exit(db1x_pcmcia_socket_unload);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCMCIA Socket Services for Alchemy Db/Pb1x00 boards");
+MODULE_AUTHOR("Manuel Lauss");
-- 
1.6.5.rc2


From manuel.lauss@googlemail.com Sun Oct  4 14:58:03 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Sun, 04 Oct 2009 14:58:10 +0200 (CEST)
Received: from mail-ew0-f214.google.com ([209.85.219.214]:40821 "EHLO
	mail-ew0-f214.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492543AbZJDMzo (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Sun, 4 Oct 2009 14:55:44 +0200
Received: by ewy10 with SMTP id 10so1846529ewy.33
        for <multiple recipients>; Sun, 04 Oct 2009 05:55:39 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer:in-reply-to:references;
        bh=LApcYr/IcqR4yW5+8d39ecmgH/FSv23SS/0/rvcJGtg=;
        b=sRs442xv1qqCo9QPUShK61wp+WDszPX8j115pQJD83JKCxRHGVVh24LRydZUzSW16e
         K0DdqpZj9zOXgtpNvV4Kdv+CeigFj9viwZL2SasSj7iHbwIzf4XGoHbn9k9mqa8+4Jxf
         bYSU0G9sre/5ju9E+b4l/5JrJ9yihsFTPMqBQ=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        b=PG/0gBXdE4tdS+Yc55pl3Y3oiqD4AqgpI6wcUwTmkKP1RA5knt6mAt7qdwE7khwfD8
         v4zALc4DAFI2TM6ME5COLthH/CFuwxAr/v8Ooja/nZot8cq6xIT5O6E0TPweU3uD9ss4
         PHbkLBvdyaU9DbvcCx+OueJ6usm/EfwJyovcw=
Received: by 10.211.161.22 with SMTP id n22mr1998414ebo.83.1254660939490;
        Sun, 04 Oct 2009 05:55:39 -0700 (PDT)
Received: from localhost.localdomain (fnoeppeil48.netpark.at [217.175.205.176])
        by mx.google.com with ESMTPS id 28sm1555483eyg.4.2009.10.04.05.55.38
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Sun, 04 Oct 2009 05:55:38 -0700 (PDT)
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Linux-MIPS <linux-mips@linux-mips.org>,
	Ralf Baechle <ralf@linux-mips.org>
Cc:	Manuel Lauss <manuel.lauss@gmail.com>,
	Florian Fainelli <florian@openwrt.org>,
	Linux-PCMCIA <linux-pcmcia@lists.infradead.org>
Subject: [PATCH 6/6] Alchemy: XXS1500 PCMCIA driver rewrite
Date:	Sun,  4 Oct 2009 14:55:29 +0200
Message-Id: <1254660929-15453-7-git-send-email-manuel.lauss@gmail.com>
X-Mailer: git-send-email 1.6.5.rc2
In-Reply-To: <1254660929-15453-6-git-send-email-manuel.lauss@gmail.com>
References: <1254660929-15453-1-git-send-email-manuel.lauss@gmail.com>
 <1254660929-15453-2-git-send-email-manuel.lauss@gmail.com>
 <1254660929-15453-3-git-send-email-manuel.lauss@gmail.com>
 <1254660929-15453-4-git-send-email-manuel.lauss@gmail.com>
 <1254660929-15453-5-git-send-email-manuel.lauss@gmail.com>
 <1254660929-15453-6-git-send-email-manuel.lauss@gmail.com>
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24143
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

Rewritten XXS1500 PCMCIA socket driver, standalone (doesn't
depend on au1000_generic.c) and added carddetect IRQ support.

Cc: Florian Fainelli <florian@openwrt.org>
Cc: Linux-PCMCIA <linux-pcmcia@lists.infradead.org>
Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
Compile-tested only; I don't have hardware to test,
CC'ing Florian, he might still have one.

V2: this one depends on the previous db1xxx_ss.c patch to apply
    cleanly; no other changes.

 arch/mips/alchemy/xxs1500/Makefile      |    2 +-
 arch/mips/alchemy/xxs1500/board_setup.c |   16 --
 arch/mips/alchemy/xxs1500/platform.c    |   63 ++++++
 drivers/pcmcia/Kconfig                  |   10 +
 drivers/pcmcia/Makefile                 |    3 +-
 drivers/pcmcia/au1000_xxs1500.c         |  188 ----------------
 drivers/pcmcia/xxs1500_ss.c             |  357 +++++++++++++++++++++++++++++++
 7 files changed, 433 insertions(+), 206 deletions(-)
 create mode 100644 arch/mips/alchemy/xxs1500/platform.c
 delete mode 100644 drivers/pcmcia/au1000_xxs1500.c
 create mode 100644 drivers/pcmcia/xxs1500_ss.c

diff --git a/arch/mips/alchemy/xxs1500/Makefile b/arch/mips/alchemy/xxs1500/Makefile
index 545d8f5..68671c2 100644
--- a/arch/mips/alchemy/xxs1500/Makefile
+++ b/arch/mips/alchemy/xxs1500/Makefile
@@ -5,4 +5,4 @@
 # Makefile for MyCable XXS1500 board.
 #
 
-lib-y := init.o board_setup.o
+lib-y := init.o board_setup.o platform.o
diff --git a/arch/mips/alchemy/xxs1500/board_setup.c b/arch/mips/alchemy/xxs1500/board_setup.c
index cad14f8..eb31350 100644
--- a/arch/mips/alchemy/xxs1500/board_setup.c
+++ b/arch/mips/alchemy/xxs1500/board_setup.c
@@ -69,22 +69,6 @@ void __init board_setup(void)
 	/* Enable DTR = USB power up */
 	au_writel(0x01, UART3_ADDR + UART_MCR); /* UART_MCR_DTR is 0x01??? */
 
-#ifdef CONFIG_PCMCIA_XXS1500
-	/* GPIO 0, 1, and 4 are inputs */
-	alchemy_gpio_direction_input(0);
-	alchemy_gpio_direction_input(1);
-	alchemy_gpio_direction_input(4);
-
-	/* GPIO2 208/9/10/11 are inputs */
-	alchemy_gpio_direction_input(208);
-	alchemy_gpio_direction_input(209);
-	alchemy_gpio_direction_input(210);
-	alchemy_gpio_direction_input(211);
-
-	/* Turn off power */
-	alchemy_gpio_direction_output(214, 0);
-#endif
-
 #ifdef CONFIG_PCI
 #if defined(__MIPSEB__)
 	au_writel(0xf | (2 << 6) | (1 << 4), Au1500_PCI_CFG);
diff --git a/arch/mips/alchemy/xxs1500/platform.c b/arch/mips/alchemy/xxs1500/platform.c
new file mode 100644
index 0000000..c14dcaa
--- /dev/null
+++ b/arch/mips/alchemy/xxs1500/platform.c
@@ -0,0 +1,63 @@
+/*
+ * XXS1500 board platform device registration
+ *
+ * Copyright (C) 2009 Manuel Lauss
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-au1x00/au1000.h>
+
+static struct resource xxs1500_pcmcia_res[] = {
+	{
+		.name	= "pseudo-io",
+		.flags	= IORESOURCE_MEM,
+		.start	= PCMCIA_IO_PSEUDO_PHYS,
+		.end	= PCMCIA_IO_PSEUDO_PHYS + 0x00040000 - 1,
+	},
+	{
+		.name	= "pseudo-attr",
+		.flags	= IORESOURCE_MEM,
+		.start	= PCMCIA_ATTR_PSEUDO_PHYS,
+		.end	= PCMCIA_ATTR_PSEUDO_PHYS + 0x00040000 - 1,
+	},
+	{
+		.name	= "pseudo-mem",
+		.flags	= IORESOURCE_MEM,
+		.start	= PCMCIA_IO_PSEUDO_PHYS,
+		.end	= PCMCIA_IO_PSEUDO_PHYS + 0x00040000 - 1,
+	},
+};
+
+static struct platform_device xxs1500_pcmcia_dev = {
+	.name		= "xxs1500_pcmcia",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(xxs1500_pcmcia_res),
+	.resource	= xxs1500_pcmcia_res,
+};
+
+static struct platform_device *xxs1500_devs[] __initdata = {
+	&xxs1500_pcmcia_dev,
+};
+
+static int __init xxs1500_dev_init(void)
+{
+	return platform_add_devices(xxs1500_devs,
+				    ARRAY_SIZE(xxs1500_devs));
+}
+device_initcall(xxs1500_dev_init);
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 22f6814..5ed3b93 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -203,6 +203,16 @@ config PCMCIA_ALCHEMY_DEVBOARD
 
 	  This driver is also available as a module called db1xxx_ss.ko
 
+config PCMCIA_XXS1500
+	tristate "MyCable XXS1500 PCMCIA socket support"
+	depends on PCMCIA && MIPS_XXS1500
+	select 64BIT_PHYS_ADDR
+	help
+	  Support for the PCMCIA/CF socket interface on MyCable XXS1500
+	  systems.
+
+	  This driver is also available as a module called xxs1500_ss.ko
+
 config PCMCIA_BCM63XX
 	tristate "bcm63xx pcmcia support"
 	depends on BCM63XX && PCMCIA
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index e58d162..8bd8b02 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -41,7 +41,6 @@ pxa2xx_core-y					+= soc_common.o pxa2xx_base.o
 
 au1x00_ss-y					+= au1000_generic.o
 au1x00_ss-$(CONFIG_MIPS_PB1000)			+= au1000_pb1x00.o
-au1x00_ss-$(CONFIG_MIPS_XXS1500)		+= au1000_xxs1500.o
 
 sa1111_cs-y					+= sa1111_generic.o
 sa1111_cs-$(CONFIG_ASSABET_NEPONSET)		+= sa1100_neponset.o
@@ -71,3 +70,5 @@ pxa2xx-obj-$(CONFIG_MACH_E740)			+= pxa2xx_e740.o
 pxa2xx-obj-$(CONFIG_MACH_STARGATE2)		+= pxa2xx_stargate2.o
 
 obj-$(CONFIG_PCMCIA_PXA2XX)			+= pxa2xx_core.o $(pxa2xx-obj-y)
+
+obj-$(CONFIG_PCMCIA_XXS1500)			+= xxs1500_ss.o
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c
deleted file mode 100644
index b43d47b..0000000
--- a/drivers/pcmcia/au1000_xxs1500.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- *
- * MyCable board specific pcmcia routines.
- *
- * Copyright 2003 MontaVista Software Inc.
- * Author: Pete Popov, MontaVista Software, Inc.
- *         	ppopov@mvista.com or source@mvista.com
- *
- * ########################################################################
- *
- *  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.
- *
- * ########################################################################
- *
- *
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/mm.h>
-#include <linux/proc_fs.h>
-#include <linux/types.h>
-
-#include <pcmcia/cs_types.h>
-#include <pcmcia/cs.h>
-#include <pcmcia/ss.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/bus_ops.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#include <asm/au1000.h>
-#include <asm/au1000_pcmcia.h>
-
-#define PCMCIA_MAX_SOCK		0
-#define PCMCIA_NUM_SOCKS	(PCMCIA_MAX_SOCK + 1)
-#define PCMCIA_IRQ		AU1000_GPIO_4
-
-#if 0
-#define DEBUG(x, args...)	printk(__func__ ": " x, ##args)
-#else
-#define DEBUG(x,args...)
-#endif
-
-static int xxs1500_pcmcia_init(struct pcmcia_init *init)
-{
-	return PCMCIA_NUM_SOCKS;
-}
-
-static int xxs1500_pcmcia_shutdown(void)
-{
-	/* turn off power */
-	au_writel(au_readl(GPIO2_PINSTATE) | (1<<14)|(1<<30),
-			GPIO2_OUTPUT);
-	au_sync_delay(100);
-
-	/* assert reset */
-	au_writel(au_readl(GPIO2_PINSTATE) | (1<<4)|(1<<20),
-			GPIO2_OUTPUT);
-	au_sync_delay(100);
-	return 0;
-}
-
-
-static int
-xxs1500_pcmcia_socket_state(unsigned sock, struct pcmcia_state *state)
-{
-	u32 inserted; u32 vs;
-	unsigned long gpio, gpio2;
-
-	if(sock > PCMCIA_MAX_SOCK) return -1;
-
-	gpio = au_readl(SYS_PINSTATERD);
-	gpio2 = au_readl(GPIO2_PINSTATE);
-
-	vs = gpio2 & ((1<<8) | (1<<9));
-	inserted = (!(gpio & 0x1) && !(gpio & 0x2));
-
-	state->ready = 0;
-	state->vs_Xv = 0;
-	state->vs_3v = 0;
-	state->detect = 0;
-
-	if (inserted) {
-		switch (vs) {
-			case 0:
-			case 1:
-			case 2:
-				state->vs_3v=1;
-				break;
-			case 3: /* 5V */
-			default:
-				/* return without setting 'detect' */
-				printk(KERN_ERR "au1x00_cs: unsupported VS\n",
-						vs);
-				return;
-		}
-		state->detect = 1;
-	}
-
-	if (state->detect) {
-		state->ready = 1;
-	}
-
-	state->bvd1= gpio2 & (1<<10);
-	state->bvd2 = gpio2 & (1<<11);
-	state->wrprot=0;
-	return 1;
-}
-
-
-static int xxs1500_pcmcia_get_irq_info(struct pcmcia_irq_info *info)
-{
-
-	if(info->sock > PCMCIA_MAX_SOCK) return -1;
-	info->irq = PCMCIA_IRQ;
-	return 0;
-}
-
-
-static int
-xxs1500_pcmcia_configure_socket(const struct pcmcia_configure *configure)
-{
-
-	if(configure->sock > PCMCIA_MAX_SOCK) return -1;
-
-	DEBUG("Vcc %dV Vpp %dV, reset %d\n",
-			configure->vcc, configure->vpp, configure->reset);
-
-	switch(configure->vcc){
-		case 33: /* Vcc 3.3V */
-			/* turn on power */
-			DEBUG("turn on power\n");
-			au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<14))|(1<<30),
-					GPIO2_OUTPUT);
-			au_sync_delay(100);
-			break;
-		case 50: /* Vcc 5V */
-		default: /* what's this ? */
-			printk(KERN_ERR "au1x00_cs: unsupported VCC\n");
-		case 0:  /* Vcc 0 */
-			/* turn off power */
-			au_sync_delay(100);
-			au_writel(au_readl(GPIO2_PINSTATE) | (1<<14)|(1<<30),
-					GPIO2_OUTPUT);
-			break;
-	}
-
-	if (!configure->reset) {
-		DEBUG("deassert reset\n");
-		au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<4))|(1<<20),
-				GPIO2_OUTPUT);
-		au_sync_delay(100);
-		au_writel((au_readl(GPIO2_PINSTATE) & ~(1<<5))|(1<<21),
-				GPIO2_OUTPUT);
-	}
-	else {
-		DEBUG("assert reset\n");
-		au_writel(au_readl(GPIO2_PINSTATE) | (1<<4)|(1<<20),
-				GPIO2_OUTPUT);
-	}
-	au_sync_delay(100);
-	return 0;
-}
-
-struct pcmcia_low_level xxs1500_pcmcia_ops = {
-	xxs1500_pcmcia_init,
-	xxs1500_pcmcia_shutdown,
-	xxs1500_pcmcia_socket_state,
-	xxs1500_pcmcia_get_irq_info,
-	xxs1500_pcmcia_configure_socket
-};
diff --git a/drivers/pcmcia/xxs1500_ss.c b/drivers/pcmcia/xxs1500_ss.c
new file mode 100644
index 0000000..4e36930
--- /dev/null
+++ b/drivers/pcmcia/xxs1500_ss.c
@@ -0,0 +1,357 @@
+/*
+ * PCMCIA socket code for the MyCable XXS1500 system.
+ *
+ * Copyright (c) 2009 Manuel Lauss <manuel.lauss@gmail.com>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/resource.h>
+#include <linux/spinlock.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cistpl.h>
+
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/mach-au1x00/au1000.h>
+
+#define MEM_MAP_SIZE	0x400000
+#define IO_MAP_SIZE	0x1000
+
+
+/*
+ * 3.3V cards only; all interfacing is done via gpios:
+ *
+ * 0/1:  carddetect (00 = card present, xx = huh)
+ * 4:	 card irq
+ * 204:  reset (high-act)
+ * 205:  buffer enable (low-act)
+ * 208/209: card voltage key (00,01,10,11)
+ * 210:  battwarn
+ * 211:  batdead
+ * 214:  power (low-act)
+ */
+#define GPIO_CDA	0
+#define GPIO_CDB	1
+#define GPIO_CARDIRQ	4
+#define GPIO_RESET	204
+#define GPIO_OUTEN	205
+#define GPIO_VSL	208
+#define GPIO_VSH	209
+#define GPIO_BATTDEAD	210
+#define GPIO_BATTWARN	211
+#define GPIO_POWER	214
+
+struct xxs1500_pcmcia_sock {
+	struct pcmcia_socket	socket;
+	void		*virt_io;
+
+	/* the "pseudo" addresses of the PCMCIA space. */
+	unsigned long	phys_io;
+	unsigned long	phys_attr;
+	unsigned long	phys_mem;
+
+	/* previous flags for set_socket() */
+	unsigned int old_flags;
+};
+
+#define to_xxs_socket(x) container_of(x, struct xxs1500_pcmcia_sock, socket)
+
+static irqreturn_t cdirq(int irq, void *data)
+{
+	struct xxs1500_pcmcia_sock *sock = data;
+
+	pcmcia_parse_events(&sock->socket, SS_DETECT);
+
+	return IRQ_HANDLED;
+}
+
+static int xxs1500_pcmcia_configure(struct pcmcia_socket *skt,
+				    struct socket_state_t *state)
+{
+	struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
+	unsigned int changed;
+
+	/* power control */
+	switch (state->Vcc) {
+	case 0:
+		gpio_set_value(GPIO_POWER, 1);	/* power off */
+		break;
+	case 33:
+		gpio_set_value(GPIO_POWER, 0);	/* power on */
+		break;
+	case 50:
+	default:
+		return -EINVAL;
+	}
+
+	changed = state->flags ^ sock->old_flags;
+
+	if (changed & SS_RESET) {
+		if (state->flags & SS_RESET) {
+			gpio_set_value(GPIO_RESET, 1);	/* assert reset */
+			gpio_set_value(GPIO_OUTEN, 1);	/* buffers off */
+		} else {
+			gpio_set_value(GPIO_RESET, 0);	/* deassert reset */
+			gpio_set_value(GPIO_OUTEN, 0);	/* buffers on */
+			msleep(500);
+		}
+	}
+
+	sock->old_flags = state->flags;
+
+	return 0;
+}
+
+static int xxs1500_pcmcia_get_status(struct pcmcia_socket *skt,
+				     unsigned int *value)
+{
+	unsigned int status;
+	int i;
+
+	status = 0;
+
+	/* check carddetects: GPIO[0:1] must both be low */
+	if (!gpio_get_value(GPIO_CDA) && !gpio_get_value(GPIO_CDB))
+		status |= SS_DETECT;
+
+	/* determine card voltage: GPIO[208:209] binary value */
+	i = (!!gpio_get_value(GPIO_VSL)) | ((!!gpio_get_value(GPIO_VSH)) << 1);
+
+	switch (i) {
+	case 0:
+	case 1:
+	case 2:
+		status |= SS_3VCARD;	/* 3V card */
+		break;
+	case 3:				/* 5V card, unsupported */
+	default:
+		status |= SS_XVCARD;	/* treated as unsupported in core */
+	}
+
+	/* GPIO214: low active power switch */
+	status |= gpio_get_value(GPIO_POWER) ? 0 : SS_POWERON;
+
+	/* GPIO204: high-active reset line */
+	status |= gpio_get_value(GPIO_RESET) ? SS_RESET : SS_READY;
+
+	/* other stuff */
+	status |= gpio_get_value(GPIO_BATTDEAD) ? 0 : SS_BATDEAD;
+	status |= gpio_get_value(GPIO_BATTWARN) ? 0 : SS_BATWARN;
+
+	*value = status;
+
+	return 0;
+}
+
+static int xxs1500_pcmcia_sock_init(struct pcmcia_socket *skt)
+{
+	gpio_direction_input(GPIO_CDA);
+	gpio_direction_input(GPIO_CDB);
+	gpio_direction_input(GPIO_VSL);
+	gpio_direction_input(GPIO_VSH);
+	gpio_direction_input(GPIO_BATTDEAD);
+	gpio_direction_input(GPIO_BATTWARN);
+	gpio_direction_output(GPIO_RESET, 1);	/* assert reset */
+	gpio_direction_output(GPIO_OUTEN, 1);	/* disable buffers */
+	gpio_direction_output(GPIO_POWER, 1);	/* power off */
+
+	return 0;
+}
+
+static int xxs1500_pcmcia_sock_suspend(struct pcmcia_socket *skt)
+{
+	return 0;
+}
+
+static int au1x00_pcmcia_set_io_map(struct pcmcia_socket *skt,
+				    struct pccard_io_map *map)
+{
+	struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
+
+	map->start = (u32)sock->virt_io;
+	map->stop = map->start + IO_MAP_SIZE;
+
+	return 0;
+}
+
+static int au1x00_pcmcia_set_mem_map(struct pcmcia_socket *skt,
+				     struct pccard_mem_map *map)
+{
+	struct xxs1500_pcmcia_sock *sock = to_xxs_socket(skt);
+
+	if (map->flags & MAP_ATTRIB)
+		map->static_start = sock->phys_attr + map->card_start;
+	else
+		map->static_start = sock->phys_mem + map->card_start;
+
+	return 0;
+}
+
+static struct pccard_operations xxs1500_pcmcia_operations = {
+	.init			= xxs1500_pcmcia_sock_init,
+	.suspend		= xxs1500_pcmcia_sock_suspend,
+	.get_status		= xxs1500_pcmcia_get_status,
+	.set_socket		= xxs1500_pcmcia_configure,
+	.set_io_map		= au1x00_pcmcia_set_io_map,
+	.set_mem_map		= au1x00_pcmcia_set_mem_map,
+};
+
+static int __devinit xxs1500_pcmcia_probe(struct platform_device *pdev)
+{
+	struct xxs1500_pcmcia_sock *sock;
+	struct resource *r;
+	phys_t physio;
+	int ret, irq;
+
+	sock = kzalloc(sizeof(struct xxs1500_pcmcia_sock), GFP_KERNEL);
+	if (!sock)
+		return -ENOMEM;
+
+	ret = -ENODEV;
+
+	/*
+	 * pseudo-attr:  The 32bit address of the PCMCIA attribute space
+	 * for this socket (usually the 36bit address shifted 4 to the
+	 * right).
+	 */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-attr");
+	if (!r) {
+		dev_err(&pdev->dev, "missing 'pseudo-attr' resource!\n");
+		goto out0;
+	}
+	sock->phys_attr = r->start;
+
+	/*
+	 * pseudo-mem:  The 32bit address of the PCMCIA memory space for
+	 * this socket (usually the 36bit address shifted 4 to the right)
+	 */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-mem");
+	if (!r) {
+		dev_err(&pdev->dev, "missing 'pseudo-mem' resource!\n");
+		goto out0;
+	}
+	sock->phys_mem = r->start;
+
+	/*
+	 * pseudo-io:  The 32bit address of the PCMCIA IO space for this
+	 * socket (usually the 36bit address shifted 4 to the right).
+	 */
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pseudo-io");
+	if (!r) {
+		dev_err(&pdev->dev, "missing 'pseudo-io' resource!\n");
+		goto out0;
+	}
+	sock->phys_io = r->start;
+
+
+	/* for io must remap the full 36bit address (for reference see
+	 * alchemy/common/setup.c::__fixup_bigphys_addr)
+	 */
+	physio = ((phys_t)sock->phys_io) << 4;
+
+	/*
+	 * PCMCIA client drivers use the inb/outb macros to access
+	 * the IO registers.  Since mips_io_port_base is added
+	 * to the access address of the mips implementation of
+	 * inb/outb, we need to subtract it here because we want
+	 * to access the I/O or MEM address directly, without
+	 * going through this "mips_io_port_base" mechanism.
+	 */
+	sock->virt_io = (void *)(ioremap(physio, IO_MAP_SIZE) -
+				 mips_io_port_base);
+
+	if (!sock->virt_io) {
+		dev_err(&pdev->dev, "cannot remap IO area\n");
+		ret = -ENOMEM;
+		goto out0;
+	}
+
+	sock->socket.ops	= &xxs1500_pcmcia_operations;
+	sock->socket.owner	= THIS_MODULE;
+	sock->socket.pci_irq	= gpio_to_irq(GPIO_CARDIRQ);
+	sock->socket.features	= SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
+	sock->socket.map_size	= MEM_MAP_SIZE;
+	sock->socket.io_offset	= (unsigned long)sock->virt_io;
+	sock->socket.dev.parent	= &pdev->dev;
+	sock->socket.resource_ops = &pccard_static_ops;
+
+	platform_set_drvdata(pdev, sock);
+
+	/* setup carddetect irq: use one of the 2 GPIOs as an
+	 * edge detector.
+	 */
+	irq = gpio_to_irq(GPIO_CDA);
+	set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
+	ret = request_irq(irq, cdirq, 0, "pcmcia_carddetect", sock);
+	if (ret) {
+		dev_err(&pdev->dev, "cannot setup cd irq\n");
+		goto out1;
+	}
+
+	ret = pcmcia_register_socket(&sock->socket);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register\n");
+		goto out2;
+	}
+
+	printk(KERN_INFO "MyCable XXS1500 PCMCIA socket services\n");
+
+	return 0;
+
+out2:
+	free_irq(gpio_to_irq(GPIO_CDA), sock);
+out1:
+	iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+out0:
+	kfree(sock);
+	return ret;
+}
+
+static int __devexit xxs1500_pcmcia_remove(struct platform_device *pdev)
+{
+	struct xxs1500_pcmcia_sock *sock = platform_get_drvdata(pdev);
+
+	pcmcia_unregister_socket(&sock->socket);
+	free_irq(gpio_to_irq(GPIO_CDA), sock);
+	iounmap((void *)(sock->virt_io + (u32)mips_io_port_base));
+	kfree(sock);
+
+	return 0;
+}
+
+static struct platform_driver xxs1500_pcmcia_socket_driver = {
+	.driver	= {
+		.name	= "xxs1500_pcmcia",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= xxs1500_pcmcia_probe,
+	.remove		= __devexit_p(xxs1500_pcmcia_remove),
+};
+
+int __init xxs1500_pcmcia_socket_load(void)
+{
+	return platform_driver_register(&xxs1500_pcmcia_socket_driver);
+}
+
+void  __exit xxs1500_pcmcia_socket_unload(void)
+{
+	platform_driver_unregister(&xxs1500_pcmcia_socket_driver);
+}
+
+module_init(xxs1500_pcmcia_socket_load);
+module_exit(xxs1500_pcmcia_socket_unload);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCMCIA Socket Services for MyCable XXS1500 systems");
+MODULE_AUTHOR("Manuel Lauss");
-- 
1.6.5.rc2


From randrianasulu@gmail.com Mon Oct  5 06:33:18 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Oct 2009 06:33:23 +0200 (CEST)
Received: from mail-ew0-f214.google.com ([209.85.219.214]:49014 "EHLO
	mail-ew0-f214.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492332AbZJEEdS convert rfc822-to-8bit
	(ORCPT <rfc822;linux-mips@linux-mips.org>);
	Mon, 5 Oct 2009 06:33:18 +0200
Received: by ewy10 with SMTP id 10so2201221ewy.33
        for <linux-mips@linux-mips.org>; Sun, 04 Oct 2009 21:33:11 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:subject:date
         :user-agent:references:in-reply-to:mime-version:content-type
         :content-transfer-encoding:content-disposition:message-id;
        bh=vkja0b6nVNazNTQLmhBok9MFipwntlPJ0m8VQ/C3TZg=;
        b=YbitVl15hEerJfwNShmQFrrijzmxY8+oosVeudT4b3K1MH13m2f5Cd9/hjYYwWvYx3
         L1bkjSxFW/fWxbvJdeiP+llXMiXS61S9tut7PlfdejOZYHSDxd6BHs49bSedvHt8ZaGR
         zvb/S6FOnvtOSFsdRz4oYIs+HGH27FegVwON8=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=gamma;
        h=from:to:subject:date:user-agent:references:in-reply-to:mime-version
         :content-type:content-transfer-encoding:content-disposition
         :message-id;
        b=T5L08fZMY77k+FryaSi75JuK+G2hlyUoz7OjZ+euGtGcTQiRR19/6GQNbcDAc76SUm
         EAgGoGNWSriVt9r2hjrOHRAqvAoWj3RKlxWxdD7i7pVEUtNxCXGjhT9jJbhmiwUxH0Ji
         OtdQmZDpFTd2sbL+KG1Qn32TNiQF/lhXm+Zzg=
Received: by 10.211.139.17 with SMTP id r17mr4746090ebn.88.1254717191176;
        Sun, 04 Oct 2009 21:33:11 -0700 (PDT)
Received: from ?192.168.1.2? ([91.196.252.17])
        by mx.google.com with ESMTPS id 5sm1232225eyh.24.2009.10.04.21.33.09
        (version=SSLv3 cipher=RC4-MD5);
        Sun, 04 Oct 2009 21:33:09 -0700 (PDT)
From:	randrianasulu@gmail.com
To:	Toy lover <toylover@gmail.com>, linux-mips@linux-mips.org
Subject: Re: mipsel-sdelinux-v6.03.01-1.i386.rpm
Date:	Mon, 5 Oct 2009 08:31:37 +0000
User-Agent: KMail/1.9.10
References: <81f85c130910032313u532c5bdt815f0633269bf79e@mail.gmail.com>
In-Reply-To: <81f85c130910032313u532c5bdt815f0633269bf79e@mail.gmail.com>
MIME-Version: 1.0
Content-Type: text/plain;
  charset="windows-1251"
Content-Transfer-Encoding: 8BIT
Content-Disposition: inline
Message-Id: <200910050831.40606.randrianasulu@gmail.com>
Return-Path: <randrianasulu@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24144
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: randrianasulu@gmail.com
Precedence: bulk
X-list: linux-mips

Â ñîîáùåíèè îò Sunday 04 October 2009 06:13:44 Toy lover íàïèñàë(à):
> I am trying to compile kernel modules for a kernel compiled with
> mipsel-sdelinux-v6.03.01-1
> but the ftp://ftp.mips.com/
> pub/tools/software/sde-for-linux/v6.03.01-1/mipsel-*sdelinux*
> -v6.03.01-1.i386.rpm
> is no longer available. I am wondering whether any of you can send me a
> copy of mipsel-*sdelinux*-v6.03.01-1.i386.rpm
> which you might still own.
>
> David


I found few files here:

http://www.mvixusa.com/support/index.php?_m=downloads&_a=viewdownload&downloaditemid=50
at least 
http://files.getdropbox.com/u/397941/Ultio%20Files/Ultio%20Firmware%20and%20Sourcecode/RealTek_GPL.tar.gz
and 
http://files.getdropbox.com/u/397941/Ultio%20Files/Ultio%20Firmware%20and%20Sourcecode/Ultio%20mipsel-sdelinux-v6.03.01-1.i386.zip 
are good, working for me.

Happy hacking!

From f.fainelli@gmail.com Mon Oct  5 11:41:20 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Oct 2009 11:41:27 +0200 (CEST)
Received: from mail-fx0-f221.google.com ([209.85.220.221]:35494 "EHLO
	mail-fx0-f221.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1493142AbZJEJlU (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Mon, 5 Oct 2009 11:41:20 +0200
Received: by fxm21 with SMTP id 21so2316720fxm.33
        for <multiple recipients>; Mon, 05 Oct 2009 02:41:13 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=domainkey-signature:received:received:sender:from:to:subject:date
         :user-agent:cc:references:in-reply-to:organization:mime-version
         :content-type:content-transfer-encoding:content-disposition
         :message-id;
        bh=ITcqckERKJb2FUuD8XBlfYImvg7NcCIKcg4+LY6bRnk=;
        b=x6aRKLYC+83BR3CHxSisdes6dFfWWwKAGSWv8kdqD7UqYdfK0CtWmT63XT/LgBiwhJ
         Cr+DYyAsSQI2YYyweo2BGfNRaiijUzWY72dS/jCECewIn7/q7Tz6O9Zs0IlSmR+Fesl9
         9CIfI8WL7Q9dktjkhMHIs/vXJimEsk/MNFHAo=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=gamma;
        h=sender:from:to:subject:date:user-agent:cc:references:in-reply-to
         :organization:mime-version:content-type:content-transfer-encoding
         :content-disposition:message-id;
        b=QC7rmbD7lpBIF78bsP13qRCyi3eO+fZmC4LcoeDKZGFeIVfx9T4j9UoSNq9B/CMMZt
         lXZqiFwoff0D/1R79CkJOqtkls1a060h3sj8Yvxjs1iEVX7hLmVRiE5ALrSfYoOCnbRK
         x7hXVhoe06cSEEgoVMCOO/XtY8njb4wdKQ5wE=
Received: by 10.86.231.5 with SMTP id d5mr4930319fgh.53.1254735673340;
        Mon, 05 Oct 2009 02:41:13 -0700 (PDT)
Received: from noex.localnet (bobafett.staff.proxad.net [213.228.1.121])
        by mx.google.com with ESMTPS id 4sm6704810fge.29.2009.10.05.02.41.10
        (version=SSLv3 cipher=RC4-MD5);
        Mon, 05 Oct 2009 02:41:10 -0700 (PDT)
From:	Florian Fainelli <florian@openwrt.org>
To:	Ralf Baechle <ralf@linux-mips.org>
Subject: Re: [PATCH] ar7: register watchdog driver only if enabled in hardware configuration
Date:	Mon, 5 Oct 2009 11:40:50 +0200
User-Agent: KMail/1.11.2 (Linux/2.6.28-15-server; KDE/4.2.2; x86_64; ; )
Cc:	linux-mips@linux-mips.org
References: <200908042309.36721.florian@openwrt.org>
In-Reply-To: <200908042309.36721.florian@openwrt.org>
Organization: OpenWrt
MIME-Version: 1.0
Content-Type: Text/Plain;
  charset="utf-8"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
Message-Id: <200910051140.51030.florian@openwrt.org>
Return-Path: <f.fainelli@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24145
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: florian@openwrt.org
Precedence: bulk
X-list: linux-mips

Ralf,

Any comments on that patch ?

Thanks !

On Tuesday 04 August 2009 23:09:36 Florian Fainelli wrote:
> This patch checks if the watchdog enable bit is set in the DCL
> register meaning that the hardware watchdog actually works and
> if so, register the ar7_wdt platform_device.
>
> Signed-off-by: Florian Fainelli <florian@openwrt.org>
> ---
> diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c
> index e2278c0..835f3f0 100644
> --- a/arch/mips/ar7/platform.c
> +++ b/arch/mips/ar7/platform.c
> @@ -503,6 +503,7 @@ static int __init ar7_register_devices(void)
>  {
>  	u16 chip_id;
>  	int res;
> +	u32 *bootcr, val;
>  #ifdef CONFIG_SERIAL_8250
>  	static struct uart_port uart_port[2];
>
> @@ -595,7 +596,13 @@ static int __init ar7_register_devices(void)
>
>  	ar7_wdt_res.end = ar7_wdt_res.start + 0x20;
>
> -	res = platform_device_register(&ar7_wdt);
> +	bootcr = (u32 *)ioremap_nocache(AR7_REGS_DCL, 4);
> +	val = *bootcr;
> +	iounmap(bootcr);
> +
> +	/* Register watchdog only if enabled in hardware */
> +	if (val & AR7_WDT_HW_ENA)
> +		res = platform_device_register(&ar7_wdt);
>
>  	return res;
>  }
> diff --git a/arch/mips/include/asm/mach-ar7/ar7.h
> b/arch/mips/include/asm/mach-ar7/ar7.h index de71694..21cbbc7 100644
> --- a/arch/mips/include/asm/mach-ar7/ar7.h
> +++ b/arch/mips/include/asm/mach-ar7/ar7.h
> @@ -78,6 +78,9 @@
>  #define AR7_REF_CLOCK	25000000
>  #define AR7_XTAL_CLOCK	24000000
>
> +/* DCL */
> +#define AR7_WDT_HW_ENA	0x10
> +
>  struct plat_cpmac_data {
>  	int reset_bit;
>  	int power_bit;


From manuel.lauss@googlemail.com Mon Oct  5 11:44:10 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Mon, 05 Oct 2009 11:44:16 +0200 (CEST)
Received: from mail-bw0-f208.google.com ([209.85.218.208]:65193 "EHLO
	mail-bw0-f208.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1493142AbZJEJoK convert rfc822-to-8bit
	(ORCPT <rfc822;linux-mips@linux-mips.org>);
	Mon, 5 Oct 2009 11:44:10 +0200
Received: by bwz4 with SMTP id 4so2381910bwz.0
        for <multiple recipients>; Mon, 05 Oct 2009 02:44:04 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:mime-version:received:in-reply-to:references
         :date:message-id:subject:from:to:cc:content-type
         :content-transfer-encoding;
        bh=d/6TZstbmcQRfxHEQTZNOtP9jmSaVJabB10uzNQH3mw=;
        b=FPq+uM5zqvAsJDb0TBPmUmv0IbRClyCYJ+J7A3zOmB05O/ezUiPlgkVqpWFJSKeWBH
         kx1wysFL/jsBWk/2QS1SWJ7H2endonnyzi0JHs+uOvle9hdWiQCvTGJCqqr1h+VeCf10
         lRqmc5K1KlhjtXHWl7vWqhCu2yFUNatZYxTAA=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type:content-transfer-encoding;
        b=NVq4X0Vb8J4lz3tKOOni6/CyS/lIuDGQrZA+1u2Y+ca25fpu15PljWIYG1D4cZuECk
         CS9b7mdETZU1GmN1JWW6BgeXlwdxSSaslvU1lt9EZ3BNT2j4Jq0PbLaMV4xQnC2EsImX
         JC+eqriqAFkHwQA+EXLD+FMhwdp2Poe2vrC8E=
MIME-Version: 1.0
Received: by 10.102.197.11 with SMTP id u11mr1619967muf.97.1254735844252; Mon, 
	05 Oct 2009 02:44:04 -0700 (PDT)
In-Reply-To: <f861ec6f0908302331p7f44a584pdae29cafce7ef950@mail.gmail.com>
References: <200908170028.27210.florian@openwrt.org>
	 <f861ec6f0908302331p7f44a584pdae29cafce7ef950@mail.gmail.com>
Date:	Mon, 5 Oct 2009 11:44:04 +0200
Message-ID: <f861ec6f0910050244l32173c9ar4662d467cc4f9ee8@mail.gmail.com>
Subject: Re: [PATCH 1/2] au1000: fix build failure for db1x00 configured for 
	Au1100 SoC
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	linux-mips@linux-mips.org, Florian Fainelli <florian@openwrt.org>
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8BIT
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24146
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

Ping?

On Mon, Aug 31, 2009 at 8:31 AM, Manuel Lauss
<manuel.lauss@googlemail.com> wrote:
> Hi Ralf,
>
> Please add Florian's patch below to your patchqueue!
>
> On Mon, Aug 17, 2009 at 12:28 AM, Florian Fainelli<florian@openwrt.org> wrote:
>> Hi Ralf,
>>
>> This patch should apply to both -master and -queue. Thanks !
>> --
>> From: Florian Fainelli <florian@openwrt.org>
>> Subject: [PATCH 1/2] au1000: fix build failure for db1x00 configured for Au1100 SoC
>>
>> This patch fixes the following warning, which becomes an error due to
>> -Werror to be turned on:
>>  CC      arch/mips/alchemy/common/gpiolib-au1000.o
>> cc1: warnings being treated as errors
>> arch/mips/alchemy/common/gpiolib-au1000.c: In function 'au1100_gpio2_to_irq':
>> /home/florian/dev/kernel/linux-queue/arch/mips/include/asm/mach-au1x00/gpio-au1000.h:107: warning: control reaches end of non-void function
>>
>> Signed-off-by: Florian Fainelli <florian@openwrt.org>
>> ---
>> diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h
>> index 127d4ed..4d54d40 100644
>> --- a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h
>> +++ b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h
>> @@ -104,6 +104,8 @@ static inline int au1100_gpio2_to_irq(int gpio)
>>
>>        if ((gpio >= 8) && (gpio <= 15))
>>                return MAKE_IRQ(0, 29);         /* shared GPIO208_215 */
>> +
>> +       return -ENXIO;
>>  }
>>
>>  #ifdef CONFIG_SOC_AU1100

From ralf@linux-mips.org Tue Oct  6 13:51:16 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Oct 2009 13:51:20 +0200 (CEST)
Received: from localhost.localdomain ([127.0.0.1]:33466 "EHLO h5.dl5rb.org.uk"
	rhost-flags-OK-OK-OK-FAIL) by ftp.linux-mips.org with ESMTP
	id S1492861AbZJFLvQ (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 6 Oct 2009 13:51:16 +0200
Received: from h5.dl5rb.org.uk (localhost.localdomain [127.0.0.1])
	by h5.dl5rb.org.uk (8.14.3/8.14.3) with ESMTP id n96BqMCH021982;
	Tue, 6 Oct 2009 13:52:22 +0200
Received: (from ralf@localhost)
	by h5.dl5rb.org.uk (8.14.3/8.14.3/Submit) id n96BqLRh021979;
	Tue, 6 Oct 2009 13:52:21 +0200
Date:	Tue, 6 Oct 2009 13:52:20 +0200
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Manuel Lauss <manuel.lauss@googlemail.com>
Cc:	Linux-MIPS <linux-mips@linux-mips.org>
Subject: Re: Reason for PIO_MASK?
Message-ID: <20091006115220.GC25263@linux-mips.org>
References: <f861ec6f0910030748l396b45bck858f15460354e58e@mail.gmail.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <f861ec6f0910030748l396b45bck858f15460354e58e@mail.gmail.com>
User-Agent: Mutt/1.5.19 (2009-01-05)
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24147
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Sat, Oct 03, 2009 at 04:48:12PM +0200, Manuel Lauss wrote:

> In arch/mips/lib/iomap.c  there's this "#define PIO_MASK 0x0ffff"
> which limits the ability to successfully call ioport_map() to the
> first 64kB.  This causes pata_pcmcia to error out on CF card
> probe because devm_ioport_map() is called with the remapped
> PCMCIA IO area, which is somewhere in MAP_BASE space.

Remapped, so that then actually be a physical address?  That'd be wrong.

> I've temporarily removed the PIO_MASK check and pata_pcmcia
> works as expected. Is there any way around this, other than
> creating an Alchemy-specific ioport_map() function?

The provocative question - why would you want to have more than 64k I/O port
space?

I/O ports are x86 legacy and deprecated.  PCI limits allocations to at
most 256 bytes and I don't know of any devices that even come close to
that.

When I wrote ioport_map I reviwed all uses of ioport addresses > 64k and
found each of them to be buggy ...

  Ralf

From manuel.lauss@googlemail.com Tue Oct  6 14:11:21 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Oct 2009 14:11:27 +0200 (CEST)
Received: from mail-bw0-f208.google.com ([209.85.218.208]:34849 "EHLO
	mail-bw0-f208.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492906AbZJFMLV convert rfc822-to-8bit
	(ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 6 Oct 2009 14:11:21 +0200
Received: by bwz4 with SMTP id 4so3257464bwz.0
        for <multiple recipients>; Tue, 06 Oct 2009 05:11:15 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:mime-version:received:in-reply-to:references
         :date:message-id:subject:from:to:cc:content-type
         :content-transfer-encoding;
        bh=Yrhe/Myo01RwUorHQly4Zk1MMU8RM5WTB9LrtMSlllY=;
        b=KDQlxJfc+Sce+j6M9sSrrQApIvrV7BDo2UXv3u8c9lPMftxBgOzl9ntr1lXvfvAhh9
         ltSJo7y+ZUe2XKL/sJ0cDQogScKhH0AMajbnMxDATECxWFI6QoPQkVWTsz2xvXUJQKuF
         zzCecmssBMi1GVnkixcX2jahBF0GYu7dRlRCs=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type:content-transfer-encoding;
        b=SGYVb0oP8MFwz3uIGE3BrEuATTjTUBz7h/sQF78QeQkHJcHDFM5gX93GIz4isCH8BM
         QtGm8X/CWC0AgbrUnCjtO1rDy94qDwBjMOXA0mNvL51xDDYFVvME9NFzRSkpwYTgA0Aa
         bfmhmvMsvOvY6qwliefG7mU+2nq/tPqZWdFPM=
MIME-Version: 1.0
Received: by 10.103.87.27 with SMTP id p27mr647648mul.125.1254831075574; Tue, 
	06 Oct 2009 05:11:15 -0700 (PDT)
In-Reply-To: <20091006115220.GC25263@linux-mips.org>
References: <f861ec6f0910030748l396b45bck858f15460354e58e@mail.gmail.com>
	 <20091006115220.GC25263@linux-mips.org>
Date:	Tue, 6 Oct 2009 14:11:15 +0200
Message-ID: <f861ec6f0910060511t3e95a089h63dc33e628349c11@mail.gmail.com>
Subject: Re: Reason for PIO_MASK?
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	Linux-MIPS <linux-mips@linux-mips.org>
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8BIT
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24148
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

On Tue, Oct 6, 2009 at 1:52 PM, Ralf Baechle <ralf@linux-mips.org> wrote:
> On Sat, Oct 03, 2009 at 04:48:12PM +0200, Manuel Lauss wrote:
>
>> In arch/mips/lib/iomap.c  there's this "#define PIO_MASK 0x0ffff"
>> which limits the ability to successfully call ioport_map() to the
>> first 64kB.  This causes pata_pcmcia to error out on CF card
>> probe because devm_ioport_map() is called with the remapped
>> PCMCIA IO area, which is somewhere in MAP_BASE space.
>
> Remapped, so that then actually be a physical address?  That'd be wrong.

I meant the result of ioremap() of the 36bit address of PCMCIA IO space:
so the ioport base is somewhere at 0xc0000000, which pata_pcmcia
tries to devm_iomap(), and this is rejected by the above mentioned file.

The old ide-cs.c driver takes the given IO base as-is (without trying to
do funky things to it) and just works. (i.e. there are 2 entries in the
0xc0000000-range per cf-card in /proc/ioports)


>> I've temporarily removed the PIO_MASK check and pata_pcmcia
>> works as expected. Is there any way around this, other than
>> creating an Alchemy-specific ioport_map() function?
>
> The provocative question - why would you want to have more than 64k I/O port
> space?

*I* don't want more; I want a smarter pata_pcmcia driver ;-)  I'll go bug other
people about this.  I brought this up here because one of my SH boards has
similar needs (need to do an ioremap() with special TLB flags to get access to
pcmcia IO space) but pata_pcmcia does work there (because SH kernel
either asks the board to translate an x86-IO port to memory address or
simply returns the port plus an offset).

Thanks!
        Manuel Lauss

From ralf@linux-mips.org Tue Oct  6 14:14:05 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Oct 2009 14:14:12 +0200 (CEST)
Received: from localhost.localdomain ([127.0.0.1]:57583 "EHLO h5.dl5rb.org.uk"
	rhost-flags-OK-OK-OK-FAIL) by ftp.linux-mips.org with ESMTP
	id S1492969AbZJFMOF (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 6 Oct 2009 14:14:05 +0200
Received: from h5.dl5rb.org.uk (localhost.localdomain [127.0.0.1])
	by h5.dl5rb.org.uk (8.14.3/8.14.3) with ESMTP id n96CFDmb022339;
	Tue, 6 Oct 2009 14:15:13 +0200
Received: (from ralf@localhost)
	by h5.dl5rb.org.uk (8.14.3/8.14.3/Submit) id n96CFCan022337;
	Tue, 6 Oct 2009 14:15:12 +0200
Date:	Tue, 6 Oct 2009 14:15:12 +0200
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Toy lover <toylover@gmail.com>
Cc:	linux-mips@linux-mips.org
Subject: Re: mipsel-sdelinux-v6.03.01-1.i386.rpm
Message-ID: <20091006121512.GD25263@linux-mips.org>
References: <81f85c130910032313u532c5bdt815f0633269bf79e@mail.gmail.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <81f85c130910032313u532c5bdt815f0633269bf79e@mail.gmail.com>
User-Agent: Mutt/1.5.19 (2009-01-05)
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24149
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Sun, Oct 04, 2009 at 02:13:44PM +0800, Toy lover wrote:

> I am trying to compile kernel modules for a kernel compiled with
> mipsel-sdelinux-v6.03.01-1
> but the ftp://ftp.mips.com/
> pub/tools/software/sde-for-linux/v6.03.01-1/mipsel-*sdelinux*
> -v6.03.01-1.i386.rpm
> is no longer available. I am wondering whether any of you can send me a copy
> of mipsel-*sdelinux*-v6.03.01-1.i386.rpm
> which you might still own.

You do not need the same compiler; just the compiler options for the kernel
proper and the module need to be compatible, that is endianess, processor
type etc. need to be the same.

  Ralf

From ralf@linux-mips.org Tue Oct  6 14:33:40 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Oct 2009 14:33:44 +0200 (CEST)
Received: from localhost.localdomain ([127.0.0.1]:59398 "EHLO h5.dl5rb.org.uk"
	rhost-flags-OK-OK-OK-FAIL) by ftp.linux-mips.org with ESMTP
	id S1492231AbZJFMdk (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 6 Oct 2009 14:33:40 +0200
Received: from h5.dl5rb.org.uk (localhost.localdomain [127.0.0.1])
	by h5.dl5rb.org.uk (8.14.3/8.14.3) with ESMTP id n96CYm3E025317;
	Tue, 6 Oct 2009 14:34:48 +0200
Received: (from ralf@localhost)
	by h5.dl5rb.org.uk (8.14.3/8.14.3/Submit) id n96CYmAt025313;
	Tue, 6 Oct 2009 14:34:48 +0200
Date:	Tue, 6 Oct 2009 14:34:48 +0200
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Manuel Lauss <manuel.lauss@googlemail.com>
Cc:	Linux-MIPS <linux-mips@linux-mips.org>,
	Manuel Lauss <manuel.lauss@gmail.com>
Subject: Re: [PATCH V2 0/6] Alchemy: devboard and platform updates
Message-ID: <20091006123448.GA22343@linux-mips.org>
References: <1254660929-15453-1-git-send-email-manuel.lauss@gmail.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <1254660929-15453-1-git-send-email-manuel.lauss@gmail.com>
User-Agent: Mutt/1.5.19 (2009-01-05)
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24150
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Sun, Oct 04, 2009 at 02:55:23PM +0200, Manuel Lauss wrote:

> Patches 1-3 are more-or-less MIPS-specific, I'd like for them
> to get applied while 4-6 await feedback from pcmcia list.

For the time being I've dropped the entire series into -queue.

  Ralf

From ralf@linux-mips.org Tue Oct  6 16:24:24 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Oct 2009 16:24:27 +0200 (CEST)
Received: from localhost.localdomain ([127.0.0.1]:48506 "EHLO h5.dl5rb.org.uk"
	rhost-flags-OK-OK-OK-FAIL) by ftp.linux-mips.org with ESMTP
	id S1493197AbZJFOYY (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 6 Oct 2009 16:24:24 +0200
Received: from h5.dl5rb.org.uk (localhost.localdomain [127.0.0.1])
	by h5.dl5rb.org.uk (8.14.3/8.14.3) with ESMTP id n96EPVvf027986;
	Tue, 6 Oct 2009 16:25:32 +0200
Received: (from ralf@localhost)
	by h5.dl5rb.org.uk (8.14.3/8.14.3/Submit) id n96EPV2U027983;
	Tue, 6 Oct 2009 16:25:31 +0200
Date:	Tue, 6 Oct 2009 16:25:31 +0200
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Manuel Lauss <manuel.lauss@googlemail.com>
Cc:	Linux-MIPS <linux-mips@linux-mips.org>
Subject: Re: Reason for PIO_MASK?
Message-ID: <20091006142531.GA27430@linux-mips.org>
References: <f861ec6f0910030748l396b45bck858f15460354e58e@mail.gmail.com> <20091006115220.GC25263@linux-mips.org> <f861ec6f0910060511t3e95a089h63dc33e628349c11@mail.gmail.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <f861ec6f0910060511t3e95a089h63dc33e628349c11@mail.gmail.com>
User-Agent: Mutt/1.5.19 (2009-01-05)
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24151
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Tue, Oct 06, 2009 at 02:11:15PM +0200, Manuel Lauss wrote:

> I meant the result of ioremap() of the 36bit address of PCMCIA IO space:
> so the ioport base is somewhere at 0xc0000000, which pata_pcmcia
> tries to devm_iomap(), and this is rejected by the above mentioned file.
> 
> The old ide-cs.c driver takes the given IO base as-is (without trying to
> do funky things to it) and just works. (i.e. there are 2 entries in the
> 0xc0000000-range per cf-card in /proc/ioports)

Feeding a virtual address as input to devm_ioremap or ioremap does not
make sense.  Ioremap is only to be used for memory resources anyway.

> >> I've temporarily removed the PIO_MASK check and pata_pcmcia
> >> works as expected. Is there any way around this, other than
> >> creating an Alchemy-specific ioport_map() function?
> >
> > The provocative question - why would you want to have more than 64k I/O port
> > space?
> 
> *I* don't want more; I want a smarter pata_pcmcia driver ;-)  I'll go bug other
> people about this.  I brought this up here because one of my SH boards has
> similar needs (need to do an ioremap() with special TLB flags to get access to
> pcmcia IO space) but pata_pcmcia does work there (because SH kernel
> either asks the board to translate an x86-IO port to memory address or
> simply returns the port plus an offset).

Well, Alchemy does this:

...
        if (!virt_io_addr) {
                printk(KERN_ERR "Unable to ioremap pci space\n");
                return 1;
        }
        au1x_controller.io_map_base = virt_io_addr;
...
set_io_port_base(virt_io_addr);
...

Which sets up a mapping for the entire port space.  Normally the PCMCIA
I/O port space should also be part of this range so inb, outb etc. for
the low 64k or so of port address range should just work without further
iomap calls of any sort.

  Ralf

From manuel.lauss@googlemail.com Tue Oct  6 17:00:08 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Tue, 06 Oct 2009 17:00:14 +0200 (CEST)
Received: from mail-fx0-f221.google.com ([209.85.220.221]:55673 "EHLO
	mail-fx0-f221.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492675AbZJFPAI convert rfc822-to-8bit
	(ORCPT <rfc822;linux-mips@linux-mips.org>);
	Tue, 6 Oct 2009 17:00:08 +0200
Received: by fxm21 with SMTP id 21so3295963fxm.33
        for <multiple recipients>; Tue, 06 Oct 2009 07:59:57 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:mime-version:received:in-reply-to:references
         :date:message-id:subject:from:to:cc:content-type
         :content-transfer-encoding;
        bh=DUm2m26vBJF5iflGOjYwWOWRtReC83OqFXc/RaudlwA=;
        b=PfKtEtWaMZNqyhmZ3BbTB+UilZT6KqWpWZmNVzoCKwBryXl7mgm7PNl78BUHviYouY
         2rOkFztagorwupK94rPDPW9BfKpHknPt4Y85ovL7KCpTZ+LfuBKfBrKlLOnStlc9A2pv
         LF75HfMNkhU2D38rfmULOwdTvauuxPrjcRPEg=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type:content-transfer-encoding;
        b=GstBAcOh0oaXFxAlZiOCyzTq/bOVebVpARxtFhLDo/zPRrDpdfcXZZnsBqbai9eJX5
         ltV6cSw7i0qz0mhScddpBiplxfbgKKMROI59vymxjJtFfMhHo+DHB00Nwg4RJUlyHdAG
         g6lwTH4umuSVjXb0LgNUZ5iFNswvgCwrJMYPA=
MIME-Version: 1.0
Received: by 10.103.84.1 with SMTP id m1mr425932mul.34.1254841197736; Tue, 06 
	Oct 2009 07:59:57 -0700 (PDT)
In-Reply-To: <20091006142531.GA27430@linux-mips.org>
References: <f861ec6f0910030748l396b45bck858f15460354e58e@mail.gmail.com>
	 <20091006115220.GC25263@linux-mips.org>
	 <f861ec6f0910060511t3e95a089h63dc33e628349c11@mail.gmail.com>
	 <20091006142531.GA27430@linux-mips.org>
Date:	Tue, 6 Oct 2009 16:59:57 +0200
Message-ID: <f861ec6f0910060759v21ac3fe1k7cb130f427834742@mail.gmail.com>
Subject: Re: Reason for PIO_MASK?
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	Linux-MIPS <linux-mips@linux-mips.org>
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8BIT
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24152
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

On Tue, Oct 6, 2009 at 4:25 PM, Ralf Baechle <ralf@linux-mips.org> wrote:
> On Tue, Oct 06, 2009 at 02:11:15PM +0200, Manuel Lauss wrote:
>
>> I meant the result of ioremap() of the 36bit address of PCMCIA IO space:
>> so the ioport base is somewhere at 0xc0000000, which pata_pcmcia
>> tries to devm_iomap(), and this is rejected by the above mentioned file.
>>
>> The old ide-cs.c driver takes the given IO base as-is (without trying to
>> do funky things to it) and just works. (i.e. there are 2 entries in the
>> 0xc0000000-range per cf-card in /proc/ioports)
>
> Feeding a virtual address as input to devm_ioremap or ioremap does not
> make sense.  Ioremap is only to be used for memory resources anyway.

Somewhere in the pcmcia socket driver I need to ioremap the 36bit
base of pcmcia io area:
io_base = ioremap(0xF 0000 0000, 0x10000) (->0xc1086000)

This is passed as io base to all drivers attached to this particular
pcmcia socket:

pata_pcmcia::pcmcia_init_one:
   devm_ioport_map(0xc1086000)
      ioport_map(0xc1086000) => no way!

With 2 sockets I have 2 isolated IO bases, and so far this works as
expected, except on drivers which use ioport_map().


>> >> I've temporarily removed the PIO_MASK check and pata_pcmcia
>> >> works as expected. Is there any way around this, other than
>> >> creating an Alchemy-specific ioport_map() function?
>> >
>> > The provocative question - why would you want to have more than 64k I/O port
>> > space?
>>
>> *I* don't want more; I want a smarter pata_pcmcia driver ;-)  I'll go bug other
>> people about this.  I brought this up here because one of my SH boards has
>> similar needs (need to do an ioremap() with special TLB flags to get access to
>> pcmcia IO space) but pata_pcmcia does work there (because SH kernel
>> either asks the board to translate an x86-IO port to memory address or
>> simply returns the port plus an offset).
>
> Well, Alchemy does this:
>
> ...
>        if (!virt_io_addr) {
>                printk(KERN_ERR "Unable to ioremap pci space\n");
>                return 1;
>        }
>        au1x_controller.io_map_base = virt_io_addr;
> ...
> set_io_port_base(virt_io_addr);
> ...
>
> Which sets up a mapping for the entire port space.  Normally the PCMCIA
> I/O port space should also be part of this range so inb, outb etc. for
> the low 64k or so of port address range should just work without further
> iomap calls of any sort.

With this scheme, if I put CF cards in both sockets, I think I'm screwed,
since both cards will use the same io ports.

/proc/ioports with 2 cf cards, independet pcmcia sockets:
c1086000-c1086007 : ide-cs
c108600e-c108600e : ide-cs
c108a000-c108a007 : ide-cs
c108a00e-c108a00e : ide-cs


Of all non-x86 archs which implement ioport_map(), MIPS is the only one
which excplicitly checks the argument; most simply return it unchanged,
some adjust the address space (and complain), add an offset,
or ioremap it (AVR32).  Why is MIPS special in this regard?

Maybe the whole logic should be turned around? Complain loudly if a driver
tries to access the range covered by PIO_MASK?

        Manuel Lauss

From afenkart@gmx.ch Wed Oct  7 11:49:43 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Oct 2009 11:49:49 +0200 (CEST)
Received: from mail.gmx.net ([213.165.64.20]:38353 "HELO mail.gmx.net"
	rhost-flags-OK-OK-OK-OK) by ftp.linux-mips.org with SMTP
	id S1492405AbZJGJtn (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Wed, 7 Oct 2009 11:49:43 +0200
Received: (qmail invoked by alias); 07 Oct 2009 09:49:34 -0000
Received: from unknown (EHLO localhost) [80.123.121.196]
  by mail.gmx.net (mp013) with SMTP; 07 Oct 2009 11:49:34 +0200
X-Authenticated: #20192376
X-Provags-ID: V01U2FsdGVkX1+OQQwSZcSOjaUizC1rKeyzxzTqDAFRVXTseDyigb
	xFXylw+CAzHizp
From:	Andreas Fenkart <andreas.fenkart@streamunlimited.com>
To:	linux-arm-kernel@lists.infradead.org, linux-mips@linux-mips.org,
	linux-am33-list@redhat.com, liqin.chen@sunplusct.com,
	x86@kernel.org, linux-kernel@vger.kernel.org,
	akpm@linux-foundation.org
Subject: Make totalhigh_pages of consistent type.
Date:	Wed,  7 Oct 2009 11:49:36 +0200
Message-Id: <1254908977-12827-1-git-send-email-andreas.fenkart@streamunlimited.com>
X-Mailer: git-send-email 1.6.4.3
X-Y-GMX-Trusted: 0
X-FuHaFi: 0.55
Return-Path: <afenkart@gmx.ch>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24153
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: andreas.fenkart@streamunlimited.com
Precedence: bulk
X-list: linux-mips

Printing the value of totalhigh_pages requires casting, see
typical print message:

arch/x86/mm/init_32.c:
  printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
      "%dk reserved, %dk data, %dk init, %ldk highmem)\n",
    nr_free_pages() << (PAGE_SHIFT-10),
    num_physpages << (PAGE_SHIFT-10),
    codesize >> 10,
    reservedpages << (PAGE_SHIFT-10),
    datasize >> 10,
    initsize >> 10,
    (unsigned long)(totalhigh_pages << (PAGE_SHIFT-10)));


The problem is that the type of totalhigh_pages is dependent on
CONFIG_HIGHMEM being set or not.

include/linux/highmem.h:
  #ifdef CONFIG_HIGHMEM
  
  extern unsigned long totalhigh_pages;
  
  #else /* CONFIG_HIGHMEM */
  
 -#define totalhigh_pages 0
 +#define totalhigh_pages 0UL
  ...

The patch changes the define, so that totalhigh_pages is of uniform
type in both cases.

Patch is build-tested on x86_32 and ARM

kind regards

Andreas



From afenkart@gmx.ch Wed Oct  7 11:50:07 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Oct 2009 11:50:15 +0200 (CEST)
Received: from mail.gmx.net ([213.165.64.20]:55355 "HELO mail.gmx.net"
	rhost-flags-OK-OK-OK-OK) by ftp.linux-mips.org with SMTP
	id S1492419AbZJGJtv (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Wed, 7 Oct 2009 11:49:51 +0200
Received: (qmail invoked by alias); 07 Oct 2009 09:49:43 -0000
Received: from unknown (EHLO localhost) [80.123.121.196]
  by mail.gmx.net (mp012) with SMTP; 07 Oct 2009 11:49:43 +0200
X-Authenticated: #20192376
X-Provags-ID: V01U2FsdGVkX1/6IZsRwmb6Ef0vE0T5laZfKLfMfXuucFndByNMbp
	Nag5h/r09w8ZVg
From:	Andreas Fenkart <andreas.fenkart@streamunlimited.com>
To:	linux-arm-kernel@lists.infradead.org, linux-mips@linux-mips.org,
	linux-am33-list@redhat.com, liqin.chen@sunplusct.com,
	x86@kernel.org, linux-kernel@vger.kernel.org,
	akpm@linux-foundation.org
Cc:	Andreas Fenkart <andreas.fenkart@streamunlimited.com>
Subject: [PATCH 1/1] Make totalhigh_pages unsigned long.
Date:	Wed,  7 Oct 2009 11:49:37 +0200
Message-Id: <1254908977-12827-2-git-send-email-andreas.fenkart@streamunlimited.com>
X-Mailer: git-send-email 1.6.4.3
In-Reply-To: <1254908977-12827-1-git-send-email-andreas.fenkart@streamunlimited.com>
References: <1254908977-12827-1-git-send-email-andreas.fenkart@streamunlimited.com>
X-Y-GMX-Trusted: 0
X-FuHaFi: 0.44
Return-Path: <afenkart@gmx.ch>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24154
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: andreas.fenkart@streamunlimited.com
Precedence: bulk
X-list: linux-mips

Makes it consistent with the extern declaration, used when
CONFIG_HIGHMEM is set
Removes redundant casts in printout messages

Signed-off-by: Andreas Fenkart <andreas.fenkart@streamunlimited.com>
---
 arch/arm/mm/init.c               |    2 +-
 arch/mips/mm/init.c              |    2 +-
 arch/mips/sgi-ip27/ip27-memory.c |    2 +-
 arch/mn10300/mm/init.c           |    3 +--
 arch/score/mm/init.c             |    2 +-
 arch/x86/mm/init_32.c            |    3 +--
 include/linux/highmem.h          |    2 +-
 7 files changed, 7 insertions(+), 9 deletions(-)

diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 877c492..8d76b50 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -598,7 +598,7 @@ void __init mem_init(void)
 		"%dK data, %dK init, %luK highmem)\n",
 		nr_free_pages() << (PAGE_SHIFT-10), codesize >> 10,
 		datasize >> 10, initsize >> 10,
-		(unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)));
+		totalhigh_pages << (PAGE_SHIFT-10));
 
 	if (PAGE_SIZE >= 16384 && num_physpages <= 128) {
 		extern int sysctl_overcommit_memory;
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 15aa190..03ac816 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -420,7 +420,7 @@ void __init mem_init(void)
 	       reservedpages << (PAGE_SHIFT-10),
 	       datasize >> 10,
 	       initsize >> 10,
-	       (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)));
+	       totalhigh_pages << (PAGE_SHIFT-10));
 }
 #endif /* !CONFIG_NEED_MULTIPLE_NODES */
 
diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c
index f61c164..bc12971 100644
--- a/arch/mips/sgi-ip27/ip27-memory.c
+++ b/arch/mips/sgi-ip27/ip27-memory.c
@@ -505,5 +505,5 @@ void __init mem_init(void)
 	       (num_physpages - tmp) << (PAGE_SHIFT-10),
 	       datasize >> 10,
 	       initsize >> 10,
-	       (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)));
+	       totalhigh_pages << (PAGE_SHIFT-10));
 }
diff --git a/arch/mn10300/mm/init.c b/arch/mn10300/mm/init.c
index ec14205..dd27a9a 100644
--- a/arch/mn10300/mm/init.c
+++ b/arch/mn10300/mm/init.c
@@ -118,8 +118,7 @@ void __init mem_init(void)
 	       reservedpages << (PAGE_SHIFT - 10),
 	       datasize >> 10,
 	       initsize >> 10,
-	       (unsigned long) (totalhigh_pages << (PAGE_SHIFT - 10))
-	       );
+	       totalhigh_pages << (PAGE_SHIFT - 10));
 }
 
 /*
diff --git a/arch/score/mm/init.c b/arch/score/mm/init.c
index 4e3dcd0..3739a41 100644
--- a/arch/score/mm/init.c
+++ b/arch/score/mm/init.c
@@ -111,7 +111,7 @@ void __init mem_init(void)
 			ram << (PAGE_SHIFT-10), codesize >> 10,
 			reservedpages << (PAGE_SHIFT-10), datasize >> 10,
 			initsize >> 10,
-			(unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)));
+			totalhigh_pages << (PAGE_SHIFT-10));
 }
 #endif /* !CONFIG_NEED_MULTIPLE_NODES */
 
diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c
index 30938c1..b1738d1 100644
--- a/arch/x86/mm/init_32.c
+++ b/arch/x86/mm/init_32.c
@@ -892,8 +892,7 @@ void __init mem_init(void)
 		reservedpages << (PAGE_SHIFT-10),
 		datasize >> 10,
 		initsize >> 10,
-		(unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))
-	       );
+		totalhigh_pages << (PAGE_SHIFT-10));
 
 	printk(KERN_INFO "virtual kernel memory layout:\n"
 		"    fixmap  : 0x%08lx - 0x%08lx   (%4ld kB)\n"
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 211ff44..ab2cc20 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -46,7 +46,7 @@ void kmap_flush_unused(void);
 
 static inline unsigned int nr_free_highpages(void) { return 0; }
 
-#define totalhigh_pages 0
+#define totalhigh_pages 0UL
 
 #ifndef ARCH_HAS_KMAP
 static inline void *kmap(struct page *page)
-- 
1.6.4.3


From manuel.lauss@googlemail.com Wed Oct  7 17:31:25 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Oct 2009 17:31:31 +0200 (CEST)
Received: from mail-ew0-f214.google.com ([209.85.219.214]:57601 "EHLO
	mail-ew0-f214.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1493437AbZJGPbZ (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Wed, 7 Oct 2009 17:31:25 +0200
Received: by ewy10 with SMTP id 10so5176065ewy.33
        for <multiple recipients>; Wed, 07 Oct 2009 08:31:19 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer;
        bh=+SPv8ow2U0YLVo0qZYkHN6lkXoNBUlwvfUusiEBt6pw=;
        b=BGXib3BtpsaqsxcS8Suuf0quF/e/injDrkv0MXYTKtoEuYIpfzNk/ROsKxKSCXS9jN
         dM/ovzt+hcvWwAaVfFUtZVmzeIy9j7qlEAyQRnnQpDaYE8hvlb/mttPi4KvSMsGeqQdt
         nQtIrbxvGsTgf80xkApetu0iRQdRa6HifHw7U=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer;
        b=iBqFSMG7kYb9QGlAMUH7f9IX00Qr7AD7imro6exTotUE8YHHbH8cBVmcyRfQ1VKoV1
         4KyNk6kONHVhf9GKj5Pal01lUw5po3RbUUrlx7LIwrSek1eF1XAKD3WNNbVDQXitQT0J
         MOf/gyUDQtSCRFVETGQEGJ8hre2576QGVAGlY=
Received: by 10.216.91.82 with SMTP id g60mr12943wef.98.1254929479616;
        Wed, 07 Oct 2009 08:31:19 -0700 (PDT)
Received: from localhost.localdomain (p5496B5E8.dip.t-dialin.net [84.150.181.232])
        by mx.google.com with ESMTPS id t12sm161148gvd.7.2009.10.07.08.31.17
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Wed, 07 Oct 2009 08:31:18 -0700 (PDT)
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	Linux-MIPS <linux-mips@linux-mips.org>,
	Manuel Lauss <manuel.lauss@gmail.com>
Subject: [PATCH -queue] Alchemy: fix pb1100/pb1500 compile failures
Date:	Wed,  7 Oct 2009 17:31:17 +0200
Message-Id: <1254929477-6697-1-git-send-email-manuel.lauss@gmail.com>
X-Mailer: git-send-email 1.6.5.rc2
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24155
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

forgot to remove inclusion of removed headers and add required ones.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
Extends  "MIPS: Alchemy: devboards: wire up new PCMCIA driver" in
Ralf's linux-queue tree.

Please apply or fold into the above mentioned patch!
Thanks!

 arch/mips/alchemy/devboards/pb1100/board_setup.c |    1 -
 arch/mips/alchemy/devboards/pb1100/platform.c    |    2 ++
 arch/mips/alchemy/devboards/pb1500/board_setup.c |    1 -
 arch/mips/alchemy/devboards/pb1500/platform.c    |    1 +
 4 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/mips/alchemy/devboards/pb1100/board_setup.c b/arch/mips/alchemy/devboards/pb1100/board_setup.c
index aad424a..b282d93 100644
--- a/arch/mips/alchemy/devboards/pb1100/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1100/board_setup.c
@@ -29,7 +29,6 @@
 #include <linux/interrupt.h>
 
 #include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-pb1x00/pb1100.h>
 #include <asm/mach-db1x00/bcsr.h>
 
 #include <prom.h>
diff --git a/arch/mips/alchemy/devboards/pb1100/platform.c b/arch/mips/alchemy/devboards/pb1100/platform.c
index 8aefecd..8487da5 100644
--- a/arch/mips/alchemy/devboards/pb1100/platform.c
+++ b/arch/mips/alchemy/devboards/pb1100/platform.c
@@ -20,6 +20,8 @@
 
 #include <linux/init.h>
 
+#include <asm/mach-au1x00/au1000.h>
+
 #include "../platform.h"
 
 static int __init pb1100_dev_init(void)
diff --git a/arch/mips/alchemy/devboards/pb1500/board_setup.c b/arch/mips/alchemy/devboards/pb1500/board_setup.c
index 4c4facb..a148802 100644
--- a/arch/mips/alchemy/devboards/pb1500/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1500/board_setup.c
@@ -29,7 +29,6 @@
 #include <linux/interrupt.h>
 
 #include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-pb1x00/pb1500.h>
 #include <asm/mach-db1x00/bcsr.h>
 
 #include <prom.h>
diff --git a/arch/mips/alchemy/devboards/pb1500/platform.c b/arch/mips/alchemy/devboards/pb1500/platform.c
index beb21e4..6c00cbe 100644
--- a/arch/mips/alchemy/devboards/pb1500/platform.c
+++ b/arch/mips/alchemy/devboards/pb1500/platform.c
@@ -19,6 +19,7 @@
  */
 
 #include <linux/init.h>
+#include <asm/mach-au1x00/au1000.h>
 
 #include "../platform.h"
 
-- 
1.6.5.rc2


From ralf@linux-mips.org Wed Oct  7 17:37:10 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Oct 2009 17:37:14 +0200 (CEST)
Received: from localhost.localdomain ([127.0.0.1]:36914 "EHLO h5.dl5rb.org.uk"
	rhost-flags-OK-OK-OK-FAIL) by ftp.linux-mips.org with ESMTP
	id S1493146AbZJGPhK (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Wed, 7 Oct 2009 17:37:10 +0200
Received: from h5.dl5rb.org.uk (localhost.localdomain [127.0.0.1])
	by h5.dl5rb.org.uk (8.14.3/8.14.3) with ESMTP id n97FcF6c016038;
	Wed, 7 Oct 2009 17:38:16 +0200
Received: (from ralf@localhost)
	by h5.dl5rb.org.uk (8.14.3/8.14.3/Submit) id n97FcEWT016035;
	Wed, 7 Oct 2009 17:38:14 +0200
Date:	Wed, 7 Oct 2009 17:38:14 +0200
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Manuel Lauss <manuel.lauss@googlemail.com>
Cc:	Linux-MIPS <linux-mips@linux-mips.org>,
	Manuel Lauss <manuel.lauss@gmail.com>
Subject: Re: [PATCH -queue] Alchemy: fix pb1100/pb1500 compile failures
Message-ID: <20091007153814.GA15076@linux-mips.org>
References: <1254929477-6697-1-git-send-email-manuel.lauss@gmail.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <1254929477-6697-1-git-send-email-manuel.lauss@gmail.com>
User-Agent: Mutt/1.5.19 (2009-01-05)
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24156
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Wed, Oct 07, 2009 at 05:31:17PM +0200, Manuel Lauss wrote:

> forgot to remove inclusion of removed headers and add required ones.
> 
> Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
> ---
> Extends  "MIPS: Alchemy: devboards: wire up new PCMCIA driver" in
> Ralf's linux-queue tree.
> 
> Please apply or fold into the above mentioned patch!
> Thanks!

Done.

From sshtylyov@ru.mvista.com Wed Oct  7 17:46:15 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Oct 2009 17:46:22 +0200 (CEST)
Received: from h155.mvista.com ([63.81.120.155]:6545 "EHLO imap.sh.mvista.com"
	rhost-flags-OK-FAIL-OK-FAIL) by ftp.linux-mips.org with ESMTP
	id S2097312AbZJGPqP (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Wed, 7 Oct 2009 17:46:15 +0200
Received: from [192.168.11.189] (unknown [10.150.0.9])
	by imap.sh.mvista.com (Postfix) with ESMTP
	id 594933EC9; Wed,  7 Oct 2009 08:46:09 -0700 (PDT)
Message-ID: <4ACCB874.1080206@ru.mvista.com>
Date:	Wed, 07 Oct 2009 19:49:08 +0400
From:	Sergei Shtylyov <sshtylyov@ru.mvista.com>
Organization: MontaVista Software Inc.
User-Agent: Mozilla/5.0 (X11; U; Linux i686; rv:1.7.2) Gecko/20040803
X-Accept-Language: ru, en-us, en-gb
MIME-Version: 1.0
To:	Manuel Lauss <manuel.lauss@googlemail.com>
Cc:	Ralf Baechle <ralf@linux-mips.org>,
	Linux-MIPS <linux-mips@linux-mips.org>
Subject: Re: Reason for PIO_MASK?
References: <f861ec6f0910030748l396b45bck858f15460354e58e@mail.gmail.com>	 <20091006115220.GC25263@linux-mips.org>	 <f861ec6f0910060511t3e95a089h63dc33e628349c11@mail.gmail.com>	 <20091006142531.GA27430@linux-mips.org> <f861ec6f0910060759v21ac3fe1k7cb130f427834742@mail.gmail.com>
In-Reply-To: <f861ec6f0910060759v21ac3fe1k7cb130f427834742@mail.gmail.com>
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit
Return-Path: <sshtylyov@ru.mvista.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24157
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: sshtylyov@ru.mvista.com
Precedence: bulk
X-list: linux-mips

Hello.

Manuel Lauss wrote:

>>>I meant the result of ioremap() of the 36bit address of PCMCIA IO space:
>>>so the ioport base is somewhere at 0xc0000000, which pata_pcmcia
>>>tries to devm_iomap(), and this is rejected by the above mentioned file.

>>>The old ide-cs.c driver takes the given IO base as-is (without trying to
>>>do funky things to it) and just works. (i.e. there are 2 entries in the
>>>0xc0000000-range per cf-card in /proc/ioports)

>>Feeding a virtual address as input to devm_ioremap or ioremap does not
>>make sense.  Ioremap is only to be used for memory resources anyway.

> Somewhere in the pcmcia socket driver I need to ioremap the 36bit
> base of pcmcia io area:
> io_base = ioremap(0xF 0000 0000, 0x10000) (->0xc1086000)

> This is passed as io base to all drivers attached to this particular
> pcmcia socket:

> pata_pcmcia::pcmcia_init_one:
>    devm_ioport_map(0xc1086000)
>       ioport_map(0xc1086000) => no way!

    But this is incorrect. You can't pass the result of ioremap to 
ioport_map() -- it's already a virtual *memory* address.

> With 2 sockets I have 2 isolated IO bases, and so far this works as
> expected, except on drivers which use ioport_map().

    There's something up with either your code or these drivers -- as what 
you're trying to do is just mixing the memory vs I/O port and physical vs 
virtual addresses.

>>>>>I've temporarily removed the PIO_MASK check and pata_pcmcia
>>>>>works as expected. Is there any way around this, other than
>>>>>creating an Alchemy-specific ioport_map() function?
>>>>
>>>>The provocative question - why would you want to have more than 64k I/O port
>>>>space?
>>>
>>>*I* don't want more; I want a smarter pata_pcmcia driver ;-)  I'll go bug other
>>>people about this.  I brought this up here because one of my SH boards has
>>>similar needs (need to do an ioremap() with special TLB flags to get access to
>>>pcmcia IO space) but pata_pcmcia does work there (because SH kernel
>>>either asks the board to translate an x86-IO port to memory address or
>>>simply returns the port plus an offset).
>>
>>Well, Alchemy does this:
>>
>>...
>>       if (!virt_io_addr) {
>>               printk(KERN_ERR "Unable to ioremap pci space\n");
>>               return 1;
>>       }
>>       au1x_controller.io_map_base = virt_io_addr;
>>...
>>set_io_port_base(virt_io_addr);
>>...
>>
>>Which sets up a mapping for the entire port space.  Normally the PCMCIA
>>I/O port space should also be part of this range so inb, outb etc. for
>>the low 64k or so of port address range should just work without further
>>iomap calls of any sort.

> With this scheme, if I put CF cards in both sockets, I think I'm screwed,
> since both cards will use the same io ports.

> /proc/ioports with 2 cf cards, independet pcmcia sockets:
> c1086000-c1086007 : ide-cs
> c108600e-c108600e : ide-cs
> c108a000-c108a007 : ide-cs
> c108a00e-c108a00e : ide-cs

> Of all non-x86 archs which implement ioport_map(), MIPS is the only one
> which excplicitly checks the argument; most simply return it unchanged,

> some adjust the address space (and complain), add an offset,
> or ioremap it (AVR32).  Why is MIPS special in this regard?

    Look at the default implementation in lib/iomap.c please -- it gets used 
when the arch doesn't implement ioport_map() and it makes use of PIO_MASK.

> Maybe the whole logic should be turned around? Complain loudly if a driver
> tries to access the range covered by PIO_MASK?

    I didn't get the idea. PIO_MASK defined the *valid* address range for 
in*()/out*(), not invalid.

>         Manuel Lauss

WBR, Sergei

From manuel.lauss@googlemail.com Wed Oct  7 18:07:59 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Oct 2009 18:08:05 +0200 (CEST)
Received: from mail-bw0-f208.google.com ([209.85.218.208]:35083 "EHLO
	mail-bw0-f208.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1493146AbZJGQH7 convert rfc822-to-8bit
	(ORCPT <rfc822;linux-mips@linux-mips.org>);
	Wed, 7 Oct 2009 18:07:59 +0200
Received: by bwz4 with SMTP id 4so6739bwz.0
        for <multiple recipients>; Wed, 07 Oct 2009 09:07:51 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:mime-version:received:in-reply-to:references
         :date:message-id:subject:from:to:cc:content-type
         :content-transfer-encoding;
        bh=reikXpFjdxug/flZ+uss0F7/AuQUeBVdNKI3lgyj36s=;
        b=RXPH5ZAI88N+FrgcD3bYLe7k1sGzu/to4Atp77D6VWLMFGgY4DI5fw1Bdp0KfZuRKh
         /bYn2183F5B/bC8p32SXMQtvlnYPq1d8T5HLcL3GO1gT+GxusL3s++xzg+AkOu9QMPbm
         YVfsqsDAoxFzDF8o6EJx8zefPtboTaYaZhTGw=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=mime-version:in-reply-to:references:date:message-id:subject:from:to
         :cc:content-type:content-transfer-encoding;
        b=oYJAeqSAfHOFQvjnfDyMbePsANiOm+ar46BXhbhG1g/a+dWDZTm0j6540VIE642cUR
         fn26xPPdHLBHet1VTD5fXdIJJdnJ//XwkpIaGLd4frx1+2EVaKTXHVZGbW2tVwgibIaq
         XMDFxwnk+qv0QKt4mBrn9bZmoP3xTJ5r8gfRw=
MIME-Version: 1.0
Received: by 10.103.125.17 with SMTP id c17mr40854mun.16.1254931671197; Wed, 
	07 Oct 2009 09:07:51 -0700 (PDT)
In-Reply-To: <4ACCB874.1080206@ru.mvista.com>
References: <f861ec6f0910030748l396b45bck858f15460354e58e@mail.gmail.com>
	 <20091006115220.GC25263@linux-mips.org>
	 <f861ec6f0910060511t3e95a089h63dc33e628349c11@mail.gmail.com>
	 <20091006142531.GA27430@linux-mips.org>
	 <f861ec6f0910060759v21ac3fe1k7cb130f427834742@mail.gmail.com>
	 <4ACCB874.1080206@ru.mvista.com>
Date:	Wed, 7 Oct 2009 18:07:51 +0200
Message-ID: <f861ec6f0910070907t469ad025xc8fdb9769d17f871@mail.gmail.com>
Subject: Re: Reason for PIO_MASK?
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Sergei Shtylyov <sshtylyov@ru.mvista.com>
Cc:	Ralf Baechle <ralf@linux-mips.org>,
	Linux-MIPS <linux-mips@linux-mips.org>
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 8BIT
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24158
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

Hi Sergei!

On Wed, Oct 7, 2009 at 5:49 PM, Sergei Shtylyov <sshtylyov@ru.mvista.com> wrote:
>>>> I meant the result of ioremap() of the 36bit address of PCMCIA IO space:
>>>> so the ioport base is somewhere at 0xc0000000, which pata_pcmcia
>>>> tries to devm_iomap(), and this is rejected by the above mentioned file.
>
>>>> The old ide-cs.c driver takes the given IO base as-is (without trying to
>>>> do funky things to it) and just works. (i.e. there are 2 entries in the
>>>> 0xc0000000-range per cf-card in /proc/ioports)
>
>>> Feeding a virtual address as input to devm_ioremap or ioremap does not
>>> make sense.  Ioremap is only to be used for memory resources anyway.
>
>> Somewhere in the pcmcia socket driver I need to ioremap the 36bit
>> base of pcmcia io area:
>> io_base = ioremap(0xF 0000 0000, 0x10000) (->0xc1086000)
>
>> This is passed as io base to all drivers attached to this particular
>> pcmcia socket:
>
>> pata_pcmcia::pcmcia_init_one:
>>   devm_ioport_map(0xc1086000)
>>      ioport_map(0xc1086000) => no way!
>
>   But this is incorrect. You can't pass the result of ioremap to
> ioport_map() -- it's already a virtual *memory* address.

Oh I don't doubt that, but how else am I supposed to access the
PCMCIA IO (which is outside the directly addressable address space!)
area on a non-PC arch?  Since this isn't a PC I don't really see why
the IO port space should be viewed as a sacred area between 0 and 0xffff
rather than another memory area with slightly different electrical
characteristics
(and the fact that it pulls the IOW#/IOR#/ lines on the PCMCIA interface
instead of the "standard" bus r/w signals).

I understand that drivers written for PC-XT hardware won't work, but I can
live with this burden..


>> With 2 sockets I have 2 isolated IO bases, and so far this works as
>> expected, except on drivers which use ioport_map().
>
>   There's something up with either your code or these drivers -- as what
> you're trying to do is just mixing the memory vs I/O port and physical vs
> virtual addresses.

The Alchemy pcmcia socket drivers haven been doing this since before
I knew Alchemy even existed (so > 3 years).


>>>>>> I've temporarily removed the PIO_MASK check and pata_pcmcia
>>>>>> works as expected. Is there any way around this, other than
>>>>>> creating an Alchemy-specific ioport_map() function?
>>>>>
>>>>> The provocative question - why would you want to have more than 64k I/O
>>>>> port
>>>>> space?
>>>>
>>>> *I* don't want more; I want a smarter pata_pcmcia driver ;-)  I'll go
>>>> bug other
>>>> people about this.  I brought this up here because one of my SH boards
>>>> has
>>>> similar needs (need to do an ioremap() with special TLB flags to get
>>>> access to
>>>> pcmcia IO space) but pata_pcmcia does work there (because SH kernel
>>>> either asks the board to translate an x86-IO port to memory address or
>>>> simply returns the port plus an offset).
>>>
>>> Well, Alchemy does this:
>>>
>>> ...
>>>      if (!virt_io_addr) {
>>>              printk(KERN_ERR "Unable to ioremap pci space\n");
>>>              return 1;
>>>      }
>>>      au1x_controller.io_map_base = virt_io_addr;
>>> ...
>>> set_io_port_base(virt_io_addr);
>>> ...
>>>
>>> Which sets up a mapping for the entire port space.  Normally the PCMCIA
>>> I/O port space should also be part of this range so inb, outb etc. for
>>> the low 64k or so of port address range should just work without further
>>> iomap calls of any sort.
>
>> With this scheme, if I put CF cards in both sockets, I think I'm screwed,
>> since both cards will use the same io ports.
>
>> /proc/ioports with 2 cf cards, independet pcmcia sockets:
>> c1086000-c1086007 : ide-cs
>> c108600e-c108600e : ide-cs
>> c108a000-c108a007 : ide-cs
>> c108a00e-c108a00e : ide-cs
>
>> Of all non-x86 archs which implement ioport_map(), MIPS is the only one
>> which excplicitly checks the argument; most simply return it unchanged,
>
>> some adjust the address space (and complain), add an offset,
>> or ioremap it (AVR32).  Why is MIPS special in this regard?
>
>   Look at the default implementation in lib/iomap.c please -- it gets used
> when the arch doesn't implement ioport_map() and it makes use of PIO_MASK.

That probably is the reason why every arch with pcmcia support does implement
its own pass-through variant.   And I'm not nearly smart enough to
figure out what
*else* to do...

In any case. thanks for the comment,
      Manuel Lauss

From manuel.lauss@googlemail.com Wed Oct  7 20:15:22 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Oct 2009 20:15:29 +0200 (CEST)
Received: from ey-out-1920.google.com ([74.125.78.147]:61781 "EHLO
	ey-out-1920.google.com" rhost-flags-OK-OK-OK-OK) by ftp.linux-mips.org
	with ESMTP id S1493516AbZJGSPW (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Wed, 7 Oct 2009 20:15:22 +0200
Received: by ey-out-1920.google.com with SMTP id 13so957149eye.52
        for <multiple recipients>; Wed, 07 Oct 2009 11:15:21 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer:in-reply-to:references;
        bh=ii8zEsFHQhopgrOb0NNHn7rnAuFjaTg46YDIhYYrwrY=;
        b=aMMtujAuN3+ferIbTZJbsa8s9FNKkqfXawKrw0t9UVWZtCSIxDEKMfWzAZ/iYrpNyn
         0i0FBo6bqGpni08EnDdXthvbIknXfYKfAF1nuby2YDFKqTATWhNj7SyG/Es5GaZmWLaH
         w8oUTm61YB4rgMEJNBw9Rfiq/txYPNfVS5X4E=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        b=dJqOx5O50fAXwsYeXkVY9DbBxRAeqJ0IR5ikCmvADHenE8t3hCMtYZEltzQe3u3WIs
         EYgpzo7zx4rcQQrN0kF0xcoVbWr+lCbhplKh6o7qNCAv6UfJUM/FzgnTbk3dE+7MVS2k
         eoSPDcVBxAqjb0DLoC54fmfyOMc1td9ygTkC8=
Received: by 10.216.88.209 with SMTP id a59mr74945wef.50.1254939321310;
        Wed, 07 Oct 2009 11:15:21 -0700 (PDT)
Received: from localhost.localdomain (p5496B5E8.dip.t-dialin.net [84.150.181.232])
        by mx.google.com with ESMTPS id f13sm94596gvd.21.2009.10.07.11.15.19
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Wed, 07 Oct 2009 11:15:20 -0700 (PDT)
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	Linux-MIPS <linux-mips@linux-mips.org>,
	Manuel Lauss <manuel.lauss@gmail.com>
Subject: [PATCH 2/4] Alchemy: higher priority for system timer.
Date:	Wed,  7 Oct 2009 20:15:13 +0200
Message-Id: <1254939315-8158-3-git-send-email-manuel.lauss@gmail.com>
X-Mailer: git-send-email 1.6.5.rc2
In-Reply-To: <1254939315-8158-2-git-send-email-manuel.lauss@gmail.com>
References: <1254939315-8158-1-git-send-email-manuel.lauss@gmail.com>
 <1254939315-8158-2-git-send-email-manuel.lauss@gmail.com>
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24159
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

Raise RTCMATCH2 interrupt priority in case it is used as the system
timer tick.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 arch/mips/alchemy/common/irq.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c
index 81acd2a..da53a3b 100644
--- a/arch/mips/alchemy/common/irq.c
+++ b/arch/mips/alchemy/common/irq.c
@@ -74,7 +74,7 @@ struct au1xxx_irqmap {
 	{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
 	{ AU1000_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
 	{ AU1000_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
 	{ AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 },
@@ -108,7 +108,7 @@ struct au1xxx_irqmap {
 	{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
 	{ AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 },
 	{ AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 },
@@ -140,7 +140,7 @@ struct au1xxx_irqmap {
 	{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
 	{ AU1000_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
 	{ AU1000_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
 	{ AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 },
@@ -174,7 +174,7 @@ struct au1xxx_irqmap {
 	{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
 	{ AU1550_NAND_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 },
 	{ AU1550_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
@@ -202,7 +202,7 @@ struct au1xxx_irqmap {
 	{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
 	{ AU1200_NAND_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1200_USB_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
 	{ AU1200_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-- 
1.6.5.rc2


From manuel.lauss@googlemail.com Wed Oct  7 20:15:47 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Oct 2009 20:15:53 +0200 (CEST)
Received: from mail-ew0-f216.google.com ([209.85.219.216]:61636 "EHLO
	mail-ew0-f216.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1493519AbZJGSP0 (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Wed, 7 Oct 2009 20:15:26 +0200
Received: by ewy12 with SMTP id 12so10566863ewy.0
        for <multiple recipients>; Wed, 07 Oct 2009 11:15:18 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer;
        bh=Cpm0WWLpEPEWkeJM2tXve3idRQTxBAQWPHrVLhgCrGg=;
        b=pLIUFGQm7RZF7Yz9yYW/J/y7olZ8+gRgbW7WHl4CHv9d2j1h5Nuf4tApqWROGyfi2C
         XSTuyq+O/AnMu+zTJWpHPAUkJRWkpMnoVYy595A92QW78SCl12gB5M8hdAu85Rs3Drld
         Z/n5qpIeoONPtKY6WMRL4N8Az1eZGgfRiZ8uw=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer;
        b=eKr1FgAdJM16gADFURfAub8GK8GI+mUNt6jjJ1FttF/Gvx2cVc5DQwwg8ArLeJAP1E
         KD39YoZ3bDmPP4Kr22lIykrBM/IaocHp9WdDZWAyf3Tct277RwGqzyKeU7FOHQ0AXujo
         6JaT5Fp927pOPpWEGxQRYr0mwaA+/WxKpqstY=
Received: by 10.216.87.75 with SMTP id x53mr80696wee.13.1254939317768;
        Wed, 07 Oct 2009 11:15:17 -0700 (PDT)
Received: from localhost.localdomain (p5496B5E8.dip.t-dialin.net [84.150.181.232])
        by mx.google.com with ESMTPS id f13sm94596gvd.21.2009.10.07.11.15.15
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Wed, 07 Oct 2009 11:15:17 -0700 (PDT)
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	Linux-MIPS <linux-mips@linux-mips.org>,
	Manuel Lauss <manuel.lauss@gmail.com>
Subject: [PATCH -queue 0/4] Alchemy: another round of IRQ changes
Date:	Wed,  7 Oct 2009 20:15:11 +0200
Message-Id: <1254939315-8158-1-git-send-email-manuel.lauss@gmail.com>
X-Mailer: git-send-email 1.6.5.rc2
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24160
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

Here's another round of Alchemy IRQ changes, intended to be applied on
top of the alchemy pcmcia changes in Ralf's linux-queue.git tree.

Major theme is to stop the name-sharing of certain Alchemy interrupt
sources.  Some parts of the alchemy core code currently rely on
specially-named irq constants in order to save code (platform.c, and
time.c for instance);  however the au1000.h header is full of
compile-time checks for a certain CPU subtype.

Eventually I'd like to get rid of all CONFIG_SOC_AU1??? checks in
au1000.h altogether (for easier Au1300 integration);  preferably
also in the vast majority of the alchemy common code. But I'm not
really convinced any more that it is at all possible.

Patch overview:
#1  tries to get rid of the special case for the usb device interrupt,
    rather than adding #ifdefs for each cpu subtype with this
    particular usb device ip, i opted to use the hardware to do the
    prioritization.

    I'm not sure whether this really is equivalent to the previous
    solution since I neither have the hardware nor a driver for the
    Au1000 UDC.

#2  changes the rtcmatch2 (system timer) irq priority to high.
    not strictly related, but it fit into the irq upddate theme.

#3  re-introduces the alchemy cpu subtype detector, it's required
    by changes in #4.

#4  does the constant renaming: irq sources are prefixed with a
    cpu subtype string, and gpio int sources get the "_INT" postfix
    (they're interrupt sources, not gpio numbers after all).

Run-tested on the DB1200, and known to build for all db1x00/pb1x00,
xxs1500, mtx-1.

Please apply (and test if you have any of the other boards).
Thanks!
	Manuel Lauss


Manuel Lauss (4):
  Alchemy: remove USB_DEV_REQ_INT prioritization hack
  Alchemy: higher priority for system timer.
  Alchemy: simple cpu subtype detector
  Alchemy: Stop IRQ name sharing

 arch/mips/alchemy/common/dbdma.c                 |   61 ++-
 arch/mips/alchemy/common/dma.c                   |   36 +-
 arch/mips/alchemy/common/irq.c                   |  322 +++++-----
 arch/mips/alchemy/common/platform.c              |    8 +-
 arch/mips/alchemy/common/time.c                  |   35 +-
 arch/mips/alchemy/devboards/db1x00/board_setup.c |   64 ++-
 arch/mips/alchemy/devboards/db1x00/platform.c    |   52 +-
 arch/mips/alchemy/devboards/pb1000/board_setup.c |    2 +-
 arch/mips/alchemy/devboards/pb1100/board_setup.c |    8 +-
 arch/mips/alchemy/devboards/pb1100/platform.c    |    6 +-
 arch/mips/alchemy/devboards/pb1200/board_setup.c |    4 +-
 arch/mips/alchemy/devboards/pb1500/board_setup.c |   20 +-
 arch/mips/alchemy/devboards/pb1500/platform.c    |    6 +-
 arch/mips/alchemy/devboards/pb1550/board_setup.c |   10 +-
 arch/mips/alchemy/devboards/pb1550/platform.c    |    8 +-
 arch/mips/alchemy/mtx-1/board_setup.c            |   26 +-
 arch/mips/alchemy/xxs1500/board_setup.c          |   24 +-
 arch/mips/include/asm/mach-au1x00/au1000.h       |  704 +++++++++++-----------
 arch/mips/include/asm/mach-au1x00/gpio-au1000.h  |   76 +--
 19 files changed, 788 insertions(+), 684 deletions(-)



From manuel.lauss@googlemail.com Wed Oct  7 20:16:11 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Oct 2009 20:16:19 +0200 (CEST)
Received: from mail-ew0-f216.google.com ([209.85.219.216]:64501 "EHLO
	mail-ew0-f216.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1493065AbZJGSP0 (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Wed, 7 Oct 2009 20:15:26 +0200
Received: by ewy12 with SMTP id 12so10566879ewy.0
        for <multiple recipients>; Wed, 07 Oct 2009 11:15:19 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer:in-reply-to:references;
        bh=oX/Z9SmEtPSOE+0ZnGmQOwk1gdKhGlYR5SNQyCZP/oU=;
        b=gD89z9gajyzDRa9RlWFSOu8ay3z11mly5ulk0mslsp+oHonkPdc7Bk2st/doV+lhPH
         3vKOEhjkZuweQiRQGWDDMvuvzkOreFMjr/dLYMYgDH58XAx8MhUtp3P1kciqQWOd7wq/
         rUp7N1iN5YpiCKlYNu3a/4MidVaD3exciqSls=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        b=hH37opULAU0Mv0iYmnt/bfBPuPAdOztSKZy8jnqn0Ymvq8G8pZW9kufIvelDU0JWfh
         DTFmjr0ECxJ/cSULDhxQsVjTHmMEpOPlxiespgzEaOaSVfjV2r5c7ICFv6BynXuGCF6W
         uD0vjbv0hIuT1j0t/UdSx0PwySsKnUc+/tKC8=
Received: by 10.216.88.68 with SMTP id z46mr77705wee.27.1254939319331;
        Wed, 07 Oct 2009 11:15:19 -0700 (PDT)
Received: from localhost.localdomain (p5496B5E8.dip.t-dialin.net [84.150.181.232])
        by mx.google.com with ESMTPS id f13sm94596gvd.21.2009.10.07.11.15.18
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Wed, 07 Oct 2009 11:15:18 -0700 (PDT)
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	Linux-MIPS <linux-mips@linux-mips.org>,
	Manuel Lauss <manuel.lauss@gmail.com>
Subject: [PATCH 1/4] Alchemy: remove USB_DEV_REQ_INT prioritization hack
Date:	Wed,  7 Oct 2009 20:15:12 +0200
Message-Id: <1254939315-8158-2-git-send-email-manuel.lauss@gmail.com>
X-Mailer: git-send-email 1.6.5.rc2
In-Reply-To: <1254939315-8158-1-git-send-email-manuel.lauss@gmail.com>
References: <1254939315-8158-1-git-send-email-manuel.lauss@gmail.com>
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24161
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

The Alchemy hardware provides a method to prioritize interrupts
on a controller by assigning them to a differenct core request line.
Assign usb device request interrupt to IC0 Request 0 (which has
highest priority in the core and the dispatcher) and others to
Request 1.  The explicit check for usb device request occurrence
should be obsolete now.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 arch/mips/alchemy/common/irq.c |   50 +++++++++++++++++----------------------
 1 files changed, 22 insertions(+), 28 deletions(-)

diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c
index cd264b1..81acd2a 100644
--- a/arch/mips/alchemy/common/irq.c
+++ b/arch/mips/alchemy/common/irq.c
@@ -39,11 +39,18 @@
 
 static int au1x_ic_settype(unsigned int irq, unsigned int flow_type);
 
+/* NOTE on interrupt priorities: The original writers of this code said:
+ *
+ * Because of the tight timing of SETUP token to reply transactions,
+ * the USB devices-side packet complete interrupt (USB_DEV_REQ_INT)
+ * needs the highest priority.
+ */
+
 /* per-processor fixed function irqs */
 struct au1xxx_irqmap {
 	int im_irq;
 	int im_type;
-	int im_request;
+	int im_request;		/* set 1 to get higher priority */
 } au1xxx_ic0_map[] __initdata = {
 #if defined(CONFIG_SOC_AU1000)
 	{ AU1000_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
@@ -63,14 +70,14 @@ struct au1xxx_irqmap {
 	{ AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
+	{ AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
 	{ AU1000_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
+	{ AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 },
 	{ AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 },
 	{ AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 },
@@ -97,12 +104,12 @@ struct au1xxx_irqmap {
 	{ AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
+	{ AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
+	{ AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 },
 	{ AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 },
 	{ AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 },
@@ -129,14 +136,14 @@ struct au1xxx_irqmap {
 	{ AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
+	{ AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
 	{ AU1000_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
+	{ AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 },
 	{ AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 },
 	{ AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 },
@@ -163,13 +170,13 @@ struct au1xxx_irqmap {
 	{ AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
+	{ AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1550_NAND_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
+	{ AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 },
 	{ AU1550_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1550_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 },
 	{ AU1550_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
@@ -191,7 +198,7 @@ struct au1xxx_irqmap {
 	{ AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
+	{ AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
 	{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
@@ -489,7 +496,7 @@ static int au1x_ic_settype(unsigned int irq, unsigned int flow_type)
 asmlinkage void plat_irq_dispatch(void)
 {
 	unsigned int pending = read_c0_status() & read_c0_cause();
-	unsigned long s, off, bit;
+	unsigned long s, off;
 
 	if (pending & CAUSEF_IP7) {
 		do_IRQ(MIPS_CPU_IRQ_BASE + 7);
@@ -509,25 +516,12 @@ asmlinkage void plat_irq_dispatch(void)
 	} else
 		goto spurious;
 
-	bit = 0;
 	s = au_readl(s);
 	if (unlikely(!s)) {
 spurious:
 		spurious_interrupt();
 		return;
 	}
-#ifdef AU1000_USB_DEV_REQ_INT
-	/*
-	 * Because of the tight timing of SETUP token to reply
-	 * transactions, the USB devices-side packet complete
-	 * interrupt needs the highest priority.
-	 */
-	bit = 1 << (AU1000_USB_DEV_REQ_INT - AU1000_INTC0_INT_BASE);
-	if ((pending & CAUSEF_IP2) && (s & bit)) {
-		do_IRQ(AU1000_USB_DEV_REQ_INT);
-		return;
-	}
-#endif
 	do_IRQ(__ffs(s) + off);
 }
 
@@ -548,11 +542,11 @@ static void __init setup_irqmap(struct au1xxx_irqmap *map, int count)
 		if (irq_nr >= AU1000_INTC1_INT_BASE) {
 			bit = irq_nr - AU1000_INTC1_INT_BASE;
 			if (map[count].im_request)
-				au_writel(1 << bit, IC1_ASSIGNCLR);
+				au_writel(1 << bit, IC1_ASSIGNSET);
 		} else {
 			bit = irq_nr - AU1000_INTC0_INT_BASE;
 			if (map[count].im_request)
-				au_writel(1 << bit, IC0_ASSIGNCLR);
+				au_writel(1 << bit, IC0_ASSIGNSET);
 		}
 
 		au1x_ic_settype(irq_nr, map[count].im_type);
@@ -570,7 +564,7 @@ void __init arch_init_irq(void)
 	au_writel(0xffffffff, IC0_CFG1CLR);
 	au_writel(0xffffffff, IC0_CFG2CLR);
 	au_writel(0xffffffff, IC0_MASKCLR);
-	au_writel(0xffffffff, IC0_ASSIGNSET);
+	au_writel(0xffffffff, IC0_ASSIGNCLR);
 	au_writel(0xffffffff, IC0_WAKECLR);
 	au_writel(0xffffffff, IC0_SRCSET);
 	au_writel(0xffffffff, IC0_FALLINGCLR);
@@ -581,7 +575,7 @@ void __init arch_init_irq(void)
 	au_writel(0xffffffff, IC1_CFG1CLR);
 	au_writel(0xffffffff, IC1_CFG2CLR);
 	au_writel(0xffffffff, IC1_MASKCLR);
-	au_writel(0xffffffff, IC1_ASSIGNSET);
+	au_writel(0xffffffff, IC1_ASSIGNCLR);
 	au_writel(0xffffffff, IC1_WAKECLR);
 	au_writel(0xffffffff, IC1_SRCSET);
 	au_writel(0xffffffff, IC1_FALLINGCLR);
-- 
1.6.5.rc2


From manuel.lauss@googlemail.com Wed Oct  7 20:16:38 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Oct 2009 20:16:44 +0200 (CEST)
Received: from mail-ew0-f216.google.com ([209.85.219.216]:39618 "EHLO
	mail-ew0-f216.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1493520AbZJGSP2 (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Wed, 7 Oct 2009 20:15:28 +0200
Received: by ewy12 with SMTP id 12so10566931ewy.0
        for <multiple recipients>; Wed, 07 Oct 2009 11:15:23 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer:in-reply-to:references;
        bh=sxUlcjyUwGyUYC27fuEmRf04Fa375es73PaB9oOoNoo=;
        b=CGCg1dYqkVNUvHzcNr8rxmLBU7k3GHm0t46bsh4TCOU6CRzXuIP/iYVSOMdLL+YBYL
         iI+unAVcTr0rxULTYsZqvVBWFMlUuUbYQs53QdAjcUnSQnJfI64Kh8wYYxDFiUMzHmVS
         Wu0xyVZADzJ4sQu3tEGUSiRPsDm1mw2E05NMI=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        b=luuCJ+yMrmHKxcs7n8XdgWlO37posqDrNDLzzTHGk802SndE1ttCBEYhyXoPZWhtht
         gea6Xhzfv03JYdnU2iAY2joHjeyl9zFKskR0+//aJLzI+9eD5qZRClHvnVa5SDtdrA49
         //xDHjKJaDJcU7dUidTExKJ5oqgxGBYs1FH6E=
Received: by 10.216.85.194 with SMTP id u44mr75152wee.65.1254939323061;
        Wed, 07 Oct 2009 11:15:23 -0700 (PDT)
Received: from localhost.localdomain (p5496B5E8.dip.t-dialin.net [84.150.181.232])
        by mx.google.com with ESMTPS id f13sm94596gvd.21.2009.10.07.11.15.21
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Wed, 07 Oct 2009 11:15:22 -0700 (PDT)
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	Linux-MIPS <linux-mips@linux-mips.org>,
	Manuel Lauss <manuel.lauss@gmail.com>
Subject: [PATCH 3/4] Alchemy: simple cpu subtype detector
Date:	Wed,  7 Oct 2009 20:15:14 +0200
Message-Id: <1254939315-8158-4-git-send-email-manuel.lauss@gmail.com>
X-Mailer: git-send-email 1.6.5.rc2
In-Reply-To: <1254939315-8158-3-git-send-email-manuel.lauss@gmail.com>
References: <1254939315-8158-1-git-send-email-manuel.lauss@gmail.com>
 <1254939315-8158-2-git-send-email-manuel.lauss@gmail.com>
 <1254939315-8158-3-git-send-email-manuel.lauss@gmail.com>
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24162
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

extract the alchemy chip variant from c0_prid register.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 arch/mips/include/asm/mach-au1x00/au1000.h |   30 ++++++++++++++++++++++++++++
 1 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index fceeca8..9174285 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -130,6 +130,36 @@ static inline int au1xxx_cpu_needs_config_od(void)
 	return 0;
 }
 
+#define ALCHEMY_CPU_UNKNOWN	-1
+#define ALCHEMY_CPU_AU1000	0
+#define ALCHEMY_CPU_AU1500	1
+#define ALCHEMY_CPU_AU1100	2
+#define ALCHEMY_CPU_AU1550	3
+#define ALCHEMY_CPU_AU1200	4
+
+static inline int alchemy_get_cputype(void)
+{
+	switch (read_c0_prid() & 0xffff0000) {
+	case 0x00030000:
+		return ALCHEMY_CPU_AU1000;
+		break;
+	case 0x01030000:
+		return ALCHEMY_CPU_AU1500;
+		break;
+	case 0x02030000:
+		return ALCHEMY_CPU_AU1100;
+		break;
+	case 0x03030000:
+		return ALCHEMY_CPU_AU1550;
+		break;
+	case 0x04030000:
+		return ALCHEMY_CPU_AU1200;
+		break;
+	}
+
+	return ALCHEMY_CPU_UNKNOWN;
+}
+
 /* arch/mips/au1000/common/clocks.c */
 extern void set_au1x00_speed(unsigned int new_freq);
 extern unsigned int get_au1x00_speed(void);
-- 
1.6.5.rc2


From manuel.lauss@googlemail.com Wed Oct  7 20:17:02 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Wed, 07 Oct 2009 20:17:09 +0200 (CEST)
Received: from mail-ew0-f216.google.com ([209.85.219.216]:34596 "EHLO
	mail-ew0-f216.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1493547AbZJGSPb (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Wed, 7 Oct 2009 20:15:31 +0200
Received: by ewy12 with SMTP id 12so10566984ewy.0
        for <multiple recipients>; Wed, 07 Oct 2009 11:15:26 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=googlemail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer:in-reply-to:references;
        bh=ac/GYxwsR8Z9IBAXYU2Pez+RfKBWDT9uQ1dPEfxzFlk=;
        b=bXoV2lBM6VQS9R0RVaXLtdLMpsxCJwYbdxmFWilb+ZghfZAgsRFhWE935WQNcYZwBA
         asqPM/TCEXf9b87ymI23JjVCR5iiBESXUHxTRWiZ8uRfoHX49kIPAkd3n/hVjKdmdnCQ
         lUuuc/+aD35dCAy/UKWXGnVmSRm3q3PZg2HVY=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=googlemail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references;
        b=xWFo2E0i6OB8hUCXCzKKqgLiMZa7lV3EJUdihaaEm6Ix31hnra2fXjuXKRtYo0hU1R
         my2/0Yx2ERRvaqIqNPt2qenQ3zj4zXxoA8czhyRNylDRVQvSm+augHtmwZ9Ej2HUry9b
         FnLYy0Y7Uy00HUGPZ4gpqdrTDLmUVG/Ti6FlA=
Received: by 10.216.86.19 with SMTP id v19mr76364wee.99.1254939325953;
        Wed, 07 Oct 2009 11:15:25 -0700 (PDT)
Received: from localhost.localdomain (p5496B5E8.dip.t-dialin.net [84.150.181.232])
        by mx.google.com with ESMTPS id f13sm94596gvd.21.2009.10.07.11.15.23
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Wed, 07 Oct 2009 11:15:25 -0700 (PDT)
From:	Manuel Lauss <manuel.lauss@googlemail.com>
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	Linux-MIPS <linux-mips@linux-mips.org>,
	Manuel Lauss <manuel.lauss@gmail.com>
Subject: [PATCH 4/4] Alchemy: Stop IRQ name sharing
Date:	Wed,  7 Oct 2009 20:15:15 +0200
Message-Id: <1254939315-8158-5-git-send-email-manuel.lauss@gmail.com>
X-Mailer: git-send-email 1.6.5.rc2
In-Reply-To: <1254939315-8158-4-git-send-email-manuel.lauss@gmail.com>
References: <1254939315-8158-1-git-send-email-manuel.lauss@gmail.com>
 <1254939315-8158-2-git-send-email-manuel.lauss@gmail.com>
 <1254939315-8158-3-git-send-email-manuel.lauss@gmail.com>
 <1254939315-8158-4-git-send-email-manuel.lauss@gmail.com>
Return-Path: <manuel.lauss@googlemail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24163
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: manuel.lauss@googlemail.com
Precedence: bulk
X-list: linux-mips

Eliminate the sharing of IRQ names among the differenct Alchemy
variants.  IRQ numbers need no longer be hidden behind a
CONFIG_SOC_AU1XXX symbol: step 1 in my quest to make the Alchemy
code less reliant on a hardcoded subtype.

This patch also renames the GPIO irq number constants. It's really
an interrupt line, NOT a GPIO number!

Code which relied on certain irq numbers to have the same name
across all supported cpu subtypes is changed to determine current
cpu subtype at runtime; in some places this isn't possible so
a "compat" symbol is used.

Run-tested on DB1200.

Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
---
 arch/mips/alchemy/common/dbdma.c                 |   61 ++-
 arch/mips/alchemy/common/dma.c                   |   36 +-
 arch/mips/alchemy/common/irq.c                   |  290 +++++-----
 arch/mips/alchemy/common/platform.c              |    8 +-
 arch/mips/alchemy/common/time.c                  |   35 +-
 arch/mips/alchemy/devboards/db1x00/board_setup.c |   64 ++-
 arch/mips/alchemy/devboards/db1x00/platform.c    |   52 +-
 arch/mips/alchemy/devboards/pb1000/board_setup.c |    2 +-
 arch/mips/alchemy/devboards/pb1100/board_setup.c |    8 +-
 arch/mips/alchemy/devboards/pb1100/platform.c    |    6 +-
 arch/mips/alchemy/devboards/pb1200/board_setup.c |    4 +-
 arch/mips/alchemy/devboards/pb1500/board_setup.c |   20 +-
 arch/mips/alchemy/devboards/pb1500/platform.c    |    6 +-
 arch/mips/alchemy/devboards/pb1550/board_setup.c |   10 +-
 arch/mips/alchemy/devboards/pb1550/platform.c    |    8 +-
 arch/mips/alchemy/mtx-1/board_setup.c            |   26 +-
 arch/mips/alchemy/xxs1500/board_setup.c          |   24 +-
 arch/mips/include/asm/mach-au1x00/au1000.h       |  674 +++++++++++-----------
 arch/mips/include/asm/mach-au1x00/gpio-au1000.h  |   76 ++--
 19 files changed, 745 insertions(+), 665 deletions(-)

diff --git a/arch/mips/alchemy/common/dbdma.c b/arch/mips/alchemy/common/dbdma.c
index 19c1c82..fb09489 100644
--- a/arch/mips/alchemy/common/dbdma.c
+++ b/arch/mips/alchemy/common/dbdma.c
@@ -30,6 +30,7 @@
  *
  */
 
+#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
@@ -58,7 +59,6 @@ static DEFINE_SPINLOCK(au1xxx_dbdma_spin_lock);
 
 static dbdma_global_t *dbdma_gptr = (dbdma_global_t *)DDMA_GLOBAL_BASE;
 static int dbdma_initialized;
-static void au1xxx_dbdma_init(void);
 
 static dbdev_tab_t dbdev_tab[] = {
 #ifdef CONFIG_SOC_AU1550
@@ -250,8 +250,7 @@ u32 au1xxx_dbdma_chan_alloc(u32 srcid, u32 destid,
 	 * which can't be done successfully during board set up.
 	 */
 	if (!dbdma_initialized)
-		au1xxx_dbdma_init();
-	dbdma_initialized = 1;
+		return 0;
 
 	stp = find_dbdev_id(srcid);
 	if (stp == NULL)
@@ -868,28 +867,6 @@ static irqreturn_t dbdma_interrupt(int irq, void *dev_id)
 	return IRQ_RETVAL(1);
 }
 
-static void au1xxx_dbdma_init(void)
-{
-	int irq_nr;
-
-	dbdma_gptr->ddma_config = 0;
-	dbdma_gptr->ddma_throttle = 0;
-	dbdma_gptr->ddma_inten = 0xffff;
-	au_sync();
-
-#if defined(CONFIG_SOC_AU1550)
-	irq_nr = AU1550_DDMA_INT;
-#elif defined(CONFIG_SOC_AU1200)
-	irq_nr = AU1200_DDMA_INT;
-#else
-	#error Unknown Au1x00 SOC
-#endif
-
-	if (request_irq(irq_nr, dbdma_interrupt, IRQF_DISABLED,
-			"Au1xxx dbdma", (void *)dbdma_gptr))
-		printk(KERN_ERR "Can't get 1550 dbdma irq");
-}
-
 void au1xxx_dbdma_dump(u32 chanid)
 {
 	chan_tab_t	 *ctp;
@@ -1038,4 +1015,38 @@ void au1xxx_dbdma_resume(void)
 	}
 }
 #endif	/* CONFIG_PM */
+
+static int __init au1xxx_dbdma_init(void)
+{
+	int irq_nr, ret;
+
+	dbdma_gptr->ddma_config = 0;
+	dbdma_gptr->ddma_throttle = 0;
+	dbdma_gptr->ddma_inten = 0xffff;
+	au_sync();
+
+	switch (alchemy_get_cputype()) {
+	case ALCHEMY_CPU_AU1550:
+		irq_nr = AU1550_DDMA_INT;
+		break;
+	case ALCHEMY_CPU_AU1200:
+		irq_nr = AU1200_DDMA_INT;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	ret = request_irq(irq_nr, dbdma_interrupt, IRQF_DISABLED,
+			"Au1xxx dbdma", (void *)dbdma_gptr);
+	if (ret)
+		printk(KERN_ERR "Cannot grab DBDMA interrupt!\n");
+	else {
+		dbdma_initialized = 1;
+		printk(KERN_INFO "Alchemy DBDMA initialized\n");
+	}
+
+	return ret;
+}
+subsys_initcall(au1xxx_dbdma_init);
+
 #endif /* defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200) */
diff --git a/arch/mips/alchemy/common/dma.c b/arch/mips/alchemy/common/dma.c
index d6fbda2..d527887 100644
--- a/arch/mips/alchemy/common/dma.c
+++ b/arch/mips/alchemy/common/dma.c
@@ -29,6 +29,8 @@
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  *
  */
+
+#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -188,17 +190,14 @@ int request_au1000_dma(int dev_id, const char *dev_str,
 		dev = &dma_dev_table[dev_id];
 
 	if (irqhandler) {
-		chan->irq = AU1000_DMA_INT_BASE + i;
 		chan->irq_dev = irq_dev_id;
 		ret = request_irq(chan->irq, irqhandler, irqflags, dev_str,
 				  chan->irq_dev);
 		if (ret) {
-			chan->irq = 0;
 			chan->irq_dev = NULL;
 			return ret;
 		}
 	} else {
-		chan->irq = 0;
 		chan->irq_dev = NULL;
 	}
 
@@ -226,13 +225,40 @@ void free_au1000_dma(unsigned int dmanr)
 	}
 
 	disable_dma(dmanr);
-	if (chan->irq)
+	if (chan->irq_dev)
 		free_irq(chan->irq, chan->irq_dev);
 
-	chan->irq = 0;
 	chan->irq_dev = NULL;
 	chan->dev_id = -1;
 }
 EXPORT_SYMBOL(free_au1000_dma);
 
+static int __init au1000_dma_init(void)
+{
+        int base, i;
+
+        switch (alchemy_get_cputype()) {
+        case ALCHEMY_CPU_AU1000:
+                base = AU1000_DMA_INT_BASE;
+                break;
+        case ALCHEMY_CPU_AU1500:
+                base = AU1500_DMA_INT_BASE;
+                break;
+        case ALCHEMY_CPU_AU1100:
+                base = AU1100_DMA_INT_BASE;
+                break;
+        default:
+                goto out;
+        }
+
+        for (i = 0; i < NUM_AU1000_DMA_CHANNELS; i++)
+                au1000_dma_table[i].irq = base + i;
+
+        printk(KERN_INFO "Alchemy DMA initialized\n");
+
+out:
+        return 0;
+}
+arch_initcall(au1000_dma_init);
+
 #endif /* AU1000 AU1500 AU1100 */
diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c
index da53a3b..ab65997 100644
--- a/arch/mips/alchemy/common/irq.c
+++ b/arch/mips/alchemy/common/irq.c
@@ -53,160 +53,160 @@ struct au1xxx_irqmap {
 	int im_request;		/* set 1 to get higher priority */
 } au1xxx_ic0_map[] __initdata = {
 #if defined(CONFIG_SOC_AU1000)
-	{ AU1000_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_UART2_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_SSI0_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_SSI1_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
-	{ AU1000_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 },
+	{ AU1000_UART0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_UART1_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_UART2_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_UART3_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_SSI0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_SSI1_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_DMA_INT_BASE,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_DMA_INT_BASE+1,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_DMA_INT_BASE+2,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_DMA_INT_BASE+3,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_DMA_INT_BASE+4,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_DMA_INT_BASE+5,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_DMA_INT_BASE+6,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_DMA_INT_BASE+7,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_TOY_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1000_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1000_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1000_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1000_RTC_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1000_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1000_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1000_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1 },
+	{ AU1000_IRDA_TX_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_IRDA_RX_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,  1 },
 	{ AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 },
-	{ AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_AC97C_INT, IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1000_USB_HOST_INT,	  IRQ_TYPE_LEVEL_LOW,   0 },
+	{ AU1000_ACSYNC_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1000_MAC0_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_MAC1_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1000_AC97C_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
 
 #elif defined(CONFIG_SOC_AU1500)
 
-	{ AU1500_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_PCI_INTA, IRQ_TYPE_LEVEL_LOW, 0 },
-	{ AU1000_PCI_INTB, IRQ_TYPE_LEVEL_LOW, 0 },
-	{ AU1500_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_PCI_INTC, IRQ_TYPE_LEVEL_LOW, 0 },
-	{ AU1000_PCI_INTD, IRQ_TYPE_LEVEL_LOW, 0 },
-	{ AU1000_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
-	{ AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 },
-	{ AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 },
-	{ AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1500_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1500_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_AC97C_INT, IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1500_UART0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1500_PCI_INTA,	  IRQ_TYPE_LEVEL_LOW,   0 },
+	{ AU1500_PCI_INTB,	  IRQ_TYPE_LEVEL_LOW,   0 },
+	{ AU1500_UART3_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1500_PCI_INTC,	  IRQ_TYPE_LEVEL_LOW,   0 },
+	{ AU1500_PCI_INTD,	  IRQ_TYPE_LEVEL_LOW,   0 },
+	{ AU1500_DMA_INT_BASE,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1500_DMA_INT_BASE+1,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1500_DMA_INT_BASE+2,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1500_DMA_INT_BASE+3,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1500_DMA_INT_BASE+4,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1500_DMA_INT_BASE+5,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1500_DMA_INT_BASE+6,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1500_DMA_INT_BASE+7,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1500_TOY_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1500_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1500_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1500_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1500_RTC_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1500_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1500_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1500_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1 },
+	{ AU1500_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,  1 },
+	{ AU1500_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1500_USB_HOST_INT,	  IRQ_TYPE_LEVEL_LOW,   0 },
+	{ AU1500_ACSYNC_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1500_MAC0_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1500_MAC1_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1500_AC97C_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
 
 #elif defined(CONFIG_SOC_AU1100)
 
-	{ AU1100_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1100_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1100_SD_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1100_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_SSI0_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_SSI1_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+1, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+2, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+3, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+4, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+5, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+6, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_DMA_INT_BASE+7, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
-	{ AU1000_IRDA_TX_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_IRDA_RX_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 },
-	{ AU1000_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 },
-	{ AU1000_ACSYNC_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1100_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1100_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_AC97C_INT, IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1100_UART0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_UART1_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_SD_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_UART3_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_SSI0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_SSI1_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_DMA_INT_BASE,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_DMA_INT_BASE+1,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_DMA_INT_BASE+2,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_DMA_INT_BASE+3,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_DMA_INT_BASE+4,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_DMA_INT_BASE+5,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_DMA_INT_BASE+6,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_DMA_INT_BASE+7,  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_TOY_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1100_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1100_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1100_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1100_RTC_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1100_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1100_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1100_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1 },
+	{ AU1100_IRDA_TX_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_IRDA_RX_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,  1 },
+	{ AU1100_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1100_USB_HOST_INT,	  IRQ_TYPE_LEVEL_LOW,   0 },
+	{ AU1100_ACSYNC_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1100_MAC0_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_LCD_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1100_AC97C_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
 
 #elif defined(CONFIG_SOC_AU1550)
 
-	{ AU1550_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1550_PCI_INTA, IRQ_TYPE_LEVEL_LOW, 0 },
-	{ AU1550_PCI_INTB, IRQ_TYPE_LEVEL_LOW, 0 },
-	{ AU1550_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1550_CRYPTO_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1550_PCI_INTC, IRQ_TYPE_LEVEL_LOW, 0 },
-	{ AU1550_PCI_INTD, IRQ_TYPE_LEVEL_LOW, 0 },
-	{ AU1550_PCI_RST_INT, IRQ_TYPE_LEVEL_LOW, 0 },
-	{ AU1550_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1550_UART3_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1550_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1550_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1550_PSC2_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1550_PSC3_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
-	{ AU1550_NAND_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH, 1 },
+	{ AU1550_UART0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1550_PCI_INTA,	  IRQ_TYPE_LEVEL_LOW,   0 },
+	{ AU1550_PCI_INTB,	  IRQ_TYPE_LEVEL_LOW,   0 },
+	{ AU1550_DDMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1550_CRYPTO_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1550_PCI_INTC,	  IRQ_TYPE_LEVEL_LOW,   0 },
+	{ AU1550_PCI_INTD,	  IRQ_TYPE_LEVEL_LOW,   0 },
+	{ AU1550_PCI_RST_INT,	  IRQ_TYPE_LEVEL_LOW,   0 },
+	{ AU1550_UART1_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1550_UART3_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1550_PSC0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1550_PSC1_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1550_PSC2_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1550_PSC3_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1550_TOY_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1550_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1550_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1550_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1550_RTC_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1550_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1550_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1550_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1 },
+	{ AU1550_NAND_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1550_USB_DEV_REQ_INT, IRQ_TYPE_LEVEL_HIGH,  1 },
 	{ AU1550_USB_DEV_SUS_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1550_USB_HOST_INT, IRQ_TYPE_LEVEL_LOW, 0 },
-	{ AU1550_MAC0_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1550_MAC1_DMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
+	{ AU1550_USB_HOST_INT,	  IRQ_TYPE_LEVEL_LOW,   0 },
+	{ AU1550_MAC0_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1550_MAC1_DMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
 
 #elif defined(CONFIG_SOC_AU1200)
 
-	{ AU1200_UART0_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1200_SWT_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1200_SD_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1200_DDMA_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1200_MAE_BE_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1200_UART1_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1200_MAE_FE_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1200_PSC0_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1200_PSC1_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1200_AES_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1200_CAMERA_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1000_TOY_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_TOY_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH0_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH1_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1000_RTC_MATCH2_INT, IRQ_TYPE_EDGE_RISING, 1 },
-	{ AU1200_NAND_INT, IRQ_TYPE_EDGE_RISING, 0 },
-	{ AU1200_USB_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1200_LCD_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
-	{ AU1200_MAE_BOTH_INT, IRQ_TYPE_LEVEL_HIGH, 0 },
+	{ AU1200_UART0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1200_SWT_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1200_SD_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1200_DDMA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1200_MAE_BE_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1200_UART1_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1200_MAE_FE_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1200_PSC0_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1200_PSC1_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1200_AES_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1200_CAMERA_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1200_TOY_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1200_TOY_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1200_TOY_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1200_TOY_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1200_RTC_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1200_RTC_MATCH0_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1200_RTC_MATCH1_INT,  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1200_RTC_MATCH2_INT,  IRQ_TYPE_EDGE_RISING, 1 },
+	{ AU1200_NAND_INT,	  IRQ_TYPE_EDGE_RISING, 0 },
+	{ AU1200_USB_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1200_LCD_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
+	{ AU1200_MAE_BOTH_INT,	  IRQ_TYPE_LEVEL_HIGH,  0 },
 
 #else
 #error "Error: Unknown Alchemy SOC"
@@ -316,7 +316,7 @@ static void au1x_ic1_unmask(unsigned int irq_nr)
  * nowhere in the current kernel sources is it disabled.	--mlau
  */
 #if defined(CONFIG_MIPS_PB1000)
-	if (irq_nr == AU1000_GPIO_15)
+	if (irq_nr == AU1000_GPIO15_INT)
 		au_writel(0x4000, PB1000_MDR); /* enable int */
 #endif
 	au_sync();
@@ -366,11 +366,13 @@ static void au1x_ic1_ack(unsigned int irq_nr)
 
 static int au1x_ic1_setwake(unsigned int irq, unsigned int on)
 {
-	unsigned int bit = irq - AU1000_INTC1_INT_BASE;
+	int bit = irq - AU1000_INTC1_INT_BASE;
 	unsigned long wakemsk, flags;
 
-	/* only GPIO 0-7 can act as wakeup source: */
-	if ((irq < AU1000_GPIO_0) || (irq > AU1000_GPIO_7))
+	/* only GPIO 0-7 can act as wakeup source.  Fortunately these
+	 * are wired up identically on all supported variants.
+	 */
+	if ((bit < 0) || (bit > 7))
 		return -EINVAL;
 
 	local_irq_save(flags);
diff --git a/arch/mips/alchemy/common/platform.c b/arch/mips/alchemy/common/platform.c
index 2b76a57..5a9a4f9 100644
--- a/arch/mips/alchemy/common/platform.c
+++ b/arch/mips/alchemy/common/platform.c
@@ -73,8 +73,8 @@ static struct resource au1xxx_usb_ohci_resources[] = {
 		.flags		= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start		= AU1000_USB_HOST_INT,
-		.end		= AU1000_USB_HOST_INT,
+		.start		= FOR_PLATFORM_C_USB_HOST_INT,
+		.end		= FOR_PLATFORM_C_USB_HOST_INT,
 		.flags		= IORESOURCE_IRQ,
 	},
 };
@@ -132,8 +132,8 @@ static struct resource au1xxx_usb_ehci_resources[] = {
 		.flags		= IORESOURCE_MEM,
 	},
 	[1] = {
-		.start		= AU1000_USB_HOST_INT,
-		.end		= AU1000_USB_HOST_INT,
+		.start		= AU1200_USB_INT,
+		.end		= AU1200_USB_INT,
 		.flags		= IORESOURCE_IRQ,
 	},
 };
diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c
index 379a664..2aecb2f 100644
--- a/arch/mips/alchemy/common/time.c
+++ b/arch/mips/alchemy/common/time.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008 Manuel Lauss <mano@roarinelk.homelinux.net>
+ * Copyright (C) 2008-2009 Manuel Lauss <manuel.lauss@gmail.com>
  *
  * Previous incarnations were:
  * Copyright (C) 2001, 2006, 2008 MontaVista Software, <source@mvista.com>
@@ -85,7 +85,6 @@ static struct clock_event_device au1x_rtcmatch2_clockdev = {
 	.name		= "rtcmatch2",
 	.features	= CLOCK_EVT_FEAT_ONESHOT,
 	.rating		= 100,
-	.irq		= AU1000_RTC_MATCH2_INT,
 	.set_next_event	= au1x_rtcmatch2_set_next_event,
 	.set_mode	= au1x_rtcmatch2_set_mode,
 	.cpumask	= cpu_all_mask,
@@ -98,11 +97,13 @@ static struct irqaction au1x_rtcmatch2_irqaction = {
 	.dev_id		= &au1x_rtcmatch2_clockdev,
 };
 
-void __init plat_time_init(void)
+static int __init alchemy_time_init(unsigned int m2int)
 {
 	struct clock_event_device *cd = &au1x_rtcmatch2_clockdev;
 	unsigned long t;
 
+	au1x_rtcmatch2_clockdev.irq = m2int;
+
 	/* Check if firmware (YAMON, ...) has enabled 32kHz and clock
 	 * has been detected.  If so install the rtcmatch2 clocksource,
 	 * otherwise don't bother.  Note that both bits being set is by
@@ -148,13 +149,18 @@ void __init plat_time_init(void)
 	cd->max_delta_ns = clockevent_delta2ns(0xffffffff, cd);
 	cd->min_delta_ns = clockevent_delta2ns(8, cd);	/* ~0.25ms */
 	clockevents_register_device(cd);
-	setup_irq(AU1000_RTC_MATCH2_INT, &au1x_rtcmatch2_irqaction);
+	setup_irq(m2int, &au1x_rtcmatch2_irqaction);
 
 	printk(KERN_INFO "Alchemy clocksource installed\n");
 
-	return;
+	return 0;
 
 cntr_err:
+	return -1;
+}
+
+static void __init alchemy_setup_c0timer(void)
+{
 	/*
 	 * MIPS kernel assigns 'au1k_wait' to 'cpu_wait' before this
 	 * function is called.  Because the Alchemy counters are unusable
@@ -166,3 +172,22 @@ cntr_err:
 	r4k_clockevent_init();
 	init_r4k_clocksource();
 }
+
+static int alchemy_m2inttab[] __initdata = {
+	AU1000_RTC_MATCH2_INT,
+	AU1500_RTC_MATCH2_INT,
+	AU1100_RTC_MATCH2_INT,
+	AU1550_RTC_MATCH2_INT,
+	AU1200_RTC_MATCH2_INT,
+};
+
+void __init plat_time_init(void)
+{
+	int t;
+
+	t = alchemy_get_cputype();
+	if (t == ALCHEMY_CPU_UNKNOWN)
+		alchemy_setup_c0timer();
+	else if (alchemy_time_init(alchemy_m2inttab[t]))
+		alchemy_setup_c0timer();
+}
diff --git a/arch/mips/alchemy/devboards/db1x00/board_setup.c b/arch/mips/alchemy/devboards/db1x00/board_setup.c
index 3b228a2..b1f3711 100644
--- a/arch/mips/alchemy/devboards/db1x00/board_setup.c
+++ b/arch/mips/alchemy/devboards/db1x00/board_setup.c
@@ -39,32 +39,32 @@
 
 #ifdef CONFIG_MIPS_DB1500
 char irq_tab_alchemy[][5] __initdata = {
-	[12] = { -1, INTA, INTX, INTX, INTX }, /* IDSEL 12 - HPT371   */
-	[13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot */
+	[12] = { -1, AU1500_PCI_INTA, 0xff, 0xff, 0xff }, /* IDSEL 12 - HPT371   */
+	[13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, AU1500_PCI_INTC, AU1500_PCI_INTD }, /* IDSEL 13 - PCI slot */
 };
 #endif
 
 #ifdef CONFIG_MIPS_BOSPORUS
 char irq_tab_alchemy[][5] __initdata = {
-	[11] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 11 - miniPCI  */
-	[12] = { -1, INTA, INTX, INTX, INTX }, /* IDSEL 12 - SN1741   */
-	[13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot */
+	[11] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, /* IDSEL 11 - miniPCI  */
+	[12] = { -1, AU1500_PCI_INTA, 0xff, 0xff, 0xff }, /* IDSEL 12 - SN1741   */
+	[13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, AU1500_PCI_INTC, AU1500_PCI_INTD }, /* IDSEL 13 - PCI slot */
 };
 #endif
 
 #ifdef CONFIG_MIPS_MIRAGE
 char irq_tab_alchemy[][5] __initdata = {
-	[11] = { -1, INTD, INTX, INTX, INTX }, /* IDSEL 11 - SMI VGX */
-	[12] = { -1, INTX, INTX, INTC, INTX }, /* IDSEL 12 - PNX1300 */
-	[13] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 13 - miniPCI */
+	[11] = { -1, AU1500_PCI_INTD, 0xff, 0xff, 0xff }, /* IDSEL 11 - SMI VGX */
+	[12] = { -1, 0xff, 0xff, AU1500_PCI_INTC, 0xff }, /* IDSEL 12 - PNX1300 */
+	[13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, /* IDSEL 13 - miniPCI */
 };
 #endif
 
 #ifdef CONFIG_MIPS_DB1550
 char irq_tab_alchemy[][5] __initdata = {
-	[11] = { -1, INTC, INTX, INTX, INTX }, /* IDSEL 11 - on-board HPT371 */
-	[12] = { -1, INTB, INTC, INTD, INTA }, /* IDSEL 12 - PCI slot 2 (left) */
-	[13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot 1 (right) */
+	[11] = { -1, AU1500_PCI_INTC, 0xff, 0xff, 0xff }, /* IDSEL 11 - on-board HPT371 */
+	[12] = { -1, AU1500_PCI_INTB, AU1500_PCI_INTC, AU1500_PCI_INTD, AU1500_PCI_INTA }, /* IDSEL 12 - PCI slot 2 (left) */
+	[13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, AU1500_PCI_INTC, AU1500_PCI_INTD }, /* IDSEL 13 - PCI slot 1 (right) */
 };
 #endif
 
@@ -185,21 +185,35 @@ void __init board_setup(void)
 static int __init db1x00_init_irq(void)
 {
 #if defined(CONFIG_MIPS_MIRAGE)
-	set_irq_type(AU1000_GPIO_7, IRQF_TRIGGER_RISING); /* TS pendown */
+	set_irq_type(AU1500_GPIO7_INT, IRQF_TRIGGER_RISING); /* TS pendown */
 #elif defined(CONFIG_MIPS_DB1550)
-	set_irq_type(AU1000_GPIO_0, IRQF_TRIGGER_LOW);	/* CD0# */
-	set_irq_type(AU1000_GPIO_1, IRQF_TRIGGER_LOW);	/* CD1# */
-	set_irq_type(AU1000_GPIO_3, IRQF_TRIGGER_LOW);	/* CARD0# */
-	set_irq_type(AU1000_GPIO_5, IRQF_TRIGGER_LOW);	/* CARD1# */
-	set_irq_type(AU1000_GPIO_21, IRQF_TRIGGER_LOW);	/* STSCHG0# */
-	set_irq_type(AU1000_GPIO_22, IRQF_TRIGGER_LOW);	/* STSCHG1# */
-#else
-	set_irq_type(AU1000_GPIO_0, IRQF_TRIGGER_LOW);	/* CD0# */
-	set_irq_type(AU1000_GPIO_3, IRQF_TRIGGER_LOW);	/* CD1# */
-	set_irq_type(AU1000_GPIO_2, IRQF_TRIGGER_LOW);	/* CARD0# */
-	set_irq_type(AU1000_GPIO_5, IRQF_TRIGGER_LOW);	/* CARD1# */
-	set_irq_type(AU1000_GPIO_1, IRQF_TRIGGER_LOW);	/* STSCHG0# */
-	set_irq_type(AU1000_GPIO_4, IRQF_TRIGGER_LOW);	/* STSCHG1# */
+	set_irq_type(AU1550_GPIO0_INT, IRQF_TRIGGER_LOW);  /* CD0# */
+	set_irq_type(AU1550_GPIO1_INT, IRQF_TRIGGER_LOW);  /* CD1# */
+	set_irq_type(AU1550_GPIO3_INT, IRQF_TRIGGER_LOW);  /* CARD0# */
+	set_irq_type(AU1550_GPIO5_INT, IRQF_TRIGGER_LOW);  /* CARD1# */
+	set_irq_type(AU1550_GPIO21_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */
+	set_irq_type(AU1550_GPIO22_INT, IRQF_TRIGGER_LOW); /* STSCHG1# */
+#elif defined(CONFIG_MIPS_DB1500)
+	set_irq_type(AU1500_GPIO0_INT, IRQF_TRIGGER_LOW); /* CD0# */
+	set_irq_type(AU1500_GPIO3_INT, IRQF_TRIGGER_LOW); /* CD1# */
+	set_irq_type(AU1500_GPIO2_INT, IRQF_TRIGGER_LOW); /* CARD0# */
+	set_irq_type(AU1500_GPIO5_INT, IRQF_TRIGGER_LOW); /* CARD1# */
+	set_irq_type(AU1500_GPIO1_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */
+	set_irq_type(AU1500_GPIO4_INT, IRQF_TRIGGER_LOW); /* STSCHG1# */
+#elif defined(CONFIG_MIPS_DB1100)
+	set_irq_type(AU1100_GPIO0_INT, IRQF_TRIGGER_LOW); /* CD0# */
+	set_irq_type(AU1100_GPIO3_INT, IRQF_TRIGGER_LOW); /* CD1# */
+	set_irq_type(AU1100_GPIO2_INT, IRQF_TRIGGER_LOW); /* CARD0# */
+	set_irq_type(AU1100_GPIO5_INT, IRQF_TRIGGER_LOW); /* CARD1# */
+	set_irq_type(AU1100_GPIO1_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */
+	set_irq_type(AU1100_GPIO4_INT, IRQF_TRIGGER_LOW); /* STSCHG1# */
+#elif defined(CONFIG_MIPS_DB1000)
+	set_irq_type(AU1000_GPIO0_INT, IRQF_TRIGGER_LOW); /* CD0# */
+	set_irq_type(AU1000_GPIO3_INT, IRQF_TRIGGER_LOW); /* CD1# */
+	set_irq_type(AU1000_GPIO2_INT, IRQF_TRIGGER_LOW); /* CARD0# */
+	set_irq_type(AU1000_GPIO5_INT, IRQF_TRIGGER_LOW); /* CARD1# */
+	set_irq_type(AU1000_GPIO1_INT, IRQF_TRIGGER_LOW); /* STSCHG0# */
+	set_irq_type(AU1000_GPIO4_INT, IRQF_TRIGGER_LOW); /* STSCHG1# */
 #endif
 	return 0;
 }
diff --git a/arch/mips/alchemy/devboards/db1x00/platform.c b/arch/mips/alchemy/devboards/db1x00/platform.c
index b762b79..0ac5dd0 100644
--- a/arch/mips/alchemy/devboards/db1x00/platform.c
+++ b/arch/mips/alchemy/devboards/db1x00/platform.c
@@ -24,32 +24,46 @@
 #include <asm/mach-au1x00/au1xxx.h>
 #include "../platform.h"
 
-#if defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || \
-    defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550)
-#define DB1XXX_HAS_PCMCIA
-#endif
-
 /* DB1xxx PCMCIA interrupt sources:
  * CD0/1 	GPIO0/3
  * STSCHG0/1	GPIO1/4
  * CARD0/1	GPIO2/5
  * Db1550:	0/1, 21/22, 3/5
  */
-#ifndef CONFIG_MIPS_DB1550
-/* Db1000, Db1100, Db1500 */
-#define DB1XXX_PCMCIA_CD0	AU1000_GPIO_0
-#define DB1XXX_PCMCIA_STSCHG0	AU1000_GPIO_1
-#define DB1XXX_PCMCIA_CARD0	AU1000_GPIO_2
-#define DB1XXX_PCMCIA_CD1	AU1000_GPIO_3
-#define DB1XXX_PCMCIA_STSCHG1	AU1000_GPIO_4
-#define DB1XXX_PCMCIA_CARD1	AU1000_GPIO_5
+
+#define DB1XXX_HAS_PCMCIA
+
+#if defined(CONFIG_MIPS_DB1000)
+#define DB1XXX_PCMCIA_CD0	AU1000_GPIO0_INT
+#define DB1XXX_PCMCIA_STSCHG0	AU1000_GPIO1_INT
+#define DB1XXX_PCMCIA_CARD0	AU1000_GPIO2_INT
+#define DB1XXX_PCMCIA_CD1	AU1000_GPIO3_INT
+#define DB1XXX_PCMCIA_STSCHG1	AU1000_GPIO4_INT
+#define DB1XXX_PCMCIA_CARD1	AU1000_GPIO5_INT
+#elif defined(CONFIG_MIPS_DB1100)
+#define DB1XXX_PCMCIA_CD0	AU1100_GPIO0_INT
+#define DB1XXX_PCMCIA_STSCHG0	AU1100_GPIO1_INT
+#define DB1XXX_PCMCIA_CARD0	AU1100_GPIO2_INT
+#define DB1XXX_PCMCIA_CD1	AU1100_GPIO3_INT
+#define DB1XXX_PCMCIA_STSCHG1	AU1100_GPIO4_INT
+#define DB1XXX_PCMCIA_CARD1	AU1100_GPIO5_INT
+#elif defined(CONFIG_MIPS_DB1500)
+#define DB1XXX_PCMCIA_CD0	AU1500_GPIO0_INT
+#define DB1XXX_PCMCIA_STSCHG0	AU1500_GPIO1_INT
+#define DB1XXX_PCMCIA_CARD0	AU1500_GPIO2_INT
+#define DB1XXX_PCMCIA_CD1	AU1500_GPIO3_INT
+#define DB1XXX_PCMCIA_STSCHG1	AU1500_GPIO4_INT
+#define DB1XXX_PCMCIA_CARD1	AU1500_GPIO5_INT
+#elif defined(CONFIG_MIPS_DB1550)
+#define DB1XXX_PCMCIA_CD0	AU1550_GPIO0_INT
+#define DB1XXX_PCMCIA_STSCHG0	AU1550_GPIO21_INT
+#define DB1XXX_PCMCIA_CARD0	AU1550_GPIO3_INT
+#define DB1XXX_PCMCIA_CD1	AU1550_GPIO1_INT
+#define DB1XXX_PCMCIA_STSCHG1	AU1550_GPIO22_INT
+#define DB1XXX_PCMCIA_CARD1	AU1550_GPIO5_INT
 #else
-#define DB1XXX_PCMCIA_CD0	AU1000_GPIO_0
-#define DB1XXX_PCMCIA_STSCHG0	AU1500_GPIO_21
-#define DB1XXX_PCMCIA_CARD0	AU1000_GPIO_3
-#define DB1XXX_PCMCIA_CD1	AU1000_GPIO_1
-#define DB1XXX_PCMCIA_STSCHG1	AU1500_GPIO_22
-#define DB1XXX_PCMCIA_CARD1	AU1000_GPIO_5
+/* other board: no PCMCIA */
+#undef DB1XXX_HAS_PCMCIA
 #endif
 
 static int __init db1xxx_dev_init(void)
diff --git a/arch/mips/alchemy/devboards/pb1000/board_setup.c b/arch/mips/alchemy/devboards/pb1000/board_setup.c
index f1cafea..287d661 100644
--- a/arch/mips/alchemy/devboards/pb1000/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1000/board_setup.c
@@ -186,7 +186,7 @@ void __init board_setup(void)
 
 static int __init pb1000_init_irq(void)
 {
-	set_irq_type(AU1000_GPIO_15, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1000_GPIO15_INT, IRQF_TRIGGER_LOW);
 	return 0;
 }
 arch_initcall(pb1000_init_irq);
diff --git a/arch/mips/alchemy/devboards/pb1100/board_setup.c b/arch/mips/alchemy/devboards/pb1100/board_setup.c
index b282d93..e0bd855 100644
--- a/arch/mips/alchemy/devboards/pb1100/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1100/board_setup.c
@@ -147,10 +147,10 @@ void __init board_setup(void)
 
 static int __init pb1100_init_irq(void)
 {
-	set_irq_type(AU1000_GPIO_9,  IRQF_TRIGGER_LOW);	/* PCCD# */
-	set_irq_type(AU1000_GPIO_10, IRQF_TRIGGER_LOW); /* PCSTSCHG# */
-	set_irq_type(AU1000_GPIO_11, IRQF_TRIGGER_LOW); /* PCCard# */
-	set_irq_type(AU1000_GPIO_13, IRQF_TRIGGER_LOW); /* DC_IRQ# */
+	set_irq_type(AU1100_GPIO9_INT,  IRQF_TRIGGER_LOW); /* PCCD# */
+	set_irq_type(AU1100_GPIO10_INT, IRQF_TRIGGER_LOW); /* PCSTSCHG# */
+	set_irq_type(AU1100_GPIO11_INT, IRQF_TRIGGER_LOW); /* PCCard# */
+	set_irq_type(AU1100_GPIO13_INT, IRQF_TRIGGER_LOW); /* DC_IRQ# */
 
 	return 0;
 }
diff --git a/arch/mips/alchemy/devboards/pb1100/platform.c b/arch/mips/alchemy/devboards/pb1100/platform.c
index 8487da5..ec932e7 100644
--- a/arch/mips/alchemy/devboards/pb1100/platform.c
+++ b/arch/mips/alchemy/devboards/pb1100/platform.c
@@ -33,9 +33,9 @@ static int __init pb1100_dev_init(void)
 				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00040000 - 1,
 				    PCMCIA_IO_PSEUDO_PHYS,
 				    PCMCIA_IO_PSEUDO_PHYS   + 0x00001000 - 1,
-				    AU1000_GPIO_11,	 /* card */
-				    AU1000_GPIO_9,	 /* insert */
-				    /*AU1000_GPIO_10*/0, /* stschg */
+				    AU1100_GPIO11_INT,	 /* card */
+				    AU1100_GPIO9_INT,	 /* insert */
+				    /*AU1100_GPIO10_INT*/0, /* stschg */
 				    0,			 /* eject */
 				    0);			 /* id */
 	return 0;
diff --git a/arch/mips/alchemy/devboards/pb1200/board_setup.c b/arch/mips/alchemy/devboards/pb1200/board_setup.c
index 76aa652..e709b9e 100644
--- a/arch/mips/alchemy/devboards/pb1200/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1200/board_setup.c
@@ -173,8 +173,8 @@ static int __init pb1200_init_irq(void)
 	}
 #endif
 
-	set_irq_type(AU1000_GPIO_7, IRQF_TRIGGER_LOW);
-	bcsr_init_irq(PB1200_INT_BEGIN, PB1200_INT_END, AU1000_GPIO_7);
+	set_irq_type(AU1200_GPIO7_INT, IRQF_TRIGGER_LOW);
+	bcsr_init_irq(PB1200_INT_BEGIN, PB1200_INT_END, AU1200_GPIO7_INT);
 
 	return 0;
 }
diff --git a/arch/mips/alchemy/devboards/pb1500/board_setup.c b/arch/mips/alchemy/devboards/pb1500/board_setup.c
index a148802..3f0c92c 100644
--- a/arch/mips/alchemy/devboards/pb1500/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1500/board_setup.c
@@ -35,8 +35,8 @@
 
 
 char irq_tab_alchemy[][5] __initdata = {
-	[12] = { -1, INTA, INTX, INTX, INTX },   /* IDSEL 12 - HPT370	*/
-	[13] = { -1, INTA, INTB, INTC, INTD },   /* IDSEL 13 - PCI slot */
+	[12] = { -1, AU1500_PCI_INTA, 0xff, 0xff, 0xff },   /* IDSEL 12 - HPT370	*/
+	[13] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, AU1500_PCI_INTC, AU1500_PCI_INTD },   /* IDSEL 13 - PCI slot */
 };
 
 
@@ -155,14 +155,14 @@ void __init board_setup(void)
 
 static int __init pb1500_init_irq(void)
 {
-	set_irq_type(AU1000_GPIO_9, IRQF_TRIGGER_LOW);	/* CD0# */
-	set_irq_type(AU1000_GPIO_10, IRQF_TRIGGER_LOW);	/* CARD0 */
-	set_irq_type(AU1000_GPIO_11, IRQF_TRIGGER_LOW);	/* STSCHG0# */
-	set_irq_type(AU1500_GPIO_204, IRQF_TRIGGER_HIGH);
-	set_irq_type(AU1500_GPIO_201, IRQF_TRIGGER_LOW);
-	set_irq_type(AU1500_GPIO_202, IRQF_TRIGGER_LOW);
-	set_irq_type(AU1500_GPIO_203, IRQF_TRIGGER_LOW);
-	set_irq_type(AU1500_GPIO_205, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO9_INT, IRQF_TRIGGER_LOW);   /* CD0# */
+	set_irq_type(AU1500_GPIO10_INT, IRQF_TRIGGER_LOW);  /* CARD0 */
+	set_irq_type(AU1500_GPIO11_INT, IRQF_TRIGGER_LOW);  /* STSCHG0# */
+	set_irq_type(AU1500_GPIO204_INT, IRQF_TRIGGER_HIGH);
+	set_irq_type(AU1500_GPIO201_INT, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO202_INT, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO203_INT, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO205_INT, IRQF_TRIGGER_LOW);
 
 	return 0;
 }
diff --git a/arch/mips/alchemy/devboards/pb1500/platform.c b/arch/mips/alchemy/devboards/pb1500/platform.c
index 6c00cbe..cdce775 100644
--- a/arch/mips/alchemy/devboards/pb1500/platform.c
+++ b/arch/mips/alchemy/devboards/pb1500/platform.c
@@ -32,9 +32,9 @@ static int __init pb1500_dev_init(void)
 				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00040000 - 1,
 				    PCMCIA_IO_PSEUDO_PHYS,
 				    PCMCIA_IO_PSEUDO_PHYS   + 0x00001000 - 1,
-				    AU1000_GPIO_11,	 /* card */
-				    AU1000_GPIO_9,	 /* insert */
-				    /*AU1000_GPIO_10*/0, /* stschg */
+				    AU1500_GPIO11_INT,	 /* card */
+				    AU1500_GPIO9_INT,	 /* insert */
+				    /*AU1500_GPIO10_INT*/0, /* stschg */
 				    0,			 /* eject */
 				    0);			 /* id */
 	return 0;
diff --git a/arch/mips/alchemy/devboards/pb1550/board_setup.c b/arch/mips/alchemy/devboards/pb1550/board_setup.c
index 64a6fc4..bb41740 100644
--- a/arch/mips/alchemy/devboards/pb1550/board_setup.c
+++ b/arch/mips/alchemy/devboards/pb1550/board_setup.c
@@ -39,8 +39,8 @@
 
 
 char irq_tab_alchemy[][5] __initdata = {
-	[12] = { -1, INTB, INTC, INTD, INTA }, /* IDSEL 12 - PCI slot 2 (left)  */
-	[13] = { -1, INTA, INTB, INTC, INTD }, /* IDSEL 13 - PCI slot 1 (right) */
+	[12] = { -1, AU1550_PCI_INTB, AU1550_PCI_INTC, AU1550_PCI_INTD, AU1550_PCI_INTA }, /* IDSEL 12 - PCI slot 2 (left)  */
+	[13] = { -1, AU1550_PCI_INTA, AU1550_PCI_INTB, AU1550_PCI_INTC, AU1550_PCI_INTD }, /* IDSEL 13 - PCI slot 1 (right) */
 };
 
 const char *get_system_type(void)
@@ -89,9 +89,9 @@ void __init board_setup(void)
 
 static int __init pb1550_init_irq(void)
 {
-	set_irq_type(AU1000_GPIO_0, IRQF_TRIGGER_LOW);
-	set_irq_type(AU1000_GPIO_1, IRQF_TRIGGER_LOW);
-	set_irq_type(AU1500_GPIO_201_205, IRQF_TRIGGER_HIGH);
+	set_irq_type(AU1550_GPIO0_INT, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1550_GPIO1_INT, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1550_GPIO201_205_INT, IRQF_TRIGGER_HIGH);
 
 	/* enable both PCMCIA card irqs in the shared line */
 	alchemy_gpio2_enable_int(201);
diff --git a/arch/mips/alchemy/devboards/pb1550/platform.c b/arch/mips/alchemy/devboards/pb1550/platform.c
index aa5016c..b496fb6 100644
--- a/arch/mips/alchemy/devboards/pb1550/platform.c
+++ b/arch/mips/alchemy/devboards/pb1550/platform.c
@@ -40,8 +40,8 @@ static int __init pb1550_dev_init(void)
 				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00040000 - 1,
 				    PCMCIA_IO_PSEUDO_PHYS,
 				    PCMCIA_IO_PSEUDO_PHYS   + 0x00001000 - 1,
-				    AU1500_GPIO_201_205,
-				    AU1000_GPIO_0,
+				    AU1550_GPIO201_205_INT,
+				    AU1550_GPIO0_INT,
 				    0,
 				    0,
 				    0);
@@ -52,8 +52,8 @@ static int __init pb1550_dev_init(void)
 				    PCMCIA_MEM_PSEUDO_PHYS  + 0x00840000 - 1,
 				    PCMCIA_IO_PSEUDO_PHYS   + 0x00800000,
 				    PCMCIA_IO_PSEUDO_PHYS   + 0x00801000 - 1,
-				    AU1500_GPIO_201_205,
-				    AU1000_GPIO_1,
+				    AU1550_GPIO201_205_INT,
+				    AU1550_GPIO1_INT,
 				    0,
 				    0,
 				    1);
diff --git a/arch/mips/alchemy/mtx-1/board_setup.c b/arch/mips/alchemy/mtx-1/board_setup.c
index 568492c..adc01ea 100644
--- a/arch/mips/alchemy/mtx-1/board_setup.c
+++ b/arch/mips/alchemy/mtx-1/board_setup.c
@@ -37,14 +37,14 @@
 #include <prom.h>
 
 char irq_tab_alchemy[][5] __initdata = {
-	[0] = { -1, INTA, INTA, INTX, INTX }, /* IDSEL 00 - AdapterA-Slot0 (top) */
-	[1] = { -1, INTB, INTA, INTX, INTX }, /* IDSEL 01 - AdapterA-Slot1 (bottom) */
-	[2] = { -1, INTC, INTD, INTX, INTX }, /* IDSEL 02 - AdapterB-Slot0 (top) */
-	[3] = { -1, INTD, INTC, INTX, INTX }, /* IDSEL 03 - AdapterB-Slot1 (bottom) */
-	[4] = { -1, INTA, INTB, INTX, INTX }, /* IDSEL 04 - AdapterC-Slot0 (top) */
-	[5] = { -1, INTB, INTA, INTX, INTX }, /* IDSEL 05 - AdapterC-Slot1 (bottom) */
-	[6] = { -1, INTC, INTD, INTX, INTX }, /* IDSEL 06 - AdapterD-Slot0 (top) */
-	[7] = { -1, INTD, INTC, INTX, INTX }, /* IDSEL 07 - AdapterD-Slot1 (bottom) */
+	[0] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTA, 0xff, 0xff }, /* IDSEL 00 - AdapterA-Slot0 (top) */
+	[1] = { -1, AU1500_PCI_INTB, AU1500_PCI_INTA, 0xff, 0xff }, /* IDSEL 01 - AdapterA-Slot1 (bottom) */
+	[2] = { -1, AU1500_PCI_INTC, AU1500_PCI_INTD, 0xff, 0xff }, /* IDSEL 02 - AdapterB-Slot0 (top) */
+	[3] = { -1, AU1500_PCI_INTD, AU1500_PCI_INTC, 0xff, 0xff }, /* IDSEL 03 - AdapterB-Slot1 (bottom) */
+	[4] = { -1, AU1500_PCI_INTA, AU1500_PCI_INTB, 0xff, 0xff }, /* IDSEL 04 - AdapterC-Slot0 (top) */
+	[5] = { -1, AU1500_PCI_INTB, AU1500_PCI_INTA, 0xff, 0xff }, /* IDSEL 05 - AdapterC-Slot1 (bottom) */
+	[6] = { -1, AU1500_PCI_INTC, AU1500_PCI_INTD, 0xff, 0xff }, /* IDSEL 06 - AdapterD-Slot0 (top) */
+	[7] = { -1, AU1500_PCI_INTD, AU1500_PCI_INTC, 0xff, 0xff }, /* IDSEL 07 - AdapterD-Slot1 (bottom) */
 };
 
 extern int (*board_pci_idsel)(unsigned int devsel, int assert);
@@ -125,11 +125,11 @@ mtx1_pci_idsel(unsigned int devsel, int assert)
 
 static int __init mtx1_init_irq(void)
 {
-	set_irq_type(AU1500_GPIO_204, IRQF_TRIGGER_HIGH);
-	set_irq_type(AU1500_GPIO_201, IRQF_TRIGGER_LOW);
-	set_irq_type(AU1500_GPIO_202, IRQF_TRIGGER_LOW);
-	set_irq_type(AU1500_GPIO_203, IRQF_TRIGGER_LOW);
-	set_irq_type(AU1500_GPIO_205, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO204_INT, IRQF_TRIGGER_HIGH);
+	set_irq_type(AU1500_GPIO201_INT, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO202_INT, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO203_INT, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO205_INT, IRQF_TRIGGER_LOW);
 
 	return 0;
 }
diff --git a/arch/mips/alchemy/xxs1500/board_setup.c b/arch/mips/alchemy/xxs1500/board_setup.c
index eb31350..21bef8d 100644
--- a/arch/mips/alchemy/xxs1500/board_setup.c
+++ b/arch/mips/alchemy/xxs1500/board_setup.c
@@ -80,19 +80,19 @@ void __init board_setup(void)
 
 static int __init xxs1500_init_irq(void)
 {
-	set_irq_type(AU1500_GPIO_204, IRQF_TRIGGER_HIGH);
-	set_irq_type(AU1500_GPIO_201, IRQF_TRIGGER_LOW);
-	set_irq_type(AU1500_GPIO_202, IRQF_TRIGGER_LOW);
-	set_irq_type(AU1500_GPIO_203, IRQF_TRIGGER_LOW);
-	set_irq_type(AU1500_GPIO_205, IRQF_TRIGGER_LOW);
-	set_irq_type(AU1500_GPIO_207, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO204_INT, IRQF_TRIGGER_HIGH);
+	set_irq_type(AU1500_GPIO201_INT, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO202_INT, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO203_INT, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO205_INT, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO207_INT, IRQF_TRIGGER_LOW);
 
-	set_irq_type(AU1000_GPIO_0, IRQF_TRIGGER_LOW);
-	set_irq_type(AU1000_GPIO_1, IRQF_TRIGGER_LOW);
-	set_irq_type(AU1000_GPIO_2, IRQF_TRIGGER_LOW);
-	set_irq_type(AU1000_GPIO_3, IRQF_TRIGGER_LOW);
-	set_irq_type(AU1000_GPIO_4, IRQF_TRIGGER_LOW); /* CF interrupt */
-	set_irq_type(AU1000_GPIO_5, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO0_INT, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO1_INT, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO2_INT, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO3_INT, IRQF_TRIGGER_LOW);
+	set_irq_type(AU1500_GPIO4_INT, IRQF_TRIGGER_LOW); /* CF irq */
+	set_irq_type(AU1500_GPIO5_INT, IRQF_TRIGGER_LOW);
 
 	return 0;
 }
diff --git a/arch/mips/include/asm/mach-au1x00/au1000.h b/arch/mips/include/asm/mach-au1x00/au1000.h
index 9174285..16ea5ad 100644
--- a/arch/mips/include/asm/mach-au1x00/au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/au1000.h
@@ -173,6 +173,333 @@ void au_sleep(void);
 void save_au1xxx_intctl(void);
 void restore_au1xxx_intctl(void);
 
+
+/* SOC Interrupt numbers */
+
+#define AU1000_INTC0_INT_BASE	(MIPS_CPU_IRQ_BASE + 8)
+#define AU1000_INTC0_INT_LAST	(AU1000_INTC0_INT_BASE + 31)
+#define AU1000_INTC1_INT_BASE	(AU1000_INTC0_INT_LAST + 1)
+#define AU1000_INTC1_INT_LAST	(AU1000_INTC1_INT_BASE + 31)
+#define AU1000_MAX_INTR 	AU1000_INTC1_INT_LAST
+
+enum soc_au1000_ints {
+	AU1000_FIRST_INT	= AU1000_INTC0_INT_BASE,
+	AU1000_UART0_INT	= AU1000_FIRST_INT,
+	AU1000_UART1_INT,
+	AU1000_UART2_INT,
+	AU1000_UART3_INT,
+	AU1000_SSI0_INT,
+	AU1000_SSI1_INT,
+	AU1000_DMA_INT_BASE,
+
+	AU1000_TOY_INT		= AU1000_FIRST_INT + 14,
+	AU1000_TOY_MATCH0_INT,
+	AU1000_TOY_MATCH1_INT,
+	AU1000_TOY_MATCH2_INT,
+	AU1000_RTC_INT,
+	AU1000_RTC_MATCH0_INT,
+	AU1000_RTC_MATCH1_INT,
+	AU1000_RTC_MATCH2_INT,
+	AU1000_IRDA_TX_INT,
+	AU1000_IRDA_RX_INT,
+	AU1000_USB_DEV_REQ_INT,
+	AU1000_USB_DEV_SUS_INT,
+	AU1000_USB_HOST_INT,
+	AU1000_ACSYNC_INT,
+	AU1000_MAC0_DMA_INT,
+	AU1000_MAC1_DMA_INT,
+	AU1000_I2S_UO_INT,
+	AU1000_AC97C_INT,
+	AU1000_GPIO0_INT,
+	AU1000_GPIO1_INT,
+	AU1000_GPIO2_INT,
+	AU1000_GPIO3_INT,
+	AU1000_GPIO4_INT,
+	AU1000_GPIO5_INT,
+	AU1000_GPIO6_INT,
+	AU1000_GPIO7_INT,
+	AU1000_GPIO8_INT,
+	AU1000_GPIO9_INT,
+	AU1000_GPIO10_INT,
+	AU1000_GPIO11_INT,
+	AU1000_GPIO12_INT,
+	AU1000_GPIO13_INT,
+	AU1000_GPIO14_INT,
+	AU1000_GPIO15_INT,
+	AU1000_GPIO16_INT,
+	AU1000_GPIO17_INT,
+	AU1000_GPIO18_INT,
+	AU1000_GPIO19_INT,
+	AU1000_GPIO20_INT,
+	AU1000_GPIO21_INT,
+	AU1000_GPIO22_INT,
+	AU1000_GPIO23_INT,
+	AU1000_GPIO24_INT,
+	AU1000_GPIO25_INT,
+	AU1000_GPIO26_INT,
+	AU1000_GPIO27_INT,
+	AU1000_GPIO28_INT,
+	AU1000_GPIO29_INT,
+	AU1000_GPIO30_INT,
+	AU1000_GPIO31_INT,
+};
+
+enum soc_au1100_ints {
+	AU1100_FIRST_INT	= AU1000_INTC0_INT_BASE,
+	AU1100_UART0_INT	= AU1100_FIRST_INT,
+	AU1100_UART1_INT,
+	AU1100_SD_INT,
+	AU1100_UART3_INT,
+	AU1100_SSI0_INT,
+	AU1100_SSI1_INT,
+	AU1100_DMA_INT_BASE,
+
+	AU1100_TOY_INT		= AU1100_FIRST_INT + 14,
+	AU1100_TOY_MATCH0_INT,
+	AU1100_TOY_MATCH1_INT,
+	AU1100_TOY_MATCH2_INT,
+	AU1100_RTC_INT,
+	AU1100_RTC_MATCH0_INT,
+	AU1100_RTC_MATCH1_INT,
+	AU1100_RTC_MATCH2_INT,
+	AU1100_IRDA_TX_INT,
+	AU1100_IRDA_RX_INT,
+	AU1100_USB_DEV_REQ_INT,
+	AU1100_USB_DEV_SUS_INT,
+	AU1100_USB_HOST_INT,
+	AU1100_ACSYNC_INT,
+	AU1100_MAC0_DMA_INT,
+	AU1100_GPIO208_215_INT,
+	AU1100_LCD_INT,
+	AU1100_AC97C_INT,
+	AU1100_GPIO0_INT,
+	AU1100_GPIO1_INT,
+	AU1100_GPIO2_INT,
+	AU1100_GPIO3_INT,
+	AU1100_GPIO4_INT,
+	AU1100_GPIO5_INT,
+	AU1100_GPIO6_INT,
+	AU1100_GPIO7_INT,
+	AU1100_GPIO8_INT,
+	AU1100_GPIO9_INT,
+	AU1100_GPIO10_INT,
+	AU1100_GPIO11_INT,
+	AU1100_GPIO12_INT,
+	AU1100_GPIO13_INT,
+	AU1100_GPIO14_INT,
+	AU1100_GPIO15_INT,
+	AU1100_GPIO16_INT,
+	AU1100_GPIO17_INT,
+	AU1100_GPIO18_INT,
+	AU1100_GPIO19_INT,
+	AU1100_GPIO20_INT,
+	AU1100_GPIO21_INT,
+	AU1100_GPIO22_INT,
+	AU1100_GPIO23_INT,
+	AU1100_GPIO24_INT,
+	AU1100_GPIO25_INT,
+	AU1100_GPIO26_INT,
+	AU1100_GPIO27_INT,
+	AU1100_GPIO28_INT,
+	AU1100_GPIO29_INT,
+	AU1100_GPIO30_INT,
+	AU1100_GPIO31_INT,
+};
+
+enum soc_au1500_ints {
+	AU1500_FIRST_INT	= AU1000_INTC0_INT_BASE,
+	AU1500_UART0_INT	= AU1500_FIRST_INT,
+	AU1500_PCI_INTA,
+	AU1500_PCI_INTB,
+	AU1500_UART3_INT,
+	AU1500_PCI_INTC,
+	AU1500_PCI_INTD,
+	AU1500_DMA_INT_BASE,
+
+	AU1500_TOY_INT		= AU1500_FIRST_INT + 14,
+	AU1500_TOY_MATCH0_INT,
+	AU1500_TOY_MATCH1_INT,
+	AU1500_TOY_MATCH2_INT,
+	AU1500_RTC_INT,
+	AU1500_RTC_MATCH0_INT,
+	AU1500_RTC_MATCH1_INT,
+	AU1500_RTC_MATCH2_INT,
+	AU1500_PCI_ERR_INT,
+	AU1500_RESERVED_INT,
+	AU1500_USB_DEV_REQ_INT,
+	AU1500_USB_DEV_SUS_INT,
+	AU1500_USB_HOST_INT,
+	AU1500_ACSYNC_INT,
+	AU1500_MAC0_DMA_INT,
+	AU1500_MAC1_DMA_INT,
+	AU1500_AC97C_INT	= AU1500_FIRST_INT + 31,
+	AU1500_GPIO0_INT,
+	AU1500_GPIO1_INT,
+	AU1500_GPIO2_INT,
+	AU1500_GPIO3_INT,
+	AU1500_GPIO4_INT,
+	AU1500_GPIO5_INT,
+	AU1500_GPIO6_INT,
+	AU1500_GPIO7_INT,
+	AU1500_GPIO8_INT,
+	AU1500_GPIO9_INT,
+	AU1500_GPIO10_INT,
+	AU1500_GPIO11_INT,
+	AU1500_GPIO12_INT,
+	AU1500_GPIO13_INT,
+	AU1500_GPIO14_INT,
+	AU1500_GPIO15_INT,
+	AU1500_GPIO200_INT,
+	AU1500_GPIO201_INT,
+	AU1500_GPIO202_INT,
+	AU1500_GPIO203_INT,
+	AU1500_GPIO20_INT,
+	AU1500_GPIO204_INT,
+	AU1500_GPIO205_INT,
+	AU1500_GPIO23_INT,
+	AU1500_GPIO24_INT,
+	AU1500_GPIO25_INT,
+	AU1500_GPIO26_INT,
+	AU1500_GPIO27_INT,
+	AU1500_GPIO28_INT,
+	AU1500_GPIO206_INT,
+	AU1500_GPIO207_INT,
+	AU1500_GPIO208_215_INT,
+};
+
+enum soc_au1550_ints {
+	AU1550_FIRST_INT	= AU1000_INTC0_INT_BASE,
+	AU1550_UART0_INT	= AU1550_FIRST_INT,
+	AU1550_PCI_INTA,
+	AU1550_PCI_INTB,
+	AU1550_DDMA_INT,
+	AU1550_CRYPTO_INT,
+	AU1550_PCI_INTC,
+	AU1550_PCI_INTD,
+	AU1550_PCI_RST_INT,
+	AU1550_UART1_INT,
+	AU1550_UART3_INT,
+	AU1550_PSC0_INT,
+	AU1550_PSC1_INT,
+	AU1550_PSC2_INT,
+	AU1550_PSC3_INT,
+	AU1550_TOY_INT,
+	AU1550_TOY_MATCH0_INT,
+	AU1550_TOY_MATCH1_INT,
+	AU1550_TOY_MATCH2_INT,
+	AU1550_RTC_INT,
+	AU1550_RTC_MATCH0_INT,
+	AU1550_RTC_MATCH1_INT,
+	AU1550_RTC_MATCH2_INT,
+
+	AU1550_NAND_INT		= AU1550_FIRST_INT + 23,
+	AU1550_USB_DEV_REQ_INT,
+	AU1550_USB_DEV_SUS_INT,
+	AU1550_USB_HOST_INT,
+	AU1550_MAC0_DMA_INT,
+	AU1550_MAC1_DMA_INT,
+	AU1550_GPIO0_INT	= AU1550_FIRST_INT + 32,
+	AU1550_GPIO1_INT,
+	AU1550_GPIO2_INT,
+	AU1550_GPIO3_INT,
+	AU1550_GPIO4_INT,
+	AU1550_GPIO5_INT,
+	AU1550_GPIO6_INT,
+	AU1550_GPIO7_INT,
+	AU1550_GPIO8_INT,
+	AU1550_GPIO9_INT,
+	AU1550_GPIO10_INT,
+	AU1550_GPIO11_INT,
+	AU1550_GPIO12_INT,
+	AU1550_GPIO13_INT,
+	AU1550_GPIO14_INT,
+	AU1550_GPIO15_INT,
+	AU1550_GPIO200_INT,
+	AU1550_GPIO201_205_INT,	/* Logical or of GPIO201:205 */
+	AU1550_GPIO16_INT,
+	AU1550_GPIO17_INT,
+	AU1550_GPIO20_INT,
+	AU1550_GPIO21_INT,
+	AU1550_GPIO22_INT,
+	AU1550_GPIO23_INT,
+	AU1550_GPIO24_INT,
+	AU1550_GPIO25_INT,
+	AU1550_GPIO26_INT,
+	AU1550_GPIO27_INT,
+	AU1550_GPIO28_INT,
+	AU1550_GPIO206_INT,
+	AU1550_GPIO207_INT,
+	AU1550_GPIO208_215_INT,	/* Logical or of GPIO208:215 */
+};
+
+enum soc_au1200_ints {
+	AU1200_FIRST_INT	= AU1000_INTC0_INT_BASE,
+	AU1200_UART0_INT	= AU1200_FIRST_INT,
+	AU1200_SWT_INT,
+	AU1200_SD_INT,
+	AU1200_DDMA_INT,
+	AU1200_MAE_BE_INT,
+	AU1200_GPIO200_INT,
+	AU1200_GPIO201_INT,
+	AU1200_GPIO202_INT,
+	AU1200_UART1_INT,
+	AU1200_MAE_FE_INT,
+	AU1200_PSC0_INT,
+	AU1200_PSC1_INT,
+	AU1200_AES_INT,
+	AU1200_CAMERA_INT,
+	AU1200_TOY_INT,
+	AU1200_TOY_MATCH0_INT,
+	AU1200_TOY_MATCH1_INT,
+	AU1200_TOY_MATCH2_INT,
+	AU1200_RTC_INT,
+	AU1200_RTC_MATCH0_INT,
+	AU1200_RTC_MATCH1_INT,
+	AU1200_RTC_MATCH2_INT,
+	AU1200_GPIO203_INT,
+	AU1200_NAND_INT,
+	AU1200_GPIO204_INT,
+	AU1200_GPIO205_INT,
+	AU1200_GPIO206_INT,
+	AU1200_GPIO207_INT,
+	AU1200_GPIO208_215_INT,	/* Logical OR of 208:215 */
+	AU1200_USB_INT,
+	AU1200_LCD_INT,
+	AU1200_MAE_BOTH_INT,
+	AU1200_GPIO0_INT,
+	AU1200_GPIO1_INT,
+	AU1200_GPIO2_INT,
+	AU1200_GPIO3_INT,
+	AU1200_GPIO4_INT,
+	AU1200_GPIO5_INT,
+	AU1200_GPIO6_INT,
+	AU1200_GPIO7_INT,
+	AU1200_GPIO8_INT,
+	AU1200_GPIO9_INT,
+	AU1200_GPIO10_INT,
+	AU1200_GPIO11_INT,
+	AU1200_GPIO12_INT,
+	AU1200_GPIO13_INT,
+	AU1200_GPIO14_INT,
+	AU1200_GPIO15_INT,
+	AU1200_GPIO16_INT,
+	AU1200_GPIO17_INT,
+	AU1200_GPIO18_INT,
+	AU1200_GPIO19_INT,
+	AU1200_GPIO20_INT,
+	AU1200_GPIO21_INT,
+	AU1200_GPIO22_INT,
+	AU1200_GPIO23_INT,
+	AU1200_GPIO24_INT,
+	AU1200_GPIO25_INT,
+	AU1200_GPIO26_INT,
+	AU1200_GPIO27_INT,
+	AU1200_GPIO28_INT,
+	AU1200_GPIO29_INT,
+	AU1200_GPIO30_INT,
+	AU1200_GPIO31_INT,
+};
+
 #endif /* !defined (_LANGUAGE_ASSEMBLY) */
 
 /*
@@ -564,70 +891,9 @@ void restore_au1xxx_intctl(void);
 
 #define IC1_TESTBIT		0xB1800080
 
-/* Interrupt Numbers */
+
 /* Au1000 */
 #ifdef CONFIG_SOC_AU1000
-enum soc_au1000_ints {
-	AU1000_FIRST_INT	= MIPS_CPU_IRQ_BASE + 8,
-	AU1000_UART0_INT	= AU1000_FIRST_INT,
-	AU1000_UART1_INT,				/* au1000 */
-	AU1000_UART2_INT,				/* au1000 */
-	AU1000_UART3_INT,
-	AU1000_SSI0_INT,				/* au1000 */
-	AU1000_SSI1_INT,				/* au1000 */
-	AU1000_DMA_INT_BASE,
-
-	AU1000_TOY_INT		= AU1000_FIRST_INT + 14,
-	AU1000_TOY_MATCH0_INT,
-	AU1000_TOY_MATCH1_INT,
-	AU1000_TOY_MATCH2_INT,
-	AU1000_RTC_INT,
-	AU1000_RTC_MATCH0_INT,
-	AU1000_RTC_MATCH1_INT,
-	AU1000_RTC_MATCH2_INT,
-	AU1000_IRDA_TX_INT,				/* au1000 */
-	AU1000_IRDA_RX_INT,				/* au1000 */
-	AU1000_USB_DEV_REQ_INT,
-	AU1000_USB_DEV_SUS_INT,
-	AU1000_USB_HOST_INT,
-	AU1000_ACSYNC_INT,
-	AU1000_MAC0_DMA_INT,
-	AU1000_MAC1_DMA_INT,
-	AU1000_I2S_UO_INT,				/* au1000 */
-	AU1000_AC97C_INT,
-	AU1000_GPIO_0,
-	AU1000_GPIO_1,
-	AU1000_GPIO_2,
-	AU1000_GPIO_3,
-	AU1000_GPIO_4,
-	AU1000_GPIO_5,
-	AU1000_GPIO_6,
-	AU1000_GPIO_7,
-	AU1000_GPIO_8,
-	AU1000_GPIO_9,
-	AU1000_GPIO_10,
-	AU1000_GPIO_11,
-	AU1000_GPIO_12,
-	AU1000_GPIO_13,
-	AU1000_GPIO_14,
-	AU1000_GPIO_15,
-	AU1000_GPIO_16,
-	AU1000_GPIO_17,
-	AU1000_GPIO_18,
-	AU1000_GPIO_19,
-	AU1000_GPIO_20,
-	AU1000_GPIO_21,
-	AU1000_GPIO_22,
-	AU1000_GPIO_23,
-	AU1000_GPIO_24,
-	AU1000_GPIO_25,
-	AU1000_GPIO_26,
-	AU1000_GPIO_27,
-	AU1000_GPIO_28,
-	AU1000_GPIO_29,
-	AU1000_GPIO_30,
-	AU1000_GPIO_31,
-};
 
 #define UART0_ADDR		0xB1100000
 #define UART1_ADDR		0xB1200000
@@ -636,6 +902,7 @@ enum soc_au1000_ints {
 
 #define USB_OHCI_BASE		0x10100000	/* phys addr for ioremap */
 #define USB_HOST_CONFIG 	0xB017FFFC
+#define FOR_PLATFORM_C_USB_HOST_INT AU1000_USB_HOST_INT
 
 #define AU1000_ETH0_BASE	0xB0500000
 #define AU1000_ETH1_BASE	0xB0510000
@@ -646,78 +913,13 @@ enum soc_au1000_ints {
 
 /* Au1500 */
 #ifdef CONFIG_SOC_AU1500
-enum soc_au1500_ints {
-	AU1500_FIRST_INT	= MIPS_CPU_IRQ_BASE + 8,
-	AU1500_UART0_INT	= AU1500_FIRST_INT,
-	AU1000_PCI_INTA,				/* au1500 */
-	AU1000_PCI_INTB,				/* au1500 */
-	AU1500_UART3_INT,
-	AU1000_PCI_INTC,				/* au1500 */
-	AU1000_PCI_INTD,				/* au1500 */
-	AU1000_DMA_INT_BASE,
-
-	AU1000_TOY_INT		= AU1500_FIRST_INT + 14,
-	AU1000_TOY_MATCH0_INT,
-	AU1000_TOY_MATCH1_INT,
-	AU1000_TOY_MATCH2_INT,
-	AU1000_RTC_INT,
-	AU1000_RTC_MATCH0_INT,
-	AU1000_RTC_MATCH1_INT,
-	AU1000_RTC_MATCH2_INT,
-	AU1500_PCI_ERR_INT,
-	AU1500_RESERVED_INT,
-	AU1000_USB_DEV_REQ_INT,
-	AU1000_USB_DEV_SUS_INT,
-	AU1000_USB_HOST_INT,
-	AU1000_ACSYNC_INT,
-	AU1500_MAC0_DMA_INT,
-	AU1500_MAC1_DMA_INT,
-	AU1000_AC97C_INT	= AU1500_FIRST_INT + 31,
-	AU1000_GPIO_0,
-	AU1000_GPIO_1,
-	AU1000_GPIO_2,
-	AU1000_GPIO_3,
-	AU1000_GPIO_4,
-	AU1000_GPIO_5,
-	AU1000_GPIO_6,
-	AU1000_GPIO_7,
-	AU1000_GPIO_8,
-	AU1000_GPIO_9,
-	AU1000_GPIO_10,
-	AU1000_GPIO_11,
-	AU1000_GPIO_12,
-	AU1000_GPIO_13,
-	AU1000_GPIO_14,
-	AU1000_GPIO_15,
-	AU1500_GPIO_200,
-	AU1500_GPIO_201,
-	AU1500_GPIO_202,
-	AU1500_GPIO_203,
-	AU1500_GPIO_20,
-	AU1500_GPIO_204,
-	AU1500_GPIO_205,
-	AU1500_GPIO_23,
-	AU1500_GPIO_24,
-	AU1500_GPIO_25,
-	AU1500_GPIO_26,
-	AU1500_GPIO_27,
-	AU1500_GPIO_28,
-	AU1500_GPIO_206,
-	AU1500_GPIO_207,
-	AU1500_GPIO_208_215,
-};
-
-/* shortcuts */
-#define INTA AU1000_PCI_INTA
-#define INTB AU1000_PCI_INTB
-#define INTC AU1000_PCI_INTC
-#define INTD AU1000_PCI_INTD
 
 #define UART0_ADDR		0xB1100000
 #define UART3_ADDR		0xB1400000
 
 #define USB_OHCI_BASE		0x10100000	/* phys addr for ioremap */
 #define USB_HOST_CONFIG 	0xB017fffc
+#define FOR_PLATFORM_C_USB_HOST_INT AU1500_USB_HOST_INT
 
 #define AU1500_ETH0_BASE	0xB1500000
 #define AU1500_ETH1_BASE	0xB1510000
@@ -728,67 +930,6 @@ enum soc_au1500_ints {
 
 /* Au1100 */
 #ifdef CONFIG_SOC_AU1100
-enum soc_au1100_ints {
-	AU1100_FIRST_INT	= MIPS_CPU_IRQ_BASE + 8,
-	AU1100_UART0_INT	= AU1100_FIRST_INT,
-	AU1100_UART1_INT,
-	AU1100_SD_INT,
-	AU1100_UART3_INT,
-	AU1000_SSI0_INT,
-	AU1000_SSI1_INT,
-	AU1000_DMA_INT_BASE,
-
-	AU1000_TOY_INT		= AU1100_FIRST_INT + 14,
-	AU1000_TOY_MATCH0_INT,
-	AU1000_TOY_MATCH1_INT,
-	AU1000_TOY_MATCH2_INT,
-	AU1000_RTC_INT,
-	AU1000_RTC_MATCH0_INT,
-	AU1000_RTC_MATCH1_INT,
-	AU1000_RTC_MATCH2_INT,
-	AU1000_IRDA_TX_INT,
-	AU1000_IRDA_RX_INT,
-	AU1000_USB_DEV_REQ_INT,
-	AU1000_USB_DEV_SUS_INT,
-	AU1000_USB_HOST_INT,
-	AU1000_ACSYNC_INT,
-	AU1100_MAC0_DMA_INT,
-	AU1100_GPIO_208_215,
-	AU1100_LCD_INT,
-	AU1000_AC97C_INT,
-	AU1000_GPIO_0,
-	AU1000_GPIO_1,
-	AU1000_GPIO_2,
-	AU1000_GPIO_3,
-	AU1000_GPIO_4,
-	AU1000_GPIO_5,
-	AU1000_GPIO_6,
-	AU1000_GPIO_7,
-	AU1000_GPIO_8,
-	AU1000_GPIO_9,
-	AU1000_GPIO_10,
-	AU1000_GPIO_11,
-	AU1000_GPIO_12,
-	AU1000_GPIO_13,
-	AU1000_GPIO_14,
-	AU1000_GPIO_15,
-	AU1000_GPIO_16,
-	AU1000_GPIO_17,
-	AU1000_GPIO_18,
-	AU1000_GPIO_19,
-	AU1000_GPIO_20,
-	AU1000_GPIO_21,
-	AU1000_GPIO_22,
-	AU1000_GPIO_23,
-	AU1000_GPIO_24,
-	AU1000_GPIO_25,
-	AU1000_GPIO_26,
-	AU1000_GPIO_27,
-	AU1000_GPIO_28,
-	AU1000_GPIO_29,
-	AU1000_GPIO_30,
-	AU1000_GPIO_31,
-};
 
 #define UART0_ADDR		0xB1100000
 #define UART1_ADDR		0xB1200000
@@ -796,6 +937,7 @@ enum soc_au1100_ints {
 
 #define USB_OHCI_BASE		0x10100000	/* phys addr for ioremap */
 #define USB_HOST_CONFIG 	0xB017FFFC
+#define FOR_PLATFORM_C_USB_HOST_INT AU1100_USB_HOST_INT
 
 #define AU1100_ETH0_BASE	0xB0500000
 #define AU1100_MAC0_ENABLE	0xB0520000
@@ -803,80 +945,6 @@ enum soc_au1100_ints {
 #endif /* CONFIG_SOC_AU1100 */
 
 #ifdef CONFIG_SOC_AU1550
-enum soc_au1550_ints {
-	AU1550_FIRST_INT	= MIPS_CPU_IRQ_BASE + 8,
-	AU1550_UART0_INT	= AU1550_FIRST_INT,
-	AU1550_PCI_INTA,
-	AU1550_PCI_INTB,
-	AU1550_DDMA_INT,
-	AU1550_CRYPTO_INT,
-	AU1550_PCI_INTC,
-	AU1550_PCI_INTD,
-	AU1550_PCI_RST_INT,
-	AU1550_UART1_INT,
-	AU1550_UART3_INT,
-	AU1550_PSC0_INT,
-	AU1550_PSC1_INT,
-	AU1550_PSC2_INT,
-	AU1550_PSC3_INT,
-	AU1000_TOY_INT,
-	AU1000_TOY_MATCH0_INT,
-	AU1000_TOY_MATCH1_INT,
-	AU1000_TOY_MATCH2_INT,
-	AU1000_RTC_INT,
-	AU1000_RTC_MATCH0_INT,
-	AU1000_RTC_MATCH1_INT,
-	AU1000_RTC_MATCH2_INT,
-
-	AU1550_NAND_INT			= AU1550_FIRST_INT + 23,
-	AU1550_USB_DEV_REQ_INT,
-	AU1000_USB_DEV_REQ_INT		= AU1550_USB_DEV_REQ_INT,
-	AU1550_USB_DEV_SUS_INT,
-	AU1000_USB_DEV_SUS_INT		= AU1550_USB_DEV_SUS_INT,
-	AU1550_USB_HOST_INT,
-	AU1000_USB_HOST_INT		= AU1550_USB_HOST_INT,
-	AU1550_MAC0_DMA_INT,
-	AU1550_MAC1_DMA_INT,
-	AU1000_GPIO_0			= AU1550_FIRST_INT + 32,
-	AU1000_GPIO_1,
-	AU1000_GPIO_2,
-	AU1000_GPIO_3,
-	AU1000_GPIO_4,
-	AU1000_GPIO_5,
-	AU1000_GPIO_6,
-	AU1000_GPIO_7,
-	AU1000_GPIO_8,
-	AU1000_GPIO_9,
-	AU1000_GPIO_10,
-	AU1000_GPIO_11,
-	AU1000_GPIO_12,
-	AU1000_GPIO_13,
-	AU1000_GPIO_14,
-	AU1000_GPIO_15,
-	AU1550_GPIO_200,
-	AU1500_GPIO_201_205,			/* Logical or of GPIO201:205 */
-	AU1500_GPIO_16,
-	AU1500_GPIO_17,
-	AU1500_GPIO_20,
-	AU1500_GPIO_21,
-	AU1500_GPIO_22,
-	AU1500_GPIO_23,
-	AU1500_GPIO_24,
-	AU1500_GPIO_25,
-	AU1500_GPIO_26,
-	AU1500_GPIO_27,
-	AU1500_GPIO_28,
-	AU1500_GPIO_206,
-	AU1500_GPIO_207,
-	AU1500_GPIO_208_218,			/* Logical or of GPIO208:218 */
-};
-
-/* shortcuts */
-#define INTA AU1550_PCI_INTA
-#define INTB AU1550_PCI_INTB
-#define INTC AU1550_PCI_INTC
-#define INTD AU1550_PCI_INTD
-
 #define UART0_ADDR		0xB1100000
 #define UART1_ADDR		0xB1200000
 #define UART3_ADDR		0xB1400000
@@ -884,6 +952,7 @@ enum soc_au1550_ints {
 #define USB_OHCI_BASE		0x14020000	/* phys addr for ioremap */
 #define USB_OHCI_LEN		0x00060000
 #define USB_HOST_CONFIG 	0xB4027ffc
+#define FOR_PLATFORM_C_USB_HOST_INT AU1550_USB_HOST_INT
 
 #define AU1550_ETH0_BASE	0xB0500000
 #define AU1550_ETH1_BASE	0xB0510000
@@ -892,75 +961,8 @@ enum soc_au1550_ints {
 #define NUM_ETH_INTERFACES 2
 #endif /* CONFIG_SOC_AU1550 */
 
+
 #ifdef CONFIG_SOC_AU1200
-enum soc_au1200_ints {
-	AU1200_FIRST_INT	= MIPS_CPU_IRQ_BASE + 8,
-	AU1200_UART0_INT	= AU1200_FIRST_INT,
-	AU1200_SWT_INT,
-	AU1200_SD_INT,
-	AU1200_DDMA_INT,
-	AU1200_MAE_BE_INT,
-	AU1200_GPIO_200,
-	AU1200_GPIO_201,
-	AU1200_GPIO_202,
-	AU1200_UART1_INT,
-	AU1200_MAE_FE_INT,
-	AU1200_PSC0_INT,
-	AU1200_PSC1_INT,
-	AU1200_AES_INT,
-	AU1200_CAMERA_INT,
-	AU1000_TOY_INT,
-	AU1000_TOY_MATCH0_INT,
-	AU1000_TOY_MATCH1_INT,
-	AU1000_TOY_MATCH2_INT,
-	AU1000_RTC_INT,
-	AU1000_RTC_MATCH0_INT,
-	AU1000_RTC_MATCH1_INT,
-	AU1000_RTC_MATCH2_INT,
-	AU1200_GPIO_203,
-	AU1200_NAND_INT,
-	AU1200_GPIO_204,
-	AU1200_GPIO_205,
-	AU1200_GPIO_206,
-	AU1200_GPIO_207,
-	AU1200_GPIO_208_215,			/* Logical OR of 208:215 */
-	AU1200_USB_INT,
-	AU1000_USB_HOST_INT	= AU1200_USB_INT,
-	AU1200_LCD_INT,
-	AU1200_MAE_BOTH_INT,
-	AU1000_GPIO_0,
-	AU1000_GPIO_1,
-	AU1000_GPIO_2,
-	AU1000_GPIO_3,
-	AU1000_GPIO_4,
-	AU1000_GPIO_5,
-	AU1000_GPIO_6,
-	AU1000_GPIO_7,
-	AU1000_GPIO_8,
-	AU1000_GPIO_9,
-	AU1000_GPIO_10,
-	AU1000_GPIO_11,
-	AU1000_GPIO_12,
-	AU1000_GPIO_13,
-	AU1000_GPIO_14,
-	AU1000_GPIO_15,
-	AU1000_GPIO_16,
-	AU1000_GPIO_17,
-	AU1000_GPIO_18,
-	AU1000_GPIO_19,
-	AU1000_GPIO_20,
-	AU1000_GPIO_21,
-	AU1000_GPIO_22,
-	AU1000_GPIO_23,
-	AU1000_GPIO_24,
-	AU1000_GPIO_25,
-	AU1000_GPIO_26,
-	AU1000_GPIO_27,
-	AU1000_GPIO_28,
-	AU1000_GPIO_29,
-	AU1000_GPIO_30,
-	AU1000_GPIO_31,
-};
 
 #define UART0_ADDR		0xB1100000
 #define UART1_ADDR		0xB1200000
@@ -989,15 +991,9 @@ enum soc_au1200_ints {
 #define USBMSRMCFG_RDCOMB	30
 #define USBMSRMCFG_PFEN 	31
 
-#endif /* CONFIG_SOC_AU1200 */
+#define FOR_PLATFORM_C_USB_HOST_INT AU1200_USB_INT
 
-#define AU1000_INTC0_INT_BASE	(MIPS_CPU_IRQ_BASE + 8)
-#define AU1000_INTC0_INT_LAST	(AU1000_INTC0_INT_BASE + 31)
-#define AU1000_INTC1_INT_BASE	(AU1000_INTC0_INT_BASE + 32)
-#define AU1000_INTC1_INT_LAST	(AU1000_INTC1_INT_BASE + 31)
-
-#define AU1000_MAX_INTR 	AU1000_INTC1_INT_LAST
-#define INTX			0xFF			/* not valid */
+#endif /* CONFIG_SOC_AU1200 */
 
 /* Programmable Counters 0 and 1 */
 #define SYS_BASE		0xB1900000
diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h
index feea001..9cf32d9 100644
--- a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h
+++ b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h
@@ -35,15 +35,13 @@ static inline int au1000_gpio2_to_irq(int gpio)
 	return -ENXIO;
 }
 
-#ifdef CONFIG_SOC_AU1000
 static inline int au1000_irq_to_gpio(int irq)
 {
-	if ((irq >= AU1000_GPIO_0) && (irq <= AU1000_GPIO_31))
-		return ALCHEMY_GPIO1_BASE + (irq - AU1000_GPIO_0) + 0;
+	if ((irq >= AU1000_GPIO0_INT) && (irq <= AU1000_GPIO31_INT))
+		return ALCHEMY_GPIO1_BASE + (irq - AU1000_GPIO0_INT) + 0;
 
 	return -ENXIO;
 }
-#endif
 
 static inline int au1500_gpio1_to_irq(int gpio)
 {
@@ -71,27 +69,25 @@ static inline int au1500_gpio2_to_irq(int gpio)
 	return -ENXIO;
 }
 
-#ifdef CONFIG_SOC_AU1500
 static inline int au1500_irq_to_gpio(int irq)
 {
 	switch (irq) {
-	case AU1000_GPIO_0 ... AU1000_GPIO_15:
-	case AU1500_GPIO_20:
-	case AU1500_GPIO_23 ... AU1500_GPIO_28:
-		return ALCHEMY_GPIO1_BASE + (irq - AU1000_GPIO_0) + 0;
-	case AU1500_GPIO_200 ... AU1500_GPIO_203:
-		return ALCHEMY_GPIO2_BASE + (irq - AU1500_GPIO_200) + 0;
-	case AU1500_GPIO_204 ... AU1500_GPIO_205:
-		return ALCHEMY_GPIO2_BASE + (irq - AU1500_GPIO_204) + 4;
-	case AU1500_GPIO_206 ... AU1500_GPIO_207:
-		return ALCHEMY_GPIO2_BASE + (irq - AU1500_GPIO_206) + 6;
-	case AU1500_GPIO_208_215:
+	case AU1500_GPIO0_INT ... AU1500_GPIO15_INT:
+	case AU1500_GPIO20_INT:
+	case AU1500_GPIO23_INT ... AU1500_GPIO28_INT:
+		return ALCHEMY_GPIO1_BASE + (irq - AU1500_GPIO0_INT) + 0;
+	case AU1500_GPIO200_INT ... AU1500_GPIO203_INT:
+		return ALCHEMY_GPIO2_BASE + (irq - AU1500_GPIO200_INT) + 0;
+	case AU1500_GPIO204_INT ... AU1500_GPIO205_INT:
+		return ALCHEMY_GPIO2_BASE + (irq - AU1500_GPIO204_INT) + 4;
+	case AU1500_GPIO206_INT ... AU1500_GPIO207_INT:
+		return ALCHEMY_GPIO2_BASE + (irq - AU1500_GPIO206_INT) + 6;
+	case AU1500_GPIO208_215_INT:
 		return ALCHEMY_GPIO2_BASE + 8;
 	}
 
 	return -ENXIO;
 }
-#endif
 
 static inline int au1100_gpio1_to_irq(int gpio)
 {
@@ -104,21 +100,21 @@ static inline int au1100_gpio2_to_irq(int gpio)
 
 	if ((gpio >= 8) && (gpio <= 15))
 		return MAKE_IRQ(0, 29);		/* shared GPIO208_215 */
+
+	return -ENXIO;
 }
 
-#ifdef CONFIG_SOC_AU1100
 static inline int au1100_irq_to_gpio(int irq)
 {
 	switch (irq) {
-	case AU1000_GPIO_0 ... AU1000_GPIO_31:
-		return ALCHEMY_GPIO1_BASE + (irq - AU1000_GPIO_0) + 0;
-	case AU1100_GPIO_208_215:
+	case AU1100_GPIO0_INT ... AU1100_GPIO31_INT:
+		return ALCHEMY_GPIO1_BASE + (irq - AU1100_GPIO0_INT) + 0;
+	case AU1100_GPIO208_215_INT:
 		return ALCHEMY_GPIO2_BASE + 8;
 	}
 
 	return -ENXIO;
 }
-#endif
 
 static inline int au1550_gpio1_to_irq(int gpio)
 {
@@ -147,24 +143,22 @@ static inline int au1550_gpio2_to_irq(int gpio)
 	return -ENXIO;
 }
 
-#ifdef CONFIG_SOC_AU1550
 static inline int au1550_irq_to_gpio(int irq)
 {
 	switch (irq) {
-	case AU1000_GPIO_0 ... AU1000_GPIO_15:
-		return ALCHEMY_GPIO1_BASE + (irq - AU1000_GPIO_0) + 0;
-	case AU1550_GPIO_200:
-	case AU1500_GPIO_201_205:
-		return ALCHEMY_GPIO2_BASE + (irq - AU1550_GPIO_200) + 0;
-	case AU1500_GPIO_16 ... AU1500_GPIO_28:
-		return ALCHEMY_GPIO1_BASE + (irq - AU1500_GPIO_16) + 16;
-	case AU1500_GPIO_206 ... AU1500_GPIO_208_218:
-		return ALCHEMY_GPIO2_BASE + (irq - AU1500_GPIO_206) + 6;
+	case AU1550_GPIO0_INT ... AU1550_GPIO15_INT:
+		return ALCHEMY_GPIO1_BASE + (irq - AU1550_GPIO0_INT) + 0;
+	case AU1550_GPIO200_INT:
+	case AU1550_GPIO201_205_INT:
+		return ALCHEMY_GPIO2_BASE + (irq - AU1550_GPIO200_INT) + 0;
+	case AU1550_GPIO16_INT ... AU1550_GPIO28_INT:
+		return ALCHEMY_GPIO1_BASE + (irq - AU1550_GPIO16_INT) + 16;
+	case AU1550_GPIO206_INT ... AU1550_GPIO208_215_INT:
+		return ALCHEMY_GPIO2_BASE + (irq - AU1550_GPIO206_INT) + 6;
 	}
 
 	return -ENXIO;
 }
-#endif
 
 static inline int au1200_gpio1_to_irq(int gpio)
 {
@@ -185,23 +179,21 @@ static inline int au1200_gpio2_to_irq(int gpio)
 	return -ENXIO;
 }
 
-#ifdef CONFIG_SOC_AU1200
 static inline int au1200_irq_to_gpio(int irq)
 {
 	switch (irq) {
-	case AU1000_GPIO_0 ... AU1000_GPIO_31:
-		return ALCHEMY_GPIO1_BASE + (irq - AU1000_GPIO_0) + 0;
-	case AU1200_GPIO_200 ... AU1200_GPIO_202:
-		return ALCHEMY_GPIO2_BASE + (irq - AU1200_GPIO_200) + 0;
-	case AU1200_GPIO_203:
+	case AU1200_GPIO0_INT ... AU1200_GPIO31_INT:
+		return ALCHEMY_GPIO1_BASE + (irq - AU1200_GPIO0_INT) + 0;
+	case AU1200_GPIO200_INT ... AU1200_GPIO202_INT:
+		return ALCHEMY_GPIO2_BASE + (irq - AU1200_GPIO200_INT) + 0;
+	case AU1200_GPIO203_INT:
 		return ALCHEMY_GPIO2_BASE + 3;
-	case AU1200_GPIO_204 ... AU1200_GPIO_208_215:
-		return ALCHEMY_GPIO2_BASE + (irq - AU1200_GPIO_204) + 4;
+	case AU1200_GPIO204_INT ... AU1200_GPIO208_215_INT:
+		return ALCHEMY_GPIO2_BASE + (irq - AU1200_GPIO204_INT) + 4;
 	}
 
 	return -ENXIO;
 }
-#endif
 
 /*
  * GPIO1 block macros for common linux gpio functions.
-- 
1.6.5.rc2


From David.Daney@caviumnetworks.com Thu Oct  8 01:08:12 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 01:08:19 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:16079 "EHLO
	mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S2097312AbZJGXIM (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 01:08:12 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,5,4,7535)
	id <B4acd1f4c0000>; Wed, 07 Oct 2009 16:07:56 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 16:07:59 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 16:07:59 -0700
Message-ID: <4ACD1F4E.8090603@caviumnetworks.com>
Date:	Wed, 07 Oct 2009 16:07:58 -0700
From:	David Daney <ddaney@caviumnetworks.com>
User-Agent: Thunderbird 2.0.0.21 (X11/20090320)
MIME-Version: 1.0
To:	Ralf Baechle <ralf@linux-mips.org>,
	linux-mips <linux-mips@linux-mips.org>, netdev@vger.kernel.org
Subject: [PATCH 0/6] netdev: Octeon MGMT new driver + octeon_ethernet updates.
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
X-OriginalArrivalTime: 07 Oct 2009 23:07:59.0276 (UTC) FILETIME=[03388EC0:01CA47A3]
Return-Path: <David.Daney@caviumnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24164
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ddaney@caviumnetworks.com
Precedence: bulk
X-list: linux-mips

The main thrust of this patch set is to add a driver for the Cavium
Networks Octeon processor's MII (Management port) Ethernet devices.
Since it shares an mdio bus with the existing octeon-ethernet driver,
there is also some rearrangement of that code.

The Octeon SOC has an mdio bus that is shared by the PHYs of all the
Ethernet ports on the chip.  Patches 1/6 and 2/6 add a stand-alone
driver for the shared mdio bus

3/6 adds platform devices for the octeon_mgmt devices.

4/6 has the register definitions needed by the driver.

5/6 the octeon_mgmt driver proper

6/6 converts octeon_ethernet to use the PHYs on the shared mdio bus.


Since the Octeon is a mips based device, we may want to merge some or
all of these patches via Ralf's tree.

I will reply with the 6 patches.

David Daney (6):
   MIPS: Octeon: Add platform device for MDIO buses.
   net: Add driver for Octeon MDIO buses.
   MIPS: Octeon: Add platform devices MGMT Ethernet ports.
   MIPS: Octeon: Add register definitions for MGMT Ethernet driver.
   netdev: Add Ethernet driver for Octeon MGMT devices.
   Staging: octeon-ethernet: Convert to use PHY Abstraction Layer.

  arch/mips/cavium-octeon/octeon-platform.c     |   88 ++
  arch/mips/include/asm/octeon/cvmx-agl-defs.h  | 1194 
+++++++++++++++++++++++++
  arch/mips/include/asm/octeon/cvmx-mixx-defs.h |  248 +++++
  arch/mips/include/asm/octeon/cvmx-smix-defs.h |  178 ++++
  drivers/net/Kconfig                           |    2 +
  drivers/net/Makefile                          |    2 +
  drivers/net/octeon/Kconfig                    |   10 +
  drivers/net/octeon/Makefile                   |    2 +
  drivers/net/octeon/octeon_mgmt.c              | 1175 
++++++++++++++++++++++++
  drivers/net/phy/Kconfig                       |   11 +
  drivers/net/phy/Makefile                      |    1 +
  drivers/net/phy/mdio-octeon.c                 |  180 ++++
  drivers/staging/octeon/Kconfig                |    3 +-
  drivers/staging/octeon/ethernet-mdio.c        |  202 ++---
  drivers/staging/octeon/ethernet-mdio.h        |    2 +-
  drivers/staging/octeon/ethernet-proc.c        |  112 ---
  drivers/staging/octeon/ethernet-rgmii.c       |   54 +-
  drivers/staging/octeon/ethernet-sgmii.c       |    2 +-
  drivers/staging/octeon/ethernet-xaui.c        |    2 +-
  drivers/staging/octeon/ethernet.c             |   68 +-
  drivers/staging/octeon/octeon-ethernet.h      |   15 +-
  21 files changed, 3255 insertions(+), 296 deletions(-)
  create mode 100644 arch/mips/include/asm/octeon/cvmx-agl-defs.h
  create mode 100644 arch/mips/include/asm/octeon/cvmx-mixx-defs.h
  create mode 100644 arch/mips/include/asm/octeon/cvmx-smix-defs.h
  create mode 100644 drivers/net/octeon/Kconfig
  create mode 100644 drivers/net/octeon/Makefile
  create mode 100644 drivers/net/octeon/octeon_mgmt.c
  create mode 100644 drivers/net/phy/mdio-octeon.c


From David.Daney@caviumnetworks.com Thu Oct  8 01:10:22 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 01:10:28 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:16106 "EHLO
	mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S2097318AbZJGXKW (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 01:10:22 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,5,4,7535)
	id <B4acd1fd90001>; Wed, 07 Oct 2009 16:10:17 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 16:10:20 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 16:10:20 -0700
Received: from dd1.caveonetworks.com (localhost.localdomain [127.0.0.1])
	by dd1.caveonetworks.com (8.14.2/8.14.2) with ESMTP id n97NAHsg007666;
	Wed, 7 Oct 2009 16:10:17 -0700
Received: (from ddaney@localhost)
	by dd1.caveonetworks.com (8.14.2/8.14.2/Submit) id n97NAHaQ007665;
	Wed, 7 Oct 2009 16:10:17 -0700
From:	David Daney <ddaney@caviumnetworks.com>
To:	ralf@linux-mips.org, linux-mips@linux-mips.org,
	netdev@vger.kernel.org
Cc:	David Daney <ddaney@caviumnetworks.com>
Subject: [PATCH 3/6] MIPS: Octeon: Add platform devices MGMT Ethernet ports.
Date:	Wed,  7 Oct 2009 16:10:12 -0700
Message-Id: <1254957015-7633-3-git-send-email-ddaney@caviumnetworks.com>
X-Mailer: git-send-email 1.6.0.6
In-Reply-To: <4ACD1F4E.8090603@caviumnetworks.com>
References: <4ACD1F4E.8090603@caviumnetworks.com>
X-OriginalArrivalTime: 07 Oct 2009 23:10:20.0137 (UTC) FILETIME=[572E3D90:01CA47A3]
Return-Path: <David.Daney@caviumnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24165
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ddaney@caviumnetworks.com
Precedence: bulk
X-list: linux-mips

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---
 arch/mips/cavium-octeon/octeon-platform.c |   58 +++++++++++++++++++++++++++++
 1 files changed, 58 insertions(+), 0 deletions(-)

diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c
index febfdd7..cfdb4c2 100644
--- a/arch/mips/cavium-octeon/octeon-platform.c
+++ b/arch/mips/cavium-octeon/octeon-platform.c
@@ -189,6 +189,64 @@ out:
 }
 device_initcall(octeon_mdiobus_device_init);
 
+/* Octeon mgmt port Ethernet interface.  */
+static int __init octeon_mgmt_device_init(void)
+{
+	struct platform_device *pd;
+	int ret = 0;
+	int port, num_ports;
+
+	struct resource mgmt_port_resource = {
+		.flags	= IORESOURCE_IRQ,
+		.start	= -1,
+		.end	= -1
+	};
+
+	if (!OCTEON_IS_MODEL(OCTEON_CN56XX) && !OCTEON_IS_MODEL(OCTEON_CN52XX))
+		return 0;
+
+	if (OCTEON_IS_MODEL(OCTEON_CN56XX))
+		num_ports = 1;
+	else
+		num_ports = 2;
+
+	for (port = 0; port < num_ports; port++) {
+		pd = platform_device_alloc("octeon_mgmt", port);
+		if (!pd) {
+			ret = -ENOMEM;
+			goto out;
+		}
+		switch (port) {
+		case 0:
+			mgmt_port_resource.start = OCTEON_IRQ_MII0;
+			break;
+		case 1:
+			mgmt_port_resource.start = OCTEON_IRQ_MII1;
+			break;
+		default:
+			BUG();
+		}
+		mgmt_port_resource.end = mgmt_port_resource.start;
+
+		ret = platform_device_add_resources(pd, &mgmt_port_resource, 1);
+
+		if (ret)
+			goto fail;
+
+		ret = platform_device_add(pd);
+		if (ret)
+			goto fail;
+	}
+	return ret;
+fail:
+	platform_device_put(pd);
+
+out:
+	return ret;
+
+}
+device_initcall(octeon_mgmt_device_init);
+
 MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Platform driver for Octeon SOC");
-- 
1.6.0.6


From David.Daney@caviumnetworks.com Thu Oct  8 01:10:46 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 01:10:53 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:16103 "EHLO
	mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S2097319AbZJGXKW (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 01:10:22 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,5,4,7535)
	id <B4acd1fd90000>; Wed, 07 Oct 2009 16:10:17 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 16:10:20 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 16:10:20 -0700
Received: from dd1.caveonetworks.com (localhost.localdomain [127.0.0.1])
	by dd1.caveonetworks.com (8.14.2/8.14.2) with ESMTP id n97NAHuM007662;
	Wed, 7 Oct 2009 16:10:17 -0700
Received: (from ddaney@localhost)
	by dd1.caveonetworks.com (8.14.2/8.14.2/Submit) id n97NAHVk007661;
	Wed, 7 Oct 2009 16:10:17 -0700
From:	David Daney <ddaney@caviumnetworks.com>
To:	ralf@linux-mips.org, linux-mips@linux-mips.org,
	netdev@vger.kernel.org
Cc:	David Daney <ddaney@caviumnetworks.com>
Subject: [PATCH 2/6] net: Add driver for Octeon MDIO buses.
Date:	Wed,  7 Oct 2009 16:10:11 -0700
Message-Id: <1254957015-7633-2-git-send-email-ddaney@caviumnetworks.com>
X-Mailer: git-send-email 1.6.0.6
In-Reply-To: <4ACD1F4E.8090603@caviumnetworks.com>
References: <4ACD1F4E.8090603@caviumnetworks.com>
X-OriginalArrivalTime: 07 Oct 2009 23:10:20.0137 (UTC) FILETIME=[572E3D90:01CA47A3]
Return-Path: <David.Daney@caviumnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24166
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ddaney@caviumnetworks.com
Precedence: bulk
X-list: linux-mips

The Octeon SOC has two types of Ethernet ports, each type with its own
driver.  However, the PHYs for all the ports are controlled by a
common MDIO bus.  Because the mdio driver is not associated with a
particular driver, but is instead a system level resource, we create s
stand-alone driver for it.

As for the driver, we put the register definitions in
arch/mips/include/asm/octeon where most of the other Octeon register
definitions live.  This is a platform driver with the platform device
for "mdio-octeon" being registered in the platform startup code.

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---
 arch/mips/include/asm/octeon/cvmx-smix-defs.h |  178 ++++++++++++++++++++++++
 drivers/net/phy/Kconfig                       |   11 ++
 drivers/net/phy/Makefile                      |    1 +
 drivers/net/phy/mdio-octeon.c                 |  180 +++++++++++++++++++++++++
 4 files changed, 370 insertions(+), 0 deletions(-)
 create mode 100644 arch/mips/include/asm/octeon/cvmx-smix-defs.h
 create mode 100644 drivers/net/phy/mdio-octeon.c

diff --git a/arch/mips/include/asm/octeon/cvmx-smix-defs.h b/arch/mips/include/asm/octeon/cvmx-smix-defs.h
new file mode 100644
index 0000000..9ae45fc
--- /dev/null
+++ b/arch/mips/include/asm/octeon/cvmx-smix-defs.h
@@ -0,0 +1,178 @@
+/***********************license start***************
+ * Author: Cavium Networks
+ *
+ * Contact: support@caviumnetworks.com
+ * This file is part of the OCTEON SDK
+ *
+ * Copyright (c) 2003-2008 Cavium Networks
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * or visit http://www.gnu.org/licenses/.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium Networks for more information
+ ***********************license end**************************************/
+
+#ifndef __CVMX_SMIX_DEFS_H__
+#define __CVMX_SMIX_DEFS_H__
+
+#define CVMX_SMIX_CLK(offset) \
+	 CVMX_ADD_IO_SEG(0x0001180000001818ull + (((offset) & 1) * 256))
+#define CVMX_SMIX_CMD(offset) \
+	 CVMX_ADD_IO_SEG(0x0001180000001800ull + (((offset) & 1) * 256))
+#define CVMX_SMIX_EN(offset) \
+	 CVMX_ADD_IO_SEG(0x0001180000001820ull + (((offset) & 1) * 256))
+#define CVMX_SMIX_RD_DAT(offset) \
+	 CVMX_ADD_IO_SEG(0x0001180000001810ull + (((offset) & 1) * 256))
+#define CVMX_SMIX_WR_DAT(offset) \
+	 CVMX_ADD_IO_SEG(0x0001180000001808ull + (((offset) & 1) * 256))
+
+union cvmx_smix_clk {
+	uint64_t u64;
+	struct cvmx_smix_clk_s {
+		uint64_t reserved_25_63:39;
+		uint64_t mode:1;
+		uint64_t reserved_21_23:3;
+		uint64_t sample_hi:5;
+		uint64_t sample_mode:1;
+		uint64_t reserved_14_14:1;
+		uint64_t clk_idle:1;
+		uint64_t preamble:1;
+		uint64_t sample:4;
+		uint64_t phase:8;
+	} s;
+	struct cvmx_smix_clk_cn30xx {
+		uint64_t reserved_21_63:43;
+		uint64_t sample_hi:5;
+		uint64_t reserved_14_15:2;
+		uint64_t clk_idle:1;
+		uint64_t preamble:1;
+		uint64_t sample:4;
+		uint64_t phase:8;
+	} cn30xx;
+	struct cvmx_smix_clk_cn30xx cn31xx;
+	struct cvmx_smix_clk_cn30xx cn38xx;
+	struct cvmx_smix_clk_cn30xx cn38xxp2;
+	struct cvmx_smix_clk_cn50xx {
+		uint64_t reserved_25_63:39;
+		uint64_t mode:1;
+		uint64_t reserved_21_23:3;
+		uint64_t sample_hi:5;
+		uint64_t reserved_14_15:2;
+		uint64_t clk_idle:1;
+		uint64_t preamble:1;
+		uint64_t sample:4;
+		uint64_t phase:8;
+	} cn50xx;
+	struct cvmx_smix_clk_s cn52xx;
+	struct cvmx_smix_clk_cn50xx cn52xxp1;
+	struct cvmx_smix_clk_s cn56xx;
+	struct cvmx_smix_clk_cn50xx cn56xxp1;
+	struct cvmx_smix_clk_cn30xx cn58xx;
+	struct cvmx_smix_clk_cn30xx cn58xxp1;
+};
+
+union cvmx_smix_cmd {
+	uint64_t u64;
+	struct cvmx_smix_cmd_s {
+		uint64_t reserved_18_63:46;
+		uint64_t phy_op:2;
+		uint64_t reserved_13_15:3;
+		uint64_t phy_adr:5;
+		uint64_t reserved_5_7:3;
+		uint64_t reg_adr:5;
+	} s;
+	struct cvmx_smix_cmd_cn30xx {
+		uint64_t reserved_17_63:47;
+		uint64_t phy_op:1;
+		uint64_t reserved_13_15:3;
+		uint64_t phy_adr:5;
+		uint64_t reserved_5_7:3;
+		uint64_t reg_adr:5;
+	} cn30xx;
+	struct cvmx_smix_cmd_cn30xx cn31xx;
+	struct cvmx_smix_cmd_cn30xx cn38xx;
+	struct cvmx_smix_cmd_cn30xx cn38xxp2;
+	struct cvmx_smix_cmd_s cn50xx;
+	struct cvmx_smix_cmd_s cn52xx;
+	struct cvmx_smix_cmd_s cn52xxp1;
+	struct cvmx_smix_cmd_s cn56xx;
+	struct cvmx_smix_cmd_s cn56xxp1;
+	struct cvmx_smix_cmd_cn30xx cn58xx;
+	struct cvmx_smix_cmd_cn30xx cn58xxp1;
+};
+
+union cvmx_smix_en {
+	uint64_t u64;
+	struct cvmx_smix_en_s {
+		uint64_t reserved_1_63:63;
+		uint64_t en:1;
+	} s;
+	struct cvmx_smix_en_s cn30xx;
+	struct cvmx_smix_en_s cn31xx;
+	struct cvmx_smix_en_s cn38xx;
+	struct cvmx_smix_en_s cn38xxp2;
+	struct cvmx_smix_en_s cn50xx;
+	struct cvmx_smix_en_s cn52xx;
+	struct cvmx_smix_en_s cn52xxp1;
+	struct cvmx_smix_en_s cn56xx;
+	struct cvmx_smix_en_s cn56xxp1;
+	struct cvmx_smix_en_s cn58xx;
+	struct cvmx_smix_en_s cn58xxp1;
+};
+
+union cvmx_smix_rd_dat {
+	uint64_t u64;
+	struct cvmx_smix_rd_dat_s {
+		uint64_t reserved_18_63:46;
+		uint64_t pending:1;
+		uint64_t val:1;
+		uint64_t dat:16;
+	} s;
+	struct cvmx_smix_rd_dat_s cn30xx;
+	struct cvmx_smix_rd_dat_s cn31xx;
+	struct cvmx_smix_rd_dat_s cn38xx;
+	struct cvmx_smix_rd_dat_s cn38xxp2;
+	struct cvmx_smix_rd_dat_s cn50xx;
+	struct cvmx_smix_rd_dat_s cn52xx;
+	struct cvmx_smix_rd_dat_s cn52xxp1;
+	struct cvmx_smix_rd_dat_s cn56xx;
+	struct cvmx_smix_rd_dat_s cn56xxp1;
+	struct cvmx_smix_rd_dat_s cn58xx;
+	struct cvmx_smix_rd_dat_s cn58xxp1;
+};
+
+union cvmx_smix_wr_dat {
+	uint64_t u64;
+	struct cvmx_smix_wr_dat_s {
+		uint64_t reserved_18_63:46;
+		uint64_t pending:1;
+		uint64_t val:1;
+		uint64_t dat:16;
+	} s;
+	struct cvmx_smix_wr_dat_s cn30xx;
+	struct cvmx_smix_wr_dat_s cn31xx;
+	struct cvmx_smix_wr_dat_s cn38xx;
+	struct cvmx_smix_wr_dat_s cn38xxp2;
+	struct cvmx_smix_wr_dat_s cn50xx;
+	struct cvmx_smix_wr_dat_s cn52xx;
+	struct cvmx_smix_wr_dat_s cn52xxp1;
+	struct cvmx_smix_wr_dat_s cn56xx;
+	struct cvmx_smix_wr_dat_s cn56xxp1;
+	struct cvmx_smix_wr_dat_s cn58xx;
+	struct cvmx_smix_wr_dat_s cn58xxp1;
+};
+
+#endif
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index d5d8e1c..fc5938b 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -115,4 +115,15 @@ config MDIO_GPIO
 	  To compile this driver as a module, choose M here: the module
 	  will be called mdio-gpio.
 
+config MDIO_OCTEON
+	tristate "Support for MDIO buses on Octeon SOCs"
+	depends on  CPU_CAVIUM_OCTEON
+	default y
+	help
+
+	  This module provides a driver for the Octeon MDIO busses.
+	  It is required by the Octeon Ethernet device drivers.
+
+	  If in doubt, say Y.
+
 endif # PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index edfaac4..1342585 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_MDIO_BITBANG)	+= mdio-bitbang.o
 obj-$(CONFIG_MDIO_GPIO)		+= mdio-gpio.o
 obj-$(CONFIG_NATIONAL_PHY)	+= national.o
 obj-$(CONFIG_STE10XP)		+= ste10Xp.o
+obj-$(CONFIG_MDIO_OCTEON)	+= mdio-octeon.o
diff --git a/drivers/net/phy/mdio-octeon.c b/drivers/net/phy/mdio-octeon.c
new file mode 100644
index 0000000..61a4461
--- /dev/null
+++ b/drivers/net/phy/mdio-octeon.c
@@ -0,0 +1,180 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Cavium Networks
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/phy.h>
+
+#include <asm/octeon/octeon.h>
+#include <asm/octeon/cvmx-smix-defs.h>
+
+#define DRV_VERSION "1.0"
+#define DRV_DESCRIPTION "Cavium Networks Octeon SMI/MDIO driver"
+
+struct octeon_mdiobus {
+	struct mii_bus *mii_bus;
+	int unit;
+	int phy_irq[PHY_MAX_ADDR];
+};
+
+static int octeon_mdiobus_read(struct mii_bus *bus, int phy_id, int regnum)
+{
+	struct octeon_mdiobus *p = bus->priv;
+	union cvmx_smix_cmd smi_cmd;
+	union cvmx_smix_rd_dat smi_rd;
+	int timeout = 1000;
+
+	smi_cmd.u64 = 0;
+	smi_cmd.s.phy_op = 1; /* MDIO_CLAUSE_22_READ */
+	smi_cmd.s.phy_adr = phy_id;
+	smi_cmd.s.reg_adr = regnum;
+	cvmx_write_csr(CVMX_SMIX_CMD(p->unit), smi_cmd.u64);
+
+	do {
+		/*
+		 * Wait 1000 clocks so we don't saturate the RSL bus
+		 * doing reads.
+		 */
+		cvmx_wait(1000);
+		smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(p->unit));
+	} while (smi_rd.s.pending && --timeout);
+
+	if (smi_rd.s.val)
+		return smi_rd.s.dat;
+	else
+		return -EIO;
+}
+
+static int octeon_mdiobus_write(struct mii_bus *bus, int phy_id,
+				int regnum, u16 val)
+{
+	struct octeon_mdiobus *p = bus->priv;
+	union cvmx_smix_cmd smi_cmd;
+	union cvmx_smix_wr_dat smi_wr;
+	int timeout = 1000;
+
+	smi_wr.u64 = 0;
+	smi_wr.s.dat = val;
+	cvmx_write_csr(CVMX_SMIX_WR_DAT(p->unit), smi_wr.u64);
+
+	smi_cmd.u64 = 0;
+	smi_cmd.s.phy_op = 0; /* MDIO_CLAUSE_22_WRITE */
+	smi_cmd.s.phy_adr = phy_id;
+	smi_cmd.s.reg_adr = regnum;
+	cvmx_write_csr(CVMX_SMIX_CMD(p->unit), smi_cmd.u64);
+
+	do {
+		/*
+		 * Wait 1000 clocks so we don't saturate the RSL bus
+		 * doing reads.
+		 */
+		cvmx_wait(1000);
+		smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(p->unit));
+	} while (smi_wr.s.pending && --timeout);
+
+	if (timeout <= 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int __init octeon_mdiobus_probe(struct platform_device *pdev)
+{
+	struct octeon_mdiobus *bus;
+	int i;
+	int err = -ENOENT;
+
+	bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
+	if (!bus)
+		return -ENOMEM;
+
+	/* The platform_device id is our unit number.  */
+	bus->unit = pdev->id;
+
+	bus->mii_bus = mdiobus_alloc();
+
+	if (!bus->mii_bus)
+		goto err;
+
+	/*
+	 * Standard Octeon evaluation boards don't support phy
+	 * interrupts, we need to poll.
+	 */
+	for (i = 0; i < PHY_MAX_ADDR; i++)
+		bus->phy_irq[i] = PHY_POLL;
+
+	bus->mii_bus->priv = bus;
+	bus->mii_bus->irq = bus->phy_irq;
+	bus->mii_bus->name = "mdio-octeon";
+	snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%x", bus->unit);
+	bus->mii_bus->parent = &pdev->dev;
+
+	bus->mii_bus->read = octeon_mdiobus_read;
+	bus->mii_bus->write = octeon_mdiobus_write;
+
+	dev_set_drvdata(&pdev->dev, bus);
+
+	err = mdiobus_register(bus->mii_bus);
+	if (err)
+		goto err_register;
+
+	dev_info(&pdev->dev, "Version " DRV_VERSION "\n");
+
+	return 0;
+err_register:
+	mdiobus_free(bus->mii_bus);
+
+err:
+	devm_kfree(&pdev->dev, bus);
+	return err;
+}
+
+static int __exit octeon_mdiobus_remove(struct platform_device *pdev)
+{
+	struct octeon_mdiobus *bus;
+
+	bus = dev_get_drvdata(&pdev->dev);
+
+	mdiobus_unregister(bus->mii_bus);
+	mdiobus_free(bus->mii_bus);
+	return 0;
+}
+
+static struct platform_driver octeon_mdiobus_driver = {
+	.driver = {
+		.name		= "mdio-octeon",
+		.owner		= THIS_MODULE,
+	},
+	.probe		= octeon_mdiobus_probe,
+	.remove		= __exit_p(octeon_mdiobus_remove),
+};
+
+void octeon_mdiobus_force_mod_depencency(void)
+{
+	/* Let ethernet drivers force us to be loaded.  */
+}
+EXPORT_SYMBOL(octeon_mdiobus_force_mod_depencency);
+
+static int __init octeon_mdiobus_mod_init(void)
+{
+	return platform_driver_register(&octeon_mdiobus_driver);
+}
+
+static void __exit octeon_mdiobus_mod_exit(void)
+{
+	platform_driver_unregister(&octeon_mdiobus_driver);
+}
+
+module_init(octeon_mdiobus_mod_init);
+module_exit(octeon_mdiobus_mod_exit);
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("David Daney");
+MODULE_LICENSE("GPL");
-- 
1.6.0.6


From David.Daney@caviumnetworks.com Thu Oct  8 01:11:12 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 01:11:18 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:16108 "EHLO
	mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S2097320AbZJGXKX (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 01:10:23 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,5,4,7535)
	id <B4acd1fd90002>; Wed, 07 Oct 2009 16:10:17 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 16:10:20 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 16:10:20 -0700
Received: from dd1.caveonetworks.com (localhost.localdomain [127.0.0.1])
	by dd1.caveonetworks.com (8.14.2/8.14.2) with ESMTP id n97NAHTM007670;
	Wed, 7 Oct 2009 16:10:17 -0700
Received: (from ddaney@localhost)
	by dd1.caveonetworks.com (8.14.2/8.14.2/Submit) id n97NAHsA007669;
	Wed, 7 Oct 2009 16:10:17 -0700
From:	David Daney <ddaney@caviumnetworks.com>
To:	ralf@linux-mips.org, linux-mips@linux-mips.org,
	netdev@vger.kernel.org
Cc:	David Daney <ddaney@caviumnetworks.com>
Subject: [PATCH 4/6] MIPS: Octeon: Add register definitions for MGMT Ethernet driver.
Date:	Wed,  7 Oct 2009 16:10:13 -0700
Message-Id: <1254957015-7633-4-git-send-email-ddaney@caviumnetworks.com>
X-Mailer: git-send-email 1.6.0.6
In-Reply-To: <4ACD1F4E.8090603@caviumnetworks.com>
References: <4ACD1F4E.8090603@caviumnetworks.com>
X-OriginalArrivalTime: 07 Oct 2009 23:10:20.0121 (UTC) FILETIME=[572BCC90:01CA47A3]
Return-Path: <David.Daney@caviumnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24167
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ddaney@caviumnetworks.com
Precedence: bulk
X-list: linux-mips

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---
 arch/mips/include/asm/octeon/cvmx-agl-defs.h  | 1194 +++++++++++++++++++++++++
 arch/mips/include/asm/octeon/cvmx-mixx-defs.h |  248 +++++
 2 files changed, 1442 insertions(+), 0 deletions(-)
 create mode 100644 arch/mips/include/asm/octeon/cvmx-agl-defs.h
 create mode 100644 arch/mips/include/asm/octeon/cvmx-mixx-defs.h

diff --git a/arch/mips/include/asm/octeon/cvmx-agl-defs.h b/arch/mips/include/asm/octeon/cvmx-agl-defs.h
new file mode 100644
index 0000000..ec94b9a
--- /dev/null
+++ b/arch/mips/include/asm/octeon/cvmx-agl-defs.h
@@ -0,0 +1,1194 @@
+/***********************license start***************
+ * Author: Cavium Networks
+ *
+ * Contact: support@caviumnetworks.com
+ * This file is part of the OCTEON SDK
+ *
+ * Copyright (c) 2003-2008 Cavium Networks
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * or visit http://www.gnu.org/licenses/.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium Networks for more information
+ ***********************license end**************************************/
+
+#ifndef __CVMX_AGL_DEFS_H__
+#define __CVMX_AGL_DEFS_H__
+
+#define CVMX_AGL_GMX_BAD_REG \
+	 CVMX_ADD_IO_SEG(0x00011800E0000518ull)
+#define CVMX_AGL_GMX_BIST \
+	 CVMX_ADD_IO_SEG(0x00011800E0000400ull)
+#define CVMX_AGL_GMX_DRV_CTL \
+	 CVMX_ADD_IO_SEG(0x00011800E00007F0ull)
+#define CVMX_AGL_GMX_INF_MODE \
+	 CVMX_ADD_IO_SEG(0x00011800E00007F8ull)
+#define CVMX_AGL_GMX_PRTX_CFG(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000010ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_ADR_CAM0(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000180ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_ADR_CAM1(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000188ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_ADR_CAM2(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000190ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_ADR_CAM3(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000198ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_ADR_CAM4(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E00001A0ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_ADR_CAM5(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E00001A8ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_ADR_CAM_EN(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000108ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_ADR_CTL(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000100ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_DECISION(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000040ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_FRM_CHK(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000020ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_FRM_CTL(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000018ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_FRM_MAX(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000030ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_FRM_MIN(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000028ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_IFG(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000058ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_INT_EN(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000008ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_INT_REG(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000000ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_JABBER(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000038ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_PAUSE_DROP_TIME(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000068ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_STATS_CTL(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000050ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_STATS_OCTS(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000088ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_STATS_OCTS_CTL(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000098ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_STATS_OCTS_DMAC(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E00000A8ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_STATS_OCTS_DRP(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E00000B8ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_STATS_PKTS(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000080ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_STATS_PKTS_BAD(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E00000C0ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_STATS_PKTS_CTL(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000090ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_STATS_PKTS_DMAC(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E00000A0ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_STATS_PKTS_DRP(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E00000B0ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RXX_UDD_SKP(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000048ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_RX_BP_DROPX(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000420ull + (((offset) & 1) * 8))
+#define CVMX_AGL_GMX_RX_BP_OFFX(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000460ull + (((offset) & 1) * 8))
+#define CVMX_AGL_GMX_RX_BP_ONX(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000440ull + (((offset) & 1) * 8))
+#define CVMX_AGL_GMX_RX_PRT_INFO \
+	 CVMX_ADD_IO_SEG(0x00011800E00004E8ull)
+#define CVMX_AGL_GMX_RX_TX_STATUS \
+	 CVMX_ADD_IO_SEG(0x00011800E00007E8ull)
+#define CVMX_AGL_GMX_SMACX(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000230ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_STAT_BP \
+	 CVMX_ADD_IO_SEG(0x00011800E0000520ull)
+#define CVMX_AGL_GMX_TXX_APPEND(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000218ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_CTL(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000270ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_MIN_PKT(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000240ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_PAUSE_PKT_INTERVAL(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000248ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_PAUSE_PKT_TIME(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000238ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_PAUSE_TOGO(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000258ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_PAUSE_ZERO(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000260ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_SOFT_PAUSE(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000250ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_STAT0(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000280ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_STAT1(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000288ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_STAT2(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000290ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_STAT3(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000298ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_STAT4(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E00002A0ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_STAT5(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E00002A8ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_STAT6(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E00002B0ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_STAT7(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E00002B8ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_STAT8(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E00002C0ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_STAT9(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E00002C8ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_STATS_CTL(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000268ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TXX_THRESH(offset) \
+	 CVMX_ADD_IO_SEG(0x00011800E0000210ull + (((offset) & 1) * 2048))
+#define CVMX_AGL_GMX_TX_BP \
+	 CVMX_ADD_IO_SEG(0x00011800E00004D0ull)
+#define CVMX_AGL_GMX_TX_COL_ATTEMPT \
+	 CVMX_ADD_IO_SEG(0x00011800E0000498ull)
+#define CVMX_AGL_GMX_TX_IFG \
+	 CVMX_ADD_IO_SEG(0x00011800E0000488ull)
+#define CVMX_AGL_GMX_TX_INT_EN \
+	 CVMX_ADD_IO_SEG(0x00011800E0000508ull)
+#define CVMX_AGL_GMX_TX_INT_REG \
+	 CVMX_ADD_IO_SEG(0x00011800E0000500ull)
+#define CVMX_AGL_GMX_TX_JAM \
+	 CVMX_ADD_IO_SEG(0x00011800E0000490ull)
+#define CVMX_AGL_GMX_TX_LFSR \
+	 CVMX_ADD_IO_SEG(0x00011800E00004F8ull)
+#define CVMX_AGL_GMX_TX_OVR_BP \
+	 CVMX_ADD_IO_SEG(0x00011800E00004C8ull)
+#define CVMX_AGL_GMX_TX_PAUSE_PKT_DMAC \
+	 CVMX_ADD_IO_SEG(0x00011800E00004A0ull)
+#define CVMX_AGL_GMX_TX_PAUSE_PKT_TYPE \
+	 CVMX_ADD_IO_SEG(0x00011800E00004A8ull)
+
+union cvmx_agl_gmx_bad_reg {
+	uint64_t u64;
+	struct cvmx_agl_gmx_bad_reg_s {
+		uint64_t reserved_38_63:26;
+		uint64_t txpsh1:1;
+		uint64_t txpop1:1;
+		uint64_t ovrflw1:1;
+		uint64_t txpsh:1;
+		uint64_t txpop:1;
+		uint64_t ovrflw:1;
+		uint64_t reserved_27_31:5;
+		uint64_t statovr:1;
+		uint64_t reserved_23_25:3;
+		uint64_t loststat:1;
+		uint64_t reserved_4_21:18;
+		uint64_t out_ovr:2;
+		uint64_t reserved_0_1:2;
+	} s;
+	struct cvmx_agl_gmx_bad_reg_s cn52xx;
+	struct cvmx_agl_gmx_bad_reg_s cn52xxp1;
+	struct cvmx_agl_gmx_bad_reg_cn56xx {
+		uint64_t reserved_35_63:29;
+		uint64_t txpsh:1;
+		uint64_t txpop:1;
+		uint64_t ovrflw:1;
+		uint64_t reserved_27_31:5;
+		uint64_t statovr:1;
+		uint64_t reserved_23_25:3;
+		uint64_t loststat:1;
+		uint64_t reserved_3_21:19;
+		uint64_t out_ovr:1;
+		uint64_t reserved_0_1:2;
+	} cn56xx;
+	struct cvmx_agl_gmx_bad_reg_cn56xx cn56xxp1;
+};
+
+union cvmx_agl_gmx_bist {
+	uint64_t u64;
+	struct cvmx_agl_gmx_bist_s {
+		uint64_t reserved_10_63:54;
+		uint64_t status:10;
+	} s;
+	struct cvmx_agl_gmx_bist_s cn52xx;
+	struct cvmx_agl_gmx_bist_s cn52xxp1;
+	struct cvmx_agl_gmx_bist_s cn56xx;
+	struct cvmx_agl_gmx_bist_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_drv_ctl {
+	uint64_t u64;
+	struct cvmx_agl_gmx_drv_ctl_s {
+		uint64_t reserved_49_63:15;
+		uint64_t byp_en1:1;
+		uint64_t reserved_45_47:3;
+		uint64_t pctl1:5;
+		uint64_t reserved_37_39:3;
+		uint64_t nctl1:5;
+		uint64_t reserved_17_31:15;
+		uint64_t byp_en:1;
+		uint64_t reserved_13_15:3;
+		uint64_t pctl:5;
+		uint64_t reserved_5_7:3;
+		uint64_t nctl:5;
+	} s;
+	struct cvmx_agl_gmx_drv_ctl_s cn52xx;
+	struct cvmx_agl_gmx_drv_ctl_s cn52xxp1;
+	struct cvmx_agl_gmx_drv_ctl_cn56xx {
+		uint64_t reserved_17_63:47;
+		uint64_t byp_en:1;
+		uint64_t reserved_13_15:3;
+		uint64_t pctl:5;
+		uint64_t reserved_5_7:3;
+		uint64_t nctl:5;
+	} cn56xx;
+	struct cvmx_agl_gmx_drv_ctl_cn56xx cn56xxp1;
+};
+
+union cvmx_agl_gmx_inf_mode {
+	uint64_t u64;
+	struct cvmx_agl_gmx_inf_mode_s {
+		uint64_t reserved_2_63:62;
+		uint64_t en:1;
+		uint64_t reserved_0_0:1;
+	} s;
+	struct cvmx_agl_gmx_inf_mode_s cn52xx;
+	struct cvmx_agl_gmx_inf_mode_s cn52xxp1;
+	struct cvmx_agl_gmx_inf_mode_s cn56xx;
+	struct cvmx_agl_gmx_inf_mode_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_prtx_cfg {
+	uint64_t u64;
+	struct cvmx_agl_gmx_prtx_cfg_s {
+		uint64_t reserved_6_63:58;
+		uint64_t tx_en:1;
+		uint64_t rx_en:1;
+		uint64_t slottime:1;
+		uint64_t duplex:1;
+		uint64_t speed:1;
+		uint64_t en:1;
+	} s;
+	struct cvmx_agl_gmx_prtx_cfg_s cn52xx;
+	struct cvmx_agl_gmx_prtx_cfg_s cn52xxp1;
+	struct cvmx_agl_gmx_prtx_cfg_s cn56xx;
+	struct cvmx_agl_gmx_prtx_cfg_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_adr_cam0 {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_adr_cam0_s {
+		uint64_t adr:64;
+	} s;
+	struct cvmx_agl_gmx_rxx_adr_cam0_s cn52xx;
+	struct cvmx_agl_gmx_rxx_adr_cam0_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_adr_cam0_s cn56xx;
+	struct cvmx_agl_gmx_rxx_adr_cam0_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_adr_cam1 {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_adr_cam1_s {
+		uint64_t adr:64;
+	} s;
+	struct cvmx_agl_gmx_rxx_adr_cam1_s cn52xx;
+	struct cvmx_agl_gmx_rxx_adr_cam1_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_adr_cam1_s cn56xx;
+	struct cvmx_agl_gmx_rxx_adr_cam1_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_adr_cam2 {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_adr_cam2_s {
+		uint64_t adr:64;
+	} s;
+	struct cvmx_agl_gmx_rxx_adr_cam2_s cn52xx;
+	struct cvmx_agl_gmx_rxx_adr_cam2_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_adr_cam2_s cn56xx;
+	struct cvmx_agl_gmx_rxx_adr_cam2_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_adr_cam3 {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_adr_cam3_s {
+		uint64_t adr:64;
+	} s;
+	struct cvmx_agl_gmx_rxx_adr_cam3_s cn52xx;
+	struct cvmx_agl_gmx_rxx_adr_cam3_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_adr_cam3_s cn56xx;
+	struct cvmx_agl_gmx_rxx_adr_cam3_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_adr_cam4 {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_adr_cam4_s {
+		uint64_t adr:64;
+	} s;
+	struct cvmx_agl_gmx_rxx_adr_cam4_s cn52xx;
+	struct cvmx_agl_gmx_rxx_adr_cam4_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_adr_cam4_s cn56xx;
+	struct cvmx_agl_gmx_rxx_adr_cam4_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_adr_cam5 {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_adr_cam5_s {
+		uint64_t adr:64;
+	} s;
+	struct cvmx_agl_gmx_rxx_adr_cam5_s cn52xx;
+	struct cvmx_agl_gmx_rxx_adr_cam5_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_adr_cam5_s cn56xx;
+	struct cvmx_agl_gmx_rxx_adr_cam5_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_adr_cam_en {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_adr_cam_en_s {
+		uint64_t reserved_8_63:56;
+		uint64_t en:8;
+	} s;
+	struct cvmx_agl_gmx_rxx_adr_cam_en_s cn52xx;
+	struct cvmx_agl_gmx_rxx_adr_cam_en_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_adr_cam_en_s cn56xx;
+	struct cvmx_agl_gmx_rxx_adr_cam_en_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_adr_ctl {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_adr_ctl_s {
+		uint64_t reserved_4_63:60;
+		uint64_t cam_mode:1;
+		uint64_t mcst:2;
+		uint64_t bcst:1;
+	} s;
+	struct cvmx_agl_gmx_rxx_adr_ctl_s cn52xx;
+	struct cvmx_agl_gmx_rxx_adr_ctl_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_adr_ctl_s cn56xx;
+	struct cvmx_agl_gmx_rxx_adr_ctl_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_decision {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_decision_s {
+		uint64_t reserved_5_63:59;
+		uint64_t cnt:5;
+	} s;
+	struct cvmx_agl_gmx_rxx_decision_s cn52xx;
+	struct cvmx_agl_gmx_rxx_decision_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_decision_s cn56xx;
+	struct cvmx_agl_gmx_rxx_decision_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_frm_chk {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_frm_chk_s {
+		uint64_t reserved_9_63:55;
+		uint64_t skperr:1;
+		uint64_t rcverr:1;
+		uint64_t lenerr:1;
+		uint64_t alnerr:1;
+		uint64_t fcserr:1;
+		uint64_t jabber:1;
+		uint64_t maxerr:1;
+		uint64_t reserved_1_1:1;
+		uint64_t minerr:1;
+	} s;
+	struct cvmx_agl_gmx_rxx_frm_chk_s cn52xx;
+	struct cvmx_agl_gmx_rxx_frm_chk_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_frm_chk_s cn56xx;
+	struct cvmx_agl_gmx_rxx_frm_chk_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_frm_ctl {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_frm_ctl_s {
+		uint64_t reserved_10_63:54;
+		uint64_t pre_align:1;
+		uint64_t pad_len:1;
+		uint64_t vlan_len:1;
+		uint64_t pre_free:1;
+		uint64_t ctl_smac:1;
+		uint64_t ctl_mcst:1;
+		uint64_t ctl_bck:1;
+		uint64_t ctl_drp:1;
+		uint64_t pre_strp:1;
+		uint64_t pre_chk:1;
+	} s;
+	struct cvmx_agl_gmx_rxx_frm_ctl_s cn52xx;
+	struct cvmx_agl_gmx_rxx_frm_ctl_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_frm_ctl_s cn56xx;
+	struct cvmx_agl_gmx_rxx_frm_ctl_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_frm_max {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_frm_max_s {
+		uint64_t reserved_16_63:48;
+		uint64_t len:16;
+	} s;
+	struct cvmx_agl_gmx_rxx_frm_max_s cn52xx;
+	struct cvmx_agl_gmx_rxx_frm_max_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_frm_max_s cn56xx;
+	struct cvmx_agl_gmx_rxx_frm_max_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_frm_min {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_frm_min_s {
+		uint64_t reserved_16_63:48;
+		uint64_t len:16;
+	} s;
+	struct cvmx_agl_gmx_rxx_frm_min_s cn52xx;
+	struct cvmx_agl_gmx_rxx_frm_min_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_frm_min_s cn56xx;
+	struct cvmx_agl_gmx_rxx_frm_min_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_ifg {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_ifg_s {
+		uint64_t reserved_4_63:60;
+		uint64_t ifg:4;
+	} s;
+	struct cvmx_agl_gmx_rxx_ifg_s cn52xx;
+	struct cvmx_agl_gmx_rxx_ifg_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_ifg_s cn56xx;
+	struct cvmx_agl_gmx_rxx_ifg_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_int_en {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_int_en_s {
+		uint64_t reserved_20_63:44;
+		uint64_t pause_drp:1;
+		uint64_t reserved_16_18:3;
+		uint64_t ifgerr:1;
+		uint64_t coldet:1;
+		uint64_t falerr:1;
+		uint64_t rsverr:1;
+		uint64_t pcterr:1;
+		uint64_t ovrerr:1;
+		uint64_t reserved_9_9:1;
+		uint64_t skperr:1;
+		uint64_t rcverr:1;
+		uint64_t lenerr:1;
+		uint64_t alnerr:1;
+		uint64_t fcserr:1;
+		uint64_t jabber:1;
+		uint64_t maxerr:1;
+		uint64_t reserved_1_1:1;
+		uint64_t minerr:1;
+	} s;
+	struct cvmx_agl_gmx_rxx_int_en_s cn52xx;
+	struct cvmx_agl_gmx_rxx_int_en_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_int_en_s cn56xx;
+	struct cvmx_agl_gmx_rxx_int_en_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_int_reg {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_int_reg_s {
+		uint64_t reserved_20_63:44;
+		uint64_t pause_drp:1;
+		uint64_t reserved_16_18:3;
+		uint64_t ifgerr:1;
+		uint64_t coldet:1;
+		uint64_t falerr:1;
+		uint64_t rsverr:1;
+		uint64_t pcterr:1;
+		uint64_t ovrerr:1;
+		uint64_t reserved_9_9:1;
+		uint64_t skperr:1;
+		uint64_t rcverr:1;
+		uint64_t lenerr:1;
+		uint64_t alnerr:1;
+		uint64_t fcserr:1;
+		uint64_t jabber:1;
+		uint64_t maxerr:1;
+		uint64_t reserved_1_1:1;
+		uint64_t minerr:1;
+	} s;
+	struct cvmx_agl_gmx_rxx_int_reg_s cn52xx;
+	struct cvmx_agl_gmx_rxx_int_reg_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_int_reg_s cn56xx;
+	struct cvmx_agl_gmx_rxx_int_reg_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_jabber {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_jabber_s {
+		uint64_t reserved_16_63:48;
+		uint64_t cnt:16;
+	} s;
+	struct cvmx_agl_gmx_rxx_jabber_s cn52xx;
+	struct cvmx_agl_gmx_rxx_jabber_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_jabber_s cn56xx;
+	struct cvmx_agl_gmx_rxx_jabber_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_pause_drop_time {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_pause_drop_time_s {
+		uint64_t reserved_16_63:48;
+		uint64_t status:16;
+	} s;
+	struct cvmx_agl_gmx_rxx_pause_drop_time_s cn52xx;
+	struct cvmx_agl_gmx_rxx_pause_drop_time_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_pause_drop_time_s cn56xx;
+	struct cvmx_agl_gmx_rxx_pause_drop_time_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_stats_ctl {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_stats_ctl_s {
+		uint64_t reserved_1_63:63;
+		uint64_t rd_clr:1;
+	} s;
+	struct cvmx_agl_gmx_rxx_stats_ctl_s cn52xx;
+	struct cvmx_agl_gmx_rxx_stats_ctl_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_stats_ctl_s cn56xx;
+	struct cvmx_agl_gmx_rxx_stats_ctl_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_stats_octs {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_stats_octs_s {
+		uint64_t reserved_48_63:16;
+		uint64_t cnt:48;
+	} s;
+	struct cvmx_agl_gmx_rxx_stats_octs_s cn52xx;
+	struct cvmx_agl_gmx_rxx_stats_octs_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_stats_octs_s cn56xx;
+	struct cvmx_agl_gmx_rxx_stats_octs_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_stats_octs_ctl {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_stats_octs_ctl_s {
+		uint64_t reserved_48_63:16;
+		uint64_t cnt:48;
+	} s;
+	struct cvmx_agl_gmx_rxx_stats_octs_ctl_s cn52xx;
+	struct cvmx_agl_gmx_rxx_stats_octs_ctl_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_stats_octs_ctl_s cn56xx;
+	struct cvmx_agl_gmx_rxx_stats_octs_ctl_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_stats_octs_dmac {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_stats_octs_dmac_s {
+		uint64_t reserved_48_63:16;
+		uint64_t cnt:48;
+	} s;
+	struct cvmx_agl_gmx_rxx_stats_octs_dmac_s cn52xx;
+	struct cvmx_agl_gmx_rxx_stats_octs_dmac_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_stats_octs_dmac_s cn56xx;
+	struct cvmx_agl_gmx_rxx_stats_octs_dmac_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_stats_octs_drp {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_stats_octs_drp_s {
+		uint64_t reserved_48_63:16;
+		uint64_t cnt:48;
+	} s;
+	struct cvmx_agl_gmx_rxx_stats_octs_drp_s cn52xx;
+	struct cvmx_agl_gmx_rxx_stats_octs_drp_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_stats_octs_drp_s cn56xx;
+	struct cvmx_agl_gmx_rxx_stats_octs_drp_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_stats_pkts {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_stats_pkts_s {
+		uint64_t reserved_32_63:32;
+		uint64_t cnt:32;
+	} s;
+	struct cvmx_agl_gmx_rxx_stats_pkts_s cn52xx;
+	struct cvmx_agl_gmx_rxx_stats_pkts_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_stats_pkts_s cn56xx;
+	struct cvmx_agl_gmx_rxx_stats_pkts_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_stats_pkts_bad {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_stats_pkts_bad_s {
+		uint64_t reserved_32_63:32;
+		uint64_t cnt:32;
+	} s;
+	struct cvmx_agl_gmx_rxx_stats_pkts_bad_s cn52xx;
+	struct cvmx_agl_gmx_rxx_stats_pkts_bad_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_stats_pkts_bad_s cn56xx;
+	struct cvmx_agl_gmx_rxx_stats_pkts_bad_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_stats_pkts_ctl {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_stats_pkts_ctl_s {
+		uint64_t reserved_32_63:32;
+		uint64_t cnt:32;
+	} s;
+	struct cvmx_agl_gmx_rxx_stats_pkts_ctl_s cn52xx;
+	struct cvmx_agl_gmx_rxx_stats_pkts_ctl_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_stats_pkts_ctl_s cn56xx;
+	struct cvmx_agl_gmx_rxx_stats_pkts_ctl_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_stats_pkts_dmac {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_stats_pkts_dmac_s {
+		uint64_t reserved_32_63:32;
+		uint64_t cnt:32;
+	} s;
+	struct cvmx_agl_gmx_rxx_stats_pkts_dmac_s cn52xx;
+	struct cvmx_agl_gmx_rxx_stats_pkts_dmac_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_stats_pkts_dmac_s cn56xx;
+	struct cvmx_agl_gmx_rxx_stats_pkts_dmac_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_stats_pkts_drp {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_stats_pkts_drp_s {
+		uint64_t reserved_32_63:32;
+		uint64_t cnt:32;
+	} s;
+	struct cvmx_agl_gmx_rxx_stats_pkts_drp_s cn52xx;
+	struct cvmx_agl_gmx_rxx_stats_pkts_drp_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_stats_pkts_drp_s cn56xx;
+	struct cvmx_agl_gmx_rxx_stats_pkts_drp_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rxx_udd_skp {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rxx_udd_skp_s {
+		uint64_t reserved_9_63:55;
+		uint64_t fcssel:1;
+		uint64_t reserved_7_7:1;
+		uint64_t len:7;
+	} s;
+	struct cvmx_agl_gmx_rxx_udd_skp_s cn52xx;
+	struct cvmx_agl_gmx_rxx_udd_skp_s cn52xxp1;
+	struct cvmx_agl_gmx_rxx_udd_skp_s cn56xx;
+	struct cvmx_agl_gmx_rxx_udd_skp_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rx_bp_dropx {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rx_bp_dropx_s {
+		uint64_t reserved_6_63:58;
+		uint64_t mark:6;
+	} s;
+	struct cvmx_agl_gmx_rx_bp_dropx_s cn52xx;
+	struct cvmx_agl_gmx_rx_bp_dropx_s cn52xxp1;
+	struct cvmx_agl_gmx_rx_bp_dropx_s cn56xx;
+	struct cvmx_agl_gmx_rx_bp_dropx_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rx_bp_offx {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rx_bp_offx_s {
+		uint64_t reserved_6_63:58;
+		uint64_t mark:6;
+	} s;
+	struct cvmx_agl_gmx_rx_bp_offx_s cn52xx;
+	struct cvmx_agl_gmx_rx_bp_offx_s cn52xxp1;
+	struct cvmx_agl_gmx_rx_bp_offx_s cn56xx;
+	struct cvmx_agl_gmx_rx_bp_offx_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rx_bp_onx {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rx_bp_onx_s {
+		uint64_t reserved_9_63:55;
+		uint64_t mark:9;
+	} s;
+	struct cvmx_agl_gmx_rx_bp_onx_s cn52xx;
+	struct cvmx_agl_gmx_rx_bp_onx_s cn52xxp1;
+	struct cvmx_agl_gmx_rx_bp_onx_s cn56xx;
+	struct cvmx_agl_gmx_rx_bp_onx_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_rx_prt_info {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rx_prt_info_s {
+		uint64_t reserved_18_63:46;
+		uint64_t drop:2;
+		uint64_t reserved_2_15:14;
+		uint64_t commit:2;
+	} s;
+	struct cvmx_agl_gmx_rx_prt_info_s cn52xx;
+	struct cvmx_agl_gmx_rx_prt_info_s cn52xxp1;
+	struct cvmx_agl_gmx_rx_prt_info_cn56xx {
+		uint64_t reserved_17_63:47;
+		uint64_t drop:1;
+		uint64_t reserved_1_15:15;
+		uint64_t commit:1;
+	} cn56xx;
+	struct cvmx_agl_gmx_rx_prt_info_cn56xx cn56xxp1;
+};
+
+union cvmx_agl_gmx_rx_tx_status {
+	uint64_t u64;
+	struct cvmx_agl_gmx_rx_tx_status_s {
+		uint64_t reserved_6_63:58;
+		uint64_t tx:2;
+		uint64_t reserved_2_3:2;
+		uint64_t rx:2;
+	} s;
+	struct cvmx_agl_gmx_rx_tx_status_s cn52xx;
+	struct cvmx_agl_gmx_rx_tx_status_s cn52xxp1;
+	struct cvmx_agl_gmx_rx_tx_status_cn56xx {
+		uint64_t reserved_5_63:59;
+		uint64_t tx:1;
+		uint64_t reserved_1_3:3;
+		uint64_t rx:1;
+	} cn56xx;
+	struct cvmx_agl_gmx_rx_tx_status_cn56xx cn56xxp1;
+};
+
+union cvmx_agl_gmx_smacx {
+	uint64_t u64;
+	struct cvmx_agl_gmx_smacx_s {
+		uint64_t reserved_48_63:16;
+		uint64_t smac:48;
+	} s;
+	struct cvmx_agl_gmx_smacx_s cn52xx;
+	struct cvmx_agl_gmx_smacx_s cn52xxp1;
+	struct cvmx_agl_gmx_smacx_s cn56xx;
+	struct cvmx_agl_gmx_smacx_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_stat_bp {
+	uint64_t u64;
+	struct cvmx_agl_gmx_stat_bp_s {
+		uint64_t reserved_17_63:47;
+		uint64_t bp:1;
+		uint64_t cnt:16;
+	} s;
+	struct cvmx_agl_gmx_stat_bp_s cn52xx;
+	struct cvmx_agl_gmx_stat_bp_s cn52xxp1;
+	struct cvmx_agl_gmx_stat_bp_s cn56xx;
+	struct cvmx_agl_gmx_stat_bp_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_append {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_append_s {
+		uint64_t reserved_4_63:60;
+		uint64_t force_fcs:1;
+		uint64_t fcs:1;
+		uint64_t pad:1;
+		uint64_t preamble:1;
+	} s;
+	struct cvmx_agl_gmx_txx_append_s cn52xx;
+	struct cvmx_agl_gmx_txx_append_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_append_s cn56xx;
+	struct cvmx_agl_gmx_txx_append_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_ctl {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_ctl_s {
+		uint64_t reserved_2_63:62;
+		uint64_t xsdef_en:1;
+		uint64_t xscol_en:1;
+	} s;
+	struct cvmx_agl_gmx_txx_ctl_s cn52xx;
+	struct cvmx_agl_gmx_txx_ctl_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_ctl_s cn56xx;
+	struct cvmx_agl_gmx_txx_ctl_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_min_pkt {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_min_pkt_s {
+		uint64_t reserved_8_63:56;
+		uint64_t min_size:8;
+	} s;
+	struct cvmx_agl_gmx_txx_min_pkt_s cn52xx;
+	struct cvmx_agl_gmx_txx_min_pkt_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_min_pkt_s cn56xx;
+	struct cvmx_agl_gmx_txx_min_pkt_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_pause_pkt_interval {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_pause_pkt_interval_s {
+		uint64_t reserved_16_63:48;
+		uint64_t interval:16;
+	} s;
+	struct cvmx_agl_gmx_txx_pause_pkt_interval_s cn52xx;
+	struct cvmx_agl_gmx_txx_pause_pkt_interval_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_pause_pkt_interval_s cn56xx;
+	struct cvmx_agl_gmx_txx_pause_pkt_interval_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_pause_pkt_time {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_pause_pkt_time_s {
+		uint64_t reserved_16_63:48;
+		uint64_t time:16;
+	} s;
+	struct cvmx_agl_gmx_txx_pause_pkt_time_s cn52xx;
+	struct cvmx_agl_gmx_txx_pause_pkt_time_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_pause_pkt_time_s cn56xx;
+	struct cvmx_agl_gmx_txx_pause_pkt_time_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_pause_togo {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_pause_togo_s {
+		uint64_t reserved_16_63:48;
+		uint64_t time:16;
+	} s;
+	struct cvmx_agl_gmx_txx_pause_togo_s cn52xx;
+	struct cvmx_agl_gmx_txx_pause_togo_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_pause_togo_s cn56xx;
+	struct cvmx_agl_gmx_txx_pause_togo_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_pause_zero {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_pause_zero_s {
+		uint64_t reserved_1_63:63;
+		uint64_t send:1;
+	} s;
+	struct cvmx_agl_gmx_txx_pause_zero_s cn52xx;
+	struct cvmx_agl_gmx_txx_pause_zero_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_pause_zero_s cn56xx;
+	struct cvmx_agl_gmx_txx_pause_zero_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_soft_pause {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_soft_pause_s {
+		uint64_t reserved_16_63:48;
+		uint64_t time:16;
+	} s;
+	struct cvmx_agl_gmx_txx_soft_pause_s cn52xx;
+	struct cvmx_agl_gmx_txx_soft_pause_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_soft_pause_s cn56xx;
+	struct cvmx_agl_gmx_txx_soft_pause_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_stat0 {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_stat0_s {
+		uint64_t xsdef:32;
+		uint64_t xscol:32;
+	} s;
+	struct cvmx_agl_gmx_txx_stat0_s cn52xx;
+	struct cvmx_agl_gmx_txx_stat0_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_stat0_s cn56xx;
+	struct cvmx_agl_gmx_txx_stat0_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_stat1 {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_stat1_s {
+		uint64_t scol:32;
+		uint64_t mcol:32;
+	} s;
+	struct cvmx_agl_gmx_txx_stat1_s cn52xx;
+	struct cvmx_agl_gmx_txx_stat1_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_stat1_s cn56xx;
+	struct cvmx_agl_gmx_txx_stat1_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_stat2 {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_stat2_s {
+		uint64_t reserved_48_63:16;
+		uint64_t octs:48;
+	} s;
+	struct cvmx_agl_gmx_txx_stat2_s cn52xx;
+	struct cvmx_agl_gmx_txx_stat2_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_stat2_s cn56xx;
+	struct cvmx_agl_gmx_txx_stat2_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_stat3 {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_stat3_s {
+		uint64_t reserved_32_63:32;
+		uint64_t pkts:32;
+	} s;
+	struct cvmx_agl_gmx_txx_stat3_s cn52xx;
+	struct cvmx_agl_gmx_txx_stat3_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_stat3_s cn56xx;
+	struct cvmx_agl_gmx_txx_stat3_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_stat4 {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_stat4_s {
+		uint64_t hist1:32;
+		uint64_t hist0:32;
+	} s;
+	struct cvmx_agl_gmx_txx_stat4_s cn52xx;
+	struct cvmx_agl_gmx_txx_stat4_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_stat4_s cn56xx;
+	struct cvmx_agl_gmx_txx_stat4_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_stat5 {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_stat5_s {
+		uint64_t hist3:32;
+		uint64_t hist2:32;
+	} s;
+	struct cvmx_agl_gmx_txx_stat5_s cn52xx;
+	struct cvmx_agl_gmx_txx_stat5_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_stat5_s cn56xx;
+	struct cvmx_agl_gmx_txx_stat5_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_stat6 {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_stat6_s {
+		uint64_t hist5:32;
+		uint64_t hist4:32;
+	} s;
+	struct cvmx_agl_gmx_txx_stat6_s cn52xx;
+	struct cvmx_agl_gmx_txx_stat6_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_stat6_s cn56xx;
+	struct cvmx_agl_gmx_txx_stat6_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_stat7 {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_stat7_s {
+		uint64_t hist7:32;
+		uint64_t hist6:32;
+	} s;
+	struct cvmx_agl_gmx_txx_stat7_s cn52xx;
+	struct cvmx_agl_gmx_txx_stat7_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_stat7_s cn56xx;
+	struct cvmx_agl_gmx_txx_stat7_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_stat8 {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_stat8_s {
+		uint64_t mcst:32;
+		uint64_t bcst:32;
+	} s;
+	struct cvmx_agl_gmx_txx_stat8_s cn52xx;
+	struct cvmx_agl_gmx_txx_stat8_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_stat8_s cn56xx;
+	struct cvmx_agl_gmx_txx_stat8_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_stat9 {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_stat9_s {
+		uint64_t undflw:32;
+		uint64_t ctl:32;
+	} s;
+	struct cvmx_agl_gmx_txx_stat9_s cn52xx;
+	struct cvmx_agl_gmx_txx_stat9_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_stat9_s cn56xx;
+	struct cvmx_agl_gmx_txx_stat9_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_stats_ctl {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_stats_ctl_s {
+		uint64_t reserved_1_63:63;
+		uint64_t rd_clr:1;
+	} s;
+	struct cvmx_agl_gmx_txx_stats_ctl_s cn52xx;
+	struct cvmx_agl_gmx_txx_stats_ctl_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_stats_ctl_s cn56xx;
+	struct cvmx_agl_gmx_txx_stats_ctl_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_txx_thresh {
+	uint64_t u64;
+	struct cvmx_agl_gmx_txx_thresh_s {
+		uint64_t reserved_6_63:58;
+		uint64_t cnt:6;
+	} s;
+	struct cvmx_agl_gmx_txx_thresh_s cn52xx;
+	struct cvmx_agl_gmx_txx_thresh_s cn52xxp1;
+	struct cvmx_agl_gmx_txx_thresh_s cn56xx;
+	struct cvmx_agl_gmx_txx_thresh_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_tx_bp {
+	uint64_t u64;
+	struct cvmx_agl_gmx_tx_bp_s {
+		uint64_t reserved_2_63:62;
+		uint64_t bp:2;
+	} s;
+	struct cvmx_agl_gmx_tx_bp_s cn52xx;
+	struct cvmx_agl_gmx_tx_bp_s cn52xxp1;
+	struct cvmx_agl_gmx_tx_bp_cn56xx {
+		uint64_t reserved_1_63:63;
+		uint64_t bp:1;
+	} cn56xx;
+	struct cvmx_agl_gmx_tx_bp_cn56xx cn56xxp1;
+};
+
+union cvmx_agl_gmx_tx_col_attempt {
+	uint64_t u64;
+	struct cvmx_agl_gmx_tx_col_attempt_s {
+		uint64_t reserved_5_63:59;
+		uint64_t limit:5;
+	} s;
+	struct cvmx_agl_gmx_tx_col_attempt_s cn52xx;
+	struct cvmx_agl_gmx_tx_col_attempt_s cn52xxp1;
+	struct cvmx_agl_gmx_tx_col_attempt_s cn56xx;
+	struct cvmx_agl_gmx_tx_col_attempt_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_tx_ifg {
+	uint64_t u64;
+	struct cvmx_agl_gmx_tx_ifg_s {
+		uint64_t reserved_8_63:56;
+		uint64_t ifg2:4;
+		uint64_t ifg1:4;
+	} s;
+	struct cvmx_agl_gmx_tx_ifg_s cn52xx;
+	struct cvmx_agl_gmx_tx_ifg_s cn52xxp1;
+	struct cvmx_agl_gmx_tx_ifg_s cn56xx;
+	struct cvmx_agl_gmx_tx_ifg_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_tx_int_en {
+	uint64_t u64;
+	struct cvmx_agl_gmx_tx_int_en_s {
+		uint64_t reserved_18_63:46;
+		uint64_t late_col:2;
+		uint64_t reserved_14_15:2;
+		uint64_t xsdef:2;
+		uint64_t reserved_10_11:2;
+		uint64_t xscol:2;
+		uint64_t reserved_4_7:4;
+		uint64_t undflw:2;
+		uint64_t reserved_1_1:1;
+		uint64_t pko_nxa:1;
+	} s;
+	struct cvmx_agl_gmx_tx_int_en_s cn52xx;
+	struct cvmx_agl_gmx_tx_int_en_s cn52xxp1;
+	struct cvmx_agl_gmx_tx_int_en_cn56xx {
+		uint64_t reserved_17_63:47;
+		uint64_t late_col:1;
+		uint64_t reserved_13_15:3;
+		uint64_t xsdef:1;
+		uint64_t reserved_9_11:3;
+		uint64_t xscol:1;
+		uint64_t reserved_3_7:5;
+		uint64_t undflw:1;
+		uint64_t reserved_1_1:1;
+		uint64_t pko_nxa:1;
+	} cn56xx;
+	struct cvmx_agl_gmx_tx_int_en_cn56xx cn56xxp1;
+};
+
+union cvmx_agl_gmx_tx_int_reg {
+	uint64_t u64;
+	struct cvmx_agl_gmx_tx_int_reg_s {
+		uint64_t reserved_18_63:46;
+		uint64_t late_col:2;
+		uint64_t reserved_14_15:2;
+		uint64_t xsdef:2;
+		uint64_t reserved_10_11:2;
+		uint64_t xscol:2;
+		uint64_t reserved_4_7:4;
+		uint64_t undflw:2;
+		uint64_t reserved_1_1:1;
+		uint64_t pko_nxa:1;
+	} s;
+	struct cvmx_agl_gmx_tx_int_reg_s cn52xx;
+	struct cvmx_agl_gmx_tx_int_reg_s cn52xxp1;
+	struct cvmx_agl_gmx_tx_int_reg_cn56xx {
+		uint64_t reserved_17_63:47;
+		uint64_t late_col:1;
+		uint64_t reserved_13_15:3;
+		uint64_t xsdef:1;
+		uint64_t reserved_9_11:3;
+		uint64_t xscol:1;
+		uint64_t reserved_3_7:5;
+		uint64_t undflw:1;
+		uint64_t reserved_1_1:1;
+		uint64_t pko_nxa:1;
+	} cn56xx;
+	struct cvmx_agl_gmx_tx_int_reg_cn56xx cn56xxp1;
+};
+
+union cvmx_agl_gmx_tx_jam {
+	uint64_t u64;
+	struct cvmx_agl_gmx_tx_jam_s {
+		uint64_t reserved_8_63:56;
+		uint64_t jam:8;
+	} s;
+	struct cvmx_agl_gmx_tx_jam_s cn52xx;
+	struct cvmx_agl_gmx_tx_jam_s cn52xxp1;
+	struct cvmx_agl_gmx_tx_jam_s cn56xx;
+	struct cvmx_agl_gmx_tx_jam_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_tx_lfsr {
+	uint64_t u64;
+	struct cvmx_agl_gmx_tx_lfsr_s {
+		uint64_t reserved_16_63:48;
+		uint64_t lfsr:16;
+	} s;
+	struct cvmx_agl_gmx_tx_lfsr_s cn52xx;
+	struct cvmx_agl_gmx_tx_lfsr_s cn52xxp1;
+	struct cvmx_agl_gmx_tx_lfsr_s cn56xx;
+	struct cvmx_agl_gmx_tx_lfsr_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_tx_ovr_bp {
+	uint64_t u64;
+	struct cvmx_agl_gmx_tx_ovr_bp_s {
+		uint64_t reserved_10_63:54;
+		uint64_t en:2;
+		uint64_t reserved_6_7:2;
+		uint64_t bp:2;
+		uint64_t reserved_2_3:2;
+		uint64_t ign_full:2;
+	} s;
+	struct cvmx_agl_gmx_tx_ovr_bp_s cn52xx;
+	struct cvmx_agl_gmx_tx_ovr_bp_s cn52xxp1;
+	struct cvmx_agl_gmx_tx_ovr_bp_cn56xx {
+		uint64_t reserved_9_63:55;
+		uint64_t en:1;
+		uint64_t reserved_5_7:3;
+		uint64_t bp:1;
+		uint64_t reserved_1_3:3;
+		uint64_t ign_full:1;
+	} cn56xx;
+	struct cvmx_agl_gmx_tx_ovr_bp_cn56xx cn56xxp1;
+};
+
+union cvmx_agl_gmx_tx_pause_pkt_dmac {
+	uint64_t u64;
+	struct cvmx_agl_gmx_tx_pause_pkt_dmac_s {
+		uint64_t reserved_48_63:16;
+		uint64_t dmac:48;
+	} s;
+	struct cvmx_agl_gmx_tx_pause_pkt_dmac_s cn52xx;
+	struct cvmx_agl_gmx_tx_pause_pkt_dmac_s cn52xxp1;
+	struct cvmx_agl_gmx_tx_pause_pkt_dmac_s cn56xx;
+	struct cvmx_agl_gmx_tx_pause_pkt_dmac_s cn56xxp1;
+};
+
+union cvmx_agl_gmx_tx_pause_pkt_type {
+	uint64_t u64;
+	struct cvmx_agl_gmx_tx_pause_pkt_type_s {
+		uint64_t reserved_16_63:48;
+		uint64_t type:16;
+	} s;
+	struct cvmx_agl_gmx_tx_pause_pkt_type_s cn52xx;
+	struct cvmx_agl_gmx_tx_pause_pkt_type_s cn52xxp1;
+	struct cvmx_agl_gmx_tx_pause_pkt_type_s cn56xx;
+	struct cvmx_agl_gmx_tx_pause_pkt_type_s cn56xxp1;
+};
+
+#endif
diff --git a/arch/mips/include/asm/octeon/cvmx-mixx-defs.h b/arch/mips/include/asm/octeon/cvmx-mixx-defs.h
new file mode 100644
index 0000000..dab6dca
--- /dev/null
+++ b/arch/mips/include/asm/octeon/cvmx-mixx-defs.h
@@ -0,0 +1,248 @@
+/***********************license start***************
+ * Author: Cavium Networks
+ *
+ * Contact: support@caviumnetworks.com
+ * This file is part of the OCTEON SDK
+ *
+ * Copyright (c) 2003-2008 Cavium Networks
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * or visit http://www.gnu.org/licenses/.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium Networks for more information
+ ***********************license end**************************************/
+
+#ifndef __CVMX_MIXX_DEFS_H__
+#define __CVMX_MIXX_DEFS_H__
+
+#define CVMX_MIXX_BIST(offset) \
+	 CVMX_ADD_IO_SEG(0x0001070000100078ull + (((offset) & 1) * 2048))
+#define CVMX_MIXX_CTL(offset) \
+	 CVMX_ADD_IO_SEG(0x0001070000100020ull + (((offset) & 1) * 2048))
+#define CVMX_MIXX_INTENA(offset) \
+	 CVMX_ADD_IO_SEG(0x0001070000100050ull + (((offset) & 1) * 2048))
+#define CVMX_MIXX_IRCNT(offset) \
+	 CVMX_ADD_IO_SEG(0x0001070000100030ull + (((offset) & 1) * 2048))
+#define CVMX_MIXX_IRHWM(offset) \
+	 CVMX_ADD_IO_SEG(0x0001070000100028ull + (((offset) & 1) * 2048))
+#define CVMX_MIXX_IRING1(offset) \
+	 CVMX_ADD_IO_SEG(0x0001070000100010ull + (((offset) & 1) * 2048))
+#define CVMX_MIXX_IRING2(offset) \
+	 CVMX_ADD_IO_SEG(0x0001070000100018ull + (((offset) & 1) * 2048))
+#define CVMX_MIXX_ISR(offset) \
+	 CVMX_ADD_IO_SEG(0x0001070000100048ull + (((offset) & 1) * 2048))
+#define CVMX_MIXX_ORCNT(offset) \
+	 CVMX_ADD_IO_SEG(0x0001070000100040ull + (((offset) & 1) * 2048))
+#define CVMX_MIXX_ORHWM(offset) \
+	 CVMX_ADD_IO_SEG(0x0001070000100038ull + (((offset) & 1) * 2048))
+#define CVMX_MIXX_ORING1(offset) \
+	 CVMX_ADD_IO_SEG(0x0001070000100000ull + (((offset) & 1) * 2048))
+#define CVMX_MIXX_ORING2(offset) \
+	 CVMX_ADD_IO_SEG(0x0001070000100008ull + (((offset) & 1) * 2048))
+#define CVMX_MIXX_REMCNT(offset) \
+	 CVMX_ADD_IO_SEG(0x0001070000100058ull + (((offset) & 1) * 2048))
+
+union cvmx_mixx_bist {
+	uint64_t u64;
+	struct cvmx_mixx_bist_s {
+		uint64_t reserved_4_63:60;
+		uint64_t mrqdat:1;
+		uint64_t ipfdat:1;
+		uint64_t irfdat:1;
+		uint64_t orfdat:1;
+	} s;
+	struct cvmx_mixx_bist_s cn52xx;
+	struct cvmx_mixx_bist_s cn52xxp1;
+	struct cvmx_mixx_bist_s cn56xx;
+	struct cvmx_mixx_bist_s cn56xxp1;
+};
+
+union cvmx_mixx_ctl {
+	uint64_t u64;
+	struct cvmx_mixx_ctl_s {
+		uint64_t reserved_8_63:56;
+		uint64_t crc_strip:1;
+		uint64_t busy:1;
+		uint64_t en:1;
+		uint64_t reset:1;
+		uint64_t lendian:1;
+		uint64_t nbtarb:1;
+		uint64_t mrq_hwm:2;
+	} s;
+	struct cvmx_mixx_ctl_s cn52xx;
+	struct cvmx_mixx_ctl_s cn52xxp1;
+	struct cvmx_mixx_ctl_s cn56xx;
+	struct cvmx_mixx_ctl_s cn56xxp1;
+};
+
+union cvmx_mixx_intena {
+	uint64_t u64;
+	struct cvmx_mixx_intena_s {
+		uint64_t reserved_7_63:57;
+		uint64_t orunena:1;
+		uint64_t irunena:1;
+		uint64_t data_drpena:1;
+		uint64_t ithena:1;
+		uint64_t othena:1;
+		uint64_t ivfena:1;
+		uint64_t ovfena:1;
+	} s;
+	struct cvmx_mixx_intena_s cn52xx;
+	struct cvmx_mixx_intena_s cn52xxp1;
+	struct cvmx_mixx_intena_s cn56xx;
+	struct cvmx_mixx_intena_s cn56xxp1;
+};
+
+union cvmx_mixx_ircnt {
+	uint64_t u64;
+	struct cvmx_mixx_ircnt_s {
+		uint64_t reserved_20_63:44;
+		uint64_t ircnt:20;
+	} s;
+	struct cvmx_mixx_ircnt_s cn52xx;
+	struct cvmx_mixx_ircnt_s cn52xxp1;
+	struct cvmx_mixx_ircnt_s cn56xx;
+	struct cvmx_mixx_ircnt_s cn56xxp1;
+};
+
+union cvmx_mixx_irhwm {
+	uint64_t u64;
+	struct cvmx_mixx_irhwm_s {
+		uint64_t reserved_40_63:24;
+		uint64_t ibplwm:20;
+		uint64_t irhwm:20;
+	} s;
+	struct cvmx_mixx_irhwm_s cn52xx;
+	struct cvmx_mixx_irhwm_s cn52xxp1;
+	struct cvmx_mixx_irhwm_s cn56xx;
+	struct cvmx_mixx_irhwm_s cn56xxp1;
+};
+
+union cvmx_mixx_iring1 {
+	uint64_t u64;
+	struct cvmx_mixx_iring1_s {
+		uint64_t reserved_60_63:4;
+		uint64_t isize:20;
+		uint64_t reserved_36_39:4;
+		uint64_t ibase:33;
+		uint64_t reserved_0_2:3;
+	} s;
+	struct cvmx_mixx_iring1_s cn52xx;
+	struct cvmx_mixx_iring1_s cn52xxp1;
+	struct cvmx_mixx_iring1_s cn56xx;
+	struct cvmx_mixx_iring1_s cn56xxp1;
+};
+
+union cvmx_mixx_iring2 {
+	uint64_t u64;
+	struct cvmx_mixx_iring2_s {
+		uint64_t reserved_52_63:12;
+		uint64_t itlptr:20;
+		uint64_t reserved_20_31:12;
+		uint64_t idbell:20;
+	} s;
+	struct cvmx_mixx_iring2_s cn52xx;
+	struct cvmx_mixx_iring2_s cn52xxp1;
+	struct cvmx_mixx_iring2_s cn56xx;
+	struct cvmx_mixx_iring2_s cn56xxp1;
+};
+
+union cvmx_mixx_isr {
+	uint64_t u64;
+	struct cvmx_mixx_isr_s {
+		uint64_t reserved_7_63:57;
+		uint64_t orun:1;
+		uint64_t irun:1;
+		uint64_t data_drp:1;
+		uint64_t irthresh:1;
+		uint64_t orthresh:1;
+		uint64_t idblovf:1;
+		uint64_t odblovf:1;
+	} s;
+	struct cvmx_mixx_isr_s cn52xx;
+	struct cvmx_mixx_isr_s cn52xxp1;
+	struct cvmx_mixx_isr_s cn56xx;
+	struct cvmx_mixx_isr_s cn56xxp1;
+};
+
+union cvmx_mixx_orcnt {
+	uint64_t u64;
+	struct cvmx_mixx_orcnt_s {
+		uint64_t reserved_20_63:44;
+		uint64_t orcnt:20;
+	} s;
+	struct cvmx_mixx_orcnt_s cn52xx;
+	struct cvmx_mixx_orcnt_s cn52xxp1;
+	struct cvmx_mixx_orcnt_s cn56xx;
+	struct cvmx_mixx_orcnt_s cn56xxp1;
+};
+
+union cvmx_mixx_orhwm {
+	uint64_t u64;
+	struct cvmx_mixx_orhwm_s {
+		uint64_t reserved_20_63:44;
+		uint64_t orhwm:20;
+	} s;
+	struct cvmx_mixx_orhwm_s cn52xx;
+	struct cvmx_mixx_orhwm_s cn52xxp1;
+	struct cvmx_mixx_orhwm_s cn56xx;
+	struct cvmx_mixx_orhwm_s cn56xxp1;
+};
+
+union cvmx_mixx_oring1 {
+	uint64_t u64;
+	struct cvmx_mixx_oring1_s {
+		uint64_t reserved_60_63:4;
+		uint64_t osize:20;
+		uint64_t reserved_36_39:4;
+		uint64_t obase:33;
+		uint64_t reserved_0_2:3;
+	} s;
+	struct cvmx_mixx_oring1_s cn52xx;
+	struct cvmx_mixx_oring1_s cn52xxp1;
+	struct cvmx_mixx_oring1_s cn56xx;
+	struct cvmx_mixx_oring1_s cn56xxp1;
+};
+
+union cvmx_mixx_oring2 {
+	uint64_t u64;
+	struct cvmx_mixx_oring2_s {
+		uint64_t reserved_52_63:12;
+		uint64_t otlptr:20;
+		uint64_t reserved_20_31:12;
+		uint64_t odbell:20;
+	} s;
+	struct cvmx_mixx_oring2_s cn52xx;
+	struct cvmx_mixx_oring2_s cn52xxp1;
+	struct cvmx_mixx_oring2_s cn56xx;
+	struct cvmx_mixx_oring2_s cn56xxp1;
+};
+
+union cvmx_mixx_remcnt {
+	uint64_t u64;
+	struct cvmx_mixx_remcnt_s {
+		uint64_t reserved_52_63:12;
+		uint64_t iremcnt:20;
+		uint64_t reserved_20_31:12;
+		uint64_t oremcnt:20;
+	} s;
+	struct cvmx_mixx_remcnt_s cn52xx;
+	struct cvmx_mixx_remcnt_s cn52xxp1;
+	struct cvmx_mixx_remcnt_s cn56xx;
+	struct cvmx_mixx_remcnt_s cn56xxp1;
+};
+
+#endif
-- 
1.6.0.6


From David.Daney@caviumnetworks.com Thu Oct  8 01:11:36 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 01:11:44 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:16109 "EHLO
	mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S2097321AbZJGXKZ (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 01:10:25 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,5,4,7535)
	id <B4acd1fdb0001>; Wed, 07 Oct 2009 16:10:19 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 16:10:22 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 16:10:22 -0700
Received: from dd1.caveonetworks.com (localhost.localdomain [127.0.0.1])
	by dd1.caveonetworks.com (8.14.2/8.14.2) with ESMTP id n97NAHwN007678;
	Wed, 7 Oct 2009 16:10:17 -0700
Received: (from ddaney@localhost)
	by dd1.caveonetworks.com (8.14.2/8.14.2/Submit) id n97NAHsh007677;
	Wed, 7 Oct 2009 16:10:17 -0700
From:	David Daney <ddaney@caviumnetworks.com>
To:	ralf@linux-mips.org, linux-mips@linux-mips.org,
	netdev@vger.kernel.org
Cc:	David Daney <ddaney@caviumnetworks.com>
Subject: [PATCH 6/6] Staging: octeon-ethernet: Convert to use PHY Abstraction Layer.
Date:	Wed,  7 Oct 2009 16:10:15 -0700
Message-Id: <1254957015-7633-6-git-send-email-ddaney@caviumnetworks.com>
X-Mailer: git-send-email 1.6.0.6
In-Reply-To: <4ACD1F4E.8090603@caviumnetworks.com>
References: <4ACD1F4E.8090603@caviumnetworks.com>
X-OriginalArrivalTime: 07 Oct 2009 23:10:22.0387 (UTC) FILETIME=[58859030:01CA47A3]
Return-Path: <David.Daney@caviumnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24168
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ddaney@caviumnetworks.com
Precedence: bulk
X-list: linux-mips

The octeon-ethernet driver shares an mdio bus with the octeon-mgmt
driver.  Here we convert the octeon-ethernet driver to use the PHY
Abstraction Layer.  The allocation of MAC addresses is also fixed so
that there is not duplication with the MAC addresses used by
octeon-mgmt, and it is consistent with the bootloader.

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---
 drivers/staging/octeon/Kconfig           |    3 +-
 drivers/staging/octeon/ethernet-mdio.c   |  198 +++++++++++-------------------
 drivers/staging/octeon/ethernet-mdio.h   |    2 +-
 drivers/staging/octeon/ethernet-proc.c   |  112 -----------------
 drivers/staging/octeon/ethernet-rgmii.c  |   52 ++++----
 drivers/staging/octeon/ethernet-sgmii.c  |    2 +-
 drivers/staging/octeon/ethernet-xaui.c   |    2 +-
 drivers/staging/octeon/ethernet.c        |   68 +++++++----
 drivers/staging/octeon/octeon-ethernet.h |   15 ++-
 9 files changed, 161 insertions(+), 293 deletions(-)

diff --git a/drivers/staging/octeon/Kconfig b/drivers/staging/octeon/Kconfig
index 536e238..638ad6b 100644
--- a/drivers/staging/octeon/Kconfig
+++ b/drivers/staging/octeon/Kconfig
@@ -1,7 +1,8 @@
 config OCTEON_ETHERNET
 	tristate "Cavium Networks Octeon Ethernet support"
 	depends on CPU_CAVIUM_OCTEON
-	select MII
+	select PHYLIB
+	select MDIO_OCTEON
 	help
 	  This driver supports the builtin ethernet ports on Cavium
 	  Networks' products in the Octeon family. This driver supports the
diff --git a/drivers/staging/octeon/ethernet-mdio.c b/drivers/staging/octeon/ethernet-mdio.c
index 31a58e5..507ca32 100644
--- a/drivers/staging/octeon/ethernet-mdio.c
+++ b/drivers/staging/octeon/ethernet-mdio.c
@@ -26,7 +26,8 @@
 **********************************************************************/
 #include <linux/kernel.h>
 #include <linux/ethtool.h>
-#include <linux/mii.h>
+#include <linux/phy.h>
+
 #include <net/dst.h>
 
 #include <asm/octeon/octeon.h>
@@ -34,86 +35,12 @@
 #include "ethernet-defines.h"
 #include "octeon-ethernet.h"
 #include "ethernet-mdio.h"
+#include "ethernet-util.h"
 
 #include "cvmx-helper-board.h"
 
 #include "cvmx-smix-defs.h"
 
-DECLARE_MUTEX(mdio_sem);
-
-/**
- * Perform an MII read. Called by the generic MII routines
- *
- * @dev:      Device to perform read for
- * @phy_id:   The MII phy id
- * @location: Register location to read
- * Returns Result from the read or zero on failure
- */
-static int cvm_oct_mdio_read(struct net_device *dev, int phy_id, int location)
-{
-	union cvmx_smix_cmd smi_cmd;
-	union cvmx_smix_rd_dat smi_rd;
-
-	smi_cmd.u64 = 0;
-	smi_cmd.s.phy_op = 1;
-	smi_cmd.s.phy_adr = phy_id;
-	smi_cmd.s.reg_adr = location;
-	cvmx_write_csr(CVMX_SMIX_CMD(0), smi_cmd.u64);
-
-	do {
-		if (!in_interrupt())
-			yield();
-		smi_rd.u64 = cvmx_read_csr(CVMX_SMIX_RD_DAT(0));
-	} while (smi_rd.s.pending);
-
-	if (smi_rd.s.val)
-		return smi_rd.s.dat;
-	else
-		return 0;
-}
-
-static int cvm_oct_mdio_dummy_read(struct net_device *dev, int phy_id,
-				   int location)
-{
-	return 0xffff;
-}
-
-/**
- * Perform an MII write. Called by the generic MII routines
- *
- * @dev:      Device to perform write for
- * @phy_id:   The MII phy id
- * @location: Register location to write
- * @val:      Value to write
- */
-static void cvm_oct_mdio_write(struct net_device *dev, int phy_id, int location,
-			       int val)
-{
-	union cvmx_smix_cmd smi_cmd;
-	union cvmx_smix_wr_dat smi_wr;
-
-	smi_wr.u64 = 0;
-	smi_wr.s.dat = val;
-	cvmx_write_csr(CVMX_SMIX_WR_DAT(0), smi_wr.u64);
-
-	smi_cmd.u64 = 0;
-	smi_cmd.s.phy_op = 0;
-	smi_cmd.s.phy_adr = phy_id;
-	smi_cmd.s.reg_adr = location;
-	cvmx_write_csr(CVMX_SMIX_CMD(0), smi_cmd.u64);
-
-	do {
-		if (!in_interrupt())
-			yield();
-		smi_wr.u64 = cvmx_read_csr(CVMX_SMIX_WR_DAT(0));
-	} while (smi_wr.s.pending);
-}
-
-static void cvm_oct_mdio_dummy_write(struct net_device *dev, int phy_id,
-				     int location, int val)
-{
-}
-
 static void cvm_oct_get_drvinfo(struct net_device *dev,
 				struct ethtool_drvinfo *info)
 {
@@ -125,49 +52,37 @@ static void cvm_oct_get_drvinfo(struct net_device *dev,
 static int cvm_oct_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct octeon_ethernet *priv = netdev_priv(dev);
-	int ret;
 
-	down(&mdio_sem);
-	ret = mii_ethtool_gset(&priv->mii_info, cmd);
-	up(&mdio_sem);
+	if (priv->phydev)
+		return phy_ethtool_gset(priv->phydev, cmd);
 
-	return ret;
+	return -EINVAL;
 }
 
 static int cvm_oct_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct octeon_ethernet *priv = netdev_priv(dev);
-	int ret;
 
-	down(&mdio_sem);
-	ret = mii_ethtool_sset(&priv->mii_info, cmd);
-	up(&mdio_sem);
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (priv->phydev)
+		return phy_ethtool_sset(priv->phydev, cmd);
 
-	return ret;
+	return -EINVAL;
 }
 
 static int cvm_oct_nway_reset(struct net_device *dev)
 {
 	struct octeon_ethernet *priv = netdev_priv(dev);
-	int ret;
-
-	down(&mdio_sem);
-	ret = mii_nway_restart(&priv->mii_info);
-	up(&mdio_sem);
-
-	return ret;
-}
 
-static u32 cvm_oct_get_link(struct net_device *dev)
-{
-	struct octeon_ethernet *priv = netdev_priv(dev);
-	u32 ret;
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
 
-	down(&mdio_sem);
-	ret = mii_link_ok(&priv->mii_info);
-	up(&mdio_sem);
+	if (priv->phydev)
+		return phy_start_aneg(priv->phydev);
 
-	return ret;
+	return -EINVAL;
 }
 
 const struct ethtool_ops cvm_oct_ethtool_ops = {
@@ -175,7 +90,7 @@ const struct ethtool_ops cvm_oct_ethtool_ops = {
 	.get_settings = cvm_oct_get_settings,
 	.set_settings = cvm_oct_set_settings,
 	.nway_reset = cvm_oct_nway_reset,
-	.get_link = cvm_oct_get_link,
+	.get_link = ethtool_op_get_link,
 	.get_sg = ethtool_op_get_sg,
 	.get_tx_csum = ethtool_op_get_tx_csum,
 };
@@ -191,41 +106,72 @@ const struct ethtool_ops cvm_oct_ethtool_ops = {
 int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct octeon_ethernet *priv = netdev_priv(dev);
-	struct mii_ioctl_data *data = if_mii(rq);
-	unsigned int duplex_chg;
-	int ret;
 
-	down(&mdio_sem);
-	ret = generic_mii_ioctl(&priv->mii_info, data, cmd, &duplex_chg);
-	up(&mdio_sem);
+	if (!netif_running(dev))
+		return -EINVAL;
+
+	if (!priv->phydev)
+		return -EINVAL;
 
-	return ret;
+	return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
 }
 
+static void cvm_oct_adjust_link(struct net_device *dev)
+{
+	struct octeon_ethernet *priv = netdev_priv(dev);
+
+	if (priv->last_link != priv->phydev->link) {
+		priv->last_link = priv->phydev->link;
+		if (priv->last_link) {
+			netif_carrier_on(dev);
+			if (priv->queue != -1)
+				DEBUGPRINT("%s: %u Mbps %s duplex, "
+					   "port %2d, queue %2d\n",
+					   dev->name, priv->phydev->speed,
+					   priv->phydev->duplex ?
+						"Full" : "Half",
+					   priv->port, priv->queue);
+			else
+				DEBUGPRINT("%s: %u Mbps %s duplex, "
+					   "port %2d, POW\n",
+					   dev->name, priv->phydev->speed,
+					   priv->phydev->duplex ?
+						"Full" : "Half",
+					   priv->port);
+		} else {
+			netif_carrier_off(dev);
+			DEBUGPRINT("%s: Link down\n", dev->name);
+		}
+	}
+}
+
+
 /**
- * Setup the MDIO device structures
+ * Setup the PHY
  *
  * @dev:    Device to setup
  *
  * Returns Zero on success, negative on failure
  */
-int cvm_oct_mdio_setup_device(struct net_device *dev)
+int cvm_oct_phy_setup_device(struct net_device *dev)
 {
 	struct octeon_ethernet *priv = netdev_priv(dev);
-	int phy_id = cvmx_helper_board_get_mii_address(priv->port);
-	if (phy_id != -1) {
-		priv->mii_info.dev = dev;
-		priv->mii_info.phy_id = phy_id;
-		priv->mii_info.phy_id_mask = 0xff;
-		priv->mii_info.supports_gmii = 1;
-		priv->mii_info.reg_num_mask = 0x1f;
-		priv->mii_info.mdio_read = cvm_oct_mdio_read;
-		priv->mii_info.mdio_write = cvm_oct_mdio_write;
-	} else {
-		/* Supply dummy MDIO routines so the kernel won't crash
-		   if the user tries to read them */
-		priv->mii_info.mdio_read = cvm_oct_mdio_dummy_read;
-		priv->mii_info.mdio_write = cvm_oct_mdio_dummy_write;
+
+	int phy_addr = cvmx_helper_board_get_mii_address(priv->port);
+	if (phy_addr != -1) {
+		char phy_id[20];
+
+		snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "0", phy_addr);
+
+		priv->phydev = phy_connect(dev, phy_id, cvm_oct_adjust_link, 0,
+					PHY_INTERFACE_MODE_GMII);
+
+		if (IS_ERR(priv->phydev)) {
+			priv->phydev = NULL;
+			return -1;
+		}
+		priv->last_link = 0;
+		phy_start_aneg(priv->phydev);
 	}
 	return 0;
 }
diff --git a/drivers/staging/octeon/ethernet-mdio.h b/drivers/staging/octeon/ethernet-mdio.h
index b3328ae..55d0614 100644
--- a/drivers/staging/octeon/ethernet-mdio.h
+++ b/drivers/staging/octeon/ethernet-mdio.h
@@ -43,4 +43,4 @@
 
 extern const struct ethtool_ops cvm_oct_ethtool_ops;
 int cvm_oct_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-int cvm_oct_mdio_setup_device(struct net_device *dev);
+int cvm_oct_phy_setup_device(struct net_device *dev);
diff --git a/drivers/staging/octeon/ethernet-proc.c b/drivers/staging/octeon/ethernet-proc.c
index 8fa88fc..16308d4 100644
--- a/drivers/staging/octeon/ethernet-proc.c
+++ b/drivers/staging/octeon/ethernet-proc.c
@@ -25,7 +25,6 @@
  * Contact Cavium Networks for more information
 **********************************************************************/
 #include <linux/kernel.h>
-#include <linux/mii.h>
 #include <linux/seq_file.h>
 #include <linux/proc_fs.h>
 #include <net/dst.h>
@@ -38,112 +37,6 @@
 #include "cvmx-helper.h"
 #include "cvmx-pip.h"
 
-static unsigned long long cvm_oct_stats_read_switch(struct net_device *dev,
-						    int phy_id, int offset)
-{
-	struct octeon_ethernet *priv = netdev_priv(dev);
-
-	priv->mii_info.mdio_write(dev, phy_id, 0x1d, 0xcc00 | offset);
-	return ((uint64_t) priv->mii_info.
-		mdio_read(dev, phy_id,
-			  0x1e) << 16) | (uint64_t) priv->mii_info.
-	    mdio_read(dev, phy_id, 0x1f);
-}
-
-static int cvm_oct_stats_switch_show(struct seq_file *m, void *v)
-{
-	static const int ports[] = { 0, 1, 2, 3, 9, -1 };
-	struct net_device *dev = cvm_oct_device[0];
-	int index = 0;
-
-	while (ports[index] != -1) {
-
-		/* Latch port */
-		struct octeon_ethernet *priv = netdev_priv(dev);
-
-		priv->mii_info.mdio_write(dev, 0x1b, 0x1d,
-					  0xdc00 | ports[index]);
-		seq_printf(m, "\nSwitch Port %d\n", ports[index]);
-		seq_printf(m, "InGoodOctets:   %12llu\t"
-			   "OutOctets:      %12llu\t"
-			   "64 Octets:      %12llu\n",
-			   cvm_oct_stats_read_switch(dev, 0x1b,
-						     0x00) |
-			   (cvm_oct_stats_read_switch(dev, 0x1b, 0x01) << 32),
-			   cvm_oct_stats_read_switch(dev, 0x1b,
-						     0x0E) |
-			   (cvm_oct_stats_read_switch(dev, 0x1b, 0x0F) << 32),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x08));
-
-		seq_printf(m, "InBadOctets:    %12llu\t"
-			   "OutUnicast:     %12llu\t"
-			   "65-127 Octets:  %12llu\n",
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x02),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x10),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x09));
-
-		seq_printf(m, "InUnicast:      %12llu\t"
-			   "OutBroadcasts:  %12llu\t"
-			   "128-255 Octets: %12llu\n",
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x04),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x13),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x0A));
-
-		seq_printf(m, "InBroadcasts:   %12llu\t"
-			   "OutMulticasts:  %12llu\t"
-			   "256-511 Octets: %12llu\n",
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x06),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x12),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x0B));
-
-		seq_printf(m, "InMulticasts:   %12llu\t"
-			   "OutPause:       %12llu\t"
-			   "512-1023 Octets:%12llu\n",
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x07),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x15),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x0C));
-
-		seq_printf(m, "InPause:        %12llu\t"
-			   "Excessive:      %12llu\t"
-			   "1024-Max Octets:%12llu\n",
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x16),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x11),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x0D));
-
-		seq_printf(m, "InUndersize:    %12llu\t"
-			   "Collisions:     %12llu\n",
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x18),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x1E));
-
-		seq_printf(m, "InFragments:    %12llu\t"
-			   "Deferred:       %12llu\n",
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x19),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x05));
-
-		seq_printf(m, "InOversize:     %12llu\t"
-			   "Single:         %12llu\n",
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x1A),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x14));
-
-		seq_printf(m, "InJabber:       %12llu\t"
-			   "Multiple:       %12llu\n",
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x1B),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x17));
-
-		seq_printf(m, "In RxErr:       %12llu\t"
-			   "OutFCSErr:      %12llu\n",
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x1C),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x03));
-
-		seq_printf(m, "InFCSErr:       %12llu\t"
-			   "Late:           %12llu\n",
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x1D),
-			   cvm_oct_stats_read_switch(dev, 0x1b, 0x1F));
-		index++;
-	}
-	return 0;
-}
-
 /**
  * User is reading /proc/octeon_ethernet_stats
  *
@@ -215,11 +108,6 @@ static int cvm_oct_stats_show(struct seq_file *m, void *v)
 		}
 	}
 
-	if (cvm_oct_device[0]) {
-		priv = netdev_priv(cvm_oct_device[0]);
-		if (priv->imode == CVMX_HELPER_INTERFACE_MODE_GMII)
-			cvm_oct_stats_switch_show(m, v);
-	}
 	return 0;
 }
 
diff --git a/drivers/staging/octeon/ethernet-rgmii.c b/drivers/staging/octeon/ethernet-rgmii.c
index 8704133..d238611 100644
--- a/drivers/staging/octeon/ethernet-rgmii.c
+++ b/drivers/staging/octeon/ethernet-rgmii.c
@@ -147,32 +147,36 @@ static void cvm_oct_rgmii_poll(struct net_device *dev)
 		cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, interface),
 			       gmxx_rxx_int_reg.u64);
 	}
-
-	link_info = cvmx_helper_link_autoconf(priv->port);
-	priv->link_info = link_info.u64;
+	if (priv->phydev == NULL) {
+		link_info = cvmx_helper_link_autoconf(priv->port);
+		priv->link_info = link_info.u64;
+	}
 	spin_unlock_irqrestore(&global_register_lock, flags);
 
-	/* Tell Linux */
-	if (link_info.s.link_up) {
-
-		if (!netif_carrier_ok(dev))
-			netif_carrier_on(dev);
-		if (priv->queue != -1)
-			DEBUGPRINT
-			    ("%s: %u Mbps %s duplex, port %2d, queue %2d\n",
-			     dev->name, link_info.s.speed,
-			     (link_info.s.full_duplex) ? "Full" : "Half",
-			     priv->port, priv->queue);
-		else
-			DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, POW\n",
-				   dev->name, link_info.s.speed,
-				   (link_info.s.full_duplex) ? "Full" : "Half",
-				   priv->port);
-	} else {
-
-		if (netif_carrier_ok(dev))
-			netif_carrier_off(dev);
-		DEBUGPRINT("%s: Link down\n", dev->name);
+	if (priv->phydev == NULL) {
+		/* Tell core. */
+		if (link_info.s.link_up) {
+			if (!netif_carrier_ok(dev))
+				netif_carrier_on(dev);
+			if (priv->queue != -1)
+				DEBUGPRINT("%s: %u Mbps %s duplex, "
+					   "port %2d, queue %2d\n",
+					   dev->name, link_info.s.speed,
+					   (link_info.s.full_duplex) ?
+						"Full" : "Half",
+					   priv->port, priv->queue);
+			else
+				DEBUGPRINT("%s: %u Mbps %s duplex, "
+					   "port %2d, POW\n",
+					   dev->name, link_info.s.speed,
+					   (link_info.s.full_duplex) ?
+						"Full" : "Half",
+					   priv->port);
+		} else {
+			if (netif_carrier_ok(dev))
+				netif_carrier_off(dev);
+			DEBUGPRINT("%s: Link down\n", dev->name);
+		}
 	}
 }
 
diff --git a/drivers/staging/octeon/ethernet-sgmii.c b/drivers/staging/octeon/ethernet-sgmii.c
index 2b54996..6061d01 100644
--- a/drivers/staging/octeon/ethernet-sgmii.c
+++ b/drivers/staging/octeon/ethernet-sgmii.c
@@ -113,7 +113,7 @@ int cvm_oct_sgmii_init(struct net_device *dev)
 	struct octeon_ethernet *priv = netdev_priv(dev);
 	cvm_oct_common_init(dev);
 	dev->netdev_ops->ndo_stop(dev);
-	if (!octeon_is_simulation())
+	if (!octeon_is_simulation() && priv->phydev == NULL)
 		priv->poll = cvm_oct_sgmii_poll;
 
 	/* FIXME: Need autoneg logic */
diff --git a/drivers/staging/octeon/ethernet-xaui.c b/drivers/staging/octeon/ethernet-xaui.c
index 0c2e7cc..ee3dc41 100644
--- a/drivers/staging/octeon/ethernet-xaui.c
+++ b/drivers/staging/octeon/ethernet-xaui.c
@@ -112,7 +112,7 @@ int cvm_oct_xaui_init(struct net_device *dev)
 	struct octeon_ethernet *priv = netdev_priv(dev);
 	cvm_oct_common_init(dev);
 	dev->netdev_ops->ndo_stop(dev);
-	if (!octeon_is_simulation())
+	if (!octeon_is_simulation() && priv->phydev == NULL)
 		priv->poll = cvm_oct_xaui_poll;
 
 	return 0;
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c
index b847951..d3dff8f 100644
--- a/drivers/staging/octeon/ethernet.c
+++ b/drivers/staging/octeon/ethernet.c
@@ -30,7 +30,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
-#include <linux/mii.h>
+#include <linux/phy.h>
 
 #include <net/dst.h>
 
@@ -122,8 +122,6 @@ static struct timer_list cvm_oct_poll_timer;
  */
 struct net_device *cvm_oct_device[TOTAL_NUMBER_OF_PORTS];
 
-extern struct semaphore mdio_sem;
-
 /**
  * Periodic timer tick for slow management operations
  *
@@ -150,13 +148,8 @@ static void cvm_do_timer(unsigned long arg)
 		goto out;
 
 	priv = netdev_priv(cvm_oct_device[port]);
-	if (priv->poll) {
-		/* skip polling if we don't get the lock */
-		if (!down_trylock(&mdio_sem)) {
-			priv->poll(cvm_oct_device[port]);
-			up(&mdio_sem);
-		}
-	}
+	if (priv->poll)
+		priv->poll(cvm_oct_device[port]);
 
 	queues_per_port = cvmx_pko_get_num_queues(port);
 	/* Drain any pending packets in the free list */
@@ -474,16 +467,30 @@ static int cvm_oct_common_set_mac_address(struct net_device *dev, void *addr)
  */
 int cvm_oct_common_init(struct net_device *dev)
 {
-	static int count;
-	char mac[8] = { 0x00, 0x00,
-		octeon_bootinfo->mac_addr_base[0],
-		octeon_bootinfo->mac_addr_base[1],
-		octeon_bootinfo->mac_addr_base[2],
-		octeon_bootinfo->mac_addr_base[3],
-		octeon_bootinfo->mac_addr_base[4],
-		octeon_bootinfo->mac_addr_base[5] + count
-	};
 	struct octeon_ethernet *priv = netdev_priv(dev);
+	struct sockaddr sa;
+	u64 mac = ((u64)(octeon_bootinfo->mac_addr_base[0] & 0xff) << 40) |
+		((u64)(octeon_bootinfo->mac_addr_base[1] & 0xff) << 32) |
+		((u64)(octeon_bootinfo->mac_addr_base[2] & 0xff) << 24) |
+		((u64)(octeon_bootinfo->mac_addr_base[3] & 0xff) << 16) |
+		((u64)(octeon_bootinfo->mac_addr_base[4] & 0xff) << 8) |
+		(u64)(octeon_bootinfo->mac_addr_base[5] & 0xff);
+
+	mac += cvm_oct_mac_addr_offset;
+	sa.sa_data[0] = (mac >> 40) & 0xff;
+	sa.sa_data[1] = (mac >> 32) & 0xff;
+	sa.sa_data[2] = (mac >> 24) & 0xff;
+	sa.sa_data[3] = (mac >> 16) & 0xff;
+	sa.sa_data[4] = (mac >> 8) & 0xff;
+	sa.sa_data[5] = mac & 0xff;
+
+	if (cvm_oct_mac_addr_offset >= octeon_bootinfo->mac_addr_count)
+		printk(KERN_DEBUG "%s: Using MAC outside of the assigned range:"
+			" %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
+			sa.sa_data[0] & 0xff, sa.sa_data[1] & 0xff,
+			sa.sa_data[2] & 0xff, sa.sa_data[3] & 0xff,
+			sa.sa_data[4] & 0xff, sa.sa_data[5] & 0xff);
+	cvm_oct_mac_addr_offset++;
 
 	/*
 	 * Force the interface to use the POW send if always_use_pow
@@ -496,14 +503,12 @@ int cvm_oct_common_init(struct net_device *dev)
 	if (priv->queue != -1 && USE_HW_TCPUDP_CHECKSUM)
 		dev->features |= NETIF_F_IP_CSUM;
 
-	count++;
-
 	/* We do our own locking, Linux doesn't need to */
 	dev->features |= NETIF_F_LLTX;
 	SET_ETHTOOL_OPS(dev, &cvm_oct_ethtool_ops);
 
-	cvm_oct_mdio_setup_device(dev);
-	dev->netdev_ops->ndo_set_mac_address(dev, mac);
+	cvm_oct_phy_setup_device(dev);
+	dev->netdev_ops->ndo_set_mac_address(dev, &sa);
 	dev->netdev_ops->ndo_change_mtu(dev, dev->mtu);
 
 	/*
@@ -518,7 +523,10 @@ int cvm_oct_common_init(struct net_device *dev)
 
 void cvm_oct_common_uninit(struct net_device *dev)
 {
-	/* Currently nothing to do */
+	struct octeon_ethernet *priv = netdev_priv(dev);
+
+	if (priv->phydev)
+		phy_disconnect(priv->phydev);
 }
 
 static const struct net_device_ops cvm_oct_npi_netdev_ops = {
@@ -605,6 +613,10 @@ static const struct net_device_ops cvm_oct_pow_netdev_ops = {
 #endif
 };
 
+unsigned int cvm_oct_mac_addr_offset;
+
+extern void octeon_mdiobus_force_mod_depencency(void);
+
 /**
  * Module/ driver initialization. Creates the linux network
  * devices.
@@ -618,8 +630,16 @@ static int __init cvm_oct_init_module(void)
 	int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE;
 	int qos;
 
+	octeon_mdiobus_force_mod_depencency();
 	pr_notice("cavium-ethernet %s\n", OCTEON_ETHERNET_VERSION);
 
+	if (OCTEON_IS_MODEL(OCTEON_CN52XX))
+		cvm_oct_mac_addr_offset = 2; /* First two are the mgmt ports. */
+	else if (OCTEON_IS_MODEL(OCTEON_CN56XX))
+		cvm_oct_mac_addr_offset = 1; /* First one is the mgmt port. */
+	else
+		cvm_oct_mac_addr_offset = 0;
+
 	cvm_oct_proc_initialize();
 	cvm_oct_rx_initialize();
 	cvm_oct_configure_common_hw();
diff --git a/drivers/staging/octeon/octeon-ethernet.h b/drivers/staging/octeon/octeon-ethernet.h
index 3aef987..9b0faeb 100644
--- a/drivers/staging/octeon/octeon-ethernet.h
+++ b/drivers/staging/octeon/octeon-ethernet.h
@@ -50,15 +50,24 @@ struct octeon_ethernet {
 	/* List of outstanding tx buffers per queue */
 	struct sk_buff_head tx_free_list[16];
 	/* Device statistics */
-	struct net_device_stats stats
-;	/* Generic MII info structure */
-	struct mii_if_info mii_info;
+	struct net_device_stats stats;
+	struct phy_device *phydev;
+	unsigned int last_link;
 	/* Last negotiated link state */
 	uint64_t link_info;
 	/* Called periodically to check link status */
 	void (*poll) (struct net_device *dev);
 };
 
+/*
+ * The offset from mac_addr_base that should be used for the next port
+ * that is configured.  By convention, if any mgmt ports exist on the
+ * chip, they get the first mac addresses, The ports controlled by
+ * this driver are numbered sequencially following any mgmt addresses
+ * that may exist.
+ */
+extern unsigned int cvm_oct_mac_addr_offset;
+
 /**
  * Free a work queue entry received in a intercept callback.
  *
-- 
1.6.0.6


From David.Daney@caviumnetworks.com Thu Oct  8 01:12:02 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 01:12:09 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:16110 "EHLO
	mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S2097322AbZJGXKZ (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 01:10:25 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,5,4,7535)
	id <B4acd1fdb0000>; Wed, 07 Oct 2009 16:10:19 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 16:10:22 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 16:10:22 -0700
Received: from dd1.caveonetworks.com (localhost.localdomain [127.0.0.1])
	by dd1.caveonetworks.com (8.14.2/8.14.2) with ESMTP id n97NAHI5007674;
	Wed, 7 Oct 2009 16:10:17 -0700
Received: (from ddaney@localhost)
	by dd1.caveonetworks.com (8.14.2/8.14.2/Submit) id n97NAHC5007673;
	Wed, 7 Oct 2009 16:10:17 -0700
From:	David Daney <ddaney@caviumnetworks.com>
To:	ralf@linux-mips.org, linux-mips@linux-mips.org,
	netdev@vger.kernel.org
Cc:	David Daney <ddaney@caviumnetworks.com>
Subject: [PATCH 5/6] netdev: Add Ethernet driver for Octeon MGMT devices.
Date:	Wed,  7 Oct 2009 16:10:14 -0700
Message-Id: <1254957015-7633-5-git-send-email-ddaney@caviumnetworks.com>
X-Mailer: git-send-email 1.6.0.6
In-Reply-To: <4ACD1F4E.8090603@caviumnetworks.com>
References: <4ACD1F4E.8090603@caviumnetworks.com>
X-OriginalArrivalTime: 07 Oct 2009 23:10:22.0215 (UTC) FILETIME=[586B5170:01CA47A3]
Return-Path: <David.Daney@caviumnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24169
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ddaney@caviumnetworks.com
Precedence: bulk
X-list: linux-mips

The Octeon MGMT Ethernet ports are present in some members of the
Octeon SOC family (cn52XX and cn56XX have them).

The mdio bus connected to the MGMT PHYs is shared with the main
octeon-ethernet driver, we force it to be loaded first by calling
octeon_mdiobus_force_mod_depencency.  The platform devices for the
MGMT Ethernet ports are added in
arch/mips/cavium-octeon/octeon-platform.c, and the register
definitions for the ports live in arch/mips/include/asm/octeon/ along
with their ilk.

Although it currently is the only driver in drivers/net/octeon, the
directory was created looking forward to the day that octeon-ethernet
will move there from its current home in drivers/staging.

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---
 drivers/net/Kconfig              |    2 +
 drivers/net/Makefile             |    2 +
 drivers/net/octeon/Kconfig       |   10 +
 drivers/net/octeon/Makefile      |    2 +
 drivers/net/octeon/octeon_mgmt.c | 1175 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 1191 insertions(+), 0 deletions(-)
 create mode 100644 drivers/net/octeon/Kconfig
 create mode 100644 drivers/net/octeon/Makefile
 create mode 100644 drivers/net/octeon/octeon_mgmt.c

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 37ff3c7..9a7a283 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1952,6 +1952,8 @@ config BCM63XX_ENET
 
 source "drivers/net/fs_enet/Kconfig"
 
+source "drivers/net/octeon/Kconfig"
+
 endif # NET_ETHERNET
 
 #
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 678a4fd..9a9b641 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -285,3 +285,5 @@ obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
 obj-$(CONFIG_SFC) += sfc/
 
 obj-$(CONFIG_WIMAX) += wimax/
+
+obj-$(CONFIG_OCTEON_MGMT_ETHERNET) += octeon/
diff --git a/drivers/net/octeon/Kconfig b/drivers/net/octeon/Kconfig
new file mode 100644
index 0000000..1e56bbf
--- /dev/null
+++ b/drivers/net/octeon/Kconfig
@@ -0,0 +1,10 @@
+config OCTEON_MGMT_ETHERNET
+	tristate "Octeon Management port ethernet driver (CN5XXX, CN6XXX)"
+	depends on  CPU_CAVIUM_OCTEON
+	select PHYLIB
+	select MDIO_OCTEON
+	default y
+	help
+	  This option enables the ethernet driver for the management
+	  port on Cavium Networks' Octeon CN57XX, CN56XX, CN55XX,
+	  CN54XX, CN52XX, and CN6XXX chips.
diff --git a/drivers/net/octeon/Makefile b/drivers/net/octeon/Makefile
new file mode 100644
index 0000000..906edec
--- /dev/null
+++ b/drivers/net/octeon/Makefile
@@ -0,0 +1,2 @@
+
+obj-$(CONFIG_OCTEON_MGMT_ETHERNET)	+= octeon_mgmt.o
diff --git a/drivers/net/octeon/octeon_mgmt.c b/drivers/net/octeon/octeon_mgmt.c
new file mode 100644
index 0000000..83a636d
--- /dev/null
+++ b/drivers/net/octeon/octeon_mgmt.c
@@ -0,0 +1,1175 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Cavium Networks
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/phy.h>
+#include <linux/spinlock.h>
+
+#include <asm/octeon/octeon.h>
+#include <asm/octeon/cvmx-mixx-defs.h>
+#include <asm/octeon/cvmx-agl-defs.h>
+
+#define DRV_NAME "octeon_mgmt"
+#define DRV_VERSION "2.0"
+#define DRV_DESCRIPTION \
+	"Cavium Networks Octeon MII (management) port Network Driver"
+
+#define OCTEON_MGMT_NAPI_WEIGHT 16
+
+/*
+ * Ring sizes that are powers of two allow for more efficient modulo
+ * opertions.
+ */
+#define OCTEON_MGMT_RX_RING_SIZE 512
+#define OCTEON_MGMT_TX_RING_SIZE 128
+
+/* Allow 8 bytes for vlan and FCS. */
+#define OCTEON_MGMT_RX_HEADROOM (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN)
+
+union mgmt_port_ring_entry {
+	u64 d64;
+	struct {
+		u64    reserved_62_63:2;
+		/* Length of the buffer/packet in bytes */
+		u64    len:14;
+		/* For TX, signals that the packet should be timestamped */
+		u64    tstamp:1;
+		/* The RX error code */
+		u64    code:7;
+#define RING_ENTRY_CODE_DONE 0xf
+#define RING_ENTRY_CODE_MORE 0x10
+		/* Physical address of the buffer */
+		u64    addr:40;
+	} s;
+};
+
+struct octeon_mgmt {
+	struct net_device *netdev;
+	int port;
+	int irq;
+	u64 *tx_ring;
+	dma_addr_t tx_ring_handle;
+	unsigned int tx_next;
+	unsigned int tx_next_clean;
+	unsigned int tx_current_fill;
+	/* The tx_list lock also protects the ring related variables */
+	struct sk_buff_head tx_list;
+
+	/* RX variables only touched in napi_poll.  No locking necessary. */
+	u64 *rx_ring;
+	dma_addr_t rx_ring_handle;
+	unsigned int rx_next;
+	unsigned int rx_next_fill;
+	unsigned int rx_current_fill;
+	struct sk_buff_head rx_list;
+
+	spinlock_t lock;
+	unsigned int last_duplex;
+	unsigned int last_link;
+	struct device *dev;
+	struct napi_struct napi;
+	struct tasklet_struct tx_clean_tasklet;
+	struct phy_device *phydev;
+};
+
+static void octeon_mgmt_set_rx_irq(struct octeon_mgmt *p, int enable)
+{
+	int port = p->port;
+	union cvmx_mixx_intena mix_intena;
+	unsigned long flags;
+
+	spin_lock_irqsave(&p->lock, flags);
+	mix_intena.u64 = cvmx_read_csr(CVMX_MIXX_INTENA(port));
+	mix_intena.s.ithena = enable ? 1 : 0;
+	cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64);
+	spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static void octeon_mgmt_set_tx_irq(struct octeon_mgmt *p, int enable)
+{
+	int port = p->port;
+	union cvmx_mixx_intena mix_intena;
+	unsigned long flags;
+
+	spin_lock_irqsave(&p->lock, flags);
+	mix_intena.u64 = cvmx_read_csr(CVMX_MIXX_INTENA(port));
+	mix_intena.s.othena = enable ? 1 : 0;
+	cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64);
+	spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static inline void octeon_mgmt_enable_rx_irq(struct octeon_mgmt *p)
+{
+	octeon_mgmt_set_rx_irq(p, 1);
+}
+
+static inline void octeon_mgmt_disable_rx_irq(struct octeon_mgmt *p)
+{
+	octeon_mgmt_set_rx_irq(p, 0);
+}
+
+static inline void octeon_mgmt_enable_tx_irq(struct octeon_mgmt *p)
+{
+	octeon_mgmt_set_tx_irq(p, 1);
+}
+
+static inline void octeon_mgmt_disable_tx_irq(struct octeon_mgmt *p)
+{
+	octeon_mgmt_set_tx_irq(p, 0);
+}
+
+static unsigned int ring_max_fill(unsigned int ring_size)
+{
+	return ring_size - 8;
+}
+
+static unsigned int ring_size_to_bytes(unsigned int ring_size)
+{
+	return ring_size * sizeof(union mgmt_port_ring_entry);
+}
+
+static void octeon_mgmt_rx_fill_ring(struct net_device *netdev)
+{
+	struct octeon_mgmt *p = netdev_priv(netdev);
+	int port = p->port;
+
+	while (p->rx_current_fill < ring_max_fill(OCTEON_MGMT_RX_RING_SIZE)) {
+		unsigned int size;
+		union mgmt_port_ring_entry re;
+		struct sk_buff *skb;
+
+		/* CN56XX pass 1 needs 8 bytes of padding.  */
+		size = netdev->mtu + OCTEON_MGMT_RX_HEADROOM + 8 + NET_IP_ALIGN;
+
+		skb = netdev_alloc_skb(netdev, size);
+		if (!skb)
+			break;
+		skb_reserve(skb, NET_IP_ALIGN);
+		__skb_queue_tail(&p->rx_list, skb);
+
+		re.d64 = 0;
+		re.s.len = size;
+		re.s.addr = dma_map_single(p->dev, skb->data,
+					   size,
+					   DMA_FROM_DEVICE);
+
+		/* Put it in the ring.  */
+		p->rx_ring[p->rx_next_fill] = re.d64;
+		dma_sync_single_for_device(p->dev, p->rx_ring_handle,
+					   ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE),
+					   DMA_BIDIRECTIONAL);
+		p->rx_next_fill =
+			(p->rx_next_fill + 1) % OCTEON_MGMT_RX_RING_SIZE;
+		p->rx_current_fill++;
+		/* Ring the bell.  */
+		cvmx_write_csr(CVMX_MIXX_IRING2(port), 1);
+	}
+}
+
+static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p)
+{
+	int port = p->port;
+	union cvmx_mixx_orcnt mix_orcnt;
+	union mgmt_port_ring_entry re;
+	struct sk_buff *skb;
+	int cleaned = 0;
+	unsigned long flags;
+
+	mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port));
+	while (mix_orcnt.s.orcnt) {
+		dma_sync_single_for_cpu(p->dev, p->tx_ring_handle,
+					ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE),
+					DMA_BIDIRECTIONAL);
+
+		spin_lock_irqsave(&p->tx_list.lock, flags);
+
+		re.d64 = p->tx_ring[p->tx_next_clean];
+		p->tx_next_clean =
+			(p->tx_next_clean + 1) % OCTEON_MGMT_TX_RING_SIZE;
+		skb = __skb_dequeue(&p->tx_list);
+
+		mix_orcnt.u64 = 0;
+		mix_orcnt.s.orcnt = 1;
+
+		/* Acknowledge to hardware that we have the buffer.  */
+		cvmx_write_csr(CVMX_MIXX_ORCNT(port), mix_orcnt.u64);
+		p->tx_current_fill--;
+
+		spin_unlock_irqrestore(&p->tx_list.lock, flags);
+
+		dma_unmap_single(p->dev, re.s.addr, re.s.len,
+				 DMA_TO_DEVICE);
+		dev_kfree_skb_any(skb);
+		cleaned++;
+
+		mix_orcnt.u64 = cvmx_read_csr(CVMX_MIXX_ORCNT(port));
+	}
+
+	if (cleaned && netif_queue_stopped(p->netdev))
+		netif_wake_queue(p->netdev);
+}
+
+static void octeon_mgmt_clean_tx_tasklet(unsigned long arg)
+{
+	struct octeon_mgmt *p = (struct octeon_mgmt *)arg;
+	octeon_mgmt_clean_tx_buffers(p);
+	octeon_mgmt_enable_tx_irq(p);
+}
+
+static void octeon_mgmt_update_rx_stats(struct net_device *netdev)
+{
+	struct octeon_mgmt *p = netdev_priv(netdev);
+	int port = p->port;
+	unsigned long flags;
+	u64 drop, bad;
+
+	/* These reads also clear the count registers.  */
+	drop = cvmx_read_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_DRP(port));
+	bad = cvmx_read_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_BAD(port));
+
+	if (drop || bad) {
+		/* Do an atomic update. */
+		spin_lock_irqsave(&p->lock, flags);
+		netdev->stats.rx_errors += bad;
+		netdev->stats.rx_dropped += drop;
+		spin_unlock_irqrestore(&p->lock, flags);
+	}
+}
+
+static void octeon_mgmt_update_tx_stats(struct net_device *netdev)
+{
+	struct octeon_mgmt *p = netdev_priv(netdev);
+	int port = p->port;
+	unsigned long flags;
+
+	union cvmx_agl_gmx_txx_stat0 s0;
+	union cvmx_agl_gmx_txx_stat1 s1;
+
+	/* These reads also clear the count registers.  */
+	s0.u64 = cvmx_read_csr(CVMX_AGL_GMX_TXX_STAT0(port));
+	s1.u64 = cvmx_read_csr(CVMX_AGL_GMX_TXX_STAT1(port));
+
+	if (s0.s.xsdef || s0.s.xscol || s1.s.scol || s1.s.mcol) {
+		/* Do an atomic update. */
+		spin_lock_irqsave(&p->lock, flags);
+		netdev->stats.tx_errors += s0.s.xsdef + s0.s.xscol;
+		netdev->stats.collisions += s1.s.scol + s1.s.mcol;
+		spin_unlock_irqrestore(&p->lock, flags);
+	}
+}
+
+/*
+ * Dequeue a receive skb and its corresponding ring entry.  The ring
+ * entry is returned, *pskb is updated to point to the skb.
+ */
+static u64 octeon_mgmt_dequeue_rx_buffer(struct octeon_mgmt *p,
+					 struct sk_buff **pskb)
+{
+	union mgmt_port_ring_entry re;
+
+	dma_sync_single_for_cpu(p->dev, p->rx_ring_handle,
+				ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE),
+				DMA_BIDIRECTIONAL);
+
+	re.d64 = p->rx_ring[p->rx_next];
+	p->rx_next = (p->rx_next + 1) % OCTEON_MGMT_RX_RING_SIZE;
+	p->rx_current_fill--;
+	*pskb = __skb_dequeue(&p->rx_list);
+
+	dma_unmap_single(p->dev, re.s.addr,
+			 ETH_FRAME_LEN + OCTEON_MGMT_RX_HEADROOM,
+			 DMA_FROM_DEVICE);
+
+	return re.d64;
+}
+
+
+static int octeon_mgmt_receive_one(struct octeon_mgmt *p)
+{
+	int port = p->port;
+	struct net_device *netdev = p->netdev;
+	union cvmx_mixx_ircnt mix_ircnt;
+	union mgmt_port_ring_entry re;
+	struct sk_buff *skb;
+	struct sk_buff *skb2;
+	struct sk_buff *skb_new;
+	union mgmt_port_ring_entry re2;
+	int rc = 1;
+
+
+	re.d64 = octeon_mgmt_dequeue_rx_buffer(p, &skb);
+	if (likely(re.s.code == RING_ENTRY_CODE_DONE)) {
+		/* A good packet, send it up. */
+		skb_put(skb, re.s.len);
+good:
+		skb->protocol = eth_type_trans(skb, netdev);
+		netdev->stats.rx_packets++;
+		netdev->stats.rx_bytes += skb->len;
+		netdev->last_rx = jiffies;
+		netif_receive_skb(skb);
+		rc = 0;
+	} else if (re.s.code == RING_ENTRY_CODE_MORE) {
+		/*
+		 * Packet split across skbs.  This can happen if we
+		 * increase the MTU.  Buffers that are already in the
+		 * rx ring can then end up being too small.  As the rx
+		 * ring is refilled, buffers sized for the new MTU
+		 * will be used and we should go back to the normal
+		 * non-split case.
+		 */
+		skb_put(skb, re.s.len);
+		do {
+			re2.d64 = octeon_mgmt_dequeue_rx_buffer(p, &skb2);
+			if (re2.s.code != RING_ENTRY_CODE_MORE
+				&& re2.s.code != RING_ENTRY_CODE_DONE)
+				goto split_error;
+			skb_put(skb2,  re2.s.len);
+			skb_new = skb_copy_expand(skb, 0, skb2->len,
+						  GFP_ATOMIC);
+			if (!skb_new)
+				goto split_error;
+			if (skb_copy_bits(skb2, 0, skb_tail_pointer(skb_new),
+					  skb2->len))
+				goto split_error;
+			skb_put(skb_new, skb2->len);
+			dev_kfree_skb_any(skb);
+			dev_kfree_skb_any(skb2);
+			skb = skb_new;
+		} while (re2.s.code == RING_ENTRY_CODE_MORE);
+		goto good;
+	} else {
+		/* Some other error, discard it. */
+		dev_kfree_skb_any(skb);
+		/*
+		 * Error statistics are accumulated in
+		 * octeon_mgmt_update_rx_stats.
+		 */
+	}
+	goto done;
+split_error:
+	/* Discard the whole mess. */
+	dev_kfree_skb_any(skb);
+	dev_kfree_skb_any(skb2);
+	while (re2.s.code == RING_ENTRY_CODE_MORE) {
+		re2.d64 = octeon_mgmt_dequeue_rx_buffer(p, &skb2);
+		dev_kfree_skb_any(skb2);
+	}
+	netdev->stats.rx_errors++;
+
+done:
+	/* Tell the hardware we processed a packet.  */
+	mix_ircnt.u64 = 0;
+	mix_ircnt.s.ircnt = 1;
+	cvmx_write_csr(CVMX_MIXX_IRCNT(port), mix_ircnt.u64);
+	return rc;
+
+}
+
+static int octeon_mgmt_receive_packets(struct octeon_mgmt *p, int budget)
+{
+	int port = p->port;
+	unsigned int work_done = 0;
+	union cvmx_mixx_ircnt mix_ircnt;
+	int rc;
+
+
+	mix_ircnt.u64 = cvmx_read_csr(CVMX_MIXX_IRCNT(port));
+	while (work_done < budget && mix_ircnt.s.ircnt) {
+
+		rc = octeon_mgmt_receive_one(p);
+		if (!rc)
+			work_done++;
+
+		/* Check for more packets. */
+		mix_ircnt.u64 = cvmx_read_csr(CVMX_MIXX_IRCNT(port));
+	}
+
+	octeon_mgmt_rx_fill_ring(p->netdev);
+
+	return work_done;
+}
+
+static int octeon_mgmt_napi_poll(struct napi_struct *napi, int budget)
+{
+	struct octeon_mgmt *p = container_of(napi, struct octeon_mgmt, napi);
+	struct net_device *netdev = p->netdev;
+	unsigned int work_done = 0;
+
+	work_done = octeon_mgmt_receive_packets(p, budget);
+
+	if (work_done < budget) {
+		/* We stopped because no more packets were available. */
+		napi_complete(napi);
+		octeon_mgmt_enable_rx_irq(p);
+	}
+	octeon_mgmt_update_rx_stats(netdev);
+
+	return work_done;
+}
+
+/* Reset the hardware to clean state.  */
+static void octeon_mgmt_reset_hw(struct octeon_mgmt *p)
+{
+	union cvmx_mixx_ctl mix_ctl;
+	union cvmx_mixx_bist mix_bist;
+	union cvmx_agl_gmx_bist agl_gmx_bist;
+
+	mix_ctl.u64 = 0;
+	cvmx_write_csr(CVMX_MIXX_CTL(p->port), mix_ctl.u64);
+	do {
+		mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(p->port));
+	} while (mix_ctl.s.busy);
+	mix_ctl.s.reset = 1;
+	cvmx_write_csr(CVMX_MIXX_CTL(p->port), mix_ctl.u64);
+	cvmx_read_csr(CVMX_MIXX_CTL(p->port));
+	cvmx_wait(64);
+
+	mix_bist.u64 = cvmx_read_csr(CVMX_MIXX_BIST(p->port));
+	if (mix_bist.u64)
+		dev_warn(p->dev, "MIX failed BIST (0x%016llx)\n",
+			(unsigned long long)mix_bist.u64);
+
+	agl_gmx_bist.u64 = cvmx_read_csr(CVMX_AGL_GMX_BIST);
+	if (agl_gmx_bist.u64)
+		dev_warn(p->dev, "AGL failed BIST (0x%016llx)\n",
+			 (unsigned long long)agl_gmx_bist.u64);
+}
+
+struct octeon_mgmt_cam_state {
+	u64 cam[6];
+	u64 cam_mask;
+	int cam_index;
+};
+
+static void octeon_mgmt_cam_state_add(struct octeon_mgmt_cam_state *cs,
+				      unsigned char *addr)
+{
+	int i;
+
+	for (i = 0; i < 6; i++)
+		cs->cam[i] |= (u64)addr[i] << (8 * (cs->cam_index));
+	cs->cam_mask |= (1ULL << cs->cam_index);
+	cs->cam_index++;
+}
+
+static void octeon_mgmt_set_rx_filtering(struct net_device *netdev)
+{
+	struct octeon_mgmt *p = netdev_priv(netdev);
+	int port = p->port;
+	int i;
+	union cvmx_agl_gmx_rxx_adr_ctl adr_ctl;
+	union cvmx_agl_gmx_prtx_cfg agl_gmx_prtx;
+	unsigned long flags;
+	unsigned int prev_packet_enable;
+	unsigned int cam_mode = 1; /* 1 - Accept on CAM match */
+	unsigned int multicast_mode = 1; /* 1 - Reject all multicast.  */
+	struct octeon_mgmt_cam_state cam_state;
+	struct dev_addr_list *list;
+	struct list_head *pos;
+	int available_cam_entries;
+
+	memset(&cam_state, 0, sizeof(cam_state));
+
+	if ((netdev->flags & IFF_PROMISC) || netdev->dev_addrs.count > 7) {
+		cam_mode = 0;
+		available_cam_entries = 8;
+	} else {
+		/*
+		 * One CAM entry for the primary address, leaves seven
+		 * for the secondary addresses.
+		 */
+		available_cam_entries = 7 - netdev->dev_addrs.count;
+	}
+
+	if (netdev->flags & IFF_MULTICAST) {
+		if (cam_mode == 0 || (netdev->flags & IFF_ALLMULTI)
+		    || netdev->mc_count  > available_cam_entries)
+			multicast_mode = 2; /* 1 - Accept all multicast.  */
+		else
+			multicast_mode = 0; /* 0 - Use CAM.  */
+	}
+
+	if (cam_mode == 1) {
+		/* Add primary address. */
+		octeon_mgmt_cam_state_add(&cam_state, netdev->dev_addr);
+		list_for_each(pos, &netdev->dev_addrs.list) {
+			struct netdev_hw_addr *hw_addr;
+			hw_addr = list_entry(pos, struct netdev_hw_addr, list);
+			octeon_mgmt_cam_state_add(&cam_state, hw_addr->addr);
+			list = list->next;
+		}
+	}
+	if (multicast_mode == 0) {
+		i = netdev->mc_count;
+		list = netdev->mc_list;
+		while (i--) {
+			octeon_mgmt_cam_state_add(&cam_state, list->da_addr);
+			list = list->next;
+		}
+	}
+
+
+	spin_lock_irqsave(&p->lock, flags);
+
+	/* Disable packet I/O. */
+	agl_gmx_prtx.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
+	prev_packet_enable = agl_gmx_prtx.s.en;
+	agl_gmx_prtx.s.en = 0;
+	cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64);
+
+
+	adr_ctl.u64 = 0;
+	adr_ctl.s.cam_mode = cam_mode;
+	adr_ctl.s.mcst = multicast_mode;
+	adr_ctl.s.bcst = 1;     /* Allow broadcast */
+
+	cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CTL(port), adr_ctl.u64);
+
+	cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM0(port), cam_state.cam[0]);
+	cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM1(port), cam_state.cam[1]);
+	cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM2(port), cam_state.cam[2]);
+	cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM3(port), cam_state.cam[3]);
+	cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM4(port), cam_state.cam[4]);
+	cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM5(port), cam_state.cam[5]);
+	cvmx_write_csr(CVMX_AGL_GMX_RXX_ADR_CAM_EN(port), cam_state.cam_mask);
+
+	/* Restore packet I/O. */
+	agl_gmx_prtx.s.en = prev_packet_enable;
+	cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), agl_gmx_prtx.u64);
+
+	spin_unlock_irqrestore(&p->lock, flags);
+}
+
+static int octeon_mgmt_set_mac_address(struct net_device *netdev, void *addr)
+{
+	struct sockaddr *sa = addr;
+
+	if (!is_valid_ether_addr(sa->sa_data))
+		return -EADDRNOTAVAIL;
+
+	memcpy(netdev->dev_addr, sa->sa_data, ETH_ALEN);
+
+	octeon_mgmt_set_rx_filtering(netdev);
+
+	return 0;
+}
+
+static int octeon_mgmt_change_mtu(struct net_device *netdev, int new_mtu)
+{
+	struct octeon_mgmt *p = netdev_priv(netdev);
+	int port = p->port;
+	int size_without_fcs = new_mtu + OCTEON_MGMT_RX_HEADROOM;
+
+	/*
+	 * Limit the MTU to make sure the ethernet packets are between
+	 * 64 bytes and 16383 bytes.
+	 */
+	if (size_without_fcs < 64 || size_without_fcs > 16383) {
+		dev_warn(p->dev, "MTU must be between %d and %d.\n",
+			 64 - OCTEON_MGMT_RX_HEADROOM,
+			 16383 - OCTEON_MGMT_RX_HEADROOM);
+		return -EINVAL;
+	}
+
+	netdev->mtu = new_mtu;
+
+	cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_MAX(port), size_without_fcs);
+	cvmx_write_csr(CVMX_AGL_GMX_RXX_JABBER(port),
+		       (size_without_fcs + 7) & 0xfff8);
+
+	return 0;
+}
+
+static irqreturn_t octeon_mgmt_interrupt(int cpl, void *dev_id)
+{
+	struct net_device *netdev = dev_id;
+	struct octeon_mgmt *p = netdev_priv(netdev);
+	int port = p->port;
+	union cvmx_mixx_isr mixx_isr;
+
+	mixx_isr.u64 = cvmx_read_csr(CVMX_MIXX_ISR(port));
+
+	/* Clear any pending interrupts */
+	cvmx_write_csr(CVMX_MIXX_ISR(port),
+		       cvmx_read_csr(CVMX_MIXX_ISR(port)));
+	cvmx_read_csr(CVMX_MIXX_ISR(port));
+
+	if (mixx_isr.s.irthresh) {
+		octeon_mgmt_disable_rx_irq(p);
+		napi_schedule(&p->napi);
+	}
+	if (mixx_isr.s.orthresh) {
+		octeon_mgmt_disable_tx_irq(p);
+		tasklet_schedule(&p->tx_clean_tasklet);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int octeon_mgmt_ioctl(struct net_device *netdev,
+			     struct ifreq *rq, int cmd)
+{
+	struct octeon_mgmt *p = netdev_priv(netdev);
+
+	if (!netif_running(netdev))
+		return -EINVAL;
+
+	if (!p->phydev)
+		return -EINVAL;
+
+	return phy_mii_ioctl(p->phydev, if_mii(rq), cmd);
+}
+
+static void octeon_mgmt_adjust_link(struct net_device *netdev)
+{
+	struct octeon_mgmt *p = netdev_priv(netdev);
+	int port = p->port;
+	union cvmx_agl_gmx_prtx_cfg prtx_cfg;
+	unsigned long flags;
+	int link_changed = 0;
+
+	spin_lock_irqsave(&p->lock, flags);
+	if (p->phydev->link) {
+		if (!p->last_link)
+			link_changed = 1;
+		if (p->last_duplex != p->phydev->duplex) {
+			p->last_duplex = p->phydev->duplex;
+			prtx_cfg.u64 =
+				cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
+			prtx_cfg.s.duplex = p->phydev->duplex;
+			cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port),
+				       prtx_cfg.u64);
+		}
+	} else {
+		if (p->last_link)
+			link_changed = -1;
+	}
+	p->last_link = p->phydev->link;
+	spin_unlock_irqrestore(&p->lock, flags);
+
+	if (link_changed != 0) {
+		if (link_changed > 0) {
+			netif_carrier_on(netdev);
+			pr_info("%s: Link is up - %d/%s\n", netdev->name,
+				p->phydev->speed,
+				DUPLEX_FULL == p->phydev->duplex ?
+				"Full" : "Half");
+		} else {
+			netif_carrier_off(netdev);
+			pr_info("%s: Link is down\n", netdev->name);
+		}
+	}
+}
+
+static int octeon_mgmt_init_phy(struct net_device *netdev)
+{
+	struct octeon_mgmt *p = netdev_priv(netdev);
+	char phy_id[20];
+
+	if (octeon_is_simulation()) {
+		/* No PHYs in the simulator. */
+		netif_carrier_on(netdev);
+		return 0;
+	}
+
+	snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, "0", p->port);
+
+	p->phydev = phy_connect(netdev, phy_id, octeon_mgmt_adjust_link, 0,
+				PHY_INTERFACE_MODE_MII);
+
+	if (IS_ERR(p->phydev)) {
+		p->phydev = NULL;
+		return -1;
+	}
+
+	phy_start_aneg(p->phydev);
+
+	return 0;
+}
+
+static int octeon_mgmt_open(struct net_device *netdev)
+{
+	struct octeon_mgmt *p = netdev_priv(netdev);
+	int port = p->port;
+	union cvmx_mixx_ctl mix_ctl;
+	union cvmx_agl_gmx_inf_mode agl_gmx_inf_mode;
+	union cvmx_mixx_oring1 oring1;
+	union cvmx_mixx_iring1 iring1;
+	union cvmx_agl_gmx_prtx_cfg prtx_cfg;
+	union cvmx_agl_gmx_rxx_frm_ctl rxx_frm_ctl;
+	union cvmx_mixx_irhwm mix_irhwm;
+	union cvmx_mixx_orhwm mix_orhwm;
+	union cvmx_mixx_intena mix_intena;
+	struct sockaddr sa;
+
+	/* Allocate ring buffers.  */
+	p->tx_ring = kzalloc(ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE),
+			     GFP_KERNEL);
+	if (!p->tx_ring)
+		return -ENOMEM;
+	p->tx_ring_handle =
+		dma_map_single(p->dev, p->tx_ring,
+			       ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE),
+			       DMA_BIDIRECTIONAL);
+	p->tx_next = 0;
+	p->tx_next_clean = 0;
+	p->tx_current_fill = 0;
+
+
+	p->rx_ring = kzalloc(ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE),
+			     GFP_KERNEL);
+	if (!p->rx_ring)
+		goto err_nomem;
+	p->rx_ring_handle =
+		dma_map_single(p->dev, p->rx_ring,
+			       ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE),
+			       DMA_BIDIRECTIONAL);
+
+	p->rx_next = 0;
+	p->rx_next_fill = 0;
+	p->rx_current_fill = 0;
+
+	octeon_mgmt_reset_hw(p);
+
+	mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port));
+
+	/* Bring it out of reset if needed. */
+	if (mix_ctl.s.reset) {
+		mix_ctl.s.reset = 0;
+		cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64);
+		do {
+			mix_ctl.u64 = cvmx_read_csr(CVMX_MIXX_CTL(port));
+		} while (mix_ctl.s.reset);
+	}
+
+	agl_gmx_inf_mode.u64 = 0;
+	agl_gmx_inf_mode.s.en = 1;
+	cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64);
+
+	oring1.u64 = 0;
+	oring1.s.obase = p->tx_ring_handle >> 3;
+	oring1.s.osize = OCTEON_MGMT_TX_RING_SIZE;
+	cvmx_write_csr(CVMX_MIXX_ORING1(port), oring1.u64);
+
+	iring1.u64 = 0;
+	iring1.s.ibase = p->rx_ring_handle >> 3;
+	iring1.s.isize = OCTEON_MGMT_RX_RING_SIZE;
+	cvmx_write_csr(CVMX_MIXX_IRING1(port), iring1.u64);
+
+	/* Disable packet I/O. */
+	prtx_cfg.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
+	prtx_cfg.s.en = 0;
+	cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), prtx_cfg.u64);
+
+	memcpy(sa.sa_data, netdev->dev_addr, ETH_ALEN);
+	octeon_mgmt_set_mac_address(netdev, &sa);
+
+	octeon_mgmt_change_mtu(netdev, netdev->mtu);
+
+	/*
+	 * Enable the port HW. Packets are not allowed until
+	 * cvmx_mgmt_port_enable() is called.
+	 */
+	mix_ctl.u64 = 0;
+	mix_ctl.s.crc_strip = 1;    /* Strip the ending CRC */
+	mix_ctl.s.en = 1;           /* Enable the port */
+	mix_ctl.s.nbtarb = 0;       /* Arbitration mode */
+	/* MII CB-request FIFO programmable high watermark */
+	mix_ctl.s.mrq_hwm = 1;
+	cvmx_write_csr(CVMX_MIXX_CTL(port), mix_ctl.u64);
+
+	if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X)
+	    || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) {
+		/*
+		 * Force compensation values, as they are not
+		 * determined properly by HW
+		 */
+		union cvmx_agl_gmx_drv_ctl drv_ctl;
+
+		drv_ctl.u64 = cvmx_read_csr(CVMX_AGL_GMX_DRV_CTL);
+		if (port) {
+			drv_ctl.s.byp_en1 = 1;
+			drv_ctl.s.nctl1 = 6;
+			drv_ctl.s.pctl1 = 6;
+		} else {
+			drv_ctl.s.byp_en = 1;
+			drv_ctl.s.nctl = 6;
+			drv_ctl.s.pctl = 6;
+		}
+		cvmx_write_csr(CVMX_AGL_GMX_DRV_CTL, drv_ctl.u64);
+	}
+
+	octeon_mgmt_rx_fill_ring(netdev);
+
+	/* Clear statistics. */
+	/* Clear on read. */
+	cvmx_write_csr(CVMX_AGL_GMX_RXX_STATS_CTL(port), 1);
+	cvmx_write_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_DRP(port), 0);
+	cvmx_write_csr(CVMX_AGL_GMX_RXX_STATS_PKTS_BAD(port), 0);
+
+	cvmx_write_csr(CVMX_AGL_GMX_TXX_STATS_CTL(port), 1);
+	cvmx_write_csr(CVMX_AGL_GMX_TXX_STAT0(port), 0);
+	cvmx_write_csr(CVMX_AGL_GMX_TXX_STAT1(port), 0);
+
+	/* Clear any pending interrupts */
+	cvmx_write_csr(CVMX_MIXX_ISR(port), cvmx_read_csr(CVMX_MIXX_ISR(port)));
+
+	if (request_irq(p->irq, octeon_mgmt_interrupt, 0, netdev->name,
+			netdev)) {
+		dev_err(p->dev, "request_irq(%d) failed.\n", p->irq);
+		goto err_noirq;
+	}
+
+	/* Interrupt every single RX packet */
+	mix_irhwm.u64 = 0;
+	mix_irhwm.s.irhwm = 0;
+	cvmx_write_csr(CVMX_MIXX_IRHWM(port), mix_irhwm.u64);
+
+	/* Interrupt when we have 5 or more packets to clean.  */
+	mix_orhwm.u64 = 0;
+	mix_orhwm.s.orhwm = 5;
+	cvmx_write_csr(CVMX_MIXX_ORHWM(port), mix_orhwm.u64);
+
+	/* Enable receive and transmit interrupts */
+	mix_intena.u64 = 0;
+	mix_intena.s.ithena = 1;
+	mix_intena.s.othena = 1;
+	cvmx_write_csr(CVMX_MIXX_INTENA(port), mix_intena.u64);
+
+
+	/* Enable packet I/O. */
+
+	rxx_frm_ctl.u64 = 0;
+	rxx_frm_ctl.s.pre_align = 1;
+	/*
+	 * When set, disables the length check for non-min sized pkts
+	 * with padding in the client data.
+	 */
+	rxx_frm_ctl.s.pad_len = 1;
+	/* When set, disables the length check for VLAN pkts */
+	rxx_frm_ctl.s.vlan_len = 1;
+	/* When set, PREAMBLE checking is  less strict */
+	rxx_frm_ctl.s.pre_free = 1;
+	/* Control Pause Frames can match station SMAC */
+	rxx_frm_ctl.s.ctl_smac = 0;
+	/* Control Pause Frames can match globally assign Multicast address */
+	rxx_frm_ctl.s.ctl_mcst = 1;
+	/* Forward pause information to TX block */
+	rxx_frm_ctl.s.ctl_bck = 1;
+	/* Drop Control Pause Frames */
+	rxx_frm_ctl.s.ctl_drp = 1;
+	/* Strip off the preamble */
+	rxx_frm_ctl.s.pre_strp = 1;
+	/*
+	 * This port is configured to send PREAMBLE+SFD to begin every
+	 * frame.  GMX checks that the PREAMBLE is sent correctly.
+	 */
+	rxx_frm_ctl.s.pre_chk = 1;
+	cvmx_write_csr(CVMX_AGL_GMX_RXX_FRM_CTL(port), rxx_frm_ctl.u64);
+
+	/* Enable the AGL block */
+	agl_gmx_inf_mode.u64 = 0;
+	agl_gmx_inf_mode.s.en = 1;
+	cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64);
+
+	/* Configure the port duplex and enables */
+	prtx_cfg.u64 = cvmx_read_csr(CVMX_AGL_GMX_PRTX_CFG(port));
+	prtx_cfg.s.tx_en = 1;
+	prtx_cfg.s.rx_en = 1;
+	prtx_cfg.s.en = 1;
+	p->last_duplex = 1;
+	prtx_cfg.s.duplex = p->last_duplex;
+	cvmx_write_csr(CVMX_AGL_GMX_PRTX_CFG(port), prtx_cfg.u64);
+
+	p->last_link = 0;
+	netif_carrier_off(netdev);
+
+	if (octeon_mgmt_init_phy(netdev)) {
+		dev_err(p->dev, "Cannot initialize PHY.\n");
+		goto err_noirq;
+	}
+
+	netif_wake_queue(netdev);
+	napi_enable(&p->napi);
+
+	return 0;
+err_noirq:
+	octeon_mgmt_reset_hw(p);
+	dma_unmap_single(p->dev, p->rx_ring_handle,
+			 ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE),
+			 DMA_BIDIRECTIONAL);
+	kfree(p->rx_ring);
+err_nomem:
+	dma_unmap_single(p->dev, p->tx_ring_handle,
+			 ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE),
+			 DMA_BIDIRECTIONAL);
+	kfree(p->tx_ring);
+	return -ENOMEM;
+}
+
+static int octeon_mgmt_stop(struct net_device *netdev)
+{
+	struct octeon_mgmt *p = netdev_priv(netdev);
+
+	napi_disable(&p->napi);
+	netif_stop_queue(netdev);
+
+	if (p->phydev)
+		phy_disconnect(p->phydev);
+
+	netif_carrier_off(netdev);
+
+	octeon_mgmt_reset_hw(p);
+
+
+	free_irq(p->irq, netdev);
+
+	/* dma_unmap is a nop on Octeon, so just free everything.  */
+	skb_queue_purge(&p->tx_list);
+	skb_queue_purge(&p->rx_list);
+
+	dma_unmap_single(p->dev, p->rx_ring_handle,
+			 ring_size_to_bytes(OCTEON_MGMT_RX_RING_SIZE),
+			 DMA_BIDIRECTIONAL);
+	kfree(p->rx_ring);
+
+	dma_unmap_single(p->dev, p->tx_ring_handle,
+			 ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE),
+			 DMA_BIDIRECTIONAL);
+	kfree(p->tx_ring);
+
+
+	return 0;
+}
+
+static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+	struct octeon_mgmt *p = netdev_priv(netdev);
+	int port = p->port;
+	union mgmt_port_ring_entry re;
+	unsigned long flags;
+
+	re.d64 = 0;
+	re.s.len = skb->len;
+	re.s.addr = dma_map_single(p->dev, skb->data,
+				   skb->len,
+				   DMA_TO_DEVICE);
+
+	spin_lock_irqsave(&p->tx_list.lock, flags);
+
+	if (unlikely(p->tx_current_fill >=
+		     ring_max_fill(OCTEON_MGMT_TX_RING_SIZE))) {
+		spin_unlock_irqrestore(&p->tx_list.lock, flags);
+
+		dma_unmap_single(p->dev, re.s.addr, re.s.len,
+				 DMA_TO_DEVICE);
+
+		netif_stop_queue(netdev);
+		return NETDEV_TX_BUSY;
+	}
+
+	__skb_queue_tail(&p->tx_list, skb);
+
+	/* Put it in the ring.  */
+	p->tx_ring[p->tx_next] = re.d64;
+	p->tx_next = (p->tx_next + 1) % OCTEON_MGMT_TX_RING_SIZE;
+	p->tx_current_fill++;
+
+	spin_unlock_irqrestore(&p->tx_list.lock, flags);
+
+	dma_sync_single_for_device(p->dev, p->tx_ring_handle,
+				   ring_size_to_bytes(OCTEON_MGMT_TX_RING_SIZE),
+				   DMA_BIDIRECTIONAL);
+
+	netdev->stats.tx_packets++;
+	netdev->stats.tx_bytes += skb->len;
+
+	/* Ring the bell.  */
+	cvmx_write_csr(CVMX_MIXX_ORING2(port), 1);
+
+	netdev->trans_start = jiffies;
+	octeon_mgmt_clean_tx_buffers(p);
+	octeon_mgmt_update_tx_stats(netdev);
+	return NETDEV_TX_OK;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void octeon_mgmt_poll_controller(struct net_device *netdev)
+{
+	struct octeon_mgmt *p = netdev_priv(netdev);
+
+	octeon_mgmt_receive_packets(p, 16);
+	octeon_mgmt_update_rx_stats(netdev);
+	return;
+}
+#endif
+
+static void octeon_mgmt_get_drvinfo(struct net_device *netdev,
+				    struct ethtool_drvinfo *info)
+{
+	strncpy(info->driver, DRV_NAME, sizeof(info->driver));
+	strncpy(info->version, DRV_VERSION, sizeof(info->version));
+	strncpy(info->fw_version, "N/A", sizeof(info->fw_version));
+	strncpy(info->bus_info, "N/A", sizeof(info->bus_info));
+	info->n_stats = 0;
+	info->testinfo_len = 0;
+	info->regdump_len = 0;
+	info->eedump_len = 0;
+}
+
+static int octeon_mgmt_get_settings(struct net_device *netdev,
+				    struct ethtool_cmd *cmd)
+{
+	struct octeon_mgmt *p = netdev_priv(netdev);
+
+	if (p->phydev)
+		return phy_ethtool_gset(p->phydev, cmd);
+
+	return -EINVAL;
+}
+
+static int octeon_mgmt_set_settings(struct net_device *netdev,
+				    struct ethtool_cmd *cmd)
+{
+	struct octeon_mgmt *p = netdev_priv(netdev);
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+
+	if (p->phydev)
+		return phy_ethtool_sset(p->phydev, cmd);
+
+	return -EINVAL;
+}
+
+static const struct ethtool_ops octeon_mgmt_ethtool_ops = {
+	.get_drvinfo = octeon_mgmt_get_drvinfo,
+	.get_link = ethtool_op_get_link,
+	.get_settings = octeon_mgmt_get_settings,
+	.set_settings = octeon_mgmt_set_settings
+};
+
+static const struct net_device_ops octeon_mgmt_ops = {
+	.ndo_open =			octeon_mgmt_open,
+	.ndo_stop =			octeon_mgmt_stop,
+	.ndo_start_xmit =		octeon_mgmt_xmit,
+	.ndo_set_rx_mode = 		octeon_mgmt_set_rx_filtering,
+	.ndo_set_multicast_list =	octeon_mgmt_set_rx_filtering,
+	.ndo_set_mac_address =		octeon_mgmt_set_mac_address,
+	.ndo_do_ioctl = 		octeon_mgmt_ioctl,
+	.ndo_change_mtu =		octeon_mgmt_change_mtu,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+	.ndo_poll_controller =		octeon_mgmt_poll_controller,
+#endif
+};
+
+static int __init octeon_mgmt_probe(struct platform_device *pdev)
+{
+	struct resource *res_irq;
+	struct net_device *netdev;
+	struct octeon_mgmt *p;
+	int i;
+
+	netdev = alloc_etherdev(sizeof(struct octeon_mgmt));
+	if (netdev == NULL)
+		return -ENOMEM;
+
+	dev_set_drvdata(&pdev->dev, netdev);
+	p = netdev_priv(netdev);
+	netif_napi_add(netdev, &p->napi, octeon_mgmt_napi_poll,
+		       OCTEON_MGMT_NAPI_WEIGHT);
+
+	p->netdev = netdev;
+	p->dev = &pdev->dev;
+
+	p->port = pdev->id;
+	snprintf(netdev->name, IFNAMSIZ, "mgmt%d", p->port);
+
+	res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res_irq)
+		goto err;
+
+	p->irq = res_irq->start;
+	spin_lock_init(&p->lock);
+
+	skb_queue_head_init(&p->tx_list);
+	skb_queue_head_init(&p->rx_list);
+	tasklet_init(&p->tx_clean_tasklet,
+		     octeon_mgmt_clean_tx_tasklet, (unsigned long)p);
+
+	netdev->netdev_ops = &octeon_mgmt_ops;
+	netdev->ethtool_ops = &octeon_mgmt_ethtool_ops;
+
+
+	/* The mgmt ports get the first N MACs.  */
+	for (i = 0; i < 6; i++)
+		netdev->dev_addr[i] = octeon_bootinfo->mac_addr_base[i];
+	netdev->dev_addr[5] += p->port;
+
+	if (p->port >= octeon_bootinfo->mac_addr_count)
+		dev_err(&pdev->dev,
+			"Error %s: Using MAC outside of the assigned range: "
+			"%02x:%02x:%02x:%02x:%02x:%02x\n", netdev->name,
+			netdev->dev_addr[0], netdev->dev_addr[1],
+			netdev->dev_addr[2], netdev->dev_addr[3],
+			netdev->dev_addr[4], netdev->dev_addr[5]);
+
+	if (register_netdev(netdev))
+		goto err;
+
+	dev_info(&pdev->dev, "Version " DRV_VERSION "\n");
+	return 0;
+err:
+	free_netdev(netdev);
+	return -ENOENT;
+}
+
+static int __exit octeon_mgmt_remove(struct platform_device *pdev)
+{
+	struct net_device *netdev = dev_get_drvdata(&pdev->dev);
+
+	unregister_netdev(netdev);
+	free_netdev(netdev);
+	return 0;
+}
+
+static struct platform_driver octeon_mgmt_driver = {
+	.driver = {
+		.name		= "octeon_mgmt",
+		.owner		= THIS_MODULE,
+	},
+	.probe		= octeon_mgmt_probe,
+	.remove		= __exit_p(octeon_mgmt_remove),
+};
+
+extern void octeon_mdiobus_force_mod_depencency(void);
+
+static int __init octeon_mgmt_mod_init(void)
+{
+	/* Force our mdiobus driver module to be loaded first. */
+	octeon_mdiobus_force_mod_depencency();
+	return platform_driver_register(&octeon_mgmt_driver);
+}
+
+static void __exit octeon_mgmt_mod_exit(void)
+{
+	platform_driver_unregister(&octeon_mgmt_driver);
+}
+
+module_init(octeon_mgmt_mod_init);
+module_exit(octeon_mgmt_mod_exit);
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_AUTHOR("David Daney");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
-- 
1.6.0.6


From David.Daney@caviumnetworks.com Thu Oct  8 01:12:26 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 01:12:34 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:16111 "EHLO
	mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S2097323AbZJGXK0 (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 01:10:26 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,5,4,7535)
	id <B4acd1fd90003>; Wed, 07 Oct 2009 16:10:17 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 16:10:20 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 16:10:20 -0700
Received: from dd1.caveonetworks.com (localhost.localdomain [127.0.0.1])
	by dd1.caveonetworks.com (8.14.2/8.14.2) with ESMTP id n97NAGtr007658;
	Wed, 7 Oct 2009 16:10:17 -0700
Received: (from ddaney@localhost)
	by dd1.caveonetworks.com (8.14.2/8.14.2/Submit) id n97NAFxt007657;
	Wed, 7 Oct 2009 16:10:15 -0700
From:	David Daney <ddaney@caviumnetworks.com>
To:	ralf@linux-mips.org, linux-mips@linux-mips.org,
	netdev@vger.kernel.org
Cc:	David Daney <ddaney@caviumnetworks.com>
Subject: [PATCH 1/6] MIPS: Octeon: Add platform device for MDIO buses.
Date:	Wed,  7 Oct 2009 16:10:10 -0700
Message-Id: <1254957015-7633-1-git-send-email-ddaney@caviumnetworks.com>
X-Mailer: git-send-email 1.6.0.6
In-Reply-To: <4ACD1F4E.8090603@caviumnetworks.com>
References: <4ACD1F4E.8090603@caviumnetworks.com>
X-OriginalArrivalTime: 07 Oct 2009 23:10:20.0137 (UTC) FILETIME=[572E3D90:01CA47A3]
Return-Path: <David.Daney@caviumnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24170
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ddaney@caviumnetworks.com
Precedence: bulk
X-list: linux-mips

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---
 arch/mips/cavium-octeon/octeon-platform.c |   30 +++++++++++++++++++++++++++++
 1 files changed, 30 insertions(+), 0 deletions(-)

diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c
index be711dd..febfdd7 100644
--- a/arch/mips/cavium-octeon/octeon-platform.c
+++ b/arch/mips/cavium-octeon/octeon-platform.c
@@ -159,6 +159,36 @@ out:
 }
 device_initcall(octeon_rng_device_init);
 
+/* Octeon SMI/MDIO interface.  */
+static int __init octeon_mdiobus_device_init(void)
+{
+	struct platform_device *pd;
+	int ret = 0;
+
+	if (octeon_is_simulation())
+		return 0; /* No mdio in the simulator. */
+
+	/* The bus number is the platform_device id.  */
+	pd = platform_device_alloc("mdio-octeon", 0);
+	if (!pd) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = platform_device_add(pd);
+	if (ret)
+		goto fail;
+
+	return ret;
+fail:
+	platform_device_put(pd);
+
+out:
+	return ret;
+
+}
+device_initcall(octeon_mdiobus_device_init);
+
 MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Platform driver for Octeon SOC");
-- 
1.6.0.6


From David.Daney@caviumnetworks.com Thu Oct  8 02:14:03 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 02:14:10 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:17573 "EHLO
	mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492981AbZJHAOD (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 02:14:03 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,5,4,7535)
	id <B4acd2ec00001>; Wed, 07 Oct 2009 17:13:52 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 17:13:51 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 17:13:51 -0700
Message-ID: <4ACD2EBF.8020901@caviumnetworks.com>
Date:	Wed, 07 Oct 2009 17:13:51 -0700
From:	David Daney <ddaney@caviumnetworks.com>
User-Agent: Thunderbird 2.0.0.21 (X11/20090320)
MIME-Version: 1.0
To:	Ralf Baechle <ralf@linux-mips.org>,
	linux-mips <linux-mips@linux-mips.org>,
	linux-usb@vger.kernel.org, Greg Kroah-Hartman <gregkh@suse.de>
Subject: [PATCH 0/2] USB: Add USB HCD for Octeon SOCs.
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
X-OriginalArrivalTime: 08 Oct 2009 00:13:51.0364 (UTC) FILETIME=[36D95440:01CA47AC]
Return-Path: <David.Daney@caviumnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24171
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ddaney@caviumnetworks.com
Precedence: bulk
X-list: linux-mips

The subject line kind of says it all.

Some members of the Cavium Networks Octeon family of SOCs contain the
Synopsys DWC-OTG USB controller.  This patch set adds the
corresponding driver.

The first patch adds between zero and two Octeon platform devices.
The second is the driver.

I have done a little bit of clean-up on the driver code, but
undoubtedly the careful scrutiny of the USB maintainers will uncover
more opportunities for improvement.  I look foreword to seeing any
suggestions for how the code might be changed so that it could be
merged.


I will reply with the two patches.

David Daney (2):
   MIPS: Octeon: Add USB platform device.
   USB: Add HCD for Octeon SOC

  arch/mips/cavium-octeon/octeon-platform.c      |  105 +
  arch/mips/include/asm/octeon/cvmx-usbcx-defs.h | 1199 ++++++++++
  arch/mips/include/asm/octeon/cvmx-usbnx-defs.h |  760 +++++++
  drivers/usb/host/Kconfig                       |    8 +
  drivers/usb/host/Makefile                      |    1 +
  drivers/usb/host/dwc_otg/Kbuild                |   16 +
  drivers/usb/host/dwc_otg/dwc_otg_attr.c        |  854 +++++++
  drivers/usb/host/dwc_otg/dwc_otg_attr.h        |   63 +
  drivers/usb/host/dwc_otg/dwc_otg_cil.c         | 2887 
++++++++++++++++++++++++
  drivers/usb/host/dwc_otg/dwc_otg_cil.h         |  866 +++++++
  drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c    |  689 ++++++
  drivers/usb/host/dwc_otg/dwc_otg_driver.h      |   63 +
  drivers/usb/host/dwc_otg/dwc_otg_hcd.c         | 2878 
+++++++++++++++++++++++
  drivers/usb/host/dwc_otg/dwc_otg_hcd.h         |  661 ++++++
  drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c    | 1890 ++++++++++++++++
  drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c   |  695 ++++++
  drivers/usb/host/dwc_otg/dwc_otg_octeon.c      | 1078 +++++++++
  drivers/usb/host/dwc_otg/dwc_otg_plat.h        |  236 ++
  drivers/usb/host/dwc_otg/dwc_otg_regs.h        | 2355 +++++++++++++++++++
  19 files changed, 17304 insertions(+), 0 deletions(-)
  create mode 100644 arch/mips/include/asm/octeon/cvmx-usbcx-defs.h
  create mode 100644 arch/mips/include/asm/octeon/cvmx-usbnx-defs.h
  create mode 100644 drivers/usb/host/dwc_otg/Kbuild
  create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.c
  create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.h
  create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.c
  create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.h
  create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
  create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.h
  create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.c
  create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.h
  create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
  create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
  create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_octeon.c
  create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_plat.h
  create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_regs.h


From David.Daney@caviumnetworks.com Thu Oct  8 02:15:58 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 02:16:04 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:17623 "EHLO
	mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492981AbZJHAP6 (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 02:15:58 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,5,4,7535)
	id <B4acd2f380000>; Wed, 07 Oct 2009 17:15:52 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 17:15:30 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 17:15:30 -0700
Received: from dd1.caveonetworks.com (localhost.localdomain [127.0.0.1])
	by dd1.caveonetworks.com (8.14.2/8.14.2) with ESMTP id n980FRIq012211;
	Wed, 7 Oct 2009 17:15:27 -0700
Received: (from ddaney@localhost)
	by dd1.caveonetworks.com (8.14.2/8.14.2/Submit) id n980FQMm012209;
	Wed, 7 Oct 2009 17:15:26 -0700
From:	David Daney <ddaney@caviumnetworks.com>
To:	ralf@linux-mips.org, linux-mips@linux-mips.org,
	linux-usb@vger.kernel.org, gregkh@suse.de
Cc:	David Daney <ddaney@caviumnetworks.com>
Subject: [PATCH 1/2] MIPS: Octeon: Add USB platform device.
Date:	Wed,  7 Oct 2009 17:15:25 -0700
Message-Id: <1254960926-12185-1-git-send-email-ddaney@caviumnetworks.com>
X-Mailer: git-send-email 1.6.0.6
In-Reply-To: <4ACD2EBF.8020901@caviumnetworks.com>
References: <4ACD2EBF.8020901@caviumnetworks.com>
X-OriginalArrivalTime: 08 Oct 2009 00:15:30.0115 (UTC) FILETIME=[71B58930:01CA47AC]
Return-Path: <David.Daney@caviumnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24172
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ddaney@caviumnetworks.com
Precedence: bulk
X-list: linux-mips

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---
 arch/mips/cavium-octeon/octeon-platform.c      |  105 ++
 arch/mips/include/asm/octeon/cvmx-usbcx-defs.h | 1199 ++++++++++++++++++++++++
 arch/mips/include/asm/octeon/cvmx-usbnx-defs.h |  760 +++++++++++++++
 3 files changed, 2064 insertions(+), 0 deletions(-)
 create mode 100644 arch/mips/include/asm/octeon/cvmx-usbcx-defs.h
 create mode 100644 arch/mips/include/asm/octeon/cvmx-usbnx-defs.h

diff --git a/arch/mips/cavium-octeon/octeon-platform.c b/arch/mips/cavium-octeon/octeon-platform.c
index cfdb4c2..20698a6 100644
--- a/arch/mips/cavium-octeon/octeon-platform.c
+++ b/arch/mips/cavium-octeon/octeon-platform.c
@@ -7,13 +7,19 @@
  * Copyright (C) 2008 Wind River Systems
  */
 
+#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/irq.h>
+#include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 
+#include <asm/time.h>
+
 #include <asm/octeon/octeon.h>
 #include <asm/octeon/cvmx-rnm-defs.h>
+#include <asm/octeon/cvmx-usbnx-defs.h>
+#include <asm/octeon/cvmx-usbcx-defs.h>
 
 static struct octeon_cf_data octeon_cf_data;
 
@@ -247,6 +253,105 @@ out:
 }
 device_initcall(octeon_mgmt_device_init);
 
+/* Octeon USB. */
+static int __init octeon_usb_device_init(void)
+{
+	int p_rtype_ref_clk = 2;
+	int number_usb_ports;
+	int usb_port;
+	int ret = 0;
+
+	if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) {
+		number_usb_ports = 0;
+	} else if (OCTEON_IS_MODEL(OCTEON_CN52XX)) {
+		number_usb_ports = 2;
+		/* CN52XX encodes this field differently */
+		p_rtype_ref_clk = 1;
+	} else {
+		number_usb_ports = 1;
+	}
+
+	for (usb_port = 0; usb_port < number_usb_ports; usb_port++) {
+		int divisor;
+		union cvmx_usbnx_clk_ctl usbn_clk_ctl;
+		struct platform_device *pdev;
+		struct resource usb_resource[2];
+
+		/*
+		 * Divide the core clock down such that USB is as
+		 * close as possible to 125Mhz.
+		 */
+		divisor = DIV_ROUND_UP(mips_hpt_frequency, 125000000);
+		/* Lower than 4 doesn't seem to work properly */
+		if (divisor < 4)
+			divisor = 4;
+
+		/* Fetch the value of the Register, and de-assert POR */
+		usbn_clk_ctl.u64 = cvmx_read_csr(CVMX_USBNX_CLK_CTL(usb_port));
+		usbn_clk_ctl.s.por = 0;
+		if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
+			usbn_clk_ctl.cn31xx.p_rclk = 1;
+			usbn_clk_ctl.cn31xx.p_xenbn = 0;
+		} else {
+			if (cvmx_sysinfo_get()->board_type !=
+			    CVMX_BOARD_TYPE_BBGW_REF)
+				usbn_clk_ctl.cn56xx.p_rtype = p_rtype_ref_clk;
+			else
+				usbn_clk_ctl.cn56xx.p_rtype = 0;
+		}
+		usbn_clk_ctl.s.divide = divisor;
+		usbn_clk_ctl.s.divide2 = 0;
+		cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb_port), usbn_clk_ctl.u64);
+
+		/* Wait for POR */
+		udelay(850);
+
+		usbn_clk_ctl.u64 = cvmx_read_csr(CVMX_USBNX_CLK_CTL(usb_port));
+		usbn_clk_ctl.s.por = 0;
+		if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
+			usbn_clk_ctl.cn31xx.p_rclk = 1;
+			usbn_clk_ctl.cn31xx.p_xenbn = 0;
+		} else {
+			if (cvmx_sysinfo_get()->board_type !=
+			    CVMX_BOARD_TYPE_BBGW_REF)
+				usbn_clk_ctl.cn56xx.p_rtype = p_rtype_ref_clk;
+			else
+				usbn_clk_ctl.cn56xx.p_rtype = 0;
+		}
+		usbn_clk_ctl.s.prst = 1;
+		cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb_port), usbn_clk_ctl.u64);
+
+		udelay(1);
+
+		usbn_clk_ctl.s.hrst = 1;
+		cvmx_write_csr(CVMX_USBNX_CLK_CTL(usb_port), usbn_clk_ctl.u64);
+		udelay(1);
+
+		memset(usb_resource, 0, sizeof(usb_resource));
+		usb_resource[0].start =
+			XKPHYS_TO_PHYS(CVMX_USBCX_GOTGCTL(usb_port));
+		usb_resource[0].end = usb_resource[0].start + 0x10000;
+		usb_resource[0].flags = IORESOURCE_MEM;
+
+		usb_resource[1].start = (usb_port == 0) ?
+			OCTEON_IRQ_USB0 : OCTEON_IRQ_USB1;
+		usb_resource[1].end = usb_resource[1].start;
+		usb_resource[1].flags = IORESOURCE_IRQ;
+
+		pdev = platform_device_register_simple("dwc_otg",
+						       usb_port,
+						       usb_resource, 2);
+		if (!pdev) {
+			pr_err("dwc_otg: Failed to allocate platform device "
+			       "for USB%d\n", usb_port);
+			ret = -ENOMEM;
+		}
+	}
+
+	return ret;
+}
+device_initcall(octeon_usb_device_init);
+
 MODULE_AUTHOR("David Daney <ddaney@caviumnetworks.com>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Platform driver for Octeon SOC");
diff --git a/arch/mips/include/asm/octeon/cvmx-usbcx-defs.h b/arch/mips/include/asm/octeon/cvmx-usbcx-defs.h
new file mode 100644
index 0000000..c1e078e
--- /dev/null
+++ b/arch/mips/include/asm/octeon/cvmx-usbcx-defs.h
@@ -0,0 +1,1199 @@
+/***********************license start***************
+ * Author: Cavium Networks
+ *
+ * Contact: support@caviumnetworks.com
+ * This file is part of the OCTEON SDK
+ *
+ * Copyright (c) 2003-2008 Cavium Networks
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * or visit http://www.gnu.org/licenses/.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium Networks for more information
+ ***********************license end**************************************/
+
+#ifndef __CVMX_USBCX_DEFS_H__
+#define __CVMX_USBCX_DEFS_H__
+
+#define CVMX_USBCX_DAINT(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000818ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DAINTMSK(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F001000081Cull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DCFG(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000800ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DCTL(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000804ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DIEPCTLX(offset, block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000900ull + (((offset) & 7) * 32) + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DIEPINTX(offset, block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000908ull + (((offset) & 7) * 32) + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DIEPMSK(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000810ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DIEPTSIZX(offset, block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000910ull + (((offset) & 7) * 32) + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DOEPCTLX(offset, block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000B00ull + (((offset) & 7) * 32) + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DOEPINTX(offset, block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000B08ull + (((offset) & 7) * 32) + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DOEPMSK(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000814ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DOEPTSIZX(offset, block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000B10ull + (((offset) & 7) * 32) + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DPTXFSIZX(offset, block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000100ull + (((offset) & 7) * 4) + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DSTS(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000808ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DTKNQR1(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000820ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DTKNQR2(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000824ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DTKNQR3(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000830ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_DTKNQR4(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000834ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GAHBCFG(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000008ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GHWCFG1(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000044ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GHWCFG2(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000048ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GHWCFG3(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F001000004Cull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GHWCFG4(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000050ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GINTMSK(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000018ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GINTSTS(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000014ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GNPTXFSIZ(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000028ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GNPTXSTS(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F001000002Cull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GOTGCTL(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000000ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GOTGINT(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000004ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GRSTCTL(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000010ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GRXFSIZ(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000024ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GRXSTSPD(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010040020ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GRXSTSPH(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000020ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GRXSTSRD(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F001004001Cull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GRXSTSRH(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F001000001Cull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GSNPSID(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000040ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_GUSBCFG(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F001000000Cull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_HAINT(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000414ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_HAINTMSK(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000418ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_HCCHARX(offset, block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000500ull + (((offset) & 7) * 32) + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_HCFG(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000400ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_HCINTMSKX(offset, block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F001000050Cull + (((offset) & 7) * 32) + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_HCINTX(offset, block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000508ull + (((offset) & 7) * 32) + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_HCSPLTX(offset, block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000504ull + (((offset) & 7) * 32) + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_HCTSIZX(offset, block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000510ull + (((offset) & 7) * 32) + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_HFIR(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000404ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_HFNUM(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000408ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_HPRT(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000440ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_HPTXFSIZ(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000100ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_HPTXSTS(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000410ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_NPTXDFIFOX(offset, block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010001000ull + (((offset) & 7) * 4096) + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBCX_PCGCCTL(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0010000E00ull + (((block_id) & 1) * 0x100000000000ull))
+
+union cvmx_usbcx_daint {
+	uint32_t u32;
+	struct cvmx_usbcx_daint_s {
+		uint32_t outepint:16;
+		uint32_t inepint:16;
+	} s;
+	struct cvmx_usbcx_daint_s cn30xx;
+	struct cvmx_usbcx_daint_s cn31xx;
+	struct cvmx_usbcx_daint_s cn50xx;
+	struct cvmx_usbcx_daint_s cn52xx;
+	struct cvmx_usbcx_daint_s cn52xxp1;
+	struct cvmx_usbcx_daint_s cn56xx;
+	struct cvmx_usbcx_daint_s cn56xxp1;
+};
+
+union cvmx_usbcx_daintmsk {
+	uint32_t u32;
+	struct cvmx_usbcx_daintmsk_s {
+		uint32_t outepmsk:16;
+		uint32_t inepmsk:16;
+	} s;
+	struct cvmx_usbcx_daintmsk_s cn30xx;
+	struct cvmx_usbcx_daintmsk_s cn31xx;
+	struct cvmx_usbcx_daintmsk_s cn50xx;
+	struct cvmx_usbcx_daintmsk_s cn52xx;
+	struct cvmx_usbcx_daintmsk_s cn52xxp1;
+	struct cvmx_usbcx_daintmsk_s cn56xx;
+	struct cvmx_usbcx_daintmsk_s cn56xxp1;
+};
+
+union cvmx_usbcx_dcfg {
+	uint32_t u32;
+	struct cvmx_usbcx_dcfg_s {
+		uint32_t reserved_23_31:9;
+		uint32_t epmiscnt:5;
+		uint32_t reserved_13_17:5;
+		uint32_t perfrint:2;
+		uint32_t devaddr:7;
+		uint32_t reserved_3_3:1;
+		uint32_t nzstsouthshk:1;
+		uint32_t devspd:2;
+	} s;
+	struct cvmx_usbcx_dcfg_s cn30xx;
+	struct cvmx_usbcx_dcfg_s cn31xx;
+	struct cvmx_usbcx_dcfg_s cn50xx;
+	struct cvmx_usbcx_dcfg_s cn52xx;
+	struct cvmx_usbcx_dcfg_s cn52xxp1;
+	struct cvmx_usbcx_dcfg_s cn56xx;
+	struct cvmx_usbcx_dcfg_s cn56xxp1;
+};
+
+union cvmx_usbcx_dctl {
+	uint32_t u32;
+	struct cvmx_usbcx_dctl_s {
+		uint32_t reserved_12_31:20;
+		uint32_t pwronprgdone:1;
+		uint32_t cgoutnak:1;
+		uint32_t sgoutnak:1;
+		uint32_t cgnpinnak:1;
+		uint32_t sgnpinnak:1;
+		uint32_t tstctl:3;
+		uint32_t goutnaksts:1;
+		uint32_t gnpinnaksts:1;
+		uint32_t sftdiscon:1;
+		uint32_t rmtwkupsig:1;
+	} s;
+	struct cvmx_usbcx_dctl_s cn30xx;
+	struct cvmx_usbcx_dctl_s cn31xx;
+	struct cvmx_usbcx_dctl_s cn50xx;
+	struct cvmx_usbcx_dctl_s cn52xx;
+	struct cvmx_usbcx_dctl_s cn52xxp1;
+	struct cvmx_usbcx_dctl_s cn56xx;
+	struct cvmx_usbcx_dctl_s cn56xxp1;
+};
+
+union cvmx_usbcx_diepctlx {
+	uint32_t u32;
+	struct cvmx_usbcx_diepctlx_s {
+		uint32_t epena:1;
+		uint32_t epdis:1;
+		uint32_t setd1pid:1;
+		uint32_t setd0pid:1;
+		uint32_t snak:1;
+		uint32_t cnak:1;
+		uint32_t txfnum:4;
+		uint32_t stall:1;
+		uint32_t reserved_20_20:1;
+		uint32_t eptype:2;
+		uint32_t naksts:1;
+		uint32_t dpid:1;
+		uint32_t usbactep:1;
+		uint32_t nextep:4;
+		uint32_t mps:11;
+	} s;
+	struct cvmx_usbcx_diepctlx_s cn30xx;
+	struct cvmx_usbcx_diepctlx_s cn31xx;
+	struct cvmx_usbcx_diepctlx_s cn50xx;
+	struct cvmx_usbcx_diepctlx_s cn52xx;
+	struct cvmx_usbcx_diepctlx_s cn52xxp1;
+	struct cvmx_usbcx_diepctlx_s cn56xx;
+	struct cvmx_usbcx_diepctlx_s cn56xxp1;
+};
+
+union cvmx_usbcx_diepintx {
+	uint32_t u32;
+	struct cvmx_usbcx_diepintx_s {
+		uint32_t reserved_7_31:25;
+		uint32_t inepnakeff:1;
+		uint32_t intknepmis:1;
+		uint32_t intkntxfemp:1;
+		uint32_t timeout:1;
+		uint32_t ahberr:1;
+		uint32_t epdisbld:1;
+		uint32_t xfercompl:1;
+	} s;
+	struct cvmx_usbcx_diepintx_s cn30xx;
+	struct cvmx_usbcx_diepintx_s cn31xx;
+	struct cvmx_usbcx_diepintx_s cn50xx;
+	struct cvmx_usbcx_diepintx_s cn52xx;
+	struct cvmx_usbcx_diepintx_s cn52xxp1;
+	struct cvmx_usbcx_diepintx_s cn56xx;
+	struct cvmx_usbcx_diepintx_s cn56xxp1;
+};
+
+union cvmx_usbcx_diepmsk {
+	uint32_t u32;
+	struct cvmx_usbcx_diepmsk_s {
+		uint32_t reserved_7_31:25;
+		uint32_t inepnakeffmsk:1;
+		uint32_t intknepmismsk:1;
+		uint32_t intkntxfempmsk:1;
+		uint32_t timeoutmsk:1;
+		uint32_t ahberrmsk:1;
+		uint32_t epdisbldmsk:1;
+		uint32_t xfercomplmsk:1;
+	} s;
+	struct cvmx_usbcx_diepmsk_s cn30xx;
+	struct cvmx_usbcx_diepmsk_s cn31xx;
+	struct cvmx_usbcx_diepmsk_s cn50xx;
+	struct cvmx_usbcx_diepmsk_s cn52xx;
+	struct cvmx_usbcx_diepmsk_s cn52xxp1;
+	struct cvmx_usbcx_diepmsk_s cn56xx;
+	struct cvmx_usbcx_diepmsk_s cn56xxp1;
+};
+
+union cvmx_usbcx_dieptsizx {
+	uint32_t u32;
+	struct cvmx_usbcx_dieptsizx_s {
+		uint32_t reserved_31_31:1;
+		uint32_t mc:2;
+		uint32_t pktcnt:10;
+		uint32_t xfersize:19;
+	} s;
+	struct cvmx_usbcx_dieptsizx_s cn30xx;
+	struct cvmx_usbcx_dieptsizx_s cn31xx;
+	struct cvmx_usbcx_dieptsizx_s cn50xx;
+	struct cvmx_usbcx_dieptsizx_s cn52xx;
+	struct cvmx_usbcx_dieptsizx_s cn52xxp1;
+	struct cvmx_usbcx_dieptsizx_s cn56xx;
+	struct cvmx_usbcx_dieptsizx_s cn56xxp1;
+};
+
+union cvmx_usbcx_doepctlx {
+	uint32_t u32;
+	struct cvmx_usbcx_doepctlx_s {
+		uint32_t epena:1;
+		uint32_t epdis:1;
+		uint32_t setd1pid:1;
+		uint32_t setd0pid:1;
+		uint32_t snak:1;
+		uint32_t cnak:1;
+		uint32_t reserved_22_25:4;
+		uint32_t stall:1;
+		uint32_t snp:1;
+		uint32_t eptype:2;
+		uint32_t naksts:1;
+		uint32_t dpid:1;
+		uint32_t usbactep:1;
+		uint32_t reserved_11_14:4;
+		uint32_t mps:11;
+	} s;
+	struct cvmx_usbcx_doepctlx_s cn30xx;
+	struct cvmx_usbcx_doepctlx_s cn31xx;
+	struct cvmx_usbcx_doepctlx_s cn50xx;
+	struct cvmx_usbcx_doepctlx_s cn52xx;
+	struct cvmx_usbcx_doepctlx_s cn52xxp1;
+	struct cvmx_usbcx_doepctlx_s cn56xx;
+	struct cvmx_usbcx_doepctlx_s cn56xxp1;
+};
+
+union cvmx_usbcx_doepintx {
+	uint32_t u32;
+	struct cvmx_usbcx_doepintx_s {
+		uint32_t reserved_5_31:27;
+		uint32_t outtknepdis:1;
+		uint32_t setup:1;
+		uint32_t ahberr:1;
+		uint32_t epdisbld:1;
+		uint32_t xfercompl:1;
+	} s;
+	struct cvmx_usbcx_doepintx_s cn30xx;
+	struct cvmx_usbcx_doepintx_s cn31xx;
+	struct cvmx_usbcx_doepintx_s cn50xx;
+	struct cvmx_usbcx_doepintx_s cn52xx;
+	struct cvmx_usbcx_doepintx_s cn52xxp1;
+	struct cvmx_usbcx_doepintx_s cn56xx;
+	struct cvmx_usbcx_doepintx_s cn56xxp1;
+};
+
+union cvmx_usbcx_doepmsk {
+	uint32_t u32;
+	struct cvmx_usbcx_doepmsk_s {
+		uint32_t reserved_5_31:27;
+		uint32_t outtknepdismsk:1;
+		uint32_t setupmsk:1;
+		uint32_t ahberrmsk:1;
+		uint32_t epdisbldmsk:1;
+		uint32_t xfercomplmsk:1;
+	} s;
+	struct cvmx_usbcx_doepmsk_s cn30xx;
+	struct cvmx_usbcx_doepmsk_s cn31xx;
+	struct cvmx_usbcx_doepmsk_s cn50xx;
+	struct cvmx_usbcx_doepmsk_s cn52xx;
+	struct cvmx_usbcx_doepmsk_s cn52xxp1;
+	struct cvmx_usbcx_doepmsk_s cn56xx;
+	struct cvmx_usbcx_doepmsk_s cn56xxp1;
+};
+
+union cvmx_usbcx_doeptsizx {
+	uint32_t u32;
+	struct cvmx_usbcx_doeptsizx_s {
+		uint32_t reserved_31_31:1;
+		uint32_t mc:2;
+		uint32_t pktcnt:10;
+		uint32_t xfersize:19;
+	} s;
+	struct cvmx_usbcx_doeptsizx_s cn30xx;
+	struct cvmx_usbcx_doeptsizx_s cn31xx;
+	struct cvmx_usbcx_doeptsizx_s cn50xx;
+	struct cvmx_usbcx_doeptsizx_s cn52xx;
+	struct cvmx_usbcx_doeptsizx_s cn52xxp1;
+	struct cvmx_usbcx_doeptsizx_s cn56xx;
+	struct cvmx_usbcx_doeptsizx_s cn56xxp1;
+};
+
+union cvmx_usbcx_dptxfsizx {
+	uint32_t u32;
+	struct cvmx_usbcx_dptxfsizx_s {
+		uint32_t dptxfsize:16;
+		uint32_t dptxfstaddr:16;
+	} s;
+	struct cvmx_usbcx_dptxfsizx_s cn30xx;
+	struct cvmx_usbcx_dptxfsizx_s cn31xx;
+	struct cvmx_usbcx_dptxfsizx_s cn50xx;
+	struct cvmx_usbcx_dptxfsizx_s cn52xx;
+	struct cvmx_usbcx_dptxfsizx_s cn52xxp1;
+	struct cvmx_usbcx_dptxfsizx_s cn56xx;
+	struct cvmx_usbcx_dptxfsizx_s cn56xxp1;
+};
+
+union cvmx_usbcx_dsts {
+	uint32_t u32;
+	struct cvmx_usbcx_dsts_s {
+		uint32_t reserved_22_31:10;
+		uint32_t soffn:14;
+		uint32_t reserved_4_7:4;
+		uint32_t errticerr:1;
+		uint32_t enumspd:2;
+		uint32_t suspsts:1;
+	} s;
+	struct cvmx_usbcx_dsts_s cn30xx;
+	struct cvmx_usbcx_dsts_s cn31xx;
+	struct cvmx_usbcx_dsts_s cn50xx;
+	struct cvmx_usbcx_dsts_s cn52xx;
+	struct cvmx_usbcx_dsts_s cn52xxp1;
+	struct cvmx_usbcx_dsts_s cn56xx;
+	struct cvmx_usbcx_dsts_s cn56xxp1;
+};
+
+union cvmx_usbcx_dtknqr1 {
+	uint32_t u32;
+	struct cvmx_usbcx_dtknqr1_s {
+		uint32_t eptkn:24;
+		uint32_t wrapbit:1;
+		uint32_t reserved_5_6:2;
+		uint32_t intknwptr:5;
+	} s;
+	struct cvmx_usbcx_dtknqr1_s cn30xx;
+	struct cvmx_usbcx_dtknqr1_s cn31xx;
+	struct cvmx_usbcx_dtknqr1_s cn50xx;
+	struct cvmx_usbcx_dtknqr1_s cn52xx;
+	struct cvmx_usbcx_dtknqr1_s cn52xxp1;
+	struct cvmx_usbcx_dtknqr1_s cn56xx;
+	struct cvmx_usbcx_dtknqr1_s cn56xxp1;
+};
+
+union cvmx_usbcx_dtknqr2 {
+	uint32_t u32;
+	struct cvmx_usbcx_dtknqr2_s {
+		uint32_t eptkn:32;
+	} s;
+	struct cvmx_usbcx_dtknqr2_s cn30xx;
+	struct cvmx_usbcx_dtknqr2_s cn31xx;
+	struct cvmx_usbcx_dtknqr2_s cn50xx;
+	struct cvmx_usbcx_dtknqr2_s cn52xx;
+	struct cvmx_usbcx_dtknqr2_s cn52xxp1;
+	struct cvmx_usbcx_dtknqr2_s cn56xx;
+	struct cvmx_usbcx_dtknqr2_s cn56xxp1;
+};
+
+union cvmx_usbcx_dtknqr3 {
+	uint32_t u32;
+	struct cvmx_usbcx_dtknqr3_s {
+		uint32_t eptkn:32;
+	} s;
+	struct cvmx_usbcx_dtknqr3_s cn30xx;
+	struct cvmx_usbcx_dtknqr3_s cn31xx;
+	struct cvmx_usbcx_dtknqr3_s cn50xx;
+	struct cvmx_usbcx_dtknqr3_s cn52xx;
+	struct cvmx_usbcx_dtknqr3_s cn52xxp1;
+	struct cvmx_usbcx_dtknqr3_s cn56xx;
+	struct cvmx_usbcx_dtknqr3_s cn56xxp1;
+};
+
+union cvmx_usbcx_dtknqr4 {
+	uint32_t u32;
+	struct cvmx_usbcx_dtknqr4_s {
+		uint32_t eptkn:32;
+	} s;
+	struct cvmx_usbcx_dtknqr4_s cn30xx;
+	struct cvmx_usbcx_dtknqr4_s cn31xx;
+	struct cvmx_usbcx_dtknqr4_s cn50xx;
+	struct cvmx_usbcx_dtknqr4_s cn52xx;
+	struct cvmx_usbcx_dtknqr4_s cn52xxp1;
+	struct cvmx_usbcx_dtknqr4_s cn56xx;
+	struct cvmx_usbcx_dtknqr4_s cn56xxp1;
+};
+
+union cvmx_usbcx_gahbcfg {
+	uint32_t u32;
+	struct cvmx_usbcx_gahbcfg_s {
+		uint32_t reserved_9_31:23;
+		uint32_t ptxfemplvl:1;
+		uint32_t nptxfemplvl:1;
+		uint32_t reserved_6_6:1;
+		uint32_t dmaen:1;
+		uint32_t hbstlen:4;
+		uint32_t glblintrmsk:1;
+	} s;
+	struct cvmx_usbcx_gahbcfg_s cn30xx;
+	struct cvmx_usbcx_gahbcfg_s cn31xx;
+	struct cvmx_usbcx_gahbcfg_s cn50xx;
+	struct cvmx_usbcx_gahbcfg_s cn52xx;
+	struct cvmx_usbcx_gahbcfg_s cn52xxp1;
+	struct cvmx_usbcx_gahbcfg_s cn56xx;
+	struct cvmx_usbcx_gahbcfg_s cn56xxp1;
+};
+
+union cvmx_usbcx_ghwcfg1 {
+	uint32_t u32;
+	struct cvmx_usbcx_ghwcfg1_s {
+		uint32_t epdir:32;
+	} s;
+	struct cvmx_usbcx_ghwcfg1_s cn30xx;
+	struct cvmx_usbcx_ghwcfg1_s cn31xx;
+	struct cvmx_usbcx_ghwcfg1_s cn50xx;
+	struct cvmx_usbcx_ghwcfg1_s cn52xx;
+	struct cvmx_usbcx_ghwcfg1_s cn52xxp1;
+	struct cvmx_usbcx_ghwcfg1_s cn56xx;
+	struct cvmx_usbcx_ghwcfg1_s cn56xxp1;
+};
+
+union cvmx_usbcx_ghwcfg2 {
+	uint32_t u32;
+	struct cvmx_usbcx_ghwcfg2_s {
+		uint32_t reserved_31_31:1;
+		uint32_t tknqdepth:5;
+		uint32_t ptxqdepth:2;
+		uint32_t nptxqdepth:2;
+		uint32_t reserved_20_21:2;
+		uint32_t dynfifosizing:1;
+		uint32_t periosupport:1;
+		uint32_t numhstchnl:4;
+		uint32_t numdeveps:4;
+		uint32_t fsphytype:2;
+		uint32_t hsphytype:2;
+		uint32_t singpnt:1;
+		uint32_t otgarch:2;
+		uint32_t otgmode:3;
+	} s;
+	struct cvmx_usbcx_ghwcfg2_s cn30xx;
+	struct cvmx_usbcx_ghwcfg2_s cn31xx;
+	struct cvmx_usbcx_ghwcfg2_s cn50xx;
+	struct cvmx_usbcx_ghwcfg2_s cn52xx;
+	struct cvmx_usbcx_ghwcfg2_s cn52xxp1;
+	struct cvmx_usbcx_ghwcfg2_s cn56xx;
+	struct cvmx_usbcx_ghwcfg2_s cn56xxp1;
+};
+
+union cvmx_usbcx_ghwcfg3 {
+	uint32_t u32;
+	struct cvmx_usbcx_ghwcfg3_s {
+		uint32_t dfifodepth:16;
+		uint32_t reserved_13_15:3;
+		uint32_t ahbphysync:1;
+		uint32_t rsttype:1;
+		uint32_t optfeature:1;
+		uint32_t vendor_control_interface_support:1;
+		uint32_t i2c_selection:1;
+		uint32_t otgen:1;
+		uint32_t pktsizewidth:3;
+		uint32_t xfersizewidth:4;
+	} s;
+	struct cvmx_usbcx_ghwcfg3_s cn30xx;
+	struct cvmx_usbcx_ghwcfg3_s cn31xx;
+	struct cvmx_usbcx_ghwcfg3_s cn50xx;
+	struct cvmx_usbcx_ghwcfg3_s cn52xx;
+	struct cvmx_usbcx_ghwcfg3_s cn52xxp1;
+	struct cvmx_usbcx_ghwcfg3_s cn56xx;
+	struct cvmx_usbcx_ghwcfg3_s cn56xxp1;
+};
+
+union cvmx_usbcx_ghwcfg4 {
+	uint32_t u32;
+	struct cvmx_usbcx_ghwcfg4_s {
+		uint32_t reserved_30_31:2;
+		uint32_t numdevmodinend:4;
+		uint32_t endedtrfifo:1;
+		uint32_t sessendfltr:1;
+		uint32_t bvalidfltr:1;
+		uint32_t avalidfltr:1;
+		uint32_t vbusvalidfltr:1;
+		uint32_t iddgfltr:1;
+		uint32_t numctleps:4;
+		uint32_t phydatawidth:2;
+		uint32_t reserved_6_13:8;
+		uint32_t ahbfreq:1;
+		uint32_t enablepwropt:1;
+		uint32_t numdevperioeps:4;
+	} s;
+	struct cvmx_usbcx_ghwcfg4_cn30xx {
+		uint32_t reserved_25_31:7;
+		uint32_t sessendfltr:1;
+		uint32_t bvalidfltr:1;
+		uint32_t avalidfltr:1;
+		uint32_t vbusvalidfltr:1;
+		uint32_t iddgfltr:1;
+		uint32_t numctleps:4;
+		uint32_t phydatawidth:2;
+		uint32_t reserved_6_13:8;
+		uint32_t ahbfreq:1;
+		uint32_t enablepwropt:1;
+		uint32_t numdevperioeps:4;
+	} cn30xx;
+	struct cvmx_usbcx_ghwcfg4_cn30xx cn31xx;
+	struct cvmx_usbcx_ghwcfg4_s cn50xx;
+	struct cvmx_usbcx_ghwcfg4_s cn52xx;
+	struct cvmx_usbcx_ghwcfg4_s cn52xxp1;
+	struct cvmx_usbcx_ghwcfg4_s cn56xx;
+	struct cvmx_usbcx_ghwcfg4_s cn56xxp1;
+};
+
+union cvmx_usbcx_gintmsk {
+	uint32_t u32;
+	struct cvmx_usbcx_gintmsk_s {
+		uint32_t wkupintmsk:1;
+		uint32_t sessreqintmsk:1;
+		uint32_t disconnintmsk:1;
+		uint32_t conidstschngmsk:1;
+		uint32_t reserved_27_27:1;
+		uint32_t ptxfempmsk:1;
+		uint32_t hchintmsk:1;
+		uint32_t prtintmsk:1;
+		uint32_t reserved_23_23:1;
+		uint32_t fetsuspmsk:1;
+		uint32_t incomplpmsk:1;
+		uint32_t incompisoinmsk:1;
+		uint32_t oepintmsk:1;
+		uint32_t inepintmsk:1;
+		uint32_t epmismsk:1;
+		uint32_t reserved_16_16:1;
+		uint32_t eopfmsk:1;
+		uint32_t isooutdropmsk:1;
+		uint32_t enumdonemsk:1;
+		uint32_t usbrstmsk:1;
+		uint32_t usbsuspmsk:1;
+		uint32_t erlysuspmsk:1;
+		uint32_t i2cint:1;
+		uint32_t ulpickintmsk:1;
+		uint32_t goutnakeffmsk:1;
+		uint32_t ginnakeffmsk:1;
+		uint32_t nptxfempmsk:1;
+		uint32_t rxflvlmsk:1;
+		uint32_t sofmsk:1;
+		uint32_t otgintmsk:1;
+		uint32_t modemismsk:1;
+		uint32_t reserved_0_0:1;
+	} s;
+	struct cvmx_usbcx_gintmsk_s cn30xx;
+	struct cvmx_usbcx_gintmsk_s cn31xx;
+	struct cvmx_usbcx_gintmsk_s cn50xx;
+	struct cvmx_usbcx_gintmsk_s cn52xx;
+	struct cvmx_usbcx_gintmsk_s cn52xxp1;
+	struct cvmx_usbcx_gintmsk_s cn56xx;
+	struct cvmx_usbcx_gintmsk_s cn56xxp1;
+};
+
+union cvmx_usbcx_gintsts {
+	uint32_t u32;
+	struct cvmx_usbcx_gintsts_s {
+		uint32_t wkupint:1;
+		uint32_t sessreqint:1;
+		uint32_t disconnint:1;
+		uint32_t conidstschng:1;
+		uint32_t reserved_27_27:1;
+		uint32_t ptxfemp:1;
+		uint32_t hchint:1;
+		uint32_t prtint:1;
+		uint32_t reserved_23_23:1;
+		uint32_t fetsusp:1;
+		uint32_t incomplp:1;
+		uint32_t incompisoin:1;
+		uint32_t oepint:1;
+		uint32_t iepint:1;
+		uint32_t epmis:1;
+		uint32_t reserved_16_16:1;
+		uint32_t eopf:1;
+		uint32_t isooutdrop:1;
+		uint32_t enumdone:1;
+		uint32_t usbrst:1;
+		uint32_t usbsusp:1;
+		uint32_t erlysusp:1;
+		uint32_t i2cint:1;
+		uint32_t ulpickint:1;
+		uint32_t goutnakeff:1;
+		uint32_t ginnakeff:1;
+		uint32_t nptxfemp:1;
+		uint32_t rxflvl:1;
+		uint32_t sof:1;
+		uint32_t otgint:1;
+		uint32_t modemis:1;
+		uint32_t curmod:1;
+	} s;
+	struct cvmx_usbcx_gintsts_s cn30xx;
+	struct cvmx_usbcx_gintsts_s cn31xx;
+	struct cvmx_usbcx_gintsts_s cn50xx;
+	struct cvmx_usbcx_gintsts_s cn52xx;
+	struct cvmx_usbcx_gintsts_s cn52xxp1;
+	struct cvmx_usbcx_gintsts_s cn56xx;
+	struct cvmx_usbcx_gintsts_s cn56xxp1;
+};
+
+union cvmx_usbcx_gnptxfsiz {
+	uint32_t u32;
+	struct cvmx_usbcx_gnptxfsiz_s {
+		uint32_t nptxfdep:16;
+		uint32_t nptxfstaddr:16;
+	} s;
+	struct cvmx_usbcx_gnptxfsiz_s cn30xx;
+	struct cvmx_usbcx_gnptxfsiz_s cn31xx;
+	struct cvmx_usbcx_gnptxfsiz_s cn50xx;
+	struct cvmx_usbcx_gnptxfsiz_s cn52xx;
+	struct cvmx_usbcx_gnptxfsiz_s cn52xxp1;
+	struct cvmx_usbcx_gnptxfsiz_s cn56xx;
+	struct cvmx_usbcx_gnptxfsiz_s cn56xxp1;
+};
+
+union cvmx_usbcx_gnptxsts {
+	uint32_t u32;
+	struct cvmx_usbcx_gnptxsts_s {
+		uint32_t reserved_31_31:1;
+		uint32_t nptxqtop:7;
+		uint32_t nptxqspcavail:8;
+		uint32_t nptxfspcavail:16;
+	} s;
+	struct cvmx_usbcx_gnptxsts_s cn30xx;
+	struct cvmx_usbcx_gnptxsts_s cn31xx;
+	struct cvmx_usbcx_gnptxsts_s cn50xx;
+	struct cvmx_usbcx_gnptxsts_s cn52xx;
+	struct cvmx_usbcx_gnptxsts_s cn52xxp1;
+	struct cvmx_usbcx_gnptxsts_s cn56xx;
+	struct cvmx_usbcx_gnptxsts_s cn56xxp1;
+};
+
+union cvmx_usbcx_gotgctl {
+	uint32_t u32;
+	struct cvmx_usbcx_gotgctl_s {
+		uint32_t reserved_20_31:12;
+		uint32_t bsesvld:1;
+		uint32_t asesvld:1;
+		uint32_t dbnctime:1;
+		uint32_t conidsts:1;
+		uint32_t reserved_12_15:4;
+		uint32_t devhnpen:1;
+		uint32_t hstsethnpen:1;
+		uint32_t hnpreq:1;
+		uint32_t hstnegscs:1;
+		uint32_t reserved_2_7:6;
+		uint32_t sesreq:1;
+		uint32_t sesreqscs:1;
+	} s;
+	struct cvmx_usbcx_gotgctl_s cn30xx;
+	struct cvmx_usbcx_gotgctl_s cn31xx;
+	struct cvmx_usbcx_gotgctl_s cn50xx;
+	struct cvmx_usbcx_gotgctl_s cn52xx;
+	struct cvmx_usbcx_gotgctl_s cn52xxp1;
+	struct cvmx_usbcx_gotgctl_s cn56xx;
+	struct cvmx_usbcx_gotgctl_s cn56xxp1;
+};
+
+union cvmx_usbcx_gotgint {
+	uint32_t u32;
+	struct cvmx_usbcx_gotgint_s {
+		uint32_t reserved_20_31:12;
+		uint32_t dbncedone:1;
+		uint32_t adevtoutchg:1;
+		uint32_t hstnegdet:1;
+		uint32_t reserved_10_16:7;
+		uint32_t hstnegsucstschng:1;
+		uint32_t sesreqsucstschng:1;
+		uint32_t reserved_3_7:5;
+		uint32_t sesenddet:1;
+		uint32_t reserved_0_1:2;
+	} s;
+	struct cvmx_usbcx_gotgint_s cn30xx;
+	struct cvmx_usbcx_gotgint_s cn31xx;
+	struct cvmx_usbcx_gotgint_s cn50xx;
+	struct cvmx_usbcx_gotgint_s cn52xx;
+	struct cvmx_usbcx_gotgint_s cn52xxp1;
+	struct cvmx_usbcx_gotgint_s cn56xx;
+	struct cvmx_usbcx_gotgint_s cn56xxp1;
+};
+
+union cvmx_usbcx_grstctl {
+	uint32_t u32;
+	struct cvmx_usbcx_grstctl_s {
+		uint32_t ahbidle:1;
+		uint32_t dmareq:1;
+		uint32_t reserved_11_29:19;
+		uint32_t txfnum:5;
+		uint32_t txfflsh:1;
+		uint32_t rxfflsh:1;
+		uint32_t intknqflsh:1;
+		uint32_t frmcntrrst:1;
+		uint32_t hsftrst:1;
+		uint32_t csftrst:1;
+	} s;
+	struct cvmx_usbcx_grstctl_s cn30xx;
+	struct cvmx_usbcx_grstctl_s cn31xx;
+	struct cvmx_usbcx_grstctl_s cn50xx;
+	struct cvmx_usbcx_grstctl_s cn52xx;
+	struct cvmx_usbcx_grstctl_s cn52xxp1;
+	struct cvmx_usbcx_grstctl_s cn56xx;
+	struct cvmx_usbcx_grstctl_s cn56xxp1;
+};
+
+union cvmx_usbcx_grxfsiz {
+	uint32_t u32;
+	struct cvmx_usbcx_grxfsiz_s {
+		uint32_t reserved_16_31:16;
+		uint32_t rxfdep:16;
+	} s;
+	struct cvmx_usbcx_grxfsiz_s cn30xx;
+	struct cvmx_usbcx_grxfsiz_s cn31xx;
+	struct cvmx_usbcx_grxfsiz_s cn50xx;
+	struct cvmx_usbcx_grxfsiz_s cn52xx;
+	struct cvmx_usbcx_grxfsiz_s cn52xxp1;
+	struct cvmx_usbcx_grxfsiz_s cn56xx;
+	struct cvmx_usbcx_grxfsiz_s cn56xxp1;
+};
+
+union cvmx_usbcx_grxstspd {
+	uint32_t u32;
+	struct cvmx_usbcx_grxstspd_s {
+		uint32_t reserved_25_31:7;
+		uint32_t fn:4;
+		uint32_t pktsts:4;
+		uint32_t dpid:2;
+		uint32_t bcnt:11;
+		uint32_t epnum:4;
+	} s;
+	struct cvmx_usbcx_grxstspd_s cn30xx;
+	struct cvmx_usbcx_grxstspd_s cn31xx;
+	struct cvmx_usbcx_grxstspd_s cn50xx;
+	struct cvmx_usbcx_grxstspd_s cn52xx;
+	struct cvmx_usbcx_grxstspd_s cn52xxp1;
+	struct cvmx_usbcx_grxstspd_s cn56xx;
+	struct cvmx_usbcx_grxstspd_s cn56xxp1;
+};
+
+union cvmx_usbcx_grxstsph {
+	uint32_t u32;
+	struct cvmx_usbcx_grxstsph_s {
+		uint32_t reserved_21_31:11;
+		uint32_t pktsts:4;
+		uint32_t dpid:2;
+		uint32_t bcnt:11;
+		uint32_t chnum:4;
+	} s;
+	struct cvmx_usbcx_grxstsph_s cn30xx;
+	struct cvmx_usbcx_grxstsph_s cn31xx;
+	struct cvmx_usbcx_grxstsph_s cn50xx;
+	struct cvmx_usbcx_grxstsph_s cn52xx;
+	struct cvmx_usbcx_grxstsph_s cn52xxp1;
+	struct cvmx_usbcx_grxstsph_s cn56xx;
+	struct cvmx_usbcx_grxstsph_s cn56xxp1;
+};
+
+union cvmx_usbcx_grxstsrd {
+	uint32_t u32;
+	struct cvmx_usbcx_grxstsrd_s {
+		uint32_t reserved_25_31:7;
+		uint32_t fn:4;
+		uint32_t pktsts:4;
+		uint32_t dpid:2;
+		uint32_t bcnt:11;
+		uint32_t epnum:4;
+	} s;
+	struct cvmx_usbcx_grxstsrd_s cn30xx;
+	struct cvmx_usbcx_grxstsrd_s cn31xx;
+	struct cvmx_usbcx_grxstsrd_s cn50xx;
+	struct cvmx_usbcx_grxstsrd_s cn52xx;
+	struct cvmx_usbcx_grxstsrd_s cn52xxp1;
+	struct cvmx_usbcx_grxstsrd_s cn56xx;
+	struct cvmx_usbcx_grxstsrd_s cn56xxp1;
+};
+
+union cvmx_usbcx_grxstsrh {
+	uint32_t u32;
+	struct cvmx_usbcx_grxstsrh_s {
+		uint32_t reserved_21_31:11;
+		uint32_t pktsts:4;
+		uint32_t dpid:2;
+		uint32_t bcnt:11;
+		uint32_t chnum:4;
+	} s;
+	struct cvmx_usbcx_grxstsrh_s cn30xx;
+	struct cvmx_usbcx_grxstsrh_s cn31xx;
+	struct cvmx_usbcx_grxstsrh_s cn50xx;
+	struct cvmx_usbcx_grxstsrh_s cn52xx;
+	struct cvmx_usbcx_grxstsrh_s cn52xxp1;
+	struct cvmx_usbcx_grxstsrh_s cn56xx;
+	struct cvmx_usbcx_grxstsrh_s cn56xxp1;
+};
+
+union cvmx_usbcx_gsnpsid {
+	uint32_t u32;
+	struct cvmx_usbcx_gsnpsid_s {
+		uint32_t synopsysid:32;
+	} s;
+	struct cvmx_usbcx_gsnpsid_s cn30xx;
+	struct cvmx_usbcx_gsnpsid_s cn31xx;
+	struct cvmx_usbcx_gsnpsid_s cn50xx;
+	struct cvmx_usbcx_gsnpsid_s cn52xx;
+	struct cvmx_usbcx_gsnpsid_s cn52xxp1;
+	struct cvmx_usbcx_gsnpsid_s cn56xx;
+	struct cvmx_usbcx_gsnpsid_s cn56xxp1;
+};
+
+union cvmx_usbcx_gusbcfg {
+	uint32_t u32;
+	struct cvmx_usbcx_gusbcfg_s {
+		uint32_t reserved_17_31:15;
+		uint32_t otgi2csel:1;
+		uint32_t phylpwrclksel:1;
+		uint32_t reserved_14_14:1;
+		uint32_t usbtrdtim:4;
+		uint32_t hnpcap:1;
+		uint32_t srpcap:1;
+		uint32_t ddrsel:1;
+		uint32_t physel:1;
+		uint32_t fsintf:1;
+		uint32_t ulpi_utmi_sel:1;
+		uint32_t phyif:1;
+		uint32_t toutcal:3;
+	} s;
+	struct cvmx_usbcx_gusbcfg_s cn30xx;
+	struct cvmx_usbcx_gusbcfg_s cn31xx;
+	struct cvmx_usbcx_gusbcfg_s cn50xx;
+	struct cvmx_usbcx_gusbcfg_s cn52xx;
+	struct cvmx_usbcx_gusbcfg_s cn52xxp1;
+	struct cvmx_usbcx_gusbcfg_s cn56xx;
+	struct cvmx_usbcx_gusbcfg_s cn56xxp1;
+};
+
+union cvmx_usbcx_haint {
+	uint32_t u32;
+	struct cvmx_usbcx_haint_s {
+		uint32_t reserved_16_31:16;
+		uint32_t haint:16;
+	} s;
+	struct cvmx_usbcx_haint_s cn30xx;
+	struct cvmx_usbcx_haint_s cn31xx;
+	struct cvmx_usbcx_haint_s cn50xx;
+	struct cvmx_usbcx_haint_s cn52xx;
+	struct cvmx_usbcx_haint_s cn52xxp1;
+	struct cvmx_usbcx_haint_s cn56xx;
+	struct cvmx_usbcx_haint_s cn56xxp1;
+};
+
+union cvmx_usbcx_haintmsk {
+	uint32_t u32;
+	struct cvmx_usbcx_haintmsk_s {
+		uint32_t reserved_16_31:16;
+		uint32_t haintmsk:16;
+	} s;
+	struct cvmx_usbcx_haintmsk_s cn30xx;
+	struct cvmx_usbcx_haintmsk_s cn31xx;
+	struct cvmx_usbcx_haintmsk_s cn50xx;
+	struct cvmx_usbcx_haintmsk_s cn52xx;
+	struct cvmx_usbcx_haintmsk_s cn52xxp1;
+	struct cvmx_usbcx_haintmsk_s cn56xx;
+	struct cvmx_usbcx_haintmsk_s cn56xxp1;
+};
+
+union cvmx_usbcx_hccharx {
+	uint32_t u32;
+	struct cvmx_usbcx_hccharx_s {
+		uint32_t chena:1;
+		uint32_t chdis:1;
+		uint32_t oddfrm:1;
+		uint32_t devaddr:7;
+		uint32_t ec:2;
+		uint32_t eptype:2;
+		uint32_t lspddev:1;
+		uint32_t reserved_16_16:1;
+		uint32_t epdir:1;
+		uint32_t epnum:4;
+		uint32_t mps:11;
+	} s;
+	struct cvmx_usbcx_hccharx_s cn30xx;
+	struct cvmx_usbcx_hccharx_s cn31xx;
+	struct cvmx_usbcx_hccharx_s cn50xx;
+	struct cvmx_usbcx_hccharx_s cn52xx;
+	struct cvmx_usbcx_hccharx_s cn52xxp1;
+	struct cvmx_usbcx_hccharx_s cn56xx;
+	struct cvmx_usbcx_hccharx_s cn56xxp1;
+};
+
+union cvmx_usbcx_hcfg {
+	uint32_t u32;
+	struct cvmx_usbcx_hcfg_s {
+		uint32_t reserved_3_31:29;
+		uint32_t fslssupp:1;
+		uint32_t fslspclksel:2;
+	} s;
+	struct cvmx_usbcx_hcfg_s cn30xx;
+	struct cvmx_usbcx_hcfg_s cn31xx;
+	struct cvmx_usbcx_hcfg_s cn50xx;
+	struct cvmx_usbcx_hcfg_s cn52xx;
+	struct cvmx_usbcx_hcfg_s cn52xxp1;
+	struct cvmx_usbcx_hcfg_s cn56xx;
+	struct cvmx_usbcx_hcfg_s cn56xxp1;
+};
+
+union cvmx_usbcx_hcintx {
+	uint32_t u32;
+	struct cvmx_usbcx_hcintx_s {
+		uint32_t reserved_11_31:21;
+		uint32_t datatglerr:1;
+		uint32_t frmovrun:1;
+		uint32_t bblerr:1;
+		uint32_t xacterr:1;
+		uint32_t nyet:1;
+		uint32_t ack:1;
+		uint32_t nak:1;
+		uint32_t stall:1;
+		uint32_t ahberr:1;
+		uint32_t chhltd:1;
+		uint32_t xfercompl:1;
+	} s;
+	struct cvmx_usbcx_hcintx_s cn30xx;
+	struct cvmx_usbcx_hcintx_s cn31xx;
+	struct cvmx_usbcx_hcintx_s cn50xx;
+	struct cvmx_usbcx_hcintx_s cn52xx;
+	struct cvmx_usbcx_hcintx_s cn52xxp1;
+	struct cvmx_usbcx_hcintx_s cn56xx;
+	struct cvmx_usbcx_hcintx_s cn56xxp1;
+};
+
+union cvmx_usbcx_hcintmskx {
+	uint32_t u32;
+	struct cvmx_usbcx_hcintmskx_s {
+		uint32_t reserved_11_31:21;
+		uint32_t datatglerrmsk:1;
+		uint32_t frmovrunmsk:1;
+		uint32_t bblerrmsk:1;
+		uint32_t xacterrmsk:1;
+		uint32_t nyetmsk:1;
+		uint32_t ackmsk:1;
+		uint32_t nakmsk:1;
+		uint32_t stallmsk:1;
+		uint32_t ahberrmsk:1;
+		uint32_t chhltdmsk:1;
+		uint32_t xfercomplmsk:1;
+	} s;
+	struct cvmx_usbcx_hcintmskx_s cn30xx;
+	struct cvmx_usbcx_hcintmskx_s cn31xx;
+	struct cvmx_usbcx_hcintmskx_s cn50xx;
+	struct cvmx_usbcx_hcintmskx_s cn52xx;
+	struct cvmx_usbcx_hcintmskx_s cn52xxp1;
+	struct cvmx_usbcx_hcintmskx_s cn56xx;
+	struct cvmx_usbcx_hcintmskx_s cn56xxp1;
+};
+
+union cvmx_usbcx_hcspltx {
+	uint32_t u32;
+	struct cvmx_usbcx_hcspltx_s {
+		uint32_t spltena:1;
+		uint32_t reserved_17_30:14;
+		uint32_t compsplt:1;
+		uint32_t xactpos:2;
+		uint32_t hubaddr:7;
+		uint32_t prtaddr:7;
+	} s;
+	struct cvmx_usbcx_hcspltx_s cn30xx;
+	struct cvmx_usbcx_hcspltx_s cn31xx;
+	struct cvmx_usbcx_hcspltx_s cn50xx;
+	struct cvmx_usbcx_hcspltx_s cn52xx;
+	struct cvmx_usbcx_hcspltx_s cn52xxp1;
+	struct cvmx_usbcx_hcspltx_s cn56xx;
+	struct cvmx_usbcx_hcspltx_s cn56xxp1;
+};
+
+union cvmx_usbcx_hctsizx {
+	uint32_t u32;
+	struct cvmx_usbcx_hctsizx_s {
+		uint32_t dopng:1;
+		uint32_t pid:2;
+		uint32_t pktcnt:10;
+		uint32_t xfersize:19;
+	} s;
+	struct cvmx_usbcx_hctsizx_s cn30xx;
+	struct cvmx_usbcx_hctsizx_s cn31xx;
+	struct cvmx_usbcx_hctsizx_s cn50xx;
+	struct cvmx_usbcx_hctsizx_s cn52xx;
+	struct cvmx_usbcx_hctsizx_s cn52xxp1;
+	struct cvmx_usbcx_hctsizx_s cn56xx;
+	struct cvmx_usbcx_hctsizx_s cn56xxp1;
+};
+
+union cvmx_usbcx_hfir {
+	uint32_t u32;
+	struct cvmx_usbcx_hfir_s {
+		uint32_t reserved_16_31:16;
+		uint32_t frint:16;
+	} s;
+	struct cvmx_usbcx_hfir_s cn30xx;
+	struct cvmx_usbcx_hfir_s cn31xx;
+	struct cvmx_usbcx_hfir_s cn50xx;
+	struct cvmx_usbcx_hfir_s cn52xx;
+	struct cvmx_usbcx_hfir_s cn52xxp1;
+	struct cvmx_usbcx_hfir_s cn56xx;
+	struct cvmx_usbcx_hfir_s cn56xxp1;
+};
+
+union cvmx_usbcx_hfnum {
+	uint32_t u32;
+	struct cvmx_usbcx_hfnum_s {
+		uint32_t frrem:16;
+		uint32_t frnum:16;
+	} s;
+	struct cvmx_usbcx_hfnum_s cn30xx;
+	struct cvmx_usbcx_hfnum_s cn31xx;
+	struct cvmx_usbcx_hfnum_s cn50xx;
+	struct cvmx_usbcx_hfnum_s cn52xx;
+	struct cvmx_usbcx_hfnum_s cn52xxp1;
+	struct cvmx_usbcx_hfnum_s cn56xx;
+	struct cvmx_usbcx_hfnum_s cn56xxp1;
+};
+
+union cvmx_usbcx_hprt {
+	uint32_t u32;
+	struct cvmx_usbcx_hprt_s {
+		uint32_t reserved_19_31:13;
+		uint32_t prtspd:2;
+		uint32_t prttstctl:4;
+		uint32_t prtpwr:1;
+		uint32_t prtlnsts:2;
+		uint32_t reserved_9_9:1;
+		uint32_t prtrst:1;
+		uint32_t prtsusp:1;
+		uint32_t prtres:1;
+		uint32_t prtovrcurrchng:1;
+		uint32_t prtovrcurract:1;
+		uint32_t prtenchng:1;
+		uint32_t prtena:1;
+		uint32_t prtconndet:1;
+		uint32_t prtconnsts:1;
+	} s;
+	struct cvmx_usbcx_hprt_s cn30xx;
+	struct cvmx_usbcx_hprt_s cn31xx;
+	struct cvmx_usbcx_hprt_s cn50xx;
+	struct cvmx_usbcx_hprt_s cn52xx;
+	struct cvmx_usbcx_hprt_s cn52xxp1;
+	struct cvmx_usbcx_hprt_s cn56xx;
+	struct cvmx_usbcx_hprt_s cn56xxp1;
+};
+
+union cvmx_usbcx_hptxfsiz {
+	uint32_t u32;
+	struct cvmx_usbcx_hptxfsiz_s {
+		uint32_t ptxfsize:16;
+		uint32_t ptxfstaddr:16;
+	} s;
+	struct cvmx_usbcx_hptxfsiz_s cn30xx;
+	struct cvmx_usbcx_hptxfsiz_s cn31xx;
+	struct cvmx_usbcx_hptxfsiz_s cn50xx;
+	struct cvmx_usbcx_hptxfsiz_s cn52xx;
+	struct cvmx_usbcx_hptxfsiz_s cn52xxp1;
+	struct cvmx_usbcx_hptxfsiz_s cn56xx;
+	struct cvmx_usbcx_hptxfsiz_s cn56xxp1;
+};
+
+union cvmx_usbcx_hptxsts {
+	uint32_t u32;
+	struct cvmx_usbcx_hptxsts_s {
+		uint32_t ptxqtop:8;
+		uint32_t ptxqspcavail:8;
+		uint32_t ptxfspcavail:16;
+	} s;
+	struct cvmx_usbcx_hptxsts_s cn30xx;
+	struct cvmx_usbcx_hptxsts_s cn31xx;
+	struct cvmx_usbcx_hptxsts_s cn50xx;
+	struct cvmx_usbcx_hptxsts_s cn52xx;
+	struct cvmx_usbcx_hptxsts_s cn52xxp1;
+	struct cvmx_usbcx_hptxsts_s cn56xx;
+	struct cvmx_usbcx_hptxsts_s cn56xxp1;
+};
+
+union cvmx_usbcx_nptxdfifox {
+	uint32_t u32;
+	struct cvmx_usbcx_nptxdfifox_s {
+		uint32_t data:32;
+	} s;
+	struct cvmx_usbcx_nptxdfifox_s cn30xx;
+	struct cvmx_usbcx_nptxdfifox_s cn31xx;
+	struct cvmx_usbcx_nptxdfifox_s cn50xx;
+	struct cvmx_usbcx_nptxdfifox_s cn52xx;
+	struct cvmx_usbcx_nptxdfifox_s cn52xxp1;
+	struct cvmx_usbcx_nptxdfifox_s cn56xx;
+	struct cvmx_usbcx_nptxdfifox_s cn56xxp1;
+};
+
+union cvmx_usbcx_pcgcctl {
+	uint32_t u32;
+	struct cvmx_usbcx_pcgcctl_s {
+		uint32_t reserved_5_31:27;
+		uint32_t physuspended:1;
+		uint32_t rstpdwnmodule:1;
+		uint32_t pwrclmp:1;
+		uint32_t gatehclk:1;
+		uint32_t stoppclk:1;
+	} s;
+	struct cvmx_usbcx_pcgcctl_s cn30xx;
+	struct cvmx_usbcx_pcgcctl_s cn31xx;
+	struct cvmx_usbcx_pcgcctl_s cn50xx;
+	struct cvmx_usbcx_pcgcctl_s cn52xx;
+	struct cvmx_usbcx_pcgcctl_s cn52xxp1;
+	struct cvmx_usbcx_pcgcctl_s cn56xx;
+	struct cvmx_usbcx_pcgcctl_s cn56xxp1;
+};
+
+#endif
diff --git a/arch/mips/include/asm/octeon/cvmx-usbnx-defs.h b/arch/mips/include/asm/octeon/cvmx-usbnx-defs.h
new file mode 100644
index 0000000..90be974
--- /dev/null
+++ b/arch/mips/include/asm/octeon/cvmx-usbnx-defs.h
@@ -0,0 +1,760 @@
+/***********************license start***************
+ * Author: Cavium Networks
+ *
+ * Contact: support@caviumnetworks.com
+ * This file is part of the OCTEON SDK
+ *
+ * Copyright (c) 2003-2008 Cavium Networks
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
+ * NONINFRINGEMENT.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * or visit http://www.gnu.org/licenses/.
+ *
+ * This file may also be available under a different license from Cavium.
+ * Contact Cavium Networks for more information
+ ***********************license end**************************************/
+
+#ifndef __CVMX_USBNX_DEFS_H__
+#define __CVMX_USBNX_DEFS_H__
+
+#define CVMX_USBNX_BIST_STATUS(block_id) \
+	 CVMX_ADD_IO_SEG(0x00011800680007F8ull + (((block_id) & 1) * 0x10000000ull))
+#define CVMX_USBNX_CLK_CTL(block_id) \
+	 CVMX_ADD_IO_SEG(0x0001180068000010ull + (((block_id) & 1) * 0x10000000ull))
+#define CVMX_USBNX_CTL_STATUS(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000800ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA0_INB_CHN0(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000818ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA0_INB_CHN1(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000820ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA0_INB_CHN2(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000828ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA0_INB_CHN3(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000830ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA0_INB_CHN4(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000838ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA0_INB_CHN5(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000840ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA0_INB_CHN6(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000848ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA0_INB_CHN7(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000850ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA0_OUTB_CHN0(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000858ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA0_OUTB_CHN1(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000860ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA0_OUTB_CHN2(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000868ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA0_OUTB_CHN3(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000870ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA0_OUTB_CHN4(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000878ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA0_OUTB_CHN5(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000880ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA0_OUTB_CHN6(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000888ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA0_OUTB_CHN7(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000890ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_DMA_TEST(block_id) \
+	 CVMX_ADD_IO_SEG(0x00016F0000000808ull + (((block_id) & 1) * 0x100000000000ull))
+#define CVMX_USBNX_INT_ENB(block_id) \
+	 CVMX_ADD_IO_SEG(0x0001180068000008ull + (((block_id) & 1) * 0x10000000ull))
+#define CVMX_USBNX_INT_SUM(block_id) \
+	 CVMX_ADD_IO_SEG(0x0001180068000000ull + (((block_id) & 1) * 0x10000000ull))
+#define CVMX_USBNX_USBP_CTL_STATUS(block_id) \
+	 CVMX_ADD_IO_SEG(0x0001180068000018ull + (((block_id) & 1) * 0x10000000ull))
+
+union cvmx_usbnx_bist_status {
+	uint64_t u64;
+	struct cvmx_usbnx_bist_status_s {
+		uint64_t reserved_7_63:57;
+		uint64_t u2nc_bis:1;
+		uint64_t u2nf_bis:1;
+		uint64_t e2hc_bis:1;
+		uint64_t n2uf_bis:1;
+		uint64_t usbc_bis:1;
+		uint64_t nif_bis:1;
+		uint64_t nof_bis:1;
+	} s;
+	struct cvmx_usbnx_bist_status_cn30xx {
+		uint64_t reserved_3_63:61;
+		uint64_t usbc_bis:1;
+		uint64_t nif_bis:1;
+		uint64_t nof_bis:1;
+	} cn30xx;
+	struct cvmx_usbnx_bist_status_cn30xx cn31xx;
+	struct cvmx_usbnx_bist_status_s cn50xx;
+	struct cvmx_usbnx_bist_status_s cn52xx;
+	struct cvmx_usbnx_bist_status_s cn52xxp1;
+	struct cvmx_usbnx_bist_status_s cn56xx;
+	struct cvmx_usbnx_bist_status_s cn56xxp1;
+};
+
+union cvmx_usbnx_clk_ctl {
+	uint64_t u64;
+	struct cvmx_usbnx_clk_ctl_s {
+		uint64_t reserved_20_63:44;
+		uint64_t divide2:2;
+		uint64_t hclk_rst:1;
+		uint64_t p_x_on:1;
+		uint64_t reserved_14_15:2;
+		uint64_t p_com_on:1;
+		uint64_t p_c_sel:2;
+		uint64_t cdiv_byp:1;
+		uint64_t sd_mode:2;
+		uint64_t s_bist:1;
+		uint64_t por:1;
+		uint64_t enable:1;
+		uint64_t prst:1;
+		uint64_t hrst:1;
+		uint64_t divide:3;
+	} s;
+	struct cvmx_usbnx_clk_ctl_cn30xx {
+		uint64_t reserved_18_63:46;
+		uint64_t hclk_rst:1;
+		uint64_t p_x_on:1;
+		uint64_t p_rclk:1;
+		uint64_t p_xenbn:1;
+		uint64_t p_com_on:1;
+		uint64_t p_c_sel:2;
+		uint64_t cdiv_byp:1;
+		uint64_t sd_mode:2;
+		uint64_t s_bist:1;
+		uint64_t por:1;
+		uint64_t enable:1;
+		uint64_t prst:1;
+		uint64_t hrst:1;
+		uint64_t divide:3;
+	} cn30xx;
+	struct cvmx_usbnx_clk_ctl_cn30xx cn31xx;
+	struct cvmx_usbnx_clk_ctl_cn50xx {
+		uint64_t reserved_20_63:44;
+		uint64_t divide2:2;
+		uint64_t hclk_rst:1;
+		uint64_t reserved_16_16:1;
+		uint64_t p_rtype:2;
+		uint64_t p_com_on:1;
+		uint64_t p_c_sel:2;
+		uint64_t cdiv_byp:1;
+		uint64_t sd_mode:2;
+		uint64_t s_bist:1;
+		uint64_t por:1;
+		uint64_t enable:1;
+		uint64_t prst:1;
+		uint64_t hrst:1;
+		uint64_t divide:3;
+	} cn50xx;
+	struct cvmx_usbnx_clk_ctl_cn50xx cn52xx;
+	struct cvmx_usbnx_clk_ctl_cn50xx cn52xxp1;
+	struct cvmx_usbnx_clk_ctl_cn50xx cn56xx;
+	struct cvmx_usbnx_clk_ctl_cn50xx cn56xxp1;
+};
+
+union cvmx_usbnx_ctl_status {
+	uint64_t u64;
+	struct cvmx_usbnx_ctl_status_s {
+		uint64_t reserved_6_63:58;
+		uint64_t dma_0pag:1;
+		uint64_t dma_stt:1;
+		uint64_t dma_test:1;
+		uint64_t inv_a2:1;
+		uint64_t l2c_emod:2;
+	} s;
+	struct cvmx_usbnx_ctl_status_s cn30xx;
+	struct cvmx_usbnx_ctl_status_s cn31xx;
+	struct cvmx_usbnx_ctl_status_s cn50xx;
+	struct cvmx_usbnx_ctl_status_s cn52xx;
+	struct cvmx_usbnx_ctl_status_s cn52xxp1;
+	struct cvmx_usbnx_ctl_status_s cn56xx;
+	struct cvmx_usbnx_ctl_status_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma0_inb_chn0 {
+	uint64_t u64;
+	struct cvmx_usbnx_dma0_inb_chn0_s {
+		uint64_t reserved_36_63:28;
+		uint64_t addr:36;
+	} s;
+	struct cvmx_usbnx_dma0_inb_chn0_s cn30xx;
+	struct cvmx_usbnx_dma0_inb_chn0_s cn31xx;
+	struct cvmx_usbnx_dma0_inb_chn0_s cn50xx;
+	struct cvmx_usbnx_dma0_inb_chn0_s cn52xx;
+	struct cvmx_usbnx_dma0_inb_chn0_s cn52xxp1;
+	struct cvmx_usbnx_dma0_inb_chn0_s cn56xx;
+	struct cvmx_usbnx_dma0_inb_chn0_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma0_inb_chn1 {
+	uint64_t u64;
+	struct cvmx_usbnx_dma0_inb_chn1_s {
+		uint64_t reserved_36_63:28;
+		uint64_t addr:36;
+	} s;
+	struct cvmx_usbnx_dma0_inb_chn1_s cn30xx;
+	struct cvmx_usbnx_dma0_inb_chn1_s cn31xx;
+	struct cvmx_usbnx_dma0_inb_chn1_s cn50xx;
+	struct cvmx_usbnx_dma0_inb_chn1_s cn52xx;
+	struct cvmx_usbnx_dma0_inb_chn1_s cn52xxp1;
+	struct cvmx_usbnx_dma0_inb_chn1_s cn56xx;
+	struct cvmx_usbnx_dma0_inb_chn1_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma0_inb_chn2 {
+	uint64_t u64;
+	struct cvmx_usbnx_dma0_inb_chn2_s {
+		uint64_t reserved_36_63:28;
+		uint64_t addr:36;
+	} s;
+	struct cvmx_usbnx_dma0_inb_chn2_s cn30xx;
+	struct cvmx_usbnx_dma0_inb_chn2_s cn31xx;
+	struct cvmx_usbnx_dma0_inb_chn2_s cn50xx;
+	struct cvmx_usbnx_dma0_inb_chn2_s cn52xx;
+	struct cvmx_usbnx_dma0_inb_chn2_s cn52xxp1;
+	struct cvmx_usbnx_dma0_inb_chn2_s cn56xx;
+	struct cvmx_usbnx_dma0_inb_chn2_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma0_inb_chn3 {
+	uint64_t u64;
+	struct cvmx_usbnx_dma0_inb_chn3_s {
+		uint64_t reserved_36_63:28;
+		uint64_t addr:36;
+	} s;
+	struct cvmx_usbnx_dma0_inb_chn3_s cn30xx;
+	struct cvmx_usbnx_dma0_inb_chn3_s cn31xx;
+	struct cvmx_usbnx_dma0_inb_chn3_s cn50xx;
+	struct cvmx_usbnx_dma0_inb_chn3_s cn52xx;
+	struct cvmx_usbnx_dma0_inb_chn3_s cn52xxp1;
+	struct cvmx_usbnx_dma0_inb_chn3_s cn56xx;
+	struct cvmx_usbnx_dma0_inb_chn3_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma0_inb_chn4 {
+	uint64_t u64;
+	struct cvmx_usbnx_dma0_inb_chn4_s {
+		uint64_t reserved_36_63:28;
+		uint64_t addr:36;
+	} s;
+	struct cvmx_usbnx_dma0_inb_chn4_s cn30xx;
+	struct cvmx_usbnx_dma0_inb_chn4_s cn31xx;
+	struct cvmx_usbnx_dma0_inb_chn4_s cn50xx;
+	struct cvmx_usbnx_dma0_inb_chn4_s cn52xx;
+	struct cvmx_usbnx_dma0_inb_chn4_s cn52xxp1;
+	struct cvmx_usbnx_dma0_inb_chn4_s cn56xx;
+	struct cvmx_usbnx_dma0_inb_chn4_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma0_inb_chn5 {
+	uint64_t u64;
+	struct cvmx_usbnx_dma0_inb_chn5_s {
+		uint64_t reserved_36_63:28;
+		uint64_t addr:36;
+	} s;
+	struct cvmx_usbnx_dma0_inb_chn5_s cn30xx;
+	struct cvmx_usbnx_dma0_inb_chn5_s cn31xx;
+	struct cvmx_usbnx_dma0_inb_chn5_s cn50xx;
+	struct cvmx_usbnx_dma0_inb_chn5_s cn52xx;
+	struct cvmx_usbnx_dma0_inb_chn5_s cn52xxp1;
+	struct cvmx_usbnx_dma0_inb_chn5_s cn56xx;
+	struct cvmx_usbnx_dma0_inb_chn5_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma0_inb_chn6 {
+	uint64_t u64;
+	struct cvmx_usbnx_dma0_inb_chn6_s {
+		uint64_t reserved_36_63:28;
+		uint64_t addr:36;
+	} s;
+	struct cvmx_usbnx_dma0_inb_chn6_s cn30xx;
+	struct cvmx_usbnx_dma0_inb_chn6_s cn31xx;
+	struct cvmx_usbnx_dma0_inb_chn6_s cn50xx;
+	struct cvmx_usbnx_dma0_inb_chn6_s cn52xx;
+	struct cvmx_usbnx_dma0_inb_chn6_s cn52xxp1;
+	struct cvmx_usbnx_dma0_inb_chn6_s cn56xx;
+	struct cvmx_usbnx_dma0_inb_chn6_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma0_inb_chn7 {
+	uint64_t u64;
+	struct cvmx_usbnx_dma0_inb_chn7_s {
+		uint64_t reserved_36_63:28;
+		uint64_t addr:36;
+	} s;
+	struct cvmx_usbnx_dma0_inb_chn7_s cn30xx;
+	struct cvmx_usbnx_dma0_inb_chn7_s cn31xx;
+	struct cvmx_usbnx_dma0_inb_chn7_s cn50xx;
+	struct cvmx_usbnx_dma0_inb_chn7_s cn52xx;
+	struct cvmx_usbnx_dma0_inb_chn7_s cn52xxp1;
+	struct cvmx_usbnx_dma0_inb_chn7_s cn56xx;
+	struct cvmx_usbnx_dma0_inb_chn7_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma0_outb_chn0 {
+	uint64_t u64;
+	struct cvmx_usbnx_dma0_outb_chn0_s {
+		uint64_t reserved_36_63:28;
+		uint64_t addr:36;
+	} s;
+	struct cvmx_usbnx_dma0_outb_chn0_s cn30xx;
+	struct cvmx_usbnx_dma0_outb_chn0_s cn31xx;
+	struct cvmx_usbnx_dma0_outb_chn0_s cn50xx;
+	struct cvmx_usbnx_dma0_outb_chn0_s cn52xx;
+	struct cvmx_usbnx_dma0_outb_chn0_s cn52xxp1;
+	struct cvmx_usbnx_dma0_outb_chn0_s cn56xx;
+	struct cvmx_usbnx_dma0_outb_chn0_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma0_outb_chn1 {
+	uint64_t u64;
+	struct cvmx_usbnx_dma0_outb_chn1_s {
+		uint64_t reserved_36_63:28;
+		uint64_t addr:36;
+	} s;
+	struct cvmx_usbnx_dma0_outb_chn1_s cn30xx;
+	struct cvmx_usbnx_dma0_outb_chn1_s cn31xx;
+	struct cvmx_usbnx_dma0_outb_chn1_s cn50xx;
+	struct cvmx_usbnx_dma0_outb_chn1_s cn52xx;
+	struct cvmx_usbnx_dma0_outb_chn1_s cn52xxp1;
+	struct cvmx_usbnx_dma0_outb_chn1_s cn56xx;
+	struct cvmx_usbnx_dma0_outb_chn1_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma0_outb_chn2 {
+	uint64_t u64;
+	struct cvmx_usbnx_dma0_outb_chn2_s {
+		uint64_t reserved_36_63:28;
+		uint64_t addr:36;
+	} s;
+	struct cvmx_usbnx_dma0_outb_chn2_s cn30xx;
+	struct cvmx_usbnx_dma0_outb_chn2_s cn31xx;
+	struct cvmx_usbnx_dma0_outb_chn2_s cn50xx;
+	struct cvmx_usbnx_dma0_outb_chn2_s cn52xx;
+	struct cvmx_usbnx_dma0_outb_chn2_s cn52xxp1;
+	struct cvmx_usbnx_dma0_outb_chn2_s cn56xx;
+	struct cvmx_usbnx_dma0_outb_chn2_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma0_outb_chn3 {
+	uint64_t u64;
+	struct cvmx_usbnx_dma0_outb_chn3_s {
+		uint64_t reserved_36_63:28;
+		uint64_t addr:36;
+	} s;
+	struct cvmx_usbnx_dma0_outb_chn3_s cn30xx;
+	struct cvmx_usbnx_dma0_outb_chn3_s cn31xx;
+	struct cvmx_usbnx_dma0_outb_chn3_s cn50xx;
+	struct cvmx_usbnx_dma0_outb_chn3_s cn52xx;
+	struct cvmx_usbnx_dma0_outb_chn3_s cn52xxp1;
+	struct cvmx_usbnx_dma0_outb_chn3_s cn56xx;
+	struct cvmx_usbnx_dma0_outb_chn3_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma0_outb_chn4 {
+	uint64_t u64;
+	struct cvmx_usbnx_dma0_outb_chn4_s {
+		uint64_t reserved_36_63:28;
+		uint64_t addr:36;
+	} s;
+	struct cvmx_usbnx_dma0_outb_chn4_s cn30xx;
+	struct cvmx_usbnx_dma0_outb_chn4_s cn31xx;
+	struct cvmx_usbnx_dma0_outb_chn4_s cn50xx;
+	struct cvmx_usbnx_dma0_outb_chn4_s cn52xx;
+	struct cvmx_usbnx_dma0_outb_chn4_s cn52xxp1;
+	struct cvmx_usbnx_dma0_outb_chn4_s cn56xx;
+	struct cvmx_usbnx_dma0_outb_chn4_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma0_outb_chn5 {
+	uint64_t u64;
+	struct cvmx_usbnx_dma0_outb_chn5_s {
+		uint64_t reserved_36_63:28;
+		uint64_t addr:36;
+	} s;
+	struct cvmx_usbnx_dma0_outb_chn5_s cn30xx;
+	struct cvmx_usbnx_dma0_outb_chn5_s cn31xx;
+	struct cvmx_usbnx_dma0_outb_chn5_s cn50xx;
+	struct cvmx_usbnx_dma0_outb_chn5_s cn52xx;
+	struct cvmx_usbnx_dma0_outb_chn5_s cn52xxp1;
+	struct cvmx_usbnx_dma0_outb_chn5_s cn56xx;
+	struct cvmx_usbnx_dma0_outb_chn5_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma0_outb_chn6 {
+	uint64_t u64;
+	struct cvmx_usbnx_dma0_outb_chn6_s {
+		uint64_t reserved_36_63:28;
+		uint64_t addr:36;
+	} s;
+	struct cvmx_usbnx_dma0_outb_chn6_s cn30xx;
+	struct cvmx_usbnx_dma0_outb_chn6_s cn31xx;
+	struct cvmx_usbnx_dma0_outb_chn6_s cn50xx;
+	struct cvmx_usbnx_dma0_outb_chn6_s cn52xx;
+	struct cvmx_usbnx_dma0_outb_chn6_s cn52xxp1;
+	struct cvmx_usbnx_dma0_outb_chn6_s cn56xx;
+	struct cvmx_usbnx_dma0_outb_chn6_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma0_outb_chn7 {
+	uint64_t u64;
+	struct cvmx_usbnx_dma0_outb_chn7_s {
+		uint64_t reserved_36_63:28;
+		uint64_t addr:36;
+	} s;
+	struct cvmx_usbnx_dma0_outb_chn7_s cn30xx;
+	struct cvmx_usbnx_dma0_outb_chn7_s cn31xx;
+	struct cvmx_usbnx_dma0_outb_chn7_s cn50xx;
+	struct cvmx_usbnx_dma0_outb_chn7_s cn52xx;
+	struct cvmx_usbnx_dma0_outb_chn7_s cn52xxp1;
+	struct cvmx_usbnx_dma0_outb_chn7_s cn56xx;
+	struct cvmx_usbnx_dma0_outb_chn7_s cn56xxp1;
+};
+
+union cvmx_usbnx_dma_test {
+	uint64_t u64;
+	struct cvmx_usbnx_dma_test_s {
+		uint64_t reserved_40_63:24;
+		uint64_t done:1;
+		uint64_t req:1;
+		uint64_t f_addr:18;
+		uint64_t count:11;
+		uint64_t channel:5;
+		uint64_t burst:4;
+	} s;
+	struct cvmx_usbnx_dma_test_s cn30xx;
+	struct cvmx_usbnx_dma_test_s cn31xx;
+	struct cvmx_usbnx_dma_test_s cn50xx;
+	struct cvmx_usbnx_dma_test_s cn52xx;
+	struct cvmx_usbnx_dma_test_s cn52xxp1;
+	struct cvmx_usbnx_dma_test_s cn56xx;
+	struct cvmx_usbnx_dma_test_s cn56xxp1;
+};
+
+union cvmx_usbnx_int_enb {
+	uint64_t u64;
+	struct cvmx_usbnx_int_enb_s {
+		uint64_t reserved_38_63:26;
+		uint64_t nd4o_dpf:1;
+		uint64_t nd4o_dpe:1;
+		uint64_t nd4o_rpf:1;
+		uint64_t nd4o_rpe:1;
+		uint64_t ltl_f_pf:1;
+		uint64_t ltl_f_pe:1;
+		uint64_t u2n_c_pe:1;
+		uint64_t u2n_c_pf:1;
+		uint64_t u2n_d_pf:1;
+		uint64_t u2n_d_pe:1;
+		uint64_t n2u_pe:1;
+		uint64_t n2u_pf:1;
+		uint64_t uod_pf:1;
+		uint64_t uod_pe:1;
+		uint64_t rq_q3_e:1;
+		uint64_t rq_q3_f:1;
+		uint64_t rq_q2_e:1;
+		uint64_t rq_q2_f:1;
+		uint64_t rg_fi_f:1;
+		uint64_t rg_fi_e:1;
+		uint64_t l2_fi_f:1;
+		uint64_t l2_fi_e:1;
+		uint64_t l2c_a_f:1;
+		uint64_t l2c_s_e:1;
+		uint64_t dcred_f:1;
+		uint64_t dcred_e:1;
+		uint64_t lt_pu_f:1;
+		uint64_t lt_po_e:1;
+		uint64_t nt_pu_f:1;
+		uint64_t nt_po_e:1;
+		uint64_t pt_pu_f:1;
+		uint64_t pt_po_e:1;
+		uint64_t lr_pu_f:1;
+		uint64_t lr_po_e:1;
+		uint64_t nr_pu_f:1;
+		uint64_t nr_po_e:1;
+		uint64_t pr_pu_f:1;
+		uint64_t pr_po_e:1;
+	} s;
+	struct cvmx_usbnx_int_enb_s cn30xx;
+	struct cvmx_usbnx_int_enb_s cn31xx;
+	struct cvmx_usbnx_int_enb_cn50xx {
+		uint64_t reserved_38_63:26;
+		uint64_t nd4o_dpf:1;
+		uint64_t nd4o_dpe:1;
+		uint64_t nd4o_rpf:1;
+		uint64_t nd4o_rpe:1;
+		uint64_t ltl_f_pf:1;
+		uint64_t ltl_f_pe:1;
+		uint64_t reserved_26_31:6;
+		uint64_t uod_pf:1;
+		uint64_t uod_pe:1;
+		uint64_t rq_q3_e:1;
+		uint64_t rq_q3_f:1;
+		uint64_t rq_q2_e:1;
+		uint64_t rq_q2_f:1;
+		uint64_t rg_fi_f:1;
+		uint64_t rg_fi_e:1;
+		uint64_t l2_fi_f:1;
+		uint64_t l2_fi_e:1;
+		uint64_t l2c_a_f:1;
+		uint64_t l2c_s_e:1;
+		uint64_t dcred_f:1;
+		uint64_t dcred_e:1;
+		uint64_t lt_pu_f:1;
+		uint64_t lt_po_e:1;
+		uint64_t nt_pu_f:1;
+		uint64_t nt_po_e:1;
+		uint64_t pt_pu_f:1;
+		uint64_t pt_po_e:1;
+		uint64_t lr_pu_f:1;
+		uint64_t lr_po_e:1;
+		uint64_t nr_pu_f:1;
+		uint64_t nr_po_e:1;
+		uint64_t pr_pu_f:1;
+		uint64_t pr_po_e:1;
+	} cn50xx;
+	struct cvmx_usbnx_int_enb_cn50xx cn52xx;
+	struct cvmx_usbnx_int_enb_cn50xx cn52xxp1;
+	struct cvmx_usbnx_int_enb_cn50xx cn56xx;
+	struct cvmx_usbnx_int_enb_cn50xx cn56xxp1;
+};
+
+union cvmx_usbnx_int_sum {
+	uint64_t u64;
+	struct cvmx_usbnx_int_sum_s {
+		uint64_t reserved_38_63:26;
+		uint64_t nd4o_dpf:1;
+		uint64_t nd4o_dpe:1;
+		uint64_t nd4o_rpf:1;
+		uint64_t nd4o_rpe:1;
+		uint64_t ltl_f_pf:1;
+		uint64_t ltl_f_pe:1;
+		uint64_t u2n_c_pe:1;
+		uint64_t u2n_c_pf:1;
+		uint64_t u2n_d_pf:1;
+		uint64_t u2n_d_pe:1;
+		uint64_t n2u_pe:1;
+		uint64_t n2u_pf:1;
+		uint64_t uod_pf:1;
+		uint64_t uod_pe:1;
+		uint64_t rq_q3_e:1;
+		uint64_t rq_q3_f:1;
+		uint64_t rq_q2_e:1;
+		uint64_t rq_q2_f:1;
+		uint64_t rg_fi_f:1;
+		uint64_t rg_fi_e:1;
+		uint64_t lt_fi_f:1;
+		uint64_t lt_fi_e:1;
+		uint64_t l2c_a_f:1;
+		uint64_t l2c_s_e:1;
+		uint64_t dcred_f:1;
+		uint64_t dcred_e:1;
+		uint64_t lt_pu_f:1;
+		uint64_t lt_po_e:1;
+		uint64_t nt_pu_f:1;
+		uint64_t nt_po_e:1;
+		uint64_t pt_pu_f:1;
+		uint64_t pt_po_e:1;
+		uint64_t lr_pu_f:1;
+		uint64_t lr_po_e:1;
+		uint64_t nr_pu_f:1;
+		uint64_t nr_po_e:1;
+		uint64_t pr_pu_f:1;
+		uint64_t pr_po_e:1;
+	} s;
+	struct cvmx_usbnx_int_sum_s cn30xx;
+	struct cvmx_usbnx_int_sum_s cn31xx;
+	struct cvmx_usbnx_int_sum_cn50xx {
+		uint64_t reserved_38_63:26;
+		uint64_t nd4o_dpf:1;
+		uint64_t nd4o_dpe:1;
+		uint64_t nd4o_rpf:1;
+		uint64_t nd4o_rpe:1;
+		uint64_t ltl_f_pf:1;
+		uint64_t ltl_f_pe:1;
+		uint64_t reserved_26_31:6;
+		uint64_t uod_pf:1;
+		uint64_t uod_pe:1;
+		uint64_t rq_q3_e:1;
+		uint64_t rq_q3_f:1;
+		uint64_t rq_q2_e:1;
+		uint64_t rq_q2_f:1;
+		uint64_t rg_fi_f:1;
+		uint64_t rg_fi_e:1;
+		uint64_t lt_fi_f:1;
+		uint64_t lt_fi_e:1;
+		uint64_t l2c_a_f:1;
+		uint64_t l2c_s_e:1;
+		uint64_t dcred_f:1;
+		uint64_t dcred_e:1;
+		uint64_t lt_pu_f:1;
+		uint64_t lt_po_e:1;
+		uint64_t nt_pu_f:1;
+		uint64_t nt_po_e:1;
+		uint64_t pt_pu_f:1;
+		uint64_t pt_po_e:1;
+		uint64_t lr_pu_f:1;
+		uint64_t lr_po_e:1;
+		uint64_t nr_pu_f:1;
+		uint64_t nr_po_e:1;
+		uint64_t pr_pu_f:1;
+		uint64_t pr_po_e:1;
+	} cn50xx;
+	struct cvmx_usbnx_int_sum_cn50xx cn52xx;
+	struct cvmx_usbnx_int_sum_cn50xx cn52xxp1;
+	struct cvmx_usbnx_int_sum_cn50xx cn56xx;
+	struct cvmx_usbnx_int_sum_cn50xx cn56xxp1;
+};
+
+union cvmx_usbnx_usbp_ctl_status {
+	uint64_t u64;
+	struct cvmx_usbnx_usbp_ctl_status_s {
+		uint64_t txrisetune:1;
+		uint64_t txvreftune:4;
+		uint64_t txfslstune:4;
+		uint64_t txhsxvtune:2;
+		uint64_t sqrxtune:3;
+		uint64_t compdistune:3;
+		uint64_t otgtune:3;
+		uint64_t otgdisable:1;
+		uint64_t portreset:1;
+		uint64_t drvvbus:1;
+		uint64_t lsbist:1;
+		uint64_t fsbist:1;
+		uint64_t hsbist:1;
+		uint64_t bist_done:1;
+		uint64_t bist_err:1;
+		uint64_t tdata_out:4;
+		uint64_t siddq:1;
+		uint64_t txpreemphasistune:1;
+		uint64_t dma_bmode:1;
+		uint64_t usbc_end:1;
+		uint64_t usbp_bist:1;
+		uint64_t tclk:1;
+		uint64_t dp_pulld:1;
+		uint64_t dm_pulld:1;
+		uint64_t hst_mode:1;
+		uint64_t tuning:4;
+		uint64_t tx_bs_enh:1;
+		uint64_t tx_bs_en:1;
+		uint64_t loop_enb:1;
+		uint64_t vtest_enb:1;
+		uint64_t bist_enb:1;
+		uint64_t tdata_sel:1;
+		uint64_t taddr_in:4;
+		uint64_t tdata_in:8;
+		uint64_t ate_reset:1;
+	} s;
+	struct cvmx_usbnx_usbp_ctl_status_cn30xx {
+		uint64_t reserved_38_63:26;
+		uint64_t bist_done:1;
+		uint64_t bist_err:1;
+		uint64_t tdata_out:4;
+		uint64_t reserved_30_31:2;
+		uint64_t dma_bmode:1;
+		uint64_t usbc_end:1;
+		uint64_t usbp_bist:1;
+		uint64_t tclk:1;
+		uint64_t dp_pulld:1;
+		uint64_t dm_pulld:1;
+		uint64_t hst_mode:1;
+		uint64_t tuning:4;
+		uint64_t tx_bs_enh:1;
+		uint64_t tx_bs_en:1;
+		uint64_t loop_enb:1;
+		uint64_t vtest_enb:1;
+		uint64_t bist_enb:1;
+		uint64_t tdata_sel:1;
+		uint64_t taddr_in:4;
+		uint64_t tdata_in:8;
+		uint64_t ate_reset:1;
+	} cn30xx;
+	struct cvmx_usbnx_usbp_ctl_status_cn30xx cn31xx;
+	struct cvmx_usbnx_usbp_ctl_status_cn50xx {
+		uint64_t txrisetune:1;
+		uint64_t txvreftune:4;
+		uint64_t txfslstune:4;
+		uint64_t txhsxvtune:2;
+		uint64_t sqrxtune:3;
+		uint64_t compdistune:3;
+		uint64_t otgtune:3;
+		uint64_t otgdisable:1;
+		uint64_t portreset:1;
+		uint64_t drvvbus:1;
+		uint64_t lsbist:1;
+		uint64_t fsbist:1;
+		uint64_t hsbist:1;
+		uint64_t bist_done:1;
+		uint64_t bist_err:1;
+		uint64_t tdata_out:4;
+		uint64_t reserved_31_31:1;
+		uint64_t txpreemphasistune:1;
+		uint64_t dma_bmode:1;
+		uint64_t usbc_end:1;
+		uint64_t usbp_bist:1;
+		uint64_t tclk:1;
+		uint64_t dp_pulld:1;
+		uint64_t dm_pulld:1;
+		uint64_t hst_mode:1;
+		uint64_t reserved_19_22:4;
+		uint64_t tx_bs_enh:1;
+		uint64_t tx_bs_en:1;
+		uint64_t loop_enb:1;
+		uint64_t vtest_enb:1;
+		uint64_t bist_enb:1;
+		uint64_t tdata_sel:1;
+		uint64_t taddr_in:4;
+		uint64_t tdata_in:8;
+		uint64_t ate_reset:1;
+	} cn50xx;
+	struct cvmx_usbnx_usbp_ctl_status_cn50xx cn52xx;
+	struct cvmx_usbnx_usbp_ctl_status_cn50xx cn52xxp1;
+	struct cvmx_usbnx_usbp_ctl_status_cn56xx {
+		uint64_t txrisetune:1;
+		uint64_t txvreftune:4;
+		uint64_t txfslstune:4;
+		uint64_t txhsxvtune:2;
+		uint64_t sqrxtune:3;
+		uint64_t compdistune:3;
+		uint64_t otgtune:3;
+		uint64_t otgdisable:1;
+		uint64_t portreset:1;
+		uint64_t drvvbus:1;
+		uint64_t lsbist:1;
+		uint64_t fsbist:1;
+		uint64_t hsbist:1;
+		uint64_t bist_done:1;
+		uint64_t bist_err:1;
+		uint64_t tdata_out:4;
+		uint64_t siddq:1;
+		uint64_t txpreemphasistune:1;
+		uint64_t dma_bmode:1;
+		uint64_t usbc_end:1;
+		uint64_t usbp_bist:1;
+		uint64_t tclk:1;
+		uint64_t dp_pulld:1;
+		uint64_t dm_pulld:1;
+		uint64_t hst_mode:1;
+		uint64_t reserved_19_22:4;
+		uint64_t tx_bs_enh:1;
+		uint64_t tx_bs_en:1;
+		uint64_t loop_enb:1;
+		uint64_t vtest_enb:1;
+		uint64_t bist_enb:1;
+		uint64_t tdata_sel:1;
+		uint64_t taddr_in:4;
+		uint64_t tdata_in:8;
+		uint64_t ate_reset:1;
+	} cn56xx;
+	struct cvmx_usbnx_usbp_ctl_status_cn50xx cn56xxp1;
+};
+
+#endif
-- 
1.6.0.6


From wuzhangjin@gmail.com Thu Oct  8 10:57:53 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 10:57:59 +0200 (CEST)
Received: from mail-px0-f187.google.com ([209.85.216.187]:59192 "EHLO
	mail-px0-f187.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492479AbZJHI5w (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 10:57:52 +0200
Received: by pxi17 with SMTP id 17so7204430pxi.21
        for <multiple recipients>; Thu, 08 Oct 2009 01:57:42 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer;
        bh=19uObl8u6Ic9ybGnHoNv5fxvphHKJoqXJsGsR50ATzU=;
        b=kAwTXKmKQZu1H3sSiqApeR7++5YYHIec4j/mJQ01ia6Jv1RQXsNPUF0Mf99MgfaA4Z
         ODkVW6QiH8A8mNLwHGjJt1mwXd2SLMLaLNmfQm907ZjNEsEZQYKbtKJceiKXodC1cWwt
         OcMjVKHqmKfCKShkVyNXC+BUStNA/dx9ciUkM=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer;
        b=JTPjIfpjpevbVVnOPiO5GfnAJh9s5ZF9hg1uaZ1xKt6HyyxCGaEqOV8qAfaVzsAVRg
         vi8hSRKSxQa730ZjBi7tPXeSCb6sKGMBx1pS0+LyCHqMGIDzfjSNMEuNgH38lwciks2Z
         ATvuWbUO5xdz1h4AChakAk5+xM5KBgYerANjg=
Received: by 10.115.102.18 with SMTP id e18mr1802178wam.174.1254992261728;
        Thu, 08 Oct 2009 01:57:41 -0700 (PDT)
Received: from localhost.localdomain ([222.92.8.142])
        by mx.google.com with ESMTPS id 21sm764214pxi.3.2009.10.08.01.57.38
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Thu, 08 Oct 2009 01:57:41 -0700 (PDT)
From:	Wu Zhangjin <wuzhangjin@gmail.com>
To:	linux-mips@linux-mips.org
Cc:	Ralf Baechle <ralf@linux-mips.org>,
	"Rafael J. Wysocki" <rjw@sisk.pl>, Pavel Machek <pavel@ucw.cz>,
	Wu Zhangjin <wuzhangjin@gmail.com>
Subject: [PATCH] MIPS: fix pfn_valid() for FLAGMEM
Date:	Thu,  8 Oct 2009 16:57:32 +0800
Message-Id: <1254992252-15923-1-git-send-email-wuzhangjin@gmail.com>
X-Mailer: git-send-email 1.6.2.1
Return-Path: <wuzhangjin@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24173
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: wuzhangjin@gmail.com
Precedence: bulk
X-list: linux-mips

When CONFIG_FLAGMEM enabled, STD/Hiberation will fail on YeeLoong
laptop, This patch fix it:

if pfn is between min_low_pfn and max_mapnr, the old pfn_valid() will
return TRUE, but in reality, if the memory is not continuous, it should
be false. for example:

$ cat /proc/iomem | grep "System RAM"
00000000-0fffffff : System RAM
90000000-bfffffff : System RAM

as we can see, it is not continuous, so, some of the memory is not valid
but regarded as valid by pfn_valid(), and at last make STD/Hibernate
fail when shrinking a too large number of invalid memory.

Here, we fix it via checking pfn is in the "System RAM" or not, if yes,
return TRUE.

Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
 arch/mips/include/asm/page.h |   11 ++++-------
 arch/mips/mm/page.c          |   17 +++++++++++++++++
 2 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index f266295..16903a6 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -168,13 +168,10 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 
 #ifdef CONFIG_FLATMEM
 
-#define pfn_valid(pfn)							\
-({									\
-	unsigned long __pfn = (pfn);					\
-	/* avoid <linux/bootmem.h> include hell */			\
-	extern unsigned long min_low_pfn;				\
-									\
-	__pfn >= min_low_pfn && __pfn < max_mapnr;			\
+#define pfn_valid(pfn)				\
+({						\
+	extern int is_pfn_valid(unsigned long); \
+	is_pfn_valid(pfn);			\
 })
 
 #elif defined(CONFIG_SPARSEMEM)
diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c
index f5c7375..48a4d2a 100644
--- a/arch/mips/mm/page.c
+++ b/arch/mips/mm/page.c
@@ -689,3 +689,20 @@ void copy_page(void *to, void *from)
 }
 
 #endif /* CONFIG_SIBYTE_DMA_PAGEOPS */
+
+#ifdef CONFIG_FLATMEM
+int is_pfn_valid(unsigned long pfn)
+{
+	int i;
+
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		if (boot_mem_map.map[i].type == BOOT_MEM_RAM) {
+			if ((pfn >= PFN_DOWN(boot_mem_map.map[i].addr)) &&
+				((pfn) <= (PFN_UP(boot_mem_map.map[i].addr +
+					boot_mem_map.map[i].size))))
+				return 1;
+		}
+	}
+	return 0;
+}
+#endif
-- 
1.6.2.1


From pavel@ucw.cz Thu Oct  8 11:29:11 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 11:29:18 +0200 (CEST)
Received: from atrey.karlin.mff.cuni.cz ([195.113.26.193]:53257 "EHLO
	atrey.karlin.mff.cuni.cz" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492250AbZJHJ3L (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 11:29:11 +0200
Received: by atrey.karlin.mff.cuni.cz (Postfix, from userid 512)
	id D4D7CF0A0C; Thu,  8 Oct 2009 11:29:10 +0200 (CEST)
Date:	Thu, 8 Oct 2009 11:29:03 +0200
From:	Pavel Machek <pavel@ucw.cz>
To:	Wu Zhangjin <wuzhangjin@gmail.com>
Cc:	linux-mips@linux-mips.org, Ralf Baechle <ralf@linux-mips.org>,
	"Rafael J. Wysocki" <rjw@sisk.pl>
Subject: Re: [PATCH] MIPS: fix pfn_valid() for FLAGMEM
Message-ID: <20091008092903.GA27054@elf.ucw.cz>
References: <1254992252-15923-1-git-send-email-wuzhangjin@gmail.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <1254992252-15923-1-git-send-email-wuzhangjin@gmail.com>
X-Warning: Reading this can be dangerous to your mental health.
User-Agent: Mutt/1.5.18 (2008-05-17)
Return-Path: <pavel@ucw.cz>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24174
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: pavel@ucw.cz
Precedence: bulk
X-list: linux-mips

On Thu 2009-10-08 16:57:32, Wu Zhangjin wrote:
> When CONFIG_FLAGMEM enabled, STD/Hiberation will fail on YeeLoong
> laptop, This patch fix it:
> 
> if pfn is between min_low_pfn and max_mapnr, the old pfn_valid() will
> return TRUE, but in reality, if the memory is not continuous, it should
> be false. for example:
> 
> $ cat /proc/iomem | grep "System RAM"
> 00000000-0fffffff : System RAM
> 90000000-bfffffff : System RAM
> 
> as we can see, it is not continuous, so, some of the memory is not valid
> but regarded as valid by pfn_valid(), and at last make STD/Hibernate
> fail when shrinking a too large number of invalid memory.
> 
> Here, we fix it via checking pfn is in the "System RAM" or not, if yes,
> return TRUE.

"return FALSE"?

> Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>

Looks mostly ok, small comments below. 

> @@ -168,13 +168,10 @@ typedef struct { unsigned long pgprot; } pgprot_t;
>  
>  #ifdef CONFIG_FLATMEM
>  
> -#define pfn_valid(pfn)							\
> -({									\
> -	unsigned long __pfn = (pfn);					\
> -	/* avoid <linux/bootmem.h> include hell */			\
> -	extern unsigned long min_low_pfn;				\
> -									\
> -	__pfn >= min_low_pfn && __pfn < max_mapnr;			\
> +#define pfn_valid(pfn)				\
> +({						\
> +	extern int is_pfn_valid(unsigned long); \
> +	is_pfn_valid(pfn);			\
>  })

"extern int pfn_valid here"

...and get away without the ugly macro?

>  #elif defined(CONFIG_SPARSEMEM)
> diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c
> index f5c7375..48a4d2a 100644
> --- a/arch/mips/mm/page.c
> +++ b/arch/mips/mm/page.c
> @@ -689,3 +689,20 @@ void copy_page(void *to, void *from)
>  }
>  
>  #endif /* CONFIG_SIBYTE_DMA_PAGEOPS */
> +
> +#ifdef CONFIG_FLATMEM
> +int is_pfn_valid(unsigned long pfn)

...with simple function rename?
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

From sshtylyov@ru.mvista.com Thu Oct  8 11:58:44 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 11:58:52 +0200 (CEST)
Received: from h155.mvista.com ([63.81.120.155]:24986 "EHLO imap.sh.mvista.com"
	rhost-flags-OK-FAIL-OK-FAIL) by ftp.linux-mips.org with ESMTP
	id S1492536AbZJHJ6o (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 8 Oct 2009 11:58:44 +0200
Received: from [127.0.0.1] (unknown [10.150.0.9])
	by imap.sh.mvista.com (Postfix) with ESMTP
	id 128053EC9; Thu,  8 Oct 2009 02:58:40 -0700 (PDT)
Message-ID: <4ACDB7CB.4030209@ru.mvista.com>
Date:	Thu, 08 Oct 2009 13:58:35 +0400
From:	Sergei Shtylyov <sshtylyov@ru.mvista.com>
User-Agent: Thunderbird 2.0.0.23 (Windows/20090812)
MIME-Version: 1.0
To:	Wu Zhangjin <wuzhangjin@gmail.com>
Cc:	linux-mips@linux-mips.org, Ralf Baechle <ralf@linux-mips.org>,
	"Rafael J. Wysocki" <rjw@sisk.pl>, Pavel Machek <pavel@ucw.cz>
Subject: Re: [PATCH] MIPS: fix pfn_valid() for FLAGMEM
References: <1254992252-15923-1-git-send-email-wuzhangjin@gmail.com>
In-Reply-To: <1254992252-15923-1-git-send-email-wuzhangjin@gmail.com>
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Return-Path: <sshtylyov@ru.mvista.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24175
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: sshtylyov@ru.mvista.com
Precedence: bulk
X-list: linux-mips

Hello.

Wu Zhangjin wrote:

> When CONFIG_FLAGMEM enabled, STD/Hiberation will fail on YeeLoong
>   

   You surely meant FLATMEM here and the subject.

> laptop, This patch fix it:
>   

   Fixes.

> Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
>   
[...]
> diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
> index f266295..16903a6 100644
> --- a/arch/mips/include/asm/page.h
> +++ b/arch/mips/include/asm/page.h
> @@ -168,13 +168,10 @@ typedef struct { unsigned long pgprot; } pgprot_t;
>  
>  #ifdef CONFIG_FLATMEM
>  
> -#define pfn_valid(pfn)							\
> -({									\
> -	unsigned long __pfn = (pfn);					\
> -	/* avoid <linux/bootmem.h> include hell */			\
> -	extern unsigned long min_low_pfn;				\
> -									\
> -	__pfn >= min_low_pfn && __pfn < max_mapnr;			\
> +#define pfn_valid(pfn)				\
> +({						\
> +	extern int is_pfn_valid(unsigned long); \
> +	is_pfn_valid(pfn);			\
>   

   Why not just define pfn_valid() as *extern* function in this case?

> diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c
> index f5c7375..48a4d2a 100644
> --- a/arch/mips/mm/page.c
> +++ b/arch/mips/mm/page.c
> @@ -689,3 +689,20 @@ void copy_page(void *to, void *from)
>  }
>  
>  #endif /* CONFIG_SIBYTE_DMA_PAGEOPS */
> +
> +#ifdef CONFIG_FLATMEM
> +int is_pfn_valid(unsigned long pfn)
> +{
> +	int i;
> +
> +	for (i = 0; i < boot_mem_map.nr_map; i++) {
> +		if (boot_mem_map.map[i].type == BOOT_MEM_RAM) {
> +			if ((pfn >= PFN_DOWN(boot_mem_map.map[i].addr)) &&
> +				((pfn) <= (PFN_UP(boot_mem_map.map[i].addr +
>   

   Not <?

> +					boot_mem_map.map[i].size))))
> +				return 1;
> +		}
> +	}
> +	return 0;
> +}
> +#endif
>   

WBR, Sergei



From wuzhangjin@gmail.com Thu Oct  8 12:33:56 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 12:34:03 +0200 (CEST)
Received: from mail-px0-f187.google.com ([209.85.216.187]:45944 "EHLO
	mail-px0-f187.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492310AbZJHKd4 (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 12:33:56 +0200
Received: by pxi17 with SMTP id 17so7273191pxi.21
        for <multiple recipients>; Thu, 08 Oct 2009 03:33:49 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=domainkey-signature:received:received:subject:from:reply-to:to:cc
         :in-reply-to:references:content-type:organization:date:message-id
         :mime-version:x-mailer:content-transfer-encoding;
        bh=J8Y0m7IEIhdTS0vmg+9+3PRr8T3OIAi7C3LXq+WLQkc=;
        b=Z+jOsvMgzvPxyq66RxgyQ50iJSu8lfdjQSATeSyuAiwDLGZn1Oly7GJSDz5kbaVr90
         w9gHE1+E8CwONP6dD7IFCe8smXG6jw5yLJIKERY/UfYw49fEQRgKZ6qFVrbf+wuOX0nr
         x6zc9RmAHiXoJggjdj7fPjT7l47fkplCEJM3Y=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=gamma;
        h=subject:from:reply-to:to:cc:in-reply-to:references:content-type
         :organization:date:message-id:mime-version:x-mailer
         :content-transfer-encoding;
        b=naRoLjPCigywHnMId7bWW8DBENr22Gu5knMV1Cxe3nQmyfdLtxgn2hjOc5fpxyivgf
         3lj7YrpzhSI0VPvaJhxh7hlE1UX942zWPhFpC+xctCKnR8dXKc7qNLbQi8NgMqsA5daI
         q/QEjKF554XY/dAn3xKBP6MUAHDwhed2+VUbE=
Received: by 10.114.237.37 with SMTP id k37mr1962454wah.31.1254998029156;
        Thu, 08 Oct 2009 03:33:49 -0700 (PDT)
Received: from ?172.16.2.101? ([222.92.8.142])
        by mx.google.com with ESMTPS id 23sm31185pxi.9.2009.10.08.03.33.46
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Thu, 08 Oct 2009 03:33:48 -0700 (PDT)
Subject: Re: [PATCH] MIPS: fix pfn_valid() for FLAGMEM
From:	Wu Zhangjin <wuzhangjin@gmail.com>
Reply-To: wuzhangjin@gmail.com
To:	Pavel Machek <pavel@ucw.cz>
Cc:	linux-mips@linux-mips.org, Ralf Baechle <ralf@linux-mips.org>,
	"Rafael J. Wysocki" <rjw@sisk.pl>
In-Reply-To: <20091008092903.GA27054@elf.ucw.cz>
References: <1254992252-15923-1-git-send-email-wuzhangjin@gmail.com>
	 <20091008092903.GA27054@elf.ucw.cz>
Content-Type: text/plain
Organization: DSLab, Lanzhou University, China
Date:	Thu, 08 Oct 2009 18:33:39 +0800
Message-Id: <1254998019.14496.21.camel@falcon>
Mime-Version: 1.0
X-Mailer: Evolution 2.26.1 
Content-Transfer-Encoding: 7bit
Return-Path: <wuzhangjin@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24176
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: wuzhangjin@gmail.com
Precedence: bulk
X-list: linux-mips

Hi,

On Thu, 2009-10-08 at 11:29 +0200, Pavel Machek wrote:
> On Thu 2009-10-08 16:57:32, Wu Zhangjin wrote:
> > When CONFIG_FLAGMEM enabled, STD/Hiberation will fail on YeeLoong
> > laptop, This patch fix it:
> > 
> > if pfn is between min_low_pfn and max_mapnr, the old pfn_valid() will
> > return TRUE, but in reality, if the memory is not continuous, it should
> > be false. for example:
> > 
> > $ cat /proc/iomem | grep "System RAM"
> > 00000000-0fffffff : System RAM
> > 90000000-bfffffff : System RAM
> > 
> > as we can see, it is not continuous, so, some of the memory is not valid
> > but regarded as valid by pfn_valid(), and at last make STD/Hibernate
> > fail when shrinking a too large number of invalid memory.
> > 
> > Here, we fix it via checking pfn is in the "System RAM" or not, if yes,
> > return TRUE.
> 
> "return FALSE"?
> 
> > Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
> 
> Looks mostly ok, small comments below. 
> 
> > @@ -168,13 +168,10 @@ typedef struct { unsigned long pgprot; } pgprot_t;
> >  
> >  #ifdef CONFIG_FLATMEM
> >  
> > -#define pfn_valid(pfn)							\
> > -({									\
> > -	unsigned long __pfn = (pfn);					\
> > -	/* avoid <linux/bootmem.h> include hell */			\
> > -	extern unsigned long min_low_pfn;				\
> > -									\
> > -	__pfn >= min_low_pfn && __pfn < max_mapnr;			\
> > +#define pfn_valid(pfn)				\
> > +({						\
> > +	extern int is_pfn_valid(unsigned long); \
> > +	is_pfn_valid(pfn);			\
> >  })
> 
> "extern int pfn_valid here"
> 
> ...and get away without the ugly macro?
> 

Perhaps need to move the whole "#ifdef CONFIG_FLATMEM" to #ifndef
ASSEMBLY, otherwise,

"arch/mips/include/asm/page.h:170: Error: unrecognized opcode `extern
int pfn_valid(unsigned long)'". 

Regards,
	Wu Zhangjin


From pavel@ucw.cz Thu Oct  8 12:36:21 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 12:36:27 +0200 (CEST)
Received: from atrey.karlin.mff.cuni.cz ([195.113.26.193]:60785 "EHLO
	atrey.karlin.mff.cuni.cz" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492592AbZJHKgV (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 12:36:21 +0200
Received: by atrey.karlin.mff.cuni.cz (Postfix, from userid 512)
	id 9A912F07C2; Thu,  8 Oct 2009 12:36:20 +0200 (CEST)
Date:	Thu, 8 Oct 2009 12:36:14 +0200
From:	Pavel Machek <pavel@ucw.cz>
To:	Wu Zhangjin <wuzhangjin@gmail.com>
Cc:	linux-mips@linux-mips.org, Ralf Baechle <ralf@linux-mips.org>,
	"Rafael J. Wysocki" <rjw@sisk.pl>
Subject: Re: [PATCH] MIPS: fix pfn_valid() for FLAGMEM
Message-ID: <20091008103614.GA27323@elf.ucw.cz>
References: <1254992252-15923-1-git-send-email-wuzhangjin@gmail.com> <20091008092903.GA27054@elf.ucw.cz> <1254998019.14496.21.camel@falcon>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <1254998019.14496.21.camel@falcon>
X-Warning: Reading this can be dangerous to your mental health.
User-Agent: Mutt/1.5.18 (2008-05-17)
Return-Path: <pavel@ucw.cz>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24177
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: pavel@ucw.cz
Precedence: bulk
X-list: linux-mips

On Thu 2009-10-08 18:33:39, Wu Zhangjin wrote:
> Hi,
> 
> On Thu, 2009-10-08 at 11:29 +0200, Pavel Machek wrote:
> > On Thu 2009-10-08 16:57:32, Wu Zhangjin wrote:
> > > When CONFIG_FLAGMEM enabled, STD/Hiberation will fail on YeeLoong
> > > laptop, This patch fix it:
> > > 
> > > if pfn is between min_low_pfn and max_mapnr, the old pfn_valid() will
> > > return TRUE, but in reality, if the memory is not continuous, it should
> > > be false. for example:
> > > 
> > > $ cat /proc/iomem | grep "System RAM"
> > > 00000000-0fffffff : System RAM
> > > 90000000-bfffffff : System RAM
> > > 
> > > as we can see, it is not continuous, so, some of the memory is not valid
> > > but regarded as valid by pfn_valid(), and at last make STD/Hibernate
> > > fail when shrinking a too large number of invalid memory.
> > > 
> > > Here, we fix it via checking pfn is in the "System RAM" or not, if yes,
> > > return TRUE.
> > 
> > "return FALSE"?
> > 
> > > Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
> > 
> > Looks mostly ok, small comments below. 
> > 
> > > @@ -168,13 +168,10 @@ typedef struct { unsigned long pgprot; } pgprot_t;
> > >  
> > >  #ifdef CONFIG_FLATMEM
> > >  
> > > -#define pfn_valid(pfn)							\
> > > -({									\
> > > -	unsigned long __pfn = (pfn);					\
> > > -	/* avoid <linux/bootmem.h> include hell */			\
> > > -	extern unsigned long min_low_pfn;				\
> > > -									\
> > > -	__pfn >= min_low_pfn && __pfn < max_mapnr;			\
> > > +#define pfn_valid(pfn)				\
> > > +({						\
> > > +	extern int is_pfn_valid(unsigned long); \
> > > +	is_pfn_valid(pfn);			\
> > >  })
> > 
> > "extern int pfn_valid here"
> > 
> > ...and get away without the ugly macro?
> > 
> 
> Perhaps need to move the whole "#ifdef CONFIG_FLATMEM" to #ifndef
> ASSEMBLY, otherwise,
> 
> "arch/mips/include/asm/page.h:170: Error: unrecognized opcode `extern
> int pfn_valid(unsigned long)'". 

I guess so. pfn_valid() will not work from assembly, anywa, so...
									Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

From wuzhangjin@gmail.com Thu Oct  8 12:36:45 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 12:36:52 +0200 (CEST)
Received: from mail-pz0-f197.google.com ([209.85.222.197]:61010 "EHLO
	mail-pz0-f197.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492604AbZJHKgk (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 12:36:40 +0200
Received: by pzk35 with SMTP id 35so720471pzk.22
        for <multiple recipients>; Thu, 08 Oct 2009 03:36:32 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=domainkey-signature:received:received:subject:from:reply-to:to:cc
         :in-reply-to:references:content-type:organization:date:message-id
         :mime-version:x-mailer:content-transfer-encoding;
        bh=H58fUuuj9w7s+5yngK1ozqhYof3T4bH5/X/GJlIhRdw=;
        b=Xvp1QZ2P7ToX3bAgsY/ASm+w9hmy/TCabJRlAv3L8R/K2S4cpNA+umoCY3wyemHw6Y
         hubJZ8pUSx0Y97XGK+0xqgFv95em/z1UoectjS0PJZgLoqqJ2j57uabAq3EaVZZ8J4BE
         kMfspH3BFxrLhDyrReepO0tmIuXtIH0oTCe4A=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=gamma;
        h=subject:from:reply-to:to:cc:in-reply-to:references:content-type
         :organization:date:message-id:mime-version:x-mailer
         :content-transfer-encoding;
        b=I4jf+imgPA4uh1PM9r5W87OhAqdDr0+DGLpXEix32gsa51DoGiIg+XF1m1+VoSivu3
         8OBFbO+IsBaNGVQBtV75sIr587nOjpU6P5gdrxPSP5RvZRk4pXek+wdifWiKI6pd1nsG
         H145eclQCRJQS6vvrjaJH5MmJaWFFy79vzKdg=
Received: by 10.114.30.7 with SMTP id d7mr1968730wad.30.1254998192795;
        Thu, 08 Oct 2009 03:36:32 -0700 (PDT)
Received: from ?172.16.2.101? ([222.92.8.142])
        by mx.google.com with ESMTPS id 20sm554896pxi.8.2009.10.08.03.36.29
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Thu, 08 Oct 2009 03:36:32 -0700 (PDT)
Subject: Re: [PATCH] MIPS: fix pfn_valid() for FLAGMEM
From:	Wu Zhangjin <wuzhangjin@gmail.com>
Reply-To: wuzhangjin@gmail.com
To:	Sergei Shtylyov <sshtylyov@ru.mvista.com>
Cc:	linux-mips@linux-mips.org, Ralf Baechle <ralf@linux-mips.org>,
	"Rafael J. Wysocki" <rjw@sisk.pl>, Pavel Machek <pavel@ucw.cz>
In-Reply-To: <4ACDB7CB.4030209@ru.mvista.com>
References: <1254992252-15923-1-git-send-email-wuzhangjin@gmail.com>
	 <4ACDB7CB.4030209@ru.mvista.com>
Content-Type: text/plain
Organization: DSLab, Lanzhou University, China
Date:	Thu, 08 Oct 2009 18:36:25 +0800
Message-Id: <1254998185.14496.24.camel@falcon>
Mime-Version: 1.0
X-Mailer: Evolution 2.26.1 
Content-Transfer-Encoding: 7bit
Return-Path: <wuzhangjin@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24178
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: wuzhangjin@gmail.com
Precedence: bulk
X-list: linux-mips

Hello,

> > When CONFIG_FLAGMEM enabled, STD/Hiberation will fail on YeeLoong
> >   
> 
>    You surely meant FLATMEM here and the subject.
> 
> > laptop, This patch fix it:
> >   
> 
>    Fixes.
> 

Thanks, will resend a new one later.

> > Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
> >   
> [...]
> > diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
> > index f266295..16903a6 100644
> > --- a/arch/mips/include/asm/page.h
> > +++ b/arch/mips/include/asm/page.h
> > @@ -168,13 +168,10 @@ typedef struct { unsigned long pgprot; } pgprot_t;
> >  
> >  #ifdef CONFIG_FLATMEM
> >  
> > -#define pfn_valid(pfn)							\
> > -({									\
> > -	unsigned long __pfn = (pfn);					\
> > -	/* avoid <linux/bootmem.h> include hell */			\
> > -	extern unsigned long min_low_pfn;				\
> > -									\
> > -	__pfn >= min_low_pfn && __pfn < max_mapnr;			\
> > +#define pfn_valid(pfn)				\
> > +({						\
> > +	extern int is_pfn_valid(unsigned long); \
> > +	is_pfn_valid(pfn);			\
> >   
> 
>    Why not just define pfn_valid() as *extern* function in this case?
> 
> > diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c
> > index f5c7375..48a4d2a 100644
> > --- a/arch/mips/mm/page.c
> > +++ b/arch/mips/mm/page.c
> > @@ -689,3 +689,20 @@ void copy_page(void *to, void *from)
> >  }
> >  
> >  #endif /* CONFIG_SIBYTE_DMA_PAGEOPS */
> > +
> > +#ifdef CONFIG_FLATMEM
> > +int is_pfn_valid(unsigned long pfn)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < boot_mem_map.nr_map; i++) {
> > +		if (boot_mem_map.map[i].type == BOOT_MEM_RAM) {
> > +			if ((pfn >= PFN_DOWN(boot_mem_map.map[i].addr)) &&
> > +				((pfn) <= (PFN_UP(boot_mem_map.map[i].addr +
> >   
> 
>    Not <?
> 

Just checked it again, here should be <.

Regards,
	Wu Zhangjin


From wuzhangjin@gmail.com Thu Oct  8 12:57:58 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 12:58:04 +0200 (CEST)
Received: from mail-px0-f187.google.com ([209.85.216.187]:60340 "EHLO
	mail-px0-f187.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492607AbZJHK56 (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 12:57:58 +0200
Received: by pxi17 with SMTP id 17so7289811pxi.21
        for <multiple recipients>; Thu, 08 Oct 2009 03:57:50 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=domainkey-signature:received:received:subject:from:reply-to:to:cc
         :in-reply-to:references:content-type:organization:date:message-id
         :mime-version:x-mailer:content-transfer-encoding;
        bh=eHMSSzz9HjcZONNxzvPtn1yUimn+ys6pozSD64FXavQ=;
        b=QXrXIzvE0kcToTyZpKOk6QKyI/DFCt/FwZ92Q55NR5kmcTvs2fy6vmlVsPNKu7hnH0
         XJfhZfzEtfJnIi3tIEKoub7El9nLTLzvlgcqa7P2BFVf7oO65LOPanpKA+VzncHa3Tfl
         +2EZiFJ3Pzrgi9HUQW8jpFNHlJP1nJ9pxkgRE=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=gamma;
        h=subject:from:reply-to:to:cc:in-reply-to:references:content-type
         :organization:date:message-id:mime-version:x-mailer
         :content-transfer-encoding;
        b=aYuULraivpXenZPcLAGbFUQQPe3OP7t3O8rVURAYc2TpLUI7jzfm52ME/y4P7umVCk
         jU3fwwbovJb2wLzPTQCYyght/641pG45UrAJCCa2NzatQocv+GTIUgaArwxQiDMfvBBY
         i5A0T/Ub1tkZG5bzeBMvOeUkuzwb5nBSrXm4g=
Received: by 10.114.51.12 with SMTP id y12mr1978841way.33.1254999470696;
        Thu, 08 Oct 2009 03:57:50 -0700 (PDT)
Received: from ?172.16.2.101? ([222.92.8.142])
        by mx.google.com with ESMTPS id 20sm294665pxi.12.2009.10.08.03.57.47
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Thu, 08 Oct 2009 03:57:50 -0700 (PDT)
Subject: Re: [PATCH] MIPS: fix pfn_valid() for FLAGMEM
From:	Wu Zhangjin <wuzhangjin@gmail.com>
Reply-To: wuzhangjin@gmail.com
To:	Pavel Machek <pavel@ucw.cz>
Cc:	linux-mips@linux-mips.org, Ralf Baechle <ralf@linux-mips.org>,
	"Rafael J. Wysocki" <rjw@sisk.pl>
In-Reply-To: <20091008103614.GA27323@elf.ucw.cz>
References: <1254992252-15923-1-git-send-email-wuzhangjin@gmail.com>
	 <20091008092903.GA27054@elf.ucw.cz> <1254998019.14496.21.camel@falcon>
	 <20091008103614.GA27323@elf.ucw.cz>
Content-Type: text/plain
Organization: DSLab, Lanzhou University, China
Date:	Thu, 08 Oct 2009 18:57:43 +0800
Message-Id: <1254999463.14496.29.camel@falcon>
Mime-Version: 1.0
X-Mailer: Evolution 2.26.1 
Content-Transfer-Encoding: 7bit
Return-Path: <wuzhangjin@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24179
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: wuzhangjin@gmail.com
Precedence: bulk
X-list: linux-mips

Hello,

> > > 
> > > Looks mostly ok, small comments below. 
> > > 
> > > > @@ -168,13 +168,10 @@ typedef struct { unsigned long pgprot; } pgprot_t;
> > > >  
> > > >  #ifdef CONFIG_FLATMEM
> > > >  
> > > > -#define pfn_valid(pfn)							\
> > > > -({									\
> > > > -	unsigned long __pfn = (pfn);					\
> > > > -	/* avoid <linux/bootmem.h> include hell */			\
> > > > -	extern unsigned long min_low_pfn;				\
> > > > -									\
> > > > -	__pfn >= min_low_pfn && __pfn < max_mapnr;			\
> > > > +#define pfn_valid(pfn)				\
> > > > +({						\
> > > > +	extern int is_pfn_valid(unsigned long); \
> > > > +	is_pfn_valid(pfn);			\
> > > >  })
> > > 
> > > "extern int pfn_valid here"
> > > 
> > > ...and get away without the ugly macro?
> > > 
> > 
> > Perhaps need to move the whole "#ifdef CONFIG_FLATMEM" to #ifndef
> > ASSEMBLY, otherwise,
> > 
> > "arch/mips/include/asm/page.h:170: Error: unrecognized opcode `extern
> > int pfn_valid(unsigned long)'". 
> 
> I guess so. pfn_valid() will not work from assembly, anywa, so...

Seems pfn_valid() is only called in non-ASSEMBLY source code, so, we are
safe to move it to "#ifndef ASSEMBLY", just tested it, works.

Regards,
	Wu Zhangjin


From wuzhangjin@gmail.com Thu Oct  8 13:32:48 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 13:32:55 +0200 (CEST)
Received: from mail-pz0-f197.google.com ([209.85.222.197]:48854 "EHLO
	mail-pz0-f197.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492655AbZJHLcs (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 13:32:48 +0200
Received: by pzk35 with SMTP id 35so753893pzk.22
        for <multiple recipients>; Thu, 08 Oct 2009 04:32:40 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer;
        bh=rzpFQ6A6+fdZUhF1ZNPocCfuThNuvy22850AX4f3nFY=;
        b=UTzOfuhqDFgg3To3F3pUz7GiaRkEcAhQL4DseCzXbEcZoLeVQ0mHkNhOfo3DS6Xh2o
         Fc/AOy6m0LP76UZQ8TWe/dBiUsZO1JUNjPEsvriiy9Xu8hhqiRNDQGcJqSTYOHWdCLI9
         WFHjBge9bj5rEFqO8+g1dQYLXysjpZDGOXzu4=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer;
        b=f/bM7Zhn+VCpijaKkEu0Fz0bG4q3dUH3eceD5dwWnReE1hC2gxa6LiepG/8f65KtSN
         rdWcb5pJWwHgPicfNkLuSeQ7zF9933axxDxur19sH81yt9ybA64rhE3LFOa3hYlElO1F
         AffKzWRQJ/lRA/Tny+b+3PY4PKCVkrRZ81NI8=
Received: by 10.115.67.24 with SMTP id u24mr2003835wak.59.1255001560078;
        Thu, 08 Oct 2009 04:32:40 -0700 (PDT)
Received: from localhost.localdomain ([222.92.8.142])
        by mx.google.com with ESMTPS id 22sm219646pzk.10.2009.10.08.04.32.36
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Thu, 08 Oct 2009 04:32:39 -0700 (PDT)
From:	Wu Zhangjin <wuzhangjin@gmail.com>
To:	linux-mips@linux-mips.org
Cc:	Ralf Baechle <ralf@linux-mips.org>,
	"Rafael J. Wysocki" <rjw@sisk.pl>,
	Sergei Shtylyov <sshtylyov@ru.mvista.com>,
	Pavel Machek <pavel@ucw.cz>, Wu Zhangjin <wuzhangjin@gmail.com>
Subject: [PATCH -v1] MIPS: fix pfn_valid() for FLATMEM
Date:	Thu,  8 Oct 2009 19:32:28 +0800
Message-Id: <1255001548-30567-1-git-send-email-wuzhangjin@gmail.com>
X-Mailer: git-send-email 1.6.2.1
Return-Path: <wuzhangjin@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24180
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: wuzhangjin@gmail.com
Precedence: bulk
X-list: linux-mips

When CONFIG_FLATMEM enabled, STD/Hiberation will fail on YeeLoong
laptop, This patch fixes it:

if pfn is between min_low_pfn and max_mapnr, the old pfn_valid() will
return TRUE, but in reality, if the memory is not continuous, it should
be false. for example:

$ cat /proc/iomem | grep "System RAM"
00000000-0fffffff : System RAM
90000000-bfffffff : System RAM

as we can see, it is not continuous, so, some of the memory is not valid
but regarded as valid by pfn_valid(), and at last make STD/Hibernate
fail when shrinking a too large number of invalid memory.

Here, we fix it via checking pfn is in the "System RAM" or not. and
Seems pfn_valid() is not called in assembly code, we move it to
"!__ASSEMBLY__" to ensure we can simply declare it via "extern int
pfn_valid(unsigned long)" without Compiling Error.

(This -v1 version incorporates feedback from Pavel Machek <pavel@ucw.cz>
 and Sergei Shtylyov <sshtylyov@ru.mvista.com>)

Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
 arch/mips/include/asm/page.h |   50 ++++++++++++++++++-----------------------
 arch/mips/mm/page.c          |   17 ++++++++++++++
 2 files changed, 39 insertions(+), 28 deletions(-)

diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index 4320239..ef43905 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -145,36 +145,9 @@ typedef struct { unsigned long pgprot; } pgprot_t;
  */
 #define ptep_buddy(x)	((pte_t *)((unsigned long)(x) ^ sizeof(pte_t)))
 
-#endif /* !__ASSEMBLY__ */
-
-/*
- * __pa()/__va() should be used only during mem init.
- */
-#ifdef CONFIG_64BIT
-#define __pa(x)								\
-({									\
-    unsigned long __x = (unsigned long)(x);				\
-    __x < CKSEG0 ? XPHYSADDR(__x) : CPHYSADDR(__x);			\
-})
-#else
-#define __pa(x)								\
-    ((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET)
-#endif
-#define __va(x)		((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
-#define __pa_symbol(x)	__pa(RELOC_HIDE((unsigned long)(x), 0))
-
-#define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
-
 #ifdef CONFIG_FLATMEM
 
-#define pfn_valid(pfn)							\
-({									\
-	unsigned long __pfn = (pfn);					\
-	/* avoid <linux/bootmem.h> include hell */			\
-	extern unsigned long min_low_pfn;				\
-									\
-	__pfn >= min_low_pfn && __pfn < max_mapnr;			\
-})
+extern int pfn_valid(unsigned long);
 
 #elif defined(CONFIG_SPARSEMEM)
 
@@ -193,6 +166,27 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 
 #endif
 
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * __pa()/__va() should be used only during mem init.
+ */
+#ifdef CONFIG_64BIT
+#define __pa(x)								\
+({									\
+    unsigned long __x = (unsigned long)(x);				\
+    __x < CKSEG0 ? XPHYSADDR(__x) : CPHYSADDR(__x);			\
+})
+#else
+#define __pa(x)								\
+    ((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET)
+#endif
+#define __va(x)		((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
+#define __pa_symbol(x)	__pa(RELOC_HIDE((unsigned long)(x), 0))
+
+#define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
+
 #define virt_to_page(kaddr)	pfn_to_page(PFN_DOWN(virt_to_phys(kaddr)))
 #define virt_addr_valid(kaddr)	pfn_valid(PFN_DOWN(virt_to_phys(kaddr)))
 
diff --git a/arch/mips/mm/page.c b/arch/mips/mm/page.c
index f5c7375..e0a3f72 100644
--- a/arch/mips/mm/page.c
+++ b/arch/mips/mm/page.c
@@ -689,3 +689,20 @@ void copy_page(void *to, void *from)
 }
 
 #endif /* CONFIG_SIBYTE_DMA_PAGEOPS */
+
+#ifdef CONFIG_FLATMEM
+int pfn_valid(unsigned long pfn)
+{
+	int i;
+
+	for (i = 0; i < boot_mem_map.nr_map; i++) {
+		if (boot_mem_map.map[i].type == BOOT_MEM_RAM) {
+			if ((pfn >= PFN_DOWN(boot_mem_map.map[i].addr)) &&
+				(pfn < PFN_UP(boot_mem_map.map[i].addr +
+					boot_mem_map.map[i].size)))
+				return 1;
+		}
+	}
+	return 0;
+}
+#endif
-- 
1.6.2.1


From wuzhangjin@gmail.com Thu Oct  8 14:40:12 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 14:40:18 +0200 (CEST)
Received: from mail-px0-f187.google.com ([209.85.216.187]:42318 "EHLO
	mail-px0-f187.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1492608AbZJHMkL (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 14:40:11 +0200
Received: by pxi17 with SMTP id 17so7362087pxi.21
        for <linux-mips@linux-mips.org>; Thu, 08 Oct 2009 05:40:01 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer;
        bh=KpNFwhQTsPP58mWa/mdiSFYSn3iEuFNMHO4t/FluFkQ=;
        b=wXF9/dnPDOvhQVLVcLXRAhfCdjIo0mXc0kHA/+Vt1lLSxXIX1xOJPDR1Uk/r5n3Xm9
         PZTMbGlEimLl+PkPxE5R31HHc7T45Ju4jkDDoLQIK+igRW/iGed3Oc4j2p+224caSZD6
         o9tFi/0roBCHAgk5k1v5Gz+jQkwdndrPs0cg8=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer;
        b=GdHkj1J+ZsuUskuqLXiBlYZoCAo5dy0Ccd7SaQtGtW7Higm94NHJXgMZOK4bGeUbyS
         AJ0ChdxZKE16hKASOjAW2DbrdNNMsOfUaEvGalYZDGvMYZg90d2WGti4v7kSmVS09F5o
         ZFEsy9uFyrk26u+0ioKo9anU3ccbaBiqrWSA4=
Received: by 10.114.6.28 with SMTP id 28mr2006639waf.115.1255005601495;
        Thu, 08 Oct 2009 05:40:01 -0700 (PDT)
Received: from localhost.localdomain ([222.92.8.142])
        by mx.google.com with ESMTPS id 23sm805450pzk.4.2009.10.08.05.39.58
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Thu, 08 Oct 2009 05:40:00 -0700 (PDT)
From:	Wu Zhangjin <wuzhangjin@gmail.com>
To:	linux-mips@linux-mips.org
Cc:	Wu Zhangjin <wuzhangjin@gmail.com>
Subject: [PATCH] [loongson] Remove redundant local_irq_disable()
Date:	Thu,  8 Oct 2009 20:39:50 +0800
Message-Id: <1255005590-16562-1-git-send-email-wuzhangjin@gmail.com>
X-Mailer: git-send-email 1.6.2.1
Return-Path: <wuzhangjin@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24181
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: wuzhangjin@gmail.com
Precedence: bulk
X-list: linux-mips

That code is executed with irq disabled already, so, Remove the redundant
local_irq_disable() here.

Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
 arch/mips/loongson/common/irq.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/arch/mips/loongson/common/irq.c b/arch/mips/loongson/common/irq.c
index 53dff17..20e7328 100644
--- a/arch/mips/loongson/common/irq.c
+++ b/arch/mips/loongson/common/irq.c
@@ -55,7 +55,6 @@ void __init arch_init_irq(void)
 	 * int-handler is not on bootstrap
 	 */
 	clear_c0_status(ST0_IM | ST0_BEV);
-	local_irq_disable();
 
 	/* setting irq trigger mode */
 	set_irq_trigger_mode();
-- 
1.6.2.1


From wuzhangjin@gmail.com Thu Oct  8 15:18:08 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 15:18:14 +0200 (CEST)
Received: from ey-out-1920.google.com ([74.125.78.146]:23579 "EHLO
	ey-out-1920.google.com" rhost-flags-OK-OK-OK-OK) by ftp.linux-mips.org
	with ESMTP id S1493120AbZJHNSH (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 15:18:07 +0200
Received: by ey-out-1920.google.com with SMTP id 13so1105689eye.52
        for <multiple recipients>; Thu, 08 Oct 2009 06:18:05 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=domainkey-signature:received:received:from:to:cc:subject:date
         :message-id:x-mailer;
        bh=iAzcz2iDKpmSNUk4NX0P5zMIL8r+FEG+Fr/217g9RZg=;
        b=NKUQ8fKTYSmfwfH89lACjxMs2v1TsQDX1Rqnq+dt+z0aSGUITw9UxntRNpPuOWwoRY
         qiMgovS0iwwXPjIfSy4SnprZPL9+JANUC/RclKRzqiv2+o7DZV/Q0mMURx6j1PX40Nlo
         pCqAhT9UUvrRIdxAwrt0ToP+MSWtYSo9W7y4o=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=gamma;
        h=from:to:cc:subject:date:message-id:x-mailer;
        b=s5ZpN/SY2yE2Z5SC9bSxMQmpox6QmT0B0UQ1U7u5TbbFs9qiwCL+TO/+jrPQIa+Y3A
         3UOBJJhZpvHnJH/H+HM/4NEPdmHxPtIIS5WkCJSEMl2o14F3yZuHrJnIyzifmhbzEqeX
         HlqEIR8vPBkaKcphiNDPF56i1iQ12U0Zp9l/Y=
Received: by 10.216.87.143 with SMTP id y15mr389057wee.39.1255007885703;
        Thu, 08 Oct 2009 06:18:05 -0700 (PDT)
Received: from localhost.localdomain ([222.92.8.142])
        by mx.google.com with ESMTPS id p37sm1721824gvf.24.2009.10.08.06.18.00
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Thu, 08 Oct 2009 06:18:04 -0700 (PDT)
From:	Wu Zhangjin <wuzhangjin@gmail.com>
To:	linux-mips@linux-mips.org,
	pm list <linux-pm@lists.linux-foundation.org>,
	linux-kernel@vger.kernel.org
Cc:	Thomas Gleixner <tglx@linutronix.de>,
	Ralf Baechle <ralf@linux-mips.org>,
	"Rafael J. Wysocki" <rjw@sisk.pl>,
	Yoichi Yuasa <yuasa@linux-mips.org>,
	Wu Zhangjin <wuzhangjin@gmail.com>
Subject: [PATCH] MIPS: add IRQF_TIMER flag for Timer Interrupts
Date:	Thu,  8 Oct 2009 21:17:54 +0800
Message-Id: <1255007874-19574-1-git-send-email-wuzhangjin@gmail.com>
X-Mailer: git-send-email 1.6.2.1
Return-Path: <wuzhangjin@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24182
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: wuzhangjin@gmail.com
Precedence: bulk
X-list: linux-mips

This patch add IRQF_TIMER flag for all Timer interrupts in linux-MIPS,
which will help to not disable the Timer IRQ when suspending to ensure
resuming normally(d6c585a4342a2ff627a29f9aea77c5ed4cd76023) and not
thread them when enabled PREEMPT_RT.

Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>
---
 arch/mips/jazz/irq.c                |    2 +-
 arch/mips/kernel/cevt-gt641xx.c     |    2 +-
 arch/mips/kernel/cevt-r4k.c         |    2 +-
 arch/mips/kernel/i8253.c            |    2 +-
 arch/mips/nxp/pnx8550/common/time.c |    2 +-
 arch/mips/sgi-ip27/ip27-timer.c     |    2 +-
 arch/mips/sni/time.c                |    2 +-
 7 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c
index 7fd170d..7bd32d0 100644
--- a/arch/mips/jazz/irq.c
+++ b/arch/mips/jazz/irq.c
@@ -134,7 +134,7 @@ static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction r4030_timer_irqaction = {
 	.handler	= r4030_timer_interrupt,
-	.flags		= IRQF_DISABLED,
+	.flags		= IRQF_DISABLED | IRQF_TIMER,
 	.name		= "R4030 timer",
 };
 
diff --git a/arch/mips/kernel/cevt-gt641xx.c b/arch/mips/kernel/cevt-gt641xx.c
index 92351e0..f5d265e 100644
--- a/arch/mips/kernel/cevt-gt641xx.c
+++ b/arch/mips/kernel/cevt-gt641xx.c
@@ -113,7 +113,7 @@ static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id)
 
 static struct irqaction gt641xx_timer0_irqaction = {
 	.handler	= gt641xx_timer0_interrupt,
-	.flags		= IRQF_DISABLED | IRQF_PERCPU,
+	.flags		= IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
 	.name		= "gt641xx_timer0",
 };
 
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index 2652362..b469ad0 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -83,7 +83,7 @@ out:
 
 struct irqaction c0_compare_irqaction = {
 	.handler = c0_compare_interrupt,
-	.flags = IRQF_DISABLED | IRQF_PERCPU,
+	.flags = IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
 	.name = "timer",
 };
 
diff --git a/arch/mips/kernel/i8253.c b/arch/mips/kernel/i8253.c
index f7d8d5d..ed5c441 100644
--- a/arch/mips/kernel/i8253.c
+++ b/arch/mips/kernel/i8253.c
@@ -98,7 +98,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction irq0  = {
 	.handler = timer_interrupt,
-	.flags = IRQF_DISABLED | IRQF_NOBALANCING,
+	.flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
 	.name = "timer"
 };
 
diff --git a/arch/mips/nxp/pnx8550/common/time.c b/arch/mips/nxp/pnx8550/common/time.c
index 18b1927..d987a89 100644
--- a/arch/mips/nxp/pnx8550/common/time.c
+++ b/arch/mips/nxp/pnx8550/common/time.c
@@ -59,7 +59,7 @@ static irqreturn_t pnx8xxx_timer_interrupt(int irq, void *dev_id)
 
 static struct irqaction pnx8xxx_timer_irq = {
 	.handler	= pnx8xxx_timer_interrupt,
-	.flags		= IRQF_DISABLED | IRQF_PERCPU,
+	.flags		= IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
 	.name		= "pnx8xxx_timer",
 };
 
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
index 6d0e59f..d6802d6 100644
--- a/arch/mips/sgi-ip27/ip27-timer.c
+++ b/arch/mips/sgi-ip27/ip27-timer.c
@@ -105,7 +105,7 @@ static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id)
 
 struct irqaction hub_rt_irqaction = {
 	.handler	= hub_rt_counter_handler,
-	.flags		= IRQF_DISABLED | IRQF_PERCPU,
+	.flags		= IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
 	.name		= "hub-rt",
 };
 
diff --git a/arch/mips/sni/time.c b/arch/mips/sni/time.c
index 62df6a5..f3b60e6 100644
--- a/arch/mips/sni/time.c
+++ b/arch/mips/sni/time.c
@@ -67,7 +67,7 @@ static irqreturn_t a20r_interrupt(int irq, void *dev_id)
 
 static struct irqaction a20r_irqaction = {
 	.handler	= a20r_interrupt,
-	.flags		= IRQF_DISABLED | IRQF_PERCPU,
+	.flags		= IRQF_DISABLED | IRQF_PERCPU | IRQF_TIMER,
 	.name		= "a20r-timer",
 };
 
-- 
1.6.2.1


From ralf@linux-mips.org Thu Oct  8 16:41:25 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 16:41:28 +0200 (CEST)
Received: from localhost.localdomain ([127.0.0.1]:58250 "EHLO h5.dl5rb.org.uk"
	rhost-flags-OK-OK-OK-FAIL) by ftp.linux-mips.org with ESMTP
	id S1493192AbZJHOlZ (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 8 Oct 2009 16:41:25 +0200
Received: from h5.dl5rb.org.uk (localhost.localdomain [127.0.0.1])
	by h5.dl5rb.org.uk (8.14.3/8.14.3) with ESMTP id n98EgWQk005713;
	Thu, 8 Oct 2009 16:42:33 +0200
Received: (from ralf@localhost)
	by h5.dl5rb.org.uk (8.14.3/8.14.3/Submit) id n98EgUro005710;
	Thu, 8 Oct 2009 16:42:30 +0200
Date:	Thu, 8 Oct 2009 16:42:30 +0200
From:	Ralf Baechle <ralf@linux-mips.org>
To:	Wu Zhangjin <wuzhangjin@gmail.com>
Cc:	linux-mips@linux-mips.org, "Rafael J. Wysocki" <rjw@sisk.pl>,
	Pavel Machek <pavel@ucw.cz>
Subject: Re: [PATCH] MIPS: fix pfn_valid() for FLAGMEM
Message-ID: <20091008144230.GA682@linux-mips.org>
References: <1254992252-15923-1-git-send-email-wuzhangjin@gmail.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <1254992252-15923-1-git-send-email-wuzhangjin@gmail.com>
User-Agent: Mutt/1.5.19 (2009-01-05)
Return-Path: <ralf@linux-mips.org>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24183
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ralf@linux-mips.org
Precedence: bulk
X-list: linux-mips

On Thu, Oct 08, 2009 at 04:57:32PM +0800, Wu Zhangjin wrote:

> When CONFIG_FLAGMEM enabled, STD/Hiberation will fail on YeeLoong
> laptop, This patch fix it:
> 
> if pfn is between min_low_pfn and max_mapnr, the old pfn_valid() will
> return TRUE, but in reality, if the memory is not continuous, it should
> be false. for example:

Hm...  All that pfn_valid() indicates is that a page frame number is valid
to index a pfn.  That is that a pfn is valid to index the mem_map array.

> $ cat /proc/iomem | grep "System RAM"
> 00000000-0fffffff : System RAM
> 90000000-bfffffff : System RAM
> 
> as we can see, it is not continuous, so, some of the memory is not valid
> but regarded as valid by pfn_valid(), and at last make STD/Hibernate
> fail when shrinking a too large number of invalid memory.
> 
> Here, we fix it via checking pfn is in the "System RAM" or not, if yes,
> return TRUE.

Are the non-memory parts marked as reserved?

  Ralf

From tglx@linutronix.de Thu Oct  8 17:13:10 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 17:13:17 +0200 (CEST)
Received: from www.tglx.de ([62.245.132.106]:41457 "EHLO www.tglx.de"
	rhost-flags-OK-OK-OK-OK) by ftp.linux-mips.org with ESMTP
	id S1493208AbZJHPNK (ORCPT <rfc822;linux-mips@linux-mips.org>);
	Thu, 8 Oct 2009 17:13:10 +0200
Received: from localhost (www.tglx.de [127.0.0.1])
	by www.tglx.de (8.13.8/8.13.8/TGLX-2007100201) with ESMTP id n98FD0cj013867
	(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO);
	Thu, 8 Oct 2009 17:13:02 +0200
Date:	Thu, 8 Oct 2009 17:13:00 +0200 (CEST)
From:	Thomas Gleixner <tglx@linutronix.de>
To:	Wu Zhangjin <wuzhangjin@gmail.com>
cc:	linux-mips@linux-mips.org,
	pm list <linux-pm@lists.linux-foundation.org>,
	linux-kernel@vger.kernel.org, Ralf Baechle <ralf@linux-mips.org>,
	"Rafael J. Wysocki" <rjw@sisk.pl>,
	Yoichi Yuasa <yuasa@linux-mips.org>
Subject: Re: [PATCH] MIPS: add IRQF_TIMER flag for Timer Interrupts
In-Reply-To: <1255007874-19574-1-git-send-email-wuzhangjin@gmail.com>
Message-ID: <alpine.LFD.2.00.0910081712390.9428@localhost.localdomain>
References: <1255007874-19574-1-git-send-email-wuzhangjin@gmail.com>
User-Agent: Alpine 2.00 (LFD 1167 2008-08-23)
MIME-Version: 1.0
Content-Type: TEXT/PLAIN; charset=US-ASCII
X-Virus-Scanned: clamav-milter 0.95.1 at www.tglx.de
X-Virus-Status:	Clean
Return-Path: <tglx@linutronix.de>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24184
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: tglx@linutronix.de
Precedence: bulk
X-list: linux-mips

On Thu, 8 Oct 2009, Wu Zhangjin wrote:

> This patch add IRQF_TIMER flag for all Timer interrupts in linux-MIPS,
> which will help to not disable the Timer IRQ when suspending to ensure
> resuming normally(d6c585a4342a2ff627a29f9aea77c5ed4cd76023) and not
> thread them when enabled PREEMPT_RT.
> 
> Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com>

Acked-by: Thomas Gleixner <tglx@linutronix.de>

From wuzhangjin@gmail.com Thu Oct  8 17:46:15 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 17:46:21 +0200 (CEST)
Received: from mail-fx0-f221.google.com ([209.85.220.221]:54608 "EHLO
	mail-fx0-f221.google.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S2097305AbZJHPqP (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 17:46:15 +0200
Received: by fxm21 with SMTP id 21so5092634fxm.33
        for <multiple recipients>; Thu, 08 Oct 2009 08:46:08 -0700 (PDT)
DKIM-Signature:	v=1; a=rsa-sha256; c=relaxed/relaxed;
        d=gmail.com; s=gamma;
        h=domainkey-signature:received:received:subject:from:reply-to:to:cc
         :in-reply-to:references:content-type:organization:date:message-id
         :mime-version:x-mailer:content-transfer-encoding;
        bh=AODrkPqhsTfduQv0rsiFZk1bC6as9Ar3nXXpednUZ7c=;
        b=v/sz8/klvSizIU3RGylqKkgkriiyRoXxgpk2BKh8WYEkANLKSh/cUuRvZxBQRBxcuy
         vbiEQTN9IiZSPvjgokUaLrMj25mXzpPvscQ/ysuHfMCMzZjfIw/PlMV8wJPcd/xe3An/
         L0GeB5isS2FkmUkj5qdICcIxU0Tr+lDuAiofE=
DomainKey-Signature: a=rsa-sha1; c=nofws;
        d=gmail.com; s=gamma;
        h=subject:from:reply-to:to:cc:in-reply-to:references:content-type
         :organization:date:message-id:mime-version:x-mailer
         :content-transfer-encoding;
        b=f3py08J8CdGzvQuzLsy9ocFlqh84t5UzBxS8Xxm6rMLQe8pf1aRRdF5XjgIlCk8Rkq
         eZP/2wwA4TqiTS7a06+wMMnq70tb5IwUxc9FvYdtaLqQa/KBnkE3dF8sh7MWjvjwCLZb
         s8wW4GeRpiHCjgO0nHlh9dJiFb/teTg/6gevw=
Received: by 10.102.160.15 with SMTP id i15mr573573mue.130.1255016768430;
        Thu, 08 Oct 2009 08:46:08 -0700 (PDT)
Received: from ?172.16.2.101? ([222.92.8.142])
        by mx.google.com with ESMTPS id j2sm194535mue.16.2009.10.08.08.46.04
        (version=TLSv1/SSLv3 cipher=RC4-MD5);
        Thu, 08 Oct 2009 08:46:07 -0700 (PDT)
Subject: Re: [PATCH] MIPS: fix pfn_valid() for FLAGMEM
From:	Wu Zhangjin <wuzhangjin@gmail.com>
Reply-To: wuzhangjin@gmail.com
To:	Ralf Baechle <ralf@linux-mips.org>
Cc:	linux-mips@linux-mips.org, "Rafael J. Wysocki" <rjw@sisk.pl>,
	Pavel Machek <pavel@ucw.cz>
In-Reply-To: <20091008144230.GA682@linux-mips.org>
References: <1254992252-15923-1-git-send-email-wuzhangjin@gmail.com>
	 <20091008144230.GA682@linux-mips.org>
Content-Type: text/plain
Organization: DSLab, Lanzhou University, China
Date:	Thu, 08 Oct 2009 23:46:00 +0800
Message-Id: <1255016760.14496.57.camel@falcon>
Mime-Version: 1.0
X-Mailer: Evolution 2.26.1 
Content-Transfer-Encoding: 7bit
Return-Path: <wuzhangjin@gmail.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24185
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: wuzhangjin@gmail.com
Precedence: bulk
X-list: linux-mips

On Thu, 2009-10-08 at 16:42 +0200, Ralf Baechle wrote:
> On Thu, Oct 08, 2009 at 04:57:32PM +0800, Wu Zhangjin wrote:
> 
> > When CONFIG_FLAGMEM enabled, STD/Hiberation will fail on YeeLoong
> > laptop, This patch fix it:
> > 
> > if pfn is between min_low_pfn and max_mapnr, the old pfn_valid() will
> > return TRUE, but in reality, if the memory is not continuous, it should
> > be false. for example:
> 
> Hm...  All that pfn_valid() indicates is that a page frame number is valid
> to index a pfn.  That is that a pfn is valid to index the mem_map array.
> 
> > $ cat /proc/iomem | grep "System RAM"
> > 00000000-0fffffff : System RAM
> > 90000000-bfffffff : System RAM
> > 
> > as we can see, it is not continuous, so, some of the memory is not valid
> > but regarded as valid by pfn_valid(), and at last make STD/Hibernate
> > fail when shrinking a too large number of invalid memory.
> > 
> > Here, we fix it via checking pfn is in the "System RAM" or not, if yes,
> > return TRUE.
> 
> Are the non-memory parts marked as reserved?
> 
No, so, is that a need to mark them?

Regrads,
	Wu Zhangjin


From David.Daney@caviumnetworks.com Thu Oct  8 02:16:22 2009
Received: with ECARTIS (v1.0.0; list linux-mips); Thu, 08 Oct 2009 18:58:18 +0200 (CEST)
Received: from mail3.caviumnetworks.com ([12.108.191.235]:17630 "EHLO
	mail3.caviumnetworks.com" rhost-flags-OK-OK-OK-OK)
	by ftp.linux-mips.org with ESMTP id S1493065AbZJHAQJ (ORCPT
	<rfc822;linux-mips@linux-mips.org>); Thu, 8 Oct 2009 02:16:09 +0200
Received: from caexch01.caveonetworks.com (Not Verified[192.168.16.9]) by mail3.caviumnetworks.com with MailMarshal (v6,5,4,7535)
	id <B4acd2f380003>; Wed, 07 Oct 2009 17:15:52 -0700
Received: from caexch01.caveonetworks.com ([192.168.16.9]) by caexch01.caveonetworks.com with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 17:15:32 -0700
Received: from dd1.caveonetworks.com ([12.108.191.236]) by caexch01.caveonetworks.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.3959);
	 Wed, 7 Oct 2009 17:15:32 -0700
Received: from dd1.caveonetworks.com (localhost.localdomain [127.0.0.1])
	by dd1.caveonetworks.com (8.14.2/8.14.2) with ESMTP id n980FScZ012215;
	Wed, 7 Oct 2009 17:15:28 -0700
Received: (from ddaney@localhost)
	by dd1.caveonetworks.com (8.14.2/8.14.2/Submit) id n980FRXV012214;
	Wed, 7 Oct 2009 17:15:27 -0700
From:	David Daney <ddaney@caviumnetworks.com>
To:	ralf@linux-mips.org, linux-mips@linux-mips.org,
	linux-usb@vger.kernel.org, gregkh@suse.de
Cc:	David Daney <ddaney@caviumnetworks.com>
Subject: [PATCH 2/2] USB: Add HCD for Octeon SOC
Date:	Wed,  7 Oct 2009 17:15:26 -0700
Message-Id: <1254960926-12185-2-git-send-email-ddaney@caviumnetworks.com>
X-Mailer: git-send-email 1.6.0.6
In-Reply-To: <4ACD2EBF.8020901@caviumnetworks.com>
References: <4ACD2EBF.8020901@caviumnetworks.com>
X-OriginalArrivalTime: 08 Oct 2009 00:15:32.0083 (UTC) FILETIME=[72E1D430:01CA47AC]
Return-Path: <David.Daney@caviumnetworks.com>
X-Envelope-To: <"|/home/ecartis/ecartis -s linux-mips"> (uid 0)
X-Orcpt: rfc822;linux-mips@linux-mips.org
Original-Recipient: rfc822;linux-mips@linux-mips.org
X-archive-position: 24186
X-Approved-By: ralf@linux-mips.org
X-ecartis-version: Ecartis v1.0.0
Sender: linux-mips-bounce@linux-mips.org
Errors-to: linux-mips-bounce@linux-mips.org
X-original-sender: ddaney@caviumnetworks.com
Precedence: bulk
X-list: linux-mips

Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---
 drivers/usb/host/Kconfig                     |    8 +
 drivers/usb/host/Makefile                    |    1 +
 drivers/usb/host/dwc_otg/Kbuild              |   16 +
 drivers/usb/host/dwc_otg/dwc_otg_attr.c      |  854 ++++++++
 drivers/usb/host/dwc_otg/dwc_otg_attr.h      |   63 +
 drivers/usb/host/dwc_otg/dwc_otg_cil.c       | 2887 ++++++++++++++++++++++++++
 drivers/usb/host/dwc_otg/dwc_otg_cil.h       |  866 ++++++++
 drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c  |  689 ++++++
 drivers/usb/host/dwc_otg/dwc_otg_driver.h    |   63 +
 drivers/usb/host/dwc_otg/dwc_otg_hcd.c       | 2878 +++++++++++++++++++++++++
 drivers/usb/host/dwc_otg/dwc_otg_hcd.h       |  661 ++++++
 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c  | 1890 +++++++++++++++++
 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c |  695 +++++++
 drivers/usb/host/dwc_otg/dwc_otg_octeon.c    | 1078 ++++++++++
 drivers/usb/host/dwc_otg/dwc_otg_plat.h      |  236 +++
 drivers/usb/host/dwc_otg/dwc_otg_regs.h      | 2355 +++++++++++++++++++++
 16 files changed, 15240 insertions(+), 0 deletions(-)
 create mode 100644 drivers/usb/host/dwc_otg/Kbuild
 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.c
 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_attr.h
 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.c
 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil.h
 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_driver.h
 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.c
 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd.h
 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_octeon.c
 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_plat.h
 create mode 100644 drivers/usb/host/dwc_otg/dwc_otg_regs.h

diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 9b43b22..342dc54 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -381,3 +381,11 @@ config USB_HWA_HCD
 
 	  To compile this driver a module, choose M here: the module
 	  will be called "hwa-hc".
+
+config USB_DWC_OTG
+	tristate "Cavium Octeon USB"
+	depends on USB && CPU_CAVIUM_OCTEON
+	---help---
+	  The Cavium Octeon on-chip USB controller.  To compile this
+	  driver as a module, choose M here: the module will be called
+	  "dwc_otg".
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index f58b249..76faf12 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -15,6 +15,7 @@ endif
 xhci-objs := xhci-hcd.o xhci-mem.o xhci-pci.o xhci-ring.o xhci-hub.o xhci-dbg.o
 
 obj-$(CONFIG_USB_WHCI_HCD)	+= whci/
+obj-$(CONFIG_USB_DWC_OTG)	+= dwc_otg/
 
 obj-$(CONFIG_PCI)		+= pci-quirks.o
 
diff --git a/drivers/usb/host/dwc_otg/Kbuild b/drivers/usb/host/dwc_otg/Kbuild
new file mode 100644
index 0000000..cb32638
--- /dev/null
+++ b/drivers/usb/host/dwc_otg/Kbuild
@@ -0,0 +1,16 @@
+#
+# Makefile for DWC_otg Highspeed USB controller driver
+#
+
+# Use one of the following flags to compile the software in host-only or
+# device-only mode.
+#EXTRA_CFLAGS   += -DDWC_HOST_ONLY
+#EXTRA_CFLAGS	+= -DDWC_DEVICE_ONLY
+
+EXTRA_CFLAGS   += -DDWC_HOST_ONLY
+obj-$(CONFIG_USB_DWC_OTG)	+= dwc_otg.o
+
+dwc_otg-y := dwc_otg_octeon.o dwc_otg_attr.o
+dwc_otg-y	+= dwc_otg_cil.o dwc_otg_cil_intr.o
+dwc_otg-y	+= dwc_otg_hcd.o dwc_otg_hcd_intr.o dwc_otg_hcd_queue.o
+
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_attr.c b/drivers/usb/host/dwc_otg/dwc_otg_attr.c
new file mode 100644
index 0000000..d854a79
--- /dev/null
+++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.c
@@ -0,0 +1,854 @@
+/* ==========================================================================
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+/*
+ *
+ * The diagnostic interface will provide access to the controller for
+ * bringing up the hardware and testing.  The Linux driver attributes
+ * feature will be used to provide the Linux Diagnostic
+ * Interface. These attributes are accessed through sysfs.
+ */
+
+/** @page "Linux Module Attributes"
+ *
+ * The Linux module attributes feature is used to provide the Linux
+ * Diagnostic Interface.  These attributes are accessed through sysfs.
+ * The diagnostic interface will provide access to the controller for
+ * bringing up the hardware and testing.
+
+ The following table shows the attributes.
+ <table>
+ <tr>
+ <td><b> Name</b></td>
+ <td><b> Description</b></td>
+ <td><b> Access</b></td>
+ </tr>
+
+ <tr>
+ <td> mode </td>
+ <td> Returns the current mode: 0 for device mode, 1 for host mode</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> hnpcapable </td>
+ <td> Gets or sets the "HNP-capable" bit in the Core USB Configuraton Register.
+ Read returns the current value.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> srpcapable </td>
+ <td> Gets or sets the "SRP-capable" bit in the Core USB Configuraton Register.
+ Read returns the current value.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> hnp </td>
+ <td> Initiates the Host Negotiation Protocol.  Read returns the status.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> srp </td>
+ <td> Initiates the Session Request Protocol.  Read returns the status.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> buspower </td>
+ <td> Gets or sets the Power State of the bus (0 - Off or 1 - On)</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> bussuspend </td>
+ <td> Suspends the USB bus.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> busconnected </td>
+ <td> Gets the connection status of the bus</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> gotgctl </td>
+ <td> Gets or sets the Core Control Status Register.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> gusbcfg </td>
+ <td> Gets or sets the Core USB Configuration Register</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> grxfsiz </td>
+ <td> Gets or sets the Receive FIFO Size Register</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> gnptxfsiz </td>
+ <td> Gets or sets the non-periodic Transmit Size Register</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> gpvndctl </td>
+ <td> Gets or sets the PHY Vendor Control Register</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> ggpio </td>
+ <td> Gets the value in the lower 16-bits of the General Purpose IO Register
+ or sets the upper 16 bits.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> guid </td>
+ <td> Gets or sets the value of the User ID Register</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> gsnpsid </td>
+ <td> Gets the value of the Synopsys ID Regester</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> devspeed </td>
+ <td> Gets or sets the device speed setting in the DCFG register</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> enumspeed </td>
+ <td> Gets the device enumeration Speed.</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> hptxfsiz </td>
+ <td> Gets the value of the Host Periodic Transmit FIFO</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> hprt0 </td>
+ <td> Gets or sets the value in the Host Port Control and Status Register</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> regoffset </td>
+ <td> Sets the register offset for the next Register Access</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> regvalue </td>
+ <td> Gets or sets the value of the register at the offset in the regoffset attribute.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> remote_wakeup </td>
+ <td> On read, shows the status of Remote Wakeup. On write, initiates a remote
+ wakeup of the host. When bit 0 is 1 and Remote Wakeup is enabled, the Remote
+ Wakeup signalling bit in the Device Control Register is set for 1
+ milli-second.</td>
+ <td> Read/Write</td>
+ </tr>
+
+ <tr>
+ <td> regdump </td>
+ <td> Dumps the contents of core registers.</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> hcddump </td>
+ <td> Dumps the current HCD state.</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> hcd_frrem </td>
+ <td> Shows the average value of the Frame Remaining
+ field in the Host Frame Number/Frame Remaining register when an SOF interrupt
+ occurs. This can be used to determine the average interrupt latency. Also
+ shows the average Frame Remaining value for start_transfer and the "a" and
+ "b" sample points. The "a" and "b" sample points may be used during debugging
+ bto determine how long it takes to execute a section of the HCD code.</td>
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> rd_reg_test </td>
+ <td> Displays the time required to read the GNPTXFSIZ register many times
+ (the output shows the number of times the register is read).
+ <td> Read</td>
+ </tr>
+
+ <tr>
+ <td> wr_reg_test </td>
+ <td> Displays the time required to write the GNPTXFSIZ register many times
+ (the output shows the number of times the register is written).
+ <td> Read</td>
+ </tr>
+
+ </table>
+
+ Example usage:
+ To get the current mode:
+ cat /sys/devices/lm0/mode
+
+ To power down the USB:
+ echo 0 > /sys/devices/lm0/buspower
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/stat.h>		/* permission constants */
+
+#include <asm/io.h>
+
+#include "dwc_otg_plat.h"
+#include "dwc_otg_attr.h"
+#include "dwc_otg_driver.h"
+#ifndef DWC_HOST_ONLY
+#include "dwc_otg_pcd.h"
+#endif
+#include "dwc_otg_hcd.h"
+
+/*
+ * MACROs for defining sysfs attribute
+ */
+#define DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_, _addr_,	\
+					_mask_, _shift_, _string_)	\
+	static ssize_t _otg_attr_name_##_show (struct device *_dev,	\
+					struct device_attribute *attr,	\
+					char *buf)			\
+	{								\
+		struct dwc_otg_device *otg_dev = _dev->platform_data;	\
+		uint32_t val;						\
+		val = dwc_read_reg32(_addr_);				\
+		val = (val & (_mask_)) >> _shift_;			\
+		return sprintf(buf, "%s = 0x%x\n", _string_, val);	\
+	}
+
+#define DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_, _addr_,	\
+					_mask_, _shift_, _string_)	\
+	static ssize_t _otg_attr_name_##_store (struct device *_dev,	\
+						struct device_attribute *attr, \
+						const char *buf, size_t count) \
+	{								\
+		struct dwc_otg_device *otg_dev = _dev->platform_data;	\
+		uint32_t set = simple_strtoul(buf, NULL, 16);		\
+		uint32_t clear = set;					\
+		clear = ((~clear) << _shift_) & _mask_;			\
+		set = (set << _shift_) & _mask_;			\
+		dev_dbg(_dev,						\
+			"Storing Address=%p Set=0x%08x Clear=0x%08x\n",	\
+			_addr_, set, clear);				\
+		dwc_modify_reg32(_addr_, clear, set);			\
+		return count;						\
+	}
+
+#define DWC_OTG_DEVICE_ATTR_BITFIELD_RW(_otg_attr_name_, _addr_,	\
+					_mask_, _shift_, _string_)	\
+	DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_, _addr_,	\
+					_mask_, _shift_, _string_)	\
+	DWC_OTG_DEVICE_ATTR_BITFIELD_STORE(_otg_attr_name_, _addr_,	\
+					_mask_, _shift_, _string_)	\
+	DEVICE_ATTR(_otg_attr_name_, 0644, _otg_attr_name_##_show,	\
+		_otg_attr_name_##_store);
+
+#define DWC_OTG_DEVICE_ATTR_BITFIELD_RO(_otg_attr_name_, _addr_,	\
+					_mask_,	_shift_, _string_)	\
+	DWC_OTG_DEVICE_ATTR_BITFIELD_SHOW(_otg_attr_name_,		\
+					_addr_, _mask_, _shift_, _string_) \
+	DEVICE_ATTR(_otg_attr_name_, 0444, _otg_attr_name_##_show, NULL);
+
+/*
+ * MACROs for defining sysfs attribute for 32-bit registers
+ */
+#define DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_, _addr_, _string_) \
+	static ssize_t _otg_attr_name_##_show(struct device *_dev,	\
+					struct device_attribute *attr,	\
+					char *buf)			\
+	{								\
+		struct dwc_otg_device *otg_dev = _dev->platform_data;	\
+		uint32_t val;						\
+		val = dwc_read_reg32(_addr_);				\
+		return sprintf(buf, "%s = 0x%08x\n", _string_, val);	\
+	}
+
+#define DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_, _addr_, _string_) \
+	static ssize_t _otg_attr_name_##_store(struct device *_dev,	\
+					struct device_attribute *attr,	\
+					const char *buf, size_t count)	\
+	{								\
+		struct dwc_otg_device *otg_dev = _dev->platform_data;	\
+		uint32_t val = simple_strtoul(buf, NULL, 16);		\
+		dev_dbg(_dev, "Storing Address=%p Val=0x%08x\n", _addr_, val); \
+		dwc_write_reg32(_addr_, val);				\
+		return count;						\
+	}
+
+#define DWC_OTG_DEVICE_ATTR_REG32_RW(_otg_attr_name_, _addr_, _string_) \
+	DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_, _addr_, _string_) \
+	DWC_OTG_DEVICE_ATTR_REG_STORE(_otg_attr_name_, _addr_, _string_) \
+	DEVICE_ATTR(_otg_attr_name_, 0644, _otg_attr_name_##_show,	\
+		_otg_attr_name_##_store);
+
+#define DWC_OTG_DEVICE_ATTR_REG32_RO(_otg_attr_name_, _addr_, _string_) \
+	DWC_OTG_DEVICE_ATTR_REG_SHOW(_otg_attr_name_, _addr_, _string_) \
+	DEVICE_ATTR(_otg_attr_name_, 0444, _otg_attr_name_##_show, NULL);
+
+/**
+ * Show the register offset of the Register Access.
+ */
+static ssize_t regoffset_show(struct device *_dev,
+			      struct device_attribute *attr, char *buf)
+{
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	return snprintf(buf, sizeof("0xFFFFFFFF\n") + 1, "0x%08x\n",
+			otg_dev->reg_offset);
+}
+
+/**
+ * Set the register offset for the next Register Access 	Read/Write
+ */
+static ssize_t regoffset_store(struct device *_dev,
+			       struct device_attribute *attr, const char *buf,
+			       size_t count)
+{
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	uint32_t offset = simple_strtoul(buf, NULL, 16);
+
+	if (offset < SZ_256K)
+		otg_dev->reg_offset = offset;
+	else
+		dev_err(_dev, "invalid offset\n");
+
+	return count;
+}
+
+DEVICE_ATTR(regoffset, S_IRUGO | S_IWUSR, regoffset_show, regoffset_store);
+
+/**
+ * Show the value of the register at the offset in the reg_offset
+ * attribute.
+ */
+static ssize_t regvalue_show(struct device *_dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	uint32_t val;
+	uint32_t *addr;
+
+	if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) {
+		/* Calculate the address */
+		addr = (uint32_t *) (otg_dev->reg_offset +
+				     (uint8_t *) otg_dev->base);
+
+		val = dwc_read_reg32(addr);
+		return snprintf(buf,
+				sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n") + 1,
+				"Reg@0x%06x = 0x%08x\n", otg_dev->reg_offset,
+				val);
+	} else {
+		dev_err(_dev, "Invalid offset (0x%0x)\n", otg_dev->reg_offset);
+		return sprintf(buf, "invalid offset\n");
+	}
+}
+
+/**
+ * Store the value in the register at the offset in the reg_offset
+ * attribute.
+ *
+ */
+static ssize_t regvalue_store(struct device *_dev,
+			      struct device_attribute *attr, const char *buf,
+			      size_t count)
+{
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	uint32_t *addr;
+	uint32_t val = simple_strtoul(buf, NULL, 16);
+
+	if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) {
+		/* Calculate the address */
+		addr = (uint32_t *) (otg_dev->reg_offset +
+				     (uint8_t *) otg_dev->base);
+
+		dwc_write_reg32(addr, val);
+	} else {
+		dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
+			otg_dev->reg_offset);
+	}
+	return count;
+}
+
+DEVICE_ATTR(regvalue, S_IRUGO | S_IWUSR, regvalue_show, regvalue_store);
+
+/*
+ * Attributes
+ */
+DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode,
+				&(otg_dev->core_if->core_global_regs->gotgctl),
+				(1 << 20), 20, "Mode");
+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable,
+				&(otg_dev->core_if->core_global_regs->gusbcfg),
+				(1 << 9), 9, "Mode");
+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable,
+				&(otg_dev->core_if->core_global_regs->gusbcfg),
+				(1 << 8), 8, "Mode");
+#if 0
+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower, &(otg_dev->core_if->core_global_regs->gotgctl), (1<<8), 8, "Mode");
+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend, &(otg_dev->core_if->core_global_regs->gotgctl), (1<<8), 8, "Mode");
+#endif
+DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected, otg_dev->core_if->host_if->hprt0,
+				0x01, 0, "Bus Connected");
+
+DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl,
+			     &(otg_dev->core_if->core_global_regs->gotgctl),
+			     "GOTGCTL");
+DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,
+			     &(otg_dev->core_if->core_global_regs->gusbcfg),
+			     "GUSBCFG");
+DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,
+			     &(otg_dev->core_if->core_global_regs->grxfsiz),
+			     "GRXFSIZ");
+DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,
+			     &(otg_dev->core_if->core_global_regs->gnptxfsiz),
+			     "GNPTXFSIZ");
+DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,
+			     &(otg_dev->core_if->core_global_regs->gpvndctl),
+			     "GPVNDCTL");
+DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,
+			     &(otg_dev->core_if->core_global_regs->ggpio),
+			     "GGPIO");
+DWC_OTG_DEVICE_ATTR_REG32_RW(guid, &(otg_dev->core_if->core_global_regs->guid),
+			     "GUID");
+DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,
+			     &(otg_dev->core_if->core_global_regs->gsnpsid),
+			     "GSNPSID");
+DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed,
+				&(otg_dev->core_if->dev_if->dev_global_regs->
+				  dcfg), 0x3, 0, "Device Speed");
+DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed,
+				&(otg_dev->core_if->dev_if->dev_global_regs->
+				  dsts), 0x6, 1, "Device Enumeration Speed");
+
+DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,
+			     &(otg_dev->core_if->core_global_regs->hptxfsiz),
+			     "HPTXFSIZ");
+DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0, otg_dev->core_if->host_if->hprt0, "HPRT0");
+
+/**
+ * @todo Add code to initiate the HNP.
+ */
+/**
+ * Show the HNP status bit
+ */
+static ssize_t hnp_show(struct device *_dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	union gotgctl_data val;
+	val.d32 =
+	    dwc_read_reg32(&(otg_dev->core_if->core_global_regs->gotgctl));
+	return sprintf(buf, "HstNegScs = 0x%x\n", val.b.hstnegscs);
+}
+
+/**
+ * Set the HNP Request bit
+ */
+static ssize_t hnp_store(struct device *_dev, struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	uint32_t in = simple_strtoul(buf, NULL, 16);
+	uint32_t *addr =
+	    (uint32_t *) &(otg_dev->core_if->core_global_regs->gotgctl);
+	union gotgctl_data mem;
+	mem.d32 = dwc_read_reg32(addr);
+	mem.b.hnpreq = in;
+	dev_dbg(_dev, "Storing Address=%p Data=0x%08x\n", addr, mem.d32);
+	dwc_write_reg32(addr, mem.d32);
+	return count;
+}
+
+DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store);
+
+/**
+ * @todo Add code to initiate the SRP.
+ */
+/**
+ * Show the SRP status bit
+ */
+static ssize_t srp_show(struct device *_dev, struct device_attribute *attr,
+			char *buf)
+{
+#ifndef DWC_HOST_ONLY
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	union gotgctl_data val;
+	val.d32 =
+	    dwc_read_reg32(&(otg_dev->core_if->core_global_regs->gotgctl));
+	return sprintf(buf, "SesReqScs = 0x%x\n", val.b.sesreqscs);
+#else
+	return sprintf(buf, "Host Only Mode!\n");
+#endif
+}
+
+/**
+ * Set the SRP Request bit
+ */
+static ssize_t srp_store(struct device *_dev, struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+#ifndef DWC_HOST_ONLY
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	dwc_otg_pcd_initiate_srp(otg_dev->pcd);
+#endif
+	return count;
+}
+
+DEVICE_ATTR(srp, 0644, srp_show, srp_store);
+
+/**
+ * @todo Need to do more for power on/off?
+ */
+/**
+ * Show the Bus Power status
+ */
+static ssize_t buspower_show(struct device *_dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	union hprt0_data val;
+	val.d32 = dwc_read_reg32(otg_dev->core_if->host_if->hprt0);
+	return sprintf(buf, "Bus Power = 0x%x\n", val.b.prtpwr);
+}
+
+/**
+ * Set the Bus Power status
+ */
+static ssize_t buspower_store(struct device *_dev,
+			      struct device_attribute *attr, const char *buf,
+			      size_t count)
+{
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	uint32_t on = simple_strtoul(buf, NULL, 16);
+	uint32_t *addr = (uint32_t *) otg_dev->core_if->host_if->hprt0;
+	union hprt0_data mem;
+
+	mem.d32 = dwc_read_reg32(addr);
+	mem.b.prtpwr = on;
+
+	dwc_write_reg32(addr, mem.d32);
+
+	return count;
+}
+
+DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store);
+
+/**
+ * @todo Need to do more for suspend?
+ */
+/**
+ * Show the Bus Suspend status
+ */
+static ssize_t bussuspend_show(struct device *_dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	union hprt0_data val;
+	val.d32 = dwc_read_reg32(otg_dev->core_if->host_if->hprt0);
+	return sprintf(buf, "Bus Suspend = 0x%x\n", val.b.prtsusp);
+}
+
+/**
+ * Set the Bus Suspend status
+ */
+static ssize_t bussuspend_store(struct device *_dev,
+				struct device_attribute *attr, const char *buf,
+				size_t count)
+{
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	uint32_t in = simple_strtoul(buf, NULL, 16);
+	uint32_t *addr = (uint32_t *) otg_dev->core_if->host_if->hprt0;
+	union hprt0_data mem;
+	mem.d32 = dwc_read_reg32(addr);
+	mem.b.prtsusp = in;
+	dev_dbg(_dev, "Storing Address=%p Data=0x%08x\n", addr, mem.d32);
+	dwc_write_reg32(addr, mem.d32);
+	return count;
+}
+
+DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store);
+
+/**
+ * Show the status of Remote Wakeup.
+ */
+static ssize_t remote_wakeup_show(struct device *_dev,
+				  struct device_attribute *attr, char *buf)
+{
+#ifndef DWC_HOST_ONLY
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	union dctl_data val;
+	val.d32 =
+	    dwc_read_reg32(&otg_dev->core_if->dev_if->dev_global_regs->dctl);
+	return sprintf(buf, "Remote Wakeup = %d Enabled = %d\n",
+		       val.b.rmtwkupsig, otg_dev->pcd->remote_wakeup_enable);
+#else
+	return sprintf(buf, "Host Only Mode!\n");
+#endif
+}
+
+/**
+ * Initiate a remote wakeup of the host.  The Device control register
+ * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable
+ * flag is set.
+ *
+ */
+static ssize_t remote_wakeup_store(struct device *_dev,
+				   struct device_attribute *attr,
+				   const char *buf, size_t count)
+{
+#ifndef DWC_HOST_ONLY
+	uint32_t val = simple_strtoul(buf, NULL, 16);
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	if (val & 1)
+		dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1);
+	else
+		dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0);
+#endif
+	return count;
+}
+
+DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR, remote_wakeup_show,
+	    remote_wakeup_store);
+
+/**
+ * Dump global registers and either host or device registers (depending on the
+ * current mode of the core).
+ */
+static ssize_t regdump_show(struct device *_dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+
+	dwc_otg_dump_global_registers(otg_dev->core_if);
+	if (dwc_otg_is_host_mode(otg_dev->core_if))
+		dwc_otg_dump_host_registers(otg_dev->core_if);
+	else
+		dwc_otg_dump_dev_registers(otg_dev->core_if);
+
+	return sprintf(buf, "Register Dump\n");
+}
+
+DEVICE_ATTR(regdump, S_IRUGO | S_IWUSR, regdump_show, 0);
+
+/**
+ * Dump the current hcd state.
+ */
+static ssize_t hcddump_show(struct device *_dev, struct device_attribute *attr,
+			    char *buf)
+{
+#ifndef DWC_DEVICE_ONLY
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	dwc_otg_hcd_dump_state(otg_dev->hcd);
+#endif
+	return sprintf(buf, "HCD Dump\n");
+}
+
+DEVICE_ATTR(hcddump, S_IRUGO | S_IWUSR, hcddump_show, 0);
+
+/**
+ * Dump the average frame remaining at SOF. This can be used to
+ * determine average interrupt latency. Frame remaining is also shown for
+ * start transfer and two additional sample points.
+ */
+static ssize_t hcd_frrem_show(struct device *_dev,
+			      struct device_attribute *attr, char *buf)
+{
+#ifndef DWC_DEVICE_ONLY
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	dwc_otg_hcd_dump_frrem(otg_dev->hcd);
+#endif
+	return sprintf(buf, "HCD Dump Frame Remaining\n");
+}
+
+DEVICE_ATTR(hcd_frrem, S_IRUGO | S_IWUSR, hcd_frrem_show, 0);
+
+/**
+ * Displays the time required to read the GNPTXFSIZ register many times (the
+ * output shows the number of times the register is read).
+ */
+#define RW_REG_COUNT 10000000
+#define MSEC_PER_JIFFIE (1000/HZ)
+static ssize_t rd_reg_test_show(struct device *_dev,
+				struct device_attribute *attr, char *buf)
+{
+	int i;
+	int time;
+	int start_jiffies;
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+
+	pr_info("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
+	       HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
+	start_jiffies = jiffies;
+	for (i = 0; i < RW_REG_COUNT; i++)
+		dwc_read_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz);
+
+	time = jiffies - start_jiffies;
+	return sprintf(buf,
+		       "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
+		       RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
+}
+
+DEVICE_ATTR(rd_reg_test, S_IRUGO | S_IWUSR, rd_reg_test_show, 0);
+
+/**
+ * Displays the time required to write the GNPTXFSIZ register many times (the
+ * output shows the number of times the register is written).
+ */
+static ssize_t wr_reg_test_show(struct device *_dev,
+				struct device_attribute *attr, char *buf)
+{
+	int i;
+	int time;
+	int start_jiffies;
+	struct dwc_otg_device *otg_dev = _dev->platform_data;
+	uint32_t reg_val;
+
+	pr_info("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
+	       HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
+	reg_val =
+	    dwc_read_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz);
+	start_jiffies = jiffies;
+	for (i = 0; i < RW_REG_COUNT; i++)
+		dwc_write_reg32(&otg_dev->core_if->core_global_regs->gnptxfsiz,
+				reg_val);
+
+	time = jiffies - start_jiffies;
+	return sprintf(buf,
+		       "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
+		       RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
+}
+
+DEVICE_ATTR(wr_reg_test, S_IRUGO | S_IWUSR, wr_reg_test_show, 0);
+
+/*
+ * Create the device files
+ */
+void dwc_otg_attr_create(struct device *dev)
+{
+	int error;
+	error = device_create_file(dev, &dev_attr_regoffset);
+	error |= device_create_file(dev, &dev_attr_regvalue);
+	error |= device_create_file(dev, &dev_attr_mode);
+	error |= device_create_file(dev, &dev_attr_hnpcapable);
+	error |= device_create_file(dev, &dev_attr_srpcapable);
+	error |= device_create_file(dev, &dev_attr_hnp);
+	error |= device_create_file(dev, &dev_attr_srp);
+	error |= device_create_file(dev, &dev_attr_buspower);
+	error |= device_create_file(dev, &dev_attr_bussuspend);
+	error |= device_create_file(dev, &dev_attr_busconnected);
+	error |= device_create_file(dev, &dev_attr_gotgctl);
+	error |= device_create_file(dev, &dev_attr_gusbcfg);
+	error |= device_create_file(dev, &dev_attr_grxfsiz);
+	error |= device_create_file(dev, &dev_attr_gnptxfsiz);
+	error |= device_create_file(dev, &dev_attr_gpvndctl);
+	error |= device_create_file(dev, &dev_attr_ggpio);
+	error |= device_create_file(dev, &dev_attr_guid);
+	error |= device_create_file(dev, &dev_attr_gsnpsid);
+	error |= device_create_file(dev, &dev_attr_devspeed);
+	error |= device_create_file(dev, &dev_attr_enumspeed);
+	error |= device_create_file(dev, &dev_attr_hptxfsiz);
+	error |= device_create_file(dev, &dev_attr_hprt0);
+	error |= device_create_file(dev, &dev_attr_remote_wakeup);
+	error |= device_create_file(dev, &dev_attr_regdump);
+	error |= device_create_file(dev, &dev_attr_hcddump);
+	error |= device_create_file(dev, &dev_attr_hcd_frrem);
+	error |= device_create_file(dev, &dev_attr_rd_reg_test);
+	error |= device_create_file(dev, &dev_attr_wr_reg_test);
+	if (error)
+		pr_err("DWC_OTG: Creating some device files failed\n");
+}
+
+/*
+ * Remove the device files
+ */
+void dwc_otg_attr_remove(struct device *dev)
+{
+	device_remove_file(dev, &dev_attr_regoffset);
+	device_remove_file(dev, &dev_attr_regvalue);
+	device_remove_file(dev, &dev_attr_mode);
+	device_remove_file(dev, &dev_attr_hnpcapable);
+	device_remove_file(dev, &dev_attr_srpcapable);
+	device_remove_file(dev, &dev_attr_hnp);
+	device_remove_file(dev, &dev_attr_srp);
+	device_remove_file(dev, &dev_attr_buspower);
+	device_remove_file(dev, &dev_attr_bussuspend);
+	device_remove_file(dev, &dev_attr_busconnected);
+	device_remove_file(dev, &dev_attr_gotgctl);
+	device_remove_file(dev, &dev_attr_gusbcfg);
+	device_remove_file(dev, &dev_attr_grxfsiz);
+	device_remove_file(dev, &dev_attr_gnptxfsiz);
+	device_remove_file(dev, &dev_attr_gpvndctl);
+	device_remove_file(dev, &dev_attr_ggpio);
+	device_remove_file(dev, &dev_attr_guid);
+	device_remove_file(dev, &dev_attr_gsnpsid);
+	device_remove_file(dev, &dev_attr_devspeed);
+	device_remove_file(dev, &dev_attr_enumspeed);
+	device_remove_file(dev, &dev_attr_hptxfsiz);
+	device_remove_file(dev, &dev_attr_hprt0);
+	device_remove_file(dev, &dev_attr_remote_wakeup);
+	device_remove_file(dev, &dev_attr_regdump);
+	device_remove_file(dev, &dev_attr_hcddump);
+	device_remove_file(dev, &dev_attr_hcd_frrem);
+	device_remove_file(dev, &dev_attr_rd_reg_test);
+	device_remove_file(dev, &dev_attr_wr_reg_test);
+}
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_attr.h b/drivers/usb/host/dwc_otg/dwc_otg_attr.h
new file mode 100644
index 0000000..925524f
--- /dev/null
+++ b/drivers/usb/host/dwc_otg/dwc_otg_attr.h
@@ -0,0 +1,63 @@
+/* ==========================================================================
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+#if !defined(__DWC_OTG_ATTR_H__)
+#define __DWC_OTG_ATTR_H__
+
+/*
+ * This file contains the interface to the Linux device attributes.
+ */
+extern struct device_attribute dev_attr_regoffset;
+extern struct device_attribute dev_attr_regvalue;
+
+extern struct device_attribute dev_attr_mode;
+extern struct device_attribute dev_attr_hnpcapable;
+extern struct device_attribute dev_attr_srpcapable;
+extern struct device_attribute dev_attr_hnp;
+extern struct device_attribute dev_attr_srp;
+extern struct device_attribute dev_attr_buspower;
+extern struct device_attribute dev_attr_bussuspend;
+extern struct device_attribute dev_attr_busconnected;
+extern struct device_attribute dev_attr_gotgctl;
+extern struct device_attribute dev_attr_gusbcfg;
+extern struct device_attribute dev_attr_grxfsiz;
+extern struct device_attribute dev_attr_gnptxfsiz;
+extern struct device_attribute dev_attr_gpvndctl;
+extern struct device_attribute dev_attr_ggpio;
+extern struct device_attribute dev_attr_guid;
+extern struct device_attribute dev_attr_gsnpsid;
+extern struct device_attribute dev_attr_devspeed;
+extern struct device_attribute dev_attr_enumspeed;
+extern struct device_attribute dev_attr_hptxfsiz;
+extern struct device_attribute dev_attr_hprt0;
+
+void dwc_otg_attr_create(struct device *dev);
+void dwc_otg_attr_remove(struct device *dev);
+
+#endif
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil.c b/drivers/usb/host/dwc_otg/dwc_otg_cil.c
new file mode 100644
index 0000000..86153ba
--- /dev/null
+++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.c
@@ -0,0 +1,2887 @@
+/* ==========================================================================
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+/*
+ *
+ * The Core Interface Layer provides basic services for accessing and
+ * managing the DWC_otg hardware. These services are used by both the
+ * Host Controller Driver and the Peripheral Controller Driver.
+ *
+ * The CIL manages the memory map for the core so that the HCD and PCD
+ * don't have to do this separately. It also handles basic tasks like
+ * reading/writing the registers and data FIFOs in the controller.
+ * Some of the data access functions provide encapsulation of several
+ * operations required to perform a task, such as writing multiple
+ * registers to start a transfer. Finally, the CIL performs basic
+ * services that are not specific to either the host or device modes
+ * of operation. These services include management of the OTG Host
+ * Negotiation Protocol (HNP) and Session Request Protocol (SRP). A
+ * Diagnostic API is also provided to allow testing of the controller
+ * hardware.
+ *
+ * The Core Interface Layer has the following requirements:
+ * - Provides basic controller operations.
+ * - Minimal use of OS services.
+ * - The OS services used will be abstracted by using inline functions
+ *   or macros.
+ *
+ */
+#include <asm/unaligned.h>
+#ifdef DEBUG
+#include <linux/jiffies.h>
+#endif
+
+#include "dwc_otg_plat.h"
+#include "dwc_otg_regs.h"
+#include "dwc_otg_cil.h"
+
+/**
+ * This function is called to initialize the DWC_otg CSR data
+ * structures.  The register addresses in the device and host
+ * structures are initialized from the base address supplied by the
+ * caller.  The calling function must make the OS calls to get the
+ * base address of the DWC_otg controller registers.  The core_params
+ * argument holds the parameters that specify how the core should be
+ * configured.
+ *
+ * @reg_base_addr: Base address of DWC_otg core registers
+ * @core_params: Pointer to the core configuration parameters
+ *
+ */
+struct dwc_otg_core_if *dwc_otg_cil_init(const uint32_t *reg_base_addr,
+				    struct dwc_otg_core_params *core_params)
+{
+	struct dwc_otg_core_if *core_if = 0;
+	struct dwc_otg_dev_if *dev_if = 0;
+	struct dwc_otg_host_if *host_if = 0;
+	uint8_t *reg_base = (uint8_t *) reg_base_addr;
+	int i = 0;
+
+	DWC_DEBUGPL(DBG_CILV, "%s(%p,%p)\n", __func__, reg_base_addr,
+		    core_params);
+
+	core_if = kmalloc(sizeof(struct dwc_otg_core_if), GFP_KERNEL);
+	if (core_if == 0) {
+		DWC_DEBUGPL(DBG_CIL,
+			    "Allocation of struct dwc_otg_core_if failed\n");
+		return 0;
+	}
+	memset(core_if, 0, sizeof(struct dwc_otg_core_if));
+
+	core_if->core_params = core_params;
+	core_if->core_global_regs =
+		(struct dwc_otg_core_global_regs *)reg_base;
+	/*
+	 * Allocate the Device Mode structures.
+	 */
+	dev_if = kmalloc(sizeof(struct dwc_otg_dev_if), GFP_KERNEL);
+	if (dev_if == 0) {
+		DWC_DEBUGPL(DBG_CIL, "Allocation of struct dwc_otg_dev_if "
+			    "failed\n");
+		kfree(core_if);
+		return 0;
+	}
+
+	dev_if->dev_global_regs =
+	    (struct dwc_otg_dev_global_regs *) (reg_base +
+					      DWC_DEV_GLOBAL_REG_OFFSET);
+
+	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+		dev_if->in_ep_regs[i] = (struct dwc_otg_dev_in_ep_regs *)
+		    (reg_base + DWC_DEV_IN_EP_REG_OFFSET +
+		     (i * DWC_EP_REG_OFFSET));
+
+		dev_if->out_ep_regs[i] = (struct dwc_otg_dev_out_ep_regs *)
+		    (reg_base + DWC_DEV_OUT_EP_REG_OFFSET +
+		     (i * DWC_EP_REG_OFFSET));
+		DWC_DEBUGPL(DBG_CILV, "in_ep_regs[%d]->diepctl=%p\n",
+			    i, &dev_if->in_ep_regs[i]->diepctl);
+		DWC_DEBUGPL(DBG_CILV, "out_ep_regs[%d]->doepctl=%p\n",
+			    i, &dev_if->out_ep_regs[i]->doepctl);
+	}
+	dev_if->speed = 0;	/* unknown */
+	dev_if->num_eps = MAX_EPS_CHANNELS;
+	dev_if->num_perio_eps = 0;
+
+	core_if->dev_if = dev_if;
+	/*
+	 * Allocate the Host Mode structures.
+	 */
+	host_if = kmalloc(sizeof(struct dwc_otg_host_if), GFP_KERNEL);
+	if (host_if == 0) {
+		DWC_DEBUGPL(DBG_CIL,
+			    "Allocation of struct dwc_otg_host_if failed\n");
+		kfree(dev_if);
+		kfree(core_if);
+		return 0;
+	}
+
+	host_if->host_global_regs = (struct dwc_otg_host_global_regs *)
+	    (reg_base + DWC_OTG_HOST_GLOBAL_REG_OFFSET);
+	host_if->hprt0 =
+	    (uint32_t *) (reg_base + DWC_OTG_HOST_PORT_REGS_OFFSET);
+	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+		host_if->hc_regs[i] = (struct dwc_otg_hc_regs *)
+		    (reg_base + DWC_OTG_HOST_CHAN_REGS_OFFSET +
+		     (i * DWC_OTG_CHAN_REGS_OFFSET));
+		DWC_DEBUGPL(DBG_CILV, "hc_reg[%d]->hcchar=%p\n",
+			    i, &host_if->hc_regs[i]->hcchar);
+	}
+	host_if->num_host_channels = MAX_EPS_CHANNELS;
+	core_if->host_if = host_if;
+
+	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+		core_if->data_fifo[i] =
+		    (uint32_t *) (reg_base + DWC_OTG_DATA_FIFO_OFFSET +
+				  (i * DWC_OTG_DATA_FIFO_SIZE));
+		DWC_DEBUGPL(DBG_CILV, "data_fifo[%d]=%p\n",
+			    i, core_if->data_fifo[i]);
+	}
+
+	core_if->pcgcctl = (uint32_t *) (reg_base + DWC_OTG_PCGCCTL_OFFSET);
+
+	/*
+	 * Store the contents of the hardware configuration registers here for
+	 * easy access later.
+	 */
+	core_if->hwcfg1.d32 =
+	    dwc_read_reg32(&core_if->core_global_regs->ghwcfg1);
+	core_if->hwcfg2.d32 =
+	    dwc_read_reg32(&core_if->core_global_regs->ghwcfg2);
+	core_if->hwcfg3.d32 =
+	    dwc_read_reg32(&core_if->core_global_regs->ghwcfg3);
+	core_if->hwcfg4.d32 =
+	    dwc_read_reg32(&core_if->core_global_regs->ghwcfg4);
+
+	DWC_DEBUGPL(DBG_CILV, "hwcfg1=%08x\n", core_if->hwcfg1.d32);
+	DWC_DEBUGPL(DBG_CILV, "hwcfg2=%08x\n", core_if->hwcfg2.d32);
+	DWC_DEBUGPL(DBG_CILV, "hwcfg3=%08x\n", core_if->hwcfg3.d32);
+	DWC_DEBUGPL(DBG_CILV, "hwcfg4=%08x\n", core_if->hwcfg4.d32);
+
+	DWC_DEBUGPL(DBG_CILV, "op_mode=%0x\n", core_if->hwcfg2.b.op_mode);
+	DWC_DEBUGPL(DBG_CILV, "arch=%0x\n", core_if->hwcfg2.b.architecture);
+	DWC_DEBUGPL(DBG_CILV, "num_dev_ep=%d\n", core_if->hwcfg2.b.num_dev_ep);
+	DWC_DEBUGPL(DBG_CILV, "num_host_chan=%d\n",
+		    core_if->hwcfg2.b.num_host_chan);
+	DWC_DEBUGPL(DBG_CILV, "nonperio_tx_q_depth=0x%0x\n",
+		    core_if->hwcfg2.b.nonperio_tx_q_depth);
+	DWC_DEBUGPL(DBG_CILV, "host_perio_tx_q_depth=0x%0x\n",
+		    core_if->hwcfg2.b.host_perio_tx_q_depth);
+	DWC_DEBUGPL(DBG_CILV, "dev_token_q_depth=0x%0x\n",
+		    core_if->hwcfg2.b.dev_token_q_depth);
+
+	DWC_DEBUGPL(DBG_CILV, "Total FIFO SZ=%d\n",
+		    core_if->hwcfg3.b.dfifo_depth);
+	DWC_DEBUGPL(DBG_CILV, "xfer_size_cntr_width=%0x\n",
+		    core_if->hwcfg3.b.xfer_size_cntr_width);
+
+	/*
+	 * Set the SRP sucess bit for FS-I2c
+	 */
+	core_if->srp_success = 0;
+	core_if->srp_timer_started = 0;
+
+	return core_if;
+}
+
+/**
+ * This function frees the structures allocated by dwc_otg_cil_init().
+ *
+ * @core_if: The core interface pointer returned from
+ * dwc_otg_cil_init().
+ *
+ */
+void dwc_otg_cil_remove(struct dwc_otg_core_if *core_if)
+{
+	/* Disable all interrupts */
+	dwc_modify_reg32(&core_if->core_global_regs->gahbcfg, 1, 0);
+	dwc_write_reg32(&core_if->core_global_regs->gintmsk, 0);
+
+	kfree(core_if->dev_if);
+	kfree(core_if->host_if);
+
+	kfree(core_if);
+}
+
+/**
+ * This function enables the controller's Global Interrupt in the AHB Config
+ * register.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+extern void dwc_otg_enable_global_interrupts(struct dwc_otg_core_if *core_if)
+{
+	union gahbcfg_data ahbcfg = {.d32 = 0 };
+	ahbcfg.b.glblintrmsk = 1;	/* Enable interrupts */
+	dwc_modify_reg32(&core_if->core_global_regs->gahbcfg, 0, ahbcfg.d32);
+}
+
+/**
+ * This function disables the controller's Global Interrupt in the AHB Config
+ * register.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+extern void dwc_otg_disable_global_interrupts(struct dwc_otg_core_if *core_if)
+{
+	union gahbcfg_data ahbcfg = {.d32 = 0 };
+	ahbcfg.b.glblintrmsk = 1;	/* Enable interrupts */
+	dwc_modify_reg32(&core_if->core_global_regs->gahbcfg, ahbcfg.d32, 0);
+}
+
+/**
+ * This function initializes the commmon interrupts, used in both
+ * device and host modes.
+ *
+ * @core_if: Programming view of the DWC_otg controller
+ *
+ */
+static void dwc_otg_enable_common_interrupts(struct dwc_otg_core_if *core_if)
+{
+	struct dwc_otg_core_global_regs *global_regs =
+		core_if->core_global_regs;
+	union gintmsk_data intr_mask = {.d32 = 0 };
+	/* Clear any pending OTG Interrupts */
+	dwc_write_reg32(&global_regs->gotgint, 0xFFFFFFFF);
+	/* Clear any pending interrupts */
+	dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF);
+	/*
+	 * Enable the interrupts in the GINTMSK.
+	 */
+	intr_mask.b.modemismatch = 1;
+	intr_mask.b.otgintr = 1;
+	if (!core_if->dma_enable)
+		intr_mask.b.rxstsqlvl = 1;
+
+	intr_mask.b.conidstschng = 1;
+	intr_mask.b.wkupintr = 1;
+	intr_mask.b.disconnect = 1;
+	intr_mask.b.usbsuspend = 1;
+	intr_mask.b.sessreqintr = 1;
+	dwc_write_reg32(&global_regs->gintmsk, intr_mask.d32);
+}
+
+/**
+ * Initializes the FSLSPClkSel field of the HCFG register depending on the PHY
+ * type.
+ */
+static void init_fslspclksel(struct dwc_otg_core_if *core_if)
+{
+	uint32_t val;
+	union hcfg_data hcfg;
+
+	if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
+	     (core_if->hwcfg2.b.fs_phy_type == 1) &&
+	     (core_if->core_params->ulpi_fs_ls)) ||
+	    (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
+		/* Full speed PHY */
+		val = DWC_HCFG_48_MHZ;
+	} else {
+		/* High speed PHY running at full speed or high speed */
+		val = DWC_HCFG_30_60_MHZ;
+	}
+
+	DWC_DEBUGPL(DBG_CIL, "Initializing HCFG.FSLSPClkSel to 0x%1x\n", val);
+	hcfg.d32 = dwc_read_reg32(&core_if->host_if->host_global_regs->hcfg);
+	hcfg.b.fslspclksel = val;
+	dwc_write_reg32(&core_if->host_if->host_global_regs->hcfg, hcfg.d32);
+}
+
+/**
+ * Initializes the DevSpd field of the DCFG register depending on the PHY type
+ * and the enumeration speed of the device.
+ */
+static void init_devspd(struct dwc_otg_core_if *core_if)
+{
+	uint32_t val;
+	union dcfg_data dcfg;
+
+	if (((core_if->hwcfg2.b.hs_phy_type == 2) &&
+	     (core_if->hwcfg2.b.fs_phy_type == 1) &&
+	     (core_if->core_params->ulpi_fs_ls)) ||
+	    (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
+		/* Full speed PHY */
+		val = 0x3;
+	} else if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
+		/* High speed PHY running at full speed */
+		val = 0x1;
+	} else {
+		/* High speed PHY running at high speed */
+		val = 0x0;
+	}
+
+	DWC_DEBUGPL(DBG_CIL, "Initializing DCFG.DevSpd to 0x%1x\n", val);
+	dcfg.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dcfg);
+	dcfg.b.devspd = val;
+	dwc_write_reg32(&core_if->dev_if->dev_global_regs->dcfg, dcfg.d32);
+}
+
+/**
+ * This function initializes the DWC_otg controller registers and
+ * prepares the core for device mode or host mode operation.
+ *
+ * @core_if: Programming view of the DWC_otg controller
+ *
+ */
+void dwc_otg_core_init(struct dwc_otg_core_if *core_if)
+{
+	struct dwc_otg_core_global_regs *global_regs = core_if->core_global_regs;
+	struct dwc_otg_dev_if *dev_if = core_if->dev_if;
+	int i = 0;
+	union gahbcfg_data ahbcfg = {.d32 = 0 };
+	union gusbcfg_data usbcfg = {.d32 = 0 };
+	union gi2cctl_data i2cctl = {.d32 = 0 };
+
+	DWC_DEBUGPL(DBG_CILV, "dwc_otg_core_init(%p)\n", core_if);
+
+	/* Common Initialization */
+
+	usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
+
+	/* Program the ULPI External VBUS bit if needed */
+	usbcfg.b.ulpi_ext_vbus_drv =
+	    (core_if->core_params->phy_ulpi_ext_vbus ==
+	     DWC_PHY_ULPI_EXTERNAL_VBUS) ? 1 : 0;
+
+	/* Set external TS Dline pulsing */
+	usbcfg.b.term_sel_dl_pulse =
+	    (core_if->core_params->ts_dline == 1) ? 1 : 0;
+	dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
+
+	/* Reset the Controller */
+	dwc_otg_core_reset(core_if);
+
+	/* Initialize parameters from Hardware configuration registers. */
+	dev_if->num_eps = core_if->hwcfg2.b.num_dev_ep;
+	dev_if->num_perio_eps = core_if->hwcfg4.b.num_dev_perio_in_ep;
+
+	DWC_DEBUGPL(DBG_CIL, "num_dev_perio_in_ep=%d\n",
+		    core_if->hwcfg4.b.num_dev_perio_in_ep);
+	for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
+		dev_if->perio_tx_fifo_size[i] =
+		    dwc_read_reg32(&global_regs->dptxfsiz[i]) >> 16;
+		DWC_DEBUGPL(DBG_CIL, "Periodic Tx FIFO SZ #%d=0x%0x\n",
+			    i, dev_if->perio_tx_fifo_size[i]);
+	}
+
+	core_if->total_fifo_size = core_if->hwcfg3.b.dfifo_depth;
+	core_if->rx_fifo_size = dwc_read_reg32(&global_regs->grxfsiz);
+	core_if->nperio_tx_fifo_size =
+	    dwc_read_reg32(&global_regs->gnptxfsiz) >> 16;
+
+	DWC_DEBUGPL(DBG_CIL, "Total FIFO SZ=%d\n", core_if->total_fifo_size);
+	DWC_DEBUGPL(DBG_CIL, "Rx FIFO SZ=%d\n", core_if->rx_fifo_size);
+	DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO SZ=%d\n",
+		    core_if->nperio_tx_fifo_size);
+
+	/* This programming sequence needs to happen in FS mode before any other
+	 * programming occurs */
+	if ((core_if->core_params->speed == DWC_SPEED_PARAM_FULL) &&
+	    (core_if->core_params->phy_type == DWC_PHY_TYPE_PARAM_FS)) {
+		/* If FS mode with FS PHY */
+
+		/* core_init() is now called on every switch so only call the
+		 * following for the first time through. */
+		if (!core_if->phy_init_done) {
+			core_if->phy_init_done = 1;
+			DWC_DEBUGPL(DBG_CIL, "FS_PHY detected\n");
+			usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
+			usbcfg.b.physel = 1;
+			dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
+
+			/* Reset after a PHY select */
+			dwc_otg_core_reset(core_if);
+		}
+
+		/* Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS.  Also
+		 * do this on HNP Dev/Host mode switches (done in dev_init and
+		 * host_init). */
+		if (dwc_otg_is_host_mode(core_if))
+			init_fslspclksel(core_if);
+		else
+			init_devspd(core_if);
+
+		if (core_if->core_params->i2c_enable) {
+			DWC_DEBUGPL(DBG_CIL, "FS_PHY Enabling I2c\n");
+			/* Program GUSBCFG.OtgUtmifsSel to I2C */
+			usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
+			usbcfg.b.otgutmifssel = 1;
+			dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
+
+			/* Program GI2CCTL.I2CEn */
+			i2cctl.d32 = dwc_read_reg32(&global_regs->gi2cctl);
+			i2cctl.b.i2cdevaddr = 1;
+			i2cctl.b.i2cen = 0;
+			dwc_write_reg32(&global_regs->gi2cctl, i2cctl.d32);
+			i2cctl.b.i2cen = 1;
+			dwc_write_reg32(&global_regs->gi2cctl, i2cctl.d32);
+		}
+
+	}
+	/* endif speed == DWC_SPEED_PARAM_FULL */
+	else {
+		/* High speed PHY. */
+		if (!core_if->phy_init_done) {
+			core_if->phy_init_done = 1;
+			/* HS PHY parameters.  These parameters are preserved
+			 * during soft reset so only program the first time.  Do
+			 * a soft reset immediately after setting phyif.  */
+			usbcfg.b.ulpi_utmi_sel =
+			    (core_if->core_params->phy_type ==
+			     DWC_PHY_TYPE_PARAM_ULPI);
+			if (usbcfg.b.ulpi_utmi_sel == 1) {
+				/* ULPI interface */
+				usbcfg.b.phyif = 0;
+				usbcfg.b.ddrsel =
+				    core_if->core_params->phy_ulpi_ddr;
+			} else {
+				/* UTMI+ interface */
+				if (core_if->core_params->phy_utmi_width == 16)
+					usbcfg.b.phyif = 1;
+				else
+					usbcfg.b.phyif = 0;
+			}
+			dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
+
+			/* Reset after setting the PHY parameters */
+			dwc_otg_core_reset(core_if);
+		}
+	}
+
+	if ((core_if->hwcfg2.b.hs_phy_type == 2) &&
+	    (core_if->hwcfg2.b.fs_phy_type == 1) &&
+	    (core_if->core_params->ulpi_fs_ls)) {
+		DWC_DEBUGPL(DBG_CIL, "Setting ULPI FSLS\n");
+		usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
+		usbcfg.b.ulpi_fsls = 1;
+		usbcfg.b.ulpi_clk_sus_m = 1;
+		dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
+	} else {
+		usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
+		usbcfg.b.ulpi_fsls = 0;
+		usbcfg.b.ulpi_clk_sus_m = 0;
+		dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
+	}
+
+	/* Program the GAHBCFG Register. */
+	switch (core_if->hwcfg2.b.architecture) {
+
+	case DWC_SLAVE_ONLY_ARCH:
+		DWC_DEBUGPL(DBG_CIL, "Slave Only Mode\n");
+		ahbcfg.b.nptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
+		ahbcfg.b.ptxfemplvl = DWC_GAHBCFG_TXFEMPTYLVL_HALFEMPTY;
+		core_if->dma_enable = 0;
+		break;
+
+	case DWC_EXT_DMA_ARCH:
+		DWC_DEBUGPL(DBG_CIL, "External DMA Mode\n");
+		ahbcfg.b.hburstlen = core_if->core_params->dma_burst_size;
+		core_if->dma_enable = (core_if->core_params->dma_enable != 0);
+		break;
+
+	case DWC_INT_DMA_ARCH:
+		DWC_DEBUGPL(DBG_CIL, "Internal DMA Mode\n");
+		ahbcfg.b.hburstlen = DWC_GAHBCFG_INT_DMA_BURST_INCR;
+		core_if->dma_enable = (core_if->core_params->dma_enable != 0);
+		break;
+
+	}
+	ahbcfg.b.dmaenable = core_if->dma_enable;
+	dwc_write_reg32(&global_regs->gahbcfg, ahbcfg.d32);
+
+	/*
+	 * Program the GUSBCFG register.
+	 */
+	usbcfg.d32 = dwc_read_reg32(&global_regs->gusbcfg);
+
+	switch (core_if->hwcfg2.b.op_mode) {
+	case DWC_MODE_HNP_SRP_CAPABLE:
+		usbcfg.b.hnpcap = (core_if->core_params->otg_cap ==
+				   DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE);
+		usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
+				   DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
+		break;
+
+	case DWC_MODE_SRP_ONLY_CAPABLE:
+		usbcfg.b.hnpcap = 0;
+		usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
+				   DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
+		break;
+
+	case DWC_MODE_NO_HNP_SRP_CAPABLE:
+		usbcfg.b.hnpcap = 0;
+		usbcfg.b.srpcap = 0;
+		break;
+
+	case DWC_MODE_SRP_CAPABLE_DEVICE:
+		usbcfg.b.hnpcap = 0;
+		usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
+				   DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
+		break;
+
+	case DWC_MODE_NO_SRP_CAPABLE_DEVICE:
+		usbcfg.b.hnpcap = 0;
+		usbcfg.b.srpcap = 0;
+		break;
+
+	case DWC_MODE_SRP_CAPABLE_HOST:
+		usbcfg.b.hnpcap = 0;
+		usbcfg.b.srpcap = (core_if->core_params->otg_cap !=
+				   DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE);
+		break;
+
+	case DWC_MODE_NO_SRP_CAPABLE_HOST:
+		usbcfg.b.hnpcap = 0;
+		usbcfg.b.srpcap = 0;
+		break;
+	}
+
+	dwc_write_reg32(&global_regs->gusbcfg, usbcfg.d32);
+
+	/* Enable common interrupts */
+	dwc_otg_enable_common_interrupts(core_if);
+
+	/* Do device or host intialization based on mode during PCD
+	 * and HCD initialization  */
+	if (dwc_otg_is_host_mode(core_if)) {
+		DWC_DEBUGPL(DBG_ANY, "Host Mode\n");
+		core_if->op_state = A_HOST;
+	} else {
+		DWC_DEBUGPL(DBG_ANY, "Device Mode\n");
+		core_if->op_state = B_PERIPHERAL;
+#ifdef DWC_DEVICE_ONLY
+		dwc_otg_core_dev_init(core_if);
+#endif
+	}
+}
+
+/**
+ * This function enables the Device mode interrupts.
+ *
+ * @core_if: Programming view of DWC_otg controller
+ */
+void dwc_otg_enable_device_interrupts(struct dwc_otg_core_if *core_if)
+{
+	union gintmsk_data intr_mask = {.d32 = 0 };
+	struct dwc_otg_core_global_regs *global_regs = core_if->core_global_regs;
+
+	DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
+
+	/* Disable all interrupts. */
+	dwc_write_reg32(&global_regs->gintmsk, 0);
+
+	/* Clear any pending interrupts */
+	dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF);
+
+	/* Enable the common interrupts */
+	dwc_otg_enable_common_interrupts(core_if);
+
+	/* Enable interrupts */
+	intr_mask.b.usbreset = 1;
+	intr_mask.b.enumdone = 1;
+	intr_mask.b.epmismatch = 1;
+	intr_mask.b.inepintr = 1;
+	intr_mask.b.outepintr = 1;
+	intr_mask.b.erlysuspend = 1;
+
+#ifdef USE_PERIODIC_EP
+	/** @todo NGS: Should this be a module parameter? */
+	intr_mask.b.isooutdrop = 1;
+	intr_mask.b.eopframe = 1;
+	intr_mask.b.incomplisoin = 1;
+	intr_mask.b.incomplisoout = 1;
+#endif
+	dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
+
+	DWC_DEBUGPL(DBG_CIL, "%s() gintmsk=%0x\n", __func__,
+		    dwc_read_reg32(&global_regs->gintmsk));
+}
+
+/**
+ * This function initializes the DWC_otg controller registers for
+ * device mode.
+ *
+ * @core_if: Programming view of DWC_otg controller
+ *
+ */
+void dwc_otg_core_dev_init(struct dwc_otg_core_if *core_if)
+{
+	struct dwc_otg_core_global_regs *global_regs = core_if->core_global_regs;
+	struct dwc_otg_dev_if *dev_if = core_if->dev_if;
+	struct dwc_otg_core_params *params = core_if->core_params;
+	union dcfg_data dcfg = {.d32 = 0 };
+	union grstctl_data resetctl = {.d32 = 0 };
+	int i;
+	uint32_t rx_fifo_size;
+	union fifosize_data nptxfifosize;
+#ifdef USE_PERIODIC_EP
+	union fifosize_data ptxfifosize;
+#endif
+
+	/* Restart the Phy Clock */
+	dwc_write_reg32(core_if->pcgcctl, 0);
+
+	/* Device configuration register */
+	init_devspd(core_if);
+	dcfg.d32 = dwc_read_reg32(&dev_if->dev_global_regs->dcfg);
+	dcfg.b.perfrint = DWC_DCFG_FRAME_INTERVAL_80;
+	dwc_write_reg32(&dev_if->dev_global_regs->dcfg, dcfg.d32);
+
+	/* Configure data FIFO sizes */
+	if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
+
+		DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
+			    core_if->total_fifo_size);
+		DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
+			    params->dev_rx_fifo_size);
+		DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
+			    params->dev_nperio_tx_fifo_size);
+
+		/* Rx FIFO */
+		DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
+			    dwc_read_reg32(&global_regs->grxfsiz));
+		rx_fifo_size = params->dev_rx_fifo_size;
+		dwc_write_reg32(&global_regs->grxfsiz, rx_fifo_size);
+		DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
+			    dwc_read_reg32(&global_regs->grxfsiz));
+
+		/* Non-periodic Tx FIFO */
+		DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
+			    dwc_read_reg32(&global_regs->gnptxfsiz));
+		nptxfifosize.b.depth = params->dev_nperio_tx_fifo_size;
+		nptxfifosize.b.startaddr = params->dev_rx_fifo_size;
+		dwc_write_reg32(&global_regs->gnptxfsiz, nptxfifosize.d32);
+		DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
+			    dwc_read_reg32(&global_regs->gnptxfsiz));
+
+#ifdef USE_PERIODIC_EP
+		/**@todo NGS: Fix Periodic FIFO Sizing! */
+		/*
+		 * Periodic Tx FIFOs These FIFOs are numbered from 1 to 15.
+		 * Indexes of the FIFO size module parameters in the
+		 * dev_perio_tx_fifo_size array and the FIFO size registers in
+		 * the dptxfsiz array run from 0 to 14.
+		 */
+		/** @todo Finish debug of this */
+		ptxfifosize.b.startaddr =
+		    nptxfifosize.b.startaddr + nptxfifosize.b.depth;
+		for (i = 0; i < dev_if->num_perio_eps; i++) {
+			ptxfifosize.b.depth = params->dev_perio_tx_fifo_size[i];
+			DWC_DEBUGPL(DBG_CIL, "initial dptxfsiz[%d]=%08x\n", i,
+				    dwc_read_reg32(&global_regs->dptxfsiz[i]));
+			dwc_write_reg32(&global_regs->dptxfsiz[i],
+					ptxfifosize.d32);
+			DWC_DEBUGPL(DBG_CIL, "new dptxfsiz[%d]=%08x\n", i,
+				    dwc_read_reg32(&global_regs->dptxfsiz[i]));
+			ptxfifosize.b.startaddr += ptxfifosize.b.depth;
+		}
+#endif
+	}
+	/* Flush the FIFOs */
+	dwc_otg_flush_tx_fifo(core_if, 0x10);	/* all Tx FIFOs */
+	dwc_otg_flush_rx_fifo(core_if);
+
+	/* Flush the Learning Queue. */
+	resetctl.b.intknqflsh = 1;
+	dwc_write_reg32(&core_if->core_global_regs->grstctl, resetctl.d32);
+
+	/* Clear all pending Device Interrupts */
+	dwc_write_reg32(&dev_if->dev_global_regs->diepmsk, 0);
+	dwc_write_reg32(&dev_if->dev_global_regs->doepmsk, 0);
+	dwc_write_reg32(&dev_if->dev_global_regs->daint, 0xFFFFFFFF);
+	dwc_write_reg32(&dev_if->dev_global_regs->daintmsk, 0);
+
+	for (i = 0; i < dev_if->num_eps; i++) {
+		union depctl_data depctl;
+		depctl.d32 = dwc_read_reg32(&dev_if->in_ep_regs[i]->diepctl);
+		if (depctl.b.epena) {
+			depctl.d32 = 0;
+			depctl.b.epdis = 1;
+			depctl.b.snak = 1;
+		} else {
+			depctl.d32 = 0;
+		}
+		dwc_write_reg32(&dev_if->in_ep_regs[i]->diepctl, depctl.d32);
+
+		depctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[i]->doepctl);
+		if (depctl.b.epena) {
+			depctl.d32 = 0;
+			depctl.b.epdis = 1;
+			depctl.b.snak = 1;
+		} else {
+			depctl.d32 = 0;
+		}
+		dwc_write_reg32(&dev_if->out_ep_regs[i]->doepctl, depctl.d32);
+
+		dwc_write_reg32(&dev_if->in_ep_regs[i]->dieptsiz, 0);
+		dwc_write_reg32(&dev_if->out_ep_regs[i]->doeptsiz, 0);
+		dwc_write_reg32(&dev_if->in_ep_regs[i]->diepdma, 0);
+		dwc_write_reg32(&dev_if->out_ep_regs[i]->doepdma, 0);
+		dwc_write_reg32(&dev_if->in_ep_regs[i]->diepint, 0xFF);
+		dwc_write_reg32(&dev_if->out_ep_regs[i]->doepint, 0xFF);
+	}
+
+	dwc_otg_enable_device_interrupts(core_if);
+}
+
+/**
+ * This function enables the Host mode interrupts.
+ *
+ * @core_if: Programming view of DWC_otg controller
+ */
+void dwc_otg_enable_host_interrupts(struct dwc_otg_core_if *core_if)
+{
+	struct dwc_otg_core_global_regs *global_regs = core_if->core_global_regs;
+	union gintmsk_data intr_mask = {.d32 = 0 };
+
+	DWC_DEBUGPL(DBG_CIL, "%s()\n", __func__);
+
+	/* Disable all interrupts. */
+	dwc_write_reg32(&global_regs->gintmsk, 0);
+
+	/* Clear any pending interrupts. */
+	dwc_write_reg32(&global_regs->gintsts, 0xFFFFFFFF);
+
+	/* Enable the common interrupts */
+	dwc_otg_enable_common_interrupts(core_if);
+
+	/*
+	 * Enable host mode interrupts without disturbing common
+	 * interrupts.
+	 */
+	intr_mask.b.sofintr = 1;
+	intr_mask.b.portintr = 1;
+	intr_mask.b.hcintr = 1;
+
+	dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, intr_mask.d32);
+}
+
+/**
+ * This function disables the Host Mode interrupts.
+ *
+ * @core_if: Programming view of DWC_otg controller
+ */
+void dwc_otg_disable_host_interrupts(struct dwc_otg_core_if *core_if)
+{
+	struct dwc_otg_core_global_regs *global_regs = core_if->core_global_regs;
+	union gintmsk_data intr_mask = {.d32 = 0 };
+
+	DWC_DEBUGPL(DBG_CILV, "%s()\n", __func__);
+
+	/*
+	 * Disable host mode interrupts without disturbing common
+	 * interrupts.
+	 */
+	intr_mask.b.sofintr = 1;
+	intr_mask.b.portintr = 1;
+	intr_mask.b.hcintr = 1;
+	intr_mask.b.ptxfempty = 1;
+	intr_mask.b.nptxfempty = 1;
+
+	dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32, 0);
+}
+
+/**
+ * The FIFOs are established based on a default percentage of the
+ * total FIFO depth. This function converts the percentage into the
+ * proper setting.
+ *
+ */
+static inline uint32_t fifo_percentage(uint16_t total_fifo_size,
+				       int32_t percentage)
+{
+	/* 16-byte aligned */
+	return ((total_fifo_size * percentage) / 100) & (-1 << 3);
+}
+
+/**
+ * This function initializes the DWC_otg controller registers for
+ * host mode.
+ *
+ * This function flushes the Tx and Rx FIFOs and it flushes any entries in the
+ * request queues. Host channels are reset to ensure that they are ready for
+ * performing transfers.
+ *
+ * @core_if: Programming view of DWC_otg controller
+ *
+ */
+void dwc_otg_core_host_init(struct dwc_otg_core_if *core_if)
+{
+	struct dwc_otg_core_global_regs *global_regs = core_if->core_global_regs;
+	struct dwc_otg_host_if *host_if = core_if->host_if;
+	struct dwc_otg_core_params *params = core_if->core_params;
+	union hprt0_data hprt0 = {.d32 = 0 };
+	union fifosize_data nptxfifosize;
+	union fifosize_data ptxfifosize;
+	int i;
+	union hcchar_data hcchar;
+	union hcfg_data hcfg;
+	struct dwc_otg_hc_regs *hc_regs;
+	int num_channels;
+	union gotgctl_data gotgctl = {.d32 = 0 };
+
+	DWC_DEBUGPL(DBG_CILV, "%s(%p)\n", __func__, core_if);
+
+	/* Restart the Phy Clock */
+	dwc_write_reg32(core_if->pcgcctl, 0);
+
+	/* Initialize Host Configuration Register */
+	init_fslspclksel(core_if);
+	if (core_if->core_params->speed == DWC_SPEED_PARAM_FULL) {
+		hcfg.d32 = dwc_read_reg32(&host_if->host_global_regs->hcfg);
+		hcfg.b.fslssupp = 1;
+		dwc_write_reg32(&host_if->host_global_regs->hcfg, hcfg.d32);
+	}
+
+	/* Configure data FIFO sizes */
+	if (core_if->hwcfg2.b.dynamic_fifo && params->enable_dynamic_fifo) {
+		DWC_DEBUGPL(DBG_CIL, "Total FIFO Size=%d\n",
+			    core_if->total_fifo_size);
+		DWC_DEBUGPL(DBG_CIL, "Rx FIFO Size=%d\n",
+			    params->host_rx_fifo_size);
+		DWC_DEBUGPL(DBG_CIL, "NP Tx FIFO Size=%d\n",
+			    params->host_nperio_tx_fifo_size);
+		DWC_DEBUGPL(DBG_CIL, "P Tx FIFO Size=%d\n",
+			    params->host_perio_tx_fifo_size);
+
+		/* Rx FIFO */
+		DWC_DEBUGPL(DBG_CIL, "initial grxfsiz=%08x\n",
+			    dwc_read_reg32(&global_regs->grxfsiz));
+		dwc_write_reg32(&global_regs->grxfsiz,
+				fifo_percentage(core_if->total_fifo_size,
+						dwc_param_host_rx_fifo_size_percentage));
+		DWC_DEBUGPL(DBG_CIL, "new grxfsiz=%08x\n",
+			    dwc_read_reg32(&global_regs->grxfsiz));
+
+		/* Non-periodic Tx FIFO */
+		DWC_DEBUGPL(DBG_CIL, "initial gnptxfsiz=%08x\n",
+			    dwc_read_reg32(&global_regs->gnptxfsiz));
+		nptxfifosize.b.depth =
+		    fifo_percentage(core_if->total_fifo_size,
+				    dwc_param_host_nperio_tx_fifo_size_percentage);
+		nptxfifosize.b.startaddr =
+		    dwc_read_reg32(&global_regs->grxfsiz);
+		dwc_write_reg32(&global_regs->gnptxfsiz, nptxfifosize.d32);
+		DWC_DEBUGPL(DBG_CIL, "new gnptxfsiz=%08x\n",
+			    dwc_read_reg32(&global_regs->gnptxfsiz));
+
+		/* Periodic Tx FIFO */
+		DWC_DEBUGPL(DBG_CIL, "initial hptxfsiz=%08x\n",
+			    dwc_read_reg32(&global_regs->hptxfsiz));
+		ptxfifosize.b.depth =
+		    core_if->total_fifo_size -
+		    dwc_read_reg32(&global_regs->grxfsiz) -
+		    nptxfifosize.b.depth;
+		ptxfifosize.b.startaddr =
+		    nptxfifosize.b.startaddr + nptxfifosize.b.depth;
+		dwc_write_reg32(&global_regs->hptxfsiz, ptxfifosize.d32);
+		DWC_DEBUGPL(DBG_CIL, "new hptxfsiz=%08x\n",
+			    dwc_read_reg32(&global_regs->hptxfsiz));
+	}
+
+	/* Clear Host Set HNP Enable in the OTG Control Register */
+	gotgctl.b.hstsethnpen = 1;
+	dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0);
+
+	/* Make sure the FIFOs are flushed. */
+	dwc_otg_flush_tx_fifo(core_if, 0x10); /* all Tx FIFOs */
+	dwc_otg_flush_rx_fifo(core_if);
+
+	/* Flush out any leftover queued requests. */
+	num_channels = core_if->core_params->host_channels;
+	for (i = 0; i < num_channels; i++) {
+		hc_regs = core_if->host_if->hc_regs[i];
+		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+		hcchar.b.chen = 0;
+		hcchar.b.chdis = 1;
+		hcchar.b.epdir = 0;
+		dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+	}
+
+	/* Halt all channels to put them into a known state. */
+	for (i = 0; i < num_channels; i++) {
+		int count = 0;
+		hc_regs = core_if->host_if->hc_regs[i];
+		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+		hcchar.b.chen = 1;
+		hcchar.b.chdis = 1;
+		hcchar.b.epdir = 0;
+		dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+		DWC_DEBUGPL(DBG_HCDV, "%s: Halt channel %d\n", __func__, i);
+		do {
+			hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+			if (++count > 1000) {
+				DWC_ERROR
+				    ("%s: Unable to clear halt on channel %d\n",
+				     __func__, i);
+				break;
+			}
+		} while (hcchar.b.chen);
+	}
+
+	/* Turn on the vbus power. */
+	DWC_PRINT("Init: Port Power? op_state=%d\n", core_if->op_state);
+	if (core_if->op_state == A_HOST) {
+		hprt0.d32 = dwc_otg_read_hprt0(core_if);
+		DWC_PRINT("Init: Power Port (%d)\n", hprt0.b.prtpwr);
+		if (hprt0.b.prtpwr == 0) {
+			hprt0.b.prtpwr = 1;
+			dwc_write_reg32(host_if->hprt0, hprt0.d32);
+		}
+	}
+
+	dwc_otg_enable_host_interrupts(core_if);
+}
+
+/**
+ * Prepares a host channel for transferring packets to/from a specific
+ * endpoint. The HCCHARn register is set up with the characteristics specified
+ * in hc. Host channel interrupts that may need to be serviced while this
+ * transfer is in progress are enabled.
+ *
+ * @core_if: Programming view of DWC_otg controller
+ * @hc: Information needed to initialize the host channel
+ */
+void dwc_otg_hc_init(struct dwc_otg_core_if *core_if, struct dwc_hc *hc)
+{
+	uint32_t intr_enable;
+	union hcintmsk_data hc_intr_mask;
+	union gintmsk_data gintmsk = {.d32 = 0 };
+	union hcchar_data hcchar;
+	union hcsplt_data hcsplt;
+
+	uint8_t hc_num = hc->hc_num;
+	struct dwc_otg_host_if *host_if = core_if->host_if;
+	struct dwc_otg_hc_regs *hc_regs = host_if->hc_regs[hc_num];
+
+	/* Clear old interrupt conditions for this host channel. */
+	hc_intr_mask.d32 = 0xFFFFFFFF;
+	hc_intr_mask.b.reserved = 0;
+	dwc_write_reg32(&hc_regs->hcint, hc_intr_mask.d32);
+
+	/* Enable channel interrupts required for this transfer. */
+	hc_intr_mask.d32 = 0;
+	hc_intr_mask.b.chhltd = 1;
+	if (core_if->dma_enable) {
+		hc_intr_mask.b.ahberr = 1;
+		if (hc->error_state && !hc->do_split &&
+		    hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
+			hc_intr_mask.b.ack = 1;
+			if (hc->ep_is_in) {
+				hc_intr_mask.b.datatglerr = 1;
+				if (hc->ep_type != DWC_OTG_EP_TYPE_INTR)
+					hc_intr_mask.b.nak = 1;
+			}
+		}
+	} else {
+		switch (hc->ep_type) {
+		case DWC_OTG_EP_TYPE_CONTROL:
+		case DWC_OTG_EP_TYPE_BULK:
+			hc_intr_mask.b.xfercompl = 1;
+			hc_intr_mask.b.stall = 1;
+			hc_intr_mask.b.xacterr = 1;
+			hc_intr_mask.b.datatglerr = 1;
+			if (hc->ep_is_in) {
+				hc_intr_mask.b.bblerr = 1;
+			} else {
+				hc_intr_mask.b.nak = 1;
+				hc_intr_mask.b.nyet = 1;
+				if (hc->do_ping)
+					hc_intr_mask.b.ack = 1;
+			}
+
+			if (hc->do_split) {
+				hc_intr_mask.b.nak = 1;
+				if (hc->complete_split)
+					hc_intr_mask.b.nyet = 1;
+				else
+					hc_intr_mask.b.ack = 1;
+			}
+
+			if (hc->error_state)
+				hc_intr_mask.b.ack = 1;
+			break;
+		case DWC_OTG_EP_TYPE_INTR:
+			hc_intr_mask.b.xfercompl = 1;
+			hc_intr_mask.b.nak = 1;
+			hc_intr_mask.b.stall = 1;
+			hc_intr_mask.b.xacterr = 1;
+			hc_intr_mask.b.datatglerr = 1;
+			hc_intr_mask.b.frmovrun = 1;
+
+			if (hc->ep_is_in)
+				hc_intr_mask.b.bblerr = 1;
+			if (hc->error_state)
+				hc_intr_mask.b.ack = 1;
+			if (hc->do_split) {
+				if (hc->complete_split)
+					hc_intr_mask.b.nyet = 1;
+				else
+					hc_intr_mask.b.ack = 1;
+			}
+			break;
+		case DWC_OTG_EP_TYPE_ISOC:
+			hc_intr_mask.b.xfercompl = 1;
+			hc_intr_mask.b.frmovrun = 1;
+			hc_intr_mask.b.ack = 1;
+
+			if (hc->ep_is_in) {
+				hc_intr_mask.b.xacterr = 1;
+				hc_intr_mask.b.bblerr = 1;
+			}
+			break;
+		}
+	}
+	dwc_write_reg32(&hc_regs->hcintmsk, hc_intr_mask.d32);
+
+	/* Enable the top level host channel interrupt. */
+	intr_enable = (1 << hc_num);
+	dwc_modify_reg32(&host_if->host_global_regs->haintmsk, 0, intr_enable);
+
+	/* Make sure host channel interrupts are enabled. */
+	gintmsk.b.hcintr = 1;
+	dwc_modify_reg32(&core_if->core_global_regs->gintmsk, 0, gintmsk.d32);
+
+	/*
+	 * Program the HCCHARn register with the endpoint characteristics for
+	 * the current transfer.
+	 */
+	hcchar.d32 = 0;
+	hcchar.b.devaddr = hc->dev_addr;
+	hcchar.b.epnum = hc->ep_num;
+	hcchar.b.epdir = hc->ep_is_in;
+	hcchar.b.lspddev = (hc->speed == DWC_OTG_EP_SPEED_LOW);
+	hcchar.b.eptype = hc->ep_type;
+	hcchar.b.mps = hc->max_packet;
+
+	dwc_write_reg32(&host_if->hc_regs[hc_num]->hcchar, hcchar.d32);
+
+	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+	DWC_DEBUGPL(DBG_HCDV, "  Dev Addr: %d\n", hcchar.b.devaddr);
+	DWC_DEBUGPL(DBG_HCDV, "  Ep Num: %d\n", hcchar.b.epnum);
+	DWC_DEBUGPL(DBG_HCDV, "  Is In: %d\n", hcchar.b.epdir);
+	DWC_DEBUGPL(DBG_HCDV, "  Is Low Speed: %d\n", hcchar.b.lspddev);
+	DWC_DEBUGPL(DBG_HCDV, "  Ep Type: %d\n", hcchar.b.eptype);
+	DWC_DEBUGPL(DBG_HCDV, "  Max Pkt: %d\n", hcchar.b.mps);
+	DWC_DEBUGPL(DBG_HCDV, "  Multi Cnt: %d\n", hcchar.b.multicnt);
+
+	/*
+	 * Program the HCSPLIT register for SPLITs
+	 */
+	hcsplt.d32 = 0;
+	if (hc->do_split) {
+		DWC_DEBUGPL(DBG_HCDV, "Programming HC %d with split --> %s\n",
+			    hc->hc_num,
+			    hc->complete_split ? "CSPLIT" : "SSPLIT");
+		hcsplt.b.compsplt = hc->complete_split;
+		hcsplt.b.xactpos = hc->xact_pos;
+		hcsplt.b.hubaddr = hc->hub_addr;
+		hcsplt.b.prtaddr = hc->port_addr;
+		DWC_DEBUGPL(DBG_HCDV, "   comp split %d\n",
+			    hc->complete_split);
+		DWC_DEBUGPL(DBG_HCDV, "   xact pos %d\n", hc->xact_pos);
+		DWC_DEBUGPL(DBG_HCDV, "   hub addr %d\n", hc->hub_addr);
+		DWC_DEBUGPL(DBG_HCDV, "   port addr %d\n", hc->port_addr);
+		DWC_DEBUGPL(DBG_HCDV, "   is_in %d\n", hc->ep_is_in);
+		DWC_DEBUGPL(DBG_HCDV, "   Max Pkt: %d\n", hcchar.b.mps);
+		DWC_DEBUGPL(DBG_HCDV, "   xferlen: %d\n", hc->xfer_len);
+	}
+	dwc_write_reg32(&host_if->hc_regs[hc_num]->hcsplt, hcsplt.d32);
+
+}
+
+/**
+ * Attempts to halt a host channel. This function should only be called in
+ * Slave mode or to abort a transfer in either Slave mode or DMA mode. Under
+ * normal circumstances in DMA mode, the controller halts the channel when the
+ * transfer is complete or a condition occurs that requires application
+ * intervention.
+ *
+ * In slave mode, checks for a free request queue entry, then sets the Channel
+ * Enable and Channel Disable bits of the Host Channel Characteristics
+ * register of the specified channel to intiate the halt. If there is no free
+ * request queue entry, sets only the Channel Disable bit of the HCCHARn
+ * register to flush requests for this channel. In the latter case, sets a
+ * flag to indicate that the host channel needs to be halted when a request
+ * queue slot is open.
+ *
+ * In DMA mode, always sets the Channel Enable and Channel Disable bits of the
+ * HCCHARn register. The controller ensures there is space in the request
+ * queue before submitting the halt request.
+ *
+ * Some time may elapse before the core flushes any posted requests for this
+ * host channel and halts. The Channel Halted interrupt handler completes the
+ * deactivation of the host channel.
+ *
+ * @core_if: Controller register interface.
+ * @hc: Host channel to halt.
+ * @halt_status: Reason for halting the channel.
+ */
+void dwc_otg_hc_halt(struct dwc_otg_core_if *core_if,
+		     struct dwc_hc *hc, enum dwc_otg_halt_status halt_status)
+{
+	union gnptxsts_data nptxsts;
+	union hptxsts_data hptxsts;
+	union hcchar_data hcchar;
+	struct dwc_otg_hc_regs *hc_regs;
+	struct dwc_otg_core_global_regs *global_regs;
+	struct dwc_otg_host_global_regs *host_global_regs;
+
+	hc_regs = core_if->host_if->hc_regs[hc->hc_num];
+	global_regs = core_if->core_global_regs;
+	host_global_regs = core_if->host_if->host_global_regs;
+
+	WARN_ON(halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS);
+
+	if (halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
+	    halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
+		/*
+		 * Disable all channel interrupts except Ch Halted. The QTD
+		 * and QH state associated with this transfer has been cleared
+		 * (in the case of URB_DEQUEUE), so the channel needs to be
+		 * shut down carefully to prevent crashes.
+		 */
+		union hcintmsk_data hcintmsk;
+		hcintmsk.d32 = 0;
+		hcintmsk.b.chhltd = 1;
+		dwc_write_reg32(&hc_regs->hcintmsk, hcintmsk.d32);
+
+		/*
+		 * Make sure no other interrupts besides halt are currently
+		 * pending. Handling another interrupt could cause a crash due
+		 * to the QTD and QH state.
+		 */
+		dwc_write_reg32(&hc_regs->hcint, ~hcintmsk.d32);
+
+		/*
+		 * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
+		 * even if the channel was already halted for some other
+		 * reason.
+		 */
+		hc->halt_status = halt_status;
+
+		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+		if (hcchar.b.chen == 0) {
+			/*
+			 * The channel is either already halted or it hasn't
+			 * started yet. In DMA mode, the transfer may halt if
+			 * it finishes normally or a condition occurs that
+			 * requires driver intervention. Don't want to halt
+			 * the channel again. In either Slave or DMA mode,
+			 * it's possible that the transfer has been assigned
+			 * to a channel, but not started yet when an URB is
+			 * dequeued. Don't want to halt a channel that hasn't
+			 * started yet.
+			 */
+			return;
+		}
+	}
+
+	if (hc->halt_pending) {
+		/*
+		 * A halt has already been issued for this channel. This might
+		 * happen when a transfer is aborted by a higher level in
+		 * the stack.
+		 */
+#ifdef DEBUG
+		DWC_PRINT
+		    ("*** %s: Channel %d, hc->halt_pending already set ***\n",
+		     __func__, hc->hc_num);
+
+/* 		dwc_otg_dump_global_registers(core_if); */
+/* 		dwc_otg_dump_host_registers(core_if); */
+#endif
+		return;
+	}
+
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+	hcchar.b.chen = 1;
+	hcchar.b.chdis = 1;
+
+	if (!core_if->dma_enable) {
+		/* Check for space in the request queue to issue the halt. */
+		if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
+		    hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
+			nptxsts.d32 = dwc_read_reg32(&global_regs->gnptxsts);
+			if (nptxsts.b.nptxqspcavail == 0)
+				hcchar.b.chen = 0;
+		} else {
+			hptxsts.d32 =
+			    dwc_read_reg32(&host_global_regs->hptxsts);
+			if ((hptxsts.b.ptxqspcavail == 0)
+			    || (core_if->queuing_high_bandwidth)) {
+				hcchar.b.chen = 0;
+			}
+		}
+	}
+
+	dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+
+	hc->halt_status = halt_status;
+
+	if (hcchar.b.chen) {
+		hc->halt_pending = 1;
+		hc->halt_on_queue = 0;
+	} else {
+		hc->halt_on_queue = 1;
+	}
+
+	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+	DWC_DEBUGPL(DBG_HCDV, "  hcchar: 0x%08x\n", hcchar.d32);
+	DWC_DEBUGPL(DBG_HCDV, "  halt_pending: %d\n", hc->halt_pending);
+	DWC_DEBUGPL(DBG_HCDV, "  halt_on_queue: %d\n", hc->halt_on_queue);
+	DWC_DEBUGPL(DBG_HCDV, "  halt_status: %d\n", hc->halt_status);
+
+	return;
+}
+
+/**
+ * Clears the transfer state for a host channel. This function is normally
+ * called after a transfer is done and the host channel is being released.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @hc: Identifies the host channel to clean up.
+ */
+void dwc_otg_hc_cleanup(struct dwc_otg_core_if *core_if, struct dwc_hc *hc)
+{
+	struct dwc_otg_hc_regs *hc_regs;
+
+	hc->xfer_started = 0;
+
+	/*
+	 * Clear channel interrupt enables and any unhandled channel interrupt
+	 * conditions.
+	 */
+	hc_regs = core_if->host_if->hc_regs[hc->hc_num];
+	dwc_write_reg32(&hc_regs->hcintmsk, 0);
+	dwc_write_reg32(&hc_regs->hcint, 0xFFFFFFFF);
+
+#ifdef DEBUG
+	del_timer(&core_if->hc_xfer_timer[hc->hc_num]);
+	{
+		union hcchar_data hcchar;
+		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+		if (hcchar.b.chdis) {
+			DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
+				 __func__, hc->hc_num, hcchar.d32);
+		}
+	}
+#endif
+}
+
+/**
+ * Sets the channel property that indicates in which frame a periodic transfer
+ * should occur. This is always set to the _next_ frame. This function has no
+ * effect on non-periodic transfers.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @hc: Identifies the host channel to set up and its properties.
+ * @hcchar: Current value of the HCCHAR register for the specified host
+ * channel.
+ */
+static inline void hc_set_even_odd_frame(struct dwc_otg_core_if *core_if,
+					 struct dwc_hc *hc,
+					 union hcchar_data *hcchar)
+{
+	if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+	    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+		union hfnum_data hfnum;
+		hfnum.d32 =
+		    dwc_read_reg32(&core_if->host_if->host_global_regs->hfnum);
+		/* 1 if _next_ frame is odd, 0 if it's even */
+		hcchar->b.oddfrm = (hfnum.b.frnum & 0x1) ? 0 : 1;
+#ifdef DEBUG
+		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR && hc->do_split
+		    && !hc->complete_split) {
+			switch (hfnum.b.frnum & 0x7) {
+			case 7:
+				core_if->hfnum_7_samples++;
+				core_if->hfnum_7_frrem_accum += hfnum.b.frrem;
+				break;
+			case 0:
+				core_if->hfnum_0_samples++;
+				core_if->hfnum_0_frrem_accum += hfnum.b.frrem;
+				break;
+			default:
+				core_if->hfnum_other_samples++;
+				core_if->hfnum_other_frrem_accum +=
+				    hfnum.b.frrem;
+				break;
+			}
+		}
+#endif
+	}
+}
+
+#ifdef DEBUG
+static void hc_xfer_timeout(unsigned long _ptr)
+{
+	struct hc_xfer_info *xfer_info = (struct hc_xfer_info *) _ptr;
+	int hc_num = xfer_info->hc->hc_num;
+	DWC_WARN("%s: timeout on channel %d\n", __func__, hc_num);
+	DWC_WARN("  start_hcchar_val 0x%08x\n",
+		 xfer_info->core_if->start_hcchar_val[hc_num]);
+}
+#endif
+
+/**
+ * This function does the setup for a data transfer for a host channel and
+ * starts the transfer. May be called in either Slave mode or DMA mode. In
+ * Slave mode, the caller must ensure that there is sufficient space in the
+ * request queue and Tx Data FIFO.
+ *
+ * For an OUT transfer in Slave mode, it loads a data packet into the
+ * appropriate FIFO. If necessary, additional data packets will be loaded in
+ * the Host ISR.
+ *
+ * For an IN transfer in Slave mode, a data packet is requested. The data
+ * packets are unloaded from the Rx FIFO in the Host ISR. If necessary,
+ * additional data packets are requested in the Host ISR.
+ *
+ * For a PING transfer in Slave mode, the Do Ping bit is set in the HCTSIZ
+ * register along with a packet count of 1 and the channel is enabled. This
+ * causes a single PING transaction to occur. Other fields in HCTSIZ are
+ * simply set to 0 since no data transfer occurs in this case.
+ *
+ * For a PING transfer in DMA mode, the HCTSIZ register is initialized with
+ * all the information required to perform the subsequent data transfer. In
+ * addition, the Do Ping bit is set in the HCTSIZ register. In this case, the
+ * controller performs the entire PING protocol, then starts the data
+ * transfer.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @hc: Information needed to initialize the host channel. The xfer_len
+ * value may be reduced to accommodate the max widths of the XferSize and
+ * PktCnt fields in the HCTSIZn register. The multi_count value may be changed
+ * to reflect the final xfer_len value.
+ */
+void dwc_otg_hc_start_transfer(struct dwc_otg_core_if *core_if,
+			       struct dwc_hc *hc)
+{
+	union hcchar_data hcchar;
+	union hctsiz_data hctsiz;
+	uint16_t num_packets;
+	uint32_t max_hc_xfer_size = core_if->core_params->max_transfer_size;
+	uint16_t max_hc_pkt_count = core_if->core_params->max_packet_count;
+	struct dwc_otg_hc_regs *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
+
+	hctsiz.d32 = 0;
+
+	if (hc->do_ping) {
+		if (!core_if->dma_enable) {
+			dwc_otg_hc_do_ping(core_if, hc);
+			hc->xfer_started = 1;
+			return;
+		} else {
+			hctsiz.b.dopng = 1;
+		}
+	}
+
+	if (hc->do_split) {
+		num_packets = 1;
+
+		if (hc->complete_split && !hc->ep_is_in) {
+			/* For CSPLIT OUT Transfer, set the size to 0 so the
+			 * core doesn't expect any data written to the FIFO */
+			hc->xfer_len = 0;
+		} else if (hc->ep_is_in || (hc->xfer_len > hc->max_packet)) {
+			hc->xfer_len = hc->max_packet;
+		} else if (!hc->ep_is_in && (hc->xfer_len > 188)) {
+			hc->xfer_len = 188;
+		}
+
+		hctsiz.b.xfersize = hc->xfer_len;
+	} else {
+		/*
+		 * Ensure that the transfer length and packet count will fit
+		 * in the widths allocated for them in the HCTSIZn register.
+		 */
+		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+		    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+			/*
+			 * Make sure the transfer size is no larger than one
+			 * (micro)frame's worth of data. (A check was done
+			 * when the periodic transfer was accepted to ensure
+			 * that a (micro)frame's worth of data can be
+			 * programmed into a channel.)
+			 */
+			uint32_t max_periodic_len =
+			    hc->multi_count * hc->max_packet;
+			if (hc->xfer_len > max_periodic_len)
+				hc->xfer_len = max_periodic_len;
+		} else if (hc->xfer_len > max_hc_xfer_size) {
+			/*
+			 * Make sure that xfer_len is a multiple of
+			 * max packet size.
+			 */
+			hc->xfer_len = max_hc_xfer_size - hc->max_packet + 1;
+		}
+
+		if (hc->xfer_len > 0) {
+			num_packets =
+			    (hc->xfer_len + hc->max_packet -
+			     1) / hc->max_packet;
+			if (num_packets > max_hc_pkt_count) {
+				num_packets = max_hc_pkt_count;
+				hc->xfer_len = num_packets * hc->max_packet;
+			}
+		} else {
+			/* Need 1 packet for transfer length of 0. */
+			num_packets = 1;
+		}
+
+		if (hc->ep_is_in) {
+			/*
+			 * Always program an integral # of max packets
+			 * for IN transfers.
+			 */
+			hc->xfer_len = num_packets * hc->max_packet;
+		}
+
+		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+		    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+			/*
+			 * Make sure that the multi_count field matches the
+			 * actual transfer length.
+			 */
+			hc->multi_count = num_packets;
+
+		}
+
+		if (hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+			/* Set up the initial PID for the transfer. */
+			if (hc->speed == DWC_OTG_EP_SPEED_HIGH) {
+				if (hc->ep_is_in) {
+					if (hc->multi_count == 1) {
+						hc->data_pid_start =
+						    DWC_OTG_HC_PID_DATA0;
+					} else if (hc->multi_count == 2) {
+						hc->data_pid_start =
+						    DWC_OTG_HC_PID_DATA1;
+					} else {
+						hc->data_pid_start =
+						    DWC_OTG_HC_PID_DATA2;
+					}
+				} else {
+					if (hc->multi_count == 1) {
+						hc->data_pid_start =
+						    DWC_OTG_HC_PID_DATA0;
+					} else {
+						hc->data_pid_start =
+						    DWC_OTG_HC_PID_MDATA;
+					}
+				}
+			} else {
+				hc->data_pid_start = DWC_OTG_HC_PID_DATA0;
+			}
+		}
+
+		hctsiz.b.xfersize = hc->xfer_len;
+	}
+
+	hc->start_pkt_count = num_packets;
+	hctsiz.b.pktcnt = num_packets;
+	hctsiz.b.pid = hc->data_pid_start;
+	dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
+
+	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+	DWC_DEBUGPL(DBG_HCDV, "  Xfer Size: %d\n", hctsiz.b.xfersize);
+	DWC_DEBUGPL(DBG_HCDV, "  Num Pkts: %d\n", hctsiz.b.pktcnt);
+	DWC_DEBUGPL(DBG_HCDV, "  Start PID: %d\n", hctsiz.b.pid);
+
+	if (core_if->dma_enable) {
+#ifdef CONFIG_CPU_CAVIUM_OCTEON
+		/* Octeon uses external DMA */
+		const uint64_t USBN_DMA0_OUTB_CHN0 =
+		    CVMX_USBNX_DMA0_OUTB_CHN0(core_if->usb_num);
+		wmb();
+		cvmx_write_csr(USBN_DMA0_OUTB_CHN0 + hc->hc_num * 8,
+			       (unsigned long)hc->xfer_buff);
+		cvmx_read_csr(USBN_DMA0_OUTB_CHN0 + hc->hc_num * 8);
+		DWC_DEBUGPL(DBG_HCDV,
+			    "OUT: hc->hc_num = %d, hc->xfer_buff = %p\n",
+			    hc->hc_num, hc->xfer_buff);
+#else
+		dwc_write_reg32(&hc_regs->hcdma,
+				(uint32_t) (long)hc->xfer_buff);
+#endif /* CONFIG_CPU_CAVIUM_OCTEON */
+	}
+
+	/* Start the split */
+	if (hc->do_split) {
+		union hcsplt_data hcsplt;
+		hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt);
+		hcsplt.b.spltena = 1;
+		dwc_write_reg32(&hc_regs->hcsplt, hcsplt.d32);
+	}
+
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+	hcchar.b.multicnt = hc->multi_count;
+	hc_set_even_odd_frame(core_if, hc, &hcchar);
+#ifdef DEBUG
+	core_if->start_hcchar_val[hc->hc_num] = hcchar.d32;
+	if (hcchar.b.chdis) {
+		DWC_WARN("%s: chdis set, channel %d, hcchar 0x%08x\n",
+			 __func__, hc->hc_num, hcchar.d32);
+	}
+#endif
+
+	/* Set host channel enable after all other setup is complete. */
+	hcchar.b.chen = 1;
+	hcchar.b.chdis = 0;
+	dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+
+	hc->xfer_started = 1;
+	hc->requests++;
+
+	if (!core_if->dma_enable && !hc->ep_is_in && hc->xfer_len > 0) {
+		/* Load OUT packet into the appropriate Tx FIFO. */
+		dwc_otg_hc_write_packet(core_if, hc);
+	}
+#ifdef DEBUG
+	/* Start a timer for this transfer. */
+	core_if->hc_xfer_timer[hc->hc_num].function = hc_xfer_timeout;
+	core_if->hc_xfer_info[hc->hc_num].core_if = core_if;
+	core_if->hc_xfer_info[hc->hc_num].hc = hc;
+	core_if->hc_xfer_timer[hc->hc_num].data =
+	    (unsigned long)(&core_if->hc_xfer_info[hc->hc_num]);
+	core_if->hc_xfer_timer[hc->hc_num].expires = jiffies + (HZ * 10);
+	add_timer(&core_if->hc_xfer_timer[hc->hc_num]);
+#endif
+}
+
+/**
+ * This function continues a data transfer that was started by previous call
+ * to <code>dwc_otg_hc_start_transfer</code>. The caller must ensure there is
+ * sufficient space in the request queue and Tx Data FIFO. This function
+ * should only be called in Slave mode. In DMA mode, the controller acts
+ * autonomously to complete transfers programmed to a host channel.
+ *
+ * For an OUT transfer, a new data packet is loaded into the appropriate FIFO
+ * if there is any data remaining to be queued. For an IN transfer, another
+ * data packet is always requested. For the SETUP phase of a control transfer,
+ * this function does nothing.
+ *
+ * Returns 1 if a new request is queued, 0 if no more requests are required
+ * for this transfer.
+ */
+int dwc_otg_hc_continue_transfer(struct dwc_otg_core_if *core_if,
+				 struct dwc_hc *hc)
+{
+	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+
+	if (hc->do_split) {
+		/* SPLITs always queue just once per channel */
+		return 0;
+	} else if (hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
+		/* SETUPs are queued only once since they can't be NAKed. */
+		return 0;
+	} else if (hc->ep_is_in) {
+		/*
+		 * Always queue another request for other IN transfers. If
+		 * back-to-back INs are issued and NAKs are received for both,
+		 * the driver may still be processing the first NAK when the
+		 * second NAK is received. When the interrupt handler clears
+		 * the NAK interrupt for the first NAK, the second NAK will
+		 * not be seen. So we can't depend on the NAK interrupt
+		 * handler to requeue a NAKed request. Instead, IN requests
+		 * are issued each time this function is called. When the
+		 * transfer completes, the extra requests for the channel will
+		 * be flushed.
+		 */
+		union hcchar_data hcchar;
+		struct dwc_otg_hc_regs *hc_regs =
+		    core_if->host_if->hc_regs[hc->hc_num];
+
+		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+		hc_set_even_odd_frame(core_if, hc, &hcchar);
+		hcchar.b.chen = 1;
+		hcchar.b.chdis = 0;
+		DWC_DEBUGPL(DBG_HCDV, "  IN xfer: hcchar = 0x%08x\n",
+			    hcchar.d32);
+		dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+		hc->requests++;
+		return 1;
+	} else {
+		/* OUT transfers. */
+		if (hc->xfer_count < hc->xfer_len) {
+			if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+			    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+				union hcchar_data hcchar;
+				struct dwc_otg_hc_regs *hc_regs;
+				hc_regs =
+				    core_if->host_if->hc_regs[hc->hc_num];
+				hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+				hc_set_even_odd_frame(core_if, hc, &hcchar);
+			}
+
+			/* Load OUT packet into the appropriate Tx FIFO. */
+			dwc_otg_hc_write_packet(core_if, hc);
+			hc->requests++;
+			return 1;
+		} else {
+			return 0;
+		}
+	}
+}
+
+/**
+ * Starts a PING transfer. This function should only be called in Slave mode.
+ * The Do Ping bit is set in the HCTSIZ register, then the channel is enabled.
+ */
+void dwc_otg_hc_do_ping(struct dwc_otg_core_if *core_if, struct dwc_hc *hc)
+{
+	union hcchar_data hcchar;
+	union hctsiz_data hctsiz;
+	struct dwc_otg_hc_regs *hc_regs = core_if->host_if->hc_regs[hc->hc_num];
+
+	DWC_DEBUGPL(DBG_HCDV, "%s: Channel %d\n", __func__, hc->hc_num);
+
+	hctsiz.d32 = 0;
+	hctsiz.b.dopng = 1;
+	hctsiz.b.pktcnt = 1;
+	dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
+
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+	hcchar.b.chen = 1;
+	hcchar.b.chdis = 0;
+	dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+}
+
+/*
+ * This function writes a packet into the Tx FIFO associated with the Host
+ * Channel. For a channel associated with a non-periodic EP, the non-periodic
+ * Tx FIFO is written. For a channel associated with a periodic EP, the
+ * periodic Tx FIFO is written. This function should only be called in Slave
+ * mode.
+ *
+ * Upon return the xfer_buff and xfer_count fields in hc are incremented by
+ * then number of bytes written to the Tx FIFO.
+ */
+void dwc_otg_hc_write_packet(struct dwc_otg_core_if *core_if, struct dwc_hc *hc)
+{
+	uint32_t i;
+	uint32_t remaining_count;
+	uint32_t byte_count;
+	uint32_t dword_count;
+
+	uint32_t *data_buff = (uint32_t *) (hc->xfer_buff);
+	uint32_t *data_fifo = core_if->data_fifo[hc->hc_num];
+
+	remaining_count = hc->xfer_len - hc->xfer_count;
+	if (remaining_count > hc->max_packet)
+		byte_count = hc->max_packet;
+	else
+		byte_count = remaining_count;
+
+	dword_count = (byte_count + 3) / 4;
+
+	if ((((unsigned long)data_buff) & 0x3) == 0) {
+		/* xfer_buff is DWORD aligned. */
+		for (i = 0; i < dword_count; i++, data_buff++)
+			dwc_write_reg32(data_fifo, *data_buff);
+	} else {
+		/* xfer_buff is not DWORD aligned. */
+		for (i = 0; i < dword_count; i++, data_buff++)
+			dwc_write_reg32(data_fifo, get_unaligned(data_buff));
+	}
+
+	hc->xfer_count += byte_count;
+	hc->xfer_buff += byte_count;
+}
+
+/**
+ * Gets the current USB frame number. This is the frame number from the last
+ * SOF packet.
+ */
+uint32_t dwc_otg_get_frame_number(struct dwc_otg_core_if *core_if)
+{
+	union dsts_data dsts;
+	dsts.d32 = dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
+
+	/* read current frame/microfreme number from DSTS register */
+	return dsts.b.soffn;
+}
+
+/**
+ * This function reads a setup packet from the Rx FIFO into the destination
+ * buffer.  This function is called from the Rx Status Queue Level (RxStsQLvl)
+ * Interrupt routine when a SETUP packet has been received in Slave mode.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @dest: Destination buffer for packet data.
+ */
+void dwc_otg_read_setup_packet(struct dwc_otg_core_if *core_if, uint32_t *dest)
+{
+	/* Get the 8 bytes of a setup transaction data */
+
+	/* Pop 2 DWORDS off the receive data FIFO into memory */
+	dest[0] = dwc_read_reg32(core_if->data_fifo[0]);
+	dest[1] = dwc_read_reg32(core_if->data_fifo[0]);
+}
+
+/**
+ * This function enables EP0 OUT to receive SETUP packets and configures EP0
+ * IN for transmitting packets.  It is normally called when the
+ * "Enumeration Done" interrupt occurs.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @ep: The EP0 data.
+ */
+void dwc_otg_ep0_activate(struct dwc_otg_core_if *core_if, struct dwc_ep *ep)
+{
+	struct dwc_otg_dev_if *dev_if = core_if->dev_if;
+	union dsts_data dsts;
+	union depctl_data diepctl;
+	union depctl_data doepctl;
+	union dctl_data dctl = {.d32 = 0 };
+
+	/* Read the Device Status and Endpoint 0 Control registers */
+	dsts.d32 = dwc_read_reg32(&dev_if->dev_global_regs->dsts);
+	diepctl.d32 = dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl);
+	doepctl.d32 = dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl);
+
+	/* Set the MPS of the IN EP based on the enumeration speed */
+	switch (dsts.b.enumspd) {
+	case DWC_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ:
+	case DWC_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ:
+	case DWC_DSTS_ENUMSPD_FS_PHY_48MHZ:
+		diepctl.b.mps = DWC_DEP0CTL_MPS_64;
+		break;
+	case DWC_DSTS_ENUMSPD_LS_PHY_6MHZ:
+		diepctl.b.mps = DWC_DEP0CTL_MPS_8;
+		break;
+	}
+
+	dwc_write_reg32(&dev_if->in_ep_regs[0]->diepctl, diepctl.d32);
+
+	/* Enable OUT EP for receive */
+	doepctl.b.epena = 1;
+	dwc_write_reg32(&dev_if->out_ep_regs[0]->doepctl, doepctl.d32);
+
+#ifdef VERBOSE
+	DWC_DEBUGPL(DBG_PCDV, "doepctl0=%0x\n",
+		    dwc_read_reg32(&dev_if->out_ep_regs[0]->doepctl));
+	DWC_DEBUGPL(DBG_PCDV, "diepctl0=%0x\n",
+		    dwc_read_reg32(&dev_if->in_ep_regs[0]->diepctl));
+#endif
+	dctl.b.cgnpinnak = 1;
+	dwc_modify_reg32(&dev_if->dev_global_regs->dctl, dctl.d32, dctl.d32);
+	DWC_DEBUGPL(DBG_PCDV, "dctl=%0x\n",
+		    dwc_read_reg32(&dev_if->dev_global_regs->dctl));
+}
+
+/**
+ * This function activates an EP.  The Device EP control register for
+ * the EP is configured as defined in the ep structure.  Note: This
+ * function is not used for EP0.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @ep: The EP to activate.
+ */
+void dwc_otg_ep_activate(struct dwc_otg_core_if *core_if, struct dwc_ep *ep)
+{
+	struct dwc_otg_dev_if *dev_if = core_if->dev_if;
+	union depctl_data depctl;
+	uint32_t *addr;
+	union daint_data daintmsk = {.d32 = 0 };
+
+	DWC_DEBUGPL(DBG_PCDV, "%s() EP%d-%s\n", __func__, ep->num,
+		    (ep->is_in ? "IN" : "OUT"));
+
+	/* Read DEPCTLn register */
+	if (ep->is_in == 1) {
+		addr = &dev_if->in_ep_regs[ep->num]->diepctl;
+		daintmsk.ep.in = 1 << ep->num;
+	} else {
+		addr = &dev_if->out_ep_regs[ep->num]->doepctl;
+		daintmsk.ep.out = 1 << ep->num;
+	}
+
+	/* If the EP is already active don't change the EP Control
+	 * register. */
+	depctl.d32 = dwc_read_reg32(addr);
+	if (!depctl.b.usbactep) {
+		depctl.b.mps = ep->maxpacket;
+		depctl.b.eptype = ep->type;
+		depctl.b.txfnum = ep->tx_fifo_num;
+
+		if (ep->type != DWC_OTG_EP_TYPE_ISOC)
+			depctl.b.setd0pid = 1;
+
+		depctl.b.usbactep = 1;
+
+		dwc_write_reg32(addr, depctl.d32);
+		DWC_DEBUGPL(DBG_PCDV, "DEPCTL=%08x\n", dwc_read_reg32(addr));
+	}
+
+	/* Enable the Interrupt for this EP */
+	dwc_modify_reg32(&dev_if->dev_global_regs->daintmsk, 0, daintmsk.d32);
+	DWC_DEBUGPL(DBG_PCDV, "DAINTMSK=%0x\n",
+		    dwc_read_reg32(&dev_if->dev_global_regs->daintmsk));
+	return;
+}
+
+/**
+ * This function deactivates an EP.  This is done by clearing the USB Active
+ * EP bit in the Device EP control register.  Note: This function is not used
+ * for EP0. EP0 cannot be deactivated.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @ep: The EP to deactivate.
+ */
+void dwc_otg_ep_deactivate(struct dwc_otg_core_if *core_if, struct dwc_ep *ep)
+{
+	union depctl_data depctl = {.d32 = 0 };
+	uint32_t *addr;
+	union daint_data daintmsk = {.d32 = 0 };
+
+	/* Read DEPCTLn register */
+	if (ep->is_in == 1) {
+		addr = &core_if->dev_if->in_ep_regs[ep->num]->diepctl;
+		daintmsk.ep.in = 1 << ep->num;
+	} else {
+		addr = &core_if->dev_if->out_ep_regs[ep->num]->doepctl;
+		daintmsk.ep.out = 1 << ep->num;
+	}
+
+	depctl.b.usbactep = 0;
+	dwc_write_reg32(addr, depctl.d32);
+
+	/* Disable the Interrupt for this EP */
+	dwc_modify_reg32(&core_if->dev_if->dev_global_regs->daintmsk,
+			 daintmsk.d32, 0);
+
+	return;
+}
+
+/**
+ * This function does the setup for a data transfer for an EP and
+ * starts the transfer.  For an IN transfer, the packets will be
+ * loaded into the appropriate Tx FIFO in the ISR. For OUT transfers,
+ * the packets are unloaded from the Rx FIFO in the ISR.  the ISR.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @ep: The EP to start the transfer on.
+ */
+void dwc_otg_ep_start_transfer(struct dwc_otg_core_if *core_if,
+			       struct dwc_ep *ep)
+{
+	/*
+	 * @todo Refactor this funciton to check the transfer size
+	 * count value does not execed the number bits in the Transfer
+	 * count register.
+	 */
+	union depctl_data depctl;
+	union deptsiz_data deptsiz;
+	union gintmsk_data intr_mask = {.d32 = 0 };
+
+#ifdef CHECK_PACKET_COUNTER_WIDTH
+	const uint32_t MAX_XFER_SIZE = core_if->core_params->max_transfer_size;
+	const uint32_t MAX_PKT_COUNT = core_if->core_params->max_packet_count;
+	uint32_t num_packets;
+	uint32_t transfer_len;
+	struct dwc_otg_dev_out_ep_regs *out_regs =
+	    core_if->dev_if->out_ep_regs[ep->num];
+	struct dwc_otg_dev_in_ep_regs *in_regs =
+	    core_if->dev_if->in_ep_regs[ep->num];
+	union gnptxsts_data txstatus;
+
+	int lvl = SET_DEBUG_LEVEL(DBG_PCD);
+
+	DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
+		    "xfer_buff=%p start_xfer_buff=%p\n",
+		    ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
+		    ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff);
+
+	transfer_len = ep->xfer_len - ep->xfer_count;
+	if (transfer_len > MAX_XFER_SIZE)
+		transfer_len = MAX_XFER_SIZE;
+
+	if (transfer_len == 0) {
+		num_packets = 1;
+		/* OUT EP to recieve Zero-length packet set transfer
+		 * size to maxpacket size. */
+		if (!ep->is_in)
+			transfer_len = ep->maxpacket;
+	} else {
+		num_packets =
+		    (transfer_len + ep->maxpacket - 1) / ep->maxpacket;
+		if (num_packets > MAX_PKT_COUNT)
+			num_packets = MAX_PKT_COUNT;
+	}
+	DWC_DEBUGPL(DBG_PCD, "transfer_len=%d #pckt=%d\n", transfer_len,
+		    num_packets);
+
+	deptsiz.b.xfersize = transfer_len;
+	deptsiz.b.pktcnt = num_packets;
+
+	/* IN endpoint */
+	if (ep->is_in == 1) {
+		depctl.d32 = dwc_read_reg32(&in_regs->diepctl);
+	} else {		/* OUT endpoint */
+		depctl.d32 = dwc_read_reg32(&out_regs->doepctl);
+	}
+
+	/* EP enable, IN data in FIFO */
+	depctl.b.cnak = 1;
+	depctl.b.epena = 1;
+	/* IN endpoint */
+	if (ep->is_in == 1) {
+		txstatus.d32 =
+		    dwc_read_reg32(&core_if->core_global_regs->gnptxsts);
+		if (txstatus.b.nptxqspcavail == 0) {
+			DWC_DEBUGPL(DBG_ANY, "TX Queue Full (0x%0x)\n",
+				    txstatus.d32);
+			return;
+		}
+		dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32);
+		dwc_write_reg32(&in_regs->diepctl, depctl.d32);
+		/*
+		 * Enable the Non-Periodic Tx FIFO empty interrupt, the
+		 * data will be written into the fifo by the ISR.
+		 */
+		if (core_if->dma_enable) {
+			dwc_write_reg32(&in_regs->diepdma,
+					(uint32_t) ep->xfer_buff);
+		} else {
+			intr_mask.b.nptxfempty = 1;
+			dwc_modify_reg32(&core_if->core_global_regs->gintsts,
+					 intr_mask.d32, 0);
+			dwc_modify_reg32(&core_if->core_global_regs->gintmsk,
+					 intr_mask.d32, intr_mask.d32);
+		}
+	} else {		/* OUT endpoint */
+		dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32);
+		dwc_write_reg32(&out_regs->doepctl, depctl.d32);
+		if (core_if->dma_enable) {
+			dwc_write_reg32(&out_regs->doepdma,
+					(uint32_t) ep->xfer_buff);
+		}
+	}
+	DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n",
+		    dwc_read_reg32(&out_regs->doepctl),
+		    dwc_read_reg32(&out_regs->doeptsiz));
+	DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n",
+		    dwc_read_reg32(&core_if->dev_if->dev_global_regs->
+				   daintmsk),
+		    dwc_read_reg32(&core_if->core_global_regs->gintmsk));
+
+	SET_DEBUG_LEVEL(lvl);
+#endif
+	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s()\n", __func__);
+
+	DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
+		    "xfer_buff=%p start_xfer_buff=%p\n",
+		    ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
+		    ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff);
+
+	/* IN endpoint */
+	if (ep->is_in == 1) {
+		struct dwc_otg_dev_in_ep_regs *in_regs =
+		    core_if->dev_if->in_ep_regs[ep->num];
+		union gnptxsts_data txstatus;
+
+		txstatus.d32 =
+		    dwc_read_reg32(&core_if->core_global_regs->gnptxsts);
+		if (txstatus.b.nptxqspcavail == 0) {
+#ifdef DEBUG
+			DWC_PRINT("TX Queue Full (0x%0x)\n", txstatus.d32);
+#endif
+			return;
+		}
+
+		depctl.d32 = dwc_read_reg32(&(in_regs->diepctl));
+		deptsiz.d32 = dwc_read_reg32(&(in_regs->dieptsiz));
+
+		/* Zero Length Packet? */
+		if (ep->xfer_len == 0) {
+			deptsiz.b.xfersize = 0;
+			deptsiz.b.pktcnt = 1;
+		} else {
+
+			/* Program the transfer size and packet count
+			 *  as follows: xfersize = N * maxpacket +
+			 *  short_packet pktcnt = N + (short_packet
+			 *  exist ? 1 : 0)
+			 */
+			deptsiz.b.xfersize = ep->xfer_len;
+			deptsiz.b.pktcnt =
+			    (ep->xfer_len - 1 + ep->maxpacket) /
+			    ep->maxpacket;
+		}
+
+		dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32);
+
+		/* Write the DMA register */
+		if (core_if->dma_enable) {
+			dwc_write_reg32(&(in_regs->diepdma),
+					(uint32_t) ep->dma_addr);
+		} else {
+			/*
+			 * Enable the Non-Periodic Tx FIFO empty interrupt,
+			 * the data will be written into the fifo by the ISR.
+			 */
+			intr_mask.b.nptxfempty = 1;
+			dwc_modify_reg32(&core_if->core_global_regs->gintsts,
+					 intr_mask.d32, 0);
+			dwc_modify_reg32(&core_if->core_global_regs->gintmsk,
+					 intr_mask.d32, intr_mask.d32);
+		}
+
+		/* EP enable, IN data in FIFO */
+		depctl.b.cnak = 1;
+		depctl.b.epena = 1;
+		dwc_write_reg32(&in_regs->diepctl, depctl.d32);
+
+		depctl.d32 =
+		    dwc_read_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl);
+		depctl.b.nextep = ep->num;
+		dwc_write_reg32(&core_if->dev_if->in_ep_regs[0]->diepctl,
+				depctl.d32);
+
+	} else {
+		/* OUT endpoint */
+		struct dwc_otg_dev_out_ep_regs *out_regs =
+		    core_if->dev_if->out_ep_regs[ep->num];
+
+		depctl.d32 = dwc_read_reg32(&(out_regs->doepctl));
+		deptsiz.d32 = dwc_read_reg32(&(out_regs->doeptsiz));
+
+		/* Program the transfer size and packet count as follows:
+		 *
+		 *  pktcnt = N
+		 *  xfersize = N * maxpacket
+		 */
+		if (ep->xfer_len == 0) {
+			/* Zero Length Packet */
+			deptsiz.b.xfersize = ep->maxpacket;
+			deptsiz.b.pktcnt = 1;
+		} else {
+			deptsiz.b.pktcnt =
+			    (ep->xfer_len + (ep->maxpacket - 1)) /
+			    ep->maxpacket;
+			deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
+		}
+		dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32);
+
+		DWC_DEBUGPL(DBG_PCDV, "ep%d xfersize=%d pktcnt=%d\n",
+			    ep->num, deptsiz.b.xfersize, deptsiz.b.pktcnt);
+
+		if (core_if->dma_enable) {
+			dwc_write_reg32(&(out_regs->doepdma),
+					(uint32_t) ep->dma_addr);
+		}
+
+		if (ep->type == DWC_OTG_EP_TYPE_ISOC) {
+			/*
+			 * @todo NGS: dpid is read-only. Use setd0pid
+			 * or setd1pid.
+			 */
+			depctl.b.dpid = ep->even_odd_frame;
+		}
+
+		/* EP enable */
+		depctl.b.cnak = 1;
+		depctl.b.epena = 1;
+
+		dwc_write_reg32(&out_regs->doepctl, depctl.d32);
+
+		DWC_DEBUGPL(DBG_PCD, "DOEPCTL=%08x DOEPTSIZ=%08x\n",
+			    dwc_read_reg32(&out_regs->doepctl),
+			    dwc_read_reg32(&out_regs->doeptsiz));
+		DWC_DEBUGPL(DBG_PCD, "DAINTMSK=%08x GINTMSK=%08x\n",
+			    dwc_read_reg32(&core_if->dev_if->dev_global_regs->
+					   daintmsk),
+			    dwc_read_reg32(&core_if->core_global_regs->
+					   gintmsk));
+	}
+}
+
+/**
+ * This function does the setup for a data transfer for EP0 and starts
+ * the transfer.  For an IN transfer, the packets will be loaded into
+ * the appropriate Tx FIFO in the ISR. For OUT transfers, the packets are
+ * unloaded from the Rx FIFO in the ISR.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @ep: The EP0 data.
+ */
+void dwc_otg_ep0_start_transfer(struct dwc_otg_core_if *core_if,
+				struct dwc_ep *ep)
+{
+	union depctl_data depctl;
+	union deptsiz0_data deptsiz;
+	union gintmsk_data intr_mask = {.d32 = 0 };
+
+	DWC_DEBUGPL(DBG_PCD, "ep%d-%s xfer_len=%d xfer_cnt=%d "
+		    "xfer_buff=%p start_xfer_buff=%p total_len=%d\n",
+		    ep->num, (ep->is_in ? "IN" : "OUT"), ep->xfer_len,
+		    ep->xfer_count, ep->xfer_buff, ep->start_xfer_buff,
+		    ep->total_len);
+	ep->total_len = ep->xfer_len;
+
+	/* IN endpoint */
+	if (ep->is_in == 1) {
+		struct dwc_otg_dev_in_ep_regs *in_regs =
+		    core_if->dev_if->in_ep_regs[0];
+		union gnptxsts_data tx_status = {.d32 = 0 };
+
+		tx_status.d32 =
+		    dwc_read_reg32(&core_if->core_global_regs->gnptxsts);
+		if (tx_status.b.nptxqspcavail == 0) {
+#ifdef DEBUG
+			deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz);
+			DWC_DEBUGPL(DBG_PCD, "DIEPCTL0=%0x\n",
+				    dwc_read_reg32(&in_regs->diepctl));
+			DWC_DEBUGPL(DBG_PCD, "DIEPTSIZ0=%0x (sz=%d, pcnt=%d)\n",
+				    deptsiz.d32,
+				    deptsiz.b.xfersize, deptsiz.b.pktcnt);
+			DWC_PRINT("TX Queue or FIFO Full (0x%0x)\n",
+				  tx_status.d32);
+#endif
+
+			return;
+		}
+
+		depctl.d32 = dwc_read_reg32(&in_regs->diepctl);
+		deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz);
+
+		/* Zero Length Packet? */
+		if (ep->xfer_len == 0) {
+			deptsiz.b.xfersize = 0;
+			deptsiz.b.pktcnt = 1;
+		} else {
+			/* Program the transfer size and packet count
+			 *  as follows: xfersize = N * maxpacket +
+			 *  short_packet pktcnt = N + (short_packet
+			 *  exist ? 1 : 0)
+			 */
+			if (ep->xfer_len > ep->maxpacket) {
+				ep->xfer_len = ep->maxpacket;
+				deptsiz.b.xfersize = ep->maxpacket;
+			} else {
+				deptsiz.b.xfersize = ep->xfer_len;
+			}
+			deptsiz.b.pktcnt = 1;
+
+		}
+		dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32);
+		DWC_DEBUGPL(DBG_PCDV,
+			    "IN len=%d  xfersize=%d pktcnt=%d [%08x]\n",
+			    ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
+			    deptsiz.d32);
+
+		/* Write the DMA register */
+		if (core_if->dma_enable) {
+			dwc_write_reg32(&(in_regs->diepdma),
+					(uint32_t) ep->dma_addr);
+		}
+
+		/* EP enable, IN data in FIFO */
+		depctl.b.cnak = 1;
+		depctl.b.epena = 1;
+		dwc_write_reg32(&in_regs->diepctl, depctl.d32);
+
+		/*
+		 * Enable the Non-Periodic Tx FIFO empty interrupt, the
+		 * data will be written into the fifo by the ISR.
+		 */
+		if (!core_if->dma_enable) {
+			/* First clear it from GINTSTS */
+			intr_mask.b.nptxfempty = 1;
+			dwc_modify_reg32(&core_if->core_global_regs->gintsts,
+					 intr_mask.d32, 0);
+
+			dwc_modify_reg32(&core_if->core_global_regs->gintmsk,
+					 intr_mask.d32, intr_mask.d32);
+		}
+
+	} else {		/* OUT endpoint */
+		struct dwc_otg_dev_out_ep_regs *out_regs =
+		    core_if->dev_if->out_ep_regs[ep->num];
+
+		depctl.d32 = dwc_read_reg32(&out_regs->doepctl);
+		deptsiz.d32 = dwc_read_reg32(&out_regs->doeptsiz);
+
+		/* Program the transfer size and packet count as follows:
+		 *  xfersize = N * (maxpacket + 4 - (maxpacket % 4))
+		 *  pktcnt = N                                          */
+		if (ep->xfer_len == 0) {
+			/* Zero Length Packet */
+			deptsiz.b.xfersize = ep->maxpacket;
+			deptsiz.b.pktcnt = 1;
+		} else {
+			deptsiz.b.pktcnt =
+			    (ep->xfer_len + (ep->maxpacket - 1)) /
+			    ep->maxpacket;
+			deptsiz.b.xfersize = deptsiz.b.pktcnt * ep->maxpacket;
+		}
+
+		dwc_write_reg32(&out_regs->doeptsiz, deptsiz.d32);
+		DWC_DEBUGPL(DBG_PCDV, "len=%d  xfersize=%d pktcnt=%d\n",
+			    ep->xfer_len,
+			    deptsiz.b.xfersize, deptsiz.b.pktcnt);
+
+		if (core_if->dma_enable) {
+			dwc_write_reg32(&(out_regs->doepdma),
+					(uint32_t) ep->dma_addr);
+		}
+
+		/* EP enable */
+		depctl.b.cnak = 1;
+		depctl.b.epena = 1;
+		dwc_write_reg32(&(out_regs->doepctl), depctl.d32);
+	}
+}
+
+/**
+ * This function continues control IN transfers started by
+ * dwc_otg_ep0_start_transfer, when the transfer does not fit in a
+ * single packet.  NOTE: The DIEPCTL0/DOEPCTL0 registers only have one
+ * bit for the packet count.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @ep: The EP0 data.
+ */
+void dwc_otg_ep0_continue_transfer(struct dwc_otg_core_if *core_if,
+				   struct dwc_ep *ep)
+{
+	union depctl_data depctl;
+	union deptsiz0_data deptsiz;
+	union gintmsk_data intr_mask = {.d32 = 0 };
+
+	if (ep->is_in == 1) {
+		struct dwc_otg_dev_in_ep_regs *in_regs =
+		    core_if->dev_if->in_ep_regs[0];
+		union gnptxsts_data tx_status = {.d32 = 0 };
+
+		tx_status.d32 =
+		    dwc_read_reg32(&core_if->core_global_regs->gnptxsts);
+		/*
+		 * @todo Should there be check for room in the Tx
+		 * Status Queue.  If not remove the code above this comment.
+		 */
+
+		depctl.d32 = dwc_read_reg32(&in_regs->diepctl);
+		deptsiz.d32 = dwc_read_reg32(&in_regs->dieptsiz);
+
+		/*
+		 * Program the transfer size and packet count
+		 * as follows: xfersize = N * maxpacket +
+		 * short_packet pktcnt = N + (short_packet
+		 * exist ? 1 : 0)
+		 */
+		deptsiz.b.xfersize =
+		    (ep->total_len - ep->xfer_count) >
+		    ep->maxpacket ? ep->maxpacket : (ep->total_len -
+						       ep->xfer_count);
+		deptsiz.b.pktcnt = 1;
+		ep->xfer_len += deptsiz.b.xfersize;
+
+		dwc_write_reg32(&in_regs->dieptsiz, deptsiz.d32);
+		DWC_DEBUGPL(DBG_PCDV,
+			    "IN len=%d  xfersize=%d pktcnt=%d [%08x]\n",
+			    ep->xfer_len, deptsiz.b.xfersize, deptsiz.b.pktcnt,
+			    deptsiz.d32);
+
+		/* Write the DMA register */
+		if (core_if->hwcfg2.b.architecture == DWC_INT_DMA_ARCH) {
+			dwc_write_reg32(&(in_regs->diepdma),
+					(uint32_t) ep->dma_addr);
+		}
+
+		/* EP enable, IN data in FIFO */
+		depctl.b.cnak = 1;
+		depctl.b.epena = 1;
+		dwc_write_reg32(&in_regs->diepctl, depctl.d32);
+
+		/*
+		 * Enable the Non-Periodic Tx FIFO empty interrupt, the
+		 * data will be written into the fifo by the ISR.
+		 */
+		if (!core_if->dma_enable) {
+			/* First clear it from GINTSTS */
+			intr_mask.b.nptxfempty = 1;
+			dwc_write_reg32(&core_if->core_global_regs->gintsts,
+					intr_mask.d32);
+
+			dwc_modify_reg32(&core_if->core_global_regs->gintmsk,
+					 intr_mask.d32, intr_mask.d32);
+		}
+
+	}
+
+}
+
+#ifdef DEBUG
+void dump_msg(const u8 *buf, unsigned int length)
+{
+	unsigned int start, num, i;
+	char line[52], *p;
+
+	if (length >= 512)
+		return;
+	start = 0;
+	while (length > 0) {
+		num = min(length, 16u);
+		p = line;
+		for (i = 0; i < num; ++i) {
+			if (i == 8)
+				*p++ = ' ';
+			sprintf(p, " %02x", buf[i]);
+			p += 3;
+		}
+		*p = 0;
+		DWC_PRINT("%6x: %s\n", start, line);
+		buf += num;
+		start += num;
+		length -= num;
+	}
+}
+#else
+static inline void dump_msg(const u8 *buf, unsigned int length)
+{
+}
+#endif
+
+/**
+ * This function writes a packet into the Tx FIFO associated with the
+ * EP.  For non-periodic EPs the non-periodic Tx FIFO is written.  For
+ * periodic EPs the periodic Tx FIFO associated with the EP is written
+ * with all packets for the next micro-frame.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @ep: The EP to write packet for.
+ * @_dma: Indicates if DMA is being used.
+ */
+void dwc_otg_ep_write_packet(struct dwc_otg_core_if *core_if,
+			     struct dwc_ep *ep,
+			     int _dma)
+{
+	/**
+	 * The buffer is padded to DWORD on a per packet basis in
+	 * slave/dma mode if the MPS is not DWORD aligned.  The last
+	 * packet, if short, is also padded to a multiple of DWORD.
+	 *
+	 * ep->xfer_buff always starts DWORD aligned in memory and is a
+	 * multiple of DWORD in length
+	 *
+	 * ep->xfer_len can be any number of bytes
+	 *
+	 * ep->xfer_count is a multiple of ep->maxpacket until the last
+	 *  packet
+	 *
+	 * FIFO access is DWORD */
+
+	uint32_t i;
+	uint32_t byte_count;
+	uint32_t dword_count;
+	uint32_t *fifo;
+	uint32_t *data_buff = (uint32_t *) ep->xfer_buff;
+
+	if (ep->xfer_count >= ep->xfer_len) {
+		DWC_WARN("%s() No data for EP%d!!!\n", __func__, ep->num);
+		return;
+	}
+
+	/* Find the byte length of the packet either short packet or MPS */
+	if ((ep->xfer_len - ep->xfer_count) < ep->maxpacket)
+		byte_count = ep->xfer_len - ep->xfer_count;
+	else
+		byte_count = ep->maxpacket;
+
+	/* Find the DWORD length, padded by extra bytes as neccessary if MPS
+	 * is not a multiple of DWORD */
+	dword_count = (byte_count + 3) / 4;
+
+#ifdef VERBOSE
+	dump_msg(ep->xfer_buff, byte_count);
+#endif
+	if (ep->type == DWC_OTG_EP_TYPE_ISOC)
+		/*
+		 *@todo NGS Where are the Periodic Tx FIFO addresses
+		 * intialized?  What should this be?
+		 */
+		fifo = core_if->data_fifo[ep->tx_fifo_num];
+	else
+		fifo = core_if->data_fifo[ep->num];
+
+	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "fifo=%p buff=%p *p=%08x bc=%d\n",
+		    fifo, data_buff, *data_buff, byte_count);
+
+	if (!_dma) {
+		for (i = 0; i < dword_count; i++, data_buff++)
+			dwc_write_reg32(fifo, *data_buff);
+	}
+
+	ep->xfer_count += byte_count;
+	ep->xfer_buff += byte_count;
+}
+
+/**
+ * Set the EP STALL.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @ep: The EP to set the stall on.
+ */
+void dwc_otg_ep_set_stall(struct dwc_otg_core_if *core_if, struct dwc_ep *ep)
+{
+	union depctl_data depctl;
+	uint32_t *depctl_addr;
+
+	DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
+		    (ep->is_in ? "IN" : "OUT"));
+
+	if (ep->is_in == 1) {
+		depctl_addr =
+		    &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
+		depctl.d32 = dwc_read_reg32(depctl_addr);
+
+		/* set the disable and stall bits */
+		if (depctl.b.epena)
+			depctl.b.epdis = 1;
+		depctl.b.stall = 1;
+		dwc_write_reg32(depctl_addr, depctl.d32);
+
+	} else {
+		depctl_addr =
+		    &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
+		depctl.d32 = dwc_read_reg32(depctl_addr);
+
+		/* set the stall bit */
+		depctl.b.stall = 1;
+		dwc_write_reg32(depctl_addr, depctl.d32);
+	}
+	DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", dwc_read_reg32(depctl_addr));
+	return;
+}
+
+/**
+ * Clear the EP STALL.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @ep: The EP to clear stall from.
+ */
+void dwc_otg_ep_clear_stall(struct dwc_otg_core_if *core_if, struct dwc_ep *ep)
+{
+	union depctl_data depctl;
+	uint32_t *depctl_addr;
+
+	DWC_DEBUGPL(DBG_PCD, "%s ep%d-%s\n", __func__, ep->num,
+		    (ep->is_in ? "IN" : "OUT"));
+
+	if (ep->is_in == 1) {
+		depctl_addr =
+		    &(core_if->dev_if->in_ep_regs[ep->num]->diepctl);
+	} else {
+		depctl_addr =
+		    &(core_if->dev_if->out_ep_regs[ep->num]->doepctl);
+	}
+
+	depctl.d32 = dwc_read_reg32(depctl_addr);
+
+	/* clear the stall bits */
+	depctl.b.stall = 0;
+
+	/*
+	 * USB Spec 9.4.5: For endpoints using data toggle, regardless
+	 * of whether an endpoint has the Halt feature set, a
+	 * ClearFeature(ENDPOINT_HALT) request always results in the
+	 * data toggle being reinitialized to DATA0.
+	 */
+	if (ep->type == DWC_OTG_EP_TYPE_INTR ||
+	    ep->type == DWC_OTG_EP_TYPE_BULK) {
+		depctl.b.setd0pid = 1;	/* DATA0 */
+	}
+
+	dwc_write_reg32(depctl_addr, depctl.d32);
+	DWC_DEBUGPL(DBG_PCD, "DEPCTL=%0x\n", dwc_read_reg32(depctl_addr));
+	return;
+}
+
+/**
+ * This function reads a packet from the Rx FIFO into the destination
+ * buffer.  To read SETUP data use dwc_otg_read_setup_packet.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @dest:   Destination buffer for the packet.
+ * @bytes:  Number of bytes to copy to the destination.
+ */
+void dwc_otg_read_packet(struct dwc_otg_core_if *core_if,
+			 uint8_t *dest, uint16_t bytes)
+{
+	int i;
+	int word_count = (bytes + 3) / 4;
+
+	uint32_t *fifo = core_if->data_fifo[0];
+	uint32_t *data_buff = (uint32_t *) dest;
+
+	/**
+	 * @todo Account for the case where dest is not dword aligned. This
+	 * requires reading data from the FIFO into a uint32_t temp buffer,
+	 * then moving it into the data buffer.
+	 */
+
+	DWC_DEBUGPL((DBG_PCDV | DBG_CILV), "%s(%p,%p,%d)\n", __func__,
+		    core_if, dest, bytes);
+
+	for (i = 0; i < word_count; i++, data_buff++)
+		*data_buff = dwc_read_reg32(fifo);
+	return;
+}
+
+/**
+ * This functions reads the device registers and prints them
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+void dwc_otg_dump_dev_registers(struct dwc_otg_core_if *core_if)
+{
+	int i;
+	uint32_t *addr;
+
+	DWC_PRINT("Device Global Registers\n");
+	addr = &core_if->dev_if->dev_global_regs->dcfg;
+	DWC_PRINT("DCFG      @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->dev_if->dev_global_regs->dctl;
+	DWC_PRINT("DCTL      @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->dev_if->dev_global_regs->dsts;
+	DWC_PRINT("DSTS      @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->dev_if->dev_global_regs->diepmsk;
+	DWC_PRINT("DIEPMSK   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->dev_if->dev_global_regs->doepmsk;
+	DWC_PRINT("DOEPMSK   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->dev_if->dev_global_regs->daint;
+	DWC_PRINT("DAINT     @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->dev_if->dev_global_regs->dtknqr1;
+	DWC_PRINT("DTKNQR1   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	if (core_if->hwcfg2.b.dev_token_q_depth > 6) {
+		addr = &core_if->dev_if->dev_global_regs->dtknqr2;
+		DWC_PRINT("DTKNQR2   @%p : 0x%08X\n",
+			  addr, dwc_read_reg32(addr));
+	}
+
+	addr = &core_if->dev_if->dev_global_regs->dvbusdis;
+	DWC_PRINT("DVBUSID   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+
+	addr = &core_if->dev_if->dev_global_regs->dvbuspulse;
+	DWC_PRINT("DVBUSPULSE   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+
+	if (core_if->hwcfg2.b.dev_token_q_depth > 14) {
+		addr = &core_if->dev_if->dev_global_regs->dtknqr3;
+		DWC_PRINT("DTKNQR3   @%p : 0x%08X\n",
+			  addr, dwc_read_reg32(addr));
+	}
+
+	if (core_if->hwcfg2.b.dev_token_q_depth > 22) {
+		addr = &core_if->dev_if->dev_global_regs->dtknqr4;
+		DWC_PRINT("DTKNQR4   @%p : 0x%08X\n",
+			  addr, dwc_read_reg32(addr));
+	}
+
+	for (i = 0; i < core_if->dev_if->num_eps; i++) {
+		DWC_PRINT("Device IN EP %d Registers\n", i);
+		addr = &core_if->dev_if->in_ep_regs[i]->diepctl;
+		DWC_PRINT("DIEPCTL   @%p : 0x%08X\n", addr,
+			  dwc_read_reg32(addr));
+		addr = &core_if->dev_if->in_ep_regs[i]->diepint;
+		DWC_PRINT("DIEPINT   @%p : 0x%08X\n", addr,
+			  dwc_read_reg32(addr));
+		addr = &core_if->dev_if->in_ep_regs[i]->dieptsiz;
+		DWC_PRINT("DIETSIZ   @%p : 0x%08X\n", addr,
+			  dwc_read_reg32(addr));
+		addr = &core_if->dev_if->in_ep_regs[i]->diepdma;
+		DWC_PRINT("DIEPDMA   @%p : 0x%08X\n", addr,
+			  dwc_read_reg32(addr));
+
+		DWC_PRINT("Device OUT EP %d Registers\n", i);
+		addr = &core_if->dev_if->out_ep_regs[i]->doepctl;
+		DWC_PRINT("DOEPCTL   @%p : 0x%08X\n", addr,
+			  dwc_read_reg32(addr));
+		addr = &core_if->dev_if->out_ep_regs[i]->doepfn;
+		DWC_PRINT("DOEPFN    @%p : 0x%08X\n", addr,
+			  dwc_read_reg32(addr));
+		addr = &core_if->dev_if->out_ep_regs[i]->doepint;
+		DWC_PRINT("DOEPINT   @%p : 0x%08X\n", addr,
+			  dwc_read_reg32(addr));
+		addr = &core_if->dev_if->out_ep_regs[i]->doeptsiz;
+		DWC_PRINT("DOETSIZ   @%p : 0x%08X\n", addr,
+			  dwc_read_reg32(addr));
+		addr = &core_if->dev_if->out_ep_regs[i]->doepdma;
+		DWC_PRINT("DOEPDMA   @%p : 0x%08X\n", addr,
+			  dwc_read_reg32(addr));
+	}
+	return;
+}
+
+/**
+ * This function reads the host registers and prints them
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+void dwc_otg_dump_host_registers(struct dwc_otg_core_if *core_if)
+{
+	int i;
+	uint32_t *addr;
+
+	DWC_PRINT("Host Global Registers\n");
+	addr = &core_if->host_if->host_global_regs->hcfg;
+	DWC_PRINT("HCFG      @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->host_if->host_global_regs->hfir;
+	DWC_PRINT("HFIR      @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->host_if->host_global_regs->hfnum;
+	DWC_PRINT("HFNUM     @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->host_if->host_global_regs->hptxsts;
+	DWC_PRINT("HPTXSTS   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->host_if->host_global_regs->haint;
+	DWC_PRINT("HAINT     @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->host_if->host_global_regs->haintmsk;
+	DWC_PRINT("HAINTMSK  @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = core_if->host_if->hprt0;
+	DWC_PRINT("HPRT0     @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+
+	for (i = 0; i < core_if->core_params->host_channels; i++) {
+		DWC_PRINT("Host Channel %d Specific Registers\n", i);
+		addr = &core_if->host_if->hc_regs[i]->hcchar;
+		DWC_PRINT("HCCHAR    @%p : 0x%08X\n", addr,
+			  dwc_read_reg32(addr));
+		addr = &core_if->host_if->hc_regs[i]->hcsplt;
+		DWC_PRINT("HCSPLT    @%p : 0x%08X\n", addr,
+			  dwc_read_reg32(addr));
+		addr = &core_if->host_if->hc_regs[i]->hcint;
+		DWC_PRINT("HCINT     @%p : 0x%08X\n", addr,
+			  dwc_read_reg32(addr));
+		addr = &core_if->host_if->hc_regs[i]->hcintmsk;
+		DWC_PRINT("HCINTMSK  @%p : 0x%08X\n", addr,
+			  dwc_read_reg32(addr));
+		addr = &core_if->host_if->hc_regs[i]->hctsiz;
+		DWC_PRINT("HCTSIZ    @%p : 0x%08X\n", addr,
+			  dwc_read_reg32(addr));
+		addr = &core_if->host_if->hc_regs[i]->hcdma;
+		DWC_PRINT("HCDMA     @%p : 0x%08X\n", addr,
+			  dwc_read_reg32(addr));
+
+	}
+	return;
+}
+
+/**
+ * This function reads the core global registers and prints them
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+void dwc_otg_dump_global_registers(struct dwc_otg_core_if *core_if)
+{
+	int i;
+	uint32_t *addr;
+
+	DWC_PRINT("Core Global Registers\n");
+	addr = &core_if->core_global_regs->gotgctl;
+	DWC_PRINT("GOTGCTL   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->gotgint;
+	DWC_PRINT("GOTGINT   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->gahbcfg;
+	DWC_PRINT("GAHBCFG   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->gusbcfg;
+	DWC_PRINT("GUSBCFG   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->grstctl;
+	DWC_PRINT("GRSTCTL   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->gintsts;
+	DWC_PRINT("GINTSTS   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->gintmsk;
+	DWC_PRINT("GINTMSK   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->grxstsr;
+	DWC_PRINT("GRXSTSR   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->grxfsiz;
+	DWC_PRINT("GRXFSIZ   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->gnptxfsiz;
+	DWC_PRINT("GNPTXFSIZ @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->gnptxsts;
+	DWC_PRINT("GNPTXSTS  @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->gi2cctl;
+	DWC_PRINT("GI2CCTL   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->gpvndctl;
+	DWC_PRINT("GPVNDCTL  @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->ggpio;
+	DWC_PRINT("GGPIO     @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->guid;
+	DWC_PRINT("GUID      @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->gsnpsid;
+	DWC_PRINT("GSNPSID   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->ghwcfg1;
+	DWC_PRINT("GHWCFG1   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->ghwcfg2;
+	DWC_PRINT("GHWCFG2   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->ghwcfg3;
+	DWC_PRINT("GHWCFG3   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->ghwcfg4;
+	DWC_PRINT("GHWCFG4   @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+	addr = &core_if->core_global_regs->hptxfsiz;
+	DWC_PRINT("HPTXFSIZ  @%p : 0x%08X\n", addr, dwc_read_reg32(addr));
+
+	for (i = 0; i < core_if->hwcfg4.b.num_dev_perio_in_ep; i++) {
+		addr = &core_if->core_global_regs->dptxfsiz[i];
+		DWC_PRINT("DPTXFSIZ[%d] @%p : 0x%08X\n", i, addr,
+			  dwc_read_reg32(addr));
+	}
+
+}
+
+/**
+ * Flush a Tx FIFO.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @_num: Tx FIFO to flush.
+ */
+extern void dwc_otg_flush_tx_fifo(struct dwc_otg_core_if *core_if, const int _num)
+{
+	struct dwc_otg_core_global_regs *global_regs = core_if->core_global_regs;
+	union grstctl_data greset = {.d32 = 0 };
+	int count = 0;
+
+	DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "Flush Tx FIFO %d\n", _num);
+
+	greset.b.txfflsh = 1;
+	greset.b.txfnum = _num;
+	dwc_write_reg32(&global_regs->grstctl, greset.d32);
+
+	do {
+		greset.d32 = dwc_read_reg32(&global_regs->grstctl);
+		if (++count > 10000) {
+			DWC_WARN("%s() HANG! GRSTCTL=%0x GNPTXSTS=0x%08x\n",
+				 __func__, greset.d32,
+				 dwc_read_reg32(&global_regs->gnptxsts));
+			break;
+		}
+
+	} while (greset.b.txfflsh == 1);
+	/* Wait for 3 PHY Clocks */
+	udelay(1);
+}
+
+/**
+ * Flush Rx FIFO.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+extern void dwc_otg_flush_rx_fifo(struct dwc_otg_core_if *core_if)
+{
+	struct dwc_otg_core_global_regs *global_regs = core_if->core_global_regs;
+	union grstctl_data greset = {.d32 = 0 };
+	int count = 0;
+
+	DWC_DEBUGPL((DBG_CIL | DBG_PCDV), "%s\n", __func__);
+	/*
+	 *
+	 */
+	greset.b.rxfflsh = 1;
+	dwc_write_reg32(&global_regs->grstctl, greset.d32);
+
+	do {
+		greset.d32 = dwc_read_reg32(&global_regs->grstctl);
+		if (++count > 10000) {
+			DWC_WARN("%s() HANG! GRSTCTL=%0x\n", __func__,
+				 greset.d32);
+			break;
+		}
+	} while (greset.b.rxfflsh == 1);
+	/* Wait for 3 PHY Clocks */
+	udelay(1);
+}
+
+/**
+ * Do core a soft reset of the core.  Be careful with this because it
+ * resets all the internal state machines of the core.
+ */
+void dwc_otg_core_reset(struct dwc_otg_core_if *core_if)
+{
+	struct dwc_otg_core_global_regs *global_regs = core_if->core_global_regs;
+	union grstctl_data greset = {.d32 = 0 };
+	int count = 0;
+
+	DWC_DEBUGPL(DBG_CILV, "%s\n", __func__);
+	/* Wait for AHB master IDLE state. */
+	do {
+		udelay(10);
+		greset.d32 = dwc_read_reg32(&global_regs->grstctl);
+		if (++count > 100000) {
+			DWC_WARN("%s() HANG! AHB Idle GRSTCTL=%0x\n", __func__,
+				 greset.d32);
+			return;
+		}
+	} while (greset.b.ahbidle == 0);
+
+	/* Core Soft Reset */
+	count = 0;
+	greset.b.csftrst = 1;
+	dwc_write_reg32(&global_regs->grstctl, greset.d32);
+	do {
+		greset.d32 = dwc_read_reg32(&global_regs->grstctl);
+		if (++count > 10000) {
+			DWC_WARN("%s() HANG! Soft Reset GRSTCTL=%0x\n",
+				 __func__, greset.d32);
+			break;
+		}
+	} while (greset.b.csftrst == 1);
+	/* Wait for 3 PHY Clocks */
+	mdelay(100);
+}
+
+/**
+ * Register HCD callbacks.  The callbacks are used to start and stop
+ * the HCD for interrupt processing.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @_cb: the HCD callback structure.
+ * @_p: pointer to be passed to callback function (usb_hcd*).
+ */
+extern void dwc_otg_cil_register_hcd_callbacks(struct dwc_otg_core_if *core_if,
+					       struct dwc_otg_cil_callbacks *_cb,
+					       void *_p)
+{
+	core_if->hcd_cb = _cb;
+	_cb->p = _p;
+}
+
+/**
+ * Register PCD callbacks.  The callbacks are used to start and stop
+ * the PCD for interrupt processing.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ * @_cb: the PCD callback structure.
+ * @_p: pointer to be passed to callback function (pcd*).
+ */
+extern void dwc_otg_cil_register_pcd_callbacks(struct dwc_otg_core_if *core_if,
+					       struct dwc_otg_cil_callbacks *_cb,
+					       void *_p)
+{
+	core_if->pcd_cb = _cb;
+	_cb->p = _p;
+}
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil.h b/drivers/usb/host/dwc_otg/dwc_otg_cil.h
new file mode 100644
index 0000000..36ef561
--- /dev/null
+++ b/drivers/usb/host/dwc_otg/dwc_otg_cil.h
@@ -0,0 +1,866 @@
+/* ==========================================================================
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+#if !defined(__DWC_CIL_H__)
+#define __DWC_CIL_H__
+
+#include "dwc_otg_plat.h"
+#include "dwc_otg_regs.h"
+#ifdef DEBUG
+#include "linux/timer.h"
+#endif
+
+/*
+ * This file contains the interface to the Core Interface Layer.
+ */
+
+/**
+ * The <code>dwc_ep</code> structure represents the state of a single
+ * endpoint when acting in device mode. It contains the data items
+ * needed for an endpoint to be activated and transfer packets.
+ */
+struct dwc_ep {
+	/** EP number used for register address lookup */
+	uint8_t num;
+	/** EP direction 0 = OUT */
+	unsigned is_in:1;
+	/** EP active. */
+	unsigned active:1;
+
+	/*
+	 * Periodic Tx FIFO # for IN EPs For INTR EP set to 0 to use
+	 * non-periodic Tx FIFO
+	 */
+	unsigned tx_fifo_num:4;
+	/** EP type: 0 - Control, 1 - ISOC,  2 - BULK,  3 - INTR */
+	unsigned type:2;
+#define DWC_OTG_EP_TYPE_CONTROL    0
+#define DWC_OTG_EP_TYPE_ISOC       1
+#define DWC_OTG_EP_TYPE_BULK       2
+#define DWC_OTG_EP_TYPE_INTR       3
+
+	/** DATA start PID for INTR and BULK EP */
+	unsigned data_pid_start:1;
+	/** Frame (even/odd) for ISOC EP */
+	unsigned even_odd_frame:1;
+	/** Max Packet bytes */
+	unsigned maxpacket:11;
+
+	/** @name Transfer state */
+	/** @{ */
+
+	/**
+	 * Pointer to the beginning of the transfer buffer -- do not modify
+	 * during transfer.
+	 */
+
+	uint32_t dma_addr;
+
+	uint8_t *start_xfer_buff;
+	/** pointer to the transfer buffer */
+	uint8_t *xfer_buff;
+	/** Number of bytes to transfer */
+	unsigned xfer_len:19;
+	/** Number of bytes transferred. */
+	unsigned xfer_count:19;
+	/** Sent ZLP */
+	unsigned sent_zlp:1;
+	/** Total len for control transfer */
+	unsigned total_len:19;
+
+	/** @} */
+};
+
+/*
+ * Reasons for halting a host channel.
+ */
+enum dwc_otg_halt_status {
+	DWC_OTG_HC_XFER_NO_HALT_STATUS,
+	DWC_OTG_HC_XFER_COMPLETE,
+	DWC_OTG_HC_XFER_URB_COMPLETE,
+	DWC_OTG_HC_XFER_ACK,
+	DWC_OTG_HC_XFER_NAK,
+	DWC_OTG_HC_XFER_NYET,
+	DWC_OTG_HC_XFER_STALL,
+	DWC_OTG_HC_XFER_XACT_ERR,
+	DWC_OTG_HC_XFER_FRAME_OVERRUN,
+	DWC_OTG_HC_XFER_BABBLE_ERR,
+	DWC_OTG_HC_XFER_DATA_TOGGLE_ERR,
+	DWC_OTG_HC_XFER_AHB_ERR,
+	DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE,
+	DWC_OTG_HC_XFER_URB_DEQUEUE
+};
+
+/**
+ * Host channel descriptor. This structure represents the state of a single
+ * host channel when acting in host mode. It contains the data items needed to
+ * transfer packets to an endpoint via a host channel.
+ */
+struct dwc_hc {
+	/** Host channel number used for register address lookup */
+	uint8_t hc_num;
+
+	/** Device to access */
+	unsigned dev_addr:7;
+
+	/** EP to access */
+	unsigned ep_num:4;
+
+	/** EP direction. 0: OUT, 1: IN */
+	unsigned ep_is_in:1;
+
+	/**
+	 * EP speed.
+	 * One of the following values:
+	 * 	- DWC_OTG_EP_SPEED_LOW
+	 *	- DWC_OTG_EP_SPEED_FULL
+	 *	- DWC_OTG_EP_SPEED_HIGH
+	 */
+	unsigned speed:2;
+#define DWC_OTG_EP_SPEED_LOW	0
+#define DWC_OTG_EP_SPEED_FULL	1
+#define DWC_OTG_EP_SPEED_HIGH	2
+
+	/**
+	 * Endpoint type.
+	 * One of the following values:
+	 *	- DWC_OTG_EP_TYPE_CONTROL: 0
+	 *	- DWC_OTG_EP_TYPE_ISOC: 1
+	 *	- DWC_OTG_EP_TYPE_BULK: 2
+	 *	- DWC_OTG_EP_TYPE_INTR: 3
+	 */
+	unsigned ep_type:2;
+
+	/** Max packet size in bytes */
+	unsigned max_packet:11;
+
+	/**
+	 * PID for initial transaction.
+	 * 0: DATA0,<br>
+	 * 1: DATA2,<br>
+	 * 2: DATA1,<br>
+	 * 3: MDATA (non-Control EP),
+	 *    SETUP (Control EP)
+	 */
+	unsigned data_pid_start:2;
+#define DWC_OTG_HC_PID_DATA0 0
+#define DWC_OTG_HC_PID_DATA2 1
+#define DWC_OTG_HC_PID_DATA1 2
+#define DWC_OTG_HC_PID_MDATA 3
+#define DWC_OTG_HC_PID_SETUP 3
+
+	/** Number of periodic transactions per (micro)frame */
+	unsigned multi_count:2;
+
+	/** @name Transfer State */
+	/** @{ */
+
+	/** Pointer to the current transfer buffer position. */
+	uint8_t *xfer_buff;
+	/** Total number of bytes to transfer. */
+	uint32_t xfer_len;
+	/** Number of bytes transferred so far. */
+	uint32_t xfer_count;
+	/** Packet count at start of transfer.*/
+	uint16_t start_pkt_count;
+
+	/**
+	 * Flag to indicate whether the transfer has been started. Set to 1 if
+	 * it has been started, 0 otherwise.
+	 */
+	uint8_t xfer_started;
+
+	/**
+	 * Set to 1 to indicate that a PING request should be issued on this
+	 * channel. If 0, process normally.
+	 */
+	uint8_t do_ping;
+
+	/**
+	 * Set to 1 to indicate that the error count for this transaction is
+	 * non-zero. Set to 0 if the error count is 0.
+	 */
+	uint8_t error_state;
+
+	/**
+	 * Set to 1 to indicate that this channel should be halted the next
+	 * time a request is queued for the channel. This is necessary in
+	 * slave mode if no request queue space is available when an attempt
+	 * is made to halt the channel.
+	 */
+	uint8_t halt_on_queue;
+
+	/**
+	 * Set to 1 if the host channel has been halted, but the core is not
+	 * finished flushing queued requests. Otherwise 0.
+	 */
+	uint8_t halt_pending;
+
+	/**
+	 * Reason for halting the host channel.
+	 */
+	enum dwc_otg_halt_status halt_status;
+
+	/*
+	 * Split settings for the host channel
+	 */
+	uint8_t do_split;	   /**< Enable split for the channel */
+	uint8_t complete_split;	   /**< Enable complete split */
+	uint8_t hub_addr;	   /**< Address of high speed hub */
+
+	uint8_t port_addr;	   /**< Port of the low/full speed device */
+	/** Split transaction position
+	 * One of the following values:
+	 *    - DWC_HCSPLIT_XACTPOS_MID
+	 *    - DWC_HCSPLIT_XACTPOS_BEGIN
+	 *    - DWC_HCSPLIT_XACTPOS_END
+	 *    - DWC_HCSPLIT_XACTPOS_ALL */
+	uint8_t xact_pos;
+
+	/** Set when the host channel does a short read. */
+	uint8_t short_read;
+
+	/**
+	 * Number of requests issued for this channel since it was assigned to
+	 * the current transfer (not counting PINGs).
+	 */
+	uint8_t requests;
+
+	/**
+	 * Queue Head for the transfer being processed by this channel.
+	 */
+	struct dwc_otg_qh *qh;
+
+	/** @} */
+
+	/** Entry in list of host channels. */
+	struct list_head hc_list_entry;
+};
+
+/**
+ * The following parameters may be specified when starting the module. These
+ * parameters define how the DWC_otg controller should be configured.
+ * Parameter values are passed to the CIL initialization function
+ * dwc_otg_cil_init.
+ */
+struct dwc_otg_core_params {
+	int32_t opt;
+#define dwc_param_opt_default 1
+
+	/*
+	 * Specifies the OTG capabilities. The driver will automatically
+	 * detect the value for this parameter if none is specified.
+	 * 0 - HNP and SRP capable (default)
+	 * 1 - SRP Only capable
+	 * 2 - No HNP/SRP capable
+	 */
+	int32_t otg_cap;
+#define DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE 0
+#define DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE 1
+#define DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE 2
+#define dwc_param_otg_cap_default DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE
+
+	/*
+	 * Specifies whether to use slave or DMA mode for accessing the data
+	 * FIFOs. The driver will automatically detect the value for this
+	 * parameter if none is specified.
+	 * 0 - Slave
+	 * 1 - DMA (default, if available)
+	 */
+	int32_t dma_enable;
+#define dwc_param_dma_enable_default 1
+
+	/*
+	 * The DMA Burst size (applicable only for External DMA
+	 * Mode). 1, 4, 8 16, 32, 64, 128, 256 (default 32)
+	 */
+	int32_t dma_burst_size;	/* Translate this to GAHBCFG values */
+#define dwc_param_dma_burst_size_default 32
+
+	/*
+	 * Specifies the maximum speed of operation in host and device mode.
+	 * The actual speed depends on the speed of the attached device and
+	 * the value of phy_type. The actual speed depends on the speed of the
+	 * attached device.
+	 * 0 - High Speed (default)
+	 * 1 - Full Speed
+	 */
+	int32_t speed;
+#define dwc_param_speed_default 0
+#define DWC_SPEED_PARAM_HIGH 0
+#define DWC_SPEED_PARAM_FULL 1
+
+	/** Specifies whether low power mode is supported when attached
+	 *  to a Full Speed or Low Speed device in host mode.
+	 * 0 - Don't support low power mode (default)
+	 * 1 - Support low power mode
+	 */
+	int32_t host_support_fs_ls_low_power;
+#define dwc_param_host_support_fs_ls_low_power_default 0
+
+	/** Specifies the PHY clock rate in low power mode when connected to a
+	 * Low Speed device in host mode. This parameter is applicable only if
+	 * HOST_SUPPORT_FS_LS_LOW_POWER is enabled.  If PHY_TYPE is set to FS
+	 * then defaults to 6 MHZ otherwise 48 MHZ.
+	 *
+	 * 0 - 48 MHz
+	 * 1 - 6 MHz
+	 */
+	int32_t host_ls_low_power_phy_clk;
+#define dwc_param_host_ls_low_power_phy_clk_default 0
+#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0
+#define DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1
+
+	/**
+	 * 0 - Use cC FIFO size parameters
+	 * 1 - Allow dynamic FIFO sizing (default)
+	 */
+	int32_t enable_dynamic_fifo;
+#define dwc_param_enable_dynamic_fifo_default 1
+
+	/** Total number of 4-byte words in the data FIFO memory. This
+	 * memory includes the Rx FIFO, non-periodic Tx FIFO, and periodic
+	 * Tx FIFOs.
+	 * 32 to 32768 (default 8192)
+	 * Note: The total FIFO memory depth in the FPGA configuration is 8192.
+	 */
+	int32_t data_fifo_size;
+#define dwc_param_data_fifo_size_default 8192
+
+	/** Number of 4-byte words in the Rx FIFO in device mode when dynamic
+	 * FIFO sizing is enabled.
+	 * 16 to 32768 (default 1064)
+	 */
+	int32_t dev_rx_fifo_size;
+#define dwc_param_dev_rx_fifo_size_default 1064
+
+	/** Number of 4-byte words in the non-periodic Tx FIFO in device mode
+	 * when dynamic FIFO sizing is enabled.
+	 * 16 to 32768 (default 1024)
+	 */
+	int32_t dev_nperio_tx_fifo_size;
+#define dwc_param_dev_nperio_tx_fifo_size_default 1024
+
+	/** Number of 4-byte words in each of the periodic Tx FIFOs in device
+	 * mode when dynamic FIFO sizing is enabled.
+	 * 4 to 768 (default 256)
+	 */
+	uint32_t dev_perio_tx_fifo_size[MAX_PERIO_FIFOS];
+#define dwc_param_dev_perio_tx_fifo_size_default 256
+
+	/** Number of 4-byte words in the Rx FIFO in host mode when dynamic
+	 * FIFO sizing is enabled.
+	 * 16 to 32768 (default 1024)
+	 */
+	int32_t host_rx_fifo_size;
+#define dwc_param_host_rx_fifo_size_default 1024
+#define dwc_param_host_rx_fifo_size_percentage 30
+
+	/** Number of 4-byte words in the non-periodic Tx FIFO in host mode
+	 * when Dynamic FIFO sizing is enabled in the core.
+	 * 16 to 32768 (default 1024)
+	 */
+	int32_t host_nperio_tx_fifo_size;
+#define dwc_param_host_nperio_tx_fifo_size_default 1024
+#define dwc_param_host_nperio_tx_fifo_size_percentage 40
+
+	/*
+	 * Number of 4-byte words in the host periodic Tx FIFO when dynamic
+	 * FIFO sizing is enabled.
+	 * 16 to 32768 (default 1024)
+	 */
+	int32_t host_perio_tx_fifo_size;
+#define dwc_param_host_perio_tx_fifo_size_default 1024
+#define dwc_param_host_perio_tx_fifo_size_percentage 30
+
+	/*
+	 * The maximum transfer size supported in bytes.
+	 * 2047 to 65,535  (default 65,535)
+	 */
+	int32_t max_transfer_size;
+#define dwc_param_max_transfer_size_default 65535
+
+	/*
+	 * The maximum number of packets in a transfer.
+	 * 15 to 511  (default 511)
+	 */
+	int32_t max_packet_count;
+#define dwc_param_max_packet_count_default 511
+
+	/*
+	 * The number of host channel registers to use.
+	 * 1 to 16 (default 12)
+	 * Note: The FPGA configuration supports a maximum of 12 host channels.
+	 */
+	int32_t host_channels;
+#define dwc_param_host_channels_default 12
+
+	/*
+	 * The number of endpoints in addition to EP0 available for device
+	 * mode operations.
+	 * 1 to 15 (default 6 IN and OUT)
+	 * Note: The FPGA configuration supports a maximum of 6 IN and OUT
+	 * endpoints in addition to EP0.
+	 */
+	int32_t dev_endpoints;
+#define dwc_param_dev_endpoints_default 6
+
+	/*
+	 * Specifies the type of PHY interface to use. By default, the driver
+	 * will automatically detect the phy_type.
+	 *
+	 * 0 - Full Speed PHY
+	 * 1 - UTMI+ (default)
+	 * 2 - ULPI
+	 */
+	int32_t phy_type;
+#define DWC_PHY_TYPE_PARAM_FS 0
+#define DWC_PHY_TYPE_PARAM_UTMI 1
+#define DWC_PHY_TYPE_PARAM_ULPI 2
+#define dwc_param_phy_type_default DWC_PHY_TYPE_PARAM_UTMI
+
+	/*
+	 * Specifies the UTMI+ Data Width.  This parameter is
+	 * applicable for a PHY_TYPE of UTMI+ or ULPI. (For a ULPI
+	 * PHY_TYPE, this parameter indicates the data width between
+	 * the MAC and the ULPI Wrapper.) Also, this parameter is
+	 * applicable only if the OTG_HSPHY_WIDTH cC parameter was set
+	 * to "8 and 16 bits", meaning that the core has been
+	 * configured to work at either data path width.
+	 *
+	 * 8 or 16 bits (default 16)
+	 */
+	int32_t phy_utmi_width;
+#define dwc_param_phy_utmi_width_default 16
+
+	/*
+	 * Specifies whether the ULPI operates at double or single
+	 * data rate. This parameter is only applicable if PHY_TYPE is
+	 * ULPI.
+	 *
+	 * 0 - single data rate ULPI interface with 8 bit wide data
+	 * bus (default)
+	 * 1 - double data rate ULPI interface with 4 bit wide data
+	 * bus
+	 */
+	int32_t phy_ulpi_ddr;
+#define dwc_param_phy_ulpi_ddr_default 0
+
+	/*
+	 * Specifies whether to use the internal or external supply to
+	 * drive the vbus with a ULPI phy.
+	 */
+	int32_t phy_ulpi_ext_vbus;
+#define DWC_PHY_ULPI_INTERNAL_VBUS 0
+#define DWC_PHY_ULPI_EXTERNAL_VBUS 1
+#define dwc_param_phy_ulpi_ext_vbus_default DWC_PHY_ULPI_INTERNAL_VBUS
+
+	/*
+	 * Specifies whether to use the I2Cinterface for full speed PHY. This
+	 * parameter is only applicable if PHY_TYPE is FS.
+	 * 0 - No (default)
+	 * 1 - Yes
+	 */
+	int32_t i2c_enable;
+#define dwc_param_i2c_enable_default 0
+
+	int32_t ulpi_fs_ls;
+#define dwc_param_ulpi_fs_ls_default 0
+
+	int32_t ts_dline;
+#define dwc_param_ts_dline_default 0
+
+};
+
+/**
+ * The FIFOs are established based on a default percentage of the total
+ * FIFO depth. This check insures that the defaults are reasonable.
+ */
+#if (((dwc_param_host_rx_fifo_size_percentage) \
+     +(dwc_param_host_nperio_tx_fifo_size_percentage) \
+     +(dwc_param_host_perio_tx_fifo_size_percentage)) > 100)
+#error Invalid FIFO allocation
+#endif
+
+#ifdef DEBUG
+struct dwc_otg_core_if;
+struct hc_xfer_info {
+	struct dwc_otg_core_if *core_if;
+	struct dwc_hc *hc;
+};
+#endif
+
+/*
+ * The <code>dwc_otg_core_if</code> structure contains information
+ * needed to manage the DWC_otg controller acting in either host or
+ * device mode. It represents the programming view of the controller
+ * as a whole.
+ */
+struct dwc_otg_core_if {
+	/** USB block index number for Octeon's that support multiple */
+	int usb_num;
+
+	/** Parameters that define how the core should be configured.*/
+	struct dwc_otg_core_params *core_params;
+
+	/** Core Global registers starting at offset 000h. */
+	struct dwc_otg_core_global_regs *core_global_regs;
+
+	/** Device-specific information */
+	struct dwc_otg_dev_if *dev_if;
+	/** Host-specific information */
+	struct dwc_otg_host_if *host_if;
+
+	/*
+	 * Set to 1 if the core PHY interface bits in USBCFG have been
+	 * initialized.
+	 */
+	uint8_t phy_init_done;
+
+	/*
+	 * SRP Success flag, set by srp success interrupt in FS I2C mode
+	 */
+	uint8_t srp_success;
+	uint8_t srp_timer_started;
+
+	/* Common configuration information */
+	/** Power and Clock Gating Control Register */
+	uint32_t *pcgcctl;
+#define DWC_OTG_PCGCCTL_OFFSET 0xE00
+
+	/** Push/pop addresses for endpoints or host channels.*/
+	uint32_t *data_fifo[MAX_EPS_CHANNELS];
+#define DWC_OTG_DATA_FIFO_OFFSET 0x1000
+#define DWC_OTG_DATA_FIFO_SIZE 0x1000
+
+	/** Total RAM for FIFOs (Bytes) */
+	uint16_t total_fifo_size;
+	/** Size of Rx FIFO (Bytes) */
+	uint16_t rx_fifo_size;
+	/** Size of Non-periodic Tx FIFO (Bytes) */
+	uint16_t nperio_tx_fifo_size;
+
+	/** 1 if DMA is enabled, 0 otherwise. */
+	uint8_t dma_enable;
+
+	/** Set to 1 if multiple packets of a high-bandwidth transfer is in
+	 * process of being queued */
+	uint8_t queuing_high_bandwidth;
+
+	/** Hardware Configuration -- stored here for convenience.*/
+	union hwcfg1_data hwcfg1;
+	union hwcfg2_data hwcfg2;
+	union hwcfg3_data hwcfg3;
+	union hwcfg4_data hwcfg4;
+
+	/*
+	 * The operational State, during transations
+	 * (a_host>>a_peripherial and b_device=>b_host) this may not
+	 * match the core but allows the software to determine
+	 * transitions.
+	 */
+	uint8_t op_state;
+
+	/*
+	 * Set to 1 if the HCD needs to be restarted on a session request
+	 * interrupt. This is required if no connector ID status change has
+	 * occurred since the HCD was last disconnected.
+	 */
+	uint8_t restart_hcd_on_session_req;
+
+	/** HCD callbacks */
+	/** A-Device is a_host */
+#define A_HOST 		(1)
+	/** A-Device is a_suspend */
+#define A_SUSPEND 	(2)
+	/** A-Device is a_peripherial */
+#define A_PERIPHERAL 	(3)
+	/** B-Device is operating as a Peripheral. */
+#define B_PERIPHERAL	(4)
+	/** B-Device is operating as a Host. */
+#define B_HOST 		(5)
+
+	/** HCD callbacks */
+	struct dwc_otg_cil_callbacks *hcd_cb;
+	/** PCD callbacks */
+	struct dwc_otg_cil_callbacks *pcd_cb;
+
+#ifdef DEBUG
+	uint32_t start_hcchar_val[MAX_EPS_CHANNELS];
+
+	struct hc_xfer_info hc_xfer_info[MAX_EPS_CHANNELS];
+	struct timer_list hc_xfer_timer[MAX_EPS_CHANNELS];
+
+	uint32_t hfnum_7_samples;
+	uint64_t hfnum_7_frrem_accum;
+	uint32_t hfnum_0_samples;
+	uint64_t hfnum_0_frrem_accum;
+	uint32_t hfnum_other_samples;
+	uint64_t hfnum_other_frrem_accum;
+#endif
+
+};
+
+/*
+ * The following functions support initialization of the CIL driver component
+ * and the DWC_otg controller.
+ */
+extern struct dwc_otg_core_if *dwc_otg_cil_init(const uint32_t *reg_base_addr,
+					   struct dwc_otg_core_params *
+					   _core_params);
+extern void dwc_otg_cil_remove(struct dwc_otg_core_if *core_if);
+extern void dwc_otg_core_init(struct dwc_otg_core_if *core_if);
+extern void dwc_otg_core_host_init(struct dwc_otg_core_if *core_if);
+extern void dwc_otg_core_dev_init(struct dwc_otg_core_if *core_if);
+extern void dwc_otg_enable_global_interrupts(struct dwc_otg_core_if *core_if);
+extern void dwc_otg_disable_global_interrupts(struct dwc_otg_core_if *core_if);
+
+/* Device CIL Functions
+ * The following functions support managing the DWC_otg controller in device
+ * mode.
+ */
+
+extern void dwc_otg_wakeup(struct dwc_otg_core_if *core_if);
+extern void dwc_otg_read_setup_packet(struct dwc_otg_core_if *core_if,
+				      uint32_t *dest);
+extern uint32_t dwc_otg_get_frame_number(struct dwc_otg_core_if *core_if);
+extern void dwc_otg_ep0_activate(struct dwc_otg_core_if *core_if,
+				 struct dwc_ep *ep);
+extern void dwc_otg_ep_activate(struct dwc_otg_core_if *core_if,
+				struct dwc_ep *ep);
+extern void dwc_otg_ep_deactivate(struct dwc_otg_core_if *core_if,
+				  struct dwc_ep *ep);
+extern void dwc_otg_ep_start_transfer(struct dwc_otg_core_if *core_if,
+				      struct dwc_ep *ep);
+extern void dwc_otg_ep0_start_transfer(struct dwc_otg_core_if *core_if,
+				       struct dwc_ep *ep);
+extern void dwc_otg_ep0_continue_transfer(struct dwc_otg_core_if *core_if,
+					  struct dwc_ep *ep);
+extern void dwc_otg_ep_write_packet(struct dwc_otg_core_if *core_if,
+				    struct dwc_ep *ep, int _dma);
+extern void dwc_otg_ep_set_stall(struct dwc_otg_core_if *core_if,
+				 struct dwc_ep *ep);
+extern void dwc_otg_ep_clear_stall(struct dwc_otg_core_if *core_if,
+				   struct dwc_ep *ep);
+extern void dwc_otg_enable_device_interrupts(struct dwc_otg_core_if *core_if);
+extern void dwc_otg_dump_dev_registers(struct dwc_otg_core_if *core_if);
+
+/* Host CIL Functions
+ * The following functions support managing the DWC_otg controller in host
+ * mode.
+ */
+
+extern void dwc_otg_hc_init(struct dwc_otg_core_if *core_if, struct dwc_hc *hc);
+extern void dwc_otg_hc_halt(struct dwc_otg_core_if *core_if,
+			    struct dwc_hc *hc,
+			    enum dwc_otg_halt_status halt_status);
+extern void dwc_otg_hc_cleanup(struct dwc_otg_core_if *core_if,
+			       struct dwc_hc *hc);
+extern void dwc_otg_hc_start_transfer(struct dwc_otg_core_if *core_if,
+				      struct dwc_hc *hc);
+extern int dwc_otg_hc_continue_transfer(struct dwc_otg_core_if *core_if,
+					struct dwc_hc *hc);
+extern void dwc_otg_hc_do_ping(struct dwc_otg_core_if *core_if,
+			       struct dwc_hc *hc);
+extern void dwc_otg_hc_write_packet(struct dwc_otg_core_if *core_if,
+				    struct dwc_hc *hc);
+extern void dwc_otg_enable_host_interrupts(struct dwc_otg_core_if *core_if);
+extern void dwc_otg_disable_host_interrupts(struct dwc_otg_core_if *core_if);
+
+/**
+ * This function Reads HPRT0 in preparation to modify.  It keeps the
+ * WC bits 0 so that if they are read as 1, they won't clear when you
+ * write it back
+ */
+static inline uint32_t dwc_otg_read_hprt0(struct dwc_otg_core_if *core_if)
+{
+	union hprt0_data hprt0;
+	hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
+	hprt0.b.prtena = 0;
+	hprt0.b.prtconndet = 0;
+	hprt0.b.prtenchng = 0;
+	hprt0.b.prtovrcurrchng = 0;
+	return hprt0.d32;
+}
+
+extern void dwc_otg_dump_host_registers(struct dwc_otg_core_if *core_if);
+
+/* Common CIL Functions
+ * The following functions support managing the DWC_otg controller in either
+ * device or host mode.
+ */
+
+
+extern void dwc_otg_read_packet(struct dwc_otg_core_if *core_if,
+				uint8_t *dest, uint16_t bytes);
+
+extern void dwc_otg_dump_global_registers(struct dwc_otg_core_if *core_if);
+
+extern void dwc_otg_flush_tx_fifo(struct dwc_otg_core_if *core_if,
+				  const int _num);
+extern void dwc_otg_flush_rx_fifo(struct dwc_otg_core_if *core_if);
+extern void dwc_otg_core_reset(struct dwc_otg_core_if *core_if);
+
+/**
+ * This function returns the Core Interrupt register.
+ */
+static inline uint32_t dwc_otg_read_core_intr(struct dwc_otg_core_if *core_if)
+{
+	return dwc_read_reg32(&core_if->core_global_regs->gintsts) &
+		dwc_read_reg32(&core_if->core_global_regs->gintmsk);
+}
+
+/**
+ * This function returns the OTG Interrupt register.
+ */
+static inline uint32_t dwc_otg_read_otg_intr(struct dwc_otg_core_if *core_if)
+{
+	return dwc_read_reg32(&core_if->core_global_regs->gotgint);
+}
+
+/**
+ * This function reads the Device All Endpoints Interrupt register and
+ * returns the IN endpoint interrupt bits.
+ */
+static inline uint32_t dwc_otg_read_dev_all_in_ep_intr(struct dwc_otg_core_if *
+						       core_if)
+{
+	uint32_t v;
+	v = dwc_read_reg32(&core_if->dev_if->dev_global_regs->daint) &
+	    dwc_read_reg32(&core_if->dev_if->dev_global_regs->daintmsk);
+	return v & 0xffff;
+
+}
+
+/**
+ * This function reads the Device All Endpoints Interrupt register and
+ * returns the OUT endpoint interrupt bits.
+ */
+static inline uint32_t
+dwc_otg_read_dev_all_out_ep_intr(struct dwc_otg_core_if *core_if)
+{
+	uint32_t v;
+	v = dwc_read_reg32(&core_if->dev_if->dev_global_regs->daint) &
+	    dwc_read_reg32(&core_if->dev_if->dev_global_regs->daintmsk);
+	return (v & 0xffff0000) >> 16;
+}
+
+/**
+ * This function returns the Device IN EP Interrupt register
+ */
+static inline uint32_t
+dwc_otg_read_dev_in_ep_intr(struct dwc_otg_core_if *core_if, struct dwc_ep *ep)
+{
+	struct dwc_otg_dev_if *dev_if = core_if->dev_if;
+	uint32_t v;
+	v = dwc_read_reg32(&dev_if->in_ep_regs[ep->num]->diepint) &
+	    dwc_read_reg32(&dev_if->dev_global_regs->diepmsk);
+	return v;
+}
+
+/**
+ * This function returns the Device OUT EP Interrupt register
+ */
+static inline uint32_t dwc_otg_read_dev_out_ep_intr(struct dwc_otg_core_if *
+						    core_if, struct dwc_ep *ep)
+{
+	struct dwc_otg_dev_if *dev_if = core_if->dev_if;
+	uint32_t v;
+	v = dwc_read_reg32(&dev_if->out_ep_regs[ep->num]->doepint) &
+	    dwc_read_reg32(&dev_if->dev_global_regs->diepmsk);
+	return v;
+}
+
+/**
+ * This function returns the Host All Channel Interrupt register
+ */
+static inline uint32_t
+dwc_otg_read_host_all_channels_intr(struct dwc_otg_core_if *core_if)
+{
+	return dwc_read_reg32(&core_if->host_if->host_global_regs->haint);
+}
+
+static inline uint32_t
+dwc_otg_read_host_channel_intr(struct dwc_otg_core_if *core_if,
+			       struct dwc_hc *hc)
+{
+	return dwc_read_reg32(&core_if->host_if->hc_regs[hc->hc_num]->hcint);
+}
+
+/**
+ * This function returns the mode of the operation, host or device.
+ *
+ * Returns 0 - Device Mode, 1 - Host Mode
+ */
+static inline uint32_t dwc_otg_mode(struct dwc_otg_core_if *core_if)
+{
+	return dwc_read_reg32(&core_if->core_global_regs->gintsts) & 0x1;
+}
+
+static inline uint8_t dwc_otg_is_device_mode(struct dwc_otg_core_if *core_if)
+{
+	return dwc_otg_mode(core_if) != DWC_HOST_MODE;
+}
+
+static inline uint8_t dwc_otg_is_host_mode(struct dwc_otg_core_if *core_if)
+{
+	return dwc_otg_mode(core_if) == DWC_HOST_MODE;
+}
+
+extern int32_t dwc_otg_handle_common_intr(struct dwc_otg_core_if *core_if);
+
+/*
+ * DWC_otg CIL callback structure.  This structure allows the HCD and
+ * PCD to register functions used for starting and stopping the PCD
+ * and HCD for role change on for a DRD.
+ */
+struct dwc_otg_cil_callbacks {
+	/* Start function for role change */
+	int (*start) (void *p);
+	/* Stop Function for role change */
+	int (*stop) (void *p);
+	/* Disconnect Function for role change */
+	int (*disconnect) (void *p);
+	/* Resume/Remote wakeup Function */
+	int (*resume_wakeup) (void *p);
+	/* Suspend function */
+	int (*suspend) (void *p);
+	/* Session Start (SRP) */
+	int (*session_start) (void *p);
+	/* Pointer passed to start() and stop() */
+	void *p;
+};
+
+extern void dwc_otg_cil_register_pcd_callbacks(struct dwc_otg_core_if *core_if,
+					       struct dwc_otg_cil_callbacks *cb,
+					       void *p);
+extern void dwc_otg_cil_register_hcd_callbacks(struct dwc_otg_core_if *core_if,
+					       struct dwc_otg_cil_callbacks *cb,
+					       void *p);
+#endif
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
new file mode 100644
index 0000000..38c46df
--- /dev/null
+++ b/drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c
@@ -0,0 +1,689 @@
+/* ==========================================================================
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+/**
+ *
+ * The Core Interface Layer provides basic services for accessing and
+ * managing the DWC_otg hardware. These services are used by both the
+ * Host Controller Driver and the Peripheral Controller Driver.
+ *
+ * This file contains the Common Interrupt handlers.
+ */
+#include "dwc_otg_plat.h"
+#include "dwc_otg_regs.h"
+#include "dwc_otg_cil.h"
+
+#ifdef DEBUG
+inline const char *op_state_str(struct dwc_otg_core_if *core_if)
+{
+	return (core_if->op_state == A_HOST ? "a_host" :
+		(core_if->op_state == A_SUSPEND ? "a_suspend" :
+		 (core_if->op_state == A_PERIPHERAL ? "a_peripheral" :
+		  (core_if->op_state == B_PERIPHERAL ? "b_peripheral" :
+		   (core_if->op_state == B_HOST ? "b_host" : "unknown")))));
+}
+#endif
+
+/** This function will log a debug message
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+int32_t dwc_otg_handle_mode_mismatch_intr(struct dwc_otg_core_if *core_if)
+{
+	union gintsts_data gintsts;
+	DWC_WARN("Mode Mismatch Interrupt: currently in %s mode\n",
+		 dwc_otg_mode(core_if) ? "Host" : "Device");
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.modemismatch = 1;
+	dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
+	return 1;
+}
+
+/** Start the HCD.  Helper function for using the HCD callbacks.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+static inline void hcd_start(struct dwc_otg_core_if *core_if)
+{
+	if (core_if->hcd_cb && core_if->hcd_cb->start)
+		core_if->hcd_cb->start(core_if->hcd_cb->p);
+}
+
+/** Stop the HCD.  Helper function for using the HCD callbacks.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+static inline void hcd_stop(struct dwc_otg_core_if *core_if)
+{
+	if (core_if->hcd_cb && core_if->hcd_cb->stop)
+		core_if->hcd_cb->stop(core_if->hcd_cb->p);
+}
+
+/** Disconnect the HCD.  Helper function for using the HCD callbacks.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+static inline void hcd_disconnect(struct dwc_otg_core_if *core_if)
+{
+	if (core_if->hcd_cb && core_if->hcd_cb->disconnect)
+		core_if->hcd_cb->disconnect(core_if->hcd_cb->p);
+}
+
+/** Inform the HCD the a New Session has begun.  Helper function for
+ * using the HCD callbacks.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+static inline void hcd_session_start(struct dwc_otg_core_if *core_if)
+{
+	if (core_if->hcd_cb && core_if->hcd_cb->session_start)
+		core_if->hcd_cb->session_start(core_if->hcd_cb->p);
+}
+
+/** Start the PCD.  Helper function for using the PCD callbacks.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+static inline void pcd_start(struct dwc_otg_core_if *core_if)
+{
+	if (core_if->pcd_cb && core_if->pcd_cb->start)
+		core_if->pcd_cb->start(core_if->pcd_cb->p);
+}
+
+/** Stop the PCD.  Helper function for using the PCD callbacks.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+static inline void pcd_stop(struct dwc_otg_core_if *core_if)
+{
+	if (core_if->pcd_cb && core_if->pcd_cb->stop)
+		core_if->pcd_cb->stop(core_if->pcd_cb->p);
+}
+
+/** Suspend the PCD.  Helper function for using the PCD callbacks.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+static inline void pcd_suspend(struct dwc_otg_core_if *core_if)
+{
+	if (core_if->pcd_cb && core_if->pcd_cb->suspend)
+		core_if->pcd_cb->suspend(core_if->pcd_cb->p);
+}
+
+/** Resume the PCD.  Helper function for using the PCD callbacks.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+static inline void pcd_resume(struct dwc_otg_core_if *core_if)
+{
+	if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup)
+		core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
+}
+
+/**
+ * This function handles the OTG Interrupts. It reads the OTG
+ * Interrupt Register (GOTGINT) to determine what interrupt has
+ * occurred.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+int32_t dwc_otg_handle_otg_intr(struct dwc_otg_core_if *core_if)
+{
+	struct dwc_otg_core_global_regs *global_regs = core_if->core_global_regs;
+	union gotgint_data gotgint;
+	union gotgctl_data gotgctl;
+	union gintmsk_data gintmsk;
+
+	gotgint.d32 = dwc_read_reg32(&global_regs->gotgint);
+	gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
+	DWC_DEBUGPL(DBG_CIL, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint.d32,
+		    op_state_str(core_if));
+
+	if (gotgint.b.sesenddet) {
+		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
+			    "Session End Detected++ (%s)\n",
+			    op_state_str(core_if));
+		gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
+
+		if (core_if->op_state == B_HOST) {
+			pcd_start(core_if);
+			core_if->op_state = B_PERIPHERAL;
+		} else {
+			/* If not B_HOST and Device HNP still set. HNP
+			 * Did not succeed!*/
+			if (gotgctl.b.devhnpen) {
+				DWC_DEBUGPL(DBG_ANY, "Session End Detected\n");
+				DWC_ERROR("Device Not Connected/Responding!\n");
+			}
+
+			/* If Session End Detected the B-Cable has
+			 * been disconnected. */
+			/* Reset PCD and Gadget driver to a
+			 * clean state. */
+			pcd_stop(core_if);
+		}
+		gotgctl.d32 = 0;
+		gotgctl.b.devhnpen = 1;
+		dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0);
+	}
+	if (gotgint.b.sesreqsucstschng) {
+		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
+			    "Session Reqeust Success Status Change++\n");
+		gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
+		if (gotgctl.b.sesreqscs) {
+			if ((core_if->core_params->phy_type ==
+			     DWC_PHY_TYPE_PARAM_FS)
+			    && (core_if->core_params->i2c_enable)) {
+				core_if->srp_success = 1;
+			} else {
+				pcd_resume(core_if);
+				/* Clear Session Request */
+				gotgctl.d32 = 0;
+				gotgctl.b.sesreq = 1;
+				dwc_modify_reg32(&global_regs->gotgctl,
+						 gotgctl.d32, 0);
+			}
+		}
+	}
+	if (gotgint.b.hstnegsucstschng) {
+		/* Print statements during the HNP interrupt handling
+		 * can cause it to fail.*/
+		gotgctl.d32 = dwc_read_reg32(&global_regs->gotgctl);
+		if (gotgctl.b.hstnegscs) {
+			if (dwc_otg_is_host_mode(core_if)) {
+				core_if->op_state = B_HOST;
+				/*
+				 * Need to disable SOF interrupt immediately.
+				 * When switching from device to host, the PCD
+				 * interrupt handler won't handle the
+				 * interrupt if host mode is already set. The
+				 * HCD interrupt handler won't get called if
+				 * the HCD state is HALT. This means that the
+				 * interrupt does not get handled and Linux
+				 * complains loudly.
+				 */
+				gintmsk.d32 = 0;
+				gintmsk.b.sofintr = 1;
+				dwc_modify_reg32(&global_regs->gintmsk,
+						 gintmsk.d32, 0);
+				pcd_stop(core_if);
+				/*
+				 * Initialize the Core for Host mode.
+				 */
+				hcd_start(core_if);
+				core_if->op_state = B_HOST;
+			}
+		} else {
+			gotgctl.d32 = 0;
+			gotgctl.b.hnpreq = 1;
+			gotgctl.b.devhnpen = 1;
+			dwc_modify_reg32(&global_regs->gotgctl, gotgctl.d32, 0);
+			DWC_DEBUGPL(DBG_ANY, "HNP Failed\n");
+			DWC_ERROR("Device Not Connected/Responding\n");
+		}
+	}
+	if (gotgint.b.hstnegdet) {
+		/* The disconnect interrupt is set at the same time as
+		 * Host Negotiation Detected.  During the mode
+		 * switch all interrupts are cleared so the disconnect
+		 * interrupt handler will not get executed.
+		 */
+		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
+			    "Host Negotiation Detected++ (%s)\n",
+			    (dwc_otg_is_host_mode(core_if) ? "Host" :
+			     "Device"));
+		if (dwc_otg_is_device_mode(core_if)) {
+			DWC_DEBUGPL(DBG_ANY, "a_suspend->a_peripheral (%d)\n",
+				    core_if->op_state);
+			hcd_disconnect(core_if);
+			pcd_start(core_if);
+			core_if->op_state = A_PERIPHERAL;
+		} else {
+			/*
+			 * Need to disable SOF interrupt immediately. When
+			 * switching from device to host, the PCD interrupt
+			 * handler won't handle the interrupt if host mode is
+			 * already set. The HCD interrupt handler won't get
+			 * called if the HCD state is HALT. This means that
+			 * the interrupt does not get handled and Linux
+			 * complains loudly.
+			 */
+			gintmsk.d32 = 0;
+			gintmsk.b.sofintr = 1;
+			dwc_modify_reg32(&global_regs->gintmsk, gintmsk.d32, 0);
+			pcd_stop(core_if);
+			hcd_start(core_if);
+			core_if->op_state = A_HOST;
+		}
+	}
+	if (gotgint.b.adevtoutchng)
+		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: "
+			    "A-Device Timeout Change++\n");
+	if (gotgint.b.debdone)
+		DWC_DEBUGPL(DBG_ANY, " ++OTG Interrupt: " "Debounce Done++\n");
+
+	/* Clear GOTGINT */
+	dwc_write_reg32(&core_if->core_global_regs->gotgint, gotgint.d32);
+
+	return 1;
+}
+
+/**
+ * This function handles the Connector ID Status Change Interrupt.  It
+ * reads the OTG Interrupt Register (GOTCTL) to determine whether this
+ * is a Device to Host Mode transition or a Host Mode to Device
+ * Transition.
+ *
+ * This only occurs when the cable is connected/removed from the PHY
+ * connector.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+int32_t dwc_otg_handle_conn_id_status_change_intr(struct dwc_otg_core_if *core_if)
+{
+	uint32_t count = 0;
+
+	union gintsts_data gintsts = {.d32 = 0 };
+	union gintmsk_data gintmsk = {.d32 = 0 };
+	union gotgctl_data gotgctl = {.d32 = 0 };
+
+	/*
+	 * Need to disable SOF interrupt immediately. If switching from device
+	 * to host, the PCD interrupt handler won't handle the interrupt if
+	 * host mode is already set. The HCD interrupt handler won't get
+	 * called if the HCD state is HALT. This means that the interrupt does
+	 * not get handled and Linux complains loudly.
+	 */
+	gintmsk.b.sofintr = 1;
+	dwc_modify_reg32(&core_if->core_global_regs->gintmsk, gintmsk.d32, 0);
+
+	DWC_DEBUGPL(DBG_CIL,
+		    " ++Connector ID Status Change Interrupt++  (%s)\n",
+		    (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"));
+	gotgctl.d32 = dwc_read_reg32(&core_if->core_global_regs->gotgctl);
+	DWC_DEBUGPL(DBG_CIL, "gotgctl=%0x\n", gotgctl.d32);
+	DWC_DEBUGPL(DBG_CIL, "gotgctl.b.conidsts=%d\n", gotgctl.b.conidsts);
+
+	/* B-Device connector (Device Mode) */
+	if (gotgctl.b.conidsts) {
+		/* Wait for switch to device mode. */
+		while (!dwc_otg_is_device_mode(core_if)) {
+			DWC_PRINT("Waiting for Peripheral Mode, Mode=%s\n",
+				  (dwc_otg_is_host_mode(core_if) ? "Host" :
+				   "Peripheral"));
+			mdelay(100);
+			if (++count > 10000)
+				*(uint32_t *) NULL = 0;
+		}
+		core_if->op_state = B_PERIPHERAL;
+		dwc_otg_core_init(core_if);
+		dwc_otg_enable_global_interrupts(core_if);
+		pcd_start(core_if);
+	} else {
+		/* A-Device connector (Host Mode) */
+		while (!dwc_otg_is_host_mode(core_if)) {
+			DWC_PRINT("Waiting for Host Mode, Mode=%s\n",
+				  (dwc_otg_is_host_mode(core_if) ? "Host" :
+				   "Peripheral"));
+			mdelay(100);
+			if (++count > 10000)
+				*(uint32_t *) NULL = 0;
+		}
+		core_if->op_state = A_HOST;
+		/*
+		 * Initialize the Core for Host mode.
+		 */
+		dwc_otg_core_init(core_if);
+		dwc_otg_enable_global_interrupts(core_if);
+		hcd_start(core_if);
+	}
+
+	/* Set flag and clear interrupt */
+	gintsts.b.conidstschng = 1;
+	dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
+
+	return 1;
+}
+
+/**
+ * This interrupt indicates that a device is initiating the Session
+ * Request Protocol to request the host to turn on bus power so a new
+ * session can begin. The handler responds by turning on bus power. If
+ * the DWC_otg controller is in low power mode, the handler brings the
+ * controller out of low power mode before turning on bus power.
+ *
+ * @core_if: Programming view of DWC_otg controller.
+ */
+int32_t dwc_otg_handle_session_req_intr(struct dwc_otg_core_if *core_if)
+{
+	union gintsts_data gintsts;
+#ifndef DWC_HOST_ONLY
+	union hprt0_data hprt0;
+
+	DWC_DEBUGPL(DBG_ANY, "++Session Request Interrupt++\n");
+
+	if (dwc_otg_is_device_mode(core_if)) {
+		DWC_PRINT("SRP: Device mode\n");
+	} else {
+		DWC_PRINT("SRP: Host mode\n");
+
+		/* Turn on the port power bit. */
+		hprt0.d32 = dwc_otg_read_hprt0(core_if);
+		hprt0.b.prtpwr = 1;
+		dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+
+		/* Start the Connection timer. So a message can be displayed
+		 * if connect does not occur within 10 seconds. */
+		hcd_session_start(core_if);
+	}
+#endif
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.sessreqintr = 1;
+	dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
+
+	return 1;
+}
+
+/**
+ * This interrupt indicates that the DWC_otg controller has detected a
+ * resume or remote wakeup sequence. If the DWC_otg controller is in
+ * low power mode, the handler must brings the controller out of low
+ * power mode. The controller automatically begins resume
+ * signaling. The handler schedules a time to stop resume signaling.
+ */
+int32_t dwc_otg_handle_wakeup_detected_intr(struct dwc_otg_core_if *core_if)
+{
+	union gintsts_data gintsts;
+
+	DWC_DEBUGPL(DBG_ANY,
+		    "++Resume and Remote Wakeup Detected Interrupt++\n");
+
+	if (dwc_otg_is_device_mode(core_if)) {
+		union dctl_data dctl = {.d32 = 0 };
+		DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n",
+			    dwc_read_reg32(&core_if->dev_if->dev_global_regs->
+					   dsts));
+#ifdef PARTIAL_POWER_DOWN
+		if (core_if->hwcfg4.b.power_optimiz) {
+			union pcgcctl_data power = {.d32 = 0 };
+
+			power.d32 = dwc_read_reg32(core_if->pcgcctl);
+			DWC_DEBUGPL(DBG_CIL, "PCGCCTL=%0x\n", power.d32);
+
+			power.b.stoppclk = 0;
+			dwc_write_reg32(core_if->pcgcctl, power.d32);
+
+			power.b.pwrclmp = 0;
+			dwc_write_reg32(core_if->pcgcctl, power.d32);
+
+			power.b.rstpdwnmodule = 0;
+			dwc_write_reg32(core_if->pcgcctl, power.d32);
+		}
+#endif
+		/* Clear the Remote Wakeup Signalling */
+		dctl.b.rmtwkupsig = 1;
+		dwc_modify_reg32(&core_if->dev_if->dev_global_regs->dctl,
+				 dctl.d32, 0);
+
+		if (core_if->pcd_cb && core_if->pcd_cb->resume_wakeup)
+			core_if->pcd_cb->resume_wakeup(core_if->pcd_cb->p);
+	} else {
+		/*
+		 * Clear the Resume after 70ms. (Need 20 ms minimum. Use 70 ms
+		 * so that OPT tests pass with all PHYs).
+		 */
+		union hprt0_data hprt0 = {.d32 = 0 };
+		union pcgcctl_data pcgcctl = {.d32 = 0 };
+		/* Restart the Phy Clock */
+		pcgcctl.b.stoppclk = 1;
+		dwc_modify_reg32(core_if->pcgcctl, pcgcctl.d32, 0);
+		udelay(10);
+
+		/* Now wait for 70 ms. */
+		hprt0.d32 = dwc_otg_read_hprt0(core_if);
+		DWC_DEBUGPL(DBG_ANY, "Resume: HPRT0=%0x\n", hprt0.d32);
+		mdelay(70);
+		hprt0.b.prtres = 0;	/* Resume */
+		dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+		DWC_DEBUGPL(DBG_ANY, "Clear Resume: HPRT0=%0x\n",
+			    dwc_read_reg32(core_if->host_if->hprt0));
+	}
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.wkupintr = 1;
+	dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
+
+	return 1;
+}
+
+/**
+ * This interrupt indicates that a device has been disconnected from
+ * the root port.
+ */
+int32_t dwc_otg_handle_disconnect_intr(struct dwc_otg_core_if *core_if)
+{
+	union gintsts_data gintsts;
+
+	DWC_DEBUGPL(DBG_ANY, "++Disconnect Detected Interrupt++ (%s) %s\n",
+		    (dwc_otg_is_host_mode(core_if) ? "Host" : "Device"),
+		    op_state_str(core_if));
+
+/** @todo Consolidate this if statement. */
+#ifndef DWC_HOST_ONLY
+	if (core_if->op_state == B_HOST) {
+		/* If in device mode Disconnect and stop the HCD, then
+		 * start the PCD. */
+		hcd_disconnect(core_if);
+		pcd_start(core_if);
+		core_if->op_state = B_PERIPHERAL;
+	} else if (dwc_otg_is_device_mode(core_if)) {
+		union gotgctl_data gotgctl = {.d32 = 0 };
+		gotgctl.d32 =
+		    dwc_read_reg32(&core_if->core_global_regs->gotgctl);
+		if (gotgctl.b.hstsethnpen == 1) {
+			/* Do nothing, if HNP in process the OTG
+			 * interrupt "Host Negotiation Detected"
+			 * interrupt will do the mode switch.
+			 */
+		} else if (gotgctl.b.devhnpen == 0) {
+			/* If in device mode Disconnect and stop the HCD, then
+			 * start the PCD. */
+			hcd_disconnect(core_if);
+			pcd_start(core_if);
+			core_if->op_state = B_PERIPHERAL;
+		} else {
+			DWC_DEBUGPL(DBG_ANY, "!a_peripheral && !devhnpen\n");
+		}
+	} else {
+		if (core_if->op_state == A_HOST) {
+			/* A-Cable still connected but device disconnected. */
+			hcd_disconnect(core_if);
+		}
+	}
+#endif
+
+	gintsts.d32 = 0;
+	gintsts.b.disconnect = 1;
+	dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
+	return 1;
+}
+
+/**
+ * This interrupt indicates that SUSPEND state has been detected on
+ * the USB.
+ *
+ * For HNP the USB Suspend interrupt signals the change from
+ * "a_peripheral" to "a_host".
+ *
+ * When power management is enabled the core will be put in low power
+ * mode.
+ */
+int32_t dwc_otg_handle_usb_suspend_intr(struct dwc_otg_core_if *core_if)
+{
+	union dsts_data dsts;
+	union gintsts_data gintsts;
+
+	DWC_DEBUGPL(DBG_ANY, "USB SUSPEND\n");
+
+	if (dwc_otg_is_device_mode(core_if)) {
+		/* Check the Device status register to determine if the Suspend
+		 * state is active. */
+		dsts.d32 =
+		    dwc_read_reg32(&core_if->dev_if->dev_global_regs->dsts);
+		DWC_DEBUGPL(DBG_PCD, "DSTS=0x%0x\n", dsts.d32);
+		DWC_DEBUGPL(DBG_PCD, "DSTS.Suspend Status=%d "
+			    "HWCFG4.power Optimize=%d\n",
+			    dsts.b.suspsts, core_if->hwcfg4.b.power_optimiz);
+
+#ifdef PARTIAL_POWER_DOWN
+/** @todo Add a module parameter for power management. */
+
+		if (dsts.b.suspsts && core_if->hwcfg4.b.power_optimiz) {
+			union pcgcctl_data_t power = {.d32 = 0 };
+			DWC_DEBUGPL(DBG_CIL, "suspend\n");
+
+			power.b.pwrclmp = 1;
+			dwc_write_reg32(core_if->pcgcctl, power.d32);
+
+			power.b.rstpdwnmodule = 1;
+			dwc_modify_reg32(core_if->pcgcctl, 0, power.d32);
+
+			power.b.stoppclk = 1;
+			dwc_modify_reg32(core_if->pcgcctl, 0, power.d32);
+
+		} else {
+			DWC_DEBUGPL(DBG_ANY, "disconnect?\n");
+		}
+#endif
+		/* PCD callback for suspend. */
+		pcd_suspend(core_if);
+	} else {
+		if (core_if->op_state == A_PERIPHERAL) {
+			DWC_DEBUGPL(DBG_ANY, "a_peripheral->a_host\n");
+			/* Clear the a_peripheral flag, back to a_host. */
+			pcd_stop(core_if);
+			hcd_start(core_if);
+			core_if->op_state = A_HOST;
+		}
+	}
+
+	/* Clear interrupt */
+	gintsts.d32 = 0;
+	gintsts.b.usbsuspend = 1;
+	dwc_write_reg32(&core_if->core_global_regs->gintsts, gintsts.d32);
+
+	return 1;
+}
+
+/**
+ * This function returns the Core Interrupt register.
+ */
+static inline uint32_t dwc_otg_read_common_intr(struct dwc_otg_core_if *core_if)
+{
+	union gintsts_data gintsts;
+	union gintmsk_data gintmsk;
+	union gintmsk_data gintmsk_common = {.d32 = 0 };
+	gintmsk_common.b.wkupintr = 1;
+	gintmsk_common.b.sessreqintr = 1;
+	gintmsk_common.b.conidstschng = 1;
+	gintmsk_common.b.otgintr = 1;
+	gintmsk_common.b.modemismatch = 1;
+	gintmsk_common.b.disconnect = 1;
+	gintmsk_common.b.usbsuspend = 1;
+	/*
+	 * @todo: The port interrupt occurs while in device
+	 * mode. Added code to CIL to clear the interrupt for now!
+	 */
+	gintmsk_common.b.portintr = 1;
+
+	gintsts.d32 = dwc_read_reg32(&core_if->core_global_regs->gintsts);
+	gintmsk.d32 = dwc_read_reg32(&core_if->core_global_regs->gintmsk);
+#ifdef DEBUG
+	/* if any common interrupts set */
+	if (gintsts.d32 & gintmsk_common.d32) {
+		DWC_DEBUGPL(DBG_ANY, "gintsts=%08x  gintmsk=%08x\n",
+			    gintsts.d32, gintmsk.d32);
+	}
+#endif
+
+	return (gintsts.d32 & gintmsk.d32) & gintmsk_common.d32;
+
+}
+
+/**
+ * Common interrupt handler.
+ *
+ * The common interrupts are those that occur in both Host and Device mode.
+ * This handler handles the following interrupts:
+ * - Mode Mismatch Interrupt
+ * - Disconnect Interrupt
+ * - OTG Interrupt
+ * - Connector ID Status Change Interrupt
+ * - Session Request Interrupt.
+ * - Resume / Remote Wakeup Detected Interrupt.
+ *
+ */
+extern int32_t dwc_otg_handle_common_intr(struct dwc_otg_core_if *core_if)
+{
+	int retval = 0;
+	union gintsts_data gintsts;
+
+	gintsts.d32 = dwc_otg_read_common_intr(core_if);
+
+	if (gintsts.b.modemismatch)
+		retval |= dwc_otg_handle_mode_mismatch_intr(core_if);
+	if (gintsts.b.otgintr)
+		retval |= dwc_otg_handle_otg_intr(core_if);
+	if (gintsts.b.conidstschng)
+		retval |= dwc_otg_handle_conn_id_status_change_intr(core_if);
+	if (gintsts.b.disconnect)
+		retval |= dwc_otg_handle_disconnect_intr(core_if);
+	if (gintsts.b.sessreqintr)
+		retval |= dwc_otg_handle_session_req_intr(core_if);
+	if (gintsts.b.wkupintr)
+		retval |= dwc_otg_handle_wakeup_detected_intr(core_if);
+	if (gintsts.b.usbsuspend)
+		retval |= dwc_otg_handle_usb_suspend_intr(core_if);
+	if (gintsts.b.portintr && dwc_otg_is_device_mode(core_if)) {
+		/* The port interrupt occurs while in device mode with HPRT0
+		 * Port Enable/Disable.
+		 */
+		gintsts.d32 = 0;
+		gintsts.b.portintr = 1;
+		dwc_write_reg32(&core_if->core_global_regs->gintsts,
+				gintsts.d32);
+		retval |= 1;
+
+	}
+	return retval;
+}
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_driver.h b/drivers/usb/host/dwc_otg/dwc_otg_driver.h
new file mode 100644
index 0000000..1cc116d
--- /dev/null
+++ b/drivers/usb/host/dwc_otg/dwc_otg_driver.h
@@ -0,0 +1,63 @@
+/* ==========================================================================
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+#ifndef __DWC_OTG_DRIVER_H__
+#define __DWC_OTG_DRIVER_H__
+
+#include "dwc_otg_cil.h"
+
+/* Type declarations */
+struct dwc_otg_pcd;
+struct dwc_otg_hcd;
+
+/**
+ * This structure is a wrapper that encapsulates the driver components used to
+ * manage a single DWC_otg controller.
+ */
+struct dwc_otg_device {
+	/** Base address returned from ioremap() */
+	void *base;
+
+	/** Pointer to the core interface structure. */
+	struct dwc_otg_core_if *core_if;
+
+	/** Register offset for Diagnostic API.*/
+	uint32_t reg_offset;
+
+	/** Pointer to the PCD structure. */
+	struct dwc_otg_pcd *pcd;
+
+	/** Pointer to the HCD structure. */
+	struct dwc_otg_hcd *hcd;
+
+	/** Flag to indicate whether the common IRQ handler is installed. */
+	uint8_t common_irq_installed;
+
+};
+
+#endif
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
new file mode 100644
index 0000000..a4392f5
--- /dev/null
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.c
@@ -0,0 +1,2878 @@
+/* ==========================================================================
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+#ifndef DWC_DEVICE_ONLY
+
+/**
+ *
+ * This file contains the implementation of the HCD. In Linux, the HCD
+ * implements the hc_driver API.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/dma-mapping.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+
+#include "dwc_otg_driver.h"
+#include "dwc_otg_hcd.h"
+#include "dwc_otg_regs.h"
+
+static const char dwc_otg_hcd_name[] = "dwc_otg_hcd";
+
+static const struct hc_driver dwc_otg_hc_driver = {
+
+	.description = dwc_otg_hcd_name,
+	.product_desc = "DWC OTG Controller",
+	.hcd_priv_size = sizeof(struct dwc_otg_hcd),
+
+	.irq = dwc_otg_hcd_irq,
+
+	.flags = HCD_MEMORY | HCD_USB2,
+
+	.start = dwc_otg_hcd_start,
+	.stop = dwc_otg_hcd_stop,
+
+	.urb_enqueue = dwc_otg_hcd_urb_enqueue,
+	.urb_dequeue = dwc_otg_hcd_urb_dequeue,
+	.endpoint_disable = dwc_otg_hcd_endpoint_disable,
+
+	.get_frame_number = dwc_otg_hcd_get_frame_number,
+
+	.hub_status_data = dwc_otg_hcd_hub_status_data,
+	.hub_control = dwc_otg_hcd_hub_control,
+};
+
+/**
+ * Work queue function for starting the HCD when A-Cable is connected.
+ * The dwc_otg_hcd_start() must be called in a process context.
+ */
+static void hcd_start_func(struct work_struct *work)
+{
+	void *_vp =
+	    (void *)(atomic_long_read(&work->data) & WORK_STRUCT_WQ_DATA_MASK);
+	struct usb_hcd *usb_hcd = (struct usb_hcd *)_vp;
+	DWC_DEBUGPL(DBG_HCDV, "%s() %p\n", __func__, usb_hcd);
+	if (usb_hcd)
+		dwc_otg_hcd_start(usb_hcd);
+}
+
+/**
+ * HCD Callback function for starting the HCD when A-Cable is
+ * connected.
+ *
+ * @_p: void pointer to the <code>struct usb_hcd</code>
+ */
+static int32_t dwc_otg_hcd_start_cb(void *_p)
+{
+	struct dwc_otg_hcd *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_p);
+	struct dwc_otg_core_if *core_if = dwc_otg_hcd->core_if;
+	union hprt0_data hprt0;
+
+	if (core_if->op_state == B_HOST) {
+		/*
+		 * Reset the port.  During a HNP mode switch the reset
+		 * needs to occur within 1ms and have a duration of at
+		 * least 50ms.
+		 */
+		hprt0.d32 = dwc_otg_read_hprt0(core_if);
+		hprt0.b.prtrst = 1;
+		dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+		((struct usb_hcd *)_p)->self.is_b_host = 1;
+	} else {
+		((struct usb_hcd *)_p)->self.is_b_host = 0;
+	}
+
+	/* Need to start the HCD in a non-interrupt context. */
+	INIT_WORK(&dwc_otg_hcd->start_work, hcd_start_func);
+	atomic_long_set(&dwc_otg_hcd->start_work.data, (long)_p);
+	schedule_work(&dwc_otg_hcd->start_work);
+
+	return 1;
+}
+
+/**
+ * HCD Callback function for stopping the HCD.
+ *
+ * @_p: void pointer to the <code>struct usb_hcd</code>
+ */
+static int32_t dwc_otg_hcd_stop_cb(void *_p)
+{
+	struct usb_hcd *usb_hcd = (struct usb_hcd *)_p;
+	DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p);
+	dwc_otg_hcd_stop(usb_hcd);
+	return 1;
+}
+
+static void del_xfer_timers(struct dwc_otg_hcd *hcd)
+{
+#ifdef DEBUG
+	int i;
+	int num_channels = hcd->core_if->core_params->host_channels;
+	for (i = 0; i < num_channels; i++)
+		del_timer(&hcd->core_if->hc_xfer_timer[i]);
+#endif
+}
+
+static void del_timers(struct dwc_otg_hcd *hcd)
+{
+	del_xfer_timers(hcd);
+	del_timer(&hcd->conn_timer);
+}
+
+/**
+ * Processes all the URBs in a single list of QHs. Completes them with
+ * -ETIMEDOUT and frees the QTD.
+ */
+static void kill_urbs_in_qh_list(struct dwc_otg_hcd *hcd,
+				 struct list_head *_qh_list)
+{
+	struct dwc_otg_qh *qh;
+	struct dwc_otg_qtd *qtd;
+	struct dwc_otg_qtd *qtd_next;
+
+	list_for_each_entry(qh, _qh_list, qh_list_entry) {
+		list_for_each_entry_safe(qtd, qtd_next, &qh->qtd_list,
+					 qtd_list_entry) {
+			if (qtd->urb != NULL) {
+				dwc_otg_hcd_complete_urb(hcd, qtd->urb,
+							 -ETIMEDOUT);
+				qtd->urb = NULL;
+			}
+			dwc_otg_hcd_qtd_remove_and_free(qtd);
+		}
+	}
+}
+
+/**
+ * Responds with an error status of ETIMEDOUT to all URBs in the non-periodic
+ * and periodic schedules. The QTD associated with each URB is removed from
+ * the schedule and freed. This function may be called when a disconnect is
+ * detected or when the HCD is being stopped.
+ */
+static void kill_all_urbs(struct dwc_otg_hcd *hcd)
+{
+	kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_inactive);
+	kill_urbs_in_qh_list(hcd, &hcd->non_periodic_sched_active);
+	kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_inactive);
+	kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_ready);
+	kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_assigned);
+	kill_urbs_in_qh_list(hcd, &hcd->periodic_sched_queued);
+}
+
+/**
+ * HCD Callback function for disconnect of the HCD.
+ *
+ * @_p: void pointer to the <code>struct usb_hcd</code>
+ */
+static int32_t dwc_otg_hcd_disconnect_cb(void *_p)
+{
+	union gintsts_data intr;
+	struct dwc_otg_hcd *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_p);
+
+	/*
+	 * Set status flags for the hub driver.
+	 */
+	dwc_otg_hcd->flags.b.port_connect_status_change = 1;
+	dwc_otg_hcd->flags.b.port_connect_status = 0;
+
+	/*
+	 * Shutdown any transfers in process by clearing the Tx FIFO Empty
+	 * interrupt mask and status bits and disabling subsequent host
+	 * channel interrupts.
+	 */
+	intr.d32 = 0;
+	intr.b.nptxfempty = 1;
+	intr.b.ptxfempty = 1;
+	intr.b.hcintr = 1;
+	dwc_modify_reg32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk,
+			 intr.d32, 0);
+	dwc_modify_reg32(&dwc_otg_hcd->core_if->core_global_regs->gintsts,
+			 intr.d32, 0);
+
+	del_timers(dwc_otg_hcd);
+
+	/*
+	 * Turn off the vbus power only if the core has transitioned to device
+	 * mode. If still in host mode, need to keep power on to detect a
+	 * reconnection.
+	 */
+	if (dwc_otg_is_device_mode(dwc_otg_hcd->core_if)) {
+		if (dwc_otg_hcd->core_if->op_state != A_SUSPEND) {
+			union hprt0_data hprt0 = {.d32 = 0 };
+			DWC_PRINT("Disconnect: PortPower off\n");
+			hprt0.b.prtpwr = 0;
+			dwc_write_reg32(dwc_otg_hcd->core_if->host_if->hprt0,
+					hprt0.d32);
+		}
+
+		dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if);
+	}
+
+	/* Respond with an error status to all URBs in the schedule. */
+	kill_all_urbs(dwc_otg_hcd);
+
+	if (dwc_otg_is_host_mode(dwc_otg_hcd->core_if)) {
+		/* Clean up any host channels that were in use. */
+		int num_channels;
+		int i;
+		struct dwc_hc *channel;
+		struct dwc_otg_hc_regs *hc_regs;
+		union hcchar_data hcchar;
+
+		num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
+
+		if (!dwc_otg_hcd->core_if->dma_enable) {
+			/* Flush out any channel requests in slave mode. */
+			for (i = 0; i < num_channels; i++) {
+				channel = dwc_otg_hcd->hc_ptr_array[i];
+				if (list_empty(&channel->hc_list_entry)) {
+					hc_regs =
+					    dwc_otg_hcd->core_if->host_if->
+					    hc_regs[i];
+					hcchar.d32 =
+					    dwc_read_reg32(&hc_regs->hcchar);
+					if (hcchar.b.chen) {
+						hcchar.b.chen = 0;
+						hcchar.b.chdis = 1;
+						hcchar.b.epdir = 0;
+						dwc_write_reg32(&hc_regs->
+								hcchar,
+								hcchar.d32);
+					}
+				}
+			}
+		}
+
+		for (i = 0; i < num_channels; i++) {
+			channel = dwc_otg_hcd->hc_ptr_array[i];
+			if (list_empty(&channel->hc_list_entry)) {
+				hc_regs =
+				    dwc_otg_hcd->core_if->host_if->hc_regs[i];
+				hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+				if (hcchar.b.chen) {
+					/* Halt the channel. */
+					hcchar.b.chdis = 1;
+					dwc_write_reg32(&hc_regs->hcchar,
+							hcchar.d32);
+				}
+
+				dwc_otg_hc_cleanup(dwc_otg_hcd->core_if,
+						   channel);
+				list_add_tail(&channel->hc_list_entry,
+					      &dwc_otg_hcd->free_hc_list);
+			}
+		}
+	}
+
+	/* A disconnect will end the session so the B-Device is no
+	 * longer a B-host. */
+	((struct usb_hcd *)_p)->self.is_b_host = 0;
+	return 1;
+}
+
+/**
+ * Connection timeout function.  An OTG host is required to display a
+ * message if the device does not connect within 10 seconds.
+ */
+void dwc_otg_hcd_connect_timeout(unsigned long _ptr)
+{
+	DWC_DEBUGPL(DBG_HCDV, "%s(%x)\n", __func__, (int)_ptr);
+	DWC_PRINT("Connect Timeout\n");
+	DWC_ERROR("Device Not Connected/Responding\n");
+}
+
+/**
+ * Start the connection timer.  An OTG host is required to display a
+ * message if the device does not connect within 10 seconds.  The
+ * timer is deleted if a port connect interrupt occurs before the
+ * timer expires.
+ */
+static void dwc_otg_hcd_start_connect_timer(struct dwc_otg_hcd *hcd)
+{
+	init_timer(&hcd->conn_timer);
+	hcd->conn_timer.function = dwc_otg_hcd_connect_timeout;
+	hcd->conn_timer.data = (unsigned long)0;
+	hcd->conn_timer.expires = jiffies + (HZ * 10);
+	add_timer(&hcd->conn_timer);
+}
+
+/**
+ * HCD Callback function for disconnect of the HCD.
+ *
+ * @_p: void pointer to the <code>struct usb_hcd</code>
+ */
+static int32_t dwc_otg_hcd_session_start_cb(void *_p)
+{
+	struct dwc_otg_hcd *dwc_otg_hcd = hcd_to_dwc_otg_hcd(_p);
+	DWC_DEBUGPL(DBG_HCDV, "%s(%p)\n", __func__, _p);
+	dwc_otg_hcd_start_connect_timer(dwc_otg_hcd);
+	return 1;
+}
+
+/**
+ * HCD Callback structure for handling mode switching.
+ */
+static struct dwc_otg_cil_callbacks hcd_cil_callbacks = {
+	.start = dwc_otg_hcd_start_cb,
+	.stop = dwc_otg_hcd_stop_cb,
+	.disconnect = dwc_otg_hcd_disconnect_cb,
+	.session_start = dwc_otg_hcd_session_start_cb,
+	.p = 0,
+};
+
+/**
+ * Reset tasklet function
+ */
+static void reset_tasklet_func(unsigned long data)
+{
+	struct dwc_otg_hcd *dwc_otg_hcd = (struct dwc_otg_hcd *)data;
+	struct dwc_otg_core_if *core_if = dwc_otg_hcd->core_if;
+	union hprt0_data hprt0;
+
+	DWC_DEBUGPL(DBG_HCDV, "USB RESET tasklet called\n");
+
+	hprt0.d32 = dwc_otg_read_hprt0(core_if);
+	hprt0.b.prtrst = 1;
+	dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+	mdelay(60);
+
+	hprt0.b.prtrst = 0;
+	dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+	dwc_otg_hcd->flags.b.port_reset_change = 1;
+
+	return;
+}
+
+static struct tasklet_struct reset_tasklet = {
+	.next = NULL,
+	.state = 0,
+	.count = ATOMIC_INIT(0),
+	.func = reset_tasklet_func,
+	.data = 0,
+};
+
+static enum hrtimer_restart delayed_enable(struct hrtimer *t)
+{
+	struct dwc_otg_hcd *hcd = container_of(t, struct dwc_otg_hcd,
+					       poll_rate_limit);
+	struct dwc_otg_core_global_regs *global_regs =
+	    hcd->core_if->core_global_regs;
+	union gintmsk_data intr_mask = {.d32 = 0 };
+	intr_mask.b.nptxfempty = 1;
+	dwc_modify_reg32(&global_regs->gintmsk, 0, intr_mask.d32);
+
+	return HRTIMER_NORESTART;
+}
+
+/**
+ * Initializes the HCD. This function allocates memory for and initializes the
+ * static parts of the usb_hcd and dwc_otg_hcd structures. It also registers the
+ * USB bus with the core and calls the hc_driver->start() function. It returns
+ * a negative error on failure.
+ */
+int __devinit dwc_otg_hcd_init(struct device *dev)
+{
+	struct usb_hcd *hcd = NULL;
+	struct dwc_otg_hcd *dwc_otg_hcd = NULL;
+	struct dwc_otg_device *otg_dev = dev->platform_data;
+
+	int num_channels;
+	int i;
+	struct dwc_hc *channel;
+
+	int retval = 0;
+
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD INIT\n");
+
+	/* Set device flags indicating whether the HCD supports DMA. */
+	if (otg_dev->core_if->dma_enable) {
+		DWC_PRINT("Using DMA mode\n");
+		dev->coherent_dma_mask = ~0;
+		dev->dma_mask = &dev->coherent_dma_mask;
+	} else {
+		DWC_PRINT("Using Slave mode\n");
+		dev->coherent_dma_mask = 0;
+		dev->dma_mask = NULL;
+	}
+
+	/*
+	 * Allocate memory for the base HCD plus the DWC OTG HCD.
+	 * Initialize the base HCD.
+	 */
+	hcd = usb_create_hcd(&dwc_otg_hc_driver, dev, dev_name(dev));
+	if (hcd == NULL) {
+		retval = -ENOMEM;
+		goto error1;
+	}
+	hcd->regs = otg_dev->base;
+	hcd->self.otg_port = 1;
+
+	/* Integrate TT in root hub, by default this is disbled. */
+	hcd->has_tt = 1;
+
+	/* Initialize the DWC OTG HCD. */
+	dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+
+	spin_lock_init(&dwc_otg_hcd->global_lock);
+
+	dwc_otg_hcd->core_if = otg_dev->core_if;
+	otg_dev->hcd = dwc_otg_hcd;
+
+	/* Register the HCD CIL Callbacks */
+	dwc_otg_cil_register_hcd_callbacks(otg_dev->core_if,
+					   &hcd_cil_callbacks, hcd);
+
+	/* Initialize the non-periodic schedule. */
+	INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_inactive);
+	INIT_LIST_HEAD(&dwc_otg_hcd->non_periodic_sched_active);
+
+	/* Initialize the periodic schedule. */
+	INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_inactive);
+	INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_ready);
+	INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_assigned);
+	INIT_LIST_HEAD(&dwc_otg_hcd->periodic_sched_queued);
+
+	/*
+	 * Create a host channel descriptor for each host channel implemented
+	 * in the controller. Initialize the channel descriptor array.
+	 */
+	INIT_LIST_HEAD(&dwc_otg_hcd->free_hc_list);
+	num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
+	for (i = 0; i < num_channels; i++) {
+		channel = kmalloc(sizeof(struct dwc_hc), GFP_KERNEL);
+		if (channel == NULL) {
+			retval = -ENOMEM;
+			DWC_ERROR("%s: host channel allocation failed\n",
+				  __func__);
+			goto error2;
+		}
+		memset(channel, 0, sizeof(struct dwc_hc));
+		channel->hc_num = i;
+		dwc_otg_hcd->hc_ptr_array[i] = channel;
+#ifdef DEBUG
+		init_timer(&dwc_otg_hcd->core_if->hc_xfer_timer[i]);
+#endif
+
+		DWC_DEBUGPL(DBG_HCDV, "HCD Added channel #%d, hc=%p\n", i,
+			    channel);
+	}
+
+	/* Initialize the Connection timeout timer. */
+	init_timer(&dwc_otg_hcd->conn_timer);
+
+	/* Initialize reset tasklet. */
+	reset_tasklet.data = (unsigned long)dwc_otg_hcd;
+	dwc_otg_hcd->reset_tasklet = &reset_tasklet;
+
+	hrtimer_init(&dwc_otg_hcd->poll_rate_limit, CLOCK_MONOTONIC,
+		     HRTIMER_MODE_REL);
+	dwc_otg_hcd->poll_rate_limit.function = delayed_enable;
+
+	/*
+	 * Finish generic HCD initialization and start the HCD. This function
+	 * allocates the DMA buffer pool, registers the USB bus, requests the
+	 * IRQ line, and calls dwc_otg_hcd_start method.
+	 */
+	retval =
+	    usb_add_hcd(hcd, platform_get_irq(to_platform_device(dev), 0),
+			IRQF_SHARED);
+	if (retval < 0)
+		goto error2;
+
+	/*
+	 * Allocate space for storing data on status transactions. Normally no
+	 * data is sent, but this space acts as a bit bucket. This must be
+	 * done after usb_add_hcd since that function allocates the DMA buffer
+	 * pool.
+	 */
+	if (otg_dev->core_if->dma_enable) {
+		dwc_otg_hcd->status_buf =
+		    dma_alloc_coherent(dev,
+				       DWC_OTG_HCD_STATUS_BUF_SIZE,
+				       &dwc_otg_hcd->status_buf_dma,
+				       GFP_KERNEL | GFP_DMA);
+	} else {
+		dwc_otg_hcd->status_buf = kmalloc(DWC_OTG_HCD_STATUS_BUF_SIZE,
+						  GFP_KERNEL);
+	}
+	if (dwc_otg_hcd->status_buf == NULL) {
+		retval = -ENOMEM;
+		DWC_ERROR("%s: status_buf allocation failed\n", __func__);
+		goto error3;
+	}
+
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Initialized HCD, usbbus=%d\n",
+		    hcd->self.busnum);
+
+	return 0;
+
+	/* Error conditions */
+error3:
+	usb_remove_hcd(hcd);
+error2:
+	dwc_otg_hcd_free(hcd);
+	usb_put_hcd(hcd);
+error1:
+	return retval;
+}
+
+/**
+ * Removes the HCD.
+ * Frees memory and resources associated with the HCD and deregisters the bus.
+ */
+void dwc_otg_hcd_remove(struct device *dev)
+{
+	struct dwc_otg_device *otg_dev = dev->platform_data;
+	struct dwc_otg_hcd *dwc_otg_hcd = otg_dev->hcd;
+	struct usb_hcd *hcd = dwc_otg_hcd_to_hcd(dwc_otg_hcd);
+
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD REMOVE\n");
+
+	/* Turn off all interrupts */
+	dwc_write_reg32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk, 0);
+	dwc_modify_reg32(&dwc_otg_hcd->core_if->core_global_regs->gahbcfg, 1,
+			 0);
+
+	usb_remove_hcd(hcd);
+	dwc_otg_hcd_free(hcd);
+	usb_put_hcd(hcd);
+
+	return;
+}
+
+/* =========================================================================
+ *  Linux HC Driver Functions
+ * ========================================================================= */
+
+/**
+ * Initializes dynamic portions of the DWC_otg HCD state.
+ */
+static void hcd_reinit(struct dwc_otg_hcd *hcd)
+{
+	struct list_head *item;
+	int num_channels;
+	int i;
+	struct dwc_hc *channel;
+
+	hcd->flags.d32 = 0;
+
+	hcd->non_periodic_qh_ptr = &hcd->non_periodic_sched_active;
+	hcd->non_periodic_channels = 0;
+	hcd->periodic_channels = 0;
+
+	/*
+	 * Put all channels in the free channel list and clean up channel
+	 * states.
+	 */
+	item = hcd->free_hc_list.next;
+	while (item != &hcd->free_hc_list) {
+		list_del(item);
+		item = hcd->free_hc_list.next;
+	}
+	num_channels = hcd->core_if->core_params->host_channels;
+	for (i = 0; i < num_channels; i++) {
+		channel = hcd->hc_ptr_array[i];
+		list_add_tail(&channel->hc_list_entry, &hcd->free_hc_list);
+		dwc_otg_hc_cleanup(hcd->core_if, channel);
+	}
+
+	/* Initialize the DWC core for host mode operation. */
+	dwc_otg_core_host_init(hcd->core_if);
+}
+
+/** Initializes the DWC_otg controller and its root hub and prepares it for host
+ * mode operation. Activates the root port. Returns 0 on success and a negative
+ * error code on failure. */
+int dwc_otg_hcd_start(struct usb_hcd *hcd)
+{
+	struct dwc_otg_hcd *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+	struct dwc_otg_core_if *core_if = dwc_otg_hcd->core_if;
+	unsigned long flags;
+
+	struct usb_bus *bus;
+
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
+
+	spin_lock_irqsave(&dwc_otg_hcd->global_lock, flags);
+
+	bus = hcd_to_bus(hcd);
+
+	/* Initialize the bus state.  If the core is in Device Mode
+	 * HALT the USB bus and return. */
+	if (dwc_otg_is_device_mode(core_if)) {
+		hcd->state = HC_STATE_HALT;
+		goto out;
+	}
+	hcd->state = HC_STATE_RUNNING;
+
+	hcd_reinit(dwc_otg_hcd);
+out:
+	spin_unlock_irqrestore(&dwc_otg_hcd->global_lock, flags);
+
+	return 0;
+}
+
+static void qh_list_free(struct dwc_otg_hcd *hcd, struct list_head *_qh_list)
+{
+	struct list_head *item;
+	struct dwc_otg_qh *qh;
+
+	if (_qh_list->next == NULL) {
+		/* The list hasn't been initialized yet. */
+		return;
+	}
+
+	/* Ensure there are no QTDs or URBs left. */
+	kill_urbs_in_qh_list(hcd, _qh_list);
+
+	for (item = _qh_list->next; item != _qh_list; item = _qh_list->next) {
+		qh = list_entry(item, struct dwc_otg_qh, qh_list_entry);
+		dwc_otg_hcd_qh_remove_and_free(hcd, qh);
+	}
+}
+
+/**
+ * Halts the DWC_otg host mode operations in a clean manner. USB transfers are
+ * stopped.
+ */
+void dwc_otg_hcd_stop(struct usb_hcd *hcd)
+{
+	struct dwc_otg_hcd *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+	union hprt0_data hprt0 = {.d32 = 0 };
+
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD STOP\n");
+
+	/* Turn off all host-specific interrupts. */
+	dwc_otg_disable_host_interrupts(dwc_otg_hcd->core_if);
+
+	/*
+	 * The root hub should be disconnected before this function is called.
+	 * The disconnect will clear the QTD lists (via ..._hcd_urb_dequeue)
+	 * and the QH lists (via ..._hcd_endpoint_disable).
+	 */
+
+	/* Turn off the vbus power */
+	DWC_PRINT("PortPower off\n");
+	hprt0.b.prtpwr = 0;
+	dwc_write_reg32(dwc_otg_hcd->core_if->host_if->hprt0, hprt0.d32);
+
+	return;
+}
+
+/** Returns the current frame number. */
+int dwc_otg_hcd_get_frame_number(struct usb_hcd *hcd)
+{
+	struct dwc_otg_hcd *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+	union hfnum_data hfnum;
+
+	hfnum.d32 =
+	    dwc_read_reg32(&dwc_otg_hcd->core_if->host_if->host_global_regs->
+			   hfnum);
+
+#ifdef DEBUG_SOF
+	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD GET FRAME NUMBER %d\n",
+		    hfnum.b.frnum);
+#endif
+	return hfnum.b.frnum;
+}
+
+/**
+ * Frees secondary storage associated with the dwc_otg_hcd structure contained
+ * in the struct usb_hcd field.
+ */
+void dwc_otg_hcd_free(struct usb_hcd *hcd)
+{
+	struct dwc_otg_hcd *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+	int i;
+
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD FREE\n");
+
+	del_timers(dwc_otg_hcd);
+
+	/* Free memory for QH/QTD lists */
+	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_inactive);
+	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->non_periodic_sched_active);
+	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_inactive);
+	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_ready);
+	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_assigned);
+	qh_list_free(dwc_otg_hcd, &dwc_otg_hcd->periodic_sched_queued);
+
+	/* Free memory for the host channels. */
+	for (i = 0; i < MAX_EPS_CHANNELS; i++) {
+		struct dwc_hc *hc = dwc_otg_hcd->hc_ptr_array[i];
+		if (hc != NULL) {
+			DWC_DEBUGPL(DBG_HCDV, "HCD Free channel #%i, hc=%p\n",
+				    i, hc);
+			kfree(hc);
+		}
+	}
+
+	if (dwc_otg_hcd->core_if->dma_enable) {
+		if (dwc_otg_hcd->status_buf_dma) {
+			dma_free_coherent(hcd->self.controller,
+					  DWC_OTG_HCD_STATUS_BUF_SIZE,
+					  dwc_otg_hcd->status_buf,
+					  dwc_otg_hcd->status_buf_dma);
+		}
+	} else if (dwc_otg_hcd->status_buf != NULL) {
+		kfree(dwc_otg_hcd->status_buf);
+	}
+
+	return;
+}
+
+#ifdef DEBUG
+static void dump_urb_info(struct urb *urb, char *_fn_name)
+{
+	DWC_PRINT("%s, urb %p\n", _fn_name, urb);
+	DWC_PRINT("  Device address: %d\n", usb_pipedevice(urb->pipe));
+	DWC_PRINT("  Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
+		  (usb_pipein(urb->pipe) ? "IN" : "OUT"));
+	DWC_PRINT("  Endpoint type: %s\n",
+		({
+			char *pipetype;
+			switch (usb_pipetype(urb->pipe)) {
+			case PIPE_CONTROL:
+				pipetype = "CONTROL";
+				break;
+			case PIPE_BULK:
+				pipetype = "BULK";
+				break;
+			case PIPE_INTERRUPT:
+				pipetype = "INTERRUPT";
+				break;
+			case PIPE_ISOCHRONOUS:
+				pipetype = "ISOCHRONOUS";
+				break;
+			default:
+				pipetype = "UNKNOWN";
+				break;
+			}
+			pipetype;
+		})) ;
+	DWC_PRINT("  Speed: %s\n",
+		({
+			char *speed;
+			switch (urb->dev->speed) {
+			case USB_SPEED_HIGH:
+				speed = "HIGH";
+				break;
+			case USB_SPEED_FULL:
+				speed = "FULL";
+				break;
+			case USB_SPEED_LOW:
+				speed = "LOW";
+				break;
+			default:
+				speed = "UNKNOWN";
+				break;
+			}
+			speed;
+		}));
+	DWC_PRINT("  Max packet size: %d\n",
+		  usb_maxpacket(urb->dev, urb->pipe,
+				usb_pipeout(urb->pipe)));
+	DWC_PRINT("  Data buffer length: %d\n", urb->transfer_buffer_length);
+	DWC_PRINT("  Transfer buffer: %p, Transfer DMA: %p\n",
+		  urb->transfer_buffer, (void *)urb->transfer_dma);
+	DWC_PRINT("  Setup buffer: %p, Setup DMA: %p\n",
+		  urb->setup_packet, (void *)urb->setup_dma);
+	DWC_PRINT("  Interval: %d\n", urb->interval);
+	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+		int i;
+		for (i = 0; i < urb->number_of_packets; i++) {
+			DWC_PRINT("  ISO Desc %d:\n", i);
+			DWC_PRINT("    offset: %d, length %d\n",
+				  urb->iso_frame_desc[i].offset,
+				  urb->iso_frame_desc[i].length);
+		}
+	}
+}
+
+static void dump_channel_info(struct dwc_otg_hcd *hcd, struct dwc_otg_qh * qh)
+{
+	if (qh->channel != NULL) {
+		struct dwc_hc *hc = qh->channel;
+		struct list_head *item;
+		struct dwc_otg_qh *qh_item;
+		int num_channels = hcd->core_if->core_params->host_channels;
+		int i;
+
+		struct dwc_otg_hc_regs *hc_regs;
+		union hcchar_data hcchar;
+		union hcsplt_data hcsplt;
+		union hctsiz_data hctsiz;
+		uint32_t hcdma;
+
+		hc_regs = hcd->core_if->host_if->hc_regs[hc->hc_num];
+		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+		hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt);
+		hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
+		hcdma = dwc_read_reg32(&hc_regs->hcdma);
+
+		DWC_PRINT("  Assigned to channel %p:\n", hc);
+		DWC_PRINT("    hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32,
+			  hcsplt.d32);
+		DWC_PRINT("    hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32,
+			  hcdma);
+		DWC_PRINT("    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
+			  hc->dev_addr, hc->ep_num, hc->ep_is_in);
+		DWC_PRINT("    ep_type: %d\n", hc->ep_type);
+		DWC_PRINT("    max_packet: %d\n", hc->max_packet);
+		DWC_PRINT("    data_pid_start: %d\n", hc->data_pid_start);
+		DWC_PRINT("    xfer_started: %d\n", hc->xfer_started);
+		DWC_PRINT("    halt_status: %d\n", hc->halt_status);
+		DWC_PRINT("    xfer_buff: %p\n", hc->xfer_buff);
+		DWC_PRINT("    xfer_len: %d\n", hc->xfer_len);
+		DWC_PRINT("    qh: %p\n", hc->qh);
+		DWC_PRINT("  NP inactive sched:\n");
+		list_for_each(item, &hcd->non_periodic_sched_inactive) {
+			qh_item = list_entry(item, struct dwc_otg_qh,
+					     qh_list_entry);
+			DWC_PRINT("    %p\n", qh_item);
+		}
+		DWC_PRINT("  NP active sched:\n");
+		list_for_each(item, &hcd->non_periodic_sched_active) {
+			qh_item = list_entry(item, struct dwc_otg_qh,
+					     qh_list_entry);
+			DWC_PRINT("    %p\n", qh_item);
+		}
+		DWC_PRINT("  Channels: \n");
+		for (i = 0; i < num_channels; i++) {
+			struct dwc_hc *hc = hcd->hc_ptr_array[i];
+			DWC_PRINT("    %2d: %p\n", i, hc);
+		}
+	}
+}
+#endif
+
+/* Starts processing a USB transfer request specified by a USB Request Block
+ * (URB). mem_flags indicates the type of memory allocation to use while
+ * processing this URB. */
+int dwc_otg_hcd_urb_enqueue(struct usb_hcd *hcd,
+			    struct urb *urb, unsigned _mem_flags)
+{
+	unsigned long flags;
+	int retval = 0;
+	struct dwc_otg_hcd *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+	struct dwc_otg_qtd *qtd;
+
+	spin_lock_irqsave(&dwc_otg_hcd->global_lock, flags);
+
+	/*
+	 * Make sure the start of frame interrupt is enabled now that
+	 * we know we should have queued data. The SOF interrupt
+	 * handler automatically disables itself when idle to reduce
+	 * the number of interrupts. See dwc_otg_hcd_handle_sof_intr()
+	 * for the disable
+	 */
+	dwc_modify_reg32(&dwc_otg_hcd->core_if->core_global_regs->gintmsk, 0,
+			 DWC_SOF_INTR_MASK);
+
+#ifdef DEBUG
+	if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB))
+		dump_urb_info(urb, "dwc_otg_hcd_urb_enqueue");
+#endif
+	if (!dwc_otg_hcd->flags.b.port_connect_status) {
+		/* No longer connected. */
+		retval =  -ENODEV;
+		goto out;
+	}
+
+	qtd = dwc_otg_hcd_qtd_create(urb);
+	if (qtd == NULL) {
+		DWC_ERROR("DWC OTG HCD URB Enqueue failed creating QTD\n");
+		retval = -ENOMEM;
+		goto out;
+	}
+
+	retval = dwc_otg_hcd_qtd_add(qtd, dwc_otg_hcd);
+	if (retval < 0) {
+		DWC_ERROR("DWC OTG HCD URB Enqueue failed adding QTD. "
+			  "Error status %d\n", retval);
+		dwc_otg_hcd_qtd_free(qtd);
+	}
+out:
+	spin_unlock_irqrestore(&dwc_otg_hcd->global_lock, flags);
+
+	return retval;
+}
+
+/** Aborts/cancels a USB transfer request. Always returns 0 to indicate
+ * success.  */
+int dwc_otg_hcd_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+	unsigned long flags;
+	struct dwc_otg_hcd *dwc_otg_hcd;
+	struct dwc_otg_qtd *urb_qtd;
+
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Dequeue\n");
+
+	dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+
+	spin_lock_irqsave(&dwc_otg_hcd->global_lock, flags);
+
+	urb_qtd = urb->hcpriv;
+
+#ifdef DEBUG
+	if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
+		dump_urb_info(urb, "dwc_otg_hcd_urb_dequeue");
+		if (urb_qtd == urb_qtd->qh->qtd_in_process)
+			dump_channel_info(dwc_otg_hcd, urb_qtd->qh);
+	}
+#endif
+
+	if (urb_qtd == urb_qtd->qh->qtd_in_process) {
+		/* The QTD is in process (it has been assigned to a channel). */
+
+		if (dwc_otg_hcd->flags.b.port_connect_status) {
+			/*
+			 * If still connected (i.e. in host mode), halt the
+			 * channel so it can be used for other transfers. If
+			 * no longer connected, the host registers can't be
+			 * written to halt the channel since the core is in
+			 * device mode.
+			 */
+			dwc_otg_hc_halt(dwc_otg_hcd->core_if,
+					urb_qtd->qh->channel,
+					DWC_OTG_HC_XFER_URB_DEQUEUE);
+		}
+	}
+
+	/*
+	 * Free the QTD and clean up the associated QH. Leave the QH in the
+	 * schedule if it has any remaining QTDs.
+	 */
+	dwc_otg_hcd_qtd_remove_and_free(urb_qtd);
+	if (urb_qtd == urb_qtd->qh->qtd_in_process) {
+		dwc_otg_hcd_qh_deactivate(dwc_otg_hcd, urb_qtd->qh, 0);
+		urb_qtd->qh->channel = NULL;
+		urb_qtd->qh->qtd_in_process = NULL;
+	} else if (list_empty(&urb_qtd->qh->qtd_list)) {
+		dwc_otg_hcd_qh_remove(dwc_otg_hcd, urb_qtd->qh);
+	}
+
+	spin_unlock_irqrestore(&dwc_otg_hcd->global_lock, flags);
+
+	urb->hcpriv = NULL;
+
+	/* Higher layer software sets URB status. */
+	usb_hcd_giveback_urb(hcd, urb, status);
+	if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
+		DWC_PRINT("Called usb_hcd_giveback_urb()\n");
+		DWC_PRINT("  urb->status = %d\n", urb->status);
+	}
+
+	return 0;
+}
+
+/* Frees resources in the DWC_otg controller related to a given endpoint. Also
+ * clears state in the HCD related to the endpoint. Any URBs for the endpoint
+ * must already be dequeued. */
+void dwc_otg_hcd_endpoint_disable(struct usb_hcd *hcd,
+				  struct usb_host_endpoint *_ep)
+{
+	unsigned long flags;
+	struct dwc_otg_qh *qh;
+	struct dwc_otg_hcd *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+
+	spin_lock_irqsave(&dwc_otg_hcd->global_lock, flags);
+
+	DWC_DEBUGPL(DBG_HCD,
+		    "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
+		    "endpoint=%d\n", _ep->desc.bEndpointAddress,
+		    dwc_ep_addr_to_endpoint(_ep->desc.bEndpointAddress));
+
+	qh = _ep->hcpriv;
+	if (qh != NULL) {
+#if 1
+		/*
+		 * FIXME: Kludge to not crash on Octeon in SMP
+		 * mode. Normally dwc_otg_hcd_qh_remove_and_free() is
+		 * called even if the list isn't empty. This causes a
+		 * crash on SMP, so we don't call it now. It works
+		 * better, but probably does evil things I don't know
+		 * about.
+		 */
+		/* Check that the QTD list is really empty */
+		if (!list_empty(&qh->qtd_list)) {
+			pr_err("DWC OTG HCD EP DISABLE:"
+			       " QTD List for this endpoint is not empty\n");
+		} else
+#endif
+		{
+			dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd, qh);
+			_ep->hcpriv = NULL;
+		}
+	}
+
+	spin_unlock_irqrestore(&dwc_otg_hcd->global_lock, flags);
+
+	return;
+}
+
+/* Handles host mode interrupts for the DWC_otg controller. Returns IRQ_NONE if
+ * there was no interrupt to handle. Returns IRQ_HANDLED if there was a valid
+ * interrupt.
+ *
+ * This function is called by the USB core when an interrupt occurs */
+irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd)
+{
+	irqreturn_t result;
+	unsigned long flags;
+	struct dwc_otg_hcd *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+
+	spin_lock_irqsave(&dwc_otg_hcd->global_lock, flags);
+
+	result = IRQ_RETVAL(dwc_otg_hcd_handle_intr(dwc_otg_hcd));
+
+	spin_unlock_irqrestore(&dwc_otg_hcd->global_lock, flags);
+
+	return result;
+}
+
+/** Creates Status Change bitmap for the root hub and root port. The bitmap is
+ * returned in buf. Bit 0 is the status change indicator for the root hub. Bit 1
+ * is the status change indicator for the single root port. Returns 1 if either
+ * change indicator is 1, otherwise returns 0. */
+int dwc_otg_hcd_hub_status_data(struct usb_hcd *hcd, char *_buf)
+{
+	struct dwc_otg_hcd *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+
+	_buf[0] = 0;
+	_buf[0] |= (dwc_otg_hcd->flags.b.port_connect_status_change ||
+		    dwc_otg_hcd->flags.b.port_reset_change ||
+		    dwc_otg_hcd->flags.b.port_enable_change ||
+		    dwc_otg_hcd->flags.b.port_suspend_change ||
+		    dwc_otg_hcd->flags.b.port_over_current_change) << 1;
+
+#ifdef DEBUG
+	if (_buf[0]) {
+		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB STATUS DATA:"
+			    " Root port status changed\n");
+		DWC_DEBUGPL(DBG_HCDV, "  port_connect_status_change: %d\n",
+			    dwc_otg_hcd->flags.b.port_connect_status_change);
+		DWC_DEBUGPL(DBG_HCDV, "  port_reset_change: %d\n",
+			    dwc_otg_hcd->flags.b.port_reset_change);
+		DWC_DEBUGPL(DBG_HCDV, "  port_enable_change: %d\n",
+			    dwc_otg_hcd->flags.b.port_enable_change);
+		DWC_DEBUGPL(DBG_HCDV, "  port_suspend_change: %d\n",
+			    dwc_otg_hcd->flags.b.port_suspend_change);
+		DWC_DEBUGPL(DBG_HCDV, "  port_over_current_change: %d\n",
+			    dwc_otg_hcd->flags.b.port_over_current_change);
+	}
+#endif
+	return (_buf[0] != 0);
+}
+
+#ifdef DWC_HS_ELECT_TST
+/*
+ * Quick and dirty hack to implement the HS Electrical Test
+ * SINGLE_STEP_GET_DEVICE_DESCRIPTOR feature.
+ *
+ * This code was copied from our userspace app "hset". It sends a
+ * Get Device Descriptor control sequence in two parts, first the
+ * Setup packet by itself, followed some time later by the In and
+ * Ack packets. Rather than trying to figure out how to add this
+ * functionality to the normal driver code, we just hijack the
+ * hardware, using these two function to drive the hardware
+ * directly.
+ */
+
+struct dwc_otg_core_global_regs *global_regs;
+struct dwc_otg_host_global_regs *hc_global_regs;
+struct dwc_otg_hc_regs *hc_regs;
+uint32_t *data_fifo;
+
+static void do_setup(void)
+{
+	union gintsts_data gintsts;
+	union hctsiz_data hctsiz;
+	union hcchar_data hcchar;
+	union haint_data haint;
+	union hcint_data hcint;
+
+	/* Enable HAINTs */
+	dwc_write_reg32(&hc_global_regs->haintmsk, 0x0001);
+
+	/* Enable HCINTs */
+	dwc_write_reg32(&hc_regs->hcintmsk, 0x04a3);
+
+	/* Read GINTSTS */
+	gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+
+	/* Read HAINT */
+	haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+
+	/* Read HCINT */
+	hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+
+	/* Read HCCHAR */
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+
+	/* Clear HCINT */
+	dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+
+	/* Clear HAINT */
+	dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+
+	/* Clear GINTSTS */
+	dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+
+	/* Read GINTSTS */
+	gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+
+	/*
+	 * Send Setup packet (Get Device Descriptor)
+	 */
+
+	/* Make sure channel is disabled */
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+	if (hcchar.b.chen) {
+		hcchar.b.chdis = 1;
+		dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+
+		mdelay(1000);
+
+		/* Read GINTSTS */
+		gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+
+		/* Read HAINT */
+		haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+
+		/* Read HCINT */
+		hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+
+		/* Read HCCHAR */
+		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+
+		/* Clear HCINT */
+		dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+
+		/* Clear HAINT */
+		dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+
+		/* Clear GINTSTS */
+		dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+
+		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+	}
+
+	/* Set HCTSIZ */
+	hctsiz.d32 = 0;
+	hctsiz.b.xfersize = 8;
+	hctsiz.b.pktcnt = 1;
+	hctsiz.b.pid = DWC_OTG_HC_PID_SETUP;
+	dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
+
+	/* Set HCCHAR */
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+	hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
+	hcchar.b.epdir = 0;
+	hcchar.b.epnum = 0;
+	hcchar.b.mps = 8;
+	hcchar.b.chen = 1;
+	dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+
+	/* Fill FIFO with Setup data for Get Device Descriptor */
+	data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
+	dwc_write_reg32(data_fifo++, 0x01000680);
+	dwc_write_reg32(data_fifo++, 0x00080000);
+
+	gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+
+	/* Wait for host channel interrupt */
+	do {
+		gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+	} while (gintsts.b.hcintr == 0);
+
+
+	/* Disable HCINTs */
+	dwc_write_reg32(&hc_regs->hcintmsk, 0x0000);
+
+	/* Disable HAINTs */
+	dwc_write_reg32(&hc_global_regs->haintmsk, 0x0000);
+
+	/* Read HAINT */
+	haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+
+	/* Read HCINT */
+	hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+
+	/* Read HCCHAR */
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+
+	/* Clear HCINT */
+	dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+
+	/* Clear HAINT */
+	dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+
+	/* Clear GINTSTS */
+	dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+
+	/* Read GINTSTS */
+	gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+}
+
+static void do_in_ack(void)
+{
+	union gintsts_data gintsts;
+	union hctsiz_data hctsiz;
+	union hcchar_data hcchar;
+	union haint_data haint;
+	union hcint_data hcint;
+	union host_grxsts_data grxsts;
+
+	/* Enable HAINTs */
+	dwc_write_reg32(&hc_global_regs->haintmsk, 0x0001);
+
+	/* Enable HCINTs */
+	dwc_write_reg32(&hc_regs->hcintmsk, 0x04a3);
+
+	/* Read GINTSTS */
+	gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+
+	/* Read HAINT */
+	haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+
+	/* Read HCINT */
+	hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+
+	/* Read HCCHAR */
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+
+	/* Clear HCINT */
+	dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+
+	/* Clear HAINT */
+	dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+
+	/* Clear GINTSTS */
+	dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+
+	/* Read GINTSTS */
+	gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+
+	/*
+	 * Receive Control In packet
+	 */
+
+	/* Make sure channel is disabled */
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+	if (hcchar.b.chen) {
+		hcchar.b.chdis = 1;
+		hcchar.b.chen = 1;
+		dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+
+		mdelay(1000);
+
+		/* Read GINTSTS */
+		gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+
+		/* Read HAINT */
+		haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+
+		/* Read HCINT */
+		hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+
+		/* Read HCCHAR */
+		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+
+		/* Clear HCINT */
+		dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+
+		/* Clear HAINT */
+		dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+
+		/* Clear GINTSTS */
+		dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+
+		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+	}
+
+	/* Set HCTSIZ */
+	hctsiz.d32 = 0;
+	hctsiz.b.xfersize = 8;
+	hctsiz.b.pktcnt = 1;
+	hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
+	dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
+
+	/* Set HCCHAR */
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+	hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
+	hcchar.b.epdir = 1;
+	hcchar.b.epnum = 0;
+	hcchar.b.mps = 8;
+	hcchar.b.chen = 1;
+	dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+
+	gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+
+	/* Wait for receive status queue interrupt */
+	do {
+		gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+	} while (gintsts.b.rxstsqlvl == 0);
+
+	/* Read RXSTS */
+	grxsts.d32 = dwc_read_reg32(&global_regs->grxstsp);
+
+	/* Clear RXSTSQLVL in GINTSTS */
+	gintsts.d32 = 0;
+	gintsts.b.rxstsqlvl = 1;
+	dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+
+	switch (grxsts.b.pktsts) {
+	case DWC_GRXSTS_PKTSTS_IN:
+		/* Read the data into the host buffer */
+		if (grxsts.b.bcnt > 0) {
+			int i;
+			int word_count = (grxsts.b.bcnt + 3) / 4;
+
+			data_fifo = (uint32_t *) ((char *)global_regs + 0x1000);
+
+			for (i = 0; i < word_count; i++)
+				(void)dwc_read_reg32(data_fifo++);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+
+	/* Wait for receive status queue interrupt */
+	do {
+		gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+	} while (gintsts.b.rxstsqlvl == 0);
+
+
+	/* Read RXSTS */
+	grxsts.d32 = dwc_read_reg32(&global_regs->grxstsp);
+
+	/* Clear RXSTSQLVL in GINTSTS */
+	gintsts.d32 = 0;
+	gintsts.b.rxstsqlvl = 1;
+	dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+
+	switch (grxsts.b.pktsts) {
+	case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
+		break;
+
+	default:
+		break;
+	}
+
+	gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+
+	/* Wait for host channel interrupt */
+	do {
+		gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+	} while (gintsts.b.hcintr == 0);
+
+
+	/* Read HAINT */
+	haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+
+	/* Read HCINT */
+	hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+
+	/* Read HCCHAR */
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+
+	/* Clear HCINT */
+	dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+
+	/* Clear HAINT */
+	dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+
+	/* Clear GINTSTS */
+	dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+
+	/* Read GINTSTS */
+	gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+
+	mdelay(1);
+
+	/*
+	 * Send handshake packet
+	 */
+
+	/* Read HAINT */
+	haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+
+	/* Read HCINT */
+	hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+
+	/* Read HCCHAR */
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+
+	/* Clear HCINT */
+	dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+
+	/* Clear HAINT */
+	dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+
+	/* Clear GINTSTS */
+	dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+
+	/* Read GINTSTS */
+	gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+
+	/* Make sure channel is disabled */
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+	if (hcchar.b.chen) {
+		hcchar.b.chdis = 1;
+		hcchar.b.chen = 1;
+		dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+
+		mdelay(1000);
+
+		/* Read GINTSTS */
+		gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+
+		/* Read HAINT */
+		haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+
+		/* Read HCINT */
+		hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+
+		/* Read HCCHAR */
+		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+
+		/* Clear HCINT */
+		dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+
+		/* Clear HAINT */
+		dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+
+		/* Clear GINTSTS */
+		dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+
+		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+	}
+
+	/* Set HCTSIZ */
+	hctsiz.d32 = 0;
+	hctsiz.b.xfersize = 0;
+	hctsiz.b.pktcnt = 1;
+	hctsiz.b.pid = DWC_OTG_HC_PID_DATA1;
+	dwc_write_reg32(&hc_regs->hctsiz, hctsiz.d32);
+
+	/* Set HCCHAR */
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+	hcchar.b.eptype = DWC_OTG_EP_TYPE_CONTROL;
+	hcchar.b.epdir = 0;
+	hcchar.b.epnum = 0;
+	hcchar.b.mps = 8;
+	hcchar.b.chen = 1;
+	dwc_write_reg32(&hc_regs->hcchar, hcchar.d32);
+
+	gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+
+	/* Wait for host channel interrupt */
+	do {
+		gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+	} while (gintsts.b.hcintr == 0);
+
+
+	/* Disable HCINTs */
+	dwc_write_reg32(&hc_regs->hcintmsk, 0x0000);
+
+	/* Disable HAINTs */
+	dwc_write_reg32(&hc_global_regs->haintmsk, 0x0000);
+
+	/* Read HAINT */
+	haint.d32 = dwc_read_reg32(&hc_global_regs->haint);
+
+	/* Read HCINT */
+	hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+
+	/* Read HCCHAR */
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+
+	/* Clear HCINT */
+	dwc_write_reg32(&hc_regs->hcint, hcint.d32);
+
+	/* Clear HAINT */
+	dwc_write_reg32(&hc_global_regs->haint, haint.d32);
+
+	/* Clear GINTSTS */
+	dwc_write_reg32(&global_regs->gintsts, gintsts.d32);
+
+	/* Read GINTSTS */
+	gintsts.d32 = dwc_read_reg32(&global_regs->gintsts);
+}
+#endif /* DWC_HS_ELECT_TST */
+
+/* Handles hub class-specific requests.*/
+int dwc_otg_hcd_hub_control(struct usb_hcd *hcd,
+			    u16 _typeReq,
+			    u16 _wValue, u16 _wIndex, char *_buf, u16 _wLength)
+{
+	int retval = 0;
+	unsigned long flags;
+
+	struct dwc_otg_hcd *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
+	struct dwc_otg_core_if *core_if = hcd_to_dwc_otg_hcd(hcd)->core_if;
+	struct usb_hub_descriptor *desc;
+	union hprt0_data hprt0 = {.d32 = 0 };
+
+	uint32_t port_status;
+#ifdef DWC_HS_ELECT_TST
+	uint32_t t;
+	union gintmsk_data gintmsk;
+#endif
+	spin_lock_irqsave(&dwc_otg_hcd->global_lock, flags);
+
+	switch (_typeReq) {
+	case ClearHubFeature:
+		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+			    "ClearHubFeature 0x%x\n", _wValue);
+		switch (_wValue) {
+		case C_HUB_LOCAL_POWER:
+		case C_HUB_OVER_CURRENT:
+			/* Nothing required here */
+			break;
+		default:
+			retval = -EINVAL;
+			DWC_ERROR("DWC OTG HCD - "
+				  "ClearHubFeature request %xh unknown\n",
+				  _wValue);
+		}
+		break;
+	case ClearPortFeature:
+		if (!_wIndex || _wIndex > 1)
+			goto error;
+
+		switch (_wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			DWC_DEBUGPL(DBG_ANY, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
+			hprt0.d32 = dwc_otg_read_hprt0(core_if);
+			hprt0.b.prtena = 1;
+			dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+			break;
+		case USB_PORT_FEAT_SUSPEND:
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
+			hprt0.d32 = dwc_otg_read_hprt0(core_if);
+			hprt0.b.prtres = 1;
+			dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+			/* Clear Resume bit */
+			mdelay(100);
+			hprt0.b.prtres = 0;
+			dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+			break;
+		case USB_PORT_FEAT_POWER:
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_POWER\n");
+			hprt0.d32 = dwc_otg_read_hprt0(core_if);
+			hprt0.b.prtpwr = 0;
+			dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+			break;
+		case USB_PORT_FEAT_INDICATOR:
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_INDICATOR\n");
+			/* Port inidicator not supported */
+			break;
+		case USB_PORT_FEAT_C_CONNECTION:
+			/* Clears drivers internal connect status change
+			 * flag */
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_C_CONNECTION\n");
+			dwc_otg_hcd->flags.b.port_connect_status_change = 0;
+			break;
+		case USB_PORT_FEAT_C_RESET:
+			/* Clears the driver's internal Port Reset Change
+			 * flag */
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_C_RESET\n");
+			dwc_otg_hcd->flags.b.port_reset_change = 0;
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+			/* Clears the driver's internal Port
+			 * Enable/Disable Change flag */
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_C_ENABLE\n");
+			dwc_otg_hcd->flags.b.port_enable_change = 0;
+			break;
+		case USB_PORT_FEAT_C_SUSPEND:
+			/* Clears the driver's internal Port Suspend
+			 * Change flag, which is set when resume signaling on
+			 * the host port is complete */
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_C_SUSPEND\n");
+			dwc_otg_hcd->flags.b.port_suspend_change = 0;
+			break;
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "ClearPortFeature USB_PORT_FEAT_C_OVER_CURRENT\n");
+			dwc_otg_hcd->flags.b.port_over_current_change = 0;
+			break;
+		default:
+			retval = -EINVAL;
+			DWC_ERROR("DWC OTG HCD - "
+				  "ClearPortFeature request %xh "
+				  "unknown or unsupported\n", _wValue);
+		}
+		break;
+	case GetHubDescriptor:
+		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+			    "GetHubDescriptor\n");
+		desc = (struct usb_hub_descriptor *)_buf;
+		desc->bDescLength = 9;
+		desc->bDescriptorType = 0x29;
+		desc->bNbrPorts = 1;
+		desc->wHubCharacteristics = 0x08;
+		desc->bPwrOn2PwrGood = 1;
+		desc->bHubContrCurrent = 0;
+		desc->bitmap[0] = 0;
+		desc->bitmap[1] = 0xff;
+		break;
+	case GetHubStatus:
+		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+			    "GetHubStatus\n");
+		memset(_buf, 0, 4);
+		break;
+	case GetPortStatus:
+		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+			    "GetPortStatus\n");
+
+		if (!_wIndex || _wIndex > 1)
+			goto error;
+
+		port_status = 0;
+
+		if (dwc_otg_hcd->flags.b.port_connect_status_change)
+			port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);
+
+		if (dwc_otg_hcd->flags.b.port_enable_change)
+			port_status |= (1 << USB_PORT_FEAT_C_ENABLE);
+
+		if (dwc_otg_hcd->flags.b.port_suspend_change)
+			port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);
+
+		if (dwc_otg_hcd->flags.b.port_reset_change)
+			port_status |= (1 << USB_PORT_FEAT_C_RESET);
+
+		if (dwc_otg_hcd->flags.b.port_over_current_change) {
+			DWC_ERROR("Device Not Supported\n");
+			port_status |= (1 << USB_PORT_FEAT_C_OVER_CURRENT);
+		}
+
+		if (!dwc_otg_hcd->flags.b.port_connect_status) {
+			/*
+			 * The port is disconnected, which means the core is
+			 * either in device mode or it soon will be. Just
+			 * return 0's for the remainder of the port status
+			 * since the port register can't be read if the core
+			 * is in device mode.
+			 */
+			*((__le32 *) _buf) = cpu_to_le32(port_status);
+			break;
+		}
+
+		hprt0.d32 = dwc_read_reg32(core_if->host_if->hprt0);
+		DWC_DEBUGPL(DBG_HCDV, "  HPRT0: 0x%08x\n", hprt0.d32);
+
+		if (hprt0.b.prtconnsts)
+			port_status |= (1 << USB_PORT_FEAT_CONNECTION);
+
+		if (hprt0.b.prtena)
+			port_status |= (1 << USB_PORT_FEAT_ENABLE);
+
+		if (hprt0.b.prtsusp)
+			port_status |= (1 << USB_PORT_FEAT_SUSPEND);
+
+		if (hprt0.b.prtovrcurract)
+			port_status |= (1 << USB_PORT_FEAT_OVER_CURRENT);
+
+		if (hprt0.b.prtrst)
+			port_status |= (1 << USB_PORT_FEAT_RESET);
+
+		if (hprt0.b.prtpwr)
+			port_status |= (1 << USB_PORT_FEAT_POWER);
+
+		if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED)
+			port_status |= (1 << USB_PORT_FEAT_HIGHSPEED);
+		else if (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
+			port_status |= (1 << USB_PORT_FEAT_LOWSPEED);
+
+		if (hprt0.b.prttstctl)
+			port_status |= (1 << USB_PORT_FEAT_TEST);
+
+		/* USB_PORT_FEAT_INDICATOR unsupported always 0 */
+
+		*((__le32 *) _buf) = cpu_to_le32(port_status);
+
+		break;
+	case SetHubFeature:
+		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+			    "SetHubFeature\n");
+		/* No HUB features supported */
+		break;
+	case SetPortFeature:
+		if (_wValue != USB_PORT_FEAT_TEST && (!_wIndex || _wIndex > 1))
+			goto error;
+
+		if (!dwc_otg_hcd->flags.b.port_connect_status) {
+			/*
+			 * The port is disconnected, which means the core is
+			 * either in device mode or it soon will be. Just
+			 * return without doing anything since the port
+			 * register can't be written if the core is in device
+			 * mode.
+			 */
+			break;
+		}
+
+		switch (_wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "SetPortFeature - USB_PORT_FEAT_SUSPEND\n");
+			if (hcd->self.otg_port == _wIndex &&
+			    hcd->self.b_hnp_enable) {
+				union gotgctl_data gotgctl = {.d32 = 0 };
+				gotgctl.b.hstsethnpen = 1;
+				dwc_modify_reg32(&core_if->core_global_regs->
+						 gotgctl, 0, gotgctl.d32);
+				core_if->op_state = A_SUSPEND;
+			}
+			hprt0.d32 = dwc_otg_read_hprt0(core_if);
+			hprt0.b.prtsusp = 1;
+			dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+			/* Suspend the Phy Clock */
+			{
+				union pcgcctl_data pcgcctl = {.d32 = 0 };
+				pcgcctl.b.stoppclk = 1;
+				dwc_write_reg32(core_if->pcgcctl, pcgcctl.d32);
+			}
+
+			/*
+			 * For HNP the bus must be suspended for at
+			 * least 200ms.
+			 */
+			if (hcd->self.b_hnp_enable)
+				mdelay(200);
+			break;
+		case USB_PORT_FEAT_POWER:
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "SetPortFeature - USB_PORT_FEAT_POWER\n");
+			hprt0.d32 = dwc_otg_read_hprt0(core_if);
+			hprt0.b.prtpwr = 1;
+			dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+			break;
+		case USB_PORT_FEAT_RESET:
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "SetPortFeature - USB_PORT_FEAT_RESET\n");
+			hprt0.d32 = dwc_otg_read_hprt0(core_if);
+			/* When B-Host the Port reset bit is set in
+			 * the Start HCD Callback function, so that
+			 * the reset is started within 1ms of the HNP
+			 * success interrupt. */
+			if (!hcd->self.is_b_host) {
+				hprt0.b.prtrst = 1;
+				dwc_write_reg32(core_if->host_if->hprt0,
+						hprt0.d32);
+			}
+			/* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
+			mdelay(60);
+			hprt0.b.prtrst = 0;
+			dwc_write_reg32(core_if->host_if->hprt0, hprt0.d32);
+			break;
+
+#ifdef DWC_HS_ELECT_TST
+		case USB_PORT_FEAT_TEST:
+			t = (_wIndex >> 8);	/* MSB wIndex USB */
+			DWC_DEBUGPL(DBG_HCD,
+				"DWC OTG HCD HUB CONTROL - "
+				"SetPortFeature - USB_PORT_FEAT_TEST %d\n", t);
+			warn("USB_PORT_FEAT_TEST %d\n", t);
+			if (t < 6) {
+				hprt0.d32 = dwc_otg_read_hprt0(core_if);
+				hprt0.b.prttstctl = t;
+				dwc_write_reg32(core_if->host_if->hprt0,
+						hprt0.d32);
+			} else {
+				/* Setup global vars with reg
+				 * addresses (quick and dirty hack,
+				 * should be cleaned up)
+				 */
+				global_regs = core_if->core_global_regs;
+				hc_global_regs =
+					core_if->host_if->host_global_regs;
+				hc_regs =
+					(struct dwc_otg_hc_regs *) ((char *)
+								global_regs +
+								0x500);
+				data_fifo =
+					(uint32_t *) ((char *)global_regs +
+						0x1000);
+
+				if (t == 6) {	/* HS_HOST_PORT_SUSPEND_RESUME */
+						/* Save current interrupt mask */
+					gintmsk.d32 =
+						dwc_read_reg32(&global_regs->gintmsk);
+
+					/* Disable all interrupts
+					 * while we muck with the
+					 * hardware directly
+					 */
+					dwc_write_reg32(&global_regs->gintmsk,
+							0);
+
+					/* 15 second delay per the test spec */
+					mdelay(15000);
+
+					/* Drive suspend on the root port */
+					hprt0.d32 =
+						dwc_otg_read_hprt0(core_if);
+					hprt0.b.prtsusp = 1;
+					hprt0.b.prtres = 0;
+					dwc_write_reg32(core_if->host_if->hprt0,
+							hprt0.d32);
+
+					/* 15 second delay per the test spec */
+					mdelay(15000);
+
+					/* Drive resume on the root port */
+					hprt0.d32 = dwc_otg_read_hprt0(core_if);
+					hprt0.b.prtsusp = 0;
+					hprt0.b.prtres = 1;
+					dwc_write_reg32(core_if->host_if->hprt0,
+							hprt0.d32);
+					mdelay(100);
+
+					/* Clear the resume bit */
+					hprt0.b.prtres = 0;
+					dwc_write_reg32(core_if->host_if->hprt0,
+							hprt0.d32);
+
+					/* Restore interrupts */
+					dwc_write_reg32(&global_regs->gintmsk,
+							gintmsk.d32);
+				} else if (t == 7) {
+					/* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */
+					/* Save current interrupt mask */
+					gintmsk.d32 =
+						dwc_read_reg32(&global_regs->gintmsk);
+
+					/*
+					 * Disable all interrupts
+					 * while we muck with the
+					 * hardware directly
+					 */
+					dwc_write_reg32(&global_regs->gintmsk,
+							0);
+
+					/* 15 second delay per the test spec */
+					mdelay(15000);
+
+					/* Send the Setup packet */
+					do_setup();
+
+					/*
+					 * 15 second delay so nothing
+					 * else happens for awhile.
+					 */
+					mdelay(15000);
+
+					/* Restore interrupts */
+					dwc_write_reg32(&global_regs->gintmsk,
+							gintmsk.d32);
+				} else if (t == 8) {
+					/* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */
+					/* Save current interrupt mask */
+					gintmsk.d32 =
+						dwc_read_reg32(&global_regs->gintmsk);
+
+					/*
+					 * Disable all interrupts
+					 * while we muck with the
+					 * hardware directly
+					 */
+					dwc_write_reg32(&global_regs->gintmsk,
+							0);
+
+					/* Send the Setup packet */
+					do_setup();
+
+					/* 15 second delay so nothing else happens for awhile */
+					mdelay(15000);
+
+					/* Send the In and Ack packets */
+					do_in_ack();
+
+					/* 15 second delay so nothing else happens for awhile */
+					mdelay(15000);
+
+					/* Restore interrupts */
+					dwc_write_reg32(&global_regs->gintmsk,
+							gintmsk.d32);
+				}
+			}
+			break;
+#endif /* DWC_HS_ELECT_TST */
+
+		case USB_PORT_FEAT_INDICATOR:
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD HUB CONTROL - "
+				    "SetPortFeature - USB_PORT_FEAT_INDICATOR\n");
+			/* Not supported */
+			break;
+		default:
+			retval = -EINVAL;
+			DWC_ERROR("DWC OTG HCD - "
+				  "SetPortFeature request %xh "
+				  "unknown or unsupported\n", _wValue);
+			break;
+		}
+		break;
+	default:
+error:
+		retval = -EINVAL;
+		DWC_WARN("DWC OTG HCD - Unknown hub control request type or "
+			 "invalid typeReq: %xh wIndex: %xh wValue: %xh\n",
+			 _typeReq, _wIndex, _wValue);
+		break;
+	}
+
+	spin_unlock_irqrestore(&dwc_otg_hcd->global_lock, flags);
+
+	return retval;
+}
+
+/**
+ * Assigns transactions from a QTD to a free host channel and initializes the
+ * host channel to perform the transactions. The host channel is removed from
+ * the free list.
+ *
+ * @hcd: The HCD state structure.
+ * @_qh: Transactions from the first QTD for this QH are selected and
+ * assigned to a free host channel.
+ */
+static void assign_and_init_hc(struct dwc_otg_hcd *hcd, struct dwc_otg_qh *_qh)
+{
+	struct dwc_hc *hc;
+	struct dwc_otg_qtd *qtd;
+	struct urb *urb;
+
+	DWC_DEBUGPL(DBG_HCDV, "%s(%p,%p)\n", __func__, hcd, _qh);
+
+	hc = list_entry(hcd->free_hc_list.next, struct dwc_hc, hc_list_entry);
+
+	/* Remove the host channel from the free list. */
+	list_del_init(&hc->hc_list_entry);
+
+	qtd = list_entry(_qh->qtd_list.next, struct dwc_otg_qtd,
+			 qtd_list_entry);
+	urb = qtd->urb;
+	_qh->channel = hc;
+	_qh->qtd_in_process = qtd;
+
+	/*
+	 * Use usb_pipedevice to determine device address. This address is
+	 * 0 before the SET_ADDRESS command and the correct address afterward.
+	 */
+	hc->dev_addr = usb_pipedevice(urb->pipe);
+	hc->ep_num = usb_pipeendpoint(urb->pipe);
+
+	if (urb->dev->speed == USB_SPEED_LOW)
+		hc->speed = DWC_OTG_EP_SPEED_LOW;
+	else if (urb->dev->speed == USB_SPEED_FULL)
+		hc->speed = DWC_OTG_EP_SPEED_FULL;
+	else
+		hc->speed = DWC_OTG_EP_SPEED_HIGH;
+
+	hc->max_packet = dwc_max_packet(_qh->maxp);
+
+	hc->xfer_started = 0;
+	hc->halt_status = DWC_OTG_HC_XFER_NO_HALT_STATUS;
+	hc->error_state = (qtd->error_count > 0);
+	hc->halt_on_queue = 0;
+	hc->halt_pending = 0;
+	hc->requests = 0;
+
+	/*
+	 * The following values may be modified in the transfer type section
+	 * below. The xfer_len value may be reduced when the transfer is
+	 * started to accommodate the max widths of the XferSize and PktCnt
+	 * fields in the HCTSIZn register.
+	 */
+	hc->do_ping = _qh->ping_state;
+	hc->ep_is_in = (usb_pipein(urb->pipe) != 0);
+	hc->data_pid_start = _qh->data_toggle;
+	hc->multi_count = 1;
+
+	if (hcd->core_if->dma_enable) {
+#ifdef CONFIG_CPU_CAVIUM_OCTEON
+		const uint64_t USBN_DMA0_INB_CHN0 =
+		    CVMX_USBNX_DMA0_INB_CHN0(hcd->core_if->usb_num);
+#endif /* CONFIG_CPU_CAVIUM_OCTEON */
+		hc->xfer_buff =
+		    (uint8_t *) (unsigned long)urb->transfer_dma +
+		    urb->actual_length;
+#ifdef CONFIG_CPU_CAVIUM_OCTEON
+		/* Octeon uses external DMA */
+		wmb();
+		cvmx_write_csr(USBN_DMA0_INB_CHN0 + hc->hc_num * 8,
+			       (unsigned long)hc->xfer_buff);
+		cvmx_read_csr(USBN_DMA0_INB_CHN0 + hc->hc_num * 8);
+		DWC_DEBUGPL(DBG_HCDV,
+			    "IN: hc->hc_num = %d, hc->xfer_buff = %p\n",
+			    hc->hc_num, hc->xfer_buff);
+#endif /* CONFIG_CPU_CAVIUM_OCTEON */
+	} else {
+		hc->xfer_buff =
+		    (uint8_t *) urb->transfer_buffer + urb->actual_length;
+	}
+	hc->xfer_len = urb->transfer_buffer_length - urb->actual_length;
+	hc->xfer_count = 0;
+
+	/*
+	 * Set the split attributes
+	 */
+	hc->do_split = 0;
+	if (_qh->do_split) {
+		hc->do_split = 1;
+		hc->xact_pos = qtd->isoc_split_pos;
+		hc->complete_split = qtd->complete_split;
+		hc->hub_addr = urb->dev->tt->hub->devnum;
+		hc->port_addr = urb->dev->ttport;
+	}
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		hc->ep_type = DWC_OTG_EP_TYPE_CONTROL;
+		switch (qtd->control_phase) {
+		case DWC_OTG_CONTROL_SETUP:
+			DWC_DEBUGPL(DBG_HCDV, "  Control setup transaction\n");
+			hc->do_ping = 0;
+			hc->ep_is_in = 0;
+			hc->data_pid_start = DWC_OTG_HC_PID_SETUP;
+			if (hcd->core_if->dma_enable) {
+				hc->xfer_buff =
+				    (uint8_t *) (unsigned long)urb->setup_dma;
+			} else {
+				hc->xfer_buff = (uint8_t *) urb->setup_packet;
+			}
+			hc->xfer_len = 8;
+			break;
+		case DWC_OTG_CONTROL_DATA:
+			DWC_DEBUGPL(DBG_HCDV, "  Control data transaction\n");
+			hc->data_pid_start = qtd->data_toggle;
+			break;
+		case DWC_OTG_CONTROL_STATUS:
+			/*
+			 * Direction is opposite of data direction or IN if no
+			 * data.
+			 */
+			DWC_DEBUGPL(DBG_HCDV, "  Control status transaction\n");
+			if (urb->transfer_buffer_length == 0) {
+				hc->ep_is_in = 1;
+			} else {
+				hc->ep_is_in =
+				    (usb_pipein(urb->pipe) != USB_DIR_IN);
+			}
+			if (hc->ep_is_in)
+				hc->do_ping = 0;
+			hc->data_pid_start = DWC_OTG_HC_PID_DATA1;
+			hc->xfer_len = 0;
+			if (hcd->core_if->dma_enable) {
+				hc->xfer_buff =
+				    (uint8_t *) (unsigned long)hcd->
+				    status_buf_dma;
+			} else {
+				hc->xfer_buff = (uint8_t *) hcd->status_buf;
+			}
+			break;
+		}
+		break;
+	case PIPE_BULK:
+		hc->ep_type = DWC_OTG_EP_TYPE_BULK;
+		break;
+	case PIPE_INTERRUPT:
+		hc->ep_type = DWC_OTG_EP_TYPE_INTR;
+		break;
+	case PIPE_ISOCHRONOUS:
+		{
+			struct usb_iso_packet_descriptor *frame_desc;
+			frame_desc =
+			    &urb->iso_frame_desc[qtd->isoc_frame_index];
+			hc->ep_type = DWC_OTG_EP_TYPE_ISOC;
+			if (hcd->core_if->dma_enable) {
+				hc->xfer_buff =
+				    (uint8_t *) (unsigned long)urb->
+				    transfer_dma;
+			} else {
+				hc->xfer_buff =
+				    (uint8_t *) urb->transfer_buffer;
+			}
+			hc->xfer_buff +=
+			    frame_desc->offset + qtd->isoc_split_offset;
+			hc->xfer_len =
+			    frame_desc->length - qtd->isoc_split_offset;
+
+			if (hc->xact_pos == DWC_HCSPLIT_XACTPOS_ALL) {
+				if (hc->xfer_len <= 188) {
+					hc->xact_pos = DWC_HCSPLIT_XACTPOS_ALL;
+				} else {
+					hc->xact_pos =
+					    DWC_HCSPLIT_XACTPOS_BEGIN;
+				}
+			}
+		}
+		break;
+	}
+
+	if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+	    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+		/*
+		 * This value may be modified when the transfer is started to
+		 * reflect the actual transfer length.
+		 */
+		hc->multi_count = dwc_hb_mult(_qh->maxp);
+	}
+
+	dwc_otg_hc_init(hcd->core_if, hc);
+	hc->qh = _qh;
+}
+
+/**
+ * This function selects transactions from the HCD transfer schedule and
+ * assigns them to available host channels. It is called from HCD interrupt
+ * handler functions.
+ *
+ * @hcd: The HCD state structure.
+ *
+ * Returns The types of new transactions that were assigned to host channels.
+ */
+enum dwc_otg_transaction_type dwc_otg_hcd_select_transactions(struct dwc_otg_hcd
+							   *hcd)
+{
+	struct list_head *qh_ptr;
+	struct dwc_otg_qh *qh;
+	int num_channels;
+	enum dwc_otg_transaction_type ret_val = DWC_OTG_TRANSACTION_NONE;
+
+#ifdef DEBUG_SOF
+	DWC_DEBUGPL(DBG_HCD, "  Select Transactions\n");
+#endif
+
+	/* Process entries in the periodic ready list. */
+	qh_ptr = hcd->periodic_sched_ready.next;
+	while (qh_ptr != &hcd->periodic_sched_ready &&
+	       !list_empty(&hcd->free_hc_list)) {
+
+		qh = list_entry(qh_ptr, struct dwc_otg_qh, qh_list_entry);
+		assign_and_init_hc(hcd, qh);
+
+		/*
+		 * Move the QH from the periodic ready schedule to the
+		 * periodic assigned schedule.
+		 */
+		qh_ptr = qh_ptr->next;
+		list_move(&qh->qh_list_entry, &hcd->periodic_sched_assigned);
+
+		ret_val = DWC_OTG_TRANSACTION_PERIODIC;
+	}
+
+	/*
+	 * Process entries in the inactive portion of the non-periodic
+	 * schedule. Some free host channels may not be used if they are
+	 * reserved for periodic transfers.
+	 */
+	qh_ptr = hcd->non_periodic_sched_inactive.next;
+	num_channels = hcd->core_if->core_params->host_channels;
+	while (qh_ptr != &hcd->non_periodic_sched_inactive &&
+	       (hcd->non_periodic_channels <
+		num_channels - hcd->periodic_channels) &&
+	       !list_empty(&hcd->free_hc_list)) {
+
+		qh = list_entry(qh_ptr, struct dwc_otg_qh, qh_list_entry);
+		assign_and_init_hc(hcd, qh);
+
+		/*
+		 * Move the QH from the non-periodic inactive schedule to the
+		 * non-periodic active schedule.
+		 */
+		qh_ptr = qh_ptr->next;
+		list_move(&qh->qh_list_entry, &hcd->non_periodic_sched_active);
+
+		if (ret_val == DWC_OTG_TRANSACTION_NONE)
+			ret_val = DWC_OTG_TRANSACTION_NON_PERIODIC;
+		else
+			ret_val = DWC_OTG_TRANSACTION_ALL;
+
+		hcd->non_periodic_channels++;
+	}
+
+	return ret_val;
+}
+
+/**
+ * Attempts to queue a single transaction request for a host channel
+ * associated with either a periodic or non-periodic transfer. This function
+ * assumes that there is space available in the appropriate request queue. For
+ * an OUT transfer or SETUP transaction in Slave mode, it checks whether space
+ * is available in the appropriate Tx FIFO.
+ *
+ * @hcd: The HCD state structure.
+ * @_hc: Host channel descriptor associated with either a periodic or
+ * non-periodic transfer.
+ * @_fifo_dwords_avail: Number of DWORDs available in the periodic Tx
+ * FIFO for periodic transfers or the non-periodic Tx FIFO for non-periodic
+ * transfers.
+ *
+ * Returns 1 if a request is queued and more requests may be needed to
+ * complete the transfer, 0 if no more requests are required for this
+ * transfer, -1 if there is insufficient space in the Tx FIFO.
+ */
+static int queue_transaction(struct dwc_otg_hcd *hcd,
+			     struct dwc_hc *_hc, uint16_t _fifo_dwords_avail)
+{
+	int retval;
+
+	if (hcd->core_if->dma_enable) {
+		if (!_hc->xfer_started) {
+			dwc_otg_hc_start_transfer(hcd->core_if, _hc);
+			_hc->qh->ping_state = 0;
+		}
+		retval = 0;
+	} else if (_hc->halt_pending) {
+		/* Don't queue a request if the channel has been halted. */
+		retval = 0;
+	} else if (_hc->halt_on_queue) {
+		dwc_otg_hc_halt(hcd->core_if, _hc, _hc->halt_status);
+		retval = 0;
+	} else if (_hc->do_ping) {
+		if (!_hc->xfer_started)
+			dwc_otg_hc_start_transfer(hcd->core_if, _hc);
+		retval = 0;
+	} else if (!_hc->ep_is_in ||
+		   _hc->data_pid_start == DWC_OTG_HC_PID_SETUP) {
+		if ((_fifo_dwords_avail * 4) >= _hc->max_packet) {
+			if (!_hc->xfer_started) {
+				dwc_otg_hc_start_transfer(hcd->core_if, _hc);
+				retval = 1;
+			} else {
+				retval =
+				    dwc_otg_hc_continue_transfer(hcd->core_if,
+								 _hc);
+			}
+		} else {
+			retval = -1;
+		}
+	} else {
+		if (!_hc->xfer_started) {
+			dwc_otg_hc_start_transfer(hcd->core_if, _hc);
+			retval = 1;
+		} else {
+			retval =
+			    dwc_otg_hc_continue_transfer(hcd->core_if, _hc);
+		}
+	}
+
+	return retval;
+}
+
+/**
+ * Processes active non-periodic channels and queues transactions for these
+ * channels to the DWC_otg controller. After queueing transactions, the NP Tx
+ * FIFO Empty interrupt is enabled if there are more transactions to queue as
+ * NP Tx FIFO or request queue space becomes available. Otherwise, the NP Tx
+ * FIFO Empty interrupt is disabled.
+ */
+static void process_non_periodic_channels(struct dwc_otg_hcd *hcd)
+{
+	union gnptxsts_data tx_status;
+	struct list_head *orig_qh_ptr;
+	struct dwc_otg_qh *qh;
+	int status;
+	int no_queue_space = 0;
+	int no_fifo_space = 0;
+	int more_to_do = 0;
+
+	struct dwc_otg_core_global_regs *global_regs =
+	    hcd->core_if->core_global_regs;
+
+	DWC_DEBUGPL(DBG_HCDV, "Queue non-periodic transactions\n");
+#ifdef DEBUG
+	tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts);
+	DWC_DEBUGPL(DBG_HCDV,
+		    "  NP Tx Req Queue Space Avail (before queue): %d\n",
+		    tx_status.b.nptxqspcavail);
+	DWC_DEBUGPL(DBG_HCDV, "  NP Tx FIFO Space Avail (before queue): %d\n",
+		    tx_status.b.nptxfspcavail);
+#endif
+	/*
+	 * Keep track of the starting point. Skip over the start-of-list
+	 * entry.
+	 */
+	if (hcd->non_periodic_qh_ptr == &hcd->non_periodic_sched_active)
+		hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
+
+	orig_qh_ptr = hcd->non_periodic_qh_ptr;
+
+	/*
+	 * Process once through the active list or until no more space is
+	 * available in the request queue or the Tx FIFO.
+	 */
+	do {
+		tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts);
+		if (!hcd->core_if->dma_enable
+		    && tx_status.b.nptxqspcavail == 0) {
+			no_queue_space = 1;
+			break;
+		}
+
+		qh = list_entry(hcd->non_periodic_qh_ptr, struct dwc_otg_qh,
+				qh_list_entry);
+		status =
+		    queue_transaction(hcd, qh->channel,
+				      tx_status.b.nptxfspcavail);
+
+		if (status > 0) {
+			more_to_do = 1;
+		} else if (status < 0) {
+			no_fifo_space = 1;
+			break;
+		}
+
+		/* Advance to next QH, skipping start-of-list entry. */
+		hcd->non_periodic_qh_ptr = hcd->non_periodic_qh_ptr->next;
+		if (hcd->non_periodic_qh_ptr ==
+		    &hcd->non_periodic_sched_active) {
+			hcd->non_periodic_qh_ptr =
+			    hcd->non_periodic_qh_ptr->next;
+		}
+
+	} while (hcd->non_periodic_qh_ptr != orig_qh_ptr);
+
+	if (!hcd->core_if->dma_enable) {
+		union gintmsk_data intr_mask = {.d32 = 0 };
+		intr_mask.b.nptxfempty = 1;
+
+#ifdef DEBUG
+		tx_status.d32 = dwc_read_reg32(&global_regs->gnptxsts);
+		DWC_DEBUGPL(DBG_HCDV,
+			    "  NP Tx Req Queue Space Avail (after queue): %d\n",
+			    tx_status.b.nptxqspcavail);
+		DWC_DEBUGPL(DBG_HCDV,
+			    "  NP Tx FIFO Space Avail (after queue): %d\n",
+			    tx_status.b.nptxfspcavail);
+#endif
+		if (no_queue_space || no_fifo_space) {
+			/*
+			 * May need to queue more transactions as the request
+			 * queue or Tx FIFO empties. Enable the non-periodic
+			 * Tx FIFO empty interrupt. (Always use the half-empty
+			 * level to ensure that new requests are loaded as
+			 * soon as possible.)
+			 */
+			dwc_modify_reg32(&global_regs->gintmsk, 0,
+					 intr_mask.d32);
+		} else {
+			/*
+			 * Disable the Tx FIFO empty interrupt since there are
+			 * no more transactions that need to be queued right
+			 * now. This function is called from interrupt
+			 * handlers to queue more transactions as transfer
+			 * states change.
+			 */
+			dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32,
+					 0);
+			if (more_to_do) {
+				/* When not using DMA, many USB
+				 * devices cause excessive loads on
+				 * the serial bus simply because they
+				 * continuously poll the device for
+				 * status. Here we use the timer to
+				 * rate limit how fast we can get the
+				 * the NP TX fifo empty interrupt. We
+				 * leave the interrupt disable until
+				 * the timer fires and reenables it */
+
+				/* We'll rate limit the interrupt at
+				 * 20000 per second. Making this
+				 * faster improves USB performance but
+				 * uses more CPU */
+				hrtimer_start_range_ns(&hcd->poll_rate_limit,
+						       ktime_set(0, 50000),
+						       5000, HRTIMER_MODE_REL);
+			}
+		}
+	}
+}
+
+/**
+ * Processes periodic channels for the next frame and queues transactions for
+ * these channels to the DWC_otg controller. After queueing transactions, the
+ * Periodic Tx FIFO Empty interrupt is enabled if there are more transactions
+ * to queue as Periodic Tx FIFO or request queue space becomes available.
+ * Otherwise, the Periodic Tx FIFO Empty interrupt is disabled.
+ */
+static void process_periodic_channels(struct dwc_otg_hcd *hcd)
+{
+	union hptxsts_data tx_status;
+	struct list_head *qh_ptr;
+	struct dwc_otg_qh *qh;
+	int status;
+	int no_queue_space = 0;
+	int no_fifo_space = 0;
+
+	struct dwc_otg_host_global_regs *host_regs;
+	host_regs = hcd->core_if->host_if->host_global_regs;
+
+	DWC_DEBUGPL(DBG_HCDV, "Queue periodic transactions\n");
+#ifdef DEBUG
+	tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts);
+	DWC_DEBUGPL(DBG_HCDV,
+		    "  P Tx Req Queue Space Avail (before queue): %d\n",
+		    tx_status.b.ptxqspcavail);
+	DWC_DEBUGPL(DBG_HCDV, "  P Tx FIFO Space Avail (before queue): %d\n",
+		    tx_status.b.ptxfspcavail);
+#endif
+
+	qh_ptr = hcd->periodic_sched_assigned.next;
+	while (qh_ptr != &hcd->periodic_sched_assigned) {
+		tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts);
+		if (tx_status.b.ptxqspcavail == 0) {
+			no_queue_space = 1;
+			break;
+		}
+
+		qh = list_entry(qh_ptr, struct dwc_otg_qh, qh_list_entry);
+
+		/*
+		 * Set a flag if we're queuing high-bandwidth in slave mode.
+		 * The flag prevents any halts to get into the request queue in
+		 * the middle of multiple high-bandwidth packets getting queued.
+		 */
+		if ((!hcd->core_if->dma_enable) &&
+		    (qh->channel->multi_count > 1)) {
+			hcd->core_if->queuing_high_bandwidth = 1;
+		}
+
+		status =
+		    queue_transaction(hcd, qh->channel,
+				      tx_status.b.ptxfspcavail);
+		if (status < 0) {
+			no_fifo_space = 1;
+			break;
+		}
+
+		/*
+		 * In Slave mode, stay on the current transfer until there is
+		 * nothing more to do or the high-bandwidth request count is
+		 * reached. In DMA mode, only need to queue one request. The
+		 * controller automatically handles multiple packets for
+		 * high-bandwidth transfers.
+		 */
+		if (hcd->core_if->dma_enable ||
+		    (status == 0 ||
+		     qh->channel->requests == qh->channel->multi_count)) {
+			qh_ptr = qh_ptr->next;
+			/*
+			 * Move the QH from the periodic assigned schedule to
+			 * the periodic queued schedule.
+			 */
+			list_move(&qh->qh_list_entry,
+				  &hcd->periodic_sched_queued);
+
+			/* done queuing high bandwidth */
+			hcd->core_if->queuing_high_bandwidth = 0;
+		}
+	}
+
+	if (!hcd->core_if->dma_enable) {
+		struct dwc_otg_core_global_regs *global_regs;
+		union gintmsk_data intr_mask = {.d32 = 0 };
+
+		global_regs = hcd->core_if->core_global_regs;
+		intr_mask.b.ptxfempty = 1;
+#ifdef DEBUG
+		tx_status.d32 = dwc_read_reg32(&host_regs->hptxsts);
+		DWC_DEBUGPL(DBG_HCDV,
+			    "  P Tx Req Queue Space Avail (after queue): %d\n",
+			    tx_status.b.ptxqspcavail);
+		DWC_DEBUGPL(DBG_HCDV,
+			    "  P Tx FIFO Space Avail (after queue): %d\n",
+			    tx_status.b.ptxfspcavail);
+#endif
+		if (!(list_empty(&hcd->periodic_sched_assigned)) ||
+		    no_queue_space || no_fifo_space) {
+			/*
+			 * May need to queue more transactions as the request
+			 * queue or Tx FIFO empties. Enable the periodic Tx
+			 * FIFO empty interrupt. (Always use the half-empty
+			 * level to ensure that new requests are loaded as
+			 * soon as possible.)
+			 */
+			dwc_modify_reg32(&global_regs->gintmsk, 0,
+					 intr_mask.d32);
+		} else {
+			/*
+			 * Disable the Tx FIFO empty interrupt since there are
+			 * no more transactions that need to be queued right
+			 * now. This function is called from interrupt
+			 * handlers to queue more transactions as transfer
+			 * states change.
+			 */
+			dwc_modify_reg32(&global_regs->gintmsk, intr_mask.d32,
+					 0);
+		}
+	}
+}
+
+/**
+ * This function processes the currently active host channels and queues
+ * transactions for these channels to the DWC_otg controller. It is called
+ * from HCD interrupt handler functions.
+ *
+ * @hcd: The HCD state structure.
+ * @_tr_type: The type(s) of transactions to queue (non-periodic,
+ * periodic, or both).
+ */
+void dwc_otg_hcd_queue_transactions(struct dwc_otg_hcd *hcd,
+				    enum dwc_otg_transaction_type _tr_type)
+{
+#ifdef DEBUG_SOF
+	DWC_DEBUGPL(DBG_HCD, "Queue Transactions\n");
+#endif
+	/* Process host channels associated with periodic transfers. */
+	if ((_tr_type == DWC_OTG_TRANSACTION_PERIODIC ||
+	     _tr_type == DWC_OTG_TRANSACTION_ALL) &&
+	    !list_empty(&hcd->periodic_sched_assigned)) {
+
+		process_periodic_channels(hcd);
+	}
+
+	/* Process host channels associated with non-periodic transfers. */
+	if ((_tr_type == DWC_OTG_TRANSACTION_NON_PERIODIC ||
+	     _tr_type == DWC_OTG_TRANSACTION_ALL)) {
+		if (!list_empty(&hcd->non_periodic_sched_active)) {
+			process_non_periodic_channels(hcd);
+		} else {
+			/*
+			 * Ensure NP Tx FIFO empty interrupt is disabled when
+			 * there are no non-periodic transfers to process.
+			 */
+			union gintmsk_data gintmsk = {.d32 = 0 };
+			gintmsk.b.nptxfempty = 1;
+			dwc_modify_reg32(&hcd->core_if->core_global_regs->
+					 gintmsk, gintmsk.d32, 0);
+		}
+	}
+}
+
+/**
+ * Sets the final status of an URB and returns it to the device driver. Any
+ * required cleanup of the URB is performed.
+ */
+void dwc_otg_hcd_complete_urb(struct dwc_otg_hcd *hcd, struct urb *urb,
+			      int status)
+{
+#ifdef DEBUG
+	if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
+		DWC_PRINT("%s: urb %p, device %d, ep %d %s, status=%d\n",
+			  __func__, urb, usb_pipedevice(urb->pipe),
+			  usb_pipeendpoint(urb->pipe),
+			  usb_pipein(urb->pipe) ? "IN" : "OUT", status);
+		if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+			int i;
+			for (i = 0; i < urb->number_of_packets; i++) {
+				DWC_PRINT("  ISO Desc %d status: %d\n",
+					  i, urb->iso_frame_desc[i].status);
+			}
+		}
+	}
+#endif
+
+	urb->status = status;
+	urb->hcpriv = NULL;
+
+	usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status);
+}
+
+/*
+ * Returns the Queue Head for an URB.
+ */
+struct dwc_otg_qh *dwc_urb_to_qh(struct urb *urb)
+{
+	struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
+	return ep->hcpriv;
+}
+
+#ifdef DEBUG
+void dwc_print_setup_data(uint8_t *setup)
+{
+	int i;
+	if (CHK_DEBUG_LEVEL(DBG_HCD)) {
+		DWC_PRINT("Setup Data = MSB ");
+		for (i = 7; i >= 0; i--)
+			DWC_PRINT("%02x ", setup[i]);
+		DWC_PRINT("\n");
+		DWC_PRINT("  bmRequestType Tranfer = %s\n",
+			  (setup[0] & 0x80) ? "Device-to-Host" :
+			  "Host-to-Device");
+		DWC_PRINT("  bmRequestType Type = ");
+		switch ((setup[0] & 0x60) >> 5) {
+		case 0:
+			DWC_PRINT("Standard\n");
+			break;
+		case 1:
+			DWC_PRINT("Class\n");
+			break;
+		case 2:
+			DWC_PRINT("Vendor\n");
+			break;
+		case 3:
+			DWC_PRINT("Reserved\n");
+			break;
+		}
+		DWC_PRINT("  bmRequestType Recipient = ");
+		switch (setup[0] & 0x1f) {
+		case 0:
+			DWC_PRINT("Device\n");
+			break;
+		case 1:
+			DWC_PRINT("Interface\n");
+			break;
+		case 2:
+			DWC_PRINT("Endpoint\n");
+			break;
+		case 3:
+			DWC_PRINT("Other\n");
+			break;
+		default:
+			DWC_PRINT("Reserved\n");
+			break;
+		}
+		DWC_PRINT("  bRequest = 0x%0x\n", setup[1]);
+		DWC_PRINT("  wValue = 0x%0x\n", *((uint16_t *) &setup[2]));
+		DWC_PRINT("  wIndex = 0x%0x\n", *((uint16_t *) &setup[4]));
+		DWC_PRINT("  wLength = 0x%0x\n\n", *((uint16_t *) &setup[6]));
+	}
+}
+#endif
+
+void dwc_otg_hcd_dump_frrem(struct dwc_otg_hcd *hcd)
+{
+#ifdef DEBUG
+	DWC_PRINT("Frame remaining at SOF:\n");
+	DWC_PRINT("  samples %u, accum %lu, avg %lu\n",
+		  hcd->frrem_samples, hcd->frrem_accum,
+		  (hcd->frrem_samples > 0) ?
+		  hcd->frrem_accum / hcd->frrem_samples : 0);
+
+	DWC_PRINT("\n");
+	DWC_PRINT("Frame remaining at start_transfer (uframe 7):\n");
+	DWC_PRINT("  samples %u, accum %lu, avg %lu\n",
+		  hcd->core_if->hfnum_7_samples,
+		  hcd->core_if->hfnum_7_frrem_accum,
+		  (hcd->core_if->hfnum_7_samples >
+		   0) ? hcd->core_if->hfnum_7_frrem_accum /
+		  hcd->core_if->hfnum_7_samples : 0);
+	DWC_PRINT("Frame remaining at start_transfer (uframe 0):\n");
+	DWC_PRINT("  samples %u, accum %lu, avg %lu\n",
+		  hcd->core_if->hfnum_0_samples,
+		  hcd->core_if->hfnum_0_frrem_accum,
+		  (hcd->core_if->hfnum_0_samples >
+		   0) ? hcd->core_if->hfnum_0_frrem_accum /
+		  hcd->core_if->hfnum_0_samples : 0);
+	DWC_PRINT("Frame remaining at start_transfer (uframe 1-6):\n");
+	DWC_PRINT("  samples %u, accum %lu, avg %lu\n",
+		  hcd->core_if->hfnum_other_samples,
+		  hcd->core_if->hfnum_other_frrem_accum,
+		  (hcd->core_if->hfnum_other_samples >
+		   0) ? hcd->core_if->hfnum_other_frrem_accum /
+		  hcd->core_if->hfnum_other_samples : 0);
+
+	DWC_PRINT("\n");
+	DWC_PRINT("Frame remaining at sample point A (uframe 7):\n");
+	DWC_PRINT("  samples %u, accum %lu, avg %lu\n",
+		  hcd->hfnum_7_samples_a, hcd->hfnum_7_frrem_accum_a,
+		  (hcd->hfnum_7_samples_a > 0) ?
+		  hcd->hfnum_7_frrem_accum_a / hcd->hfnum_7_samples_a : 0);
+	DWC_PRINT("Frame remaining at sample point A (uframe 0):\n");
+	DWC_PRINT("  samples %u, accum %lu, avg %lu\n",
+		  hcd->hfnum_0_samples_a, hcd->hfnum_0_frrem_accum_a,
+		  (hcd->hfnum_0_samples_a > 0) ?
+		  hcd->hfnum_0_frrem_accum_a / hcd->hfnum_0_samples_a : 0);
+	DWC_PRINT("Frame remaining at sample point A (uframe 1-6):\n");
+	DWC_PRINT("  samples %u, accum %lu, avg %lu\n",
+		  hcd->hfnum_other_samples_a, hcd->hfnum_other_frrem_accum_a,
+		  (hcd->hfnum_other_samples_a > 0) ?
+		  hcd->hfnum_other_frrem_accum_a /
+		  hcd->hfnum_other_samples_a : 0);
+
+	DWC_PRINT("\n");
+	DWC_PRINT("Frame remaining at sample point B (uframe 7):\n");
+	DWC_PRINT("  samples %u, accum %lu, avg %lu\n",
+		  hcd->hfnum_7_samples_b, hcd->hfnum_7_frrem_accum_b,
+		  (hcd->hfnum_7_samples_b > 0) ?
+		  hcd->hfnum_7_frrem_accum_b / hcd->hfnum_7_samples_b : 0);
+	DWC_PRINT("Frame remaining at sample point B (uframe 0):\n");
+	DWC_PRINT("  samples %u, accum %lu, avg %lu\n",
+		  hcd->hfnum_0_samples_b, hcd->hfnum_0_frrem_accum_b,
+		  (hcd->hfnum_0_samples_b > 0) ?
+		  hcd->hfnum_0_frrem_accum_b / hcd->hfnum_0_samples_b : 0);
+	DWC_PRINT("Frame remaining at sample point B (uframe 1-6):\n");
+	DWC_PRINT("  samples %u, accum %lu, avg %lu\n",
+		  hcd->hfnum_other_samples_b, hcd->hfnum_other_frrem_accum_b,
+		  (hcd->hfnum_other_samples_b > 0) ?
+		  hcd->hfnum_other_frrem_accum_b /
+		  hcd->hfnum_other_samples_b : 0);
+#endif
+}
+
+void dwc_otg_hcd_dump_state(struct dwc_otg_hcd *hcd)
+{
+#ifdef DEBUG
+	int num_channels;
+	int i;
+	union gnptxsts_data np_tx_status;
+	union hptxsts_data p_tx_status;
+
+	num_channels = hcd->core_if->core_params->host_channels;
+	DWC_PRINT("\n");
+	DWC_PRINT
+	    ("************************************************************\n");
+	DWC_PRINT("HCD State:\n");
+	DWC_PRINT("  Num channels: %d\n", num_channels);
+	for (i = 0; i < num_channels; i++) {
+		struct dwc_hc *hc = hcd->hc_ptr_array[i];
+		DWC_PRINT("  Channel %d:\n", i);
+		DWC_PRINT("    dev_addr: %d, ep_num: %d, ep_is_in: %d\n",
+			  hc->dev_addr, hc->ep_num, hc->ep_is_in);
+		DWC_PRINT("    speed: %d\n", hc->speed);
+		DWC_PRINT("    ep_type: %d\n", hc->ep_type);
+		DWC_PRINT("    max_packet: %d\n", hc->max_packet);
+		DWC_PRINT("    data_pid_start: %d\n", hc->data_pid_start);
+		DWC_PRINT("    multi_count: %d\n", hc->multi_count);
+		DWC_PRINT("    xfer_started: %d\n", hc->xfer_started);
+		DWC_PRINT("    xfer_buff: %p\n", hc->xfer_buff);
+		DWC_PRINT("    xfer_len: %d\n", hc->xfer_len);
+		DWC_PRINT("    xfer_count: %d\n", hc->xfer_count);
+		DWC_PRINT("    halt_on_queue: %d\n", hc->halt_on_queue);
+		DWC_PRINT("    halt_pending: %d\n", hc->halt_pending);
+		DWC_PRINT("    halt_status: %d\n", hc->halt_status);
+		DWC_PRINT("    do_split: %d\n", hc->do_split);
+		DWC_PRINT("    complete_split: %d\n", hc->complete_split);
+		DWC_PRINT("    hub_addr: %d\n", hc->hub_addr);
+		DWC_PRINT("    port_addr: %d\n", hc->port_addr);
+		DWC_PRINT("    xact_pos: %d\n", hc->xact_pos);
+		DWC_PRINT("    requests: %d\n", hc->requests);
+		DWC_PRINT("    qh: %p\n", hc->qh);
+		if (hc->xfer_started) {
+			union hfnum_data hfnum;
+			union hcchar_data hcchar;
+			union hctsiz_data hctsiz;
+			union hcint_data hcint;
+			union hcintmsk_data hcintmsk;
+			hfnum.d32 =
+			    dwc_read_reg32(&hcd->core_if->host_if->
+					   host_global_regs->hfnum);
+			hcchar.d32 =
+			    dwc_read_reg32(&hcd->core_if->host_if->hc_regs[i]->
+					   hcchar);
+			hctsiz.d32 =
+			    dwc_read_reg32(&hcd->core_if->host_if->hc_regs[i]->
+					   hctsiz);
+			hcint.d32 =
+			    dwc_read_reg32(&hcd->core_if->host_if->hc_regs[i]->
+					   hcint);
+			hcintmsk.d32 =
+			    dwc_read_reg32(&hcd->core_if->host_if->hc_regs[i]->
+					   hcintmsk);
+			DWC_PRINT("    hfnum: 0x%08x\n", hfnum.d32);
+			DWC_PRINT("    hcchar: 0x%08x\n", hcchar.d32);
+			DWC_PRINT("    hctsiz: 0x%08x\n", hctsiz.d32);
+			DWC_PRINT("    hcint: 0x%08x\n", hcint.d32);
+			DWC_PRINT("    hcintmsk: 0x%08x\n", hcintmsk.d32);
+		}
+		if (hc->xfer_started && (hc->qh != NULL)
+		    && (hc->qh->qtd_in_process != NULL)) {
+			struct dwc_otg_qtd *qtd;
+			struct urb *urb;
+			qtd = hc->qh->qtd_in_process;
+			urb = qtd->urb;
+			DWC_PRINT("    URB Info:\n");
+			DWC_PRINT("      qtd: %p, urb: %p\n", qtd, urb);
+			if (urb != NULL) {
+				DWC_PRINT("      Dev: %d, EP: %d %s\n",
+					  usb_pipedevice(urb->pipe),
+					  usb_pipeendpoint(urb->pipe),
+					  usb_pipein(urb->pipe) ? "IN" : "OUT");
+				DWC_PRINT("      Max packet size: %d\n",
+					  usb_maxpacket(urb->dev, urb->pipe,
+							usb_pipeout(urb->
+								    pipe)));
+				DWC_PRINT("      transfer_buffer: %p\n",
+					  urb->transfer_buffer);
+				DWC_PRINT("      transfer_dma: %p\n",
+					  (void *)urb->transfer_dma);
+				DWC_PRINT("      transfer_buffer_length: %d\n",
+					  urb->transfer_buffer_length);
+				DWC_PRINT("      actual_length: %d\n",
+					  urb->actual_length);
+			}
+		}
+	}
+	DWC_PRINT("  non_periodic_channels: %d\n", hcd->non_periodic_channels);
+	DWC_PRINT("  periodic_channels: %d\n", hcd->periodic_channels);
+	DWC_PRINT("  periodic_usecs: %d\n", hcd->periodic_usecs);
+	np_tx_status.d32 =
+	    dwc_read_reg32(&hcd->core_if->core_global_regs->gnptxsts);
+	DWC_PRINT("  NP Tx Req Queue Space Avail: %d\n",
+		  np_tx_status.b.nptxqspcavail);
+	DWC_PRINT("  NP Tx FIFO Space Avail: %d\n",
+		  np_tx_status.b.nptxfspcavail);
+	p_tx_status.d32 =
+	    dwc_read_reg32(&hcd->core_if->host_if->host_global_regs->hptxsts);
+	DWC_PRINT("  P Tx Req Queue Space Avail: %d\n",
+		  p_tx_status.b.ptxqspcavail);
+	DWC_PRINT("  P Tx FIFO Space Avail: %d\n", p_tx_status.b.ptxfspcavail);
+	dwc_otg_hcd_dump_frrem(hcd);
+	dwc_otg_dump_global_registers(hcd->core_if);
+	dwc_otg_dump_host_registers(hcd->core_if);
+	DWC_PRINT
+	    ("************************************************************\n");
+	DWC_PRINT("\n");
+#endif
+}
+#endif /* DWC_DEVICE_ONLY */
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd.h b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
new file mode 100644
index 0000000..6dcf1f5
--- /dev/null
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd.h
@@ -0,0 +1,661 @@
+/* ==========================================================================
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+#ifndef DWC_DEVICE_ONLY
+#if !defined(__DWC_HCD_H__)
+#define __DWC_HCD_H__
+
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/hrtimer.h>
+
+#include <../drivers/usb/core/hcd.h>
+
+struct dwc_otg_device;
+
+#include "dwc_otg_cil.h"
+
+/**
+ *
+ * This file contains the structures, constants, and interfaces for
+ * the Host Contoller Driver (HCD).
+ *
+ * The Host Controller Driver (HCD) is responsible for translating requests
+ * from the USB Driver into the appropriate actions on the DWC_otg controller.
+ * It isolates the USBD from the specifics of the controller by providing an
+ * API to the USBD.
+ */
+
+/**
+ * Phases for control transfers.
+ */
+enum dwc_otg_control_phase {
+	DWC_OTG_CONTROL_SETUP,
+	DWC_OTG_CONTROL_DATA,
+	DWC_OTG_CONTROL_STATUS
+};
+
+/** Transaction types. */
+enum dwc_otg_transaction_type {
+	DWC_OTG_TRANSACTION_NONE,
+	DWC_OTG_TRANSACTION_PERIODIC,
+	DWC_OTG_TRANSACTION_NON_PERIODIC,
+	DWC_OTG_TRANSACTION_ALL
+};
+
+struct dwc_otg_qh;
+
+/*
+ * A Queue Transfer Descriptor (QTD) holds the state of a bulk, control,
+ * interrupt, or isochronous transfer. A single QTD is created for each URB
+ * (of one of these types) submitted to the HCD. The transfer associated with
+ * a QTD may require one or multiple transactions.
+ *
+ * A QTD is linked to a Queue Head, which is entered in either the
+ * non-periodic or periodic schedule for execution. When a QTD is chosen for
+ * execution, some or all of its transactions may be executed. After
+ * execution, the state of the QTD is updated. The QTD may be retired if all
+ * its transactions are complete or if an error occurred. Otherwise, it
+ * remains in the schedule so more transactions can be executed later.
+ */
+struct dwc_otg_qtd {
+	/*
+	 * Determines the PID of the next data packet for the data phase of
+	 * control transfers. Ignored for other transfer types.<br>
+	 * One of the following values:
+	 *	- DWC_OTG_HC_PID_DATA0
+	 *	- DWC_OTG_HC_PID_DATA1
+	 */
+	uint8_t data_toggle;
+
+	/** Current phase for control transfers (Setup, Data, or Status). */
+	enum dwc_otg_control_phase control_phase;
+
+	/** Keep track of the current split type
+	 * for FS/LS endpoints on a HS Hub */
+	uint8_t complete_split;
+
+	/** How many bytes transferred during SSPLIT OUT */
+	uint32_t ssplit_out_xfer_count;
+
+	/**
+	 * Holds the number of bus errors that have occurred for a transaction
+	 * within this transfer.
+	 */
+	uint8_t error_count;
+
+	/**
+	 * Index of the next frame descriptor for an isochronous transfer. A
+	 * frame descriptor describes the buffer position and length of the
+	 * data to be transferred in the next scheduled (micro)frame of an
+	 * isochronous transfer. It also holds status for that transaction.
+	 * The frame index starts at 0.
+	 */
+	int isoc_frame_index;
+
+	/** Position of the ISOC split on full/low speed */
+	uint8_t isoc_split_pos;
+
+	/** Position of the ISOC split in the buffer for the current frame */
+	uint16_t isoc_split_offset;
+
+	/** URB for this transfer */
+	struct urb *urb;
+
+	/* The queue head for this transfer. */
+	struct dwc_otg_qh *qh;
+
+	/** This list of QTDs */
+	struct list_head qtd_list_entry;
+
+};
+
+/**
+ * A Queue Head (QH) holds the static characteristics of an endpoint and
+ * maintains a list of transfers (QTDs) for that endpoint. A QH structure may
+ * be entered in either the non-periodic or periodic schedule.
+ */
+struct dwc_otg_qh {
+	/**
+	 * Endpoint type.
+	 * One of the following values:
+	 * 	- USB_ENDPOINT_XFER_CONTROL
+	 *	- USB_ENDPOINT_XFER_ISOC
+	 *	- USB_ENDPOINT_XFER_BULK
+	 *	- USB_ENDPOINT_XFER_INT
+	 */
+	uint8_t ep_type;
+	uint8_t ep_is_in;
+
+	/** wMaxPacketSize Field of Endpoint Descriptor. */
+	uint16_t maxp;
+
+	/**
+	 * Determines the PID of the next data packet for non-control
+	 * transfers. Ignored for control transfers.<br>
+	 * One of the following values:
+	 *	- DWC_OTG_HC_PID_DATA0
+	 * 	- DWC_OTG_HC_PID_DATA1
+	 */
+	uint8_t data_toggle;
+
+	/** Ping state if 1. */
+	uint8_t ping_state;
+
+	/**
+	 * List of QTDs for this QH.
+	 */
+	struct list_head qtd_list;
+
+	/** Host channel currently processing transfers for this QH. */
+	struct dwc_hc *channel;
+
+	/** QTD currently assigned to a host channel for this QH. */
+	struct dwc_otg_qtd *qtd_in_process;
+
+	/** Full/low speed endpoint on high-speed hub requires split. */
+	uint8_t do_split;
+
+	/** @name Periodic schedule information */
+	/** @{ */
+
+	/** Bandwidth in microseconds per (micro)frame. */
+	uint8_t usecs;
+
+	/** Interval between transfers in (micro)frames. */
+	uint16_t interval;
+
+	/**
+	 * (micro)frame to initialize a periodic transfer. The transfer
+	 * executes in the following (micro)frame.
+	 */
+	uint16_t sched_frame;
+
+	/** (micro)frame at which last start split was initialized. */
+	uint16_t start_split_frame;
+
+	/** @} */
+
+	/** Entry for QH in either the periodic or non-periodic schedule. */
+	struct list_head qh_list_entry;
+};
+
+/**
+ * This structure holds the state of the HCD, including the non-periodic and
+ * periodic schedules.
+ */
+struct dwc_otg_hcd {
+
+	/** DWC OTG Core Interface Layer */
+	struct dwc_otg_core_if *core_if;
+
+	/** Internal DWC HCD Flags */
+	union dwc_otg_hcd_internal_flags {
+		uint32_t d32;
+		struct {
+#ifdef __BIG_ENDIAN_BITFIELD
+			unsigned reserved:26;
+			unsigned port_over_current_change:1;
+			unsigned port_suspend_change:1;
+			unsigned port_enable_change:1;
+			unsigned port_reset_change:1;
+			unsigned port_connect_status:1;
+			unsigned port_connect_status_change:1;
+#else
+			unsigned port_connect_status_change:1;
+			unsigned port_connect_status:1;
+			unsigned port_reset_change:1;
+			unsigned port_enable_change:1;
+			unsigned port_suspend_change:1;
+			unsigned port_over_current_change:1;
+			unsigned reserved:26;
+#endif
+		} b;
+	} flags;
+
+	/**
+	 * Inactive items in the non-periodic schedule. This is a list of
+	 * Queue Heads. Transfers associated with these Queue Heads are not
+	 * currently assigned to a host channel.
+	 */
+	struct list_head non_periodic_sched_inactive;
+
+	/**
+	 * Active items in the non-periodic schedule. This is a list of
+	 * Queue Heads. Transfers associated with these Queue Heads are
+	 * currently assigned to a host channel.
+	 */
+	struct list_head non_periodic_sched_active;
+
+	/**
+	 * Pointer to the next Queue Head to process in the active
+	 * non-periodic schedule.
+	 */
+	struct list_head *non_periodic_qh_ptr;
+
+	/**
+	 * Inactive items in the periodic schedule. This is a list of QHs for
+	 * periodic transfers that are _not_ scheduled for the next frame.
+	 * Each QH in the list has an interval counter that determines when it
+	 * needs to be scheduled for execution. This scheduling mechanism
+	 * allows only a simple calculation for periodic bandwidth used (i.e.
+	 * must assume that all periodic transfers may need to execute in the
+	 * same frame). However, it greatly simplifies scheduling and should
+	 * be sufficient for the vast majority of OTG hosts, which need to
+	 * connect to a small number of peripherals at one time.
+	 *
+	 * Items move from this list to periodic_sched_ready when the QH
+	 * interval counter is 0 at SOF.
+	 */
+	struct list_head periodic_sched_inactive;
+
+	/**
+	 * List of periodic QHs that are ready for execution in the next
+	 * frame, but have not yet been assigned to host channels.
+	 *
+	 * Items move from this list to periodic_sched_assigned as host
+	 * channels become available during the current frame.
+	 */
+	struct list_head periodic_sched_ready;
+
+	/**
+	 * List of periodic QHs to be executed in the next frame that are
+	 * assigned to host channels.
+	 *
+	 * Items move from this list to periodic_sched_queued as the
+	 * transactions for the QH are queued to the DWC_otg controller.
+	 */
+	struct list_head periodic_sched_assigned;
+
+	/**
+	 * List of periodic QHs that have been queued for execution.
+	 *
+	 * Items move from this list to either periodic_sched_inactive or
+	 * periodic_sched_ready when the channel associated with the transfer
+	 * is released. If the interval for the QH is 1, the item moves to
+	 * periodic_sched_ready because it must be rescheduled for the next
+	 * frame. Otherwise, the item moves to periodic_sched_inactive.
+	 */
+	struct list_head periodic_sched_queued;
+
+	/**
+	 * Total bandwidth claimed so far for periodic transfers. This value
+	 * is in microseconds per (micro)frame. The assumption is that all
+	 * periodic transfers may occur in the same (micro)frame.
+	 */
+	uint16_t periodic_usecs;
+
+	/**
+	 * Frame number read from the core at SOF. The value ranges from 0 to
+	 * DWC_HFNUM_MAX_FRNUM.
+	 */
+	uint16_t frame_number;
+
+	/**
+	 * Free host channels in the controller. This is a list of
+	 * struct dwc_hc items.
+	 */
+	struct list_head free_hc_list;
+
+	/**
+	 * Number of host channels assigned to periodic transfers. Currently
+	 * assuming that there is a dedicated host channel for each periodic
+	 * transaction and at least one host channel available for
+	 * non-periodic transactions.
+	 */
+	int periodic_channels;
+
+	/**
+	 * Number of host channels assigned to non-periodic transfers.
+	 */
+	int non_periodic_channels;
+
+	/**
+	 * Array of pointers to the host channel descriptors. Allows accessing
+	 * a host channel descriptor given the host channel number. This is
+	 * useful in interrupt handlers.
+	 */
+	struct dwc_hc *hc_ptr_array[MAX_EPS_CHANNELS];
+
+	/**
+	 * Buffer to use for any data received during the status phase of a
+	 * control transfer. Normally no data is transferred during the status
+	 * phase. This buffer is used as a bit bucket.
+	 */
+	uint8_t *status_buf;
+
+	/**
+	 * DMA address for status_buf.
+	 */
+	dma_addr_t status_buf_dma;
+#define DWC_OTG_HCD_STATUS_BUF_SIZE 64
+
+	/**
+	 * Structure to allow starting the HCD in a non-interrupt context
+	 * during an OTG role change.
+	 */
+	struct work_struct start_work;
+
+	/**
+	 * Connection timer. An OTG host must display a message if the device
+	 * does not connect. Started when the VBus power is turned on via
+	 * sysfs attribute "buspower".
+	 */
+	struct timer_list conn_timer;
+
+	/* Tasket to do a reset */
+	struct tasklet_struct *reset_tasklet;
+
+	struct hrtimer poll_rate_limit;
+
+	spinlock_t global_lock;
+
+#ifdef DEBUG
+	uint32_t frrem_samples;
+	uint64_t frrem_accum;
+
+	uint32_t hfnum_7_samples_a;
+	uint64_t hfnum_7_frrem_accum_a;
+	uint32_t hfnum_0_samples_a;
+	uint64_t hfnum_0_frrem_accum_a;
+	uint32_t hfnum_other_samples_a;
+	uint64_t hfnum_other_frrem_accum_a;
+
+	uint32_t hfnum_7_samples_b;
+	uint64_t hfnum_7_frrem_accum_b;
+	uint32_t hfnum_0_samples_b;
+	uint64_t hfnum_0_frrem_accum_b;
+	uint32_t hfnum_other_samples_b;
+	uint64_t hfnum_other_frrem_accum_b;
+#endif
+
+};
+
+/** Gets the dwc_otg_hcd from a struct usb_hcd */
+static inline struct dwc_otg_hcd *hcd_to_dwc_otg_hcd(struct usb_hcd *hcd)
+{
+	return (struct dwc_otg_hcd *)(hcd->hcd_priv);
+}
+
+/** Gets the struct usb_hcd that contains a struct dwc_otg_hcd. */
+static inline struct usb_hcd *dwc_otg_hcd_to_hcd(struct dwc_otg_hcd
+						 *dwc_otg_hcd)
+{
+	return container_of((void *)dwc_otg_hcd, struct usb_hcd, hcd_priv);
+}
+
+/** @name HCD Create/Destroy Functions */
+/** @{ */
+extern int __init dwc_otg_hcd_init(struct device *_dev);
+extern void dwc_otg_hcd_remove(struct device *_dev);
+/** @} */
+
+/** @name Linux HC Driver API Functions */
+
+extern int dwc_otg_hcd_start(struct usb_hcd *hcd);
+extern void dwc_otg_hcd_stop(struct usb_hcd *hcd);
+extern int dwc_otg_hcd_get_frame_number(struct usb_hcd *hcd);
+extern void dwc_otg_hcd_free(struct usb_hcd *hcd);
+extern int dwc_otg_hcd_urb_enqueue(struct usb_hcd *hcd,
+				   struct urb *urb, unsigned mem_flags);
+extern int dwc_otg_hcd_urb_dequeue(struct usb_hcd *hcd,
+				   struct urb *urb, int status);
+extern void dwc_otg_hcd_endpoint_disable(struct usb_hcd *hcd,
+					 struct usb_host_endpoint *ep);
+extern irqreturn_t dwc_otg_hcd_irq(struct usb_hcd *hcd);
+extern int dwc_otg_hcd_hub_status_data(struct usb_hcd *hcd, char *buf);
+extern int dwc_otg_hcd_hub_control(struct usb_hcd *hcd,
+				   u16 typeReq,
+				   u16 wValue,
+				   u16 wIndex, char *buf, u16 wLength);
+
+
+/** @name Transaction Execution Functions */
+extern enum dwc_otg_transaction_type dwc_otg_hcd_select_transactions(struct
+								  dwc_otg_hcd
+								  *hcd);
+extern void dwc_otg_hcd_queue_transactions(struct dwc_otg_hcd *hcd,
+					   enum dwc_otg_transaction_type tr_type);
+extern void dwc_otg_hcd_complete_urb(struct dwc_otg_hcd *hcd, struct urb *urb,
+				     int status);
+
+/** @name Interrupt Handler Functions */
+extern int32_t dwc_otg_hcd_handle_intr(struct dwc_otg_hcd *dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_sof_intr(struct dwc_otg_hcd *dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_rx_status_q_level_intr(struct dwc_otg_hcd
+							 *dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(struct dwc_otg_hcd
+							*dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(struct dwc_otg_hcd
+							   *dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_incomplete_periodic_intr(struct dwc_otg_hcd
+							   *dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_port_intr(struct dwc_otg_hcd *dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_conn_id_status_change_intr(struct dwc_otg_hcd
+							     *dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_disconnect_intr(struct dwc_otg_hcd
+						  *dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_hc_intr(struct dwc_otg_hcd *dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_hc_n_intr(struct dwc_otg_hcd *dwc_otg_hcd,
+					    uint32_t num);
+extern int32_t dwc_otg_hcd_handle_session_req_intr(struct dwc_otg_hcd
+						   *dwc_otg_hcd);
+extern int32_t dwc_otg_hcd_handle_wakeup_detected_intr(struct dwc_otg_hcd
+						       *dwc_otg_hcd);
+
+/** @name Schedule Queue Functions */
+
+/* Implemented in dwc_otg_hcd_queue.c */
+extern struct dwc_otg_qh *dwc_otg_hcd_qh_create(struct dwc_otg_hcd *hcd,
+					   struct urb *urb);
+extern void dwc_otg_hcd_qh_init(struct dwc_otg_hcd *hcd, struct dwc_otg_qh *qh,
+				struct urb *urb);
+extern void dwc_otg_hcd_qh_free(struct dwc_otg_qh *qh);
+extern int dwc_otg_hcd_qh_add(struct dwc_otg_hcd *hcd, struct dwc_otg_qh *qh);
+extern void dwc_otg_hcd_qh_remove(struct dwc_otg_hcd *hcd, struct dwc_otg_qh *qh);
+extern void dwc_otg_hcd_qh_deactivate(struct dwc_otg_hcd *hcd,
+				      struct dwc_otg_qh *qh, int sched_csplit);
+
+/** Remove and free a QH */
+static inline void dwc_otg_hcd_qh_remove_and_free(struct dwc_otg_hcd *hcd,
+						  struct dwc_otg_qh *qh)
+{
+	dwc_otg_hcd_qh_remove(hcd, qh);
+	dwc_otg_hcd_qh_free(qh);
+}
+
+/** Allocates memory for a QH structure.
+ * Returns Returns the memory allocate or NULL on error. */
+static inline struct dwc_otg_qh *dwc_otg_hcd_qh_alloc(void)
+{
+	return kmalloc(sizeof(struct dwc_otg_qh), GFP_ATOMIC);
+}
+
+extern struct dwc_otg_qtd *dwc_otg_hcd_qtd_create(struct urb *urb);
+extern void dwc_otg_hcd_qtd_init(struct dwc_otg_qtd *qtd, struct urb *urb);
+extern int dwc_otg_hcd_qtd_add(struct dwc_otg_qtd *qtd,
+			       struct dwc_otg_hcd *dwc_otg_hcd);
+
+/** Allocates memory for a QTD structure.
+ * Returns Returns the memory allocate or NULL on error. */
+static inline struct dwc_otg_qtd *dwc_otg_hcd_qtd_alloc(void)
+{
+	return kmalloc(sizeof(struct dwc_otg_qtd), GFP_ATOMIC);
+}
+
+/**
+ * Frees the memory for a QTD structure.  QTD should already be removed from
+ * list.
+ * @qtd: QTD to free.
+ */
+static inline void dwc_otg_hcd_qtd_free(struct dwc_otg_qtd *qtd)
+{
+	kfree(qtd);
+}
+
+/**
+ * Removes a QTD from list.
+ * @qtd: QTD to remove from list.
+ */
+static inline void dwc_otg_hcd_qtd_remove(struct dwc_otg_qtd *qtd)
+{
+	list_del(&qtd->qtd_list_entry);
+}
+
+/** Remove and free a QTD */
+static inline void dwc_otg_hcd_qtd_remove_and_free(struct dwc_otg_qtd *qtd)
+{
+	dwc_otg_hcd_qtd_remove(qtd);
+	dwc_otg_hcd_qtd_free(qtd);
+}
+
+/** @name Internal Functions */
+struct dwc_otg_qh *dwc_urb_to_qh(struct urb *urb);
+void dwc_otg_hcd_dump_frrem(struct dwc_otg_hcd *hcd);
+void dwc_otg_hcd_dump_state(struct dwc_otg_hcd *hcd);
+
+/** Gets the usb_host_endpoint associated with an URB. */
+static inline struct usb_host_endpoint *dwc_urb_to_endpoint(struct urb *urb)
+{
+	struct usb_device *dev = urb->dev;
+	int ep_num = usb_pipeendpoint(urb->pipe);
+
+	if (usb_pipein(urb->pipe))
+		return dev->ep_in[ep_num];
+	else
+		return dev->ep_out[ep_num];
+}
+
+/*
+ * Gets the endpoint number from a bEndpointAddress argument. The endpoint is
+ * qualified with its direction (possible 32 endpoints per device).
+ */
+#define dwc_ep_addr_to_endpoint(_bEndpointAddress_)	\
+	((_bEndpointAddress_ & USB_ENDPOINT_NUMBER_MASK) |		\
+		((_bEndpointAddress_ & USB_DIR_IN) != 0) << 4)
+
+/** Gets the QH that contains the list_head */
+#define dwc_list_to_qh(_list_head_ptr_)					\
+	(container_of(_list_head_ptr_, struct dwc_otg_qh, qh_list_entry))
+
+/** Gets the QTD that contains the list_head */
+#define dwc_list_to_qtd(_list_head_ptr_)				\
+	(container_of(_list_head_ptr_, struct dwc_otg_qtd, qtd_list_entry))
+
+/** Check if QH is non-periodic  */
+#define dwc_qh_is_non_per(_qh_ptr_)					\
+	((_qh_ptr_->ep_type == USB_ENDPOINT_XFER_BULK) ||		\
+		(_qh_ptr_->ep_type == USB_ENDPOINT_XFER_CONTROL))
+
+/** High bandwidth multiplier as encoded in highspeed endpoint descriptors */
+#define dwc_hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+
+/** Packet size for any kind of endpoint descriptor */
+#define dwc_max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+
+/**
+ * Returns true if frame1 is less than or equal to frame2. The comparison is
+ * done modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the
+ * frame number when the max frame number is reached.
+ */
+static inline int dwc_frame_num_le(uint16_t frame1, uint16_t frame2)
+{
+	return ((frame2 - frame1) & DWC_HFNUM_MAX_FRNUM) <=
+	    (DWC_HFNUM_MAX_FRNUM >> 1);
+}
+
+/**
+ * Returns true if frame1 is greater than frame2. The comparison is done
+ * modulo DWC_HFNUM_MAX_FRNUM. This accounts for the rollover of the frame
+ * number when the max frame number is reached.
+ */
+static inline int dwc_frame_num_gt(uint16_t frame1, uint16_t frame2)
+{
+	return (frame1 != frame2) &&
+		(((frame1 - frame2) & DWC_HFNUM_MAX_FRNUM) <
+			(DWC_HFNUM_MAX_FRNUM >> 1));
+}
+
+/**
+ * Increments frame by the amount specified by inc. The addition is done
+ * modulo DWC_HFNUM_MAX_FRNUM. Returns the incremented value.
+ */
+static inline uint16_t dwc_frame_num_inc(uint16_t frame, uint16_t inc)
+{
+	return (frame + inc) & DWC_HFNUM_MAX_FRNUM;
+}
+
+static inline uint16_t dwc_full_frame_num(uint16_t frame)
+{
+	return (frame & DWC_HFNUM_MAX_FRNUM) >> 3;
+}
+
+static inline uint16_t dwc_micro_frame_num(uint16_t frame)
+{
+	return frame & 0x7;
+}
+
+#ifdef DEBUG
+/**
+ * Macro to sample the remaining PHY clocks left in the current frame. This
+ * may be used during debugging to determine the average time it takes to
+ * execute sections of code. There are two possible sample points, "a" and
+ * "b", so the letter argument must be one of these values.
+ *
+ * To dump the average sample times, read the "hcd_frrem" sysfs attribute. For
+ * example, "cat /sys/devices/lm0/hcd_frrem".
+ */
+#define dwc_sample_frrem(_hcd, _qh, _letter) \
+{ \
+	union hfnum_data hfnum; \
+	struct dwc_otg_qtd *qtd; \
+	qtd = list_entry(_qh->qtd_list.next, struct dwc_otg_qtd, qtd_list_entry); \
+	if (usb_pipeint(qtd->urb->pipe) && qh->start_split_frame != 0 && !qtd->complete_split) { \
+		hfnum.d32 = dwc_read_reg32(&_hcd->core_if->host_if->host_global_regs->hfnum); \
+		switch (hfnum.b.frnum & 0x7) { \
+		case 7: \
+			_hcd->hfnum_7_samples_##_letter++; \
+			_hcd->hfnum_7_frrem_accum_##_letter += hfnum.b.frrem; \
+			break; \
+		case 0: \
+			_hcd->hfnum_0_samples_##_letter++; \
+			_hcd->hfnum_0_frrem_accum_##_letter += hfnum.b.frrem; \
+			break; \
+		default: \
+			_hcd->hfnum_other_samples_##_letter++; \
+			_hcd->hfnum_other_frrem_accum_##_letter += \
+				hfnum.b.frrem;			   \
+			break; \
+		} \
+	} \
+}
+#else
+#define dwc_sample_frrem(hcd, qh, letter)
+#endif
+#endif
+#endif /* DWC_DEVICE_ONLY */
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
new file mode 100644
index 0000000..2c4266f
--- /dev/null
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c
@@ -0,0 +1,1890 @@
+/* ==========================================================================
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+#ifndef DWC_DEVICE_ONLY
+
+#include "dwc_otg_driver.h"
+#include "dwc_otg_hcd.h"
+#include "dwc_otg_regs.h"
+
+/*
+ * This file contains the implementation of the HCD Interrupt handlers.
+ */
+
+/* This function handles interrupts for the HCD. */
+int32_t dwc_otg_hcd_handle_intr(struct dwc_otg_hcd *dwc_otg_hcd)
+{
+	int retval = 0;
+
+	struct dwc_otg_core_if *core_if = dwc_otg_hcd->core_if;
+	union gintsts_data gintsts;
+#ifdef DEBUG
+	struct dwc_otg_core_global_regs *global_regs =
+		core_if->core_global_regs;
+#endif
+
+	/* Check if HOST Mode */
+	if (dwc_otg_is_host_mode(core_if)) {
+		gintsts.d32 = dwc_otg_read_core_intr(core_if);
+		if (!gintsts.d32)
+			return 0;
+#ifdef DEBUG
+		/* Don't print debug message in the interrupt handler on SOF */
+#  ifndef DEBUG_SOF
+		if (gintsts.d32 != DWC_SOF_INTR_MASK)
+#  endif
+			DWC_DEBUGPL(DBG_HCD, "\n");
+#endif
+
+#ifdef DEBUG
+#  ifndef DEBUG_SOF
+		if (gintsts.d32 != DWC_SOF_INTR_MASK)
+#  endif
+			DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Interrupt Detected "
+				    "gintsts&gintmsk=0x%08x\n",
+				    gintsts.d32);
+#endif
+
+		if (gintsts.b.sofintr)
+			retval |= dwc_otg_hcd_handle_sof_intr(dwc_otg_hcd);
+
+		if (gintsts.b.rxstsqlvl)
+			retval |=
+				dwc_otg_hcd_handle_rx_status_q_level_intr(dwc_otg_hcd);
+
+		if (gintsts.b.nptxfempty)
+			retval |=
+				dwc_otg_hcd_handle_np_tx_fifo_empty_intr(dwc_otg_hcd);
+
+		if (gintsts.b.i2cintr)
+			;/** @todo Implement i2cintr handler. */
+
+		if (gintsts.b.portintr)
+			retval |= dwc_otg_hcd_handle_port_intr(dwc_otg_hcd);
+
+		if (gintsts.b.hcintr)
+			retval |= dwc_otg_hcd_handle_hc_intr(dwc_otg_hcd);
+
+		if (gintsts.b.ptxfempty) {
+			retval |=
+			    dwc_otg_hcd_handle_perio_tx_fifo_empty_intr
+			    (dwc_otg_hcd);
+		}
+#ifdef DEBUG
+#  ifndef DEBUG_SOF
+		if (gintsts.d32 != DWC_SOF_INTR_MASK)
+#  endif
+		{
+			DWC_DEBUGPL(DBG_HCD,
+				    "DWC OTG HCD Finished Servicing Interrupts\n");
+			DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintsts=0x%08x\n",
+				    dwc_read_reg32(&global_regs->gintsts));
+			DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD gintmsk=0x%08x\n",
+				    dwc_read_reg32(&global_regs->gintmsk));
+		}
+#endif
+
+#ifdef DEBUG
+#  ifndef DEBUG_SOF
+		if (gintsts.d32 != DWC_SOF_INTR_MASK)
+#  endif
+			DWC_DEBUGPL(DBG_HCD, "\n");
+#endif
+
+	}
+
+	return retval;
+}
+
+#ifdef DWC_TRACK_MISSED_SOFS
+#warning Compiling code to track missed SOFs
+#define FRAME_NUM_ARRAY_SIZE 1000
+/**
+ * This function is for debug only.
+ */
+static inline void track_missed_sofs(uint16_t _curr_frame_number)
+{
+	static uint16_t frame_num_array[FRAME_NUM_ARRAY_SIZE];
+	static uint16_t last_frame_num_array[FRAME_NUM_ARRAY_SIZE];
+	static int frame_num_idx;
+	static uint16_t last_frame_num = DWC_HFNUM_MAX_FRNUM;
+	static int dumped_frame_num_array;
+
+	if (frame_num_idx < FRAME_NUM_ARRAY_SIZE) {
+		if ((((last_frame_num + 1) & DWC_HFNUM_MAX_FRNUM) !=
+		     _curr_frame_number)) {
+			frame_num_array[frame_num_idx] = _curr_frame_number;
+			last_frame_num_array[frame_num_idx++] = last_frame_num;
+		}
+	} else if (!dumped_frame_num_array) {
+		int i;
+		printk(KERN_EMERG USB_DWC "Frame     Last Frame\n");
+		printk(KERN_EMERG USB_DWC "-----     ----------\n");
+		for (i = 0; i < FRAME_NUM_ARRAY_SIZE; i++) {
+			printk(KERN_EMERG USB_DWC "0x%04x    0x%04x\n",
+			       frame_num_array[i], last_frame_num_array[i]);
+		}
+		dumped_frame_num_array = 1;
+	}
+	last_frame_num = _curr_frame_number;
+}
+#endif
+
+/**
+ * Handles the start-of-frame interrupt in host mode. Non-periodic
+ * transactions may be queued to the DWC_otg controller for the current
+ * (micro)frame. Periodic transactions may be queued to the controller for the
+ * next (micro)frame.
+ */
+int32_t dwc_otg_hcd_handle_sof_intr(struct dwc_otg_hcd *hcd)
+{
+	union hfnum_data hfnum;
+	struct list_head *qh_entry;
+	struct dwc_otg_qh *qh;
+	enum dwc_otg_transaction_type tr_type;
+	union gintsts_data gintsts = {.d32 = 0 };
+
+	hfnum.d32 =
+	    dwc_read_reg32(&hcd->core_if->host_if->host_global_regs->hfnum);
+
+#ifdef DEBUG_SOF
+	DWC_DEBUGPL(DBG_HCD, "--Start of Frame Interrupt--\n");
+#endif
+
+	hcd->frame_number = hfnum.b.frnum;
+
+#ifdef DEBUG
+	hcd->frrem_accum += hfnum.b.frrem;
+	hcd->frrem_samples++;
+#endif
+
+#ifdef DWC_TRACK_MISSED_SOFS
+	track_missed_sofs(hcd->frame_number);
+#endif
+
+	/* Determine whether any periodic QHs should be executed. */
+	qh_entry = hcd->periodic_sched_inactive.next;
+	while (qh_entry != &hcd->periodic_sched_inactive) {
+		qh = list_entry(qh_entry, struct dwc_otg_qh, qh_list_entry);
+		qh_entry = qh_entry->next;
+		if (dwc_frame_num_le(qh->sched_frame, hcd->frame_number)) {
+			/*
+			 * Move QH to the ready list to be executed next
+			 * (micro)frame.
+			 */
+			list_move(&qh->qh_list_entry,
+				  &hcd->periodic_sched_ready);
+		}
+	}
+
+	tr_type = dwc_otg_hcd_select_transactions(hcd);
+	if (tr_type != DWC_OTG_TRANSACTION_NONE) {
+		dwc_otg_hcd_queue_transactions(hcd, tr_type);
+	} else if (list_empty(&hcd->periodic_sched_inactive) &&
+		   list_empty(&hcd->periodic_sched_ready) &&
+		   list_empty(&hcd->periodic_sched_assigned) &&
+		   list_empty(&hcd->periodic_sched_queued)) {
+		/*
+		 * We don't have USB data to send. Unfortunately the
+		 * Synopsis block continues to generate interrupts at
+		 * about 8k/sec. In order not waste time on these
+		 * useless interrupts, we're going to disable the SOF
+		 * interrupt. It will be re-enabled when a new packet
+		 * is enqueued in dwc_otg_hcd_urb_enqueue()
+		 */
+		dwc_modify_reg32(&hcd->core_if->core_global_regs->gintmsk,
+				 DWC_SOF_INTR_MASK, 0);
+	}
+
+	/* Clear interrupt */
+	gintsts.b.sofintr = 1;
+	dwc_write_reg32(&hcd->core_if->core_global_regs->gintsts, gintsts.d32);
+
+	return 1;
+}
+
+/* Handles the Rx Status Queue Level Interrupt, which indicates that
+ * there is at least one packet in the Rx FIFO.  The packets are moved
+ * from the FIFO to memory if the DWC_otg controller is operating in
+ * Slave mode. */
+int32_t
+dwc_otg_hcd_handle_rx_status_q_level_intr(struct dwc_otg_hcd *dwc_otg_hcd)
+{
+	union host_grxsts_data grxsts;
+	struct dwc_hc *hc = NULL;
+
+	DWC_DEBUGPL(DBG_HCD, "--RxStsQ Level Interrupt--\n");
+
+	grxsts.d32 =
+	    dwc_read_reg32(&dwc_otg_hcd->core_if->core_global_regs->grxstsp);
+
+	hc = dwc_otg_hcd->hc_ptr_array[grxsts.b.chnum];
+
+	/* Packet Status */
+	DWC_DEBUGPL(DBG_HCDV, "    Ch num = %d\n", grxsts.b.chnum);
+	DWC_DEBUGPL(DBG_HCDV, "    Count = %d\n", grxsts.b.bcnt);
+	DWC_DEBUGPL(DBG_HCDV, "    DPID = %d, hc.dpid = %d\n", grxsts.b.dpid,
+		    hc->data_pid_start);
+	DWC_DEBUGPL(DBG_HCDV, "    PStatus = %d\n", grxsts.b.pktsts);
+
+	switch (grxsts.b.pktsts) {
+	case DWC_GRXSTS_PKTSTS_IN:
+		/* Read the data into the host buffer. */
+		if (grxsts.b.bcnt > 0) {
+			dwc_otg_read_packet(dwc_otg_hcd->core_if,
+					    hc->xfer_buff, grxsts.b.bcnt);
+
+			/* Update the HC fields for the next packet received. */
+			hc->xfer_count += grxsts.b.bcnt;
+			hc->xfer_buff += grxsts.b.bcnt;
+		}
+
+	case DWC_GRXSTS_PKTSTS_IN_XFER_COMP:
+	case DWC_GRXSTS_PKTSTS_DATA_TOGGLE_ERR:
+	case DWC_GRXSTS_PKTSTS_CH_HALTED:
+		/* Handled in interrupt, just ignore data */
+		break;
+	default:
+		DWC_ERROR("RX_STS_Q Interrupt: Unknown status %d\n",
+			  grxsts.b.pktsts);
+		break;
+	}
+
+	return 1;
+}
+
+/* This interrupt occurs when the non-periodic Tx FIFO is
+ * half-empty. More data packets may be written to the FIFO for OUT
+ * transfers. More requests may be written to the non-periodic request
+ * queue for IN transfers. This interrupt is enabled only in Slave
+ * mode. */
+int32_t dwc_otg_hcd_handle_np_tx_fifo_empty_intr(struct dwc_otg_hcd *
+						 dwc_otg_hcd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Non-Periodic TxFIFO Empty Interrupt--\n");
+	dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
+				       DWC_OTG_TRANSACTION_NON_PERIODIC);
+	return 1;
+}
+
+/* This interrupt occurs when the periodic Tx FIFO is half-empty. More
+ * data packets may be written to the FIFO for OUT transfers. More
+ * requests may be written to the periodic request queue for IN
+ * transfers. This interrupt is enabled only in Slave mode. */
+int32_t dwc_otg_hcd_handle_perio_tx_fifo_empty_intr(struct dwc_otg_hcd *
+						    dwc_otg_hcd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Periodic TxFIFO Empty Interrupt--\n");
+	dwc_otg_hcd_queue_transactions(dwc_otg_hcd,
+				       DWC_OTG_TRANSACTION_PERIODIC);
+	return 1;
+}
+
+/* There are multiple conditions that can cause a port interrupt. This
+ * function determines which interrupt conditions have occurred and
+ * handles them appropriately. */
+int32_t dwc_otg_hcd_handle_port_intr(struct dwc_otg_hcd *dwc_otg_hcd)
+{
+	int retval = 0;
+	union hprt0_data hprt0;
+	union hprt0_data hprt0_modify;
+
+	hprt0.d32 = dwc_read_reg32(dwc_otg_hcd->core_if->host_if->hprt0);
+	hprt0_modify.d32 =
+	    dwc_read_reg32(dwc_otg_hcd->core_if->host_if->hprt0);
+
+	/* Clear appropriate bits in HPRT0 to clear the interrupt bit in
+	 * GINTSTS */
+
+	hprt0_modify.b.prtena = 0;
+	hprt0_modify.b.prtconndet = 0;
+	hprt0_modify.b.prtenchng = 0;
+	hprt0_modify.b.prtovrcurrchng = 0;
+
+	/* Port Connect Detected
+	 * Set flag and clear if detected */
+	if (hprt0.b.prtconndet) {
+		DWC_DEBUGPL(DBG_HCD, "--Port Interrupt HPRT0=0x%08x "
+			    "Port Connect Detected--\n", hprt0.d32);
+		dwc_otg_hcd->flags.b.port_connect_status_change = 1;
+		dwc_otg_hcd->flags.b.port_connect_status = 1;
+		hprt0_modify.b.prtconndet = 1;
+
+		/* B-Device has connected, Delete the connection timer.  */
+		del_timer(&dwc_otg_hcd->conn_timer);
+
+		/* The Hub driver asserts a reset when it sees port connect
+		 * status change flag */
+		retval |= 1;
+	}
+
+	/* Port Enable Changed
+	 * Clear if detected - Set internal flag if disabled */
+	if (hprt0.b.prtenchng) {
+		DWC_DEBUGPL(DBG_HCD, "  --Port Interrupt HPRT0=0x%08x "
+			    "Port Enable Changed--\n", hprt0.d32);
+		hprt0_modify.b.prtenchng = 1;
+		if (hprt0.b.prtena == 1) {
+			int do_reset = 0;
+			struct dwc_otg_core_params *params =
+			    dwc_otg_hcd->core_if->core_params;
+			struct dwc_otg_core_global_regs *global_regs =
+			    dwc_otg_hcd->core_if->core_global_regs;
+			struct dwc_otg_host_if *host_if =
+			    dwc_otg_hcd->core_if->host_if;
+
+			/* Check if we need to adjust the PHY clock speed for
+			 * low power and adjust it */
+			if (params->host_support_fs_ls_low_power) {
+				union gusbcfg_data usbcfg;
+
+				usbcfg.d32 =
+				    dwc_read_reg32(&global_regs->gusbcfg);
+
+				if ((hprt0.b.prtspd == DWC_HPRT0_PRTSPD_LOW_SPEED)
+				    || (hprt0.b.prtspd == DWC_HPRT0_PRTSPD_FULL_SPEED)) {
+					/*
+					 * Low power
+					 */
+					union hcfg_data hcfg;
+					if (usbcfg.b.phylpwrclksel == 0) {
+						/* Set PHY low power clock select for FS/LS devices */
+						usbcfg.b.phylpwrclksel = 1;
+						dwc_write_reg32(&global_regs->gusbcfg,
+								usbcfg.d32);
+						do_reset = 1;
+					}
+
+					hcfg.d32 =
+					    dwc_read_reg32(&host_if->host_global_regs->hcfg);
+
+					if ((hprt0.b.prtspd ==
+					     DWC_HPRT0_PRTSPD_LOW_SPEED)
+					    && (params->
+						host_ls_low_power_phy_clk ==
+						DWC_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)) {
+						/* 6 MHZ */
+						DWC_DEBUGPL(DBG_CIL,
+							    "FS_PHY programming HCFG to 6 MHz (Low Power)\n");
+						if (hcfg.b.fslspclksel !=
+						    DWC_HCFG_6_MHZ) {
+							hcfg.b.fslspclksel =
+							    DWC_HCFG_6_MHZ;
+							dwc_write_reg32(&host_if->host_global_regs->hcfg,
+									hcfg.d32);
+							do_reset = 1;
+						}
+					} else {
+						/* 48 MHZ */
+						DWC_DEBUGPL(DBG_CIL,
+							    "FS_PHY programming HCFG to 48 MHz ()\n");
+						if (hcfg.b.fslspclksel !=
+						    DWC_HCFG_48_MHZ) {
+							hcfg.b.fslspclksel = DWC_HCFG_48_MHZ;
+							dwc_write_reg32(&host_if->host_global_regs->hcfg,
+									hcfg.d32);
+							do_reset = 1;
+						}
+					}
+				} else {
+					/*
+					 * Not low power
+					 */
+					if (usbcfg.b.phylpwrclksel == 1) {
+						usbcfg.b.phylpwrclksel = 0;
+						dwc_write_reg32(&global_regs->gusbcfg,
+								usbcfg.d32);
+						do_reset = 1;
+					}
+				}
+				if (do_reset)
+					tasklet_schedule(dwc_otg_hcd->reset_tasklet);
+			}
+			if (!do_reset)
+				/*
+				 * Port has been enabled set the reset
+				 * change flag
+				 */
+				dwc_otg_hcd->flags.b.port_reset_change = 1;
+		} else {
+			dwc_otg_hcd->flags.b.port_enable_change = 1;
+		}
+		retval |= 1;
+	}
+
+	/** Overcurrent Change Interrupt */
+	if (hprt0.b.prtovrcurrchng) {
+		DWC_DEBUGPL(DBG_HCD, "  --Port Interrupt HPRT0=0x%08x "
+			    "Port Overcurrent Changed--\n", hprt0.d32);
+		dwc_otg_hcd->flags.b.port_over_current_change = 1;
+		hprt0_modify.b.prtovrcurrchng = 1;
+		retval |= 1;
+	}
+
+	/* Clear Port Interrupts */
+	dwc_write_reg32(dwc_otg_hcd->core_if->host_if->hprt0,
+			hprt0_modify.d32);
+
+	return retval;
+}
+
+/** This interrupt indicates that one or more host channels has a pending
+ * interrupt. There are multiple conditions that can cause each host channel
+ * interrupt. This function determines which conditions have occurred for each
+ * host channel interrupt and handles them appropriately. */
+int32_t dwc_otg_hcd_handle_hc_intr(struct dwc_otg_hcd *dwc_otg_hcd)
+{
+	int i;
+	int retval = 0;
+	union haint_data haint;
+
+	/* Clear appropriate bits in HCINTn to clear the interrupt bit in
+	 * GINTSTS */
+
+	haint.d32 = dwc_otg_read_host_all_channels_intr(dwc_otg_hcd->core_if);
+
+	for (i = 0; i < dwc_otg_hcd->core_if->core_params->host_channels; i++) {
+		if (haint.b2.chint & (1 << i))
+			retval |= dwc_otg_hcd_handle_hc_n_intr(dwc_otg_hcd, i);
+	}
+
+	return retval;
+}
+
+/* Macro used to clear one channel interrupt */
+#define clear_hc_int(_hc_regs_, _intr_) \
+do { \
+	union hcint_data hcint_clear = {.d32 = 0}; \
+	hcint_clear.b._intr_ = 1; \
+	dwc_write_reg32(&((_hc_regs_)->hcint), hcint_clear.d32); \
+} while (0)
+
+/*
+ * Macro used to disable one channel interrupt. Channel interrupts are
+ * disabled when the channel is halted or released by the interrupt handler.
+ * There is no need to handle further interrupts of that type until the
+ * channel is re-assigned. In fact, subsequent handling may cause crashes
+ * because the channel structures are cleaned up when the channel is released.
+ */
+#define disable_hc_int(_hc_regs_, _intr_)				\
+	do {								\
+		union hcintmsk_data hcintmsk = {.d32 = 0};		\
+		hcintmsk.b._intr_ = 1;					\
+		dwc_modify_reg32(&((_hc_regs_)->hcintmsk), hcintmsk.d32, 0); \
+	} while (0)
+
+/**
+ * Gets the actual length of a transfer after the transfer halts. _halt_status
+ * holds the reason for the halt.
+ *
+ * For IN transfers where _halt_status is DWC_OTG_HC_XFER_COMPLETE,
+ * *_short_read is set to 1 upon return if less than the requested
+ * number of bytes were transferred. Otherwise, *_short_read is set to 0 upon
+ * return. _short_read may also be NULL on entry, in which case it remains
+ * unchanged.
+ */
+static uint32_t get_actual_xfer_length(struct dwc_hc *hc,
+				       struct dwc_otg_hc_regs *hc_regs,
+				       struct dwc_otg_qtd *qtd,
+				       enum dwc_otg_halt_status _halt_status,
+				       int *_short_read)
+{
+	union hctsiz_data hctsiz;
+	uint32_t length;
+
+	if (_short_read != NULL)
+		*_short_read = 0;
+
+	hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
+
+	if (_halt_status == DWC_OTG_HC_XFER_COMPLETE) {
+		if (hc->ep_is_in) {
+			length = hc->xfer_len - hctsiz.b.xfersize;
+			if (_short_read != NULL)
+				*_short_read = (hctsiz.b.xfersize != 0);
+		} else if (hc->qh->do_split) {
+			length = qtd->ssplit_out_xfer_count;
+		} else {
+			length = hc->xfer_len;
+		}
+	} else {
+		/*
+		 * Must use the hctsiz.pktcnt field to determine how much data
+		 * has been transferred. This field reflects the number of
+		 * packets that have been transferred via the USB. This is
+		 * always an integral number of packets if the transfer was
+		 * halted before its normal completion. (Can't use the
+		 * hctsiz.xfersize field because that reflects the number of
+		 * bytes transferred via the AHB, not the USB).
+		 */
+		length =
+		    (hc->start_pkt_count - hctsiz.b.pktcnt) * hc->max_packet;
+	}
+
+	return length;
+}
+
+/**
+ * Updates the state of the URB after a Transfer Complete interrupt on the
+ * host channel. Updates the actual_length field of the URB based on the
+ * number of bytes transferred via the host channel. Sets the URB status
+ * if the data transfer is finished.
+ *
+ * Returns 1 if the data transfer specified by the URB is completely finished,
+ * 0 otherwise.
+ */
+static int update_urb_state_xfer_comp(struct dwc_hc *hc,
+				      struct dwc_otg_hc_regs *hc_regs,
+				      struct urb *urb, struct dwc_otg_qtd *qtd)
+{
+	int xfer_done = 0;
+	int short_read = 0;
+
+	urb->actual_length += get_actual_xfer_length(hc, hc_regs, qtd,
+						     DWC_OTG_HC_XFER_COMPLETE,
+						     &short_read);
+
+	if (short_read || (urb->actual_length == urb->transfer_buffer_length)) {
+		xfer_done = 1;
+		if (short_read && (urb->transfer_flags & URB_SHORT_NOT_OK))
+			urb->status = -EREMOTEIO;
+		else
+			urb->status = 0;
+	}
+#ifdef DEBUG
+	{
+		union hctsiz_data hctsiz;
+		hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
+		DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
+			    __func__, (hc->ep_is_in ? "IN" : "OUT"),
+			    hc->hc_num);
+		DWC_DEBUGPL(DBG_HCDV, "  hc->xfer_len %d\n", hc->xfer_len);
+		DWC_DEBUGPL(DBG_HCDV, "  hctsiz.xfersize %d\n",
+			    hctsiz.b.xfersize);
+		DWC_DEBUGPL(DBG_HCDV, "  urb->transfer_buffer_length %d\n",
+			    urb->transfer_buffer_length);
+		DWC_DEBUGPL(DBG_HCDV, "  urb->actual_length %d\n",
+			    urb->actual_length);
+		DWC_DEBUGPL(DBG_HCDV, "  short_read %d, xfer_done %d\n",
+			    short_read, xfer_done);
+	}
+#endif
+
+	return xfer_done;
+}
+
+/*
+ * Save the starting data toggle for the next transfer. The data toggle is
+ * saved in the QH for non-control transfers and it's saved in the QTD for
+ * control transfers.
+ */
+static void save_data_toggle(struct dwc_hc *hc,
+			     struct dwc_otg_hc_regs *hc_regs,
+			     struct dwc_otg_qtd *qtd)
+{
+	union hctsiz_data hctsiz;
+	hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
+
+	if (hc->ep_type != DWC_OTG_EP_TYPE_CONTROL) {
+		struct dwc_otg_qh *qh = hc->qh;
+		if (hctsiz.b.pid == DWC_HCTSIZ_DATA0)
+			qh->data_toggle = DWC_OTG_HC_PID_DATA0;
+		else
+			qh->data_toggle = DWC_OTG_HC_PID_DATA1;
+	} else {
+		if (hctsiz.b.pid == DWC_HCTSIZ_DATA0)
+			qtd->data_toggle = DWC_OTG_HC_PID_DATA0;
+		else
+			qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
+	}
+}
+
+/**
+ * Frees the first QTD in the QH's list if free_qtd is 1. For non-periodic
+ * QHs, removes the QH from the active non-periodic schedule. If any QTDs are
+ * still linked to the QH, the QH is added to the end of the inactive
+ * non-periodic schedule. For periodic QHs, removes the QH from the periodic
+ * schedule if no more QTDs are linked to the QH.
+ */
+static void deactivate_qh(struct dwc_otg_hcd *hcd,
+			  struct dwc_otg_qh *qh, int free_qtd)
+{
+	int continue_split = 0;
+	struct dwc_otg_qtd *qtd;
+
+	DWC_DEBUGPL(DBG_HCDV, "  %s(%p,%p,%d)\n", __func__, hcd, qh, free_qtd);
+
+	qtd = list_entry(qh->qtd_list.next, struct dwc_otg_qtd, qtd_list_entry);
+
+	if (qtd->complete_split) {
+		continue_split = 1;
+	} else if ((qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_MID) ||
+		   (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_END)) {
+		continue_split = 1;
+	}
+
+	if (free_qtd) {
+		dwc_otg_hcd_qtd_remove_and_free(qtd);
+		continue_split = 0;
+	}
+
+	qh->channel = NULL;
+	qh->qtd_in_process = NULL;
+	dwc_otg_hcd_qh_deactivate(hcd, qh, continue_split);
+}
+
+/**
+ * Updates the state of an Isochronous URB when the transfer is stopped for
+ * any reason. The fields of the current entry in the frame descriptor array
+ * are set based on the transfer state and the input _halt_status. Completes
+ * the Isochronous URB if all the URB frames have been completed.
+ *
+ * Returns DWC_OTG_HC_XFER_COMPLETE if there are more frames remaining to be
+ * transferred in the URB. Otherwise return DWC_OTG_HC_XFER_URB_COMPLETE.
+ */
+static enum dwc_otg_halt_status
+update_isoc_urb_state(struct dwc_otg_hcd *hcd,
+		      struct dwc_hc *hc,
+		      struct dwc_otg_hc_regs *hc_regs,
+		      struct dwc_otg_qtd *qtd,
+		      enum dwc_otg_halt_status halt_status)
+{
+	struct urb *urb = qtd->urb;
+	enum dwc_otg_halt_status ret_val = halt_status;
+	struct usb_iso_packet_descriptor *frame_desc;
+
+	frame_desc = &urb->iso_frame_desc[qtd->isoc_frame_index];
+	switch (halt_status) {
+	case DWC_OTG_HC_XFER_COMPLETE:
+		frame_desc->status = 0;
+		frame_desc->actual_length =
+		    get_actual_xfer_length(hc, hc_regs, qtd,
+					   halt_status, NULL);
+		break;
+	case DWC_OTG_HC_XFER_FRAME_OVERRUN:
+		urb->error_count++;
+		if (hc->ep_is_in)
+			frame_desc->status = -ENOSR;
+		else
+			frame_desc->status = -ECOMM;
+		frame_desc->actual_length = 0;
+		break;
+	case DWC_OTG_HC_XFER_BABBLE_ERR:
+		urb->error_count++;
+		frame_desc->status = -EOVERFLOW;
+		/* Don't need to update actual_length in this case. */
+		break;
+	case DWC_OTG_HC_XFER_XACT_ERR:
+		urb->error_count++;
+		frame_desc->status = -EPROTO;
+		frame_desc->actual_length =
+		    get_actual_xfer_length(hc, hc_regs, qtd,
+					   halt_status, NULL);
+		break;
+	default:
+		DWC_ERROR("%s: Unhandled halt_status (%d)\n", __func__,
+			  halt_status);
+		BUG();
+		break;
+	}
+
+	if (++qtd->isoc_frame_index == urb->number_of_packets) {
+		/*
+		 * urb->status is not used for isoc transfers.
+		 * The individual frame_desc statuses are used instead.
+		 */
+		dwc_otg_hcd_complete_urb(hcd, urb, 0);
+		qtd->urb = NULL;
+		ret_val = DWC_OTG_HC_XFER_URB_COMPLETE;
+	} else {
+		ret_val = DWC_OTG_HC_XFER_COMPLETE;
+	}
+
+	return ret_val;
+}
+
+/**
+ * Releases a host channel for use by other transfers. Attempts to select and
+ * queue more transactions since at least one host channel is available.
+ *
+ * @hcd: The HCD state structure.
+ * @hc: The host channel to release.
+ * @qtd: The QTD associated with the host channel. This QTD may be freed
+ * if the transfer is complete or an error has occurred.
+ * @_halt_status: Reason the channel is being released. This status
+ * determines the actions taken by this function.
+ */
+static void release_channel(struct dwc_otg_hcd *hcd,
+			    struct dwc_hc *hc,
+			    struct dwc_otg_qtd *qtd,
+			    enum dwc_otg_halt_status halt_status)
+{
+	enum dwc_otg_transaction_type tr_type;
+	int free_qtd;
+
+	DWC_DEBUGPL(DBG_HCDV, "  %s: channel %d, halt_status %d\n",
+		    __func__, hc->hc_num, halt_status);
+
+	switch (halt_status) {
+	case DWC_OTG_HC_XFER_URB_COMPLETE:
+		free_qtd = 1;
+		break;
+	case DWC_OTG_HC_XFER_AHB_ERR:
+	case DWC_OTG_HC_XFER_STALL:
+	case DWC_OTG_HC_XFER_BABBLE_ERR:
+		free_qtd = 1;
+		break;
+	case DWC_OTG_HC_XFER_XACT_ERR:
+		if (qtd->error_count >= 3) {
+			DWC_DEBUGPL(DBG_HCDV,
+				    "  Complete URB with transaction error\n");
+			free_qtd = 1;
+			qtd->urb->status = -EPROTO;
+			dwc_otg_hcd_complete_urb(hcd, qtd->urb, -EPROTO);
+			qtd->urb = NULL;
+		} else {
+			free_qtd = 0;
+		}
+		break;
+	case DWC_OTG_HC_XFER_URB_DEQUEUE:
+		/*
+		 * The QTD has already been removed and the QH has been
+		 * deactivated. Don't want to do anything except release the
+		 * host channel and try to queue more transfers.
+		 */
+		goto cleanup;
+	case DWC_OTG_HC_XFER_NO_HALT_STATUS:
+		DWC_ERROR("%s: No halt_status, channel %d\n", __func__,
+			  hc->hc_num);
+		free_qtd = 0;
+		break;
+	default:
+		free_qtd = 0;
+		break;
+	}
+
+	deactivate_qh(hcd, hc->qh, free_qtd);
+
+cleanup:
+	/*
+	 * Release the host channel for use by other transfers. The cleanup
+	 * function clears the channel interrupt enables and conditions, so
+	 * there's no need to clear the Channel Halted interrupt separately.
+	 */
+	dwc_otg_hc_cleanup(hcd->core_if, hc);
+	list_add_tail(&hc->hc_list_entry, &hcd->free_hc_list);
+
+	switch (hc->ep_type) {
+	case DWC_OTG_EP_TYPE_CONTROL:
+	case DWC_OTG_EP_TYPE_BULK:
+		hcd->non_periodic_channels--;
+		break;
+
+	default:
+		/*
+		 * Don't release reservations for periodic channels here.
+		 * That's done when a periodic transfer is descheduled (i.e.
+		 * when the QH is removed from the periodic schedule).
+		 */
+		break;
+	}
+
+	/* Try to queue more transfers now that there's a free channel. */
+	tr_type = dwc_otg_hcd_select_transactions(hcd);
+	if (tr_type != DWC_OTG_TRANSACTION_NONE)
+		dwc_otg_hcd_queue_transactions(hcd, tr_type);
+}
+
+/**
+ * Halts a host channel. If the channel cannot be halted immediately because
+ * the request queue is full, this function ensures that the FIFO empty
+ * interrupt for the appropriate queue is enabled so that the halt request can
+ * be queued when there is space in the request queue.
+ *
+ * This function may also be called in DMA mode. In that case, the channel is
+ * simply released since the core always halts the channel automatically in
+ * DMA mode.
+ */
+static void halt_channel(struct dwc_otg_hcd *hcd,
+			 struct dwc_hc *hc,
+			 struct dwc_otg_qtd *qtd,
+			 enum dwc_otg_halt_status halt_status)
+{
+	if (hcd->core_if->dma_enable) {
+		release_channel(hcd, hc, qtd, halt_status);
+		return;
+	}
+
+	/* Slave mode processing... */
+	dwc_otg_hc_halt(hcd->core_if, hc, halt_status);
+
+	if (hc->halt_on_queue) {
+		union gintmsk_data gintmsk = {.d32 = 0 };
+		struct dwc_otg_core_global_regs *global_regs;
+		global_regs = hcd->core_if->core_global_regs;
+
+		if (hc->ep_type == DWC_OTG_EP_TYPE_CONTROL ||
+		    hc->ep_type == DWC_OTG_EP_TYPE_BULK) {
+			/*
+			 * Make sure the Non-periodic Tx FIFO empty interrupt
+			 * is enabled so that the non-periodic schedule will
+			 * be processed.
+			 */
+			gintmsk.b.nptxfempty = 1;
+			dwc_modify_reg32(&global_regs->gintmsk, 0, gintmsk.d32);
+		} else {
+			/*
+			 * Move the QH from the periodic queued schedule to
+			 * the periodic assigned schedule. This allows the
+			 * halt to be queued when the periodic schedule is
+			 * processed.
+			 */
+			list_move(&hc->qh->qh_list_entry,
+				  &hcd->periodic_sched_assigned);
+
+			/*
+			 * Make sure the Periodic Tx FIFO Empty interrupt is
+			 * enabled so that the periodic schedule will be
+			 * processed.
+			 */
+			gintmsk.b.ptxfempty = 1;
+			dwc_modify_reg32(&global_regs->gintmsk, 0, gintmsk.d32);
+		}
+	}
+}
+
+/**
+ * Performs common cleanup for non-periodic transfers after a Transfer
+ * Complete interrupt. This function should be called after any endpoint type
+ * specific handling is finished to release the host channel.
+ */
+static void complete_non_periodic_xfer(struct dwc_otg_hcd *hcd,
+				       struct dwc_hc *hc,
+				       struct dwc_otg_hc_regs *hc_regs,
+				       struct dwc_otg_qtd *qtd,
+				       enum dwc_otg_halt_status halt_status)
+{
+	union hcint_data hcint;
+
+	qtd->error_count = 0;
+
+	hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+	if (hcint.b.nyet) {
+		/*
+		 * Got a NYET on the last transaction of the transfer. This
+		 * means that the endpoint should be in the PING state at the
+		 * beginning of the next transfer.
+		 */
+		hc->qh->ping_state = 1;
+		clear_hc_int(hc_regs, nyet);
+	}
+
+	/*
+	 * Always halt and release the host channel to make it available for
+	 * more transfers. There may still be more phases for a control
+	 * transfer or more data packets for a bulk transfer at this point,
+	 * but the host channel is still halted. A channel will be reassigned
+	 * to the transfer when the non-periodic schedule is processed after
+	 * the channel is released. This allows transactions to be queued
+	 * properly via dwc_otg_hcd_queue_transactions, which also enables the
+	 * Tx FIFO Empty interrupt if necessary.
+	 */
+	if (hc->ep_is_in) {
+		/*
+		 * IN transfers in Slave mode require an explicit disable to
+		 * halt the channel. (In DMA mode, this call simply releases
+		 * the channel.)
+		 */
+		halt_channel(hcd, hc, qtd, halt_status);
+	} else {
+		/*
+		 * The channel is automatically disabled by the core for OUT
+		 * transfers in Slave mode.
+		 */
+		release_channel(hcd, hc, qtd, halt_status);
+	}
+}
+
+/**
+ * Performs common cleanup for periodic transfers after a Transfer Complete
+ * interrupt. This function should be called after any endpoint type specific
+ * handling is finished to release the host channel.
+ */
+static void complete_periodic_xfer(struct dwc_otg_hcd *hcd,
+				   struct dwc_hc *hc,
+				   struct dwc_otg_hc_regs *hc_regs,
+				   struct dwc_otg_qtd *qtd,
+				   enum dwc_otg_halt_status halt_status)
+{
+	union hctsiz_data hctsiz;
+	qtd->error_count = 0;
+
+	hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
+	if (!hc->ep_is_in || hctsiz.b.pktcnt == 0) {
+		/* Core halts channel in these cases. */
+		release_channel(hcd, hc, qtd, halt_status);
+	} else {
+		/* Flush any outstanding requests from the Tx queue. */
+		halt_channel(hcd, hc, qtd, halt_status);
+	}
+}
+
+/**
+ * Handles a host channel Transfer Complete interrupt. This handler may be
+ * called in either DMA mode or Slave mode.
+ */
+static int32_t handle_hc_xfercomp_intr(struct dwc_otg_hcd *hcd,
+				       struct dwc_hc *hc,
+				       struct dwc_otg_hc_regs *hc_regs,
+				       struct dwc_otg_qtd *qtd)
+{
+	int urb_xfer_done;
+	enum dwc_otg_halt_status halt_status = DWC_OTG_HC_XFER_COMPLETE;
+	struct urb *urb = qtd->urb;
+	int pipe_type = usb_pipetype(urb->pipe);
+
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "Transfer Complete--\n", hc->hc_num);
+
+	/*
+	 * Handle xfer complete on CSPLIT.
+	 */
+	if (hc->qh->do_split)
+		qtd->complete_split = 0;
+
+	/* Update the QTD and URB states. */
+	switch (pipe_type) {
+	case PIPE_CONTROL:
+		switch (qtd->control_phase) {
+		case DWC_OTG_CONTROL_SETUP:
+			if (urb->transfer_buffer_length > 0)
+				qtd->control_phase = DWC_OTG_CONTROL_DATA;
+			else
+				qtd->control_phase = DWC_OTG_CONTROL_STATUS;
+			DWC_DEBUGPL(DBG_HCDV,
+				    "  Control setup transaction done\n");
+			halt_status = DWC_OTG_HC_XFER_COMPLETE;
+			break;
+		case DWC_OTG_CONTROL_DATA:{
+				urb_xfer_done =
+				    update_urb_state_xfer_comp(hc, hc_regs,
+							       urb, qtd);
+				if (urb_xfer_done) {
+					qtd->control_phase =
+					    DWC_OTG_CONTROL_STATUS;
+					DWC_DEBUGPL(DBG_HCDV,
+						    " Control data transfer done\n");
+				} else {
+					save_data_toggle(hc, hc_regs, qtd);
+				}
+				halt_status = DWC_OTG_HC_XFER_COMPLETE;
+				break;
+			}
+		case DWC_OTG_CONTROL_STATUS:
+			DWC_DEBUGPL(DBG_HCDV, "  Control transfer complete\n");
+			if (urb->status == -EINPROGRESS)
+				urb->status = 0;
+			dwc_otg_hcd_complete_urb(hcd, urb, urb->status);
+			qtd->urb = NULL;
+			halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
+			break;
+		}
+
+		complete_non_periodic_xfer(hcd, hc, hc_regs, qtd,
+					   halt_status);
+		break;
+	case PIPE_BULK:
+		DWC_DEBUGPL(DBG_HCDV, "  Bulk transfer complete\n");
+		urb_xfer_done =
+		    update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
+		if (urb_xfer_done) {
+			dwc_otg_hcd_complete_urb(hcd, urb, urb->status);
+			qtd->urb = NULL;
+			halt_status = DWC_OTG_HC_XFER_URB_COMPLETE;
+		} else {
+			halt_status = DWC_OTG_HC_XFER_COMPLETE;
+		}
+
+		save_data_toggle(hc, hc_regs, qtd);
+		complete_non_periodic_xfer(hcd, hc, hc_regs, qtd,
+					   halt_status);
+		break;
+	case PIPE_INTERRUPT:
+		DWC_DEBUGPL(DBG_HCDV, "  Interrupt transfer complete\n");
+		update_urb_state_xfer_comp(hc, hc_regs, urb, qtd);
+
+		/*
+		 * Interrupt URB is done on the first transfer complete
+		 * interrupt.
+		 */
+		dwc_otg_hcd_complete_urb(hcd, urb, urb->status);
+		qtd->urb = NULL;
+		save_data_toggle(hc, hc_regs, qtd);
+		complete_periodic_xfer(hcd, hc, hc_regs, qtd,
+				       DWC_OTG_HC_XFER_URB_COMPLETE);
+		break;
+	case PIPE_ISOCHRONOUS:
+		DWC_DEBUGPL(DBG_HCDV, "  Isochronous transfer complete\n");
+		if (qtd->isoc_split_pos == DWC_HCSPLIT_XACTPOS_ALL) {
+			halt_status =
+			    update_isoc_urb_state(hcd, hc, hc_regs, qtd,
+						  DWC_OTG_HC_XFER_COMPLETE);
+		}
+		complete_periodic_xfer(hcd, hc, hc_regs, qtd, halt_status);
+		break;
+	}
+
+	disable_hc_int(hc_regs, xfercompl);
+
+	return 1;
+}
+
+/**
+ * Handles a host channel STALL interrupt. This handler may be called in
+ * either DMA mode or Slave mode.
+ */
+static int32_t handle_hc_stall_intr(struct dwc_otg_hcd *hcd,
+				    struct dwc_hc *hc,
+				    struct dwc_otg_hc_regs *hc_regs,
+				    struct dwc_otg_qtd *qtd)
+{
+	struct urb *urb = qtd->urb;
+	int pipe_type = usb_pipetype(urb->pipe);
+
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "STALL Received--\n", hc->hc_num);
+
+	if (pipe_type == PIPE_CONTROL) {
+		dwc_otg_hcd_complete_urb(hcd, qtd->urb, -EPIPE);
+		qtd->urb = NULL;
+	}
+
+	if (pipe_type == PIPE_BULK || pipe_type == PIPE_INTERRUPT) {
+		dwc_otg_hcd_complete_urb(hcd, qtd->urb, -EPIPE);
+		qtd->urb = NULL;
+		/*
+		 * USB protocol requires resetting the data toggle for bulk
+		 * and interrupt endpoints when a CLEAR_FEATURE(ENDPOINT_HALT)
+		 * setup command is issued to the endpoint. Anticipate the
+		 * CLEAR_FEATURE command since a STALL has occurred and reset
+		 * the data toggle now.
+		 */
+		hc->qh->data_toggle = 0;
+	}
+
+	halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_STALL);
+
+	disable_hc_int(hc_regs, stall);
+
+	return 1;
+}
+
+/*
+ * Updates the state of the URB when a transfer has been stopped due to an
+ * abnormal condition before the transfer completes. Modifies the
+ * actual_length field of the URB to reflect the number of bytes that have
+ * actually been transferred via the host channel.
+ */
+static void update_urb_state_xfer_intr(struct dwc_hc *hc,
+				       struct dwc_otg_hc_regs *hc_regs,
+				       struct urb *urb,
+				       struct dwc_otg_qtd *qtd,
+				       enum dwc_otg_halt_status halt_status)
+{
+	uint32_t bytes_transferred = get_actual_xfer_length(hc, hc_regs, qtd,
+							    halt_status, NULL);
+	urb->actual_length += bytes_transferred;
+
+#ifdef DEBUG
+	{
+		union hctsiz_data hctsiz;
+		hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
+		DWC_DEBUGPL(DBG_HCDV, "DWC_otg: %s: %s, channel %d\n",
+			    __func__, (hc->ep_is_in ? "IN" : "OUT"),
+			    hc->hc_num);
+		DWC_DEBUGPL(DBG_HCDV, "  hc->start_pkt_count %d\n",
+			    hc->start_pkt_count);
+		DWC_DEBUGPL(DBG_HCDV, "  hctsiz.pktcnt %d\n", hctsiz.b.pktcnt);
+		DWC_DEBUGPL(DBG_HCDV, "  hc->max_packet %d\n",
+			    hc->max_packet);
+		DWC_DEBUGPL(DBG_HCDV, "  bytes_transferred %d\n",
+			    bytes_transferred);
+		DWC_DEBUGPL(DBG_HCDV, "  urb->actual_length %d\n",
+			    urb->actual_length);
+		DWC_DEBUGPL(DBG_HCDV, "  urb->transfer_buffer_length %d\n",
+			    urb->transfer_buffer_length);
+	}
+#endif
+}
+
+/**
+ * Handles a host channel NAK interrupt. This handler may be called in either
+ * DMA mode or Slave mode.
+ */
+static int32_t handle_hc_nak_intr(struct dwc_otg_hcd *hcd,
+				  struct dwc_hc *hc,
+				  struct dwc_otg_hc_regs *hc_regs,
+				  struct dwc_otg_qtd *qtd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "NAK Received--\n", hc->hc_num);
+
+	/*
+	 * Handle NAK for IN/OUT SSPLIT/CSPLIT transfers, bulk, control, and
+	 * interrupt.  Re-start the SSPLIT transfer.
+	 */
+	if (hc->do_split) {
+		if (hc->complete_split)
+			qtd->error_count = 0;
+		qtd->complete_split = 0;
+		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
+		goto handle_nak_done;
+	}
+
+	switch (usb_pipetype(qtd->urb->pipe)) {
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+		if (hcd->core_if->dma_enable && hc->ep_is_in) {
+			/*
+			 * NAK interrupts are enabled on bulk/control IN
+			 * transfers in DMA mode for the sole purpose of
+			 * resetting the error count after a transaction error
+			 * occurs. The core will continue transferring data.
+			 */
+			qtd->error_count = 0;
+			goto handle_nak_done;
+		}
+
+		/*
+		 * NAK interrupts normally occur during OUT transfers in DMA
+		 * or Slave mode. For IN transfers, more requests will be
+		 * queued as request queue space is available.
+		 */
+		qtd->error_count = 0;
+
+		if (!hc->qh->ping_state) {
+			update_urb_state_xfer_intr(hc, hc_regs, qtd->urb,
+						   qtd, DWC_OTG_HC_XFER_NAK);
+			save_data_toggle(hc, hc_regs, qtd);
+			if (qtd->urb->dev->speed == USB_SPEED_HIGH)
+				hc->qh->ping_state = 1;
+		}
+
+		/*
+		 * Halt the channel so the transfer can be re-started from
+		 * the appropriate point or the PING protocol will
+		 * start/continue.
+		 */
+		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
+		break;
+	case PIPE_INTERRUPT:
+		qtd->error_count = 0;
+		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NAK);
+		break;
+	case PIPE_ISOCHRONOUS:
+		/* Should never get called for isochronous transfers. */
+		BUG();
+		break;
+	}
+
+handle_nak_done:
+	disable_hc_int(hc_regs, nak);
+
+	return 1;
+}
+
+/**
+ * Handles a host channel ACK interrupt. This interrupt is enabled when
+ * performing the PING protocol in Slave mode, when errors occur during
+ * either Slave mode or DMA mode, and during Start Split transactions.
+ */
+static int32_t handle_hc_ack_intr(struct dwc_otg_hcd *hcd,
+				  struct dwc_hc *hc,
+				  struct dwc_otg_hc_regs *hc_regs,
+				  struct dwc_otg_qtd *qtd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "ACK Received--\n", hc->hc_num);
+
+	if (hc->do_split) {
+		/*
+		 * Handle ACK on SSPLIT.
+		 * ACK should not occur in CSPLIT.
+		 */
+		if ((!hc->ep_is_in)
+		    && (hc->data_pid_start != DWC_OTG_HC_PID_SETUP)) {
+			qtd->ssplit_out_xfer_count = hc->xfer_len;
+		}
+		if (!(hc->ep_type == DWC_OTG_EP_TYPE_ISOC && !hc->ep_is_in)) {
+			/* Don't need complete for isochronous out transfers. */
+			qtd->complete_split = 1;
+		}
+
+		/* ISOC OUT */
+		if ((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && !hc->ep_is_in) {
+			switch (hc->xact_pos) {
+			case DWC_HCSPLIT_XACTPOS_ALL:
+				break;
+			case DWC_HCSPLIT_XACTPOS_END:
+				qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
+				qtd->isoc_split_offset = 0;
+				break;
+			case DWC_HCSPLIT_XACTPOS_BEGIN:
+			case DWC_HCSPLIT_XACTPOS_MID:
+				/*
+				 * For BEGIN or MID, calculate the length for
+				 * the next microframe to determine the correct
+				 * SSPLIT token, either MID or END.
+				 */
+				do {
+					struct usb_iso_packet_descriptor
+					    *frame_desc;
+
+					frame_desc =
+					    &qtd->urb->iso_frame_desc[qtd->isoc_frame_index];
+					qtd->isoc_split_offset += 188;
+
+					if ((frame_desc->length -
+					     qtd->isoc_split_offset) <= 188) {
+						qtd->isoc_split_pos =
+						    DWC_HCSPLIT_XACTPOS_END;
+					} else {
+						qtd->isoc_split_pos =
+						    DWC_HCSPLIT_XACTPOS_MID;
+					}
+
+				} while (0);
+				break;
+			}
+		} else {
+			halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
+		}
+	} else {
+		qtd->error_count = 0;
+
+		if (hc->qh->ping_state) {
+			hc->qh->ping_state = 0;
+			/*
+			 * Halt the channel so the transfer can be re-started
+			 * from the appropriate point. This only happens in
+			 * Slave mode. In DMA mode, the ping_state is cleared
+			 * when the transfer is started because the core
+			 * automatically executes the PING, then the transfer.
+			 */
+			halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_ACK);
+		}
+	}
+
+	/*
+	 * If the ACK occurred when _not_ in the PING state, let the channel
+	 * continue transferring data after clearing the error count.
+	 */
+
+	disable_hc_int(hc_regs, ack);
+
+	return 1;
+}
+
+/**
+ * Handles a host channel NYET interrupt. This interrupt should only occur on
+ * Bulk and Control OUT endpoints and for complete split transactions. If a
+ * NYET occurs at the same time as a Transfer Complete interrupt, it is
+ * handled in the xfercomp interrupt handler, not here. This handler may be
+ * called in either DMA mode or Slave mode.
+ */
+static int32_t handle_hc_nyet_intr(struct dwc_otg_hcd *hcd,
+				   struct dwc_hc *hc,
+				   struct dwc_otg_hc_regs *hc_regs,
+				   struct dwc_otg_qtd *qtd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "NYET Received--\n", hc->hc_num);
+
+	/*
+	 * NYET on CSPLIT
+	 * re-do the CSPLIT immediately on non-periodic
+	 */
+	if ((hc->do_split) && (hc->complete_split)) {
+		if ((hc->ep_type == DWC_OTG_EP_TYPE_INTR) ||
+		    (hc->ep_type == DWC_OTG_EP_TYPE_ISOC)) {
+			int frnum =
+			    dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_hcd
+							 (hcd));
+
+			if (dwc_full_frame_num(frnum) !=
+			    dwc_full_frame_num(hc->qh->sched_frame)) {
+				/*
+				 * No longer in the same full speed frame.
+				 * Treat this as a transaction error.
+				 */
+#if 0
+				/** @todo Fix system performance so this can
+				 * be treated as an error. Right now complete
+				 * splits cannot be scheduled precisely enough
+				 * due to other system activity, so this error
+				 * occurs regularly in Slave mode.
+				 */
+				qtd->error_count++;
+#endif
+				qtd->complete_split = 0;
+				halt_channel(hcd, hc, qtd,
+					     DWC_OTG_HC_XFER_XACT_ERR);
+				/** @todo add support for isoc release */
+				goto handle_nyet_done;
+			}
+		}
+
+		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
+		goto handle_nyet_done;
+	}
+
+	hc->qh->ping_state = 1;
+	qtd->error_count = 0;
+
+	update_urb_state_xfer_intr(hc, hc_regs, qtd->urb, qtd,
+				   DWC_OTG_HC_XFER_NYET);
+	save_data_toggle(hc, hc_regs, qtd);
+
+	/*
+	 * Halt the channel and re-start the transfer so the PING
+	 * protocol will start.
+	 */
+	halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_NYET);
+
+handle_nyet_done:
+	disable_hc_int(hc_regs, nyet);
+	return 1;
+}
+
+/**
+ * Handles a host channel babble interrupt. This handler may be called in
+ * either DMA mode or Slave mode.
+ */
+static int32_t handle_hc_babble_intr(struct dwc_otg_hcd *hcd,
+				     struct dwc_hc *hc,
+				     struct dwc_otg_hc_regs *hc_regs,
+				     struct dwc_otg_qtd *qtd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "Babble Error--\n", hc->hc_num);
+	if (hc->ep_type != DWC_OTG_EP_TYPE_ISOC) {
+		dwc_otg_hcd_complete_urb(hcd, qtd->urb, -EOVERFLOW);
+		qtd->urb = NULL;
+		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_BABBLE_ERR);
+	} else {
+		enum dwc_otg_halt_status halt_status;
+		halt_status = update_isoc_urb_state(hcd, hc, hc_regs, qtd,
+						    DWC_OTG_HC_XFER_BABBLE_ERR);
+		halt_channel(hcd, hc, qtd, halt_status);
+	}
+	disable_hc_int(hc_regs, bblerr);
+	return 1;
+}
+
+/**
+ * Handles a host channel AHB error interrupt. This handler is only called in
+ * DMA mode.
+ */
+static int32_t handle_hc_ahberr_intr(struct dwc_otg_hcd *hcd,
+				     struct dwc_hc *hc,
+				     struct dwc_otg_hc_regs *hc_regs,
+				     struct dwc_otg_qtd *qtd)
+{
+	union hcchar_data hcchar;
+	union hcsplt_data hcsplt;
+	union hctsiz_data hctsiz;
+	uint32_t hcdma;
+	struct urb *urb = qtd->urb;
+
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "AHB Error--\n", hc->hc_num);
+
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+	hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt);
+	hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
+	hcdma = dwc_read_reg32(&hc_regs->hcdma);
+
+	DWC_ERROR("AHB ERROR, Channel %d\n", hc->hc_num);
+	DWC_ERROR("  hcchar 0x%08x, hcsplt 0x%08x\n", hcchar.d32, hcsplt.d32);
+	DWC_ERROR("  hctsiz 0x%08x, hcdma 0x%08x\n", hctsiz.d32, hcdma);
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD URB Enqueue\n");
+	DWC_ERROR("  Device address: %d\n", usb_pipedevice(urb->pipe));
+	DWC_ERROR("  Endpoint: %d, %s\n", usb_pipeendpoint(urb->pipe),
+		  (usb_pipein(urb->pipe) ? "IN" : "OUT"));
+	DWC_ERROR("  Endpoint type: %s\n",
+		({
+			char *pipetype;
+			switch (usb_pipetype(urb->pipe)) {
+			case PIPE_CONTROL:
+				pipetype = "CONTROL";
+				break;
+			case PIPE_BULK:
+				pipetype = "BULK";
+				break;
+			case PIPE_INTERRUPT:
+				pipetype = "INTERRUPT";
+				break;
+			case PIPE_ISOCHRONOUS:
+				pipetype = "ISOCHRONOUS";
+				break;
+			default:
+				pipetype = "UNKNOWN";
+				break;
+			}
+			pipetype;
+		}));
+	DWC_ERROR("  Speed: %s\n",
+		({
+			char *speed;
+			switch (urb->dev->speed) {
+			case USB_SPEED_HIGH:
+				speed = "HIGH";
+				break;
+			case USB_SPEED_FULL:
+				speed = "FULL";
+				break;
+			case USB_SPEED_LOW:
+				speed = "LOW";
+				break;
+			default:
+				speed = "UNKNOWN";
+				break;
+			}
+			speed;
+		}));
+	DWC_ERROR("  Max packet size: %d\n",
+		  usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)));
+	DWC_ERROR("  Data buffer length: %d\n", urb->transfer_buffer_length);
+	DWC_ERROR("  Transfer buffer: %p, Transfer DMA: 0x%llx\n",
+		  urb->transfer_buffer, (unsigned long long)urb->transfer_dma);
+	DWC_ERROR("  Setup buffer: %p, Setup DMA: 0x%llx\n",
+		  urb->setup_packet, (unsigned long long)urb->setup_dma);
+	DWC_ERROR("  Interval: %d\n", urb->interval);
+
+	dwc_otg_hcd_complete_urb(hcd, urb, -EIO);
+	qtd->urb = NULL;
+
+	/*
+	 * Force a channel halt. Don't call halt_channel because that won't
+	 * write to the HCCHARn register in DMA mode to force the halt.
+	 */
+	dwc_otg_hc_halt(hcd->core_if, hc, DWC_OTG_HC_XFER_AHB_ERR);
+
+	disable_hc_int(hc_regs, ahberr);
+	return 1;
+}
+
+/**
+ * Handles a host channel transaction error interrupt. This handler may be
+ * called in either DMA mode or Slave mode.
+ */
+static int32_t handle_hc_xacterr_intr(struct dwc_otg_hcd *hcd,
+				      struct dwc_hc *hc,
+				      struct dwc_otg_hc_regs *hc_regs,
+				      struct dwc_otg_qtd *qtd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "Transaction Error--\n", hc->hc_num);
+
+	switch (usb_pipetype(qtd->urb->pipe)) {
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+		qtd->error_count++;
+		if (!hc->qh->ping_state) {
+			update_urb_state_xfer_intr(hc, hc_regs, qtd->urb,
+						   qtd,
+						   DWC_OTG_HC_XFER_XACT_ERR);
+			save_data_toggle(hc, hc_regs, qtd);
+			if (!hc->ep_is_in
+			    && qtd->urb->dev->speed == USB_SPEED_HIGH) {
+				hc->qh->ping_state = 1;
+			}
+		}
+
+		/*
+		 * Halt the channel so the transfer can be re-started from
+		 * the appropriate point or the PING protocol will start.
+		 */
+		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
+		break;
+	case PIPE_INTERRUPT:
+		qtd->error_count++;
+		if ((hc->do_split) && (hc->complete_split))
+			qtd->complete_split = 0;
+		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_XACT_ERR);
+		break;
+	case PIPE_ISOCHRONOUS:
+		{
+			enum dwc_otg_halt_status halt_status;
+			halt_status =
+			    update_isoc_urb_state(hcd, hc, hc_regs, qtd,
+						  DWC_OTG_HC_XFER_XACT_ERR);
+
+			halt_channel(hcd, hc, qtd, halt_status);
+		}
+		break;
+	}
+
+	disable_hc_int(hc_regs, xacterr);
+
+	return 1;
+}
+
+/**
+ * Handles a host channel frame overrun interrupt. This handler may be called
+ * in either DMA mode or Slave mode.
+ */
+static int32_t handle_hc_frmovrun_intr(struct dwc_otg_hcd *hcd,
+				       struct dwc_hc *hc,
+				       struct dwc_otg_hc_regs *hc_regs,
+				       struct dwc_otg_qtd *qtd)
+{
+	enum dwc_otg_halt_status halt_status;
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "Frame Overrun--\n", hc->hc_num);
+
+	switch (usb_pipetype(qtd->urb->pipe)) {
+	case PIPE_CONTROL:
+	case PIPE_BULK:
+		break;
+	case PIPE_INTERRUPT:
+		halt_channel(hcd, hc, qtd, DWC_OTG_HC_XFER_FRAME_OVERRUN);
+		break;
+	case PIPE_ISOCHRONOUS:
+		halt_status =
+			update_isoc_urb_state(hcd, hc, hc_regs, qtd,
+					      DWC_OTG_HC_XFER_FRAME_OVERRUN);
+			halt_channel(hcd, hc, qtd, halt_status);
+		break;
+	}
+
+	disable_hc_int(hc_regs, frmovrun);
+
+	return 1;
+}
+
+/**
+ * Handles a host channel data toggle error interrupt. This handler may be
+ * called in either DMA mode or Slave mode.
+ */
+static int32_t handle_hc_datatglerr_intr(struct dwc_otg_hcd *hcd,
+					 struct dwc_hc *hc,
+					 struct dwc_otg_hc_regs *hc_regs,
+					 struct dwc_otg_qtd *qtd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "Data Toggle Error--\n", hc->hc_num);
+
+	if (hc->ep_is_in) {
+		qtd->error_count = 0;
+	} else {
+		DWC_ERROR("Data Toggle Error on OUT transfer,"
+			  "channel %d\n", hc->hc_num);
+	}
+
+	disable_hc_int(hc_regs, datatglerr);
+
+	return 1;
+}
+
+#ifdef DEBUG
+/**
+ * This function is for debug only. It checks that a valid halt status is set
+ * and that HCCHARn.chdis is clear. If there's a problem, corrective action is
+ * taken and a warning is issued.
+ * Returns 1 if halt status is ok, 0 otherwise.
+ */
+static inline int halt_status_ok(struct dwc_otg_hcd *hcd,
+				 struct dwc_hc *hc,
+				 struct dwc_otg_hc_regs *hc_regs,
+				 struct dwc_otg_qtd *qtd)
+{
+	union hcchar_data hcchar;
+	union hctsiz_data hctsiz;
+	union hcint_data hcint;
+	union hcintmsk_data hcintmsk;
+	union hcsplt_data hcsplt;
+
+	if (hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS) {
+		/*
+		 * This code is here only as a check. This condition should
+		 * never happen. Ignore the halt if it does occur.
+		 */
+		hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+		hctsiz.d32 = dwc_read_reg32(&hc_regs->hctsiz);
+		hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+		hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk);
+		hcsplt.d32 = dwc_read_reg32(&hc_regs->hcsplt);
+		DWC_WARN
+		    ("%s: hc->halt_status == DWC_OTG_HC_XFER_NO_HALT_STATUS, "
+		     "channel %d, hcchar 0x%08x, hctsiz 0x%08x, "
+		     "hcint 0x%08x, hcintmsk 0x%08x, "
+		     "hcsplt 0x%08x, qtd->complete_split %d\n", __func__,
+		     hc->hc_num, hcchar.d32, hctsiz.d32, hcint.d32,
+		     hcintmsk.d32, hcsplt.d32, qtd->complete_split);
+
+		DWC_WARN("%s: no halt status, channel %d, ignoring interrupt\n",
+			 __func__, hc->hc_num);
+		DWC_WARN("\n");
+		clear_hc_int(hc_regs, chhltd);
+		return 0;
+	}
+
+	/*
+	 * This code is here only as a check. hcchar.chdis should
+	 * never be set when the halt interrupt occurs. Halt the
+	 * channel again if it does occur.
+	 */
+	hcchar.d32 = dwc_read_reg32(&hc_regs->hcchar);
+	if (hcchar.b.chdis) {
+		DWC_WARN("%s: hcchar.chdis set unexpectedly, "
+			 "hcchar 0x%08x, trying to halt again\n",
+			 __func__, hcchar.d32);
+		clear_hc_int(hc_regs, chhltd);
+		hc->halt_pending = 0;
+		halt_channel(hcd, hc, qtd, hc->halt_status);
+		return 0;
+	}
+
+	return 1;
+}
+#endif
+
+/**
+ * Handles a host Channel Halted interrupt in DMA mode. This handler
+ * determines the reason the channel halted and proceeds accordingly.
+ */
+static void handle_hc_chhltd_intr_dma(struct dwc_otg_hcd *hcd,
+				      struct dwc_hc *hc,
+				      struct dwc_otg_hc_regs *hc_regs,
+				      struct dwc_otg_qtd *qtd)
+{
+	union hcint_data hcint;
+	union hcintmsk_data hcintmsk;
+
+	if (hc->halt_status == DWC_OTG_HC_XFER_URB_DEQUEUE ||
+	    hc->halt_status == DWC_OTG_HC_XFER_AHB_ERR) {
+		/*
+		 * Just release the channel. A dequeue can happen on a
+		 * transfer timeout. In the case of an AHB Error, the channel
+		 * was forced to halt because there's no way to gracefully
+		 * recover.
+		 */
+		release_channel(hcd, hc, qtd, hc->halt_status);
+		return;
+	}
+
+	/* Read the HCINTn register to determine the cause for the halt. */
+	hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+	hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk);
+
+	if (hcint.b.xfercomp) {
+		/*
+		 * @todo This is here because of a possible hardware
+		 * bug.  Spec says that on SPLIT-ISOC OUT transfers in
+		 * DMA mode that a HALT interrupt w/ACK bit set should
+		 * occur, but I only see the XFERCOMP bit, even with
+		 * it masked out.  This is a workaround for that
+		 * behavior.  Should fix this when hardware is fixed.
+		 */
+		if ((hc->ep_type == DWC_OTG_EP_TYPE_ISOC) && (!hc->ep_is_in))
+			handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
+		handle_hc_xfercomp_intr(hcd, hc, hc_regs, qtd);
+	} else if (hcint.b.stall) {
+		handle_hc_stall_intr(hcd, hc, hc_regs, qtd);
+	} else if (hcint.b.xacterr) {
+		/*
+		 * Must handle xacterr before nak or ack. Could get a xacterr
+		 * at the same time as either of these on a BULK/CONTROL OUT
+		 * that started with a PING. The xacterr takes precedence.
+		 */
+		handle_hc_xacterr_intr(hcd, hc, hc_regs, qtd);
+	} else if (hcint.b.nyet) {
+		/*
+		 * Must handle nyet before nak or ack. Could get a nyet at the
+		 * same time as either of those on a BULK/CONTROL OUT that
+		 * started with a PING. The nyet takes precedence.
+		 */
+		handle_hc_nyet_intr(hcd, hc, hc_regs, qtd);
+	} else if (hcint.b.bblerr) {
+		handle_hc_babble_intr(hcd, hc, hc_regs, qtd);
+	} else if (hcint.b.frmovrun) {
+		handle_hc_frmovrun_intr(hcd, hc, hc_regs, qtd);
+	} else if (hcint.b.nak && !hcintmsk.b.nak) {
+		/*
+		 * If nak is not masked, it's because a non-split IN transfer
+		 * is in an error state. In that case, the nak is handled by
+		 * the nak interrupt handler, not here. Handle nak here for
+		 * BULK/CONTROL OUT transfers, which halt on a NAK to allow
+		 * rewinding the buffer pointer.
+		 */
+		handle_hc_nak_intr(hcd, hc, hc_regs, qtd);
+	} else if (hcint.b.ack && !hcintmsk.b.ack) {
+		/*
+		 * If ack is not masked, it's because a non-split IN transfer
+		 * is in an error state. In that case, the ack is handled by
+		 * the ack interrupt handler, not here. Handle ack here for
+		 * split transfers. Start splits halt on ACK.
+		 */
+		handle_hc_ack_intr(hcd, hc, hc_regs, qtd);
+	} else {
+		if (hc->ep_type == DWC_OTG_EP_TYPE_INTR ||
+		    hc->ep_type == DWC_OTG_EP_TYPE_ISOC) {
+			/*
+			 * A periodic transfer halted with no other channel
+			 * interrupts set. Assume it was halted by the core
+			 * because it could not be completed in its scheduled
+			 * (micro)frame.
+			 */
+#ifdef DEBUG
+			DWC_PRINT("%s: Halt channel %d (assume incomplete "
+				  "periodic transfer)\n",
+				__func__, hc->hc_num);
+#endif
+			halt_channel(hcd, hc, qtd,
+				     DWC_OTG_HC_XFER_PERIODIC_INCOMPLETE);
+		} else {
+			DWC_ERROR("%s: Channel %d, DMA Mode -- ChHltd set, "
+				  "but reason for halting is unknown, hcint "
+				  "0x%08x, intsts 0x%08x\n",
+				__func__, hc->hc_num, hcint.d32,
+				dwc_read_reg32(&hcd->core_if->core_global_regs->
+					gintsts));
+		}
+	}
+}
+
+/**
+ * Handles a host channel Channel Halted interrupt.
+ *
+ * In slave mode, this handler is called only when the driver specifically
+ * requests a halt. This occurs during handling other host channel interrupts
+ * (e.g. nak, xacterr, stall, nyet, etc.).
+ *
+ * In DMA mode, this is the interrupt that occurs when the core has finished
+ * processing a transfer on a channel. Other host channel interrupts (except
+ * ahberr) are disabled in DMA mode.
+ */
+static int32_t handle_hc_chhltd_intr(struct dwc_otg_hcd *hcd,
+				     struct dwc_hc *hc,
+				     struct dwc_otg_hc_regs *hc_regs,
+				     struct dwc_otg_qtd *qtd)
+{
+	DWC_DEBUGPL(DBG_HCD, "--Host Channel %d Interrupt: "
+		    "Channel Halted--\n", hc->hc_num);
+
+	if (hcd->core_if->dma_enable) {
+		handle_hc_chhltd_intr_dma(hcd, hc, hc_regs, qtd);
+	} else {
+#ifdef DEBUG
+		if (!halt_status_ok(hcd, hc, hc_regs, qtd))
+			return 1;
+#endif
+		release_channel(hcd, hc, qtd, hc->halt_status);
+	}
+
+	return 1;
+}
+
+/** Handles interrupt for a specific Host Channel */
+int32_t dwc_otg_hcd_handle_hc_n_intr(struct dwc_otg_hcd *dwc_otg_hcd,
+				     uint32_t _num)
+{
+	int retval = 0;
+	union hcint_data hcint;
+	union hcintmsk_data hcintmsk;
+	struct dwc_hc *hc;
+	struct dwc_otg_hc_regs *hc_regs;
+	struct dwc_otg_qtd *qtd;
+
+	DWC_DEBUGPL(DBG_HCDV, "--Host Channel Interrupt--, Channel %d\n", _num);
+
+	hc = dwc_otg_hcd->hc_ptr_array[_num];
+	hc_regs = dwc_otg_hcd->core_if->host_if->hc_regs[_num];
+	qtd = list_entry(hc->qh->qtd_list.next, struct dwc_otg_qtd,
+			 qtd_list_entry);
+
+	hcint.d32 = dwc_read_reg32(&hc_regs->hcint);
+	hcintmsk.d32 = dwc_read_reg32(&hc_regs->hcintmsk);
+	DWC_DEBUGPL(DBG_HCDV,
+		    "  hcint 0x%08x, hcintmsk 0x%08x, hcint&hcintmsk 0x%08x\n",
+		    hcint.d32, hcintmsk.d32, (hcint.d32 & hcintmsk.d32));
+	hcint.d32 = hcint.d32 & hcintmsk.d32;
+
+	if (!dwc_otg_hcd->core_if->dma_enable) {
+		if ((hcint.b.chhltd) && (hcint.d32 != 0x2))
+			hcint.b.chhltd = 0;
+	}
+
+	if (hcint.b.xfercomp) {
+		retval |=
+		    handle_hc_xfercomp_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+		/*
+		 * If NYET occurred at same time as Xfer Complete, the NYET is
+		 * handled by the Xfer Complete interrupt handler. Don't want
+		 * to call the NYET interrupt handler in this case.
+		 */
+		hcint.b.nyet = 0;
+	}
+	if (hcint.b.chhltd)
+		retval |= handle_hc_chhltd_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+
+	if (hcint.b.ahberr)
+		retval |= handle_hc_ahberr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+
+	if (hcint.b.stall)
+		retval |= handle_hc_stall_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+
+	if (hcint.b.nak)
+		retval |= handle_hc_nak_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+
+	if (hcint.b.ack)
+		retval |= handle_hc_ack_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+
+	if (hcint.b.nyet)
+		retval |= handle_hc_nyet_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+
+	if (hcint.b.xacterr)
+		retval |=
+		    handle_hc_xacterr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+
+	if (hcint.b.bblerr)
+		retval |= handle_hc_babble_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+
+	if (hcint.b.frmovrun)
+		retval |=
+		    handle_hc_frmovrun_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+
+	if (hcint.b.datatglerr)
+		retval |=
+		    handle_hc_datatglerr_intr(dwc_otg_hcd, hc, hc_regs, qtd);
+
+	return retval;
+}
+
+#endif /* DWC_DEVICE_ONLY */
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
new file mode 100644
index 0000000..e4c96f2
--- /dev/null
+++ b/drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c
@@ -0,0 +1,695 @@
+/* ==========================================================================
+ *
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+#ifndef DWC_DEVICE_ONLY
+
+/*
+ *
+ * This file contains the functions to manage Queue Heads and Queue
+ * Transfer Descriptors.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+
+#include "dwc_otg_driver.h"
+#include "dwc_otg_hcd.h"
+#include "dwc_otg_regs.h"
+
+/**
+ * This function allocates and initializes a QH.
+ *
+ * @hcd: The HCD state structure for the DWC OTG controller.
+ * @urb: Holds the information about the device/endpoint that we need
+ * to initialize the QH.
+ *
+ * Returns Returns pointer to the newly allocated QH, or NULL on error. */
+struct dwc_otg_qh *dwc_otg_hcd_qh_create(struct dwc_otg_hcd *hcd,
+				    struct urb *urb)
+{
+	struct dwc_otg_qh *qh;
+
+	/* Allocate memory */
+	/** @todo add memflags argument */
+	qh = dwc_otg_hcd_qh_alloc();
+	if (qh == NULL)
+		return NULL;
+
+	dwc_otg_hcd_qh_init(hcd, qh, urb);
+	return qh;
+}
+
+/** Free each QTD in the QH's QTD-list then free the QH.  QH should already be
+ * removed from a list.  QTD list should already be empty if called from URB
+ * Dequeue.
+ *
+ * @qh: The QH to free.
+ */
+void dwc_otg_hcd_qh_free(struct dwc_otg_qh *qh)
+{
+	struct dwc_otg_qtd *qtd;
+	struct list_head *pos;
+
+	/* Free each QTD in the QTD list */
+	for (pos = qh->qtd_list.next;
+	     pos != &qh->qtd_list; pos = qh->qtd_list.next) {
+		list_del(pos);
+		qtd = dwc_list_to_qtd(pos);
+		dwc_otg_hcd_qtd_free(qtd);
+	}
+
+	kfree(qh);
+	return;
+}
+
+/** Initializes a QH structure.
+ *
+ * @hcd: The HCD state structure for the DWC OTG controller.
+ * @qh: The QH to init.
+ * @urb: Holds the information about the device/endpoint that we need
+ * to initialize the QH. */
+#define SCHEDULE_SLOP 10
+void dwc_otg_hcd_qh_init(struct dwc_otg_hcd *hcd, struct dwc_otg_qh *qh,
+			 struct urb *urb)
+{
+	memset(qh, 0, sizeof(struct dwc_otg_qh));
+
+	/* Initialize QH */
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		qh->ep_type = USB_ENDPOINT_XFER_CONTROL;
+		break;
+	case PIPE_BULK:
+		qh->ep_type = USB_ENDPOINT_XFER_BULK;
+		break;
+	case PIPE_ISOCHRONOUS:
+		qh->ep_type = USB_ENDPOINT_XFER_ISOC;
+		break;
+	case PIPE_INTERRUPT:
+		qh->ep_type = USB_ENDPOINT_XFER_INT;
+		break;
+	}
+
+	qh->ep_is_in = usb_pipein(urb->pipe) ? 1 : 0;
+
+	qh->data_toggle = DWC_OTG_HC_PID_DATA0;
+	qh->maxp =
+	    usb_maxpacket(urb->dev, urb->pipe, !(usb_pipein(urb->pipe)));
+	INIT_LIST_HEAD(&qh->qtd_list);
+	INIT_LIST_HEAD(&qh->qh_list_entry);
+	qh->channel = NULL;
+
+	/* FS/LS Enpoint on HS Hub
+	 * NOT virtual root hub */
+	qh->do_split = 0;
+	if (((urb->dev->speed == USB_SPEED_LOW) ||
+	     (urb->dev->speed == USB_SPEED_FULL)) &&
+	    (urb->dev->tt) && (urb->dev->tt->hub->devnum != 1)) {
+		DWC_DEBUGPL(DBG_HCD,
+			    "QH init: EP %d: TT found at hub addr %d, for "
+			    "port %d\n",
+			    usb_pipeendpoint(urb->pipe),
+			    urb->dev->tt->hub->devnum, urb->dev->ttport);
+		qh->do_split = 1;
+	}
+
+	if (qh->ep_type == USB_ENDPOINT_XFER_INT ||
+	    qh->ep_type == USB_ENDPOINT_XFER_ISOC) {
+		/* Compute scheduling parameters once and save them. */
+		union hprt0_data hprt;
+
+		/* todo Account for split transfers in the bus time. */
+		int bytecount =
+		    dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);
+		/*
+		 * The results from usb_calc_bus_time are in nanosecs,
+		 * so divide the result by 1000 to convert to
+		 * microsecs expected by this driver
+		 */
+		qh->usecs = usb_calc_bus_time(urb->dev->speed,
+					       usb_pipein(urb->pipe),
+					       (qh->ep_type ==
+						USB_ENDPOINT_XFER_ISOC),
+					       bytecount) / 1000;
+
+		/* Start in a slightly future (micro)frame. */
+		qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
+						     SCHEDULE_SLOP);
+		qh->interval = urb->interval;
+#if 0
+		/* Increase interrupt polling rate for debugging. */
+		if (qh->ep_type == USB_ENDPOINT_XFER_INT)
+			qh->interval = 8;
+#endif
+		hprt.d32 = dwc_read_reg32(hcd->core_if->host_if->hprt0);
+		if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
+		    ((urb->dev->speed == USB_SPEED_LOW) ||
+		     (urb->dev->speed == USB_SPEED_FULL))) {
+			qh->interval *= 8;
+			qh->sched_frame |= 0x7;
+			qh->start_split_frame = qh->sched_frame;
+		}
+
+	}
+
+	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
+	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - qh = %p\n", qh);
+	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Device Address = %d\n",
+		    urb->dev->devnum);
+	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Endpoint %d, %s\n",
+		    usb_pipeendpoint(urb->pipe),
+		    usb_pipein(urb->pipe) == USB_DIR_IN ? "IN" : "OUT");
+	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Speed = %s\n",
+		({
+			char *speed;
+			switch (urb->dev->speed) {
+			case USB_SPEED_LOW:
+				speed = "low";
+				break;
+			case USB_SPEED_FULL:
+				speed = "full";
+				break;
+			case USB_SPEED_HIGH:
+				speed = "high";
+				break;
+			default:
+				speed = "?";
+				break;
+			}
+			speed;
+		}));
+	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Type = %s\n",
+		({
+			char *type;
+			switch (qh->ep_type) {
+			case USB_ENDPOINT_XFER_ISOC:
+				type = "isochronous";
+				break;
+			case USB_ENDPOINT_XFER_INT:
+				type = "interrupt";
+				break;
+			case USB_ENDPOINT_XFER_CONTROL:
+				type = "control";
+				break;
+			case USB_ENDPOINT_XFER_BULK:
+				type = "bulk";
+				break;
+			default:
+				type = "?";
+				break;
+			}
+			type;
+		}));
+#ifdef DEBUG
+	if (qh->ep_type == USB_ENDPOINT_XFER_INT) {
+		DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
+			    qh->usecs);
+		DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
+			    qh->interval);
+	}
+#endif
+
+	return;
+}
+
+/**
+ * Checks that a channel is available for a periodic transfer.
+ *
+ * Returns 0 if successful, negative error code otherise.
+ */
+static int periodic_channel_available(struct dwc_otg_hcd *hcd)
+{
+	/*
+	 * Currently assuming that there is a dedicated host channnel for each
+	 * periodic transaction plus at least one host channel for
+	 * non-periodic transactions.
+	 */
+	int status;
+	int num_channels;
+
+	num_channels = hcd->core_if->core_params->host_channels;
+	if ((hcd->periodic_channels + hcd->non_periodic_channels <
+	     num_channels) && (hcd->periodic_channels < num_channels - 1)) {
+		status = 0;
+	} else {
+		DWC_NOTICE
+		    ("%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n",
+		     __func__, num_channels, hcd->periodic_channels,
+		     hcd->non_periodic_channels);
+		status = -ENOSPC;
+	}
+
+	return status;
+}
+
+/**
+ * Checks that there is sufficient bandwidth for the specified QH in the
+ * periodic schedule. For simplicity, this calculation assumes that all the
+ * transfers in the periodic schedule may occur in the same (micro)frame.
+ *
+ * @hcd: The HCD state structure for the DWC OTG controller.
+ * @qh: QH containing periodic bandwidth required.
+ *
+ * Returns 0 if successful, negative error code otherwise.
+ */
+static int check_periodic_bandwidth(struct dwc_otg_hcd *hcd,
+				    struct dwc_otg_qh *qh)
+{
+	int status;
+	uint16_t max_claimed_usecs;
+
+	status = 0;
+
+	if (hcd->core_if->core_params->speed == DWC_SPEED_PARAM_HIGH) {
+		/*
+		 * High speed mode.
+		 * Max periodic usecs is 80% x 125 usec = 100 usec.
+		 */
+		max_claimed_usecs = 100 - qh->usecs;
+	} else {
+		/*
+		 * Full speed mode.
+		 * Max periodic usecs is 90% x 1000 usec = 900 usec.
+		 */
+		max_claimed_usecs = 900 - qh->usecs;
+	}
+
+	if (hcd->periodic_usecs > max_claimed_usecs) {
+		DWC_NOTICE("%s: already claimed usecs %d, required usecs %d\n",
+			   __func__, hcd->periodic_usecs, qh->usecs);
+		status = -ENOSPC;
+	}
+
+	return status;
+}
+
+/**
+ * Checks that the max transfer size allowed in a host channel is large enough
+ * to handle the maximum data transfer in a single (micro)frame for a periodic
+ * transfer.
+ *
+ * @hcd: The HCD state structure for the DWC OTG controller.
+ * @qh: QH for a periodic endpoint.
+ *
+ * Returns 0 if successful, negative error code otherwise.
+ */
+static int check_max_xfer_size(struct dwc_otg_hcd *hcd, struct dwc_otg_qh *qh)
+{
+	int status;
+	uint32_t max_xfer_size;
+	uint32_t max_channel_xfer_size;
+
+	status = 0;
+
+	max_xfer_size = dwc_max_packet(qh->maxp) * dwc_hb_mult(qh->maxp);
+	max_channel_xfer_size = hcd->core_if->core_params->max_transfer_size;
+
+	if (max_xfer_size > max_channel_xfer_size) {
+		DWC_NOTICE("%s: Periodic xfer length %d > "
+			   "max xfer length for channel %d\n",
+			   __func__, max_xfer_size, max_channel_xfer_size);
+		status = -ENOSPC;
+	}
+
+	return status;
+}
+
+/**
+ * Schedules an interrupt or isochronous transfer in the periodic schedule.
+ *
+ * @hcd: The HCD state structure for the DWC OTG controller.
+ * @qh: QH for the periodic transfer. The QH should already contain the
+ * scheduling information.
+ *
+ * Returns 0 if successful, negative error code otherwise.
+ */
+static int schedule_periodic(struct dwc_otg_hcd *hcd, struct dwc_otg_qh *qh)
+{
+	int status = 0;
+
+	status = periodic_channel_available(hcd);
+	if (status) {
+		DWC_NOTICE("%s: No host channel available for periodic "
+			   "transfer.\n", __func__);
+		return status;
+	}
+
+	status = check_periodic_bandwidth(hcd, qh);
+	if (status) {
+		DWC_NOTICE("%s: Insufficient periodic bandwidth for "
+			   "periodic transfer.\n", __func__);
+		return status;
+	}
+
+	status = check_max_xfer_size(hcd, qh);
+	if (status) {
+		DWC_NOTICE("%s: Channel max transfer size too small "
+			   "for periodic transfer.\n", __func__);
+		return status;
+	}
+
+	/* Always start in the inactive schedule. */
+	list_add_tail(&qh->qh_list_entry, &hcd->periodic_sched_inactive);
+
+	/* Reserve the periodic channel. */
+	hcd->periodic_channels++;
+
+	/* Update claimed usecs per (micro)frame. */
+	hcd->periodic_usecs += qh->usecs;
+
+	/*
+	 * Update average periodic bandwidth claimed and # periodic
+	 * reqs for usbfs.
+	 */
+	hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))->bandwidth_allocated +=
+	    qh->usecs / qh->interval;
+	if (qh->ep_type == USB_ENDPOINT_XFER_INT) {
+		hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))->bandwidth_int_reqs++;
+		DWC_DEBUGPL(DBG_HCD,
+			    "Scheduled intr: qh %p, usecs %d, period %d\n", qh,
+			    qh->usecs, qh->interval);
+	} else {
+		hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))->bandwidth_isoc_reqs++;
+		DWC_DEBUGPL(DBG_HCD,
+			    "Scheduled isoc: qh %p, usecs %d, period %d\n", qh,
+			    qh->usecs, qh->interval);
+	}
+
+	return status;
+}
+
+/**
+ * This function adds a QH to either the non periodic or periodic schedule if
+ * it is not already in the schedule. If the QH is already in the schedule, no
+ * action is taken.
+ *
+ * Returns 0 if successful, negative error code otherwise.
+ */
+int dwc_otg_hcd_qh_add(struct dwc_otg_hcd *hcd, struct dwc_otg_qh *qh)
+{
+	int status = 0;
+
+	if (!spin_is_locked(&hcd->global_lock))	{
+		pr_err("%s don't have hcd->global_lock", __func__);
+		BUG();
+	}
+
+	if (!list_empty(&qh->qh_list_entry)) {
+		/* QH already in a schedule. */
+		goto done;
+	}
+
+	/* Add the new QH to the appropriate schedule */
+	if (dwc_qh_is_non_per(qh)) {
+		/* Always start in the inactive schedule. */
+		list_add_tail(&qh->qh_list_entry,
+			      &hcd->non_periodic_sched_inactive);
+	} else {
+		status = schedule_periodic(hcd, qh);
+	}
+
+done:
+	return status;
+}
+
+/**
+ * Removes an interrupt or isochronous transfer from the periodic schedule.
+ *
+ * @hcd: The HCD state structure for the DWC OTG controller.
+ * @qh: QH for the periodic transfer.
+ */
+static void deschedule_periodic(struct dwc_otg_hcd *hcd, struct dwc_otg_qh *qh)
+{
+	list_del_init(&qh->qh_list_entry);
+
+	/* Release the periodic channel reservation. */
+	hcd->periodic_channels--;
+
+	/* Update claimed usecs per (micro)frame. */
+	hcd->periodic_usecs -= qh->usecs;
+
+	/*
+	 * Update average periodic bandwidth claimed and # periodic
+	 * reqs for usbfs.
+	 */
+	hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))->bandwidth_allocated -=
+	    qh->usecs / qh->interval;
+
+	if (qh->ep_type == USB_ENDPOINT_XFER_INT) {
+		hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))->bandwidth_int_reqs--;
+		DWC_DEBUGPL(DBG_HCD,
+			    "Descheduled intr: qh %p, usecs %d, period %d\n",
+			    qh, qh->usecs, qh->interval);
+	} else {
+		hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))->bandwidth_isoc_reqs--;
+		DWC_DEBUGPL(DBG_HCD,
+			    "Descheduled isoc: qh %p, usecs %d, period %d\n",
+			    qh, qh->usecs, qh->interval);
+	}
+}
+
+/**
+ * Removes a QH from either the non-periodic or periodic schedule.  Memory is
+ * not freed.
+ *
+ * @hcd: The HCD state structure.
+ * @qh: QH to remove from schedule. */
+void dwc_otg_hcd_qh_remove(struct dwc_otg_hcd *hcd, struct dwc_otg_qh *qh)
+{
+	if (!spin_is_locked(&hcd->global_lock))	{
+		pr_err("%s don't have hcd->global_lock", __func__);
+		BUG();
+	}
+
+	if (list_empty(&qh->qh_list_entry)) {
+		/* QH is not in a schedule. */
+		goto done;
+	}
+
+	if (dwc_qh_is_non_per(qh)) {
+		if (hcd->non_periodic_qh_ptr == &qh->qh_list_entry) {
+			hcd->non_periodic_qh_ptr =
+			    hcd->non_periodic_qh_ptr->next;
+		}
+		list_del_init(&qh->qh_list_entry);
+	} else {
+		deschedule_periodic(hcd, qh);
+	}
+
+done:
+	;
+}
+
+/**
+ * Deactivates a QH. For non-periodic QHs, removes the QH from the active
+ * non-periodic schedule. The QH is added to the inactive non-periodic
+ * schedule if any QTDs are still attached to the QH.
+ *
+ * For periodic QHs, the QH is removed from the periodic queued schedule. If
+ * there are any QTDs still attached to the QH, the QH is added to either the
+ * periodic inactive schedule or the periodic ready schedule and its next
+ * scheduled frame is calculated. The QH is placed in the ready schedule if
+ * the scheduled frame has been reached already. Otherwise it's placed in the
+ * inactive schedule. If there are no QTDs attached to the QH, the QH is
+ * completely removed from the periodic schedule.
+ */
+void dwc_otg_hcd_qh_deactivate(struct dwc_otg_hcd *hcd, struct dwc_otg_qh *qh,
+			       int sched_next_periodic_split)
+{
+	uint16_t frame_number;
+
+	if (!spin_is_locked(&hcd->global_lock))	{
+		pr_err("%s don't have hcd->global_lock", __func__);
+		BUG();
+	}
+
+	if (dwc_qh_is_non_per(qh)) {
+		dwc_otg_hcd_qh_remove(hcd, qh);
+		if (!list_empty(&qh->qtd_list))
+			/* Add back to inactive non-periodic schedule. */
+			dwc_otg_hcd_qh_add(hcd, qh);
+		return;
+	}
+
+	frame_number = dwc_otg_hcd_get_frame_number(dwc_otg_hcd_to_hcd(hcd));
+
+	if (qh->do_split) {
+		/* Schedule the next continuing periodic split transfer */
+		if (sched_next_periodic_split) {
+
+			qh->sched_frame = frame_number;
+			if (dwc_frame_num_le(frame_number,
+				dwc_frame_num_inc(qh->start_split_frame,
+						  1))) {
+				/*
+				 * Allow one frame to elapse after
+				 * start split microframe before
+				 * scheduling complete split, but DONT
+				 * if we are doing the next start
+				 * split in the same frame for an ISOC
+				 * out.
+				 */
+				if ((qh->ep_type != USB_ENDPOINT_XFER_ISOC)
+				     || (qh->ep_is_in != 0)) {
+					qh->sched_frame =
+						dwc_frame_num_inc(qh->sched_frame,
+								  1);
+				}
+			}
+		} else {
+			qh->sched_frame =
+				dwc_frame_num_inc(qh->start_split_frame,
+						  qh->interval);
+			if (dwc_frame_num_le(qh->sched_frame, frame_number))
+				qh->sched_frame = frame_number;
+
+			qh->sched_frame |= 0x7;
+			qh->start_split_frame = qh->sched_frame;
+		}
+	} else {
+		qh->sched_frame = dwc_frame_num_inc(qh->sched_frame,
+						    qh->interval);
+		if (dwc_frame_num_le(qh->sched_frame, frame_number))
+			qh->sched_frame = frame_number;
+	}
+
+	if (list_empty(&qh->qtd_list)) {
+		dwc_otg_hcd_qh_remove(hcd, qh);
+	} else {
+		/*
+		 * Remove from periodic_sched_queued and move to
+		 * appropriate queue.
+		 */
+		if (qh->sched_frame == frame_number) {
+			list_move(&qh->qh_list_entry,
+				&hcd->periodic_sched_ready);
+		} else {
+			list_move(&qh->qh_list_entry,
+				&hcd->periodic_sched_inactive);
+		}
+	}
+}
+
+/**
+ * This function allocates and initializes a QTD.
+ *
+ * @urb: The URB to create a QTD from.  Each URB-QTD pair will end up
+ * pointing to each other so each pair should have a unique correlation.
+ *
+ * Returns Returns pointer to the newly allocated QTD, or NULL on error. */
+struct dwc_otg_qtd *dwc_otg_hcd_qtd_create(struct urb *urb)
+{
+	struct dwc_otg_qtd *qtd;
+
+	qtd = dwc_otg_hcd_qtd_alloc();
+	if (qtd == NULL)
+		return NULL;
+
+	dwc_otg_hcd_qtd_init(qtd, urb);
+	return qtd;
+}
+
+/**
+ * Initializes a QTD structure.
+ *
+ * @qtd: The QTD to initialize.
+ * @urb: The URB to use for initialization.
+ */
+void dwc_otg_hcd_qtd_init(struct dwc_otg_qtd *qtd, struct urb *urb)
+{
+	memset(qtd, 0, sizeof(struct dwc_otg_qtd));
+	qtd->urb = urb;
+	if (usb_pipecontrol(urb->pipe)) {
+		/*
+		 * The only time the QTD data toggle is used is on the data
+		 * phase of control transfers. This phase always starts with
+		 * DATA1.
+		 */
+		qtd->data_toggle = DWC_OTG_HC_PID_DATA1;
+		qtd->control_phase = DWC_OTG_CONTROL_SETUP;
+	}
+
+	/* start split */
+	qtd->complete_split = 0;
+	qtd->isoc_split_pos = DWC_HCSPLIT_XACTPOS_ALL;
+	qtd->isoc_split_offset = 0;
+
+	/* Store the qtd ptr in the urb to reference what QTD. */
+	urb->hcpriv = qtd;
+	return;
+}
+
+/**
+ * This function adds a QTD to the QTD-list of a QH.  It will find the correct
+ * QH to place the QTD into.  If it does not find a QH, then it will create a
+ * new QH. If the QH to which the QTD is added is not currently scheduled, it
+ * is placed into the proper schedule based on its EP type.
+ *
+ * @qtd: The QTD to add
+ * @dwc_otg_hcd: The DWC HCD structure
+ *
+ * Returns 0 if successful, negative error code otherwise.
+ */
+int dwc_otg_hcd_qtd_add(struct dwc_otg_qtd *qtd,
+			struct dwc_otg_hcd *dwc_otg_hcd)
+{
+	struct usb_host_endpoint *ep;
+	struct dwc_otg_qh *qh;
+	int retval = 0;
+
+	struct urb *urb = qtd->urb;
+
+	/*
+	 * Get the QH which holds the QTD-list to insert to. Create QH if it
+	 * doesn't exist.
+	 */
+	ep = dwc_urb_to_endpoint(urb);
+	qh = ep->hcpriv;
+	if (qh == NULL) {
+		qh = dwc_otg_hcd_qh_create(dwc_otg_hcd, urb);
+		if (qh == NULL) {
+			retval = -ENOMEM;
+			goto done;
+		}
+		ep->hcpriv = qh;
+	}
+	qtd->qh = qh;
+	retval = dwc_otg_hcd_qh_add(dwc_otg_hcd, qh);
+	if (retval == 0)
+		list_add_tail(&qtd->qtd_list_entry, &qh->qtd_list);
+done:
+	return retval;
+}
+
+#endif /* DWC_DEVICE_ONLY */
diff --git a/drivers/usb/host/dwc_otg/dwc_otg_octeon.c b/drivers/usb/host/dwc_otg/dwc_otg_octeon.c
new file mode 100644
index 0000000..5e92b3c
--- /dev/null
+++ b/drivers/usb/host/dwc_otg/dwc_otg_octeon.c
@@ -0,0 +1,1078 @@
+/* ==========================================================================
+ * Synopsys HS OTG Linux Software Driver and documentation (hereinafter,
+ * "Software") is an Unsupported proprietary work of Synopsys, Inc. unless
+ * otherwise expressly agreed to in writing between Synopsys and you.
+ *
+ * The Software IS NOT an item of Licensed Software or Licensed Product under
+ * any End User Software License Agreement or Agreement for Licensed Product
+ * with Synopsys or any supplement thereto. You are permitted to use and
+ * redistribute this Software in source and binary forms, with or without
+ * modification, provided that redistributions of source code must retain this
+ * notice. You may not view, use, disclose, copy or distribute this file or
+ * any information contained herein except pursuant to this license grant from
+ * Synopsys. If you do not agree with this notice, including the disclaimer
+ * below, then you are not authorized to use the Software.
+ *
+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" BASIS
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE HEREBY DISCLAIMED. IN NO EVENT SHALL SYNOPSYS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * ========================================================================== */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/stat.h>		/* permission constants */
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include "dwc_otg_plat.h"
+#include "dwc_otg_attr.h"
+#include "dwc_otg_driver.h"
+#include "dwc_otg_cil.h"
+#ifndef DWC_HOST_ONLY
+#include "dwc_otg_pcd.h"
+#endif
+#include "dwc_otg_hcd.h"
+
+#define	DWC_DRIVER_VERSION	"2.40a 10-APR-2006"
+#define	DWC_DRIVER_DESC		"HS OTG USB Controller driver"
+
+static const char dwc_driver_name[] = "dwc_otg";
+int dwc_errata_write_count;	/* See dwc_otg_plat.h, dwc_write_reg32 */
+
+/*-------------------------------------------------------------------------*/
+/* Encapsulate the module parameter settings */
+
+static struct dwc_otg_core_params dwc_otg_module_params = {
+	.opt = -1,
+	.otg_cap = -1,
+	.dma_enable = -1,
+	.dma_burst_size = -1,
+	.speed = -1,
+	.host_support_fs_ls_low_power = -1,
+	.host_ls_low_power_phy_clk = -1,
+	.enable_dynamic_fifo = -1,
+	.data_fifo_size = -1,
+	.dev_rx_fifo_size = -1,
+	.dev_nperio_tx_fifo_size = -1,
+	.dev_perio_tx_fifo_size = {-1,	/* dev_perio_tx_fifo_size_1 */
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1,
+				   -1},	/* 15 */
+	.host_rx_fifo_size = -1,
+	.host_nperio_tx_fifo_size = -1,
+	.host_perio_tx_fifo_size = -1,
+	.max_transfer_size = -1,
+	.max_packet_count = -1,
+	.host_channels = -1,
+	.dev_endpoints = -1,
+	.phy_type = -1,
+	.phy_utmi_width = -1,
+	.phy_ulpi_ddr = -1,
+	.phy_ulpi_ext_vbus = -1,
+	.i2c_enable = -1,
+	.ulpi_fs_ls = -1,
+	.ts_dline = -1,
+};
+
+/**
+ * Global Debug Level Mask.
+ */
+uint32_t g_dbg_lvl;		/* 0 -> OFF */
+
+/**
+ * This function shows the Driver Version.
+ */
+static ssize_t version_show(struct device_driver *dev, char *buf)
+{
+	return snprintf(buf, sizeof(DWC_DRIVER_VERSION) + 2, "%s\n",
+			DWC_DRIVER_VERSION);
+}
+
+static DRIVER_ATTR(version, S_IRUGO, version_show, NULL);
+
+/**
+ * This function is called during module intialization to verify that
+ * the module parameters are in a valid state.
+ */
+static int check_parameters(struct dwc_otg_core_if *core_if)
+{
+	int i;
+	int retval = 0;
+
+/* Checks if the parameter is outside of its valid range of values */
+#define DWC_OTG_PARAM_TEST(_param_, _low_, _high_)    \
+	((dwc_otg_module_params._param_ < (_low_)) || \
+		(dwc_otg_module_params._param_ > (_high_)))
+
+/* If the parameter has been set by the user, check that the parameter value is
+ * within the value range of values.  If not, report a module error. */
+#define DWC_OTG_PARAM_ERR(_param_, _low_, _high_, _string_)	\
+	do {								\
+		if (dwc_otg_module_params._param_ != -1) {		\
+			if (DWC_OTG_PARAM_TEST(_param_, (_low_), (_high_))) { \
+				DWC_ERROR("`%d' invalid for parameter `%s'\n", \
+					dwc_otg_module_params._param_, _string_); \
+				dwc_otg_module_params._param_ = dwc_param_##_param_##_default; \
+				retval++; \
+			} \
+		} \
+	} while (0)
+
+	DWC_OTG_PARAM_ERR(opt, 0, 1, "opt");
+	DWC_OTG_PARAM_ERR(otg_cap, 0, 2, "otg_cap");
+	DWC_OTG_PARAM_ERR(dma_enable, 0, 1, "dma_enable");
+	DWC_OTG_PARAM_ERR(speed, 0, 1, "speed");
+	DWC_OTG_PARAM_ERR(host_support_fs_ls_low_power, 0, 1,
+			  "host_support_fs_ls_low_power");
+	DWC_OTG_PARAM_ERR(host_ls_low_power_phy_clk, 0, 1,
+			  "host_ls_low_power_phy_clk");
+	DWC_OTG_PARAM_ERR(enable_dynamic_fifo, 0, 1, "enable_dynamic_fifo");
+	DWC_OTG_PARAM_ERR(data_fifo_size, 32, 32768, "data_fifo_size");
+	DWC_OTG_PARAM_ERR(dev_rx_fifo_size, 16, 32768, "dev_rx_fifo_size");
+	DWC_OTG_PARAM_ERR(dev_nperio_tx_fifo_size, 16, 32768,
+			  "dev_nperio_tx_fifo_size");
+	DWC_OTG_PARAM_ERR(host_rx_fifo_size, 16, 32768, "host_rx_fifo_size");
+	DWC_OTG_PARAM_ERR(host_nperio_tx_fifo_size, 16, 32768,
+			  "host_nperio_tx_fifo_size");
+	DWC_OTG_PARAM_ERR(host_perio_tx_fifo_size, 16, 32768,
+			  "host_perio_tx_fifo_size");
+	DWC_OTG_PARAM_ERR(max_transfer_size, 2047, 524288, "max_transfer_size");
+	DWC_OTG_PARAM_ERR(max_packet_count, 15, 511, "max_packet_count");
+	DWC_OTG_PARAM_ERR(host_channels, 1, 16, "host_channels");
+	DWC_OTG_PARAM_ERR(dev_endpoints, 1, 15, "dev_endpoints");
+	DWC_OTG_PARAM_ERR(phy_type, 0, 2, "phy_type");
+	DWC_OTG_PARAM_ERR(phy_ulpi_ddr, 0, 1, "phy_ulpi_ddr");
+	DWC_OTG_PARAM_ERR(phy_ulpi_ext_vbus, 0, 1, "phy_ulpi_ext_vbus");
+	DWC_OTG_PARAM_ERR(i2c_enable, 0, 1, "i2c_enable");
+	DWC_OTG_PARAM_ERR(ulpi_fs_ls, 0, 1, "ulpi_fs_ls");
+	DWC_OTG_PARAM_ERR(ts_dline, 0, 1, "ts_dline");
+
+	if (dwc_otg_module_params.dma_burst_size != -1) {
+		if (DWC_OTG_PARAM_TEST(dma_burst_size, 1, 1) &&
+		    DWC_OTG_PARAM_TEST(dma_burst_size, 4, 4) &&
+		    DWC_OTG_PARAM_TEST(dma_burst_size, 8, 8) &&
+		    DWC_OTG_PARAM_TEST(dma_burst_size, 16, 16) &&
+		    DWC_OTG_PARAM_TEST(dma_burst_size, 32, 32) &&
+		    DWC_OTG_PARAM_TEST(dma_burst_size, 64, 64) &&
+		    DWC_OTG_PARAM_TEST(dma_burst_size, 128, 128) &&
+		    DWC_OTG_PARAM_TEST(dma_burst_size, 256, 256)) {
+			DWC_ERROR
+			    ("`%d' invalid for parameter `dma_burst_size'\n",
+			     dwc_otg_module_params.dma_burst_size);
+			dwc_otg_module_params.dma_burst_size = 32;
+			retval++;
+		}
+	}
+
+	if (dwc_otg_module_params.phy_utmi_width != -1) {
+		if (DWC_OTG_PARAM_TEST(phy_utmi_width, 8, 8) &&
+		    DWC_OTG_PARAM_TEST(phy_utmi_width, 16, 16)) {
+			DWC_ERROR
+			    ("`%d' invalid for parameter `phy_utmi_width'\n",
+			     dwc_otg_module_params.phy_utmi_width);
+			dwc_otg_module_params.phy_utmi_width = 16;
+			retval++;
+		}
+	}
+
+	for (i = 0; i < 15; i++) {
+		/* @todo should be like above */
+		if (dwc_otg_module_params.dev_perio_tx_fifo_size[i] !=
+		    (unsigned)-1) {
+			if (DWC_OTG_PARAM_TEST
+			    (dev_perio_tx_fifo_size[i], 4, 768)) {
+				DWC_ERROR
+				    ("`%d' invalid for parameter `%s_%d'\n",
+				     dwc_otg_module_params.
+				     dev_perio_tx_fifo_size[i],
+				     "dev_perio_tx_fifo_size", i);
+				dwc_otg_module_params.
+				    dev_perio_tx_fifo_size[i] =
+				    dwc_param_dev_perio_tx_fifo_size_default;
+				retval++;
+			}
+		}
+	}
+
+	/* At this point, all module parameters that have been set by the user
+	 * are valid, and those that have not are left unset.  Now set their
+	 * default values and/or check the parameters against the hardware
+	 * configurations of the OTG core. */
+
+/* This sets the parameter to the default value if it has not been set by the
+ * user */
+#define PARAM_SET_DEFAULT(_param_) \
+	({ \
+		int changed = 1; \
+		if (dwc_otg_module_params._param_ == -1) { \
+			changed = 0; \
+			dwc_otg_module_params._param_ = dwc_param_##_param_##_default; \
+		} \
+		changed; \
+	})
+
+/* This checks the macro agains the hardware configuration to see if it is
+ * valid.  It is possible that the default value could be invalid.  In this
+ * case, it will report a module error if the user touched the parameter.
+ * Otherwise it will adjust the value without any error. */
+#define PARAM_CHECK_VALID(_param_, _str_, _is_valid_, _set_valid_) \
+	({								\
+		int changed = PARAM_SET_DEFAULT(_param_);	\
+		int error = 0;						\
+		if (!(_is_valid_)) {					\
+			if (changed) {					\
+				DWC_ERROR("`%d' invalid for parameter `%s'.  Check HW configuration.\n", dwc_otg_module_params._param_, _str_); \
+				error = 1;				\
+			}						\
+			dwc_otg_module_params._param_ = (_set_valid_);	\
+		}							\
+		error;							\
+	})
+
+	/* OTG Cap */
+	retval += PARAM_CHECK_VALID(otg_cap, "otg_cap",
+		({
+			int valid;
+			valid = 1;
+			switch (dwc_otg_module_params.otg_cap) {
+			case DWC_OTG_CAP_PARAM_HNP_SRP_CAPABLE:
+				if (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
+					valid = 0;
+				break;
+			case DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE:
+				if ((core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
+					&& (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
+					&& (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
+					&& (core_if->hwcfg2.b.op_mode != DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST))
+					valid = 0;
+				break;
+			case DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE:
+				/* always valid */
+				break;
+			}
+			valid;
+		}),
+		(((core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_HNP_SRP_CAPABLE_OTG)
+			|| (core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_ONLY_CAPABLE_OTG)
+			|| (core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_DEVICE)
+			|| (core_if->hwcfg2.b.op_mode == DWC_HWCFG2_OP_MODE_SRP_CAPABLE_HOST))
+			?
+			DWC_OTG_CAP_PARAM_SRP_ONLY_CAPABLE : DWC_OTG_CAP_PARAM_NO_HNP_SRP_CAPABLE));
+
+	retval += PARAM_CHECK_VALID(dma_enable, "dma_enable",
+					((dwc_otg_module_params.
+						dma_enable == 1)
+						&& (core_if->hwcfg2.b.
+							architecture == 0)) ? 0 : 1,
+					0);
+
+	retval += PARAM_CHECK_VALID(opt, "opt", 1, 0);
+
+	PARAM_SET_DEFAULT(dma_burst_size);
+
+	retval += PARAM_CHECK_VALID(host_support_fs_ls_low_power,
+					    "host_support_fs_ls_low_power",
+					    1, 0);
+
+	retval += PARAM_CHECK_VALID(enable_dynamic_fifo,
+				    "enable_dynamic_fifo",
+				    ((dwc_otg_module_params.enable_dynamic_fifo == 0)
+				     || (core_if->hwcfg2.b.dynamic_fifo == 1)), 0);
+
+	retval += PARAM_CHECK_VALID(data_fifo_size,
+				    "data_fifo_size",
+				    dwc_otg_module_params.data_fifo_size <= core_if->hwcfg3.b.dfifo_depth,
+				    core_if->hwcfg3.b.dfifo_depth);
+
+	retval += PARAM_CHECK_VALID(dev_rx_fifo_size,
+				    "dev_rx_fifo_size",
+				    (dwc_otg_module_params.dev_rx_fifo_size <=
+					    dwc_read_reg32(&core_if->core_global_regs->grxfsiz)),
+				    dwc_read_reg32(&core_if->core_global_regs->grxfsiz));
+
+	retval += PARAM_CHECK_VALID(dev_nperio_tx_fifo_size,
+				    "dev_nperio_tx_fifo_size",
+				    dwc_otg_module_params.dev_nperio_tx_fifo_size <=
+					     (dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16),
+				    dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16);
+
+	retval += PARAM_CHECK_VALID(host_rx_fifo_size,
+				    "host_rx_fifo_size",
+				    dwc_otg_module_params.host_rx_fifo_size <=
+					dwc_read_reg32(&core_if->core_global_regs->grxfsiz),
+				    dwc_read_reg32(&core_if->core_global_regs->grxfsiz));
+
+	retval += PARAM_CHECK_VALID(host_nperio_tx_fifo_size,
+				    "host_nperio_tx_fifo_size",
+				    dwc_otg_module_params.host_nperio_tx_fifo_size <=
+					(dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16),
+				    dwc_read_reg32(&core_if->core_global_regs->gnptxfsiz) >> 16);
+
+	retval += PARAM_CHECK_VALID(host_perio_tx_fifo_size,
+				    "host_perio_tx_fifo_size",
+				    dwc_otg_module_params.host_perio_tx_fifo_size <=
+					(dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >> 16),
+				    (dwc_read_reg32(&core_if->core_global_regs->hptxfsiz) >> 16));
+
+	retval += PARAM_CHECK_VALID(max_transfer_size,
+				    "max_tran