1 /* $OpenBSD: lance.c,v 1.4 2023/01/10 17:10:57 miod Exp $ */
2 /* $NetBSD: lance.c,v 1.1 2013/01/13 14:10:55 tsutsui Exp $ */
3
4 /*
5 * Copyright (c) 2013 Izumi Tsutsui. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 /*-
28 * Copyright (c) 2004 The NetBSD Foundation, Inc.
29 * All rights reserved.
30 *
31 * This code is derived from software contributed to The NetBSD Foundation
32 * by UCHIYAMA Yasushi.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
44 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
45 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
46 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
47 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
48 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
49 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
50 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
51 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
52 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
53 * POSSIBILITY OF SUCH DAMAGE.
54 */
55
56 /*
57 * LANCE driver for LUNA
58 * based on sys/arch/ews4800mips/stand/common/lance.c
59 */
60
61 #include <luna88k/stand/boot/samachdep.h>
62
63 #include <dev/ic/am7990reg.h>
64 #include <dev/ic/lancereg.h>
65
66 #include <luna88k/stand/boot/lance.h>
67
68 static void lance_setup(struct le_softc *);
69 static int lance_set_initblock(struct le_softc *);
70 static int lance_do_initialize(struct le_softc *);
71
72 #define NLE 1 /* XXX for now */
73 static struct le_softc lesc[NLE];
74
75 void *
lance_attach(uint unit,void * reg,void * mem,uint8_t * eaddr)76 lance_attach(uint unit, void *reg, void *mem, uint8_t *eaddr)
77 {
78 struct le_softc *sc;
79
80 if (unit >= NLE) {
81 printf("%s: invalid unit number\n", __func__);
82 return NULL;
83 }
84 sc = &lesc[unit];
85
86 if (sc->sc_reg != NULL) {
87 printf("%s: unit %d is already attached\n", __func__, unit);
88 return NULL;
89 }
90 sc->sc_reg = reg;
91 sc->sc_mem = mem;
92 memcpy(sc->sc_enaddr, eaddr, 6);
93
94 return sc;
95 }
96
97 void *
lance_cookie(uint unit)98 lance_cookie(uint unit)
99 {
100 struct le_softc *sc;
101
102 if (unit >= NLE)
103 return NULL;
104
105 sc = &lesc[unit];
106
107 if (sc->sc_reg == NULL)
108 return NULL;
109
110 return sc;
111 }
112
113 uint8_t *
lance_eaddr(void * cookie)114 lance_eaddr(void *cookie)
115 {
116 struct le_softc *sc = cookie;
117
118 if (sc == NULL || sc->sc_reg == NULL)
119 return NULL;
120
121 return sc->sc_enaddr;
122 }
123
124 int
lance_init(void * cookie)125 lance_init(void *cookie)
126 {
127 struct le_softc *sc = cookie;
128
129 lance_setup(sc);
130
131 if (!lance_set_initblock(sc))
132 return 0;
133
134 if (!lance_do_initialize(sc))
135 return 0;
136
137 return 1;
138 }
139
140 int
lance_get(void * cookie,void * data,size_t maxlen)141 lance_get(void *cookie, void *data, size_t maxlen)
142 {
143 struct le_softc *sc = cookie;
144 struct lereg *lereg = sc->sc_reg;
145 struct lemem *lemem = sc->sc_mem;
146 struct lermd_v *rmd;
147 uint16_t csr;
148 int len = -1;
149
150 lereg->ler_rap = LE_CSR0;
151 if ((lereg->ler_rdp & LE_C0_RINT) != 0)
152 lereg->ler_rdp = LE_C0_RINT;
153 rmd = &lemem->lem_rmd[sc->sc_currmd];
154 if ((rmd->rmd1_bits & LE_R1_OWN) != 0)
155 return -1;
156
157 csr = lereg->ler_rdp;
158 #if 0
159 if ((csr & LE_C0_ERR) != 0)
160 printf("%s: RX poll error (CSR=0x%x)\n", __func__, csr);
161 #endif
162 if ((rmd->rmd1_bits & LE_R1_ERR) != 0) {
163 printf("%s: RX error (rmd status=0x%x)\n", __func__,
164 rmd->rmd1_bits);
165 goto out;
166 }
167
168 len = rmd->rmd3;
169 if (len < LEMINSIZE + 4 || len > LEMTU) {
170 printf("%s: RX error (bad length %d)\n", __func__, len);
171 goto out;
172 }
173 len -= 4;
174 memcpy(data, (void *)lemem->lem_rbuf[sc->sc_currmd], min(len, maxlen));
175
176 out:
177 rmd->rmd2 = -LEMTU;
178 rmd->rmd1_bits = LE_R1_OWN; /* return to LANCE */
179 sc->sc_currmd = LE_NEXTRMD(sc->sc_currmd);
180
181 return len;
182 }
183
184 int
lance_put(void * cookie,void * data,size_t len)185 lance_put(void *cookie, void *data, size_t len)
186 {
187 struct le_softc *sc = cookie;
188 struct lereg *lereg = sc->sc_reg;
189 struct lemem *lemem = sc->sc_mem;
190 struct letmd_v *tmd;
191 uint16_t stat;
192 int timeout;
193
194 lereg->ler_rap = LE_CSR0;
195 stat = lereg->ler_rdp;
196 lereg->ler_rdp =
197 stat & (LE_C0_BABL | LE_C0_CERR | LE_C0_MISS | LE_C0_TINT);
198 #if 0
199 if (stat & (LE_C0_BABL | LE_C0_CERR | LE_C0_MISS | LE_C0_MERR))
200 printf("%s: TX error before xmit csr0=0x%x\n",
201 __func__, stat);
202 #endif
203
204 /* setup TX descriptor */
205 tmd = &lemem->lem_tmd[sc->sc_curtmd];
206 while (tmd->tmd1_bits & LE_T1_OWN)
207 continue;
208 tmd->tmd1_bits = LE_T1_STP | LE_T1_ENP;
209 memcpy((void *)lemem->lem_tbuf[sc->sc_curtmd], data, len);
210 tmd->tmd2 = -max(len, LEMINSIZE);
211 tmd->tmd3 = 0;
212
213 /* start TX */
214 tmd->tmd1_bits |= LE_T1_OWN;
215 lereg->ler_rap = LE_CSR0;
216 lereg->ler_rdp = LE_C0_TDMD;
217
218 /* check TX complete */
219 timeout = 0;
220 do {
221 lereg->ler_rap = LE_CSR0;
222 stat = lereg->ler_rdp;
223 #if 0
224 if (stat & LE_C0_ERR) {
225 printf("%s: TX error (CSR0=%x)\n", __func__, stat);
226 if (stat & LE_C0_CERR) {
227 lereg->ler_rdp = LE_C0_CERR;
228 }
229 }
230 #endif
231 if (timeout++ > 1000) {
232 printf("%s: TX timeout (CSR0=%x)\n", __func__, stat);
233 return 0;
234 }
235 } while ((stat & LE_C0_TINT) == 0);
236
237 lereg->ler_rdp = LE_C0_TINT;
238
239 sc->sc_curtmd = LE_NEXTTMD(sc->sc_curtmd);
240
241 return 1;
242 }
243
244 int
lance_end(void * cookie)245 lance_end(void *cookie)
246 {
247 struct le_softc *sc = cookie;
248 struct lereg *lereg = sc->sc_reg;
249
250 lereg->ler_rap = LE_CSR0;
251 lereg->ler_rdp = LE_C0_STOP;
252
253 return 1;
254 }
255
256 static int
lance_set_initblock(struct le_softc * sc)257 lance_set_initblock(struct le_softc *sc)
258 {
259 struct lereg *lereg = sc->sc_reg;
260 uint32_t addr = (uint32_t)sc->sc_mem;
261
262 lereg->ler_rap = LE_CSR0;
263 lereg->ler_rdp = LE_C0_STOP; /* disable all external activity */
264 DELAY(100);
265
266 /* Set the correct byte swapping mode */
267 lereg->ler_rap = LE_CSR3;
268 lereg->ler_rdp = LE_C3_BSWP;
269
270 /* Low address of init block */
271 lereg->ler_rap = LE_CSR1;
272 lereg->ler_rdp = addr & 0xfffe;
273
274 /* High address of init block */
275 lereg->ler_rap = LE_CSR2;
276 lereg->ler_rdp = (addr >> 16) & 0x00ff;
277 DELAY(100);
278
279 return 1;
280 }
281
282 static int
lance_do_initialize(struct le_softc * sc)283 lance_do_initialize(struct le_softc *sc)
284 {
285 struct lereg *lereg = sc->sc_reg;
286 uint16_t reg;
287 int timeout;
288
289 sc->sc_curtmd = 0;
290 sc->sc_currmd = 0;
291
292 /* Initialize LANCE */
293 lereg->ler_rap = LE_CSR0;
294 lereg->ler_rdp = LE_C0_INIT;
295
296 /* Wait interrupt */
297 timeout = 1000000;
298 do {
299 lereg->ler_rap = LE_CSR0;
300 reg = lereg->ler_rdp;
301 if (--timeout == 0) {
302 printf("le: init timeout (CSR=0x%x)\n", reg);
303 return 0;
304 }
305 DELAY(1);
306 } while ((reg & LE_C0_IDON) == 0);
307
308 lereg->ler_rap = LE_CSR0;
309 lereg->ler_rdp = LE_C0_STRT | LE_C0_IDON;
310
311 return 1;
312 }
313
314 static void
lance_setup(struct le_softc * sc)315 lance_setup(struct le_softc *sc)
316 {
317 struct lereg *lereg = sc->sc_reg;
318 struct lemem *lemem = sc->sc_mem;
319 uint32_t addr;
320 int i;
321
322 /* make sure to stop LANCE chip before setup memory */
323 lereg->ler_rap = LE_CSR0;
324 lereg->ler_rdp = LE_C0_STOP;
325
326 memset(lemem, 0, sizeof *lemem);
327
328 /* Init block */
329 lemem->lem_mode = LE_MODE_NORMAL;
330 lemem->lem_padr[0] = (sc->sc_enaddr[1] << 8) | sc->sc_enaddr[0];
331 lemem->lem_padr[1] = (sc->sc_enaddr[3] << 8) | sc->sc_enaddr[2];
332 lemem->lem_padr[2] = (sc->sc_enaddr[5] << 8) | sc->sc_enaddr[4];
333 /* Logical address filter */
334 for (i = 0; i < 4; i++)
335 lemem->lem_ladrf[i] = 0x0000;
336
337 /* Location of Rx descriptor ring */
338 addr = (uint32_t)lemem->lem_rmd;
339 lemem->lem_rdra = addr & 0xffff;
340 lemem->lem_rlen = LE_RLEN | ((addr >> 16) & 0xff);
341
342 /* Location of Tx descriptor ring */
343 addr = (uint32_t)lemem->lem_tmd;
344 lemem->lem_tdra = addr & 0xffff;
345 lemem->lem_tlen = LE_TLEN | ((addr >> 16) & 0xff);
346
347 /* Rx descriptor */
348 for (i = 0; i < LERBUF; i++) {
349 addr = (uint32_t)lemem->lem_rbuf[i];
350 lemem->lem_rmd[i].rmd0 = addr & 0xffff;
351 lemem->lem_rmd[i].rmd1_hadr = (addr >> 16) & 0xff;
352 lemem->lem_rmd[i].rmd1_bits = LE_R1_OWN;
353 lemem->lem_rmd[i].rmd2 = LE_XMD2_ONES | -LEMTU;
354 lemem->lem_rmd[i].rmd3 = 0;
355 }
356
357 /* Tx descriptor */
358 for (i = 0; i < LETBUF; i++) {
359 addr = (uint32_t)lemem->lem_tbuf[i];
360 lemem->lem_tmd[i].tmd0 = addr & 0xffff;
361 lemem->lem_tmd[i].tmd1_hadr = (addr >> 16) & 0xff;
362 lemem->lem_tmd[i].tmd1_bits = 0;
363 lemem->lem_tmd[i].tmd2 = LE_XMD2_ONES | 0;
364 lemem->lem_tmd[i].tmd3 = 0;
365 }
366 }
367