firewire.c revision 329183
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 329183 2018-02-12 20:51:28Z 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 "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
53extern uint32_t dcons_paddr;
54extern struct console dconsole;
55
56struct 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
67static int	fw_init(void);
68static int	fw_strategy(void *devdata, int flag, daddr_t dblk,
69		    size_t size, char *buf, size_t *rsize);
70static int	fw_open(struct open_file *f, ...);
71static int	fw_close(struct open_file *f);
72static int	fw_print(int verbose);
73static void	fw_cleanup(void);
74
75void		fw_enable(void);
76
77struct 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
89static struct fwohci_softc fwinfo[MAX_OHCI];
90static int fw_initialized = 0;
91
92static void
93fw_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		BIOSPCI_16BITS);
112
113	biospci_read_config(sc->locator, 0x00 /*devid*/, BIOSPCI_32BITS,
114		&sc->devid);
115	biospci_read_config(sc->locator, 0x10 /*base_addr*/, BIOSPCI_32BITS,
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
124static int
125fw_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 */
151static int
152fw_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
177static int
178fw_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
194static int
195fw_close(struct open_file *f)
196{
197    return (0);
198}
199
200static void
201fw_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
212static int
213fw_strategy(void *devdata, int rw, daddr_t dblk, size_t size,
214    char *buf, size_t *rsize)
215{
216	return (EIO);
217}
218
219static void
220fw_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
259static void
260fw_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
292static void
293dcons_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
314void
315fw_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
341static int
342fw_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
365void
366fw_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
394void
395fw_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 */
412static int
413fw_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
427static int
428fw_poll_cmd(int argc, char *argv[])
429{
430	fw_poll();
431	return(CMD_OK);
432}
433
434static int
435fw_enable_cmd(int argc, char *argv[])
436{
437	fw_print(0);
438	fw_enable();
439	return(CMD_OK);
440}
441
442
443static int
444dcons_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
452static int
453dcons_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
464static int
465dcons_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}
478COMMAND_SET(firewire, "firewire", "enable firewire", fw_enable_cmd);
479COMMAND_SET(fwbusreset, "fwbusreset", "firewire busreset", fw_busreset_cmd);
480COMMAND_SET(fwpoll, "fwpoll", "firewire poll", fw_poll_cmd);
481COMMAND_SET(dcons, "dcons", "enable dcons", dcons_enable);
482COMMAND_SET(dread, "dread", "read from dcons", dcons_read);
483COMMAND_SET(dwrite, "dwrite", "write to dcons", dcons_write);
484#endif
485