#include #include "pci.h" #define I_VENDOR_ID 0x00 #define PCI_DEVICE_ID 0x02 #define PCI_CMD_REG 0x04 #define PCI_STATUS_REG 0x06 #define PCI_REV_ID 0x08 /* including the class code */ #define PCI_CACHE_LINE_SIZE 0x0C #define PCI_LATENCY_TIMER 0x0D #define PCI_HEAD_TYPE 0x0E #define PCI_BIST 0x0F #define PCI_BASE_ADDR_0 0x10 #define PCI_BASE_ADDR_1 0x14 #define PCI_BASE_ADDR_2 0x18 #define PCI_BASE_ADDR_3 0x1C #define PCI_BASE_ADDR_4 0x20 #define PCI_BASE_ADDR_5 0x24 #define PCI_CIS_POINTER 0x28 #define PCI_SUB_VENDOR_ID 0x2C #define PCI_SUB_SYSTEM_ID 0x2E #define PCI_EXP_ROM_BASE 0x30 #define PCI_INTR_LINE 0x3C #define PCI_INTR_PIN 0x3D #define PCI_MIN_GNT 0x3E #define PCI_MAX_LAT 0x3F #define OFFSET_TO_DW_INDEX(x) ((x) & ~0x3) #define OFFSET_TO_BYTE_INDEX(x) ((x) & 0x3) /*---------------------------------------------------------------------*/ /* Ports and the bit patterns used by the Configuration Mechanism One */ /*---------------------------------------------------------------------*/ #define CFG_ADDR_REG 0x0CF8 #define CFG_DATA_REG 0x0CFC #define CFG_SPACE_ENA 0x80000000 /*---------------------------------------------------------------------*/ /* Ports and the bit patterns used by the Configuration Mechanism Two */ /*---------------------------------------------------------------------*/ #define CFG_ENABLE_REG 0x0CF8 #define CFG_FORWARD_REG 0x0CFA #define CFG_BASE_REG 0xC000 #define CFG_SPACE_KEY 0xF0 #define SPE_CYC_ENA 0x01 #define MULTI_FUNC_BIT 0x80 #define MAX_PCI_DEVICES 16 #define MAX_BUS_NUM 16 /* the maximum value is 256 */ #define MAX_DEV_NUM 32 #define MAX_FUNC_NUM 8 #define PCI_CFG_MECHANISM_1 1 #define PCI_CFG_MECHANISM_2 2 #define PCI_NO_DEVICE_ID 0xffffffff #define USHORT unsigned short #define ULONG unsigned long #define UCHAR unsigned char typedef struct pci_cfg_info { struct pci_cfg_info *next; USHORT vendor_id; USHORT dev_id; USHORT pci_bus_num; USHORT pci_dev_num; USHORT pci_func_num; USHORT rev_id; USHORT base_class; USHORT sub_class; ULONG class_code; USHORT subsys_vendor_id; USHORT subsys_id; ULONG cfg_addr; } PCI_CFG_INFO; static PCI_CFG_INFO pci_cfg_info[MAX_PCI_DEVICES]; unsigned long g_bridge_setting_IO; USHORT pci_cfg_rd_w(ULONG addr, ULONG offset); UCHAR pci_cfg_rd_b(ULONG addr, ULONG offset); ULONG pci_cfg_rd_l(ULONG addr, ULONG offset); static ULONG inpd(int portnum) { static ULONG value ; asm mov dx,portnum ; asm lea bx,value ; __emit__(0x66,0x50, // push EAX 0x66,0xED, // in EAX,DX 0x66,0x89,0x07, // mov [BX],EAX 0x66,0x58) ; // pop EAX return value ; } static void outpd(int portnum, ULONG val) { static ULONG value = 0 ; value = val ; asm mov dx,portnum ; asm lea bx,value ; __emit__(0x66,0x50, // push EAX 0x66,0x8B,0x07, // mov EAX,[BX] 0x66,0xEF, // out DX,EAX 0x66,0x58) ; // pop EAX return ; } PCI_CFG_INFO * get_pci_cfg_info_tbl() { PCI_CFG_INFO *pinfo; ULONG dnum, fnum, bus_num; ULONG addr, addr_f; ULONG tmpl; ULONG tmps; ULONG pci_found; pinfo = &pci_cfg_info[0]; pci_found = 0; for(bus_num=0; bus_num < MAX_BUS_NUM; bus_num++) { for(dnum=0; dnum < MAX_DEV_NUM; dnum++) { addr = (bus_num << 16) | (dnum << 11); for(fnum=0; fnum < MAX_FUNC_NUM; fnum++) { /*---------------------------------------------------------*/ /* read vendor and device IDs and check them */ /*---------------------------------------------------------*/ addr_f = addr | (fnum << 8); tmpl = pci_cfg_rd_l(addr_f, 0); if(tmpl == PCI_NO_DEVICE_ID) break; pinfo->vendor_id = tmpl & 0xFFFF; pinfo->dev_id = (tmpl >> 16) & 0xFFFF; pinfo->pci_bus_num = bus_num; pinfo->pci_dev_num = dnum; pinfo->pci_func_num = fnum; pinfo->subsys_id = pci_cfg_rd_w(addr_f, PCI_SUB_VENDOR_ID); pinfo->subsys_vendor_id = pci_cfg_rd_w(addr_f, PCI_SUB_SYSTEM_ID); tmpl = pci_cfg_rd_l(addr_f, PCI_REV_ID); pinfo->rev_id = tmpl & 0xf; pinfo->class_code = (tmpl >> 8) & 0xffffff; pinfo->base_class = (tmpl >> 24) & 0xff; pinfo->sub_class = (tmpl >> 16) & 0xff; pinfo->cfg_addr = addr_f; pci_found++; if(pci_found >= MAX_PCI_DEVICES) break; pinfo->next = &pci_cfg_info[pci_found]; pinfo = pinfo->next; tmpl = pci_cfg_rd_b(addr| (fnum << 8), PCI_HEAD_TYPE); if(!(tmpl & MULTI_FUNC_BIT)) break; } } } pinfo->next = 0; return &pci_cfg_info[0]; } /* get_pci_cfg_info_tbl() */ ULONG pci_cfg_read(ULONG dev_idx, ULONG offset, ULONG bytes) { ULONG addr; addr = pci_cfg_info[dev_idx].cfg_addr; if(bytes == 1) return pci_cfg_rd_b(addr, offset); else if(bytes == 2) return pci_cfg_rd_w(addr, offset); else return pci_cfg_rd_l(addr, offset); } USHORT pci_cfg_rd_w(ULONG addr, ULONG offset) { USHORT wtmp; addr |= CFG_SPACE_ENA; outpd(CFG_ADDR_REG, addr | OFFSET_TO_DW_INDEX(offset)); wtmp = inport(CFG_DATA_REG | OFFSET_TO_BYTE_INDEX(offset)); outpd(CFG_ADDR_REG, 0); return wtmp; } /* pci_cfg_rd_w() */ UCHAR pci_cfg_rd_b(ULONG addr, ULONG offset) { UCHAR btmp; addr |= CFG_SPACE_ENA; outpd(CFG_ADDR_REG, addr | OFFSET_TO_DW_INDEX(offset)); btmp = inportb(CFG_DATA_REG | OFFSET_TO_BYTE_INDEX(offset)); outpd(CFG_ADDR_REG, 0); return btmp; } /* pci_cfg_rd_b() */ ULONG pci_cfg_rd_l(ULONG addr, ULONG offset) { ULONG ltmp; addr |= CFG_SPACE_ENA; outpd(CFG_ADDR_REG, addr | OFFSET_TO_DW_INDEX(offset)); ltmp = inpd(CFG_DATA_REG); outpd(CFG_ADDR_REG, 0); return ltmp; } /* pci_cfg_rd_l() */ ULONG findPCIdev(ULONG classcode, ULONG *puBaseAddress, ULONG *puIntLevel) { PCI_CFG_INFO *pci_tblp; ULONG dev_idx; ULONG uHostType; ULONG uRetVal; ULONG uData; dev_idx = 0; pci_tblp = get_pci_cfg_info_tbl(); /*************************************/ /* No PCI device found in the system */ /*************************************/ if(pci_tblp->vendor_id == 0xffff && pci_tblp->dev_id == 0xffff) { return 0; } /*************************************/ /* Search for USB host controllers */ /*************************************/ while (pci_tblp) { /* Is it the end of pSOS PCI device table? */ if (pci_tblp->vendor_id == 0xffff && pci_tblp->dev_id == 0xffff) break; /* Is it a USB host controller? */ if (pci_tblp->class_code == classcode) { *puBaseAddress = pci_cfg_read(dev_idx, PCI_BASE_ADDR_2, 4UL) & 0xFFFFFFF0; g_bridge_setting_IO = pci_cfg_read(dev_idx, PCI_BASE_ADDR_1, 4UL) & 0xFFFFFFF0; *puIntLevel = pci_cfg_read(dev_idx, PCI_INTR_LINE, 1UL); return 1; } /* if */ dev_idx++; pci_tblp = pci_tblp->next; } /* while */ return 0; } /* findPCIdev() */ void set_pci_bridge( void ) { unsigned long wait_cycle=3L; unsigned long tmp; tmp = inpd (g_bridge_setting_IO + 0x18); tmp &= ~0x0000003C; // mask register[5..2] tmp |= wait_cycle << 2; outpd(g_bridge_setting_IO + 0x18, tmp); outpd( g_bridge_setting_IO + 0x68, 0x00000900 ); }