mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-27 09:12:32 +00:00
6106e64aac
This commit moves the headers residing in `repos/base/include/spec/*/drivers` to `repos/base/include/drivers/defs` or repos/base/include/drivers/uart` respectively. The first one contains definitions about board-specific MMIO iand RAM addresses, or IRQ lines. While the latter contains device driver code for UART devices. Those definitions are used by driver implementations in `repos/base-hw`, `repos/os`, and `repos/dde-linux`, which now need to include them more explicitely. This work is a step in the direction of reducing 'SPEC' identifiers overall. Ref #2403
247 lines
5.8 KiB
C++
247 lines
5.8 KiB
C++
/*
|
|
* \brief UART driver for the Texas instruments TL16C750 module
|
|
* \author Martin stein
|
|
* \date 2011-10-17
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2011-2017 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
#ifndef _INCLUDE__DRIVERS__UART__TL16C750_H_
|
|
#define _INCLUDE__DRIVERS__UART__TL16C750_H_
|
|
|
|
/* Genode includes */
|
|
#include <util/mmio.h>
|
|
|
|
namespace Genode { class Tl16c750_uart; }
|
|
|
|
|
|
/**
|
|
* Base driver Texas instruments TL16C750 UART module
|
|
*
|
|
* In contrast to the abilities of the TL16C750, this driver targets only
|
|
* the basic UART functionalities.
|
|
*/
|
|
class Genode::Tl16c750_uart : public Mmio
|
|
{
|
|
protected:
|
|
/**
|
|
* 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> { };
|
|
};
|
|
|
|
/**
|
|
* Receiver holding register
|
|
*/
|
|
struct Uart_rhr : Register<0x0, 32>
|
|
{
|
|
struct Rhr : 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> { };
|
|
};
|
|
|
|
/**
|
|
* 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> { };
|
|
};
|
|
|
|
void _init(unsigned long const clock, unsigned long const baud_rate)
|
|
{
|
|
/* disable UART */
|
|
write<Uart_mdr1::Mode_select>(Uart_mdr1::Mode_select::DISABLED);
|
|
|
|
/* enable access to 'Uart_fcr' and 'Uart_ier' */
|
|
write<Uart_lcr::Reg_mode>(Uart_lcr::Reg_mode::OPERATIONAL);
|
|
|
|
/*
|
|
* Configure FIFOs, we don't use any interrupts or DMA,
|
|
* thus FIFO trigger and DMA configurations are dispensable.
|
|
*/
|
|
write<Uart_fcr::Fifo_enable>(1);
|
|
|
|
/* disable interrupts and sleep mode */
|
|
write<Uart_ier>(Uart_ier::Rhr_it::bits(0)
|
|
| 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));
|
|
|
|
/* enable access to 'Uart_dlh' and 'Uart_dll' */
|
|
write<Uart_lcr::Reg_mode>(Uart_lcr::Reg_mode::CONFIG_B);
|
|
|
|
/*
|
|
* Load the new divisor value (this driver solely uses
|
|
* 'UART_16X' mode)
|
|
*/
|
|
enum { UART_16X_DIVIDER_LOG2 = 4 };
|
|
unsigned long const adjusted_br = baud_rate << UART_16X_DIVIDER_LOG2;
|
|
double const divisor = (double)clock / adjusted_br;
|
|
unsigned long const divisor_uint = (unsigned long)divisor;
|
|
write<Uart_dll::Clock_lsb>(divisor_uint);
|
|
write<Uart_dlh::Clock_msb>(divisor_uint>>Uart_dll::Clock_lsb::WIDTH);
|
|
|
|
/*
|
|
* 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));
|
|
|
|
/*
|
|
* Switch to UART mode, we don't use hardware or software flow
|
|
* control, thus according configurations are dispensable
|
|
*/
|
|
write<Uart_mdr1::Mode_select>(Uart_mdr1::Mode_select::UART_16X);
|
|
}
|
|
|
|
public:
|
|
/**
|
|
* Constructor
|
|
*
|
|
* \param base MMIO base address
|
|
* \param clock reference clock
|
|
* \param baud_rate targeted baud rate
|
|
*/
|
|
Tl16c750_uart(addr_t const base, unsigned long const clock,
|
|
unsigned long const baud_rate) : Mmio(base)
|
|
{
|
|
/* reset and init UART */
|
|
write<Uart_sysc::Softreset>(1);
|
|
while (!read<Uart_syss::Resetdone>()) ;
|
|
_init(clock, baud_rate);
|
|
}
|
|
|
|
/**
|
|
* Transmit ASCII char 'c'
|
|
*/
|
|
void put_char(char const c)
|
|
{
|
|
/* wait as long as the transmission buffer is full */
|
|
while (!read<Uart_lsr::Tx_fifo_empty>()) ;
|
|
|
|
/* transmit character */
|
|
write<Uart_thr::Thr>(c);
|
|
}
|
|
};
|
|
|
|
#endif /* _INCLUDE__DRIVERS__UART__TL16C750_H_ */
|