Contiki 3.x
uart-16x50.c
1 /*
2  * Copyright (C) 2015, Intel Corporation. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  *
13  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include <stdlib.h>
32 #include "helpers.h"
33 #include "paging.h"
34 #include "prot-domains.h"
35 #include "syscalls.h"
36 #include "uart-16x50.h"
37 
38 /* Refer to Intel Quark SoC X1000 Datasheet, Chapter 18 for more details on
39  * UART operation.
40  */
41 
42 /* Divisor Latch Access Bit (DLAB) mask for Line Control Register (LCR).
43  *
44  * When bit is set, enables access to divisor registers to set baud rate. When
45  * clear, enables access to other registers mapped to the same addresses as the
46  * divisor registers.
47  */
48 #define UART_LCR_7_DLAB BIT(7)
49 /* Setting for LCR that configures the UART to operate with no parity, 1 stop
50  * bit, and eight bits per character.
51  */
52 #define UART_LCR_8BITS 0x03
53 
54 /* FIFO Control Register (FCR) bitmasks */
55 #define UART_FCR_0_FIFOE BIT(0) /*< enable FIFOs */
56 #define UART_FCR_1_RFIFOR BIT(1) /*< reset RX FIFO */
57 #define UART_FCR_2_XFIFOR BIT(2) /*< reset TX FIFO */
58 
59 /* Line Status Register (LSR) Transmit Holding Register Empty bitmask to check
60  * whether the Transmit Holding Register (THR) or TX FIFO is empty.
61  */
62 #define UART_LSR_5_THRE BIT(5)
63 
64 /* MMIO registers for UART */
65 typedef struct uart_16x50_regs {
66  volatile uint32_t rbr_thr_dll, ier_dlh, iir_fcr, lcr;
67  volatile uint32_t mcr, lsr, msr, scr, usr, htx, dmasa;
68 } uart_16x50_regs_t;
69 
70 #if X86_CONF_PROT_DOMAINS == X86_CONF_PROT_DOMAINS__PAGING
71 /* When paging-based protection domains are in use, at least one page of memory
72  * must be reserved to facilitate access to the MMIO region, since that is the
73  * smallest unit of memory that can be managed with paging:
74  */
75 #define UART_MMIO_SZ MIN_PAGE_SIZE
76 #else
77 /* Multi-segment protection domain implementations can control memory with
78  * byte granularity. Thus, only the registers defined in the uart_16x50_regs
79  * structure are included in the MMIO region allocated for this protection
80  * domain:
81  */
82 #define UART_MMIO_SZ sizeof(uart_16x50_regs_t)
83 #endif
84 
85 void uart_16x50_setup(uart_16x50_driver_t c_this, uint16_t dl);
86 
87 /*---------------------------------------------------------------------------*/
88 SYSCALLS_DEFINE(uart_16x50_setup, uart_16x50_driver_t c_this, uint16_t dl)
89 {
90  uart_16x50_regs_t ATTR_MMIO_ADDR_SPACE *regs =
91  (uart_16x50_regs_t ATTR_MMIO_ADDR_SPACE *)PROT_DOMAINS_MMIO(c_this);
92 
93  prot_domains_enable_mmio();
94 
95  /* Set the DLAB bit to enable access to divisor settings. */
96  MMIO_WRITEL(regs->lcr, UART_LCR_7_DLAB);
97 
98  /* The divisor settings configure the baud rate, and may need to be defined
99  * on a per-device basis.
100  */
101  MMIO_WRITEL(regs->rbr_thr_dll, dl & UINT8_MAX);
102  MMIO_WRITEL(regs->ier_dlh, dl >> 8);
103 
104  /* Clear the DLAB bit to enable access to other settings and configure other
105  * UART parameters.
106  */
107  MMIO_WRITEL(regs->lcr, UART_LCR_8BITS);
108 
109  /* Enable the FIFOs. */
110  MMIO_WRITEL(regs->iir_fcr,
111  UART_FCR_0_FIFOE | UART_FCR_1_RFIFOR | UART_FCR_2_XFIFOR);
112 
113  prot_domains_disable_mmio();
114 }
115 /*---------------------------------------------------------------------------*/
116 /**
117  * \brief Transmit a character through a UART.
118  * \param c_this Initialized structure representing the device.
119  * \param c Character to be transmitted.
120  *
121  * This procedure will block indefinitely until the UART is ready
122  * to accept the character to be transmitted.
123  */
124 SYSCALLS_DEFINE(uart_16x50_tx, uart_16x50_driver_t c_this, uint8_t c)
125 {
126  uint32_t ready;
127  uart_16x50_regs_t ATTR_MMIO_ADDR_SPACE *regs =
128  (uart_16x50_regs_t ATTR_MMIO_ADDR_SPACE *)PROT_DOMAINS_MMIO(c_this);
129 
130  prot_domains_enable_mmio();
131 
132  /* Wait for space in TX FIFO. */
133  do {
134  MMIO_READL(ready, regs->lsr);
135  } while((ready & UART_LSR_5_THRE) == 0);
136 
137  /* Add character to TX FIFO. */
138  MMIO_WRITEL(regs->rbr_thr_dll, c);
139 
140  prot_domains_disable_mmio();
141 }
142 /*---------------------------------------------------------------------------*/
143 /**
144  * \brief Initialize an MMIO-programmable 16X50 UART.
145  * \param c_this Structure that will be initialized to represent the device.
146  * \param pci_addr PCI address of device.
147  * \param dl Divisor setting to configure the baud rate.
148  */
149 void
150 uart_16x50_init(uart_16x50_driver_t ATTR_KERN_ADDR_SPACE *c_this,
151  pci_config_addr_t pci_addr,
152  uint16_t dl)
153 {
154  uart_16x50_driver_t loc_c_this;
155 
156  /* This assumes that the UART had an MMIO range assigned to it by the
157  * firmware during boot.
158  */
159  pci_init(c_this, pci_addr, UART_MMIO_SZ, 0, 0);
160  SYSCALLS_INIT(uart_16x50_setup);
161  SYSCALLS_AUTHZ(uart_16x50_setup, *c_this);
162  SYSCALLS_INIT(uart_16x50_tx);
163  SYSCALLS_AUTHZ(uart_16x50_tx, *c_this);
164 
165  prot_domains_copy_dcd(&loc_c_this, c_this);
166 
167  uart_16x50_setup(loc_c_this, dl);
168 }
169 /*---------------------------------------------------------------------------*/
PCI configuration address.
Definition: pci.h:85
Data associated with each protection domain that is owned by clients of that domain and used to ident...
Definition: prot-domains.h:247