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