tlp.c revision 1.2 1 /* $NetBSD: tlp.c,v 1.2 2007/10/30 16:38:54 tsutsui Exp $ */
2
3 /*-
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/param.h>
40 #include <sys/socket.h>
41
42 #include <netinet/in.h>
43 #include <netinet/in_systm.h>
44
45 #include <lib/libsa/stand.h>
46 #include <lib/libsa/net.h>
47
48 #include <mips/cpuregs.h>
49
50 #include "boot.h"
51
52 /*
53 * - little endian access for CSR register.
54 * - assume KSEG0 on vtophys() translation.
55 * - PIPT writeback cache aware.
56 */
57 #define CSR_WRITE(l, r, v) \
58 do { \
59 *(volatile uint32_t *)((l)->csr + (r)) = (v); \
60 } while (0)
61 #define CSR_READ(l, r) (*(volatile uint32_t *)((l)->csr + (r)))
62 #define VTOPHYS(va) MIPS_KSEG0_TO_PHYS(va)
63 #define wb(adr, siz) pdcache_wb((uint32_t)(adr), (u_int)(siz))
64 #define wbinv(adr, siz) pdcache_wbinv((uint32_t)(adr), (u_int)(siz))
65 #define inv(adr, siz) pdcache_inv((uint32_t)(adr), (u_int)(siz))
66 #define DELAY(n) delay(n)
67 #define ALLOC(T, A) (T *)((uint32_t)alloc(sizeof(T) + (A)) & ~((A) - 1))
68
69 #define T0_OWN (1U<<31) /* desc is ready to tx */
70 #define T0_ES (1U<<15) /* Tx error summary */
71 #define T1_LS (1U<<30) /* last segment */
72 #define T1_FS (1U<<29) /* first segment */
73 #define T1_SET (1U<<27) /* "setup packet" */
74 #define T1_TER (1U<<25) /* end of ring mark */
75 #define T1_TBS_MASK 0x7ff /* segment size 10:0 */
76 #define R0_OWN (1U<<31) /* desc is empty */
77 #define R0_FS (1U<<30) /* first desc of frame */
78 #define R0_LS (1U<<8) /* last desc of frame */
79 #define R0_ES (1U<<15) /* Rx error summary */
80 #define R1_RER (1U<<25) /* end of ring mark */
81 #define R0_FL_MASK 0x3fff0000 /* frame length 29:16 */
82 #define R1_RBS_MASK 0x7ff /* segment size 10:0 */
83
84 struct desc {
85 volatile uint32_t xd0, xd1, xd2, xd3;
86 };
87
88 #define TLP_BMR 0x000 /* 0: bus mode */
89 #define BMR_RST (1U<< 0) /* software reset */
90 #define TLP_TPD 0x008 /* 1: instruct Tx to start */
91 #define TPD_POLL (1U<< 0) /* transmit poll demand */
92 #define TLP_RPD 0x010 /* 2: instruct Rx to start */
93 #define RPD_POLL (1U<< 0) /* receive poll demand */
94 #define TLP_RRBA 0x018 /* 3: Rx descriptor base */
95 #define TLP_TRBA 0x020 /* 4: Tx descriptor base */
96 #define TLP_STS 0x028 /* 5: status */
97 #define STS_TS 0x00700000 /* Tx status */
98 #define STS_RS 0x000e0000 /* Rx status */
99 #define TLP_OMR 0x030 /* 6: operation mode */
100 #define OMR_SDP (1U<<25) /* always ON */
101 #define OMR_PS (1U<<18) /* port select */
102 #define OMR_PM (1U<< 6) /* promicuous */
103 #define OMR_TEN (1U<<13) /* instruct start/stop Tx */
104 #define OMR_REN (1U<< 1) /* instruct start/stop Rx */
105 #define OMR_FD (1U<< 9) /* FDX */
106 #define TLP_IEN 0x38 /* 7: interrupt enable mask */
107 #define TLP_APROM 0x048 /* 9: SEEPROM and MII management */
108 #define SROM_RD (1U <<14) /* read operation */
109 #define SROM_WR (1U <<13) /* write openration */
110 #define SROM_SR (1U <<11) /* SEEPROM select */
111 #define TLP_CSR12 0x60 /* SIA status */
112
113 #define TLP_CSR15 0x78 /* SIA general register */
114 #define SIAGEN_MD0 (1U<<16)
115 #define SIAGEN_CWE (1U<<28)
116
117 #define FRAMESIZE 1536
118 #define BUFSIZE 2048
119 #define NRXBUF 2
120 #define NEXT_RXBUF(x) (((x) + 1) & (NRXBUF - 1))
121
122 struct local {
123 struct desc TxD;
124 #if CACHELINESIZE > 16
125 uint8_t pad[CACHELINESIZE - sizeof(struct desc)];
126 #endif
127 struct desc RxD[NRXBUF];
128 uint8_t txstore[BUFSIZE];
129 uint8_t rxstore[NRXBUF][BUFSIZE];
130 uint32_t csr, omr;
131 u_int rx;
132 u_int sromsft;
133 u_int phy;
134 uint32_t bmsr, anlpar;
135 };
136
137 #define COBALT_TLP0_BASE 0x10100000
138 #define SROM_MAC_OFFSET 0
139
140 static void size_srom(struct local *);
141 static u_int read_srom(struct local *, int);
142 #if 0
143 static u_int tlp_mii_read(struct local *, int, int);
144 static void tlp_mii_write(struct local *, int, int, int);
145 static void mii_initphy(struct local *);
146 #endif
147
148 void *
149 tlp_init(void *cookie)
150 {
151 uint32_t val;
152 struct local *l;
153 struct desc *TxD, *RxD;
154 uint8_t *en;
155 int i;
156
157 l = ALLOC(struct local, CACHELINESIZE);
158 memset(l, 0, sizeof(struct local));
159
160 DPRINTF(("tlp: l = %p, TxD = %p, RxD[0] = %p, RxD[1] = %p\n",
161 l, &l->TxD, &l->RxD[0], &l->RxD[1]));
162 DPRINTF(("tlp: txstore = %p, rxstore[0] = %p, rxstore[1] = %p\n",
163 l->txstore, l->rxstore[0], l->rxstore[1]));
164
165 #if 0
166 /* XXX assume tlp0 at pci0 dev 7 function 0 */
167 tag = (0 << 16) | ( 7 << 11) | (0 << 8);
168 /* memory map is not initialized by the firmware on cobalt */
169 l->csr = MIPS_PHYS_TO_KSEG1(pcicfgread(tag, 0x10) & 0xfffffffc);
170 DPRINTF(("%s: CSR = 0x%x\n", __func__, l->csr));
171 #else
172 l->csr = MIPS_PHYS_TO_KSEG1(COBALT_TLP0_BASE);
173 #endif
174
175 val = CSR_READ(l, TLP_BMR);
176 CSR_WRITE(l, TLP_BMR, val | BMR_RST);
177 DELAY(1000);
178 CSR_WRITE(l, TLP_BMR, val);
179 DELAY(1000);
180 (void)CSR_READ(l, TLP_BMR);
181
182 l->omr = OMR_PS | OMR_SDP;
183 CSR_WRITE(l, TLP_OMR, l->omr);
184 CSR_WRITE(l, TLP_STS, ~0);
185 CSR_WRITE(l, TLP_IEN, 0);
186
187 #if 0
188 mii_initphy(l);
189 #endif
190 size_srom(l);
191
192 en = cookie;
193 /* MAC address is stored at offset 0 in SROM on cobalt */
194 val = read_srom(l, SROM_MAC_OFFSET / 2 + 0);
195 en[0] = val;
196 en[1] = val >> 8;
197 val = read_srom(l, SROM_MAC_OFFSET / 2 + 1);
198 en[2] = val;
199 en[3] = val >> 8;
200 val = read_srom(l, SROM_MAC_OFFSET / 2 + 2);
201 en[4] = val;
202 en[5] = val >> 8;
203
204 DPRINTF(("tlp: MAC address %x:%x:%x:%x:%x:%x\n",
205 en[0], en[1], en[2], en[3], en[4], en[5]));
206
207 RxD = &l->RxD[0];
208 for (i = 0; i < NRXBUF; i++) {
209 RxD[i].xd3 = htole32(VTOPHYS(&RxD[NEXT_RXBUF(i)]));
210 RxD[i].xd2 = htole32(VTOPHYS(l->rxstore[i]));
211 RxD[i].xd1 = htole32(FRAMESIZE);
212 RxD[i].xd0 = htole32(R0_OWN|R0_FS|R0_LS);
213 }
214 RxD[NRXBUF - 1].xd1 |= htole32(R1_RER);
215 CSR_WRITE(l, TLP_RRBA, VTOPHYS(RxD));
216
217 /* "setup packet" to have own station address */
218 TxD = &l->TxD;
219 TxD->xd3 = htole32(VTOPHYS(TxD));
220 TxD->xd2 = htole32(VTOPHYS(l->txstore));
221 TxD->xd1 = htole32(T1_SET | T1_TER);
222 TxD->xd0 = htole32(0);
223 CSR_WRITE(l, TLP_TRBA, VTOPHYS(TxD));
224
225 memset(l->txstore, 0, FRAMESIZE);
226
227 /* make sure the entire descriptors transfered to memory */
228 wbinv(l, sizeof(struct local));
229
230 l->rx = 0;
231 l->omr |= OMR_FD | OMR_TEN | OMR_REN;
232
233 #if 1
234 /* reset PHY (cobalt quirk from if_tlp_pci.c) */
235 CSR_WRITE(l, TLP_CSR15, SIAGEN_CWE | SIAGEN_MD0);
236 DELAY(10);
237 CSR_WRITE(l, TLP_CSR15, SIAGEN_CWE);
238 DELAY(10);
239 #endif
240
241 /* start Tx/Rx */
242 CSR_WRITE(l, TLP_OMR, l->omr);
243 #if 0
244 CSR_WRITE(l, TLP_TPD, TPD_POLL);
245 #endif
246 CSR_WRITE(l, TLP_RPD, RPD_POLL);
247
248 return l;
249 }
250
251 int
252 tlp_send(void *dev, char *buf, u_int len)
253 {
254 struct local *l = dev;
255 struct desc *TxD;
256 u_int loop;
257
258 #if 1
259 wb(buf, len);
260 TxD = &l->TxD;
261 TxD->xd3 = htole32(VTOPHYS(TxD));
262 TxD->xd2 = htole32(VTOPHYS(buf));
263 TxD->xd1 = htole32(T1_FS | T1_LS | T1_TER | (len & T1_TBS_MASK));
264 #else
265 memcpy(l->txstore, buf, len);
266 wb(l->txstore, len);
267 TxD = &l->TxD;
268 TxD->xd3 = htole32(VTOPHYS(TxD));
269 TxD->xd2 = htole32(VTOPHYS(l->txstore));
270 TxD->xd1 = htole32(T1_FS | T1_LS | T1_TER | (len & T1_TBS_MASK));
271 #endif
272 TxD->xd0 = htole32(T0_OWN);
273 wbinv(TxD, sizeof(struct desc));
274 CSR_WRITE(l, TLP_TPD, TPD_POLL);
275 loop = 100;
276 do {
277 if ((le32toh(TxD->xd0) & T0_OWN) == 0)
278 goto done;
279 inv(TxD, sizeof(struct desc));
280 DELAY(10);
281 } while (--loop > 0);
282 printf("xmit failed\n");
283 return -1;
284 done:
285 return len;
286 }
287
288 int
289 tlp_recv(void *dev, char *buf, u_int maxlen, u_int timo)
290 {
291 struct local *l = dev;
292 struct desc *RxD;
293 u_int bound, len;
294 uint32_t rxstat;
295 uint8_t *ptr;
296
297 bound = 1000 * timo;
298
299 again:
300 RxD = &l->RxD[l->rx];
301 do {
302 rxstat = le32toh(RxD->xd0);
303 inv(RxD, sizeof(struct desc));
304 if ((rxstat & R0_OWN) == 0)
305 goto gotone;
306 DELAY(1000); /* 1 milli second */
307 } while (--bound > 0);
308 errno = 0;
309 CSR_WRITE(l, TLP_RPD, RPD_POLL);
310 return -1;
311 gotone:
312 if (rxstat & R0_ES) {
313 RxD->xd0 = htole32(R0_OWN|R0_FS|R0_LS);
314 wbinv(RxD, sizeof(struct desc));
315 l->rx = NEXT_RXBUF(l->rx);
316 CSR_WRITE(l, TLP_RPD, RPD_POLL);
317 goto again;
318 }
319 /* good frame */
320 len = ((rxstat & R0_FL_MASK) >> 16) - 4; /* HASFCS */
321 if (len > maxlen)
322 len = maxlen;
323 ptr = l->rxstore[l->rx];
324 memcpy(buf, ptr, len);
325 inv(ptr, FRAMESIZE);
326 RxD->xd0 = htole32(R0_OWN|R0_FS|R0_LS);
327 wbinv(RxD, sizeof(struct desc));
328 l->rx = NEXT_RXBUF(l->rx);
329 CSR_WRITE(l, TLP_OMR, l->omr); /* necessary? */
330 return len;
331 }
332
333 static void
334 size_srom(struct local *l)
335 {
336 /* determine 8/6 bit addressing SEEPROM */
337 l->sromsft = 8;
338 l->sromsft = (read_srom(l, 255) & 0x40000) ? 8 : 6;
339 }
340
341 /*
342 * bare SEEPROM access with bitbang'ing
343 */
344 #define R110 6 /* SEEPROM read op */
345 #define CS (1U << 0) /* hold chip select */
346 #define CLK (1U << 1) /* clk bit */
347 #define D1 (1U << 2) /* bit existence */
348 #define D0 0 /* bit absence */
349 #define VV (1U << 3) /* taken 0/1 from SEEPROM */
350
351 static u_int
352 read_srom(struct local *l, int off)
353 {
354 u_int idx, cnt, ret;
355 uint32_t val, x1, x0, bit;
356
357 idx = off & 0xff; /* A7-A0 */
358 idx |= R110 << l->sromsft; /* 110 for READ */
359
360 val = SROM_RD | SROM_SR;
361 CSR_WRITE(l, TLP_APROM, val);
362 val |= CS; /* hold CS */
363 CSR_WRITE(l, TLP_APROM, val);
364
365 x1 = val | D1; /* 1 */
366 x0 = val | D0; /* 0 */
367 /* instruct R110 op. at off in MSB first order */
368 for (cnt = (1 << (l->sromsft + 2)); cnt > 0; cnt >>= 1) {
369 bit = (idx & cnt) ? x1 : x0;
370 CSR_WRITE(l, TLP_APROM, bit);
371 DELAY(10);
372 CSR_WRITE(l, TLP_APROM, bit | CLK);
373 DELAY(10);
374 }
375 /* read 16bit quantity in MSB first order */
376 ret = 0;
377 for (cnt = 16; cnt > 0; cnt--) {
378 CSR_WRITE(l, TLP_APROM, val);
379 DELAY(10);
380 CSR_WRITE(l, TLP_APROM, val | CLK);
381 DELAY(10);
382 ret = (ret << 1) | !!(CSR_READ(l, TLP_APROM) & VV);
383 }
384 val &= ~CS; /* turn off chip select */
385 CSR_WRITE(l, TLP_APROM, val);
386
387 return ret;
388 }
389
390 #if 0
391
392 static u_int
393 tlp_mii_read(struct local *l, int phy, int reg)
394 {
395 /* later ... */
396 return 0;
397 }
398
399 static void
400 tlp_mii_write(struct local *l, int phy, int reg, int val)
401 {
402 /* later ... */
403 }
404
405 #define MII_BMCR 0x00 /* Basic mode control register (rw) */
406 #define BMCR_RESET 0x8000 /* reset */
407 #define BMCR_AUTOEN 0x1000 /* autonegotiation enable */
408 #define BMCR_ISO 0x0400 /* isolate */
409 #define BMCR_STARTNEG 0x0200 /* restart autonegotiation */
410 #define MII_BMSR 0x01 /* Basic mode status register (ro) */
411
412 static void
413 mii_initphy(struct local *l)
414 {
415 int phy, bound;
416 uint32_t ctl, sts;
417
418 for (phy = 0; phy < 32; phy++) {
419 ctl = tlp_mii_read(l, phy, MII_BMCR);
420 sts = tlp_mii_read(l, phy, MII_BMSR);
421 if (ctl != 0xffff && sts != 0xffff)
422 goto found;
423 }
424 printf("MII: no PHY found\n");
425 return;
426 found:
427 ctl = tlp_mii_read(l, phy, MII_BMCR);
428 tlp_mii_write(l, phy, MII_BMCR, ctl | BMCR_RESET);
429 bound = 100;
430 do {
431 DELAY(10);
432 ctl = tlp_mii_read(l, phy, MII_BMCR);
433 if (ctl == 0xffff) {
434 printf("MII: PHY %d has died after reset\n", phy);
435 return;
436 }
437 } while (bound-- > 0 && (ctl & BMCR_RESET));
438 if (bound == 0) {
439 printf("PHY %d reset failed\n", phy);
440 }
441 ctl &= ~BMCR_ISO;
442 tlp_mii_write(l, phy, MII_BMCR, ctl);
443 sts = tlp_mii_read(l, phy, MII_BMSR) |
444 tlp_mii_read(l, phy, MII_BMSR); /* read twice */
445 l->phy = phy;
446 l->bmsr = sts;
447 }
448
449 static void
450 mii_dealan(struct local *, u_int timo)
451 {
452 uint32_t anar;
453 u_int bound;
454
455 anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA;
456 tlp_mii_write(l, l->phy, MII_ANAR, anar);
457 tlp_mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
458 l->anlpar = 0;
459 bound = getsecs() + timo;
460 do {
461 l->bmsr = tlp_mii_read(l, l->phy, MII_BMSR) |
462 tlp_mii_read(l, l->phy, MII_BMSR); /* read twice */
463 if ((l->bmsr & BMSR_LINK) && (l->bmsr & BMSR_ACOMP)) {
464 l->anlpar = tlp_mii_read(l, l->phy, MII_ANLPAR);
465 break;
466 }
467 DELAY(10 * 1000);
468 } while (getsecs() < bound);
469 return;
470 }
471 #endif
472