* Re: cpm_uart_port_map not initialised before serial console setup
From: Vitaly Bordug @ 2006-07-13 17:05 UTC (permalink / raw)
To: Laurent Pinchart; +Cc: linuxppc-embedded
In-Reply-To: <200607131655.35899.laurent.pinchart@tbox.biz>
On Thu, 13 Jul 2006 16:55:35 +0200
Laurent Pinchart <laurent.pinchart@tbox.biz> wrote:
> Hi everybody,
>
> while trying to use SCC1 as a serial console, I found a bug in the cpm_uart
> driver.
>
> The cpm_uart_port_map table is initialised by cpm_uart_count() which is called
> in cpm_uart_init() at module_init() time. cpm_uart_console_setup(), called at
> console_initcall() time, accesses cpm_uart_port_map, leading to a crash when
> using any serial port except SMC1 as the serial console.
>
> I attached a very simple patch to fix the problem, but it might be subject to
> race conditions. Could anyone familiar with the cpm_uart driver have a look
> at it ?
>
Ugh, you're right.
But I think we need to finally get rid of the stupid count/port_map creation based on #ifdefs.
I'll have a look at it immediately as time permits
--
Sincerely,
Vitaly
^ permalink raw reply
* new IRQ stuff : some details?
From: Vitaly Bordug @ 2006-07-13 18:06 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
Hi Ben,
As your irq rewrite touched mainstream, I am wondering about some details/directions to move fw and
update the boards up to it. Currently, the irq numbers are messed (since the board has 2 Int controllers), and I am assuming some touch to devicetree is needed, but not sure what exactly.
Sorry if it have been brought up somewhere...
--
Sincerely,
Vitaly
^ permalink raw reply
* Re: [PATCH] reorg RTAS delay code
From: Nathan Lynch @ 2006-07-13 18:20 UTC (permalink / raw)
To: John Rose; +Cc: External List, Paul Mackerras
In-Reply-To: <1149543108.17307.6.camel@sinatra.austin.ibm.com>
Hi folks-
John Rose wrote:
> This patch attempts to handle RTAS "busy" return codes in a more simple
> and consistent manner. Typical callers of RTAS shouldn't have to
> manage wait times and delay calls.
>
> This patch also changes the kernel to use msleep() rather than udelay()
> when a runtime delay is necessary. This will avoid CPU soft lockups
> for extended delay conditions.
...
> +/* For an RTAS busy status code, perform the hinted delay. */
> +unsigned int rtas_busy_delay(int status)
> +{
> + unsigned int ms;
>
> - /* Use microseconds for reasonable accuracy */
> - for (ms = 1; order > 0; order--)
> - ms *= 10;
> + might_sleep();
> + ms = rtas_busy_delay_time(status);
> + if (ms)
> + msleep(ms);
>
> - return ms;
> + return ms;
> }
So I managed to test this with cpu hotplug recently and the
might_sleep warning triggers in the cpu offline path (I had to
reconstruct this from xmon due to the kernel crashing later on for a
different reason, so it might be a little off):
BUG: sleeping function called from invalid context at arch/powerpc/kernel/rtas.c:463.
in_atomic():1, irqs_disabled():1.
Call Trace:
[C0000000AAD379A0] [C000000000010ADC] .show_stack+0x68/0x1b4 (unreliable)
[C0000000AAD37A50] [C000000000050C98] .__might_sleep+0xd0/0xec
[C0000000AAD37AE0] [C00000000001DF5C] .rtas_busy_delay+0x20/0x54
[C0000000AAD37B70] [C00000000001E2D0] .rtas_set_indicator+0x70/0xd4
[C0000000AAD37C10] [C0000000000491C8] .xics_migrate_irqs_away+0x78/0x228
[C0000000AAD37CD0] [C000000000047C14] .pSeries_cpu_disable+0x98/0xb4
[C0000000AAD37D50] [C000000000029A5C] .__cpu_disable+0x4c/0x60
[C0000000AAD37DC0] [C000000000080834] .take_cpu_down+0x10/0x38
[C0000000AAD37E40] [C00000000008D1C0] .do_stop+0x198/0x248
[C0000000AAD37EE0] [C000000000078124] .kthread+0x124/0x174
[C0000000AAD37F90] [C000000000026568] .kernel_thread+0x4c/0x68
As it turns out, set-indicator is not allowed to return a busy delay
in this context, so we're actually safe here. Maybe we need an
rtas_set_indicator_fast which could take that into account, e.g.
int rtas_set_indicator_fast(int indicator, int index, int new_value)
{
int token = rtas_token("set-indicator");
int rc;
rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value);
WARN_ON(rc == -2 || rc >= 9000 || rc <= 9005);
if (rc < 0)
return rtas_error_rc(rc);
return rc;
}
^ permalink raw reply
* Re: Maple platform - adding graphics to IBM PIBS firmware
From: Benjamin Herrenschmidt @ 2006-07-13 19:43 UTC (permalink / raw)
To: jf simon; +Cc: linuxppc-dev
In-Reply-To: <44B4D2A4.7090204@yahoo.fr>
> I was (naively) thinking that if I could access the legacy VGA register
> set, I could set the graphic card to text mode and use the graphic
> screen as a alphanumeric console, until linux soft boots the graphic
> card . Do you think this is doable? I haven't been able to locate that
> VGA register set yet.
The legacy VGA operations also require the card to be fully initialized
by the BIOS. In addition to that, there is an issue with using VGA text
mode on machines using the CPC925 bridge as it doesn't have a legacy
memory window: It doesn't have a facility to generate PCI or HT memory
cycles in the low addresses required for VGA.
You can still hack-around in a somewhat card-specific way using the main
memory apperture and doing your onw interleaving of characters and
attributes but it's dodgy.
In any case, you still need the card to be initialized.
Ben.
^ permalink raw reply
* Re: new IRQ stuff : some details?
From: Benjamin Herrenschmidt @ 2006-07-13 19:55 UTC (permalink / raw)
To: Vitaly Bordug; +Cc: linuxppc-dev
In-Reply-To: <20060713220628.54c2912d@vitb.ru.mvista.com>
On Thu, 2006-07-13 at 22:06 +0400, Vitaly Bordug wrote:
> Hi Ben,
>
> As your irq rewrite touched mainstream, I am wondering about some details/directions to move fw and
> update the boards up to it. Currently, the irq numbers are messed (since the board has 2 Int controllers), and I am assuming some touch to devicetree is needed, but not sure what exactly.
>
>
> Sorry if it have been brought up somewhere...
It certainly needs some documentation update... I'm travelling at the
moment, but soon. Discussion is welcome :)
Ben.
^ permalink raw reply
* Knowing kernel module load address (insmod hasn't -m)
From: Antonio Di Bacco @ 2006-07-13 20:38 UTC (permalink / raw)
To: linuxppc-embedded
Hi all,
where can be read at which memory address a module was loaded. I use the bb
insmod that doesn't provide -m option.
Bye,
Antonio.
^ permalink raw reply
* [JOB] Senior Embedded Linux Video Engineer
From: Davenport, Richard @ 2006-07-13 20:33 UTC (permalink / raw)
To: linuxppc-dev
Senior Embedded Linux Video Engineer=20
=20
Responsible for the technical leadership in design and development of =
embedded OS features for Cisco's next generation Audio/Video application =
which will change the entire video conferencing industry.
=20
Please check out these links for an overview of the project:
=20
http://www.humanproductivitylab.com/archive_blogs/2006/03/26/ciscos_chann=
el_partners_should_1.php
=20
http://www.msnbc.msn.com/id/11768174/site/newsweek/
=20
Requirements:
=B7 Strong technical skills with an emphasis on Embedded Linux, =
Operating System interfaces, and Platform Software and Services.=20
=B7 5-7 years of embedded C programming.
=B7 4 years Linux experience with at least 2 years embedded =
Linux.
=B7 Linux expertise on PowerPC architecture.
=B7 Experience in Linux internals such as file systems, device =
drivers, network interfaces.
=B7 Thorough understanding of Linux utilities such as system =
logging and run time options.
=B7 Experience in building BSP packaging
=B7 Familiar with gcc/gdb toolchain=20
=B7 Excellent written and verbal communication skills
=B7 Permanent US work authorization or transferable H1b with a =
minimum of two years remaining eligibility.
=20
Desired Skills/Experience:=20
=B7 Experience in providing Technical and team leadership=20
=B7 Experience in GPL compliance=20
=B7 Build systems, tool chain, executable/library structures and =
makefile=20
=B7 Background in a startup or dynamic working environment
=B7 Strong understanding of operating system Kernel internals=20
=B7 Experience with writing/debugging BSP's for Linux=20
=B7 Background in VoIP Audio/Video systems=20
=20
Typically requires MSEE/CS combined with 5-7 years of related =
experience, or
BSEE/CS combined with 7-10+ yrs related experience.
=20
Opportunity is in San Jose, CA. (Relocation assistance is not available)
=20
If interested, please respond with a copy of your resume and the best =
numbers and times for a follow-up phone conversation.
=20
Thank you,
=20
Richard Davenport
Recruiter=20
Cisco Recruiting Team
(888) 329-3480 or (501) 351-7396
richarddavenport@spherion.com <mailto:richarddavenport@spherion.com>=20
^ permalink raw reply
* [JOB] Senior Embedded Linux Video Engineer
From: Davenport, Richard @ 2006-07-13 20:51 UTC (permalink / raw)
To: linuxppc-embedded
Senior Embedded Linux Video Engineer=20
=20
Responsible for the technical leadership in design and development of =
embedded OS features for Cisco's next generation Audio/Video application =
which will change the entire video conferencing industry.
=20
Please check out these links for an overview of the project:
=20
http://www.humanproductivitylab.com/archive_blogs/2006/03/26/ciscos_chann=
el_partners_should_1.php
=20
http://www.msnbc.msn.com/id/11768174/site/newsweek/
=20
Requirements:
=B7 Strong technical skills with an emphasis on Embedded Linux, =
Operating System interfaces, and Platform Software and Services.=20
=B7 5-7 years of embedded C programming.
=B7 4 years Linux experience with at least 2 years embedded =
Linux.
=B7 Linux expertise on PowerPC architecture.
=B7 Experience in Linux internals such as file systems, device =
drivers, network interfaces.
=B7 Thorough understanding of Linux utilities such as system =
logging and run time options.
=B7 Experience in building BSP packaging
=B7 Familiar with gcc/gdb toolchain=20
=B7 Excellent written and verbal communication skills
=B7 Permanent US work authorization or transferable H1b with a =
minimum of two years remaining eligibility.
=20
Desired Skills/Experience:=20
=B7 Experience in providing Technical and team leadership=20
=B7 Experience in GPL compliance=20
=B7 Build systems, tool chain, executable/library structures and =
makefile=20
=B7 Background in a startup or dynamic working environment
=B7 Strong understanding of operating system Kernel internals=20
=B7 Experience with writing/debugging BSP's for Linux=20
=B7 Background in VoIP Audio/Video systems=20
=20
Typically requires MSEE/CS combined with 5-7 years of related =
experience, or
BSEE/CS combined with 7-10+ yrs related experience.
=20
Opportunity is in San Jose, CA. (Relocation assistance is not available)
=20
If interested, please respond with a copy of your resume and the best =
numbers and times for a follow-up phone conversation.
=20
Thank you,
=20
Richard Davenport
Recruiter=20
Cisco Recruiting Team
(888) 329-3480 or (501) 351-7396
richarddavenport@spherion.com
^ permalink raw reply
* Re: Knowing kernel module load address (insmod hasn't -m)
From: Ben Warren @ 2006-07-13 21:04 UTC (permalink / raw)
To: Antonio Di Bacco; +Cc: linuxppc-embedded
In-Reply-To: <200607132238.11177.antonio.dibacco@aruba.it>
cat /proc/modules
If you want more detailed information about a module (locations
of .text, .data, .bss etc), enable CONFIG_KALLSYMS in your kernel and
you'll see lots of goodness in the /sys/module/<YOUR MODULE>/sections
directory.
Do yourself a favor and browse http://lwn.net/Articles/driver-porting/
where Jon Corbet has written a really good series of articles about
modules and device drivers in the 2.6 kernel.
cheers,
Ben
On Thu, 2006-07-13 at 22:38 +0200, Antonio Di Bacco wrote:
> Hi all,
>
> where can be read at which memory address a module was loaded. I use the bb
> insmod that doesn't provide -m option.
>
> Bye,
> Antonio.
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
^ permalink raw reply
* Re: Knowing kernel module load address (insmod hasn't -m)
From: Antonio Di Bacco @ 2006-07-13 21:27 UTC (permalink / raw)
To: bwarren; +Cc: linuxppc-embedded
In-Reply-To: <1152824648.5238.12.camel@saruman.qstreams.net>
> cat /proc/modules
>
> If you want more detailed information about a module (locations
> of .text, .data, .bss etc), enable CONFIG_KALLSYMS in your kernel and
Does this option exist in kernel 2.4 too? I didn't find it!
Thank you,
Antonio.
^ permalink raw reply
* Re: some problems on the SystemACE driver.
From: Ming Liu @ 2006-07-13 21:41 UTC (permalink / raw)
To: ammubhai; +Cc: linuxppc-embedded
In-Reply-To: <44B671D2.304@gmail.com>
Dear Ameet,
>1. Which TEMAC patch are you using?
>(http://source.mvista.com/~ank/paulus-powerpc/20060309/ppc32_xilinx_edk_temac.patch)
There are five patches in the directory 20060309 whose address is listed
above by you. I applied all of them in my system, because without any there
will be problems.
>2. After applying the patch, is the driver getting compiled directly
>without having to select it via "make menuconfig"?
No. there is an option named "xilinx 10/100/1000 Mbit TEMAC support" in the
menuconfig. I must select it and then compile the kernel.
>3. I don't see a Makefile in the drivers/net/xilinx_temac/ folder?
I have checked. In my kernel, there is the Makefile. I don't know why this
happened to you.
Let me describe the detailed process I did. First, download the kernel
2.6.17.1 (or 2.6.16-rc5). Then apply the five patches for Temac.(If I use
2.6.17.1, I need to upgrade some files manually. For 2.6.16, there is no
problem.) And then apply the patch for SystemACE. Also copy and replace the
xparameters_ml403.h by my own file generated by EDK. Then make menuconfig,
selecting both Temac and SystemACE and other basic options. Then make dep
and make zImage. During this process, I need to modify some little problems
which are about the inclusion of some header files, or specify some lib
inclusion directories instead. Then that problem appears. There are some
main points: 1. configured for ml403 board. 2.both Temac and SystemACE are
selected. 3. 5 patches for Temac and 1 patch for SystemACE. 4. linux
version is 2.6.17 or 2.6.16. I really have no idea why this still happens
after your modification. So I have to ask you again.
>Ofcourse, I can work my way to compile the driver. But is there any doc.
>present explaining this?
Sorry that there is no doc to explain this. I just did following the
procedure described above. I am totally lost. The strange thing is, when I
select only one of these two drivers, no problem, but if both, problem.
By the way, I noticed that in the address where I get your patch, there is
also a patch called linuxppc-2.6.17.1-sysace-1.0.patch which is much larger
than the 1.1 one. I needn't apply the 1.0 one, right?
Thanks for your hard work. Hopefully we can solve the problem.
Regards
Ming
_________________________________________________________________
免费下载 MSN Explorer: http://explorer.msn.com/lccn
^ permalink raw reply
* Re: Knowing kernel module load address (insmod hasn't -m)
From: Ben Warren @ 2006-07-13 21:42 UTC (permalink / raw)
To: Antonio Di Bacco; +Cc: linuxppc-embedded
In-Reply-To: <200607132327.58708.antonio.dibacco@aruba.it>
[-- Attachment #1: Type: text/plain, Size: 562 bytes --]
/proc/modules support is in 2.4, but the other stuff is 2.6 only (I
believe somewhere around 2.6.11 or so?) You should be able to 'insmod
-m' in 2.4. You may need to reconfigure busybox or use a non-busybox
'insmod', though.
cheers,
Ben
On Thu, 2006-07-13 at 23:27 +0200, Antonio Di Bacco wrote:
> > cat /proc/modules
> >
> > If you want more detailed information about a module (locations
> > of .text, .data, .bss etc), enable CONFIG_KALLSYMS in your kernel and
>
> Does this option exist in kernel 2.4 too? I didn't find it!
>
> Thank you,
> Antonio.
[-- Attachment #2: Type: text/html, Size: 1067 bytes --]
^ permalink raw reply
* Xilinx hard TEMAC
From: David H. Lynch Jr. @ 2006-07-13 23:49 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <44B671D2.304@gmail.com>
I am trying to get the Xilinx TEMAC working. I am getting an education
in Xilinx, TEMAC's, PHY's, ... in the process.
The hardware I have to support is the Hard TEMAC on the LocalLink Bus.
It is my understanding that this is the TEMAC builtin to the FX parts,
not one that is created in the FPGA.
Is anyone else working to support that configuration ? I think that is
basically the same as the GRSD TEMAC.
Is it sane to try to adapt the soft TEMAC patch from the list ?
I have a driver that works under uCos as a starting point. It initially
appeared to use basically the same xilinx_edk code that the linux temac
driver patch that has been the subject of a number of messages uses. But
on deeper inspection that dependence appears to be very shallow - mostly
using the edk macros to read the PHY and registers in the MAC.
Am I correct that the TEMAC patch floating arround is not for that TEMAC ?
I am also trying to digest the paternity of the TEMAC. Is the basic
programming of the hard TEMAC and the IP TEMAC the same ? i.e. does the
fact that the both have TEMAC in their name actually express some
commonality ? TEMAC means Tri-Mode EMAC - does that mean there is some
commonality with the IBM EMAC ?
I have a driver in the works that is based on the working uCos code I
mentioned, as well as I think the pcnet32 driver as a very basic template.
I seem to got the PHY portions working, but then addapted to the
separate PHY driver model with the MAC driver providing routines to
access the PHY registers. I may have that working. I think I have DCR
access to the MAC registers working. I am just starting on getting the
TX and RX code working.
I actually started trying to get the posted TEMAC patch working but that
quickly went off the rails - I presumed because the hard and soft
TEMAC's are just too different, or because the xilinx_edk really does
not support the hard TEMAC.
The xilinx_edk based driver seems incredibly complex. I think the OS
independent xilinx_edk incurrs a high cost in obscurity - but I am not
looking to gore someone elses ox, just solve my problem.
If the edk based driver is going to make it into the kernel, and
somebody who understands better than I beleives that it is reasonable to
adapt that to support the hard TEMAC too, I am willing to pursue that
approach.
Regardless. I need to get a driver working, and I am not looking to
duplicate effort.
--
Dave Lynch DLA Systems
Software Development: Embedded Linux
717.627.3770 dhlii@dlasys.net http://www.dlasys.net
fax: 1.253.369.9244 Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.
"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein
^ permalink raw reply
* JTAG PPC info ?
From: David H. Lynch Jr. @ 2006-07-13 23:55 UTC (permalink / raw)
To: linuxppc-embedded
In-Reply-To: <1152782030.3534.27.camel@petra.pixel>
Has anyone not covered by non-disclosure deciphered the JTAG codes
for the PowerPC ?
I have a situation using a custom JTAG interface that is looking to
impliment host side PPC debugging. JTAG access and manipulation of most
all other JTAG devices on the target is working.
Right now the problem is deciphering the JTAG commands etc to the
PPC itself.
Ria Roy wrote:
> Hi,
>
> Does anyone know if Macriagor's mpDemon is capable of debugging the
> linux kernel via the JTAG interface.
>
> Thanks in advance,
> Ria
>
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
--
Dave Lynch DLA Systems
Software Development: Embedded Linux
717.627.3770 dhlii@dlasys.net http://www.dlasys.net
fax: 1.253.369.9244 Cell: 1.717.587.7774
Over 25 years' experience in platforms, languages, and technologies too numerous to list.
"Any intelligent fool can make things bigger and more complex... It takes a touch of genius - and a lot of courage to move in the opposite direction."
Albert Einstein
^ permalink raw reply
* [PATCH] iseries: Move iommu_table_cb into platforms/iseries
From: Michael Ellerman @ 2006-07-14 4:25 UTC (permalink / raw)
To: Stephen Rothwell; +Cc: linuxppc-dev
In-Reply-To: <20060713075223.D1FC767BCD@ozlabs.org>
Although we pass the address of an iommu_table_cb to HvCallXm_getTceTableParms,
we don't actually need the structure definition anywhere except in the
iseries iommu code, so move the struct in there.
Signed-off-by: Michael Ellerman <michael@ellerman.id.au>
---
arch/powerpc/platforms/iseries/iommu.c | 17 +++++++++++++++++
include/asm-powerpc/iseries/hv_call_xm.h | 17 -----------------
2 files changed, 17 insertions(+), 17 deletions(-)
Index: to-merge/arch/powerpc/platforms/iseries/iommu.c
===================================================================
--- to-merge.orig/arch/powerpc/platforms/iseries/iommu.c
+++ to-merge/arch/powerpc/platforms/iseries/iommu.c
@@ -88,6 +88,23 @@ static void tce_free_iSeries(struct iomm
}
/*
+ * Structure passed to HvCallXm_getTceTableParms
+ */
+struct iommu_table_cb {
+ unsigned long itc_busno; /* Bus number for this tce table */
+ unsigned long itc_start; /* Will be NULL for secondary */
+ unsigned long itc_totalsize; /* Size (in pages) of whole table */
+ unsigned long itc_offset; /* Index into real tce table of the
+ start of our section */
+ unsigned long itc_size; /* Size (in pages) of our section */
+ unsigned long itc_index; /* Index of this tce table */
+ unsigned short itc_maxtables; /* Max num of tables for partition */
+ unsigned char itc_virtbus; /* Flag to indicate virtual bus */
+ unsigned char itc_slotno; /* IOA Tce Slot Index */
+ unsigned char itc_rsvd[4];
+};
+
+/*
* Call Hv with the architected data structure to get TCE table info.
* info. Put the returned data into the Linux representation of the
* TCE table data.
Index: to-merge/include/asm-powerpc/iseries/hv_call_xm.h
===================================================================
--- to-merge.orig/include/asm-powerpc/iseries/hv_call_xm.h
+++ to-merge/include/asm-powerpc/iseries/hv_call_xm.h
@@ -16,23 +16,6 @@
#define HvCallXmSetTce HvCallXm + 11
#define HvCallXmSetTces HvCallXm + 13
-/*
- * Structure passed to HvCallXm_getTceTableParms
- */
-struct iommu_table_cb {
- unsigned long itc_busno; /* Bus number for this tce table */
- unsigned long itc_start; /* Will be NULL for secondary */
- unsigned long itc_totalsize; /* Size (in pages) of whole table */
- unsigned long itc_offset; /* Index into real tce table of the
- start of our section */
- unsigned long itc_size; /* Size (in pages) of our section */
- unsigned long itc_index; /* Index of this tce table */
- unsigned short itc_maxtables; /* Max num of tables for partition */
- unsigned char itc_virtbus; /* Flag to indicate virtual bus */
- unsigned char itc_slotno; /* IOA Tce Slot Index */
- unsigned char itc_rsvd[4];
-};
-
static inline void HvCallXm_getTceTableParms(u64 cb)
{
HvCall1(HvCallXmGetTceTableParms, cb);
^ permalink raw reply
* Re: Re: Want to port a linux in V4-FX
From: Grant Likely @ 2006-07-14 5:28 UTC (permalink / raw)
To: 杨强浩, linuxppc-embedded list
In-Reply-To: <200607141248212381692@neusoft.com>
T24gNy8xMy8wNiwg0e7Hv7rGIDx5YW5nLXFoQG5ldXNvZnQuY29tPiB3cm90ZToKPiBHcmFudCBM
aWtlbHksCj4KPiBQbHMgdGVsbCBtZSB0aGUgbWFpbGJveCBvZiAgbGludXhwcGMtZW1iZWRkZWQg
bWFpbGluZyBsaXN0LCB0aGVuIEkgY2FuIGNjIHRvIGl0LgoKbGludXhwcGMtZW1iZWRkZWRAb3ps
YWJzLm9yZwoKUGVvcGxlIGZhciBzbWFydGVyIHRoYW4gbWUgaGFuZyBvdXQgdGhlcmUuICBJdCdz
IGEgYmV0dGVyIHdheSB0byBnZXQgYW5zd2Vycy4KCmcuCgotLSAKR3JhbnQgTGlrZWx5LCBCLlNj
LiBQLkVuZy4KU2VjcmV0IExhYiBUZWNobm9sb2dpZXMgTHRkLgpncmFudC5saWtlbHlAc2VjcmV0
bGFiLmNhCig0MDMpIDM5OS0wMTk1Cg==
^ permalink raw reply
* Failed to bring up the kernel on PPC440GP
From: Denny @ 2006-07-14 7:14 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 1290 bytes --]
The system hangs, after it print "## Transferring control to Linux (at address 00000000) ..."
I dump the log buf, but still can't find the root cause, can anyone give some advice, thanks.
dump:
BDI>md 0x012c5c4
0012c5c4 : 20322e36 2e313420 08726f6f 73696f6e 2.6.14 .roosion
0012c5d4 : 20322e36 2e313420 08726f6f 74406c6f 2.6.14 .root@lo
0012c5e4 : 63616c68 6f73742e 6c6f6361 6c646f6d calhost.localdom
0012c5f4 : 61696e29 20286763 63207665 5820454c ain) (gcc veX EL
0012c604 : 444b2034 2e302034 2e302e30 5820454c DK 4.0 4.0.0X EL
0012c614 : 444b2034 2e302034 2e302e30 2031b43a DK 4.0 4.0.0 1.:
0012c624 : 35353a32 30200353 54203230 2031b43a 55:20 .ST 20 1.:
0012c634 : 35353a32 30200353 54203230 6e452063 55:20 .ST 20nE c
0012c644 : 6865636b 20696e20 6b65726e 6e452063 heck in kernnE c
0012c654 : 6865636b 20696e20 6b65726e 656c206d heck in kernel m
0012c664 : 6f64652e 0a3c343e 504c4230 3a204245 ode..<4>PLB0: BE
0012c674 : 41523d30 78303030 30303030 32306563 AR=0x000000020ec
0012c684 : 30303030 36204143 523d2020 30783962 00006 ACR= 0x9b
0012c694 : 30303030 30302042 4553523d 20307830 000000 BESR= 0x0
0012c6a4 : 63303030 3030300a 3c343e50 4f42303a c000000.<4>POB0:
0012c6b4 : 20424541 523d3078 30303030 30303030 BEAR=0x00000000
BDI>
Thanks in advance!
- Denny
[-- Attachment #2: Type: text/html, Size: 2165 bytes --]
^ permalink raw reply
* Re: [JOB] Senior Embedded Linux Video Engineer
From: Christoph Hellwig @ 2006-07-14 8:07 UTC (permalink / raw)
To: Davenport, Richard; +Cc: linuxppc-dev
In-Reply-To: <44FA7A8E32709444A9078DA2E1C027FD0489B9E6@USCSCMSC8.na.entroot.biz>
On Thu, Jul 13, 2006 at 04:33:06PM -0400, Davenport, Richard wrote:
> Senior Embedded Linux Video Engineer
>
>
>
> Responsible for the technical leadership in design and development of embedded OS features for Cisco's next generation Audio/Video application which will change the entire video conferencing industry.
Please stop spamming people, especially on public mailinglists.
^ permalink raw reply
* Re: [JOB] Senior Embedded Linux Video Engineer
From: Stephen Rothwell @ 2006-07-14 8:43 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: linuxppc-dev, RichardDavenport
In-Reply-To: <20060714080754.GA10177@lst.de>
[-- Attachment #1: Type: text/plain, Size: 389 bytes --]
On Fri, 14 Jul 2006 10:07:54 +0200 Christoph Hellwig <hch@lst.de> wrote:
>
> Please stop spamming people, especially on public mailinglists.
Richard asked the list admins before he sent this message and we decided
it would be OK if he identifed the message in its subject.
--
Cheers,
Stephen Rothwell sfr@canb.auug.org.au
http://www.canb.auug.org.au/~sfr/
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* native gcc for ml403(ppc405)
From: Robert Zach so-logic @ 2006-07-14 10:13 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 533 bytes --]
Hello!
I am working on a ml403 with virtex 4 (ppc405).
I have build me a crosscompiler and a glibc with crosstool.
This worked very good for me...(i can compile 2.4 and 2.6 kernel...)
Now i would like to build a native compiler for the ppc405...(I need
a native compiler for a few things that are hard to crosscompile.)
Is it possible to compile the binutils and gcc with my crosscompiler
to get a native compiler??
Yes anybody done this already? How?
Thanks in Advanced!
Nice greetings
Robert Zach
robert.zach@wvnet.at
[-- Attachment #2: Type: text/html, Size: 2637 bytes --]
^ permalink raw reply
* [Fwd: Re: [Ilugc] help regarding powerpc and vga card]
From: sudheer @ 2006-07-14 10:38 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 1 bytes --]
[-- Attachment #2: Re: [Ilugc] help regarding powerpc and vga card --]
[-- Type: message/rfc822, Size: 4481 bytes --]
[-- Attachment #2.1.1: Type: text/plain, Size: 1437 bytes --]
On 7/13/06, sudheer <urwithsudheer@gmail.com> wrote:
>
>
>
> Anyone please help me if i am missing anything.
>
> All PCI VGA cards for use on x86 PCs have a ROMscan BIOS
extension on them. This initializes the card after POST - basically,
the motherboard BIOS transfers control to the BIOS on the
PCI VGA card, which then initializes itself. If control is not
transfered to the VGA BIOS on the card, the VGA controller
stays isolated and will not respond to PCI device enumeration,
etc. This is actually part of the PC-98 spec., which allows
multiple VGA controllers to co-exist on the PCI and/or AGP
bus.
On a PowerPC system, the ROMscan BIOS cannot execute
(because it has x86 instructions in it), so there will be an alternate
way to initialize the VGA controller so that it can respond to the
PCI enumeration, etc. However, that method will be card/controller
specific - neither the card manufacturer nor ATI may ever have
released the specs for how this is done. Usually, it will be through
hidden memory-mapped IO (MMIO) registers on the VGA controller
chip, but there are numerous proprietary ways to implement this,
most of it being undocumented or controller-specific.
(Lots of things are taken for granted in the x86 PC world, which
are actually very complex and difficult-to-implement protocols.
That's one of the reasons why all the alternative PC processor
architectures have failed over the last 20 years).
-Siva
[-- Attachment #2.1.2: Type: text/html, Size: 1846 bytes --]
^ permalink raw reply
* [Fwd: Re: [Ilugc] help regarding powerpc and vga card]
From: sudheer @ 2006-07-14 10:39 UTC (permalink / raw)
To: linuxppc-embedded
[-- Attachment #1: Type: text/plain, Size: 1 bytes --]
[-- Attachment #2: Re: [Ilugc] help regarding powerpc and vga card --]
[-- Type: message/rfc822, Size: 6523 bytes --]
From: sudheer <urwithsudheer@gmail.com>
To: Sivasankar Chander <siva.ilugc@gmail.com>
Cc: ilugc@ae.iitm.ac.in
Subject: Re: [Ilugc] help regarding powerpc and vga card
Date: Fri, 14 Jul 2006 15:30:08 +0530
Message-ID: <44B76B28.8080200@gmail.com>
Hello Sivasankar,
sudheer wrote:
> Hello Sivasankar,
>
> Sivasankar Chander wrote:
>
>>
>>
>> On 7/13/06, *sudheer* <urwithsudheer@gmail.com
>> <mailto:urwithsudheer@gmail.com>> wrote:
>>
>>
>>
>> Anyone please help me if i am missing anything.
>>
>> All PCI VGA cards for use on x86 PCs have a ROMscan BIOS
>> extension on them. This initializes the card after POST - basically,
>> the motherboard BIOS transfers control to the BIOS on the
>> PCI VGA card, which then initializes itself. If control is not
>> transfered to the VGA BIOS on the card, the VGA controller
>> stays isolated and will not respond to PCI device enumeration,
>> etc.
>
I have a doubt here. How does the processor know that the card sitting
here is a vga card
and control should be transfered to initialize it. I think it can know
that it is a vga card only by reading the config space .
And bios is necesary for vga card to work in its normal way. Is it
necesary for bios to be initialised to get detected.
Please correct me if i am wrong.
>> This is actually part of the PC-98 spec., which allows
>> multiple VGA controllers to co-exist on the PCI and/or AGP
>> bus.
>>
>> On a PowerPC system, the ROMscan BIOS cannot execute
>> (because it has x86 instructions in it), so there will be an alternate
>> way to initialize the VGA controller so that it can respond to the
>> PCI enumeration, etc. However, that method will be card/controller
>> specific - neither the card manufacturer nor ATI may ever have
>> released the specs for how this is done. Usually, it will be through
>> hidden memory-mapped IO (MMIO) registers on the VGA controller
>> chip, but there are numerous proprietary ways to implement this,
>> most of it being undocumented or controller-specific.
>
>
> Thanks for your information.
> Could anyone please suggest me which vga card i need to buy so that
> it can be supported
> with powerpc boards and available in the market. Or can i have any
> other alternative solution .
>
> Thanks & Regards
> Sudheer
>
>>
>> (Lots of things are taken for granted in the x86 PC world, which
>> are actually very complex and difficult-to-implement protocols.
>> That's one of the reasons why all the alternative PC processor
>> architectures have failed over the last 20 years).
>>
>> -Siva
>
Thanks & Regards
Sudheer
_______________________________________________
To unsubscribe, email ilugc-request@ae.iitm.ac.in with
"unsubscribe <password> <address>"
in the subject or body of the message.
http://www.ae.iitm.ac.in/mailman/listinfo/ilugc
^ permalink raw reply
* regarding profinet
From: sudheer @ 2006-07-14 10:46 UTC (permalink / raw)
To: linuxppc-embedded, ilugc-request
Hello All
I am working on powerpc board and need to use profinet. I need to
diagnose the profinet .
For Ethernet tests, we have the tests like mac , phy, external loopback
tests.
Similarlly, i want to know how what kind of tests can be done on profinet .
Anyone please help in this regard.
Thanks & Regards
Sudheer
^ permalink raw reply
* [PATCH] Add Freescale high-speed USB DR module device driver
From: Li Yang @ 2006-07-14 10:58 UTC (permalink / raw)
To: gregkh; +Cc: linuxppc-dev, linux-usb-devel
Freescale high-speed USB SOC can be found on MPC834x and probably more in the future. Its DR(dual-role) module can work as a USB device. This patch adds its support for Linux USB Gadget.
Signed-off-by: Li Yang <leoli@freescale.com>
Signed-off-by: Jiang Bo <Tanya.jiang@freescale.com>
---
This is a resubmission. The first version of the driver is posted on the lists in Aug, 2005. This version adds OTG support (needs separated OTG patch), works with latest gadget drivers and powerpc arch, and some minor fixes.
drivers/usb/gadget/Kconfig | 21
drivers/usb/gadget/Makefile | 1
drivers/usb/gadget/fsl_usb2_udc.c | 2529 +++++++++++++++++++++++++++++++++++++
drivers/usb/gadget/fsl_usb2_udc.h | 608 +++++++++
drivers/usb/gadget/gadget_chips.h | 8
5 files changed, 3167 insertions(+), 0 deletions(-)
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 363b2ad..598c200 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -68,6 +68,27 @@ choice
Many controller drivers are platform-specific; these
often need board-specific hooks.
+config USB_GADGET_FSL_USB2
+ boolean "Freescale MPC834x DR"
+ depends on MPC834x
+ select USB_GADGET_DUALSPEED
+ help
+ Some of Freescale PowerPC processors have a High Speed
+ Dual-Role(DR) USB controller, which support device mode
+ with 5 programmable endpoints. This driver supports the
+ controller in the MPC834x, and should work with DR module
+ in other Freescale processors too, given minor tweaks.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "fsl_usb2_udc" and force
+ all gadget drivers to also be dynamically linked.
+
+config USB_FSL_USB2
+ tristate
+ depends on USB_GADGET_FSL_USB2
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_NET2280
boolean "NetChip 228x"
depends on PCI
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 5a28e61..c283e5e 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_USB_GOKU) += goku_udc.o
obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
obj-$(CONFIG_USB_AT91) += at91_udc.o
+obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
#
# USB gadget drivers
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
new file mode 100644
index 0000000..3bea88f
--- /dev/null
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -0,0 +1,2529 @@
+/*
+ * Copyright (C) 2004-2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Author: Li Yang <leoli@freescale.com>
+ * Jiang Bo <tanya.jiang@freescale.com>
+ *
+ * Description:
+ * Freescale high-speed USB SOC DR module device controller driver.
+ * This SOC can be found on MPC8349E cpu. The driver is previously named
+ * as mpc_udc.c. Based on bare board code from Dave Liu and Shlomi Gridish.
+ *
+ * Note: The driver will not work with old gadget drivers, as the API
+ * parameter endian has changed.
+ *
+ * Changelog:
+ * Aug 1, 2005
+ * - Initial Version
+ * Jul 13, 2006 Li Yang <LeoLi@freescale.com>
+ * - adopted to powerpc arch and gadget drivers in latest kernel
+ * - add otg support, and minor style fixes
+ *
+ * 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.
+ */
+
+#undef DEBUG
+#undef VERBOSE
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+#include <linux/usb_otg.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/dma.h>
+#include <asm/cacheflush.h>
+
+#include "fsl_usb2_udc.h"
+
+#undef USB_TRACE
+
+#define DRIVER_DESC "Freescale PowerPC USB2 DR Device Controller driver"
+#define DRIVER_AUTHOR "Li Yang/Jiang Bo"
+#define DRIVER_VERSION "Jul 13, 2006"
+
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+#if defined(CONFIG_FSL_USB_OTG) || defined(CONFIG_FSL_USB_OTG_MODULE)
+static const char driver_name[] = "fsl-usb2-dr-udc";
+#else
+static const char driver_name[] = "fsl-usb2-dr";
+#endif
+static const char driver_desc[] = DRIVER_DESC;
+
+volatile static struct usb_dr_device *usb_slave_regs = NULL;
+volatile static struct usb_sys_interface *usb_sys_regs = NULL;
+
+/* it is initialized in probe() */
+static struct mpc_udc *udc_controller = NULL;
+
+/* ep_qh_base store the base address before 2K align */
+static struct ep_queue_head *ep_qh_base = NULL;
+
+/*ep name is important in gadget, it should obey the convention of ep_match()*/
+static const char *const ep_name[] = {
+ "ep0-control", NULL, /* everyone has ep0 */
+ /* 5 configurable endpoints */
+ "ep1out",
+ "ep1in",
+ "ep2out",
+ "ep2in",
+ "ep3out",
+ "ep3in",
+ "ep4out",
+ "ep4in",
+ "ep5out",
+ "ep5in"
+};
+static struct usb_endpoint_descriptor
+mpc_ep0_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0,
+ .bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+ .wMaxPacketSize = USB_MAX_CTRL_PAYLOAD,
+};
+
+static int mpc_udc_suspend(struct platform_device *pdev, pm_message_t state);
+static int mpc_udc_resume(struct platform_device *pdev);
+
+/********************************************************************
+ * Internal Used Function
+********************************************************************/
+/*-----------------------------------------------------------------
+ * done() - retire a request; caller blocked irqs
+ * @status : when req->req.status is -EINPROGRESSS, it is input para
+ * else it will be a output parameter
+ * req->req.status : in ep_queue() it will be set as -EINPROGRESS
+ *--------------------------------------------------------------*/
+static void done(struct mpc_ep *ep, struct mpc_req *req, int status)
+{
+ struct mpc_udc *udc = NULL;
+ unsigned char stopped = ep->stopped;
+
+ udc = (struct mpc_udc *) ep->udc;
+ /* the req->queue pointer is used by ep_queue() func, in which
+ * the request will be added into a udc_ep->queue 'd tail
+ * so here the req will be dropped from the ep->queue
+ */
+ list_del_init(&req->queue);
+
+ /* req.status should be set as -EINPROGRESS in ep_queue() */
+ if (req->req.status == -EINPROGRESS)
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ if (req->mapped) {
+ dma_unmap_single(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+ req->req.dma = DMA_ADDR_INVALID;
+ req->mapped = 0;
+ } else
+ dma_sync_single_for_cpu(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE
+ : DMA_FROM_DEVICE);
+
+ if (status && (status != -ESHUTDOWN))
+ VDBG("complete %s req %p stat %d len %u/%u",
+ ep->ep.name, &req->req, status,
+ req->req.actual, req->req.length);
+
+ /* don't modify queue heads during completion callback */
+ ep->stopped = 1;
+
+ spin_unlock(&ep->udc->lock);
+ /* this complete() should a func implemented by gadget layer,
+ * eg fsg->bulk_in_complete() */
+ if (req->req.complete)
+ req->req.complete(&ep->ep, &req->req);
+
+ spin_lock(&ep->udc->lock);
+ ep->stopped = stopped;
+}
+
+/*-----------------------------------------------------------------
+ * nuke(): delete all requests related to this ep
+ * called by ep_disable() within spinlock held
+ * add status paramter?
+ *--------------------------------------------------------------*/
+static void nuke(struct mpc_ep *ep, int status)
+{
+ ep->stopped = 1;
+
+ /* Whether this eq has request linked */
+ while (!list_empty(&ep->queue)) {
+ struct mpc_req *req = NULL;
+
+ req = list_entry(ep->queue.next, struct mpc_req, queue);
+ done(ep, req, status);
+ }
+}
+
+/*------------------------------------------------------------------
+ Internal Hardware related function
+ ------------------------------------------------------------------*/
+
+/* @qh_addr is the aligned virt addr of ep QH addr
+ * it is used to set endpointlistaddr Reg */
+static int dr_controller_setup(void *qh_addr)
+{
+ unsigned int tmp = 0, portctrl = 0, ctrl = 0;
+
+ /* before here, make sure usb_slave_regs has been initialized */
+ if (!qh_addr)
+ return -EINVAL;
+
+ /* Stop and reset the usb controller */
+ tmp = le32_to_cpu(usb_slave_regs->usbcmd);
+ tmp &= ~USB_CMD_RUN_STOP;
+ usb_slave_regs->usbcmd = cpu_to_le32(tmp);
+
+ tmp = le32_to_cpu(usb_slave_regs->usbcmd);
+ tmp |= USB_CMD_CTRL_RESET;
+ usb_slave_regs->usbcmd = cpu_to_le32(tmp);
+ /* Wait reset completed */
+ while (le32_to_cpu(usb_slave_regs->usbcmd) & USB_CMD_CTRL_RESET) {
+ }
+
+ /* Set the controller as device mode */
+ tmp = le32_to_cpu(usb_slave_regs->usbmode);
+ tmp |= USB_MODE_CTRL_MODE_DEVICE;
+ /* Disable Setup Lockout */
+ tmp |= USB_MODE_SETUP_LOCK_OFF;
+ usb_slave_regs->usbmode = cpu_to_le32(tmp);
+
+ /* Clear the setup status */
+ usb_slave_regs->usbsts = 0;
+
+ tmp = virt_to_phys(qh_addr);
+ tmp &= USB_EP_LIST_ADDRESS_MASK;
+ usb_slave_regs->endpointlistaddr = cpu_to_le32(tmp);
+
+ VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x",
+ qh_addr, (int)tmp, le32_to_cpu(usb_slave_regs->
+ endpointlistaddr));
+
+ /* Config PHY interface as ULPI for DR */
+ portctrl = le32_to_cpu(usb_slave_regs->portsc1);
+
+ portctrl &= ~PORTSCX_PHY_TYPE_SEL;
+ portctrl |= PORTSCX_PTS_ULPI;
+ usb_slave_regs->portsc1 = cpu_to_le32(portctrl);
+
+ /* Config control enable i/o output, big endian register */
+ ctrl = usb_sys_regs->control;
+ ctrl |= USB_CTRL_IOENB;
+ usb_sys_regs->control = ctrl;
+
+ /* Config snooping, keep the cache consistent
+ * Snoop between 0x0 and 1GB */
+ tmp = 0;
+ tmp &= SNOOP_ADDRESS_MASK;
+ usb_sys_regs->snoop1 = tmp | SNOOP_SIZE_1GB;
+
+ return 0;
+}
+
+/* just Enable DR irq reg and Set Dr controller Run */
+static void dr_controller_run(struct mpc_udc *udc)
+{
+ u32 temp;
+
+ /*Enable DR irq reg */
+ temp = USB_INTR_INT_EN | USB_INTR_ERR_INT_EN |
+ USB_INTR_PTC_DETECT_EN | USB_INTR_RESET_EN |
+ USB_INTR_DEVICE_SUSPEND | USB_INTR_SYS_ERR_EN;
+
+ usb_slave_regs->usbintr = le32_to_cpu(temp);
+
+ /* Clear stopped bit */
+ udc->stopped = 0;
+
+ /* Set the controller as device mode */
+ temp = le32_to_cpu(usb_slave_regs->usbmode);
+ temp |= USB_MODE_CTRL_MODE_DEVICE;
+ usb_slave_regs->usbmode = cpu_to_le32(temp);
+
+
+ /* Set controller to Run */
+ temp = le32_to_cpu(usb_slave_regs->usbcmd);
+ temp |= USB_CMD_RUN_STOP;
+ usb_slave_regs->usbcmd = le32_to_cpu(temp);
+
+ return;
+}
+
+static void dr_controller_stop(struct mpc_udc *udc)
+{
+ unsigned int tmp;
+
+ /* disable all INTR */
+ usb_slave_regs->usbintr = 0;
+
+ /* Set stopped bit for isr */
+ udc->stopped = 1;
+
+ /* disable IO output */
+/* usb_sys_regs->control = 0; */
+
+ /* set controller to Stop */
+ tmp = le32_to_cpu(usb_slave_regs->usbcmd);
+ tmp &= ~USB_CMD_RUN_STOP;
+ usb_slave_regs->usbcmd = le32_to_cpu(tmp);
+
+ return;
+}
+
+void dr_ep_setup(unsigned char ep_num, unsigned char dir,
+ unsigned char ep_type)
+{
+ unsigned int tmp_epctrl = 0;
+
+ tmp_epctrl = le32_to_cpu(usb_slave_regs->endptctrl[ep_num]);
+ if (dir) {
+ if (ep_num)
+ tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+ tmp_epctrl |= EPCTRL_TX_ENABLE;
+ tmp_epctrl |=
+ ((unsigned int) (ep_type) << EPCTRL_TX_EP_TYPE_SHIFT);
+ } else {
+ if (ep_num)
+ tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+ tmp_epctrl |= EPCTRL_RX_ENABLE;
+ tmp_epctrl |=
+ ((unsigned int) (ep_type) << EPCTRL_RX_EP_TYPE_SHIFT);
+ }
+
+ usb_slave_regs->endptctrl[ep_num] = cpu_to_le32(tmp_epctrl);
+
+ /* wait the write reg finished */
+ while (!(le32_to_cpu(usb_slave_regs->endptctrl[ep_num]) &
+ (tmp_epctrl & (EPCTRL_TX_ENABLE | EPCTRL_RX_ENABLE))));
+}
+
+static void dr_ep_change_stall(unsigned char ep_num, unsigned char dir,
+ int value)
+{
+ unsigned int tmp_epctrl = 0;
+
+ tmp_epctrl = le32_to_cpu(usb_slave_regs->endptctrl[ep_num]);
+
+ if (value) {
+ /* set the stall bit */
+ if (dir)
+ tmp_epctrl |= EPCTRL_TX_EP_STALL;
+ else
+ tmp_epctrl |= EPCTRL_RX_EP_STALL;
+ } else {
+ /* clear the stall bit and reset data toggle */
+ if (dir) {
+ tmp_epctrl &= ~EPCTRL_TX_EP_STALL;
+ tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST;
+ }
+ else {
+ tmp_epctrl &= ~EPCTRL_RX_EP_STALL;
+ tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST;
+ }
+ }
+ usb_slave_regs->endptctrl[ep_num] = cpu_to_le32(tmp_epctrl);
+}
+
+/********************************************************************
+ Internal Structure Build up functions
+********************************************************************/
+
+/*------------------------------------------------------------------
+* struct_ep_qh_setup(): set the Endpoint Capabilites field of QH
+ * @zlt: Zero Length Termination Select
+ * @mult: Mult field
+ ------------------------------------------------------------------*/
+static void struct_ep_qh_setup(void *handle, unsigned char ep_num,
+ unsigned char dir, unsigned char ep_type,
+ unsigned int max_pkt_len,
+ unsigned int zlt, unsigned char mult)
+{
+ struct mpc_udc *udc = NULL;
+ struct ep_queue_head *p_QH = NULL;
+ unsigned int tmp = 0;
+
+ udc = (struct mpc_udc *) handle;
+
+ p_QH = &udc->ep_qh[2 * ep_num + dir];
+
+ /* set the Endpoint Capabilites Reg of QH */
+ switch (ep_type) {
+ case USB_ENDPOINT_XFER_CONTROL:
+ /* Interrupt On Setup (IOS). for control ep */
+ tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) |
+ EP_QUEUE_HEAD_IOS;
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ tmp = (max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS) |
+ (mult << EP_QUEUE_HEAD_MULT_POS);
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ case USB_ENDPOINT_XFER_INT:
+ tmp = max_pkt_len << EP_QUEUE_HEAD_MAX_PKT_LEN_POS;
+ if (zlt)
+ tmp |= EP_QUEUE_HEAD_ZLT_SEL;
+ break;
+ default:
+ VDBG("error ep type is %d",ep_type);
+ return;
+ }
+ p_QH->max_pkt_length = le32_to_cpu(tmp);
+ flush_dcache_range((unsigned long)p_QH, (unsigned long)p_QH +
+ sizeof(struct ep_queue_head));
+
+ return;
+}
+
+/* This function only to make code looks good
+ * it is a collection of struct_ep_qh_setup and dr_ep_setup for ep0
+ * ep0 should set OK before the bind() of gadget layer
+ */
+static void ep0_dr_and_qh_setup(struct mpc_udc *udc)
+{
+ /* the intialization of an ep includes: fields in QH, Regs,
+ * mpc_ep struct */
+ struct_ep_qh_setup(udc, 0, USB_RECV,
+ USB_ENDPOINT_XFER_CONTROL, USB_MAX_CTRL_PAYLOAD,
+ 0, 0);
+ struct_ep_qh_setup(udc, 0, USB_SEND,
+ USB_ENDPOINT_XFER_CONTROL, USB_MAX_CTRL_PAYLOAD,
+ 0, 0);
+ dr_ep_setup(0, USB_RECV, USB_ENDPOINT_XFER_CONTROL);
+ dr_ep_setup(0, USB_SEND, USB_ENDPOINT_XFER_CONTROL);
+
+ return;
+
+}
+
+/***********************************************************************
+ Endpoint Management Functions
+***********************************************************************/
+
+/*-------------------------------------------------------------------------
+ * when configurations are set, or when interface settings change
+ * for example the do_set_interface() in gadget layer,
+ * the driver will enable or disable the relevant endpoints
+ * ep0 will not use this func it is enable in probe()
+-------------------------------------------------------------------------*/
+static int mpc_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct mpc_udc *udc = NULL;
+ struct mpc_ep *ep = NULL;
+ unsigned short max = 0;
+ unsigned char mult = 0, zlt = 0;
+ int retval = 0;
+ unsigned long flags = 0;
+ char *val = NULL; /* for debug */
+
+ ep = container_of(_ep, struct mpc_ep, ep);
+
+ /* catch various bogus parameters */
+ if (!_ep || !desc || ep->desc || _ep->name == ep_name[0] ||
+ (desc->bDescriptorType != USB_DT_ENDPOINT))
+ /* FIXME: add judge for ep->bEndpointAddress */
+ return -EINVAL;
+
+ udc = ep->udc;
+
+ if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN))
+ return -ESHUTDOWN;
+
+ max = le16_to_cpu(desc->wMaxPacketSize);
+ retval = -EINVAL;
+
+ /* check the max package size validate for this endpoint */
+ /* Refer to USB2.0 spec table 9-13,
+ */
+ switch (desc->bmAttributes & 0x03) {
+ case USB_ENDPOINT_XFER_BULK:
+ if (strstr(ep->ep.name, "-iso")
+ || strstr(ep->ep.name, "-int"))
+ goto en_done;
+ mult = 0;
+ zlt = 1;
+ switch (udc->gadget.speed) {
+ case USB_SPEED_HIGH:
+ if ((max == 128) || (max == 256) || (max == 512))
+ break;
+ default:
+ switch (max) {
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ break;
+ default:
+ case USB_SPEED_LOW:
+ goto en_done;
+ }
+ }
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ if (strstr(ep->ep.name, "-iso")) /* bulk is ok */
+ goto en_done;
+ mult = 0;
+ zlt = 1;
+ switch (udc->gadget.speed) {
+ case USB_SPEED_HIGH:
+ if (max <= 1024)
+ break;
+ case USB_SPEED_FULL:
+ if (max <= 64)
+ break;
+ default:
+ if (max <= 8)
+ break;
+ goto en_done;
+ }
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ if (strstr(ep->ep.name, "-bulk") || strstr(ep->ep.name, "-int"))
+ goto en_done;
+ mult = (unsigned char) (1 +((le16_to_cpu(desc->wMaxPacketSize)
+ >> 11) & 0x03));
+ zlt = 0;
+ switch (udc->gadget.speed) {
+ case USB_SPEED_HIGH:
+ if (max <= 1024)
+ break;
+ case USB_SPEED_FULL:
+ if (max <= 1023)
+ break;
+ default:
+ goto en_done;
+ }
+ break;
+ case USB_ENDPOINT_XFER_CONTROL:
+ if (strstr(ep->ep.name, "-iso")
+ || strstr(ep->ep.name, "-int"))
+ goto en_done;
+ mult = 0;
+ zlt = 1;
+ switch (udc->gadget.speed) {
+ case USB_SPEED_HIGH:
+ case USB_SPEED_FULL:
+ switch (max) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ break;
+ default:
+ goto en_done;
+ }
+ case USB_SPEED_LOW:
+ switch (max) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ goto en_done;
+ }
+ default:
+ goto en_done;
+ }
+ break;
+
+ default:
+ goto en_done;
+ }
+
+ /* here initialize variable of ep */
+ spin_lock_irqsave(&udc->lock, flags);
+ ep->ep.maxpacket = max;
+ ep->desc = desc;
+ ep->stopped = 0;
+
+ /* hardware special operation */
+
+ /* Init EPx Queue Head (Ep Capabilites field in QH
+ * according to max, zlt, mult) */
+ struct_ep_qh_setup((void *) udc, (unsigned char) ep_index(ep),
+ (unsigned char) ((desc->
+ bEndpointAddress & USB_DIR_IN) ?
+ USB_SEND : USB_RECV),
+ (unsigned char) (desc->bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK),
+ max, zlt, mult);
+
+ /* Init endpoint x at here */
+ /* 83xx RM chapter 16.3.2.24, here init the endpoint ctrl reg */
+ dr_ep_setup((unsigned char) ep_index(ep),
+ (unsigned char) ((desc->bEndpointAddress & USB_DIR_IN)
+ ? USB_SEND : USB_RECV),
+ (unsigned char) (desc->bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK));
+
+ /* Now HW will be NAKing transfers to that EP,
+ * until a buffer is queued to it. */
+
+ /* should have stop the lock */
+ spin_unlock_irqrestore(&udc->lock, flags);
+ retval = 0;
+ switch (desc->bmAttributes & 0x03) {
+ case USB_ENDPOINT_XFER_BULK:
+ val = "bulk";
+ break;
+ case USB_ENDPOINT_XFER_ISOC:
+ val = "iso";
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ val = "intr";
+ break;
+ default:
+ val = "ctrl";
+ break;
+ }
+
+ VDBG("enabled %s (ep%d%s-%s) maxpacket %d",ep->ep.name,
+ ep->desc->bEndpointAddress & 0x0f,
+ (desc->bEndpointAddress & USB_DIR_IN) ?
+ "in" : "out", val, max);
+en_done:
+ return retval;
+}
+
+/*---------------------------------------------------------------------
+ * @ep : the ep being unconfigured. May not be ep0
+ * Any pending and uncomplete req will complete with status (-ESHUTDOWN)
+*---------------------------------------------------------------------*/
+static int mpc_ep_disable(struct usb_ep *_ep)
+{
+ struct mpc_udc *udc = NULL;
+ struct mpc_ep *ep = NULL;
+ unsigned long flags = 0;
+
+ ep = container_of(_ep, struct mpc_ep, ep);
+ if (!_ep || !ep->desc) {
+ VDBG("%s not enabled", _ep ? ep->ep.name : NULL);
+ return -EINVAL;
+ }
+
+ udc = (struct mpc_udc *) ep->udc;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* Nuke all pending requests (does flush) */
+ nuke(ep, -ESHUTDOWN);
+
+ ep->desc = 0;
+ ep->stopped = 1;
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ VDBG("disabled %s OK", _ep->name);
+ return 0;
+}
+
+/*---------------------------------------------------------------------
+ * allocate a request object used by this endpoint
+ * the main operation is to insert the req->queue to the eq->queue
+ * Returns the request, or null if one could not be allocated
+*---------------------------------------------------------------------*/
+static struct usb_request *mpc_alloc_request(struct usb_ep *_ep,
+ gfp_t gfp_flags)
+{
+ struct mpc_req *req = NULL;
+
+ req = kzalloc(sizeof *req, gfp_flags);
+ if (!req)
+ return NULL;
+
+ req->req.dma = DMA_ADDR_INVALID;
+ INIT_LIST_HEAD(&req->queue);
+
+ return &req->req;
+}
+
+static void mpc_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct mpc_req *req = NULL;
+
+ req = container_of(_req, struct mpc_req, req);
+
+ if (_req)
+ kfree(req);
+}
+
+/*------------------------------------------------------------------
+ * Allocate an I/O buffer for the ep->req->buf
+ * @len: length of the desired buffer
+ * @dma: pointer to the buffer's DMA address; must be valid
+ * when gadget layer calls this function, ma is &req->dma
+ * @gfp_flags : GFP_* flags to use
+ * Returns a new buffer, or null if one could not be allocated
+*---------------------------------------------------------------------*/
+static void *mpc_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
+ dma_addr_t * dma, gfp_t gfp_flags)
+{
+ void *retval = NULL;
+
+ if (!bytes)
+ return 0;
+
+ retval = kmalloc(bytes, gfp_flags);
+ if (retval)
+ *dma = virt_to_phys(retval);
+ return retval;
+}
+
+/*------------------------------------------------------------------
+ * Free an I/O buffer for the ep->req->buf
+ * @dma:for 834x, we will not touch dma field
+*---------------------------------------------------------------------*/
+static void mpc_free_buffer(struct usb_ep *_ep, void *buf,
+ dma_addr_t dma, unsigned bytes)
+{
+ if (buf)
+ kfree(buf);
+}
+
+/*-------------------------------------------------------------------------*/
+static int mpc_queue_td(struct mpc_ep *ep, struct mpc_req *req)
+{
+ int i = ep_index(ep) * 2 + ep_is_in(ep);
+ u32 temp, bitmask, tmp_stat;
+ struct ep_queue_head *dQH = &ep->udc->ep_qh[i];
+
+ //VDBG("QH addr Register 0x%8x", usb_slave_regs->endpointlistaddr);
+ //VDBG("ep_qh[%d] addr is 0x%8x", i, (u32)&(ep->udc->ep_qh[i]));
+
+ bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) :
+ (1 << (ep_index(ep)));
+
+ /* check if the pipe is empty */
+ if (!(list_empty(&ep->queue))) {
+ /* Add td to the end */
+ struct mpc_req *lastreq;
+ lastreq = list_entry(ep->queue.prev, struct mpc_req, queue);
+ lastreq->tail->next_td_ptr =
+ cpu_to_le32(virt_to_phys(req->head) & DTD_ADDR_MASK);
+
+ /* Read prime bit, if 1 goto done */
+ if (usb_slave_regs->endpointprime & cpu_to_le32(bitmask))
+ goto out;
+
+ do {
+ /* Set ATDTW bit in USBCMD */
+ usb_slave_regs->usbcmd |=
+ cpu_to_le32(USB_CMD_ATDTW);
+
+ /* Read correct status bit */
+ tmp_stat = le32_to_cpu(usb_slave_regs->
+ endptstatus) & bitmask;
+
+ } while (!(usb_slave_regs->
+ usbcmd & cpu_to_le32(USB_CMD_ATDTW)));
+
+ /* Write ATDTW bit to 0 */
+ usb_slave_regs->usbcmd &= cpu_to_le32(~USB_CMD_ATDTW);
+
+ if (tmp_stat)
+ goto out;
+ }
+
+ /* Write dQH next pointer and terminate bit to 0 */
+ temp = virt_to_phys((void *)req->head) &
+ EP_QUEUE_HEAD_NEXT_POINTER_MASK;
+ dQH->next_dtd_ptr = cpu_to_le32(temp);
+
+ /* Clear active and halt bit */
+ temp = cpu_to_le32(~(EP_QUEUE_HEAD_STATUS_ACTIVE |
+ EP_QUEUE_HEAD_STATUS_HALT));
+ dQH->size_ioc_int_sts &= temp;
+ flush_dcache_range((unsigned long)dQH,(unsigned long)dQH +
+ sizeof(struct ep_queue_head));
+
+ /* Prime endpoint by writing 1 to ENDPTPRIME */
+ temp = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) :
+ (1 << (ep_index(ep)));
+
+ usb_slave_regs->endpointprime = cpu_to_le32(temp);
+out:
+ return 0;
+}
+
+static int
+mpc_build_dtd (struct mpc_req *req, unsigned max, struct ep_td_struct **address)
+{
+ unsigned length;
+ u32 swap_temp;
+ struct ep_td_struct *dtd;
+
+ /* how big will this packet be? */
+ length = min(req->req.length - req->req.actual, max);
+
+ /* Assume CACHELINE alignment garantees 32-byte alignment */
+ dtd = kzalloc(sizeof(struct ep_td_struct), GFP_KERNEL);
+ /* check alignment */
+ if ((u32) dtd & ~DTD_ADDR_MASK)
+ panic("Can not allocate aligned memory for dtd");
+
+ /* Fill in the transfer size; set interrupt on every dtd;
+ set active bit */
+ swap_temp = ((length << DTD_LENGTH_BIT_POS) | DTD_IOC
+ | DTD_STATUS_ACTIVE);
+
+ dtd->size_ioc_sts = cpu_to_le32(swap_temp);
+
+ /* Clear reserved field */
+ swap_temp = cpu_to_le32(dtd->size_ioc_sts);
+ swap_temp &= ~DTD_RESERVED_FIELDS;
+ dtd->size_ioc_sts = cpu_to_le32(swap_temp);
+
+ /* Init all of buffer page pointers */
+ swap_temp = (u32) (req->req.dma + req->req.actual);
+ dtd->buff_ptr0 = cpu_to_le32(swap_temp);
+ dtd->buff_ptr1 = cpu_to_le32(swap_temp + 0x1000);
+ dtd->buff_ptr2 = cpu_to_le32(swap_temp + 0x2000);
+ dtd->buff_ptr3 = cpu_to_le32(swap_temp + 0x3000);
+ dtd->buff_ptr4 = cpu_to_le32(swap_temp + 0x4000);
+
+ req->req.actual += length;
+ *address = dtd;
+ VDBG("length = %d address= 0x%x", length, (int) dtd);
+
+ return length;
+}
+
+static int
+mpc_req_to_dtd (struct mpc_req *req)
+{
+ unsigned max;
+ unsigned count;
+ int is_last;
+ int is_first =1;
+ struct ep_td_struct *last_addr = NULL, *addr;
+
+ max = EP_MAX_LENGTH_TRANSFER;
+ do {
+ count = mpc_build_dtd(req, max, &addr);
+
+ if (is_first) {
+ is_first = 0;
+ req->head = addr;
+ }
+ else {
+ last_addr->next_td_ptr
+ = cpu_to_le32(virt_to_phys(addr));
+ flush_dcache_range((unsigned long)last_addr,
+ (unsigned long)last_addr +
+ sizeof(struct ep_td_struct));
+ last_addr = addr;
+ }
+ /* last packet is usually short (or a zlp) */
+ if (unlikely (count != max))
+ is_last = 1;
+ else if (likely(req->req.length != req->req.actual)
+ || req->req.zero)
+ is_last = 0;
+ else
+ is_last = 1;
+
+ req->dtd_count ++;
+ }while(!is_last);
+
+ addr->next_td_ptr = cpu_to_le32(DTD_NEXT_TERMINATE);
+ flush_dcache_range((unsigned long)addr, (unsigned long)addr +
+ sizeof(struct ep_td_struct));
+
+ req->tail = addr;
+
+ return 0;
+}
+
+/* queues (submits) an I/O request to an endpoint */
+static int
+mpc_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+ struct mpc_ep *ep = container_of(_ep, struct mpc_ep, ep);
+ struct mpc_req *req = container_of(_req, struct mpc_req, req);
+ struct mpc_udc *udc;
+ unsigned long flags;
+ int is_iso = 0;
+
+ /* catch various bogus parameters */
+ if (!_req || !req->req.complete || !req->req.buf
+ || !list_empty(&req->queue) ) {
+ VDBG("%s, bad params\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ if (!_ep || (!ep->desc && ep_index(ep))) {
+ VDBG("%s, bad ep\n", __FUNCTION__);
+ return -EINVAL;
+ }
+ if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+ if (req->req.length > ep->ep.maxpacket)
+ return -EMSGSIZE;
+ is_iso = 1;
+ }
+
+ udc = ep->udc;
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN)
+ return -ESHUTDOWN;
+
+ req->ep = ep;
+
+ /* map virtual address to hardware */
+ if (req->req.dma == DMA_ADDR_INVALID) {
+ req->req.dma = dma_map_single(ep->udc->gadget.dev.parent,
+ req->req.buf,
+ req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE :
+ DMA_FROM_DEVICE);
+ req->mapped = 1;
+ } else {
+ dma_sync_single_for_device(ep->udc->gadget.dev.parent,
+ req->req.dma, req->req.length,
+ ep_is_in(ep)
+ ? DMA_TO_DEVICE :
+ DMA_FROM_DEVICE);
+ req->mapped = 0;
+ }
+
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+ req->dtd_count = 0;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* push the dtds to device queue */
+ if (!mpc_req_to_dtd(req))
+ mpc_queue_td(ep, req);
+
+ /* EP0 */
+ if ((ep_index(ep) == 0))
+ udc->ep0_state = DATA_STATE_XMIT;
+
+ /* irq handler advances the queue */
+ if (req != NULL)
+ list_add_tail(&req->queue, &ep->queue);
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+/* dequeues (cancels, unlinks) an I/O request from an endpoint */
+static int mpc_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct mpc_ep *ep = container_of(_ep, struct mpc_ep, ep);
+ struct mpc_req *req;
+ unsigned long flags;
+
+ if (!_ep || !_req)
+ return -EINVAL;
+
+ 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;
+ }
+
+ done(ep, req, -ECONNRESET);
+
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+ return 0;
+
+}
+
+/*-------------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------
+ * modify the endpoint halt feature
+ * @ep: the non-isochronous endpoint being stalled
+ * @value: 1--set halt 0--clear halt
+ * Returns zero, or a negative error code.
+*----------------------------------------------------------------*/
+static int _mpc_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ struct mpc_ep *ep = NULL;
+ unsigned long flags = 0;
+ int status = -EOPNOTSUPP; /* operation not supported */
+ unsigned char ep_dir = 0, ep_num = 0;
+ struct mpc_udc *udc = NULL;
+
+ ep = container_of(_ep, struct mpc_ep, ep);
+ udc = ep->udc;
+ if (!_ep || !ep->desc) {
+ status = -EINVAL;
+ goto out;
+ }
+
+ if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) {
+ status = -EOPNOTSUPP;
+ goto out;
+ }
+
+ /* Attemp to halt IN ep will fail if any transfer requests
+ are still queue */
+ if ( value && ep_is_in(ep) && !list_empty(&ep->queue) ) {
+
+ status = -EAGAIN;
+ goto out;
+ }
+
+ status = 0;
+ ep_dir = ep_is_in(ep) ? USB_SEND : USB_RECV;
+ ep_num = (unsigned char) (ep_index(ep));
+ spin_lock_irqsave(&ep->udc->lock, flags);
+ dr_ep_change_stall(ep_num, ep_dir, value);
+ spin_unlock_irqrestore(&ep->udc->lock, flags);
+
+ if ( ep_index(ep) == 0 )
+ {
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+ }
+out:
+ VDBG(" %s %s halt stat %d", ep->ep.name, value ?
+ "set" : "clear", status);
+
+ return status;
+}
+
+static int mpc_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ return (_mpc_ep_set_halt(_ep, value));
+}
+
+static struct usb_ep_ops mpc_ep_ops = {
+ .enable = mpc_ep_enable,
+ .disable = mpc_ep_disable,
+
+ .alloc_request = mpc_alloc_request,
+ .free_request = mpc_free_request,
+
+ .alloc_buffer = mpc_alloc_buffer,
+ .free_buffer = mpc_free_buffer,
+
+ .queue = mpc_ep_queue,
+ .dequeue = mpc_ep_dequeue,
+
+ .set_halt = mpc_ep_set_halt,
+// .fifo_status = mpc_ep_fifo_status, /* report bytes in fifo */
+// .fifo_flush = mpc_ep_fifo_flush, /* flush fifo */
+};
+
+/*-------------------------------------------------------------------------
+ Gadget Driver Layer Operations
+-------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------
+ * Get the current frame number (from DR frame_index Reg )
+ *----------------------------------------------------------------------*/
+static int mpc_get_frame(struct usb_gadget *gadget)
+{
+ return (int) (le32_to_cpu(usb_slave_regs->frindex) &
+ USB_FRINDEX_MASKS);
+}
+
+/*-----------------------------------------------------------------------
+ * Tries to wake up the host connected to this gadget
+ *
+ * Return : 0-success
+ * Negative-this feature not enabled by host or not supported by device hw
+ * FIXME: RM 16.6.2.2.1 DR support this wake-up feature?
+ -----------------------------------------------------------------------*/
+static int mpc_wakeup(struct usb_gadget *gadget)
+{
+ return -ENOTSUPP;
+}
+
+/* sets the device selfpowered feature
+ * this affects the device status reported by the hw driver
+ * to reflect that it now has a local power supply
+ * usually device hw has register for this feature
+ */
+static int
+mpc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
+{
+ return -ENOTSUPP;
+}
+
+static int can_pullup(struct mpc_udc *udc)
+{
+ return udc->driver && udc->softconnect && udc->vbus_active;
+}
+
+/* Notify controller that VBUS is powered, Called by whatever
+ detects VBUS sessions */
+static int mpc_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+ struct mpc_udc *udc;
+ unsigned long flags;
+
+ udc = container_of(gadget, struct mpc_udc, gadget);
+ spin_lock_irqsave(&udc->lock, flags);
+ VDBG("VBUS %s\n", is_active ? "on" : "off");
+ udc->vbus_active = (is_active != 0);
+ if (can_pullup(udc))
+ usb_slave_regs->usbcmd |= USB_CMD_RUN_STOP;
+ else
+ usb_slave_regs->usbcmd &= ~USB_CMD_RUN_STOP;
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return 0;
+}
+
+/* constrain controller's VBUS power usage
+ * This call is used by gadget drivers during SET_CONFIGURATION calls,
+ * reporting how much power the device may consume. For example, this
+ * could affect how quickly batteries are recharged.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static int mpc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+ struct mpc_udc *udc;
+
+ udc = container_of(gadget, struct mpc_udc, gadget);
+
+ if (udc->transceiver)
+ return otg_set_power(udc->transceiver, mA);
+ return -ENOTSUPP;
+}
+
+/* Change Data+ pullup status
+ * this func is used by usb_gadget_connect/disconnet
+ */
+static int mpc_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct mpc_udc *udc;
+
+ udc = container_of(gadget, struct mpc_udc, gadget);
+ udc->softconnect = (is_on != 0);
+ if (can_pullup(udc))
+ usb_slave_regs->usbcmd |= USB_CMD_RUN_STOP;
+ else
+ usb_slave_regs->usbcmd &= ~USB_CMD_RUN_STOP;
+
+ return 0;
+}
+
+/* defined in usb_gadget.h */
+static struct usb_gadget_ops mpc_gadget_ops = {
+ .get_frame = mpc_get_frame,
+ .wakeup = mpc_wakeup,
+ .set_selfpowered = mpc_set_selfpowered,
+ .vbus_session = mpc_vbus_session,
+ .vbus_draw = mpc_vbus_draw,
+ .pullup = mpc_pullup,
+};
+
+static void Ep0Stall(struct mpc_udc *udc)
+{
+ u32 tmp;
+
+ /* a protocol stall */
+ tmp = le32_to_cpu(usb_slave_regs->endptctrl[0]);
+ tmp |= EPCTRL_TX_EP_STALL | EPCTRL_RX_EP_STALL;
+ usb_slave_regs->endptctrl[0] = cpu_to_le32(tmp);
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+}
+
+/* if direction is EP_IN, the status is Device->Host
+ * if direction is EP_OUT, the status transaction is Device<-Host
+ */
+static int ep0_prime_status(struct mpc_udc *udc, int direction)
+{
+ struct mpc_req *req = udc->status_req;
+ struct mpc_ep *ep;
+ int status = 0;
+
+ if (direction == EP_DIR_IN)
+ udc->ep0_dir = USB_DIR_IN;
+ else
+ udc->ep0_dir = USB_DIR_OUT;
+
+ ep = &udc->eps[0];
+ udc->ep0_state = WAIT_FOR_OUT_STATUS;
+
+ req->ep = ep;
+ req->req.length = 0;
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+ req->req.complete = NULL;
+ req->dtd_count = 0;
+
+ if ((mpc_req_to_dtd(req) == 0))
+ status = mpc_queue_td(ep, req);
+ if (status)
+ printk("Can't get control status request \n");
+ list_add_tail(&req->queue, &ep->queue);
+
+ return status;
+}
+
+static int udc_reset_ep_queue(struct mpc_udc *udc, u8 pipe)
+{
+ struct mpc_ep *ep = get_ep_by_pipe(udc, pipe);
+
+ /* FIXME: collect completed requests? */
+ if (!ep->name)
+ return 0;
+
+ nuke(ep, -ECONNRESET);
+
+ return 0;
+}
+
+/*
+ * ch9 Set address
+ */
+static void ch9SetAddress(struct mpc_udc *udc, u16 value, u16 index,
+ u16 length)
+{
+ /* Save the new address to device struct */
+ udc->device_address = (u8) value;
+ /* Update usb state */
+ udc->usb_state = USB_STATE_ADDRESS;
+ /* Status phase */
+ if (ep0_prime_status(udc, EP_DIR_IN))
+ Ep0Stall(udc);
+}
+
+/*
+ * ch9 Get status
+ */
+static void ch9GetStatus(struct mpc_udc *udc, u16 value, u16 index,
+ u16 length)
+{
+ u16 usb_status = 0; /* fix me to give correct status */
+
+ struct mpc_req *req;
+ struct mpc_ep *ep;
+ int status = 0;
+
+ ep = &udc->eps[0];
+
+ req = container_of(mpc_alloc_request(&ep->ep, GFP_KERNEL),
+ struct mpc_req, req);
+ req->req.length = 2;
+ req->req.buf = &usb_status;
+ req->req.status = -EINPROGRESS;
+ req->req.actual = 0;
+
+ /* data phase */
+ if ((mpc_req_to_dtd(req) == 0))
+ status = mpc_queue_td(ep, req);
+ if (status) {
+ printk("Can't respond to getstatus request \n");
+ Ep0Stall(udc);
+ } else
+ udc->ep0_state = DATA_STATE_XMIT;
+}
+
+/*
+ * ch9 Set config
+ */
+static void ch9SetConfig(struct mpc_udc *udc, u16 value, u16 index,
+ u16 length)
+{
+
+ udc->ep0_dir = USB_DIR_IN;
+ if (udc->driver->setup(&udc->gadget, &udc->local_setup_buff) >= 0)
+ {
+ /* gadget layer deal with the status phase */
+ udc->usb_state = USB_STATE_CONFIGURED;
+ udc->ep0_state = WAIT_FOR_OUT_STATUS;
+ }
+}
+
+static void setup_received_irq(struct mpc_udc *udc,
+ struct usb_ctrlrequest *setup)
+{
+ u16 wValue = le16_to_cpu(setup->wValue);
+ u16 wIndex = le16_to_cpu(setup->wIndex);
+ u16 wLength = le16_to_cpu(setup->wLength);
+
+ udc_reset_ep_queue(udc, 0);
+
+ /* We asume setup only occurs on EP0 */
+ if (setup->bRequestType & USB_DIR_IN)
+ udc->ep0_dir = USB_DIR_IN;
+ else
+ udc->ep0_dir = USB_DIR_OUT;
+
+ switch (setup->bRequest) {
+ case USB_BULK_RESET_REQUEST:
+ if ((setup->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS)
+ break;
+ udc->ep0_dir = USB_DIR_IN;
+ if (udc->driver->setup(&udc->gadget,
+ &udc->local_setup_buff) >= 0)
+ udc->ep0_state = WAIT_FOR_SETUP;
+ break;
+
+ case USB_REQ_GET_STATUS:
+ if ((setup-> bRequestType & (USB_DIR_IN | USB_TYPE_STANDARD))
+ != (USB_DIR_IN | USB_TYPE_STANDARD))
+ break;
+ ch9GetStatus(udc, wValue, wIndex, wLength);
+ break;
+
+ case USB_REQ_SET_ADDRESS:
+ if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
+ USB_RECIP_DEVICE))
+ break;
+ ch9SetAddress(udc, wValue, wIndex, wLength);
+ break;
+
+ case USB_REQ_SET_CONFIGURATION:
+ if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
+ USB_RECIP_DEVICE))
+ break;
+ /* gadget layer take over the status phase */
+ ch9SetConfig(udc, wValue, wIndex, wLength);
+ break;
+ case USB_REQ_SET_INTERFACE:
+ if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD |
+ USB_RECIP_INTERFACE))
+ break;
+ udc->ep0_dir = USB_DIR_IN;
+ if (udc->driver->setup(&udc->gadget,
+ &udc->local_setup_buff) >= 0)
+ /* gadget layer take over the status phase */
+ break;
+ /* Requests with no data phase */
+ case USB_REQ_CLEAR_FEATURE:
+ case USB_REQ_SET_FEATURE:
+ { /* status transaction */
+ int rc = -EOPNOTSUPP;
+
+ if (setup->bRequestType == USB_RECIP_ENDPOINT) {
+ int dir = (wIndex & 0x0080) ?
+ EP_DIR_IN: EP_DIR_OUT;
+ int num = (wIndex & 0x000f);
+ struct mpc_ep *ep;
+
+ if (wValue != 0 || wLength != 0
+ || (num *2 + dir) > USB_MAX_PIPES)
+ break;
+ ep = &udc->eps[num*2+dir];
+
+ if (setup->bRequest == USB_REQ_SET_FEATURE) {
+ rc = _mpc_ep_set_halt(&ep->ep, 1);
+ }
+ else {
+ rc = _mpc_ep_set_halt(&ep->ep, 0);
+ }
+
+ } else if (setup->bRequestType == USB_RECIP_DEVICE) {
+ if (!udc->gadget.is_otg)
+ break;
+ else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
+ udc->gadget.b_hnp_enable = 1;
+ else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT)
+ udc->gadget.a_hnp_support = 1;
+ else if (setup->bRequest ==
+ USB_DEVICE_A_ALT_HNP_SUPPORT)
+ udc->gadget.a_alt_hnp_support = 1;
+ rc = 0;
+ }
+ if (rc == 0) {
+ /* send status only if _mpc_ep_set_halt success */
+ if (ep0_prime_status(udc, EP_DIR_IN))
+ Ep0Stall(udc);
+ }
+ break;
+ }
+ default:
+ if (udc->driver->setup(&udc->gadget, &udc->local_setup_buff)
+ != 0) {
+ Ep0Stall(udc);
+ }
+ else if (setup->bRequestType & USB_DIR_IN)
+ udc->ep0_state = DATA_STATE_XMIT;
+ else
+ udc->ep0_state = DATA_STATE_RECV;
+ break;
+ }
+}
+
+static void ep0_req_complete(struct mpc_udc *udc, struct mpc_ep *ep0,
+ struct mpc_req *req)
+{
+ if (udc->usb_state == USB_STATE_ADDRESS) {
+ /* Set the new address */
+ u32 new_address = (u32) udc->device_address;
+ usb_slave_regs->deviceaddr = cpu_to_le32(new_address <<
+ USB_DEVICE_ADDRESS_BIT_POS);
+ }
+
+ switch (udc->ep0_state) {
+ case DATA_STATE_XMIT:
+
+ done(ep0, req, 0);
+ /* receive status phase */
+ if (ep0_prime_status(udc, EP_DIR_OUT))
+ Ep0Stall(udc);
+ break;
+
+ case DATA_STATE_RECV:
+
+ done(ep0, req, 0);
+ /* send status phase */
+ if (ep0_prime_status(udc, EP_DIR_IN))
+ Ep0Stall(udc);
+ break;
+
+ case WAIT_FOR_OUT_STATUS:
+ done(ep0, req, 0);
+ udc->ep0_state = WAIT_FOR_SETUP;
+ break;
+
+ case WAIT_FOR_SETUP:
+ VDBG("Unexpected interrupt");
+ break;
+
+ default:
+ Ep0Stall(udc);
+ break;
+ }
+}
+
+static void tripwire_handler(struct mpc_udc *udc, u8 ep_num,
+ u8 * buffer_ptr)
+{
+ u32 temp;
+ struct ep_queue_head *qh;
+
+ qh = &udc->ep_qh[ep_num*2 + EP_DIR_OUT];
+
+ /* Clear bit in ENDPTSETUPSTAT */
+ temp = cpu_to_le32(1 << ep_num);
+ usb_slave_regs->endptsetupstat |= temp;
+
+ /* while a hazard exists when setup package arrives */
+ do {
+ /* Set Setup Tripwire */
+ temp = cpu_to_le32(USB_CMD_SUTW);
+ usb_slave_regs->usbcmd |= temp;
+
+ /* Copy the setup packet to local buffer */
+ memcpy(buffer_ptr, (u8 *) qh->setup_buffer, 8);
+ } while (!(le32_to_cpu(usb_slave_regs->usbcmd) & USB_CMD_SUTW));
+
+ /* Clear Setup Tripwire */
+ temp = le32_to_cpu(usb_slave_regs->usbcmd);
+ temp &= ~USB_CMD_SUTW;
+ usb_slave_regs->usbcmd = le32_to_cpu(temp);
+}
+
+/*process-ep_req(): free the completed Tds for this req */
+/* FIXME: ERROR handling for multi-dtd requests */
+static int process_ep_req(struct mpc_udc *udc, int pipe,
+ struct mpc_req* curr_req)
+{
+ struct ep_td_struct *curr_td, *tmp_td;
+ int td_complete, actual, remaining_length, j, tmp;
+ int status = 0;
+ int errors = 0;
+ struct ep_queue_head *curr_qh = &udc->ep_qh[pipe];
+ int direction = pipe % 2;
+
+ curr_td = curr_req->head;
+ td_complete = 0;
+ actual = curr_req->req.length;
+
+ for (j = 0; j < curr_req->dtd_count; j++) {
+ remaining_length = ((le32_to_cpu(curr_td->size_ioc_sts)
+ & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS);
+ actual -= remaining_length;
+
+ if ((errors = le32_to_cpu(curr_td->size_ioc_sts) &
+ DTD_ERROR_MASK)) {
+ if (errors & DTD_STATUS_HALTED) {
+ printk("dTD error %08x \n", errors);
+ /* Clear the errors and Halt condition */
+ tmp = le32_to_cpu(curr_qh->size_ioc_int_sts);
+ tmp &= ~errors;
+ curr_qh->size_ioc_int_sts = cpu_to_le32(tmp);
+ status = -EPIPE;
+ /*FIXME clearing active bit, update
+ * nextTD pointer re-prime ep */
+
+ break;
+ }
+ if (errors & DTD_STATUS_DATA_BUFF_ERR) {
+ VDBG( "Transfer overflow");
+ status = -EPROTO;
+ break;
+ }
+ else if (errors & DTD_STATUS_TRANSACTION_ERR) {
+ VDBG("ISO error");
+ status = -EILSEQ;
+ break;
+ }
+ else
+ printk("Unknown error has occured (0x%x)!\r\n",
+ errors);
+
+ } else if (le32_to_cpu(curr_td->size_ioc_sts) &
+ DTD_STATUS_ACTIVE) {
+ VDBG("Request not wholly complete");
+ status = REQ_UNCOMPLETE;
+ return status;
+ } else if (remaining_length)
+ if (direction) {
+ VDBG("Transmit dTD remaining length not zero");
+ status = -EPROTO;
+ break;
+ } else {
+ td_complete +=1;
+ break;
+ }
+ else {
+ td_complete += 1;
+ VDBG("dTD transmitted successful ");
+ }
+
+ if (j != curr_req->dtd_count - 1)
+ curr_td = (struct ep_td_struct*) phys_to_virt(
+ le32_to_cpu(curr_td->next_td_ptr)
+ & DTD_ADDR_MASK);
+ }
+
+ if (status)
+ return status;
+
+ curr_req->req.actual = actual;
+
+ /* Free dtd for completed/error request */
+ curr_td = curr_req->head;
+ for (j = 0; j < curr_req->dtd_count; j++) {
+ tmp_td = curr_td;
+ if (j != curr_req->dtd_count - 1 )
+ curr_td = (struct ep_td_struct*) phys_to_virt(
+ le32_to_cpu(curr_td->next_td_ptr)
+ & DTD_ADDR_MASK);
+ kfree(tmp_td);
+ }
+ return status;
+}
+
+static void dtd_complete_irq(struct mpc_udc *udc)
+{
+ u32 bit_pos;
+ int i, ep_num, direction, bit_mask, status;
+ struct mpc_ep *curr_ep;
+ struct mpc_req *curr_req, *temp_req;
+
+ /* Clear the bits in the register */
+ bit_pos = usb_slave_regs->endptcomplete;
+ usb_slave_regs->endptcomplete = bit_pos;
+ bit_pos = le32_to_cpu(bit_pos);
+
+ if (!bit_pos)
+ return;
+
+ for (i = 0; i < USB_MAX_ENDPOINTS * 2; i++) {
+ ep_num = i >> 1;
+ direction = i % 2;
+
+ bit_mask = 1 << (ep_num + 16 * direction);
+
+ if (!(bit_pos & bit_mask))
+ continue;
+
+ curr_ep = get_ep_by_pipe(udc, i);
+
+ /* If the ep is configured */
+ if (curr_ep->name == NULL) {
+ WARN("Invalid EP?");
+ continue;
+ }
+
+ /* search all mpc_reqs of ep */
+ list_for_each_entry_safe(curr_req, temp_req, &curr_ep->queue,
+ queue) {
+ status = process_ep_req(udc, i, curr_req);
+ if (status == REQ_UNCOMPLETE) {
+ VDBG("Not all tds are completed in the req");
+ break;
+ }
+
+ if (ep_num == 0) {
+ ep0_req_complete(udc, curr_ep, curr_req);
+ break;
+ } else
+ done(curr_ep, curr_req, status);
+ }
+ }
+}
+
+static void port_change_irq(struct mpc_udc *udc)
+{
+ u32 speed;
+
+ if (udc->bus_reset)
+ udc->bus_reset = 0;
+
+ /* Bus resetting is finished */
+ if (!(le32_to_cpu(usb_slave_regs->portsc1) & PORTSCX_PORT_RESET)) {
+ /* Get the speed */
+ speed = (le32_to_cpu(usb_slave_regs->portsc1) &
+ PORTSCX_PORT_SPEED_MASK);
+ switch (speed) {
+ case PORTSCX_PORT_SPEED_HIGH:
+ udc->gadget.speed = USB_SPEED_HIGH;
+ break;
+ case PORTSCX_PORT_SPEED_FULL:
+ udc->gadget.speed = USB_SPEED_FULL;
+ break;
+ case PORTSCX_PORT_SPEED_LOW:
+ udc->gadget.speed = USB_SPEED_LOW;
+ break;
+ default:
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ break;
+ }
+ }
+
+ /* Update USB state */
+ if (!udc->resume_state)
+ udc->usb_state = USB_STATE_DEFAULT;
+}
+
+static void suspend_irq(struct mpc_udc *udc)
+{
+ udc->resume_state = udc->usb_state;
+ udc->usb_state = USB_STATE_SUSPENDED;
+
+ /* report suspend to the driver ,serial.c not support this*/
+ if (udc->driver->suspend)
+ udc->driver->suspend(&udc->gadget);
+}
+
+static void resume_irq(struct mpc_udc *udc)
+{
+ udc->usb_state = udc->resume_state;
+ udc->resume_state = 0;
+
+ /* report resume to the driver , serial.c not support this*/
+ if (udc->driver->resume)
+ udc->driver->resume (&udc->gadget);
+}
+
+static int reset_queues(struct mpc_udc *udc)
+{
+ u8 pipe;
+
+ for (pipe = 0; pipe < udc->max_pipes; pipe++)
+ udc_reset_ep_queue(udc, pipe);
+
+ /* report disconnect; the driver is already quiesced */
+ udc->driver->disconnect(&udc->gadget);
+
+ return 0;
+}
+
+/*
+ * Interrupt handler for USB reset received
+ */
+
+static void reset_irq(struct mpc_udc *udc)
+{
+ u32 temp;
+
+ /* Clear the device address */
+ temp = le32_to_cpu(usb_slave_regs->deviceaddr);
+ temp &= ~USB_DEVICE_ADDRESS_MASK;
+ usb_slave_regs->deviceaddr = cpu_to_le32(temp);
+ udc->device_address = 0;
+
+ /* Clear usb state */
+ udc->usb_state = USB_STATE_DEFAULT;
+
+ /* Clear all the setup token semaphores */
+ temp = le32_to_cpu(usb_slave_regs->endptsetupstat);
+ usb_slave_regs->endptsetupstat = cpu_to_le32(temp);
+
+ /* Clear all the endpoint complete status bits */
+ temp = le32_to_cpu(usb_slave_regs->endptcomplete);
+ usb_slave_regs->endptcomplete = cpu_to_le32(temp);
+
+ while (usb_slave_regs->endpointprime) {
+ /* Wait until all endptprime bits cleared */
+ }
+
+ /* Write 1s to the Flush register */
+ usb_slave_regs->endptflush = 0xFFFFFFFF;
+
+ if (le32_to_cpu(usb_slave_regs->portsc1) & PORTSCX_PORT_RESET) {
+ VDBG("Bus RESET");
+ /* Bus is reseting */
+ udc->bus_reset = 1;
+ udc->ep0_state = WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+ /* Reset all the queues, include XD, dTD, EP queue
+ * head and TR Queue */
+ VDBG("RESET queue");
+ reset_queues(udc);
+ VDBG("RESET queue done");
+ } else {
+ VDBG("Controller reset");
+ /* initialize usb hw reg except for regs for EP, not
+ * touch usbintr reg */
+ dr_controller_setup(udc->ep_qh);
+
+ /* FIXME: Reset all internal used Queues */
+ reset_queues(udc);
+
+ ep0_dr_and_qh_setup(udc);
+
+ /* Enable DR IRQ reg, Set Run bit, change udc state */
+ dr_controller_run(udc);
+ udc->usb_state = USB_STATE_ATTACHED;
+ udc->ep0_state =WAIT_FOR_SETUP;
+ udc->ep0_dir = 0;
+ }
+}
+
+/*
+ * USB device controller interrupt handler
+ */
+static irqreturn_t mpc_udc_irq(int irq, void *_udc, struct pt_regs *r)
+{
+ struct mpc_udc *udc = _udc;
+ u32 irq_src;
+ irqreturn_t status = IRQ_NONE;
+ unsigned long flags;
+
+ /* Disable ISR for OTG host mode */
+ if (udc->stopped)
+ return IRQ_NONE;
+ spin_lock_irqsave(&udc->lock, flags);
+ irq_src = usb_slave_regs->usbsts & usb_slave_regs->usbintr;
+ /* Clear notification bits */
+ usb_slave_regs->usbsts &= irq_src;
+
+ irq_src = le32_to_cpu(irq_src);
+ /* VDBG("irq_src [0x%8x]", irq_src); */
+
+ /* USB Interrupt */
+ if (irq_src & USB_STS_INT) {
+ VDBG("Packet int");
+ /* Setup package, we only support ep0 as control ep */
+ if (usb_slave_regs->endptsetupstat & cpu_to_le32(
+ EP_SETUP_STATUS_EP0)) {
+ tripwire_handler(udc, 0,
+ (u8 *) (&udc->local_setup_buff));
+ setup_received_irq(udc, &udc->local_setup_buff);
+ status = IRQ_HANDLED;
+ }
+
+ /* completion of dtd */
+ if (usb_slave_regs->endptcomplete) {
+ dtd_complete_irq(udc);
+ status = IRQ_HANDLED;
+ }
+ }
+
+ /* SOF (for ISO transfer) */
+ if (irq_src & USB_STS_SOF) {
+ status = IRQ_HANDLED;
+ }
+
+ /* Port Change */
+ if (irq_src & USB_STS_PORT_CHANGE) {
+ port_change_irq(udc);
+ status = IRQ_HANDLED;
+ }
+
+ /* Reset Received */
+ if (irq_src & USB_STS_RESET) {
+ reset_irq(udc);
+ status = IRQ_HANDLED;
+ }
+
+ /* Sleep Enable (Suspend) */
+ if (irq_src & USB_STS_SUSPEND) {
+ suspend_irq(udc);
+ status = IRQ_HANDLED;
+ } else if (udc->resume_state) {
+ resume_irq(udc);
+ }
+
+ if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) {
+ VDBG("Error IRQ %x ", irq_src);
+ }
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return status;
+}
+
+
+/*----------------------------------------------------------------*
+ * tell the controller driver about gadget layer driver
+ * The driver's bind function will be called to bind it to a gadget.
+ * @driver: for example fsg_driver from file_storage.c
+*----------------------------------------------------------------*/
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ int retval = -ENODEV;
+ unsigned long flags = 0;
+
+ /* standard operations */
+ if (!udc_controller)
+ return -ENODEV;
+
+ if (!driver || (driver->speed != USB_SPEED_FULL
+ && driver->speed != USB_SPEED_HIGH)
+ || !driver->bind || !driver->unbind ||
+ !driver->disconnect || !driver->setup)
+ return -EINVAL;
+
+ if (udc_controller->driver)
+ return -EBUSY;
+ /* lock is needed but whether should use this lock or another */
+ spin_lock_irqsave(&udc_controller->lock, flags);
+
+ driver->driver.bus = 0;
+ /* hook up the driver */
+ udc_controller->driver = driver;
+ udc_controller->gadget.dev.driver = &driver->driver;
+ spin_unlock_irqrestore(&udc_controller->lock, flags);
+
+ retval = driver->bind(&udc_controller->gadget);
+ if (retval) {
+ VDBG("bind to %s --> %d", driver->driver.name,
+ retval);
+ udc_controller->gadget.dev.driver = 0;
+ udc_controller->driver = 0;
+ goto out;
+ }
+
+#if defined(CONFIG_FSL_USB_OTG) || defined(CONFIG_FSL_USB_OTG_MODULE)
+ /* Suspend the controller until OTG enable it */
+ mpc_udc_suspend(&udc_controller->gadget.dev, 0);
+ printk("Suspend udc for OTG auto detect \n");
+
+ /* export udc suspend/resume call to OTG */
+ udc_controller->gadget.dev.driver->suspend = mpc_udc_suspend;
+ udc_controller->gadget.dev.driver->resume = mpc_udc_resume;
+
+ /* connect to bus through transceiver */
+ if (udc_controller->transceiver) {
+ retval = otg_set_peripheral(udc_controller->transceiver,
+ &udc_controller->gadget);
+ if (retval < 0) {
+ ERR("can't bind to transceiver\n");
+ driver->unbind (&udc_controller->gadget);
+ udc_controller->gadget.dev.driver = 0;
+ udc_controller->driver = 0;
+ return retval;
+ }
+ }
+
+#else
+ /* Enable DR IRQ reg and Set usbcmd reg Run bit */
+ dr_controller_run(udc_controller);
+ udc_controller->usb_state = USB_STATE_ATTACHED;
+ udc_controller->ep0_state = WAIT_FOR_SETUP;
+ udc_controller->ep0_dir = 0;
+#endif
+ printk("mpc_udc: %s bind to driver %s \n", udc_controller->gadget.name,
+ driver->driver.name);
+
+out:
+ if (retval)
+ printk("retval %d \n", retval);
+ return retval;
+}
+
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct mpc_ep *loop_ep;
+ unsigned long flags;
+
+ if (!udc_controller)
+ return -ENODEV;
+
+ if (!driver || driver != udc_controller->driver)
+ return -EINVAL;
+
+ if (udc_controller->transceiver)
+ (void) otg_set_peripheral(udc_controller->transceiver, 0);
+
+ /* stop DR, disable intr */
+ dr_controller_stop(udc_controller);
+
+ /* in fact, no needed */
+ udc_controller->usb_state = USB_STATE_ATTACHED;
+ udc_controller->ep0_state =WAIT_FOR_SETUP;
+ udc_controller->ep0_dir = 0;
+
+ /* stand operation */
+ spin_lock_irqsave(&udc_controller->lock, flags);
+ udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
+ nuke(&udc_controller->eps[0], -ESHUTDOWN);
+ list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list,
+ ep.ep_list)
+ nuke(loop_ep, -ESHUTDOWN);
+ spin_unlock_irqrestore(&udc_controller->lock, flags);
+
+ /* unbind gadget and unhook driver. */
+ driver->unbind(&udc_controller->gadget);
+ udc_controller->gadget.dev.driver = 0;
+ udc_controller->driver = 0;
+
+ printk("unregistered gadget driver '%s'\r\n", driver->driver.name);
+ return 0;
+}
+
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/*-------------------------------------------------------------------------
+ PROC File System Support
+-------------------------------------------------------------------------*/
+#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+
+#include <linux/seq_file.h>
+
+static const char proc_filename[] = "driver/fsl_usb2_udc";
+
+static int mpc_proc_read(char *page, char **start, off_t off, int count,
+ int *eof, void *_dev)
+{
+ char *buf = page;
+ char *next = buf;
+ unsigned size = count;
+ unsigned long flags;
+ int t, i;
+ u32 tmp_reg;
+ struct mpc_ep *ep = NULL;
+ struct mpc_req *req;
+
+ struct mpc_udc *udc = udc_controller;
+ if (off != 0)
+ return 0;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* ------basic driver infomation ---- */
+ t = scnprintf(next, size,
+ DRIVER_DESC "\n" "%s version: %s\n"
+ "Gadget driver: %s\n\n", driver_name, DRIVER_VERSION,
+ udc->driver ? udc->driver->
+ driver.name : "(none)");
+ size -= t;
+ next += t;
+
+ /* ------ DR Registers ----- */
+ tmp_reg = le32_to_cpu(usb_slave_regs->usbcmd);
+ t = scnprintf(next, size,
+ "USBCMD reg:\n" "SetupTW: %d\n" "Run/Stop: %s\n\n",
+ (tmp_reg & USB_CMD_SUTW) ? 1 : 0,
+ (tmp_reg & USB_CMD_RUN_STOP) ? "Run" : "Stop");
+ size -= t;
+ next += t;
+
+ tmp_reg = le32_to_cpu(usb_slave_regs->usbsts);
+ t = scnprintf(next, size,
+ "USB Status Reg:\n" "Dr Suspend: %d"
+ "Reset Received: %d" "System Error: %s"
+ "USB Error Interrupt: %s\n\n",
+ (tmp_reg & USB_STS_SUSPEND) ? 1 : 0,
+ (tmp_reg & USB_STS_RESET) ? 1 : 0,
+ (tmp_reg & USB_STS_SYS_ERR) ? "Err" : "Normal",
+ (tmp_reg & USB_STS_ERR) ? "Err detected" : "No err");
+ size -= t;
+ next += t;
+
+ tmp_reg = le32_to_cpu(usb_slave_regs->usbintr);
+ t = scnprintf(next, size,
+ "USB Intrrupt Enable Reg:\n"
+ "Sleep Enable: %d" "SOF Received Enable: %d"
+ "Reset Enable: %d\n" "System Error Enable: %d"
+ "Port Change Dectected Enable: %d\n"
+ "USB Error Intr Enable: %d"
+ "USB Intr Enable: %d\n\n",
+ (tmp_reg & USB_INTR_DEVICE_SUSPEND) ? 1 : 0,
+ (tmp_reg & USB_INTR_SOF_EN) ? 1 : 0,
+ (tmp_reg & USB_INTR_RESET_EN) ? 1 : 0,
+ (tmp_reg & USB_INTR_SYS_ERR_EN) ? 1 : 0,
+ (tmp_reg & USB_INTR_PTC_DETECT_EN) ? 1 : 0,
+ (tmp_reg & USB_INTR_ERR_INT_EN) ? 1 : 0,
+ (tmp_reg & USB_INTR_INT_EN) ? 1 : 0);
+ size -= t;
+ next += t;
+
+ tmp_reg = le32_to_cpu(usb_slave_regs->frindex);
+ t = scnprintf(next, size,
+ "USB Frame Index Reg:" "Frame Number is 0x%x\n\n",
+ (tmp_reg & USB_FRINDEX_MASKS));
+ size -= t;
+ next += t;
+
+ tmp_reg = le32_to_cpu(usb_slave_regs->deviceaddr);
+ t = scnprintf(next, size,
+ "USB Device Address Reg:" "Device Addr is 0x%x\n\n",
+ (tmp_reg & USB_DEVICE_ADDRESS_MASK));
+ size -= t;
+ next += t;
+
+ tmp_reg = le32_to_cpu(usb_slave_regs->endpointlistaddr);
+ t = scnprintf(next, size,
+ "USB Endpoint List Address Reg:"
+ "Device Addr is 0x%x\n\n",
+ (tmp_reg & USB_EP_LIST_ADDRESS_MASK));
+ size -= t;
+ next += t;
+
+ tmp_reg = le32_to_cpu(usb_slave_regs->portsc1);
+ t = scnprintf(next, size,
+ "USB Port Status&Control Reg:\n"
+ "Port Transceiver Type : %s" "Port Speed: %s \n"
+ "PHY Low Power Suspend: %s" "Port Reset: %s"
+ "Port Suspend Mode: %s \n" "Over-current Change: %s"
+ "Port Enable/Disable Change: %s\n"
+ "Port Enabled/Disabled: %s"
+ "Current Connect Status: %s\n\n", ( {
+ char *s;
+ switch (tmp_reg & PORTSCX_PTS_FSLS) {
+ case PORTSCX_PTS_UTMI:
+ s = "UTMI"; break;
+ case PORTSCX_PTS_ULPI:
+ s = "ULPI "; break;
+ case PORTSCX_PTS_FSLS:
+ s = "FS/LS Serial"; break;
+ default:
+ s = "None"; break;
+ }
+ s;} ), ( {
+ char *s;
+ switch (tmp_reg & PORTSCX_PORT_SPEED_UNDEF) {
+ case PORTSCX_PORT_SPEED_FULL:
+ s = "Full Speed"; break;
+ case PORTSCX_PORT_SPEED_LOW:
+ s = "Low Speed"; break;
+ case PORTSCX_PORT_SPEED_HIGH:
+ s = "High Speed"; break;
+ default:
+ s = "Undefined"; break;
+ }
+ s;
+ } ),
+ (tmp_reg & PORTSCX_PHY_LOW_POWER_SPD) ?
+ "Normal PHY mode" : "Low power mode",
+ (tmp_reg & PORTSCX_PORT_RESET) ? "In Reset" :
+ "Not in Reset",
+ (tmp_reg & PORTSCX_PORT_SUSPEND) ? "In " : "Not in",
+ (tmp_reg & PORTSCX_OVER_CURRENT_CHG) ? "Dected" :
+ "No",
+ (tmp_reg & PORTSCX_PORT_EN_DIS_CHANGE) ? "Disable" :
+ "Not change",
+ (tmp_reg & PORTSCX_PORT_ENABLE) ? "Enable" :
+ "Not correct",
+ (tmp_reg & PORTSCX_CURRENT_CONNECT_STATUS) ?
+ "Attached" : "Not-Att");
+ size -= t;
+ next += t;
+
+ tmp_reg = le32_to_cpu(usb_slave_regs->usbmode);
+ t = scnprintf(next, size,
+ "USB Mode Reg:" "Controller Mode is : %s\n\n", ( {
+ char *s;
+ switch (tmp_reg & USB_MODE_CTRL_MODE_HOST) {
+ case USB_MODE_CTRL_MODE_IDLE:
+ s = "Idle"; break;
+ case USB_MODE_CTRL_MODE_DEVICE:
+ s = "Device Controller"; break;
+ case USB_MODE_CTRL_MODE_HOST:
+ s = "Host Controller"; break;
+ default:
+ s = "None"; break;
+ }
+ s;
+ } ));
+ size -= t;
+ next += t;
+
+ tmp_reg = le32_to_cpu(usb_slave_regs->endptsetupstat);
+ t = scnprintf(next, size,
+ "Endpoint Setup Status Reg:" "SETUP on ep 0x%x\n\n",
+ (tmp_reg & EP_SETUP_STATUS_MASK));
+ size -= t;
+ next += t;
+
+ for (i = 0; i < USB_MAX_ENDPOINTS; i++) {
+ tmp_reg = le32_to_cpu(usb_slave_regs->endptctrl[i]);
+ t = scnprintf(next, size, "EP Ctrl Reg [0x%x]: = [0x%x]\n",
+ i, tmp_reg);
+ size -= t;
+ next += t;
+ }
+ tmp_reg = le32_to_cpu(usb_slave_regs->endpointprime);
+ t = scnprintf(next, size, "EP Prime Reg = [0x%x]\n", tmp_reg);
+ size -= t;
+ next += t;
+
+ tmp_reg = usb_sys_regs->snoop1;
+ t = scnprintf(next, size, "\nSnoop1 Reg : = [0x%x]\n\n", tmp_reg);
+ size -= t;
+ next += t;
+
+ tmp_reg = usb_sys_regs->control;
+ t = scnprintf(next, size, "General Control Reg : = [0x%x]\n\n",
+ tmp_reg);
+ size -= t;
+ next += t;
+
+ /* ------mpc_udc, mpc_ep, mpc_request structure information ----- */
+ ep = &udc->eps[0];
+ t = scnprintf(next, size, "For %s Maxpkt is 0x%x index is 0x%x\n",
+ ep->ep.name, ep_maxpacket(ep), ep_index(ep));
+ size -= t;
+ next += t;
+
+ if (list_empty(&ep->queue)) {
+ t = scnprintf(next, size, "its req queue is empty\n\n");
+ size -= t;
+ next += t;
+ } else {
+ list_for_each_entry(req, &ep->queue, queue) {
+ t = scnprintf(next, size,
+ "req %p actual 0x%x length 0x%x buf %p\n",
+ &req->req, req->req.actual,
+ req->req.length, req->req.buf);
+ size -= t;
+ next += t;
+ }
+ }
+ /* other gadget->eplist ep */
+ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+ if (ep->desc) {
+ t = scnprintf(next, size,
+ "\nFor %s Maxpkt is 0x%x index is 0x%x\n",
+ ep->ep.name,
+ ep_maxpacket(ep),
+ ep_index(ep));
+ size -= t;
+ next += t;
+
+ if (list_empty(&ep->queue)) {
+ t = scnprintf(next, size,
+ "its req queue is empty\n\n");
+ size -= t;
+ next += t;
+ } else {
+ list_for_each_entry(req, &ep->queue, queue) {
+ t = scnprintf(next, size,
+ "req %p actual 0x%x length"
+ "0x%x buf %p\n",
+ &req->req, req->req.actual,
+ req->req.length, req->req.buf);
+ size -= t;
+ next += t;
+ } // end for each_entry of ep req
+ } //end for else
+ } //end for if(ep->queue)
+ } // end (ep->desc)
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ *eof = 1;
+ return count - size;
+}
+
+#define create_proc_file() create_proc_read_entry(proc_filename, \
+ 0, NULL, mpc_proc_read, NULL)
+
+#define remove_proc_file() remove_proc_entry(proc_filename, NULL)
+
+#else /* !CONFIG_USB_GADGET_DEBUG_FILES */
+
+#define create_proc_file() do {} while (0)
+#define remove_proc_file() do {} while (0)
+
+#endif /*CONFIG_USB_GADGET_DEBUG_FILES */
+
+/*-------------------------------------------------------------------------*/
+
+/*-------------------------------------------------------------------------
+ * Release the mpc specific udc structure
+ * it is not stand gadget function
+ * it is called when the last reference to the device is removed;
+ * it is called from the embedded kobject's release method.
+ * All device structures registered with the core must have a
+ * release method, or the kernel prints out scary complaints
+ *-------------------------------------------------------------------------*/
+static void mpc_udc_release(struct device *dev)
+{
+ complete(udc_controller->done);
+ kfree(ep_qh_base);
+ ep_qh_base = NULL;
+ kfree(udc_controller);
+ udc_controller = NULL;
+}
+
+/******************************************************************
+ Internal structure setup functions
+*******************************************************************/
+/*------------------------------------------------------------------
+ * this func will init resource for globle controller
+ * Return the udc handle on success or Null on failing
+ ------------------------------------------------------------------*/
+static void *struct_udc_setup(struct platform_device *pdev)
+{
+ struct mpc_udc *udc = NULL;
+ unsigned int tmp_sz = 0;
+
+ udc = (struct mpc_udc *)kzalloc(sizeof(struct mpc_udc), GFP_KERNEL);
+ if (udc == NULL) {
+ printk("malloc udc failed\n");
+ goto cleanup;
+ }
+
+ /* initialized QHs, take care the 2K align */
+ tmp_sz = USB_MAX_PIPES * sizeof(struct ep_queue_head);
+ udc->ep_qh = (struct ep_queue_head *)KMALLOC_ALIGN(tmp_sz, GFP_KERNEL,
+ 2 * 1024,
+ (void **)&ep_qh_base);
+ if (!udc->ep_qh) {
+ printk("malloc QHs for udc failed\n");
+ goto cleanup;
+ }
+ /* Initialize ep0 status request structure */
+ /* FIXME: mpc_alloc_request() ignores ep argument */
+ udc->status_req = container_of(mpc_alloc_request(NULL, GFP_KERNEL),
+ struct mpc_req, req);
+ /* allocate a small amount of memory to get valid address */
+ udc->status_req->req.buf = kmalloc(8, GFP_KERNEL);
+ udc->status_req->req.dma = virt_to_phys(udc->status_req->req.buf);
+
+ udc->resume_state = USB_STATE_NOTATTACHED;
+ udc->usb_state = USB_STATE_POWERED;
+ udc->ep0_dir = 0;
+ spin_lock_init(&udc->lock);
+
+ return udc;
+
+cleanup:
+ kfree(udc);
+ return NULL;
+}
+
+/*----------------------------------------------------------------
+ * set up the mpc_ep struct for eps
+ * ep0out isnot used so do nothing here
+ * ep0in should be taken care
+ * It also link this mpc_ep->ep to gadget->ep_list
+ *--------------------------------------------------------------*/
+static int struct_ep_setup(void *handle, unsigned char pipe_num)
+{
+ struct mpc_udc *udc = (struct mpc_udc *)handle;
+ struct mpc_ep *ep = get_ep_by_pipe(udc, pipe_num);
+
+ ep->udc = udc;
+ strcpy(ep->name, ep_name[pipe_num]);
+ ep->ep.name = ep_name[pipe_num];
+ ep->ep.ops = &mpc_ep_ops;
+ ep->stopped = 0;
+
+ /* for ep0: the desc defined here;
+ * for other eps, gadget layer called ep_enable with defined desc
+ */
+ /* for ep0: maxP defined in desc
+ * for other eps, maxP is set by epautoconfig() called by gadget layer
+ */
+ if (pipe_num == 0)
+ {
+ ep->desc = &mpc_ep0_desc;
+ ep->ep.maxpacket = USB_MAX_CTRL_PAYLOAD;
+ }
+ else
+ {
+ ep->ep.maxpacket = (unsigned short) ~0;
+ ep->desc = NULL;
+ }
+
+ /* the queue lists any req for this ep */
+ INIT_LIST_HEAD(&ep->queue);
+
+ /* gagdet.ep_list used for ep_autoconfig so no ep0*/
+ if (pipe_num != 0)
+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+ ep->gadget = &udc->gadget;
+
+ return 0;
+}
+
+/* Driver probe function
+ * all intialize operations implemented here except enabling usb_intr reg
+ */
+static int __init mpc_udc_probe(struct platform_device *pdev)
+{
+ struct resource *dr_resources;
+ int dr_num_resources;
+
+ int tmp_status = -ENODEV;
+ unsigned int i;
+
+ if (strcmp(pdev->name, driver_name)) {
+ VDBG("Wrong device\n");
+ return -ENODEV;
+ }
+
+ /* board env setting should be OK before here
+ * including:
+ * Set up I2C if using USB port of PMC board
+ * Set SCCR for usb clock
+ * Set SICR for io pin according to 83xx RM table 16-1
+ * Set up PCA9555 according PHY interface type if using usb port of PMC
+ */
+
+ /* Initialize the udc structure including QH member and other member */
+ udc_controller = (struct mpc_udc *)struct_udc_setup(pdev);
+ if (!udc_controller)
+ {
+ VDBG("udc_controller is NULL \n");
+ return -ENOMEM;
+ }
+#if defined(CONFIG_FSL_USB_OTG) || defined(CONFIG_FSL_USB_OTG_MODULE)
+ /* Memory and interrupt resources will be passed from OTG */
+ udc_controller->transceiver = otg_get_transceiver();
+ if (!udc_controller->transceiver) {
+ printk("Can't find OTG driver!\n");
+ return -ENODEV;
+ }
+
+ dr_resources = otg_get_resources(&dr_num_resources);
+ if (!dr_resources) {
+ DBG("resource not registered!\n");
+ return -ENODEV;
+ }
+#else
+ dr_resources = pdev->resource;
+ dr_num_resources = pdev->num_resources;
+
+ if (!request_mem_region(dr_resources[0].start,
+ dr_resources[0].end -
+ dr_resources[0].start + 1,
+ driver_name)) {
+ printk("request mem region for %s failed \n", pdev->name);
+ return -EBUSY;
+ }
+#endif
+ /* Initialize the dr register map addr */
+ if (dr_resources[0].flags != IORESOURCE_MEM
+ || dr_resources[1].flags != IORESOURCE_IRQ) {
+ return -ENODEV;
+ }
+
+ usb_slave_regs = ioremap(dr_resources[0].start,
+ sizeof(struct usb_dr_device));
+ usb_sys_regs = (struct usb_sys_interface *)((int)usb_slave_regs +
+ USB_DR_SYS_OFFSET);
+
+ tmp_status = request_irq(dr_resources[1].start, mpc_udc_irq, SA_SHIRQ,
+ driver_name,udc_controller);
+ if (tmp_status != 0) {
+ printk("cannot request irq %d err %d \n",
+ (int)dr_resources[1].start, tmp_status);
+ return tmp_status;
+ }
+
+
+ /* initialize usb hw reg except for regs for EP,
+ * leave usbintr reg untouched */
+ dr_controller_setup(udc_controller->ep_qh);
+ /* standard operations for probe */
+ udc_controller->gadget.ops = &mpc_gadget_ops;
+ udc_controller->gadget.ep0 = &udc_controller->eps[0].ep;
+
+ INIT_LIST_HEAD(&udc_controller->gadget.ep_list);
+
+ udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
+
+ /* name: Identifies the controller hardware type. */
+ udc_controller->gadget.name = driver_name;
+
+ device_initialize(&udc_controller->gadget.dev);
+
+ strcpy(udc_controller->gadget.dev.bus_id, "gadget");
+
+ udc_controller->gadget.dev.release = mpc_udc_release;
+ udc_controller->gadget.dev.parent = &pdev->dev;
+
+#if (defined(CONFIG_FSL_USB_OTG) || defined(CONFIG_FSL_USB_OTG_MODULE)) && \
+ (defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE))
+ udc_controller->gadget.is_otg = 1;
+#endif
+
+ /* for an EP, the intialization includes: fields in QH, Regs,
+ * mpc_ep struct */
+ ep0_dr_and_qh_setup(udc_controller);
+ for (i = 0; i < USB_MAX_PIPES ; i++) {
+ /* because the ep type isnot decide here so
+ * struct_ep_qh_setup() and dr_ep_setup()
+ * should be called in ep_enable()
+ */
+ if ( ep_name[i] != NULL )
+ /* setup the mpc_ep struct and link ep.ep.list
+ * into gadget.ep_list */
+ struct_ep_setup(udc_controller, i);
+ }
+
+ create_proc_file();
+ device_add(&udc_controller->gadget.dev);
+ return 0;
+}
+
+/* Driver removal functions
+ * Free resources
+ * Finish pending transaction
+ */
+static int __exit mpc_udc_remove(struct platform_device *pdev)
+{
+#if defined(CONFIG_FSL_USB_OTG) || defined(CONFIG_FSL_USB_OTG_MODULE)
+ int dr_num_resources;
+ struct resource *dr_resources = otg_get_resources(&dr_num_resources);
+#endif
+
+ DECLARE_COMPLETION(done);
+
+ if (!udc_controller)
+ return -ENODEV;
+ udc_controller->done = &done;
+
+ /* DR has been stopped in usb_gadget_unregister_driver() */
+
+ remove_proc_file();
+
+ /* Free allocated memory */
+ kfree(udc_controller->status_req->req.buf);
+ kfree(udc_controller->status_req);
+
+#if defined(CONFIG_FSL_USB_OTG) || defined(CONFIG_FSL_USB_OTG_MODULE)
+ free_irq(dr_resources[1].start, udc_controller);
+ /* The OTG driver is responsible to free resources */
+#else
+ free_irq(pdev->resource[1].start, udc_controller);
+
+ release_mem_region(pdev->resource[0].start,
+ pdev->resource[0].end -
+ pdev->resource[0].start + 1);
+#endif
+
+ device_unregister(&udc_controller->gadget.dev);
+ /* free udc --wait for the release() finished */
+ wait_for_completion(&done);
+
+ return 0;
+}
+
+/*-----------------------------------------------------------------
+ * Modify Power management attributes
+ * Here we stop the DR controller and disable the irq
+ -----------------------------------------------------------------*/
+static int mpc_udc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ dr_controller_stop(udc_controller);
+ return 0;
+}
+
+/*-----------------------------------------------------------------
+ * Invoked on USB resume. May be called in_interrupt.
+ * Here we start the DR controller and enable the irq
+ *-----------------------------------------------------------------*/
+static int mpc_udc_resume(struct platform_device *pdev)
+{
+ /*Enable DR irq reg and set controller Run */
+ if (udc_controller->stopped) {
+ dr_controller_setup(udc_controller->ep_qh);
+ dr_controller_run(udc_controller);
+ }
+ udc_controller->usb_state = USB_STATE_ATTACHED;
+ udc_controller->ep0_state = WAIT_FOR_SETUP;
+ udc_controller->ep0_dir = 0;
+ return 0;
+}
+
+/*-------------------------------------------------------------------------
+ Register entry point for the peripheral controller driver
+--------------------------------------------------------------------------*/
+
+static struct platform_driver udc_driver = {
+ .probe = mpc_udc_probe,
+ .remove = __exit_p(mpc_udc_remove),
+ /* these suspend and resume are not usb suspend and resume */
+ .suspend = mpc_udc_suspend,
+ .resume = mpc_udc_resume,
+ .driver = {
+ .name = (char *)driver_name,
+ .owner = THIS_MODULE,
+ },
+};
+
+
+static int __init udc_init(void)
+{
+ printk("%s version %s init \n", driver_desc, DRIVER_VERSION);
+ return platform_driver_register(&udc_driver);
+}
+
+module_init(udc_init);
+
+static void __exit udc_exit(void)
+{
+ platform_driver_unregister(&udc_driver);
+}
+
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
new file mode 100644
index 0000000..bee746c
--- /dev/null
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -0,0 +1,608 @@
+/*
+ * Freescale USB device/endpoint management registers
+ * some defines from shlomi
+ */
+#ifndef __MPC_UDC_H
+#define __MPC_UDC_H
+
+/* ### define USB registers here
+ */
+#define USB_MAX_ENDPOINTS 6
+#define USB_MAX_PIPES (USB_MAX_ENDPOINTS*2)
+#define USB_MAX_CTRL_PAYLOAD 64
+#define USB_DR_SYS_OFFSET 0x400
+
+ /* USB DR device mode registers (Little Endian) */
+struct usb_dr_device {
+ /* Capability register */
+ u8 res1[256];
+ u16 caplength; /* Capability Register Length */
+ u16 hciversion; /* Host Controller Interface Version */
+ u32 hcsparams; /* Host Controller Structual Parameters */
+ u32 hccparams; /* Host Controller Capability Parameters */
+ u8 res2[20];
+ u32 dciversion; /* Device Controller Interface Version */
+ u32 dccparams; /* Device Controller Capability Parameters */
+ u8 res3[24];
+ /* Operation register */
+ u32 usbcmd; /* USB Command Register */
+ u32 usbsts; /* USB Status Register */
+ u32 usbintr; /* USB Interrupt Enable Register */
+ u32 frindex; /* Frame Index Register */
+ u8 res4[4];
+ u32 deviceaddr; /* Device Address */
+ u32 endpointlistaddr; /* Endpoint List Address Register */
+ u8 res5[4];
+ u32 burstsize; /* Master Interface Data Burst Size Register */
+ u32 txttfilltuning; /* Transmit FIFO Tuning Controls Register */
+ u8 res6[24];
+ u32 configflag; /* Configure Flag Register */
+ u32 portsc1; /* Port 1 Status and Control Register */
+ u8 res7[28];
+ u32 otgsc; /* On-The-Go Status and Control */
+ u32 usbmode; /* USB Mode Register */
+ u32 endptsetupstat; /* Endpoint Setup Status Register */
+ u32 endpointprime; /* Endpoint Initialization Register */
+ u32 endptflush; /* Endpoint Flush Register */
+ u32 endptstatus; /* Endpoint Status Register */
+ u32 endptcomplete; /* Endpoint Complete Register */
+ u32 endptctrl[6]; /* Endpoint Control Registers */
+};
+
+ /* USB DR host mode registers (Little Endian) */
+struct usb_dr_host {
+ /* Capability register */
+ u8 res1[256];
+ u16 caplength; /* Capability Register Length */
+ u16 hciversion; /* Host Controller Interface Version */
+ u32 hcsparams; /* Host Controller Structual Parameters */
+ u32 hccparams; /* Host Controller Capability Parameters */
+ u8 res2[20];
+ u32 dciversion; /* Device Controller Interface Version */
+ u32 dccparams; /* Device Controller Capability Parameters */
+ u8 res3[24];
+ /* Operation register */
+ u32 usbcmd; /* USB Command Register */
+ u32 usbsts; /* USB Status Register */
+ u32 usbintr; /* USB Interrupt Enable Register */
+ u32 frindex; /* Frame Index Register */
+ u8 res4[4];
+ u32 periodiclistbase; /* Periodic Frame List Base Address Register */
+ u32 asynclistaddr; /* Current Asynchronous List Address Register */
+ u8 res5[4];
+ u32 burstsize; /* Master Interface Data Burst Size Register */
+ u32 txttfilltuning; /* Transmit FIFO Tuning Controls Register */
+ u8 res6[24];
+ u32 configflag; /* Configure Flag Register */
+ u32 portsc1; /* Port 1 Status and Control Register */
+ u8 res7[28];
+ u32 otgsc; /* On-The-Go Status and Control */
+ u32 usbmode; /* USB Mode Register */
+ u32 endptsetupstat; /* Endpoint Setup Status Register */
+ u32 endpointprime; /* Endpoint Initialization Register */
+ u32 endptflush; /* Endpoint Flush Register */
+ u32 endptstatus; /* Endpoint Status Register */
+ u32 endptcomplete; /* Endpoint Complete Register */
+ u32 endptctrl[6]; /* Endpoint Control Registers */
+};
+
+
+ /* non-EHCI USB system interface registers (Big Endian) */
+struct usb_sys_interface {
+ u32 snoop1;
+ u32 snoop2;
+ u32 age_cnt_thresh; /* Age Count Threshold Register */
+ u32 pri_ctrl; /* Priority Control Register */
+ u32 si_ctrl; /* System Interface Control Register */
+ u8 res[236];
+ u32 control; /* General Purpose Control Register */
+};
+
+/* ep0 transfer state */
+#define WAIT_FOR_SETUP 0
+#define DATA_STATE_XMIT 1
+#define DATA_STATE_NEED_ZLP 2
+#define WAIT_FOR_OUT_STATUS 3
+#define DATA_STATE_RECV 4
+
+
+/* Frame Index Register Bit Masks */
+#define USB_FRINDEX_MASKS (0x3fff)
+/* USB CMD Register Bit Masks */
+#define USB_CMD_RUN_STOP (0x00000001)
+#define USB_CMD_CTRL_RESET (0x00000002)
+#define USB_CMD_PERIODIC_SCHEDULE_EN (0x00000010)
+#define USB_CMD_ASYNC_SCHEDULE_EN (0x00000020)
+#define USB_CMD_INT_AA_DOORBELL (0x00000040)
+#define USB_CMD_ASP (0x00000300)
+#define USB_CMD_ASYNC_SCH_PARK_EN (0x00000800)
+#define USB_CMD_SUTW (0x00002000)
+#define USB_CMD_ATDTW (0x00004000)
+#define USB_CMD_ITC (0x00FF0000)
+
+/* bit 15,3,2 are frame list size */
+#define USB_CMD_FRAME_SIZE_1024 (0x00000000)
+#define USB_CMD_FRAME_SIZE_512 (0x00000004)
+#define USB_CMD_FRAME_SIZE_256 (0x00000008)
+#define USB_CMD_FRAME_SIZE_128 (0x0000000C)
+#define USB_CMD_FRAME_SIZE_64 (0x00008000)
+#define USB_CMD_FRAME_SIZE_32 (0x00008004)
+#define USB_CMD_FRAME_SIZE_16 (0x00008008)
+#define USB_CMD_FRAME_SIZE_8 (0x0000800C)
+
+/* bit 9-8 are async schedule park mode count */
+#define USB_CMD_ASP_00 (0x00000000)
+#define USB_CMD_ASP_01 (0x00000100)
+#define USB_CMD_ASP_10 (0x00000200)
+#define USB_CMD_ASP_11 (0x00000300)
+#define USB_CMD_ASP_BIT_POS (8)
+
+/* bit 23-16 are interrupt threshold control */
+#define USB_CMD_ITC_NO_THRESHOLD (0x00000000)
+#define USB_CMD_ITC_1_MICRO_FRM (0x00010000)
+#define USB_CMD_ITC_2_MICRO_FRM (0x00020000)
+#define USB_CMD_ITC_4_MICRO_FRM (0x00040000)
+#define USB_CMD_ITC_8_MICRO_FRM (0x00080000)
+#define USB_CMD_ITC_16_MICRO_FRM (0x00100000)
+#define USB_CMD_ITC_32_MICRO_FRM (0x00200000)
+#define USB_CMD_ITC_64_MICRO_FRM (0x00400000)
+#define USB_CMD_ITC_BIT_POS (16)
+
+/* USB STS Register Bit Masks */
+#define USB_STS_INT (0x00000001)
+#define USB_STS_ERR (0x00000002)
+#define USB_STS_PORT_CHANGE (0x00000004)
+#define USB_STS_FRM_LST_ROLL (0x00000008)
+#define USB_STS_SYS_ERR (0x00000010)
+#define USB_STS_IAA (0x00000020)
+#define USB_STS_RESET (0x00000040)
+#define USB_STS_SOF (0x00000080)
+#define USB_STS_SUSPEND (0x00000100)
+#define USB_STS_HC_HALTED (0x00001000)
+#define USB_STS_RCL (0x00002000)
+#define USB_STS_PERIODIC_SCHEDULE (0x00004000)
+#define USB_STS_ASYNC_SCHEDULE (0x00008000)
+
+/* USB INTR Register Bit Masks */
+#define USB_INTR_INT_EN (0x00000001)
+#define USB_INTR_ERR_INT_EN (0x00000002)
+#define USB_INTR_PTC_DETECT_EN (0x00000004)
+#define USB_INTR_FRM_LST_ROLL_EN (0x00000008)
+#define USB_INTR_SYS_ERR_EN (0x00000010)
+#define USB_INTR_ASYN_ADV_EN (0x00000020)
+#define USB_INTR_RESET_EN (0x00000040)
+#define USB_INTR_SOF_EN (0x00000080)
+#define USB_INTR_DEVICE_SUSPEND (0x00000100)
+
+/* Device Address bit masks */
+#define USB_DEVICE_ADDRESS_MASK (0xFE000000)
+#define USB_DEVICE_ADDRESS_BIT_POS (25)
+
+/* endpoint list address bit masks */
+#define USB_EP_LIST_ADDRESS_MASK (0xfffff800)
+
+/* PORTSCX Register Bit Masks */
+#define PORTSCX_CURRENT_CONNECT_STATUS (0x00000001)
+#define PORTSCX_CONNECT_STATUS_CHANGE (0x00000002)
+#define PORTSCX_PORT_ENABLE (0x00000004)
+#define PORTSCX_PORT_EN_DIS_CHANGE (0x00000008)
+#define PORTSCX_OVER_CURRENT_ACT (0x00000010)
+#define PORTSCX_OVER_CURRENT_CHG (0x00000020)
+#define PORTSCX_PORT_FORCE_RESUME (0x00000040)
+#define PORTSCX_PORT_SUSPEND (0x00000080)
+#define PORTSCX_PORT_RESET (0x00000100)
+#define PORTSCX_LINE_STATUS_BITS (0x00000C00)
+#define PORTSCX_PORT_POWER (0x00001000)
+#define PORTSCX_PORT_INDICTOR_CTRL (0x0000C000)
+#define PORTSCX_PORT_TEST_CTRL (0x000F0000)
+#define PORTSCX_WAKE_ON_CONNECT_EN (0x00100000)
+#define PORTSCX_WAKE_ON_CONNECT_DIS (0x00200000)
+#define PORTSCX_WAKE_ON_OVER_CURRENT (0x00400000)
+#define PORTSCX_PHY_LOW_POWER_SPD (0x00800000)
+#define PORTSCX_PORT_FORCE_FULL_SPEED (0x01000000)
+#define PORTSCX_PORT_SPEED_MASK (0x0C000000)
+#define PORTSCX_PORT_WIDTH (0x10000000)
+#define PORTSCX_PHY_TYPE_SEL (0xC0000000)
+
+/* bit 11-10 are line status */
+#define PORTSCX_LINE_STATUS_SE0 (0x00000000)
+#define PORTSCX_LINE_STATUS_JSTATE (0x00000400)
+#define PORTSCX_LINE_STATUS_KSTATE (0x00000800)
+#define PORTSCX_LINE_STATUS_UNDEF (0x00000C00)
+#define PORTSCX_LINE_STATUS_BIT_POS (10)
+
+/* bit 15-14 are port indicator control */
+#define PORTSCX_PIC_OFF (0x00000000)
+#define PORTSCX_PIC_AMBER (0x00004000)
+#define PORTSCX_PIC_GREEN (0x00008000)
+#define PORTSCX_PIC_UNDEF (0x0000C000)
+#define PORTSCX_PIC_BIT_POS (14)
+
+/* bit 19-16 are port test control */
+#define PORTSCX_PTC_DISABLE (0x00000000)
+#define PORTSCX_PTC_JSTATE (0x00010000)
+#define PORTSCX_PTC_KSTATE (0x00020000)
+#define PORTSCX_PTC_SEQNAK (0x00030000)
+#define PORTSCX_PTC_PACKET (0x00040000)
+#define PORTSCX_PTC_FORCE_EN (0x00050000)
+#define PORTSCX_PTC_BIT_POS (16)
+
+/* bit 27-26 are port speed */
+#define PORTSCX_PORT_SPEED_FULL (0x00000000)
+#define PORTSCX_PORT_SPEED_LOW (0x04000000)
+#define PORTSCX_PORT_SPEED_HIGH (0x08000000)
+#define PORTSCX_PORT_SPEED_UNDEF (0x0C000000)
+#define PORTSCX_SPEED_BIT_POS (26)
+
+/* bit 28 is parallel transceiver width for UTMI interface */
+#define PORTSCX_PTW (0x10000000)
+#define PORTSCX_PTW_8BIT (0x00000000)
+#define PORTSCX_PTW_16BIT (0x10000000)
+
+/* bit 31-30 are port transceiver select */
+#define PORTSCX_PTS_UTMI (0x00000000)
+#define PORTSCX_PTS_ULPI (0x80000000)
+#define PORTSCX_PTS_FSLS (0xC0000000)
+#define PORTSCX_PTS_BIT_POS (30)
+
+/* otgsc Register Bit Masks */
+#define OTGSC_CTRL_VUSB_DISCHARGE (0x00000001)
+#define OTGSC_CTRL_VUSB_CHARGE (0x00000002)
+#define OTGSC_CTRL_OTG_TERM (0x00000008)
+#define OTGSC_CTRL_DATA_PULSING (0x00000010)
+#define OTGSC_STS_USB_ID (0x00000100)
+#define OTGSC_STS_A_VBUS_VALID (0x00000200)
+#define OTGSC_STS_A_SESSION_VALID (0x00000400)
+#define OTGSC_STS_B_SESSION_VALID (0x00000800)
+#define OTGSC_STS_B_SESSION_END (0x00001000)
+#define OTGSC_STS_1MS_TOGGLE (0x00002000)
+#define OTGSC_STS_DATA_PULSING (0x00004000)
+#define OTGSC_INTSTS_USB_ID (0x00010000)
+#define OTGSC_INTSTS_A_VBUS_VALID (0x00020000)
+#define OTGSC_INTSTS_A_SESSION_VALID (0x00040000)
+#define OTGSC_INTSTS_B_SESSION_VALID (0x00080000)
+#define OTGSC_INTSTS_B_SESSION_END (0x00100000)
+#define OTGSC_INTSTS_1MS (0x00200000)
+#define OTGSC_INTSTS_DATA_PULSING (0x00400000)
+#define OTGSC_INTR_USB_ID (0x01000000)
+#define OTGSC_INTR_A_VBUS_VALID (0x02000000)
+#define OTGSC_INTR_A_SESSION_VALID (0x04000000)
+#define OTGSC_INTR_B_SESSION_VALID (0x08000000)
+#define OTGSC_INTR_B_SESSION_END (0x10000000)
+#define OTGSC_INTR_1MS_TIMER (0x20000000)
+#define OTGSC_INTR_DATA_PULSING (0x40000000)
+
+/* USB MODE Register Bit Masks */
+#define USB_MODE_CTRL_MODE_IDLE (0x00000000)
+#define USB_MODE_CTRL_MODE_DEVICE (0x00000002)
+#define USB_MODE_CTRL_MODE_HOST (0x00000003)
+#define USB_MODE_CTRL_MODE_RSV (0x00000001)
+#define USB_MODE_SETUP_LOCK_OFF (0x00000008)
+#define USB_MODE_STREAM_DISABLE (0x00000010)
+/* Endpoint Flush Register */
+#define EPFLUSH_TX_OFFSET (0x00010000)
+#define EPFLUSH_RX_OFFSET (0x00000000)
+
+/* Endpoint Setup Status bit masks */
+#define EP_SETUP_STATUS_MASK (0x0000003F)
+#define EP_SETUP_STATUS_EP0 (0x00000001)
+
+/* ENDPOINTCTRLx Register Bit Masks */
+#define EPCTRL_TX_ENABLE (0x00800000)
+#define EPCTRL_TX_DATA_TOGGLE_RST (0x00400000) /* Not EP0 */
+#define EPCTRL_TX_DATA_TOGGLE_INH (0x00200000) /* Not EP0 */
+#define EPCTRL_TX_TYPE (0x000C0000)
+#define EPCTRL_TX_DATA_SOURCE (0x00020000) /* Not EP0 */
+#define EPCTRL_TX_EP_STALL (0x00010000)
+#define EPCTRL_RX_ENABLE (0x00000080)
+#define EPCTRL_RX_DATA_TOGGLE_RST (0x00000040) /* Not EP0 */
+#define EPCTRL_RX_DATA_TOGGLE_INH (0x00000020) /* Not EP0 */
+#define EPCTRL_RX_TYPE (0x0000000C)
+#define EPCTRL_RX_DATA_SINK (0x00000002) /* Not EP0 */
+#define EPCTRL_RX_EP_STALL (0x00000001)
+
+/* bit 19-18 and 3-2 are endpoint type */
+#define EPCTRL_EP_TYPE_CONTROL (0)
+#define EPCTRL_EP_TYPE_ISO (1)
+#define EPCTRL_EP_TYPE_BULK (2)
+#define EPCTRL_EP_TYPE_INTERRUPT (3)
+#define EPCTRL_TX_EP_TYPE_SHIFT (18)
+#define EPCTRL_RX_EP_TYPE_SHIFT (2)
+
+
+/* SNOOPn Register Bit Masks */
+#define SNOOP_ADDRESS_MASK (0xFFFFF000)
+#define SNOOP_SIZE_ZERO (0x00) /* snooping disable */
+#define SNOOP_SIZE_4KB (0x0B) /* 4KB snoop size */
+#define SNOOP_SIZE_8KB (0x0C)
+#define SNOOP_SIZE_16KB (0x0D)
+#define SNOOP_SIZE_32KB (0x0E)
+#define SNOOP_SIZE_64KB (0x0F)
+#define SNOOP_SIZE_128KB (0x10)
+#define SNOOP_SIZE_256KB (0x11)
+#define SNOOP_SIZE_512KB (0x12)
+#define SNOOP_SIZE_1MB (0x13)
+#define SNOOP_SIZE_2MB (0x14)
+#define SNOOP_SIZE_4MB (0x15)
+#define SNOOP_SIZE_8MB (0x16)
+#define SNOOP_SIZE_16MB (0x17)
+#define SNOOP_SIZE_32MB (0x18)
+#define SNOOP_SIZE_64MB (0x19)
+#define SNOOP_SIZE_128MB (0x1A)
+#define SNOOP_SIZE_256MB (0x1B)
+#define SNOOP_SIZE_512MB (0x1C)
+#define SNOOP_SIZE_1GB (0x1D)
+#define SNOOP_SIZE_2GB (0x1E) /* 2GB snoop size */
+
+
+/* pri_ctrl Register Bit Masks */
+#define PRI_CTRL_PRI_LVL1 (0x0000000C)
+#define PRI_CTRL_PRI_LVL0 (0x00000003)
+
+/* si_ctrl Register Bit Masks */
+#define SI_CTRL_ERR_DISABLE (0x00000010)
+#define SI_CTRL_IDRC_DISABLE (0x00000008)
+#define SI_CTRL_RD_SAFE_EN (0x00000004)
+#define SI_CTRL_RD_PREFETCH_DISABLE (0x00000002)
+#define SI_CTRL_RD_PREFEFETCH_VAL (0x00000001)
+
+/* control Register Bit Masks */
+#define USB_CTRL_IOENB (0x00000004)
+#define USB_CTRL_ULPI_INT0EN (0x00000001)
+
+/* Endpoint Queue Head data struct
+ * Rem: all the variables of qh are LittleEndian Mode
+ * and NEXT_POINTER_MASK should operate on a LittleEndian, Phy Addr
+ */
+struct ep_queue_head {
+ u32 max_pkt_length; /* Mult(31-30) , Zlt(29) , Max Pkt len
+ and IOS(15) */
+ u32 curr_dtd_ptr; /* Current dTD Pointer(31-5) */
+ u32 next_dtd_ptr; /* Next dTD Pointer(31-5), T(0) */
+ u32 size_ioc_int_sts; /* Total bytes (30-16), IOC (15),
+ MultO(11-10), STS (7-0) */
+ u32 buff_ptr0; /* Buffer pointer Page 0 (31-12) */
+ u32 buff_ptr1; /* Buffer pointer Page 1 (31-12) */
+ u32 buff_ptr2; /* Buffer pointer Page 2 (31-12) */
+ u32 buff_ptr3; /* Buffer pointer Page 3 (31-12) */
+ u32 buff_ptr4; /* Buffer pointer Page 4 (31-12) */
+ u32 res1;
+ u8 setup_buffer[8]; /* Setup data 8 bytes */
+ u32 res2[4];
+};
+
+/* Endpoint Queue Head Bit Masks */
+#define EP_QUEUE_HEAD_MULT_POS (30)
+#define EP_QUEUE_HEAD_ZLT_SEL (0x20000000)
+#define EP_QUEUE_HEAD_MAX_PKT_LEN_POS (16)
+#define EP_QUEUE_HEAD_MAX_PKT_LEN(ep_info) (((ep_info)>>16)&0x07ff)
+#define EP_QUEUE_HEAD_IOS (0x00008000)
+#define EP_QUEUE_HEAD_NEXT_TERMINATE (0x00000001)
+#define EP_QUEUE_HEAD_IOC (0x00008000)
+#define EP_QUEUE_HEAD_MULTO (0x00000C00)
+#define EP_QUEUE_HEAD_STATUS_HALT (0x00000040)
+#define EP_QUEUE_HEAD_STATUS_ACTIVE (0x00000080)
+#define EP_QUEUE_CURRENT_OFFSET_MASK (0x00000FFF)
+#define EP_QUEUE_HEAD_NEXT_POINTER_MASK (0xFFFFFFE0)
+#define EP_QUEUE_FRINDEX_MASK (0x000007FF)
+#define EP_MAX_LENGTH_TRANSFER (0x4000)
+
+/* Endpoint Transfer Descriptor data struct */
+/* Rem: all the variables of td are LittleEndian Mode */
+struct ep_td_struct {
+ u32 next_td_ptr; /* Next TD pointer(31-5), T(0) set
+ indicate invalid */
+ u32 size_ioc_sts; /* Total bytes (30-16), IOC (15),
+ MultO(11-10), STS (7-0) */
+ u32 buff_ptr0; /* Buffer pointer Page 0 */
+ u32 buff_ptr1; /* Buffer pointer Page 1 */
+ u32 buff_ptr2; /* Buffer pointer Page 2 */
+ u32 buff_ptr3; /* Buffer pointer Page 3 */
+ u32 buff_ptr4; /* Buffer pointer Page 4 */
+};
+
+/* Endpoint Transfer Descriptor bit Masks */
+#define DTD_NEXT_TERMINATE (0x00000001)
+#define DTD_IOC (0x00008000)
+#define DTD_STATUS_ACTIVE (0x00000080)
+#define DTD_STATUS_HALTED (0x00000040)
+#define DTD_STATUS_DATA_BUFF_ERR (0x00000020)
+#define DTD_STATUS_TRANSACTION_ERR (0x00000008)
+#define DTD_RESERVED_FIELDS (0x80007300)
+#define DTD_ADDR_MASK (0xFFFFFFE0)
+#define DTD_PACKET_SIZE (0x7FFF0000)
+#define DTD_LENGTH_BIT_POS (16)
+#define DTD_ERROR_MASK (DTD_STATUS_HALTED | \
+ DTD_STATUS_DATA_BUFF_ERR | \
+ DTD_STATUS_TRANSACTION_ERR)
+
+/* -----------------------------------------------------------------------*/
+/* ##### enum data
+*/
+typedef enum {
+ e_ULPI,
+ e_UTMI_8BIT,
+ e_UTMI_16BIT,
+ e_SERIAL
+} e_PhyInterface;
+
+/*-------------------------------------------------------------------------*/
+
+/* ### driver private data, Need rework
+ */
+struct mpc_req {
+ struct usb_request req;
+ struct list_head queue;
+ /* ep_queue() func will add
+ a request->queue into a udc_ep->queue 'd tail */
+ struct mpc_ep *ep;
+ unsigned mapped:1;
+
+ struct ep_td_struct *head, *tail; /* For dTD List
+ this is a BigEndian Virtual addr */
+ unsigned int dtd_count;
+};
+
+
+#define REQ_UNCOMPLETE (1)
+
+struct mpc_ep {
+ struct usb_ep ep;
+ struct list_head queue;
+ struct mpc_udc *udc;
+ const struct usb_endpoint_descriptor *desc;
+ struct usb_gadget *gadget;
+
+ u8 already_seen;
+ u8 setup_stage;
+ u32 last_io; /* timestamp */
+
+ char name[14];
+#if 0
+ u16 maxpacket;
+ u8 bEndpointAddress;
+ u8 bmAttributes;
+#endif
+ unsigned double_buf:1;
+ unsigned stopped:1;
+ unsigned fnf:1;
+ unsigned has_dma:1;
+ u8 ackwait;
+ u8 dma_channel;
+ u16 dma_counter;
+ int lch;
+
+ struct timer_list timer;
+
+};
+
+#define EP_DIR_IN 1
+#define EP_DIR_OUT 0
+
+struct mpc_udc {
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct mpc_ep eps[USB_MAX_ENDPOINTS * 2];
+ struct usb_ctrlrequest local_setup_buff;
+ spinlock_t lock;
+ struct otg_transceiver *transceiver;
+ unsigned softconnect:1;
+ unsigned vbus_active:1;
+ unsigned stopped:1;
+
+ struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */
+ struct mpc_req *status_req; /* ep0 status request */
+
+ u32 max_pipes; /* Device max pipes */
+ u32 max_use_endpts; /* Max endpointes to be used */
+ u32 bus_reset; /* Device is bus reseting */
+ u32 resume_state; /* USB state to resume*/
+ u32 usb_state; /* USB current state */
+ u32 usb_next_state; /* USB next state */
+ u32 ep0_state; /* Enpoint zero state */
+ u32 ep0_dir; /* Enpoint zero direction: can be
+ USB_DIR_IN or USB_DIR_OUT*/
+ u32 usb_sof_count; /* SOF count */
+ u32 errors; /* USB ERRORs count */
+ u8 device_address; /* Device USB address */
+
+ struct completion *done; /* to make sure release() is done */
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#define DBG(fmt, args...) printk(KERN_DEBUG "[%s] " fmt "\n", \
+ __FUNCTION__, ## args)
+#else
+#define DBG(fmt, args...) do{}while(0)
+#endif
+
+#if 0
+static void dump_msg(const char *label,
+ const u8 *buf, unsigned int length)
+{
+ unsigned int start, num, i;
+ char line[52], *p;
+
+
+ if (length >= 512)
+ return;
+ DBG("%s, length %u:\n", label, length);
+ 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;
+ printk(KERN_DEBUG "%6x: %s\n", start, line);
+ buf += num;
+ start += num;
+ length -= num;
+ }
+}
+#endif
+
+#ifdef VERBOSE
+#define VDBG DBG
+#else
+#define VDBG(stuff...) do{}while(0)
+#endif
+
+#define ERR(stuff...) printk(KERN_ERR "udc: " stuff)
+#define WARN(stuff...) printk(KERN_WARNING "udc: " stuff)
+#define INFO(stuff...) printk(KERN_INFO "udc: " stuff)
+
+/*-------------------------------------------------------------------------*/
+
+
+/* ### Add board specific defines here
+ */
+
+/*
+ * ### pipe direction macro from device view
+ */
+#define USB_RECV (0) /* OUT EP */
+#define USB_SEND (1) /* IN EP */
+
+/*
+ * ### internal used help routines.
+ */
+#define ep_index(EP) ((EP)->desc->bEndpointAddress&0xF)
+#define ep_maxpacket(EP) ((EP)->ep.maxpacket)
+#define ep_is_in(EP) ( (ep_index(EP) == 0) ? (EP->udc->ep0_dir == \
+ USB_DIR_IN ):((EP)->desc->bEndpointAddress \
+ & USB_DIR_IN)==USB_DIR_IN)
+#define get_ep_by_pipe(udc, pipe) ((pipe == 1)? &udc->eps[0]: \
+ &udc->eps[pipe])
+/*
+ * memory kmalloc with alignning size and zero the content
+ * @base :output parameter. It store the base address before align.
+ * Return value it the address after align
+ *
+ */
+static inline void *KMALLOC_ALIGN(size_t size, int flags, unsigned int align,
+ void **base)
+{
+ *base = kzalloc(size + align, flags);
+ if (*base == NULL)
+ return NULL;
+ return (void *) ALIGN((unsigned int) (*base), align);
+}
+
+/* Bulk only class request */
+#define USB_BULK_RESET_REQUEST 0xff
+
+#if defined(CONFIG_FSL_USB_OTG) || defined(CONFIG_FSL_USB_OTG_MODULE)
+/* Get platform resource from OTG driver */
+extern struct resource *otg_get_resources(int* num);
+#endif
+
+#endif
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index aa80f09..d76f06c 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -93,6 +93,12 @@ #else
#define gadget_is_imx(g) 0
#endif
+#ifdef CONFIG_USB_GADGET_FSL_USB2
+#define gadget_is_fsl_usb2(g) !strncmp("fsl-usb2-dr-udc", (g)->name, 11)
+#else
+#define gadget_is_fsl_usb2(g) 0
+#endif
+
/* Mentor high speed function controller */
#ifdef CONFIG_USB_GADGET_MUSBHSFC
#define gadget_is_musbhsfc(g) !strcmp("musbhsfc_udc", (g)->name)
@@ -169,5 +175,7 @@ static inline int usb_gadget_controller_
return 0x16;
else if (gadget_is_mpc8272(gadget))
return 0x17;
+ else if (gadget_is_fsl_usb2(gadget))
+ return 0x18;
return -ENOENT;
}
^ permalink raw reply related
* Re: Knowing kernel module load address (insmod hasn't -m)
From: antonio.dibacco @ 2006-07-14 11:10 UTC (permalink / raw)
To: bwarren; +Cc: linuxppc-embedded
In-Reply-To: <1152826969.5238.16.camel@saruman.qstreams.net>
I enabled the -m option for insmod in the busybox as adviced by you and now
I can see the address of all the modules I load.
Really amazing.
Thank you for you help,
Antonio.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox