Add OMAP4 UART driver

Fixes #444
This commit is contained in:
Ivan Loskutov 2012-12-20 13:59:47 +04:00 committed by Norman Feske
parent f4e0230dde
commit 5b8a0e5423
9 changed files with 439 additions and 108 deletions

View File

@ -33,8 +33,8 @@ namespace Genode
* \param baud_rate targeted transfer baud-rate
*/
Serial_log(unsigned const baud_rate) :
Tl16c750_base(Board::TL16C750_3_MMIO_BASE,
Board::TL16C750_3_CLOCK, baud_rate)
Tl16c750_base(Board::TL16C750_MMIO_BASE,
Board::TL16C750_CLOCK, baud_rate)
{ }
};
}

View File

@ -79,7 +79,7 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i)
Board::CORTEX_A9_PRIVATE_MEM_SIZE },
/* core UART */
{ Board::TL16C750_3_MMIO_BASE, Board::TL16C750_3_MMIO_SIZE }
{ Board::TL16C750_3_MMIO_BASE, Board::TL16C750_MMIO_SIZE }
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}

View File

@ -27,120 +27,137 @@ namespace Genode
*/
class Tl16c750_base : public Mmio
{
/**
* Least significant divisor part
*/
struct Uart_dll : Register<0x0, 32>
{
struct Clock_lsb : Bitfield<0, 8> { };
};
/**
* Transmit holding register
*/
struct Uart_thr : Register<0x0, 32>
{
struct Thr : Bitfield<0, 8> { };
};
/**
* Most significant divisor part
*/
struct Uart_dlh : Register<0x4, 32>
{
struct Clock_msb : Bitfield<0, 6> { };
};
/**
* Interrupt enable register
*/
struct Uart_ier : Register<0x4, 32>
{
struct Rhr_it : Bitfield<0, 1> { };
struct Thr_it : Bitfield<1, 1> { };
struct Line_sts_it : Bitfield<2, 1> { };
struct Modem_sts_it : Bitfield<3, 1> { };
struct Sleep_mode : Bitfield<4, 1> { };
struct Xoff_it : Bitfield<5, 1> { };
struct Rts_it : Bitfield<6, 1> { };
struct Cts_it : Bitfield<7, 1> { };
};
/**
* FIFO control register
*/
struct Uart_fcr : Register<0x8, 32>
{
struct Fifo_enable : Bitfield<0, 1> { };
};
/**
* Line control register
*/
struct Uart_lcr : Register<0xc, 32>
{
struct Char_length : Bitfield<0, 2>
protected:
/**
* Least significant divisor part
*/
struct Uart_dll : Register<0x0, 32>
{
enum { _8_BIT = 3 };
struct Clock_lsb : Bitfield<0, 8> { };
};
struct Nb_stop : Bitfield<2, 1>
/**
* Transmit holding register
*/
struct Uart_thr : Register<0x0, 32>
{
enum { _1_STOP_BIT = 0 };
struct Thr : Bitfield<0, 8> { };
};
struct Parity_en : Bitfield<3, 1> { };
struct Break_en : Bitfield<6, 1> { };
struct Div_en : Bitfield<7, 1> { };
struct Reg_mode : Bitfield<0, 8>
/**
* Receiver holding register
*/
struct Uart_rhr : Register<0x0, 32>
{
enum { OPERATIONAL = 0, CONFIG_A = 0x80, CONFIG_B = 0xbf };
struct Rhr : Bitfield<0, 8> { };
};
};
/**
* Modem control register
*/
struct Uart_mcr : Register<0x10, 32>
{
struct Tcr_tlr : Bitfield<6, 1> { };
};
/**
* Line status register
*/
struct Uart_lsr : Register<0x14, 32>
{
struct Tx_fifo_empty : Bitfield<5, 1> { };
};
/**
* Mode definition register 1
*/
struct Uart_mdr1 : Register<0x20, 32>
{
struct Mode_select : Bitfield<0, 3>
/**
* Most significant divisor part
*/
struct Uart_dlh : Register<0x4, 32>
{
enum { UART_16X = 0, DISABLED = 7 };
struct Clock_msb : Bitfield<0, 6> { };
};
};
/**
* System control register
*/
struct Uart_sysc : Register<0x54, 32>
{
struct Softreset : Bitfield<1, 1> { };
};
/**
* Interrupt enable register
*/
struct Uart_ier : Register<0x4, 32>
{
struct Rhr_it : Bitfield<0, 1> { };
struct Thr_it : Bitfield<1, 1> { };
struct Line_sts_it : Bitfield<2, 1> { };
struct Modem_sts_it : Bitfield<3, 1> { };
struct Sleep_mode : Bitfield<4, 1> { };
struct Xoff_it : Bitfield<5, 1> { };
struct Rts_it : Bitfield<6, 1> { };
struct Cts_it : Bitfield<7, 1> { };
};
/**
* System status register
*/
struct Uart_syss : Register<0x58, 32>
{
struct Resetdone : Bitfield<0, 1> { };
};
/**
* Interrupt identification register
*/
struct Uart_iir : Register<0x8, 32>
{
struct It_pending : Bitfield<0, 1> { };
};
/**
* FIFO control register
*/
struct Uart_fcr : Register<0x8, 32>
{
struct Fifo_enable : Bitfield<0, 1> { };
};
/**
* Line control register
*/
struct Uart_lcr : Register<0xc, 32>
{
struct Char_length : Bitfield<0, 2>
{
enum { _8_BIT = 3 };
};
struct Nb_stop : Bitfield<2, 1>
{
enum { _1_STOP_BIT = 0 };
};
struct Parity_en : Bitfield<3, 1> { };
struct Break_en : Bitfield<6, 1> { };
struct Div_en : Bitfield<7, 1> { };
struct Reg_mode : Bitfield<0, 8>
{
enum { OPERATIONAL = 0, CONFIG_A = 0x80, CONFIG_B = 0xbf };
};
};
/**
* Modem control register
*/
struct Uart_mcr : Register<0x10, 32>
{
struct Tcr_tlr : Bitfield<6, 1> { };
};
/**
* Line status register
*/
struct Uart_lsr : Register<0x14, 32>
{
struct Rx_fifo_empty : Bitfield<0, 1> { };
struct Tx_fifo_empty : Bitfield<5, 1> { };
};
/**
* Mode definition register 1
*/
struct Uart_mdr1 : Register<0x20, 32>
{
struct Mode_select : Bitfield<0, 3>
{
enum { UART_16X = 0, DISABLED = 7 };
};
};
/**
* System control register
*/
struct Uart_sysc : Register<0x54, 32>
{
struct Softreset : Bitfield<1, 1> { };
};
/**
* System status register
*/
struct Uart_syss : Register<0x58, 32>
{
struct Resetdone : Bitfield<0, 1> { };
};
public:
/**
* Constructor
*

View File

@ -36,11 +36,19 @@ namespace Genode
/* clocks */
MPU_DPLL_CLOCK = 200*1000*1000,
/* UART */
TL16C750_3_MMIO_BASE = 0x48020000,
TL16C750_3_MMIO_SIZE = 0x00002000,
TL16C750_3_CLOCK = 48*1000*1000,
/* UARTs */
TL16C750_1_MMIO_BASE = MMIO_0_BASE + 0x6a000,
TL16C750_2_MMIO_BASE = MMIO_0_BASE + 0x6c000,
TL16C750_3_MMIO_BASE = MMIO_0_BASE + 0x20000,
TL16C750_4_MMIO_BASE = MMIO_0_BASE + 0x6e000,
TL16C750_MMIO_SIZE = 0x2000,
TL16C750_CLOCK = 48*1000*1000,
TL16C750_1_IRQ = 72,
TL16C750_2_IRQ = 73,
TL16C750_3_IRQ = 74,
TL16C750_4_IRQ = 70,
/* CPU */
CORTEX_A9_PRIVATE_MEM_BASE = 0x48240000,

View File

@ -0,0 +1,39 @@
/*
* \brief OMAP4 UART definitions
* \author Ivan Loskutov <ivan.loskutov@ksyslabs.org>
* \date 2012-11-08
*/
/*
* Copyright (C) 2012 Ksys Labs LLC
* Copyright (C) 2011-2012 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 _INCLUDE__PLATFORM__PANDABOARD__UART_DEFS_H_
#define _INCLUDE__PLATFORM__PANDABOARD__UART_DEFS_H_
#include <platform/panda/drivers/board.h>
enum {
/** Number of UARTs */
UARTS_NUM = 4,
BAUD_115200 = 26,
};
static struct Omap_uart_cfg {
Genode::addr_t mmio_base;
Genode::size_t mmio_size;
int irq_number;
} omap_uart_cfg[UARTS_NUM] = {
{ Genode::Board::TL16C750_1_MMIO_BASE, Genode::Board::TL16C750_MMIO_SIZE, Genode::Board::TL16C750_1_IRQ + 32 },
{ Genode::Board::TL16C750_2_MMIO_BASE, Genode::Board::TL16C750_MMIO_SIZE, Genode::Board::TL16C750_2_IRQ + 32 },
{ Genode::Board::TL16C750_3_MMIO_BASE, Genode::Board::TL16C750_MMIO_SIZE, Genode::Board::TL16C750_3_IRQ + 32 },
{ Genode::Board::TL16C750_4_MMIO_BASE, Genode::Board::TL16C750_MMIO_SIZE, Genode::Board::TL16C750_4_IRQ + 32 },
};
#endif /* _INCLUDE__PLATFORM__PANDABOARD__UART_DEFS_H_ */

View File

@ -0,0 +1,72 @@
#
# Build
#
assert_spec foc
assert_spec platform_panda
# generic components
set build_components {
core init
drivers/timer drivers/uart
test/terminal_echo
}
build $build_components
create_boot_directory
#
# Config
#
set config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
</parent-provides>
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="uart_drv">
<resource name="RAM" quantum="1M"/>
<provides><service name="Terminal"/></provides>
<config>
<policy label="test-terminal_echo" uart="3"/>
</config>
</start>
<start name="test-terminal_echo">
<resource name="RAM" quantum="1M"/>
</start>
</config>
}
install_config $config
#
# Boot modules
#
# generic modules
set boot_modules {
core init
timer uart_drv test-terminal_echo
}
build_boot_image $boot_modules

View File

@ -0,0 +1,88 @@
/*
* \brief Driver for OMAP4 UARTs
* \author Ivan Loskutov <ivan.loskutov@ksyslabs.org>
* \date 2012-11-08
*/
/*
* Copyright (C) 2012 Ksys Labs LLC
* Copyright (C) 2011-2012 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.
*/
/* Genode includes */
#include <base/printf.h>
#include <base/sleep.h>
#include <os/config.h>
#include <cap_session/connection.h>
#include <os/attached_io_mem_dataspace.h>
#include <uart_defs.h>
/* local includes */
#include "omap_uart.h"
#include "uart_component.h"
int main(int argc, char **argv)
{
using namespace Genode;
PDBG("--- OMAP4 UART driver started ---\n");
/**
* Factory used by 'Terminal::Root' at session creation/destruction time
*/
struct Omap_uart_driver_factory : Uart::Driver_factory
{
Omap_uart *created[UARTS_NUM];
/**
* Constructor
*/
Omap_uart_driver_factory()
{
for (unsigned i = 0; i < UARTS_NUM; i++)
created[i] = 0;
}
Uart::Driver *create(unsigned index,
Uart::Char_avail_callback &callback)
{
if (index > UARTS_NUM)
throw Uart::Driver_factory::Not_available();
Omap_uart_cfg *cfg = &omap_uart_cfg[index];
Omap_uart *uart = created[index];
Genode::Attached_io_mem_dataspace *uart_mmio = new (env()->heap())
Genode::Attached_io_mem_dataspace(cfg->mmio_base, cfg->mmio_size);
if (!uart) {
uart = new (env()->heap())
Omap_uart(uart_mmio, cfg->irq_number, BAUD_115200, callback);
/* update 'created' table */
created[index] = uart;
}
return uart;
}
void destroy(Uart::Driver *driver) { /* TODO */ }
} driver_factory;
enum { STACK_SIZE = 0x2000 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "uart_ep");
static Uart::Root uart_root(&ep, env()->heap(), driver_factory);
env()->parent()->announce(ep.manage(&uart_root));
sleep_forever();
return 0;
}

View File

@ -0,0 +1,101 @@
/*
* \brief Driver for OMAP4 UARTs
* \author Ivan Loskutov <ivan.loskutov@ksyslabs.org>
* \date 2012-11-08
*/
/*
* Copyright (C) 2012 Ksys Labs LLC
* Copyright (C) 2011-2012 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 _OMAP_UART_H_
#define _OMAP_UART_H_
/* Genode includes */
#include <base/env.h>
#include <base/printf.h>
#include <os/irq_activation.h>
#include <os/attached_io_mem_dataspace.h>
#include <drivers/uart/tl16c750_base.h>
/* local includes */
#include "uart_driver.h"
class Omap_uart : public Genode::Tl16c750_base, public Uart::Driver, public Genode::Irq_handler
{
private:
Genode::Attached_io_mem_dataspace _uart_mmio;
Uart::Char_avail_callback &_char_avail_callback;
enum { IRQ_STACK_SIZE = 4096 };
Genode::Irq_activation _irq_activation;
void _enable_rx_interrupt()
{
/* enable access to 'Uart_fcr' and 'Uart_ier' */
write<Uart_lcr::Reg_mode>(Uart_lcr::Reg_mode::OPERATIONAL);
/* enable rx interrupt, disable other interrupts and sleep mode */
write<Uart_ier>(Uart_ier::Rhr_it::bits(1)
| Uart_ier::Thr_it::bits(0)
| Uart_ier::Line_sts_it::bits(0)
| Uart_ier::Modem_sts_it::bits(0)
| Uart_ier::Sleep_mode::bits(0)
| Uart_ier::Xoff_it::bits(0)
| Uart_ier::Rts_it::bits(0)
| Uart_ier::Cts_it::bits(0));
/*
* Configure protocol formatting and thereby return to
* operational mode.
*/
write<Uart_lcr>(Uart_lcr::Char_length::bits(Uart_lcr::Char_length::_8_BIT)
| Uart_lcr::Nb_stop::bits(Uart_lcr::Nb_stop::_1_STOP_BIT)
| Uart_lcr::Parity_en::bits(0)
| Uart_lcr::Break_en::bits(0)
| Uart_lcr::Div_en::bits(0));
}
public:
/**
* Constructor
*/
Omap_uart(Genode::Attached_io_mem_dataspace *uart_mmio, int irq_number,
unsigned baud_rate, Uart::Char_avail_callback &callback)
:
Tl16c750_base((Genode::addr_t)uart_mmio->local_addr<void>(), Genode::Board::TL16C750_CLOCK, baud_rate),
_uart_mmio(*uart_mmio),
_char_avail_callback(callback),
_irq_activation(irq_number, *this, IRQ_STACK_SIZE)
{
_enable_rx_interrupt();
}
/**
* * IRQ handler interface **
*/
void handle_irq(int irq_number)
{
/* inform client about the availability of data */
unsigned int iir = read<Uart_iir::It_pending>();
if (iir) return;
_char_avail_callback();
}
/**
* * UART driver interface **
*/
void put_char(char c) { Tl16c750_base::put_char(c); }
bool char_avail() { return read<Uart_lsr::Rx_fifo_empty>(); }
char get_char() { return read<Uart_rhr::Rhr>(); }
};
#endif /* _OMAP_UART_H_ */

View File

@ -0,0 +1,6 @@
TARGET = uart_drv
REQUIRES = omap4
SRC_CC = main.cc
LIBS = cxx env server signal
INC_DIR += $(PRG_DIR) $(PRG_DIR)/..