+#include <stdio.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include "uart.h"
+
+#define CLK 3000000
+
+#define IOBASEADDR 0x3f000000
+#define IOSIZE 16777216
+#define IOREGADDR(x) ((x) | IOBASEADDR)
+
+#define REG_UART_FLAGS *(volatile uint32_t*)IOREGADDR(0x201018)
+#define REG_UART_IBRD *(volatile uint32_t*)IOREGADDR(0x201024)
+#define REG_UART_FBRD *(volatile uint32_t*)IOREGADDR(0x201028)
+#define REG_UART_LCTL *(volatile uint32_t*)IOREGADDR(0x20102c)
+#define REG_UART_CTL *(volatile uint32_t*)IOREGADDR(0x201030)
+
+#define FLAGS_TXEMPTY 0x80
+#define FLAGS_RXFULL 0x40
+#define FLAGS_TXFULL 0x20
+#define FLAGS_RXEMPTY 0x10
+#define FLAGS_BUSY 0x08
+#define FLAGS_CTS 0x01
+
+#define LCTL_8BIT 0x60
+#define LCTL_FIFOEN 0x10
+#define LCTL_PAREN 0x02
+#define LCLT_BRK 0x01
+
+#define CTL_RXEN 0x200
+#define CTL_TXEN 0x100
+#define CTL_EN 0x001
+
+int uart_config(int rate)
+{
+ int fd, div;
+ void *ptr;
+
+ if((fd = open("/dev/mem", O_RDWR)) == -1) {
+ perror("failed to open /dev/mem");
+ return 1;
+ }
+ if((ptr = mmap((void*)IOBASEADDR, IOSIZE, PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_FIXED, fd, IOBASEADDR)) == (void*)-1) {
+ perror("failed to map IO space");
+ return 1;
+ }
+
+ REG_UART_CTL = 0;
+ while(REG_UART_FLAGS & FLAGS_BUSY);
+
+ div = (CLK << 6) / (rate << 4);
+ printf("setting divisor (i/f): %d %d\n", div >> 6, div & 0x3f);
+ REG_UART_IBRD = div >> 6;
+ REG_UART_FBRD = div & 0x3f;
+ REG_UART_LCTL = LCTL_8BIT | LCTL_FIFOEN;
+
+ REG_UART_CTL = CTL_RXEN | CTL_TXEN | CTL_EN;
+
+ munmap(ptr, IOSIZE);
+ close(fd);
+ return 0;
+}