1139749Simp/*- 2121468Ssimokawa * Copyright (C) 2003 3121468Ssimokawa * Hidetoshi Shimokawa. All rights reserved. 4121468Ssimokawa * 5121468Ssimokawa * Redistribution and use in source and binary forms, with or without 6121468Ssimokawa * modification, are permitted provided that the following conditions 7121468Ssimokawa * are met: 8121468Ssimokawa * 1. Redistributions of source code must retain the above copyright 9121468Ssimokawa * notice, this list of conditions and the following disclaimer. 10121468Ssimokawa * 2. Redistributions in binary form must reproduce the above copyright 11121468Ssimokawa * notice, this list of conditions and the following disclaimer in the 12121468Ssimokawa * documentation and/or other materials provided with the distribution. 13121468Ssimokawa * 3. All advertising materials mentioning features or use of this software 14121468Ssimokawa * must display the following acknowledgement: 15121468Ssimokawa * 16121468Ssimokawa * This product includes software developed by Hidetoshi Shimokawa. 17121468Ssimokawa * 18121468Ssimokawa * 4. Neither the name of the author nor the names of its contributors 19121468Ssimokawa * may be used to endorse or promote products derived from this software 20121468Ssimokawa * without specific prior written permission. 21121468Ssimokawa * 22121468Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23121468Ssimokawa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24121468Ssimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25121468Ssimokawa * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26121468Ssimokawa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27121468Ssimokawa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28121468Ssimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29121468Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30121468Ssimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31121468Ssimokawa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32121468Ssimokawa * SUCH DAMAGE. 33121468Ssimokawa * 34121468Ssimokawa * $Id: dcons_crom.c,v 1.8 2003/10/23 15:47:21 simokawa Exp $ 35121468Ssimokawa * $FreeBSD$ 36121468Ssimokawa */ 37121468Ssimokawa 38121468Ssimokawa#include <sys/param.h> 39121468Ssimokawa#include <sys/kernel.h> 40129879Sphk#include <sys/module.h> 41121468Ssimokawa#include <sys/systm.h> 42121468Ssimokawa#include <sys/types.h> 43121468Ssimokawa#include <sys/conf.h> 44121468Ssimokawa#include <sys/malloc.h> 45121468Ssimokawa 46121468Ssimokawa#include <sys/bus.h> 47121468Ssimokawa#include <machine/bus.h> 48121468Ssimokawa 49121468Ssimokawa#include <dev/firewire/firewire.h> 50121468Ssimokawa#include <dev/firewire/firewirereg.h> 51121468Ssimokawa#include <dev/firewire/iec13213.h> 52121468Ssimokawa#include <dev/dcons/dcons.h> 53136467Ssimokawa#include <dev/dcons/dcons_os.h> 54121468Ssimokawa 55125862Ssimokawa#include <sys/cons.h> 56125862Ssimokawa 57277505Swill#if (defined(__i386__) || defined(__amd64__)) 58170420Ssimokawa#include <vm/vm.h> 59170420Ssimokawa#include <vm/vm_param.h> 60170420Ssimokawa#include <vm/pmap.h> 61170420Ssimokawa#include <machine/segments.h> /* for idt */ 62170420Ssimokawa#endif 63277505Swill 64121468Ssimokawastatic bus_addr_t dcons_paddr; 65121468Ssimokawa 66170018Ssimokawastatic int force_console = 0; 67125862SsimokawaTUNABLE_INT("hw.firewire.dcons_crom.force_console", &force_console); 68125862Ssimokawa 69121468Ssimokawa#define ADDR_HI(x) (((x) >> 24) & 0xffffff) 70121468Ssimokawa#define ADDR_LO(x) ((x) & 0xffffff) 71121468Ssimokawa 72121468Ssimokawastruct dcons_crom_softc { 73121468Ssimokawa struct firewire_dev_comm fd; 74121468Ssimokawa struct crom_chunk unit; 75121468Ssimokawa struct crom_chunk spec; 76121468Ssimokawa struct crom_chunk ver; 77121468Ssimokawa bus_dma_tag_t dma_tag; 78121468Ssimokawa bus_dmamap_t dma_map; 79121468Ssimokawa bus_addr_t bus_addr; 80170408Ssimokawa eventhandler_tag ehand; 81121468Ssimokawa}; 82121468Ssimokawa 83121468Ssimokawastatic void 84121468Ssimokawadcons_crom_identify(driver_t *driver, device_t parent) 85121468Ssimokawa{ 86121468Ssimokawa BUS_ADD_CHILD(parent, 0, "dcons_crom", device_get_unit(parent)); 87121468Ssimokawa} 88121468Ssimokawa 89121468Ssimokawastatic int 90121468Ssimokawadcons_crom_probe(device_t dev) 91121468Ssimokawa{ 92121468Ssimokawa device_t pa; 93121468Ssimokawa 94121468Ssimokawa pa = device_get_parent(dev); 95121468Ssimokawa if(device_get_unit(dev) != device_get_unit(pa)){ 96121468Ssimokawa return(ENXIO); 97121468Ssimokawa } 98121468Ssimokawa 99121468Ssimokawa device_set_desc(dev, "dcons configuration ROM"); 100121468Ssimokawa return (0); 101121468Ssimokawa} 102121468Ssimokawa 103277505Swill#if (defined(__i386__) || defined(__amd64__)) 104121468Ssimokawastatic void 105170420Ssimokawadcons_crom_expose_idt(struct dcons_crom_softc *sc) 106170420Ssimokawa{ 107170420Ssimokawa static off_t idt_paddr; 108170420Ssimokawa 109170420Ssimokawa /* XXX */ 110170420Ssimokawa idt_paddr = (char *)idt - (char *)KERNBASE; 111170420Ssimokawa 112170420Ssimokawa crom_add_entry(&sc->unit, DCONS_CSR_KEY_RESET_HI, ADDR_HI(idt_paddr)); 113170420Ssimokawa crom_add_entry(&sc->unit, DCONS_CSR_KEY_RESET_LO, ADDR_LO(idt_paddr)); 114170420Ssimokawa} 115170420Ssimokawa#endif 116277505Swill 117170420Ssimokawastatic void 118121468Ssimokawadcons_crom_post_busreset(void *arg) 119121468Ssimokawa{ 120121468Ssimokawa struct dcons_crom_softc *sc; 121121468Ssimokawa struct crom_src *src; 122121468Ssimokawa struct crom_chunk *root; 123121468Ssimokawa 124121468Ssimokawa sc = (struct dcons_crom_softc *) arg; 125121468Ssimokawa src = sc->fd.fc->crom_src; 126121468Ssimokawa root = sc->fd.fc->crom_root; 127121468Ssimokawa 128121468Ssimokawa bzero(&sc->unit, sizeof(struct crom_chunk)); 129121468Ssimokawa 130121468Ssimokawa crom_add_chunk(src, root, &sc->unit, CROM_UDIR); 131121468Ssimokawa crom_add_entry(&sc->unit, CSRKEY_SPEC, CSRVAL_VENDOR_PRIVATE); 132121468Ssimokawa crom_add_simple_text(src, &sc->unit, &sc->spec, "FreeBSD"); 133121468Ssimokawa crom_add_entry(&sc->unit, CSRKEY_VER, DCONS_CSR_VAL_VER); 134121468Ssimokawa crom_add_simple_text(src, &sc->unit, &sc->ver, "dcons"); 135121468Ssimokawa crom_add_entry(&sc->unit, DCONS_CSR_KEY_HI, ADDR_HI(dcons_paddr)); 136121468Ssimokawa crom_add_entry(&sc->unit, DCONS_CSR_KEY_LO, ADDR_LO(dcons_paddr)); 137277505Swill#if (defined(__i386__) || defined(__amd64__)) 138170420Ssimokawa dcons_crom_expose_idt(sc); 139170420Ssimokawa#endif 140121468Ssimokawa} 141121468Ssimokawa 142121468Ssimokawastatic void 143121468Ssimokawadmamap_cb(void *arg, bus_dma_segment_t *segments, int seg, int error) 144121468Ssimokawa{ 145122310Ssimokawa struct dcons_crom_softc *sc; 146121468Ssimokawa 147121468Ssimokawa if (error) 148121468Ssimokawa printf("dcons_dmamap_cb: error=%d\n", error); 149121468Ssimokawa 150122310Ssimokawa sc = (struct dcons_crom_softc *)arg; 151122310Ssimokawa sc->bus_addr = segments[0].ds_addr; 152122310Ssimokawa 153122310Ssimokawa bus_dmamap_sync(sc->dma_tag, sc->dma_map, BUS_DMASYNC_PREWRITE); 154122310Ssimokawa device_printf(sc->fd.dev, 155122310Ssimokawa "bus_addr 0x%jx\n", (uintmax_t)sc->bus_addr); 156122310Ssimokawa if (dcons_paddr != 0) { 157122310Ssimokawa /* XXX */ 158122310Ssimokawa device_printf(sc->fd.dev, "dcons_paddr is already set\n"); 159122310Ssimokawa return; 160122310Ssimokawa } 161125862Ssimokawa dcons_conf->dma_tag = sc->dma_tag; 162125862Ssimokawa dcons_conf->dma_map = sc->dma_map; 163122310Ssimokawa dcons_paddr = sc->bus_addr; 164125862Ssimokawa 165125862Ssimokawa /* Force to be the high-level console */ 166125862Ssimokawa if (force_console) 167125862Ssimokawa cnselect(dcons_conf->cdev); 168121468Ssimokawa} 169121468Ssimokawa 170170408Ssimokawastatic void 171170408Ssimokawadcons_crom_poll(void *p, int arg) 172170408Ssimokawa{ 173170408Ssimokawa struct dcons_crom_softc *sc = (struct dcons_crom_softc *) p; 174170408Ssimokawa 175170408Ssimokawa sc->fd.fc->poll(sc->fd.fc, -1, -1); 176170408Ssimokawa} 177170408Ssimokawa 178121468Ssimokawastatic int 179121468Ssimokawadcons_crom_attach(device_t dev) 180121468Ssimokawa{ 181121468Ssimokawa struct dcons_crom_softc *sc; 182186876Smarius int error; 183121468Ssimokawa 184186876Smarius if (dcons_conf->buf == NULL) 185186876Smarius return (ENXIO); 186121468Ssimokawa sc = (struct dcons_crom_softc *) device_get_softc(dev); 187121468Ssimokawa sc->fd.fc = device_get_ivars(dev); 188121468Ssimokawa sc->fd.dev = dev; 189121468Ssimokawa sc->fd.post_explore = NULL; 190121468Ssimokawa sc->fd.post_busreset = (void *) dcons_crom_post_busreset; 191121468Ssimokawa 192121468Ssimokawa /* map dcons buffer */ 193186876Smarius error = bus_dma_tag_create( 194121468Ssimokawa /*parent*/ sc->fd.fc->dmat, 195121468Ssimokawa /*alignment*/ sizeof(u_int32_t), 196121468Ssimokawa /*boundary*/ 0, 197121468Ssimokawa /*lowaddr*/ BUS_SPACE_MAXADDR, 198121468Ssimokawa /*highaddr*/ BUS_SPACE_MAXADDR, 199121468Ssimokawa /*filter*/NULL, /*filterarg*/NULL, 200125862Ssimokawa /*maxsize*/ dcons_conf->size, 201121468Ssimokawa /*nsegments*/ 1, 202121468Ssimokawa /*maxsegsz*/ BUS_SPACE_MAXSIZE_32BIT, 203121468Ssimokawa /*flags*/ BUS_DMA_ALLOCNOW, 204121468Ssimokawa /*lockfunc*/busdma_lock_mutex, 205121468Ssimokawa /*lockarg*/&Giant, 206121468Ssimokawa &sc->dma_tag); 207186876Smarius if (error != 0) 208186876Smarius return (error); 209186876Smarius error = bus_dmamap_create(sc->dma_tag, BUS_DMA_COHERENT, &sc->dma_map); 210186876Smarius if (error != 0) 211186876Smarius return (error); 212186876Smarius error = bus_dmamap_load(sc->dma_tag, sc->dma_map, 213125862Ssimokawa (void *)dcons_conf->buf, dcons_conf->size, 214122310Ssimokawa dmamap_cb, sc, 0); 215186876Smarius if (error != 0) 216186876Smarius return (error); 217170408Ssimokawa sc->ehand = EVENTHANDLER_REGISTER(dcons_poll, dcons_crom_poll, 218170408Ssimokawa (void *)sc, 0); 219121468Ssimokawa return (0); 220121468Ssimokawa} 221121468Ssimokawa 222121468Ssimokawastatic int 223121468Ssimokawadcons_crom_detach(device_t dev) 224121468Ssimokawa{ 225121468Ssimokawa struct dcons_crom_softc *sc; 226121468Ssimokawa 227121468Ssimokawa sc = (struct dcons_crom_softc *) device_get_softc(dev); 228121468Ssimokawa sc->fd.post_busreset = NULL; 229121468Ssimokawa 230170408Ssimokawa if (sc->ehand) 231170408Ssimokawa EVENTHANDLER_DEREGISTER(dcons_poll, sc->ehand); 232170408Ssimokawa 233121468Ssimokawa /* XXX */ 234125862Ssimokawa if (dcons_conf->dma_tag == sc->dma_tag) 235125862Ssimokawa dcons_conf->dma_tag = NULL; 236121468Ssimokawa 237121468Ssimokawa bus_dmamap_unload(sc->dma_tag, sc->dma_map); 238121468Ssimokawa bus_dmamap_destroy(sc->dma_tag, sc->dma_map); 239121468Ssimokawa bus_dma_tag_destroy(sc->dma_tag); 240121468Ssimokawa 241121468Ssimokawa return 0; 242121468Ssimokawa} 243121468Ssimokawa 244121468Ssimokawastatic devclass_t dcons_crom_devclass; 245121468Ssimokawa 246121468Ssimokawastatic device_method_t dcons_crom_methods[] = { 247121468Ssimokawa /* device interface */ 248121468Ssimokawa DEVMETHOD(device_identify, dcons_crom_identify), 249121468Ssimokawa DEVMETHOD(device_probe, dcons_crom_probe), 250121468Ssimokawa DEVMETHOD(device_attach, dcons_crom_attach), 251121468Ssimokawa DEVMETHOD(device_detach, dcons_crom_detach), 252121468Ssimokawa { 0, 0 } 253121468Ssimokawa}; 254121468Ssimokawa 255121468Ssimokawastatic driver_t dcons_crom_driver = { 256121468Ssimokawa "dcons_crom", 257121468Ssimokawa dcons_crom_methods, 258121468Ssimokawa sizeof(struct dcons_crom_softc), 259121468Ssimokawa}; 260121468Ssimokawa 261121468SsimokawaDRIVER_MODULE(dcons_crom, firewire, dcons_crom_driver, 262121468Ssimokawa dcons_crom_devclass, 0, 0); 263121468SsimokawaMODULE_VERSION(dcons_crom, 1); 264121468SsimokawaMODULE_DEPEND(dcons_crom, dcons, 265121468Ssimokawa DCONS_VERSION, DCONS_VERSION, DCONS_VERSION); 266121468SsimokawaMODULE_DEPEND(dcons_crom, firewire, 1, 1, 1); 267