/[pearpc]/src/io/pci/pci.cc
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /src/io/pci/pci.cc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1 - (hide annotations)
Wed Sep 5 17:11:21 2007 UTC (16 years, 8 months ago) by dpavlin
File size: 14770 byte(s)
import upstream CVS
1 dpavlin 1 /*
2     * PearPC
3     * pci.cc
4     *
5     * Copyright (C) 2003 Sebastian Biallas (sb@biallas.net)
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License version 2 as
9     * published by the Free Software Foundation.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19     */
20    
21     #include <cstdlib>
22     #include <cstring>
23    
24     #include "tools/data.h"
25     #include "system/arch/sysendian.h"
26     #include "cpu/cpu.h"
27     #include "cpu/debug.h"
28     #include "cpu/mem.h"
29     #include "debug/tracers.h"
30     #include "pci.h"
31    
32     #define PCI_ADDRESS_ECD(v) ((v) & 0x80000000)
33     #define PCI_ADDRESS_BUS(v) (((v)>>16) & 0xff)
34     #define PCI_ADDRESS_UNIT(v) (((v)>>11) & 0x1f)
35     #define PCI_ADDRESS_FUNCT(v) (((v)>>8) & 7)
36     #define PCI_ADDRESS_REG(v) (((v)) & 0xfc)
37     #define PCI_ADDRESS_TYPE(v) ((v) & 3)
38    
39     uint32 gPCI_Address;
40     uint32 gPCI_Data;
41     static uint32 gPCI_Data_LE;
42     Container *gPCI_Devices;
43    
44     class PCI_Bridge: public PCI_Device {
45     public:
46     PCI_Bridge(const char *aName, uint8 aBus, uint8 aUnit)
47     :PCI_Device(aName, aBus, aUnit)
48     {
49     mIORegsCount = 2;
50     }
51    
52     };
53    
54     class PCI_BridgeHost: public PCI_Bridge {
55     public:
56     PCI_BridgeHost();
57     };
58    
59     class PCI_BridgeP2P: public PCI_Bridge {
60     public:
61     PCI_BridgeP2P();
62     };
63    
64     PCI_Device::PCI_Device(const char *aName, uint8 aBus, uint8 aUnit)
65     :Object()
66     {
67     mName = strdup(aName);
68     mUnit = aUnit;
69     mBus = aBus;
70     mIORegsCount = 6;
71     memset(&mConfig, 0, sizeof mConfig);
72     memset(&mAddress, 0, sizeof mAddress);
73     memset(&mPort, 0, sizeof mPort);
74     memset(&mIORegType, 0, sizeof mIORegType);
75     memset(&mIORegSize, 0, sizeof mIORegSize);
76     }
77    
78     PCI_Device::~PCI_Device()
79     {
80     free(mName);
81     }
82    
83     int PCI_Device::compareTo(const Object *obj) const
84     {
85     int busdelta = (int)mBus - (int)((PCI_Device*)obj)->mBus;
86     if (!busdelta) {
87     return (int)mUnit - (int)((PCI_Device*)obj)->mUnit;
88     }
89     return busdelta;
90     }
91    
92     void PCI_Device::assignMemAddress(uint r, uint32 aAddress)
93     {
94     IO_PCI_TRACE("assign-address[mem]: %s: %d: %08x\n", mName, r, aAddress);
95     mAddress[r] = aAddress;
96     mConfig[0x4] |= 0x2; // Enable response in memory space
97     mConfig[0x10+4*r] = aAddress | mIORegType[r];
98     mConfig[0x11+4*r] = aAddress>>8;
99     mConfig[0x12+4*r] = aAddress>>16;
100     mConfig[0x13+4*r] = aAddress>>24;
101     }
102    
103     void PCI_Device::assignIOPort(uint r, uint32 aPort)
104     {
105     IO_PCI_TRACE("assign-address[io]: %s: %d: %08x\n", mName, r, aPort);
106     mPort[r] = aPort;
107     mConfig[0x4] |= 0x1; // Enable response in io space
108     mConfig[0x10+4*r] = aPort | 1; // Mark as io address
109     mConfig[0x11+4*r] = aPort>>8;
110     mConfig[0x12+4*r] = aPort>>16;
111     mConfig[0x13+4*r] = aPort>>24;
112     }
113    
114     bool PCI_Device::readMem(uint32 aAddress, uint32 &data, uint size)
115     {
116     for (uint i=0; i < mIORegsCount; i++) {
117     if ((mIORegType[i] & 1) == PCI_ADDRESS_SPACE_MEM
118     && aAddress >= mAddress[i] && aAddress < (mAddress[i] + mIORegSize[i])) {
119     if (!readDeviceMem(i, aAddress-mAddress[i], data, size)) {
120     IO_PCI_ERR("%s: reg: %d: %08x read unimpl.\n", mName, i, aAddress-mAddress[i]);
121     }
122     return true;
123     }
124     }
125     return false;
126     }
127    
128     bool PCI_Device::readIO(uint32 aPort, uint32 &data, uint size)
129     {
130     for (uint i=0; i < mIORegsCount; i++) {
131     if (mIORegType[i] == PCI_ADDRESS_SPACE_IO
132     && aPort >= mPort[i] && aPort < (mPort[i] + mIORegSize[i])) {
133     if (!readDeviceIO(i, aPort-mPort[i], data, size)) {
134     IO_PCI_ERR("%s: reg: %d: %08x read(%d) unimpl.\n", mName, i, aPort-mPort[i], size);
135     }
136     return true;
137     }
138     }
139     return false;
140     }
141    
142     bool PCI_Device::writeMem(uint32 aAddress, uint32 data, uint size)
143     {
144     for (uint i=0; i < mIORegsCount; i++) {
145     if ((mIORegType[i] & 1) == PCI_ADDRESS_SPACE_MEM
146     && aAddress >= mAddress[i] && aAddress < (mAddress[i] + mIORegSize[i])) {
147     if (!writeDeviceMem(i, aAddress-mAddress[i], data, size)) {
148     IO_PCI_ERR("%s: reg: %d: %08x write unimpl.\n", mName, i, aAddress-mAddress[i]);
149     }
150     return true;
151     }
152     }
153     return false;
154     }
155    
156     bool PCI_Device::writeIO(uint32 aPort, uint32 data, uint size)
157     {
158     for (uint i=0; i < mIORegsCount; i++) {
159     if (mIORegType[i] == PCI_ADDRESS_SPACE_IO
160     && aPort >= mPort[i] && aPort < (mPort[i] + mIORegSize[i])) {
161     if (!writeDeviceIO(i, aPort-mPort[i], data, size)) {
162     IO_PCI_ERR("%s: reg: %d: %08x write(%d) unimpl.\n", mName, i, aPort-mPort[i], size);
163     }
164     return true;
165     }
166     }
167     return false;
168     }
169    
170     bool PCI_Device::readDeviceMem(uint r, uint32 address, uint32 &data, uint size)
171     {
172     return false;
173     }
174    
175     bool PCI_Device::readDeviceIO(uint r, uint32 io, uint32 &data, uint size)
176     {
177     return false;
178     }
179    
180     bool PCI_Device::writeDeviceMem(uint r, uint32 address, uint32 data, uint size)
181     {
182     return false;
183     }
184    
185     bool PCI_Device::writeDeviceIO(uint r, uint32 io, uint32 data, uint size)
186     {
187     return false;
188     }
189    
190     void PCI_Device::readConfig(uint reg)
191     {
192     gPCI_Data = ppc_word_from_LE(*(uint32*)&(mConfig[reg]));
193     }
194    
195     void PCI_Device::writeConfig(uint reg, int offset, int size)
196     {
197     if (reg >= 0x10 && reg < (4*mIORegsCount+0x10)) {
198     uint rreg = (reg-0x10) >> 2;
199     if (mIORegSize[rreg]) {
200     if (gPCI_Data != 0xffffffff && gPCI_Data != 0) {
201     if (mIORegType[rreg]==PCI_ADDRESS_SPACE_MEM) {
202     assignMemAddress(rreg, gPCI_Data & ~0xf);
203     } else {
204     assignIOPort(rreg, gPCI_Data & ~0x3);
205     }
206     }
207     if ((mIORegType[rreg] & 1) == PCI_ADDRESS_SPACE_MEM) {
208     uint32 x = 8;
209     for (int i=2; i<31; i++) {
210     gPCI_Data &= ~x;
211     x <<= 1;
212     if (x >= mIORegSize[rreg]) break;
213     }
214     gPCI_Data &= ~0xf;
215     } else {
216     uint32 x = 2;
217     for (int i=2; i<31; i++) {
218     gPCI_Data &= ~x;
219     x <<= 1;
220     if (x >= mIORegSize[rreg]) break;
221     }
222     gPCI_Data &= ~0x3;
223     }
224     gPCI_Data |= mIORegType[rreg];
225     }
226     }
227     *(uint32*)&(mConfig[reg]) = ppc_word_to_LE(gPCI_Data);
228     }
229    
230     void PCI_Device::setCommand(uint16 command)
231     {
232     }
233    
234     void PCI_Device::setStatus(uint16 status)
235     {
236     }
237    
238     PCI_BridgeP2P::PCI_BridgeP2P()
239     :PCI_Bridge("pci-bridge-p2p", 0x00, 0x0d)
240     {
241     mConfig[0x00] = 0x11; // vendor ID
242     mConfig[0x01] = 0x10;
243     mConfig[0x02] = 0x26; // unit ID
244     mConfig[0x03] = 0x00;
245    
246     mConfig[0x08] = 0x02; // revision
247     mConfig[0x09] = 0x00; // programming interface code
248     mConfig[0x0a] = 0x04; // pci2pci
249     mConfig[0x0b] = 0x06; // bridge
250    
251     mConfig[0x0e] = 0x01; // header-type
252    
253     mConfig[0x18] = 0x0; // primary bus number
254     mConfig[0x19] = 0x1; // secondary bus number
255     mConfig[0x1a] = 0x1; // highest bus number behind bridge
256     mConfig[0x1c] = 0x10; // i/o base behind bridge
257     mConfig[0x1d] = 0x20; // i/o limit
258    
259     mConfig[0x20] = 0x80; // memory base
260     mConfig[0x21] = 0x80; // memory base
261     mConfig[0x22] = 0x90; // memory limit
262     mConfig[0x23] = 0x80; // memory limit
263    
264     mConfig[0x24] = 0x00; // prefetch memory base
265     mConfig[0x25] = 0x84; // prefetch memory base
266     mConfig[0x26] = 0x00; // prefetch memory limit
267     mConfig[0x27] = 0x85; // prefetch memory limit
268    
269     mConfig[0x32] = 0x00; // upper io limit
270     }
271    
272     PCI_BridgeHost::PCI_BridgeHost()
273     :PCI_Bridge("pci-bridge-host", 0x00, 0x0e)
274     {
275     mConfig[0x00] = 0x11; // vendor ID
276     mConfig[0x01] = 0x10;
277     mConfig[0x02] = 0x26; // unit ID
278     mConfig[0x03] = 0x00;
279    
280     mConfig[0x08] = 0x00; // revision
281     mConfig[0x09] = 0x01;
282     mConfig[0x0a] = 0x04; // host
283     mConfig[0x0b] = 0x06; // bridge
284    
285     mConfig[0x0e] = 0x01; // header-type
286    
287     mConfig[0x18] = 0x0; // primary bus number
288     mConfig[0x19] = 0x1; // secondary bus number
289     mConfig[0x1a] = 0x0; // highest bus number behind bridge
290     mConfig[0x1c] = 0x0; // i/o behind bridge
291    
292     mConfig[0x20] = 0x0; // memory base
293     mConfig[0x21] = 0x0; // memory base
294     mConfig[0x22] = 0x1; // memory limit
295     mConfig[0x23] = 0x0; // memory limit
296    
297     mConfig[0x24] = 0x0; // prefetch memory base
298     mConfig[0x25] = 0x0; // prefetch memory base
299     mConfig[0x26] = 0x0; // prefetch memory limit
300     mConfig[0x27] = 0x0; // prefetch memory limit
301     }
302    
303     /**************************************************************************************
304     *
305     */
306    
307     static void pci_config_read_write(bool write, int offset, int size)
308     {
309     IO_PCI_TRACE("ecd: %d bus: 0x%02x unit: 0x%02x funct: 0x%02x reg: 0x%02x type: %d\n",
310     PCI_ADDRESS_ECD(gPCI_Address)?1:0, PCI_ADDRESS_BUS(gPCI_Address),
311     PCI_ADDRESS_UNIT(gPCI_Address), PCI_ADDRESS_FUNCT(gPCI_Address),
312     PCI_ADDRESS_REG(gPCI_Address),PCI_ADDRESS_TYPE(gPCI_Address));
313    
314     if (PCI_ADDRESS_FUNCT(gPCI_Address)) {
315     IO_PCI_ERR("PCI: func != 0\n");
316     }
317     if (PCI_ADDRESS_TYPE(gPCI_Address)) {
318     IO_PCI_ERR("PCI: type != 0\n");
319     }
320     if (PCI_ADDRESS_ECD(gPCI_Address)) {
321     PCI_Device empty("", PCI_ADDRESS_BUS(gPCI_Address), PCI_ADDRESS_UNIT(gPCI_Address));
322     PCI_Device *p = (PCI_Device*)gPCI_Devices->get(gPCI_Devices->find(&empty));
323     if (!p) {
324     if (!write) gPCI_Data = 0;
325     return;
326     }
327     if (write) {
328     gPCI_Data = ppc_word_from_LE(gPCI_Data_LE);
329     p->writeConfig(PCI_ADDRESS_REG(gPCI_Address), offset, size);
330     } else {
331     p->readConfig(PCI_ADDRESS_REG(gPCI_Address));
332     gPCI_Data_LE = ppc_word_to_LE(gPCI_Data);
333     }
334     } else {
335     IO_PCI_WARN("PCI: ecd != 1\n");
336     }
337     }
338    
339     void pci_write(uint32 addr, uint32 data, int size)
340     {
341     if (addr != IO_PCI_PA_START) IO_PCI_TRACE("write (%d) @%08x: %08x (from %08x, %08x)\n", size, addr, data, gCPU.pc, gCPU.lr);
342     addr -= IO_PCI_PA_START;
343     switch (addr) {
344     case 0:
345     case 0xcf8:
346     if (size != 4) {
347     IO_PCI_ERR("pci bla\n");
348     }
349     gPCI_Address = data;
350     pci_config_read_write(false, 0, 4);
351     return;
352     case 0x200000:
353     case 0x200cfc:
354     if (size == 1) {
355     void *p = &gPCI_Data_LE;
356     *(uint8 *)p = data;
357     pci_config_read_write(true, 0, 1);
358     return;
359     }
360     if (size == 2) {
361     void *p = &gPCI_Data_LE;
362     *(uint16 *)p = ppc_half_to_LE(data);
363     pci_config_read_write(true, 0, 2);
364     return;
365     }
366     if (size != 4) {
367     IO_PCI_ERR("pci bla\n");
368     }
369     gPCI_Data_LE = ppc_word_to_LE(data);
370     pci_config_read_write(true, 0, 4);
371     return;
372     case 0x200001:
373     case 0x200cfd: {
374     if (size != 1) {
375     IO_PCI_ERR("pci bla\n");
376     }
377     char *p = (char*)&gPCI_Data_LE;
378     *(uint8 *)(p+1) = data;
379     pci_config_read_write(true, 1, 1);
380     return;
381     }
382     case 0x200002:
383     case 0x200cfe: {
384     if (size > 2) {
385     IO_PCI_ERR("pci bla\n");
386     }
387     if (size == 1) {
388     char *p = (char *)&gPCI_Data_LE;
389     *(uint8 *)(p+2) = data;
390     pci_config_read_write(true, 2, 1);
391     return;
392     }
393     char *p = (char *)&gPCI_Data_LE;
394     *(uint16 *)(p+2) = ppc_half_to_LE(data);
395     pci_config_read_write(true, 2, 2);
396     return;
397     }
398     case 0x200003:
399     case 0x200cff: {
400     if (size != 1) {
401     IO_PCI_ERR("pci bla\n");
402     }
403     char *p = (char *)&gPCI_Data_LE;
404     *(uint8 *)(p+3) = data;
405     pci_config_read_write(true, 3, 1);
406     return;
407     }
408     }
409     SINGLESTEP("unknown service\n");
410     }
411    
412     void pci_read(uint32 addr, uint32 &data, int size)
413     {
414     // SINGLESTEP("usdf\n");
415     if (addr != IO_PCI_PA_START) IO_PCI_TRACE("read (%d) @%08x (from %08x, lr: %08x) -> \n", size, addr, gCPU.pc, gCPU.lr);
416     addr -= IO_PCI_PA_START;
417     switch (addr) {
418     case 0:
419     case 0xcf8:
420     data = gPCI_Address;
421     return;
422     case 0x200000:
423     case 0x200cfc:
424     if (size == 1) {
425     void *p = &gPCI_Data_LE;
426     data = *(uint8 *)p;
427     IO_PCI_TRACE("%02x\n", data);
428     return;
429     }
430     if (size == 2) {
431     void *p = &gPCI_Data_LE;
432     data = ppc_half_from_LE(*(uint16 *)p);
433     IO_PCI_TRACE("%04x\n", data);
434     return;
435     }
436     if (size != 4) {
437     IO_PCI_ERR("pci bla\n");
438     }
439     data = ppc_word_from_LE(gPCI_Data_LE);
440     IO_PCI_TRACE("%08x\n", data);
441     return;
442     case 0x200001:
443     case 0x200cfd: {
444     if (size != 1) {
445     IO_PCI_ERR("pci bla\n");
446     }
447     char *p = (char*)&gPCI_Data_LE;
448     data = *(uint8 *)(p+1);
449     IO_PCI_TRACE("%02x\n", data);
450     return;
451     }
452     case 0x200002:
453     case 0x200cfe: {
454     if (size > 2) {
455     IO_PCI_ERR("pci bla\n");
456     }
457     if (size==1) {
458     char *p = (char*)&gPCI_Data_LE;
459     data = *(uint8 *)(p+2);
460     IO_PCI_TRACE("%02x\n", data);
461     return;
462     }
463     char *p = (char*)&gPCI_Data_LE;
464     data = ppc_half_from_LE(*(uint16 *)(p+2));
465     IO_PCI_TRACE("%04x\n", data);
466     return;
467     }
468     case 0x200003:
469     case 0x200cff:
470     if (size != 1) {
471     IO_PCI_ERR("pci bla\n");
472     }
473     char *p = (char*)&gPCI_Data_LE;
474     data = *(uint8 *)(p+3);
475     IO_PCI_TRACE("%02x\n", data);
476     return;
477     }
478     data = 0;
479     SINGLESTEP("%08x unknown service\n", addr);
480     }
481    
482     bool isa_read(uint32 addr, uint32 &data, int size)
483     {
484     // Translate address into port
485     addr -= IO_ISA_PA_START;
486     ObjHandle oh = gPCI_Devices->findFirst();
487     while (oh != InvObjHandle) {
488     PCI_Device *pd = (PCI_Device*)gPCI_Devices->get(oh);
489     if (pd->readIO(addr, data, size)) {
490     return true;
491     }
492     oh = gPCI_Devices->findNext(oh);
493     }
494     data = 0;
495     // gSinglestep = true;
496     IO_PCI_WARN("port %08x not registered! (for read)\n", addr);
497     return false;
498     }
499    
500     bool isa_write(uint32 addr, uint32 data, int size)
501     {
502     // Translate address into port
503     addr -= IO_ISA_PA_START;
504     ObjHandle oh = gPCI_Devices->findFirst();
505     while (oh != InvObjHandle) {
506     PCI_Device *pd = (PCI_Device*)gPCI_Devices->get(oh);
507     if (pd->writeIO(addr, data, size)) {
508     return true;
509     }
510     oh = gPCI_Devices->findNext(oh);
511     }
512     // gSinglestep = true;
513     IO_PCI_WARN("port %08x not registered! (for write)\n", addr);
514     return false;
515     }
516    
517     bool pci_write_device(uint32 addr, uint32 data, int size)
518     {
519     IO_PCI_TRACE("write DEVICE (%d) @%08x %08x (from %08x, lr: %08x)\n", size, addr, data, gCPU.pc, gCPU.lr);
520     ObjHandle oh = gPCI_Devices->findFirst();
521     while (oh != InvObjHandle) {
522     PCI_Device *pd = (PCI_Device*)gPCI_Devices->get(oh);
523     if (pd->writeMem(addr, data, size)) {
524     return true;
525     }
526     oh = gPCI_Devices->findNext(oh);
527     }
528     return false;
529     }
530    
531     bool pci_read_device(uint32 addr, uint32 &data, int size)
532     {
533     IO_PCI_TRACE("read DEVICE (%d) @%08x (from %08x, lr: %08x)\n", size, addr, gCPU.pc, gCPU.lr);
534     ObjHandle oh = gPCI_Devices->findFirst();
535     while (oh != InvObjHandle) {
536     PCI_Device *pd = (PCI_Device*)gPCI_Devices->get(oh);
537     if (pd->readMem(addr, data, size)) {
538     IO_PCI_TRACE("->%08x\n", data);
539     return true;
540     }
541     oh = gPCI_Devices->findNext(oh);
542     }
543     data = 0;
544     return false;
545     }
546    
547     // PCI devices
548     #include "io/graphic/gcard.h"
549     #include "io/ide/ide.h"
550     #include "io/macio/macio.h"
551     #include "io/3c90x/3c90x.h"
552     #include "io/rtl8139/rtl8139.h"
553     #include "io/usb/usb.h"
554     #include "io/serial/serial.h"
555    
556     void pci_init()
557     {
558     gPCI_Devices = new AVLTree(true);
559     gPCI_Devices->insert(new PCI_BridgeP2P());
560     // gPCI_Devices->insert(new PCI_BridgeHost());
561    
562     gcard_init();
563     ide_init();
564     macio_init();
565     _3c90x_init();
566     rtl8139_init();
567     usb_init();
568     serial_init();
569     }
570    
571     void pci_done()
572     {
573     serial_done();
574     usb_done();
575     rtl8139_done();
576     _3c90x_done();
577     macio_done();
578     ide_done();
579     gcard_done();
580    
581     delete gPCI_Devices;
582     }
583    
584     void pci_init_config()
585     {
586     gcard_init_config();
587     ide_init_config();
588     macio_init_config();
589     _3c90x_init_config();
590     rtl8139_init_config();
591     usb_init_config();
592     serial_init_config();
593     }

  ViewVC Help
Powered by ViewVC 1.1.26