From 638dcf3d4044af8a24d245ade0a63fe03ab1b590 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Fri, 25 Jan 2013 14:25:50 +0100 Subject: [PATCH] arndale: UART driver base ref #601 --- base/include/drivers/uart/arndale_uart_base.h | 206 ++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 base/include/drivers/uart/arndale_uart_base.h diff --git a/base/include/drivers/uart/arndale_uart_base.h b/base/include/drivers/uart/arndale_uart_base.h new file mode 100644 index 000000000..3f5b80f5f --- /dev/null +++ b/base/include/drivers/uart/arndale_uart_base.h @@ -0,0 +1,206 @@ +/* + * \brief Driver base for the Arndale UART + * \author Martin stein + * \date 2013-01-09 + */ + +/* + * Copyright (C) 2013 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__DRIVERS__UART__ARNDALE_UART_BASE_H_ +#define _INCLUDE__DRIVERS__UART__ARNDALE_UART_BASE_H_ + +/* Genode includes */ +#include + +namespace Genode +{ + /** + * Arndale UART driver base + */ + class Arndale_uart_base : Mmio + { + /** + * Line control + */ + struct Ulcon : Register<0x0, 32> + { + struct Word_length : Bitfield<0, 2> { enum { _8_BIT = 3 }; }; + struct Stop_bits : Bitfield<2, 1> { enum { _1_BIT = 0 }; }; + struct Parity_mode : Bitfield<3, 3> { enum { NONE = 0 }; }; + struct Infrared_mode : Bitfield<6, 1> { }; + + /** + * Initialization value + */ + static access_t init_value() + { + return Word_length::bits(Word_length::_8_BIT) | + Stop_bits::bits(Stop_bits::_1_BIT) | + Parity_mode::bits(Parity_mode::NONE) | + Infrared_mode::bits(0); + } + }; + + /** + * Control + */ + struct Ucon : Register<0x4, 32> + { + struct Receive_mode : Bitfield<0, 2> { enum { IRQ_POLL = 1 }; }; + struct Transmit_mode : Bitfield<2, 2> { enum { IRQ_POLL = 1 }; }; + struct Send_brk_signal : Bitfield<4, 1> { }; + struct Loop_back_mode : Bitfield<5, 1> { }; + struct Rx_err_irq : Bitfield<6, 1> { }; + struct Rx_timeout : Bitfield<7, 1> { }; + struct Rx_irq_type : Bitfield<8, 1> { enum { LEVEL = 1 }; }; + struct Tx_irq_type : Bitfield<9, 1> { enum { LEVEL = 1 }; }; + struct Rx_to_dma_susp : Bitfield<10, 1> { }; + struct Rx_to_empty_rx : Bitfield<11, 1> { }; + struct Rx_to_interval : Bitfield<12, 4> { }; + struct Rx_dma_bst_size : Bitfield<16, 3> { }; + struct Tx_dma_bst_size : Bitfield<20, 3> { }; + + /** + * Initialization value + */ + static access_t init_value() + { + return Receive_mode::bits(Receive_mode::IRQ_POLL) | + Transmit_mode::bits(Transmit_mode::IRQ_POLL) | + Send_brk_signal::bits(0) | + Loop_back_mode::bits(0) | + Rx_err_irq::bits(1) | + Rx_timeout::bits(0) | + Rx_irq_type::bits(Rx_irq_type::LEVEL) | + Tx_irq_type::bits(Tx_irq_type::LEVEL) | + Rx_to_dma_susp::bits(0) | + Rx_to_empty_rx::bits(0) | + Rx_to_interval::bits(3) | + Rx_dma_bst_size::bits(0) | + Tx_dma_bst_size::bits(0); + } + }; + + /** + * FIFO control + */ + struct Ufcon : Register<0x8, 32> + { + struct Fifo_en : Bitfield<0, 1> { }; + struct Rx_fifo_rst : Bitfield<1, 1> { }; + struct Tx_fifo_rst : Bitfield<2, 1> { }; + struct Rx_fifo_trigger : Bitfield<4, 3> { }; + struct Tx_fifo_trigger : Bitfield<8, 3> { }; + + /** + * Initialization value + */ + static access_t init_value() + { + return Fifo_en::bits(1) | + Rx_fifo_rst::bits(0) | + Tx_fifo_rst::bits(0) | + Rx_fifo_trigger::bits(0) | + Tx_fifo_trigger::bits(0); + } + }; + + /** + * Modem control + */ + struct Umcon : Register<0xc, 32> + { + struct Send_request : Bitfield<0, 1> { }; + struct Modem_irq : Bitfield<3, 1> { }; + struct Auto_flow_ctl : Bitfield<4, 1> { }; + struct Rts_trigger : Bitfield<5, 3> { }; + + /** + * Initialization value + */ + static access_t init_value() + { + return Send_request::bits(0) | + Modem_irq::bits(0) | + Auto_flow_ctl::bits(0) | + Rts_trigger::bits(0); + } + }; + + /** + * FIFO status + */ + struct Ufstat : Register<0x18, 32> + { + struct Tx_fifo_full : Bitfield<24, 1> { }; + }; + + /** + * Transmit buffer + */ + struct Utxh : Register<0x20, 32> + { + struct Transmit_data : Bitfield<0, 8> { }; + }; + + /** + * Baud Rate Divisor + */ + struct Ubrdiv : Register<0x28, 32> + { + struct Baud_rate_div : Bitfield<0, 16> { }; + }; + + /** + * Fractional part of Baud Rate Divisor + */ + struct Ufracval : Register<0x2c, 32> + { + struct Baud_rate_frac : Bitfield<0, 4> { }; + }; + + public: + + /** + * Constructor + * + * \param base MMIO base address + * \param clock reference clock + * \param baud_rate targeted baud rate + */ + Arndale_uart_base(addr_t const base, unsigned const clock, + unsigned const baud_rate) : Mmio(base) + { + /* init control registers */ + write(Ulcon::init_value()); + write(Ucon::init_value()); + write(Ufcon::init_value()); + write(Umcon::init_value()); + + /* apply baud rate */ + float const div_val = ((float)clock / (baud_rate * 16)) - 1; + Ubrdiv::access_t const ubrdiv = div_val; + Ufracval::access_t const ufracval = + ((float)div_val - ubrdiv) * 16; + write(ubrdiv); + write(ufracval); + } + + /** + * Print character 'c' through the UART + */ + void put_char(char const c) + { + while (read()) ; + write(c); + } + }; +} + +#endif /* _INCLUDE__DRIVERS__UART__ARNDALE_UART_BASE_H_ */ +