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