MicroDigital PCIManager      July 2004
=======================

This module initialises the PCI bus system and any PCI devices fitted either
on the motherboard or on plug in expansion cards.  It provides support
to device driver modules to configure and operate individual devices.  Also,
it controls operation of interrupts from PCI devices, and provides access to
information about the devices that are fitted.
 
Virtually all modern PCI devices expect to operate using bus-master DMA. 
However there is no standardisation of register level API for DMA
controllers in PCI devices, so every chip set is different, even within the
same class.  Therefore, operation of each DMA controller has to be from
within the appropriate device driver module.

On the Omega motherboard, PCI devices are all in the SouthBridge, which
includes UDMA IDE, two USB 1.1 controllers, and a bridge to the integrated
SuperCombo which provides the Floppy, serial and parallel ports and a PS/2
interface to keyboard and mouse.

*Commands
=========

*PCIDevices

This displays diagnostic information about devices visible across the PCI bus,
including :-
 Logical device number;
 Location ie Card slot number or motherboard device name;
 Vendor ID;
 Device ID;
 Class code;
 Name of device driver module controlling that device, if any;
 Description of purpose of devices of that class code
Syntax: *PCIDevices

*MemoryW

This writes new memory contents in words, but without reading.
(cf *MemoryA which alters but also reads back)
Syntax: *MemoryW <addr> <data word>

*MemoryWB

This writes new memory contents in bytes, but without reading.
Syntax: *MemoryWB <addr> <data byte>



SWIs
====

PCI_ReturnNumberOfDevices    (SWI &50E40)

On Entry
(no entry parameters)

On Exit
  R0 = Number of PCI devices/functions found in the system.

Use

This SWI returns the number of PCI devices. There can be up to 8 devices per
PCI card, implying a maximum of 48 devices on Omega (4 slots, the host
(northbridge) and the southbridge.  However, the SWI should be treated as
though it can return any value to allow for future expansion (such as
supporting PCI bridge chips).  In practice, virtually all commonly available
PCI cards have only one device with one function.

PCI_ReadID    (SWI &50E41)

On Entry
  R0 = Flags  (All bits reserved. Should be 0).
  R3 = PCI logical device number. (ie in range 0 to number of devices - 1)

On Exit
  R0 = PCI card information:
       bits meaning 0-15 Vendor ID
                   16-31 Device ID
       If there is no such PCI device, the Vendor and Device IDs are
       returned as &FFFF.
  R1 = PCI slot number of the card the device is on
        (or &FFFFFFFF if the motherboard).
  R2 = PCI card information: class information in bits 0-23
  R3 = PCI card information: 
       bits meaning 0-15 Subsystem Vendor ID
                   16-31 Subsystem Device ID
  R4 = base offset of CMOS memory allocation, or ZERO if none
       (ie only for plug-in cards, taken from the allocation used
       previously by podules)

Use

This SWI returns the Vendor and ID strings and other similar information
from the specified PCI device.  It also returns the physical slot number
that the device is in (and thus the card it's on).

PCI_RegisterDriver    (SWI &50E42)

On Entry
  R0 = Flags  (All bits reserved. Should be 0).
  R1 = Vendor and Device ID information
       bits meaning 0-15 Vendor ID of card being looked for
                   16-31 Device ID of card being looked for
  R2 = Bitmask to indicate which bits of R1 are relevant. A '1' bit
       indicates 'interested'
  R4 = Arbitrary identifying word, also used in PCI_DeRegisterDriver.
  R5 -> text string to use in *PCIDevices.  Maximum of 23 characters.

On Exit
  R0 = PCI logical device number which represents the device searched for. 
       or &FFFFFFFF if no matching devices found.

Use

This SWI allows a module to register itself with the PCI manager. It passes
the vendor/device word in, along with a bitmask (to allow for covering a
range of similar devices), and it returns the device number of the first 
device that matches the search criteria, and does not already have a driver
associated with it. NOTE that subsystem vendor and device ids are also
checked, which allows a driver to work with cards from different
manufacturers that use the same chip set.
 

PCI_DeRegisterDriver    (SWI &50E43)

On Entry
  R0 = Flags  (All bits reserved. Should be 0).
  R3 = PCI logical device number.
  R4 = Identifying word previously passed into PCI_RegisterDriver in R4.

On Exit
  R0 = Zero if deregister succeeded. -1 if deregister failed.

Use

This SWI deregisters a previously registered driver.


PCI_ConfigurationRead    (SWI &50E44)

On Entry
  R0 = Flags  (All bits reserved. Should be 0).
  R1 = byte offset within configuration space (on word boundary)
  R3 = PCI logical device number.


On Exit
  R2 = word read from configuration space of specificed device at
       specified offset

Use

This SWI reads a word from the configuration space of the specified device.

PCI_ConfigurationWrite    (SWI &50E45)

On Entry
  R0 = Flags  (All bits reserved. Should be 0).
  R1 = byte offset within configuration space (on word boundary)
  R2 = Data word to write at that offset
  R3 = PCI logical device number.

On Exit
  All registers preserved, unless an error, returned in R0

Use

This SWI writes a data word into the configuration space of the specified
device.


PCI_AddressMapping    (SWI &50E46)

On Entry
  R0 = Flags  (All bits reserved. Should be 0).
  R1 -> word-aligned buffer to receive the results
        maximum possible length is 7 records of 20 bytes ie 140 bytes total
  R2 = Length of supplied buffer in bytes
  R3 = PCI logical device number.


On Exit
  R0 = Length of results in bytes

Use

This SWI returns information about the mapping of the address space(s) used
by the specified PCI device.

The results are returned in 20 byte records as described below:

 [0]  bits 0-7: Address region on the PCI device (ie BAR number)
                bits 8-29:  Reserved
                bits 30-31: 0 = Memory area
                            1 = IO area
                            2 = Expansion ROM,
                            3 = reserved
 [4]  Base address of area in PCI bus address map
 [8]  Base address of area in ARM cpu logical address map
      (for word access, ie with LDR/STR/LDM/STM)
 [12] Size of area in bytes.
 [16] Base address of I/O area in PCI bus address map
      (for byte access, ie with LDRB/STRB *only*)
      NB set to same as word adrs if byte-mode not supported
      (ie memory or ROM areas and also i/o areas beyond first 256K)
      NB beware for i/o areas bigger than 16K that 64K pages are swapped to
      support legacy mappings
      eg Parallel Port at 0278 is visible at 030 109E0;
      ports in region of &1000-1FFF visible at 030 0xxxx

Note that devices within the SuperCombo part of the SouthBridge are
hardwired into traditional locations to allow existing drivers to operate
with minimum modification.

The physical addresses for the I/O areas are the same as the logical
addresses.  For memory areas, the physical address is the same as the PCI
bus address, but note that only part of the bus address map is visible to
the CPU.

Note that although currently the mapping is configured completely at module
startup, in future versions that may change and only happen as each device
is registered with a driver.

PCI_ConfigurationReadBlock    (SWI &50E47)

On Entry
  R0 = Flags  (All bits reserved. Should be 0).
  R2 -> Word-aligned buffer of 256 bytes.
  R3 = PCI logical device number.

On Exit
  All registers preserved, unless no such device
  Then 1st word of buffer set to 0xFFFFFFFF (ie vendor and device id)

Use

This SWI reads the entire 256-byte PCI type 00h configuration space header
region into the buffer pointed to by R2

PCI_InterruptMapping    (SWI &50E48)

On Entry
  R0 = Flags  (All bits reserved. Should be 0).
  R1 -> Word-aligned buffer to receive the results of maximum length 20
        bytes.
  R2 = Length of buffer in bytes
  R3 = PCI logical device number.

On Exit
  All registers preserved, unless no such device
  Then 1st word of buffer set to &FFFFFFFF

Use

This SWI puts the following irq interrupt information into the buffer
pointed to by R1 :-

  [0] = irq device number
        if no such device, set to &FFFFFFFF
  [1] = mask to use: OR to enable irq; BIC to disable
  [2] = logical address of enable mask word:
        set the bit to enable irq generation
  [3] = logical address of status word:
        bit is set if irq being requested
  [4] = logical address of current interrupt status:
        bit is set if active AND enabled

Note that there can be up to 8 functions per PCI device.  Most cards will
only have the one (eg SCSI, ethernet, sound, video etc).  One exception I
have found so far is a USB2 card which had 3 functions (ie 2 USB1.1 OHCI
controllers and one USB2 EHCI controller).  These functions have independent
interrupt requests (irq).  The primary IRQ channel for each slot is unique,
so if the slots are all either empty or contain a single-function device,
then irqs are device specific. However, the secondary (up to 3) irq channels
for multifunction devices are shared with the primary irq of neighbouring
cards/slots.  In order to support shared irq channels, PCI interrupts are
routed via the MicroDigital irq controller system.

If the irq device number is less than 128, use the normal Risc OS SWI
  OS_ClaimDeviceVector and OS_ReleaseDeviceVector
otherwise use
 MicroDigital_ClaimDeviceVector    (&54001) and
 MicroDigital_ReleaseDeviceVector  (&54002)

These are identical in use to the Risc OS version, except that /all/ irq
device channels require r3 and r4 to be supplied (with word aligned address
pointer and 32bit bit mask of an irq active flag bit(s)).  If there is only
one claimant of an irq channel, then /all/ irqs on that channel will be
routed to that handler, without checking the active flag.  If there are more
than one claimant, then each handler will only get called if its active flag
is set.  If there are no active flags set then the irq will be disabled.

The irq enable mask should be enabled by each driver after claiming the
vector, but should NOT be disabled when releasing the vector, in case there
are other users of that channel.  When the last claimant releases, then the
mask will be automatically cleared.



PCI_FlushCaches    (SWI &50E49)

On Entry
  R0 -> logical address of start of area to be shared with another
        processor or bus-mastering device
  R1 =  length of area in bytes

On Exit
  All registers preserved.

Use

This SWI ensures that the whole of the specified memory area has been
cleared out of the ARM CPU data cache.  This should be performed for all
areas that are about to be read or written to directly by any bus mastering
DMA controller, prior to the data transfer being initiated.

All the caches and buffers inside the Omega NorthBridge and video FPGAs do
full bus-snooping and so are automatically kept fully up to date with any
changes made to memory content.

There is an alternative approach to avoiding the CPU cache-cohency problem
by simply marking relevant memory pages as uncachable. However StrongARM
access to that memory then becomes very slow because burst memory access is
disabled, and each single memory access then takes as almost as long as the
burst would otherwise have done.

Note that the act of writing the start command/control word to the DMA
controller register will automatically force the CPU to first flush the
write buffer(s).