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