]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/i386/libfirewire/firewire.c
MFC r341253, r341328, r342619, r342626, r342707, r342785, r342865
[FreeBSD/FreeBSD.git] / stand / i386 / libfirewire / firewire.c
1 /*-
2  * Copyright (c) 2004 Hidetoshi Shimokawa <simokawa@FreeBSD.ORG>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 /*
31  * FireWire disk device handling.
32  * 
33  */
34
35 #include <stand.h>
36
37 #include <machine/bootinfo.h>
38
39 #include <stdarg.h>
40
41 #include <bootstrap.h>
42 #include <btxv86.h>
43 #include <libi386.h>
44 #include <dev/firewire/firewire.h>
45 #include "fwohci.h"
46 #include <dev/dcons/dcons.h>
47
48 /* XXX */
49 #define BIT4x2(x,y)      uint8_t  y:4, x:4
50 #define BIT16x2(x,y)    uint32_t y:16, x:16
51 #define _KERNEL
52 #include <dev/firewire/iec13213.h>
53
54 extern uint32_t dcons_paddr;
55 extern struct console dconsole;
56
57 struct crom_src_buf {
58         struct crom_src src;
59         struct crom_chunk root;
60         struct crom_chunk vendor;
61         struct crom_chunk hw;
62         /* for dcons */
63         struct crom_chunk unit;
64         struct crom_chunk spec;
65         struct crom_chunk ver;
66 };
67
68 static int      fw_init(void);
69 static int      fw_strategy(void *devdata, int flag, daddr_t dblk,
70                     size_t size, char *buf, size_t *rsize);
71 static int      fw_open(struct open_file *f, ...);
72 static int      fw_close(struct open_file *f);
73 static int      fw_print(int verbose);
74 static void     fw_cleanup(void);
75
76 void            fw_enable(void);
77
78 struct devsw fwohci = {
79     "FW1394",   /* 7 chars at most */
80     DEVT_NET, 
81     fw_init,
82     fw_strategy, 
83     fw_open, 
84     fw_close, 
85     noioctl,
86     fw_print,
87     fw_cleanup
88 };
89
90 static struct fwohci_softc fwinfo[MAX_OHCI];
91 static int fw_initialized = 0;
92
93 static void
94 fw_probe(int index, struct fwohci_softc *sc)
95 {
96         int err;
97
98         sc->state = FWOHCI_STATE_INIT;
99         err = biospci_find_devclass(
100                 0x0c0010        /* Serial:FireWire:OHCI */,
101                 index           /* index */,
102                 &sc->locator);
103
104         if (err != 0) {
105                 sc->state = FWOHCI_STATE_DEAD;
106                 return;
107         }
108
109         biospci_write_config(sc->locator,
110             0x4 /* command */,
111             BIOSPCI_16BITS,
112             0x6 /* enable bus master and memory mapped I/O */);
113
114         biospci_read_config(sc->locator, 0x00 /*devid*/, BIOSPCI_32BITS,
115                 &sc->devid);
116         biospci_read_config(sc->locator, 0x10 /*base_addr*/, BIOSPCI_32BITS,
117                 &sc->base_addr);
118
119         sc->handle = (uint32_t)PTOV(sc->base_addr);
120         sc->bus_id = OREAD(sc, OHCI_BUS_ID);
121
122         return;
123 }
124
125 static int
126 fw_init(void) 
127 {
128         int i, avail;
129         struct fwohci_softc *sc;
130
131         if (fw_initialized)
132                 return (0);
133
134         avail = 0;
135         for (i = 0; i < MAX_OHCI; i ++) {
136                 sc = &fwinfo[i];
137                 fw_probe(i, sc);
138                 if (sc->state == FWOHCI_STATE_DEAD)
139                         break;
140                 avail ++;
141                 break;
142         }
143         fw_initialized = 1;
144
145         return (0);
146 }
147
148
149 /*
150  * Print information about OHCI chips
151  */
152 static int
153 fw_print(int verbose)
154 {
155         char line[80];
156         int i, ret = 0;
157         struct fwohci_softc *sc;
158
159         printf("%s devices:", fwohci.dv_name);
160         if ((ret = pager_output("\n")) != 0)
161                 return (ret);
162
163         for (i = 0; i < MAX_OHCI; i ++) {
164                 sc = &fwinfo[i];
165                 if (sc->state == FWOHCI_STATE_DEAD)
166                         break;
167                 snprintf(line, sizeof(line), "%d: locator=0x%04x devid=0x%08x"
168                         " base_addr=0x%08x handle=0x%08x bus_id=0x%08x\n",
169                         i, sc->locator, sc->devid,
170                         sc->base_addr, sc->handle, sc->bus_id);
171                 ret = pager_output(line);
172                 if (ret != 0)
173                         break;
174         }
175         return (ret);
176 }
177
178 static int 
179 fw_open(struct open_file *f, ...)
180 {
181 #if 0
182     va_list                     ap;
183     struct i386_devdesc         *dev;
184     struct open_disk            *od;
185     int                         error;
186
187     va_start(ap, f);
188     dev = va_arg(ap, struct i386_devdesc *);
189     va_end(ap);
190 #endif
191
192     return (ENXIO);
193 }
194
195 static int
196 fw_close(struct open_file *f)
197 {
198     return (0);
199 }
200
201 static void 
202 fw_cleanup()
203 {
204     struct dcons_buf *db;
205
206     /* invalidate dcons buffer */
207     if (dcons_paddr) {
208         db = (struct dcons_buf *)PTOV(dcons_paddr);
209         db->magic = 0;
210     }
211 }
212
213 static int 
214 fw_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
215     char *buf, size_t *rsize)
216 {
217         return (EIO);
218 }
219
220 static void
221 fw_init_crom(struct fwohci_softc *sc)
222 {
223         struct crom_src *src;
224
225         printf("fw_init_crom\n");
226         sc->crom_src_buf = (struct crom_src_buf *)
227                 malloc(sizeof(struct crom_src_buf));
228         if (sc->crom_src_buf == NULL)
229                 return;
230
231         src = &sc->crom_src_buf->src;
232         bzero(src, sizeof(struct crom_src));
233
234         /* BUS info sample */
235         src->hdr.info_len = 4;
236
237         src->businfo.bus_name = CSR_BUS_NAME_IEEE1394;
238
239         src->businfo.irmc = 1;
240         src->businfo.cmc = 1;
241         src->businfo.isc = 1;
242         src->businfo.bmc = 1;
243         src->businfo.pmc = 0;
244         src->businfo.cyc_clk_acc = 100;
245         src->businfo.max_rec = sc->maxrec;
246         src->businfo.max_rom = MAXROM_4;
247 #define FW_GENERATION_CHANGEABLE 2
248         src->businfo.generation = FW_GENERATION_CHANGEABLE;
249         src->businfo.link_spd = sc->speed;
250
251         src->businfo.eui64.hi = sc->eui.hi;
252         src->businfo.eui64.lo = sc->eui.lo;
253
254         STAILQ_INIT(&src->chunk_list);
255
256         sc->crom_src = src;
257         sc->crom_root = &sc->crom_src_buf->root;
258 }
259
260 static void
261 fw_reset_crom(struct fwohci_softc *sc)
262 {
263         struct crom_src_buf *buf;
264         struct crom_src *src;
265         struct crom_chunk *root;
266
267         printf("fw_reset\n");
268         if (sc->crom_src_buf == NULL)
269                 fw_init_crom(sc);
270
271         buf = sc->crom_src_buf;
272         src = sc->crom_src;
273         root = sc->crom_root;
274
275         STAILQ_INIT(&src->chunk_list);
276
277         bzero(root, sizeof(struct crom_chunk));
278         crom_add_chunk(src, NULL, root, 0);
279         crom_add_entry(root, CSRKEY_NCAP, 0x0083c0); /* XXX */
280         /* private company_id */
281         crom_add_entry(root, CSRKEY_VENDOR, CSRVAL_VENDOR_PRIVATE);
282 #ifdef __DragonFly__
283         crom_add_simple_text(src, root, &buf->vendor, "DragonFly Project");
284 #else
285         crom_add_simple_text(src, root, &buf->vendor, "FreeBSD Project");
286 #endif
287 }
288
289
290 #define ADDR_HI(x)      (((x) >> 24) & 0xffffff)
291 #define ADDR_LO(x)      ((x) & 0xffffff)
292
293 static void
294 dcons_crom(struct fwohci_softc *sc)
295 {
296         struct crom_src_buf *buf;
297         struct crom_src *src;
298         struct crom_chunk *root;
299
300         buf = sc->crom_src_buf;
301         src = sc->crom_src;
302         root = sc->crom_root;
303
304         bzero(&buf->unit, sizeof(struct crom_chunk));
305
306         crom_add_chunk(src, root, &buf->unit, CROM_UDIR);
307         crom_add_entry(&buf->unit, CSRKEY_SPEC, CSRVAL_VENDOR_PRIVATE);
308         crom_add_simple_text(src, &buf->unit, &buf->spec, "FreeBSD");
309         crom_add_entry(&buf->unit, CSRKEY_VER, DCONS_CSR_VAL_VER);
310         crom_add_simple_text(src, &buf->unit, &buf->ver, "dcons");
311         crom_add_entry(&buf->unit, DCONS_CSR_KEY_HI, ADDR_HI(dcons_paddr));
312         crom_add_entry(&buf->unit, DCONS_CSR_KEY_LO, ADDR_LO(dcons_paddr));
313 }
314
315 void
316 fw_crom(struct fwohci_softc *sc)
317 {
318         struct crom_src *src;
319         void *newrom;
320
321         fw_reset_crom(sc);
322         dcons_crom(sc);
323
324         newrom = malloc(CROMSIZE);
325         src = &sc->crom_src_buf->src;
326         crom_load(src, (uint32_t *)newrom, CROMSIZE);
327         if (bcmp(newrom, sc->config_rom, CROMSIZE) != 0) {
328                 /* Bump generation and reload. */
329                 src->businfo.generation++;
330
331                 /* Handle generation count wraps. */
332                 if (src->businfo.generation < 2)
333                         src->businfo.generation = 2;
334
335                 /* Recalculate CRC to account for generation change. */
336                 crom_load(src, (uint32_t *)newrom, CROMSIZE);
337                 bcopy(newrom, (void *)sc->config_rom, CROMSIZE);
338         }
339         free(newrom);
340 }
341
342 static int
343 fw_busreset(struct fwohci_softc *sc)
344 {
345         int count;
346
347         if (sc->state < FWOHCI_STATE_ENABLED) {
348                 printf("fwohci not enabled\n");
349                 return(CMD_OK);
350         }
351         fw_crom(sc);
352         fwohci_ibr(sc);
353         count = 0;
354         while (sc->state< FWOHCI_STATE_NORMAL) {
355                 fwohci_poll(sc);
356                 count ++;
357                 if (count > 1000) {
358                         printf("give up to wait bus initialize\n");
359                         return (-1);
360                 }
361         }
362         printf("poll count = %d\n", count);
363         return (0);
364 }
365
366 void
367 fw_enable(void)
368 {
369         struct fwohci_softc *sc;
370         int i;
371
372         if (fw_initialized == 0)
373                 fw_init();
374
375         for (i = 0; i < MAX_OHCI; i ++) {
376                 sc = &fwinfo[i];
377                 if (sc->state != FWOHCI_STATE_INIT)
378                         break;
379
380                 sc->config_rom = (uint32_t *)
381                         (((uint32_t)sc->config_rom_buf
382                                 + (CROMSIZE - 1)) & ~(CROMSIZE - 1));
383 #if 0
384                 printf("configrom: %08p %08p\n",
385                         sc->config_rom_buf, sc->config_rom);
386 #endif
387                 if (fwohci_init(sc, 0) == 0) {
388                         sc->state = FWOHCI_STATE_ENABLED;
389                         fw_busreset(sc);
390                 } else
391                         sc->state = FWOHCI_STATE_DEAD;
392         }
393 }
394
395 void
396 fw_poll(void)
397 {
398         struct fwohci_softc *sc;
399         int i;
400
401         if (fw_initialized == 0)
402                 return;
403
404         for (i = 0; i < MAX_OHCI; i ++) {
405                 sc = &fwinfo[i];
406                 if (sc->state < FWOHCI_STATE_ENABLED)
407                         break;
408                 fwohci_poll(sc);
409         }
410 }
411
412 #if 0 /* for debug */
413 static int
414 fw_busreset_cmd(int argc, char *argv[])
415 {
416         struct fwohci_softc *sc;
417         int i;
418
419         for (i = 0; i < MAX_OHCI; i ++) {
420                 sc = &fwinfo[i];
421                 if (sc->state < FWOHCI_STATE_INIT)
422                         break;
423                 fw_busreset(sc);
424         }
425         return(CMD_OK);
426 }
427
428 static int
429 fw_poll_cmd(int argc, char *argv[])
430 {
431         fw_poll();
432         return(CMD_OK);
433 }
434
435 static int
436 fw_enable_cmd(int argc, char *argv[])
437 {
438         fw_print(0);
439         fw_enable();
440         return(CMD_OK);
441 }
442
443
444 static int
445 dcons_enable(int argc, char *argv[])
446 {
447         dconsole.c_init(0);
448         fw_enable();
449         dconsole.c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
450         return(CMD_OK);
451 }
452
453 static int
454 dcons_read(int argc, char *argv[])
455 {
456         char c;
457         while (dconsole.c_ready()) {
458                 c = dconsole.c_in();
459                 printf("%c", c);
460         }
461         printf("\r\n");
462         return(CMD_OK);
463 }
464
465 static int
466 dcons_write(int argc, char *argv[])
467 {
468         int len, i;
469         if (argc < 2)
470                 return(CMD_OK);
471
472         len = strlen(argv[1]);
473         for (i = 0; i < len; i ++)
474                 dconsole.c_out(argv[1][i]);
475         dconsole.c_out('\r');
476         dconsole.c_out('\n');
477         return(CMD_OK);
478 }
479 COMMAND_SET(firewire, "firewire", "enable firewire", fw_enable_cmd);
480 COMMAND_SET(fwbusreset, "fwbusreset", "firewire busreset", fw_busreset_cmd);
481 COMMAND_SET(fwpoll, "fwpoll", "firewire poll", fw_poll_cmd);
482 COMMAND_SET(dcons, "dcons", "enable dcons", dcons_enable);
483 COMMAND_SET(dread, "dread", "read from dcons", dcons_read);
484 COMMAND_SET(dwrite, "dwrite", "write to dcons", dcons_write);
485 #endif