sbbc.c revision 206453
1206451Smarius/* $OpenBSD: sbbc.c,v 1.7 2009/11/09 17:53:39 nicm Exp $ */ 2206453Smarius/*- 3206451Smarius * Copyright (c) 2008 Mark Kettenis 4206451Smarius * 5206451Smarius * Permission to use, copy, modify, and distribute this software for any 6206451Smarius * purpose with or without fee is hereby granted, provided that the above 7206451Smarius * copyright notice and this permission notice appear in all copies. 8206451Smarius * 9206451Smarius * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10206451Smarius * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11206451Smarius * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12206451Smarius * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13206451Smarius * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14206451Smarius * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15206451Smarius * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16206451Smarius */ 17206451Smarius/*- 18206451Smarius * Copyright (c) 2010 Marius Strobl <marius@FreeBSD.org> 19206451Smarius * All rights reserved. 20206451Smarius * 21206451Smarius * Redistribution and use in source and binary forms, with or without 22206451Smarius * modification, are permitted provided that the following conditions 23206451Smarius * are met: 24206451Smarius * 1. Redistributions of source code must retain the above copyright 25206451Smarius * notice, this list of conditions and the following disclaimer. 26206451Smarius * 2. Redistributions in binary form must reproduce the above copyright 27206451Smarius * notice, this list of conditions and the following disclaimer in the 28206451Smarius * documentation and/or other materials provided with the distribution. 29206451Smarius * 30206451Smarius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 31206451Smarius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32206451Smarius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33206451Smarius * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 34206451Smarius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35206451Smarius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36206451Smarius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37206451Smarius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38206451Smarius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39206451Smarius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40206451Smarius * SUCH DAMAGE. 41206451Smarius */ 42206451Smarius 43206451Smarius#include <sys/cdefs.h> 44206451Smarius__FBSDID("$FreeBSD: head/sys/sparc64/pci/sbbc.c 206453 2010-04-10 12:10:11Z marius $"); 45206451Smarius 46206451Smarius#include <sys/param.h> 47206451Smarius#include <sys/systm.h> 48206451Smarius#include <sys/bus.h> 49206451Smarius#include <sys/clock.h> 50206451Smarius#include <sys/endian.h> 51206451Smarius#include <sys/kernel.h> 52206451Smarius#include <sys/lock.h> 53206451Smarius#include <sys/module.h> 54206451Smarius#include <sys/mutex.h> 55206451Smarius#include <sys/resource.h> 56206451Smarius#include <sys/rman.h> 57206451Smarius 58206451Smarius#include <dev/ofw/ofw_bus.h> 59206451Smarius#include <dev/ofw/openfirm.h> 60206451Smarius 61206451Smarius#include <machine/bus.h> 62206451Smarius#include <machine/cpu.h> 63206451Smarius#include <machine/resource.h> 64206451Smarius 65206451Smarius#include <dev/pci/pcireg.h> 66206451Smarius#include <dev/pci/pcivar.h> 67206451Smarius#include <dev/uart/uart.h> 68206451Smarius#include <dev/uart/uart_cpu.h> 69206451Smarius#include <dev/uart/uart_bus.h> 70206451Smarius 71206451Smarius#include "clock_if.h" 72206451Smarius#include "uart_if.h" 73206451Smarius 74206451Smarius#define SBBC_PCI_BAR PCIR_BAR(0) 75206451Smarius#define SBBC_PCI_VENDOR 0x108e 76206451Smarius#define SBBC_PCI_PRODUCT 0xc416 77206451Smarius 78206451Smarius#define SBBC_REGS_OFFSET 0x800000 79206451Smarius#define SBBC_REGS_SIZE 0x6230 80206451Smarius#define SBBC_EPLD_OFFSET 0x8e0000 81206451Smarius#define SBBC_EPLD_SIZE 0x20 82206451Smarius#define SBBC_SRAM_OFFSET 0x900000 83206451Smarius#define SBBC_SRAM_SIZE 0x20000 /* 128KB SRAM */ 84206451Smarius 85206451Smarius#define SBBC_PCI_INT_STATUS 0x2320 86206451Smarius#define SBBC_PCI_INT_ENABLE 0x2330 87206451Smarius#define SBBC_PCI_ENABLE_INT_A 0x11 88206451Smarius 89206451Smarius#define SBBC_EPLD_INTERRUPT 0x13 90206451Smarius#define SBBC_EPLD_INTERRUPT_ON 0x01 91206451Smarius 92206451Smarius#define SBBC_SRAM_CONS_IN 0x00000001 93206451Smarius#define SBBC_SRAM_CONS_OUT 0x00000002 94206451Smarius#define SBBC_SRAM_CONS_BRK 0x00000004 95206451Smarius#define SBBC_SRAM_CONS_SPACE_IN 0x00000008 96206451Smarius#define SBBC_SRAM_CONS_SPACE_OUT 0x00000010 97206451Smarius 98206451Smarius#define SBBC_TAG_KEY_SIZE 8 99206451Smarius#define SBBC_TAG_KEY_SCSOLIE "SCSOLIE" /* SC -> OS int. enable */ 100206451Smarius#define SBBC_TAG_KEY_SCSOLIR "SCSOLIR" /* SC -> OS int. reason */ 101206451Smarius#define SBBC_TAG_KEY_SOLCONS "SOLCONS" /* OS console buffer */ 102206451Smarius#define SBBC_TAG_KEY_SOLSCIE "SOLSCIE" /* OS -> SC int. enable */ 103206451Smarius#define SBBC_TAG_KEY_SOLSCIR "SOLSCIR" /* OS -> SC int. reason */ 104206451Smarius#define SBBC_TAG_KEY_TODDATA "TODDATA" /* OS TOD struct */ 105206451Smarius#define SBBC_TAG_OFF(x) offsetof(struct sbbc_sram_tag, x) 106206451Smarius 107206451Smariusstruct sbbc_sram_tag { 108206451Smarius char tag_key[SBBC_TAG_KEY_SIZE]; 109206451Smarius uint32_t tag_size; 110206451Smarius uint32_t tag_offset; 111206451Smarius} __packed; 112206451Smarius 113206451Smarius#define SBBC_TOC_MAGIC "TOCSRAM" 114206451Smarius#define SBBC_TOC_MAGIC_SIZE 8 115206451Smarius#define SBBC_TOC_TAGS_MAX 32 116206451Smarius#define SBBC_TOC_OFF(x) offsetof(struct sbbc_sram_toc, x) 117206451Smarius 118206451Smariusstruct sbbc_sram_toc { 119206451Smarius char toc_magic[SBBC_TOC_MAGIC_SIZE]; 120206451Smarius uint8_t toc_reserved; 121206451Smarius uint8_t toc_type; 122206451Smarius uint16_t toc_version; 123206451Smarius uint32_t toc_ntags; 124206451Smarius struct sbbc_sram_tag toc_tag[SBBC_TOC_TAGS_MAX]; 125206451Smarius} __packed; 126206451Smarius 127206451Smarius#define SBBC_TOD_MAGIC 0x54443100 /* "TD1" */ 128206451Smarius#define SBBC_TOD_VERSION 1 129206451Smarius#define SBBC_TOD_OFF(x) offsetof(struct sbbc_sram_tod, x) 130206451Smarius 131206451Smariusstruct sbbc_sram_tod { 132206451Smarius uint32_t tod_magic; 133206451Smarius uint32_t tod_version; 134206451Smarius uint64_t tod_time; 135206451Smarius uint64_t tod_skew; 136206451Smarius uint32_t tod_reserved; 137206451Smarius uint32_t tod_heartbeat; 138206451Smarius uint32_t tod_timeout; 139206451Smarius} __packed; 140206451Smarius 141206451Smarius#define SBBC_CONS_MAGIC 0x434f4e00 /* "CON" */ 142206451Smarius#define SBBC_CONS_VERSION 1 143206451Smarius#define SBBC_CONS_OFF(x) offsetof(struct sbbc_sram_cons, x) 144206451Smarius 145206451Smariusstruct sbbc_sram_cons { 146206451Smarius uint32_t cons_magic; 147206451Smarius uint32_t cons_version; 148206451Smarius uint32_t cons_size; 149206451Smarius 150206451Smarius uint32_t cons_in_begin; 151206451Smarius uint32_t cons_in_end; 152206451Smarius uint32_t cons_in_rdptr; 153206451Smarius uint32_t cons_in_wrptr; 154206451Smarius 155206451Smarius uint32_t cons_out_begin; 156206451Smarius uint32_t cons_out_end; 157206451Smarius uint32_t cons_out_rdptr; 158206451Smarius uint32_t cons_out_wrptr; 159206451Smarius} __packed; 160206451Smarius 161206451Smariusstruct sbbc_softc { 162206451Smarius struct resource *sc_res; 163206451Smarius}; 164206451Smarius 165206451Smarius#define SBBC_READ_N(wdth, offs) \ 166206451Smarius bus_space_read_ ## wdth((bst), (bsh), (offs)) 167206451Smarius#define SBBC_WRITE_N(wdth, offs, val) \ 168206451Smarius bus_space_write_ ## wdth((bst), (bsh), (offs), (val)) 169206451Smarius 170206451Smarius#define SBBC_READ_1(offs) \ 171206451Smarius SBBC_READ_N(1, (offs)) 172206451Smarius#define SBBC_READ_2(offs) \ 173206451Smarius bswap16(SBBC_READ_N(2, (offs))) 174206451Smarius#define SBBC_READ_4(offs) \ 175206451Smarius bswap32(SBBC_READ_N(4, (offs))) 176206451Smarius#define SBBC_READ_8(offs) \ 177206451Smarius bswap64(SBBC_READ_N(8, (offs))) 178206451Smarius#define SBBC_WRITE_1(offs, val) \ 179206451Smarius SBBC_WRITE_N(1, (offs), (val)) 180206451Smarius#define SBBC_WRITE_2(offs, val) \ 181206451Smarius SBBC_WRITE_N(2, (offs), bswap16(val)) 182206451Smarius#define SBBC_WRITE_4(offs, val) \ 183206451Smarius SBBC_WRITE_N(4, (offs), bswap32(val)) 184206451Smarius#define SBBC_WRITE_8(offs, val) \ 185206451Smarius SBBC_WRITE_N(8, (offs), bswap64(val)) 186206451Smarius 187206451Smarius#define SBBC_REGS_READ_1(offs) \ 188206451Smarius SBBC_READ_1((offs) + SBBC_REGS_OFFSET) 189206451Smarius#define SBBC_REGS_READ_2(offs) \ 190206451Smarius SBBC_READ_2((offs) + SBBC_REGS_OFFSET) 191206451Smarius#define SBBC_REGS_READ_4(offs) \ 192206451Smarius SBBC_READ_4((offs) + SBBC_REGS_OFFSET) 193206451Smarius#define SBBC_REGS_READ_8(offs) \ 194206451Smarius SBBC_READ_8((offs) + SBBC_REGS_OFFSET) 195206451Smarius#define SBBC_REGS_WRITE_1(offs, val) \ 196206451Smarius SBBC_WRITE_1((offs) + SBBC_REGS_OFFSET, (val)) 197206451Smarius#define SBBC_REGS_WRITE_2(offs, val) \ 198206451Smarius SBBC_WRITE_2((offs) + SBBC_REGS_OFFSET, (val)) 199206451Smarius#define SBBC_REGS_WRITE_4(offs, val) \ 200206451Smarius SBBC_WRITE_4((offs) + SBBC_REGS_OFFSET, (val)) 201206451Smarius#define SBBC_REGS_WRITE_8(offs, val) \ 202206451Smarius SBBC_WRITE_8((offs) + SBBC_REGS_OFFSET, (val)) 203206451Smarius 204206451Smarius#define SBBC_EPLD_READ_1(offs) \ 205206451Smarius SBBC_READ_1((offs) + SBBC_EPLD_OFFSET) 206206451Smarius#define SBBC_EPLD_READ_2(offs) \ 207206451Smarius SBBC_READ_2((offs) + SBBC_EPLD_OFFSET) 208206451Smarius#define SBBC_EPLD_READ_4(offs) \ 209206451Smarius SBBC_READ_4((offs) + SBBC_EPLD_OFFSET) 210206451Smarius#define SBBC_EPLD_READ_8(offs) \ 211206451Smarius SBBC_READ_8((offs) + SBBC_EPLD_OFFSET) 212206451Smarius#define SBBC_EPLD_WRITE_1(offs, val) \ 213206451Smarius SBBC_WRITE_1((offs) + SBBC_EPLD_OFFSET, (val)) 214206451Smarius#define SBBC_EPLD_WRITE_2(offs, val) \ 215206451Smarius SBBC_WRITE_2((offs) + SBBC_EPLD_OFFSET, (val)) 216206451Smarius#define SBBC_EPLD_WRITE_4(offs, val) \ 217206451Smarius SBBC_WRITE_4((offs) + SBBC_EPLD_OFFSET, (val)) 218206451Smarius#define SBBC_EPLD_WRITE_8(offs, val) \ 219206451Smarius SBBC_WRITE_8((offs) + SBBC_EPLD_OFFSET, (val)) 220206451Smarius 221206451Smarius#define SBBC_SRAM_READ_1(offs) \ 222206451Smarius SBBC_READ_1((offs) + SBBC_SRAM_OFFSET) 223206451Smarius#define SBBC_SRAM_READ_2(offs) \ 224206451Smarius SBBC_READ_2((offs) + SBBC_SRAM_OFFSET) 225206451Smarius#define SBBC_SRAM_READ_4(offs) \ 226206451Smarius SBBC_READ_4((offs) + SBBC_SRAM_OFFSET) 227206451Smarius#define SBBC_SRAM_READ_8(offs) \ 228206451Smarius SBBC_READ_8((offs) + SBBC_SRAM_OFFSET) 229206451Smarius#define SBBC_SRAM_WRITE_1(offs, val) \ 230206451Smarius SBBC_WRITE_1((offs) + SBBC_SRAM_OFFSET, (val)) 231206451Smarius#define SBBC_SRAM_WRITE_2(offs, val) \ 232206451Smarius SBBC_WRITE_2((offs) + SBBC_SRAM_OFFSET, (val)) 233206451Smarius#define SBBC_SRAM_WRITE_4(offs, val) \ 234206451Smarius SBBC_WRITE_4((offs) + SBBC_SRAM_OFFSET, (val)) 235206451Smarius#define SBBC_SRAM_WRITE_8(offs, val) \ 236206451Smarius SBBC_WRITE_8((offs) + SBBC_SRAM_OFFSET, (val)) 237206451Smarius 238206451Smarius#define SUNW_SETCONSINPUT "SUNW,set-console-input" 239206451Smarius#define SUNW_SETCONSINPUT_CLNT "CON_CLNT" 240206451Smarius#define SUNW_SETCONSINPUT_OBP "CON_OBP" 241206451Smarius 242206451Smariusstatic u_int sbbc_console; 243206451Smarius 244206451Smariusstatic uint32_t sbbc_scsolie; 245206451Smariusstatic uint32_t sbbc_scsolir; 246206451Smariusstatic uint32_t sbbc_solcons; 247206451Smariusstatic uint32_t sbbc_solscie; 248206451Smariusstatic uint32_t sbbc_solscir; 249206451Smariusstatic uint32_t sbbc_toddata; 250206451Smarius 251206451Smarius/* 252206451Smarius * internal helpers 253206451Smarius */ 254206451Smariusstatic int sbbc_parse_toc(bus_space_tag_t bst, bus_space_handle_t bsh); 255206451Smariusstatic inline void sbbc_send_intr(bus_space_tag_t bst, 256206451Smarius bus_space_handle_t bsh); 257206451Smariusstatic const char *sbbc_serengeti_set_console_input(char *new); 258206451Smarius 259206451Smarius/* 260206451Smarius * SBBC PCI interface 261206451Smarius */ 262206451Smariusstatic bus_alloc_resource_t sbbc_bus_alloc_resource; 263206451Smariusstatic bus_release_resource_t sbbc_bus_release_resource; 264206451Smariusstatic bus_get_resource_list_t sbbc_bus_get_resource_list; 265206451Smariusstatic bus_setup_intr_t sbbc_bus_setup_intr; 266206451Smariusstatic bus_teardown_intr_t sbbc_bus_teardown_intr; 267206451Smarius 268206451Smariusstatic device_attach_t sbbc_pci_attach; 269206451Smariusstatic device_probe_t sbbc_pci_probe; 270206451Smarius 271206451Smariusstatic clock_gettime_t sbbc_tod_gettime; 272206451Smariusstatic clock_settime_t sbbc_tod_settime; 273206451Smarius 274206451Smariusstatic device_method_t sbbc_pci_methods[] = { 275206451Smarius /* Device interface */ 276206451Smarius DEVMETHOD(device_probe, sbbc_pci_probe), 277206451Smarius DEVMETHOD(device_attach, sbbc_pci_attach), 278206451Smarius 279206451Smarius DEVMETHOD(bus_print_child, bus_generic_print_child), 280206451Smarius DEVMETHOD(bus_alloc_resource, sbbc_bus_alloc_resource), 281206451Smarius DEVMETHOD(bus_release_resource, sbbc_bus_release_resource), 282206451Smarius DEVMETHOD(bus_setup_intr, sbbc_bus_setup_intr), 283206451Smarius DEVMETHOD(bus_teardown_intr, sbbc_bus_teardown_intr), 284206451Smarius DEVMETHOD(bus_get_resource_list, sbbc_bus_get_resource_list), 285206451Smarius 286206451Smarius /* clock interface */ 287206451Smarius DEVMETHOD(clock_gettime, sbbc_tod_gettime), 288206451Smarius DEVMETHOD(clock_settime, sbbc_tod_settime), 289206451Smarius 290206451Smarius KOBJMETHOD_END 291206451Smarius}; 292206451Smarius 293206451Smariusstatic devclass_t sbbc_devclass; 294206451Smarius 295206451SmariusDEFINE_CLASS_0(sbbc, sbbc_driver, sbbc_pci_methods, sizeof(struct sbbc_softc)); 296206451SmariusDRIVER_MODULE(sbbc, pci, sbbc_driver, sbbc_devclass, 0, 0); 297206451Smarius 298206451Smariusstatic int 299206451Smariussbbc_pci_probe(device_t dev) 300206451Smarius{ 301206451Smarius 302206451Smarius if (pci_get_vendor(dev) == SBBC_PCI_VENDOR && 303206451Smarius pci_get_device(dev) == SBBC_PCI_PRODUCT) { 304206451Smarius device_set_desc(dev, "Sun BootBus controller"); 305206451Smarius return (BUS_PROBE_DEFAULT); 306206451Smarius } 307206451Smarius return (ENXIO); 308206451Smarius} 309206451Smarius 310206451Smariusstatic int 311206451Smariussbbc_pci_attach(device_t dev) 312206451Smarius{ 313206451Smarius struct sbbc_softc *sc; 314206451Smarius struct timespec ts; 315206451Smarius device_t child; 316206451Smarius bus_space_tag_t bst; 317206451Smarius bus_space_handle_t bsh; 318206451Smarius phandle_t node; 319206451Smarius int error, rid; 320206451Smarius uint32_t val; 321206451Smarius 322206451Smarius /* Nothing to to if we're not the chosen one. */ 323206451Smarius if ((node = OF_finddevice("/chosen")) == -1) { 324206451Smarius device_printf(dev, "failed to find /chosen\n"); 325206451Smarius return (ENXIO); 326206451Smarius } 327206451Smarius if (OF_getprop(node, "iosram", &node, sizeof(node)) == -1) { 328206451Smarius device_printf(dev, "failed to get iosram\n"); 329206451Smarius return (ENXIO); 330206451Smarius } 331206451Smarius if (node != ofw_bus_get_node(dev)) 332206451Smarius return (0); 333206451Smarius 334206451Smarius sc = device_get_softc(dev); 335206451Smarius rid = SBBC_PCI_BAR; 336206451Smarius /* 337206451Smarius * Note that we don't activate the resource so it's not mapped twice 338206451Smarius * but only once by the the firmware. 339206451Smarius */ 340206451Smarius sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 0); 341206451Smarius if (sc->sc_res == NULL) { 342206451Smarius device_printf(dev, "failed to allocate resources\n"); 343206451Smarius return (ENXIO); 344206451Smarius } 345206451Smarius bst = rman_get_bustag(sc->sc_res); 346206451Smarius bsh = rman_get_bushandle(sc->sc_res); 347206451Smarius if (sbbc_console != 0) { 348206451Smarius /* Once again the interrupt pin isn't set. */ 349206451Smarius if (pci_get_intpin(dev) == 0) 350206451Smarius pci_set_intpin(dev, 1); 351206451Smarius child = device_add_child(dev, NULL, -1); 352206451Smarius if (child == NULL) 353206451Smarius device_printf(dev, "failed to add UART device\n"); 354206451Smarius error = bus_generic_attach(dev); 355206451Smarius if (error != 0) 356206451Smarius device_printf(dev, "failed to attach UART device\n"); 357206451Smarius } else { 358206451Smarius error = sbbc_parse_toc(rman_get_bustag(sc->sc_res), 359206451Smarius rman_get_bushandle(sc->sc_res)); 360206451Smarius if (error != 0) { 361206451Smarius device_printf(dev, "failed to parse TOC\n"); 362206451Smarius if (sbbc_console != 0) { 363206451Smarius bus_release_resource(dev, SYS_RES_MEMORY, rid, 364206451Smarius sc->sc_res); 365206451Smarius return (error); 366206451Smarius } 367206451Smarius } 368206451Smarius } 369206451Smarius if (sbbc_toddata != 0) { 370206451Smarius if ((val = SBBC_SRAM_READ_4(sbbc_toddata + 371206451Smarius SBBC_TOD_OFF(tod_magic))) != SBBC_TOD_MAGIC) 372206451Smarius device_printf(dev, "invalid TOD magic %#x\n", val); 373206451Smarius else if ((val = SBBC_SRAM_READ_4(sbbc_toddata + 374206451Smarius SBBC_TOD_OFF(tod_version))) < SBBC_TOD_VERSION) 375206451Smarius device_printf(dev, "invalid TOD version %#x\n", val); 376206451Smarius else { 377206451Smarius clock_register(dev, 1000000); /* 1 sec. resolution */ 378206451Smarius if (bootverbose) { 379206451Smarius sbbc_tod_gettime(dev, &ts); 380206451Smarius device_printf(dev, 381206451Smarius "current time: %ld.%09ld\n", 382206451Smarius (long)ts.tv_sec, ts.tv_nsec); 383206451Smarius } 384206451Smarius } 385206451Smarius } 386206451Smarius return (0); 387206451Smarius} 388206451Smarius 389206451Smarius/* 390206451Smarius * Note that the bus methods don't pass-through the uart(4) requests but act 391206451Smarius * as if they would come from sbbc(4) in order to avoid complications with 392206451Smarius * pci(4) (actually, uart(4) isn't a real child but rather a function of 393206451Smarius * sbbc(4) anyway). 394206451Smarius */ 395206451Smarius 396206451Smariusstatic struct resource * 397206451Smariussbbc_bus_alloc_resource(device_t dev, device_t child __unused, int type, 398206451Smarius int *rid, u_long start, u_long end, u_long count, u_int flags) 399206451Smarius{ 400206451Smarius struct sbbc_softc *sc; 401206451Smarius 402206451Smarius sc = device_get_softc(dev); 403206451Smarius switch (type) { 404206451Smarius case SYS_RES_IRQ: 405206451Smarius return (BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, type, 406206451Smarius rid, start, end, count, flags)); 407206451Smarius case SYS_RES_MEMORY: 408206451Smarius return (sc->sc_res); 409206451Smarius default: 410206451Smarius return (NULL); 411206451Smarius /* NOTREACHED */ 412206451Smarius } 413206451Smarius} 414206451Smarius 415206451Smariusstatic int 416206451Smariussbbc_bus_release_resource(device_t dev, device_t child __unused, int type, 417206451Smarius int rid, struct resource *res) 418206451Smarius{ 419206451Smarius 420206451Smarius if (type == SYS_RES_IRQ) 421206451Smarius return (BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, 422206451Smarius type, rid, res)); 423206451Smarius return (0); 424206451Smarius} 425206451Smarius 426206451Smariusstatic struct resource_list * 427206451Smariussbbc_bus_get_resource_list(device_t dev, device_t child __unused) 428206451Smarius{ 429206451Smarius 430206451Smarius return (BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev)); 431206451Smarius} 432206451Smarius 433206451Smariusstatic int 434206451Smariussbbc_bus_setup_intr(device_t dev, device_t child __unused, 435206451Smarius struct resource *res, int flags, driver_filter_t *filt, 436206451Smarius driver_intr_t *intr, void *arg, void **cookiep) 437206451Smarius{ 438206451Smarius 439206451Smarius return (BUS_SETUP_INTR(device_get_parent(dev), dev, res, flags, filt, 440206451Smarius intr, arg, cookiep)); 441206451Smarius} 442206451Smarius 443206451Smariusstatic int 444206451Smariussbbc_bus_teardown_intr(device_t dev, device_t child __unused, 445206451Smarius struct resource *res, void *cookie) 446206451Smarius{ 447206451Smarius 448206451Smarius return (BUS_TEARDOWN_INTR(device_get_parent(dev), dev, res, cookie)); 449206451Smarius} 450206451Smarius 451206451Smarius/* 452206451Smarius * internal helpers 453206451Smarius */ 454206451Smariusstatic int 455206451Smariussbbc_parse_toc(bus_space_tag_t bst, bus_space_handle_t bsh) 456206451Smarius{ 457206451Smarius char buf[MAX(SBBC_TAG_KEY_SIZE, SBBC_TOC_MAGIC_SIZE)]; 458206451Smarius bus_size_t tag; 459206451Smarius phandle_t node; 460206451Smarius uint32_t off, sram_toc; 461206451Smarius u_int i, tags; 462206451Smarius 463206451Smarius if ((node = OF_finddevice("/chosen")) == -1) 464206451Smarius return (ENXIO); 465206451Smarius /* SRAM TOC offset defaults to 0. */ 466206451Smarius if (OF_getprop(node, "iosram-toc", &sram_toc, sizeof(sram_toc)) <= 0) 467206451Smarius sram_toc = 0; 468206451Smarius 469206451Smarius bus_space_read_region_1(bst, bsh, SBBC_SRAM_OFFSET + sram_toc + 470206451Smarius SBBC_TOC_OFF(toc_magic), buf, SBBC_TOC_MAGIC_SIZE); 471206451Smarius buf[SBBC_TOC_MAGIC_SIZE - 1] = '\0'; 472206451Smarius if (strcmp(buf, SBBC_TOC_MAGIC) != 0) 473206451Smarius return (ENXIO); 474206451Smarius 475206451Smarius tags = SBBC_SRAM_READ_4(sram_toc + SBBC_TOC_OFF(toc_ntags)); 476206451Smarius for (i = 0; i < tags; i++) { 477206451Smarius tag = sram_toc + SBBC_TOC_OFF(toc_tag) + 478206451Smarius i * sizeof(struct sbbc_sram_tag); 479206451Smarius bus_space_read_region_1(bst, bsh, SBBC_SRAM_OFFSET + tag + 480206451Smarius SBBC_TAG_OFF(tag_key), buf, SBBC_TAG_KEY_SIZE); 481206451Smarius buf[SBBC_TAG_KEY_SIZE - 1] = '\0'; 482206451Smarius off = SBBC_SRAM_READ_4(tag + SBBC_TAG_OFF(tag_offset)); 483206451Smarius if (strcmp(buf, SBBC_TAG_KEY_SCSOLIE) == 0) 484206451Smarius sbbc_scsolie = off; 485206451Smarius else if (strcmp(buf, SBBC_TAG_KEY_SCSOLIR) == 0) 486206451Smarius sbbc_scsolir = off; 487206451Smarius else if (strcmp(buf, SBBC_TAG_KEY_SOLCONS) == 0) 488206451Smarius sbbc_solcons = off; 489206451Smarius else if (strcmp(buf, SBBC_TAG_KEY_SOLSCIE) == 0) 490206451Smarius sbbc_solscie = off; 491206451Smarius else if (strcmp(buf, SBBC_TAG_KEY_SOLSCIR) == 0) 492206451Smarius sbbc_solscir = off; 493206451Smarius else if (strcmp(buf, SBBC_TAG_KEY_TODDATA) == 0) 494206451Smarius sbbc_toddata = off; 495206451Smarius } 496206451Smarius return (0); 497206451Smarius} 498206451Smarius 499206451Smariusstatic const char * 500206451Smariussbbc_serengeti_set_console_input(char *new) 501206451Smarius{ 502206451Smarius struct { 503206451Smarius cell_t name; 504206451Smarius cell_t nargs; 505206451Smarius cell_t nreturns; 506206451Smarius cell_t new; 507206451Smarius cell_t old; 508206451Smarius } args = { 509206451Smarius (cell_t)SUNW_SETCONSINPUT, 510206451Smarius 1, 511206451Smarius 1, 512206451Smarius }; 513206451Smarius 514206451Smarius args.new = (cell_t)new; 515206451Smarius if (ofw_entry(&args) == -1) 516206451Smarius return (NULL); 517206451Smarius return ((const char *)args.old); 518206451Smarius} 519206451Smarius 520206451Smariusstatic inline void 521206451Smariussbbc_send_intr(bus_space_tag_t bst, bus_space_handle_t bsh) 522206451Smarius{ 523206451Smarius 524206451Smarius SBBC_EPLD_WRITE_1(SBBC_EPLD_INTERRUPT, SBBC_EPLD_INTERRUPT_ON); 525206451Smarius bus_space_barrier(bst, bsh, SBBC_EPLD_OFFSET + SBBC_EPLD_INTERRUPT, 1, 526206451Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 527206451Smarius} 528206451Smarius 529206451Smarius/* 530206451Smarius * TOD interface 531206451Smarius */ 532206451Smariusstatic int 533206451Smariussbbc_tod_gettime(device_t dev, struct timespec *ts) 534206451Smarius{ 535206451Smarius struct sbbc_softc *sc; 536206451Smarius bus_space_tag_t bst; 537206451Smarius bus_space_handle_t bsh; 538206451Smarius 539206451Smarius sc = device_get_softc(dev); 540206451Smarius bst = rman_get_bustag(sc->sc_res); 541206451Smarius bsh = rman_get_bushandle(sc->sc_res); 542206451Smarius 543206451Smarius ts->tv_sec = SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_time)) + 544206451Smarius SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_skew)); 545206451Smarius ts->tv_nsec = 0; 546206451Smarius return (0); 547206451Smarius} 548206451Smarius 549206451Smariusstatic int 550206451Smariussbbc_tod_settime(device_t dev, struct timespec *ts) 551206451Smarius{ 552206451Smarius struct sbbc_softc *sc; 553206451Smarius bus_space_tag_t bst; 554206451Smarius bus_space_handle_t bsh; 555206451Smarius 556206451Smarius sc = device_get_softc(dev); 557206451Smarius bst = rman_get_bustag(sc->sc_res); 558206451Smarius bsh = rman_get_bushandle(sc->sc_res); 559206451Smarius 560206451Smarius SBBC_SRAM_WRITE_8(sbbc_toddata + SBBC_TOD_OFF(tod_skew), ts->tv_sec - 561206451Smarius SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_time))); 562206451Smarius return (0); 563206451Smarius} 564206451Smarius 565206451Smarius/* 566206451Smarius * UART bus front-end 567206451Smarius */ 568206451Smariusstatic device_probe_t sbbc_uart_sbbc_probe; 569206451Smarius 570206451Smariusstatic device_method_t sbbc_uart_sbbc_methods[] = { 571206451Smarius /* Device interface */ 572206451Smarius DEVMETHOD(device_probe, sbbc_uart_sbbc_probe), 573206451Smarius DEVMETHOD(device_attach, uart_bus_attach), 574206451Smarius DEVMETHOD(device_detach, uart_bus_detach), 575206451Smarius 576206451Smarius KOBJMETHOD_END 577206451Smarius}; 578206451Smarius 579206451SmariusDEFINE_CLASS_0(uart, sbbc_uart_driver, sbbc_uart_sbbc_methods, 580206451Smarius sizeof(struct uart_softc)); 581206451SmariusDRIVER_MODULE(uart, sbbc, sbbc_uart_driver, uart_devclass, 0, 0); 582206451Smarius 583206451Smariusstatic int 584206451Smariussbbc_uart_sbbc_probe(device_t dev) 585206451Smarius{ 586206451Smarius struct uart_softc *sc; 587206451Smarius 588206451Smarius sc = device_get_softc(dev); 589206451Smarius sc->sc_class = &uart_sbbc_class; 590206451Smarius device_set_desc(dev, "Serengeti console"); 591206451Smarius return (uart_bus_probe(dev, 0, 0, SBBC_PCI_BAR, 0)); 592206451Smarius} 593206451Smarius 594206451Smarius/* 595206451Smarius * Low-level UART interface 596206451Smarius */ 597206451Smariusstatic int sbbc_uart_probe(struct uart_bas *bas); 598206451Smariusstatic void sbbc_uart_init(struct uart_bas *bas, int baudrate, int databits, 599206451Smarius int stopbits, int parity); 600206451Smariusstatic void sbbc_uart_term(struct uart_bas *bas); 601206451Smariusstatic void sbbc_uart_putc(struct uart_bas *bas, int c); 602206451Smariusstatic int sbbc_uart_rxready(struct uart_bas *bas); 603206451Smariusstatic int sbbc_uart_getc(struct uart_bas *bas, struct mtx *hwmtx); 604206451Smarius 605206451Smariusstatic struct uart_ops sbbc_uart_ops = { 606206451Smarius .probe = sbbc_uart_probe, 607206451Smarius .init = sbbc_uart_init, 608206451Smarius .term = sbbc_uart_term, 609206451Smarius .putc = sbbc_uart_putc, 610206451Smarius .rxready = sbbc_uart_rxready, 611206451Smarius .getc = sbbc_uart_getc, 612206451Smarius}; 613206451Smarius 614206451Smariusstatic int 615206451Smariussbbc_uart_probe(struct uart_bas *bas) 616206451Smarius{ 617206451Smarius bus_space_tag_t bst; 618206451Smarius bus_space_handle_t bsh; 619206451Smarius int error; 620206451Smarius 621206451Smarius sbbc_console = 1; 622206451Smarius bst = bas->bst; 623206451Smarius bsh = bas->bsh; 624206451Smarius error = sbbc_parse_toc(bst, bsh); 625206451Smarius if (error != 0) 626206451Smarius return (error); 627206451Smarius 628206451Smarius if (sbbc_scsolie == 0 || sbbc_scsolir == 0 || sbbc_solcons == 0 || 629206451Smarius sbbc_solscie == 0 || sbbc_solscir == 0) 630206451Smarius return (ENXIO); 631206451Smarius 632206451Smarius if (SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_magic)) != 633206451Smarius SBBC_CONS_MAGIC || SBBC_SRAM_READ_4(sbbc_solcons + 634206451Smarius SBBC_CONS_OFF(cons_version)) < SBBC_CONS_VERSION) 635206451Smarius return (ENXIO); 636206451Smarius return (0); 637206451Smarius} 638206451Smarius 639206451Smariusstatic void 640206451Smariussbbc_uart_init(struct uart_bas *bas, int baudrate __unused, 641206451Smarius int databits __unused, int stopbits __unused, int parity __unused) 642206451Smarius{ 643206451Smarius bus_space_tag_t bst; 644206451Smarius bus_space_handle_t bsh; 645206451Smarius 646206451Smarius bst = bas->bst; 647206451Smarius bsh = bas->bsh; 648206451Smarius 649206451Smarius /* Enable output to and space in from the SC interrupts. */ 650206451Smarius SBBC_SRAM_WRITE_4(sbbc_solscie, SBBC_SRAM_READ_4(sbbc_solscie) | 651206451Smarius SBBC_SRAM_CONS_OUT | SBBC_SRAM_CONS_SPACE_IN); 652206451Smarius uart_barrier(bas); 653206451Smarius 654206451Smarius /* Take over the console input. */ 655206451Smarius sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_CLNT); 656206451Smarius} 657206451Smarius 658206451Smariusstatic void 659206451Smariussbbc_uart_term(struct uart_bas *bas __unused) 660206451Smarius{ 661206451Smarius 662206451Smarius /* Give back the console input. */ 663206451Smarius sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_OBP); 664206451Smarius} 665206451Smarius 666206451Smariusstatic void 667206451Smariussbbc_uart_putc(struct uart_bas *bas, int c) 668206451Smarius{ 669206451Smarius bus_space_tag_t bst; 670206451Smarius bus_space_handle_t bsh; 671206451Smarius uint32_t wrptr; 672206451Smarius 673206451Smarius bst = bas->bst; 674206451Smarius bsh = bas->bsh; 675206451Smarius 676206451Smarius wrptr = SBBC_SRAM_READ_4(sbbc_solcons + 677206451Smarius SBBC_CONS_OFF(cons_out_wrptr)); 678206451Smarius SBBC_SRAM_WRITE_1(sbbc_solcons + wrptr, c); 679206451Smarius uart_barrier(bas); 680206451Smarius if (++wrptr == SBBC_SRAM_READ_4(sbbc_solcons + 681206451Smarius SBBC_CONS_OFF(cons_out_end))) 682206451Smarius wrptr = SBBC_SRAM_READ_4(sbbc_solcons + 683206451Smarius SBBC_CONS_OFF(cons_out_begin)); 684206451Smarius SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr), 685206451Smarius wrptr); 686206451Smarius uart_barrier(bas); 687206451Smarius 688206451Smarius SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) | 689206451Smarius SBBC_SRAM_CONS_OUT); 690206451Smarius uart_barrier(bas); 691206451Smarius sbbc_send_intr(bst, bsh); 692206451Smarius} 693206451Smarius 694206451Smariusstatic int 695206451Smariussbbc_uart_rxready(struct uart_bas *bas) 696206451Smarius{ 697206451Smarius bus_space_tag_t bst; 698206451Smarius bus_space_handle_t bsh; 699206451Smarius 700206451Smarius bst = bas->bst; 701206451Smarius bsh = bas->bsh; 702206451Smarius 703206451Smarius if (SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr)) == 704206451Smarius SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_wrptr))) 705206451Smarius return (0); 706206451Smarius return (1); 707206451Smarius} 708206451Smarius 709206451Smariusstatic int 710206451Smariussbbc_uart_getc(struct uart_bas *bas, struct mtx *hwmtx) 711206451Smarius{ 712206451Smarius bus_space_tag_t bst; 713206451Smarius bus_space_handle_t bsh; 714206451Smarius int c; 715206451Smarius uint32_t rdptr; 716206451Smarius 717206451Smarius bst = bas->bst; 718206451Smarius bsh = bas->bsh; 719206451Smarius 720206451Smarius uart_lock(hwmtx); 721206451Smarius 722206451Smarius while (sbbc_uart_rxready(bas) == 0) { 723206451Smarius uart_unlock(hwmtx); 724206451Smarius DELAY(4); 725206451Smarius uart_lock(hwmtx); 726206451Smarius } 727206451Smarius 728206451Smarius rdptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr)); 729206451Smarius c = SBBC_SRAM_READ_1(sbbc_solcons + rdptr); 730206451Smarius uart_barrier(bas); 731206451Smarius if (++rdptr == SBBC_SRAM_READ_4(sbbc_solcons + 732206451Smarius SBBC_CONS_OFF(cons_in_end))) 733206451Smarius rdptr = SBBC_SRAM_READ_4(sbbc_solcons + 734206451Smarius SBBC_CONS_OFF(cons_in_begin)); 735206451Smarius SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr), 736206451Smarius rdptr); 737206451Smarius uart_barrier(bas); 738206451Smarius SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) | 739206451Smarius SBBC_SRAM_CONS_SPACE_IN); 740206451Smarius uart_barrier(bas); 741206451Smarius sbbc_send_intr(bst, bsh); 742206451Smarius 743206451Smarius uart_unlock(hwmtx); 744206451Smarius return (c); 745206451Smarius} 746206451Smarius 747206451Smarius/* 748206451Smarius * High-level UART interface 749206451Smarius */ 750206451Smariusstatic int sbbc_uart_bus_attach(struct uart_softc *sc); 751206451Smariusstatic int sbbc_uart_bus_detach(struct uart_softc *sc); 752206451Smariusstatic int sbbc_uart_bus_flush(struct uart_softc *sc, int what); 753206451Smariusstatic int sbbc_uart_bus_getsig(struct uart_softc *sc); 754206451Smariusstatic int sbbc_uart_bus_ioctl(struct uart_softc *sc, int request, 755206451Smarius intptr_t data); 756206451Smariusstatic int sbbc_uart_bus_ipend(struct uart_softc *sc); 757206451Smariusstatic int sbbc_uart_bus_param(struct uart_softc *sc, int baudrate, 758206451Smarius int databits, int stopbits, int parity); 759206451Smariusstatic int sbbc_uart_bus_probe(struct uart_softc *sc); 760206451Smariusstatic int sbbc_uart_bus_receive(struct uart_softc *sc); 761206451Smariusstatic int sbbc_uart_bus_setsig(struct uart_softc *sc, int sig); 762206451Smariusstatic int sbbc_uart_bus_transmit(struct uart_softc *sc); 763206451Smarius 764206451Smariusstatic kobj_method_t sbbc_uart_methods[] = { 765206451Smarius KOBJMETHOD(uart_attach, sbbc_uart_bus_attach), 766206451Smarius KOBJMETHOD(uart_detach, sbbc_uart_bus_detach), 767206451Smarius KOBJMETHOD(uart_flush, sbbc_uart_bus_flush), 768206451Smarius KOBJMETHOD(uart_getsig, sbbc_uart_bus_getsig), 769206451Smarius KOBJMETHOD(uart_ioctl, sbbc_uart_bus_ioctl), 770206451Smarius KOBJMETHOD(uart_ipend, sbbc_uart_bus_ipend), 771206451Smarius KOBJMETHOD(uart_param, sbbc_uart_bus_param), 772206451Smarius KOBJMETHOD(uart_probe, sbbc_uart_bus_probe), 773206451Smarius KOBJMETHOD(uart_receive, sbbc_uart_bus_receive), 774206451Smarius KOBJMETHOD(uart_setsig, sbbc_uart_bus_setsig), 775206451Smarius KOBJMETHOD(uart_transmit, sbbc_uart_bus_transmit), 776206451Smarius 777206451Smarius KOBJMETHOD_END 778206451Smarius}; 779206451Smarius 780206451Smariusstruct uart_class uart_sbbc_class = { 781206451Smarius "sbbc", 782206451Smarius sbbc_uart_methods, 783206451Smarius sizeof(struct uart_softc), 784206451Smarius .uc_ops = &sbbc_uart_ops, 785206451Smarius .uc_range = 1, 786206451Smarius .uc_rclk = 0x5bbc /* arbitrary */ 787206451Smarius}; 788206451Smarius 789206451Smarius#define SIGCHG(c, i, s, d) \ 790206451Smarius if ((c) != 0) { \ 791206451Smarius i |= (((i) & (s)) != 0) ? (s) : (s) | (d); \ 792206451Smarius } else { \ 793206451Smarius i = (((i) & (s)) != 0) ? ((i) & ~(s)) | (d) : (i); \ 794206451Smarius } 795206451Smarius 796206451Smariusstatic int 797206451Smariussbbc_uart_bus_attach(struct uart_softc *sc) 798206451Smarius{ 799206451Smarius struct uart_bas *bas; 800206451Smarius bus_space_tag_t bst; 801206451Smarius bus_space_handle_t bsh; 802206451Smarius uint32_t wrptr; 803206451Smarius 804206451Smarius bas = &sc->sc_bas; 805206451Smarius bst = bas->bst; 806206451Smarius bsh = bas->bsh; 807206451Smarius 808206451Smarius sc->sc_rxfifosz = SBBC_SRAM_READ_4(sbbc_solcons + 809206451Smarius SBBC_CONS_OFF(cons_in_end)) - SBBC_SRAM_READ_4(sbbc_solcons + 810206451Smarius SBBC_CONS_OFF(cons_in_begin)) - 1; 811206451Smarius sc->sc_txfifosz = SBBC_SRAM_READ_4(sbbc_solcons + 812206451Smarius SBBC_CONS_OFF(cons_out_end)) - SBBC_SRAM_READ_4(sbbc_solcons + 813206451Smarius SBBC_CONS_OFF(cons_out_begin)) - 1; 814206451Smarius 815206451Smarius uart_lock(sc->sc_hwmtx); 816206451Smarius 817206451Smarius /* 818206451Smarius * Let the current output drain before enabling interrupts. Not 819206451Smarius * doing so tends to cause lost output when turning them on. 820206451Smarius */ 821206451Smarius wrptr = SBBC_SRAM_READ_4(sbbc_solcons + 822206451Smarius SBBC_CONS_OFF(cons_out_wrptr)); 823206451Smarius while (SBBC_SRAM_READ_4(sbbc_solcons + 824206451Smarius SBBC_CONS_OFF(cons_out_rdptr)) != wrptr); 825206451Smarius cpu_spinwait(); 826206451Smarius 827206451Smarius /* Clear and acknowledge possibly outstanding interrupts. */ 828206451Smarius SBBC_SRAM_WRITE_4(sbbc_scsolir, 0); 829206451Smarius uart_barrier(bas); 830206451Smarius SBBC_REGS_WRITE_4(SBBC_PCI_INT_STATUS, 831206451Smarius SBBC_SRAM_READ_4(sbbc_scsolir)); 832206451Smarius uart_barrier(bas); 833206451Smarius /* Enable PCI interrupts. */ 834206451Smarius SBBC_REGS_WRITE_4(SBBC_PCI_INT_ENABLE, SBBC_PCI_ENABLE_INT_A); 835206451Smarius uart_barrier(bas); 836206451Smarius /* Enable input from and output to SC as well as break interrupts. */ 837206451Smarius SBBC_SRAM_WRITE_4(sbbc_scsolie, SBBC_SRAM_READ_4(sbbc_scsolie) | 838206451Smarius SBBC_SRAM_CONS_IN | SBBC_SRAM_CONS_BRK | 839206451Smarius SBBC_SRAM_CONS_SPACE_OUT); 840206451Smarius uart_barrier(bas); 841206451Smarius 842206451Smarius uart_unlock(sc->sc_hwmtx); 843206451Smarius return (0); 844206451Smarius} 845206451Smarius 846206451Smariusstatic int 847206451Smariussbbc_uart_bus_detach(struct uart_softc *sc) 848206451Smarius{ 849206451Smarius 850206451Smarius /* Give back the console input. */ 851206451Smarius sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_OBP); 852206451Smarius return (0); 853206451Smarius} 854206451Smarius 855206451Smariusstatic int 856206451Smariussbbc_uart_bus_flush(struct uart_softc *sc, int what) 857206451Smarius{ 858206451Smarius struct uart_bas *bas; 859206451Smarius bus_space_tag_t bst; 860206451Smarius bus_space_handle_t bsh; 861206451Smarius 862206451Smarius bas = &sc->sc_bas; 863206451Smarius bst = bas->bst; 864206451Smarius bsh = bas->bsh; 865206451Smarius 866206451Smarius if ((what & UART_FLUSH_TRANSMITTER) != 0) 867206451Smarius return (ENODEV); 868206451Smarius if ((what & UART_FLUSH_RECEIVER) != 0) { 869206451Smarius SBBC_SRAM_WRITE_4(sbbc_solcons + 870206451Smarius SBBC_CONS_OFF(cons_in_rdptr), 871206451Smarius SBBC_SRAM_READ_4(sbbc_solcons + 872206451Smarius SBBC_CONS_OFF(cons_in_wrptr))); 873206451Smarius uart_barrier(bas); 874206451Smarius } 875206451Smarius return (0); 876206451Smarius} 877206451Smarius 878206451Smariusstatic int 879206451Smariussbbc_uart_bus_getsig(struct uart_softc *sc) 880206451Smarius{ 881206451Smarius uint32_t dummy, new, old, sig; 882206451Smarius 883206451Smarius do { 884206451Smarius old = sc->sc_hwsig; 885206451Smarius sig = old; 886206451Smarius dummy = 0; 887206451Smarius SIGCHG(dummy, sig, SER_CTS, SER_DCTS); 888206451Smarius SIGCHG(dummy, sig, SER_DCD, SER_DDCD); 889206451Smarius SIGCHG(dummy, sig, SER_DSR, SER_DDSR); 890206451Smarius new = sig & ~SER_MASK_DELTA; 891206451Smarius } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 892206451Smarius return (sig); 893206451Smarius} 894206451Smarius 895206451Smariusstatic int 896206451Smariussbbc_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) 897206451Smarius{ 898206451Smarius int error; 899206451Smarius 900206451Smarius error = 0; 901206451Smarius uart_lock(sc->sc_hwmtx); 902206451Smarius switch (request) { 903206451Smarius case UART_IOCTL_BAUD: 904206451Smarius *(int*)data = 9600; /* arbitrary */ 905206451Smarius break; 906206451Smarius default: 907206451Smarius error = EINVAL; 908206451Smarius break; 909206451Smarius } 910206451Smarius uart_unlock(sc->sc_hwmtx); 911206451Smarius return (error); 912206451Smarius} 913206451Smarius 914206451Smariusstatic int 915206451Smariussbbc_uart_bus_ipend(struct uart_softc *sc) 916206451Smarius{ 917206451Smarius struct uart_bas *bas; 918206451Smarius bus_space_tag_t bst; 919206451Smarius bus_space_handle_t bsh; 920206451Smarius int ipend; 921206451Smarius uint32_t reason, status; 922206451Smarius 923206451Smarius bas = &sc->sc_bas; 924206451Smarius bst = bas->bst; 925206451Smarius bsh = bas->bsh; 926206451Smarius 927206451Smarius uart_lock(sc->sc_hwmtx); 928206451Smarius status = SBBC_REGS_READ_4(SBBC_PCI_INT_STATUS); 929206451Smarius if (status == 0) { 930206451Smarius uart_unlock(sc->sc_hwmtx); 931206451Smarius return (0); 932206451Smarius } 933206451Smarius 934206451Smarius /* 935206451Smarius * Unfortunately, we can't use compare and swap for non-cachable 936206451Smarius * memory. 937206451Smarius */ 938206451Smarius reason = SBBC_SRAM_READ_4(sbbc_scsolir); 939206451Smarius SBBC_SRAM_WRITE_4(sbbc_scsolir, 0); 940206451Smarius uart_barrier(bas); 941206451Smarius /* Acknowledge the interrupt. */ 942206451Smarius SBBC_REGS_WRITE_4(SBBC_PCI_INT_STATUS, status); 943206451Smarius uart_barrier(bas); 944206451Smarius 945206451Smarius uart_unlock(sc->sc_hwmtx); 946206451Smarius 947206451Smarius ipend = 0; 948206451Smarius if ((reason & SBBC_SRAM_CONS_IN) != 0) 949206451Smarius ipend |= SER_INT_RXREADY; 950206451Smarius if ((reason & SBBC_SRAM_CONS_BRK) != 0) 951206451Smarius ipend |= SER_INT_BREAK; 952206451Smarius if ((reason & SBBC_SRAM_CONS_SPACE_OUT) != 0 && 953206451Smarius SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_rdptr)) == 954206451Smarius SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr))) 955206451Smarius ipend |= SER_INT_TXIDLE; 956206451Smarius return (ipend); 957206451Smarius} 958206451Smarius 959206451Smariusstatic int 960206451Smariussbbc_uart_bus_param(struct uart_softc *sc __unused, int baudrate __unused, 961206451Smarius int databits __unused, int stopbits __unused, int parity __unused) 962206451Smarius{ 963206451Smarius 964206451Smarius return (0); 965206451Smarius} 966206451Smarius 967206451Smariusstatic int 968206451Smariussbbc_uart_bus_probe(struct uart_softc *sc __unused) 969206451Smarius{ 970206451Smarius 971206451Smarius if (sbbc_console != 0) 972206451Smarius return (0); 973206451Smarius return (ENXIO); 974206451Smarius} 975206451Smarius 976206451Smariusstatic int 977206451Smariussbbc_uart_bus_receive(struct uart_softc *sc) 978206451Smarius{ 979206451Smarius struct uart_bas *bas; 980206451Smarius bus_space_tag_t bst; 981206451Smarius bus_space_handle_t bsh; 982206451Smarius int c; 983206451Smarius uint32_t end, rdptr, wrptr; 984206451Smarius 985206451Smarius bas = &sc->sc_bas; 986206451Smarius bst = bas->bst; 987206451Smarius bsh = bas->bsh; 988206451Smarius 989206451Smarius uart_lock(sc->sc_hwmtx); 990206451Smarius 991206451Smarius end = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_end)); 992206451Smarius rdptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr)); 993206451Smarius wrptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_wrptr)); 994206451Smarius while (rdptr != wrptr) { 995206451Smarius if (uart_rx_full(sc) != 0) { 996206451Smarius sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; 997206451Smarius break; 998206451Smarius } 999206451Smarius c = SBBC_SRAM_READ_1(sbbc_solcons + rdptr); 1000206451Smarius uart_rx_put(sc, c); 1001206451Smarius if (++rdptr == end) 1002206451Smarius rdptr = SBBC_SRAM_READ_4(sbbc_solcons + 1003206451Smarius SBBC_CONS_OFF(cons_in_begin)); 1004206451Smarius } 1005206451Smarius uart_barrier(bas); 1006206451Smarius SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr), 1007206451Smarius rdptr); 1008206451Smarius uart_barrier(bas); 1009206451Smarius SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) | 1010206451Smarius SBBC_SRAM_CONS_SPACE_IN); 1011206451Smarius uart_barrier(bas); 1012206451Smarius sbbc_send_intr(bst, bsh); 1013206451Smarius 1014206451Smarius uart_unlock(sc->sc_hwmtx); 1015206451Smarius return (0); 1016206451Smarius} 1017206451Smarius 1018206451Smariusstatic int 1019206451Smariussbbc_uart_bus_setsig(struct uart_softc *sc, int sig) 1020206451Smarius{ 1021206451Smarius struct uart_bas *bas; 1022206451Smarius uint32_t new, old; 1023206451Smarius 1024206451Smarius bas = &sc->sc_bas; 1025206451Smarius do { 1026206451Smarius old = sc->sc_hwsig; 1027206451Smarius new = old; 1028206451Smarius if ((sig & SER_DDTR) != 0) { 1029206451Smarius SIGCHG(sig & SER_DTR, new, SER_DTR, SER_DDTR); 1030206451Smarius } 1031206451Smarius if ((sig & SER_DRTS) != 0) { 1032206451Smarius SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS); 1033206451Smarius } 1034206451Smarius } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 1035206451Smarius return (0); 1036206451Smarius} 1037206451Smarius 1038206451Smariusstatic int 1039206451Smariussbbc_uart_bus_transmit(struct uart_softc *sc) 1040206451Smarius{ 1041206451Smarius struct uart_bas *bas; 1042206451Smarius bus_space_tag_t bst; 1043206451Smarius bus_space_handle_t bsh; 1044206451Smarius int i; 1045206451Smarius uint32_t end, wrptr; 1046206451Smarius 1047206451Smarius bas = &sc->sc_bas; 1048206451Smarius bst = bas->bst; 1049206451Smarius bsh = bas->bsh; 1050206451Smarius 1051206451Smarius uart_lock(sc->sc_hwmtx); 1052206451Smarius 1053206451Smarius end = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_end)); 1054206451Smarius wrptr = SBBC_SRAM_READ_4(sbbc_solcons + 1055206451Smarius SBBC_CONS_OFF(cons_out_wrptr)); 1056206451Smarius for (i = 0; i < sc->sc_txdatasz; i++) { 1057206451Smarius SBBC_SRAM_WRITE_1(sbbc_solcons + wrptr, sc->sc_txbuf[i]); 1058206451Smarius if (++wrptr == end) 1059206451Smarius wrptr = SBBC_SRAM_READ_4(sbbc_solcons + 1060206451Smarius SBBC_CONS_OFF(cons_out_begin)); 1061206451Smarius } 1062206451Smarius uart_barrier(bas); 1063206451Smarius SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr), 1064206451Smarius wrptr); 1065206451Smarius uart_barrier(bas); 1066206451Smarius SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) | 1067206451Smarius SBBC_SRAM_CONS_OUT); 1068206451Smarius uart_barrier(bas); 1069206451Smarius sbbc_send_intr(bst, bsh); 1070206451Smarius sc->sc_txbusy = 1; 1071206451Smarius 1072206451Smarius uart_unlock(sc->sc_hwmtx); 1073206451Smarius return (0); 1074206451Smarius} 1075