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 *MemoryWB This writes new memory contents in bytes, but without reading. Syntax: *MemoryWB 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).