1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13#include <stdint.h> 14#include <stdbool.h> 15#include <stdarg.h> 16#include <string.h> 17#include <camkes/gdb/serial.h> 18#include <camkes/gdb/gdb.h> 19#include <sel4/sel4.h> 20#include <utils/util.h> 21 22 23#define BAUD_RATE 115200 24#define MAX_PRINTF_LENGTH 256 25// Register layout. Done by offset from base port 26#define THR_ADDR (0) 27#define RBR_ADDR (0) 28#define LATCH_LOW_ADDR (0) 29#define LATCH_HIGH_ADDR (1) 30#define IER_ADDR (1) 31#define FCR_ADDR (2) 32#define IIR_ADDR (2) 33#define LCR_ADDR (3) 34#define MCR_ADDR (4) 35#define LSR_ADDR (5) 36#define MSR_ADDR (6) 37 38#define IER_RESERVED_MASK (BIT(6) | BIT(7)) 39 40#define FCR_ENABLE BIT(0) 41#define FCR_CLEAR_RECEIVE BIT(1) 42#define FCR_CLEAR_TRANSMIT BIT(2) 43#define FCR_TRIGGER_16_1 (0) 44 45#define LCR_DLAB BIT(7) 46 47#define MCR_DTR BIT(0) 48#define MCR_RTS BIT(1) 49#define MCR_AO1 BIT(2) 50#define MCR_AO2 BIT(3) 51 52#define LSR_EMPTY_DHR BIT(6) 53#define LSR_EMPTY_THR BIT(5) 54#define LSR_DATA_READY BIT(0) 55 56#define IIR_FIFO_ENABLED (BIT(6) | BIT(7)) 57#define IIR_REASON (BIT(1) | BIT(2) | BIT(3)) 58#define IIR_MSR (0) 59#define IIR_THR BIT(1) 60#define IIR_RDA BIT(2) 61#define IIR_TIME (BIT(3) | BIT(2)) 62#define IIR_LSR (BIT(2) | BIT(1)) 63#define IIR_PENDING BIT(0) 64 65 66 67static void serial_putchar(int c); 68 69// Serial buffer manipulation 70static void initialise_buffer(void); 71static int push_buffer(int c); 72static void clear_buffer(void); 73 74// Register manipulation functions 75static void write_latch(uint16_t val); 76static void write_latch_high(uint8_t val); 77static void write_latch_low(uint8_t val); 78static void write_ier(uint8_t val); 79static uint8_t read_ier(void); 80static void write_lcr(uint8_t val); 81static uint8_t read_lcr(void); 82static void write_fcr(uint8_t val); 83static void write_mcr(uint8_t val); 84static uint8_t read_lsr(void); 85static uint8_t read_rbr(void); 86static void write_thr(uint8_t val); 87static uint8_t read_iir(void); 88static uint8_t read_msr(void); 89 90// Serial config 91static void set_dlab(int v); 92static void disable_interrupt(void); 93static void disable_fifo(void); 94static void set_baud_rate(uint32_t baud); 95static void reset_state(void); 96static void enable_fifo(void); 97static void enable_interrupt(void); 98static void reset_lcr(void); 99static void reset_mcr(void); 100static void wait_for_fifo(void); 101static bool clear_iir(void); 102 103void serial_port_out8_offset(uint16_t offset, uint8_t value); 104uint8_t serial_port_in8_offset(uint16_t offset); 105 106 107int command_wait = false; 108int fifo_depth = 1; 109int fifo_used = 0; 110static gdb_state_t *gdb_state; 111// Serial buffer manipulation 112static void initialise_buffer(void) 113{ 114 buf.length = 0; 115 buf.checksum_count = 0; 116 buf.checksum_index = 0; 117} 118 119static int push_buffer(int c) 120{ 121 if (buf.length == GETCHAR_BUFSIZ) { 122 return -1; 123 } else { 124 buf.data[buf.length] = c; 125 buf.length++; 126 return 0; 127 } 128} 129 130static void clear_buffer(void) 131{ 132 int i; 133 for (i = 0; i < buf.length; i++) { 134 buf.data[i] = 0; 135 } 136 initialise_buffer(); 137} 138 139// Register manipulation functions 140static inline void write_latch(uint16_t val) 141{ 142 set_dlab(1); 143 write_latch_high(val >> 8); 144 write_latch_low(val & 0xff); 145 set_dlab(0); 146} 147 148static inline void write_latch_high(uint8_t val) 149{ 150 serial_port_out8_offset(LATCH_HIGH_ADDR, val); 151} 152 153static inline void write_latch_low(uint8_t val) 154{ 155 serial_port_out8_offset(LATCH_LOW_ADDR, val); 156} 157 158static inline void write_ier(uint8_t val) 159{ 160 serial_port_out8_offset(IER_ADDR, val); 161} 162static inline uint8_t read_ier() 163{ 164 return serial_port_in8_offset(IER_ADDR); 165} 166 167static inline void write_lcr(uint8_t val) 168{ 169 serial_port_out8_offset(LCR_ADDR, val); 170} 171static inline uint8_t read_lcr() 172{ 173 return serial_port_in8_offset(LCR_ADDR); 174} 175 176static inline void write_fcr(uint8_t val) 177{ 178 serial_port_out8_offset(FCR_ADDR, val); 179} 180// you cannot read the fcr 181 182static inline void write_mcr(uint8_t val) 183{ 184 serial_port_out8_offset(MCR_ADDR, val); 185} 186 187static inline uint8_t read_lsr() 188{ 189 return serial_port_in8_offset(LSR_ADDR); 190} 191 192static inline uint8_t read_rbr() 193{ 194 return serial_port_in8_offset(RBR_ADDR); 195} 196 197static inline void write_thr(uint8_t val) 198{ 199 serial_port_out8_offset(THR_ADDR, val); 200} 201 202static inline uint8_t read_iir() 203{ 204 return serial_port_in8_offset(IIR_ADDR); 205} 206 207static inline uint8_t read_msr() 208{ 209 return serial_port_in8_offset(MSR_ADDR); 210} 211 212// Serial config 213 214void serial_init(gdb_state_t *gdb) 215{ 216 // Initialize the serial port 217 int UNUSED error; 218 error = serial_lock(); 219 gdb_state = gdb; 220 set_dlab(0); // we always assume the dlab is 0 unless we explicitly change it 221 disable_interrupt(); 222 disable_fifo(); 223 reset_lcr(); 224 reset_mcr(); 225 clear_iir(); 226 set_baud_rate(BAUD_RATE); 227 reset_state(); 228 enable_fifo(); 229 enable_interrupt(); 230 clear_iir(); 231 initialise_buffer(); 232 error = serial_unlock(); 233 234} 235 236static void set_dlab(int v) 237{ 238 if (v) { 239 write_lcr(read_lcr() | LCR_DLAB); 240 } else { 241 write_lcr(read_lcr() & ~LCR_DLAB); 242 } 243} 244 245static void disable_interrupt() 246{ 247 write_ier(0); 248} 249 250static void disable_fifo() 251{ 252 // first attempt to use the clear fifo commands 253 write_fcr(FCR_CLEAR_TRANSMIT | FCR_CLEAR_RECEIVE); 254 // now disable with a 0 255 write_fcr(0); 256} 257 258static void set_baud_rate(uint32_t baud) 259{ 260 assert(baud != 0); 261 assert(115200 % baud == 0); 262 uint16_t divisor = 115200 / baud; 263 write_latch(divisor); 264} 265 266static void reset_state(void) 267{ 268 // clear internal global state here 269 fifo_used = 0; 270} 271 272static void enable_fifo(void) 273{ 274 // check if there is a fifo and how deep it is 275 uint8_t info = read_iir(); 276 if ((info & IIR_FIFO_ENABLED) == IIR_FIFO_ENABLED) { 277 fifo_depth = 16; 278 write_fcr(FCR_TRIGGER_16_1 | FCR_ENABLE); 279 } else { 280 fifo_depth = 1; 281 } 282} 283 284static void enable_interrupt(void) 285{ 286 write_ier(1); 287} 288 289static void reset_lcr(void) 290{ 291 // set 8-n-1 292 write_lcr(3); 293} 294 295static void reset_mcr(void) 296{ 297 write_mcr(MCR_DTR | MCR_RTS | MCR_AO1 | MCR_AO2); 298} 299 300static void wait_for_fifo() 301{ 302 while (!(read_lsr() & (LSR_EMPTY_DHR | LSR_EMPTY_THR))); 303 fifo_used = 0; 304} 305 306static bool handle_char(void) 307{ 308 char c = read_rbr(); 309 if (c == '$') { 310 command_wait = true; 311 clear_buffer(); 312 313 } else if (buf.checksum_index) { 314 buf.checksum_count++; 315 } else if (c == '#') { 316 buf.checksum_index = buf.length; 317 } 318 push_buffer(c); 319 if (buf.checksum_count == 2 && command_wait) { 320 /* Got a command */ 321 return true; 322 } 323 return false; 324} 325 326static bool clear_iir(void) 327{ 328 uint8_t iir; 329 while (!((iir = read_iir()) & IIR_PENDING)) { 330 switch (iir & IIR_REASON) { 331 case IIR_RDA: 332 case IIR_TIME: 333 while (read_lsr() & LSR_DATA_READY) { 334 bool result = handle_char(); 335 if (result) { 336 return result; 337 } 338 } 339 default: 340 break; 341 } 342 } 343 return false; 344} 345 346static void serial_output_via_fifo(uint8_t c) 347{ 348 // check how much fifo we've used and if we need to drain it 349 if (fifo_used == fifo_depth) { 350 wait_for_fifo(); 351 } 352 353 write_thr(c); 354 fifo_used++; 355} 356 357// Serial usage 358static void serial_putchar(int c) 359{ 360 if (c == '\n') { 361 serial_output_via_fifo('\r'); 362 } 363 364 serial_output_via_fifo((uint8_t)c); 365} 366 367 368void serial_irq_handle(void) 369{ 370 int UNUSED error; 371 error = serial_lock(); 372 bool got_command = clear_iir(); 373 error = serial_irq_acknowledge(); 374 error = serial_unlock(); 375 if (got_command) { 376 handle_gdb(gdb_state); 377 error = serial_lock(); 378 clear_buffer(); 379 command_wait = false; 380 error = serial_unlock(); 381 } 382} 383 384void gdb_printf(const char *format, ...) 385{ 386 va_list arg; 387 char text_buf[MAX_PRINTF_LENGTH]; 388 va_start(arg, format); 389 vsnprintf(text_buf, MAX_PRINTF_LENGTH, format, arg); 390 va_end(arg); 391 int UNUSED error; 392 error = serial_lock(); 393 for (int i = 0; i < strlen(text_buf); i++) { 394 serial_putchar(text_buf[i]); 395 } 396 error = serial_unlock(); 397} 398