📄 405gp_pci.c
字号:
/*-----------------------------------------------------------------------------+
|
| This source code has been made available to you by IBM on an AS-IS
| basis. Anyone receiving this source is licensed under IBM
| copyrights to use it in any way he or she deems fit, including
| copying it, modifying it, compiling it, and redistributing it either
| with or without modifications. No license under IBM patents or
| patent applications is to be implied by the copyright license.
|
| Any user of this software should understand that IBM cannot provide
| technical support for this software and will not be responsible for
| any consequences resulting from the use of this software.
|
| Any person who transfers this source code or any derivative work
| must include the IBM copyright notice, this paragraph, and the
| preceding two paragraphs in the transferred software.
|
| COPYRIGHT I B M CORPORATION 1995
| LICENSED MATERIAL - PROGRAM PROPERTY OF I B M
+-----------------------------------------------------------------------------*/
#include <ppcboot.h>
#include <command.h>
#include <cmd_boot.h>
#include <405gp_pci.h>
#include <asm/processor.h>
#ifdef CONFIG_PPC405GP
#ifdef CONFIG_PCI_PNP
/*#define DEBUG*/
/*------------------------------------------------------------------------
| These are the lowest addresses allowed for PCI configuration.
| They correspond to lowest available I/O and Memory addresses.
| In the case where where multiple PMM regs are being used to map
| different PLB to PCI regions, each region should have it's own
| minimum address.
+-----------------------------------------------------------------------*/
unsigned long LowestMemAddr1 = MIN_PCI_MEMADDR1;
unsigned long LowestMemAddr2 = MIN_PCI_MEMADDR2;
unsigned long LowestIOAddr = MIN_PCI_PCI_IOADDR;
unsigned long MaxBusNum = 0;
static __inline__ unsigned long get_msr(void)
{
unsigned long msr;
asm volatile("mfmsr %0" : "=r" (msr) :);
return msr;
}
static __inline__ void set_msr(unsigned long msr)
{
asm volatile("mtmsr %0" : : "r" (msr));
}
/*-----------------------------------------------------------------------------+
| pci_init. Initializes the 405GP PCI Configuration regs.
+-----------------------------------------------------------------------------*/
void pci_init(void)
{
unsigned short temp_short;
/*--------------------------------------------------------------------------+
| 405GP PCI Master configuration.
| Map one 512 MB range of PLB/processor addresses to PCI memory space.
| PLB address 0x80000000-0x9FFFFFFF ==> PCI address 0x80000000-0x9FFFFFFF
| Use byte reversed out routines to handle endianess.
+--------------------------------------------------------------------------*/
out32r(PMM0MA, 0x00000000); /* ensure disabled b4 setting PMM0LA */
out32r(PMM0LA, 0x80000000);
out32r(PMM0PCILA, 0x80000000);
out32r(PMM0PCIHA, 0x00000000);
out32r(PMM0MA, 0xE0000001); /* no prefetching, and enable region */
/*--------------------------------------------------------------------------+
| Map one 512 MB range of PLB/processor addresses to PCI memory space.
| PLB address 0xA0000000-0xBFFFFFFF ==> PCI address 0x00000000-0x1FFFFFFF
| Use byte reversed out routines to handle endianess.
| This space is for the VGA card.
+--------------------------------------------------------------------------*/
out32r(PMM1MA, 0x00000000); /* ensure disabled b4 setting PMM1LA */
out32r(PMM1LA, 0xA0000000);
out32r(PMM1PCILA, 0x00000000);
out32r(PMM1PCIHA, 0x00000000);
out32r(PMM1MA, 0xE0000001); /* no prefetching, and enable region */
/*--------------------------------------------------------------------------+
| PMM2 is not used. Initialize them to zero.
+--------------------------------------------------------------------------*/
out32r(PMM2MA, 0x00000000); /* ensure disabled b4 setting PMM2LA */
out32r(PMM2LA, 0x00000000);
out32r(PMM2PCILA, 0x00000000);
out32r(PMM2PCIHA, 0x00000000);
out32r(PMM2MA, 0x00000000); /* not enabled */
/*--------------------------------------------------------------------------+
| 405GP PCI Target configuration. (PTM1)
| Map one 2 GB range of PCI addresses to PLB/processor address space.
| PCI address 0x00000000-0x7FFFFFFF ==> PLB address 0x00000000-0x7FFFFFFF
| The 0x00000008 default value of the 405GP PTM1 Base Address Register
| (in the PCI config header) is correct for this mapping.
| Note: PTM1MS is hardwire enabled but we set the enable bit anyway.
+--------------------------------------------------------------------------*/
out32r(PTM1LA, 0x00000000);
out32r(PTM1MS, 0x80000001); /* 2GB, enable bit is hard-wired to 1 */
/*--------------------------------------------------------------------------+
| 405GP PCI Target configuration. (PTM2) Not used here.
| It is possible that the enable bit in PTM2MS could be set at power
| up. The ROM monitor only needs to use PTM1, so we must make sure that
| PTM2 is disabled to avoid PCI target conflicts.
| Note: PTM2MS must be enabled to write PTM 2 BAR.
| Zero out PTM 2 BAR, then disable via PTM2MS.
+--------------------------------------------------------------------------*/
out32r(PTM2LA, 0x00000000);
out32r(PTM2MS, 0x00000001); /* set enable bit */
PCI_Write_CFG_Reg(PCIDEVID_405GP, PCIBASEADDR2, 0x00000000, 4);
out32r(PTM2MS, 0x00000000); /* disable */
/*--------------------------------------------------------------------------+
| Write the 405GP PCI Configuration regs.
| Enable 405GP to be a master on the PCI bus (PMM).
| Enable 405GP to act as a PCI memory target (PTM).
+--------------------------------------------------------------------------*/
temp_short = PCI_Read_CFG_Reg(PCIDEVID_405GP, PCICMD, 2);
PCI_Write_CFG_Reg(PCIDEVID_405GP, PCICMD, temp_short | BM_EN | MEM_EN, 2);
#if 0 /* test-only: no need yet! */
/*--------------------------------------------------------------------------+
| If PCI speed = 66Mhz, set 66Mhz capable bit.
+--------------------------------------------------------------------------*/
if (board_cfg.pci_speed==66666666) {
temp_short = PCI_Read_CFG_Reg(PCIDEVID_405GP, PCISTATUS, 2);
PCI_Write_CFG_Reg(PCIDEVID_405GP,PCISTATUS,(temp_short|CAPABLE_66MHZ), 2);
}
#endif
#if 0 /* test-only: no need yet! */
/*--------------------------------------------------------------------------+
| Default value of the Bridge Options1 register is OK (0xFF60).
| Default value of the Bridge Options2 register is OK (0x0100).
| No need to change them in pass 2 405GP.
| Low subsequent target latency timer values are not supported in pass 1.
| STLD = '1111' if asynchronous PCI
| STLD = '0111' if synchronous PCI
+--------------------------------------------------------------------------*/
/* The following should only be required for PASS 1 405GP because of */
/* errata #26 */
if (ppcMfpvr() == PVR_405GP_PASS1)
{
temp_short = PCI_Read_CFG_Reg(PCIDEVID_405GP, PCIBRDGOPT2, 2);
if (ppcMfstrap() & PCI_ASYNC_MODE_EN) {
PCI_Write_CFG_Reg(PCIDEVID_405GP, PCIBRDGOPT2,(temp_short | 0x0F00), 2);
}
else {
PCI_Write_CFG_Reg(PCIDEVID_405GP, PCIBRDGOPT2,(temp_short | 0x0700), 2);
}
}
#endif
/*--------------------------------------------------------------------------+
| Scan the PCI bus and configure devices found.
+--------------------------------------------------------------------------*/
PCI_Scan(0);
}
/*-----------------------------------------------------------------------------+
| Subroutine: PCI_Read_CFG_Reg
| Description: Read a PCI configuration register
| Inputs:
| BusDevFunc PCI Bus+Device+Function number
| Reg Configuration register number
| Width Number of bytes to read (1, 2, or 4)
| Return value:
| (unsigned int) Value of the configuration register read.
| For reads shorter than 4 bytes, return value
| is LSB-justified
+-----------------------------------------------------------------------------*/
unsigned int PCI_Read_CFG_Reg(int BusDevFunc, int Reg, int Width)
{
unsigned int RegAddr;
/*--------------------------------------------------------------------------+
| bit 31 must be 1 and bits 1:0 must be 0 (note Little Endian bit notation)
+--------------------------------------------------------------------------*/
RegAddr = 0x80000000 | ((Reg|BusDevFunc) & 0xFFFFFFFC);
/*--------------------------------------------------------------------------+
| Write reg to PCI Config Address
+--------------------------------------------------------------------------*/
out32r(PCICFGADR, RegAddr);
/*--------------------------------------------------------------------------+
| Read reg value from PCI Config Data
+--------------------------------------------------------------------------*/
switch (Width)
{
case 1: return ((unsigned int) in8(PCICFGDATA | (Reg & 0x3)));
case 2: return ((unsigned int) in16r(PCICFGDATA | (Reg & 0x3)));
case 4: return (in32r(PCICFGDATA | (Reg & 0x3)));
}
return 0; /* not reached: just to satisfy the compiler */
}
/*-----------------------------------------------------------------------------+
| Subroutine: PCI_Write_CFG_Reg
| Description: Write a PCI configuration register.
| Inputs:
| BusDevFunc PCI Bus+Device+Function number
| Reg Configuration register number
| Value Configuration register value
| Width Number of bytes to write (1, 2, or 4)
| Return value:
| 0 Successful
| Updated for pass2 errata #6. Need to disable interrupts and clear the
| PCICFGADR reg after writing the PCICFGDATA reg.
+-----------------------------------------------------------------------------*/
int PCI_Write_CFG_Reg(int BusDevFunc, int Reg, unsigned int Value, int Width)
{
unsigned int RegAddr;
unsigned int msr;
/*--------------------------------------------------------------------------+
| Ensure interrupts disabled for pass2 errata #6.
+--------------------------------------------------------------------------*/
msr = get_msr();
set_msr(msr & ~(MSR_EE|MSR_CE));
/*--------------------------------------------------------------------------+
| bit 31 must be 1 and bits 1:0 must be 0 (note Little Endian bit notation)
+--------------------------------------------------------------------------*/
RegAddr = 0x80000000 | ((Reg|BusDevFunc) & 0xFFFFFFFC);
/*--------------------------------------------------------------------------+
| Write reg to PCI Config Address
+--------------------------------------------------------------------------*/
out32r(PCICFGADR, RegAddr);
/*--------------------------------------------------------------------------+
| Write reg value to PCI Config Data
+--------------------------------------------------------------------------*/
switch (Width)
{
case 1: out8(PCICFGDATA | (Reg & 0x3), (unsigned char)(Value & 0xFF));
break;
case 2: out16r(PCICFGDATA | (Reg & 0x3),(unsigned short)(Value & 0xFFFF));
break;
case 4: out32r(PCICFGDATA | (Reg & 0x3), Value);
break;
}
/*--------------------------------------------------------------------------+
| Write PCI Config Address after writing PCICFGDATA for pass2 errata #6.
+--------------------------------------------------------------------------*/
out32r(PCICFGADR, 0x00000000);
/*--------------------------------------------------------------------------+
| Restore msr (for pass2 errata #6).
+--------------------------------------------------------------------------*/
set_msr(msr);
return (0);
}
/*-----------------------------------------------------------------------
|
| Subroutine: PCI_Scan
|
| Prototype: void PCI_Scan(int BusNum)
|
| Description: Scan through all 16 allowable PCI IDs and configure
| those for which the vendor ID indicates there is a
| device present.
|
| Inputs:
| BusNum Bus number where scanning begins
|
| Return value:
| None
|
+----------------------------------------------------------------------*/
void PCI_Scan(int BusNum)
{
int Device;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -