diff --git a/devices/kernel.mk b/devices/kernel.mk index a0451c7..8707352 100644 --- a/devices/kernel.mk +++ b/devices/kernel.mk @@ -5,7 +5,8 @@ include $(BASEDIR)/header.mk OBJS_$(d) := $(d)/pl011.o \ $(d)/pl110.o \ - $(d)/pl111.o + $(d)/pl111.o \ + $(d)/pi_mini_uart.o KOBJS += $(OBJS_$(d)) diff --git a/devices/pi_mini_uart.c b/devices/pi_mini_uart.c new file mode 100644 index 0000000..d22ff7a --- /dev/null +++ b/devices/pi_mini_uart.c @@ -0,0 +1,105 @@ +/* + Copyright (C) 2012, Aaron Lindsay + + This file is part of Aedrix. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#define VC_MMU_IO_OFFSET(addr) (addr - 0x7E000000 + 0x20000000) + +/* Auxiliary IO registers (includes both mini-UART and SPI) */ +#define AUX_IRQ VC_MMU_IO_OFFSET(0x7E215000) +#define AUX_ENABLES VC_MMU_IO_OFFSET(0x7E215004) +#define AUX_MU_IO_REG VC_MMU_IO_OFFSET(0x7E215040) +#define AUX_MU_IER_REG VC_MMU_IO_OFFSET(0x7E215044) +#define AUX_MU_IIR_REG VC_MMU_IO_OFFSET(0x7E215048) +#define AUX_MU_LCR_REG VC_MMU_IO_OFFSET(0x7E21504C) +#define AUX_MU_MCR_REG VC_MMU_IO_OFFSET(0x7E215050) +#define AUX_MU_LSR_REG VC_MMU_IO_OFFSET(0x7E215054) +#define AUX_MU_MSR_REG VC_MMU_IO_OFFSET(0x7E215058) +#define AUX_MU_SCRATCH VC_MMU_IO_OFFSET(0x7E21505C) +#define AUX_MU_CNTL_REG VC_MMU_IO_OFFSET(0x7E215060) +#define AUX_MU_STAT_REG VC_MMU_IO_OFFSET(0x7E215064) +#define AUX_MU_BAUD_REG VC_MMU_IO_OFFSET(0x7E215068) +#define AUX_SPI0_CNTL0_REG VC_MMU_IO_OFFSET(0x7E215080) +#define AUX_SPI0_CNTL1_REG VC_MMU_IO_OFFSET(0x7E215084) +#define AUX_SPI0_STAT_REG VC_MMU_IO_OFFSET(0x7E215088) +#define AUX_SPI0_IO_REG VC_MMU_IO_OFFSET(0x7E215090) +#define AUX_SPI0_PEEK_REG VC_MMU_IO_OFFSET(0x7E215094) +#define AUX_SPI1_CNTL0_REG VC_MMU_IO_OFFSET(0x7E2150C0) +#define AUX_SPI1_CNTL1_REG VC_MMU_IO_OFFSET(0x7E2150C4) +#define AUX_SPI1_STAT_REG VC_MMU_IO_OFFSET(0x7E2150C8) +#define AUX_SPI1_IO_REG VC_MMU_IO_OFFSET(0x7E2150D0) +#define AUX_SPI1_PEEK_REG VC_MMU_IO_OFFSET(0x7E2150D4) + +/* Constants for mini-UART operation */ +#define MINI_UART_TX_EMPTY 0x20 + +/* General GPIO pin registers */ +#define GPFSEL1 VC_MMU_IO_OFFSET(0x7E200004) +#define GPSET0 VC_MMU_IO_OFFSET(0x7E20001C) +#define GPCLR0 VC_MMU_IO_OFFSET(0x7E200028) +#define GPPUD VC_MMU_IO_OFFSET(0x7E200094) +#define GPPUDCLK0 VC_MMU_IO_OFFSET(0x7E200098) + +void mini_uart_init() { + uint32 aux_enables; + uint32 gpfsel1; + unsigned int i; + + /* Enable the mini-UART */ + aux_enables = (*(uint32 *)AUX_ENABLES) & 0x7; + *(uint32 *)AUX_ENABLES = aux_enables | 0x1; + + //TODO are these all necessary? + *(uint32 *)AUX_MU_IER_REG = 0; //disable interrupts + *(uint32 *)AUX_MU_CNTL_REG = 0; //disable RX and TX + *(uint32 *)AUX_MU_LCR_REG = 3; //set to 8-bit mode (though this only takes setting bit 0, no clue why bit 1 is set too) + *(uint32 *)AUX_MU_MCR_REG = 0; //"If clear the UART1_RTS line is high If set the UART1_RTS line is low" + *(uint32 *)AUX_MU_IER_REG = 0; //disable interrupts again? + *(uint32 *)AUX_MU_IIR_REG = 0xC6; //why are we setting the interrupt status - this looks like a read-only register? + //also, the manual says setting bits 2&3 simultaneously shouldn't be possible... + + // baudrate = system_clock_freq / ( 8 * (baudrate_reg + 1)) + // baudrate_reg = system_clock_freq / baudrate / 8 - 1 + // baudrate_reg = 250000000 / 115200 / 8 - 1 = 270 + *(uint32 *)AUX_MU_BAUD_REG = 270; + + //set the GPIO pin to the alternate function for this UART + gpfsel1 = (*(uint32 *)GPFSEL1) & ~(7<<12); //get the GPIO Function Select 1 register, and keep all the bits except those that are for GPIO pin 14 + gpfsel1 |= 2<<12; // set to 010 (GPIO Pin 14 takes alternate function 5) + *(uint32 *)GPFSEL1 = gpfsel1; + + //Follow the procedure for change pull-up/pull-down status (see page 101 of the BCM2835 ARM Peripherals datasheet) + *(uint32 *)GPPUD = 0; //disable pull-up/pull-down for those pins which receive a write to their bit in GPPUDCLK0/1 + for(i = 0; i < 150; i++) asm(""); //wait at least 150 cycles + *(uint32 *)GPPUDCLK0 = 1<<14; //"Write to GPPUDCLK0/1 to clock the control signal into the GPIO pads you wish to modify" (in our case, this is 14) + for(i = 0; i < 150; i++) asm(""); //wait at least 150 cycles +// *(uint32 *)GPPUD = 0; //remove the signal (shouldn't really be necessary since it was 0 anyway in our case) + *(uint32 *)GPPUDCLK0 = 0; //clear the clock + + *(uint32 *)AUX_MU_CNTL_REG = 2; //enable TX +} + +void mini_uart_putc(char c) { + /* Wait until the serial buffer is empty */ + while (!(*(volatile uint32*)AUX_MU_LSR_REG & MINI_UART_TX_EMPTY)); + + /* When it's empty, write our character */ + *(volatile uint32*)AUX_MU_IO_REG = c; +} diff --git a/include/devices/pi_mini_uart.h b/include/devices/pi_mini_uart.h new file mode 100644 index 0000000..6867c98 --- /dev/null +++ b/include/devices/pi_mini_uart.h @@ -0,0 +1,27 @@ +/* + Copyright (C) 2012, Aaron Lindsay + + This file is part of Aedrix. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef PI_MINI_UART_H +#define PI_MINI_UART_H + +void mini_uart_init(); +void mini_uart_putc(char c); + +#endif /* PI_MINI_UART_H */