The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/altera/jtag_uart/altera_jtag_uart_cons.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2011-2012 Robert N. M. Watson
    3  * All rights reserved.
    4  *
    5  * This software was developed by SRI International and the University of
    6  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
    7  * ("CTSRD"), as part of the DARPA CRASH research programme.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 #include <sys/param.h>
   35 #include <sys/bus.h>
   36 #include <sys/cons.h>
   37 #include <sys/endian.h>
   38 #include <sys/kdb.h>
   39 #include <sys/kernel.h>
   40 #include <sys/lock.h>
   41 #include <sys/mutex.h>
   42 #include <sys/reboot.h>
   43 #include <sys/systm.h>
   44 #include <sys/tty.h>
   45 
   46 #include <ddb/ddb.h>
   47 
   48 #include <dev/altera/jtag_uart/altera_jtag_uart.h>
   49 
   50 devclass_t      altera_jtag_uart_devclass;
   51 
   52 /*
   53  * One-byte buffer as we can't check whether the UART is readable without
   54  * actually reading from it, synchronised by a spinlock; this lock also
   55  * synchronises access to the I/O ports for non-atomic sequences.  These
   56  * symbols are public so that the TTY layer can use them when working on an
   57  * instance of the UART that is also a low-level console.
   58  */
   59 char            aju_cons_buffer_data;
   60 int             aju_cons_buffer_valid;
   61 int             aju_cons_jtag_present;
   62 u_int           aju_cons_jtag_missed;
   63 struct mtx      aju_cons_lock;
   64 
   65 /*
   66  * Low-level console driver functions.
   67  */
   68 static cn_probe_t       aju_cnprobe;
   69 static cn_init_t        aju_cninit;
   70 static cn_term_t        aju_cnterm;
   71 static cn_getc_t        aju_cngetc;
   72 static cn_putc_t        aju_cnputc;
   73 static cn_grab_t        aju_cngrab;
   74 static cn_ungrab_t      aju_cnungrab;
   75 
   76 /*
   77  * JTAG sets the ALTERA_JTAG_UART_CONTROL_AC bit whenever it accesses the
   78  * FIFO.  This allows us to (sort of) tell when JTAG is present, so that we
   79  * can adopt lossy, rather than blocking, behaviour when JTAG isn't there.
   80  * When it is present, we do full flow control.  This delay is how long we
   81  * wait to see if JTAG has really disappeared when finding a full buffer and
   82  * no AC bit set.
   83  */
   84 #define ALTERA_JTAG_UART_AC_POLL_DELAY  10000
   85 
   86 /*
   87  * I/O routines lifted from Deimos.  This is not only MIPS-specific, but also
   88  * BERI-specific, as we're hard coding the address at which we expect to
   89  * find the Altera JTAG UART and using it unconditionally.  We use these
   90  * low-level routines so that we can perform console I/O long before newbus
   91  * has initialised and devices have attached.  The TTY layer of the driver
   92  * knows about this, and uses the console-layer spinlock instead of the
   93  * TTY-layer lock to avoid confusion between layers for the console UART.
   94  *
   95  * XXXRW: The only place this inter-layer behaviour breaks down is if the
   96  * low-level console is used for polled read while the TTY driver is also
   97  * looking for input.  Probably we should also share buffers between layers.
   98  */
   99 #define MIPS_XKPHYS_UNCACHED_BASE       0x9000000000000000
  100 
  101 typedef uint64_t        paddr_t;
  102 typedef uint64_t        vaddr_t;
  103 
  104 static inline vaddr_t
  105 mips_phys_to_uncached(paddr_t phys)            
  106 {
  107 
  108         return (phys | MIPS_XKPHYS_UNCACHED_BASE);
  109 }
  110 
  111 static inline uint32_t
  112 mips_ioread_uint32(vaddr_t vaddr)
  113 {
  114         uint32_t v;
  115 
  116         __asm__ __volatile__ ("lw %0, 0(%1)" : "=r" (v) : "r" (vaddr));
  117         return (v);
  118 }
  119 
  120 static inline void
  121 mips_iowrite_uint32(vaddr_t vaddr, uint32_t v)
  122 {
  123 
  124         __asm__ __volatile__ ("sw %0, 0(%1)" : : "r" (v), "r" (vaddr));
  125 }
  126 
  127 /*
  128  * Little-endian versions of 32-bit I/O routines.
  129  */
  130 static inline uint32_t
  131 mips_ioread_uint32le(vaddr_t vaddr)
  132 {
  133 
  134         return (le32toh(mips_ioread_uint32(vaddr)));
  135 }
  136 
  137 static inline void
  138 mips_iowrite_uint32le(vaddr_t vaddr, uint32_t v)
  139 {
  140 
  141         mips_iowrite_uint32(vaddr, htole32(v));
  142 }
  143 
  144 /*
  145  * Low-level read and write register routines; the Altera UART is little
  146  * endian, so we byte swap 32-bit reads and writes.
  147  */
  148 static inline uint32_t
  149 aju_cons_data_read(void)
  150 {
  151 
  152         return (mips_ioread_uint32le(mips_phys_to_uncached(BERI_UART_BASE +
  153             ALTERA_JTAG_UART_DATA_OFF)));
  154 }
  155 
  156 static inline void
  157 aju_cons_data_write(uint32_t v)
  158 {
  159 
  160         mips_iowrite_uint32le(mips_phys_to_uncached(BERI_UART_BASE +
  161             ALTERA_JTAG_UART_DATA_OFF), v);
  162 }
  163 
  164 static inline uint32_t
  165 aju_cons_control_read(void)
  166 {
  167 
  168         return (mips_ioread_uint32le(mips_phys_to_uncached(BERI_UART_BASE +
  169             ALTERA_JTAG_UART_CONTROL_OFF)));
  170 }
  171 
  172 static inline void
  173 aju_cons_control_write(uint32_t v)
  174 {
  175 
  176         mips_iowrite_uint32le(mips_phys_to_uncached(BERI_UART_BASE +
  177             ALTERA_JTAG_UART_CONTROL_OFF), v);
  178 }
  179 
  180 /*
  181  * Slightly higher-level routines aware of buffering and flow control.
  182  */
  183 static int
  184 aju_cons_readable(void)
  185 {
  186         uint32_t v;
  187 
  188         AJU_CONSOLE_LOCK_ASSERT();
  189 
  190         if (aju_cons_buffer_valid)
  191                 return (1);
  192         v = aju_cons_data_read();
  193         if ((v & ALTERA_JTAG_UART_DATA_RVALID) != 0) {
  194                 aju_cons_buffer_valid = 1;
  195                 aju_cons_buffer_data = (v & ALTERA_JTAG_UART_DATA_DATA);
  196                 return (1);
  197         }
  198         return (0);
  199 }
  200 
  201 static void
  202 aju_cons_write(char ch)
  203 {
  204         uint32_t v;
  205 
  206         AJU_CONSOLE_LOCK_ASSERT();
  207 
  208         /*
  209          * The flow control logic here is somewhat subtle: we want to wait for
  210          * write buffer space only while JTAG is present.  However, we can't
  211          * directly ask if JTAG is present -- just whether it's been seen
  212          * since we last cleared the ALTERA_JTAG_UART_CONTROL_AC bit.  As
  213          * such, implement a polling loop in which we both wait for space and
  214          * try to decide whether JTAG has disappeared on us.  We will have to
  215          * wait one complete polling delay to detect that JTAG has gone away,
  216          * but otherwise shouldn't wait any further once it has gone.  And we
  217          * had to wait for buffer space anyway, if it was there.
  218          *
  219          * If JTAG is spotted, reset the TTY-layer miss counter so console-
  220          * layer clearing of the bit doesn't trigger a TTY-layer
  221          * disconnection.
  222          *
  223          * XXXRW: The polling delay may require tuning.
  224          *
  225          * XXXRW: Notice the inherent race with hardware: in clearing the
  226          * bit, we may race with hardware setting the same bit.
  227          */
  228         v = aju_cons_control_read();
  229         if (v & ALTERA_JTAG_UART_CONTROL_AC) {
  230                 aju_cons_jtag_present = 1;
  231                 aju_cons_jtag_missed = 0;
  232                 v &= ~ALTERA_JTAG_UART_CONTROL_AC;
  233                 aju_cons_control_write(v);
  234         }
  235         while ((v & ALTERA_JTAG_UART_CONTROL_WSPACE) == 0) {
  236                 if (!aju_cons_jtag_present)
  237                         return;
  238                 DELAY(ALTERA_JTAG_UART_AC_POLL_DELAY);
  239                 v = aju_cons_control_read();
  240                 if (v & ALTERA_JTAG_UART_CONTROL_AC) {
  241                         aju_cons_jtag_present = 1;
  242                         v &= ~ALTERA_JTAG_UART_CONTROL_AC;
  243                         aju_cons_control_write(v);
  244                 } else
  245                         aju_cons_jtag_present = 0;
  246         }
  247         aju_cons_data_write(ch);
  248 }
  249 
  250 static char
  251 aju_cons_read(void)
  252 {
  253 
  254         AJU_CONSOLE_LOCK_ASSERT();
  255 
  256         while (!aju_cons_readable());
  257         aju_cons_buffer_valid = 0;
  258         return (aju_cons_buffer_data);
  259 }
  260 
  261 /*
  262  * Implementation of a FreeBSD low-level, polled console driver.
  263  */
  264 static void
  265 aju_cnprobe(struct consdev *cp)
  266 {
  267 
  268         sprintf(cp->cn_name, "%s%d", AJU_TTYNAME, 0);
  269         cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
  270 }
  271 
  272 static void
  273 aju_cninit(struct consdev *cp)
  274 {
  275         uint32_t v;
  276 
  277         AJU_CONSOLE_LOCK_INIT();
  278 
  279         AJU_CONSOLE_LOCK();
  280         v = aju_cons_control_read();
  281         v &= ~ALTERA_JTAG_UART_CONTROL_AC;
  282         aju_cons_control_write(v);
  283         AJU_CONSOLE_UNLOCK();
  284 }
  285 
  286 static void
  287 aju_cnterm(struct consdev *cp)
  288 {
  289 
  290 }
  291 
  292 static int
  293 aju_cngetc(struct consdev *cp)
  294 {
  295         int ret;
  296 
  297         AJU_CONSOLE_LOCK();
  298         ret = aju_cons_read();
  299         AJU_CONSOLE_UNLOCK();
  300         return (ret);
  301 }
  302 
  303 static void
  304 aju_cnputc(struct consdev *cp, int c)
  305 {
  306 
  307         AJU_CONSOLE_LOCK();
  308         aju_cons_write(c);
  309         AJU_CONSOLE_UNLOCK();
  310 }
  311 
  312 static void
  313 aju_cngrab(struct consdev *cp)
  314 {
  315 
  316 }
  317 
  318 static void
  319 aju_cnungrab(struct consdev *cp)
  320 {
  321 
  322 }
  323 
  324 CONSOLE_DRIVER(aju);

Cache object: b57d068f0af7753f98ac447e34d6c214


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.