提交 adf6d34e 编写于 作者: R Russell King 提交者: Russell King

Merge branch 'omap2-upstream' into devel

...@@ -271,8 +271,6 @@ netlabel/ ...@@ -271,8 +271,6 @@ netlabel/
- directory with information on the NetLabel subsystem. - directory with information on the NetLabel subsystem.
networking/ networking/
- directory with info on various aspects of networking with Linux. - directory with info on various aspects of networking with Linux.
nfsroot.txt
- short guide on setting up a diskless box with NFS root filesystem.
nmi_watchdog.txt nmi_watchdog.txt
- info on NMI watchdog for SMP systems. - info on NMI watchdog for SMP systems.
nommu-mmap.txt nommu-mmap.txt
...@@ -321,8 +319,6 @@ robust-futexes.txt ...@@ -321,8 +319,6 @@ robust-futexes.txt
- a description of what robust futexes are. - a description of what robust futexes are.
rocket.txt rocket.txt
- info on the Comtrol RocketPort multiport serial driver. - info on the Comtrol RocketPort multiport serial driver.
rpc-cache.txt
- introduction to the caching mechanisms in the sunrpc layer.
rt-mutex-design.txt rt-mutex-design.txt
- description of the RealTime mutex implementation design. - description of the RealTime mutex implementation design.
rt-mutex.txt rt-mutex.txt
......
...@@ -328,7 +328,7 @@ now, but you can do this to mark internal company procedures or just ...@@ -328,7 +328,7 @@ now, but you can do this to mark internal company procedures or just
point out some special detail about the sign-off. point out some special detail about the sign-off.
13) When to use Acked-by: 13) When to use Acked-by: and Cc:
The Signed-off-by: tag indicates that the signer was involved in the The Signed-off-by: tag indicates that the signer was involved in the
development of the patch, or that he/she was in the patch's delivery path. development of the patch, or that he/she was in the patch's delivery path.
...@@ -349,11 +349,59 @@ Acked-by: does not necessarily indicate acknowledgement of the entire patch. ...@@ -349,11 +349,59 @@ Acked-by: does not necessarily indicate acknowledgement of the entire patch.
For example, if a patch affects multiple subsystems and has an Acked-by: from For example, if a patch affects multiple subsystems and has an Acked-by: from
one subsystem maintainer then this usually indicates acknowledgement of just one subsystem maintainer then this usually indicates acknowledgement of just
the part which affects that maintainer's code. Judgement should be used here. the part which affects that maintainer's code. Judgement should be used here.
When in doubt people should refer to the original discussion in the mailing When in doubt people should refer to the original discussion in the mailing
list archives. list archives.
If a person has had the opportunity to comment on a patch, but has not
provided such comments, you may optionally add a "Cc:" tag to the patch.
This is the only tag which might be added without an explicit action by the
person it names. This tag documents that potentially interested parties
have been included in the discussion
14) The canonical patch format
14) Using Test-by: and Reviewed-by:
A Tested-by: tag indicates that the patch has been successfully tested (in
some environment) by the person named. This tag informs maintainers that
some testing has been performed, provides a means to locate testers for
future patches, and ensures credit for the testers.
Reviewed-by:, instead, indicates that the patch has been reviewed and found
acceptable according to the Reviewer's Statement:
Reviewer's statement of oversight
By offering my Reviewed-by: tag, I state that:
(a) I have carried out a technical review of this patch to
evaluate its appropriateness and readiness for inclusion into
the mainline kernel.
(b) Any problems, concerns, or questions relating to the patch
have been communicated back to the submitter. I am satisfied
with the submitter's response to my comments.
(c) While there may be things that could be improved with this
submission, I believe that it is, at this time, (1) a
worthwhile modification to the kernel, and (2) free of known
issues which would argue against its inclusion.
(d) While I have reviewed the patch and believe it to be sound, I
do not (unless explicitly stated elsewhere) make any
warranties or guarantees that it will achieve its stated
purpose or function properly in any given situation.
A Reviewed-by tag is a statement of opinion that the patch is an
appropriate modification of the kernel without any remaining serious
technical issues. Any interested reviewer (who has done the work) can
offer a Reviewed-by tag for a patch. This tag serves to give credit to
reviewers and to inform maintainers of the degree of review which has been
done on the patch. Reviewed-by: tags, when supplied by reviewers known to
understand the subject area and to perform thorough reviews, will normally
increase the liklihood of your patch getting into the kernel.
15) The canonical patch format
The canonical patch subject line is: The canonical patch subject line is:
...@@ -512,7 +560,7 @@ They provide type safety, have no length limitations, no formatting ...@@ -512,7 +560,7 @@ They provide type safety, have no length limitations, no formatting
limitations, and under gcc they are as cheap as macros. limitations, and under gcc they are as cheap as macros.
Macros should only be used for cases where a static inline is clearly Macros should only be used for cases where a static inline is clearly
suboptimal [there a few, isolated cases of this in fast paths], suboptimal [there are a few, isolated cases of this in fast paths],
or where it is impossible to use a static inline function [such as or where it is impossible to use a static inline function [such as
string-izing]. string-izing].
......
...@@ -66,6 +66,8 @@ mandatory-locking.txt ...@@ -66,6 +66,8 @@ mandatory-locking.txt
- info on the Linux implementation of Sys V mandatory file locking. - info on the Linux implementation of Sys V mandatory file locking.
ncpfs.txt ncpfs.txt
- info on Novell Netware(tm) filesystem using NCP protocol. - info on Novell Netware(tm) filesystem using NCP protocol.
nfsroot.txt
- short guide on setting up a diskless box with NFS root filesystem.
ntfs.txt ntfs.txt
- info and mount options for the NTFS filesystem (Windows NT). - info and mount options for the NTFS filesystem (Windows NT).
ocfs2.txt ocfs2.txt
...@@ -82,6 +84,10 @@ relay.txt ...@@ -82,6 +84,10 @@ relay.txt
- info on relay, for efficient streaming from kernel to user space. - info on relay, for efficient streaming from kernel to user space.
romfs.txt romfs.txt
- description of the ROMFS filesystem. - description of the ROMFS filesystem.
rpc-cache.txt
- introduction to the caching mechanisms in the sunrpc layer.
seq_file.txt
- how to use the seq_file API
sharedsubtree.txt sharedsubtree.txt
- a description of shared subtrees for namespaces. - a description of shared subtrees for namespaces.
smbfs.txt smbfs.txt
......
The seq_file interface
Copyright 2003 Jonathan Corbet <corbet@lwn.net>
This file is originally from the LWN.net Driver Porting series at
http://lwn.net/Articles/driver-porting/
There are numerous ways for a device driver (or other kernel component) to
provide information to the user or system administrator. One useful
technique is the creation of virtual files, in debugfs, /proc or elsewhere.
Virtual files can provide human-readable output that is easy to get at
without any special utility programs; they can also make life easier for
script writers. It is not surprising that the use of virtual files has
grown over the years.
Creating those files correctly has always been a bit of a challenge,
however. It is not that hard to make a virtual file which returns a
string. But life gets trickier if the output is long - anything greater
than an application is likely to read in a single operation. Handling
multiple reads (and seeks) requires careful attention to the reader's
position within the virtual file - that position is, likely as not, in the
middle of a line of output. The kernel has traditionally had a number of
implementations that got this wrong.
The 2.6 kernel contains a set of functions (implemented by Alexander Viro)
which are designed to make it easy for virtual file creators to get it
right.
The seq_file interface is available via <linux/seq_file.h>. There are
three aspects to seq_file:
* An iterator interface which lets a virtual file implementation
step through the objects it is presenting.
* Some utility functions for formatting objects for output without
needing to worry about things like output buffers.
* A set of canned file_operations which implement most operations on
the virtual file.
We'll look at the seq_file interface via an extremely simple example: a
loadable module which creates a file called /proc/sequence. The file, when
read, simply produces a set of increasing integer values, one per line. The
sequence will continue until the user loses patience and finds something
better to do. The file is seekable, in that one can do something like the
following:
dd if=/proc/sequence of=out1 count=1
dd if=/proc/sequence skip=1 out=out2 count=1
Then concatenate the output files out1 and out2 and get the right
result. Yes, it is a thoroughly useless module, but the point is to show
how the mechanism works without getting lost in other details. (Those
wanting to see the full source for this module can find it at
http://lwn.net/Articles/22359/).
The iterator interface
Modules implementing a virtual file with seq_file must implement a simple
iterator object that allows stepping through the data of interest.
Iterators must be able to move to a specific position - like the file they
implement - but the interpretation of that position is up to the iterator
itself. A seq_file implementation that is formatting firewall rules, for
example, could interpret position N as the Nth rule in the chain.
Positioning can thus be done in whatever way makes the most sense for the
generator of the data, which need not be aware of how a position translates
to an offset in the virtual file. The one obvious exception is that a
position of zero should indicate the beginning of the file.
The /proc/sequence iterator just uses the count of the next number it
will output as its position.
Four functions must be implemented to make the iterator work. The first,
called start() takes a position as an argument and returns an iterator
which will start reading at that position. For our simple sequence example,
the start() function looks like:
static void *ct_seq_start(struct seq_file *s, loff_t *pos)
{
loff_t *spos = kmalloc(sizeof(loff_t), GFP_KERNEL);
if (! spos)
return NULL;
*spos = *pos;
return spos;
}
The entire data structure for this iterator is a single loff_t value
holding the current position. There is no upper bound for the sequence
iterator, but that will not be the case for most other seq_file
implementations; in most cases the start() function should check for a
"past end of file" condition and return NULL if need be.
For more complicated applications, the private field of the seq_file
structure can be used. There is also a special value whch can be returned
by the start() function called SEQ_START_TOKEN; it can be used if you wish
to instruct your show() function (described below) to print a header at the
top of the output. SEQ_START_TOKEN should only be used if the offset is
zero, however.
The next function to implement is called, amazingly, next(); its job is to
move the iterator forward to the next position in the sequence. The
example module can simply increment the position by one; more useful
modules will do what is needed to step through some data structure. The
next() function returns a new iterator, or NULL if the sequence is
complete. Here's the example version:
static void *ct_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
loff_t *spos = v;
*pos = ++*spos;
return spos;
}
The stop() function is called when iteration is complete; its job, of
course, is to clean up. If dynamic memory is allocated for the iterator,
stop() is the place to free it.
static void ct_seq_stop(struct seq_file *s, void *v)
{
kfree(v);
}
Finally, the show() function should format the object currently pointed to
by the iterator for output. It should return zero, or an error code if
something goes wrong. The example module's show() function is:
static int ct_seq_show(struct seq_file *s, void *v)
{
loff_t *spos = v;
seq_printf(s, "%lld\n", (long long)*spos);
return 0;
}
We will look at seq_printf() in a moment. But first, the definition of the
seq_file iterator is finished by creating a seq_operations structure with
the four functions we have just defined:
static const struct seq_operations ct_seq_ops = {
.start = ct_seq_start,
.next = ct_seq_next,
.stop = ct_seq_stop,
.show = ct_seq_show
};
This structure will be needed to tie our iterator to the /proc file in
a little bit.
It's worth noting that the interator value returned by start() and
manipulated by the other functions is considered to be completely opaque by
the seq_file code. It can thus be anything that is useful in stepping
through the data to be output. Counters can be useful, but it could also be
a direct pointer into an array or linked list. Anything goes, as long as
the programmer is aware that things can happen between calls to the
iterator function. However, the seq_file code (by design) will not sleep
between the calls to start() and stop(), so holding a lock during that time
is a reasonable thing to do. The seq_file code will also avoid taking any
other locks while the iterator is active.
Formatted output
The seq_file code manages positioning within the output created by the
iterator and getting it into the user's buffer. But, for that to work, that
output must be passed to the seq_file code. Some utility functions have
been defined which make this task easy.
Most code will simply use seq_printf(), which works pretty much like
printk(), but which requires the seq_file pointer as an argument. It is
common to ignore the return value from seq_printf(), but a function
producing complicated output may want to check that value and quit if
something non-zero is returned; an error return means that the seq_file
buffer has been filled and further output will be discarded.
For straight character output, the following functions may be used:
int seq_putc(struct seq_file *m, char c);
int seq_puts(struct seq_file *m, const char *s);
int seq_escape(struct seq_file *m, const char *s, const char *esc);
The first two output a single character and a string, just like one would
expect. seq_escape() is like seq_puts(), except that any character in s
which is in the string esc will be represented in octal form in the output.
There is also a function for printing filenames:
int seq_path(struct seq_file *m, struct path *path, char *esc);
Here, path indicates the file of interest, and esc is a set of characters
which should be escaped in the output.
Making it all work
So far, we have a nice set of functions which can produce output within the
seq_file system, but we have not yet turned them into a file that a user
can see. Creating a file within the kernel requires, of course, the
creation of a set of file_operations which implement the operations on that
file. The seq_file interface provides a set of canned operations which do
most of the work. The virtual file author still must implement the open()
method, however, to hook everything up. The open function is often a single
line, as in the example module:
static int ct_open(struct inode *inode, struct file *file)
{
return seq_open(file, &ct_seq_ops);
}
Here, the call to seq_open() takes the seq_operations structure we created
before, and gets set up to iterate through the virtual file.
On a successful open, seq_open() stores the struct seq_file pointer in
file->private_data. If you have an application where the same iterator can
be used for more than one file, you can store an arbitrary pointer in the
private field of the seq_file structure; that value can then be retrieved
by the iterator functions.
The other operations of interest - read(), llseek(), and release() - are
all implemented by the seq_file code itself. So a virtual file's
file_operations structure will look like:
static const struct file_operations ct_file_ops = {
.owner = THIS_MODULE,
.open = ct_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
};
There is also a seq_release_private() which passes the contents of the
seq_file private field to kfree() before releasing the structure.
The final step is the creation of the /proc file itself. In the example
code, that is done in the initialization code in the usual way:
static int ct_init(void)
{
struct proc_dir_entry *entry;
entry = create_proc_entry("sequence", 0, NULL);
if (entry)
entry->proc_fops = &ct_file_ops;
return 0;
}
module_init(ct_init);
And that is pretty much it.
seq_list
If your file will be iterating through a linked list, you may find these
routines useful:
struct list_head *seq_list_start(struct list_head *head,
loff_t pos);
struct list_head *seq_list_start_head(struct list_head *head,
loff_t pos);
struct list_head *seq_list_next(void *v, struct list_head *head,
loff_t *ppos);
These helpers will interpret pos as a position within the list and iterate
accordingly. Your start() and next() functions need only invoke the
seq_list_* helpers with a pointer to the appropriate list_head structure.
The extra-simple version
For extremely simple virtual files, there is an even easier interface. A
module can define only the show() function, which should create all the
output that the virtual file will contain. The file's open() method then
calls:
int single_open(struct file *file,
int (*show)(struct seq_file *m, void *p),
void *data);
When output time comes, the show() function will be called once. The data
value given to single_open() can be found in the private field of the
seq_file structure. When using single_open(), the programmer should use
single_release() instead of seq_release() in the file_operations structure
to avoid a memory leak.
...@@ -98,7 +98,7 @@ System-level global event devices are used for the Linux periodic tick. Per-CPU ...@@ -98,7 +98,7 @@ System-level global event devices are used for the Linux periodic tick. Per-CPU
event devices are used to provide local CPU functionality such as process event devices are used to provide local CPU functionality such as process
accounting, profiling, and high resolution timers. accounting, profiling, and high resolution timers.
The management layer assignes one or more of the folliwing functions to a clock The management layer assigns one or more of the following functions to a clock
event device: event device:
- system global periodic tick (jiffies update) - system global periodic tick (jiffies update)
- cpu local update_process_times - cpu local update_process_times
......
...@@ -70,7 +70,7 @@ Every PCI card emits a PCI IRQ, which can be INTA, INTB, INTC or INTD: ...@@ -70,7 +70,7 @@ Every PCI card emits a PCI IRQ, which can be INTA, INTB, INTC or INTD:
These INTA-D PCI IRQs are always 'local to the card', their real meaning These INTA-D PCI IRQs are always 'local to the card', their real meaning
depends on which slot they are in. If you look at the daisy chaining diagram, depends on which slot they are in. If you look at the daisy chaining diagram,
a card in slot4, issuing INTA IRQ, it will end up as a signal on PIRQ2 of a card in slot4, issuing INTA IRQ, it will end up as a signal on PIRQ4 of
the PCI chipset. Most cards issue INTA, this creates optimal distribution the PCI chipset. Most cards issue INTA, this creates optimal distribution
between the PIRQ lines. (distributing IRQ sources properly is not a between the PIRQ lines. (distributing IRQ sources properly is not a
necessity, PCI IRQs can be shared at will, but it's a good for performance necessity, PCI IRQs can be shared at will, but it's a good for performance
......
...@@ -170,11 +170,6 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -170,11 +170,6 @@ and is between 256 and 4096 characters. It is defined in the file
acpi_irq_isa= [HW,ACPI] If irq_balance, mark listed IRQs used by ISA acpi_irq_isa= [HW,ACPI] If irq_balance, mark listed IRQs used by ISA
Format: <irq>,<irq>... Format: <irq>,<irq>...
acpi_new_pts_ordering [HW,ACPI]
Enforce the ACPI 2.0 ordering of the _PTS control
method wrt putting devices into low power states
default: pre ACPI 2.0 ordering of _PTS
acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT
acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS
...@@ -380,6 +375,10 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -380,6 +375,10 @@ and is between 256 and 4096 characters. It is defined in the file
ccw_timeout_log [S390] ccw_timeout_log [S390]
See Documentation/s390/CommonIO for details. See Documentation/s390/CommonIO for details.
cgroup_disable= [KNL] Disable a particular controller
Format: {name of the controller(s) to disable}
{Currently supported controllers - "memory"}
checkreqprot [SELINUX] Set initial checkreqprot flag value. checkreqprot [SELINUX] Set initial checkreqprot flag value.
Format: { "0" | "1" } Format: { "0" | "1" }
See security/selinux/Kconfig help text. See security/selinux/Kconfig help text.
...@@ -845,7 +844,7 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -845,7 +844,7 @@ and is between 256 and 4096 characters. It is defined in the file
arch/alpha/kernel/core_marvel.c. arch/alpha/kernel/core_marvel.c.
ip= [IP_PNP] ip= [IP_PNP]
See Documentation/nfsroot.txt. See Documentation/filesystems/nfsroot.txt.
ip2= [HW] Set IO/IRQ pairs for up to 4 IntelliPort boards ip2= [HW] Set IO/IRQ pairs for up to 4 IntelliPort boards
See comment before ip2_setup() in See comment before ip2_setup() in
...@@ -1199,10 +1198,10 @@ and is between 256 and 4096 characters. It is defined in the file ...@@ -1199,10 +1198,10 @@ and is between 256 and 4096 characters. It is defined in the file
file if at all. file if at all.
nfsaddrs= [NFS] nfsaddrs= [NFS]
See Documentation/nfsroot.txt. See Documentation/filesystems/nfsroot.txt.
nfsroot= [NFS] nfs root filesystem for disk-less boxes. nfsroot= [NFS] nfs root filesystem for disk-less boxes.
See Documentation/nfsroot.txt. See Documentation/filesystems/nfsroot.txt.
nfs.callback_tcpport= nfs.callback_tcpport=
[NFS] set the TCP port on which the NFSv4 callback [NFS] set the TCP port on which the NFSv4 callback
......
/*P:100 This is the Launcher code, a simple program which lays out the /*P:100 This is the Launcher code, a simple program which lays out the
* "physical" memory for the new Guest by mapping the kernel image and the * "physical" memory for the new Guest by mapping the kernel image and
* virtual devices, then reads repeatedly from /dev/lguest to run the Guest. * the virtual devices, then opens /dev/lguest to tell the kernel
:*/ * about the Guest and control it. :*/
#define _LARGEFILE64_SOURCE #define _LARGEFILE64_SOURCE
#define _GNU_SOURCE #define _GNU_SOURCE
#include <stdio.h> #include <stdio.h>
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
#include "linux/virtio_console.h" #include "linux/virtio_console.h"
#include "linux/virtio_ring.h" #include "linux/virtio_ring.h"
#include "asm-x86/bootparam.h" #include "asm-x86/bootparam.h"
/*L:110 We can ignore the 38 include files we need for this program, but I do /*L:110 We can ignore the 39 include files we need for this program, but I do
* want to draw attention to the use of kernel-style types. * want to draw attention to the use of kernel-style types.
* *
* As Linus said, "C is a Spartan language, and so should your naming be." I * As Linus said, "C is a Spartan language, and so should your naming be." I
...@@ -320,7 +320,7 @@ static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr) ...@@ -320,7 +320,7 @@ static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr)
err(1, "Reading program headers"); err(1, "Reading program headers");
/* Try all the headers: there are usually only three. A read-only one, /* Try all the headers: there are usually only three. A read-only one,
* a read-write one, and a "note" section which isn't loadable. */ * a read-write one, and a "note" section which we don't load. */
for (i = 0; i < ehdr->e_phnum; i++) { for (i = 0; i < ehdr->e_phnum; i++) {
/* If this isn't a loadable segment, we ignore it */ /* If this isn't a loadable segment, we ignore it */
if (phdr[i].p_type != PT_LOAD) if (phdr[i].p_type != PT_LOAD)
...@@ -387,7 +387,7 @@ static unsigned long load_kernel(int fd) ...@@ -387,7 +387,7 @@ static unsigned long load_kernel(int fd)
if (memcmp(hdr.e_ident, ELFMAG, SELFMAG) == 0) if (memcmp(hdr.e_ident, ELFMAG, SELFMAG) == 0)
return map_elf(fd, &hdr); return map_elf(fd, &hdr);
/* Otherwise we assume it's a bzImage, and try to unpack it */ /* Otherwise we assume it's a bzImage, and try to load it. */
return load_bzimage(fd); return load_bzimage(fd);
} }
...@@ -433,12 +433,12 @@ static unsigned long load_initrd(const char *name, unsigned long mem) ...@@ -433,12 +433,12 @@ static unsigned long load_initrd(const char *name, unsigned long mem)
return len; return len;
} }
/* Once we know how much memory we have, we can construct simple linear page /* Once we know how much memory we have we can construct simple linear page
* tables which set virtual == physical which will get the Guest far enough * tables which set virtual == physical which will get the Guest far enough
* into the boot to create its own. * into the boot to create its own.
* *
* We lay them out of the way, just below the initrd (which is why we need to * We lay them out of the way, just below the initrd (which is why we need to
* know its size). */ * know its size here). */
static unsigned long setup_pagetables(unsigned long mem, static unsigned long setup_pagetables(unsigned long mem,
unsigned long initrd_size) unsigned long initrd_size)
{ {
...@@ -850,7 +850,8 @@ static void handle_console_output(int fd, struct virtqueue *vq) ...@@ -850,7 +850,8 @@ static void handle_console_output(int fd, struct virtqueue *vq)
* *
* Handling output for network is also simple: we get all the output buffers * Handling output for network is also simple: we get all the output buffers
* and write them (ignoring the first element) to this device's file descriptor * and write them (ignoring the first element) to this device's file descriptor
* (stdout). */ * (/dev/net/tun).
*/
static void handle_net_output(int fd, struct virtqueue *vq) static void handle_net_output(int fd, struct virtqueue *vq)
{ {
unsigned int head, out, in; unsigned int head, out, in;
...@@ -924,7 +925,7 @@ static void enable_fd(int fd, struct virtqueue *vq) ...@@ -924,7 +925,7 @@ static void enable_fd(int fd, struct virtqueue *vq)
write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd)); write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd));
} }
/* Resetting a device is fairly easy. */ /* When the Guest asks us to reset a device, it's is fairly easy. */
static void reset_device(struct device *dev) static void reset_device(struct device *dev)
{ {
struct virtqueue *vq; struct virtqueue *vq;
...@@ -1003,8 +1004,8 @@ static void handle_input(int fd) ...@@ -1003,8 +1004,8 @@ static void handle_input(int fd)
if (select(devices.max_infd+1, &fds, NULL, NULL, &poll) == 0) if (select(devices.max_infd+1, &fds, NULL, NULL, &poll) == 0)
break; break;
/* Otherwise, call the device(s) which have readable /* Otherwise, call the device(s) which have readable file
* file descriptors and a method of handling them. */ * descriptors and a method of handling them. */
for (i = devices.dev; i; i = i->next) { for (i = devices.dev; i; i = i->next) {
if (i->handle_input && FD_ISSET(i->fd, &fds)) { if (i->handle_input && FD_ISSET(i->fd, &fds)) {
int dev_fd; int dev_fd;
...@@ -1015,8 +1016,7 @@ static void handle_input(int fd) ...@@ -1015,8 +1016,7 @@ static void handle_input(int fd)
* should no longer service it. Networking and * should no longer service it. Networking and
* console do this when there's no input * console do this when there's no input
* buffers to deliver into. Console also uses * buffers to deliver into. Console also uses
* it when it discovers that stdin is * it when it discovers that stdin is closed. */
* closed. */
FD_CLR(i->fd, &devices.infds); FD_CLR(i->fd, &devices.infds);
/* Tell waker to ignore it too, by sending a /* Tell waker to ignore it too, by sending a
* negative fd number (-1, since 0 is a valid * negative fd number (-1, since 0 is a valid
...@@ -1033,7 +1033,8 @@ static void handle_input(int fd) ...@@ -1033,7 +1033,8 @@ static void handle_input(int fd)
* *
* All devices need a descriptor so the Guest knows it exists, and a "struct * All devices need a descriptor so the Guest knows it exists, and a "struct
* device" so the Launcher can keep track of it. We have common helper * device" so the Launcher can keep track of it. We have common helper
* routines to allocate and manage them. */ * routines to allocate and manage them.
*/
/* The layout of the device page is a "struct lguest_device_desc" followed by a /* The layout of the device page is a "struct lguest_device_desc" followed by a
* number of virtqueue descriptors, then two sets of feature bits, then an * number of virtqueue descriptors, then two sets of feature bits, then an
...@@ -1078,7 +1079,7 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs, ...@@ -1078,7 +1079,7 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
struct virtqueue **i, *vq = malloc(sizeof(*vq)); struct virtqueue **i, *vq = malloc(sizeof(*vq));
void *p; void *p;
/* First we need some pages for this virtqueue. */ /* First we need some memory for this virtqueue. */
pages = (vring_size(num_descs, getpagesize()) + getpagesize() - 1) pages = (vring_size(num_descs, getpagesize()) + getpagesize() - 1)
/ getpagesize(); / getpagesize();
p = get_pages(pages); p = get_pages(pages);
...@@ -1122,7 +1123,7 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs, ...@@ -1122,7 +1123,7 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
} }
/* The first half of the feature bitmask is for us to advertise features. The /* The first half of the feature bitmask is for us to advertise features. The
* second half if for the Guest to accept features. */ * second half is for the Guest to accept features. */
static void add_feature(struct device *dev, unsigned bit) static void add_feature(struct device *dev, unsigned bit)
{ {
u8 *features = get_feature_bits(dev); u8 *features = get_feature_bits(dev);
...@@ -1151,7 +1152,9 @@ static void set_config(struct device *dev, unsigned len, const void *conf) ...@@ -1151,7 +1152,9 @@ static void set_config(struct device *dev, unsigned len, const void *conf)
} }
/* This routine does all the creation and setup of a new device, including /* This routine does all the creation and setup of a new device, including
* calling new_dev_desc() to allocate the descriptor and device memory. */ * calling new_dev_desc() to allocate the descriptor and device memory.
*
* See what I mean about userspace being boring? */
static struct device *new_device(const char *name, u16 type, int fd, static struct device *new_device(const char *name, u16 type, int fd,
bool (*handle_input)(int, struct device *)) bool (*handle_input)(int, struct device *))
{ {
...@@ -1383,7 +1386,6 @@ struct vblk_info ...@@ -1383,7 +1386,6 @@ struct vblk_info
* Launcher triggers interrupt to Guest. */ * Launcher triggers interrupt to Guest. */
int done_fd; int done_fd;
}; };
/*:*/
/*L:210 /*L:210
* The Disk * The Disk
...@@ -1493,7 +1495,10 @@ static int io_thread(void *_dev) ...@@ -1493,7 +1495,10 @@ static int io_thread(void *_dev)
while (read(vblk->workpipe[0], &c, 1) == 1) { while (read(vblk->workpipe[0], &c, 1) == 1) {
/* We acknowledge each request immediately to reduce latency, /* We acknowledge each request immediately to reduce latency,
* rather than waiting until we've done them all. I haven't * rather than waiting until we've done them all. I haven't
* measured to see if it makes any difference. */ * measured to see if it makes any difference.
*
* That would be an interesting test, wouldn't it? You could
* also try having more than one I/O thread. */
while (service_io(dev)) while (service_io(dev))
write(vblk->done_fd, &c, 1); write(vblk->done_fd, &c, 1);
} }
...@@ -1501,7 +1506,7 @@ static int io_thread(void *_dev) ...@@ -1501,7 +1506,7 @@ static int io_thread(void *_dev)
} }
/* Now we've seen the I/O thread, we return to the Launcher to see what happens /* Now we've seen the I/O thread, we return to the Launcher to see what happens
* when the thread tells us it's completed some I/O. */ * when that thread tells us it's completed some I/O. */
static bool handle_io_finish(int fd, struct device *dev) static bool handle_io_finish(int fd, struct device *dev)
{ {
char c; char c;
...@@ -1573,7 +1578,8 @@ static void setup_block_file(const char *filename) ...@@ -1573,7 +1578,8 @@ static void setup_block_file(const char *filename)
* more work. */ * more work. */
pipe(vblk->workpipe); pipe(vblk->workpipe);
/* Create stack for thread and run it */ /* Create stack for thread and run it. Since stack grows upwards, we
* point the stack pointer to the end of this region. */
stack = malloc(32768); stack = malloc(32768);
/* SIGCHLD - We dont "wait" for our cloned thread, so prevent it from /* SIGCHLD - We dont "wait" for our cloned thread, so prevent it from
* becoming a zombie. */ * becoming a zombie. */
...@@ -1587,14 +1593,14 @@ static void setup_block_file(const char *filename) ...@@ -1587,14 +1593,14 @@ static void setup_block_file(const char *filename)
verbose("device %u: virtblock %llu sectors\n", verbose("device %u: virtblock %llu sectors\n",
devices.device_num, le64_to_cpu(conf.capacity)); devices.device_num, le64_to_cpu(conf.capacity));
} }
/* That's the end of device setup. :*/ /* That's the end of device setup. */
/* Reboot */ /*L:230 Reboot is pretty easy: clean up and exec() the Launcher afresh. */
static void __attribute__((noreturn)) restart_guest(void) static void __attribute__((noreturn)) restart_guest(void)
{ {
unsigned int i; unsigned int i;
/* Closing pipes causes the waker thread and io_threads to die, and /* Closing pipes causes the Waker thread and io_threads to die, and
* closing /dev/lguest cleans up the Guest. Since we don't track all * closing /dev/lguest cleans up the Guest. Since we don't track all
* open fds, we simply close everything beyond stderr. */ * open fds, we simply close everything beyond stderr. */
for (i = 3; i < FD_SETSIZE; i++) for (i = 3; i < FD_SETSIZE; i++)
...@@ -1603,7 +1609,7 @@ static void __attribute__((noreturn)) restart_guest(void) ...@@ -1603,7 +1609,7 @@ static void __attribute__((noreturn)) restart_guest(void)
err(1, "Could not exec %s", main_args[0]); err(1, "Could not exec %s", main_args[0]);
} }
/*L:220 Finally we reach the core of the Launcher, which runs the Guest, serves /*L:220 Finally we reach the core of the Launcher which runs the Guest, serves
* its input and output, and finally, lays it to rest. */ * its input and output, and finally, lays it to rest. */
static void __attribute__((noreturn)) run_guest(int lguest_fd) static void __attribute__((noreturn)) run_guest(int lguest_fd)
{ {
...@@ -1644,7 +1650,7 @@ static void __attribute__((noreturn)) run_guest(int lguest_fd) ...@@ -1644,7 +1650,7 @@ static void __attribute__((noreturn)) run_guest(int lguest_fd)
err(1, "Resetting break"); err(1, "Resetting break");
} }
} }
/* /*L:240
* This is the end of the Launcher. The good news: we are over halfway * This is the end of the Launcher. The good news: we are over halfway
* through! The bad news: the most fiendish part of the code still lies ahead * through! The bad news: the most fiendish part of the code still lies ahead
* of us. * of us.
...@@ -1691,8 +1697,8 @@ int main(int argc, char *argv[]) ...@@ -1691,8 +1697,8 @@ int main(int argc, char *argv[])
* device receive input from a file descriptor, we keep an fdset * device receive input from a file descriptor, we keep an fdset
* (infds) and the maximum fd number (max_infd) with the head of the * (infds) and the maximum fd number (max_infd) with the head of the
* list. We also keep a pointer to the last device. Finally, we keep * list. We also keep a pointer to the last device. Finally, we keep
* the next interrupt number to hand out (1: remember that 0 is used by * the next interrupt number to use for devices (1: remember that 0 is
* the timer). */ * used by the timer). */
FD_ZERO(&devices.infds); FD_ZERO(&devices.infds);
devices.max_infd = -1; devices.max_infd = -1;
devices.lastdev = NULL; devices.lastdev = NULL;
...@@ -1793,8 +1799,8 @@ int main(int argc, char *argv[]) ...@@ -1793,8 +1799,8 @@ int main(int argc, char *argv[])
lguest_fd = tell_kernel(pgdir, start); lguest_fd = tell_kernel(pgdir, start);
/* We fork off a child process, which wakes the Launcher whenever one /* We fork off a child process, which wakes the Launcher whenever one
* of the input file descriptors needs attention. Otherwise we would * of the input file descriptors needs attention. We call this the
* run the Guest until it tries to output something. */ * Waker, and we'll cover it in a moment. */
waker_fd = setup_waker(lguest_fd); waker_fd = setup_waker(lguest_fd);
/* Finally, run the Guest. This doesn't return. */ /* Finally, run the Guest. This doesn't return. */
......
Rusty's Remarkably Unreliable Guide to Lguest __
- or, A Young Coder's Illustrated Hypervisor (___()'`; Rusty's Remarkably Unreliable Guide to Lguest
http://lguest.ozlabs.org /, /` - or, A Young Coder's Illustrated Hypervisor
\\"--\\ http://lguest.ozlabs.org
Lguest is designed to be a minimal hypervisor for the Linux kernel, for Lguest is designed to be a minimal hypervisor for the Linux kernel, for
Linux developers and users to experiment with virtualization with the Linux developers and users to experiment with virtualization with the
...@@ -41,9 +42,13 @@ Running Lguest: ...@@ -41,9 +42,13 @@ Running Lguest:
CONFIG_PHYSICAL_ALIGN=0x100000) CONFIG_PHYSICAL_ALIGN=0x100000)
"Device Drivers": "Device Drivers":
"Block devices"
"Virtio block driver (EXPERIMENTAL)" = M/Y
"Network device support" "Network device support"
"Universal TUN/TAP device driver support" = M/Y "Universal TUN/TAP device driver support" = M/Y
(CONFIG_TUN=m) "Virtio network driver (EXPERIMENTAL)" = M/Y
(CONFIG_VIRTIO_BLK=m, CONFIG_VIRTIO_NET=m and CONFIG_TUN=m)
"Virtualization" "Virtualization"
"Linux hypervisor example code" = M/Y "Linux hypervisor example code" = M/Y
(CONFIG_LGUEST=m) (CONFIG_LGUEST=m)
......
...@@ -84,9 +84,6 @@ policy-routing.txt ...@@ -84,9 +84,6 @@ policy-routing.txt
- IP policy-based routing - IP policy-based routing
ray_cs.txt ray_cs.txt
- Raylink Wireless LAN card driver info. - Raylink Wireless LAN card driver info.
sk98lin.txt
- Marvell Yukon Chipset / SysKonnect SK-98xx compliant Gigabit
Ethernet Adapter family driver info
skfp.txt skfp.txt
- SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info. - SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info.
smc9.txt smc9.txt
......
此差异已折叠。
...@@ -23,8 +23,7 @@ kernel debugging options, such as Kernel Stack Meter or Kernel Tracer, ...@@ -23,8 +23,7 @@ kernel debugging options, such as Kernel Stack Meter or Kernel Tracer,
may implicitly disable the NMI watchdog.] may implicitly disable the NMI watchdog.]
For x86-64, the needed APIC is always compiled in, and the NMI watchdog is For x86-64, the needed APIC is always compiled in, and the NMI watchdog is
always enabled with I/O-APIC mode (nmi_watchdog=1). Currently, local APIC always enabled with I/O-APIC mode (nmi_watchdog=1).
mode (nmi_watchdog=2) does not work on x86-64.
Using local APIC (nmi_watchdog=2) needs the first performance register, so Using local APIC (nmi_watchdog=2) needs the first performance register, so
you can't use it for other purposes (such as high precision performance you can't use it for other purposes (such as high precision performance
......
...@@ -12,5 +12,7 @@ sched-domains.txt ...@@ -12,5 +12,7 @@ sched-domains.txt
- information on scheduling domains. - information on scheduling domains.
sched-nice-design.txt sched-nice-design.txt
- How and why the scheduler's nice levels are implemented. - How and why the scheduler's nice levels are implemented.
sched-rt-group.txt
- real-time group scheduling.
sched-stats.txt sched-stats.txt
- information on schedstats (Linux Scheduler Statistics). - information on schedstats (Linux Scheduler Statistics).
...@@ -116,6 +116,13 @@ low order bit. So when a chip's timing diagram shows the clock ...@@ -116,6 +116,13 @@ low order bit. So when a chip's timing diagram shows the clock
starting low (CPOL=0) and data stabilized for sampling during the starting low (CPOL=0) and data stabilized for sampling during the
trailing clock edge (CPHA=1), that's SPI mode 1. trailing clock edge (CPHA=1), that's SPI mode 1.
Note that the clock mode is relevant as soon as the chipselect goes
active. So the master must set the clock to inactive before selecting
a slave, and the slave can tell the chosen polarity by sampling the
clock level when its select line goes active. That's why many devices
support for example both modes 0 and 3: they don't care about polarity,
and alway clock data in/out on rising clock edges.
How do these driver programming interfaces work? How do these driver programming interfaces work?
------------------------------------------------ ------------------------------------------------
...@@ -379,8 +386,14 @@ any more such messages. ...@@ -379,8 +386,14 @@ any more such messages.
+ when bidirectional reads and writes start ... by how its + when bidirectional reads and writes start ... by how its
sequence of spi_transfer requests is arranged; sequence of spi_transfer requests is arranged;
+ which I/O buffers are used ... each spi_transfer wraps a
buffer for each transfer direction, supporting full duplex
(two pointers, maybe the same one in both cases) and half
duplex (one pointer is NULL) transfers;
+ optionally defining short delays after transfers ... using + optionally defining short delays after transfers ... using
the spi_transfer.delay_usecs setting; the spi_transfer.delay_usecs setting (this delay can be the
only protocol effect, if the buffer length is zero);
+ whether the chipselect becomes inactive after a transfer and + whether the chipselect becomes inactive after a transfer and
any delay ... by using the spi_transfer.cs_change flag; any delay ... by using the spi_transfer.cs_change flag;
......
...@@ -5,6 +5,28 @@ Please use DEFINE_SPINLOCK()/DEFINE_RWLOCK() or ...@@ -5,6 +5,28 @@ Please use DEFINE_SPINLOCK()/DEFINE_RWLOCK() or
__SPIN_LOCK_UNLOCKED()/__RW_LOCK_UNLOCKED() as appropriate for static __SPIN_LOCK_UNLOCKED()/__RW_LOCK_UNLOCKED() as appropriate for static
initialization. initialization.
Most of the time, you can simply turn:
static spinlock_t xxx_lock = SPIN_LOCK_UNLOCKED;
into:
static DEFINE_SPINLOCK(xxx_lock);
Static structure member variables go from:
struct foo bar {
.lock = SPIN_LOCK_UNLOCKED;
};
to:
struct foo bar {
.lock = __SPIN_LOCK_UNLOCKED(bar.lock);
};
Declaration of static rw_locks undergo a similar transformation.
Dynamic initialization, when necessary, may be performed as Dynamic initialization, when necessary, may be performed as
demonstrated below. demonstrated below.
......
...@@ -57,7 +57,7 @@ here; a summary of the common scenarios is presented below: ...@@ -57,7 +57,7 @@ here; a summary of the common scenarios is presented below:
unaligned access to be corrected. unaligned access to be corrected.
- Some architectures are not capable of unaligned memory access, but will - Some architectures are not capable of unaligned memory access, but will
silently perform a different memory access to the one that was requested, silently perform a different memory access to the one that was requested,
resulting a a subtle code bug that is hard to detect! resulting in a subtle code bug that is hard to detect!
It should be obvious from the above that if your code causes unaligned It should be obvious from the above that if your code causes unaligned
memory accesses to happen, your code will not work correctly on certain memory accesses to happen, your code will not work correctly on certain
...@@ -209,7 +209,7 @@ memory and you wish to avoid unaligned access, its usage is as follows: ...@@ -209,7 +209,7 @@ memory and you wish to avoid unaligned access, its usage is as follows:
u32 value = get_unaligned((u32 *) data); u32 value = get_unaligned((u32 *) data);
These macros work work for memory accesses of any length (not just 32 bits as These macros work for memory accesses of any length (not just 32 bits as
in the examples above). Be aware that when compared to standard access of in the examples above). Be aware that when compared to standard access of
aligned memory, using these macros to access unaligned memory can be costly in aligned memory, using these macros to access unaligned memory can be costly in
terms of performance. terms of performance.
......
...@@ -163,6 +163,12 @@ M: A2232@gmx.net ...@@ -163,6 +163,12 @@ M: A2232@gmx.net
L: linux-m68k@lists.linux-m68k.org L: linux-m68k@lists.linux-m68k.org
S: Maintained S: Maintained
AFS FILESYSTEM & AF_RXRPC SOCKET DOMAIN
P: David Howells
M: dhowells@redhat.com
L: linux-afs@lists.infradead.org
S: Supported
AIO AIO
P: Benjamin LaHaise P: Benjamin LaHaise
M: bcrl@kvack.org M: bcrl@kvack.org
...@@ -2116,7 +2122,7 @@ M: reinette.chatre@intel.com ...@@ -2116,7 +2122,7 @@ M: reinette.chatre@intel.com
L: linux-wireless@vger.kernel.org L: linux-wireless@vger.kernel.org
L: ipw3945-devel@lists.sourceforge.net L: ipw3945-devel@lists.sourceforge.net
W: http://intellinuxwireless.org W: http://intellinuxwireless.org
T: git git://intellinuxwireless.org/repos/iwlwifi T: git git://git.kernel.org/pub/scm/linux/kernel/git/rchatre/iwlwifi-2.6.git
S: Supported S: Supported
IOC3 ETHERNET DRIVER IOC3 ETHERNET DRIVER
...@@ -2320,14 +2326,14 @@ L: kexec@lists.infradead.org ...@@ -2320,14 +2326,14 @@ L: kexec@lists.infradead.org
S: Maintained S: Maintained
KPROBES KPROBES
P: Prasanna S Panchamukhi
M: prasanna@in.ibm.com
P: Ananth N Mavinakayanahalli P: Ananth N Mavinakayanahalli
M: ananth@in.ibm.com M: ananth@in.ibm.com
P: Anil S Keshavamurthy P: Anil S Keshavamurthy
M: anil.s.keshavamurthy@intel.com M: anil.s.keshavamurthy@intel.com
P: David S. Miller P: David S. Miller
M: davem@davemloft.net M: davem@davemloft.net
P: Masami Hiramatsu
M: mhiramat@redhat.com
L: linux-kernel@vger.kernel.org L: linux-kernel@vger.kernel.org
S: Maintained S: Maintained
......
VERSION = 2 VERSION = 2
PATCHLEVEL = 6 PATCHLEVEL = 6
SUBLEVEL = 25 SUBLEVEL = 25
EXTRAVERSION = -rc7 EXTRAVERSION = -rc9
NAME = Funky Weasel is Jiggy wit it NAME = Funky Weasel is Jiggy wit it
# *DOCUMENTATION* # *DOCUMENTATION*
......
...@@ -424,11 +424,13 @@ EXPORT_SYMBOL(pci_unmap_page); ...@@ -424,11 +424,13 @@ EXPORT_SYMBOL(pci_unmap_page);
else DMA_ADDRP is undefined. */ else DMA_ADDRP is undefined. */
void * void *
pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp) __pci_alloc_consistent(struct pci_dev *pdev, size_t size,
dma_addr_t *dma_addrp, gfp_t gfp)
{ {
void *cpu_addr; void *cpu_addr;
long order = get_order(size); long order = get_order(size);
gfp_t gfp = GFP_ATOMIC;
gfp &= ~GFP_DMA;
try_again: try_again:
cpu_addr = (void *)__get_free_pages(gfp, order); cpu_addr = (void *)__get_free_pages(gfp, order);
...@@ -458,7 +460,7 @@ pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp) ...@@ -458,7 +460,7 @@ pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp)
return cpu_addr; return cpu_addr;
} }
EXPORT_SYMBOL(pci_alloc_consistent); EXPORT_SYMBOL(__pci_alloc_consistent);
/* Free and unmap a consistent DMA buffer. CPU_ADDR and DMA_ADDR must /* Free and unmap a consistent DMA buffer. CPU_ADDR and DMA_ADDR must
be values that were returned from pci_alloc_consistent. SIZE must be values that were returned from pci_alloc_consistent. SIZE must
......
...@@ -476,6 +476,7 @@ config ARCH_DAVINCI ...@@ -476,6 +476,7 @@ config ARCH_DAVINCI
config ARCH_OMAP config ARCH_OMAP
bool "TI OMAP" bool "TI OMAP"
select GENERIC_GPIO select GENERIC_GPIO
select HAVE_GPIO_LIB
select GENERIC_TIME select GENERIC_TIME
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
help help
......
...@@ -120,6 +120,7 @@ void it8152_irq_demux(unsigned int irq, struct irq_desc *desc) ...@@ -120,6 +120,7 @@ void it8152_irq_demux(unsigned int irq, struct irq_desc *desc)
time, when they all three were 0. */ time, when they all three were 0. */
bits_pd = __raw_readl(IT8152_INTC_PDCNIRR); bits_pd = __raw_readl(IT8152_INTC_PDCNIRR);
bits_lp = __raw_readl(IT8152_INTC_LPCNIRR); bits_lp = __raw_readl(IT8152_INTC_LPCNIRR);
bits_ld = __raw_readl(IT8152_INTC_LDCNIRR);
if (!(bits_ld | bits_lp | bits_pd)) if (!(bits_ld | bits_lp | bits_pd))
return; return;
} }
...@@ -133,14 +134,14 @@ void it8152_irq_demux(unsigned int irq, struct irq_desc *desc) ...@@ -133,14 +134,14 @@ void it8152_irq_demux(unsigned int irq, struct irq_desc *desc)
bits_lp &= ((1 << IT8152_LP_IRQ_COUNT) - 1); bits_lp &= ((1 << IT8152_LP_IRQ_COUNT) - 1);
while (bits_lp) { while (bits_lp) {
i = __ffs(bits_pd); i = __ffs(bits_lp);
it8152_irq(IT8152_LP_IRQ(i)); it8152_irq(IT8152_LP_IRQ(i));
bits_lp &= ~(1 << i); bits_lp &= ~(1 << i);
} }
bits_ld &= ((1 << IT8152_LD_IRQ_COUNT) - 1); bits_ld &= ((1 << IT8152_LD_IRQ_COUNT) - 1);
while (bits_ld) { while (bits_ld) {
i = __ffs(bits_pd); i = __ffs(bits_ld);
it8152_irq(IT8152_LD_IRQ(i)); it8152_irq(IT8152_LD_IRQ(i));
bits_ld &= ~(1 << i); bits_ld &= ~(1 << i);
} }
......
...@@ -336,7 +336,7 @@ ...@@ -336,7 +336,7 @@
CALL(sys_mknodat) CALL(sys_mknodat)
/* 325 */ CALL(sys_fchownat) /* 325 */ CALL(sys_fchownat)
CALL(sys_futimesat) CALL(sys_futimesat)
CALL(sys_fstatat64) CALL(ABI(sys_fstatat64, sys_oabi_fstatat64))
CALL(sys_unlinkat) CALL(sys_unlinkat)
CALL(sys_renameat) CALL(sys_renameat)
/* 330 */ CALL(sys_linkat) /* 330 */ CALL(sys_linkat)
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
* sys_stat64: * sys_stat64:
* sys_lstat64: * sys_lstat64:
* sys_fstat64: * sys_fstat64:
* sys_fstatat64:
* *
* struct stat64 has different sizes and some members are shifted * struct stat64 has different sizes and some members are shifted
* Compatibility wrappers are needed for them and provided below. * Compatibility wrappers are needed for them and provided below.
...@@ -169,6 +170,29 @@ asmlinkage long sys_oabi_fstat64(unsigned long fd, ...@@ -169,6 +170,29 @@ asmlinkage long sys_oabi_fstat64(unsigned long fd,
return error; return error;
} }
asmlinkage long sys_oabi_fstatat64(int dfd,
char __user *filename,
struct oldabi_stat64 __user *statbuf,
int flag)
{
struct kstat stat;
int error = -EINVAL;
if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
goto out;
if (flag & AT_SYMLINK_NOFOLLOW)
error = vfs_lstat_fd(dfd, filename, &stat);
else
error = vfs_stat_fd(dfd, filename, &stat);
if (!error)
error = cp_oldabi_stat64(&stat, statbuf);
out:
return error;
}
struct oabi_flock64 { struct oabi_flock64 {
short l_type; short l_type;
short l_whence; short l_whence;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
obj-y := io.o id.o clock.o irq.o mux.o serial.o devices.o obj-y := io.o id.o clock.o irq.o mux.o serial.o devices.o
obj-$(CONFIG_OMAP_MPU_TIMER) += time.o obj-$(CONFIG_OMAP_MPU_TIMER) += time.o
obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o
# Power Management # Power Management
obj-$(CONFIG_PM) += pm.o sleep.o obj-$(CONFIG_PM) += pm.o sleep.o
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/leds.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
...@@ -183,11 +184,80 @@ static struct platform_device *osk5912_devices[] __initdata = { ...@@ -183,11 +184,80 @@ static struct platform_device *osk5912_devices[] __initdata = {
&osk5912_mcbsp1_device, &osk5912_mcbsp1_device,
}; };
static struct gpio_led tps_leds[] = {
/* NOTE: D9 and D2 have hardware blink support.
* Also, D9 requires non-battery power.
*/
{ .gpio = OSK_TPS_GPIO_LED_D9, .name = "d9", },
{ .gpio = OSK_TPS_GPIO_LED_D2, .name = "d2", },
{ .gpio = OSK_TPS_GPIO_LED_D3, .name = "d3", .active_low = 1,
.default_trigger = "heartbeat", },
};
static struct gpio_led_platform_data tps_leds_data = {
.num_leds = 3,
.leds = tps_leds,
};
static struct platform_device osk5912_tps_leds = {
.name = "leds-gpio",
.id = 0,
.dev.platform_data = &tps_leds_data,
};
static int osk_tps_setup(struct i2c_client *client, void *context)
{
/* Set GPIO 1 HIGH to disable VBUS power supply;
* OHCI driver powers it up/down as needed.
*/
gpio_request(OSK_TPS_GPIO_USB_PWR_EN, "n_vbus_en");
gpio_direction_output(OSK_TPS_GPIO_USB_PWR_EN, 1);
/* Set GPIO 2 high so LED D3 is off by default */
tps65010_set_gpio_out_value(GPIO2, HIGH);
/* Set GPIO 3 low to take ethernet out of reset */
gpio_request(OSK_TPS_GPIO_LAN_RESET, "smc_reset");
gpio_direction_output(OSK_TPS_GPIO_LAN_RESET, 0);
/* GPIO4 is VDD_DSP */
gpio_request(OSK_TPS_GPIO_DSP_PWR_EN, "dsp_power");
gpio_direction_output(OSK_TPS_GPIO_DSP_PWR_EN, 1);
/* REVISIT if DSP support isn't configured, power it off ... */
/* Let LED1 (D9) blink; leds-gpio may override it */
tps65010_set_led(LED1, BLINK);
/* Set LED2 off by default */
tps65010_set_led(LED2, OFF);
/* Enable LOW_PWR handshake */
tps65010_set_low_pwr(ON);
/* Switch VLDO2 to 3.0V for AIC23 */
tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V
| TPS_LDO1_ENABLE);
/* register these three LEDs */
osk5912_tps_leds.dev.parent = &client->dev;
platform_device_register(&osk5912_tps_leds);
return 0;
}
static struct tps65010_board tps_board = {
.base = OSK_TPS_GPIO_BASE,
.outmask = 0x0f,
.setup = osk_tps_setup,
};
static struct i2c_board_info __initdata osk_i2c_board_info[] = { static struct i2c_board_info __initdata osk_i2c_board_info[] = {
{ {
I2C_BOARD_INFO("tps65010", 0x48), I2C_BOARD_INFO("tps65010", 0x48),
.type = "tps65010", .type = "tps65010",
.irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1)), .irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1)),
.platform_data = &tps_board,
}, },
/* TODO when driver support is ready: /* TODO when driver support is ready:
* - aic23 audio chip at 0x1a * - aic23 audio chip at 0x1a
...@@ -198,7 +268,7 @@ static struct i2c_board_info __initdata osk_i2c_board_info[] = { ...@@ -198,7 +268,7 @@ static struct i2c_board_info __initdata osk_i2c_board_info[] = {
static void __init osk_init_smc91x(void) static void __init osk_init_smc91x(void)
{ {
if ((omap_request_gpio(0)) < 0) { if ((gpio_request(0, "smc_irq")) < 0) {
printk("Error requesting gpio 0 for smc91x irq\n"); printk("Error requesting gpio 0 for smc91x irq\n");
return; return;
} }
...@@ -210,7 +280,7 @@ static void __init osk_init_smc91x(void) ...@@ -210,7 +280,7 @@ static void __init osk_init_smc91x(void)
static void __init osk_init_cf(void) static void __init osk_init_cf(void)
{ {
omap_cfg_reg(M7_1610_GPIO62); omap_cfg_reg(M7_1610_GPIO62);
if ((omap_request_gpio(62)) < 0) { if ((gpio_request(62, "cf_irq")) < 0) {
printk("Error requesting gpio 62 for CF irq\n"); printk("Error requesting gpio 62 for CF irq\n");
return; return;
} }
...@@ -334,7 +404,7 @@ static struct platform_device *mistral_devices[] __initdata = { ...@@ -334,7 +404,7 @@ static struct platform_device *mistral_devices[] __initdata = {
static int mistral_get_pendown_state(void) static int mistral_get_pendown_state(void)
{ {
return !omap_get_gpio_datain(4); return !gpio_get_value(4);
} }
static const struct ads7846_platform_data mistral_ts_info = { static const struct ads7846_platform_data mistral_ts_info = {
...@@ -396,25 +466,31 @@ static void __init osk_mistral_init(void) ...@@ -396,25 +466,31 @@ static void __init osk_mistral_init(void)
omap_cfg_reg(W14_1610_CCP_DATAP); omap_cfg_reg(W14_1610_CCP_DATAP);
/* CAM_PWDN */ /* CAM_PWDN */
if (omap_request_gpio(11) == 0) { if (gpio_request(11, "cam_pwdn") == 0) {
omap_cfg_reg(N20_1610_GPIO11); omap_cfg_reg(N20_1610_GPIO11);
omap_set_gpio_direction(11, 0 /* out */); gpio_direction_output(11, 0);
omap_set_gpio_dataout(11, 0 /* off */);
} else } else
pr_debug("OSK+Mistral: CAM_PWDN is awol\n"); pr_debug("OSK+Mistral: CAM_PWDN is awol\n");
/* omap_cfg_reg(P19_1610_GPIO6); */ /* BUSY */ /* omap_cfg_reg(P19_1610_GPIO6); */ /* BUSY */
gpio_request(6, "ts_busy");
gpio_direction_input(6);
omap_cfg_reg(P20_1610_GPIO4); /* PENIRQ */ omap_cfg_reg(P20_1610_GPIO4); /* PENIRQ */
gpio_request(4, "ts_int");
gpio_direction_input(4);
set_irq_type(OMAP_GPIO_IRQ(4), IRQT_FALLING); set_irq_type(OMAP_GPIO_IRQ(4), IRQT_FALLING);
spi_register_board_info(mistral_boardinfo, spi_register_board_info(mistral_boardinfo,
ARRAY_SIZE(mistral_boardinfo)); ARRAY_SIZE(mistral_boardinfo));
/* the sideways button (SW1) is for use as a "wakeup" button */ /* the sideways button (SW1) is for use as a "wakeup" button */
omap_cfg_reg(N15_1610_MPUIO2); omap_cfg_reg(N15_1610_MPUIO2);
if (omap_request_gpio(OMAP_MPUIO(2)) == 0) { if (gpio_request(OMAP_MPUIO(2), "wakeup") == 0) {
int ret = 0; int ret = 0;
omap_set_gpio_direction(OMAP_MPUIO(2), 1);
gpio_direction_input(OMAP_MPUIO(2));
set_irq_type(OMAP_GPIO_IRQ(OMAP_MPUIO(2)), IRQT_RISING); set_irq_type(OMAP_GPIO_IRQ(OMAP_MPUIO(2)), IRQT_RISING);
#ifdef CONFIG_PM #ifdef CONFIG_PM
/* share the IRQ in case someone wants to use the /* share the IRQ in case someone wants to use the
...@@ -425,7 +501,7 @@ static void __init osk_mistral_init(void) ...@@ -425,7 +501,7 @@ static void __init osk_mistral_init(void)
IRQF_SHARED, "mistral_wakeup", IRQF_SHARED, "mistral_wakeup",
&osk_mistral_wake_interrupt); &osk_mistral_wake_interrupt);
if (ret != 0) { if (ret != 0) {
omap_free_gpio(OMAP_MPUIO(2)); gpio_free(OMAP_MPUIO(2));
printk(KERN_ERR "OSK+Mistral: no wakeup irq, %d?\n", printk(KERN_ERR "OSK+Mistral: no wakeup irq, %d?\n",
ret); ret);
} else } else
...@@ -438,10 +514,8 @@ static void __init osk_mistral_init(void) ...@@ -438,10 +514,8 @@ static void __init osk_mistral_init(void)
* board, like the touchscreen, EEPROM, and wakeup (!) switch. * board, like the touchscreen, EEPROM, and wakeup (!) switch.
*/ */
omap_cfg_reg(PWL); omap_cfg_reg(PWL);
if (omap_request_gpio(2) == 0) { if (gpio_request(2, "lcd_pwr") == 0)
omap_set_gpio_direction(2, 0 /* out */); gpio_direction_output(2, 1);
omap_set_gpio_dataout(2, 1 /* on */);
}
platform_add_devices(mistral_devices, ARRAY_SIZE(mistral_devices)); platform_add_devices(mistral_devices, ARRAY_SIZE(mistral_devices));
} }
...@@ -484,44 +558,6 @@ static void __init osk_map_io(void) ...@@ -484,44 +558,6 @@ static void __init osk_map_io(void)
omap1_map_common_io(); omap1_map_common_io();
} }
#ifdef CONFIG_TPS65010
static int __init osk_tps_init(void)
{
if (!machine_is_omap_osk())
return 0;
/* Let LED1 (D9) blink */
tps65010_set_led(LED1, BLINK);
/* Disable LED 2 (D2) */
tps65010_set_led(LED2, OFF);
/* Set GPIO 1 HIGH to disable VBUS power supply;
* OHCI driver powers it up/down as needed.
*/
tps65010_set_gpio_out_value(GPIO1, HIGH);
/* Set GPIO 2 low to turn on LED D3 */
tps65010_set_gpio_out_value(GPIO2, HIGH);
/* Set GPIO 3 low to take ethernet out of reset */
tps65010_set_gpio_out_value(GPIO3, LOW);
/* gpio4 for VDD_DSP */
/* FIXME send power to DSP iff it's configured */
/* Enable LOW_PWR */
tps65010_set_low_pwr(ON);
/* Switch VLDO2 to 3.0V for AIC23 */
tps65010_config_vregs1(TPS_LDO2_ENABLE | TPS_VLDO2_3_0V
| TPS_LDO1_ENABLE);
return 0;
}
fs_initcall(osk_tps_init);
#endif
MACHINE_START(OMAP_OSK, "TI-OSK") MACHINE_START(OMAP_OSK, "TI-OSK")
/* Maintainer: Dirk Behme <dirk.behme@de.bosch.com> */ /* Maintainer: Dirk Behme <dirk.behme@de.bosch.com> */
.phys_io = 0xfff00000, .phys_io = 0xfff00000,
......
/* /*
* linux/arch/arm/mach-omap1/leds-osk.c * linux/arch/arm/mach-omap1/leds-osk.c
* *
* LED driver for OSK, and optionally Mistral QVGA, boards * LED driver for OSK with optional Mistral QVGA board
*/ */
#include <linux/init.h> #include <linux/init.h>
#include <linux/workqueue.h>
#include <linux/i2c/tps65010.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/leds.h> #include <asm/leds.h>
...@@ -20,49 +18,11 @@ ...@@ -20,49 +18,11 @@
#define LED_STATE_CLAIMED (1 << 1) #define LED_STATE_CLAIMED (1 << 1)
static u8 led_state; static u8 led_state;
#define GREEN_LED (1 << 0) /* TPS65010 LED1 */
#define AMBER_LED (1 << 1) /* TPS65010 LED2 */
#define RED_LED (1 << 2) /* TPS65010 GPIO2 */
#define TIMER_LED (1 << 3) /* Mistral board */ #define TIMER_LED (1 << 3) /* Mistral board */
#define IDLE_LED (1 << 4) /* Mistral board */ #define IDLE_LED (1 << 4) /* Mistral board */
static u8 hw_led_state; static u8 hw_led_state;
/* TPS65010 leds are changed using i2c -- from a task context.
* Using one of these for the "idle" LED would be impractical...
*/
#define TPS_LEDS (GREEN_LED | RED_LED | AMBER_LED)
static u8 tps_leds_change;
static void tps_work(struct work_struct *unused)
{
for (;;) {
u8 leds;
local_irq_disable();
leds = tps_leds_change;
tps_leds_change = 0;
local_irq_enable();
if (!leds)
break;
/* careful: the set_led() value is on/off/blink */
if (leds & GREEN_LED)
tps65010_set_led(LED1, !!(hw_led_state & GREEN_LED));
if (leds & AMBER_LED)
tps65010_set_led(LED2, !!(hw_led_state & AMBER_LED));
/* the gpio led doesn't have that issue */
if (leds & RED_LED)
tps65010_set_gpio_out_value(GPIO2,
!(hw_led_state & RED_LED));
}
}
static DECLARE_WORK(work, tps_work);
#ifdef CONFIG_OMAP_OSK_MISTRAL #ifdef CONFIG_OMAP_OSK_MISTRAL
/* For now, all system indicators require the Mistral board, since that /* For now, all system indicators require the Mistral board, since that
...@@ -112,7 +72,6 @@ void osk_leds_event(led_event_t evt) ...@@ -112,7 +72,6 @@ void osk_leds_event(led_event_t evt)
case led_stop: case led_stop:
led_state &= ~LED_STATE_ENABLED; led_state &= ~LED_STATE_ENABLED;
hw_led_state = 0; hw_led_state = 0;
/* NOTE: work may still be pending!! */
break; break;
case led_claim: case led_claim:
...@@ -145,48 +104,11 @@ void osk_leds_event(led_event_t evt) ...@@ -145,48 +104,11 @@ void osk_leds_event(led_event_t evt)
#endif /* CONFIG_OMAP_OSK_MISTRAL */ #endif /* CONFIG_OMAP_OSK_MISTRAL */
/* "green" == tps LED1 (leftmost, normally power-good)
* works only with DC adapter, not on battery power!
*/
case led_green_on:
if (led_state & LED_STATE_CLAIMED)
hw_led_state |= GREEN_LED;
break;
case led_green_off:
if (led_state & LED_STATE_CLAIMED)
hw_led_state &= ~GREEN_LED;
break;
/* "amber" == tps LED2 (middle) */
case led_amber_on:
if (led_state & LED_STATE_CLAIMED)
hw_led_state |= AMBER_LED;
break;
case led_amber_off:
if (led_state & LED_STATE_CLAIMED)
hw_led_state &= ~AMBER_LED;
break;
/* "red" == LED on tps gpio3 (rightmost) */
case led_red_on:
if (led_state & LED_STATE_CLAIMED)
hw_led_state |= RED_LED;
break;
case led_red_off:
if (led_state & LED_STATE_CLAIMED)
hw_led_state &= ~RED_LED;
break;
default: default:
break; break;
} }
leds ^= hw_led_state; leds ^= hw_led_state;
leds &= TPS_LEDS;
if (leds && (led_state & LED_STATE_CLAIMED)) {
tps_leds_change |= leds;
schedule_work(&work);
}
done: done:
local_irq_restore(flags); local_irq_restore(flags);
......
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
* *
* OMAP1 pin multiplexing configurations * OMAP1 pin multiplexing configurations
* *
* Copyright (C) 2003 - 2005 Nokia Corporation * Copyright (C) 2003 - 2008 Nokia Corporation
* *
* Written by Tony Lindgren <tony.lindgren@nokia.com> * Written by Tony Lindgren
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -32,8 +32,10 @@ ...@@ -32,8 +32,10 @@
#ifdef CONFIG_OMAP_MUX #ifdef CONFIG_OMAP_MUX
static struct omap_mux_cfg arch_mux_cfg;
#ifdef CONFIG_ARCH_OMAP730 #ifdef CONFIG_ARCH_OMAP730
struct pin_config __initdata_or_module omap730_pins[] = { static struct pin_config __initdata_or_module omap730_pins[] = {
MUX_CFG_730("E2_730_KBR0", 12, 21, 0, 20, 1, 0) MUX_CFG_730("E2_730_KBR0", 12, 21, 0, 20, 1, 0)
MUX_CFG_730("J7_730_KBR1", 12, 25, 0, 24, 1, 0) MUX_CFG_730("J7_730_KBR1", 12, 25, 0, 24, 1, 0)
MUX_CFG_730("E1_730_KBR2", 12, 29, 0, 28, 1, 0) MUX_CFG_730("E1_730_KBR2", 12, 29, 0, 28, 1, 0)
...@@ -49,10 +51,14 @@ MUX_CFG_730("AA17_730_USB_DM", 2, 21, 0, 20, 0, 0) ...@@ -49,10 +51,14 @@ MUX_CFG_730("AA17_730_USB_DM", 2, 21, 0, 20, 0, 0)
MUX_CFG_730("W16_730_USB_PU_EN", 2, 25, 0, 24, 0, 0) MUX_CFG_730("W16_730_USB_PU_EN", 2, 25, 0, 24, 0, 0)
MUX_CFG_730("W17_730_USB_VBUSI", 2, 29, 0, 28, 0, 0) MUX_CFG_730("W17_730_USB_VBUSI", 2, 29, 0, 28, 0, 0)
}; };
#endif #define OMAP730_PINS_SZ ARRAY_SIZE(omap730_pins)
#else
#define omap730_pins NULL
#define OMAP730_PINS_SZ 0
#endif /* CONFIG_ARCH_OMAP730 */
#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX) #if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
struct pin_config __initdata_or_module omap1xxx_pins[] = { static struct pin_config __initdata_or_module omap1xxx_pins[] = {
/* /*
* description mux mode mux pull pull pull pu_pd pu dbg * description mux mode mux pull pull pull pu_pd pu dbg
* reg offset mode reg bit ena reg * reg offset mode reg bit ena reg
...@@ -306,22 +312,136 @@ MUX_CFG("Y12_1610_CCP_CLKP", 8, 18, 6, 1, 24, 1, 1, 0, 0) ...@@ -306,22 +312,136 @@ MUX_CFG("Y12_1610_CCP_CLKP", 8, 18, 6, 1, 24, 1, 1, 0, 0)
MUX_CFG("W13_1610_CCP_CLKM", 9, 0, 6, 1, 28, 1, 1, 0, 0) MUX_CFG("W13_1610_CCP_CLKM", 9, 0, 6, 1, 28, 1, 1, 0, 0)
MUX_CFG("W14_1610_CCP_DATAP", 9, 24, 6, 2, 4, 1, 2, 0, 0) MUX_CFG("W14_1610_CCP_DATAP", 9, 24, 6, 2, 4, 1, 2, 0, 0)
MUX_CFG("Y14_1610_CCP_DATAM", 9, 21, 6, 2, 3, 1, 2, 0, 0) MUX_CFG("Y14_1610_CCP_DATAM", 9, 21, 6, 2, 3, 1, 2, 0, 0)
}; };
#define OMAP1XXX_PINS_SZ ARRAY_SIZE(omap1xxx_pins)
#else
#define omap1xxx_pins NULL
#define OMAP1XXX_PINS_SZ 0
#endif /* CONFIG_ARCH_OMAP15XX || CONFIG_ARCH_OMAP16XX */ #endif /* CONFIG_ARCH_OMAP15XX || CONFIG_ARCH_OMAP16XX */
int __init omap1_mux_init(void) int __init_or_module omap1_cfg_reg(const struct pin_config *cfg)
{ {
static DEFINE_SPINLOCK(mux_spin_lock);
#ifdef CONFIG_ARCH_OMAP730 unsigned long flags;
omap_mux_register(omap730_pins, ARRAY_SIZE(omap730_pins)); unsigned int reg_orig = 0, reg = 0, pu_pd_orig = 0, pu_pd = 0,
pull_orig = 0, pull = 0;
unsigned int mask, warn = 0;
/* Check the mux register in question */
if (cfg->mux_reg) {
unsigned tmp1, tmp2;
spin_lock_irqsave(&mux_spin_lock, flags);
reg_orig = omap_readl(cfg->mux_reg);
/* The mux registers always seem to be 3 bits long */
mask = (0x7 << cfg->mask_offset);
tmp1 = reg_orig & mask;
reg = reg_orig & ~mask;
tmp2 = (cfg->mask << cfg->mask_offset);
reg |= tmp2;
if (tmp1 != tmp2)
warn = 1;
omap_writel(reg, cfg->mux_reg);
spin_unlock_irqrestore(&mux_spin_lock, flags);
}
/* Check for pull up or pull down selection on 1610 */
if (!cpu_is_omap15xx()) {
if (cfg->pu_pd_reg && cfg->pull_val) {
spin_lock_irqsave(&mux_spin_lock, flags);
pu_pd_orig = omap_readl(cfg->pu_pd_reg);
mask = 1 << cfg->pull_bit;
if (cfg->pu_pd_val) {
if (!(pu_pd_orig & mask))
warn = 1;
/* Use pull up */
pu_pd = pu_pd_orig | mask;
} else {
if (pu_pd_orig & mask)
warn = 1;
/* Use pull down */
pu_pd = pu_pd_orig & ~mask;
}
omap_writel(pu_pd, cfg->pu_pd_reg);
spin_unlock_irqrestore(&mux_spin_lock, flags);
}
}
/* Check for an associated pull down register */
if (cfg->pull_reg) {
spin_lock_irqsave(&mux_spin_lock, flags);
pull_orig = omap_readl(cfg->pull_reg);
mask = 1 << cfg->pull_bit;
if (cfg->pull_val) {
if (pull_orig & mask)
warn = 1;
/* Low bit = pull enabled */
pull = pull_orig & ~mask;
} else {
if (!(pull_orig & mask))
warn = 1;
/* High bit = pull disabled */
pull = pull_orig | mask;
}
omap_writel(pull, cfg->pull_reg);
spin_unlock_irqrestore(&mux_spin_lock, flags);
}
if (warn) {
#ifdef CONFIG_OMAP_MUX_WARNINGS
printk(KERN_WARNING "MUX: initialized %s\n", cfg->name);
#endif #endif
}
#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
omap_mux_register(omap1xxx_pins, ARRAY_SIZE(omap1xxx_pins)); #ifdef CONFIG_OMAP_MUX_DEBUG
if (cfg->debug || warn) {
printk("MUX: Setting register %s\n", cfg->name);
printk(" %s (0x%08x) = 0x%08x -> 0x%08x\n",
cfg->mux_reg_name, cfg->mux_reg, reg_orig, reg);
if (!cpu_is_omap15xx()) {
if (cfg->pu_pd_reg && cfg->pull_val) {
printk(" %s (0x%08x) = 0x%08x -> 0x%08x\n",
cfg->pu_pd_name, cfg->pu_pd_reg,
pu_pd_orig, pu_pd);
}
}
if (cfg->pull_reg)
printk(" %s (0x%08x) = 0x%08x -> 0x%08x\n",
cfg->pull_name, cfg->pull_reg, pull_orig, pull);
}
#endif #endif
#ifdef CONFIG_OMAP_MUX_ERRORS
return warn ? -ETXTBSY : 0;
#else
return 0; return 0;
#endif
}
int __init omap1_mux_init(void)
{
if (cpu_is_omap730()) {
arch_mux_cfg.pins = omap730_pins;
arch_mux_cfg.size = OMAP730_PINS_SZ;
arch_mux_cfg.cfg_reg = omap1_cfg_reg;
}
if (cpu_is_omap15xx() || cpu_is_omap16xx()) {
arch_mux_cfg.pins = omap1xxx_pins;
arch_mux_cfg.size = OMAP1XXX_PINS_SZ;
arch_mux_cfg.cfg_reg = omap1_cfg_reg;
}
return omap_mux_register(&arch_mux_cfg);
} }
#endif #endif
...@@ -56,37 +56,6 @@ ...@@ -56,37 +56,6 @@
#define OMAP_MPU_TIMER_BASE OMAP_MPU_TIMER1_BASE #define OMAP_MPU_TIMER_BASE OMAP_MPU_TIMER1_BASE
#define OMAP_MPU_TIMER_OFFSET 0x100 #define OMAP_MPU_TIMER_OFFSET 0x100
/* cycles to nsec conversions taken from arch/i386/kernel/timers/timer_tsc.c,
* converted to use kHz by Kevin Hilman */
/* convert from cycles(64bits) => nanoseconds (64bits)
* basic equation:
* ns = cycles / (freq / ns_per_sec)
* ns = cycles * (ns_per_sec / freq)
* ns = cycles * (10^9 / (cpu_khz * 10^3))
* ns = cycles * (10^6 / cpu_khz)
*
* Then we use scaling math (suggested by george at mvista.com) to get:
* ns = cycles * (10^6 * SC / cpu_khz / SC
* ns = cycles * cyc2ns_scale / SC
*
* And since SC is a constant power of two, we can convert the div
* into a shift.
* -johnstul at us.ibm.com "math is hard, lets go shopping!"
*/
static unsigned long cyc2ns_scale;
#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
static inline void set_cyc2ns_scale(unsigned long cpu_khz)
{
cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz;
}
static inline unsigned long long cycles_2_ns(unsigned long long cyc)
{
return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
}
typedef struct { typedef struct {
u32 cntl; /* CNTL_TIMER, R/W */ u32 cntl; /* CNTL_TIMER, R/W */
u32 load_tim; /* LOAD_TIM, W */ u32 load_tim; /* LOAD_TIM, W */
...@@ -194,8 +163,6 @@ static struct irqaction omap_mpu_timer1_irq = { ...@@ -194,8 +163,6 @@ static struct irqaction omap_mpu_timer1_irq = {
static __init void omap_init_mpu_timer(unsigned long rate) static __init void omap_init_mpu_timer(unsigned long rate)
{ {
set_cyc2ns_scale(rate / 1000);
setup_irq(INT_TIMER1, &omap_mpu_timer1_irq); setup_irq(INT_TIMER1, &omap_mpu_timer1_irq);
omap_mpu_timer_start(0, (rate / HZ) - 1, 1); omap_mpu_timer_start(0, (rate / HZ) - 1, 1);
...@@ -260,22 +227,6 @@ static void __init omap_init_clocksource(unsigned long rate) ...@@ -260,22 +227,6 @@ static void __init omap_init_clocksource(unsigned long rate)
printk(err, clocksource_mpu.name); printk(err, clocksource_mpu.name);
} }
/*
* Scheduler clock - returns current time in nanosec units.
*/
unsigned long long sched_clock(void)
{
unsigned long ticks = 0 - omap_mpu_timer_read(1);
unsigned long long ticks64;
ticks64 = omap_mpu_timer2_overflows;
ticks64 <<= 32;
ticks64 |= ticks;
return cycles_2_ns(ticks64);
}
/* /*
* --------------------------------------------------------------------------- * ---------------------------------------------------------------------------
* Timer initialization * Timer initialization
......
/* /*
* linux/arch/arm/plat-omap/timer32k.c * linux/arch/arm/mach-omap1/timer32k.c
* *
* OMAP 32K Timer * OMAP 32K Timer
* *
...@@ -70,8 +70,6 @@ struct sys_timer omap_timer; ...@@ -70,8 +70,6 @@ struct sys_timer omap_timer;
#if defined(CONFIG_ARCH_OMAP16XX) #if defined(CONFIG_ARCH_OMAP16XX)
#define TIMER_32K_SYNCHRONIZED 0xfffbc410 #define TIMER_32K_SYNCHRONIZED 0xfffbc410
#elif defined(CONFIG_ARCH_OMAP24XX)
#define TIMER_32K_SYNCHRONIZED (OMAP24XX_32KSYNCT_BASE + 0x10)
#else #else
#error OMAP 32KHz timer does not currently work on 15XX! #error OMAP 32KHz timer does not currently work on 15XX!
#endif #endif
...@@ -93,8 +91,6 @@ struct sys_timer omap_timer; ...@@ -93,8 +91,6 @@ struct sys_timer omap_timer;
#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \ #define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \
(((nr_jiffies) * (clock_rate)) / HZ) (((nr_jiffies) * (clock_rate)) / HZ)
#if defined(CONFIG_ARCH_OMAP1)
static inline void omap_32k_timer_write(int val, int reg) static inline void omap_32k_timer_write(int val, int reg)
{ {
omap_writew(val, OMAP1_32K_TIMER_BASE + reg); omap_writew(val, OMAP1_32K_TIMER_BASE + reg);
...@@ -120,30 +116,14 @@ static inline void omap_32k_timer_stop(void) ...@@ -120,30 +116,14 @@ static inline void omap_32k_timer_stop(void)
#define omap_32k_timer_ack_irq() #define omap_32k_timer_ack_irq()
#elif defined(CONFIG_ARCH_OMAP2) static int omap_32k_timer_set_next_event(unsigned long delta,
struct clock_event_device *dev)
static struct omap_dm_timer *gptimer;
static inline void omap_32k_timer_start(unsigned long load_val)
{
omap_dm_timer_set_load(gptimer, 1, 0xffffffff - load_val);
omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW);
omap_dm_timer_start(gptimer);
}
static inline void omap_32k_timer_stop(void)
{ {
omap_dm_timer_stop(gptimer); omap_32k_timer_start(delta);
}
static inline void omap_32k_timer_ack_irq(void) return 0;
{
u32 status = omap_dm_timer_read_status(gptimer);
omap_dm_timer_write_status(gptimer, status);
} }
#endif
static void omap_32k_timer_set_mode(enum clock_event_mode mode, static void omap_32k_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt) struct clock_event_device *evt)
{ {
...@@ -164,8 +144,9 @@ static void omap_32k_timer_set_mode(enum clock_event_mode mode, ...@@ -164,8 +144,9 @@ static void omap_32k_timer_set_mode(enum clock_event_mode mode,
static struct clock_event_device clockevent_32k_timer = { static struct clock_event_device clockevent_32k_timer = {
.name = "32k-timer", .name = "32k-timer",
.features = CLOCK_EVT_FEAT_PERIODIC, .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.shift = 32, .shift = 32,
.set_next_event = omap_32k_timer_set_next_event,
.set_mode = omap_32k_timer_set_mode, .set_mode = omap_32k_timer_set_mode,
}; };
...@@ -178,32 +159,6 @@ static inline unsigned long omap_32k_sync_timer_read(void) ...@@ -178,32 +159,6 @@ static inline unsigned long omap_32k_sync_timer_read(void)
return omap_readl(TIMER_32K_SYNCHRONIZED); return omap_readl(TIMER_32K_SYNCHRONIZED);
} }
/*
* Rounds down to nearest usec. Note that this will overflow for larger values.
*/
static inline unsigned long omap_32k_ticks_to_usecs(unsigned long ticks_32k)
{
return (ticks_32k * 5*5*5*5*5*5) >> 9;
}
/*
* Rounds down to nearest nsec.
*/
static inline unsigned long long
omap_32k_ticks_to_nsecs(unsigned long ticks_32k)
{
return (unsigned long long) ticks_32k * 1000 * 5*5*5*5*5*5 >> 9;
}
/*
* Returns current time from boot in nsecs. It's OK for this to wrap
* around for now, as it's just a relative time stamp.
*/
unsigned long long sched_clock(void)
{
return omap_32k_ticks_to_nsecs(omap_32k_sync_timer_read());
}
static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id) static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id)
{ {
struct clock_event_device *evt = &clockevent_32k_timer; struct clock_event_device *evt = &clockevent_32k_timer;
...@@ -222,23 +177,8 @@ static struct irqaction omap_32k_timer_irq = { ...@@ -222,23 +177,8 @@ static struct irqaction omap_32k_timer_irq = {
static __init void omap_init_32k_timer(void) static __init void omap_init_32k_timer(void)
{ {
if (cpu_class_is_omap1())
setup_irq(INT_OS_TIMER, &omap_32k_timer_irq); setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
#ifdef CONFIG_ARCH_OMAP2
/* REVISIT: Check 24xx TIOCP_CFG settings after idle works */
if (cpu_is_omap24xx()) {
gptimer = omap_dm_timer_request_specific(1);
BUG_ON(gptimer == NULL);
omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_32_KHZ);
setup_irq(omap_dm_timer_get_irq(gptimer), &omap_32k_timer_irq);
omap_dm_timer_set_int_enable(gptimer,
OMAP_TIMER_INT_CAPTURE | OMAP_TIMER_INT_OVERFLOW |
OMAP_TIMER_INT_MATCH);
}
#endif
clockevent_32k_timer.mult = div_sc(OMAP_32K_TICKS_PER_SEC, clockevent_32k_timer.mult = div_sc(OMAP_32K_TICKS_PER_SEC,
NSEC_PER_SEC, NSEC_PER_SEC,
clockevent_32k_timer.shift); clockevent_32k_timer.shift);
......
...@@ -3,13 +3,15 @@ ...@@ -3,13 +3,15 @@
# #
# Common support # Common support
obj-y := irq.o id.o io.o sram-fn.o memory.o prcm.o clock.o mux.o devices.o \ obj-y := irq.o id.o io.o sram-fn.o memory.o control.o prcm.o clock.o mux.o \
serial.o gpmc.o devices.o serial.o gpmc.o timer-gp.o
obj-$(CONFIG_OMAP_MPU_TIMER) += timer-gp.o
# Power Management # Power Management
obj-$(CONFIG_PM) += pm.o pm-domain.o sleep.o obj-$(CONFIG_PM) += pm.o sleep.o
# Clock framework
obj-$(CONFIG_ARCH_OMAP2) += clock24xx.o
obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o
# Specific board support # Specific board support
obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o
......
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#include <asm/arch/board.h> #include <asm/arch/board.h>
#include <asm/arch/common.h> #include <asm/arch/common.h>
#include <asm/arch/gpmc.h> #include <asm/arch/gpmc.h>
#include "prcm-regs.h"
#include <asm/io.h> #include <asm/io.h>
...@@ -125,15 +124,18 @@ static inline void __init sdp2430_init_smc91x(void) ...@@ -125,15 +124,18 @@ static inline void __init sdp2430_init_smc91x(void)
int eth_cs; int eth_cs;
unsigned long cs_mem_base; unsigned long cs_mem_base;
unsigned int rate; unsigned int rate;
struct clk *l3ck; struct clk *gpmc_fck;
eth_cs = SDP2430_SMC91X_CS; eth_cs = SDP2430_SMC91X_CS;
l3ck = clk_get(NULL, "core_l3_ck"); gpmc_fck = clk_get(NULL, "gpmc_fck"); /* Always on ENABLE_ON_INIT */
if (IS_ERR(l3ck)) if (IS_ERR(gpmc_fck)) {
rate = 100000000; WARN_ON(1);
else return;
rate = clk_get_rate(l3ck); }
clk_enable(gpmc_fck);
rate = clk_get_rate(gpmc_fck);
/* Make sure CS1 timings are correct, for 2430 always muxed */ /* Make sure CS1 timings are correct, for 2430 always muxed */
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG1, 0x00011200); gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG1, 0x00011200);
...@@ -160,7 +162,7 @@ static inline void __init sdp2430_init_smc91x(void) ...@@ -160,7 +162,7 @@ static inline void __init sdp2430_init_smc91x(void)
if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) { if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
printk(KERN_ERR "Failed to request GPMC mem for smc91x\n"); printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
return; goto out;
} }
sdp2430_smc91x_resources[0].start = cs_mem_base + 0x300; sdp2430_smc91x_resources[0].start = cs_mem_base + 0x300;
...@@ -171,10 +173,13 @@ static inline void __init sdp2430_init_smc91x(void) ...@@ -171,10 +173,13 @@ static inline void __init sdp2430_init_smc91x(void)
printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n", printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
OMAP24XX_ETHR_GPIO_IRQ); OMAP24XX_ETHR_GPIO_IRQ);
gpmc_cs_free(eth_cs); gpmc_cs_free(eth_cs);
return; goto out;
} }
omap_set_gpio_direction(OMAP24XX_ETHR_GPIO_IRQ, 1); omap_set_gpio_direction(OMAP24XX_ETHR_GPIO_IRQ, 1);
out:
clk_disable(gpmc_fck);
clk_put(gpmc_fck);
} }
static void __init omap_2430sdp_init_irq(void) static void __init omap_2430sdp_init_irq(void)
......
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
...@@ -39,7 +41,7 @@ ...@@ -39,7 +41,7 @@
#include <asm/arch/board.h> #include <asm/arch/board.h>
#include <asm/arch/common.h> #include <asm/arch/common.h>
#include <asm/arch/gpmc.h> #include <asm/arch/gpmc.h>
#include "prcm-regs.h" #include <asm/arch/control.h>
/* LED & Switch macros */ /* LED & Switch macros */
#define LED0_GPIO13 13 #define LED0_GPIO13 13
...@@ -187,17 +189,47 @@ static inline void __init apollon_init_smc91x(void) ...@@ -187,17 +189,47 @@ static inline void __init apollon_init_smc91x(void)
{ {
unsigned long base; unsigned long base;
unsigned int rate;
struct clk *gpmc_fck;
int eth_cs;
gpmc_fck = clk_get(NULL, "gpmc_fck"); /* Always on ENABLE_ON_INIT */
if (IS_ERR(gpmc_fck)) {
WARN_ON(1);
return;
}
clk_enable(gpmc_fck);
rate = clk_get_rate(gpmc_fck);
eth_cs = APOLLON_ETH_CS;
/* Make sure CS1 timings are correct */ /* Make sure CS1 timings are correct */
GPMC_CONFIG1_1 = 0x00011203; gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG1, 0x00011200);
GPMC_CONFIG2_1 = 0x001f1f01;
GPMC_CONFIG3_1 = 0x00080803; if (rate >= 160000000) {
GPMC_CONFIG4_1 = 0x1c091c09; gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f01);
GPMC_CONFIG5_1 = 0x041f1f1f; gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080803);
GPMC_CONFIG6_1 = 0x000004c4; gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1c0b1c0a);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
} else if (rate >= 130000000) {
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
} else {/* rate = 100000000 */
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x031A1F1F);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2);
}
if (gpmc_cs_request(APOLLON_ETH_CS, SZ_16M, &base) < 0) { if (gpmc_cs_request(APOLLON_ETH_CS, SZ_16M, &base) < 0) {
printk(KERN_ERR "Failed to request GPMC CS for smc91x\n"); printk(KERN_ERR "Failed to request GPMC CS for smc91x\n");
return; goto out;
} }
apollon_smc91x_resources[0].start = base + 0x300; apollon_smc91x_resources[0].start = base + 0x300;
apollon_smc91x_resources[0].end = base + 0x30f; apollon_smc91x_resources[0].end = base + 0x30f;
...@@ -208,9 +240,13 @@ static inline void __init apollon_init_smc91x(void) ...@@ -208,9 +240,13 @@ static inline void __init apollon_init_smc91x(void)
printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n", printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n",
APOLLON_ETHR_GPIO_IRQ); APOLLON_ETHR_GPIO_IRQ);
gpmc_cs_free(APOLLON_ETH_CS); gpmc_cs_free(APOLLON_ETH_CS);
return; goto out;
} }
omap_set_gpio_direction(APOLLON_ETHR_GPIO_IRQ, 1); omap_set_gpio_direction(APOLLON_ETHR_GPIO_IRQ, 1);
out:
clk_disable(gpmc_fck);
clk_put(gpmc_fck);
} }
static void __init omap_apollon_init_irq(void) static void __init omap_apollon_init_irq(void)
...@@ -330,6 +366,8 @@ static void __init apollon_usb_init(void) ...@@ -330,6 +366,8 @@ static void __init apollon_usb_init(void)
static void __init omap_apollon_init(void) static void __init omap_apollon_init(void)
{ {
u32 v;
apollon_led_init(); apollon_led_init();
apollon_sw_init(); apollon_sw_init();
apollon_flash_init(); apollon_flash_init();
...@@ -339,7 +377,9 @@ static void __init omap_apollon_init(void) ...@@ -339,7 +377,9 @@ static void __init omap_apollon_init(void)
omap_cfg_reg(W19_24XX_SYS_NIRQ); omap_cfg_reg(W19_24XX_SYS_NIRQ);
/* Use Interal loop-back in MMC/SDIO Module Input Clock selection */ /* Use Interal loop-back in MMC/SDIO Module Input Clock selection */
CONTROL_DEVCONF |= (1 << 24); v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
v |= (1 << 24);
omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0);
/* /*
* Make sure the serial ports are muxed on at this point. * Make sure the serial ports are muxed on at this point.
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
...@@ -26,6 +28,7 @@ ...@@ -26,6 +28,7 @@
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <asm/mach/flash.h> #include <asm/mach/flash.h>
#include <asm/arch/control.h>
#include <asm/arch/gpio.h> #include <asm/arch/gpio.h>
#include <asm/arch/gpioexpander.h> #include <asm/arch/gpioexpander.h>
#include <asm/arch/mux.h> #include <asm/arch/mux.h>
...@@ -36,10 +39,13 @@ ...@@ -36,10 +39,13 @@
#include <asm/arch/keypad.h> #include <asm/arch/keypad.h>
#include <asm/arch/menelaus.h> #include <asm/arch/menelaus.h>
#include <asm/arch/dma.h> #include <asm/arch/dma.h>
#include "prcm-regs.h" #include <asm/arch/gpmc.h>
#include <asm/io.h> #include <asm/io.h>
#define H4_FLASH_CS 0
#define H4_SMC91X_CS 1
static unsigned int row_gpios[6] = { 88, 89, 124, 11, 6, 96 }; static unsigned int row_gpios[6] = { 88, 89, 124, 11, 6, 96 };
static unsigned int col_gpios[7] = { 90, 91, 100, 36, 12, 97, 98 }; static unsigned int col_gpios[7] = { 90, 91, 100, 36, 12, 97, 98 };
...@@ -116,8 +122,6 @@ static struct flash_platform_data h4_flash_data = { ...@@ -116,8 +122,6 @@ static struct flash_platform_data h4_flash_data = {
}; };
static struct resource h4_flash_resource = { static struct resource h4_flash_resource = {
.start = H4_CS0_BASE,
.end = H4_CS0_BASE + SZ_64M - 1,
.flags = IORESOURCE_MEM, .flags = IORESOURCE_MEM,
}; };
...@@ -253,21 +257,107 @@ static struct platform_device *h4_devices[] __initdata = { ...@@ -253,21 +257,107 @@ static struct platform_device *h4_devices[] __initdata = {
&h4_lcd_device, &h4_lcd_device,
}; };
/* 2420 Sysboot setup (2430 is different) */
static u32 get_sysboot_value(void)
{
return (omap_ctrl_readl(OMAP24XX_CONTROL_STATUS) &
(OMAP2_SYSBOOT_5_MASK | OMAP2_SYSBOOT_4_MASK |
OMAP2_SYSBOOT_3_MASK | OMAP2_SYSBOOT_2_MASK |
OMAP2_SYSBOOT_1_MASK | OMAP2_SYSBOOT_0_MASK));
}
/* H4-2420's always used muxed mode, H4-2422's always use non-muxed
*
* Note: OMAP-GIT doesn't correctly do is_cpu_omap2422 and is_cpu_omap2423
* correctly. The macro needs to look at production_id not just hawkeye.
*/
static u32 is_gpmc_muxed(void)
{
u32 mux;
mux = get_sysboot_value();
if ((mux & 0xF) == 0xd)
return 1; /* NAND config (could be either) */
if (mux & 0x2) /* if mux'ed */
return 1;
else
return 0;
}
static inline void __init h4_init_debug(void) static inline void __init h4_init_debug(void)
{ {
int eth_cs;
unsigned long cs_mem_base;
unsigned int muxed, rate;
struct clk *gpmc_fck;
eth_cs = H4_SMC91X_CS;
gpmc_fck = clk_get(NULL, "gpmc_fck"); /* Always on ENABLE_ON_INIT */
if (IS_ERR(gpmc_fck)) {
WARN_ON(1);
return;
}
clk_enable(gpmc_fck);
rate = clk_get_rate(gpmc_fck);
clk_disable(gpmc_fck);
clk_put(gpmc_fck);
if (is_gpmc_muxed())
muxed = 0x200;
else
muxed = 0;
/* Make sure CS1 timings are correct */ /* Make sure CS1 timings are correct */
GPMC_CONFIG1_1 = 0x00011200; gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG1,
GPMC_CONFIG2_1 = 0x001f1f01; 0x00011000 | muxed);
GPMC_CONFIG3_1 = 0x00080803;
GPMC_CONFIG4_1 = 0x1c091c09; if (rate >= 160000000) {
GPMC_CONFIG5_1 = 0x041f1f1f; gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f01);
GPMC_CONFIG6_1 = 0x000004c4; gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080803);
GPMC_CONFIG7_1 = 0x00000f40 | (0x08000000 >> 24); gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1c0b1c0a);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
} else if (rate >= 130000000) {
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x041f1F1F);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000004C4);
} else {/* rate = 100000000 */
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG2, 0x001f1f00);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG3, 0x00080802);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG4, 0x1C091C09);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG5, 0x031A1F1F);
gpmc_cs_write_reg(eth_cs, GPMC_CS_CONFIG6, 0x000003C2);
}
if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
goto out;
}
udelay(100); udelay(100);
omap_cfg_reg(M15_24XX_GPIO92); omap_cfg_reg(M15_24XX_GPIO92);
if (debug_card_init(cs_mem_base, OMAP24XX_ETHR_GPIO_IRQ) < 0) if (debug_card_init(cs_mem_base, OMAP24XX_ETHR_GPIO_IRQ) < 0)
gpmc_cs_free(eth_cs); gpmc_cs_free(eth_cs);
out:
clk_disable(gpmc_fck);
clk_put(gpmc_fck);
}
static void __init h4_init_flash(void)
{
unsigned long base;
if (gpmc_cs_request(H4_FLASH_CS, SZ_64M, &base) < 0) {
printk("Can't request GPMC CS for flash\n");
return;
}
h4_flash_resource.start = base;
h4_flash_resource.end = base + SZ_64M - 1;
} }
static void __init omap_h4_init_irq(void) static void __init omap_h4_init_irq(void)
...@@ -275,6 +365,7 @@ static void __init omap_h4_init_irq(void) ...@@ -275,6 +365,7 @@ static void __init omap_h4_init_irq(void)
omap2_init_common_hw(); omap2_init_common_hw();
omap_init_irq(); omap_init_irq();
omap_gpio_init(); omap_gpio_init();
h4_init_flash();
} }
static struct omap_uart_config h4_uart_config __initdata = { static struct omap_uart_config h4_uart_config __initdata = {
......
此差异已折叠。
此差异已折叠。
/*
* linux/arch/arm/mach-omap2/clock.c
*
* Copyright (C) 2005-2008 Texas Instruments, Inc.
* Copyright (C) 2004-2008 Nokia Corporation
*
* Contacts:
* Richard Woodruff <r-woodruff2@ti.com>
* Paul Walmsley
*
* Based on earlier work by Tuukka Tikkanen, Tony Lindgren,
* Gordon McNutt and RidgeRun, Inc.
*
* 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.
*/
#undef DEBUG
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/cpufreq.h>
#include <asm/arch/clock.h>
#include <asm/arch/sram.h>
#include <asm/div64.h>
#include <asm/bitops.h>
#include "memory.h"
#include "clock.h"
#include "clock24xx.h"
#include "prm.h"
#include "prm-regbits-24xx.h"
#include "cm.h"
#include "cm-regbits-24xx.h"
/* CM_CLKEN_PLL.EN_{54,96}M_PLL options (24XX) */
#define EN_APLL_STOPPED 0
#define EN_APLL_LOCKED 3
/* CM_CLKSEL1_PLL.APLLS_CLKIN options (24XX) */
#define APLLS_CLKIN_19_2MHZ 0
#define APLLS_CLKIN_13MHZ 2
#define APLLS_CLKIN_12MHZ 3
/* #define DOWN_VARIABLE_DPLL 1 */ /* Experimental */
static struct prcm_config *curr_prcm_set;
static struct clk *vclk;
static struct clk *sclk;
/*-------------------------------------------------------------------------
* Omap24xx specific clock functions
*-------------------------------------------------------------------------*/
/* This actually returns the rate of core_ck, not dpll_ck. */
static u32 omap2_get_dpll_rate_24xx(struct clk *tclk)
{
long long dpll_clk;
u8 amult;
dpll_clk = omap2_get_dpll_rate(tclk);
amult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
amult &= OMAP24XX_CORE_CLK_SRC_MASK;
dpll_clk *= amult;
return dpll_clk;
}
static int omap2_enable_osc_ck(struct clk *clk)
{
u32 pcc;
pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
__raw_writel(pcc & ~OMAP_AUTOEXTCLKMODE_MASK,
OMAP24XX_PRCM_CLKSRC_CTRL);
return 0;
}
static void omap2_disable_osc_ck(struct clk *clk)
{
u32 pcc;
pcc = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
__raw_writel(pcc | OMAP_AUTOEXTCLKMODE_MASK,
OMAP24XX_PRCM_CLKSRC_CTRL);
}
#ifdef OLD_CK
/* Recalculate SYST_CLK */
static void omap2_sys_clk_recalc(struct clk * clk)
{
u32 div = PRCM_CLKSRC_CTRL;
div &= (1 << 7) | (1 << 6); /* Test if ext clk divided by 1 or 2 */
div >>= clk->rate_offset;
clk->rate = (clk->parent->rate / div);
propagate_rate(clk);
}
#endif /* OLD_CK */
/* Enable an APLL if off */
static int omap2_clk_fixed_enable(struct clk *clk)
{
u32 cval, apll_mask;
apll_mask = EN_APLL_LOCKED << clk->enable_bit;
cval = cm_read_mod_reg(PLL_MOD, CM_CLKEN);
if ((cval & apll_mask) == apll_mask)
return 0; /* apll already enabled */
cval &= ~apll_mask;
cval |= apll_mask;
cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN);
if (clk == &apll96_ck)
cval = OMAP24XX_ST_96M_APLL;
else if (clk == &apll54_ck)
cval = OMAP24XX_ST_54M_APLL;
omap2_wait_clock_ready(OMAP_CM_REGADDR(PLL_MOD, CM_IDLEST), cval,
clk->name);
/*
* REVISIT: Should we return an error code if omap2_wait_clock_ready()
* fails?
*/
return 0;
}
/* Stop APLL */
static void omap2_clk_fixed_disable(struct clk *clk)
{
u32 cval;
cval = cm_read_mod_reg(PLL_MOD, CM_CLKEN);
cval &= ~(EN_APLL_LOCKED << clk->enable_bit);
cm_write_mod_reg(cval, PLL_MOD, CM_CLKEN);
}
/*
* Uses the current prcm set to tell if a rate is valid.
* You can go slower, but not faster within a given rate set.
*/
static u32 omap2_dpll_round_rate(unsigned long target_rate)
{
u32 high, low, core_clk_src;
core_clk_src = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
core_clk_src &= OMAP24XX_CORE_CLK_SRC_MASK;
if (core_clk_src == CORE_CLK_SRC_DPLL) { /* DPLL clockout */
high = curr_prcm_set->dpll_speed * 2;
low = curr_prcm_set->dpll_speed;
} else { /* DPLL clockout x 2 */
high = curr_prcm_set->dpll_speed;
low = curr_prcm_set->dpll_speed / 2;
}
#ifdef DOWN_VARIABLE_DPLL
if (target_rate > high)
return high;
else
return target_rate;
#else
if (target_rate > low)
return high;
else
return low;
#endif
}
static void omap2_dpll_recalc(struct clk *clk)
{
clk->rate = omap2_get_dpll_rate_24xx(clk);
propagate_rate(clk);
}
static int omap2_reprogram_dpll(struct clk *clk, unsigned long rate)
{
u32 cur_rate, low, mult, div, valid_rate, done_rate;
u32 bypass = 0;
struct prcm_config tmpset;
const struct dpll_data *dd;
unsigned long flags;
int ret = -EINVAL;
local_irq_save(flags);
cur_rate = omap2_get_dpll_rate_24xx(&dpll_ck);
mult = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
mult &= OMAP24XX_CORE_CLK_SRC_MASK;
if ((rate == (cur_rate / 2)) && (mult == 2)) {
omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL, 1);
} else if ((rate == (cur_rate * 2)) && (mult == 1)) {
omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1);
} else if (rate != cur_rate) {
valid_rate = omap2_dpll_round_rate(rate);
if (valid_rate != rate)
goto dpll_exit;
if (mult == 1)
low = curr_prcm_set->dpll_speed;
else
low = curr_prcm_set->dpll_speed / 2;
dd = clk->dpll_data;
if (!dd)
goto dpll_exit;
tmpset.cm_clksel1_pll = __raw_readl(dd->mult_div1_reg);
tmpset.cm_clksel1_pll &= ~(dd->mult_mask |
dd->div1_mask);
div = ((curr_prcm_set->xtal_speed / 1000000) - 1);
tmpset.cm_clksel2_pll = cm_read_mod_reg(PLL_MOD, CM_CLKSEL2);
tmpset.cm_clksel2_pll &= ~OMAP24XX_CORE_CLK_SRC_MASK;
if (rate > low) {
tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL_X2;
mult = ((rate / 2) / 1000000);
done_rate = CORE_CLK_SRC_DPLL_X2;
} else {
tmpset.cm_clksel2_pll |= CORE_CLK_SRC_DPLL;
mult = (rate / 1000000);
done_rate = CORE_CLK_SRC_DPLL;
}
tmpset.cm_clksel1_pll |= (div << __ffs(dd->mult_mask));
tmpset.cm_clksel1_pll |= (mult << __ffs(dd->div1_mask));
/* Worst case */
tmpset.base_sdrc_rfr = SDRC_RFR_CTRL_BYPASS;
if (rate == curr_prcm_set->xtal_speed) /* If asking for 1-1 */
bypass = 1;
omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1); /* For init_mem */
/* Force dll lock mode */
omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr,
bypass);
/* Errata: ret dll entry state */
omap2_init_memory_params(omap2_dll_force_needed());
omap2_reprogram_sdrc(done_rate, 0);
}
omap2_dpll_recalc(&dpll_ck);
ret = 0;
dpll_exit:
local_irq_restore(flags);
return(ret);
}
/**
* omap2_table_mpu_recalc - just return the MPU speed
* @clk: virt_prcm_set struct clk
*
* Set virt_prcm_set's rate to the mpu_speed field of the current PRCM set.
*/
static void omap2_table_mpu_recalc(struct clk *clk)
{
clk->rate = curr_prcm_set->mpu_speed;
}
/*
* Look for a rate equal or less than the target rate given a configuration set.
*
* What's not entirely clear is "which" field represents the key field.
* Some might argue L3-DDR, others ARM, others IVA. This code is simple and
* just uses the ARM rates.
*/
static long omap2_round_to_table_rate(struct clk *clk, unsigned long rate)
{
struct prcm_config *ptr;
long highest_rate;
if (clk != &virt_prcm_set)
return -EINVAL;
highest_rate = -EINVAL;
for (ptr = rate_table; ptr->mpu_speed; ptr++) {
if (!(ptr->flags & cpu_mask))
continue;
if (ptr->xtal_speed != sys_ck.rate)
continue;
highest_rate = ptr->mpu_speed;
/* Can check only after xtal frequency check */
if (ptr->mpu_speed <= rate)
break;
}
return highest_rate;
}
/* Sets basic clocks based on the specified rate */
static int omap2_select_table_rate(struct clk *clk, unsigned long rate)
{
u32 cur_rate, done_rate, bypass = 0, tmp;
struct prcm_config *prcm;
unsigned long found_speed = 0;
unsigned long flags;
if (clk != &virt_prcm_set)
return -EINVAL;
for (prcm = rate_table; prcm->mpu_speed; prcm++) {
if (!(prcm->flags & cpu_mask))
continue;
if (prcm->xtal_speed != sys_ck.rate)
continue;
if (prcm->mpu_speed <= rate) {
found_speed = prcm->mpu_speed;
break;
}
}
if (!found_speed) {
printk(KERN_INFO "Could not set MPU rate to %luMHz\n",
rate / 1000000);
return -EINVAL;
}
curr_prcm_set = prcm;
cur_rate = omap2_get_dpll_rate_24xx(&dpll_ck);
if (prcm->dpll_speed == cur_rate / 2) {
omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL, 1);
} else if (prcm->dpll_speed == cur_rate * 2) {
omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1);
} else if (prcm->dpll_speed != cur_rate) {
local_irq_save(flags);
if (prcm->dpll_speed == prcm->xtal_speed)
bypass = 1;
if ((prcm->cm_clksel2_pll & OMAP24XX_CORE_CLK_SRC_MASK) ==
CORE_CLK_SRC_DPLL_X2)
done_rate = CORE_CLK_SRC_DPLL_X2;
else
done_rate = CORE_CLK_SRC_DPLL;
/* MPU divider */
cm_write_mod_reg(prcm->cm_clksel_mpu, MPU_MOD, CM_CLKSEL);
/* dsp + iva1 div(2420), iva2.1(2430) */
cm_write_mod_reg(prcm->cm_clksel_dsp,
OMAP24XX_DSP_MOD, CM_CLKSEL);
cm_write_mod_reg(prcm->cm_clksel_gfx, GFX_MOD, CM_CLKSEL);
/* Major subsystem dividers */
tmp = cm_read_mod_reg(CORE_MOD, CM_CLKSEL1) & OMAP24XX_CLKSEL_DSS2_MASK;
cm_write_mod_reg(prcm->cm_clksel1_core | tmp, CORE_MOD, CM_CLKSEL1);
if (cpu_is_omap2430())
cm_write_mod_reg(prcm->cm_clksel_mdm,
OMAP2430_MDM_MOD, CM_CLKSEL);
/* x2 to enter init_mem */
omap2_reprogram_sdrc(CORE_CLK_SRC_DPLL_X2, 1);
omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr,
bypass);
omap2_init_memory_params(omap2_dll_force_needed());
omap2_reprogram_sdrc(done_rate, 0);
local_irq_restore(flags);
}
omap2_dpll_recalc(&dpll_ck);
return 0;
}
static struct clk_functions omap2_clk_functions = {
.clk_enable = omap2_clk_enable,
.clk_disable = omap2_clk_disable,
.clk_round_rate = omap2_clk_round_rate,
.clk_set_rate = omap2_clk_set_rate,
.clk_set_parent = omap2_clk_set_parent,
.clk_disable_unused = omap2_clk_disable_unused,
};
static u32 omap2_get_apll_clkin(void)
{
u32 aplls, sclk = 0;
aplls = cm_read_mod_reg(PLL_MOD, CM_CLKSEL1);
aplls &= OMAP24XX_APLLS_CLKIN_MASK;
aplls >>= OMAP24XX_APLLS_CLKIN_SHIFT;
if (aplls == APLLS_CLKIN_19_2MHZ)
sclk = 19200000;
else if (aplls == APLLS_CLKIN_13MHZ)
sclk = 13000000;
else if (aplls == APLLS_CLKIN_12MHZ)
sclk = 12000000;
return sclk;
}
static u32 omap2_get_sysclkdiv(void)
{
u32 div;
div = __raw_readl(OMAP24XX_PRCM_CLKSRC_CTRL);
div &= OMAP_SYSCLKDIV_MASK;
div >>= OMAP_SYSCLKDIV_SHIFT;
return div;
}
static void omap2_osc_clk_recalc(struct clk *clk)
{
clk->rate = omap2_get_apll_clkin() * omap2_get_sysclkdiv();
propagate_rate(clk);
}
static void omap2_sys_clk_recalc(struct clk *clk)
{
clk->rate = clk->parent->rate / omap2_get_sysclkdiv();
propagate_rate(clk);
}
/*
* Set clocks for bypass mode for reboot to work.
*/
void omap2_clk_prepare_for_reboot(void)
{
u32 rate;
if (vclk == NULL || sclk == NULL)
return;
rate = clk_get_rate(sclk);
clk_set_rate(vclk, rate);
}
/*
* Switch the MPU rate if specified on cmdline.
* We cannot do this early until cmdline is parsed.
*/
static int __init omap2_clk_arch_init(void)
{
if (!mpurate)
return -EINVAL;
if (omap2_select_table_rate(&virt_prcm_set, mpurate))
printk(KERN_ERR "Could not find matching MPU rate\n");
recalculate_root_clocks();
printk(KERN_INFO "Switched to new clocking rate (Crystal/DPLL/MPU): "
"%ld.%01ld/%ld/%ld MHz\n",
(sys_ck.rate / 1000000), (sys_ck.rate / 100000) % 10,
(dpll_ck.rate / 1000000), (mpu_ck.rate / 1000000)) ;
return 0;
}
arch_initcall(omap2_clk_arch_init);
int __init omap2_clk_init(void)
{
struct prcm_config *prcm;
struct clk **clkp;
u32 clkrate;
if (cpu_is_omap242x())
cpu_mask = RATE_IN_242X;
else if (cpu_is_omap2430())
cpu_mask = RATE_IN_243X;
clk_init(&omap2_clk_functions);
omap2_osc_clk_recalc(&osc_ck);
omap2_sys_clk_recalc(&sys_ck);
for (clkp = onchip_24xx_clks;
clkp < onchip_24xx_clks + ARRAY_SIZE(onchip_24xx_clks);
clkp++) {
if ((*clkp)->flags & CLOCK_IN_OMAP242X && cpu_is_omap2420()) {
clk_register(*clkp);
continue;
}
if ((*clkp)->flags & CLOCK_IN_OMAP243X && cpu_is_omap2430()) {
clk_register(*clkp);
continue;
}
}
/* Check the MPU rate set by bootloader */
clkrate = omap2_get_dpll_rate_24xx(&dpll_ck);
for (prcm = rate_table; prcm->mpu_speed; prcm++) {
if (!(prcm->flags & cpu_mask))
continue;
if (prcm->xtal_speed != sys_ck.rate)
continue;
if (prcm->dpll_speed <= clkrate)
break;
}
curr_prcm_set = prcm;
recalculate_root_clocks();
printk(KERN_INFO "Clocking rate (Crystal/DPLL/MPU): "
"%ld.%01ld/%ld/%ld MHz\n",
(sys_ck.rate / 1000000), (sys_ck.rate / 100000) % 10,
(dpll_ck.rate / 1000000), (mpu_ck.rate / 1000000)) ;
/*
* Only enable those clocks we will need, let the drivers
* enable other clocks as necessary
*/
clk_enable_init_clocks();
/* Avoid sleeping sleeping during omap2_clk_prepare_for_reboot() */
vclk = clk_get(NULL, "virt_prcm_set");
sclk = clk_get(NULL, "sys_ck");
return 0;
}
此差异已折叠。
/*
* OMAP3-specific clock framework functions
*
* Copyright (C) 2007 Texas Instruments, Inc.
* Copyright (C) 2007 Nokia Corporation
*
* Written by Paul Walmsley
*
* Parts of this code are based on code written by
* Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu
*
* 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.
*/
#undef DEBUG
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/sram.h>
#include <asm/div64.h>
#include <asm/bitops.h>
#include "memory.h"
#include "clock.h"
#include "clock34xx.h"
#include "prm.h"
#include "prm-regbits-34xx.h"
#include "cm.h"
#include "cm-regbits-34xx.h"
/* CM_CLKEN_PLL*.EN* bit values */
#define DPLL_LOCKED 0x7
/**
* omap3_dpll_recalc - recalculate DPLL rate
* @clk: DPLL struct clk
*
* Recalculate and propagate the DPLL rate.
*/
static void omap3_dpll_recalc(struct clk *clk)
{
clk->rate = omap2_get_dpll_rate(clk);
propagate_rate(clk);
}
/**
* omap3_clkoutx2_recalc - recalculate DPLL X2 output virtual clock rate
* @clk: DPLL output struct clk
*
* Using parent clock DPLL data, look up DPLL state. If locked, set our
* rate to the dpll_clk * 2; otherwise, just use dpll_clk.
*/
static void omap3_clkoutx2_recalc(struct clk *clk)
{
const struct dpll_data *dd;
u32 v;
struct clk *pclk;
/* Walk up the parents of clk, looking for a DPLL */
pclk = clk->parent;
while (pclk && !pclk->dpll_data)
pclk = pclk->parent;
/* clk does not have a DPLL as a parent? */
WARN_ON(!pclk);
dd = pclk->dpll_data;
WARN_ON(!dd->control_reg || !dd->enable_mask);
v = __raw_readl(dd->control_reg) & dd->enable_mask;
v >>= __ffs(dd->enable_mask);
if (v != DPLL_LOCKED)
clk->rate = clk->parent->rate;
else
clk->rate = clk->parent->rate * 2;
if (clk->flags & RATE_PROPAGATES)
propagate_rate(clk);
}
/*
* As it is structured now, this will prevent an OMAP2/3 multiboot
* kernel from compiling. This will need further attention.
*/
#if defined(CONFIG_ARCH_OMAP3)
static struct clk_functions omap2_clk_functions = {
.clk_enable = omap2_clk_enable,
.clk_disable = omap2_clk_disable,
.clk_round_rate = omap2_clk_round_rate,
.clk_set_rate = omap2_clk_set_rate,
.clk_set_parent = omap2_clk_set_parent,
.clk_disable_unused = omap2_clk_disable_unused,
};
/*
* Set clocks for bypass mode for reboot to work.
*/
void omap2_clk_prepare_for_reboot(void)
{
/* REVISIT: Not ready for 343x */
#if 0
u32 rate;
if (vclk == NULL || sclk == NULL)
return;
rate = clk_get_rate(sclk);
clk_set_rate(vclk, rate);
#endif
}
/* REVISIT: Move this init stuff out into clock.c */
/*
* Switch the MPU rate if specified on cmdline.
* We cannot do this early until cmdline is parsed.
*/
static int __init omap2_clk_arch_init(void)
{
if (!mpurate)
return -EINVAL;
/* REVISIT: not yet ready for 343x */
#if 0
if (omap2_select_table_rate(&virt_prcm_set, mpurate))
printk(KERN_ERR "Could not find matching MPU rate\n");
#endif
recalculate_root_clocks();
printk(KERN_INFO "Switched to new clocking rate (Crystal/DPLL3/MPU): "
"%ld.%01ld/%ld/%ld MHz\n",
(osc_sys_ck.rate / 1000000), (osc_sys_ck.rate / 100000) % 10,
(core_ck.rate / 1000000), (dpll1_fck.rate / 1000000)) ;
return 0;
}
arch_initcall(omap2_clk_arch_init);
int __init omap2_clk_init(void)
{
/* struct prcm_config *prcm; */
struct clk **clkp;
/* u32 clkrate; */
u32 cpu_clkflg;
/* REVISIT: Ultimately this will be used for multiboot */
#if 0
if (cpu_is_omap242x()) {
cpu_mask = RATE_IN_242X;
cpu_clkflg = CLOCK_IN_OMAP242X;
clkp = onchip_24xx_clks;
} else if (cpu_is_omap2430()) {
cpu_mask = RATE_IN_243X;
cpu_clkflg = CLOCK_IN_OMAP243X;
clkp = onchip_24xx_clks;
}
#endif
if (cpu_is_omap34xx()) {
cpu_mask = RATE_IN_343X;
cpu_clkflg = CLOCK_IN_OMAP343X;
clkp = onchip_34xx_clks;
/*
* Update this if there are further clock changes between ES2
* and production parts
*/
if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0)) {
/* No 3430ES1-only rates exist, so no RATE_IN_3430ES1 */
cpu_clkflg |= CLOCK_IN_OMAP3430ES1;
} else {
cpu_mask |= RATE_IN_3430ES2;
cpu_clkflg |= CLOCK_IN_OMAP3430ES2;
}
}
clk_init(&omap2_clk_functions);
for (clkp = onchip_34xx_clks;
clkp < onchip_34xx_clks + ARRAY_SIZE(onchip_34xx_clks);
clkp++) {
if ((*clkp)->flags & cpu_clkflg)
clk_register(*clkp);
}
/* REVISIT: Not yet ready for OMAP3 */
#if 0
/* Check the MPU rate set by bootloader */
clkrate = omap2_get_dpll_rate_24xx(&dpll_ck);
for (prcm = rate_table; prcm->mpu_speed; prcm++) {
if (!(prcm->flags & cpu_mask))
continue;
if (prcm->xtal_speed != sys_ck.rate)
continue;
if (prcm->dpll_speed <= clkrate)
break;
}
curr_prcm_set = prcm;
#endif
recalculate_root_clocks();
printk(KERN_INFO "Clocking rate (Crystal/DPLL/ARM core): "
"%ld.%01ld/%ld/%ld MHz\n",
(osc_sys_ck.rate / 1000000), (osc_sys_ck.rate / 100000) % 10,
(core_ck.rate / 1000000), (arm_fck.rate / 1000000));
/*
* Only enable those clocks we will need, let the drivers
* enable other clocks as necessary
*/
clk_enable_init_clocks();
/* Avoid sleeping during omap2_clk_prepare_for_reboot() */
/* REVISIT: not yet ready for 343x */
#if 0
vclk = clk_get(NULL, "virt_prcm_set");
sclk = clk_get(NULL, "sys_ck");
#endif
return 0;
}
#endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
/*
* OMAP2/3 System Control Module register access
*
* Copyright (C) 2007 Texas Instruments, Inc.
* Copyright (C) 2007 Nokia Corporation
*
* Written by Paul Walmsley
*
* 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.
*/
#undef DEBUG
#include <linux/kernel.h>
#include <asm/io.h>
#include <asm/arch/control.h>
static u32 omap2_ctrl_base;
#define OMAP_CTRL_REGADDR(reg) (void __iomem *)IO_ADDRESS(omap2_ctrl_base \
+ (reg))
void omap_ctrl_base_set(u32 base)
{
omap2_ctrl_base = base;
}
u32 omap_ctrl_base_get(void)
{
return omap2_ctrl_base;
}
u8 omap_ctrl_readb(u16 offset)
{
return __raw_readb(OMAP_CTRL_REGADDR(offset));
}
u16 omap_ctrl_readw(u16 offset)
{
return __raw_readw(OMAP_CTRL_REGADDR(offset));
}
u32 omap_ctrl_readl(u16 offset)
{
return __raw_readl(OMAP_CTRL_REGADDR(offset));
}
void omap_ctrl_writeb(u8 val, u16 offset)
{
pr_debug("omap_ctrl_writeb: writing 0x%0x to 0x%0x\n", val,
(u32)OMAP_CTRL_REGADDR(offset));
__raw_writeb(val, OMAP_CTRL_REGADDR(offset));
}
void omap_ctrl_writew(u16 val, u16 offset)
{
pr_debug("omap_ctrl_writew: writing 0x%0x to 0x%0x\n", val,
(u32)OMAP_CTRL_REGADDR(offset));
__raw_writew(val, OMAP_CTRL_REGADDR(offset));
}
void omap_ctrl_writel(u32 val, u16 offset)
{
pr_debug("omap_ctrl_writel: writing 0x%0x to 0x%0x\n", val,
(u32)OMAP_CTRL_REGADDR(offset));
__raw_writel(val, OMAP_CTRL_REGADDR(offset));
}
此差异已折叠。
此差异已折叠。
...@@ -32,3 +32,5 @@ extern void omap2_init_memory_params(u32 force_lock_to_unlock_mode); ...@@ -32,3 +32,5 @@ extern void omap2_init_memory_params(u32 force_lock_to_unlock_mode);
extern u32 omap2_memory_get_slow_dll_ctrl(void); extern u32 omap2_memory_get_slow_dll_ctrl(void);
extern u32 omap2_memory_get_fast_dll_ctrl(void); extern u32 omap2_memory_get_fast_dll_ctrl(void);
extern u32 omap2_memory_get_type(void); extern u32 omap2_memory_get_type(void);
u32 omap2_dll_force_needed(void);
u32 omap2_reprogram_sdrc(u32 level, u32 force);
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -9,8 +9,6 @@ obj-m := ...@@ -9,8 +9,6 @@ obj-m :=
obj-n := obj-n :=
obj- := obj- :=
obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o
# OCPI interconnect support for 1710, 1610 and 5912 # OCPI interconnect support for 1710, 1610 and 5912
obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -163,6 +163,7 @@ add_reserved_region(resource_size_t start, resource_size_t end, ...@@ -163,6 +163,7 @@ add_reserved_region(resource_size_t start, resource_size_t end,
new->start = start; new->start = start;
new->end = end; new->end = end;
new->name = name; new->name = name;
new->sibling = next;
new->flags = IORESOURCE_MEM; new->flags = IORESOURCE_MEM;
*pprev = new; *pprev = new;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
...@@ -46,5 +46,5 @@ ...@@ -46,5 +46,5 @@
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
__sdram_base = 0x00000000 /* base address to which SDRAM relocated */ __sdram_base = 0x00000000 /* base address to which SDRAM relocated */
#else #else
__sdram_base = 0xc0000000 /* base address to which SDRAM relocated */ __sdram_base = __page_offset /* base address to which SDRAM relocated */
#endif #endif
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册