]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/teg2/pciteg.c
d6cc8a2917bfdf32c36bb6b7123140aae5752d5e
[plan9front.git] / sys / src / 9 / teg2 / pciteg.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/pci.h"
8
9 typedef struct {
10         ulong   cap;
11         ulong   ctl;
12 } Capctl;
13
14 typedef struct {
15         Capctl  dev;
16         Capctl  link;
17         Capctl  slot;
18 } Devlinkslot;
19
20 /* capability list id 0x10 is pci-e */
21 typedef struct Pci Pci;
22 struct Pci {
23         /* pci-compatible config */
24         /* what io.h calls type 0 & type 1 pre-defined header */
25         ulong   id;
26         ulong   cs;
27         ulong   revclass;
28         ulong   misc;   /* cache line size, latency timer, header type, bist */
29         ulong   bar[2];         /* always 0 on tegra 2 */
30
31         /* types 1 & 2 pre-defined header */
32         ulong   bus;
33         ulong   ioaddrs;
34         ulong   memaddrs;
35         ulong   prefmem;
36         ulong   prefbasehi;
37         ulong   preflimhi;
38         /* type 2 pre-defined header only */
39         ulong   ioaddrhi;
40         ulong   cfgcapoff;      /* offset in cfg. space to cap. list (0x40) */
41         ulong   rom;
42         ulong   intr;           /* PciINT[LP] */
43         /* subsystem capability regs */
44         ulong   subsysid;
45         ulong   subsyscap;
46         /* */
47
48         Capctl  pwrmgmt;
49
50         /* msi */
51         ulong   msictlcap;
52         ulong   msimsgaddr[2];  /* little-endian */
53         ulong   msimsgdata;
54
55         /* pci-e cap. */
56         uchar   _pad0[0x80-0x60];
57         ulong   pciecap;
58         Devlinkslot port0;
59         ulong   rootctl;
60         ulong   rootsts;
61         Devlinkslot port1;
62
63         /* 0xbc */
64         
65 };
66
67 enum {
68         /* offsets from soc.pci */
69         Port0           = 0,
70         Port1           = 0x1000,
71         Pads            = 0x3000,
72         Afi             = 0x3800,
73         Aficfg          = Afi + 0xac,
74         Cfgspace        = 0x4000,
75         Ecfgspace       = 0x104000,
76
77         /* cs bits */
78         Iospace         = 1<<0,
79         Memspace        = 1<<1,
80         Busmaster       = 1<<2,
81
82         /* Aficfg bits */
83         Fpcion          = 1<<0,
84 };
85
86 struct Pcictlr {
87         union {
88                 uchar   _padpci[0x1000];
89                 Pci;
90         } ports[2];
91         uchar   _padpads[0x1000];
92         uchar   pads[0x800];
93         uchar   afi[0x800];
94         ulong   cfg[0x1000];
95         ulong   extcfg[0x1000];
96 };
97
98 static int pcicfgmode = -1;
99 static int pcimaxbno = 1;  /* was 7; only 2 pci buses; touching 3rd hangs */
100 static Pcidev* pciroot;
101
102 extern void rtl8169interrupt(Ureg*, void* arg);
103
104 /* not used yet */
105 static void
106 pciintr(Ureg *ureg, void *p)
107 {
108         rtl8169interrupt(ureg, p);              /* HACK */
109 }
110
111 static void
112 pcicfginit(void)
113 {
114         char *p;
115         Pci *pci = (Pci *)soc.pci;
116         Pcidev **list;
117         int bno, n;
118
119         /*
120          * TrimSlice # pci 0 1
121          * Scanning PCI devices on bus 0 1
122          * BusDevFun  VendorId   DeviceId   Device Class       Sub-Class
123          * _____________________________________________________________
124          * 00.00.00   0x10de     0x0bf0     Bridge device           0x04
125          * 01.00.00   0x10ec     0x8168     Network controller      0x00
126          *
127          * thus pci bus 0 has a bridge with, perhaps, an ide/sata ctlr behind,
128          * and pci bus 1 has the realtek 8169 on it:
129          *
130          * TrimSlice # pci 1 long
131          * Scanning PCI devices on bus 1
132          *
133          * Found PCI device 01.00.00:
134          *   vendor ID =                   0x10ec
135          *   device ID =                   0x8168
136          *   command register =            0x0007
137          *   status register =             0x0010
138          *   revision ID =                 0x03
139          *   class code =                  0x02 (Network controller)
140          *   sub class code =              0x00
141          *   programming interface =       0x00
142          *   cache line =                  0x08
143          *   base address 0 =              0x80400001           config
144          *   base address 1 =              0x00000000           (ext. config)
145          *   base address 2 =              0xa000000c           "downstream"
146          *   base address 3 =              0x00000000           (prefetchable)
147          *   base address 4 =              0xa000400c           not "
148          *   base address 5 =              0x00000000           (unused)
149          */
150         n = pci->id >> 16;
151         if (((pci->id & MASK(16)) != Vnvidia || (n != 0xbf0 && n != 0xbf1)) &&
152              (pci->id & MASK(16)) != Vrealtek) {
153                 print("no pci controller at %#p\n", pci);
154                 return;
155         }
156         if (0)
157                 iprint("pci: %#p: nvidia, rev %#ux class %#6.6lux misc %#8.8lux\n",
158                         pci, (uchar)pci->revclass, pci->revclass >> 8,
159                         pci->misc);
160
161         pci->cs &= Iospace;
162         pci->cs |= Memspace | Busmaster;
163         coherence();
164
165         pcicfgmode = 1;
166         pcimaxdno = 15;                 /* for trimslice */
167
168         fmtinstall('T', tbdffmt);
169
170         if(p = getconf("*pcimaxbno")){
171                 n = strtoul(p, 0, 0);
172                 if(n < pcimaxbno)
173                         pcimaxbno = n;
174         }
175         if(p = getconf("*pcimaxdno")){
176                 n = strtoul(p, 0, 0);
177                 if(n < pcimaxdno)
178                         pcimaxdno = n;
179         }
180
181         list = &pciroot;
182         /* was bno = 0; trimslice needs to start at 1 */
183         for(bno = 1; bno <= pcimaxbno; bno++) {
184                 bno = pciscan(bno, list);
185                 while(*list)
186                         list = &(*list)->link;
187         }
188
189         if(getconf("*pcihinv"))
190                 pcihinv(pciroot);
191 }
192
193 enum {
194         Afiintrcode     = 0xb8,
195 };
196
197 void
198 pcieintrdone(void)                              /* dismiss pci-e intr */
199 {
200         ulong *afi;
201
202         afi = (ulong *)(soc.pci + Afi);
203         afi[Afiintrcode/sizeof *afi] = 0;       /* magic */
204         coherence();
205 }
206
207 /*
208  * whole config space for tbdf should be at (return address - rno).
209  */
210 static void *
211 tegracfgaddr(int tbdf, int rno)
212 {
213         uintptr addr;
214
215         addr = soc.pci + (rno < 256? Cfgspace: Ecfgspace) + BUSBDF(tbdf) + rno;
216 //      if (BUSBNO(tbdf) == 1)
217 //              addr += Port1;
218         return (void *)addr;
219 }
220
221 int
222 pcicfgrw8(int tbdf, int rno, int data, int read)
223 {
224         void *addr;
225
226         addr = tegracfgaddr(tbdf, rno);
227         if(read)
228                 data = *(uchar *)addr;
229         else
230                 *(uchar *)addr = data;
231         return data;
232 }
233
234 int
235 pcicfgrw16(int tbdf, int rno, int data, int read)
236 {
237         void *addr;
238
239         addr = tegracfgaddr(tbdf, rno);
240         if(read)
241                 data = *(ushort *)addr;
242         else
243                 *(ushort *)addr = data;
244         return data;
245 }
246
247 int
248 pcicfgrw32(int tbdf, int rno, int data, int read)
249 {
250         vlong v;
251         void *addr;
252
253         addr = tegracfgaddr(tbdf, rno);
254         v = probeaddr((uintptr)addr);
255         if (v < 0)
256                 return -1;
257         if(read)
258                 data = *(ulong *)addr;
259         else
260                 *(ulong *)addr = data;
261         return data;
262 }
263
264 void
265 pciteglink(void)
266 {
267         pcicfginit();
268 }