Commit c90594ca authored by Russell King's avatar Russell King

[ARM] Update ARM documentation

Add 00-INDEX and booting documentation, remove obsolete DMA
documentation.
parent 364b47ea
00-INDEX
- this file
Booting
- requirements for booting
Interrupts
- ARM Interrupt subsystem documentation
Netwinder
- Netwinder specific documentation
README
- General ARM documentation
SA1100
- SA1100 documentation
XScale
- XScale documentation
empeg
- Empeg documentation
mem_alignment
- alignment abort handler documentation
nwfpe
- NWFPE floating point emulator documentation
Booting ARM Linux
=================
Author: Russell King
Date : 18 May 2002
The following documentation is relevant to 2.4.18-rmk6 and beyond.
In order to boot ARM Linux, you require a boot loader, which is a small
program that runs before the main kernel. The boot loader is expected
to initialise various devices, and eventually call the Linux kernel,
passing information to the kernel.
Essentially, the boot loader should provide (as a minimum) the
following:
1. Setup and initialise the RAM.
2. Initialise one serial port.
3. Detect the machine type.
4. Setup the kernel tagged list.
5. Call the kernel image.
1. Setup and initialise RAM
---------------------------
Existing boot loaders: MANDATORY
New boot loaders: MANDATORY
The boot loader is expected to find and initialise all RAM that the
kernel will use for volatile data storage in the system. It performs
this in a machine dependent manner. (It may use internal algorithms
to automatically locate and size all RAM, or it may use knowledge of
the RAM in the machine, or any other method the boot loader designer
sees fit.)
2. Initialise one serial port
-----------------------------
Existing boot loaders: OPTIONAL, RECOMMENDED
New boot loaders: OPTIONAL, RECOMMENDED
The boot loader should initialise and enable one serial port on the
target. This allows the kernel serial driver to automatically detect
which serial port it should use for the kernel console (generally
used for debugging purposes, or communication with the target.)
As an alternative, the boot loader can pass the relevant 'console='
option to the kernel via the tagged lists specifing the port, and
serial format options as described in
linux/Documentation/kernel-parameters.txt.
3. Detect the machine type
--------------------------
Existing boot loaders: OPTIONAL
New boot loaders: MANDATORY
The boot loader should detect the machine type its running on by some
method. Whether this is a hard coded value or some algorithm that
looks at the connected hardware is beyond the scope of this document.
The boot loader must ultimately be able to provide a MACH_TYPE_xxx
value to the kernel. (see linux/arch/arm/tools/mach-types).
4. Setup the kernel tagged list
-------------------------------
Existing boot loaders: OPTIONAL, HIGHLY RECOMMENDED
New boot loaders: MANDATORY
The boot loader must create and initialise the kernel tagged list.
A valid tagged list starts with ATAG_CORE and ends with ATAG_NONE.
The ATAG_CORE tag may or may not be empty. An empty ATAG_CORE tag
has the size field set to '2' (0x00000002). The ATAG_NONE must set
the size field to zero.
Any number of tags can be placed in the list. It is undefined
whether a repeated tag appends to the information carried by the
previous tag, or whether it replaces the information in its
entirety; some tags behave as the former, others the latter.
The boot loader must pass at a minimum the size and location of
the system memory, and root filesystem location. Therefore, the
minimum tagged list should look:
+-----------+
base -> | ATAG_CORE | |
+-----------+ |
| ATAG_MEM | | increasing address
+-----------+ |
| ATAG_NONE | |
+-----------+ v
The tagged list should be stored in system RAM.
The tagged list must be placed in a region of memory where neither
the kernel decompressor nor initrd 'bootp' program will overwrite
it. The recommended placement is in the first 16KiB of RAM.
5. Calling the kernel image
---------------------------
Existing boot loaders: MANDATORY
New boot loaders: MANDATORY
There are two options for calling the kernel zImage. If the zImage
is stored in flash, and is linked correctly to be run from flash,
then it is legal for the boot loader to call the zImage in flash
directly.
The zImage may also be placed in system RAM (at any location) and
called there. Note that the kernel uses 16K of RAM below the image
to store page tables. The recommended placement is 32KiB into RAM.
In either case, the following conditions must be met:
- CPU register settings
r0 = 0,
r1 = machine type number discovered in (3) above.
r2 = physical address of tagged list in system RAM.
- CPU mode
All forms of interrupts must be disabled (IRQs and FIQs)
The CPU must be in SVC mode. (A special exception exists for Angel)
- Caches, MMUs
The MMU must be off.
Instruction cache may be on or off.
Data cache must be off.
- The boot loader is expected to call the kernel image by jumping
directly to the first instruction of the kernel image.
Support functions for the SA11x0 internal DMA channels
======================================================
Nicolas Pitre <nico@cam.org>
Last updated: 2001/07/15
The DMA controller consists of six independent DMA channels. Each channel
can be configured to service any of the serial controllers. Two channels
are required to service a full-duplex serial controller. The DMA
controller is intended to relieve the processor of the interrupt overhead
in servicing these ports with programmed I/ O.
If desired, any or all peripherals (except the UDC) may be serviced with
programmed I/ O instead of DMA. Each peripheral is capable of requesting
processor service through its own interrupt lines or through a DMA
request.
A set of functions is provided to support drivers working with DMA buffers
through a generic interface for (wishfully) all DMA usages. Those
functions will take care of buffer queueing and splitting, DMA register
management, interrupt handling, etc.
SA11x0 DMA API
--------------
Here is the description for the DMA API.
int sa1100_request_dma( dmach_t *channel, const char *device_id,
dma_device_t device );
This function will search for a free DMA channel and returns the channel
number in '*channel'. 'device_id' should point to a string identifying
the DMA usage or device (mainly for /proc). 'device' is the SA11x0
peripheral's ports. Note that reading from a port and writing to the
same port are actually considered as two different streams requiring
two DMA channels with their own device type. All possible dma_device_t
are defined in include/asm-arm/arch-sa1100/dma.h. If no channel is
available, or if the desired device is already in use by another DMA
channel, then an error code is returned. This function must be called
before any other DMA calls.
int sa1100_dma_queue_buffer( dmach_t channel, void *buf_id,
dma_addr_t data, int size );
This function enqueue the specified buffer for DMA processing. The buffer
will be transmitted or filled with incoming data depending on the channel
configuration made through sa1100_dma_set_device(). If the queue is
empty, DMA starts immediately on the given buffer.
Arguments are:
dmach_t channel: the channel number.
void *buf_id: a buffer identification known by the caller.
dma_addr_t data: the buffer's physical address.
int size: the buffer size in bytes.
Note here the dma_addr_t which is not the same as the virtual address as
returned by kmalloc() and friends. The DMA controller must be given a
physical address to a buffer which is not cached bye the CPU data cache.
To get such address, the DMA mapping functions (see
Documentation/DMA-mapping.txt) are recommended. The only relevant
functions are pci_alloc_consistent(), pci_map_single() and their unmap
counterparts. The PCI dev argument is NULL of course.
There is no restriction on the buffer size. The DMA code will split it up
internally to acommodate the DMA controller as needed. If the buffer
can't be enqueued the appropriate error code is returned.
int sa1100_dma_set_callback( dmach_t channel, dma_callback_t cb );
As soon as the DMa completes with a buffer, a callback function is used to
notify the driver which would have registered one. The callback function
is prototyped as:
void dma_callback( void *buf_id, int size );
The 'buf_id' argument is the buffer identifier as passed to
sa1100_dma_queue_buffer(). The 'size' argument is the number of bytes the
DMA processed (should be the same as the buffer size).
Note that this callback function is called while in interrupt context.
So it has to be small and efficient while posponing more complex
processing to a bottom-half function or similar. All
restrictions for interrupt handlers still apply.
int sa1100_dma_get_current( dmach_t channel, void **buf_id,
dma_addr_t *addr );
This returns the buffer ID and the DMA address pointer within the buffer
currently being processed. If no such buffer is currently processed, an
error code is returned. This is useful for mmap()'ed buffers like in
audio drivers.
int sa1100_dma_stop( dmach_t channel );
This call stops any DMA transfer on the given channel.
int sa1100_dma_resume( dmach_t channel );
This call resumes a DMA transfer which would have been stopped through
sa1100_dma_stop().
int sa1100_dma_flush_all( dmach_t channel );
This completely flushes all queued buffers and on-going DMA transfers on a
given channel. The next enqueued buffer following this call will be
processed right away.
int sa1100_dma_set_spin( dmach_t channel, dma_addr_t addr, int size );
Because there is at least one device out there that uses its receive
signal for its transmit clock reference, we need a mecanism to make the
DMA "spin" on a certain buffer for when there is no more actual buffer to
process. The 'addr' argument is the physical memory address to use, and
the 'size' argument determines the spin DMA chunk. This size can't be
larger than 8191 (if so, it is clamped to 4096). When the size is 0,
the spin function is turned off.
When activated, DMA will "spin" until there is any buffer in the queue.
The current DMA chunk will terminate before a newly queued buffer is
processed. The spin buffer will only be reused when there is no more
acctual buffer to process.
It is important not to choose a too small 'size' value since it will
greatly increase the interrupt load required to restart the spin. Since
this feature will typically be used on transmit DMAs, and because a buffer
full of zeros is probably the best thing to spin out, the 'addr' argument
may well be used with FLUSH_BASE_PHYS for which no allocation nor memory
bus request are needed.
The spinning DMA is affected by sa1100_dma_stop() and sa1100_dma_resume()
but not bu sa1100_dma_flush_all().
void sa1100_free_dma( dmach_t channel );
This clears all activities on a given DMA channel and releases it for
future requests.
Buffer allocation
-----------------
Like mentionned above, it is the driver's responsibility to allocate, free
and keep track of buffer space with dma_addr_t type addresses. However the
driver must not change the state of any buffer after it has been sent to
sa1100-dma_queue_buffer(). When that function has been called, the buffer
becomes the DMA's ownership until one of these events occur:
- The callback function is called by the DMA code with a buffer ID to
indicate that DMA processing terminated on that buffer. Then the
driver owns the buffer again.
- The sa1100-dma_flush_all() function is called by the driver at which
point *all* queued buffers are owned by the driver again.
- The sa1100-free_dma() does the same as sa1100-dma_flush_all().
This doesn't mean that you can't change the content of a queued buffer in
conjonction with the usage of pci_map_consistent() and
sa1100_dma_get_current()... but then you must be sure you know what you're
doing (this doesn't work with pci_map_single()).
Examples
--------
A real example of audio ring buffers is implemented in the
drivers/sound/sa1100-audio.c driver. The SA1110 USB client and the
SA11x0 FIR drivers are also using this interface to implement packetized
DMA.
A transmit DMA for network packets could look like this (largely simplified):
struct sk_buff *tx_ring_skb[RING_SIZE];
dma_addr_t tx_ring_dma[RING_SIZE];
int cur_tx;
...
transmit function:
tx_ring_skb[cur_tx] = skb;
tx_ring_dma[cur_tx] = pci_map_single(NULL, skb->data, skb->len,
PCI_DMA_TODEVICE);
sa1100_dma_queue_buffer(channel, (void*)cur_tx,
tx_ring_dma[cur_tx], skb->len);
cur_tx++; cur_tx %= RING_SIZE;
...
and the callback function:
void tx_done_callback( void *buf_id, int size ) {
int done_tx = (int) buf_id;
struct sk_buff *skb = tx_ring_skb[done_tx];
pci_unmap_single(NULL, tx_ring_dma[done_tx], skb->len,
PCI_DMA_TODEVICE);
stats.tx_packets++;
stats.tx_bytes += size;
dev_kfree_skb_irq(skb);
tx_ring_skb[done_tx] = NULL;
}
For drivers expecting variable length packets i.e. USB client, it is
necessary to register the appropriate IRQ to be notified when the receiver
is idle, the packet is complete, etc. We could use one buffer at a time
with its ID being the virtual address of the buffer.
Then the sequence:
/* be sure DMA won't continue under our feet */
sa1100_dma_stop(channel);
/* get the actual DMA length */
sa1100_get_current(channel, &data, &dma_ptr);
/* acquire ownership for the buffer */
sa1100_dma_flush_all(channel);
/* unmap the DMA buffer (actually doing cache coherency on ARM) */
pci_unmap_single (NULL, dma_addr, MAX_PKT_SIZE, PCI_DMA_FROMDEVICE);
/* get remaining bytes from the fifo */
ptr = data + dma_ptr - dma_addr;
while (fifo_not_empty)
*ptr++ = get_byte_from_fifo;
/* feed another free buffer for the next packet */
dma_addr2 = pci_map_single(NULL, data2, MAX_PKT_SIZE,
PCI_DMA_FROMDEVICE);
sa1100_dma_queue_buffer(channel, data2, dma_addr2, MAX_PKT_SIZE);
/* process the current packet */
...
might do the trick. This looks a bit ugly but that's a starting point for
improvements.
TODO
----
- Create kernel-doc comments in the source to document the API and
let the documentation be generated automatically.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment