mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-22 15:02:25 +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
274 lines
7.2 KiB
C++
274 lines
7.2 KiB
C++
/*
|
|
* \brief Driver for Freescale's i.MX UART
|
|
* \author Norman Feske
|
|
* \author Martin Stein
|
|
* \date 2012-08-30
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2012-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__IMX_H_
|
|
#define _INCLUDE__DRIVERS__UART__IMX_H_
|
|
|
|
/* Genode includes */
|
|
#include <util/mmio.h>
|
|
|
|
namespace Genode { class Imx_uart; }
|
|
|
|
|
|
/**
|
|
* Driver base for i.MX UART-module
|
|
*/
|
|
class Genode::Imx_uart: Mmio
|
|
{
|
|
/**
|
|
* Control register 1
|
|
*/
|
|
struct Cr1 : Register<0x80, 32>
|
|
{
|
|
struct Uart_en : Bitfield<0, 1> { }; /* enable UART */
|
|
struct Doze : Bitfield<1, 1> { }; /* disable on doze */
|
|
struct At_dma_en : Bitfield<2, 1> { }; /* aging DMA
|
|
* timer on */
|
|
struct Tx_dma_en : Bitfield<3, 1> { }; /* TX ready DMA on */
|
|
struct Snd_brk : Bitfield<4, 1> { }; /* send breaks */
|
|
struct Rtsd_en : Bitfield<5, 1> { }; /* RTS delta IRQ on */
|
|
struct Tx_mpty_en : Bitfield<6, 1> { }; /* TX empty IRQ on */
|
|
struct Ir_en : Bitfield<7, 1> { }; /* enable infrared */
|
|
struct Rx_dma_en : Bitfield<8, 1> { }; /* RX ready DMA on */
|
|
struct R_rdy_en : Bitfield<9, 1> { }; /* RX ready IRQ on */
|
|
|
|
struct Icd : Bitfield<10, 2> /* idle IRQ condition */
|
|
{
|
|
enum { IDLE_4_FRAMES = 0 };
|
|
};
|
|
|
|
struct Id_en : Bitfield<12, 1> { }; /* enable idle IRQ */
|
|
struct T_rdy_en : Bitfield<13, 1> { }; /* TX ready IRQ on */
|
|
struct Adbr : Bitfield<14, 1> { }; /* enable baud-rate
|
|
* auto detect */
|
|
struct Ad_en : Bitfield<15, 1> { }; /* enable ADBR IRQ */
|
|
|
|
/**
|
|
* Initialization value
|
|
*/
|
|
static access_t init_value()
|
|
{
|
|
return Uart_en::bits(1) |
|
|
Doze::bits(0) |
|
|
At_dma_en::bits(0) |
|
|
Tx_dma_en::bits(0) |
|
|
Snd_brk::bits(0) |
|
|
Rtsd_en::bits(0) |
|
|
Tx_mpty_en::bits(0) |
|
|
Ir_en::bits(0) |
|
|
Rx_dma_en::bits(0) |
|
|
R_rdy_en::bits(0) |
|
|
Id_en::bits(0) |
|
|
T_rdy_en::bits(0) |
|
|
Adbr::bits(0) |
|
|
Ad_en::bits(0);
|
|
}
|
|
|
|
};
|
|
|
|
/**
|
|
* Control register 2
|
|
*/
|
|
struct Cr2 : Register<0x84, 32>
|
|
{
|
|
struct S_rst : Bitfield<0, 1> /* SW reset bit */
|
|
{
|
|
enum { NO_RESET = 1 };
|
|
};
|
|
|
|
struct Rx_en : Bitfield<1, 1> { }; /* enable receiver */
|
|
struct Tx_en : Bitfield<2, 1> { }; /* enable transmitter */
|
|
struct At_en : Bitfield<3, 1> { }; /* enable aging timer */
|
|
struct Rts_en : Bitfield<4, 1> { }; /* send request IRQ on */
|
|
|
|
struct Ws : Bitfield<5, 1> /* select word size */
|
|
{
|
|
enum { _8_BITS = 1 };
|
|
};
|
|
|
|
struct Stpb : Bitfield<6, 1> /* number of stop bits */
|
|
{
|
|
enum { _1_BIT = 0 };
|
|
};
|
|
|
|
struct Pr_en : Bitfield<8, 1> { }; /* enable parity */
|
|
struct Esc_en : Bitfield<11, 1> { }; /* escape detection on */
|
|
|
|
struct Ctsc : Bitfield<13, 1> /* select CTS control */
|
|
{
|
|
enum { BY_RECEIVER = 1 };
|
|
};
|
|
|
|
struct Irts : Bitfield<14, 1> { }; /* ignore RTS pin */
|
|
struct Esci : Bitfield<15, 1> { }; /* enable escape IRQ */
|
|
|
|
/**
|
|
* Initialization value
|
|
*/
|
|
static access_t init_value()
|
|
{
|
|
return S_rst::bits(S_rst::NO_RESET) |
|
|
Rx_en::bits(0) |
|
|
Tx_en::bits(1) |
|
|
At_en::bits(0) |
|
|
Rts_en::bits(0) |
|
|
Ws::bits(Ws::_8_BITS) |
|
|
Stpb::bits(Stpb::_1_BIT) |
|
|
Pr_en::bits(0) |
|
|
Esc_en::bits(0) |
|
|
Ctsc::bits(Ctsc::BY_RECEIVER) |
|
|
Irts::bits(1) |
|
|
Esci::bits(0);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Control register 3
|
|
*/
|
|
struct Cr3 : Register<0x88, 32>
|
|
{
|
|
struct Rxdmux_sel : Bitfield<2, 1> { }; /* use muxed RXD */
|
|
struct Aci_en : Bitfield<0, 1> { }; /* autobaud count IRQ on */
|
|
struct Dtrd_en : Bitfield<3, 1> { }; /* data terminal ready
|
|
* delta IRQ on */
|
|
struct Awak_en : Bitfield<4, 1> { }; /* wake IRQ on */
|
|
struct Air_int_en : Bitfield<5, 1> { }; /* IR wake IRQ on */
|
|
struct Rx_ds_en : Bitfield<6, 1> { }; /* RX status IRQ on */
|
|
struct Ad_nimp : Bitfield<7, 1> { }; /* autobaud detect off */
|
|
struct Ri_en : Bitfield<8, 1> { }; /* ring indicator IRQ on */
|
|
struct Dcd_en : Bitfield<9, 1> { }; /* data carrier detect
|
|
* IRQ on */
|
|
struct Dsr : Bitfield<10,1> { }; /* DSR/DTR output */
|
|
struct Frame_en : Bitfield<11,1> { }; /* frame error IRQ on */
|
|
struct Parity_en : Bitfield<12,1> { }; /* parity error IRQ on */
|
|
struct Dtr_en : Bitfield<13,1> { }; /* data terminal ready
|
|
* IRQ on */
|
|
struct Dpec_ctrl : Bitfield<14,2> { }; /* DTR/DSR IRQ edge
|
|
* control */
|
|
|
|
/**
|
|
* Initialization value
|
|
*/
|
|
static access_t init_value()
|
|
{
|
|
return Aci_en::bits(0) |
|
|
Rxdmux_sel::bits(0) |
|
|
Dtrd_en::bits(0) |
|
|
Awak_en::bits(0) |
|
|
Air_int_en::bits(0) |
|
|
Rx_ds_en::bits(0) |
|
|
Ad_nimp::bits(1) |
|
|
Ri_en::bits(0) |
|
|
Dcd_en::bits(0) |
|
|
Dsr::bits(0) |
|
|
Frame_en::bits(0) |
|
|
Parity_en::bits(0) |
|
|
Dtr_en::bits(0) |
|
|
Dpec_ctrl::bits(0);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Control register 4
|
|
*/
|
|
struct Cr4 : Register<0x8c, 32>
|
|
{
|
|
struct Dr_en : Bitfield<0, 1> { }; /* RX data ready IRQ on */
|
|
struct Or_en : Bitfield<1, 1> { }; /* RX overrun IRQ on */
|
|
struct Bk_en : Bitfield<2, 1> { }; /* BREAK IRQ on */
|
|
struct Tc_en : Bitfield<3, 1> { }; /* TX complete IRQ on */
|
|
struct Lp_dis : Bitfield<4, 1> { }; /* low power off */
|
|
struct IR_sc : Bitfield<5, 1> { }; /* use UART ref clock
|
|
* for vote logic */
|
|
struct Id_dma_en : Bitfield<6, 1> { }; /* idle DMA IRQ on */
|
|
struct Wake_en : Bitfield<7, 1> { }; /* WAKE IRQ on */
|
|
struct IR_en : Bitfield<8, 1> { }; /* serial IR IRQ on */
|
|
struct Cts_level : Bitfield<10,6> { }; /* CTS trigger level*/
|
|
|
|
/**
|
|
* Initialization value
|
|
*/
|
|
static access_t init_value()
|
|
{
|
|
return Dr_en::bits(0) |
|
|
Or_en::bits(0) |
|
|
Bk_en::bits(0) |
|
|
Tc_en::bits(0) |
|
|
Lp_dis::bits(0) |
|
|
IR_sc::bits(0) |
|
|
Id_dma_en::bits(0) |
|
|
Wake_en::bits(0) |
|
|
IR_en::bits(0) |
|
|
Cts_level::bits(0);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Status register 2
|
|
*/
|
|
struct Sr2 : Register<0x98, 32>
|
|
{
|
|
struct Txdc : Bitfield<3, 1> { }; /* transmission complete */
|
|
};
|
|
|
|
/**
|
|
* Transmitter register
|
|
*/
|
|
struct Txd : Register<0x40, 32>
|
|
{
|
|
struct Tx_data : Bitfield<0, 8> { }; /* transmit data */
|
|
};
|
|
|
|
/**
|
|
* Transmit character 'c' without care about its type
|
|
*/
|
|
void _put_char(char c)
|
|
{
|
|
while (!read<Sr2::Txdc>()) ;
|
|
write<Txd::Tx_data>(c);
|
|
}
|
|
|
|
public:
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* \param base device MMIO base
|
|
*/
|
|
Imx_uart(addr_t base, uint32_t, uint32_t) : Mmio(base)
|
|
{
|
|
write<Cr1>(Cr1::init_value());
|
|
write<Cr2>(Cr2::init_value());
|
|
write<Cr3>(Cr3::init_value());
|
|
write<Cr4>(Cr4::init_value());
|
|
}
|
|
|
|
/**
|
|
* Print character 'c' through the UART
|
|
*/
|
|
void put_char(char c)
|
|
{
|
|
enum { ASCII_LINE_FEED = 10,
|
|
ASCII_CARRIAGE_RETURN = 13 };
|
|
|
|
/* prepend line feed with carriage return */
|
|
if (c == ASCII_LINE_FEED) _put_char(ASCII_CARRIAGE_RETURN);
|
|
|
|
/* transmit character */
|
|
_put_char(c);
|
|
}
|
|
};
|
|
|
|
#endif /* _INCLUDE__DRIVERS__UART__IMX_H_ */
|