github.com/f-secure-foundry/tamago@v0.0.0-20220307101044-d73fcdd7f11b/soc/imx6/uart.go (about) 1 // NXP i.MX6 UART driver 2 // https://github.com/f-secure-foundry/tamago 3 // 4 // Copyright (c) F-Secure Corporation 5 // https://foundry.f-secure.com 6 // 7 // Use of this source code is governed by the license 8 // that can be found in the LICENSE file. 9 10 package imx6 11 12 import ( 13 "sync" 14 15 "github.com/f-secure-foundry/tamago/bits" 16 "github.com/f-secure-foundry/tamago/internal/reg" 17 ) 18 19 // UART registers 20 const ( 21 UART_DEFAULT_BAUDRATE = 115200 22 ESC = 0x1b 23 24 // p3608, 55.15 UART Memory Map/Register Definition, IMX6ULLRM 25 26 // i.MX 6UltraLite (G0, G1, G2, G3, G4) 27 // i.MX 6ULL (Y0, Y1, Y2) 28 // i.MX 6ULZ (Z0) 29 UART1_BASE = 0x02020000 30 UART2_BASE = 0x021e8000 31 UART3_BASE = 0x021ec000 32 UART4_BASE = 0x021f0000 33 34 // i.MX 6UltraLite (G1, G2, G3, G4) 35 // i.MX 6ULL (Y1, Y2) 36 UART5_BASE = 0x021f4000 37 UART6_BASE = 0x021fc000 38 UART7_BASE = 0x02018000 39 UART8_BASE = 0x02024000 40 41 UARTx_URXD = 0x0000 42 URXD_CHARRDY = 15 43 URXD_ERR = 14 44 URXD_OVRRUN = 13 45 URXD_FRMERR = 12 46 URXD_BRK = 11 47 URXD_PRERR = 10 48 URXD_RX_DATA = 0 49 50 UARTx_UTXD = 0x0040 51 UTXD_TX_DATA = 0 52 53 UARTx_UCR1 = 0x0080 54 UCR1_ADEN = 15 55 UCR1_ADBR = 14 56 UCR1_TRDYEN = 13 57 UCR1_IDEN = 12 58 UCR1_ICD = 10 59 UCR1_RRDYEN = 9 60 UCR1_RXDMAEN = 8 61 UCR1_IREN = 7 62 UCR1_TXMPTYEN = 6 63 UCR1_RTSDEN = 5 64 UCR1_SNDBRK = 4 65 UCR1_TXDMAEN = 3 66 UCR1_ATDMAEN = 2 67 UCR1_DOZE = 1 68 UCR1_UARTEN = 0 69 70 UARTx_UCR2 = 0x0084 71 UCR2_ESCI = 15 72 UCR2_IRTS = 14 73 UCR2_CTSC = 13 74 UCR2_CTS = 12 75 UCR2_ESCEN = 11 76 UCR2_RTEC = 9 77 UCR2_PREN = 8 78 UCR2_PROE = 7 79 UCR2_STPB = 6 80 UCR2_WS = 5 81 UCR2_RTSEN = 4 82 UCR2_ATEN = 3 83 UCR2_TXEN = 2 84 UCR2_RXEN = 1 85 UCR2_SRST = 0 86 87 UARTx_UCR3 = 0x0088 88 UCR3_DPEC = 14 89 UCR3_DTREN = 13 90 UCR3_PARERREN = 12 91 UCR3_FRAERREN = 11 92 UCR3_DSR = 10 93 UCR3_DCD = 9 94 UCR3_RI = 8 95 UCR3_ADNIMP = 7 96 UCR3_RXDSEN = 6 97 UCR3_AIRINTEN = 5 98 UCR3_AWAKEN = 4 99 UCR3_DTRDEN = 3 100 UCR3_RXDMUXSEL = 2 101 UCR3_INVT = 1 102 UCR3_ACIEN = 0 103 104 UARTx_UCR4 = 0x008c 105 UCR4_CTSTL = 10 106 107 UARTx_UFCR = 0x0090 108 UFCR_TXTL = 10 109 UFCR_RFDIV = 7 110 UFCR_DCEDTE = 6 111 UFCR_RXTL = 0 112 113 UARTx_USR2 = 0x0098 114 USR2_RDR = 0 115 116 UARTx_UESC = 0x009c 117 UARTx_UTIM = 0x00a0 118 UARTx_UBIR = 0x00a4 119 UARTx_UBMR = 0x00a8 120 121 UARTx_UTS = 0x00b4 122 UTS_TXFULL = 4 123 ) 124 125 // UART represents a serial port instance 126 type UART struct { 127 sync.Mutex 128 129 // controller index 130 n int 131 132 // port speed 133 Baudrate uint32 134 // DTE mode 135 DTE bool 136 // hardware flow control 137 Flow bool 138 139 // control registers 140 urxd uint32 141 utxd uint32 142 ucr1 uint32 143 ucr2 uint32 144 ucr3 uint32 145 ucr4 uint32 146 ufcr uint32 147 usr2 uint32 148 uesc uint32 149 utim uint32 150 ubir uint32 151 ubmr uint32 152 uts uint32 153 } 154 155 // UART1 instance 156 var UART1 = &UART{ 157 n: 1, 158 Baudrate: UART_DEFAULT_BAUDRATE, 159 } 160 161 // UART2 instance 162 var UART2 = &UART{ 163 n: 2, 164 Baudrate: UART_DEFAULT_BAUDRATE, 165 } 166 167 // Init initializes and enables the UART for RS-232 mode, 168 // p3605, 55.13.1 Programming the UART in RS-232 mode, IMX6ULLRM. 169 func (hw *UART) Init() { 170 var base uint32 171 172 hw.Lock() 173 174 switch hw.n { 175 case 1: 176 base = UART1_BASE 177 case 2: 178 base = UART2_BASE 179 case 3: 180 base = UART3_BASE 181 case 4: 182 base = UART4_BASE 183 default: 184 panic("invalid UART controller instance") 185 } 186 187 hw.urxd = base + UARTx_URXD 188 hw.utxd = base + UARTx_UTXD 189 hw.ucr1 = base + UARTx_UCR1 190 hw.ucr2 = base + UARTx_UCR2 191 hw.ucr3 = base + UARTx_UCR3 192 hw.ucr4 = base + UARTx_UCR4 193 hw.ufcr = base + UARTx_UFCR 194 hw.usr2 = base + UARTx_USR2 195 hw.uesc = base + UARTx_UESC 196 hw.utim = base + UARTx_UTIM 197 hw.ubir = base + UARTx_UBIR 198 hw.ubmr = base + UARTx_UBMR 199 hw.uts = base + UARTx_UTS 200 201 hw.setup() 202 203 hw.Unlock() 204 } 205 206 func uartclk() uint32 { 207 var freq uint32 208 209 if reg.Get(CCM_CSCDR1, CSCDR1_UART_CLK_SEL, 0b1) == 1 { 210 freq = OSC_FREQ 211 } else { 212 // match /6 static divider (p630, Figure 18-3. Clock Tree - Part 2, IMX6ULLRM) 213 freq = PLL3_FREQ / 6 214 } 215 216 podf := reg.Get(CCM_CSCDR1, CSCDR1_UART_CLK_PODF, 0b111111) 217 218 return freq / (podf + 1) 219 } 220 221 func (hw *UART) txFull() bool { 222 return reg.Get(hw.uts, UTS_TXFULL, 1) == 1 223 } 224 225 func (hw *UART) rxReady() bool { 226 return reg.Get(hw.usr2, USR2_RDR, 1) == 1 227 } 228 229 func (hw *UART) setup() { 230 // disable UART 231 reg.Write(hw.ucr1, 0) 232 reg.Write(hw.ucr2, 0) 233 234 // wait for software reset deassertion 235 reg.Wait(hw.ucr2, UCR2_SRST, 1, 1) 236 237 var ucr3 uint32 238 // Data Set Ready 239 bits.Set(&ucr3, UCR3_DSR) 240 // Data Carrier Detect 241 bits.Set(&ucr3, UCR3_DCD) 242 // Ring Indicator 243 bits.Set(&ucr3, UCR3_RI) 244 // Disable autobaud detection 245 bits.Set(&ucr3, UCR3_ADNIMP) 246 // UART is in MUXED mode 247 bits.Set(&ucr3, UCR3_RXDMUXSEL) 248 // set UCR3 249 reg.Write(hw.ucr3, ucr3) 250 251 // set escape character 252 reg.Write(hw.uesc, ESC) 253 // reset escape timer 254 reg.Write(hw.utim, 0) 255 256 var ufcr uint32 257 // Divide input clock by 2 258 bits.SetN(&ufcr, UFCR_RFDIV, 0b111, 0b100) 259 // TxFIFO has 2 or fewer characters 260 bits.SetN(&ufcr, UFCR_TXTL, 0b111111, 2) 261 // RxFIFO has 1 character 262 bits.SetN(&ufcr, UFCR_RXTL, 0b111111, 1) 263 264 if hw.DTE { 265 bits.Set(&ufcr, UFCR_DCEDTE) 266 } 267 268 // set UFCR 269 reg.Write(hw.ufcr, ufcr) 270 271 // p3592, 55.5 Binary Rate Multiplier (BRM), IMX6ULLRM 272 // 273 // ref_clk_freq 274 // baudrate = ----------------- 275 // UBMR + 1 276 // 16 * ---------- 277 // UBIR + 1 278 // 279 // ref_clk_freq = module_clock 280 281 // multiply to match UFCR_RFDIV divider value 282 ubmr := uartclk() / (2 * hw.Baudrate) 283 // neutralize denominator 284 reg.Write(hw.ubir, 15) 285 // set UBMR 286 reg.Write(hw.ubmr, ubmr) 287 288 var ucr2 uint32 289 // 8-bit transmit and receive character length 290 bits.Set(&ucr2, UCR2_WS) 291 // Enable the transmitter 292 bits.Set(&ucr2, UCR2_TXEN) 293 // Enable the receiver 294 bits.Set(&ucr2, UCR2_RXEN) 295 // Software reset 296 bits.Set(&ucr2, UCR2_SRST) 297 298 if hw.Flow { 299 // Receiver controls CTS 300 bits.Set(&ucr2, UCR2_CTSC) 301 302 // 16 characters in the RxFIFO as the maximum value leads to 303 // overflow even with hardware flow control in place. 304 reg.SetN(hw.ucr4, UCR4_CTSTL, 0b111111, 16) 305 } else { 306 // Ignore the RTS pin 307 bits.Set(&ucr2, UCR2_IRTS) 308 309 // 32 characters in the RxFIFO (maximum) 310 reg.SetN(hw.ucr4, UCR4_CTSTL, 0b111111, 32) 311 } 312 313 // set UCR2 314 reg.Write(hw.ucr2, ucr2) 315 // Enable the UART 316 reg.Set(hw.ucr1, UCR1_UARTEN) 317 } 318 319 // Enable enables the UART, this is only required after an explicit disable 320 // (see Disable()) as initialized interfaces (see Init()) are enabled by default. 321 func (hw *UART) Enable() { 322 reg.Set(hw.ucr1, UCR1_UARTEN) 323 } 324 325 // Disable disables the UART. 326 func (hw *UART) Disable() { 327 reg.Clear(hw.ucr1, UCR1_UARTEN) 328 } 329 330 // Tx transmits a single character to the serial port. 331 func (hw *UART) Tx(c byte) { 332 for hw.txFull() { 333 // wait for TX FIFO to have room for a character 334 } 335 reg.Write(hw.utxd, uint32(c)) 336 } 337 338 // Rx receives a single character from the serial port. 339 func (hw *UART) Rx() (c byte, valid bool) { 340 if !hw.rxReady() { 341 return 342 } 343 344 urxd := reg.Read(hw.urxd) 345 346 if bits.Get(&urxd, URXD_PRERR, 0b11111) != 0 { 347 return 348 } 349 350 return byte(bits.Get(&urxd, URXD_RX_DATA, 0xff)), true 351 } 352 353 // Write data from buffer to serial port. 354 func (hw *UART) Write(buf []byte) { 355 for i := 0; i < len(buf); i++ { 356 hw.Tx(buf[i]) 357 } 358 } 359 360 // Read available data to buffer from serial port. 361 func (hw *UART) Read(buf []byte) (n int) { 362 var valid bool 363 364 for n = 0; n < len(buf); n++ { 365 buf[n], valid = hw.Rx() 366 367 if !valid { 368 break 369 } 370 } 371 372 return 373 }