pci.c
来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 612 行 · 第 1/2 页
C
612 行
/* -*-C-*-
*
* $Revision: 1.4 $
* $Author: kwelton $
* $Date: 2000/08/08 21:45:52 $
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
* Copyright (c) 1995-1998 Microsoft Corporation
* Copyright (c) 2000 ARM Limited
* All Rights Reserved
*/
#include "windows.h"
#include "ceddk.h"
#ifdef OldCode
# include "uhal.h"
#else
# include "cdefs.h"
#endif
#include "pcilib.h"
#include "pci.h"
#include "win_plat.h"
/*
* The value for these globals will be set by code that's
* unique to either the OS or Eboot. That's because, for the
* OS, we want to use the virtual address, and for Eboot,
* the physical.
*/
unsigned int PciMemBase;
unsigned int PciCfgBase;
unsigned int PciV3Base;
unsigned int PciIOBase;
typedef struct _TYPE1_PCI_ADDRESS {
union {
struct {
ULONG Reserved:2;
ULONG Register:6;
ULONG Function:3;
ULONG Device:5;
ULONG Bus:8;
ULONG Reserved2:7;
ULONG ConfigurationAccess:1;
} bits;
ULONG AsULONG;
} u;
} TYPE1_PCI_ADDRESS, *PTYPE1_PCI_ADDRESS;
/*
The V3 PCI interface chip in Integrator provides several windows from
local bus memory into the PCI memory areas. Unfortunately, there
are not really enough windows for our usage, therefore we reuse
one of the windows for access to PCI configuration space. The
memory map is as follows:
Local Bus Memory Usage
80000000 - 8FFFFFFF PCI memory. 256M non-prefetchable
90000000 - 9FFFFFFF PCI memory. 256M prefetchable
B0000000 - B0FFFFFF PCI IO. 16M
B8000000 - B8FFFFFF PCI Configuration. 16M
There are three V3 windows, each described by a pair of V3 registers.
These are LB_BASE0/LB_MAP0, LB_BASE1/LB_MAP1 and LB_BASE2/LB_MAP2.
Base0 and Base1 can be used for any type of PCI memory access. Base2
can be used either for PCI I/O or for I20 accesses.
PCI Memory is mapped so that assigned addresses in PCI Memory match
local bus memory addresses. In other words, if a PCI device is assigned
address 80200000 then that address is a valid local bus address as well
as a valid PCI Memory address. PCI IO addresses are mapped to start
at zero. This means that local bus address B0000000 maps to PCI IO address
00000000 and so on. Device driver writers need to be aware of this
distinction.
Normally these spaces are mapped using the following base registers:
Usage Local Bus Memory Base/Map registers used
Mem 80000000 - 8FFFFFFF LB_BASE0/LB_MAP0
Mem 90000000 - 9FFFFFFF LB_BASE1/LB_MAP1
A0000000 - AFFFFFFF
IO B0000000 - B0FFFFFF LB_BASE2/LB_MAP2
Cfg B8000000 - B8FFFFFF
This means that I20 and PCI configuration space accesses will fail.
When PCI configuration accesses are needed we must remap the spaces
as follows:
Usage Local Bus Memory Base/Map registers used
Mem 80000000 - 8FFFFFFF LB_BASE0/LB_MAP0
Mem 90000000 - 9FFFFFFF LB_BASE0/LB_MAP0
A0000000 - AFFFFFFF
IO B0000000 - B0FFFFFF LB_BASE2/LB_MAP2
Cfg B8000000 - B8FFFFFF LB_BASE1/LB_MAP1
To make this work, the code depends on overlapping windows working.
The V3 chip translates an address by checking its range within
each of the BASE/MAP pairs in turn (in ascending register number
order). It will use the first matching pair. So, for example,
if the same address is mapped by both LB_BASE0/LB_MAP0 and
LB_BASE1/LB_MAP1, the V3 will use the translation from
LB_BASE0/LB_MAP0.
To allow PCI Configuration space access, the code enlarges the
window mapped by LB_BASE0/LB_MAP0 from 256M to 512M. This occludes
the windows currently mapped by LB_BASE1/LB_MAP1 so that it can
be remapped for use by configuration cycles.
At the end of the PCI Configuration space accesses,
LB_BASE1/LB_MAP1 is reset to map PCI Memory. Finally the window
mapped by LB_BASE0/LB_MAP0 is reduced in size from 512M to 256M to
reveal the now restored LB_BASE1/LB_MAP1 window.
NOTE: We do not set up I20 mapping.
*/
// V3 access routines
#define _V3Write16(o,v) (*(volatile U16 *)(PciV3Base + (U32)(o)) = (U16)(v))
#define _V3Read16(o) (*(volatile U16 *)(PciV3Base + (U32)(o)))
#define _V3Write32(o,v) (*(volatile U32 *)(PciV3Base + (U32)(o)) = (U32)(v))
#define _V3Read32(o) (*(volatile U32 *)(PciV3Base + (U32)(o)))
void _V3OpenConfigWindow(void) {
// Set up base0 to see all 512Mbytes of memory space (not prefetchable), this
// frees up base1 for re-use by configuration memory
_V3Write32(V3_LB_BASE0, ((PHYS_PCI_MEM_BASE & 0xFFF00000) | 0x90 | V3_LB_BASE_M_ENABLE)) ;
// Set up base1 to point into configuration space, note that MAP1 register is
// set up by PCIMakeConfigAddress().
_V3Write32(V3_LB_BASE1, ((PHYS_PCI_CONFIG_BASE & 0xFFF00000) | 0x40 | V3_LB_BASE_M_ENABLE)) ;
}
void _V3CloseConfigWindow(void) {
// Reassign base1 for use by prefetchable PCI memory
_V3Write32(V3_LB_BASE1, (((PHYS_PCI_MEM_BASE + SZ_256M) & 0xFFF00000) | 0x84 | V3_LB_BASE_M_ENABLE)) ;
_V3Write16(V3_LB_MAP1, (((PHYS_PCI_MEM_BASE + SZ_256M) & 0xFFF00000) >> 16) | 0x0006) ;
// And shrink base0 back to a 256M window (NOTE: MAP0 already correct)
_V3Write32(V3_LB_BASE0, ((PHYS_PCI_MEM_BASE & 0xFFF00000) | 0x80 | V3_LB_BASE_M_ENABLE)) ;
}
/*============================================================================
*
* routine: PCIMakeConfigAddress()
*
* parameters: bus = which bus
* device = which device
* function = which function
* offset = configuration space register we are interested in
*
* description: this routine will generate a platform dependant config
* address.
*
* calls: none
*
* returns: configuration address to play on the PCI bus
*
* To generate the appropriate PCI configuration cycles in the PCI
* configuration address space, you present the V3 with the following pattern
* (which is very nearly a type 1 (except that the lower two bits are 00 and
* not 01). In order for this mapping to work you need to set up one of
* the local to PCI aperatures to 16Mbytes in length translating to
* PCI configuration space starting at 0x0000.0000.
*
* PCI configuration cycles look like this:
*
* Type 0:
*
* 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
* 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* 31:11 Device select bit.
* 10:8 Function number
* 7:2 Register number
*
* Type 1:
*
* 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
* 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* 31:24 reserved
* 23:16 bus number (8 bits = 128 possible buses)
* 15:11 Device number (5 bits)
* 10:8 function number
* 7:2 register number
*
*/
DWORD PCIMakeConfigAddress(DWORD bus, DWORD device,
DWORD function, DWORD offset)
{
DWORD address, devicebit;
WORD mapaddress;
address = PciCfgBase;
address |= ((function & 0x07) << 8);
address |= offset & 0xFF;
if (bus == 0)
{
/*
* local bus segment so need a type 0 config cycle
* build the PCI configuration "address" with one-hot in A31-A11
*/
mapaddress = 0x000A; /* 101=>config cycle, 0=>A1=A0=0 */
devicebit = (1 << (device + 11));
if ((devicebit & 0xFF000000) != 0)
{
/* high order bits are handled by the MAP register */
mapaddress |= (devicebit >>16) ;
}
else
{
/* low order bits handled directly in the address */
address |= devicebit ;
}
}
else
{
/*
* bus !=0
*
* not the local bus segment so need a type 1 config cycle
* A31-A24 are don't care (so clear to 0)
*/
mapaddress = 0x000B; /* 101=>config cycle, 1=>A1&A0 from
* PCI_CFG */
address |= (bus & 0xFF) << 16; /* bits 23..16 = bus number */
address |= (device & 0x1F) << 11; /* bits 15..11 = device number */
}
_V3Write16(V3_LB_MAP1, mapaddress);
return(address);
}
/*
* Initialise the serial port
* NOTE: HOST_COMPORT and OS_COMPORT must be defined (see platform.[sh])
*
* uHALr_ResetPort() is aliased to be
* uHALir_InitSerial(OS_COMPORT, DEFAULT_OS_BAUD)
*/
void uHALir_InitSerial(unsigned int port, unsigned int baudRate)
{
/* If running under a debugger, don't re-initialise its comport. */
if (HOST_COMPORT != port)
{
/* first, disable everything */
IO_WRITE(port + AMBA_UARTCR, 0x0);
/* Set baud rate */
IO_WRITE(port + AMBA_UARTLCR_M, ((baudRate & 0xf00) >> 8));
IO_WRITE(port + AMBA_UARTLCR_L, (baudRate & 0xff));
/*
* ----------v----------v----------v----------v----------
* NOTE: MUST BE WRITTEN LAST (AFTER UARTLCR_M & UARTLCR_L)
* ----------^----------^----------^----------^----------
*
* set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled
*/
IO_WRITE(port + AMBA_UARTLCR_H,
(AMBA_UARTLCR_H_WLEN_8 | AMBA_UARTLCR_H_FEN));
/* finally, enable the uart */
IO_WRITE(port + AMBA_UARTCR, AMBA_UARTCR_UARTEN);
}
}
#if 0
/*============================================================================
*
* routine: bridgeSwizzle
*
* A small note about bridges and interrupts. The DECchip 21050 (and later chips)
* adheres to the PCI-PCI bridge specification. This says that the interrupts on
* the other side of a bridge are swizzled in the following manner:
*
* Dev Interrupt Interrupt
* Pin on Pin on
* Device Connector
*
* 4 A A
* B B
* C C
* D D
*
* 5 A B
* B C
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?