genode/repos/os/src/drivers/uart/spec/pbxa9/uart_driver.h
Stefan Kalkowski f1535b2481 uart_drv: transition to new base API
* Unify uart drivers of different hardware drivers
* Remove deprecated IRQ activations
* Remove additional timer thread in Fiasco* KDB driver
* Move more generic UART definitions to specific supported
  platforms (e.g.: pl011 -> pbxa9)
* Move internal definitions from global to local headers

Ref #1987
Fix #2071
2016-08-29 17:29:35 +02:00

206 lines
5.2 KiB
C++

/*
* \brief Pbxa9 UART driver
* \author Christian Helmuth
* \author Stefan Kalkowski
* \date 2011-05-27
*/
/*
* Copyright (C) 2011-2016 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _UART_DRIVER_H_
#define _UART_DRIVER_H_
/* Genode includes */
#include <base/attached_io_mem_dataspace.h>
#include <base/env.h>
#include <drivers/board_base.h>
enum { UARTS_NUM = 4 }; /* needed by base class definitions */
/* local includes */
#include <uart_driver_base.h>
class Uart::Driver : public Genode::Attached_io_mem_dataspace,
public Uart::Driver_base
{
private:
enum {
/**
* MMIO regions
*/
PL011_PHYS0 = 0x10009000, /* base for UART 0 */
PL011_PHYS1 = 0x1000a000, /* base for UART 1 */
PL011_PHYS2 = 0x1000b000, /* base for UART 2 */
PL011_PHYS3 = 0x1000c000, /* base for UART 3 */
PL011_SIZE = 0x1000, /* size of each MMIO region */
/**
* Interrupt lines
*/
PL011_IRQ0 = Genode::Board_base::PL011_0_IRQ, /* UART 0 */
PL011_IRQ1 = Genode::Board_base::PL011_1_IRQ, /* UART 1 */
PL011_IRQ2 = Genode::Board_base::PL011_2_IRQ, /* UART 2 */
PL011_IRQ3 = Genode::Board_base::PL011_3_IRQ, /* UART 3 */
/**
* UART baud rate configuration (precalculated)
*
* div = 24000000 / 16 / baud rate
* IBRD = floor(div)
* FBRD = floor((div - IBRD) * 64 + 0.5)
*/
PL011_IBRD_115200 = 13, PL011_FBRD_115200 = 1,
PL011_IBRD_19200 = 78, PL011_FBRD_19200 = 8,
PL011_IBRD_9600 = 156, PL011_FBRD_9600 = 16,
BAUD_115200 = 115200
};
struct Uart {
Genode::addr_t mmio_base;
Genode::size_t mmio_size;
int irq_number;
};
Uart & _config(unsigned index)
{
using namespace Genode;
static Uart cfg[UARTS_NUM] = {
{ PL011_PHYS0, PL011_SIZE, PL011_IRQ0 },
{ PL011_PHYS1, PL011_SIZE, PL011_IRQ1 },
{ PL011_PHYS2, PL011_SIZE, PL011_IRQ2 },
{ PL011_PHYS3, PL011_SIZE, PL011_IRQ3 },
};
return cfg[index];
}
/*
* Constants for flags, registers, etc. only visible in this file are
* named as in the specification documents to relieve correlation
* between implementation and specification.
*/
/**
* Register offsets
*
* Registers are read/writable unless explicitly stated.
*/
enum Register {
UARTDR = 0x000, /* data */
UARTFR = 0x018, /* flags (read-only) */
UARTIBRD = 0x024, /* integer baud rate divisor */
UARTFBRD = 0x028, /* fractional baud rate divisor */
UARTLCR_H = 0x02c, /* line control */
UARTCR = 0x030, /* control */
UARTIMSC = 0x038, /* interrupt mask register */
UARTICR = 0x044, /* interrupt clear register */
};
/**
* Flags
*/
enum Flag {
/* flag register */
UARTFR_BUSY = 0x0008, /* busy on tx */
UARTFR_TXFF = 0x0020, /* tx FIFO full */
UARTFR_RXFE = 0x0010, /* rx FIFO empty */
/* line control register */
UARTLCR_H_FEN = 0x0010, /* enable FIFOs */
UARTLCR_H_WLEN_8 = 0x0060, /* 8 bit word length */
/* control register */
UARTCR_UARTEN = 0x0001, /* enable uart */
UARTCR_TXE = 0x0100, /* enable tx */
UARTCR_RXE = 0x0200, /* enable rx */
/* interrupt mask register */
UARTIMSC_RXIM = 0x10, /* rx interrupt mask */
/* interrupt clear register */
UARTICR_RXIC = 0x10, /* rx interrupt clear */
};
Genode::uint32_t volatile *_base;
Genode::uint32_t _read_reg(Register reg) const {
return _base[reg >> 2]; }
void _write_reg(Register reg, Genode::uint32_t v) {
_base[reg >> 2] = v; }
public:
Driver(Genode::Env &env, unsigned index,
unsigned baud_rate, Char_avail_functor &func)
: Genode::Attached_io_mem_dataspace(env, _config(index).mmio_base,
_config(index).mmio_size),
Driver_base(env, _config(index).irq_number, func),
_base(local_addr<unsigned volatile>())
{
if (baud_rate != BAUD_115200)
Genode::warning("baud_rate ", baud_rate,
" not supported, set to default");
/* disable and flush uart */
_write_reg(UARTCR, 0);
while (_read_reg(UARTFR) & UARTFR_BUSY) ;
_write_reg(UARTLCR_H, 0);
/* set baud-rate divisor */
_write_reg(UARTIBRD, PL011_IBRD_115200);
_write_reg(UARTFBRD, PL011_FBRD_115200);
/* enable FIFOs, 8-bit words */
_write_reg(UARTLCR_H, UARTLCR_H_FEN | UARTLCR_H_WLEN_8);
/* enable transmission */
_write_reg(UARTCR, UARTCR_TXE);
/* enable uart */
_write_reg(UARTCR, _read_reg(UARTCR) | UARTCR_UARTEN);
/* enable rx interrupt */
_write_reg(UARTIMSC, UARTIMSC_RXIM);
}
/***************************
** UART driver interface **
***************************/
void handle_irq() override
{
/* inform client about the availability of data */
Driver_base::handle_irq();
/* acknowledge irq */
_write_reg(UARTICR, UARTICR_RXIC);
}
void put_char(char c) override
{
/* spin while FIFO full */
while (_read_reg(UARTFR) & UARTFR_TXFF) ;
_write_reg(UARTDR, c);
}
bool char_avail() override {
return !(_read_reg(UARTFR) & UARTFR_RXFE); }
char get_char() override {
return _read_reg(UARTDR); }
};
#endif /* _UART_DRIVER_H_ */