firewire.c revision 346476
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: stable/11/stand/i386/libfirewire/firewire.c 346476 2019-04-21 03:36:05Z kevans $");
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
54extern uint32_t dcons_paddr;
55extern struct console dconsole;
56
57struct 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
68static int	fw_init(void);
69static int	fw_strategy(void *devdata, int flag, daddr_t dblk,
70		    size_t size, char *buf, size_t *rsize);
71static int	fw_open(struct open_file *f, ...);
72static int	fw_close(struct open_file *f);
73static int	fw_print(int verbose);
74static void	fw_cleanup(void);
75
76void		fw_enable(void);
77
78struct 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
90static struct fwohci_softc fwinfo[MAX_OHCI];
91static int fw_initialized = 0;
92
93static void
94fw_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
125static int
126fw_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 */
152static int
153fw_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
178static int
179fw_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
195static int
196fw_close(struct open_file *f)
197{
198    return (0);
199}
200
201static void
202fw_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
213static int
214fw_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
215    char *buf, size_t *rsize)
216{
217	return (EIO);
218}
219
220static void
221fw_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
260static void
261fw_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
293static void
294dcons_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
315void
316fw_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
342static int
343fw_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
366void
367fw_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
395void
396fw_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 */
413static int
414fw_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
428static int
429fw_poll_cmd(int argc, char *argv[])
430{
431	fw_poll();
432	return(CMD_OK);
433}
434
435static int
436fw_enable_cmd(int argc, char *argv[])
437{
438	fw_print(0);
439	fw_enable();
440	return(CMD_OK);
441}
442
443
444static int
445dcons_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
453static int
454dcons_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
465static int
466dcons_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}
479COMMAND_SET(firewire, "firewire", "enable firewire", fw_enable_cmd);
480COMMAND_SET(fwbusreset, "fwbusreset", "firewire busreset", fw_busreset_cmd);
481COMMAND_SET(fwpoll, "fwpoll", "firewire poll", fw_poll_cmd);
482COMMAND_SET(dcons, "dcons", "enable dcons", dcons_enable);
483COMMAND_SET(dread, "dread", "read from dcons", dcons_read);
484COMMAND_SET(dwrite, "dwrite", "write to dcons", dcons_write);
485#endif
486