LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v2][POWERPC] Fix initial lmb add region with a non-zero base
From: David Miller @ 2008-02-20  0:30 UTC (permalink / raw)
  To: galak; +Cc: sparclinux, linuxppc-dev, linux-kernel
In-Reply-To: <Pine.LNX.4.64.0802191350590.10089@blarg.am.freescale.net>

From: Kumar Gala <galak@kernel.crashing.org>
Date: Tue, 19 Feb 2008 13:51:37 -0600 (CST)

> If we add to an empty lmb region with a non-zero base we will not coalesce
> the number of regions down to one.  This causes problems on ppc32 for the
> memory region as its assumed to only have one region.
> 
> We can fix this easily by causing the initial add to replace the dummy
> region.
> 
> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
> ---
> 
> Fix a bug the initial patch introduced if we have a region that gets added
> at the beginning of the list we wouldn't actually add it.
> 
> Dave can you replace the patch in you tree with this one.

I think my tree has already or will soon be pulled in so
I don't want to rebase it.

Why don't you simply send me the relative bug fix instead?

Thanks!

^ permalink raw reply

* Re: [Linux-fbdev-devel] [PATCH 1/2] fb: add support for foreign endianness
From: Valdis.Kletnieks @ 2008-02-20  0:47 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-fbdev-devel, adaplas, Krzysztof Helt, linux-kernel,
	linuxppc-dev, Geert Uytterhoeven
In-Reply-To: <20080219040530.7b1d115d.akpm@linux-foundation.org>

[-- Attachment #1: Type: text/plain, Size: 886 bytes --]

On Tue, 19 Feb 2008 04:05:30 PST, Andrew Morton said:
> On Tue, 19 Feb 2008 12:27:54 +0100 Clemens Koller <clemens.koller@anagramm.de
> wrote:
> > That's not an issue in my case. The SM50x can be connected to
> > either an PCI or some Local/CPU-whateverbus IF.
> > I.e. on the MPC85xx PowerPC, PCI and LocalBus are separate bussses.
> > If the sm501 is attached to the MPC85xx' PCI like any other video card,
> > the PCI config-space is can be accessed as usual, whereas the framebuffer
> > memory area is byte-swapped compared to other common video cards.

> Anyway, my head is now officially spinning.  Did anyone actually have a
> reason why we shouldn't proceed with Anton's patch?

Clemens answered my question regarding the real-life existence of hardware
that would benefit.  I'd say if Anton's patch works on Clemens' hardware and
otherwise passes review, we should proceed...


[-- Attachment #2: Type: application/pgp-signature, Size: 226 bytes --]

^ permalink raw reply

* Re: [Linux-fbdev-devel] [PATCH 1/2] fb: add support for foreign endianness
From: Benjamin Herrenschmidt @ 2008-02-20  0:50 UTC (permalink / raw)
  To: Valdis.Kletnieks
  Cc: linux-fbdev-devel, adaplas, Krzysztof Helt, linux-kernel,
	linuxppc-dev, Geert Uytterhoeven, Andrew Morton
In-Reply-To: <28238.1203468428@turing-police.cc.vt.edu>


On Tue, 2008-02-19 at 19:47 -0500, Valdis.Kletnieks@vt.edu wrote:
> On Tue, 19 Feb 2008 04:05:30 PST, Andrew Morton said:
> > On Tue, 19 Feb 2008 12:27:54 +0100 Clemens Koller <clemens.koller@anagramm.de
> > wrote:
> > > That's not an issue in my case. The SM50x can be connected to
> > > either an PCI or some Local/CPU-whateverbus IF.
> > > I.e. on the MPC85xx PowerPC, PCI and LocalBus are separate bussses.
> > > If the sm501 is attached to the MPC85xx' PCI like any other video card,
> > > the PCI config-space is can be accessed as usual, whereas the framebuffer
> > > memory area is byte-swapped compared to other common video cards.
> 
> > Anyway, my head is now officially spinning.  Did anyone actually have a
> > reason why we shouldn't proceed with Anton's patch?
> 
> Clemens answered my question regarding the real-life existence of hardware
> that would benefit.  I'd say if Anton's patch works on Clemens' hardware and
> otherwise passes review, we should proceed...

No objection here neither.

Ben.

^ permalink raw reply

* Re: [Linux-fbdev-devel] [PATCH 1/2] fb: add support for foreign endianness
From: Paul Mackerras @ 2008-02-20  0:56 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-fbdev-devel, adaplas, Krzysztof Helt, linux-kernel,
	linuxppc-dev, Geert Uytterhoeven
In-Reply-To: <20080219040530.7b1d115d.akpm@linux-foundation.org>

Andrew Morton writes:

> Bizarrely, the original author of the patch (Anton) has fallen off the cc. 
> Could whoever did that please thwap himself?
> 
> Anyway, my head is now officially spinning.  Did anyone actually have a
> reason why we shouldn't proceed with Anton's patch?

I was wondering if it would be sufficient to provide alternative
versions of fb_readl, fb_writel etc. that do byte-swapping.  That
would mean that all framebuffers would have to have the same
endianness, but that would suffice for embedded systems such as
Anton's and would end up a lot simpler IMHO.

Paul.

^ permalink raw reply

* Re: libfdt: More tests of NOP handling behaviour
From: Jerry Van Baren @ 2008-02-20  1:18 UTC (permalink / raw)
  To: Jon Loeliger; +Cc: linuxppc-dev, David Gibson
In-Reply-To: <E1JR6vQ-0000h9-2f@jdl.com>

Jon Loeliger wrote:
> So, like, the other day David Gibson mumbled:
>> In light of the recently discovered bug with NOP handling, this adds
>> some more testcases for NOP handling.  Specifically, it adds a helper
>> program which will add a NOP tag after every existing tag in a dtb,
>> and runs the standard battery of tests over trees mangled in this way.
>>
>> For now, this does not add a NOP at the very beginning of the
>> structure block.  This causes problems for libfdt at present, because
>> we assume in many places that the root node's BEGIN_NODE tag is at
>> offset 0.  I'm still contemplating what to do about this (with one
>> option being simply to declare such dtbs invalid).
>>
>> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> 
> Applied.
> 
> BTW, declaring DTBs with BEGIN_NODES not at offset 0
> as invalid seems like a fine choice to me.
> 
> jdl

FWIIW, I vote ditto on declaring DTBs with BEGIN_NODES not at offset 0 
as invalid.  The root being at offset 0 assumption is pretty well 
entrenched and I cannot think of any reason to change it that would be 
worth the effort.

Best regards,
gvb

^ permalink raw reply

* Re: libfdt: More tests of NOP handling behaviour
From: David Gibson @ 2008-02-20  2:04 UTC (permalink / raw)
  To: Jerry Van Baren; +Cc: linuxppc-dev, Jon Loeliger
In-Reply-To: <47BB7FDB.3050809@gmail.com>

On Tue, Feb 19, 2008 at 08:18:19PM -0500, Jerry Van Baren wrote:
> Jon Loeliger wrote:
> > So, like, the other day David Gibson mumbled:
> >> In light of the recently discovered bug with NOP handling, this adds
> >> some more testcases for NOP handling.  Specifically, it adds a helper
> >> program which will add a NOP tag after every existing tag in a dtb,
> >> and runs the standard battery of tests over trees mangled in this way.
> >>
> >> For now, this does not add a NOP at the very beginning of the
> >> structure block.  This causes problems for libfdt at present, because
> >> we assume in many places that the root node's BEGIN_NODE tag is at
> >> offset 0.  I'm still contemplating what to do about this (with one
> >> option being simply to declare such dtbs invalid).
> >>
> >> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> > 
> > Applied.
> > 
> > BTW, declaring DTBs with BEGIN_NODES not at offset 0
> > as invalid seems like a fine choice to me.
> > 
> > jdl
> 
> FWIIW, I vote ditto on declaring DTBs with BEGIN_NODES not at offset 0 
> as invalid.  The root being at offset 0 assumption is pretty well 
> entrenched and I cannot think of any reason to change it that would be 
> worth the effort.

Well, it's actually not that hard to deal with.  I've already been
planning to add a helper function/macro which validates a node offset
(something currently open-coded in a whole bunch of places).  It would
be fairly easy to make it skip over nops as well.

But, likewise I can think of no reason that NOPs before the root node
would be useful or likely to occur in practice.

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

^ permalink raw reply

* Re: [PATCH v2][POWERPC] Fix initial lmb add region with a non-zero base
From: Kumar Gala @ 2008-02-20  3:02 UTC (permalink / raw)
  To: David Miller; +Cc: sparclinux, linuxppc-dev, linux-kernel
In-Reply-To: <20080219.163003.152862383.davem@davemloft.net>


On Feb 19, 2008, at 6:30 PM, David Miller wrote:

> From: Kumar Gala <galak@kernel.crashing.org>
> Date: Tue, 19 Feb 2008 13:51:37 -0600 (CST)
>
>> If we add to an empty lmb region with a non-zero base we will not  
>> coalesce
>> the number of regions down to one.  This causes problems on ppc32  
>> for the
>> memory region as its assumed to only have one region.
>>
>> We can fix this easily by causing the initial add to replace the  
>> dummy
>> region.
>>
>> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
>> ---
>>
>> Fix a bug the initial patch introduced if we have a region that  
>> gets added
>> at the beginning of the list we wouldn't actually add it.
>>
>> Dave can you replace the patch in you tree with this one.
>
> I think my tree has already or will soon be pulled in so
> I don't want to rebase it.
>
> Why don't you simply send me the relative bug fix instead?

np.  Are we trying to get this into 2.6.25 or .26?

- k

^ permalink raw reply

* Re: [PATCH v2][POWERPC] Fix initial lmb add region with a non-zero base
From: David Miller @ 2008-02-20  3:31 UTC (permalink / raw)
  To: galak; +Cc: sparclinux, linuxppc-dev, linux-kernel
In-Reply-To: <4130F47E-4F4A-4911-B63B-403A8C423565@kernel.crashing.org>

From: Kumar Gala <galak@kernel.crashing.org>
Date: Tue, 19 Feb 2008 21:02:04 -0600

> np.  Are we trying to get this into 2.6.25 or .26?

I'm ambivalent but I would obviously prefer 2.6.25 because
it would allow me to proceed more easily with my sparc64
NUMA work as well as get your bug fixes in more smoothly.

^ permalink raw reply

* Please pull powerpc.git merge branch
From: Paul Mackerras @ 2008-02-20  3:46 UTC (permalink / raw)
  To: torvalds; +Cc: linuxppc-dev, akpm, linux-kernel

Linus,

Please do

git pull \
git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc.git merge

to get a few more bug and warning fixes for powerpc.  The diffstat is
bloated by the defconfig updates -- the actual code changes are only a
few dozen lines.

Thanks,
Paul.

 arch/powerpc/boot/Makefile             |    8 
 arch/powerpc/boot/dts/bamboo.dts       |    3 
 arch/powerpc/boot/dts/ebony.dts        |    2 
 arch/powerpc/boot/dts/katmai.dts       |    2 
 arch/powerpc/boot/dts/kilauea.dts      |    3 
 arch/powerpc/boot/dts/makalu.dts       |    3 
 arch/powerpc/boot/dts/rainier.dts      |    4 
 arch/powerpc/boot/dts/sequoia.dts      |    4 
 arch/powerpc/boot/dts/taishan.dts      |    4 
 arch/powerpc/configs/bamboo_defconfig  |   81 ++-
 arch/powerpc/configs/ebony_defconfig   |   79 ++-
 arch/powerpc/configs/ep405_defconfig   |   92 ++-
 arch/powerpc/configs/kilauea_defconfig |   69 ++
 arch/powerpc/configs/makalu_defconfig  |   69 ++
 arch/powerpc/configs/ppc44x_defconfig  |  904 ++++++++++++++++++++++++++++++++
 arch/powerpc/configs/rainier_defconfig |   82 ++-
 arch/powerpc/configs/sequoia_defconfig |   77 ++-
 arch/powerpc/configs/taishan_defconfig |   81 ++-
 arch/powerpc/configs/walnut_defconfig  |   81 ++-
 arch/powerpc/configs/warp_defconfig    |  139 +++--
 arch/powerpc/kernel/kprobes.c          |    9 
 arch/powerpc/kernel/prom.c             |   13 
 arch/powerpc/platforms/44x/Kconfig     |   10 
 arch/powerpc/platforms/pseries/power.c |    2 
 arch/ppc/platforms/4xx/ibm440ep.c      |    6 
 drivers/net/ibm_newemac/rgmii.c        |    1 
 26 files changed, 1497 insertions(+), 331 deletions(-)
 create mode 100644 arch/powerpc/configs/ppc44x_defconfig

Ananth N Mavinakayanahalli (1):
      [POWERPC] Kill sparse warnings in kprobes

Becky Bruce (1):
      [POWERPC] Fix dt_mem_next_cell() to read the full address

Josh Boyer (4):
      [POWERPC] 4xx: Update defconfigs for 2.6.25
      [POWERPC] 44x: Fix Kconfig formatting
      [POWERPC] 44x: Add multiplatform defconfig
      [POWERPC] Fix bootwrapper builds with older gcc versions

Stefan Roese (2):
      [POWERPC] net: NEWEMAC: Remove "rgmii-interface" from rgmii matching table
      [POWERPC] 4xx: Remove "i2c" and "xxmii-interface" device_types from dts

Stephen Rothwell (1):
      [POWERPC] Fix warning in pseries/power.c

Wolfgang Ocker (1):
      [POWERPC] PPC440EP Interrupt Triggering and Level Settings

^ permalink raw reply

* Sample driver
From: Silwer star @ 2008-02-20  4:13 UTC (permalink / raw)
  To: linuxppc-embedded


Does anyone have sample drivers in Linux for the EBC interface for PPC405Ex?
I would be thankful if someone could put in a sample code here. 
-- 
View this message in context: http://www.nabble.com/Sample-driver-tp15582059p15582059.html
Sent from the linuxppc-embedded mailing list archive at Nabble.com.

^ permalink raw reply

* [PATCH] [LMB]: Fix lmb_add_region if region should be added at the head
From: Kumar Gala @ 2008-02-20  4:27 UTC (permalink / raw)
  To: davem; +Cc: sparclinux, linuxppc-dev, linux-kernel

We introduced a bug in fixing lmb_add_region to handle an initial
region being non-zero.  Before that fix it was impossible to insert
a region at the head of the list since the first region always started
at zero.

Now that its possible for the first region to be non-zero we need to
check to see if the new region should be added at the head and if so
actually add it.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 lib/lmb.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/lib/lmb.c b/lib/lmb.c
index e3c8dcb..3c43b95 100644
--- a/lib/lmb.c
+++ b/lib/lmb.c
@@ -184,6 +184,11 @@ static long __init lmb_add_region(struct lmb_region *rgn, u64 base, u64 size)
 			break;
 		}
 	}
+
+	if (base < rgn->region[0].base) {
+		rgn->region[0].base = base;
+		rgn->region[0].size = size;
+	}
 	rgn->cnt++;

 	return 0;
-- 
1.5.3.8

^ permalink raw reply related

* Re: [PATCH] [LMB]: Fix lmb_add_region if region should be added at the head
From: David Miller @ 2008-02-20  4:45 UTC (permalink / raw)
  To: galak; +Cc: sparclinux, linuxppc-dev, linux-kernel
In-Reply-To: <Pine.LNX.4.64.0802192227170.2215@blarg.am.freescale.net>

From: Kumar Gala <galak@kernel.crashing.org>
Date: Tue, 19 Feb 2008 22:27:48 -0600 (CST)

> We introduced a bug in fixing lmb_add_region to handle an initial
> region being non-zero.  Before that fix it was impossible to insert
> a region at the head of the list since the first region always started
> at zero.
> 
> Now that its possible for the first region to be non-zero we need to
> check to see if the new region should be added at the head and if so
> actually add it.
> 
> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
 ...
> @@ -184,6 +184,11 @@ static long __init lmb_add_region(struct lmb_region *rgn, u64 base, u64 size)
>  			break;
>  		}
>  	}
> +
> +	if (base < rgn->region[0].base) {
> +		rgn->region[0].base = base;
> +		rgn->region[0].size = size;
> +	}
>  	rgn->cnt++;
> 
>  	return 0;

Are you sure this is sufficient?

It seems to me, to handle this properly, you'll need to handle
the case where the lower addressed entry you are inserting is
not contiguous with the existing entry 0.

Therefore, you need to move all existing entries up a slot,
then you can set the 0 entry to 'base' and 'size'.

What do you think?

^ permalink raw reply

* Re: [PATCH] [LMB]: Fix lmb_add_region if region should be added at the head
From: Kumar Gala @ 2008-02-20  5:16 UTC (permalink / raw)
  To: David Miller; +Cc: sparclinux, linuxppc-dev, linux-kernel
In-Reply-To: <20080219.204525.193731674.davem@davemloft.net>


On Feb 19, 2008, at 10:45 PM, David Miller wrote:

> From: Kumar Gala <galak@kernel.crashing.org>
> Date: Tue, 19 Feb 2008 22:27:48 -0600 (CST)
>
>> We introduced a bug in fixing lmb_add_region to handle an initial
>> region being non-zero.  Before that fix it was impossible to insert
>> a region at the head of the list since the first region always  
>> started
>> at zero.
>>
>> Now that its possible for the first region to be non-zero we need to
>> check to see if the new region should be added at the head and if so
>> actually add it.
>>
>> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
> ...
>> @@ -184,6 +184,11 @@ static long __init lmb_add_region(struct  
>> lmb_region *rgn, u64 base, u64 size)
>> 			break;
>> 		}
>> 	}
>> +
>> +	if (base < rgn->region[0].base) {
>> +		rgn->region[0].base = base;
>> +		rgn->region[0].size = size;
>> +	}
>> 	rgn->cnt++;
>>
>> 	return 0;
>
> Are you sure this is sufficient?
>
> It seems to me, to handle this properly, you'll need to handle
> the case where the lower addressed entry you are inserting is
> not contiguous with the existing entry 0.
>
> Therefore, you need to move all existing entries up a slot,
> then you can set the 0 entry to 'base' and 'size'.

The for loop above the code I added will move all the existing slots  
up one.  Its just the tail cleanup we are missing.

- k

^ permalink raw reply

* Re: 2.6.24 for mpc8458amc
From: Kumar Gala @ 2008-02-20  5:19 UTC (permalink / raw)
  To: raul.moreno
  Cc: maxime louvel,
	linuxppc-embedded-bounces+raul.moreno=telvent.abengoa.com,
	linuxppc-embedded
In-Reply-To: <OF5ABF0D8A.75A05AE1-ONC12573F4.00426B12-C12573F4.0043B5F0@abengoa.com>


On Feb 19, 2008, at 6:19 AM, raul.moreno@telvent.abengoa.com wrote:

>
> Hello Maxime,
>
> if your board is still running, although you can't see the messages  
> that
> means you don't have any console. Try to set one (I think you can  
> use a SCM
> of the CPM) in the kernel configuration (characters devices)  or in  
> the
> command line (console=).

If you really have a mpc8548 than there is no CPM.  It has 16550 style  
UARTs on it.

- k

^ permalink raw reply

* Re: [PATCH] [LMB]: Fix lmb_add_region if region should be added at the head
From: David Miller @ 2008-02-20  5:26 UTC (permalink / raw)
  To: galak; +Cc: sparclinux, linuxppc-dev, linux-kernel
In-Reply-To: <7A7ECF09-E547-4C04-A388-C3E8755478DD@kernel.crashing.org>

From: Kumar Gala <galak@kernel.crashing.org>
Date: Tue, 19 Feb 2008 23:16:18 -0600

> The for loop above the code I added will move all the existing slots  
> up one.  Its just the tail cleanup we are missing.

Aha, I see how this works now, thanks!

I'll add this to my LMB tree.

^ permalink raw reply

* Re: [PATCH] [LMB]: Fix lmb_add_region if region should be added at the head
From: Kumar Gala @ 2008-02-20  5:29 UTC (permalink / raw)
  To: David Miller; +Cc: sparclinux, linuxppc-dev, linux-kernel
In-Reply-To: <20080219.212655.173468988.davem@davemloft.net>


On Feb 19, 2008, at 11:26 PM, David Miller wrote:

> From: Kumar Gala <galak@kernel.crashing.org>
> Date: Tue, 19 Feb 2008 23:16:18 -0600
>
>> The for loop above the code I added will move all the existing slots
>> up one.  Its just the tail cleanup we are missing.
>
> Aha, I see how this works now, thanks!
>
> I'll add this to my LMB tree.

Sounds good.  Now just convince Paul or Linus to pull this in for  
2.6.25 :)

- k

^ permalink raw reply

* [GIT PULL] Please pull spufs.git master branch
From: Jeremy Kerr @ 2008-02-20  5:36 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev, cbe-oss-dev

Hi Paul,

Please do a:

git pull \
    git://git.kernel.org/pub/scm/linux/kernel/git/jk/spufs.git master

I have two new bugfixes for spufs: these are both fixes for regressions
since .24.

Cheers,


Jeremy


--- 2 commits:

  [POWERPC] spufs: fix scheduler starvation by idle contexts
    Jeremy Kerr <jk@ozlabs.org>

    arch/powerpc/platforms/cell/spufs/run.c   |    1 +
    arch/powerpc/platforms/cell/spufs/sched.c |    8 +++-----
    2 files changed, 4 insertions(+), 5 deletions(-)
   
  [POWERPC] cell: fix spurious false return from spu_trap_data_{map,seg}
    Andre Detsch <adetsch@br.ibm.com>

    arch/powerpc/platforms/cell/spu_base.c     |   12 ------------
    arch/powerpc/platforms/cell/spufs/switch.c |    6 +++---
    include/asm-powerpc/spu.h                  |    3 +--
    3 files changed, 4 insertions(+), 17 deletions(-)
   

^ permalink raw reply

* Re: [patch 0/4] RFC: PCI: consolidate several pcibios_enable_resources() implementations
From: Grant Grundler @ 2008-02-20  6:24 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: linux-arch, Chris Zankel, Grant Grundler, linux-parisc,
	Matthew Wilcox, Kyle McMartin, linuxppc-dev, Paul Mackerras,
	linux-pci, linux-arm-kernel, Russell King
In-Reply-To: <20080219043952.845136014@ldl.fc.hp.com>

On Mon, Feb 18, 2008 at 09:39:52PM -0700, Bjorn Helgaas wrote:
> There are many implementations of pcibios_enable_resources() that differ
> in minor ways that look more like bugs than architectural differences.
> This patch series consolidates most of them to use the x86 version.
> 
> This series is for discussion only at this point.  I'm interested in
> feedback about whether any of the differences are "real" and need to
> be preserved.
> 
> ARM and PA-RISC, in particular, have interesting differences:
>     - ARM always enables bridge devices, which no other arch does
>     - PA-RISC always turns on SERR and PARITY, which no other arch does
> 
> Should other arches do the same thing, or are these somehow related to
> ARM and PA-RISC architecture?

My impression was most x86 BIOS's did NOT turn on SERR/PERR when I added
that code to parisc-linux port (2000 or 2001 so) . HPUX was turning on
SERR/PERR and so I was comfortable the HW was stable and it not crash
under normal use unless something was really broken.

There is certainly nothing architectural specific about SERR/PERR.
I felt (at the time) this is more of a case of "if it's not reported to the
user, we won't get blamed for it not working well."

hth,
grant

^ permalink raw reply

* Re: [PATCH 2/2] i2c-ibm_iic driver
From: Jean Delvare @ 2008-02-20  6:57 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev, Stefan Roese, i2c, Sean MacLennan
In-Reply-To: <200802192355.17707.arnd@arndb.de>

Hi Arnd,

On Tue, 19 Feb 2008 23:55:16 +0100, Arnd Bergmann wrote:
> On Tuesday 19 February 2008, Stefan Roese wrote:
> > On Tuesday 19 February 2008, Jean Delvare wrote:
> > >
> > > With this Kconfig change, "make menuconfig" lets me select the
> > > i2c-ibm_iic driver on x86_64, but it fails to build horribly. I think
> > > that you want to restrict the build to PPC machines somehow, or at
> > > least make sure that either IBM_OCP or OF support is present.
> >=20
> > How about this:
> >=20
> > -=A0=A0=A0=A0=A0=A0=A0depends on IBM_OCP
> > +=A0=A0=A0=A0=A0=A0=A0depends on 4xx
>=20
> I think we should allow it to be built on other platforms as well,
> as long as they have of_platform_device support.
>=20
> The Axon south bridge used on IBMs QS21 blade probably has an ibm_iic,
> even though it's managed by the firmware and we probably don't want
> to use it at this time, someone could use the same chip in a new
> design and actually do that.
>=20
> In general, I also like to make it possible to enable drivers just
> for the benefit of compile testing, even for stuff that you can't
> find in any existing HW configuration, so as long as it builds on
> a platform, I think we shouldn't forbid it:

Fine with me as long as the default is set appropriately (i.e. default
to not building the driver on archs/platforms where it builds but is
known to be useless.)

>=20
> -       depends on IBM_OCP
> +       depends on IBM_OCP || PPC_MERGE

--=20
Jean Delvare

^ permalink raw reply

* Re: [PATCH 2/2] i2c-ibm_iic driver
From: Jean Delvare @ 2008-02-20  7:20 UTC (permalink / raw)
  To: Sean MacLennan; +Cc: LinuxPPC-dev, i2c
In-Reply-To: <47BB50E9.60508@pikatech.com>

Hi Sean,

On Tue, 19 Feb 2008 16:58:01 -0500, Sean MacLennan wrote:
> Signed-off-by: Sean MacLennan <smaclennan@pikatech.com>
> 
> --- for-2.6.25/drivers/i2c/busses/orig-i2c-ibm_iic.c	2008-02-18 16:36:30.000000000 -0500
> +++ for-2.6.25/drivers/i2c/busses/i2c-ibm_iic.c	2008-02-19 16:46:35.000000000 -0500
> @@ -6,6 +6,9 @@
>   * Copyright (c) 2003, 2004 Zultys Technologies.
>   * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
>   *
> + * Copyright (c) 2008 PIKA Technologies
> + * Sean MacLennan <smaclennan@pikatech.com>
> + *
>   * Based on original work by
>   * 	Ian DaSilva  <idasilva@mvista.com>
>   *      Armin Kuster <akuster@mvista.com>
> (...)
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -244,7 +244,7 @@ config I2C_PIIX4
>  
>  config I2C_IBM_IIC
>  	tristate "IBM PPC 4xx on-chip I2C interface"
> -	depends on IBM_OCP
> +	depends on 4xx
>  	help
>  	  Say Y here if you want to use IIC peripheral found on 
>  	  embedded IBM PPC 4xx based systems. 

I've applied this version. I see that there are discussions going on
about the best "depends on" statement in Kconfig, feel free to submit
an updated (or incremental) patch as soon as a decision will have been
taken.

Thanks,
-- 
Jean Delvare

^ permalink raw reply

* Re: [PATCH 1/3] Fix Unlikely(x) == y
From: Willy Tarreau @ 2008-02-20  7:32 UTC (permalink / raw)
  To: Andi Kleen
  Cc: Nick Piggin, Roel Kluin, lkml, linuxppc-dev, cbe-oss-dev,
	Arjan van de Ven
In-Reply-To: <20080219092846.GB6485@one.firstfloor.org>

On Tue, Feb 19, 2008 at 10:28:46AM +0100, Andi Kleen wrote:
> > Sometimes, for performance critical paths, I would like gcc to be dumb and
> > follow *my* code and not its hard-coded probabilities. 
> 
> If you really want that, simple: just disable optimization @)

already tried. It fixed some difficulties, but create new expected issues
with data being reloaded often from memory instead of being passed along
a few registers. Don't forget that optimizing for x86 requires a lot of
smartness from the compiler because of the very small number of registers!

> > Maybe one thing we would need would be the ability to assign probabilities
> > to each branch based on what we expect, so that gcc could build a better
> > tree keeping most frequently used code tight.
> 
> Just use profile feedback then for user space. I don't think it's a good
> idea for kernel code though because it leads to unreproducible binaries
> which would wreck the development model.

I never found this to be practically usable in fact, because you have to
use it on the *exact* same source. End of game for cross-compilation. It
would be good to be able to use a few pragmas in the code to say "hey, I
want this block optimized like this". This is what I understood the
__builtin_expect() was for, except that it tends to throw unpredicted
branches too far away.

> > Hmm I've just noticed -fno-guess-branch-probability in the man, I never tried
> > it.
> 
> Or -fno-reorder-blocks

Thanks for the hint, I will try it.

Willy

^ permalink raw reply

* Réf. : Status of I2C on mpc5200
From: Eric DUJARDIN @ 2008-02-20  8:33 UTC (permalink / raw)
  To: linuxppc-dev

[-- Attachment #1: Type: text/plain, Size: 1933 bytes --]

Got it. The mpc52xx's still don't support interrupts i.e. reads require 
polling.
As a consequence reads may time out.
But it doesn't prevent I2c from working.
Sorry for disturbing,

Eric Dujardin

-------------------------------
Sagem DS - DP Combat Terrestre
178 rue de Paris - F-91344 Massy Cedex
(33) 1 69196792 (direct)
(33) 1 69196904 (fax)
-------------------------------





"Eric DUJARDIN" <eric.dujardin@sagem.com>

Envoyé par : linuxppc-dev-bounces+eric.dujardin=sagem.com@ozlabs.org
19/02/2008 19:00
Remis le : 19/02/2008 19:01

 
        Pour : 
        cc :    (ccc : Eric DUJARDIN/DRD/SAGEM)
        Objet : Status of I2C on mpc5200




Hello all,

I have a question regarding the stability of I2C on mpc52xx.
According to menuconfig's help it isn't still stable as it says:
"The driver may also work on 52xx family processors, though interrupts are 
known not to work"

However there has been a patch from Domen Puncer that apparently fixed the 
driver in 2.6.23.
<snip>

If any kind soul could provide a status I'd be glad to provide the patch 
for the help file...
Thanks,

Eric Dujardin






" Ce courriel et les documents qui y sont attaches peuvent contenir des informations confidentielles. Si vous n'etes  pas le destinataire escompte, merci d'en informer l'expediteur immediatement et de detruire ce courriel  ainsi que tous les documents attaches de votre systeme informatique. Toute divulgation, distribution ou copie du present courriel et des documents attaches sans autorisation prealable de son emetteur est interdite." 

" This e-mail and any attached documents may contain confidential or proprietary information. If you are not the intended recipient, please advise the sender immediately and delete this e-mail and all attached documents from your computer system. Any unauthorised disclosure, distribution or copying hereof is prohibited."

[-- Attachment #2: Type: text/html, Size: 3242 bytes --]

^ permalink raw reply

* Re: [patch v7 3/4] USB: add Cypress c67x00 OTG controller HCD driver
From: Peter Korsgaard @ 2008-02-20  9:01 UTC (permalink / raw)
  To: Greg KH; +Cc: linuxppc-dev, dbrownell, stern, linux-usb
In-Reply-To: <20080219235554.GA13304@kroah.com>

>>>>> "Greg" == Greg KH <greg@kroah.com> writes:

 Greg> On Tue, Feb 19, 2008 at 04:09:19PM +0100, Peter Korsgaard wrote:
 >> This patch adds HCD support for the Cypress c67x00 family of devices.
 >> 
 >> Signed-off-by: Peter Korsgaard <jacmet@sunsite.dk>

 Greg> And it doesn't build:

 Greg>   CC [M]  drivers/usb/c67x00/c67x00-hcd.o
 Greg> distcc[2413] ERROR: compile /home/gregkh/.ccache/c67x00-hcd.tmp.mini.2409.i on localhost failed
 Greg> drivers/usb/c67x00/c67x00-hcd.c:345: error: redefinition of 'c67x00_hcd_probe'
 Greg> drivers/usb/c67x00/c67x00-hcd.h:119: error: previous definition of 'c67x00_hcd_probe' was here
 Greg> drivers/usb/c67x00/c67x00-hcd.c:402: error: redefinition of 'c67x00_hcd_remove'
 Greg> drivers/usb/c67x00/c67x00-hcd.h:126: error: previous definition of 'c67x00_hcd_remove' was here
 Greg> make[2]: *** [drivers/usb/c67x00/c67x00-hcd.o] Error 1
 Greg> make[1]: *** [drivers/usb/c67x00] Error 2
 Greg> make: *** [_module_drivers/usb] Error 2

Huh, that doesn't make any sense to me. The dumy definitions of
c67x00_hcd_{probe,remove} are protected by an ifndef
CONFIG_USB_C67X00_HCD, and c67x00-hcd.c which contains the real
definitions only gets compiled if CONFIG_USB_C67X00_HCD is
enabled. Could you perhaps provide some more details?

Anyway, the conditional hcd stuff isn't really needed at this point in
the patch series, so I have moved it into patch 4 in the v8 series
I'll post in a minute.

 Greg> This is _after_ removing the obviously incorrect usb_disabled()
 Greg> function that you included in your .h file.

That was again for conditional hcd/udc support. I have now moved the
check into _hcd_probe() instead.

 Greg> I'm going to hold off applying any of these for now, as it
 Greg> doesn't look like something is configured properly here.

Could you give the v8 series a try please?

-- 
Bye, Peter Korsgaard

^ permalink raw reply

* [patch v8 0/4] Cypress c67x00 (EZ-Host/EZ-OTG) support
From: Peter Korsgaard @ 2008-02-20  9:07 UTC (permalink / raw)
  To: dbrownell, linux-usb, linuxppc-dev, grant.likely, stern, greg

The Cypress c67x00 (EZ-Host/EZ-OTG) controllers are multi-role low/fullspeed
USB controllers. This patch series implements a HCD driver and shows the
work-in-progress status of a gadget driver.

I believe patch 1..3 are ready, and I would like to see them queued up for
mainline.

Changes since v7:
 - Moved dummy hcd probe/remove functions for conditional hcd support into
   udc patch.
 - Moved usb_disabled() check into c67x00_hcd_probe().
 - Moved c67x00_get_comm_reg() to udc patch as it is only needed for gadget
   support.

Changes since v6:
 - Addressed David and Alan's comments (removed done list + tasklet)

Changes since v5:
 - Merged c67x00_ll_{get,set}_siemsg() into c67x00_ll_fetch_siemsg().
 - Fix for interrupt race condition at probe time (reported by Grant)

Changes since v4:
 - Addressed Grant's comments (c67x00_dev->c67x00_hcd_dev, label indent)
 - Moved c67x00_ll_set_ep_{ctrl,packet_size}_reg() to patch 4 as they are
   only needed for gadget support.

Changes since v3:
- Lots of cleanups: checkpatch, interrupt handling, c67x00_ prefixes, ..
- The dummy platform_device's created per serial engine are gone.
- Gadget driver (WIP)

--
Bye, Peter Korsgaard

^ permalink raw reply

* [patch v8 4/4] USB: add Cypress c67x00 OTG controller gadget driver
From: Peter Korsgaard @ 2008-02-20  9:07 UTC (permalink / raw)
  To: dbrownell, linux-usb, linuxppc-dev, grant.likely, stern, greg
In-Reply-To: <20080220090727.904160000@sunsite.dk>

This patch adds USB gadget support for the Cypress c67x00 family of devices.

This is work in progress and not ready to be committed yet. I'm posting this
to show how it fits with the rest of the driver and to collect feedback.

The driver works good enought to use g_serial, but there are still issues
to be solved. The biggest issue is that endpoint 0 is currently handled by
the BIOS inside the c67x00, so the gadget stack never sees the data.
The BIOS also has other deficiencies, E.G. see the patching done in
c67x00_ll_susb_init().
---
 drivers/usb/Kconfig                |    2 
 drivers/usb/Makefile               |    2 
 drivers/usb/c67x00/Kconfig         |   21 
 drivers/usb/c67x00/Makefile        |    7 
 drivers/usb/c67x00/c67x00-drv.c    |   11 
 drivers/usb/c67x00/c67x00-hcd.h    |   13 
 drivers/usb/c67x00/c67x00-ll-hpi.c |  206 ++++++++
 drivers/usb/c67x00/c67x00-udc.c    |  905 +++++++++++++++++++++++++++++++++++++
 drivers/usb/c67x00/c67x00-udc.h    |   48 +
 drivers/usb/c67x00/c67x00.h        |   21 
 drivers/usb/gadget/Kconfig         |    7 
 drivers/usb/gadget/gadget_chips.h  |    8 
 drivers/usb/host/Kconfig           |   12 
 13 files changed, 1248 insertions(+), 15 deletions(-)

Index: linux-2.6/drivers/usb/c67x00/c67x00-udc.c
===================================================================
--- /dev/null
+++ linux-2.6/drivers/usb/c67x00/c67x00-udc.c
@@ -0,0 +1,905 @@
+/*
+ * c67x00-udc.c: Cypress C67X00 USB device controller
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ *    based on multiple device controller drivers inside the linux kernel.
+ *
+ * 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 Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA.
+ */
+
+#include <linux/device.h>
+#include <linux/usb.h>
+#include <linux/usb/c67x00.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/ch9.h>
+
+#include "c67x00.h"
+#include "c67x00-udc.h"
+
+/* Defined in DEVICE n ENDPOINT STATUS REGISTERS */
+#define OVERFLOW_FLG		0x0800	/* Receive overflow */
+#define UNDERFLOW_FLG		0x0400	/* Receive underflow */
+#define OUT_EXCEPTION_FLG	0x0200	/* OUT received when armed for IN */
+#define IN_EXCEPTION_FLG	0x0100	/* IN received when armed for OUT */
+#define STALL_FLG		0x0080	/* Stall sent */
+#define NAK_FLG			0x0040	/* NAK sent */
+#define LENGTH_EXCEPT_FLG	0x0020	/* Overflow or Underflow occured */
+#define SETUP_FLG		0x0010	/* SETUP packet received */
+#define SEQ_STAT		0x0008	/* Last Data Toggle Sequence bit sent
+						or received */
+#define TIMEOUT_FLG		0x0004	/* Last transmission timed out */
+#define ERROR_FLG		0x0002	/* CRC Err detected in last
+						reception*/
+#define ACK_FLG			0x0001	/* Last transaction ACK'D (sent
+						or received) */
+
+/* Defined in DEVICE n ENDPOINT CONTROL REGISTERS */
+#define DIR_SEL_IN	0x0004	/* Last transmission timed out */
+#define EP_ENABLE	0x0002	/* Enable Endpoint */
+
+
+
+struct c67x00_request {
+	struct usb_request req;
+	struct list_head queue;
+};
+
+
+
+struct c67x00_udc_ep {
+	struct usb_ep ep;
+	struct c67x00_udc *udc;
+
+	struct list_head queue;
+	int ep_num;
+	int is_ep_in;
+	int enable;
+	int stopped;
+	int start_io;
+};
+
+#define C67X00_MAX_NB_END_POINTS 8
+
+struct c67x00_udc {
+	spinlock_t lock;
+	struct c67x00_sie *sie;
+	struct usb_gadget gadget;
+	struct usb_gadget_driver *driver;
+	struct c67x00_udc_ep ep[C67X00_MAX_NB_END_POINTS];
+	struct work_struct io_work;
+	int config_nr;
+	/* The highest string descriptor entry
+	   (used to retrieve descriptors from gadget driver) */
+	int top_str_id;
+	u16 string_desc_addr;
+};
+
+const static unsigned char get_descriptor_device[] = {
+	USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+	USB_REQ_GET_DESCRIPTOR,
+	0x00,
+	USB_DT_DEVICE,
+	0x00,
+	0x00,
+	0x12,
+	0x00
+};
+
+const static unsigned char get_descriptor_config[] = {
+	USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+	USB_REQ_GET_DESCRIPTOR,
+	0x00,
+	USB_DT_CONFIG,
+	0x00,
+	0x00,
+	0x40,
+	0x00
+};
+
+static unsigned char get_descriptor_string[] = {
+	USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
+	USB_REQ_GET_DESCRIPTOR,
+	0x00,
+	USB_DT_STRING,
+	0x00,
+	0x00,
+	0xFF,
+	0x00
+};
+
+#define SIEx_DEV_DESC_LOC(x)	((x) ? (CY_UDC_DESC_BASE_ADDRESS + 0x200) \
+				 : CY_UDC_DESC_BASE_ADDRESS)
+#define SIEx_CONF_DESC_LOC(x)	(SIEx_DEV_DESC_LOC(x) + 32)
+
+/* ------------------------------------------------------------------------- */
+/* gadget ops */
+
+static int c67x00_get_frame(struct usb_gadget *_gadget)
+{
+	printk(KERN_DEBUG "c67x00-udc : c67x00_get_frame\n");
+	return -ENODEV;
+}
+
+static int c67x00_wakeup(struct usb_gadget *_gadget)
+{
+	printk(KERN_DEBUG "c67x00-udc : c67x00_wakeup\n");
+	return -ENODEV;
+}
+
+static int c67x00_selfpowered(struct usb_gadget *_gadget,
+			      int is_selfpowered)
+{
+	printk(KERN_DEBUG "c67x00-udc : c67x00_selfpowered\n");
+	return -ENODEV;
+}
+
+static int c67x00_vbus_session(struct usb_gadget *_gadget, int is_active)
+{
+	printk(KERN_DEBUG "c67x00-udc : c67x00_vbus_session\n");
+	return -ENODEV;
+}
+
+static int c67x00_pullup(struct usb_gadget *_gadget, int is_on)
+{
+	printk(KERN_DEBUG "c67x00-udc : c67x00_pullup\n");
+	return -ENODEV;
+}
+
+
+static const struct usb_gadget_ops c67x00_udc_ops = {
+	.get_frame = c67x00_get_frame,
+	.wakeup = c67x00_wakeup,
+	.set_selfpowered = c67x00_selfpowered,
+	.vbus_session = c67x00_vbus_session,
+	.pullup = c67x00_pullup
+};
+
+
+
+/*
+ * the sie and gadget_driver get probed/registered from 2 totally independant
+ * places, this datastructure binds them together
+ */
+static struct c67x00_udc controller = {
+	.gadget = {
+		.ops = &c67x00_udc_ops,
+		.name = "c67x00_udc",
+		.speed = USB_SPEED_FULL,
+		.is_dualspeed = 1,
+		.is_a_peripheral = 1,
+		.dev = {
+			.bus_id = "gadget",
+		},
+	},
+};
+
+
+/*----------------------------------------------------------------------------*/
+
+static void c67x00_udc_set_configuration(struct c67x00_sie *sie, u16 config)
+{
+	struct usb_ctrlrequest request;
+	struct c67x00_udc *udc = sie->private_data;
+
+	dev_dbg(sie_dev(sie), "set configuration %d\n", config);
+
+	request.bRequest = USB_REQ_SET_CONFIGURATION;
+	request.bRequestType = 0;
+	request.wValue = cpu_to_le16(config);
+	udc->driver->setup(&udc->gadget, &request);
+}
+
+static int c67x00_udc_parse_descriptor(struct c67x00_udc *udc,
+				       struct c67x00_request *req)
+{
+	int retval = 0;
+	u8 *buf = req->req.buf;
+
+	if (req->req.length < 2)
+		return 0;
+
+	switch (buf[1]) {
+	case USB_DT_DEVICE: {
+		struct usb_device_descriptor *desc = req->req.buf;
+
+		/* Look for the highest stringIndex */
+		if (desc->iManufacturer > udc->top_str_id)
+			udc->top_str_id = desc->iManufacturer;
+		if (desc->iProduct > udc->top_str_id)
+			udc->top_str_id = desc->iProduct;
+		if (desc->iSerialNumber > udc->top_str_id)
+			udc->top_str_id = desc->iSerialNumber;
+
+		/* Write descriptor to C67x00 memory */
+		c67x00_ll_write_mem_le16(udc->sie->dev,
+					 SIEx_DEV_DESC_LOC(udc->sie->sie_num),
+					 req->req.buf, req->req.length);
+
+		/* Write vector address to c67x00 */
+		c67x00_ll_set_device_descriptor_location(
+			udc->sie, SIEx_DEV_DESC_LOC(udc->sie->sie_num));
+
+		retval = 1;
+		break;
+	}
+
+	case USB_DT_CONFIG: {
+		struct usb_config_descriptor *desc = req->req.buf;
+		int offset;
+		u16 length;
+
+		/* store config number to pass to the gadget driver,
+		   once the c67x00 is configured */
+		udc->config_nr = desc->bConfigurationValue;
+
+		length = le16_to_cpu(desc->wTotalLength);
+
+		if (desc->iConfiguration > udc->top_str_id)
+			udc->top_str_id = desc->iConfiguration;
+
+		offset = desc->bLength;
+
+		while (offset < length) {
+			if (buf[offset + 1] == USB_DT_INTERFACE) {
+				struct usb_interface_descriptor *if_desc =
+					(struct usb_interface_descriptor *)
+					(buf + offset);
+
+				if (if_desc->iInterface > udc->top_str_id)
+					udc->top_str_id = if_desc->iInterface;
+			}
+
+			offset += buf[offset];
+		}
+
+		if ((length % 8) == 0) {
+			/* BIOS can't handle descriptors with size multiple
+			   of xfer size */
+			length += 1;
+			/* desc->wTotalLength = cpu_to_le16(length); */
+		}
+
+		/* BIOS can only handle configuration 1,
+		   so make sure the config nr is 1 */
+		desc->bConfigurationValue = 1;
+
+		c67x00_ll_write_mem_le16(udc->sie->dev,
+					 SIEx_CONF_DESC_LOC(udc->sie->sie_num),
+					 req->req.buf, length);
+
+		/* Write vector address to SW interrupt */
+		c67x00_ll_set_configuration_descriptor_location(
+			udc->sie, SIEx_CONF_DESC_LOC(udc->sie->sie_num));
+
+		/* String descriptors start behind configuration descriptor */
+		udc->string_desc_addr =
+			SIEx_CONF_DESC_LOC(udc->sie->sie_num) + length;
+
+		/* Make sure the address is even */
+		if (udc->string_desc_addr & 0x01)
+			udc->string_desc_addr++;
+
+		/* Write string descriptor vector address */
+		c67x00_ll_set_string_descriptor_location(
+			udc->sie, udc->string_desc_addr);
+
+		retval = 1;
+		break;
+	}
+
+	case USB_DT_STRING:
+		/* Write string descriptor */
+		c67x00_ll_write_mem_le16(udc->sie->dev, udc->string_desc_addr,
+					 req->req.buf, req->req.length);
+
+		/* set address to end of this descriptor */
+		udc->string_desc_addr += req->req.length;
+
+		retval = 1;
+		break;
+	}
+
+	return retval;
+}
+
+/*
+ * done - retire a request; caller blocked irqs
+ */
+static void c67x00_udc_done(struct c67x00_udc_ep *ep,
+			    struct c67x00_request *req, int status)
+{
+	int stopped = ep->stopped;
+
+	list_del_init(&req->queue);
+
+	if (likely(req->req.status == -EINPROGRESS))
+		req->req.status = status;
+	else
+		status = req->req.status;
+/*
+	if (status && status != -ESHUTDOWN)
+		DBG(DBG_VERBOSE, "complete %s req %p stat %d len %u/%u\n",
+			ep->ep.name, &req->req, status,
+			req->req.actual, req->req.length);
+*/
+
+	/* don't modify queue heads during completion callback */
+	ep->stopped = 1;
+	req->req.complete(&ep->ep, &req->req);
+	ep->stopped = stopped;
+}
+
+/*----------- UDC send/receive functions -------------------------------------*/
+
+static void c67x00_udc_start_io_irq(struct c67x00_udc_ep *ep)
+{
+	struct c67x00_sie *sie = ep->udc->sie;
+	struct c67x00_request *req =
+		list_entry(ep->queue.next, struct c67x00_request, queue);
+
+	if (ep->is_ep_in)
+		c67x00_ll_susb_start_send(sie, ep->ep_num,
+					  req->req.buf, req->req.length);
+	else
+		c67x00_ll_susb_start_receive(sie, ep->ep_num, req->req.length);
+}
+
+static void c67x00_udc_io_work(struct work_struct *_udc)
+{
+	int i = 0;
+	struct c67x00_udc *udc =
+	    container_of(_udc, struct c67x00_udc, io_work);
+
+	for (i = 0; i < C67X00_MAX_NB_END_POINTS; i++) {
+		struct c67x00_udc_ep *ep = &udc->ep[i];
+		if (ep->start_io) {
+			ep->start_io = 0;
+			c67x00_udc_start_io_irq(ep);
+		}
+	}
+}
+
+static void c67x00_udc_schedule_io_irq(struct c67x00_udc_ep *ep)
+{
+	ep->start_io = 1;
+
+	/* start work queue */
+	schedule_work(&ep->udc->io_work);
+}
+
+static void c67x00_udc_done_irq(struct c67x00_udc_ep *ep, int status)
+{
+	struct c67x00_request *req;
+	struct c67x00_sie *sie = ep->udc->sie;
+	int result;
+
+	result = c67x00_ll_susb_get_transfer_status(sie, ep->ep_num);
+	if (result < 0) {
+		dev_err(sie_dev(sie), "udc_done_irq error (%d)\n", result);
+		return;
+	}
+
+	if (unlikely(list_empty(&ep->queue)))
+		return;
+
+	req = list_entry(ep->queue.next, struct c67x00_request, queue);
+
+	req->req.actual = req->req.length - result;
+
+	if (!ep->is_ep_in && ep->ep_num != 0)
+		c67x00_ll_susb_receive(sie, ep->ep_num,
+				       req->req.buf, req->req.actual);
+
+	c67x00_udc_done(ep, req, 0);
+	if (!list_empty(&ep->queue) && !ep->stopped)
+		/* restart io req */
+		c67x00_udc_schedule_io_irq(ep);
+}
+
+/* -------------------------------------------------------------------------- */
+/* endpoints */
+
+static const char *c67x00_ep_name[C67X00_MAX_NB_END_POINTS] = {
+	"ep0", "ep1out-bulk", "ep2in-bulk", "ep3", "ep4", "ep5", "ep6", "ep7"
+};
+
+
+/* -------------------------------------------------------------------------- */
+/* ep opts */
+
+/*
+ * empties entire endpoint queue
+ */
+static void c67x00_nuke_ep(struct c67x00_udc_ep *ep, int status)
+{
+	ep->stopped = 1;
+
+	while (!list_empty(&ep->queue)) {
+		struct c67x00_request *req =
+			list_entry(ep->queue.next, struct c67x00_request,
+				   queue);
+		c67x00_udc_done(ep, req, status);
+	}
+}
+
+static int c67x00_ep_enable(struct usb_ep *_ep,
+			    const struct usb_endpoint_descriptor *desc)
+{
+	struct c67x00_udc_ep *ep;
+	struct c67x00_sie *sie;
+	u16 maxpacket;
+
+	ep = container_of(_ep, struct c67x00_udc_ep, ep);
+	sie = ep->udc->sie;
+
+	maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+
+	c67x00_ll_set_device_ep_status(sie, ep->ep_num, 0x0000);
+
+	if (desc->bEndpointAddress & USB_DIR_IN) {
+		ep->is_ep_in = 1;
+		c67x00_ll_set_ep_ctrl_reg(sie, ep->ep_num,
+					  EP_ENABLE | DIR_SEL_IN);
+		c67x00_ll_set_ep_packet_size_reg(sie, ep->ep_num, maxpacket);
+	} else {
+		ep->is_ep_in = 0;
+		c67x00_ll_set_ep_ctrl_reg(sie, ep->ep_num, EP_ENABLE);
+		c67x00_ll_set_ep_packet_size_reg(sie, ep->ep_num, maxpacket);
+	}
+
+	ep->enable = 1;
+	ep->stopped = 0;
+	ep->ep.maxpacket = maxpacket;
+
+	return 0;
+}
+
+static int c67x00_ep_disable(struct usb_ep *_ep)
+{
+	unsigned long flags;
+	struct c67x00_udc_ep *ep;
+
+	ep = container_of(_ep, struct c67x00_udc_ep, ep);
+
+	dev_dbg(sie_dev(ep->udc->sie), "ep_disable %s\n", _ep->name);
+
+	spin_lock_irqsave(&ep->udc->lock, flags);
+
+	ep->enable = 0;
+	ep->stopped = 1;
+
+	c67x00_nuke_ep(ep, -ESHUTDOWN);
+
+	spin_unlock_irqrestore(&ep->udc->lock, flags);
+
+	return 0;
+}
+
+
+struct usb_request *c67x00_ep_alloc_request(struct usb_ep *_ep,
+					    gfp_t gfp_flags)
+{
+	struct c67x00_request *req;
+
+	req = kzalloc(sizeof(struct c67x00_request), gfp_flags);
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->queue);
+	return &req->req;
+}
+
+static void c67x00_ep_free_request(struct usb_ep *_ep,
+				   struct usb_request *_req)
+{
+	struct c67x00_request *req = NULL;
+	struct c67x00_udc_ep *ep;
+
+	ep = container_of(_ep, struct c67x00_udc_ep, ep);
+	dev_dbg(sie_dev(ep->udc->sie), "free_request %s\n", _ep->name);
+
+	req = container_of(_req, struct c67x00_request, req);
+
+	if (_req)
+		kfree(req);
+}
+
+static int c67x00_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
+			   gfp_t gfp_flags)
+{
+	struct c67x00_udc_ep *ep;
+	struct c67x00_request *req;
+	unsigned long flags;
+	int request = 0;
+	struct c67x00_udc *dev;
+
+	req = container_of(_req, struct c67x00_request, req);
+	if (unlikely
+	    (!_req || !_req->complete || !_req->buf
+	     || !list_empty(&req->queue))) {
+		printk(KERN_WARNING "bad params\n");
+		return -EINVAL;
+	}
+
+	ep = container_of(_ep, struct c67x00_udc_ep, ep);
+	if (unlikely(!_ep)) {
+		dev_warn(sie_dev(ep->udc->sie), "bad ep\n");
+		return -EINVAL;
+	}
+
+	dev = ep->udc;
+	if (unlikely
+	    (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+		dev_warn(sie_dev(ep->udc->sie), "bogus device state\n");
+		return -ESHUTDOWN;
+	}
+
+	if (ep->ep_num == 0) {
+		/* The gadget driver returns the descriptors through this way */
+		if (!c67x00_udc_parse_descriptor(dev, req)) {
+			req->req.actual = req->req.length;
+			return -EINVAL;
+		} else {
+			req->req.status = 0;
+			req->req.actual = req->req.length;
+			req->req.complete(&ep->ep, &req->req);
+			return 0;
+		}
+
+	}
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	/* Start I/O queue if the list was empty */
+	if (list_empty(&ep->queue) && !ep->stopped)
+		request = 1;
+
+	/* Add the request to the queue of the endpoint */
+	list_add_tail(&req->queue, &ep->queue);
+
+	if (request)
+		c67x00_udc_schedule_io_irq(ep);
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return 0;
+}
+
+
+static int c67x00_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct c67x00_udc_ep *ep;
+	struct c67x00_request *req;
+	unsigned long flags;
+
+	ep = container_of(_ep, struct c67x00_udc_ep, ep);
+	if (!_ep || ep->ep_num == 0)
+		return -EINVAL;
+
+	dev_dbg(sie_dev(ep->udc->sie), "dequeue %s\n", _ep->name);
+
+	spin_lock_irqsave(&ep->udc->lock, flags);
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req) {
+		spin_unlock_irqrestore(&ep->udc->lock, flags);
+		return -EINVAL;
+	}
+
+	c67x00_udc_done(ep, req, -ECONNRESET);
+
+	spin_unlock_irqrestore(&ep->udc->lock, flags);
+	return 0;
+}
+
+
+
+static int c67x00_ep_set_halt(struct usb_ep *_ep, int value)
+{
+	printk(KERN_WARNING "c67x00-udc : ep set_halt %s\n", _ep->name);
+	return -ENODEV;
+}
+
+static void c67x00_ep_fifo_flush(struct usb_ep *_ep)
+{
+	printk(KERN_WARNING "c67x00-udc : ep fifo_flush %s\n", _ep->name);
+}
+
+
+static const struct usb_ep_ops c67x00_ep_ops = {
+	.enable = c67x00_ep_enable,
+	.disable = c67x00_ep_disable,
+
+	.alloc_request = c67x00_ep_alloc_request,
+	.free_request = c67x00_ep_free_request,
+
+	.queue = c67x00_ep_queue,
+	.dequeue = c67x00_ep_dequeue,
+
+	.set_halt = c67x00_ep_set_halt,
+	.fifo_flush = c67x00_ep_fifo_flush,
+};
+
+/* -------------------------------------------------------------------------- */
+
+void c67x00_udc_msg_received(struct c67x00_sie *sie, u16 msg)
+{
+	struct c67x00_udc *udc = sie->private_data;
+	u16 EPx_msg_mask = /*SUSB_EP0_MSG | */ SUSB_EP1_MSG
+		| SUSB_EP2_MSG
+		| SUSB_EP3_MSG
+		| SUSB_EP4_MSG
+		| SUSB_EP5_MSG
+		| SUSB_EP6_MSG
+		| SUSB_EP7_MSG;
+
+	if ((msg & EPx_msg_mask) != 0) {
+		int i, mask = 0x01;
+
+		for (i = 0; i < C67X00_MAX_NB_END_POINTS; i++, mask <<= 1)
+			if (msg & mask)
+				c67x00_udc_done_irq(&udc->ep[i], 0);
+	}
+
+	if (msg & SUSB_RST_MSG) {
+		int i;
+		dev_dbg(sie_dev(sie),
+			 "udc_msg_rec (0x%04X) : SUSB_RST_MSG\n", msg);
+
+		for (i = 0; i < C67X00_MAX_NB_END_POINTS; i++) {
+			struct c67x00_udc_ep *ep = &udc->ep[i];
+			if (i != 0 && ep->enable) {
+				ep->stopped = 1;
+				c67x00_nuke_ep(ep, -ESHUTDOWN);
+			}
+		}
+		if (udc->driver && udc->driver->disconnect)
+			udc->driver->disconnect(&udc->gadget);
+	}
+
+	if (msg & SUSB_SOF_MSG) {
+		dev_dbg(sie_dev(sie),
+			 "udc_msg_rec (0x%04X) : SUSB_SOF_MSG\n", msg);
+	}
+
+	if (msg & SUSB_CFG_MSG) {
+		dev_dbg(sie_dev(sie),
+			 "udc_msg_rec (0x%04X) : SUSB_CFG_MSG\n", msg);
+		/* the c67x00 BIOS only supports 1 configuration,
+		   so it must be configuration 1 */
+		c67x00_udc_set_configuration(sie, udc->config_nr);
+	}
+
+	if (msg & SUSB_SUS_MSG) {
+		dev_dbg(sie_dev(sie),
+			 "udc_msg_rec (0x%04X) : SUSB_SUS_MSG\n", msg);
+	}
+
+	if (msg & SUSB_ID_MSG) {
+		dev_dbg(sie_dev(sie),
+			 "udc_msg_rec (0x%04X) : SUSB_ID_MSG\n", msg);
+	}
+
+	if (msg & SUSB_VBUS_MSG) {
+		dev_dbg(sie_dev(sie),
+			 "udc_msg_rec (0x%04X) : SUSB_VBUS_MSG\n", msg);
+	}
+}
+
+
+/*
+ * This function is called from the interrupt handler in c67x00-drv.c
+ */
+static void c67x00_udc_irq(struct c67x00_sie *sie, u16 int_status, u16 msg)
+{
+	u16 device_status;
+
+	if (msg)
+		c67x00_udc_msg_received(sie, msg);
+
+	device_status = c67x00_ll_usb_get_status(sie);
+
+	if (int_status & SOFEOP_FLG(sie->sie_num))
+		c67x00_ll_usb_clear_status(sie, SOF_EOP_IRQ_FLG);
+
+	if (int_status & RESET_FLG(sie->sie_num)) {
+		dev_info(sie_dev(sie), "sie%d : reset IRQ\n",
+			 sie->sie_num);
+
+		/* Handle reset here */
+		c67x00_ll_usb_clear_status(sie, RESET_IRQ_FLG);
+	}
+
+	if (int_status & DONE_FLG(sie->sie_num))
+		dev_info(sie_dev(sie), "sie%d : done IRQ -> "
+			 "device status 0x%04X\n",
+			 sie->sie_num, device_status);
+}
+
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct c67x00_udc *udc = &controller;
+	int i, retval;
+
+	if (!driver
+/*		|| driver->speed < USB_SPEED_FULL*/
+	    || !driver->bind || !driver->setup) {
+
+		printk(KERN_ERR
+		       "c67x00 : invalid gadget driver provided\n");
+		return -EINVAL;
+	}
+
+
+	spin_lock(&udc->lock);
+	if (!udc->sie || udc->driver) {
+		spin_unlock(&udc->lock);
+		return -EBUSY;
+	}
+
+	udc->driver = driver;
+	udc->gadget.dev.driver = &driver->driver;
+	udc->config_nr = 1;
+	udc->top_str_id = 0;
+	device_add(&udc->gadget.dev);
+
+	driver->driver.bus = NULL;
+
+	dev_dbg(sie_dev(udc->sie), "Binding %s to SIE%d\n",
+		 driver->function, udc->sie->sie_num);
+
+	retval = driver->bind(&udc->gadget);
+	if (retval) {
+		dev_warn(sie_dev(udc->sie), "Driver bind failed\n");
+		goto error;
+	}
+
+	/* retrieve descriptors from gadget and program them in device */
+	udc->driver->setup(&udc->gadget,
+			   (struct usb_ctrlrequest *)
+			   get_descriptor_device);
+	udc->driver->setup(&udc->gadget,
+			   (struct usb_ctrlrequest *)
+			   get_descriptor_config);
+
+	for (i = 0; i <= udc->top_str_id; i++) {
+		get_descriptor_string[2] = i;
+		udc->driver->setup(&udc->gadget,
+				   (struct usb_ctrlrequest *)
+				   get_descriptor_string);
+	}
+
+	spin_unlock(&udc->lock);
+
+	/* enable device */
+	c67x00_ll_susb_init(udc->sie);
+
+	return 0;
+
+error :
+	udc->driver = NULL;
+	udc->gadget.dev.driver = NULL;
+	device_del(&udc->gadget.dev);
+
+	spin_unlock(&udc->lock);
+
+	return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct c67x00_udc *udc = &controller;
+
+	printk(KERN_WARNING "c67x00-udc : usb_gadget_unregister_driver\n");
+
+	spin_lock(&udc->lock);
+	if (udc->driver != driver) {
+		spin_unlock(&udc->lock);
+		return -EINVAL;
+	}
+
+	udc->driver = NULL;
+
+	driver->unbind(&udc->gadget);
+	device_del(&udc->gadget.dev);
+
+	c67x00_ll_susb_disable(udc->sie);
+
+	spin_unlock(&udc->lock);
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/* -------------------------------------------------------------------------- */
+
+int c67x00_udc_probe(struct c67x00_sie *sie)
+{
+	struct c67x00_udc *udc = &controller;
+	unsigned long flags;
+	int i;
+
+	if (udc->sie) {
+		dev_err(sie_dev(sie),
+			"Only 1 peripheral port supported, check sie_config\n");
+		return -EBUSY;
+	}
+
+	spin_lock_init(&udc->lock);
+	INIT_WORK(&udc->io_work, c67x00_udc_io_work);
+	INIT_LIST_HEAD(&udc->gadget.ep_list);
+
+	udc->gadget.ep0 = &udc->ep[0].ep;
+	INIT_LIST_HEAD(&udc->gadget.ep0->ep_list);
+	for (i = 0; i < C67X00_MAX_NB_END_POINTS; i++) {
+		struct c67x00_udc_ep *ep = &udc->ep[i];
+		if (i != 0) {
+			INIT_LIST_HEAD(&udc->ep[i].ep.ep_list);
+			list_add_tail(&udc->ep[i].ep.ep_list,
+				      &udc->gadget.ep_list);
+		}
+		ep->ep.name = c67x00_ep_name[i];
+		ep->ep.ops = &c67x00_ep_ops;
+		ep->enable = 0;
+		ep->start_io = 0;
+		if (i == 0)
+			ep->ep.maxpacket = 8;
+		else
+			/* Size is set when endpoint is enabled */
+			ep->ep.maxpacket = 512;
+		ep->ep_num = i;
+		ep->udc = udc;
+		INIT_LIST_HEAD(&ep->queue);
+	}
+
+	udc->sie = sie;
+	udc->gadget.dev.parent = &sie->dev->pdev->dev;
+	device_initialize(&udc->gadget.dev);
+
+	spin_lock_irqsave(&sie->lock, flags);
+	sie->private_data = udc;
+	sie->irq = c67x00_udc_irq;
+	spin_unlock_irqrestore(&sie->lock, flags);
+
+	return 0;
+}
+
+void c67x00_udc_remove(struct c67x00_sie *sie)
+{
+	struct c67x00_udc *udc = sie->private_data;
+
+	if (!udc) {
+		dev_err(sie_dev(sie), "No udc found!\n");
+		return;
+	}
+
+	/* gadget driver must not be registered */
+	BUG_ON(udc->driver != NULL);
+
+	spin_lock(&udc->lock);
+	sie->private_data = NULL;
+	udc->sie = NULL;
+	spin_unlock(&udc->lock);
+}
Index: linux-2.6/drivers/usb/c67x00/c67x00-udc.h
===================================================================
--- /dev/null
+++ linux-2.6/drivers/usb/c67x00/c67x00-udc.h
@@ -0,0 +1,48 @@
+/*
+ * c67x00-udc.h: Cypress C67X00 USB device controller
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *    Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ *    based on multiple device controller drivers inside the linux kernel.
+ *
+ * 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 Street, Fifth Floor, Boston,
+ * MA  02110-1301  USA.
+ */
+
+#ifndef _USB_C67X00_UDC_H
+#define _USB_C67X00_UDC_H
+
+#include <linux/kernel.h>
+
+#include "c67x00.h"
+
+#ifdef CONFIG_USB_GADGET_C67X00
+/* Functions used by drv */
+int c67x00_udc_probe(struct c67x00_sie *sie);
+void c67x00_udc_remove(struct c67x00_sie *sie);
+#else
+static inline int c67x00_udc_probe(struct c67x00_sie *sie)
+{
+	printk(KERN_ERR "udc requested but CONFIG_USB_GADGET_C67X00 "
+	       "not enabled!\n");
+	return -ENODEV;
+}
+
+static inline void c67x00_udc_remove(struct c67x00_sie *sie)
+{
+}
+#endif				/* CONFIG_USB_GADGET_C67X00 */
+
+#endif				/* _USB_C67X00_UDC_H */
Index: linux-2.6/drivers/usb/c67x00/c67x00-drv.c
===================================================================
--- linux-2.6.orig/drivers/usb/c67x00/c67x00-drv.c
+++ linux-2.6/drivers/usb/c67x00/c67x00-drv.c
@@ -42,6 +42,7 @@
 
 #include "c67x00.h"
 #include "c67x00-hcd.h"
+#include "c67x00-udc.h"
 
 static void c67x00_probe_sie(struct c67x00_sie *sie,
 			     struct c67x00_device *dev, int sie_num)
@@ -56,6 +57,11 @@
 		c67x00_hcd_probe(sie);
 		break;
 
+	case C67X00_SIE_PERIPHERAL_A:
+	case C67X00_SIE_PERIPHERAL_B:
+		c67x00_udc_probe(sie);
+		break;
+
 	case C67X00_SIE_UNUSED:
 		dev_info(sie_dev(sie),
 			 "Not using SIE %d as requested\n", sie->sie_num);
@@ -76,6 +82,11 @@
 		c67x00_hcd_remove(sie);
 		break;
 
+	case C67X00_SIE_PERIPHERAL_A:
+	case C67X00_SIE_PERIPHERAL_B:
+		c67x00_udc_remove(sie);
+		break;
+
 	default:
 		break;
 	}
Index: linux-2.6/drivers/usb/c67x00/c67x00-ll-hpi.c
===================================================================
--- linux-2.6.orig/drivers/usb/c67x00/c67x00-ll-hpi.c
+++ linux-2.6/drivers/usb/c67x00/c67x00-ll-hpi.c
@@ -296,6 +296,11 @@
 	return rc;
 }
 
+static u16 c67x00_get_comm_reg(struct c67x00_device *dev, u16 nr)
+{
+	return hpi_read_word(dev, COMM_R(nr));
+}
+
 /* -------------------------------------------------------------------------- */
 /* Host specific functions */
 
@@ -372,6 +377,207 @@
 }
 
 /* -------------------------------------------------------------------------- */
+void c67x00_ll_susb_init(struct c67x00_sie *sie)
+{
+	struct c67x00_device *dev = sie->dev;
+	struct c67x00_lcp_int_data data;
+	u16 addr;
+	int rc;
+
+	/* The BIOS SUSB_INIT_INT handler for some reason is hardcoded to only
+	   enable peripheral support for port A. Relocate the routine to RAM
+	   and patch out that instruction (mov [r10-0xe],[r8]) */
+	addr = hpi_read_word(dev, SUSB_INIT_INT_LOC);
+
+	/* already patched? */
+	if (addr != CY_UDC_BIOS_REPLACE_BASE) {
+		u16 buf[64]; /* should be plenty for the handler */
+		int i;
+
+		c67x00_ll_read_mem_le16(dev, addr, buf, sizeof(buf));
+
+		/* patch it */
+		for (i = 0; i < (ARRAY_SIZE(buf)-1); i++) {
+			if ((buf[i] == cpu_to_le16(0x0432))
+			    && (buf[i+1] == cpu_to_le16(0xfff2))) {
+				buf[i] = buf[i+1] = 0; /* nop */
+				break;
+			}
+		}
+
+		if (i >= ARRAY_SIZE(buf))
+			dev_warn(sie_dev(sie), "BIOS code not recognized, "
+				 "port B may not be available\n");
+
+		c67x00_ll_write_mem_le16(dev, CY_UDC_BIOS_REPLACE_BASE,
+					 buf, sizeof(buf));
+		hpi_write_word(dev, SUSB_INIT_INT_LOC,
+			       CY_UDC_BIOS_REPLACE_BASE);
+	}
+
+	hpi_clear_bits(dev, HPI_IRQ_ROUTING_REG,
+		       SOFEOP_TO_HPI_EN(sie->sie_num));
+	hpi_set_bits(dev,
+		     HPI_IRQ_ROUTING_REG,
+		     SOFEOP_TO_CPU_EN(sie->sie_num)
+		     | RESUME_TO_HPI_ENABLE(sie->sie_num)
+		     | ID_TO_HPI_ENABLE | VBUS_TO_HPI_ENABLE);
+
+	hpi_set_bits(dev,
+		     DEVICE_N_IRQ_EN_REG(sie->sie_num),
+		     SOF_EOP_TMOUT_IRQ_EN | ID_IRQ_EN | VBUS_IRQ_EN);
+
+	hpi_clear_bits(dev,
+		       USB_CTL_REG(sie->sie_num),
+		       SOF_EOP_EN(0) | SOF_EOP_EN(1));
+
+	if (sie->mode == C67X00_SIE_PERIPHERAL_A)
+		hpi_write_word(dev, DEVICE_N_PORT_SEL(sie->sie_num),  0x0000);
+	else
+		hpi_write_word(dev, DEVICE_N_PORT_SEL(sie->sie_num),  0x4000);
+
+	data.regs[1] = 0; /* full speed */
+	data.regs[2] = sie->sie_num + 1;
+	rc = c67x00_comm_exec_int(dev, SUSB_INIT_INT, &data);
+
+	if ((hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)) & HOST_MODE))
+		dev_warn(sie_dev(sie),
+			 "SIE %d not set to peri mode\n", sie->sie_num);
+
+	BUG_ON(rc); /* No return path for error code; crash spectacularly */
+
+	hpi_set_bits(dev,
+		     DEVICE_N_IRQ_EN_REG(sie->sie_num),
+		     SOF_EOP_TMOUT_IRQ_EN | ID_IRQ_EN | VBUS_IRQ_EN);
+
+	dev_info(sie_dev(sie),
+		 "Peripheral USB device setup on SIE%d\n",
+		 sie->sie_num);
+}
+
+void c67x00_ll_susb_disable(struct c67x00_sie *sie)
+{
+	hpi_write_word(sie->dev, DEVICE_N_IRQ_EN_REG(sie->sie_num), 0);
+	hpi_write_word(sie->dev, USB_CTL_REG(sie->sie_num),  0x0000);
+}
+
+void c67x00_ll_set_ep_ctrl_reg(struct c67x00_sie *sie, int ep_num, u16 val)
+{
+	hpi_write_word(sie->dev,
+		       DEVICE_N_ENDPOINT_N_CTL_REG(sie->sie_num, ep_num), val);
+}
+
+void c67x00_ll_set_ep_packet_size_reg(struct c67x00_sie *sie, int ep_num,
+				      u16 val)
+{
+	/* This undocumented register needs to be set to the packet size
+	   Normally the BIOS sets this correctly when it is able to parse
+	   the configuration descriptor correctly */
+	hpi_write_word(sie->dev,
+		       (DEVICE_N_ENDPOINT_N_CTL_REG(sie->sie_num, ep_num)
+			+ 0x0A), val);
+}
+
+u16 c67x00_ll_get_device_ep_status(struct c67x00_sie *sie, int ep)
+{
+	return hpi_read_word(sie->dev,
+			     DEVICE_N_ENDPOINT_N_STAT_REG(sie->sie_num, ep));
+}
+
+void c67x00_ll_set_device_ep_status(struct c67x00_sie *sie,
+				    int ep, u16 value)
+{
+	hpi_write_word(sie->dev,
+		       DEVICE_N_ENDPOINT_N_STAT_REG(sie->sie_num, ep),
+		       value);
+}
+
+void c67x00_ll_set_device_descriptor_location(struct c67x00_sie *sie,
+					      u16 address)
+{
+	hpi_write_word(sie->dev, SUSBx_DEV_DESC_VEC(sie->sie_num), address);
+}
+
+void c67x00_ll_set_configuration_descriptor_location(struct c67x00_sie *sie,
+						     u16 address)
+{
+	hpi_write_word(sie->dev, SUSBx_CONF_DESC_VEC(sie->sie_num), address);
+}
+
+void c67x00_ll_set_string_descriptor_location(struct c67x00_sie *sie,
+					      u16 address)
+{
+	hpi_write_word(sie->dev, SUSBx_STRING_DESC_VEC(sie->sie_num), address);
+}
+
+int c67x00_ll_susb_start_send(struct c67x00_sie *sie, int ep,
+			      void *data, int len)
+{
+	u16 header[4];
+	struct c67x00_lcp_int_data regs;
+
+	c67x00_ll_write_mem_le16(sie->dev, CY_UDC_REQ_BUFFER_ADDR(ep),
+				 data, len);
+
+	header[0] = 0;
+	header[1] = cpu_to_le16(CY_UDC_REQ_BUFFER_ADDR(ep));
+	header[2] = cpu_to_le16(len);
+	header[3] = 0;
+
+	c67x00_ll_write_mem_le16(sie->dev, CY_UDC_REQ_HEADER_ADDR(ep), header,
+				 sizeof(header));
+
+	regs.regs[0] = 0;
+	regs.regs[1] = ep;
+	regs.regs[8] = CY_UDC_REQ_HEADER_ADDR(ep);
+
+	return c67x00_comm_exec_int(sie->dev, SUSBx_SEND_INT(sie->sie_num),
+				    &regs);
+}
+
+int c67x00_ll_susb_start_receive(struct c67x00_sie *sie, int ep, int len)
+{
+	u16 header[4];
+	struct c67x00_lcp_int_data regs;
+
+	header[0] = 0;
+	header[1] = cpu_to_le16(CY_UDC_REQ_BUFFER_ADDR(ep));
+	header[2] = cpu_to_le16(len);
+	header[3] = 0;
+
+	c67x00_ll_write_mem_le16(sie->dev, CY_UDC_REQ_HEADER_ADDR(ep), header,
+				 sizeof(header));
+
+	regs.regs[0] = 0;
+	regs.regs[1] = ep;
+	regs.regs[8] = CY_UDC_REQ_HEADER_ADDR(ep);
+
+	return c67x00_comm_exec_int(sie->dev, SUSBx_RECEIVE_INT(sie->sie_num),
+				    &regs);
+}
+
+int c67x00_ll_susb_get_transfer_status(struct c67x00_sie *sie, int ep)
+{
+	u16 header[4];
+	u16 result = c67x00_get_comm_reg(sie->dev, 0);
+
+	if (result)
+		return -result;
+
+	c67x00_ll_read_mem_le16(sie->dev, CY_UDC_REQ_HEADER_ADDR(ep),
+				header, sizeof(header));
+	/* nr of bytes not transferred */
+	return le16_to_cpu(header[2]);
+}
+
+void c67x00_ll_susb_receive(struct c67x00_sie *sie, int ep,
+			    void *data, int len)
+{
+	c67x00_ll_read_mem_le16(sie->dev, CY_UDC_REQ_BUFFER_ADDR(ep),
+				data, len);
+}
+
+/* -------------------------------------------------------------------------- */
 
 void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status)
 {
Index: linux-2.6/drivers/usb/c67x00/c67x00.h
===================================================================
--- linux-2.6.orig/drivers/usb/c67x00/c67x00.h
+++ linux-2.6/drivers/usb/c67x00/c67x00.h
@@ -283,6 +283,27 @@
 void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie);
 void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port);
 
+/* Slave specific functions */
+void c67x00_ll_susb_init(struct c67x00_sie *sie);
+void c67x00_ll_susb_disable(struct c67x00_sie *sie);
+void c67x00_ll_set_ep_ctrl_reg(struct c67x00_sie *sie, int ep_num, u16 val);
+void c67x00_ll_set_ep_packet_size_reg(struct c67x00_sie *sie, int ep_num,
+				      u16 val);
+u16 c67x00_ll_get_device_ep_status(struct c67x00_sie *sie, int ep);
+void c67x00_ll_set_device_ep_status(struct c67x00_sie *sie, int ep, u16 value);
+void c67x00_ll_set_device_descriptor_location(struct c67x00_sie *sie,
+					      u16 address);
+void c67x00_ll_set_configuration_descriptor_location(struct c67x00_sie *sie,
+						     u16 address);
+void c67x00_ll_set_string_descriptor_location(struct c67x00_sie *sie,
+					      u16 address);
+int c67x00_ll_susb_start_send(struct c67x00_sie *sie, int ep,
+			      void *data, int len);
+int c67x00_ll_susb_start_receive(struct c67x00_sie *sie, int ep, int len);
+int c67x00_ll_susb_get_transfer_status(struct c67x00_sie *sie, int ep);
+void c67x00_ll_susb_receive(struct c67x00_sie *sie, int ep,
+			    void *data, int len);
+
 /* Called by c67x00_irq to handle lcp interrupts */
 void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status);
 
Index: linux-2.6/drivers/usb/c67x00/Makefile
===================================================================
--- linux-2.6.orig/drivers/usb/c67x00/Makefile
+++ linux-2.6/drivers/usb/c67x00/Makefile
@@ -6,6 +6,9 @@
 	EXTRA_CFLAGS		+= -DDEBUG
 endif
 
-obj-$(CONFIG_USB_C67X00_HCD)	+= c67x00.o
+obj-$(CONFIG_USB_C67X00_DRV)	+= c67x00.o
 
-c67x00-objs := c67x00-drv.o c67x00-ll-hpi.o c67x00-hcd.o c67x00-sched.o
+c67x00-y			+= c67x00-drv.o c67x00-ll-hpi.o
+
+c67x00-$(CONFIG_USB_C67X00_HCD) += c67x00-hcd.o c67x00-sched.o
+c67x00-$(CONFIG_USB_GADGET_C67X00)	+= c67x00-udc.o
Index: linux-2.6/drivers/usb/gadget/Kconfig
===================================================================
--- linux-2.6.orig/drivers/usb/gadget/Kconfig
+++ linux-2.6/drivers/usb/gadget/Kconfig
@@ -335,6 +335,13 @@
 	depends on USB_GADGET_AT91
 	default USB_GADGET
 
+config USB_GADGET_C67X00
+	boolean "Cypress C67X00 Gadget support"
+	depends on USB_C67X00_DRV
+	select USB_GADGET_SELECTED
+	help
+	  This enables the gadget functionality of the Cypress C67X00.
+
 config USB_GADGET_DUMMY_HCD
 	boolean "Dummy HCD (DEVELOPMENT)"
 	depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL
Index: linux-2.6/drivers/usb/gadget/gadget_chips.h
===================================================================
--- linux-2.6.orig/drivers/usb/gadget/gadget_chips.h
+++ linux-2.6/drivers/usb/gadget/gadget_chips.h
@@ -147,6 +147,12 @@
 #define	gadget_is_m66592(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_C67X00
+#define	gadget_is_c67x00(g)	!strcmp("c67x00_udc", (g)->name)
+#else
+#define	gadget_is_c67x00(g)	0
+#endif
+
 
 // CONFIG_USB_GADGET_SX2
 // CONFIG_USB_GADGET_AU1X00
@@ -212,5 +218,7 @@
 		return 0x20;
 	else if (gadget_is_m66592(gadget))
 		return 0x21;
+	else if (gadget_is_c67x00(gadget))
+		return 0x22;
 	return -ENOENT;
 }
Index: linux-2.6/drivers/usb/host/Kconfig
===================================================================
--- linux-2.6.orig/drivers/usb/host/Kconfig
+++ linux-2.6/drivers/usb/host/Kconfig
@@ -261,15 +261,3 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called r8a66597-hcd.
 
-config USB_C67X00_HCD
-	tristate "Cypress C67x00 HCD support"
-	depends on USB
-	help
-	  The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role
-	  host/peripheral/OTG USB controllers.
-
-	  Enable this option to support this chip in host controller mode.
-	  If unsure, say N.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called c67x00.
Index: linux-2.6/drivers/usb/Makefile
===================================================================
--- linux-2.6.orig/drivers/usb/Makefile
+++ linux-2.6/drivers/usb/Makefile
@@ -17,7 +17,7 @@
 obj-$(CONFIG_USB_U132_HCD)	+= host/
 obj-$(CONFIG_USB_R8A66597_HCD)	+= host/
 
-obj-$(CONFIG_USB_C67X00_HCD)	+= c67x00/
+obj-$(CONFIG_USB_C67X00_DRV)	+= c67x00/
 
 obj-$(CONFIG_USB_ACM)		+= class/
 obj-$(CONFIG_USB_PRINTER)	+= class/
Index: linux-2.6/drivers/usb/Kconfig
===================================================================
--- linux-2.6.orig/drivers/usb/Kconfig
+++ linux-2.6/drivers/usb/Kconfig
@@ -97,6 +97,8 @@
 
 source "drivers/usb/host/Kconfig"
 
+source "drivers/usb/c67x00/Kconfig"
+
 source "drivers/usb/class/Kconfig"
 
 source "drivers/usb/storage/Kconfig"
Index: linux-2.6/drivers/usb/c67x00/Kconfig
===================================================================
--- /dev/null
+++ linux-2.6/drivers/usb/c67x00/Kconfig
@@ -0,0 +1,21 @@
+#
+# Cypress C67x00 USB controller
+#
+config USB_C67X00_DRV
+	tristate "Cypress C67x00 support"
+	# only allowed to be =y if both USB!=m and USB_GADGET!=m
+	depends on (!USB && USB_GADGET) || (!USB_GADGET && USB) || (USB && USB_GADGET)
+	help
+	  The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role
+	  host/peripheral USB controllers.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called c67x00.
+
+config USB_C67X00_HCD
+	bool "Cypress C67X00 HCD support"
+	depends on USB && USB_C67X00_DRV
+	default y
+	help
+	  Enable this option to support the Cypress C67x00 in host
+	  controller mode.
Index: linux-2.6/drivers/usb/c67x00/c67x00-hcd.h
===================================================================
--- linux-2.6.orig/drivers/usb/c67x00/c67x00-hcd.h
+++ linux-2.6/drivers/usb/c67x00/c67x00-hcd.h
@@ -112,8 +112,21 @@
  * Functions used by c67x00-drv
  */
 
+#ifdef CONFIG_USB_C67X00_HCD
 int c67x00_hcd_probe(struct c67x00_sie *sie);
 void c67x00_hcd_remove(struct c67x00_sie *sie);
+#else
+static inline int c67x00_hcd_probe(struct c67x00_sie *sie)
+{
+	printk(KERN_ERR "hcd requested but CONFIG_USB_C67X00_HCD "
+	       "not enabled!\n");
+	return -ENODEV;
+}
+
+static inline void c67x00_hcd_remove(struct c67x00_sie *sie)
+{
+}
+#endif				/* CONFIG_USB_C67X00_HCD */
 
 /* ---------------------------------------------------------------------
  * Transfer Descriptor scheduling functions

--
Bye, Peter Korsgaard

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox