Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / sandpoint / stand / netboot / tlp.c
blob31db68f8b006d7769056bd3e2ef1e3366ee1fa65
1 /* $NetBSD: tlp.c,v 1.23 2009/07/03 10:31:19 nisimura Exp $ */
3 /*-
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tohru Nishimura.
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/param.h>
34 #include <netinet/in.h>
35 #include <netinet/in_systm.h>
37 #include <lib/libsa/stand.h>
38 #include <lib/libsa/net.h>
40 #include "globals.h"
43 * - reverse endian access for CSR register.
44 * - no vtophys() translation, vaddr_t == paddr_t.
45 * - PIPT writeback cache aware.
47 #define CSR_READ(l, r) in32rb((l)->csr+(r))
48 #define CSR_WRITE(l, r, v) out32rb((l)->csr+(r), (v))
49 #define VTOPHYS(va) (uint32_t)(va)
50 #define DEVTOV(pa) (uint32_t)(pa)
51 #define wbinv(adr, siz) _wbinv(VTOPHYS(adr), (uint32_t)(siz))
52 #define inv(adr, siz) _inv(VTOPHYS(adr), (uint32_t)(siz))
53 #define DELAY(n) delay(n)
54 #define ALLOC(T,A) (T *)((unsigned)alloc(sizeof(T) + (A)) &~ ((A) - 1))
56 struct desc {
57 uint32_t xd0, xd1, xd2, xd3;
59 #define T0_OWN (1U<<31) /* desc is ready to tx */
60 #define T0_ES (1U<<15) /* Tx error summary */
61 #define T1_LS (1U<<30) /* last segment */
62 #define T1_FS (1U<<29) /* first segment */
63 #define T1_TER (1U<<25) /* end of ring mark */
64 #define T1_TCH (1U<<24) /* TDES3 points the next desc */
65 #define T1_TBS_MASK 0x7ff /* segment size 10:0 */
66 #define R0_OWN (1U<<31) /* desc is empty */
67 #define R0_FS (1U<<30) /* first desc of frame */
68 #define R0_LS (1U<<8) /* last desc of frame */
69 #define R0_ES (1U<<15) /* Rx error summary */
70 #define R1_RER (1U<<25) /* end of ring mark */
71 #define R1_RCH (1U<<24) /* RDES3 points the next desc */
72 #define R0_FLMASK 0x3fff0000 /* frame length 29:16 */
73 #define R1_RBS_MASK 0x7ff /* segment size 10:0 */
75 #define PAR_CSR0 0x00 /* bus mode */
76 #define PAR_DEFAULTS 0x00001000 /* PDF sez it should be ... */
77 #define PAR_SWR 01
78 #define TDR_CSR1 0x08 /* T0_OWN poll demand */
79 #define RDR_CSR2 0x10 /* R0_OWN poll demand */
80 #define RDB_CSR3 0x18 /* Rx descriptor base */
81 #define TDB_CSR4 0x20 /* Tx descriptor base */
82 #define SR_CSR5 0x28 /* interrupt stauts */
83 #define NAR_CSR6 0x30 /* operation mode */
84 #define NAR_NOSQE (1U<<19) /* _not_ use SQE signal */
85 #define NAR_TEN (1U<<13) /* instruct start/stop Tx */
86 #define NAR_REN (1U<< 1) /* instruct start/stop Rx */
87 #define IER_CSR7 0x38 /* interrupt enable mask */
88 #define SPR_CSR9 0x48 /* SEEPROM and MII management */
89 #define MII_MDI (1U<<19) /* 0/1 presense after read op */
90 #define MII_MIDIR (1U<<18) /* 1 for PHY->HOST */
91 #define MII_MDO (1U<<17) /* 0/1 for write op */
92 #define MII_MDC (1U<<16) /* MDIO clock */
93 #define SROM_RD (1U<<14) /* read operation */
94 #define SROM_WR (1U<<13) /* write openration */
95 #define SROM_SR (1U<<11) /* SEEPROM select */
96 #define PAR0_CSR25 0xa4 /* MAC 3:0 */
97 #define PAR1_CSR26 0xa8 /* MAC 5:4 */
98 #define AN_OMODE 0xfc /* operation mode */
100 #define FRAMESIZE 1536
102 struct local {
103 struct desc txd[2];
104 struct desc rxd[2];
105 uint8_t rxstore[2][FRAMESIZE];
106 unsigned csr, omr, tx, rx;
107 unsigned phy, bmsr, anlpar;
110 static unsigned mii_read(struct local *, int, int);
111 static void mii_write(struct local *, int, int, int);
112 static void mii_initphy(struct local *);
113 static void mii_dealan(struct local *, unsigned);
116 tlp_match(unsigned tag, void *data)
118 unsigned v;
120 v = pcicfgread(tag, PCI_ID_REG);
121 switch (v) {
122 case PCI_DEVICE(0x1317, 0x0985): /* ADMTek/Infineon 983B/BX */
123 return 1;
125 return 0;
128 void *
129 tlp_init(unsigned tag, void *data)
131 struct local *l;
132 struct desc *txd, *rxd;
133 unsigned i, val, fdx;
134 uint8_t *en;
136 l = ALLOC(struct local, 2 * sizeof(struct desc)); /* desc alignment */
137 memset(l, 0, sizeof(struct local));
138 l->csr = DEVTOV(pcicfgread(tag, 0x14)); /* use mem space */
140 CSR_WRITE(l, PAR_CSR0, PAR_SWR);
141 i = 100;
142 do {
143 DELAY(10);
144 } while (i-- > 0 && (CSR_READ(l, PAR_CSR0) & PAR_SWR) != 0);
145 CSR_WRITE(l, PAR_CSR0, PAR_DEFAULTS);
147 l->omr = NAR_NOSQE;
148 CSR_WRITE(l, NAR_CSR6, l->omr);
149 CSR_WRITE(l, SR_CSR5, ~0);
150 CSR_WRITE(l, IER_CSR7, 0);
152 en = data;
153 val = CSR_READ(l, PAR0_CSR25);
154 en[0] = val & 0xff;
155 en[1] = (val >> 8) & 0xff;
156 en[2] = (val >> 16) & 0xff;
157 en[3] = (val >> 24) & 0xff;
158 val = CSR_READ(l, PAR1_CSR26);
159 en[4] = val & 0xff;
160 en[5] = (val >> 8) & 0xff;
161 #if 1
162 printf("MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
163 en[0], en[1], en[2], en[3], en[4], en[5]);
164 #endif
166 mii_initphy(l);
167 mii_dealan(l, 5);
169 val = CSR_READ(l, AN_OMODE);
170 if (val & (1U << 29)) {
171 printf("%s", (val & (1U << 31)) ? "100Mbps" : "10Mbps");
172 fdx = !!(val & (1U << 30));
173 if (fdx)
174 printf("-FDX");
175 printf("\n");
178 txd = &l->txd[0];
179 txd[1].xd1 = htole32(T1_TER);
180 rxd = &l->rxd[0];
181 rxd[0].xd0 = htole32(R0_OWN);
182 rxd[0].xd1 = htole32(FRAMESIZE);
183 rxd[0].xd2 = htole32(VTOPHYS(l->rxstore[0]));
184 rxd[1].xd0 = htole32(R0_OWN);
185 rxd[1].xd1 = htole32(R1_RER | FRAMESIZE);
186 rxd[1].xd2 = htole32(VTOPHYS(l->rxstore[1]));
187 l->tx = l->rx = 0;
189 /* make sure the entire descriptors transfered to memory */
190 wbinv(l, sizeof(struct local));
192 CSR_WRITE(l, TDB_CSR4, VTOPHYS(txd));
193 CSR_WRITE(l, RDB_CSR3, VTOPHYS(rxd));
195 /* start Tx/Rx */
196 CSR_WRITE(l, NAR_CSR6, l->omr | NAR_TEN | NAR_REN);
198 return l;
202 tlp_send(void *dev, char *buf, unsigned len)
204 struct local *l = dev;
205 volatile struct desc *txd;
206 unsigned txstat, loop;
208 wbinv(buf, len);
209 txd = &l->txd[l->tx];
210 txd->xd2 = htole32(VTOPHYS(buf));
211 txd->xd1 &= htole32(T1_TER);
212 txd->xd1 |= htole32(T1_FS | T1_LS | (len & T1_TBS_MASK));
213 txd->xd0 = htole32(T0_OWN);
214 wbinv(txd, sizeof(struct desc));
215 CSR_WRITE(l, TDR_CSR1, 01);
216 loop = 100;
217 do {
218 txstat = le32toh(txd->xd0);
219 if ((txstat & T0_OWN) == 0)
220 goto done;
221 DELAY(10);
222 inv(txd, sizeof(struct desc));
223 } while (--loop != 0);
224 printf("xmit failed\n");
225 return -1;
226 done:
227 l->tx ^= 1;
228 return len;
232 tlp_recv(void *dev, char *buf, unsigned maxlen, unsigned timo)
234 struct local *l = dev;
235 volatile struct desc *rxd;
236 unsigned bound, rxstat, len;
237 uint8_t *ptr;
239 bound = 1000 * timo;
240 #if 0
241 printf("recving with %u sec. timeout\n", timo);
242 #endif
243 again:
244 rxd = &l->rxd[l->rx];
245 do {
246 inv(rxd, sizeof(struct desc));
247 rxstat = le32toh(rxd->xd0);
248 if ((rxstat & R0_OWN) == 0)
249 goto gotone;
250 DELAY(1000); /* 1 milli second */
251 } while (--bound > 0);
252 errno = 0;
253 return -1;
254 gotone:
255 if (rxstat & R0_ES) {
256 rxd->xd0 = htole32(R0_OWN);
257 wbinv(rxd, sizeof(struct desc));
258 l->rx ^= 1;
259 goto again;
261 /* good frame */
262 len = ((rxstat & R0_FLMASK) >> 16) - 4 /* HASFCS */;
263 if (len > maxlen)
264 len = maxlen;
265 ptr = l->rxstore[l->rx];
266 inv(ptr, len);
267 memcpy(buf, ptr, len);
268 rxd->xd0 = htole32(R0_OWN);
269 wbinv(rxd, sizeof(struct desc));
270 l->rx ^= 1;
271 return len;
275 * bare MII access with bitbang'ing
277 #define R110 6 /* SEEPROM/MDIO read op */
278 #define W101 5 /* SEEPROM/MDIO write op */
279 #define CS (1U << 0) /* hold chip select */
280 #define CLK (1U << 1) /* clk bit */
281 #define D1 (1U << 2) /* bit existence */
282 #define VV (1U << 3) /* taken 0/1 from SEEPROM */
284 static unsigned
285 mii_read(struct local *l, int phy, int reg)
287 unsigned data, rv, v, i;
289 data = (R110 << 10) | (phy << 5) | reg;
290 CSR_WRITE(l, SPR_CSR9, MII_MDO);
291 for (i = 0; i < 32; i++) {
292 CSR_WRITE(l, SPR_CSR9, MII_MDO | MII_MDC);
293 DELAY(1);
294 CSR_WRITE(l, SPR_CSR9, MII_MDO);
295 DELAY(1);
297 CSR_WRITE(l, SPR_CSR9, 0);
298 v = 0; /* 4OP + 5ADDR + 5REG */
299 for (i = (1 << 13); i != 0; i >>= 1) {
300 if (data & i)
301 v |= MII_MDO;
302 else
303 v &= ~MII_MDO;
304 CSR_WRITE(l, SPR_CSR9, v);
305 DELAY(1);
306 CSR_WRITE(l, SPR_CSR9, v | MII_MDC);
307 DELAY(1);
308 CSR_WRITE(l, SPR_CSR9, v);
309 DELAY(1);
311 rv = 0; /* 2TA + 16MDI */
312 for (i = 0; i < 18; i++) {
313 CSR_WRITE(l, SPR_CSR9, MII_MIDIR);
314 DELAY(1);
315 rv = (rv << 1) | !!(CSR_READ(l, SPR_CSR9) & MII_MDI);
316 CSR_WRITE(l, SPR_CSR9, MII_MIDIR | MII_MDC);
317 DELAY(1);
319 CSR_WRITE(l, SPR_CSR9, 0);
320 return rv & 0xffff;
323 static void
324 mii_write(struct local *l, int phy, int reg, int val)
326 unsigned data, v, i;
328 data = (W101 << 28) | (phy << 23) | (reg << 18) | (02 << 16);
329 data |= val & 0xffff;
330 CSR_WRITE(l, SPR_CSR9, MII_MDO);
331 for (i = 0; i < 32; i++) {
332 CSR_WRITE(l, SPR_CSR9, MII_MDO | MII_MDC);
333 DELAY(1);
334 CSR_WRITE(l, SPR_CSR9, MII_MDO);
335 DELAY(1);
337 CSR_WRITE(l, SPR_CSR9, 0);
338 v = 0; /* 4OP + 5ADDR + 5REG + 2TA + 16DATA */
339 for (i = (1 << 31); i != 0; i >>= 1) {
340 if (data & i)
341 v |= MII_MDO;
342 else
343 v &= ~MII_MDO;
344 CSR_WRITE(l, SPR_CSR9, v);
345 DELAY(1);
346 CSR_WRITE(l, SPR_CSR9, v | MII_MDC);
347 DELAY(1);
348 CSR_WRITE(l, SPR_CSR9, v);
349 DELAY(1);
351 CSR_WRITE(l, SPR_CSR9, 0);
354 #define MII_BMCR 0x00 /* Basic mode control register (rw) */
355 #define BMCR_RESET 0x8000 /* reset */
356 #define BMCR_AUTOEN 0x1000 /* autonegotiation enable */
357 #define BMCR_ISO 0x0400 /* isolate */
358 #define BMCR_STARTNEG 0x0200 /* restart autonegotiation */
359 #define MII_BMSR 0x01 /* Basic mode status register (ro) */
360 #define BMSR_ACOMP 0x0020 /* Autonegotiation complete */
361 #define BMSR_LINK 0x0004 /* Link status */
362 #define MII_ANAR 0x04 /* Autonegotiation advertisement (rw) */
363 #define ANAR_FC 0x0400 /* local device supports PAUSE */
364 #define ANAR_TX_FD 0x0100 /* local device supports 100bTx FD */
365 #define ANAR_TX 0x0080 /* local device supports 100bTx */
366 #define ANAR_10_FD 0x0040 /* local device supports 10bT FD */
367 #define ANAR_10 0x0020 /* local device supports 10bT */
368 #define ANAR_CSMA 0x0001 /* protocol selector CSMA/CD */
369 #define MII_ANLPAR 0x05 /* Autonegotiation lnk partner abilities (rw) */
371 static void
372 mii_initphy(struct local *l)
374 int phy, ctl, sts, bound;
376 for (phy = 0; phy < 32; phy++) {
377 ctl = mii_read(l, phy, MII_BMCR);
378 sts = mii_read(l, phy, MII_BMSR);
379 if (ctl != 0xffff && sts != 0xffff)
380 goto found;
382 printf("MII: no PHY found\n");
383 return;
384 found:
385 ctl = mii_read(l, phy, MII_BMCR);
386 mii_write(l, phy, MII_BMCR, ctl | BMCR_RESET);
387 bound = 100;
388 do {
389 DELAY(10);
390 ctl = mii_read(l, phy, MII_BMCR);
391 if (ctl == 0xffff) {
392 printf("MII: PHY %d has died after reset\n", phy);
393 return;
395 } while (bound-- > 0 && (ctl & BMCR_RESET));
396 if (bound == 0) {
397 printf("PHY %d reset failed\n", phy);
399 ctl &= ~BMCR_ISO;
400 mii_write(l, phy, MII_BMCR, ctl);
401 sts = mii_read(l, phy, MII_BMSR) |
402 mii_read(l, phy, MII_BMSR); /* read twice */
403 l->phy = phy;
404 l->bmsr = sts;
407 static void
408 mii_dealan(struct local *l, unsigned timo)
410 unsigned anar, bound;
412 anar = ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10 | ANAR_CSMA;
413 mii_write(l, l->phy, MII_ANAR, anar);
414 mii_write(l, l->phy, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG);
415 l->anlpar = 0;
416 bound = getsecs() + timo;
417 do {
418 l->bmsr = mii_read(l, l->phy, MII_BMSR) |
419 mii_read(l, l->phy, MII_BMSR); /* read twice */
420 if ((l->bmsr & BMSR_LINK) && (l->bmsr & BMSR_ACOMP)) {
421 l->anlpar = mii_read(l, l->phy, MII_ANLPAR);
422 break;
424 DELAY(10 * 1000);
425 } while (getsecs() < bound);
426 return;