diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS 2004-10-18 14:56:48 -07:00
+++ b/CREDITS 2004-10-18 14:56:48 -07:00
@@ -281,6 +281,11 @@
S: Greenbelt, Maryland 20771
S: USA
+N: Adam Belay
+E: ambx1@neo.rr.com
+D: Linux Plug and Play Support
+S: USA
+
N: Daniele Bellucci
E: bellucda@tiscali.it
D: Various Janitor work.
@@ -513,6 +518,14 @@
S: Oxford
S: United Kingdom
+N: Luiz Fernando N. Capitulino
+E: lcapitulino@terra.com.br
+E: lcapitulino@prefeitura.sp.gov.br
+W: http://www.telecentros.sp.gov.br
+D: Little fixes and a lot of janitorial work
+S: E-GOV Telecentros SP
+S: Brazil
+
N: Remy Card
E: Remy.Card@masi.ibp.fr
E: Remy.Card@linux.org
@@ -625,6 +638,14 @@
D: Assorted sched/mm titbits
S: Oxfordshire, UK.
+N: Kees Cook
+E: kees@outflux.net
+W: http://outflux.net/
+P: 1024D/17063E6D 9FA3 C49C 23C9 D1BC 2E30 1975 1FFF 4BA9 1706 3E6D
+D: Minor updates to SCSI code for the Communications type
+S: (ask for current address)
+S: USA
+
N: Mark Corner
E: mcorner@umich.edu
W: http://www.eecs.umich.edu/~mcorner/
@@ -639,14 +660,6 @@
S: Santa Cruz, California
S: USA
-N: Kees Cook
-E: kees@outflux.net
-W: http://outflux.net/
-P: 1024D/17063E6D 9FA3 C49C 23C9 D1BC 2E30 1975 1FFF 4BA9 1706 3E6D
-D: Minor updates to SCSI code for the Communications type
-S: (ask for current address)
-S: USA
-
N: Alan Cox
W: http://www.linux.org.uk/diary/
D: Linux Networking (0.99.10->2.0.29)
@@ -735,6 +748,12 @@
S: D-69231 Rauenberg
S: Germany
+N: Jean Delvare
+E: khali@linux-fr.org
+W: http://khali.linux-fr.org/
+D: Several hardware monitoring drivers
+S: France
+
N: Peter Denison
E: peterd@pnd-pc.demon.co.uk
W: http://www.pnd-pc.demon.co.uk/promise/
@@ -754,7 +773,7 @@
D: HTB qdisc and random networking hacks
N: Alex deVries
-E: adevries@thepuffingroup.com
+E: alex@onefishtwo.ca
D: Various SGI parts, bits of HAL2 and Newport, PA-RISC Linux.
S: 41.5 William Street
S: Ottawa, Ontario
@@ -905,6 +924,10 @@
S: S-114 79 Stockholm
S: Sweden
+N: David Engebretsen
+E: engebret@us.ibm.com
+D: Linux port to 64-bit PowerPC architecture
+
N: Michael Engel
E: engel@unix-ag.org
D: DECstation framebuffer drivers
@@ -1049,6 +1072,12 @@
S: 80050-430 - Curitiba - Paraná
S: Brazil
+N: Kumar Gala
+E: kumar.gala@freescale.com
+D: Embedded PowerPC 6xx/7xx/74xx/82xx/85xx support
+S: Austin, Texas 78729
+S: USA
+
N: Nigel Gamble
E: nigel@nrg.org
D: Interrupt-driven printer driver
@@ -1060,12 +1089,6 @@
N: Jeff Garzik
E: jgarzik@pobox.com
-N: Kumar Gala
-E: kumar.gala@freescale.com
-D: Embedded PowerPC 6xx/7xx/74xx/82xx/85xx support
-S: Austin, Texas 78729
-S: USA
-
N: Jacques Gelinas
E: jacques@solucorp.qc.ca
D: Author of the Umsdos file system
@@ -1563,10 +1586,37 @@
D: Various Janitor work.
S: United Kingdom
+N: Martin Josfsson
+E: gandalf@wlug.westbo.se
+P: 1024D/F6B6D3B1 7610 7CED 5C34 4AA6 DBA2 8BE1 5A6D AF95 F6B6 D3B1
+D: netfilter: SAME target
+D: netfilter: helper target
+D: netfilter: various other hacks
+S: Ronneby
+S: Sweden
+
N: Ani Joshi
E: ajoshi@shell.unixbox.com
D: fbdev hacking
+N: Jesper Juhl
+E: juhl-lkml@dif.dk
+D: Various small janitor fixes, cleanups etc.
+S: Lemnosvej 1, 3.tv
+S: 2300 Copenhagen S
+S: Denmark
+
+N: Jozsef Kadlecsik
+E: kadlec@blackhole.kfki.hu
+P: 1024D/470DB964 4CB3 1A05 713E 9BF7 FAC5 5809 DD8C B7B1 470D B964
+D: netfilter: TCP window tracking code
+D: netfilter: raw table
+D: netfilter: iprange match
+D: netfilter: new logging interfaces
+D: netfilter: various other hacks
+S: Tata
+S: Hungary
+
N: Bernhard Kaindl
E: bkaindl@netway.at
E: edv@bartelt.via.at
@@ -1818,11 +1868,6 @@
S: 370 01 Ceske Budejovice
S: Czech Republic
-N: Adam Belay
-E: ambx1@neo.rr.com
-D: Linux Plug and Play Support
-S: USA
-
N: Bas Laarhoven
E: sjml@xs4all.nl
D: Loadable modules and ftape driver
@@ -1954,12 +1999,6 @@
S: Niwot, Colorado 80503
S: USA
-N: Pete Popov
-E: pete_popov@yahoo.com
-D: Linux/MIPS AMD/Alchemy Port and mips hacking and debugging
-S: San Jose, CA 95134
-S: USA
-
N: Robert M. Love
E: rml@tech9.net
E: rml@novell.com
@@ -2127,6 +2166,16 @@
S: (address available on request)
S: USA
+N: Patrick McHardy
+E: kaber@trash.net
+P: 1024D/12155E80 B128 7DE6 FF0A C2B2 48BE AB4C C9D4 964E 1215 5E80
+D: netfilter: endless number of bugfixes
+D: netfilter: CLASSIFY target
+D: netfilter: addrtype match
+D: tc: HFSC scheduler
+S: Freiburg
+S: Germany
+
N: Mike McLagan
E: mike.mclagan@linux.org
W: http://www.invlogic.com/~mmclagan
@@ -2214,14 +2263,13 @@
S: Netherlands
N: David S. Miller
-E: davem@redhat.com
+E: davem@davemloft.net
D: Sparc and blue box hacker
D: Vger Linux mailing list co-maintainer
D: Linux Emacs elf/qmagic support + other libc/gcc things
D: Yee bore de yee bore! ;-)
-S: 750 N. Shoreline Blvd.
-S: Apt. #111
-S: Mountain View, California 94043
+S: 575 Harrison St. #103
+S: San Francisco, CA 94105
S: USA
N: Rick Miller
@@ -2570,6 +2618,7 @@
E: nico@cam.org
D: StrongARM SA1100 support integrator & hacker
D: Xscale PXA architecture
+D: unified SMC 91C9x/91C11x ethernet driver (smc91x)
S: Montreal, Quebec, Canada
N: Ken Pizzini
@@ -2582,6 +2631,12 @@
D: sonypi, meye drivers, mct_u232 usb serial hacks
S: Paris, France
+N: Pete Popov
+E: pete_popov@yahoo.com
+D: Linux/MIPS AMD/Alchemy Port and mips hacking and debugging
+S: San Jose, CA 95134
+S: USA
+
N: Matt Porter
E: mporter@kernel.crashing.org
D: Motorola PowerPC PReP support
@@ -2797,7 +2852,7 @@
N: Paul `Rusty' Russell
E: rusty@rustcorp.com.au
-W: http://www.samba.org/netfilter
+W: http://ozlabs.org/~rusty
D: Ruggedly handsome.
D: netfilter, ipchains with Michael Neuling.
S: 52 Moore St
@@ -2821,7 +2876,6 @@
S: Wellington
S: New Zealand
-
N: Sampo Saaristo
E: sambo@cs.tut.fi
D: Co-author of Multi-Protocol Over ATM (MPOA)
@@ -2838,6 +2892,9 @@
S: 8006 Zuerich
S: Switzerland
+N: Manuel Estrada Sainz
+D: Firmware loader (request_firmware)
+
N: Wayne Salamon
E: wsalamon@tislabs.com
E: wsalamon@nai.com
@@ -3289,14 +3346,6 @@
S: 10200 Prague 10, Hostivar
S: Czech Republic
-N: James R. Van Zandt
-E: jrv@vanzandt.mv.com
-P: 1024/E298966D F0 37 4F FD E5 7E C5 E6 F1 A0 1E 22 6F 46 DA 0C
-D: Author and maintainer of the Double Talk speech synthesizer driver
-S: 27 Spencer Drive
-S: Nashua, New Hampshire 03062
-S: USA
-
N: Heikki Vatiainen
E: hessu@cs.tut.fi
D: Co-author of Multi-Protocol Over ATM (MPOA), some LANE hacks
@@ -3387,6 +3436,18 @@
S: Berkeley, CA 94720-1776
S: USA
+N: Harald Welte
+E: laforge@netfilter.org
+P: 1024D/30F48BFF DBDE 6912 8831 9A53 879B 9190 5DA5 C655 30F4 8BFF
+W: http://gnumonks.org/users/laforge
+D: netfilter: new nat helper infrastructure
+D: netfilter: ULOG, ECN, DSCP target
+D: netfilter: TTL match
+D: netfilter: IPv6 mangle table
+D: netfilter: various other hacks
+S: Berlin
+S: Germany
+
N: Bill Wendling
E: wendling@ganymede.isdn.uiuc.edu
W: http://www.ncsa.uiuc.edu/~wendling/
@@ -3578,6 +3639,14 @@
S: Tokyo 153
S: Japan
+N: James R. Van Zandt
+E: jrv@vanzandt.mv.com
+P: 1024/E298966D F0 37 4F FD E5 7E C5 E6 F1 A0 1E 22 6F 46 DA 0C
+D: Author and maintainer of the Double Talk speech synthesizer driver
+S: 27 Spencer Drive
+S: Nashua, New Hampshire 03062
+S: USA
+
N: Orest Zborowski
E: orestz@eskimo.com
D: XFree86 and kernel development
@@ -3619,13 +3688,6 @@
D: EISA/sysfs subsystem
S: France
-N: Luiz Fernando N. Capitulino
-E: lcapitulino@terra.com.br
-E: lcapitulino@prefeitura.sp.gov.br
-W: http://www.telecentros.sp.gov.br
-D: Little fixes and a lot of janitorial work
-S: E-GOV Telecentros SP
-S: Brazil
# Don't add your name here, unless you really _are_ after Marc
# alphabetically. Leonard used to be very proud of being the
diff -Nru a/Documentation/CodingStyle b/Documentation/CodingStyle
--- a/Documentation/CodingStyle 2004-10-18 14:56:28 -07:00
+++ b/Documentation/CodingStyle 2004-10-18 14:56:28 -07:00
@@ -356,10 +356,10 @@
Macros with multiple statements should be enclosed in a do - while block:
-#define macrofun(a,b,c) \
+#define macrofun(a, b, c) \
do { \
if (a == 5) \
- do_this(b,c); \
+ do_this(b, c); \
} while (0)
Things to avoid when using macros:
diff -Nru a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt
--- a/Documentation/DMA-API.txt 2004-10-18 14:56:32 -07:00
+++ b/Documentation/DMA-API.txt 2004-10-18 14:56:32 -07:00
@@ -444,4 +444,83 @@
continuing on for size. Again, you *must* observe the cache line
boundaries when doing this.
+int
+dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
+ dma_addr_t device_addr, size_t size, int
+ flags)
+
+
+Declare region of memory to be handed out by dma_alloc_coherent when
+it's asked for coherent memory for this device.
+
+bus_addr is the physical address to which the memory is currently
+assigned in the bus responding region (this will be used by the
+platform to perform the mapping)
+
+device_addr is the physical address the device needs to be programmed
+with actually to address this memory (this will be handed out as the
+dma_addr_t in dma_alloc_coherent())
+
+size is the size of the area (must be multiples of PAGE_SIZE).
+
+flags can be or'd together and are
+
+DMA_MEMORY_MAP - request that the memory returned from
+dma_alloc_coherent() be directly writeable.
+
+DMA_MEMORY_IO - request that the memory returned from
+dma_alloc_coherent() be addressable using read/write/memcpy_toio etc.
+
+One or both of these flags must be present
+
+DMA_MEMORY_INCLUDES_CHILDREN - make the declared memory be allocated by
+dma_alloc_coherent of any child devices of this one (for memory residing
+on a bridge).
+
+DMA_MEMORY_EXCLUSIVE - only allocate memory from the declared regions.
+Do not allow dma_alloc_coherent() to fall back to system memory when
+it's out of memory in the declared region.
+
+The return value will be either DMA_MEMORY_MAP or DMA_MEMORY_IO and
+must correspond to a passed in flag (i.e. no returning DMA_MEMORY_IO
+if only DMA_MEMORY_MAP were passed in) for success or zero for
+failure.
+
+Note, for DMA_MEMORY_IO returns, all subsequent memory returned by
+dma_alloc_coherent() may no longer be accessed directly, but instead
+must be accessed using the correct bus functions. If your driver
+isn't prepared to handle this contingency, it should not specify
+DMA_MEMORY_IO in the input flags.
+
+As a simplification for the platforms, only *one* such region of
+memory may be declared per device.
+
+For reasons of efficiency, most platforms choose to track the declared
+region only at the granularity of a page. For smaller allocations,
+you should use the dma_pool() API.
+
+void
+dma_release_declared_memory(struct device *dev)
+
+Remove the memory region previously declared from the system. This
+API performs *no* in-use checking for this region and will return
+unconditionally having removed all the required structures. It is the
+drivers job to ensure that no parts of this memory region are
+currently in use.
+
+void *
+dma_mark_declared_memory_occupied(struct device *dev,
+ dma_addr_t device_addr, size_t size)
+
+This is used to occupy specific regions of the declared space
+(dma_alloc_coherent() will hand out the first free region it finds).
+
+device_addr is the *device* address of the region requested
+
+size is the size (and should be a page sized multiple).
+
+The return value will be either a pointer to the processor virtual
+address of the memory, or an error (via PTR_ERR()) if any part of the
+region is occupied.
+
diff -Nru a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
--- a/Documentation/DocBook/Makefile 2004-10-18 14:56:29 -07:00
+++ b/Documentation/DocBook/Makefile 2004-10-18 14:56:29 -07:00
@@ -185,9 +185,7 @@
$(patsubst %.sgml, %.9, $(DOCBOOKS)) \
$(C-procfs-example)
-ifneq ($(wildcard $(patsubst %.html,%,$(HTML))),)
-clean-rule := rm -rf $(wildcard $(patsubst %.html,%,$(HTML)))
-endif
+clean-dirs := $(patsubst %.sgml,%,$(DOCBOOKS))
#man put files in man subdir - traverse down
subdir- := man/
diff -Nru a/Documentation/DocBook/gadget.tmpl b/Documentation/DocBook/gadget.tmpl
--- a/Documentation/DocBook/gadget.tmpl 2004-10-18 14:56:31 -07:00
+++ b/Documentation/DocBook/gadget.tmpl 2004-10-18 14:56:31 -07:00
@@ -2,8 +2,8 @@
USB Gadget API for Linux
- 02 June 2003
- 02 June 2003
+ 20 August 2004
+ 20 August 2004
@@ -34,7 +34,7 @@
- 2003
+ 2003-2004
David Brownell
@@ -73,9 +73,13 @@
composite devices,
and alternate interface settings.
+ USB "On-The-Go" (OTG) support, in conjunction
+ with updates to the Linux-USB host side.
+
Sharing data structures and API models with the
- Linux-USB host side API. This looks forward to USB "On-The-Go"
- (OTG) and similar more-symmetric frameworks.
+ Linux-USB host side API. This helps the OTG support, and
+ looks forward to more-symmetric frameworks (where the same
+ I/O model is used by both host and device side drivers).
Minimalist, so it's easier to support new device
controller hardware. I/O processing doesn't imply large
@@ -153,6 +157,7 @@
the SA-11x0 or PXA-25x UDC (found within many PDAs),
and a variety of other products.
+
@@ -162,10 +167,14 @@
The lower boundary of this driver implements hardware-neutral
USB functions, using calls to the controller driver.
Because such hardware varies widely in capabilities and restrictions,
- the gadget driver is normally configured at compile time
+ and is used in embedded environments where space is at a premium,
+ the gadget driver is often configured at compile time
to work with endpoints supported by one particular controller.
Gadget drivers may be portable to several different controllers,
using conditional compilation.
+ (Recent kernels substantially simplify the work involved in
+ supporting new hardware, by autoconfiguring
+ endpoints automatically for many bulk-oriented drivers.)
Gadget driver responsibilities include:
@@ -178,8 +187,9 @@
altsettings, including enabling and configuring endpoints
handling life cycle events, such as managing
- bindings
- to hardware, and disconnection from the USB host.
+ bindings to hardware,
+ USB suspend/resume, remote wakeup,
+ and disconnection from the USB host.
managing IN and OUT transfers on all currently
enabled endpoints
@@ -244,15 +254,38 @@
-Over time, reusable utilities should evolve to help make some
-gadget driver tasks simpler. An example of particular interest
+OTG-capable systems will also need to include a standard Linux-USB
+host side stack,
+with usbcore,
+one or more Host Controller Drivers (HCDs),
+USB Device Drivers to support
+the OTG "Targeted Peripheral List",
+and so forth.
+There will also be an OTG Controller Driver,
+which is visible to gadget and device driver developers only indirectly.
+That helps the host and device side USB controllers implement the
+two new OTG protocols (HNP and SRP).
+Roles switch (host to peripheral, or vice versa) using HNP
+during USB suspend processing, and SRP can be viewed as a
+more battery-friendly kind of device wakeup protocol.
+
+
+Over time, reusable utilities are evolving to help make some
+gadget driver tasks simpler.
+For example, building configuration descriptors from vectors of
+descriptors for the configurations interfaces and endpoints is
+now automated, and many drivers now use autoconfiguration to
+choose hardware endpoints and initialize their descriptors.
+
+A potential example of particular interest
is code implementing standard USB-IF protocols for
HID, networking, storage, or audio classes.
Some developers are interested in KDB or KGDB hooks, to let
target hardware be remotely debugged.
Most such USB protocol code doesn't need to be hardware-specific,
any more than network protocols like X11, HTTP, or NFS are.
-Such interface drivers might be combined, to support composite devices.
+Such gadget-side interface drivers should eventually be combined,
+to implement composite devices.
@@ -284,7 +317,7 @@
However, docproc does not understand all the C constructs
that are used, so some relevant information is likely omitted from
what you are reading.
-One example of such information is several per-request flags.
+One example of such information is endpoint autoconfiguration.
You'll have to read the header file, and use example source
code (such as that for "Gadget Zero"), to fully understand the API.
@@ -292,7 +325,7 @@
The part of the API implementing some basic
driver capabilities is specific to the version of the
Linux kernel that's in use.
-The 2.5 kernel includes a driver model
+The 2.6 kernel includes a driver model
framework that has no analogue on earlier kernels;
so those parts of the gadget API are not fully portable.
(They are implemented on 2.4 kernels, but in a different way.)
@@ -308,17 +341,21 @@
that would be added using hardware-specific APIs.
-This API expects drivers to use conditional compilation to handle
-endpoint capabilities of different hardware.
-Those tend to have arbitrary restrictions, relating to
+This API allows drivers to use conditional compilation to handle
+endpoint capabilities of different hardware, but doesn't require that.
+Hardware tends to have arbitrary restrictions, relating to
transfer types, addressing, packet sizes, buffering, and availability.
As a rule, such differences only matter for "endpoint zero" logic
that handles device configuration and management.
-The API only supports limited run-time
+The API supports limited run-time
detection of capabilities, through naming conventions for endpoints.
-Although a gadget driver could scan the endpoints available to it and
-choose to map those capabilities onto driver functionality in some way,
-few drivers will want to reconfigure themselves at run-time.
+Many drivers will be able to at least partially autoconfigure
+themselves.
+In particular, driver init sections will often have endpoint
+autoconfiguration logic that scans the hardware's list of endpoints
+to find ones matching the driver requirements
+(relying on those conventions), to eliminate some of the most
+common reasons for conditional compilation.
Like the Linux-USB host side API, this API exposes
@@ -355,10 +392,14 @@
At this point the device is logically in the USB ch9 initial state
("attached"), drawing no power and not usable
(since it does not yet support enumeration).
+Any host should not see the device, since it's not
+activated the data line pullup used by the host to
+detect a device, even if VBUS power is available.
Register a gadget driver that implements some higher level
-device function. That will then bind() to a usb_gadget.
+device function. That will then bind() to a usb_gadget, which
+activates the data line pullup sometime after detecting VBUS.
The hardware driver can now start enumerating.
@@ -373,6 +414,8 @@
functionality being implemented.
That can involve alternate settings or configurations,
unless the hardware prevents such operation.
+For OTG devices, each configuration descriptor includes
+an OTG descriptor.
The gadget driver handles the last step of enumeration,
@@ -381,13 +424,18 @@
with all interfaces in their default settings.
That involves using a list of the hardware's endpoints, enabling each
endpoint according to its descriptor.
+It may also involve using usb_gadget_vbus_draw
+to let more power be drawn from VBUS, as allowed by that configuration.
+For OTG devices, setting a configuration may also involve reporting
+HNP capabilities through a user interface.
Do real work and perform data transfers, possibly involving
changes to interface settings or switching to new configurations, until the
device is disconnect()ed from the host.
Queue any number of transfer requests to each endpoint.
-The drivers then go back to step 3 (above).
+It may be suspended and resumed several times before being disconnected.
+On disconnect, the drivers go back to step 3 (above).
When the gadget driver module is being unloaded,
@@ -399,7 +447,9 @@
Drivers will normally be arranged so that just loading the
gadget driver module (or statically linking it into a Linux kernel)
-allows the peripheral device to be enumerated.
+allows the peripheral device to be enumerated, but some drivers
+will defer enumeration until some higher level component (like
+a user mode daemon) enables it.
Note that at this lowest level there are no policies about how
ep0 configuration logic is implemented,
except that it should obey USB specifications.
@@ -410,6 +460,18 @@
be built by integrating reusable components.
+Note that the lifecycle above can be slightly different
+for OTG devices.
+Other than providing an additional OTG descriptor in each
+configuration, only the HNP-related differences are particularly
+visible to driver code.
+They involve reporting requirements during the SET_CONFIGURATION
+request, and the option to invoke HNP during some suspend callbacks.
+Also, SRP changes the semantics of
+usb_gadget_wakeup
+slightly.
+
+
USB 2.0 Chapter 9 Types and Constants
@@ -418,9 +480,9 @@
rely on common USB structures and constants
defined in the
<linux/usb_ch9.h>
-header file, which is standard in Linux 2.5 kernels.
+header file, which is standard in Linux 2.6 kernels.
These are the same types and constants used by host
-side drivers.
+side drivers (and usbcore).
!Iinclude/linux/usb_ch9.h
@@ -451,26 +513,38 @@
The core API is sufficient for writing a USB Gadget Driver,
but some optional utilities are provided to simplify common tasks.
+These utilities include endpoint autoconfiguration.
!Edrivers/usb/gadget/usbstring.c
!Edrivers/usb/gadget/config.c
+
Peripheral Controller Drivers
-The first hardware supporting this API is the NetChip 2280
+The first hardware supporting this API was the NetChip 2280
controller, which supports USB 2.0 high speed and is based on PCI.
This is the net2280 driver module.
-The driver supports Linux kernel versions 2.4 and 2.5;
+The driver supports Linux kernel versions 2.4 and 2.6;
contact NetChip Technologies for development boards and product
information.
-For users of Intel's PXA 2xx series processors,
-a pxa2xx_udc driver is available.
+Other hardware working in the "gadget" framework includes:
+Intel's PXA 25x and IXP42x series processors
+(pxa2xx_udc),
+Toshiba TC86c001 "Goku-S" (goku_udc),
+Renesas SH7705/7727 (sh_udc),
+MediaQ 11xx (mq11xx_udc),
+Hynix HMS30C7202 (h7202_udc),
+National 9303/4 (n9604_udc),
+Texas Instruments OMAP (omap_udc),
+Sharp LH7A40x (lh7a40x_udc),
+and more.
+Most of those are full speed controllers.
At this writing, there are people at work on drivers in
@@ -526,6 +600,15 @@
to avoid creating problems.)
+Support for Microsoft's RNDIS
+protocol has been contributed by Pengutronix and Auerswald GmbH.
+This is like CDC Ethernet, but it runs on more slightly USB hardware
+(but less than the CDC subset).
+However, its main claim to fame is being able to connect directly to
+recent versions of Windows, using drivers that Microsoft bundles
+and supports, making it much simpler to network with Windows.
+
+
There is also support for user mode gadget drivers,
using gadgetfs.
This provides a User Mode API that presents
@@ -535,6 +618,10 @@
develop and debug user mode drivers, so that once a robust
controller driver is available many applications for it
won't require new kernel mode software.
+Linux 2.6 Async I/O (AIO)
+support is available, so that user mode software
+can stream data with only slightly more overhead
+than a kernel driver.
There's a USB Mass Storage class driver, which provides
@@ -548,6 +635,16 @@
to access the data from the backing store.
+There's a "serial line" driver, useful for TTY style
+operation over USB.
+The latest version of that driver supports CDC ACM style
+operation, like a USB modem, and so on most hardware it can
+interoperate easily with MS-Windows.
+One interesting use of that driver is in boot firmware (like a BIOS),
+which can sometimes use that model with very small systems without
+real serial lines.
+
+
Support for other kinds of gadget is expected to
be developed and contributed
over time, as this driver framework evolves.
@@ -555,6 +652,96 @@
+USB On-The-GO (OTG)
+
+USB OTG support on Linux 2.6 was initially developed
+by Texas Instruments for
+OMAP 16xx and 17xx
+series processors.
+Other OTG systems should work in similar ways, but the
+hardware level details could be very different.
+
+
+Systems need specialized hardware support to implement OTG,
+notably including a special Mini-AB jack
+and associated transciever to support Dual-Role
+operation:
+they can act either as a host, using the standard
+Linux-USB host side driver stack,
+or as a peripheral, using this "gadget" framework.
+To do that, the system software relies on small additions
+to those programming interfaces,
+and on a new internal component (here called an "OTG Controller")
+affecting which driver stack connects to the OTG port.
+In each role, the system can re-use the existing pool of
+hardware-neutral drivers, layered on top of the controller
+driver interfaces (usb_bus or
+usb_gadget).
+Such drivers need at most minor changes, and most of the calls
+added to support OTG can also benefit non-OTG products.
+
+
+
+ Gadget drivers test the is_otg
+ flag, and use it to determine whether or not to include
+ an OTG descriptor in each of their configurations.
+
+ Gadget drivers may need changes to support the
+ two new OTG protocols, exposed in new gadget attributes
+ such as b_hnp_enable flag.
+ HNP support should be reported through a user interface
+ (two LEDs could suffice), and is triggered in some cases
+ when the host suspends the peripheral.
+ SRP support can be user-initiated just like remote wakeup,
+ probably by pressing the same button.
+
+ On the host side, USB device drivers need
+ to be taught to trigger HNP at appropriate moments, using
+ usb_suspend_device().
+ That also conserves battery power, which is useful even
+ for non-OTG configurations.
+
+ Also on the host side, a driver must support the
+ OTG "Targeted Peripheral List". That's just a whitelist,
+ used to reject peripherals not supported with a given
+ Linux OTG host.
+ This whitelist is product-specific;
+ each product must modify otg_whitelist.h
+ to match its interoperability specification.
+
+
+ Non-OTG Linux hosts, like PCs and workstations,
+ normally have some solution for adding drivers, so that
+ peripherals that aren't recognized can eventually be supported.
+ That approach is unreasonable for consumer products that may
+ never have their firmware upgraded, and where it's usually
+ unrealistic to expect traditional PC/workstation/server kinds
+ of support model to work.
+ For example, it's often impractical to change device firmware
+ once the product has been distributed, so driver bugs can't
+ normally be fixed if they're found after shipment.
+
+
+
+
+Additional changes are needed below those hardware-neutral
+usb_bus and usb_gadget
+driver interfaces; those aren't discussed here in any detail.
+Those affect the hardware-specific code for each USB Host or Peripheral
+controller, and how the HCD initializes (since OTG can be active only
+on a single port).
+They also involve what may be called an OTG Controller
+Driver, managing the OTG transceiver and the OTG state
+machine logic as well as much of the root hub behavior for the
+OTG port.
+The OTG controller driver needs to activate and deactivate USB
+controllers depending on the relevant device role.
+Some related changes were needed inside usbcore, so that it
+can identify OTG-capable devices and respond appropriately
+to HNP or SRP protocols.
+
+
+
Slave NPU
+ * |
+ * |
+ * P2P
+ * |
+ *
+ * Bus 1 |
+ * <--+------+---------+---------+------+-->
+ * | | | | |
+ * | | | | |
+ * ... Dev PMC Media Eth0 Eth1 ...
+ *
+ * The master controlls all but Eth1, which is controlled by the
+ * slave. What this measn is that the both the master and the slave
+ * have to scan the bus, but only one of them can enumerate the bus.
+ * In addition, after the bus is scaned, each kernel must remove
+ * the device(s) it does not control from the PCI dev list otherwise
+ * a driver on each NPU will try to manage it and we will have horrible
+ * conflicts. Oh..and the slave NPU needs to see the master NPU
+ * for Intel's drivers to work properly. Closed source drivers...
+ *
+ * The way we deal with this is fairly simple but ugly:
+ *
+ * 1) Let master scan and enumerate the bus completely.
+ * 2) Master deletes Eth1 from device list.
+ * 3) Slave scans bus and then deletes all but Eth1 (Eth0 on slave)
+ * from device list.
+ * 4) Find HW designers and LART them.
+ *
+ * The boards also do not do normal PCI IRQ routing, or any sort of
+ * sensical swizzling, so we just need to check where on the bus a
+ * device sits and figure out to which CPLD pin the interrupt is routed.
+ * See ixdp2[48]00.c files.
+ *
+ *************************************************************************/
+void ixdp2x00_slave_pci_postinit(void)
+{
+ struct pci_dev *dev;
+
+ /*
+ * Remove PMC device is there is one
+ */
+ if((dev = pci_find_slot(1, IXDP2X00_PMC_DEVFN)))
+ pci_remove_bus_device(dev);
+
+ dev = pci_find_slot(0, IXDP2X00_21555_DEVFN);
+ pci_remove_bus_device(dev);
+}
+
+/**************************************************************************
+ * IXDP2x00 Machine Setup
+ *************************************************************************/
+static struct flash_platform_data ixdp2x00_platform_data = {
+ .map_name = "cfi_probe",
+ .width = 1,
+};
+
+static struct ixp2000_flash_data ixdp2x00_flash_data = {
+ .platform_data = &ixdp2x00_platform_data,
+ .nr_banks = 1
+};
+
+static struct resource ixdp2x00_flash_resource = {
+ .start = 0xc4000000,
+ .end = 0xc4000000 + 0x00ffffff,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ixdp2x00_flash = {
+ .name = "IXP2000-Flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &ixdp2x00_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &ixdp2x00_flash_resource,
+};
+
+static struct ixp2000_i2c_pins ixdp2x00_i2c_gpio_pins = {
+ .sda_pin = IXDP2X00_GPIO_SDA,
+ .scl_pin = IXDP2X00_GPIO_SCL,
+};
+
+static struct platform_device ixdp2x00_i2c_controller = {
+ .name = "IXP2000-I2C",
+ .id = 0,
+ .dev = {
+ .platform_data = &ixdp2x00_i2c_gpio_pins,
+ },
+ .num_resources = 0
+};
+
+static struct platform_device *ixdp2x00_devices[] __initdata = {
+ &ixdp2x00_flash,
+ &ixdp2x00_i2c_controller
+};
+
+void __init ixdp2x00_init_machine(void)
+{
+ gpio_line_set(IXDP2X00_GPIO_I2C_ENABLE, 1);
+ gpio_line_config(IXDP2X00_GPIO_I2C_ENABLE, GPIO_OUT);
+
+ platform_add_devices(ixdp2x00_devices, ARRAY_SIZE(ixdp2x00_devices));
+}
+
diff -Nru a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c 2004-10-18 14:57:21 -07:00
@@ -0,0 +1,381 @@
+/*
+ * arch/arm/mach-ixp2000/ixdp2x01.c
+ *
+ * Code common to Intel IXDP2401 and IXDP2801 platforms
+ *
+ * Original Author: Andrzej Mialwoski
+ * Maintainer: Deepak Saxena
+ *
+ * Copyright (C) 2002-2003 Intel Corp.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * 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.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+/*************************************************************************
+ * IXDP2x01 IRQ Handling
+ *************************************************************************/
+static void ixdp2x01_irq_mask(unsigned int irq)
+{
+ *IXDP2X01_INT_MASK_SET_REG = IXP2000_BOARD_IRQ_MASK(irq);
+}
+
+static void ixdp2x01_irq_unmask(unsigned int irq)
+{
+ *IXDP2X01_INT_MASK_CLR_REG = IXP2000_BOARD_IRQ_MASK(irq);
+}
+
+static u32 valid_irq_mask;
+
+static void ixdp2x01_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+{
+ u32 ex_interrupt;
+ int i;
+
+ desc->chip->mask(irq);
+
+ ex_interrupt = *IXDP2X01_INT_STAT_REG & valid_irq_mask;
+
+ if (!ex_interrupt) {
+ printk(KERN_ERR "Spurious IXDP2X01 CPLD interrupt!\n");
+ return;
+ }
+
+ for (i = 0; i < IXP2000_BOARD_IRQS; i++) {
+ if (ex_interrupt & (1 << i)) {
+ struct irqdesc *cpld_desc;
+ int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
+ cpld_desc = irq_desc + cpld_irq;
+ cpld_desc->handle(cpld_irq, cpld_desc, regs);
+ }
+ }
+
+ desc->chip->unmask(irq);
+}
+
+static struct irqchip ixdp2x01_irq_chip = {
+ .mask = ixdp2x01_irq_mask,
+ .ack = ixdp2x01_irq_mask,
+ .unmask = ixdp2x01_irq_unmask
+};
+
+/*
+ * We only do anything if we are the master NPU on the board.
+ * The slave NPU only has the ethernet chip going directly to
+ * the PCIB interrupt input.
+ */
+void __init ixdp2x01_init_irq(void)
+{
+ int irq = 0;
+
+ /* initialize chip specific interrupts */
+ ixp2000_init_irq();
+
+ if (machine_is_ixdp2401())
+ valid_irq_mask = IXDP2401_VALID_IRQ_MASK;
+ else
+ valid_irq_mask = IXDP2801_VALID_IRQ_MASK;
+
+ /* Mask all interrupts from CPLD, disable simulation */
+ *IXDP2X01_INT_MASK_SET_REG = 0xffffffff;
+ *IXDP2X01_INT_SIM_REG = 0;
+
+ for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) {
+ if (irq & valid_irq_mask) {
+ set_irq_chip(irq, &ixdp2x01_irq_chip);
+ set_irq_handler(irq, do_level_IRQ);
+ set_irq_flags(irq, IRQF_VALID);
+ } else {
+ set_irq_flags(irq, 0);
+ }
+ }
+
+ /* Hook into PCI interrupts */
+ set_irq_chained_handler(IRQ_IXP2000_PCIB, &ixdp2x01_irq_handler);
+}
+
+
+/*************************************************************************
+ * IXDP2x01 memory map and serial ports
+ *************************************************************************/
+static struct map_desc ixdp2x01_io_desc __initdata = {
+ .virtual = IXDP2X01_VIRT_CPLD_BASE,
+ .physical = IXDP2X01_PHYS_CPLD_BASE,
+ .length = IXDP2X01_CPLD_REGION_SIZE,
+ .type = MT_DEVICE
+};
+
+static struct uart_port ixdp2x01_serial_ports[2] = {
+ {
+ .membase = (char *)(IXDP2X01_UART1_VIRT_BASE),
+ .mapbase = (unsigned long)IXDP2X01_UART1_PHYS_BASE,
+ .irq = IRQ_IXDP2X01_UART1,
+ .flags = UPF_SKIP_TEST,
+ .iotype = UPIO_MEM32,
+ .regshift = 2,
+ .uartclk = IXDP2X01_UART_CLK,
+ .line = 1,
+ .type = PORT_16550A,
+ .fifosize = 16
+ }, {
+ .membase = (char *)(IXDP2X01_UART2_VIRT_BASE),
+ .mapbase = (unsigned long)IXDP2X01_UART2_PHYS_BASE,
+ .irq = IRQ_IXDP2X01_UART2,
+ .flags = UPF_SKIP_TEST,
+ .iotype = UPIO_MEM32,
+ .regshift = 2,
+ .uartclk = IXDP2X01_UART_CLK,
+ .line = 2,
+ .type = PORT_16550A,
+ .fifosize = 16
+ },
+};
+
+static void __init ixdp2x01_map_io(void)
+{
+ ixp2000_map_io();
+
+ iotable_init(&ixdp2x01_io_desc, 1);
+
+ early_serial_setup(&ixdp2x01_serial_ports[0]);
+ early_serial_setup(&ixdp2x01_serial_ports[1]);
+}
+
+
+/*************************************************************************
+ * IXDP2x01 timer tick configuration
+ *************************************************************************/
+static unsigned int ixdp2x01_clock;
+
+static int __init ixdp2x01_clock_setup(char *str)
+{
+ ixdp2x01_clock = simple_strtoul(str, NULL, 10);
+
+ return 1;
+}
+
+__setup("ixdp2x01_clock=", ixdp2x01_clock_setup);
+
+static void __init ixdp2x01_init_time(void)
+{
+ if (!ixdp2x01_clock)
+ ixdp2x01_clock = 50000000;
+
+ ixp2000_init_time(ixdp2x01_clock);
+}
+
+/*************************************************************************
+ * IXDP2x01 PCI
+ *************************************************************************/
+void __init ixdp2x01_pci_preinit(void)
+{
+ ixp2000_reg_write(IXP2000_PCI_ADDR_EXT, 0x00000000);
+ ixp2000_pci_preinit();
+}
+
+#define DEVPIN(dev, pin) ((pin) | ((dev) << 3))
+
+static int __init ixdp2x01_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ u8 bus = dev->bus->number;
+ u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin);
+ struct pci_bus *tmp_bus = dev->bus;
+
+ /* Primary bus, no interrupts here */
+ if (bus == 0) {
+ return -1;
+ }
+
+ /* Lookup first leaf in bus tree */
+ while ((tmp_bus->parent != NULL) && (tmp_bus->parent->parent != NULL)) {
+ tmp_bus = tmp_bus->parent;
+ }
+
+ /* Select between known bridges */
+ switch (tmp_bus->self->devfn | (tmp_bus->self->bus->number << 8)) {
+ /* Device is located after first MB bridge */
+ case 0x0008:
+ if (tmp_bus == dev->bus) {
+ /* Device is located directy after first MB bridge */
+ switch (devpin) {
+ case DEVPIN(1, 1): /* Onboard 82546 ch 0 */
+ if (machine_is_ixdp2401())
+ return IRQ_IXDP2401_INTA_82546;
+ return -1;
+ case DEVPIN(1, 2): /* Onboard 82546 ch 1 */
+ if (machine_is_ixdp2401())
+ return IRQ_IXDP2401_INTB_82546;
+ return -1;
+ case DEVPIN(0, 1): /* PMC INTA# */
+ return IRQ_IXDP2X01_SPCI_PMC_INTA;
+ case DEVPIN(0, 2): /* PMC INTB# */
+ return IRQ_IXDP2X01_SPCI_PMC_INTB;
+ case DEVPIN(0, 3): /* PMC INTC# */
+ return IRQ_IXDP2X01_SPCI_PMC_INTC;
+ case DEVPIN(0, 4): /* PMC INTD# */
+ return IRQ_IXDP2X01_SPCI_PMC_INTD;
+ }
+ }
+ break;
+ case 0x0010:
+ if (tmp_bus == dev->bus) {
+ /* Device is located directy after second MB bridge */
+ /* Secondary bus of second bridge */
+ switch (devpin) {
+ case DEVPIN(0, 1): /* DB#0 */
+ return IRQ_IXDP2X01_SPCI_DB_0;
+ case DEVPIN(1, 1): /* DB#1 */
+ return IRQ_IXDP2X01_SPCI_DB_1;
+ }
+ } else {
+ /* Device is located indirectly after second MB bridge */
+ /* Not supported now */
+ }
+ break;
+ }
+
+ return -1;
+}
+
+
+static int ixdp2x01_pci_setup(int nr, struct pci_sys_data *sys)
+{
+ sys->mem_offset = 0xe0000000;
+
+ if (machine_is_ixdp2801())
+ sys->mem_offset -= ((*IXP2000_PCI_ADDR_EXT & 0xE000) << 16);
+
+ return ixp2000_pci_setup(nr, sys);
+}
+
+struct hw_pci ixdp2x01_pci __initdata = {
+ .nr_controllers = 1,
+ .setup = ixdp2x01_pci_setup,
+ .preinit = ixdp2x01_pci_preinit,
+ .scan = ixp2000_pci_scan_bus,
+ .map_irq = ixdp2x01_pci_map_irq,
+};
+
+int __init ixdp2x01_pci_init(void)
+{
+
+ pci_common_init(&ixdp2x01_pci);
+ return 0;
+}
+
+subsys_initcall(ixdp2x01_pci_init);
+
+/*************************************************************************
+ * IXDP2x01 Machine Intialization
+ *************************************************************************/
+static struct flash_platform_data ixdp2x01_flash_platform_data = {
+ .map_name = "cfi_probe",
+ .width = 1,
+};
+
+static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs)
+{
+ *IXDP2X01_CPLD_FLASH_REG =
+ ((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN);
+ return (ofs & IXDP2X01_FLASH_WINDOW_MASK);
+}
+
+static struct ixp2000_flash_data ixdp2x01_flash_data = {
+ .platform_data = &ixdp2x01_flash_platform_data,
+ .bank_setup = ixdp2x01_flash_bank_setup
+};
+
+static struct resource ixdp2x01_flash_resource = {
+ .start = 0xc4000000,
+ .end = 0xc4000000 + 0x01ffffff,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ixdp2x01_flash = {
+ .name = "IXP2000-Flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &ixdp2x01_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &ixdp2x01_flash_resource,
+};
+
+static struct platform_device *ixdp2x01_devices[] __initdata = {
+ &ixdp2x01_flash
+};
+
+static void __init ixdp2x01_init_machine(void)
+{
+ *IXDP2X01_CPLD_FLASH_REG =
+ (IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN);
+
+ ixdp2x01_flash_data.nr_banks =
+ ((*IXDP2X01_CPLD_FLASH_REG & IXDP2X01_CPLD_FLASH_BANK_MASK) + 1);
+
+ platform_add_devices(ixdp2x01_devices, ARRAY_SIZE(ixdp2x01_devices));
+}
+
+
+#ifdef CONFIG_ARCH_IXDP2401
+MACHINE_START(IXDP2401, "Intel IXDP2401 Development Platform")
+ MAINTAINER("MontaVista Software, Inc.")
+ BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
+ BOOT_PARAMS(0x00000100)
+ MAPIO(ixdp2x01_map_io)
+ INITIRQ(ixdp2x01_init_irq)
+ INITTIME(ixdp2x01_init_time)
+ INIT_MACHINE(ixdp2x01_init_machine)
+MACHINE_END
+#endif
+
+#ifdef CONFIG_ARCH_IXDP2801
+MACHINE_START(IXDP2801, "Intel IXDP2801 Development Platform")
+ MAINTAINER("MontaVista Software, Inc.")
+ BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
+ BOOT_PARAMS(0x00000100)
+ MAPIO(ixdp2x01_map_io)
+ INITIRQ(ixdp2x01_init_irq)
+ INITTIME(ixdp2x01_init_time)
+ INIT_MACHINE(ixdp2x01_init_machine)
+MACHINE_END
+#endif
+
+
diff -Nru a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/arch/arm/mach-ixp2000/pci.c 2004-10-18 14:57:23 -07:00
@@ -0,0 +1,233 @@
+/*
+ * arch/arm/mach-ixp2000/pci.c
+ *
+ * PCI routines for IXDP2400/IXDP2800 boards
+ *
+ * Original Author: Naeem Afzal
+ * Maintained by: Deepak Saxena
+ *
+ * Copyright 2002 Intel Corp.
+ * Copyright (C) 2003-2004 MontaVista Software, Inc.
+ *
+ * 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.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+static int pci_master_aborts = 0;
+
+static int clear_master_aborts(void);
+
+static u32 *
+ixp2000_pci_config_addr(unsigned int bus_nr, unsigned int devfn, int where)
+{
+ u32 *paddress;
+
+ if (PCI_SLOT(devfn) > 7)
+ return 0;
+
+ /* Must be dword aligned */
+ where &= ~3;
+
+ /*
+ * For top bus, generate type 0, else type 1
+ */
+ if (!bus_nr) {
+ /* only bits[23:16] are used for IDSEL */
+ paddress = (u32 *) (IXP2000_PCI_CFG0_VIRT_BASE
+ | (1 << (PCI_SLOT(devfn) + 16))
+ | (PCI_FUNC(devfn) << 8) | where);
+ } else {
+ paddress = (u32 *) (IXP2000_PCI_CFG1_VIRT_BASE
+ | (bus_nr << 16)
+ | (PCI_SLOT(devfn) << 11)
+ | (PCI_FUNC(devfn) << 8) | where);
+ }
+
+ return paddress;
+}
+
+/*
+ * Mask table, bits to mask for quantity of size 1, 2 or 4 bytes.
+ * 0 and 3 are not valid indexes...
+ */
+static u32 bytemask[] = {
+ /*0*/ 0,
+ /*1*/ 0xff,
+ /*2*/ 0xffff,
+ /*3*/ 0,
+ /*4*/ 0xffffffff,
+};
+
+
+int ixp2000_pci_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 *value)
+{
+ u32 n;
+ u32 *addr;
+
+ n = where % 4;
+
+ addr = ixp2000_pci_config_addr(bus->number, devfn, where);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ pci_master_aborts = 0;
+ *value = (*addr >> (8*n)) & bytemask[size];
+ if (pci_master_aborts) {
+ pci_master_aborts = 0;
+ *value = 0xffffffff;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/*
+ * We don't do error checks by callling clear_master_aborts() b/c the
+ * assumption is that the caller did a read first to make sure a device
+ * exists.
+ */
+int ixp2000_pci_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 value)
+{
+ u32 mask;
+ u32 *addr;
+ u32 temp;
+
+ mask = ~(bytemask[size] << ((where % 0x4) * 8));
+ addr = ixp2000_pci_config_addr(bus->number, devfn, where);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ temp = (u32) (value) << ((where % 0x4) * 8);
+ *addr = (*addr & mask) | temp;
+
+ clear_master_aborts();
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+
+static struct pci_ops ixp2000_pci_ops = {
+ .read = ixp2000_pci_read_config,
+ .write = ixp2000_pci_write_config
+};
+
+struct pci_bus *ixp2000_pci_scan_bus(int nr, struct pci_sys_data *sysdata)
+{
+ return pci_scan_bus(sysdata->busnr, &ixp2000_pci_ops, sysdata);
+}
+
+
+int ixp2000_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+{
+
+ volatile u32 temp;
+
+ pci_master_aborts = 1;
+
+ cli();
+ temp = *(IXP2000_PCI_CONTROL);
+ if (temp & ((1 << 8) | (1 << 5))) {
+ *(IXP2000_PCI_CONTROL) = temp;
+ }
+
+ temp = *(IXP2000_PCI_CMDSTAT);
+ if (temp & (1 << 29)) {
+ while (temp & (1 << 29)) {
+ *(IXP2000_PCI_CMDSTAT) = temp;
+ temp = *(IXP2000_PCI_CMDSTAT);
+ }
+ }
+ sti();
+
+ /*
+ * If it was an imprecise abort, then we need to correct the
+ * return address to be _after_ the instruction.
+ */
+ if (fsr & (1 << 10))
+ regs->ARM_pc += 4;
+
+ return 0;
+}
+
+int
+clear_master_aborts(void)
+{
+ volatile u32 temp;
+
+ cli();
+ temp = *(IXP2000_PCI_CONTROL);
+ if (temp & ((1 << 8) | (1 << 5))) {
+ *(IXP2000_PCI_CONTROL) = temp;
+ }
+
+ temp = *(IXP2000_PCI_CMDSTAT);
+ if (temp & (1 << 29)) {
+ while (temp & (1 << 29)) {
+ *(IXP2000_PCI_CMDSTAT) = temp;
+ temp = *(IXP2000_PCI_CMDSTAT);
+ }
+ }
+ sti();
+
+ return 0;
+}
+
+void __init
+ixp2000_pci_preinit(void)
+{
+ hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS,
+ "PCI config cycle to non-existent device");
+}
+
+
+/*
+ * IXP2000 systems often have large resource requirements, so we just
+ * use our own resource space.
+ */
+static struct resource ixp2000_pci_mem_space = {
+ .start = 0x00000000,
+ .end = 0xffffffff,
+ .flags = IORESOURCE_MEM,
+ .name = "PCI Mem Space"
+};
+
+static struct resource ixp2000_pci_io_space = {
+ .start = 0x00000000,
+ .end = 0xffffffff,
+ .flags = IORESOURCE_IO,
+ .name = "PCI I/O Space"
+};
+
+int ixp2000_pci_setup(int nr, struct pci_sys_data *sys)
+{
+ if (nr >= 1)
+ return 0;
+
+ sys->resource[0] = &ixp2000_pci_io_space;
+ sys->resource[1] = &ixp2000_pci_mem_space;
+ sys->resource[2] = NULL;
+
+ return 1;
+}
+
diff -Nru a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
--- a/arch/arm/mach-ixp4xx/common.c 2004-10-18 14:56:32 -07:00
+++ b/arch/arm/mach-ixp4xx/common.c 2004-10-18 14:56:32 -07:00
@@ -207,7 +207,7 @@
static unsigned volatile last_jiffy_time;
-#define CLOCK_TICKS_PER_USEC (CLOCK_TICK_RATE / USEC_PER_SEC)
+#define CLOCK_TICKS_PER_USEC ((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC)
/* IRQs are disabled before entering here from do_gettimeofday() */
static unsigned long ixp4xx_gettimeoffset(void)
diff -Nru a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
--- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c 2004-10-18 14:55:54 -07:00
+++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c 2004-10-18 14:55:54 -07:00
@@ -45,7 +45,6 @@
.resource = smc91x_resources,
};
-#if 0
static struct resource lh7a40x_usbclient_resources[] = {
[0] = {
.start = USB_PHYS,
@@ -53,8 +52,8 @@
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = IRQ_USB,
- .end = IRQ_USB,
+ .start = IRQ_USBINTR,
+ .end = IRQ_USBINTR,
.flags = IORESOURCE_IRQ,
},
};
@@ -62,7 +61,7 @@
static u64 lh7a40x_usbclient_dma_mask = 0xffffffffUL;
static struct platform_device lh7a40x_usbclient_device = {
- .name = "lh7a40x-udc",
+ .name = "lh7a40x_udc",
.id = 0,
.dev = {
.dma_mask = &lh7a40x_usbclient_dma_mask,
@@ -71,7 +70,6 @@
.num_resources = ARRAY_SIZE (lh7a40x_usbclient_resources),
.resource = lh7a40x_usbclient_resources,
};
-#endif
#if defined (CONFIG_ARCH_LH7A404)
@@ -105,8 +103,7 @@
static struct platform_device *lpd7a40x_devs[] __initdata = {
&smc91x_device,
-/* &lh7a40x_usbclient_device, */
-
+ &lh7a40x_usbclient_device,
#if defined (CONFIG_ARCH_LH7A404)
&lh7a404_usbhost_device,
#endif
diff -Nru a/arch/arm/mach-lh7a40x/time.c b/arch/arm/mach-lh7a40x/time.c
--- a/arch/arm/mach-lh7a40x/time.c 2004-10-18 14:56:32 -07:00
+++ b/arch/arm/mach-lh7a40x/time.c 2004-10-18 14:56:32 -07:00
@@ -22,12 +22,12 @@
#include
#if HZ < 100
-# define TIMER_CONTROL TIMER_CONTROL1
-# define TIMER_LOAD TIMER_LOAD1
+# define TIMER_CONTROL TIMER_CONTROL2
+# define TIMER_LOAD TIMER_LOAD2
# define TIMER_CONSTANT (508469/HZ)
# define TIMER_MODE (TIMER_C_ENABLE | TIMER_C_PERIODIC | TIMER_C_508KHZ)
-# define TIMER_EOI TIMER_EOI1
-# define TIMER_IRQ IRQ_T1UI
+# define TIMER_EOI TIMER_EOI2
+# define TIMER_IRQ IRQ_T2UI
#else
# define TIMER_CONTROL TIMER_CONTROL3
# define TIMER_LOAD TIMER_LOAD3
diff -Nru a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile
--- a/arch/arm/mach-omap/Makefile 2004-10-18 14:56:13 -07:00
+++ b/arch/arm/mach-omap/Makefile 2004-10-18 14:56:13 -07:00
@@ -3,25 +3,29 @@
#
# Common support
-obj-y := common.o irq.o dma.o clocks.o mux.o bus.o gpio.o time.o
+obj-y := common.o time.o irq.o dma.o clocks.o mux.o gpio.o mcbsp.o
obj-m :=
obj-n :=
obj- :=
led-y := leds.o
# Specific board support
+obj-$(CONFIG_MACH_OMAP_H2) += board-h2.o
obj-$(CONFIG_MACH_OMAP_INNOVATOR) += board-innovator.o
obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o
obj-$(CONFIG_MACH_OMAP_PERSEUS2) += board-perseus2.o
obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o
+obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o
-# OCPI interconnect support for 1610 and 5912
+# OCPI interconnect support for 1710, 1610 and 5912
+obj-$(CONFIG_ARCH_OMAP1710) += ocpi.o
obj-$(CONFIG_ARCH_OMAP1610) += ocpi.o
obj-$(CONFIG_ARCH_OMAP5912) += ocpi.o
# LEDs support
+led-$(CONFIG_MACH_OMAP_H2) += leds-h2p2-debug.o
led-$(CONFIG_MACH_OMAP_INNOVATOR) += leds-innovator.o
-led-$(CONFIG_MACH_OMAP_PERSEUS2) += leds-perseus2.o
+led-$(CONFIG_MACH_OMAP_PERSEUS2) += leds-h2p2-debug.o
obj-$(CONFIG_LEDS) += $(led-y)
# Power Management
diff -Nru a/arch/arm/mach-omap/board-generic.c b/arch/arm/mach-omap/board-generic.c
--- a/arch/arm/mach-omap/board-generic.c 2004-10-18 14:56:33 -07:00
+++ b/arch/arm/mach-omap/board-generic.c 2004-10-18 14:56:33 -07:00
@@ -25,9 +25,13 @@
#include
#include
#include
+#include
+#include
#include "common.h"
+extern void __init omap_init_time(void);
+
static void __init omap_generic_init_irq(void)
{
omap_init_irq();
@@ -36,17 +40,49 @@
/*
* Muxes the serial ports on
*/
+#ifdef CONFIG_ARCH_OMAP1510
static void __init omap_early_serial_init(void)
{
+#ifdef CONFIG_OMAP_LL_DEBUG_UART1
omap_cfg_reg(UART1_TX);
omap_cfg_reg(UART1_RTS);
+#endif
+#ifdef CONFIG_OMAP_LL_DEBUG_UART2
omap_cfg_reg(UART2_TX);
omap_cfg_reg(UART2_RTS);
+#endif
+#ifdef CONFIG_OMAP_LL_DEBUG_UART1
omap_cfg_reg(UART3_TX);
omap_cfg_reg(UART3_RX);
+#endif
}
+#endif
+
+/* assume no Mini-AB port */
+
+#ifdef CONFIG_ARCH_OMAP1510
+static struct omap_usb_config generic1510_usb_config __initdata = {
+ .register_host = 1,
+ .register_dev = 1,
+ .hmc_mode = 16,
+ .pins[0] = 3,
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP1610
+static struct omap_usb_config generic1610_usb_config __initdata = {
+ .register_host = 1,
+ .register_dev = 1,
+ .hmc_mode = 16,
+ .pins[0] = 6,
+};
+#endif
+
+static struct omap_board_config_kernel generic_config[] = {
+ { OMAP_TAG_USB, NULL },
+};
static void __init omap_generic_init(void)
{
@@ -55,9 +91,19 @@
* You have to mux them off in device drivers later on
* if not needed.
*/
+#ifdef CONFIG_ARCH_OMAP1510
if (cpu_is_omap1510()) {
omap_early_serial_init();
+ generic_config[0].data = &generic1510_usb_config;
+ }
+#endif
+#ifdef CONFIG_ARCH_OMAP1610
+ if (!cpu_is_omap1510()) {
+ generic_config[0].data = &generic1610_usb_config;
}
+#endif
+ omap_board_config = generic_config;
+ omap_board_config_size = ARRAY_SIZE(generic_config);
}
static void __init omap_generic_map_io(void)
@@ -65,18 +111,12 @@
omap_map_io();
}
-static void __init omap_generic_init_time(void)
-{
- omap_init_time();
-}
-
-MACHINE_START(OMAP_GENERIC, "Generic OMAP-1510/1610/1710")
+MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710")
MAINTAINER("Tony Lindgren ")
BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
BOOT_PARAMS(0x10000100)
MAPIO(omap_generic_map_io)
INITIRQ(omap_generic_init_irq)
INIT_MACHINE(omap_generic_init)
- INITTIME(omap_generic_init_time)
+ INITTIME(omap_init_time)
MACHINE_END
-
diff -Nru a/arch/arm/mach-omap/board-h2.c b/arch/arm/mach-omap/board-h2.c
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/arch/arm/mach-omap/board-h2.c 2004-10-18 14:57:24 -07:00
@@ -0,0 +1,115 @@
+/*
+ * linux/arch/arm/mach-omap/board-h2.c
+ *
+ * Board specific inits for OMAP-1610 H2
+ *
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Author: Greg Lonnon
+ *
+ * Copyright (C) 2002 MontaVista Software, Inc.
+ *
+ * Separated FPGA interrupts from innovator1510.c and cleaned up for 2.6
+ * Copyright (C) 2004 Nokia Corporation by Tony Lindrgen
+ *
+ * H2 specific changes and cleanup
+ * Copyright (C) 2004 Nokia Corporation by Imre Deak
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "common.h"
+
+extern void __init omap_init_time(void);
+
+static struct map_desc h2_io_desc[] __initdata = {
+{ OMAP1610_ETHR_BASE, OMAP1610_ETHR_START, OMAP1610_ETHR_SIZE,MT_DEVICE },
+{ OMAP1610_NOR_FLASH_BASE, OMAP1610_NOR_FLASH_START, OMAP1610_NOR_FLASH_SIZE,
+ MT_DEVICE },
+};
+
+static struct resource h2_smc91x_resources[] = {
+ [0] = {
+ .start = OMAP1610_ETHR_START, /* Physical */
+ .end = OMAP1610_ETHR_START + SZ_4K,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0, /* Really GPIO 0 */
+ .end = 0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device h2_smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(h2_smc91x_resources),
+ .resource = h2_smc91x_resources,
+};
+
+static struct platform_device *h2_devices[] __initdata = {
+ &h2_smc91x_device,
+};
+
+void h2_init_irq(void)
+{
+ omap_init_irq();
+}
+
+static struct omap_usb_config h2_usb_config __initdata = {
+ /* usb1 has a Mini-AB port and external isp1301 transceiver */
+ .otg = 2,
+
+#ifdef CONFIG_USB_GADGET_OMAP
+ .hmc_mode = 19, // 0:host(off) 1:dev|otg 2:disabled
+ // .hmc_mode = 21, // 0:host(off) 1:dev(loopback) 2:host(loopback)
+#elif defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+ /* NONSTANDARD CABLE NEEDED (B-to-Mini-B) */
+ .hmc_mode = 20, // 1:dev|otg(off) 1:host 2:disabled
+#endif
+
+ .pins[1] = 3,
+};
+
+static struct omap_board_config_kernel h2_config[] = {
+ { OMAP_TAG_USB, &h2_usb_config },
+};
+
+static void __init h2_init(void)
+{
+ platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
+ omap_board_config = h2_config;
+ omap_board_config_size = ARRAY_SIZE(h2_config);
+}
+
+static void __init h2_map_io(void)
+{
+ omap_map_io();
+ iotable_init(h2_io_desc, ARRAY_SIZE(h2_io_desc));
+}
+
+MACHINE_START(OMAP_H2, "TI-H2")
+ MAINTAINER("Imre Deak ")
+ BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
+ BOOT_PARAMS(0x10000100)
+ MAPIO(h2_map_io)
+ INITIRQ(h2_init_irq)
+ INIT_MACHINE(h2_init)
+ INITTIME(omap_init_time)
+MACHINE_END
diff -Nru a/arch/arm/mach-omap/board-h3.c b/arch/arm/mach-omap/board-h3.c
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/arch/arm/mach-omap/board-h3.c 2004-10-18 14:57:21 -07:00
@@ -0,0 +1,90 @@
+/*
+ * linux/arch/arm/mach-omap/board-h3.c
+ *
+ * This file contains OMAP1710 H3 specific code.
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ * Copyright (C) 2002 MontaVista Software, Inc.
+ * Copyright (C) 2001 RidgeRun, Inc.
+ * Author: RidgeRun, Inc.
+ * Greg Lonnon (glonnon@ridgerun.com) or info@ridgerun.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "common.h"
+
+extern void __init omap_init_time(void);
+
+void h3_init_irq(void)
+{
+ omap_init_irq();
+}
+
+static struct resource smc91x_resources[] = {
+ [0] = {
+ .start = OMAP1710_ETHR_START, /* Physical */
+ .end = OMAP1710_ETHR_START + OMAP1710_ETHR_SIZE,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+
+static struct platform_device *devices[] __initdata = {
+ &smc91x_device,
+};
+
+static void __init h3_init(void)
+{
+ (void) platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+static struct map_desc h3_io_desc[] __initdata = {
+{ OMAP1710_ETHR_BASE, OMAP1710_ETHR_START, OMAP1710_ETHR_SIZE, MT_DEVICE },
+{ OMAP_NOR_FLASH_BASE, OMAP_NOR_FLASH_START, OMAP_NOR_FLASH_SIZE, MT_DEVICE },
+};
+
+static void __init h3_map_io(void)
+{
+ omap_map_io();
+ iotable_init(h3_io_desc, ARRAY_SIZE(h3_io_desc));
+}
+
+MACHINE_START(OMAP_H3, "TI OMAP1710 H3 board")
+ MAINTAINER("Texas Instruments, Inc.")
+ BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
+ BOOT_PARAMS(0x10000100)
+ MAPIO(h3_map_io)
+ INITIRQ(h3_init_irq)
+ INIT_MACHINE(h3_init)
+ INITTIME(omap_init_time)
+MACHINE_END
diff -Nru a/arch/arm/mach-omap/board-innovator.c b/arch/arm/mach-omap/board-innovator.c
--- a/arch/arm/mach-omap/board-innovator.c 2004-10-18 14:55:54 -07:00
+++ b/arch/arm/mach-omap/board-innovator.c 2004-10-18 14:55:54 -07:00
@@ -29,9 +29,12 @@
#include
#include
#include
+#include
#include "common.h"
+extern void __init omap_init_time(void);
+
#ifdef CONFIG_ARCH_OMAP1510
extern int omap_gpio_init(void);
@@ -49,8 +52,8 @@
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = INT_ETHER,
- .end = INT_ETHER,
+ .start = OMAP1510_INT_ETHER,
+ .end = OMAP1510_INT_ETHER,
.flags = IORESOURCE_IRQ,
},
};
@@ -108,11 +111,43 @@
#ifdef CONFIG_ARCH_OMAP1510
if (cpu_is_omap1510()) {
omap_gpio_init();
- fpga_init_irq();
+ omap1510_fpga_init_irq();
}
#endif
}
+#ifdef CONFIG_ARCH_OMAP1510
+static struct omap_usb_config innovator1510_usb_config __initdata = {
+ /* has usb host and device, but no Mini-AB port */
+ .register_host = 1,
+ .register_dev = 1,
+ /* Assume bad Innovator wiring; Use internal host only with custom cable */
+ .hmc_mode = 16,
+ .pins[0] = 2,
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP1610
+static struct omap_usb_config h2_usb_config __initdata = {
+ /* usb1 has a Mini-AB port and external isp1301 transceiver */
+ .otg = 2,
+
+#ifdef CONFIG_USB_GADGET_OMAP
+ .hmc_mode = 19, // 0:host(off) 1:dev|otg 2:disabled
+ // .hmc_mode = 21, // 0:host(off) 1:dev(loopback) 2:host(loopback)
+#elif defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+ /* NONSTANDARD CABLE NEEDED (B-to-Mini-B) */
+ .hmc_mode = 20, // 1:dev|otg(off) 1:host 2:disabled
+#endif
+
+ .pins[1] = 3,
+};
+#endif
+
+static struct omap_board_config_kernel innovator_config[] = {
+ { OMAP_TAG_USB, NULL },
+};
+
static void __init innovator_init(void)
{
#ifdef CONFIG_ARCH_OMAP1510
@@ -121,10 +156,21 @@
}
#endif
#ifdef CONFIG_ARCH_OMAP1610
- if (cpu_is_omap1610()) {
+ if (!cpu_is_omap1510()) {
platform_add_devices(innovator1610_devices, ARRAY_SIZE(innovator1610_devices));
}
#endif
+
+#ifdef CONFIG_ARCH_OMAP1510
+ if (cpu_is_omap1510())
+ innovator_config[0].data = &innovator1510_usb_config;
+#endif
+#ifdef CONFIG_ARCH_OMAP1610
+ if (cpu_is_omap1610())
+ innovator_config[0].data = &h2_usb_config;
+#endif
+ omap_board_config = innovator_config;
+ omap_board_config_size = ARRAY_SIZE(innovator_config);
}
static void __init innovator_map_io(void)
@@ -144,7 +190,7 @@
}
#endif
#ifdef CONFIG_ARCH_OMAP1610
- if (cpu_is_omap1610()) {
+ if (!cpu_is_omap1510()) {
iotable_init(innovator1610_io_desc, ARRAY_SIZE(innovator1610_io_desc));
}
#endif
@@ -156,6 +202,6 @@
BOOT_PARAMS(0x10000100)
MAPIO(innovator_map_io)
INITIRQ(innovator_init_irq)
- INITTIME(omap_init_time)
INIT_MACHINE(innovator_init)
+ INITTIME(omap_init_time)
MACHINE_END
diff -Nru a/arch/arm/mach-omap/board-osk.c b/arch/arm/mach-omap/board-osk.c
--- a/arch/arm/mach-omap/board-osk.c 2004-10-18 14:56:50 -07:00
+++ b/arch/arm/mach-omap/board-osk.c 2004-10-18 14:56:50 -07:00
@@ -41,6 +41,8 @@
#include "common.h"
+extern void __init omap_init_time(void);
+
static struct map_desc osk5912_io_desc[] __initdata = {
{ OMAP_OSK_ETHR_BASE, OMAP_OSK_ETHR_START, OMAP_OSK_ETHR_SIZE,MT_DEVICE },
{ OMAP_OSK_NOR_FLASH_BASE, OMAP_OSK_NOR_FLASH_START, OMAP_OSK_NOR_FLASH_SIZE,
@@ -94,6 +96,6 @@
BOOT_PARAMS(0x10000100)
MAPIO(osk_map_io)
INITIRQ(osk_init_irq)
- INITTIME(omap_init_time)
INIT_MACHINE(osk_init)
+ INITTIME(omap_init_time)
MACHINE_END
diff -Nru a/arch/arm/mach-omap/board-perseus2.c b/arch/arm/mach-omap/board-perseus2.c
--- a/arch/arm/mach-omap/board-perseus2.c 2004-10-18 14:56:49 -07:00
+++ b/arch/arm/mach-omap/board-perseus2.c 2004-10-18 14:56:49 -07:00
@@ -23,9 +23,12 @@
#include
#include
#include
+#include
#include "common.h"
+extern void __init omap_init_time(void);
+
void omap_perseus2_init_irq(void)
{
omap_init_irq();
@@ -33,14 +36,14 @@
static struct resource smc91x_resources[] = {
[0] = {
- .start = OMAP730_FPGA_ETHR_START, /* Physical */
- .end = OMAP730_FPGA_ETHR_START + SZ_4K,
+ .start = H2P2_DBG_FPGA_ETHR_START, /* Physical */
+ .end = H2P2_DBG_FPGA_ETHR_START + SZ_4K,
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 0,
+ .start = INT_730_MPU_EXT_NIRQ,
.end = 0,
- .flags = INT_ETHER,
+ .flags = IORESOURCE_IRQ,
},
};
@@ -62,7 +65,7 @@
/* Only FPGA needs to be mapped here. All others are done with ioremap */
static struct map_desc omap_perseus2_io_desc[] __initdata = {
- {OMAP730_FPGA_BASE, OMAP730_FPGA_START, OMAP730_FPGA_SIZE,
+ {H2P2_DBG_FPGA_BASE, H2P2_DBG_FPGA_START, H2P2_DBG_FPGA_SIZE,
MT_DEVICE},
};
@@ -111,6 +114,6 @@
BOOT_PARAMS(0x10000100)
MAPIO(omap_perseus2_map_io)
INITIRQ(omap_perseus2_init_irq)
- INITTIME(omap_init_time)
INIT_MACHINE(omap_perseus2_init)
+ INITTIME(omap_init_time)
MACHINE_END
diff -Nru a/arch/arm/mach-omap/bus.c b/arch/arm/mach-omap/bus.c
--- a/arch/arm/mach-omap/bus.c 2004-10-18 14:57:18 -07:00
+++ /dev/null Wed Dec 31 16:00:00 196900
@@ -1,246 +0,0 @@
-/*
- * linux/arch/arm/mach-omap/bus.c
- *
- * Virtual bus for OMAP. Allows better power management, such as managing
- * shared clocks, and mapping of bus addresses to Local Bus addresses.
- *
- * See drivers/usb/host/ohci-omap.c or drivers/video/omap/omapfb.c for
- * examples on how to register drivers to this bus.
- *
- * Copyright (C) 2003 - 2004 Nokia Corporation
- * Written by Tony Lindgren
- * Portions of code based on sa1111.c.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-static int omap_bus_match(struct device *_dev, struct device_driver *_drv);
-static int omap_bus_suspend(struct device *dev, u32 state);
-static int omap_bus_resume(struct device *dev);
-
-/*
- * OMAP bus definitions
- *
- * NOTE: Most devices should use TIPB. LBUS does automatic address mapping
- * to Local Bus addresses, and should only be used for Local Bus devices.
- * We may add new buses later on for power management reasons. Basically
- * we want to be able to turn off any bus if it's not used by device
- * drivers.
- */
-static struct device omap_bus_devices[OMAP_NR_BUSES] = {
- {
- .bus_id = OMAP_BUS_NAME_TIPB
- }, {
- .bus_id = OMAP_BUS_NAME_LBUS
- },
-};
-
-static struct bus_type omap_bus_types[OMAP_NR_BUSES] = {
- {
- .name = OMAP_BUS_NAME_TIPB,
- .match = omap_bus_match,
- .suspend = omap_bus_suspend,
- .resume = omap_bus_resume,
- }, {
- .name = OMAP_BUS_NAME_LBUS, /* Local bus on 1510 */
- .match = omap_bus_match,
- .suspend = omap_bus_suspend,
- .resume = omap_bus_resume,
- },
-};
-
-static int omap_bus_match(struct device *dev, struct device_driver *drv)
-{
- struct omap_dev *omapdev = OMAP_DEV(dev);
- struct omap_driver *omapdrv = OMAP_DRV(drv);
-
- return omapdev->devid == omapdrv->devid;
-}
-
-static int omap_bus_suspend(struct device *dev, u32 state)
-{
- struct omap_dev *omapdev = OMAP_DEV(dev);
- struct omap_driver *omapdrv = OMAP_DRV(dev->driver);
- int ret = 0;
-
- if (omapdrv && omapdrv->suspend)
- ret = omapdrv->suspend(omapdev, state);
- return ret;
-}
-
-static int omap_bus_resume(struct device *dev)
-{
- struct omap_dev *omapdev = OMAP_DEV(dev);
- struct omap_driver *omapdrv = OMAP_DRV(dev->driver);
- int ret = 0;
-
- if (omapdrv && omapdrv->resume)
- ret = omapdrv->resume(omapdev);
- return ret;
-}
-
-static int omap_device_probe(struct device *dev)
-{
- struct omap_dev *omapdev = OMAP_DEV(dev);
- struct omap_driver *omapdrv = OMAP_DRV(dev->driver);
- int ret = -ENODEV;
-
- if (omapdrv && omapdrv->probe)
- ret = omapdrv->probe(omapdev);
-
- return ret;
-}
-
-static int omap_device_remove(struct device *dev)
-{
- struct omap_dev *omapdev = OMAP_DEV(dev);
- struct omap_driver *omapdrv = OMAP_DRV(dev->driver);
- int ret = 0;
-
- if (omapdrv && omapdrv->remove)
- ret = omapdrv->remove(omapdev);
- return ret;
-}
-
-int omap_device_register(struct omap_dev *odev)
-{
- if (!odev)
- return -EINVAL;
-
- if (odev->busid < 0 || odev->busid >= OMAP_NR_BUSES) {
- printk(KERN_ERR "%s: busid invalid: %s: bus: %i\n",
- __FUNCTION__, odev->name, odev->busid);
- return -EINVAL;
- }
-
- odev->dev.parent = &omap_bus_devices[odev->busid];
- odev->dev.bus = &omap_bus_types[odev->busid];
-
- /* This is needed for USB OHCI to work */
- if (odev->dma_mask)
- odev->dev.dma_mask = odev->dma_mask;
-
- if (odev->coherent_dma_mask)
- odev->dev.coherent_dma_mask = odev->coherent_dma_mask;
-
- snprintf(odev->dev.bus_id, BUS_ID_SIZE, "%s%u",
- odev->name, odev->devid);
-
- printk("Registering OMAP device '%s'. Parent at %s\n",
- odev->dev.bus_id, odev->dev.parent->bus_id);
-
- return device_register(&odev->dev);
-}
-
-void omap_device_unregister(struct omap_dev *odev)
-{
- if (odev)
- device_unregister(&odev->dev);
-}
-
-int omap_driver_register(struct omap_driver *driver)
-{
- int ret;
-
- if (driver->busid < 0 || driver->busid >= OMAP_NR_BUSES) {
- printk(KERN_ERR "%s: busid invalid: bus: %i device: %i\n",
- __FUNCTION__, driver->busid, driver->devid);
- return -EINVAL;
- }
-
- driver->drv.probe = omap_device_probe;
- driver->drv.remove = omap_device_remove;
- driver->drv.bus = &omap_bus_types[driver->busid];
-
- /*
- * driver_register calls bus_add_driver
- */
- ret = driver_register(&driver->drv);
-
- return ret;
-}
-
-void omap_driver_unregister(struct omap_driver *driver)
-{
- driver_unregister(&driver->drv);
-}
-
-static int __init omap_bus_init(void)
-{
- int i, ret;
-
- /* Initialize all OMAP virtual buses */
- for (i = 0; i < OMAP_NR_BUSES; i++) {
- ret = device_register(&omap_bus_devices[i]);
- if (ret != 0) {
- printk(KERN_ERR "Unable to register bus device %s\n",
- omap_bus_devices[i].bus_id);
- continue;
- }
- ret = bus_register(&omap_bus_types[i]);
- if (ret != 0) {
- printk(KERN_ERR "Unable to register bus %s\n",
- omap_bus_types[i].name);
- device_unregister(&omap_bus_devices[i]);
- }
- }
- printk("OMAP virtual buses initialized\n");
-
- return ret;
-}
-
-static void __exit omap_bus_exit(void)
-{
- int i;
-
- /* Unregister all OMAP virtual buses */
- for (i = 0; i < OMAP_NR_BUSES; i++) {
- bus_unregister(&omap_bus_types[i]);
- device_unregister(&omap_bus_devices[i]);
- }
-}
-
-postcore_initcall(omap_bus_init);
-module_exit(omap_bus_exit);
-
-MODULE_DESCRIPTION("Virtual bus for OMAP");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(omap_bus_types);
-EXPORT_SYMBOL(omap_driver_register);
-EXPORT_SYMBOL(omap_driver_unregister);
-EXPORT_SYMBOL(omap_device_register);
-EXPORT_SYMBOL(omap_device_unregister);
-
diff -Nru a/arch/arm/mach-omap/clocks.c b/arch/arm/mach-omap/clocks.c
--- a/arch/arm/mach-omap/clocks.c 2004-10-18 14:56:32 -07:00
+++ b/arch/arm/mach-omap/clocks.c 2004-10-18 14:56:32 -07:00
@@ -36,6 +36,8 @@
#include
#include
+extern void start_mputimer1(unsigned long load_val);
+
/* Input clock in MHz */
static unsigned int source_clock = 12;
@@ -239,7 +241,7 @@
int ck_debug = 0;
#define CK_MAX_PLL_FREQ OMAP_CK_MAX_RATE
-static __u8 ck_valid_table[CK_MAX_PLL_FREQ / 8 + 1];
+static __u32 ck_valid_table[CK_MAX_PLL_FREQ / 32 + 1];
static __u8 ck_lookup_table[CK_MAX_PLL_FREQ];
int
@@ -615,11 +617,11 @@
int __init
init_ck(void)
{
- const struct omap_clock_info *info;
+ const struct omap_clock_config *info;
int crystal_type = 0; /* Default 12 MHz */
__ck_make_lookup_table();
- info = omap_get_per_info(OMAP_TAG_CLOCK, struct omap_clock_info);
+ info = omap_get_config(OMAP_TAG_CLOCK, struct omap_clock_config);
if (info != NULL) {
if (!cpu_is_omap1510())
crystal_type = info->system_clock_type;
@@ -645,7 +647,8 @@
#elif defined(CONFIG_OMAP_ARM_182MHZ) && defined(CONFIG_ARCH_OMAP730)
omap_writew(0x250E, ARM_CKCTL);
omap_writew(0x2710, DPLL_CTL);
-#elif defined(CONFIG_OMAP_ARM_192MHZ) && (defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912))
+#elif defined(CONFIG_OMAP_ARM_192MHZ) && (defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) \
+ || defined(CONFIG_ARCH_OMAP1710))
omap_writew(0x150f, ARM_CKCTL);
if (crystal_type == 2) {
source_clock = 13; /* MHz */
diff -Nru a/arch/arm/mach-omap/common.c b/arch/arm/mach-omap/common.c
--- a/arch/arm/mach-omap/common.c 2004-10-18 14:57:04 -07:00
+++ b/arch/arm/mach-omap/common.c 2004-10-18 14:57:04 -07:00
@@ -104,7 +104,7 @@
};
#endif
-#ifdef CONFIG_ARCH_OMAP1610
+#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710)
static struct map_desc omap1610_io_desc[] __initdata = {
{ OMAP1610_DSP_BASE, OMAP1610_DSP_START, OMAP1610_DSP_SIZE, MT_DEVICE },
{ OMAP1610_DSPREG_BASE, OMAP1610_DSPREG_START, OMAP1610_DSPREG_SIZE, MT_DEVICE },
@@ -147,8 +147,8 @@
iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc));
}
#endif
-#ifdef CONFIG_ARCH_OMAP1610
- if (cpu_is_omap1610()) {
+#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710)
+ if (cpu_is_omap1610() || cpu_is_omap1710()) {
iotable_init(omap1610_io_desc, ARRAY_SIZE(omap1610_io_desc));
}
#endif
@@ -181,13 +181,18 @@
extern int omap_bootloader_tag_len;
extern u8 omap_bootloader_tag[];
-const void *__omap_get_per_info(u16 tag, size_t len)
+struct omap_board_config_kernel *omap_board_config;
+int omap_board_config_size = 0;
+
+const void *__omap_get_config(u16 tag, size_t len)
{
- struct omap_board_info_entry *info = NULL;
+ struct omap_board_config_entry *info = NULL;
+ struct omap_board_config_kernel *kinfo = NULL;
+ int i;
#ifdef CONFIG_OMAP_BOOT_TAG
if (omap_bootloader_tag_len > 4)
- info = (struct omap_board_info_entry *) omap_bootloader_tag;
+ info = (struct omap_board_config_entry *) omap_bootloader_tag;
while (info != NULL) {
u8 *next;
@@ -198,26 +203,38 @@
if (next >= omap_bootloader_tag + omap_bootloader_tag_len)
info = NULL;
else
- info = (struct omap_board_info_entry *) next;
+ info = (struct omap_board_config_entry *) next;
}
-#endif
- if (info == NULL)
- return NULL;
- if (info->len != len) {
- printk(KERN_ERR "OMAP per_info: Length mismatch with tag %x (want %d, got %d)\n",
- tag, len, info->len);
- return NULL;
+ if (info != NULL) {
+ /* Check the length as a lame attempt to check for
+ * binary inconsistancy. */
+ if (info->len != len) {
+ printk(KERN_ERR "OMAP peripheral config: Length mismatch with tag %x (want %d, got %d)\n",
+ tag, len, info->len);
+ return NULL;
+ }
+ return info->data;
+ }
+#endif
+ /* Try to find the config from the board-specific structures
+ * in the kernel. */
+ for (i = 0; i < omap_board_config_size; i++) {
+ if (omap_board_config[i].tag == tag) {
+ kinfo = &omap_board_config[i];
+ break;
+ }
}
-
- return info->data;
+ if (kinfo == NULL)
+ return NULL;
+ return kinfo->data;
}
-EXPORT_SYMBOL(__omap_get_per_info);
+EXPORT_SYMBOL(__omap_get_config);
static int __init omap_add_serial_console(void)
{
- const struct omap_uart_info *info;
+ const struct omap_uart_config *info;
- info = omap_get_per_info(OMAP_TAG_UART, struct omap_uart_info);
+ info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config);
if (info != NULL && info->console_uart) {
static char speed[11], *opt = NULL;
diff -Nru a/arch/arm/mach-omap/common.h b/arch/arm/mach-omap/common.h
--- a/arch/arm/mach-omap/common.h 2004-10-18 14:56:32 -07:00
+++ b/arch/arm/mach-omap/common.h 2004-10-18 14:56:32 -07:00
@@ -28,7 +28,6 @@
#define __ARCH_ARM_MACH_OMAP_COMMON_H
extern void omap_map_io(void);
-extern void omap_init_time(void);
#endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */
diff -Nru a/arch/arm/mach-omap/dma.c b/arch/arm/mach-omap/dma.c
--- a/arch/arm/mach-omap/dma.c 2004-10-18 14:57:04 -07:00
+++ b/arch/arm/mach-omap/dma.c 2004-10-18 14:57:04 -07:00
@@ -118,7 +118,7 @@
u16 w;
#ifdef CONFIG_DEBUG_KERNEL
- if (omap_dma_in_1510_mode) {
+ if (omap_dma_in_1510_mode()) {
printk(KERN_ERR "OMAP DMA constant fill not available in 1510 mode.");
BUG();
return;
@@ -141,7 +141,7 @@
u16 w;
#ifdef CONFIG_DEBUG_KERNEL
- if (omap_dma_in_1510_mode) {
+ if (omap_dma_in_1510_mode()) {
printk(KERN_ERR "OMAP DMA transparent copy not available in 1510 mode.");
BUG();
}
@@ -266,46 +266,78 @@
omap_writew(w, OMAP_DMA_CSDP(lch));
}
+static inline void init_intr(int lch)
+{
+ u16 w;
+
+ /* Read CSR to make sure it's cleared. */
+ w = omap_readw(OMAP_DMA_CSR(lch));
+ /* Enable some nice interrupts. */
+ omap_writew(dma_chan[lch].enabled_irqs, OMAP_DMA_CICR(lch));
+ dma_chan[lch].flags |= OMAP_DMA_ACTIVE;
+}
+
+static inline void enable_lnk(int lch)
+{
+ u16 w;
+
+ /* Clear the STOP_LNK bits */
+ w = omap_readw(OMAP_DMA_CLNK_CTRL(lch));
+ w &= ~(1 << 14);
+ omap_writew(w, OMAP_DMA_CLNK_CTRL(lch));
+
+ /* And set the ENABLE_LNK bits */
+ if (dma_chan[lch].next_lch != -1)
+ omap_writew(dma_chan[lch].next_lch | (1 << 15),
+ OMAP_DMA_CLNK_CTRL(lch));
+}
+
+static inline void disable_lnk(int lch)
+{
+ u16 w;
+
+ /* Disable interrupts */
+ omap_writew(0, OMAP_DMA_CICR(lch));
+
+ /* Set the STOP_LNK bit */
+ w = omap_readw(OMAP_DMA_CLNK_CTRL(lch));
+ w |= (1 << 14);
+ w = omap_writew(w, OMAP_DMA_CLNK_CTRL(lch));
+
+ dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
+}
+
void omap_start_dma(int lch)
{
u16 w;
- if (!omap_dma_in_1510_mode()) {
- int next_lch;
+ if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
+ int next_lch, cur_lch;
+ char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT];
+
+ dma_chan_link_map[lch] = 1;
+ /* Set the link register of the first channel */
+ enable_lnk(lch);
+
+ memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
+ cur_lch = dma_chan[lch].next_lch;
+ do {
+ next_lch = dma_chan[cur_lch].next_lch;
- next_lch = dma_chan[lch].next_lch;
+ /* The loop case: we've been here already */
+ if (dma_chan_link_map[cur_lch])
+ break;
+ /* Mark the current channel */
+ dma_chan_link_map[cur_lch] = 1;
- /* Enable the queue, if needed so. */
- if (next_lch != -1) {
- /* Clear the STOP_LNK bits */
- w = omap_readw(OMAP_DMA_CLNK_CTRL(lch));
- w &= ~(1 << 14);
- omap_writew(w, OMAP_DMA_CLNK_CTRL(lch));
- w = omap_readw(OMAP_DMA_CLNK_CTRL(next_lch));
- w &= ~(1 << 14);
- omap_writew(w, OMAP_DMA_CLNK_CTRL(next_lch));
-
- /* And set the ENABLE_LNK bits */
- omap_writew(next_lch | (1 << 15),
- OMAP_DMA_CLNK_CTRL(lch));
- /* The loop case */
- if (dma_chan[next_lch].next_lch == lch)
- omap_writew(lch | (1 << 15),
- OMAP_DMA_CLNK_CTRL(next_lch));
-
- /* Read CSR to make sure it's cleared. */
- w = omap_readw(OMAP_DMA_CSR(next_lch));
- /* Enable some nice interrupts. */
- omap_writew(dma_chan[next_lch].enabled_irqs,
- OMAP_DMA_CICR(next_lch));
- dma_chan[next_lch].flags |= OMAP_DMA_ACTIVE;
- }
+ enable_lnk(cur_lch);
+ init_intr(cur_lch);
+
+ cur_lch = next_lch;
+ } while (next_lch != -1);
}
- /* Read CSR to make sure it's cleared. */
- w = omap_readw(OMAP_DMA_CSR(lch));
- /* Enable some nice interrupts. */
- omap_writew(dma_chan[lch].enabled_irqs, OMAP_DMA_CICR(lch));
+ init_intr(lch);
w = omap_readw(OMAP_DMA_CCR(lch));
w |= OMAP_DMA_CCR_EN;
@@ -316,37 +348,34 @@
void omap_stop_dma(int lch)
{
u16 w;
- int next_lch;
- /* Disable all interrupts on the channel */
- omap_writew(0, OMAP_DMA_CICR(lch));
+ if (!omap_dma_in_1510_mode() && dma_chan[lch].next_lch != -1) {
+ int next_lch, cur_lch = lch;
+ char dma_chan_link_map[OMAP_LOGICAL_DMA_CH_COUNT];
+
+ memset(dma_chan_link_map, 0, sizeof(dma_chan_link_map));
+ do {
+ /* The loop case: we've been here already */
+ if (dma_chan_link_map[cur_lch])
+ break;
+ /* Mark the current channel */
+ dma_chan_link_map[cur_lch] = 1;
+
+ disable_lnk(cur_lch);
+
+ next_lch = dma_chan[cur_lch].next_lch;
+ cur_lch = next_lch;
+ } while (next_lch != -1);
- if (omap_dma_in_1510_mode()) {
- w = omap_readw(OMAP_DMA_CCR(lch));
- w &= ~OMAP_DMA_CCR_EN;
- omap_writew(w, OMAP_DMA_CCR(lch));
- dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
return;
}
+ /* Disable all interrupts on the channel */
+ omap_writew(0, OMAP_DMA_CICR(lch));
- next_lch = dma_chan[lch].next_lch;
-
- /*
- * According to thw HW spec, enabling the STOP_LNK bit
- * resets the CCR_EN bit at the same time.
- */
- w = omap_readw(OMAP_DMA_CLNK_CTRL(lch));
- w |= (1 << 14);
- w = omap_writew(w, OMAP_DMA_CLNK_CTRL(lch));
+ w = omap_readw(OMAP_DMA_CCR(lch));
+ w &= ~OMAP_DMA_CCR_EN;
+ omap_writew(w, OMAP_DMA_CCR(lch));
dma_chan[lch].flags &= ~OMAP_DMA_ACTIVE;
-
- if (next_lch != -1) {
- omap_writew(0, OMAP_DMA_CICR(next_lch));
- w = omap_readw(OMAP_DMA_CLNK_CTRL(next_lch));
- w |= (1 << 14);
- w = omap_writew(w, OMAP_DMA_CLNK_CTRL(next_lch));
- dma_chan[next_lch].flags &= ~OMAP_DMA_ACTIVE;
- }
}
void omap_enable_dma_irq(int lch, u16 bits)
@@ -445,7 +474,7 @@
chan->data = data;
chan->enabled_irqs = OMAP_DMA_TOUT_IRQ | OMAP_DMA_DROP_IRQ | OMAP_DMA_BLOCK_IRQ;
- if (cpu_is_omap1610() || cpu_is_omap5912()) {
+ if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap730() || cpu_is_omap1710()) {
/* If the sync device is set, configure it dynamically. */
if (dev_id != 0) {
set_gdma_dev(free_ch + 1, dev_id);
@@ -533,7 +562,6 @@
}
dma_chan[lch_head].next_lch = -1;
- dma_chan[lch_queue].next_lch = -1;
}
@@ -713,7 +741,7 @@
printk(KERN_INFO "DMA support for OMAP1510 initialized\n");
dma_chan_count = 9;
enable_1510_mode = 1;
- } else if (cpu_is_omap1610() || cpu_is_omap5912()) {
+ } else if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap730() || cpu_is_omap1710()) {
printk(KERN_INFO "OMAP DMA hardware version %d\n",
omap_readw(OMAP_DMA_HW_ID));
printk(KERN_INFO "DMA capabilities: %08x:%08x:%04x:%04x:%04x\n",
@@ -771,6 +799,8 @@
EXPORT_SYMBOL(omap_free_dma);
EXPORT_SYMBOL(omap_start_dma);
EXPORT_SYMBOL(omap_stop_dma);
+EXPORT_SYMBOL(omap_enable_dma_irq);
+EXPORT_SYMBOL(omap_disable_dma_irq);
EXPORT_SYMBOL(omap_set_dma_transfer_params);
EXPORT_SYMBOL(omap_set_dma_constant_fill);
diff -Nru a/arch/arm/mach-omap/fpga.c b/arch/arm/mach-omap/fpga.c
--- a/arch/arm/mach-omap/fpga.c 2004-10-18 14:56:20 -07:00
+++ b/arch/arm/mach-omap/fpga.c 2004-10-18 14:56:20 -07:00
@@ -31,19 +31,9 @@
#include
#include
-unsigned char fpga_read(int reg)
-{
- return __raw_readb(reg);
-}
-
-void fpga_write(unsigned char val, int reg)
-{
- __raw_writeb(val, reg);
-}
-
static void fpga_mask_irq(unsigned int irq)
{
- irq -= IH_FPGA_BASE;
+ irq -= OMAP1510_IH_FPGA_BASE;
if (irq < 8)
__raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO)
@@ -76,7 +66,7 @@
static void fpga_unmask_irq(unsigned int irq)
{
- irq -= IH_FPGA_BASE;
+ irq -= OMAP1510_IH_FPGA_BASE;
if (irq < 8)
__raw_writeb((__raw_readb(OMAP1510_FPGA_IMR_LO) | (1 << irq)),
@@ -114,8 +104,8 @@
break;
}
- for (fpga_irq = IH_FPGA_BASE;
- (fpga_irq < (IH_FPGA_BASE + NR_FPGA_IRQS)) && stat;
+ for (fpga_irq = OMAP1510_IH_FPGA_BASE;
+ (fpga_irq < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS)) && stat;
fpga_irq++, stat >>= 1) {
if (stat & 1) {
d = irq_desc + fpga_irq;
@@ -162,7 +152,7 @@
* interrupts at the interrupt controller via disable_irq/enable_irq
* could pose a problem.
*/
-void fpga_init_irq(void)
+void omap1510_fpga_init_irq(void)
{
int i;
@@ -170,9 +160,9 @@
__raw_writeb(0, OMAP1510_FPGA_IMR_HI);
__raw_writeb(0, INNOVATOR_FPGA_IMR2);
- for (i = IH_FPGA_BASE; i < (IH_FPGA_BASE + NR_FPGA_IRQS); i++) {
+ for (i = OMAP1510_IH_FPGA_BASE; i < (OMAP1510_IH_FPGA_BASE + NR_FPGA_IRQS); i++) {
- if (i == INT_FPGA_TS) {
+ if (i == OMAP1510_INT_FPGA_TS) {
/*
* The touchscreen interrupt is level-sensitive, so
* we'll use the regular mask_ack routine for it.
@@ -201,9 +191,7 @@
omap_request_gpio(13);
omap_set_gpio_direction(13, 1);
omap_set_gpio_edge_ctrl(13, OMAP_GPIO_RISING_EDGE);
- set_irq_chained_handler(INT_FPGA, innovator_fpga_IRQ_demux);
+ set_irq_chained_handler(OMAP1510_INT_FPGA, innovator_fpga_IRQ_demux);
}
-EXPORT_SYMBOL(fpga_init_irq);
-EXPORT_SYMBOL(fpga_read);
-EXPORT_SYMBOL(fpga_write);
+EXPORT_SYMBOL(omap1510_fpga_init_irq);
diff -Nru a/arch/arm/mach-omap/gpio.c b/arch/arm/mach-omap/gpio.c
--- a/arch/arm/mach-omap/gpio.c 2004-10-18 14:56:29 -07:00
+++ b/arch/arm/mach-omap/gpio.c 2004-10-18 14:56:29 -07:00
@@ -94,7 +94,7 @@
#define METHOD_GPIO_1610 2
#define METHOD_GPIO_730 3
-#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912)
+#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912)
static struct gpio_bank gpio_bank_1610[5] = {
{ OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO},
{ OMAP1610_GPIO1_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_1610 },
@@ -113,7 +113,7 @@
#ifdef CONFIG_ARCH_OMAP730
static struct gpio_bank gpio_bank_730[7] = {
- { OMAP_MPUIO_BASE, INT_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO },
+ { OMAP_MPUIO_BASE, INT_730_MPUIO, IH_MPUIO_BASE, METHOD_MPUIO },
{ OMAP730_GPIO1_BASE, INT_GPIO_BANK1, IH_GPIO_BASE, METHOD_GPIO_730 },
{ OMAP730_GPIO2_BASE, INT_730_GPIO_BANK2, IH_GPIO_BASE + 32, METHOD_GPIO_730 },
{ OMAP730_GPIO3_BASE, INT_730_GPIO_BANK3, IH_GPIO_BASE + 64, METHOD_GPIO_730 },
@@ -135,8 +135,8 @@
return &gpio_bank[1];
}
#endif
-#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912)
- if (cpu_is_omap1610() || cpu_is_omap5912()) {
+#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912)
+ if (cpu_is_omap1610() || cpu_is_omap1710() || cpu_is_omap5912()) {
if (OMAP_GPIO_IS_MPUIO(gpio))
return &gpio_bank[0];
return &gpio_bank[1 + (gpio >> 4)];
@@ -172,8 +172,8 @@
if (cpu_is_omap1510() && gpio < 16)
return 0;
#endif
-#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912)
- if ((cpu_is_omap1610() || cpu_is_omap5912()) && gpio < 64)
+#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912)
+ if ((cpu_is_omap1610() || cpu_is_omap1710() || cpu_is_omap5912()) && gpio < 64)
return 0;
#endif
#ifdef CONFIG_ARCH_OMAP730
@@ -554,7 +554,7 @@
if (bank->method == METHOD_GPIO_1510)
isr_reg = bank->base + OMAP1510_GPIO_INT_STATUS;
#endif
-#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912)
+#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912)
if (bank->method == METHOD_GPIO_1610)
isr_reg = bank->base + OMAP1610_GPIO_IRQSTATUS1;
#endif
@@ -588,7 +588,7 @@
if (bank->method == METHOD_GPIO_1510)
__raw_writew(1 << (gpio & 0x0f), bank->base + OMAP1510_GPIO_INT_STATUS);
#endif
-#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912)
+#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912)
if (bank->method == METHOD_GPIO_1610)
__raw_writew(1 << (gpio & 0x0f), bank->base + OMAP1610_GPIO_IRQSTATUS1);
#endif
@@ -629,7 +629,7 @@
unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
struct gpio_bank *bank = get_gpio_bank(gpio);
- _set_gpio_irqenable(bank, gpio, 0);
+ _set_gpio_irqenable(bank, get_gpio_index(gpio), 0);
}
static void mpuio_unmask_irq(unsigned int irq)
@@ -637,7 +637,7 @@
unsigned int gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
struct gpio_bank *bank = get_gpio_bank(gpio);
- _set_gpio_irqenable(bank, gpio, 1);
+ _set_gpio_irqenable(bank, get_gpio_index(gpio), 1);
}
static struct irqchip gpio_irq_chip = {
@@ -668,8 +668,8 @@
gpio_bank = gpio_bank_1510;
}
#endif
-#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912)
- if (cpu_is_omap1610() || cpu_is_omap5912()) {
+#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912)
+ if (cpu_is_omap1610() || cpu_is_omap1710() || cpu_is_omap5912()) {
int rev;
gpio_bank_count = 5;
@@ -702,7 +702,7 @@
__raw_writew(0x0000, bank->base + OMAP1510_GPIO_INT_STATUS);
}
#endif
-#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912)
+#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710) || defined(CONFIG_ARCH_OMAP5912)
if (bank->method == METHOD_GPIO_1610) {
__raw_writew(0x0000, bank->base + OMAP1610_GPIO_IRQENABLE1);
__raw_writew(0xffff, bank->base + OMAP1610_GPIO_IRQSTATUS1);
@@ -731,7 +731,7 @@
/* Enable system clock for GPIO module.
* The CAM_CLK_CTRL *is* really the right place. */
- if (cpu_is_omap1610())
+ if (cpu_is_omap1610() || cpu_is_omap1710())
omap_writel(omap_readl(ULPD_CAM_CLK_CTRL) | 0x04, ULPD_CAM_CLK_CTRL);
return 0;
diff -Nru a/arch/arm/mach-omap/irq.c b/arch/arm/mach-omap/irq.c
--- a/arch/arm/mach-omap/irq.c 2004-10-18 14:56:13 -07:00
+++ b/arch/arm/mach-omap/irq.c 2004-10-18 14:56:13 -07:00
@@ -140,7 +140,9 @@
};
#endif
-#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912)
+#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) \
+ || defined(CONFIG_ARCH_OMAP1710)
+
static struct omap_irq_bank omap1610_irq_banks[] = {
{ .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3fefe8f },
{ .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfffff7ff },
@@ -171,8 +173,9 @@
irq_bank_count = ARRAY_SIZE(omap1510_irq_banks);
}
#endif
-#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912)
- if (cpu_is_omap1610() || cpu_is_omap5912()) {
+#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP5912) \
+ || defined(CONFIG_ARCH_OMAP1710)
+ if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap1710()) {
irq_banks = omap1610_irq_banks;
irq_bank_count = ARRAY_SIZE(omap1610_irq_banks);
}
@@ -190,6 +193,11 @@
irq_bank_writel(0x03, 0, IRQ_CONTROL_REG_OFFSET);
irq_bank_writel(0x03, 1, IRQ_CONTROL_REG_OFFSET);
+ /* Enable interrupts in global mask */
+ if (cpu_is_omap730()) {
+ irq_bank_writel(0x0, 0, IRQ_GMR_REG_OFFSET);
+ }
+
/* Install the interrupt handlers for each bank */
for (i = 0; i < irq_bank_count; i++) {
for (j = i * 32; j < (i + 1) * 32; j++) {
@@ -205,5 +213,9 @@
}
/* Unmask level 2 handler */
- omap_unmask_irq(INT_IH2_IRQ);
+ if (cpu_is_omap730()) {
+ omap_unmask_irq(INT_730_IH2_IRQ);
+ } else {
+ omap_unmask_irq(INT_IH2_IRQ);
+ }
}
diff -Nru a/arch/arm/mach-omap/leds-h2p2-debug.c b/arch/arm/mach-omap/leds-h2p2-debug.c
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/arch/arm/mach-omap/leds-h2p2-debug.c 2004-10-18 14:56:49 -07:00
@@ -0,0 +1,104 @@
+/*
+ * linux/arch/arm/mach-omap/leds-h2p2-debug.c
+ *
+ * Copyright 2003 by Texas Instruments Incorporated
+ *
+ */
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#include "leds.h"
+
+void h2p2_dbg_leds_event(led_event_t evt)
+{
+ unsigned long flags;
+ static unsigned long hw_led_state = 0;
+
+ local_irq_save(flags);
+
+ switch (evt) {
+ case led_start:
+ hw_led_state |= H2P2_DBG_FPGA_LED_STARTSTOP;
+ break;
+
+ case led_stop:
+ hw_led_state &= ~H2P2_DBG_FPGA_LED_STARTSTOP;
+ break;
+
+ case led_claim:
+ hw_led_state |= H2P2_DBG_FPGA_LED_CLAIMRELEASE;
+ break;
+
+ case led_release:
+ hw_led_state &= ~H2P2_DBG_FPGA_LED_CLAIMRELEASE;
+ break;
+
+#ifdef CONFIG_LEDS_TIMER
+ case led_timer:
+ /*
+ * Toggle Timer LED
+ */
+ if (hw_led_state & H2P2_DBG_FPGA_LED_TIMER)
+ hw_led_state &= ~H2P2_DBG_FPGA_LED_TIMER;
+ else
+ hw_led_state |= H2P2_DBG_FPGA_LED_TIMER;
+ break;
+#endif
+
+#ifdef CONFIG_LEDS_CPU
+ case led_idle_start:
+ hw_led_state |= H2P2_DBG_FPGA_LED_IDLE;
+ break;
+
+ case led_idle_end:
+ hw_led_state &= ~H2P2_DBG_FPGA_LED_IDLE;
+ break;
+#endif
+
+ case led_halted:
+ if (hw_led_state & H2P2_DBG_FPGA_LED_HALTED)
+ hw_led_state &= ~H2P2_DBG_FPGA_LED_HALTED;
+ else
+ hw_led_state |= H2P2_DBG_FPGA_LED_HALTED;
+ break;
+
+ case led_green_on:
+ break;
+
+ case led_green_off:
+ break;
+
+ case led_amber_on:
+ break;
+
+ case led_amber_off:
+ break;
+
+ case led_red_on:
+ break;
+
+ case led_red_off:
+ break;
+
+ default:
+ break;
+ }
+
+
+ /*
+ * Actually burn the LEDs
+ */
+ __raw_writew(~hw_led_state & 0xffff, H2P2_DBG_FPGA_LEDS);
+
+ local_irq_restore(flags);
+}
diff -Nru a/arch/arm/mach-omap/leds-perseus2.c b/arch/arm/mach-omap/leds-perseus2.c
--- a/arch/arm/mach-omap/leds-perseus2.c 2004-10-18 14:56:49 -07:00
+++ /dev/null Wed Dec 31 16:00:00 196900
@@ -1,102 +0,0 @@
-/*
- * linux/arch/arm/mach-omap/leds-perseus2.c
- *
- * Copyright 2003 by Texas Instruments Incorporated
- *
- */
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-
-#include "leds.h"
-
-void perseus2_leds_event(led_event_t evt)
-{
- unsigned long flags;
- static unsigned long hw_led_state = 0;
-
- local_irq_save(flags);
-
- switch (evt) {
- case led_start:
- hw_led_state |= OMAP730_FPGA_LED_STARTSTOP;
- break;
-
- case led_stop:
- hw_led_state &= ~OMAP730_FPGA_LED_STARTSTOP;
- break;
-
- case led_claim:
- hw_led_state |= OMAP730_FPGA_LED_CLAIMRELEASE;
- break;
-
- case led_release:
- hw_led_state &= ~OMAP730_FPGA_LED_CLAIMRELEASE;
- break;
-
-#ifdef CONFIG_LEDS_TIMER
- case led_timer:
- /*
- * Toggle Timer LED
- */
- if (hw_led_state & OMAP730_FPGA_LED_TIMER)
- hw_led_state &= ~OMAP730_FPGA_LED_TIMER;
- else
- hw_led_state |= OMAP730_FPGA_LED_TIMER;
- break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
- case led_idle_start:
- hw_led_state |= OMAP730_FPGA_LED_IDLE;
- break;
-
- case led_idle_end:
- hw_led_state &= ~OMAP730_FPGA_LED_IDLE;
- break;
-#endif
-
- case led_halted:
- if (hw_led_state & OMAP730_FPGA_LED_HALTED)
- hw_led_state &= ~OMAP730_FPGA_LED_HALTED;
- else
- hw_led_state |= OMAP730_FPGA_LED_HALTED;
- break;
-
- case led_green_on:
- break;
-
- case led_green_off:
- break;
-
- case led_amber_on:
- break;
-
- case led_amber_off:
- break;
-
- case led_red_on:
- break;
-
- case led_red_off:
- break;
-
- default:
- break;
- }
-
-
- /*
- * Actually burn the LEDs
- */
- __raw_writew(~hw_led_state & 0xffff, OMAP730_FPGA_LEDS);
-
- local_irq_restore(flags);
-}
diff -Nru a/arch/arm/mach-omap/leds.c b/arch/arm/mach-omap/leds.c
--- a/arch/arm/mach-omap/leds.c 2004-10-18 14:56:50 -07:00
+++ b/arch/arm/mach-omap/leds.c 2004-10-18 14:56:50 -07:00
@@ -3,6 +3,7 @@
*
* OMAP LEDs dispatcher
*/
+#include
#include
#include
@@ -11,17 +12,17 @@
#include "leds.h"
static int __init
-omap1510_leds_init(void)
+omap_leds_init(void)
{
if (machine_is_omap_innovator())
leds_event = innovator_leds_event;
- else if (machine_is_omap_perseus2()) {
- leds_event = perseus2_leds_event;
+ else if (machine_is_omap_h2() || machine_is_omap_perseus2()) {
+ leds_event = h2p2_dbg_leds_event;
}
leds_event(led_start);
return 0;
}
-__initcall(omap1510_leds_init);
+__initcall(omap_leds_init);
diff -Nru a/arch/arm/mach-omap/leds.h b/arch/arm/mach-omap/leds.h
--- a/arch/arm/mach-omap/leds.h 2004-10-18 14:57:05 -07:00
+++ b/arch/arm/mach-omap/leds.h 2004-10-18 14:57:05 -07:00
@@ -1,2 +1,2 @@
extern void innovator_leds_event(led_event_t evt);
-extern void perseus2_leds_event(led_event_t evt);
+extern void h2p2_dbg_leds_event(led_event_t evt);
diff -Nru a/arch/arm/mach-omap/mcbsp.c b/arch/arm/mach-omap/mcbsp.c
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/arch/arm/mach-omap/mcbsp.c 2004-10-18 14:57:23 -07:00
@@ -0,0 +1,669 @@
+/*
+ * linux/arch/arm/omap/mcbsp.c
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Author: Samuel Ortiz
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Multichannel mode not supported.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#ifdef CONFIG_MCBSP_DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...) do { } while (0)
+#endif
+
+struct omap_mcbsp {
+ u32 io_base;
+ u8 id;
+ u8 free;
+ omap_mcbsp_word_length rx_word_length;
+ omap_mcbsp_word_length tx_word_length;
+
+ /* IRQ based TX/RX */
+ int rx_irq;
+ int tx_irq;
+
+ /* DMA stuff */
+ u8 dma_rx_sync;
+ short dma_rx_lch;
+ u8 dma_tx_sync;
+ short dma_tx_lch;
+
+ /* Completion queues */
+ struct completion tx_irq_completion;
+ struct completion rx_irq_completion;
+ struct completion tx_dma_completion;
+ struct completion rx_dma_completion;
+
+ spinlock_t lock;
+};
+
+static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT];
+
+
+static void omap_mcbsp_dump_reg(u8 id)
+{
+ DBG("**** MCBSP%d regs ****\n", mcbsp[id].id);
+ DBG("DRR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR2));
+ DBG("DRR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DRR1));
+ DBG("DXR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR2));
+ DBG("DXR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, DXR1));
+ DBG("SPCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR2));
+ DBG("SPCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SPCR1));
+ DBG("RCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR2));
+ DBG("RCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, RCR1));
+ DBG("XCR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR2));
+ DBG("XCR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, XCR1));
+ DBG("SRGR2: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR2));
+ DBG("SRGR1: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, SRGR1));
+ DBG("PCR0: 0x%04x\n", OMAP_MCBSP_READ(mcbsp[id].io_base, PCR0));
+ DBG("***********************\n");
+}
+
+
+static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id);
+
+ DBG("TX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2));
+
+ complete(&mcbsp_tx->tx_irq_completion);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct omap_mcbsp * mcbsp_rx = (struct omap_mcbsp *)(dev_id);
+
+ DBG("RX IRQ callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2));
+
+ complete(&mcbsp_rx->rx_irq_completion);
+ return IRQ_HANDLED;
+}
+
+
+static void omap_mcbsp_tx_dma_callback(int lch, u16 ch_status, void *data)
+{
+ struct omap_mcbsp * mcbsp_dma_tx = (struct omap_mcbsp *)(data);
+
+ DBG("TX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_tx->io_base, SPCR2));
+
+ /* We can free the channels */
+ omap_free_dma(mcbsp_dma_tx->dma_tx_lch);
+ mcbsp_dma_tx->dma_tx_lch = -1;
+
+ complete(&mcbsp_dma_tx->tx_dma_completion);
+}
+
+static void omap_mcbsp_rx_dma_callback(int lch, u16 ch_status, void *data)
+{
+ struct omap_mcbsp * mcbsp_dma_rx = (struct omap_mcbsp *)(data);
+
+ DBG("RX DMA callback : 0x%x\n", OMAP_MCBSP_READ(mcbsp_dma_rx->io_base, SPCR2));
+
+ /* We can free the channels */
+ omap_free_dma(mcbsp_dma_rx->dma_rx_lch);
+ mcbsp_dma_rx->dma_rx_lch = -1;
+
+ complete(&mcbsp_dma_rx->rx_dma_completion);
+}
+
+
+/*
+ * omap_mcbsp_config simply write a config to the
+ * appropriate McBSP.
+ * You either call this function or set the McBSP registers
+ * by yourself before calling omap_mcbsp_start().
+ */
+
+void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config)
+{
+ u32 io_base = mcbsp[id].io_base;
+
+ DBG("OMAP-McBSP: McBSP%d io_base: 0x%8x\n", id+1, io_base);
+
+ /* We write the given config */
+ OMAP_MCBSP_WRITE(io_base, SPCR2, config->spcr2);
+ OMAP_MCBSP_WRITE(io_base, SPCR1, config->spcr1);
+ OMAP_MCBSP_WRITE(io_base, RCR2, config->rcr2);
+ OMAP_MCBSP_WRITE(io_base, RCR1, config->rcr1);
+ OMAP_MCBSP_WRITE(io_base, XCR2, config->xcr2);
+ OMAP_MCBSP_WRITE(io_base, XCR1, config->xcr1);
+ OMAP_MCBSP_WRITE(io_base, SRGR2, config->srgr2);
+ OMAP_MCBSP_WRITE(io_base, SRGR1, config->srgr1);
+ OMAP_MCBSP_WRITE(io_base, SRGR2, config->mcr2);
+ OMAP_MCBSP_WRITE(io_base, SRGR1, config->mcr1);
+ OMAP_MCBSP_WRITE(io_base, PCR0, config->pcr0);
+}
+
+
+
+static int omap_mcbsp_check(unsigned int id)
+{
+ if (cpu_is_omap730()) {
+ if (id > OMAP_MAX_MCBSP_COUNT - 1) {
+ printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
+ return -1;
+ }
+ return 0;
+ }
+
+ if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) {
+ if (id > OMAP_MAX_MCBSP_COUNT) {
+ printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
+ return -1;
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
+#define DSP_RSTCT2 0xe1008014
+
+static void omap_mcbsp_dsp_request(void)
+{
+ if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) {
+ omap_writew((omap_readw(ARM_RSTCT1) | (1 << 1) | (1 << 2)),
+ ARM_RSTCT1);
+ omap_writew((omap_readw(ARM_CKCTL) | 1 << EN_DSPCK),
+ ARM_CKCTL);
+ omap_writew((omap_readw(ARM_IDLECT2) | (1 << EN_APICK)),
+ ARM_IDLECT2);
+
+ /* enable 12MHz clock to mcbsp 1 & 3 */
+ __raw_writew(__raw_readw(DSP_IDLECT2) | (1 << EN_XORPCK),
+ DSP_IDLECT2);
+ __raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1,
+ DSP_RSTCT2);
+ }
+}
+
+static void omap_mcbsp_dsp_free(void)
+{
+ /* Useless for now */
+}
+
+
+int omap_mcbsp_request(unsigned int id)
+{
+ int err;
+
+ if (omap_mcbsp_check(id) < 0)
+ return -EINVAL;
+
+ /*
+ * On 1510, 1610 and 1710, McBSP1 and McBSP3
+ * are DSP public peripherals.
+ */
+ if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)
+ omap_mcbsp_dsp_request();
+
+ spin_lock(&mcbsp[id].lock);
+ if (!mcbsp[id].free) {
+ printk (KERN_ERR "OMAP-McBSP: McBSP%d is currently in use\n", id + 1);
+ spin_unlock(&mcbsp[id].lock);
+ return -1;
+ }
+
+ mcbsp[id].free = 0;
+ spin_unlock(&mcbsp[id].lock);
+
+ /* We need to get IRQs here */
+ err = request_irq(mcbsp[id].tx_irq, omap_mcbsp_tx_irq_handler, 0,
+ "McBSP",
+ (void *) (&mcbsp[id]));
+ if (err != 0) {
+ printk(KERN_ERR "OMAP-McBSP: Unable to request TX IRQ %d for McBSP%d\n",
+ mcbsp[id].tx_irq, mcbsp[id].id);
+ return err;
+ }
+
+ init_completion(&(mcbsp[id].tx_irq_completion));
+
+
+ err = request_irq(mcbsp[id].rx_irq, omap_mcbsp_rx_irq_handler, 0,
+ "McBSP",
+ (void *) (&mcbsp[id]));
+ if (err != 0) {
+ printk(KERN_ERR "OMAP-McBSP: Unable to request RX IRQ %d for McBSP%d\n",
+ mcbsp[id].rx_irq, mcbsp[id].id);
+ free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
+ return err;
+ }
+
+ init_completion(&(mcbsp[id].rx_irq_completion));
+ return 0;
+
+}
+
+void omap_mcbsp_free(unsigned int id)
+{
+ if (omap_mcbsp_check(id) < 0)
+ return;
+
+ if (id == OMAP_MCBSP1 || id == OMAP_MCBSP3)
+ omap_mcbsp_dsp_free();
+
+ spin_lock(&mcbsp[id].lock);
+ if (mcbsp[id].free) {
+ printk (KERN_ERR "OMAP-McBSP: McBSP%d was not reserved\n", id + 1);
+ spin_unlock(&mcbsp[id].lock);
+ return;
+ }
+
+ mcbsp[id].free = 1;
+ spin_unlock(&mcbsp[id].lock);
+
+ /* Free IRQs */
+ free_irq(mcbsp[id].rx_irq, (void *) (&mcbsp[id]));
+ free_irq(mcbsp[id].tx_irq, (void *) (&mcbsp[id]));
+}
+
+/*
+ * Here we start the McBSP, by enabling the sample
+ * generator, both transmitter and receivers,
+ * and the frame sync.
+ */
+void omap_mcbsp_start(unsigned int id)
+{
+ u32 io_base;
+ u16 w;
+
+ if (omap_mcbsp_check(id) < 0)
+ return;
+
+ io_base = mcbsp[id].io_base;
+
+ mcbsp[id].rx_word_length = ((OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7);
+ mcbsp[id].tx_word_length = ((OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7);
+
+ /* Start the sample generator */
+ w = OMAP_MCBSP_READ(io_base, SPCR2);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));
+
+ /* Enable transmitter and receiver */
+ w = OMAP_MCBSP_READ(io_base, SPCR2);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1);
+
+ w = OMAP_MCBSP_READ(io_base, SPCR1);
+ OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1);
+
+ udelay(100);
+
+ /* Start frame sync */
+ w = OMAP_MCBSP_READ(io_base, SPCR2);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));
+
+ /* Dump McBSP Regs */
+ omap_mcbsp_dump_reg(id);
+
+}
+
+void omap_mcbsp_stop(unsigned int id)
+{
+ u32 io_base;
+ u16 w;
+
+ if (omap_mcbsp_check(id) < 0)
+ return;
+
+ io_base = mcbsp[id].io_base;
+
+ /* Reset transmitter */
+ w = OMAP_MCBSP_READ(io_base, SPCR2);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1));
+
+ /* Reset receiver */
+ w = OMAP_MCBSP_READ(io_base, SPCR1);
+ OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1));
+
+ /* Reset the sample rate generator */
+ w = OMAP_MCBSP_READ(io_base, SPCR2);
+ OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));
+}
+
+
+/*
+ * IRQ based word transmission.
+ */
+void omap_mcbsp_xmit_word(unsigned int id, u32 word)
+{
+ u32 io_base;
+ omap_mcbsp_word_length word_length = mcbsp[id].tx_word_length;
+
+ if (omap_mcbsp_check(id) < 0)
+ return;
+
+ io_base = mcbsp[id].io_base;
+
+ wait_for_completion(&(mcbsp[id].tx_irq_completion));
+
+ if (word_length > OMAP_MCBSP_WORD_16)
+ OMAP_MCBSP_WRITE(io_base, DXR2, word >> 16);
+ OMAP_MCBSP_WRITE(io_base, DXR1, word & 0xffff);
+}
+
+u32 omap_mcbsp_recv_word(unsigned int id)
+{
+ u32 io_base;
+ u16 word_lsb, word_msb = 0;
+ omap_mcbsp_word_length word_length = mcbsp[id].rx_word_length;
+
+ if (omap_mcbsp_check(id) < 0)
+ return -EINVAL;
+
+ io_base = mcbsp[id].io_base;
+
+ wait_for_completion(&(mcbsp[id].rx_irq_completion));
+
+ if (word_length > OMAP_MCBSP_WORD_16)
+ word_msb = OMAP_MCBSP_READ(io_base, DRR2);
+ word_lsb = OMAP_MCBSP_READ(io_base, DRR1);
+
+ return (word_lsb | (word_msb << 16));
+}
+
+
+/*
+ * Simple DMA based buffer rx/tx routines.
+ * Nothing fancy, just a single buffer tx/rx through DMA.
+ * The DMA resources are released once the transfer is done.
+ * For anything fancier, you should use your own customized DMA
+ * routines and callbacks.
+ */
+int omap_mcbsp_xmit_buffer(unsigned int id, dma_addr_t buffer, unsigned int length)
+{
+ int dma_tx_ch;
+
+ if (omap_mcbsp_check(id) < 0)
+ return -EINVAL;
+
+ if (omap_request_dma(mcbsp[id].dma_tx_sync, "McBSP TX", omap_mcbsp_tx_dma_callback,
+ &mcbsp[id],
+ &dma_tx_ch)) {
+ printk("OMAP-McBSP: Unable to request DMA channel for McBSP%d TX. Trying IRQ based TX\n", id+1);
+ return -EAGAIN;
+ }
+ mcbsp[id].dma_tx_lch = dma_tx_ch;
+
+ DBG("TX DMA on channel %d\n", dma_tx_ch);
+
+ init_completion(&(mcbsp[id].tx_dma_completion));
+
+ omap_set_dma_transfer_params(mcbsp[id].dma_tx_lch,
+ OMAP_DMA_DATA_TYPE_S16,
+ length >> 1, 1,
+ OMAP_DMA_SYNC_ELEMENT);
+
+ omap_set_dma_dest_params(mcbsp[id].dma_tx_lch,
+ OMAP_DMA_PORT_TIPB,
+ OMAP_DMA_AMODE_CONSTANT,
+ mcbsp[id].io_base + OMAP_MCBSP_REG_DXR1);
+
+ omap_set_dma_src_params(mcbsp[id].dma_tx_lch,
+ OMAP_DMA_PORT_EMIFF,
+ OMAP_DMA_AMODE_POST_INC,
+ buffer);
+
+ omap_start_dma(mcbsp[id].dma_tx_lch);
+ wait_for_completion(&(mcbsp[id].tx_dma_completion));
+ return 0;
+}
+
+
+int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length)
+{
+ int dma_rx_ch;
+
+ if (omap_mcbsp_check(id) < 0)
+ return -EINVAL;
+
+ if (omap_request_dma(mcbsp[id].dma_rx_sync, "McBSP RX", omap_mcbsp_rx_dma_callback,
+ &mcbsp[id],
+ &dma_rx_ch)) {
+ printk("Unable to request DMA channel for McBSP%d RX. Trying IRQ based RX\n", id+1);
+ return -EAGAIN;
+ }
+ mcbsp[id].dma_rx_lch = dma_rx_ch;
+
+ DBG("RX DMA on channel %d\n", dma_rx_ch);
+
+ init_completion(&(mcbsp[id].rx_dma_completion));
+
+ omap_set_dma_transfer_params(mcbsp[id].dma_rx_lch,
+ OMAP_DMA_DATA_TYPE_S16,
+ length >> 1, 1,
+ OMAP_DMA_SYNC_ELEMENT);
+
+ omap_set_dma_src_params(mcbsp[id].dma_rx_lch,
+ OMAP_DMA_PORT_TIPB,
+ OMAP_DMA_AMODE_CONSTANT,
+ mcbsp[id].io_base + OMAP_MCBSP_REG_DRR1);
+
+ omap_set_dma_dest_params(mcbsp[id].dma_rx_lch,
+ OMAP_DMA_PORT_EMIFF,
+ OMAP_DMA_AMODE_POST_INC,
+ buffer);
+
+ omap_start_dma(mcbsp[id].dma_rx_lch);
+ wait_for_completion(&(mcbsp[id].rx_dma_completion));
+ return 0;
+}
+
+
+/*
+ * SPI wrapper.
+ * Since SPI setup is much simpler than the generic McBSP one,
+ * this wrapper just need an omap_mcbsp_spi_cfg structure as an input.
+ * Once this is done, you can call omap_mcbsp_start().
+ */
+void omap_mcbsp_set_spi_mode(unsigned int id, const struct omap_mcbsp_spi_cfg * spi_cfg)
+{
+ struct omap_mcbsp_reg_cfg mcbsp_cfg;
+
+ if (omap_mcbsp_check(id) < 0)
+ return;
+
+ memset(&mcbsp_cfg, 0, sizeof(struct omap_mcbsp_reg_cfg));
+
+ /* SPI has only one frame */
+ mcbsp_cfg.rcr1 |= (RWDLEN1(spi_cfg->word_length) | RFRLEN1(0));
+ mcbsp_cfg.xcr1 |= (XWDLEN1(spi_cfg->word_length) | XFRLEN1(0));
+
+ /* Clock stop mode */
+ if (spi_cfg->clk_stp_mode == OMAP_MCBSP_CLK_STP_MODE_NO_DELAY)
+ mcbsp_cfg.spcr1 |= (1 << 12);
+ else
+ mcbsp_cfg.spcr1 |= (3 << 11);
+
+ /* Set clock parities */
+ if (spi_cfg->rx_clock_polarity == OMAP_MCBSP_CLK_RISING)
+ mcbsp_cfg.pcr0 |= CLKRP;
+ else
+ mcbsp_cfg.pcr0 &= ~CLKRP;
+
+ if (spi_cfg->tx_clock_polarity == OMAP_MCBSP_CLK_RISING)
+ mcbsp_cfg.pcr0 &= ~CLKXP;
+ else
+ mcbsp_cfg.pcr0 |= CLKXP;
+
+ /* Set SCLKME to 0 and CLKSM to 1 */
+ mcbsp_cfg.pcr0 &= ~SCLKME;
+ mcbsp_cfg.srgr2 |= CLKSM;
+
+ /* Set FSXP */
+ if (spi_cfg->fsx_polarity == OMAP_MCBSP_FS_ACTIVE_HIGH)
+ mcbsp_cfg.pcr0 &= ~FSXP;
+ else
+ mcbsp_cfg.pcr0 |= FSXP;
+
+ if (spi_cfg->spi_mode == OMAP_MCBSP_SPI_MASTER) {
+ mcbsp_cfg.pcr0 |= CLKXM;
+ mcbsp_cfg.srgr1 |= CLKGDV(spi_cfg->clk_div -1);
+ mcbsp_cfg.pcr0 |= FSXM;
+ mcbsp_cfg.srgr2 &= ~FSGM;
+ mcbsp_cfg.xcr2 |= XDATDLY(1);
+ mcbsp_cfg.rcr2 |= RDATDLY(1);
+ }
+ else {
+ mcbsp_cfg.pcr0 &= ~CLKXM;
+ mcbsp_cfg.srgr1 |= CLKGDV(1);
+ mcbsp_cfg.pcr0 &= ~FSXM;
+ mcbsp_cfg.xcr2 &= ~XDATDLY(3);
+ mcbsp_cfg.rcr2 &= ~RDATDLY(3);
+ }
+
+ mcbsp_cfg.xcr2 &= ~XPHASE;
+ mcbsp_cfg.rcr2 &= ~RPHASE;
+
+ omap_mcbsp_config(id, &mcbsp_cfg);
+}
+
+
+/*
+ * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
+ * 730 has only 2 McBSP, and both of them are MPU peripherals.
+ */
+struct omap_mcbsp_info {
+ u32 virt_base;
+ u8 dma_rx_sync, dma_tx_sync;
+ u16 rx_irq, tx_irq;
+};
+
+#ifdef CONFIG_ARCH_OMAP730
+static const struct omap_mcbsp_info mcbsp_730[] = {
+ [0] = { .virt_base = io_p2v(OMAP730_MCBSP1_BASE),
+ .dma_rx_sync = OMAP_DMA_MCBSP1_RX,
+ .dma_tx_sync = OMAP_DMA_MCBSP1_TX,
+ .rx_irq = INT_730_McBSP1RX,
+ .tx_irq = INT_730_McBSP1TX },
+ [1] = { .virt_base = io_p2v(OMAP730_MCBSP2_BASE),
+ .dma_rx_sync = OMAP_DMA_MCBSP3_RX,
+ .dma_tx_sync = OMAP_DMA_MCBSP3_TX,
+ .rx_irq = INT_730_McBSP2RX,
+ .tx_irq = INT_730_McBSP2TX },
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP1510
+static const struct omap_mcbsp_info mcbsp_1510[] = {
+ [0] = { .virt_base = OMAP1510_MCBSP1_BASE,
+ .dma_rx_sync = OMAP_DMA_MCBSP1_RX,
+ .dma_tx_sync = OMAP_DMA_MCBSP1_TX,
+ .rx_irq = INT_McBSP1RX,
+ .tx_irq = INT_McBSP1TX },
+ [1] = { .virt_base = io_p2v(OMAP1510_MCBSP2_BASE),
+ .dma_rx_sync = OMAP_DMA_MCBSP2_RX,
+ .dma_tx_sync = OMAP_DMA_MCBSP2_TX,
+ .rx_irq = INT_1510_SPI_RX,
+ .tx_irq = INT_1510_SPI_TX },
+ [2] = { .virt_base = OMAP1510_MCBSP3_BASE,
+ .dma_rx_sync = OMAP_DMA_MCBSP3_RX,
+ .dma_tx_sync = OMAP_DMA_MCBSP3_TX,
+ .rx_irq = INT_McBSP3RX,
+ .tx_irq = INT_McBSP3TX },
+};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710)
+static const struct omap_mcbsp_info mcbsp_1610[] = {
+ [0] = { .virt_base = OMAP1610_MCBSP1_BASE,
+ .dma_rx_sync = OMAP_DMA_MCBSP1_RX,
+ .dma_tx_sync = OMAP_DMA_MCBSP1_TX,
+ .rx_irq = INT_McBSP1RX,
+ .tx_irq = INT_McBSP1TX },
+ [1] = { .virt_base = io_p2v(OMAP1610_MCBSP2_BASE),
+ .dma_rx_sync = OMAP_DMA_MCBSP2_RX,
+ .dma_tx_sync = OMAP_DMA_MCBSP2_TX,
+ .rx_irq = INT_1610_McBSP2_RX,
+ .tx_irq = INT_1610_McBSP2_TX },
+ [2] = { .virt_base = OMAP1610_MCBSP3_BASE,
+ .dma_rx_sync = OMAP_DMA_MCBSP3_RX,
+ .dma_tx_sync = OMAP_DMA_MCBSP3_TX,
+ .rx_irq = INT_McBSP3RX,
+ .tx_irq = INT_McBSP3TX },
+};
+#endif
+
+static int __init omap_mcbsp_init(void)
+{
+ int mcbsp_count = 0, i;
+ static const struct omap_mcbsp_info *mcbsp_info;
+
+ printk("Initializing OMAP McBSP system\n");
+#ifdef CONFIG_ARCH_OMAP730
+ if (cpu_is_omap730()) {
+ mcbsp_info = mcbsp_730;
+ mcbsp_count = ARRAY_SIZE(mcbsp_730);
+ }
+#endif
+#ifdef CONFIG_ARCH_OMAP1510
+ if (cpu_is_omap1510()) {
+ mcbsp_info = mcbsp_1510;
+ mcbsp_count = ARRAY_SIZE(mcbsp_1510);
+ }
+#endif
+#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710)
+ if (cpu_is_omap1610() || cpu_is_omap1710()) {
+ mcbsp_info = mcbsp_1610;
+ mcbsp_count = ARRAY_SIZE(mcbsp_1610);
+ }
+#endif
+ for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) {
+ if (i >= mcbsp_count) {
+ mcbsp[i].io_base = 0;
+ mcbsp[i].free = 0;
+ continue;
+ }
+ mcbsp[i].id = i + 1;
+ mcbsp[i].free = 1;
+ mcbsp[i].dma_tx_lch = -1;
+ mcbsp[i].dma_rx_lch = -1;
+
+ mcbsp[i].io_base = mcbsp_info[i].virt_base;
+ mcbsp[i].tx_irq = mcbsp_info[i].tx_irq;
+ mcbsp[i].rx_irq = mcbsp_info[i].rx_irq;
+ mcbsp[i].dma_rx_sync = mcbsp_info[i].dma_rx_sync;
+ mcbsp[i].dma_tx_sync = mcbsp_info[i].dma_tx_sync;
+ spin_lock_init(&mcbsp[i].lock);
+ }
+
+ return 0;
+}
+
+
+arch_initcall(omap_mcbsp_init);
+
+EXPORT_SYMBOL(omap_mcbsp_config);
+EXPORT_SYMBOL(omap_mcbsp_request);
+EXPORT_SYMBOL(omap_mcbsp_free);
+EXPORT_SYMBOL(omap_mcbsp_start);
+EXPORT_SYMBOL(omap_mcbsp_stop);
+EXPORT_SYMBOL(omap_mcbsp_xmit_word);
+EXPORT_SYMBOL(omap_mcbsp_recv_word);
+EXPORT_SYMBOL(omap_mcbsp_xmit_buffer);
+EXPORT_SYMBOL(omap_mcbsp_recv_buffer);
+EXPORT_SYMBOL(omap_mcbsp_set_spi_mode);
diff -Nru a/arch/arm/mach-omap/ocpi.c b/arch/arm/mach-omap/ocpi.c
--- a/arch/arm/mach-omap/ocpi.c 2004-10-18 14:57:04 -07:00
+++ b/arch/arm/mach-omap/ocpi.c 2004-10-18 14:57:04 -07:00
@@ -59,8 +59,8 @@
/* Make sure there's clock for OCPI */
-#ifdef CONFIG_ARCH_OMAP1610
- if (cpu_is_omap1610()) {
+#if defined(CONFIG_ARCH_OMAP1610) || defined(CONFIG_ARCH_OMAP1710)
+ if (cpu_is_omap1610() || cpu_is_omap1710()) {
val = omap_readl(OMAP1610_ARM_IDLECT3);
val |= EN_OCPI_CK;
val &= ~IDLOCPI_ARM;
diff -Nru a/arch/arm/mach-omap/usb.c b/arch/arm/mach-omap/usb.c
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/arch/arm/mach-omap/usb.c 2004-10-18 14:57:24 -07:00
@@ -0,0 +1,541 @@
+/*
+ * arch/arm/mach-omap/usb.c -- platform level USB initialization
+ *
+ * Copyright (C) 2004 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#undef DEBUG
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+/* These routines should handle the standard chip-specific modes
+ * for usb0/1/2 ports, covering basic mux and transceiver setup.
+ * Call omap_usb_init() once, from INIT_MACHINE().
+ *
+ * Some board-*.c files will need to set up additional mux options,
+ * like for suspend handling, vbus sensing, GPIOs, and the D+ pullup.
+ */
+
+/* TESTED ON:
+ * - 1611B H2 (with usb1 mini-AB)
+ * - 1510 Innovator with built-in transceiver (custom cable feeding 5V VBUS)
+ * - 1710 custom development board using alternate pin group
+ */
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_ARCH_OMAP_OTG
+
+static struct otg_transceiver *xceiv;
+
+/**
+ * otg_get_transceiver - find the (single) OTG transceiver driver
+ *
+ * Returns the transceiver driver, after getting a refcount to it; or
+ * null if there is no such transceiver. The caller is responsible for
+ * releasing that count.
+ */
+struct otg_transceiver *otg_get_transceiver(void)
+{
+ if (xceiv)
+ get_device(xceiv->dev);
+ return xceiv;
+}
+EXPORT_SYMBOL(otg_get_transceiver);
+
+int otg_set_transceiver(struct otg_transceiver *x)
+{
+ if (xceiv && x)
+ return -EBUSY;
+ xceiv = x;
+ return 0;
+}
+EXPORT_SYMBOL(otg_set_transceiver);
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static u32 __init omap_usb0_init(unsigned nwires, unsigned is_device)
+{
+ u32 syscon1 = 0;
+
+ if (nwires == 0) {
+ USB_TRANSCEIVER_CTRL_REG &= ~(1 << 3);
+ return 0;
+ }
+
+ /*
+ * VP and VM are needed for all active usb0 configurations.
+ * USB0_VP and USB0_VM are always set on 1510, there's no muxing
+ * available for them.
+ */
+ if (nwires >= 2 && !cpu_is_omap1510()) {
+ omap_cfg_reg(AA9_USB0_VP);
+ omap_cfg_reg(R9_USB0_VM);
+ }
+
+ /* internal transceiver */
+ if (nwires == 2) {
+ if (cpu_is_omap1510()) {
+ /* This works for OHCI on 1510-Innovator, nothing to mux */
+ return 0;
+ }
+
+#if 0
+ /* NOTE: host OR device mode for now, no OTG */
+ USB_TRANSCEIVER_CTRL_REG &= ~(3 << 4);
+ if (is_device) {
+ omap_cfg_reg(W4_USB_PUEN);
+ omap_cfg_reg(R18_1510_USB_GPIO0);
+ // omap_cfg_reg(USB0_VBUS);
+ // omap_cfg_reg(USB0_PUEN);
+ // USB_TRANSCEIVER_CTRL_REG.CONF_USB0_PORT_R = 7
+ // when USB0_PUEN is needed
+ } else /* host mode needs D+ and D- pulldowns */
+ USB_TRANSCEIVER_CTRL_REG &= ~(3 << 1);
+ return 3 << 16;
+#else
+ /* FIXME: 1610 needs to return the right value here */
+ printk(KERN_ERR "usb0 internal transceiver, nyet\n");
+ return 0;
+#endif
+ }
+
+ /* alternate pin config, external transceiver */
+ omap_cfg_reg(V6_USB0_TXD);
+ omap_cfg_reg(W9_USB0_TXEN);
+ omap_cfg_reg(W5_USB0_SE0);
+
+#ifdef CONFIG_ARCH_OMAP_USB_SPEED
+ /* FIXME: there's good chance that pin V9 is used for MMC2 port cmddir */
+ omap_cfg_reg(V9_USB0_SPEED);
+ // omap_cfg_reg(V9_USB0_SUSP);
+#endif
+
+ if (nwires != 3)
+ omap_cfg_reg(Y5_USB0_RCV);
+
+ switch (nwires) {
+ case 3:
+ syscon1 = 2;
+ break;
+ case 4:
+ syscon1 = 1;
+ break;
+ case 6:
+ syscon1 = 3;
+ /* REVISIT: Is CONF_USB2_UNI_R only needed when nwires = 6? */
+ USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
+ break;
+ default:
+ printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
+ 0, nwires);
+ }
+ return syscon1 << 16;
+}
+
+static u32 __init omap_usb1_init(unsigned nwires)
+{
+ u32 syscon1 = 0;
+
+ if (nwires != 6)
+ USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB1_UNI_R;
+ if (nwires == 0)
+ return 0;
+
+ /* external transceiver */
+ omap_cfg_reg(USB1_TXD);
+ omap_cfg_reg(USB1_TXEN);
+ if (cpu_is_omap1510()) {
+ omap_cfg_reg(USB1_SEO);
+ omap_cfg_reg(USB1_SPEED);
+ // SUSP
+ } else if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap1710()) {
+ omap_cfg_reg(W13_1610_USB1_SE0);
+ omap_cfg_reg(R13_1610_USB1_SPEED);
+ // SUSP
+ } else {
+ pr_debug("usb unrecognized\n");
+ }
+ if (nwires != 3)
+ omap_cfg_reg(USB1_RCV);
+
+ switch (nwires) {
+ case 3:
+ syscon1 = 2;
+ break;
+ case 4:
+ syscon1 = 1;
+ break;
+ case 6:
+ syscon1 = 3;
+ omap_cfg_reg(USB1_VP);
+ omap_cfg_reg(USB1_VM);
+ USB_TRANSCEIVER_CTRL_REG |= CONF_USB1_UNI_R;
+ break;
+ default:
+ printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
+ 1, nwires);
+ }
+ return syscon1 << 20;
+}
+
+static u32 __init omap_usb2_init(unsigned nwires, unsigned alt_pingroup)
+{
+ u32 syscon1 = 0;
+
+ if (alt_pingroup)
+ return 0;
+ if (nwires != 6)
+ USB_TRANSCEIVER_CTRL_REG &= ~CONF_USB2_UNI_R;
+ if (nwires == 0)
+ return 0;
+
+ /* external transceiver */
+ if (cpu_is_omap1510()) {
+ omap_cfg_reg(USB2_TXD);
+ omap_cfg_reg(USB2_TXEN);
+ omap_cfg_reg(USB2_SEO);
+ if (nwires != 3)
+ omap_cfg_reg(USB2_RCV);
+ } else if (cpu_is_omap1610() || cpu_is_omap5912() || cpu_is_omap1710()) {
+ omap_cfg_reg(V6_USB2_TXD);
+ omap_cfg_reg(W9_USB2_TXEN);
+ omap_cfg_reg(W5_USB2_SE0);
+ if (nwires != 3)
+ omap_cfg_reg(Y5_USB2_RCV);
+ } else {
+ pr_debug("usb unrecognized\n");
+ }
+ // omap_cfg_reg(USB2_SUSP);
+ // FIXME omap_cfg_reg(USB2_SPEED);
+
+ switch (nwires) {
+ case 3:
+ syscon1 = 2;
+ break;
+ case 4:
+ syscon1 = 1;
+ break;
+ case 6:
+ syscon1 = 3;
+ if (cpu_is_omap1510()) {
+ omap_cfg_reg(USB2_VP);
+ omap_cfg_reg(USB2_VM);
+ } else {
+ omap_cfg_reg(AA9_USB2_VP);
+ omap_cfg_reg(R9_USB2_VM);
+ }
+ USB_TRANSCEIVER_CTRL_REG |= CONF_USB2_UNI_R;
+ break;
+ default:
+ printk(KERN_ERR "illegal usb%d %d-wire transceiver\n",
+ 2, nwires);
+ }
+ return syscon1 << 24;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#if defined(CONFIG_USB_GADGET_OMAP) || \
+ defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE) || \
+ (defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG))
+static void usb_release(struct device *dev)
+{
+ /* normally not freed */
+}
+#endif
+
+#ifdef CONFIG_USB_GADGET_OMAP
+
+static struct resource udc_resources[] = {
+ /* order is significant! */
+ { /* registers */
+ .start = IO_ADDRESS(UDC_BASE),
+ .end = IO_ADDRESS(UDC_BASE + 0xff),
+ .flags = IORESOURCE_MEM,
+ }, { /* general IRQ */
+ .start = IH2_BASE + 20,
+ .flags = IORESOURCE_IRQ,
+ }, { /* PIO IRQ */
+ .start = IH2_BASE + 30,
+ .flags = IORESOURCE_IRQ,
+ }, { /* SOF IRQ */
+ .start = IH2_BASE + 29,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 udc_dmamask = ~(u32)0;
+
+static struct platform_device udc_device = {
+ .name = "omap_udc",
+ .id = -1,
+ .dev = {
+ .release = usb_release,
+ .dma_mask = &udc_dmamask,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(udc_resources),
+ .resource = udc_resources,
+};
+
+#endif
+
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+
+/* The dmamask must be set for OHCI to work */
+static u64 ohci_dmamask = ~(u32)0;
+
+static struct resource ohci_resources[] = {
+ {
+ .start = IO_ADDRESS(OMAP_OHCI_BASE),
+ .end = IO_ADDRESS(OMAP_OHCI_BASE + 4096),
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = INT_USB_HHC_1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device ohci_device = {
+ .name = "ohci",
+ .id = -1,
+ .dev = {
+ .release = usb_release,
+ .dma_mask = &ohci_dmamask,
+ .coherent_dma_mask = 0x0fffffff,
+ },
+ .num_resources = ARRAY_SIZE(ohci_resources),
+ .resource = ohci_resources,
+};
+
+#endif
+
+#if defined(CONFIG_USB_OTG) && defined(CONFIG_ARCH_OMAP_OTG)
+
+static struct resource otg_resources[] = {
+ /* order is significant! */
+ {
+ .start = IO_ADDRESS(OTG_BASE),
+ .end = IO_ADDRESS(OTG_BASE + 0xff),
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = IH2_BASE + 8,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device otg_device = {
+ .name = "omap_otg",
+ .id = -1,
+ .dev = {
+ .release = usb_release,
+ },
+ .num_resources = ARRAY_SIZE(otg_resources),
+ .resource = otg_resources,
+};
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+// FIXME correct answer depends on hmc_mode,
+// as does any nonzero value for config->otg port number
+#define is_usb0_device(config) 0
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_ARCH_OMAP_OTG
+
+void __init
+omap_otg_init(struct omap_usb_config *config)
+{
+ u32 syscon = OTG_SYSCON_1_REG & 0xffff;
+ int status;
+ int alt_pingroup = 0;
+
+ /* NOTE: no bus or clock setup (yet?) */
+
+ syscon = OTG_SYSCON_1_REG & 0xffff;
+ if (!(syscon & OTG_RESET_DONE))
+ pr_debug("USB resets not complete?\n");
+
+ // OTG_IRQ_EN_REG = 0;
+
+ /* pin muxing and transceiver pinouts */
+ if (config->pins[0] > 2) /* alt pingroup 2 */
+ alt_pingroup = 1;
+ syscon |= omap_usb0_init(config->pins[0], is_usb0_device(config));
+ syscon |= omap_usb1_init(config->pins[1]);
+ syscon |= omap_usb2_init(config->pins[2], alt_pingroup);
+ pr_debug("OTG_SYSCON_1_REG = %08x\n", syscon);
+ OTG_SYSCON_1_REG = syscon;
+
+ syscon = config->hmc_mode;
+ syscon |= USBX_SYNCHRO | (4 << 16) /* B_ASE0_BRST */;
+ if (config->otg || config->register_host)
+ syscon |= UHOST_EN;
+#ifdef CONFIG_USB_OTG
+ if (config->otg)
+ syscon |= OTG_EN;
+#endif
+ pr_debug("OTG_SYSCON_2_REG = %08x\n", syscon);
+ OTG_SYSCON_2_REG = syscon;
+
+ printk("USB: hmc %d", config->hmc_mode);
+ if (alt_pingroup)
+ printk(", usb2 alt %d wires", config->pins[2]);
+ else if (config->pins[0])
+ printk(", usb0 %d wires%s", config->pins[2],
+ is_usb0_device(config) ? " (dev)" : "");
+ if (config->pins[1])
+ printk(", usb1 %d wires", config->pins[1]);
+ if (!alt_pingroup && config->pins[2])
+ printk(", usb2 %d wires", config->pins[2]);
+ if (config->otg)
+ printk(", Mini-AB on usb%d", config->otg - 1);
+ printk("\n");
+
+ /* don't clock unused USB controllers */
+ syscon = OTG_SYSCON_1_REG;
+ syscon |= HST_IDLE_EN|DEV_IDLE_EN|OTG_IDLE_EN;
+
+#ifdef CONFIG_USB_GADGET_OMAP
+ if (config->otg || config->register_dev) {
+ syscon &= ~DEV_IDLE_EN;
+ udc_device.dev.platform_data = config;
+ status = platform_device_register(&udc_device);
+ if (status)
+ pr_debug("can't register UDC device, %d\n", status);
+ }
+#endif
+
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+ if (config->otg || config->register_host) {
+ syscon &= ~HST_IDLE_EN;
+ ohci_device.dev.platform_data = config;
+ status = platform_device_register(&ohci_device);
+ if (status)
+ pr_debug("can't register OHCI device, %d\n", status);
+ }
+#endif
+
+#ifdef CONFIG_USB_OTG
+ if (config->otg) {
+ syscon &= ~OTG_IDLE_EN;
+ if (cpu_is_omap730())
+ otg_resources[1].start = INT_730_USB_OTG;
+ status = platform_device_register(&otg_device);
+ // ...
+ }
+#endif
+ pr_debug("OTG_SYSCON_1_REG = %08x\n", syscon);
+ OTG_SYSCON_1_REG = syscon;
+
+ status = 0;
+}
+
+#else
+static inline void omap_otg_init(struct omap_usb_config *config) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef CONFIG_ARCH_OMAP1510
+
+static void __init omap_1510_usb_init(struct omap_usb_config *config)
+{
+ int status;
+ unsigned int val;
+
+ omap_usb0_init(config->pins[0], is_usb0_device(config));
+ omap_usb1_init(config->pins[1]);
+ omap_usb2_init(config->pins[2], 0);
+
+ val = omap_readl(MOD_CONF_CTRL_0) & ~(0x3f << 1);
+ val |= (config->hmc_mode << 1);
+ omap_writel(val, MOD_CONF_CTRL_0);
+
+ // FIXME this has a UDC controller too
+
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+ if (config->otg || config->register_host) {
+ ohci_device.dev.platform_data = config;
+ status = platform_device_register(&ohci_device);
+ if (status)
+ pr_debug("can't register OHCI device, %d\n", status);
+ }
+ // FIXME completely untested ...
+#endif
+
+}
+
+#else
+static inline void omap_1510_usb_init(struct omap_usb_config *config) {}
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static struct omap_usb_config platform_data;
+
+static int __init
+omap_usb_init(void)
+{
+ const struct omap_usb_config *config;
+
+ config = omap_get_config(OMAP_TAG_USB, struct omap_usb_config);
+ if (config == NULL) {
+ printk(KERN_ERR "USB: No board-specific platform config found\n");
+ return -ENODEV;
+ }
+ platform_data = *config;
+
+ if (cpu_is_omap730()
+ || cpu_is_omap1610()
+ || cpu_is_omap1710()
+ || cpu_is_omap5912())
+ omap_otg_init(&platform_data);
+ else if (cpu_is_omap1510())
+ omap_1510_usb_init(&platform_data);
+ else {
+ printk(KERN_ERR "USB: No init for your chip yet\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+subsys_initcall(omap_usb_init);
diff -Nru a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
--- a/arch/arm/mach-pxa/Kconfig 2004-10-18 14:56:20 -07:00
+++ b/arch/arm/mach-pxa/Kconfig 2004-10-18 14:56:20 -07:00
@@ -12,7 +12,7 @@
config MACH_MAINSTONE
bool "Intel HCDDBBVA0 Development Platform"
select PXA27x
- #select IWMMXT
+ select IWMMXT
config ARCH_PXA_IDP
bool "Accelent Xscale IDP"
@@ -31,5 +31,10 @@
bool
help
Select code specific to PXA27x variants
+
+config IWMMXT
+ bool
+ help
+ Enable support for iWMMXt
endif
diff -Nru a/arch/arm/mach-pxa/dma.c b/arch/arm/mach-pxa/dma.c
--- a/arch/arm/mach-pxa/dma.c 2004-10-18 14:57:05 -07:00
+++ b/arch/arm/mach-pxa/dma.c 2004-10-18 14:57:05 -07:00
@@ -23,6 +23,7 @@
#include
#include
+#include
static struct dma_channel {
char *name;
diff -Nru a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
--- a/arch/arm/mach-pxa/generic.c 2004-10-18 14:56:27 -07:00
+++ b/arch/arm/mach-pxa/generic.c 2004-10-18 14:56:27 -07:00
@@ -30,8 +30,10 @@
#include
#include
+#include
#include
#include
+#include
#include "generic.h"
@@ -127,6 +129,12 @@
.num_resources = ARRAY_SIZE(pxamci_resources),
.resource = pxamci_resources,
};
+
+void __init pxa_set_mci_info(struct pxamci_platform_data *info)
+{
+ pxamci_device.dev.platform_data = info;
+}
+EXPORT_SYMBOL(pxa_set_mci_info);
static struct pxa2xx_udc_mach_info pxa_udc_info;
diff -Nru a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
--- a/arch/arm/mach-pxa/idp.c 2004-10-18 14:55:46 -07:00
+++ b/arch/arm/mach-pxa/idp.c 2004-10-18 14:55:46 -07:00
@@ -27,6 +27,7 @@
#include
#include
+#include
#include
#include "generic.h"
@@ -100,7 +101,7 @@
pxa_map_io();
iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc));
- set_irq_type(IRQ_TO_GPIO_2_80(TOUCH_PANEL_IRQ), TOUCH_PANEL_IRQ_EDGE);
+ set_irq_type(TOUCH_PANEL_IRQ, TOUCH_PANEL_IRQ_EDGE);
// serial ports 2 & 3
pxa_gpio_mode(GPIO42_BTRXD_MD);
diff -Nru a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
--- a/arch/arm/mach-pxa/irq.c 2004-10-18 14:57:03 -07:00
+++ b/arch/arm/mach-pxa/irq.c 2004-10-18 14:57:03 -07:00
@@ -20,39 +20,64 @@
#include
#include
#include
+#include
#include "generic.h"
/*
- * This is for IRQs known as PXA_IRQ([8...31]).
+ * This is for peripheral IRQs internal to the PXA chip.
*/
-static void pxa_mask_irq(unsigned int irq)
+static void pxa_mask_low_irq(unsigned int irq)
{
ICMR &= ~(1 << (irq + PXA_IRQ_SKIP));
}
-static void pxa_unmask_irq(unsigned int irq)
+static void pxa_unmask_low_irq(unsigned int irq)
{
ICMR |= (1 << (irq + PXA_IRQ_SKIP));
}
-static struct irqchip pxa_internal_chip = {
- .ack = pxa_mask_irq,
- .mask = pxa_mask_irq,
- .unmask = pxa_unmask_irq,
+static struct irqchip pxa_internal_chip_low = {
+ .ack = pxa_mask_low_irq,
+ .mask = pxa_mask_low_irq,
+ .unmask = pxa_unmask_low_irq,
};
+#if PXA_INTERNAL_IRQS > 32
+
+/*
+ * This is for the second set of internal IRQs as found on the PXA27x.
+ */
+
+static void pxa_mask_high_irq(unsigned int irq)
+{
+ ICMR2 &= ~(1 << (irq - 32 + PXA_IRQ_SKIP));
+}
+
+static void pxa_unmask_high_irq(unsigned int irq)
+{
+ ICMR2 |= (1 << (irq - 32 + PXA_IRQ_SKIP));
+}
+
+static struct irqchip pxa_internal_chip_high = {
+ .ack = pxa_mask_high_irq,
+ .mask = pxa_mask_high_irq,
+ .unmask = pxa_unmask_high_irq,
+};
+
+#endif
+
/*
* PXA GPIO edge detection for IRQs:
* IRQs are generated on Falling-Edge, Rising-Edge, or both.
* Use this instead of directly setting GRER/GFER.
*/
-static long GPIO_IRQ_rising_edge[3];
-static long GPIO_IRQ_falling_edge[3];
-static long GPIO_IRQ_mask[3];
+static long GPIO_IRQ_rising_edge[4];
+static long GPIO_IRQ_falling_edge[4];
+static long GPIO_IRQ_mask[4];
static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
{
@@ -106,13 +131,13 @@
static struct irqchip pxa_low_gpio_chip = {
.ack = pxa_ack_low_gpio,
- .mask = pxa_mask_irq,
- .unmask = pxa_unmask_irq,
+ .mask = pxa_mask_low_irq,
+ .unmask = pxa_unmask_low_irq,
.type = pxa_gpio_irq_type,
};
/*
- * Demux handler for GPIO 2-80 edge detect interrupts
+ * Demux handler for GPIO>=2 edge detect interrupts
*/
static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc,
@@ -169,6 +194,23 @@
} while (mask);
loop = 1;
}
+
+#if PXA_LAST_GPIO >= 96
+ mask = GEDR3;
+ if (mask) {
+ GEDR3 = mask;
+ irq = IRQ_GPIO(96);
+ desc = irq_desc + irq;
+ do {
+ if (mask & 1)
+ desc->handle(irq, desc, regs);
+ irq++;
+ desc++;
+ mask >>= 1;
+ } while (mask);
+ loop = 1;
+ }
+#endif
} while (loop);
}
@@ -214,12 +256,25 @@
ICLR = 0;
/* clear all GPIO edge detects */
- GFER0 = GFER1 = GFER2 = 0;
- GRER0 = GRER1 = GRER2 = 0;
+ GFER0 = 0;
+ GFER1 = 0;
+ GFER2 = 0;
+ GRER0 = 0;
+ GRER1 = 0;
+ GRER2 = 0;
GEDR0 = GEDR0;
GEDR1 = GEDR1;
GEDR2 = GEDR2;
+#ifdef CONFIG_PXA27x
+ /* And similarly for the extra regs on the PXA27x */
+ ICMR2 = 0;
+ ICLR2 = 0;
+ GFER3 = 0;
+ GRER3 = 0;
+ GEDR3 = GEDR3;
+#endif
+
/* only unmasked interrupts kick us out of idle */
ICCR = 1;
@@ -227,10 +282,18 @@
GPIO_IRQ_mask[0] = 3;
for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) {
- set_irq_chip(irq, &pxa_internal_chip);
+ set_irq_chip(irq, &pxa_internal_chip_low);
+ set_irq_handler(irq, do_level_IRQ);
+ set_irq_flags(irq, IRQF_VALID);
+ }
+
+#if PXA_INTERNAL_IRQS > 32
+ for (irq = PXA_IRQ(32); irq < PXA_IRQ(PXA_INTERNAL_IRQS); irq++) {
+ set_irq_chip(irq, &pxa_internal_chip_high);
set_irq_handler(irq, do_level_IRQ);
set_irq_flags(irq, IRQF_VALID);
}
+#endif
for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) {
set_irq_chip(irq, &pxa_low_gpio_chip);
@@ -238,13 +301,13 @@
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
- for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(80); irq++) {
+ for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(PXA_LAST_GPIO); irq++) {
set_irq_chip(irq, &pxa_muxed_gpio_chip);
set_irq_handler(irq, do_edge_IRQ);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
- /* Install handler for GPIO 2-80 edge detect interrupts */
- set_irq_chip(IRQ_GPIO_2_80, &pxa_internal_chip);
- set_irq_chained_handler(IRQ_GPIO_2_80, pxa_gpio_demux_handler);
+ /* Install handler for GPIO>=2 edge detect interrupts */
+ set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low);
+ set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler);
}
diff -Nru a/arch/arm/mach-pxa/leds-lubbock.c b/arch/arm/mach-pxa/leds-lubbock.c
--- a/arch/arm/mach-pxa/leds-lubbock.c 2004-10-18 14:55:54 -07:00
+++ b/arch/arm/mach-pxa/leds-lubbock.c 2004-10-18 14:55:54 -07:00
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
#include
#include "leds.h"
diff -Nru a/arch/arm/mach-pxa/leds-mainstone.c b/arch/arm/mach-pxa/leds-mainstone.c
--- a/arch/arm/mach-pxa/leds-mainstone.c 2004-10-18 14:55:53 -07:00
+++ b/arch/arm/mach-pxa/leds-mainstone.c 2004-10-18 14:55:53 -07:00
@@ -17,6 +17,7 @@
#include
#include
+#include
#include
#include "leds.h"
diff -Nru a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
--- a/arch/arm/mach-pxa/lubbock.c 2004-10-18 14:56:28 -07:00
+++ b/arch/arm/mach-pxa/lubbock.c 2004-10-18 14:56:28 -07:00
@@ -29,6 +29,7 @@
#include
#include
+#include
#include
#include
#include
diff -Nru a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
--- a/arch/arm/mach-pxa/mainstone.c 2004-10-18 14:57:04 -07:00
+++ b/arch/arm/mach-pxa/mainstone.c 2004-10-18 14:57:04 -07:00
@@ -31,6 +31,7 @@
#include
#include
+#include
#include
#include
diff -Nru a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
--- a/arch/arm/mach-pxa/pm.c 2004-10-18 14:56:33 -07:00
+++ b/arch/arm/mach-pxa/pm.c 2004-10-18 14:56:33 -07:00
@@ -19,7 +19,9 @@
#include
#include
#include
+#include
#include
+#include
/*
@@ -45,7 +47,7 @@
*/
enum { SLEEP_SAVE_START = 0,
- SLEEP_SAVE_OSCR, SLEEP_SAVE_OIER,
+ SLEEP_SAVE_OIER,
SLEEP_SAVE_OSMR0, SLEEP_SAVE_OSMR1, SLEEP_SAVE_OSMR2, SLEEP_SAVE_OSMR3,
SLEEP_SAVE_GPLR0, SLEEP_SAVE_GPLR1, SLEEP_SAVE_GPLR2,
@@ -68,17 +70,18 @@
{
unsigned long sleep_save[SLEEP_SAVE_SIZE];
unsigned long checksum = 0;
- unsigned long delta;
+ struct timespec delta, rtc;
int i;
if (state != PM_SUSPEND_MEM)
return -EINVAL;
/* preserve current time */
- delta = xtime.tv_sec - RCNR;
+ rtc.tv_sec = RCNR;
+ rtc.tv_nsec = 0;
+ save_time_delta(&delta, &rtc);
/* save vital registers */
- SAVE(OSCR);
SAVE(OSMR0);
SAVE(OSMR1);
SAVE(OSMR2);
@@ -149,9 +152,11 @@
RESTORE(OSMR1);
RESTORE(OSMR2);
RESTORE(OSMR3);
- RESTORE(OSCR);
RESTORE(OIER);
+ /* OSMR0 is the system timer: make sure OSCR is sufficiently behind */
+ OSCR = OSMR0 - LATCH;
+
RESTORE(CKEN);
ICLR = 0;
@@ -159,7 +164,8 @@
RESTORE(ICMR);
/* restore current time */
- xtime.tv_sec = RCNR + delta;
+ rtc.tv_sec = RCNR;
+ restore_time_delta(&delta, &rtc);
#ifdef DEBUG
printk(KERN_DEBUG "*** made it back from resume\n");
diff -Nru a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
--- a/arch/arm/mach-pxa/pxa25x.c 2004-10-18 14:57:19 -07:00
+++ b/arch/arm/mach-pxa/pxa25x.c 2004-10-18 14:57:19 -07:00
@@ -22,6 +22,7 @@
#include
#include
+#include
#include "generic.h"
diff -Nru a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
--- a/arch/arm/mach-pxa/pxa27x.c 2004-10-18 14:56:32 -07:00
+++ b/arch/arm/mach-pxa/pxa27x.c 2004-10-18 14:56:32 -07:00
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
#include
#include
diff -Nru a/arch/arm/mach-pxa/sleep.S b/arch/arm/mach-pxa/sleep.S
--- a/arch/arm/mach-pxa/sleep.S 2004-10-18 14:57:03 -07:00
+++ b/arch/arm/mach-pxa/sleep.S 2004-10-18 14:57:03 -07:00
@@ -16,6 +16,8 @@
#include
#include
+#include
+
.text
/*
@@ -64,6 +66,37 @@
@ prepare pointer to physical address 0 (virtual mapping in generic.c)
mov r2, #UNCACHED_PHYS_0
+ @ Intel PXA255 Specification Update notes problems
+ @ about suspending with PXBus operating above 133MHz
+ @ (see Errata 31, GPIO output signals, ... unpredictable in sleep
+ @
+ @ We keep the change-down close to the actual suspend on SDRAM
+ @ as possible to eliminate messing about with the refresh clock
+ @ as the system will restore with the original speed settings
+ @
+ @ Ben Dooks, 13-Sep-2004
+
+ ldr r6, =CCCR
+ ldr r8, [r6] @ keep original value for resume
+
+ @ ensure x1 for run and turbo mode with memory clock
+ bic r7, r8, #CCCR_M_MASK | CCCR_N_MASK
+ orr r7, r7, #(1<<5) | (2<<7)
+
+ @ check that the memory frequency is within limits
+ and r14, r7, #CCCR_L_MASK
+ teq r14, #1
+ bicne r7, r7, #CCCR_L_MASK
+ orrne r7, r7, #1 @@ 99.53MHz
+
+ @ get ready for the change
+ @ note, since we are making turbo=run, do not remove the turbo
+ @ as this may cause non-turbo mode on resume
+ mrc p14, 0, r0, c6, c0, 0
+ bic r0, r0, #2 @ clear change bit
+ mcr p14, 0, r0, c6, c0, 0
+ orr r0, r0, #2 @ initiate change bit
+
@ align execution to a cache line
b 1f
@@ -74,6 +107,13 @@
@ All needed values are now in registers.
@ These last instructions should be in cache
+ @ initiate the frequency change...
+ str r7, [r6]
+ mcr p14, 0, r0, c6, c0, 0
+
+ @ restore the original cpu speed value for resume
+ str r8, [r6]
+
@ put SDRAM into self-refresh
str r5, [r4]
@@ -83,8 +123,7 @@
@ enter sleep mode
mcr p14, 0, r1, c7, c0, 0
-20: nop
- b 20b @ loop waiting for sleep
+20: b 20b @ loop waiting for sleep
/*
* cpu_pxa_resume()
diff -Nru a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
--- a/arch/arm/mach-pxa/time.c 2004-10-18 14:56:29 -07:00
+++ b/arch/arm/mach-pxa/time.c 2004-10-18 14:56:29 -07:00
@@ -27,6 +27,7 @@
#include
#include
#include
+#include
static inline unsigned long pxa_get_rtc_time(void)
diff -Nru a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
--- a/arch/arm/mach-s3c2410/Kconfig 2004-10-18 14:56:29 -07:00
+++ b/arch/arm/mach-s3c2410/Kconfig 2004-10-18 14:56:29 -07:00
@@ -1,9 +1,10 @@
if ARCH_S3C2410
-menu "S3C2410 Implementations"
+menu "S3C24XX Implementations"
config ARCH_BAST
bool "Simtec Electronics BAST (EB2410ITX)"
+ select CPU_S3C2410
help
Say Y here if you are using the Simtec Electronics EB2410ITX
development board (also known as BAST)
@@ -12,18 +13,22 @@
config ARCH_H1940
bool "IPAQ H1940"
+ select CPU_S3C2410
help
Say Y here if you are using the HP IPAQ H1940
+
.
config ARCH_SMDK2410
bool "SMDK2410/A9M2410"
+ select CPU_S3C2410
help
Say Y here if you are using the SMDK2410 or the derived module A9M2410
config MACH_VR1000
bool "Thorcom VR1000"
+ select CPU_S3C2410
help
Say Y here if you are using the Thorcom VR1000 board.
@@ -31,5 +36,40 @@
of Thorcom. Any queries, please contact Thorcom first.
endmenu
+
+config CPU_S3C2410
+ bool
+ depends on ARCH_S3C2410
+ help
+ Support for S3C2410 and S3C2410A family from the S3C24XX line
+ of Samsung Mobile CPUs.
+
+config CPU_S3C2440
+ bool
+ depends on ARCH_S3C2410
+ help
+ Support for S3C2440 Samsung Mobile CPU based systems.
+
+comment "S3C2410 Setup"
+
+config S3C2410_DMA
+ bool "S3C2410 DMA support"
+ depends on ARCH_S3C2410
+ help
+ S3C2410 DMA support. This is needed for drivers like sound which
+ use the S3C2410's DMA system to move data to and from the
+ peripheral blocks.
+
+config S3C2410_DMA_DEBUG
+ bool "S3C2410 DMA support debug"
+ depends on ARCH_S3C2410 && S3C2410_DMA
+ help
+ Enable debugging output for the DMA code. This option sends info
+ to the kernel log, at priority KERN_DEBUG.
+
+ Note, it is easy to create and fill the log buffer in a small
+ amount of time, as well as using an significant percantage of
+ the CPU time doing so.
+
endif
diff -Nru a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
--- a/arch/arm/mach-s3c2410/Makefile 2004-10-18 14:56:17 -07:00
+++ b/arch/arm/mach-s3c2410/Makefile 2004-10-18 14:56:17 -07:00
@@ -1,19 +1,28 @@
+
#
# Makefile for the linux kernel.
#
# Object file lists.
-obj-y := s3c2410.o irq.o time.o gpio.o
+obj-y := cpu.o irq.o time.o gpio.o clock.o devs.o
obj-m :=
obj-n :=
obj- :=
-obj-$(CONFIG_ARCH_BAST) += mach-bast.o
-obj-$(CONFIG_MACH_H1940) += mach-h1940.o
-obj-$(CONFIG_ARCH_H1940) += mach-h1940.o
-obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o
-obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o
+# S3C2410 support files
+
+obj-$(CONFIG_CPU_S3C2410) += s3c2410.o
+obj-$(CONFIG_S3C2410_DMA) += dma.o
+
+# S3C2440 support
+
+obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o
+
+# machine specific support
+
+obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o
+obj-$(CONFIG_ARCH_H1940) += mach-h1940.o
+obj-$(CONFIG_ARCH_SMDK2410) += mach-smdk2410.o
+obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o
-#obj-$(CONFIG_PCI) +=$(pci-y)
-#obj-$(CONFIG_LEDS) +=$(leds-y)
diff -Nru a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/arch/arm/mach-s3c2410/clock.c 2004-10-18 14:57:21 -07:00
@@ -0,0 +1,310 @@
+/* linux/arch/arm/mach-s3c2410/clock.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks
+ *
+ * S3C2410 Clock control support
+ *
+ * Based on, and code from linux/arch/arm/mach-versatile/clock.c
+ **
+ ** Copyright (C) 2004 ARM Limited.
+ ** Written by Deep Blue Solutions Limited.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "clock.h"
+
+
+static LIST_HEAD(clocks);
+static DECLARE_MUTEX(clocks_sem);
+
+
+/* old functions */
+
+void s3c2410_clk_enable(unsigned int clocks, unsigned int enable)
+{
+ unsigned long clkcon;
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ clkcon = __raw_readl(S3C2410_CLKCON);
+ clkcon &= ~clocks;
+
+ if (enable)
+ clkcon |= clocks;
+
+ __raw_writel(clkcon, S3C2410_CLKCON);
+
+ local_irq_restore(flags);
+}
+
+
+/* Clock API calls */
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+ struct clk *p;
+ struct clk *clk = ERR_PTR(-ENOENT);
+
+ down(&clocks_sem);
+ list_for_each_entry(p, &clocks, list) {
+ if (strcmp(id, p->name) == 0 &&
+ try_module_get(p->owner)) {
+ clk = p;
+ break;
+ }
+ }
+ up(&clocks_sem);
+
+ return clk;
+}
+
+void clk_put(struct clk *clk)
+{
+ module_put(clk->owner);
+}
+
+int clk_enable(struct clk *clk)
+{
+ if (clk->ctrlbit != 0)
+ s3c2410_clk_enable(clk->ctrlbit, 1);
+
+ return 0;
+}
+
+void clk_disable(struct clk *clk)
+{
+ s3c2410_clk_enable(clk->ctrlbit, 0);
+}
+
+
+int clk_use(struct clk *clk)
+{
+ atomic_inc(&clk->used);
+ return 0;
+}
+
+
+void clk_unuse(struct clk *clk)
+{
+ atomic_dec(&clk->used);
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (clk->parent != NULL)
+ return clk->parent->rate;
+
+ return clk->rate;
+}
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ return rate;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ return -EINVAL;
+}
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+ return clk->parent;
+}
+
+EXPORT_SYMBOL(clk_get);
+EXPORT_SYMBOL(clk_put);
+EXPORT_SYMBOL(clk_enable);
+EXPORT_SYMBOL(clk_disable);
+EXPORT_SYMBOL(clk_use);
+EXPORT_SYMBOL(clk_unuse);
+EXPORT_SYMBOL(clk_get_rate);
+EXPORT_SYMBOL(clk_round_rate);
+EXPORT_SYMBOL(clk_set_rate);
+EXPORT_SYMBOL(clk_get_parent);
+
+/* base clocks */
+
+static struct clk clk_f = {
+ .name = "fclk",
+ .rate = 0,
+ .parent = NULL,
+ .ctrlbit = 0
+};
+
+static struct clk clk_h = {
+ .name = "hclk",
+ .rate = 0,
+ .parent = NULL,
+ .ctrlbit = 0
+};
+
+static struct clk clk_p = {
+ .name = "pclk",
+ .rate = 0,
+ .parent = NULL,
+ .ctrlbit = 0
+};
+
+/* clock definitions */
+
+static struct clk init_clocks[] = {
+ { .name = "nand",
+ .parent = &clk_h,
+ .ctrlbit = S3C2410_CLKCON_NAND
+ },
+ { .name = "lcd",
+ .parent = &clk_h,
+ .ctrlbit = S3C2410_CLKCON_LCDC
+ },
+ { .name = "usb-host",
+ .parent = &clk_h,
+ .ctrlbit = S3C2410_CLKCON_USBH
+ },
+ { .name = "usb-device",
+ .parent = &clk_h,
+ .ctrlbit = S3C2410_CLKCON_USBD
+ },
+ { .name = "timers",
+ .parent = &clk_p,
+ .ctrlbit = S3C2410_CLKCON_PWMT
+ },
+ { .name = "sdi",
+ .parent = &clk_p,
+ .ctrlbit = S3C2410_CLKCON_SDI
+ },
+ { .name = "uart0",
+ .parent = &clk_p,
+ .ctrlbit = S3C2410_CLKCON_UART0
+ },
+ { .name = "uart1",
+ .parent = &clk_p,
+ .ctrlbit = S3C2410_CLKCON_UART1
+ },
+ { .name = "uart2",
+ .parent = &clk_p,
+ .ctrlbit = S3C2410_CLKCON_UART2
+ },
+ { .name = "gpio",
+ .parent = &clk_p,
+ .ctrlbit = S3C2410_CLKCON_GPIO
+ },
+ { .name = "rtc",
+ .parent = &clk_p,
+ .ctrlbit = S3C2410_CLKCON_RTC
+ },
+ { .name = "adc",
+ .parent = &clk_p,
+ .ctrlbit = S3C2410_CLKCON_ADC
+ },
+ { .name = "i2c",
+ .parent = &clk_p,
+ .ctrlbit = S3C2410_CLKCON_IIC
+ },
+ { .name = "iis",
+ .parent = &clk_p,
+ .ctrlbit = S3C2410_CLKCON_IIS
+ },
+ { .name = "spi",
+ .parent = &clk_p,
+ .ctrlbit = S3C2410_CLKCON_SPI
+ },
+ { .name = "watchdog",
+ .parent = &clk_p,
+ .ctrlbit = 0
+ }
+};
+
+/* initialise the clock system */
+
+int s3c2410_register_clock(struct clk *clk)
+{
+ clk->owner = THIS_MODULE;
+ atomic_set(&clk->used, 0);
+
+ /* add to the list of available clocks */
+
+ down(&clocks_sem);
+ list_add(&clk->list, &clocks);
+ up(&clocks_sem);
+
+ return 0;
+}
+
+/* initalise all the clocks */
+
+static int __init s3c2410_init_clocks(void)
+{
+ struct clk *clkp = init_clocks;
+ int ptr;
+ int ret;
+
+ printk(KERN_INFO "S3C2410 Clock control, (c) 2004 Simtec Electronics\n");
+
+ /* initialise the main system clocks */
+
+ clk_h.rate = s3c2410_hclk;
+ clk_p.rate = s3c2410_pclk;
+ clk_f.rate = s3c2410_fclk;
+
+ /* set the enabled clocks to a minimal (known) state */
+ __raw_writel(S3C2410_CLKCON_PWMT | S3C2410_CLKCON_UART0 | S3C2410_CLKCON_UART1 | S3C2410_CLKCON_UART2 | S3C2410_CLKCON_GPIO | S3C2410_CLKCON_RTC, S3C2410_CLKCON);
+
+ /* register our clocks */
+
+ if (s3c2410_register_clock(&clk_f) < 0)
+ printk(KERN_ERR "failed to register cpu fclk\n");
+
+ if (s3c2410_register_clock(&clk_h) < 0)
+ printk(KERN_ERR "failed to register cpu hclk\n");
+
+ if (s3c2410_register_clock(&clk_p) < 0)
+ printk(KERN_ERR "failed to register cpu pclk\n");
+
+ for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
+ ret = s3c2410_register_clock(clkp);
+ if (ret < 0) {
+ printk(KERN_ERR "Failed to register clock %s (%d)\n",
+ clkp->name, ret);
+ }
+ }
+
+ return 0;
+}
+
+arch_initcall(s3c2410_init_clocks);
+
diff -Nru a/arch/arm/mach-s3c2410/clock.h b/arch/arm/mach-s3c2410/clock.h
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/arch/arm/mach-s3c2410/clock.h 2004-10-18 14:57:23 -07:00
@@ -0,0 +1,20 @@
+/*
+ * linux/arch/arm/mach-s3c2410/clock.h
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Written by Ben Dooks,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+struct clk {
+ struct list_head list;
+ struct module *owner;
+ struct clk *parent;
+ const char *name;
+ atomic_t used;
+ unsigned long rate;
+ unsigned long ctrlbit;
+};
diff -Nru a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/arch/arm/mach-s3c2410/cpu.c 2004-10-18 14:57:23 -07:00
@@ -0,0 +1,152 @@
+/* linux/arch/arm/mach-s3c2410/cpu.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks
+ *
+ * S3C24XX CPU Support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include