📄 pci.c
字号:
/* *---------------------------------------------------------------------- * T-Kernel * * Copyright (C) 2004 by Ken Sakamura. All rights reserved. * T-Kernel is distributed under the T-License. *---------------------------------------------------------------------- * * Version: 1.01.00 * Released by T-Engine Forum(http://www.t-engine.org) at 2004/6/28. * *---------------------------------------------------------------------- *//* * @(#)pci.c (libtk/VR5500) * * PCI device access sequence */#include <basic.h>#include <libstr.h>#include <tk/syslib.h>#include <tm/tmonitor.h>#include "pci.h"/* PCI configuration information */LOCAL PciInfo *pciInfo = NULL;/* PCI configuration address definitions */#define CADDR(bus, dev, func) (((bus) << 8) | ((dev) << 3) | (func))#define BUSNO(caddr) (((caddr) >> 8) & 0xff)#define DEVNO(caddr) (((caddr) >> 3) & 0x1f)#define FUNCNO(caddr) ((caddr) & 0x07)/* PCI bus number definitions *//* * The PCI bus number/Bus#0device number is defined as follows. * * Host * | * | Bus #0 (used by virtual objects, IPOCI bridge, * | and external PCI bridge) * | * +---- Device #1(IOPCI(PCI1) bridge) * | | * | | Bus #1(for IOPCI device * | | * | +---- Device #x (AC97 codec) * | +---- Device #y (USB Function) * | +---- Device #z (USB Host) * | * +----Device #2(external PCI(PCI0) bridge) * | * | Bus #2 (for external PCI device * | * +---- Device #a * +---- Device #b * +---- Device #c */#define PCI_BRIDGE 0#define PCI_IOPCI 1#define PCI_EXTPCI 2/* VRC5477 definition */#define IO_START 0xaf000000#define PCI_MEMWIN 0xb0000000#define IOPCI_MEMWIN 0xb8000000/* PCI0 */#define VID0 0x0200 /* PCI0 vendor ID */#define DID0 0x0202 /* PCI0 device ID */#define PCICMD0 0x0204 /* PCI0 command */#define PCISTS0 0x0206 /* PCI0 status */#define REVID0 0x0208 /* PCI0 revision ID */#define CLASS0 0x0209 /* PCI0 class code */#define CLSIZ0 0x020c /* PCI0 cache line size */#define MLTIM0 0x020d /* PCI0 latency timer */#define HTYPE0 0x020e /* PCI0 header type */#define BARC0 0x0210 /* PCI0 base address */#define BARM010 0x0218 /* PCI0 base address SDRAM bank 01 */#define BARM230 0x0220 /* PCI0 base address SDRAM bank 23 */#define SSVID0 0x022c /* PCI0 subsystem vendor ID */#define SSID0 0x022e /* PCI0 subsystem ID */#define INTLIN0 0x023c /* PCI0 interrupt line */#define INTPIN0 0x023d /* PCI0 interrupt terminal */#define BAR00 0x0240 /* PCI0 base address LDCS0 */#define BAR10 0x0248 /* PCI0 base address LDCS1 */#define BAR20 0x0250 /* PCI0 base address LDCS2 */#define BAR30 0x0258 /* PCI0 base address LDCS3 */#define BAR40 0x0260 /* PCI0 base address LDCS4 */#define BAR50 0x0268 /* PCI0 base address LDCS5 */#define BARB0 0x0280 /* PCI0 base address BOOT */#define BARP00 0x0290 /* PCI0 base address PCI1 window0 */#define BARP10 0x0298 /* PCI0 base address PCI1 window1 */#define PCISWP0 0x02b0 /* PCI0 swap */#define PCIERR0 0x02b8 /* PCI0 error */#define PCICTL0_L 0x02e0 /* PCI0 control -L */#define PCICTL0_H 0x02e4 /* PCI0 control -H */#define PCIARB0_L 0x02e8 /* PCI0 arbitration -L */#define PCIARB0_H 0x02ec /* PCI0 arbitration -H */#define PCIINIT00 0x02f0 /* PCI0 initiator 0 */#define PCIINIT10 0x02f8 /* PCI0 initiator 1 *//* PCI1 */#define VID1 0x0600 /* PCI1 vendor ID */#define DID1 0x0602 /* PCI1 device ID */#define PCICMD1 0x0604 /* PCI1 command */#define PCISTS1 0x0606 /* PCI1 status */#define REVID1 0x0608 /* PCI1 revision ID */#define CLASS1 0x0609 /* PCI1 class code CLASS1 */#define CLSIZ1 0x060c /* PCI1 cache line size */#define MLTIM1 0x060d /* PCI1 latency timer */#define HTYPE1 0x060e /* PCI1 header type */#define BARC1 0x0610 /* PCI1 base address */#define BARM011 0x0618 /* PCI1 base address SDRAM bank 01 */#define BARM231 0x0620 /* PCI1 base address SDRAM bank 23 */#define SSVID1 0x062c /* PCI1 subsystem vendor ID */#define SSID1 0x062e /* PCI1 subsystem ID */#define INTLIN1 0x063c /* PCI1 interrupt line */#define INTPIN1 0x063d /* PCI1 interrupt terminal */#define BAR01 0x0640 /* PCI1 base address LDCS0 */#define BAR11 0x0648 /* PCI1 base address LDCS1 */#define BAR21 0x0650 /* PCI1 base address LDCS2 */#define BAR31 0x0658 /* PCI1 base address LDCS3 */#define BAR41 0x0660 /* PCI1 base address LDCS4 */#define BAR51 0x0668 /* PCI1 base address LDCS5 */#define BARB1 0x0680 /* PCI1 base address BOOT */#define BARP01 0x0690 /* PCI1 base address PCI0 window0 */#define BARP11 0x0698 /* PCI1 base address PCI0 window1 */#define PCISWP1 0x06b0 /* PCI1 swap */#define PCIERR1 0x06b8 /* PCI1 error */#define PCICTL1_L 0x06e0 /* PCI1 control -L */#define PCICTL1_H 0x06e4 /* PCI1 control -H */#define PCIARB1_L 0x06e8 /* PCI1 arbitration -L */#define PCIARB1_H 0x06ec /* PCI1 arbitration -H */#define PCIINIT01 0x06f0 /* PCI1 initiator 0 */#define PCIINIT11 0x06f8 /* PCI1 initiator 1 *//* PDAR input/output */#define in_pdar_b(idx) in_b(IO_START + (idx))#define in_pdar_h(idx) in_h(IO_START + (idx))#define in_pdar_w(idx) in_w(IO_START + (idx))#define out_pdar_b(idx, dat) out_b(IO_START + (idx), (dat))#define out_pdar_h(idx, dat) out_h(IO_START + (idx), (dat))#define out_pdar_w(idx, dat) out_w(IO_START + (idx), (dat))/* PCI configuration register input/output */LOCAL UW ioPciConf(W caddr, W reg, W mode, UW dat){ UW ofs, init, win, cfg, msk, svinit, imask, idsl, sh, dtmsk; UW dt = ~0; ofs = reg & 0xfc; switch (BUSNO(caddr)) { case PCI_BRIDGE: /* Virtual PCI bus for host-PCI bridge */ switch (DEVNO(caddr)) { case PCI_EXTPCI: ofs |= IO_START | VID0; break; case PCI_IOPCI: ofs |= IO_START | VID1; break; default: ofs = 0; break; } win = init = cfg = msk = 0; break; case PCI_IOPCI: /* IOPCI device */ win = IOPCI_MEMWIN; msk = 0x00ffffff; /* 16Mbyte */ idsl = (((UW)0x80000000) >> DEVNO(caddr)) & 0xfffff800; ofs = idsl ? (ofs | idsl | (FUNCNO(caddr) << 8)) : 0; init = PCIINIT01; cfg = (0 << 9) | 0x1a; break; case PCI_EXTPCI: /* PCI device */ win = PCI_MEMWIN; msk = 0x03ffffff; /* 64Mbyte */ idsl = (((UW)0x80000000) >> DEVNO(caddr)) & 0xfffff800; ofs = idsl ? (ofs | idsl | (FUNCNO(caddr) << 8)) : 0; init = PCIINIT00; cfg = (0 << 9) | 0x1a; break; default: /* PCI device(with PCI-PCI bridge) */ win = PCI_MEMWIN; msk = 0x03ffffff; ofs |= caddr << 8; init = PCIINIT00; cfg = (1 << 9) | 0x1a; break; } svinit = 0; DI(imask); if (win) { /* Change memory space window to configuration space */ svinit = in_pdar_w(init); out_pdar_w(init, (ofs & ~msk) | cfg); (void)in_pdar_w(init); ofs = win + (ofs & msk); } if (ofs) { switch (mode) { default: case 0x04: dt = in_w(ofs); goto fin; case 0x02: dt = in_w(ofs); if (reg & 2) dt >>= 16; dt &= 0x0000ffff; goto fin; case 0x01: dt = in_w(ofs); if (reg & 1) dt >>= 8; if (reg & 2) dt >>= 16; dt &= 0x000000ff; goto fin; case 0x14: out_w(ofs, dat); goto fin; case 0x12: sh = (reg & 2) ? 16 : 0; dtmsk = 0x0000ffff << sh; break; case 0x11: sh = ((reg & 1) ? 8 : 0) + ((reg & 2) ? 16 :0); dtmsk = 0x000000ff << sh; break; } dt = in_w(ofs); out_w(ofs, ((dat << sh) & dtmsk) | (dt & ~dtmsk)); } fin: if (win) { /* Restore window previously changed to configuration space */ out_pdar_w(init, svinit); (void)in_pdar_w(init); } EI(imask); return dt;}/* Input from PCI configuration register (UB: 1byte) */EXPORT UB inPciConfB(W caddr, W reg){ return (UB)ioPciConf(caddr, reg, 0x01, 0);}/* Input from PCI configuration register (UH: 2byte) */EXPORT UH inPciConfH(W caddr, W reg){ return (UH)ioPciConf(caddr, reg, 0x02, 0);}/* Input from PCI configuration register (UW: 4byte) */EXPORT UW inPciConfW(W caddr, W reg){ return (UW)ioPciConf(caddr, reg, 0x04, 0);}/* Output to PCI configuration register (UB: 1byte) */EXPORT void outPciConfB(W caddr, W reg, UW dat){ ioPciConf(caddr, reg, 0x11, dat);}/* Output to PCI configuration register (UH: 2byte) */EXPORT void outPciConfH(W caddr, W reg, UW dat){ ioPciConf(caddr, reg, 0x12, dat);}/* Output to PCI configuration register (UW: 4byte) */EXPORT void outPciConfW(W caddr, W reg, UW dat){ ioPciConf(caddr, reg, 0x14, dat);}/* * Get base address/size for PCI configuration space * Return value PTTI I = 1:I/O address, 0:memory address * T = 0:32bit, 1:20bit, 2:64bit * P = 1:prefetch enable */EXPORT W getPciBaseAddr(W caddr, W reg, VP *addr, W *size){ UW imask; UW adr, tmp; W sz, kind; /* Write 0xffffffff, then determine size from how far it was possible to write from the top order */ DI(imask); adr = inPciConfW(caddr, reg); outPciConfW(caddr, reg, ~0); tmp = inPciConfW(caddr, reg); outPciConfW(caddr, reg, adr); EI(imask); if (adr & 1) { /* I/O space */ kind = 1; tmp &= ~0x03; adr &= ~0x03; } else { /* Memory space */ kind = adr & 0x0f; tmp &= ~0x0f; adr &= ~0x0f; } if (!tmp) sz = 0; else for (sz = 1; !(tmp & 1); tmp >>= 1) sz <<= 1; *addr = (VP)adr; *size = sz; return kind;}/* * PCI device search * * vendor < 0x10000 : vendor, devid device * == 0x1ffff : devid number device * == 0x1#### : devid number class == #### device * Function number >= 0 : PCI address * < 0 : not found */EXPORT INT searchPciDev(W vendor, W devid){ W i, caddr, class; class = vendor & 0xffff; if (!pciInfo) tm_extsvc(0x02, (INT)&pciInfo, 0, 0); for (i = 0; ; i++) { caddr = pciInfo[i].caddr; if (caddr == 0xffff) break; /* Terminal */ if (vendor >= 0x10000) { /* devid in order of appearance (0 - ) */ if (class == 0xffff || pciInfo[i].devclass == class) { if (devid-- == 0) return caddr; } } else { if (pciInfo[i].vendor == vendor && pciInfo[i].devid == devid) return caddr; } } return -1; /* Not found */}/* * PCI - CPU memory / I/O space address conversion * * pciMemToCpuAddr: Gets CPU memory address * corresponding to PCI memory address * pciIoToCpuAddr: Gets CPU I/O address corresponding to PCI I/O space * (for memory mapped I/O, the CPU memory address * corresponding to the PCI I/O space) * cpuAddrToPciMem: Gets PCI memory address corresponding * to CPU address */EXPORT UW pciMemToCpuAddr(UW pcimem){ UW cnvaddr; tm_extsvc(0x03, 0x00, pcimem, (INT)&cnvaddr); return cnvaddr;}EXPORT UW pciIoToCpuAddr(UW pciio){ UW cnvaddr; tm_extsvc(0x03, 0x01, pciio, (INT)&cnvaddr); return cnvaddr;}EXPORT UW cpuAddrToPciMem(UW cpuaddr){ UW cnvaddr; tm_extsvc(0x03, 0x02, cpuaddr, (INT)&cnvaddr); return cnvaddr;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -