1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2012 Juli Mallett <jmallett@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31#include <sys/cdefs.h> 32__FBSDID("$FreeBSD$"); 33 34#include <sys/param.h> 35#include <sys/systm.h> 36#include <sys/bus.h> 37#include <sys/conf.h> 38#include <sys/cons.h> 39#include <sys/kernel.h> 40#include <sys/reboot.h> 41 42#include <contrib/octeon-sdk/cvmx.h> 43#include <contrib/octeon-sdk/cvmx-bootmem.h> 44#include <contrib/octeon-sdk/cvmx-interrupt.h> 45#include <contrib/octeon-sdk/octeon-pci-console.h> 46 47#ifdef OCTEON_VENDOR_RADISYS 48#define OPCIC_FLAG_RSYS (0x00000001) 49 50#define OPCIC_RSYS_FIFO_SIZE (0x2000) 51#endif 52 53struct opcic_softc { 54 unsigned sc_flags; 55 uint64_t sc_base_addr; 56}; 57 58static struct opcic_softc opcic_instance; 59 60static cn_probe_t opcic_cnprobe; 61static cn_init_t opcic_cninit; 62static cn_term_t opcic_cnterm; 63static cn_getc_t opcic_cngetc; 64static cn_putc_t opcic_cnputc; 65static cn_grab_t opcic_cngrab; 66static cn_ungrab_t opcic_cnungrab; 67 68#ifdef OCTEON_VENDOR_RADISYS 69static int opcic_rsys_cngetc(struct opcic_softc *); 70static void opcic_rsys_cnputc(struct opcic_softc *, int); 71#endif 72 73CONSOLE_DRIVER(opcic); 74 75static void 76opcic_cnprobe(struct consdev *cp) 77{ 78 const struct cvmx_bootmem_named_block_desc *pci_console_block; 79 struct opcic_softc *sc; 80 81 sc = &opcic_instance; 82 sc->sc_flags = 0; 83 sc->sc_base_addr = 0; 84 85 cp->cn_pri = CN_DEAD; 86 87 switch (cvmx_sysinfo_get()->board_type) { 88#ifdef OCTEON_VENDOR_RADISYS 89 case CVMX_BOARD_TYPE_CUST_RADISYS_RSYS4GBE: 90 pci_console_block = 91 cvmx_bootmem_find_named_block("rsys_gbl_memory"); 92 if (pci_console_block != NULL) { 93 sc->sc_flags |= OPCIC_FLAG_RSYS; 94 sc->sc_base_addr = pci_console_block->base_addr; 95 break; 96 } 97#endif 98 default: 99 pci_console_block = 100 cvmx_bootmem_find_named_block(OCTEON_PCI_CONSOLE_BLOCK_NAME); 101 if (pci_console_block == NULL) 102 return; 103 sc->sc_base_addr = pci_console_block->base_addr; 104 break; 105 } 106 107 cp->cn_arg = sc; 108 snprintf(cp->cn_name, sizeof cp->cn_name, "opcic@%p", cp->cn_arg); 109 cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL; 110} 111 112static void 113opcic_cninit(struct consdev *cp) 114{ 115 (void)cp; 116} 117 118static void 119opcic_cnterm(struct consdev *cp) 120{ 121 (void)cp; 122} 123 124static int 125opcic_cngetc(struct consdev *cp) 126{ 127 struct opcic_softc *sc; 128 char ch; 129 int rv; 130 131 sc = cp->cn_arg; 132 133#ifdef OCTEON_VENDOR_RADISYS 134 if ((sc->sc_flags & OPCIC_FLAG_RSYS) != 0) 135 return (opcic_rsys_cngetc(sc)); 136#endif 137 138 rv = octeon_pci_console_read(sc->sc_base_addr, 0, &ch, 1, 139 OCT_PCI_CON_FLAG_NONBLOCK); 140 if (rv != 1) 141 return (-1); 142 return (ch); 143} 144 145static void 146opcic_cnputc(struct consdev *cp, int c) 147{ 148 struct opcic_softc *sc; 149 char ch; 150 int rv; 151 152 sc = cp->cn_arg; 153 ch = c; 154 155#ifdef OCTEON_VENDOR_RADISYS 156 if ((sc->sc_flags & OPCIC_FLAG_RSYS) != 0) { 157 opcic_rsys_cnputc(sc, c); 158 return; 159 } 160#endif 161 162 rv = octeon_pci_console_write(sc->sc_base_addr, 0, &ch, 1, 0); 163 if (rv == -1) 164 panic("%s: octeon_pci_console_write failed.", __func__); 165} 166 167static void 168opcic_cngrab(struct consdev *cp) 169{ 170 (void)cp; 171} 172 173static void 174opcic_cnungrab(struct consdev *cp) 175{ 176 (void)cp; 177} 178 179#ifdef OCTEON_VENDOR_RADISYS 180static int 181opcic_rsys_cngetc(struct opcic_softc *sc) 182{ 183 uint64_t gbl_base; 184 uint64_t console_base; 185 uint64_t console_rbuf; 186 uint64_t console_rcnt[2]; 187 uint16_t rcnt[2]; 188 uint16_t roff; 189 int c; 190 191 gbl_base = CVMX_ADD_IO_SEG(sc->sc_base_addr); 192 console_base = gbl_base + 0x10; 193 194 console_rbuf = console_base + 0x2018; 195 console_rcnt[0] = console_base + 0x08; 196 console_rcnt[1] = console_base + 0x0a; 197 198 /* Check if there is anything new in the FIFO. */ 199 rcnt[0] = cvmx_read64_uint16(console_rcnt[0]); 200 rcnt[1] = cvmx_read64_uint16(console_rcnt[1]); 201 if (rcnt[0] == rcnt[1]) 202 return (-1); 203 204 /* Get first new character in the FIFO. */ 205 if (rcnt[0] != 0) 206 roff = rcnt[0] - 1; 207 else 208 roff = OPCIC_RSYS_FIFO_SIZE - 1; 209 c = cvmx_read64_uint8(console_rbuf + roff); 210 211 /* Advance FIFO. */ 212 rcnt[1] = (rcnt[1] + 1) % OPCIC_RSYS_FIFO_SIZE; 213 cvmx_write64_uint16(console_rcnt[1], rcnt[1]); 214 215 return (c); 216} 217 218static void 219opcic_rsys_cnputc(struct opcic_softc *sc, int c) 220{ 221 uint64_t gbl_base; 222 uint64_t console_base; 223 uint64_t console_wbuf; 224 uint64_t console_wcnt; 225 uint16_t wcnt; 226 227 gbl_base = CVMX_ADD_IO_SEG(sc->sc_base_addr); 228 console_base = gbl_base + 0x10; 229 230 console_wbuf = console_base + 0x0018; 231 console_wcnt = console_base + 0x0c; 232 233 /* Append character to FIFO. */ 234 wcnt = cvmx_read64_uint16(console_wcnt) % OPCIC_RSYS_FIFO_SIZE; 235 cvmx_write64_uint8(console_wbuf + wcnt, (uint8_t)c); 236 cvmx_write64_uint16(console_wcnt, wcnt + 1); 237} 238#endif 239