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: stable/11/sys/sparc64/pci/sbbc.c 340145 2018-11-04 23:28:56Z mmacy $"); 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 */ 262225931Smariusstatic bus_activate_resource_t sbbc_bus_activate_resource; 263225931Smariusstatic bus_adjust_resource_t sbbc_bus_adjust_resource; 264225931Smariusstatic bus_deactivate_resource_t sbbc_bus_deactivate_resource; 265206451Smariusstatic bus_alloc_resource_t sbbc_bus_alloc_resource; 266206451Smariusstatic bus_release_resource_t sbbc_bus_release_resource; 267206451Smariusstatic bus_get_resource_list_t sbbc_bus_get_resource_list; 268206451Smariusstatic bus_setup_intr_t sbbc_bus_setup_intr; 269206451Smariusstatic bus_teardown_intr_t sbbc_bus_teardown_intr; 270206451Smarius 271206451Smariusstatic device_attach_t sbbc_pci_attach; 272206451Smariusstatic device_probe_t sbbc_pci_probe; 273206451Smarius 274206451Smariusstatic clock_gettime_t sbbc_tod_gettime; 275206451Smariusstatic clock_settime_t sbbc_tod_settime; 276206451Smarius 277206451Smariusstatic device_method_t sbbc_pci_methods[] = { 278206451Smarius /* Device interface */ 279206451Smarius DEVMETHOD(device_probe, sbbc_pci_probe), 280206451Smarius DEVMETHOD(device_attach, sbbc_pci_attach), 281206451Smarius 282206451Smarius DEVMETHOD(bus_alloc_resource, sbbc_bus_alloc_resource), 283225931Smarius DEVMETHOD(bus_activate_resource,sbbc_bus_activate_resource), 284225931Smarius DEVMETHOD(bus_deactivate_resource,sbbc_bus_deactivate_resource), 285225931Smarius DEVMETHOD(bus_adjust_resource, sbbc_bus_adjust_resource), 286206451Smarius DEVMETHOD(bus_release_resource, sbbc_bus_release_resource), 287206451Smarius DEVMETHOD(bus_setup_intr, sbbc_bus_setup_intr), 288206451Smarius DEVMETHOD(bus_teardown_intr, sbbc_bus_teardown_intr), 289225931Smarius DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 290206451Smarius DEVMETHOD(bus_get_resource_list, sbbc_bus_get_resource_list), 291206451Smarius 292206451Smarius /* clock interface */ 293206451Smarius DEVMETHOD(clock_gettime, sbbc_tod_gettime), 294206451Smarius DEVMETHOD(clock_settime, sbbc_tod_settime), 295206451Smarius 296227843Smarius DEVMETHOD_END 297206451Smarius}; 298206451Smarius 299206451Smariusstatic devclass_t sbbc_devclass; 300206451Smarius 301206451SmariusDEFINE_CLASS_0(sbbc, sbbc_driver, sbbc_pci_methods, sizeof(struct sbbc_softc)); 302247574SmariusDRIVER_MODULE(sbbc, pci, sbbc_driver, sbbc_devclass, NULL, NULL); 303206451Smarius 304206451Smariusstatic int 305206451Smariussbbc_pci_probe(device_t dev) 306206451Smarius{ 307206451Smarius 308206451Smarius if (pci_get_vendor(dev) == SBBC_PCI_VENDOR && 309206451Smarius pci_get_device(dev) == SBBC_PCI_PRODUCT) { 310206451Smarius device_set_desc(dev, "Sun BootBus controller"); 311206451Smarius return (BUS_PROBE_DEFAULT); 312206451Smarius } 313206451Smarius return (ENXIO); 314206451Smarius} 315206451Smarius 316206451Smariusstatic int 317206451Smariussbbc_pci_attach(device_t dev) 318206451Smarius{ 319206451Smarius struct sbbc_softc *sc; 320206451Smarius struct timespec ts; 321206451Smarius device_t child; 322206451Smarius bus_space_tag_t bst; 323206451Smarius bus_space_handle_t bsh; 324206451Smarius phandle_t node; 325206451Smarius int error, rid; 326206451Smarius uint32_t val; 327206451Smarius 328330446Seadler /* Nothing to do if we're not the chosen one. */ 329206451Smarius if ((node = OF_finddevice("/chosen")) == -1) { 330206451Smarius device_printf(dev, "failed to find /chosen\n"); 331206451Smarius return (ENXIO); 332206451Smarius } 333206451Smarius if (OF_getprop(node, "iosram", &node, sizeof(node)) == -1) { 334206451Smarius device_printf(dev, "failed to get iosram\n"); 335206451Smarius return (ENXIO); 336206451Smarius } 337206451Smarius if (node != ofw_bus_get_node(dev)) 338206451Smarius return (0); 339206451Smarius 340206451Smarius sc = device_get_softc(dev); 341206451Smarius rid = SBBC_PCI_BAR; 342225931Smarius sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 343225931Smarius RF_ACTIVE); 344206451Smarius if (sc->sc_res == NULL) { 345206451Smarius device_printf(dev, "failed to allocate resources\n"); 346206451Smarius return (ENXIO); 347206451Smarius } 348206451Smarius bst = rman_get_bustag(sc->sc_res); 349206451Smarius bsh = rman_get_bushandle(sc->sc_res); 350206451Smarius if (sbbc_console != 0) { 351206451Smarius /* Once again the interrupt pin isn't set. */ 352206451Smarius if (pci_get_intpin(dev) == 0) 353206451Smarius pci_set_intpin(dev, 1); 354206451Smarius child = device_add_child(dev, NULL, -1); 355206451Smarius if (child == NULL) 356206451Smarius device_printf(dev, "failed to add UART device\n"); 357206451Smarius error = bus_generic_attach(dev); 358206451Smarius if (error != 0) 359206451Smarius device_printf(dev, "failed to attach UART device\n"); 360206451Smarius } else { 361247574Smarius error = sbbc_parse_toc(bst, bsh); 362206451Smarius if (error != 0) { 363206451Smarius device_printf(dev, "failed to parse TOC\n"); 364206451Smarius if (sbbc_console != 0) { 365206451Smarius bus_release_resource(dev, SYS_RES_MEMORY, rid, 366206451Smarius sc->sc_res); 367206451Smarius return (error); 368206451Smarius } 369206451Smarius } 370206451Smarius } 371206451Smarius if (sbbc_toddata != 0) { 372206451Smarius if ((val = SBBC_SRAM_READ_4(sbbc_toddata + 373206451Smarius SBBC_TOD_OFF(tod_magic))) != SBBC_TOD_MAGIC) 374206451Smarius device_printf(dev, "invalid TOD magic %#x\n", val); 375206451Smarius else if ((val = SBBC_SRAM_READ_4(sbbc_toddata + 376206451Smarius SBBC_TOD_OFF(tod_version))) < SBBC_TOD_VERSION) 377206451Smarius device_printf(dev, "invalid TOD version %#x\n", val); 378206451Smarius else { 379206451Smarius clock_register(dev, 1000000); /* 1 sec. resolution */ 380206451Smarius if (bootverbose) { 381206451Smarius sbbc_tod_gettime(dev, &ts); 382206451Smarius device_printf(dev, 383206451Smarius "current time: %ld.%09ld\n", 384206451Smarius (long)ts.tv_sec, ts.tv_nsec); 385206451Smarius } 386206451Smarius } 387206451Smarius } 388206451Smarius return (0); 389206451Smarius} 390206451Smarius 391206451Smarius/* 392206451Smarius * Note that the bus methods don't pass-through the uart(4) requests but act 393206451Smarius * as if they would come from sbbc(4) in order to avoid complications with 394206451Smarius * pci(4) (actually, uart(4) isn't a real child but rather a function of 395206451Smarius * sbbc(4) anyway). 396206451Smarius */ 397206451Smarius 398206451Smariusstatic struct resource * 399206451Smariussbbc_bus_alloc_resource(device_t dev, device_t child __unused, int type, 400294883Sjhibbits int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 401206451Smarius{ 402206451Smarius struct sbbc_softc *sc; 403206451Smarius 404206451Smarius sc = device_get_softc(dev); 405206451Smarius switch (type) { 406206451Smarius case SYS_RES_IRQ: 407225931Smarius return (bus_generic_alloc_resource(dev, dev, type, rid, start, 408225931Smarius end, count, flags)); 409206451Smarius case SYS_RES_MEMORY: 410206451Smarius return (sc->sc_res); 411206451Smarius default: 412206451Smarius return (NULL); 413206451Smarius } 414206451Smarius} 415206451Smarius 416206451Smariusstatic int 417225931Smariussbbc_bus_activate_resource(device_t bus, device_t child, int type, int rid, 418225931Smarius struct resource *res) 419225931Smarius{ 420225931Smarius 421225931Smarius if (type == SYS_RES_MEMORY) 422225931Smarius return (0); 423225931Smarius return (bus_generic_activate_resource(bus, child, type, rid, res)); 424225931Smarius} 425225931Smarius 426225931Smariusstatic int 427225931Smariussbbc_bus_deactivate_resource(device_t bus, device_t child, int type, int rid, 428225931Smarius struct resource *res) 429225931Smarius{ 430225931Smarius 431225931Smarius if (type == SYS_RES_MEMORY) 432225931Smarius return (0); 433225931Smarius return (bus_generic_deactivate_resource(bus, child, type, rid, res)); 434225931Smarius} 435225931Smarius 436225931Smariusstatic int 437225931Smariussbbc_bus_adjust_resource(device_t bus __unused, device_t child __unused, 438294883Sjhibbits int type __unused, struct resource *res __unused, rman_res_t start __unused, 439294883Sjhibbits rman_res_t end __unused) 440225931Smarius{ 441225931Smarius 442225931Smarius return (ENXIO); 443225931Smarius} 444225931Smarius 445225931Smariusstatic int 446206451Smariussbbc_bus_release_resource(device_t dev, device_t child __unused, int type, 447206451Smarius int rid, struct resource *res) 448206451Smarius{ 449206451Smarius 450206451Smarius if (type == SYS_RES_IRQ) 451225931Smarius return (bus_generic_release_resource(dev, dev, type, rid, 452225931Smarius res)); 453206451Smarius return (0); 454206451Smarius} 455206451Smarius 456206451Smariusstatic struct resource_list * 457206451Smariussbbc_bus_get_resource_list(device_t dev, device_t child __unused) 458206451Smarius{ 459206451Smarius 460225931Smarius return (bus_generic_get_resource_list(dev, dev)); 461206451Smarius} 462206451Smarius 463206451Smariusstatic int 464206451Smariussbbc_bus_setup_intr(device_t dev, device_t child __unused, 465206451Smarius struct resource *res, int flags, driver_filter_t *filt, 466206451Smarius driver_intr_t *intr, void *arg, void **cookiep) 467206451Smarius{ 468206451Smarius 469225931Smarius return (bus_generic_setup_intr(dev, dev, res, flags, filt, intr, arg, 470225931Smarius cookiep)); 471206451Smarius} 472206451Smarius 473206451Smariusstatic int 474206451Smariussbbc_bus_teardown_intr(device_t dev, device_t child __unused, 475206451Smarius struct resource *res, void *cookie) 476206451Smarius{ 477206451Smarius 478225931Smarius return (bus_generic_teardown_intr(dev, dev, res, cookie)); 479206451Smarius} 480206451Smarius 481206451Smarius/* 482206451Smarius * internal helpers 483206451Smarius */ 484206451Smariusstatic int 485206451Smariussbbc_parse_toc(bus_space_tag_t bst, bus_space_handle_t bsh) 486206451Smarius{ 487206451Smarius char buf[MAX(SBBC_TAG_KEY_SIZE, SBBC_TOC_MAGIC_SIZE)]; 488206451Smarius bus_size_t tag; 489206451Smarius phandle_t node; 490206451Smarius uint32_t off, sram_toc; 491206451Smarius u_int i, tags; 492206451Smarius 493206451Smarius if ((node = OF_finddevice("/chosen")) == -1) 494206451Smarius return (ENXIO); 495206451Smarius /* SRAM TOC offset defaults to 0. */ 496206451Smarius if (OF_getprop(node, "iosram-toc", &sram_toc, sizeof(sram_toc)) <= 0) 497206451Smarius sram_toc = 0; 498206451Smarius 499206451Smarius bus_space_read_region_1(bst, bsh, SBBC_SRAM_OFFSET + sram_toc + 500206451Smarius SBBC_TOC_OFF(toc_magic), buf, SBBC_TOC_MAGIC_SIZE); 501206451Smarius buf[SBBC_TOC_MAGIC_SIZE - 1] = '\0'; 502206451Smarius if (strcmp(buf, SBBC_TOC_MAGIC) != 0) 503206451Smarius return (ENXIO); 504206451Smarius 505206451Smarius tags = SBBC_SRAM_READ_4(sram_toc + SBBC_TOC_OFF(toc_ntags)); 506206451Smarius for (i = 0; i < tags; i++) { 507206451Smarius tag = sram_toc + SBBC_TOC_OFF(toc_tag) + 508206451Smarius i * sizeof(struct sbbc_sram_tag); 509206451Smarius bus_space_read_region_1(bst, bsh, SBBC_SRAM_OFFSET + tag + 510206451Smarius SBBC_TAG_OFF(tag_key), buf, SBBC_TAG_KEY_SIZE); 511206451Smarius buf[SBBC_TAG_KEY_SIZE - 1] = '\0'; 512206451Smarius off = SBBC_SRAM_READ_4(tag + SBBC_TAG_OFF(tag_offset)); 513206451Smarius if (strcmp(buf, SBBC_TAG_KEY_SCSOLIE) == 0) 514206451Smarius sbbc_scsolie = off; 515206451Smarius else if (strcmp(buf, SBBC_TAG_KEY_SCSOLIR) == 0) 516206451Smarius sbbc_scsolir = off; 517206451Smarius else if (strcmp(buf, SBBC_TAG_KEY_SOLCONS) == 0) 518206451Smarius sbbc_solcons = off; 519206451Smarius else if (strcmp(buf, SBBC_TAG_KEY_SOLSCIE) == 0) 520206451Smarius sbbc_solscie = off; 521206451Smarius else if (strcmp(buf, SBBC_TAG_KEY_SOLSCIR) == 0) 522206451Smarius sbbc_solscir = off; 523206451Smarius else if (strcmp(buf, SBBC_TAG_KEY_TODDATA) == 0) 524206451Smarius sbbc_toddata = off; 525206451Smarius } 526206451Smarius return (0); 527206451Smarius} 528206451Smarius 529206451Smariusstatic const char * 530206451Smariussbbc_serengeti_set_console_input(char *new) 531206451Smarius{ 532206451Smarius struct { 533206451Smarius cell_t name; 534206451Smarius cell_t nargs; 535206451Smarius cell_t nreturns; 536206451Smarius cell_t new; 537206451Smarius cell_t old; 538206451Smarius } args = { 539206451Smarius (cell_t)SUNW_SETCONSINPUT, 540206451Smarius 1, 541206451Smarius 1, 542206451Smarius }; 543206451Smarius 544206451Smarius args.new = (cell_t)new; 545206451Smarius if (ofw_entry(&args) == -1) 546206451Smarius return (NULL); 547206451Smarius return ((const char *)args.old); 548206451Smarius} 549206451Smarius 550206451Smariusstatic inline void 551206451Smariussbbc_send_intr(bus_space_tag_t bst, bus_space_handle_t bsh) 552206451Smarius{ 553206451Smarius 554206451Smarius SBBC_EPLD_WRITE_1(SBBC_EPLD_INTERRUPT, SBBC_EPLD_INTERRUPT_ON); 555206451Smarius bus_space_barrier(bst, bsh, SBBC_EPLD_OFFSET + SBBC_EPLD_INTERRUPT, 1, 556206451Smarius BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE); 557206451Smarius} 558206451Smarius 559206451Smarius/* 560206451Smarius * TOD interface 561206451Smarius */ 562206451Smariusstatic int 563206451Smariussbbc_tod_gettime(device_t dev, struct timespec *ts) 564206451Smarius{ 565206451Smarius struct sbbc_softc *sc; 566206451Smarius bus_space_tag_t bst; 567206451Smarius bus_space_handle_t bsh; 568206451Smarius 569206451Smarius sc = device_get_softc(dev); 570206451Smarius bst = rman_get_bustag(sc->sc_res); 571206451Smarius bsh = rman_get_bushandle(sc->sc_res); 572206451Smarius 573206451Smarius ts->tv_sec = SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_time)) + 574206451Smarius SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_skew)); 575206451Smarius ts->tv_nsec = 0; 576206451Smarius return (0); 577206451Smarius} 578206451Smarius 579206451Smariusstatic int 580206451Smariussbbc_tod_settime(device_t dev, struct timespec *ts) 581206451Smarius{ 582206451Smarius struct sbbc_softc *sc; 583206451Smarius bus_space_tag_t bst; 584206451Smarius bus_space_handle_t bsh; 585206451Smarius 586206451Smarius sc = device_get_softc(dev); 587206451Smarius bst = rman_get_bustag(sc->sc_res); 588206451Smarius bsh = rman_get_bushandle(sc->sc_res); 589206451Smarius 590206451Smarius SBBC_SRAM_WRITE_8(sbbc_toddata + SBBC_TOD_OFF(tod_skew), ts->tv_sec - 591206451Smarius SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_time))); 592206451Smarius return (0); 593206451Smarius} 594206451Smarius 595206451Smarius/* 596206451Smarius * UART bus front-end 597206451Smarius */ 598206451Smariusstatic device_probe_t sbbc_uart_sbbc_probe; 599206451Smarius 600206451Smariusstatic device_method_t sbbc_uart_sbbc_methods[] = { 601206451Smarius /* Device interface */ 602206451Smarius DEVMETHOD(device_probe, sbbc_uart_sbbc_probe), 603206451Smarius DEVMETHOD(device_attach, uart_bus_attach), 604206451Smarius DEVMETHOD(device_detach, uart_bus_detach), 605206451Smarius 606227843Smarius DEVMETHOD_END 607206451Smarius}; 608206451Smarius 609206451SmariusDEFINE_CLASS_0(uart, sbbc_uart_driver, sbbc_uart_sbbc_methods, 610206451Smarius sizeof(struct uart_softc)); 611247574SmariusDRIVER_MODULE(uart, sbbc, sbbc_uart_driver, uart_devclass, NULL, NULL); 612206451Smarius 613206451Smariusstatic int 614206451Smariussbbc_uart_sbbc_probe(device_t dev) 615206451Smarius{ 616206451Smarius struct uart_softc *sc; 617206451Smarius 618206451Smarius sc = device_get_softc(dev); 619206451Smarius sc->sc_class = &uart_sbbc_class; 620206451Smarius device_set_desc(dev, "Serengeti console"); 621340145Smmacy return (uart_bus_probe(dev, 0, 0, 0, SBBC_PCI_BAR, 0, 0)); 622206451Smarius} 623206451Smarius 624206451Smarius/* 625206451Smarius * Low-level UART interface 626206451Smarius */ 627206451Smariusstatic int sbbc_uart_probe(struct uart_bas *bas); 628206451Smariusstatic void sbbc_uart_init(struct uart_bas *bas, int baudrate, int databits, 629206451Smarius int stopbits, int parity); 630206451Smariusstatic void sbbc_uart_term(struct uart_bas *bas); 631206451Smariusstatic void sbbc_uart_putc(struct uart_bas *bas, int c); 632206451Smariusstatic int sbbc_uart_rxready(struct uart_bas *bas); 633206451Smariusstatic int sbbc_uart_getc(struct uart_bas *bas, struct mtx *hwmtx); 634206451Smarius 635206451Smariusstatic struct uart_ops sbbc_uart_ops = { 636206451Smarius .probe = sbbc_uart_probe, 637206451Smarius .init = sbbc_uart_init, 638206451Smarius .term = sbbc_uart_term, 639206451Smarius .putc = sbbc_uart_putc, 640206451Smarius .rxready = sbbc_uart_rxready, 641206451Smarius .getc = sbbc_uart_getc, 642206451Smarius}; 643206451Smarius 644206451Smariusstatic int 645206451Smariussbbc_uart_probe(struct uart_bas *bas) 646206451Smarius{ 647206451Smarius bus_space_tag_t bst; 648206451Smarius bus_space_handle_t bsh; 649206451Smarius int error; 650206451Smarius 651206451Smarius sbbc_console = 1; 652206451Smarius bst = bas->bst; 653206451Smarius bsh = bas->bsh; 654206451Smarius error = sbbc_parse_toc(bst, bsh); 655206451Smarius if (error != 0) 656206451Smarius return (error); 657206451Smarius 658206451Smarius if (sbbc_scsolie == 0 || sbbc_scsolir == 0 || sbbc_solcons == 0 || 659206451Smarius sbbc_solscie == 0 || sbbc_solscir == 0) 660206451Smarius return (ENXIO); 661206451Smarius 662206451Smarius if (SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_magic)) != 663206451Smarius SBBC_CONS_MAGIC || SBBC_SRAM_READ_4(sbbc_solcons + 664206451Smarius SBBC_CONS_OFF(cons_version)) < SBBC_CONS_VERSION) 665206451Smarius return (ENXIO); 666206451Smarius return (0); 667206451Smarius} 668206451Smarius 669206451Smariusstatic void 670206451Smariussbbc_uart_init(struct uart_bas *bas, int baudrate __unused, 671206451Smarius int databits __unused, int stopbits __unused, int parity __unused) 672206451Smarius{ 673206451Smarius bus_space_tag_t bst; 674206451Smarius bus_space_handle_t bsh; 675206451Smarius 676206451Smarius bst = bas->bst; 677206451Smarius bsh = bas->bsh; 678206451Smarius 679206451Smarius /* Enable output to and space in from the SC interrupts. */ 680206451Smarius SBBC_SRAM_WRITE_4(sbbc_solscie, SBBC_SRAM_READ_4(sbbc_solscie) | 681206451Smarius SBBC_SRAM_CONS_OUT | SBBC_SRAM_CONS_SPACE_IN); 682206451Smarius uart_barrier(bas); 683206451Smarius 684206451Smarius /* Take over the console input. */ 685206451Smarius sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_CLNT); 686206451Smarius} 687206451Smarius 688206451Smariusstatic void 689206451Smariussbbc_uart_term(struct uart_bas *bas __unused) 690206451Smarius{ 691206451Smarius 692206451Smarius /* Give back the console input. */ 693206451Smarius sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_OBP); 694206451Smarius} 695206451Smarius 696206451Smariusstatic void 697206451Smariussbbc_uart_putc(struct uart_bas *bas, int c) 698206451Smarius{ 699206451Smarius bus_space_tag_t bst; 700206451Smarius bus_space_handle_t bsh; 701206451Smarius uint32_t wrptr; 702206451Smarius 703206451Smarius bst = bas->bst; 704206451Smarius bsh = bas->bsh; 705206451Smarius 706206451Smarius wrptr = SBBC_SRAM_READ_4(sbbc_solcons + 707206451Smarius SBBC_CONS_OFF(cons_out_wrptr)); 708206451Smarius SBBC_SRAM_WRITE_1(sbbc_solcons + wrptr, c); 709206451Smarius uart_barrier(bas); 710206451Smarius if (++wrptr == SBBC_SRAM_READ_4(sbbc_solcons + 711206451Smarius SBBC_CONS_OFF(cons_out_end))) 712206451Smarius wrptr = SBBC_SRAM_READ_4(sbbc_solcons + 713206451Smarius SBBC_CONS_OFF(cons_out_begin)); 714206451Smarius SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr), 715206451Smarius wrptr); 716206451Smarius uart_barrier(bas); 717206451Smarius 718206451Smarius SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) | 719206451Smarius SBBC_SRAM_CONS_OUT); 720206451Smarius uart_barrier(bas); 721206451Smarius sbbc_send_intr(bst, bsh); 722206451Smarius} 723206451Smarius 724206451Smariusstatic int 725206451Smariussbbc_uart_rxready(struct uart_bas *bas) 726206451Smarius{ 727206451Smarius bus_space_tag_t bst; 728206451Smarius bus_space_handle_t bsh; 729206451Smarius 730206451Smarius bst = bas->bst; 731206451Smarius bsh = bas->bsh; 732206451Smarius 733206451Smarius if (SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr)) == 734206451Smarius SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_wrptr))) 735206451Smarius return (0); 736206451Smarius return (1); 737206451Smarius} 738206451Smarius 739206451Smariusstatic int 740206451Smariussbbc_uart_getc(struct uart_bas *bas, struct mtx *hwmtx) 741206451Smarius{ 742206451Smarius bus_space_tag_t bst; 743206451Smarius bus_space_handle_t bsh; 744206451Smarius int c; 745206451Smarius uint32_t rdptr; 746206451Smarius 747206451Smarius bst = bas->bst; 748206451Smarius bsh = bas->bsh; 749206451Smarius 750206451Smarius uart_lock(hwmtx); 751206451Smarius 752206451Smarius while (sbbc_uart_rxready(bas) == 0) { 753206451Smarius uart_unlock(hwmtx); 754206451Smarius DELAY(4); 755206451Smarius uart_lock(hwmtx); 756206451Smarius } 757206451Smarius 758206451Smarius rdptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr)); 759206451Smarius c = SBBC_SRAM_READ_1(sbbc_solcons + rdptr); 760206451Smarius uart_barrier(bas); 761206451Smarius if (++rdptr == SBBC_SRAM_READ_4(sbbc_solcons + 762206451Smarius SBBC_CONS_OFF(cons_in_end))) 763206451Smarius rdptr = SBBC_SRAM_READ_4(sbbc_solcons + 764206451Smarius SBBC_CONS_OFF(cons_in_begin)); 765206451Smarius SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr), 766206451Smarius rdptr); 767206451Smarius uart_barrier(bas); 768206451Smarius SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) | 769206451Smarius SBBC_SRAM_CONS_SPACE_IN); 770206451Smarius uart_barrier(bas); 771206451Smarius sbbc_send_intr(bst, bsh); 772206451Smarius 773206451Smarius uart_unlock(hwmtx); 774206451Smarius return (c); 775206451Smarius} 776206451Smarius 777206451Smarius/* 778206451Smarius * High-level UART interface 779206451Smarius */ 780206451Smariusstatic int sbbc_uart_bus_attach(struct uart_softc *sc); 781206451Smariusstatic int sbbc_uart_bus_detach(struct uart_softc *sc); 782206451Smariusstatic int sbbc_uart_bus_flush(struct uart_softc *sc, int what); 783206451Smariusstatic int sbbc_uart_bus_getsig(struct uart_softc *sc); 784206451Smariusstatic int sbbc_uart_bus_ioctl(struct uart_softc *sc, int request, 785206451Smarius intptr_t data); 786206451Smariusstatic int sbbc_uart_bus_ipend(struct uart_softc *sc); 787206451Smariusstatic int sbbc_uart_bus_param(struct uart_softc *sc, int baudrate, 788206451Smarius int databits, int stopbits, int parity); 789206451Smariusstatic int sbbc_uart_bus_probe(struct uart_softc *sc); 790206451Smariusstatic int sbbc_uart_bus_receive(struct uart_softc *sc); 791206451Smariusstatic int sbbc_uart_bus_setsig(struct uart_softc *sc, int sig); 792206451Smariusstatic int sbbc_uart_bus_transmit(struct uart_softc *sc); 793206451Smarius 794206451Smariusstatic kobj_method_t sbbc_uart_methods[] = { 795206451Smarius KOBJMETHOD(uart_attach, sbbc_uart_bus_attach), 796206451Smarius KOBJMETHOD(uart_detach, sbbc_uart_bus_detach), 797206451Smarius KOBJMETHOD(uart_flush, sbbc_uart_bus_flush), 798206451Smarius KOBJMETHOD(uart_getsig, sbbc_uart_bus_getsig), 799206451Smarius KOBJMETHOD(uart_ioctl, sbbc_uart_bus_ioctl), 800206451Smarius KOBJMETHOD(uart_ipend, sbbc_uart_bus_ipend), 801206451Smarius KOBJMETHOD(uart_param, sbbc_uart_bus_param), 802206451Smarius KOBJMETHOD(uart_probe, sbbc_uart_bus_probe), 803206451Smarius KOBJMETHOD(uart_receive, sbbc_uart_bus_receive), 804206451Smarius KOBJMETHOD(uart_setsig, sbbc_uart_bus_setsig), 805206451Smarius KOBJMETHOD(uart_transmit, sbbc_uart_bus_transmit), 806206451Smarius 807227843Smarius DEVMETHOD_END 808206451Smarius}; 809206451Smarius 810206451Smariusstruct uart_class uart_sbbc_class = { 811206451Smarius "sbbc", 812206451Smarius sbbc_uart_methods, 813206451Smarius sizeof(struct uart_softc), 814206451Smarius .uc_ops = &sbbc_uart_ops, 815206451Smarius .uc_range = 1, 816281438Sandrew .uc_rclk = 0x5bbc, /* arbitrary */ 817281438Sandrew .uc_rshift = 0 818206451Smarius}; 819206451Smarius 820206451Smarius#define SIGCHG(c, i, s, d) \ 821206451Smarius if ((c) != 0) { \ 822206451Smarius i |= (((i) & (s)) != 0) ? (s) : (s) | (d); \ 823206451Smarius } else { \ 824206451Smarius i = (((i) & (s)) != 0) ? ((i) & ~(s)) | (d) : (i); \ 825206451Smarius } 826206451Smarius 827206451Smariusstatic int 828206451Smariussbbc_uart_bus_attach(struct uart_softc *sc) 829206451Smarius{ 830206451Smarius struct uart_bas *bas; 831206451Smarius bus_space_tag_t bst; 832206451Smarius bus_space_handle_t bsh; 833206451Smarius uint32_t wrptr; 834206451Smarius 835206451Smarius bas = &sc->sc_bas; 836206451Smarius bst = bas->bst; 837206451Smarius bsh = bas->bsh; 838206451Smarius 839206451Smarius uart_lock(sc->sc_hwmtx); 840206451Smarius 841206451Smarius /* 842206451Smarius * Let the current output drain before enabling interrupts. Not 843206451Smarius * doing so tends to cause lost output when turning them on. 844206451Smarius */ 845206451Smarius wrptr = SBBC_SRAM_READ_4(sbbc_solcons + 846206451Smarius SBBC_CONS_OFF(cons_out_wrptr)); 847206451Smarius while (SBBC_SRAM_READ_4(sbbc_solcons + 848206451Smarius SBBC_CONS_OFF(cons_out_rdptr)) != wrptr); 849206451Smarius cpu_spinwait(); 850206451Smarius 851206451Smarius /* Clear and acknowledge possibly outstanding interrupts. */ 852206451Smarius SBBC_SRAM_WRITE_4(sbbc_scsolir, 0); 853206451Smarius uart_barrier(bas); 854206451Smarius SBBC_REGS_WRITE_4(SBBC_PCI_INT_STATUS, 855206451Smarius SBBC_SRAM_READ_4(sbbc_scsolir)); 856206451Smarius uart_barrier(bas); 857206451Smarius /* Enable PCI interrupts. */ 858206451Smarius SBBC_REGS_WRITE_4(SBBC_PCI_INT_ENABLE, SBBC_PCI_ENABLE_INT_A); 859206451Smarius uart_barrier(bas); 860206451Smarius /* Enable input from and output to SC as well as break interrupts. */ 861206451Smarius SBBC_SRAM_WRITE_4(sbbc_scsolie, SBBC_SRAM_READ_4(sbbc_scsolie) | 862206451Smarius SBBC_SRAM_CONS_IN | SBBC_SRAM_CONS_BRK | 863206451Smarius SBBC_SRAM_CONS_SPACE_OUT); 864206451Smarius uart_barrier(bas); 865206451Smarius 866206451Smarius uart_unlock(sc->sc_hwmtx); 867206451Smarius return (0); 868206451Smarius} 869206451Smarius 870206451Smariusstatic int 871206451Smariussbbc_uart_bus_detach(struct uart_softc *sc) 872206451Smarius{ 873206451Smarius 874206451Smarius /* Give back the console input. */ 875206451Smarius sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_OBP); 876206451Smarius return (0); 877206451Smarius} 878206451Smarius 879206451Smariusstatic int 880206451Smariussbbc_uart_bus_flush(struct uart_softc *sc, int what) 881206451Smarius{ 882206451Smarius struct uart_bas *bas; 883206451Smarius bus_space_tag_t bst; 884206451Smarius bus_space_handle_t bsh; 885206451Smarius 886206451Smarius bas = &sc->sc_bas; 887206451Smarius bst = bas->bst; 888206451Smarius bsh = bas->bsh; 889206451Smarius 890206451Smarius if ((what & UART_FLUSH_TRANSMITTER) != 0) 891206451Smarius return (ENODEV); 892206451Smarius if ((what & UART_FLUSH_RECEIVER) != 0) { 893206451Smarius SBBC_SRAM_WRITE_4(sbbc_solcons + 894206451Smarius SBBC_CONS_OFF(cons_in_rdptr), 895206451Smarius SBBC_SRAM_READ_4(sbbc_solcons + 896206451Smarius SBBC_CONS_OFF(cons_in_wrptr))); 897206451Smarius uart_barrier(bas); 898206451Smarius } 899206451Smarius return (0); 900206451Smarius} 901206451Smarius 902206451Smariusstatic int 903206451Smariussbbc_uart_bus_getsig(struct uart_softc *sc) 904206451Smarius{ 905206451Smarius uint32_t dummy, new, old, sig; 906206451Smarius 907206451Smarius do { 908206451Smarius old = sc->sc_hwsig; 909206451Smarius sig = old; 910206451Smarius dummy = 0; 911206451Smarius SIGCHG(dummy, sig, SER_CTS, SER_DCTS); 912206451Smarius SIGCHG(dummy, sig, SER_DCD, SER_DDCD); 913206451Smarius SIGCHG(dummy, sig, SER_DSR, SER_DDSR); 914206451Smarius new = sig & ~SER_MASK_DELTA; 915206451Smarius } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 916206451Smarius return (sig); 917206451Smarius} 918206451Smarius 919206451Smariusstatic int 920206451Smariussbbc_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data) 921206451Smarius{ 922206451Smarius int error; 923206451Smarius 924206451Smarius error = 0; 925206451Smarius uart_lock(sc->sc_hwmtx); 926206451Smarius switch (request) { 927206451Smarius case UART_IOCTL_BAUD: 928206451Smarius *(int*)data = 9600; /* arbitrary */ 929206451Smarius break; 930206451Smarius default: 931206451Smarius error = EINVAL; 932206451Smarius break; 933206451Smarius } 934206451Smarius uart_unlock(sc->sc_hwmtx); 935206451Smarius return (error); 936206451Smarius} 937206451Smarius 938206451Smariusstatic int 939206451Smariussbbc_uart_bus_ipend(struct uart_softc *sc) 940206451Smarius{ 941206451Smarius struct uart_bas *bas; 942206451Smarius bus_space_tag_t bst; 943206451Smarius bus_space_handle_t bsh; 944206451Smarius int ipend; 945206451Smarius uint32_t reason, status; 946206451Smarius 947206451Smarius bas = &sc->sc_bas; 948206451Smarius bst = bas->bst; 949206451Smarius bsh = bas->bsh; 950206451Smarius 951206451Smarius uart_lock(sc->sc_hwmtx); 952206451Smarius status = SBBC_REGS_READ_4(SBBC_PCI_INT_STATUS); 953206451Smarius if (status == 0) { 954206451Smarius uart_unlock(sc->sc_hwmtx); 955206451Smarius return (0); 956206451Smarius } 957206451Smarius 958206451Smarius /* 959206451Smarius * Unfortunately, we can't use compare and swap for non-cachable 960206451Smarius * memory. 961206451Smarius */ 962206451Smarius reason = SBBC_SRAM_READ_4(sbbc_scsolir); 963206451Smarius SBBC_SRAM_WRITE_4(sbbc_scsolir, 0); 964206451Smarius uart_barrier(bas); 965206451Smarius /* Acknowledge the interrupt. */ 966206451Smarius SBBC_REGS_WRITE_4(SBBC_PCI_INT_STATUS, status); 967206451Smarius uart_barrier(bas); 968206451Smarius 969206451Smarius uart_unlock(sc->sc_hwmtx); 970206451Smarius 971206451Smarius ipend = 0; 972206451Smarius if ((reason & SBBC_SRAM_CONS_IN) != 0) 973206451Smarius ipend |= SER_INT_RXREADY; 974206451Smarius if ((reason & SBBC_SRAM_CONS_BRK) != 0) 975206451Smarius ipend |= SER_INT_BREAK; 976206451Smarius if ((reason & SBBC_SRAM_CONS_SPACE_OUT) != 0 && 977206451Smarius SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_rdptr)) == 978206451Smarius SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr))) 979206451Smarius ipend |= SER_INT_TXIDLE; 980206451Smarius return (ipend); 981206451Smarius} 982206451Smarius 983206451Smariusstatic int 984206451Smariussbbc_uart_bus_param(struct uart_softc *sc __unused, int baudrate __unused, 985206451Smarius int databits __unused, int stopbits __unused, int parity __unused) 986206451Smarius{ 987206451Smarius 988206451Smarius return (0); 989206451Smarius} 990206451Smarius 991206451Smariusstatic int 992248965Siansbbc_uart_bus_probe(struct uart_softc *sc) 993206451Smarius{ 994248965Sian struct uart_bas *bas; 995248965Sian bus_space_tag_t bst; 996248965Sian bus_space_handle_t bsh; 997206451Smarius 998248965Sian if (sbbc_console != 0) { 999248965Sian bas = &sc->sc_bas; 1000248965Sian bst = bas->bst; 1001248965Sian bsh = bas->bsh; 1002248965Sian sc->sc_rxfifosz = SBBC_SRAM_READ_4(sbbc_solcons + 1003248965Sian SBBC_CONS_OFF(cons_in_end)) - SBBC_SRAM_READ_4(sbbc_solcons + 1004248965Sian SBBC_CONS_OFF(cons_in_begin)) - 1; 1005248965Sian sc->sc_txfifosz = SBBC_SRAM_READ_4(sbbc_solcons + 1006248965Sian SBBC_CONS_OFF(cons_out_end)) - SBBC_SRAM_READ_4(sbbc_solcons + 1007248965Sian SBBC_CONS_OFF(cons_out_begin)) - 1; 1008206451Smarius return (0); 1009248965Sian } 1010206451Smarius return (ENXIO); 1011206451Smarius} 1012206451Smarius 1013206451Smariusstatic int 1014206451Smariussbbc_uart_bus_receive(struct uart_softc *sc) 1015206451Smarius{ 1016206451Smarius struct uart_bas *bas; 1017206451Smarius bus_space_tag_t bst; 1018206451Smarius bus_space_handle_t bsh; 1019206451Smarius int c; 1020206451Smarius uint32_t end, rdptr, wrptr; 1021206451Smarius 1022206451Smarius bas = &sc->sc_bas; 1023206451Smarius bst = bas->bst; 1024206451Smarius bsh = bas->bsh; 1025206451Smarius 1026206451Smarius uart_lock(sc->sc_hwmtx); 1027206451Smarius 1028206451Smarius end = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_end)); 1029206451Smarius rdptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr)); 1030206451Smarius wrptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_wrptr)); 1031206451Smarius while (rdptr != wrptr) { 1032206451Smarius if (uart_rx_full(sc) != 0) { 1033206451Smarius sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN; 1034206451Smarius break; 1035206451Smarius } 1036206451Smarius c = SBBC_SRAM_READ_1(sbbc_solcons + rdptr); 1037206451Smarius uart_rx_put(sc, c); 1038206451Smarius if (++rdptr == end) 1039206451Smarius rdptr = SBBC_SRAM_READ_4(sbbc_solcons + 1040206451Smarius SBBC_CONS_OFF(cons_in_begin)); 1041206451Smarius } 1042206451Smarius uart_barrier(bas); 1043206451Smarius SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr), 1044206451Smarius rdptr); 1045206451Smarius uart_barrier(bas); 1046206451Smarius SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) | 1047206451Smarius SBBC_SRAM_CONS_SPACE_IN); 1048206451Smarius uart_barrier(bas); 1049206451Smarius sbbc_send_intr(bst, bsh); 1050206451Smarius 1051206451Smarius uart_unlock(sc->sc_hwmtx); 1052206451Smarius return (0); 1053206451Smarius} 1054206451Smarius 1055206451Smariusstatic int 1056206451Smariussbbc_uart_bus_setsig(struct uart_softc *sc, int sig) 1057206451Smarius{ 1058206451Smarius struct uart_bas *bas; 1059206451Smarius uint32_t new, old; 1060206451Smarius 1061206451Smarius bas = &sc->sc_bas; 1062206451Smarius do { 1063206451Smarius old = sc->sc_hwsig; 1064206451Smarius new = old; 1065206451Smarius if ((sig & SER_DDTR) != 0) { 1066206451Smarius SIGCHG(sig & SER_DTR, new, SER_DTR, SER_DDTR); 1067206451Smarius } 1068206451Smarius if ((sig & SER_DRTS) != 0) { 1069206451Smarius SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS); 1070206451Smarius } 1071206451Smarius } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new)); 1072206451Smarius return (0); 1073206451Smarius} 1074206451Smarius 1075206451Smariusstatic int 1076206451Smariussbbc_uart_bus_transmit(struct uart_softc *sc) 1077206451Smarius{ 1078206451Smarius struct uart_bas *bas; 1079206451Smarius bus_space_tag_t bst; 1080206451Smarius bus_space_handle_t bsh; 1081206451Smarius int i; 1082206451Smarius uint32_t end, wrptr; 1083206451Smarius 1084206451Smarius bas = &sc->sc_bas; 1085206451Smarius bst = bas->bst; 1086206451Smarius bsh = bas->bsh; 1087206451Smarius 1088206451Smarius uart_lock(sc->sc_hwmtx); 1089206451Smarius 1090206451Smarius end = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_end)); 1091206451Smarius wrptr = SBBC_SRAM_READ_4(sbbc_solcons + 1092206451Smarius SBBC_CONS_OFF(cons_out_wrptr)); 1093206451Smarius for (i = 0; i < sc->sc_txdatasz; i++) { 1094206451Smarius SBBC_SRAM_WRITE_1(sbbc_solcons + wrptr, sc->sc_txbuf[i]); 1095206451Smarius if (++wrptr == end) 1096206451Smarius wrptr = SBBC_SRAM_READ_4(sbbc_solcons + 1097206451Smarius SBBC_CONS_OFF(cons_out_begin)); 1098206451Smarius } 1099206451Smarius uart_barrier(bas); 1100206451Smarius SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr), 1101206451Smarius wrptr); 1102206451Smarius uart_barrier(bas); 1103206451Smarius SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) | 1104206451Smarius SBBC_SRAM_CONS_OUT); 1105206451Smarius uart_barrier(bas); 1106206451Smarius sbbc_send_intr(bst, bsh); 1107206451Smarius sc->sc_txbusy = 1; 1108206451Smarius 1109206451Smarius uart_unlock(sc->sc_hwmtx); 1110206451Smarius return (0); 1111206451Smarius} 1112