genode/repos/os/src/drivers/sd_card/spec/imx/driver.h

300 lines
8.7 KiB
C++

/*
* \brief Secured Digital Host Controller
* \author Martin Stein
* \date 2015-02-05
*/
/*
* Copyright (C) 2015-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 _DRIVER_H_
#define _DRIVER_H_
/* Genode includes */
#include <timer_session/connection.h>
#include <irq_session/connection.h>
#include <os/attached_mmio.h>
/* local includes */
#include <driver_base.h>
#include <adma2.h>
namespace Sd_card { class Driver; }
class Sd_card::Driver : public Driver_base,
private Attached_mmio
{
private:
enum Bus_width { BUS_WIDTH_1, BUS_WIDTH_4 };
enum Clock { CLOCK_INITIAL, CLOCK_OPERATIONAL };
enum Clock_divider { CLOCK_DIV_4, CLOCK_DIV_8, CLOCK_DIV_512 };
/********************
** MMIO structure **
********************/
struct Blkattr : Register<0x4, 32>
{
struct Blksize : Bitfield<0, 13> { };
struct Blkcnt : Bitfield<16, 16> { };
};
template <off_t OFFSET>
struct Cmdrsp_tpl : Register<OFFSET, 32>
{
struct Rsp136_8_24 : Register<OFFSET, 32>::template Bitfield<0, 24> { };
struct Rsp136_0_8 : Register<OFFSET, 32>::template Bitfield<24, 8> { };
};
struct Cmdarg : Register<0x8, 32> { };
struct Cmdrsp0 : Cmdrsp_tpl<0x10> { };
struct Cmdrsp1 : Cmdrsp_tpl<0x14> { };
struct Cmdrsp2 : Cmdrsp_tpl<0x18> { };
struct Cmdrsp3 : Cmdrsp_tpl<0x1c> { };
struct Rsp136_0 : Bitset_2<Cmdrsp3::Rsp136_0_8, Cmdrsp0::Rsp136_8_24> { };
struct Rsp136_1 : Bitset_2<Cmdrsp0::Rsp136_0_8, Cmdrsp1::Rsp136_8_24> { };
struct Rsp136_2 : Bitset_2<Cmdrsp1::Rsp136_0_8, Cmdrsp2::Rsp136_8_24> { };
struct Rsp136_3 : Bitset_2<Cmdrsp2::Rsp136_0_8, Cmdrsp3::Rsp136_8_24> { };
template <off_t OFFSET>
struct Xfertyp_base : Register<OFFSET, 32>
{
struct Dmaen : Register<OFFSET, 32>::template Bitfield<0, 1> { };
struct Bcen : Register<OFFSET, 32>::template Bitfield<1, 1> { };
struct Ac12en : Register<OFFSET, 32>::template Bitfield<2, 1> { };
struct Dtdsel : Register<OFFSET, 32>::template Bitfield<4, 1>
{
enum { WRITE = 0, READ = 1, };
};
struct Msbsel : Register<OFFSET, 32>::template Bitfield<5, 1> { };
};
struct Mixctrl : Xfertyp_base<0x48>
{
struct Ddren : Bitfield<3, 1> { };
struct Nibblepos : Bitfield<6, 1> { };
struct Ac23en : Bitfield<7, 1> { };
struct Always_ones : Bitfield<31, 1> { };
};
struct Xfertyp : Xfertyp_base<0xc>
{
struct Rsptyp : Bitfield<16, 2>
{
enum {
_0BIT = 0,
_136BIT = 1,
_48BIT = 2,
_48BIT_BUSY = 3,
};
};
struct Cccen : Bitfield<19, 1> { };
struct Cicen : Bitfield<20, 1> { };
struct Dpsel : Bitfield<21, 1> { };
struct Cmdtyp : Bitfield<22, 2>
{
enum { ABORT_CMD12 = 3 };
};
struct Cmdinx : Bitfield<24, 6> { };
};
struct Prsstat : Register<0x24, 32>
{
struct Cihb : Bitfield<0, 1> { };
struct Cdihb : Bitfield<1, 1> { };
struct Dla : Bitfield<2, 1> { };
struct Sdstb : Bitfield<3, 1> { };
};
struct Proctl : Register<0x28, 32>
{
struct Dtw : Bitfield<1, 2>
{
enum { _1BIT = 0, _4BIT = 1 };
};
struct Dmas : Bitfield<8, 2> { enum { ADMA2 = 2 }; };
};
struct Sysctl : Register<0x2c, 32>
{
struct Ipgen : Bitfield<0, 1> { };
struct Hcken : Bitfield<1, 1> { };
struct Peren : Bitfield<2, 1> { };
struct Dvs : Bitfield<4, 4>
{
enum { DIV1 = 0x0, DIV4 = 0x3, DIV16 = 0xf, };
};
struct Sdclkfs : Bitfield<8, 8>
{
enum { DIV1 = 0x00, DIV2 = 0x01, DIV32 = 0x10, };
};
struct Dtocv : Bitfield<16, 4>
{
enum {
SDCLK_TIMES_2_POW_28 = 0xf,
SDCLK_TIMES_2_POW_27 = 0xe,
SDCLK_TIMES_2_POW_13 = 0x0,
};
};
struct Ipp_rst_n : Bitfield<23, 1> { };
struct Rsta : Bitfield<24, 1> { };
struct Rstc : Bitfield<25, 1> { };
struct Rstd : Bitfield<26, 1> { };
};
template <off_t OFFSET>
struct Irq_tpl : Register<OFFSET, 32>
{
struct Cc : Register<OFFSET, 32>::template Bitfield<0, 1> { };
struct Tc : Register<OFFSET, 32>::template Bitfield<1, 1> { };
struct Dint : Register<OFFSET, 32>::template Bitfield<3, 1> { };
struct Ctoe : Register<OFFSET, 32>::template Bitfield<16, 1> { };
struct Cce : Register<OFFSET, 32>::template Bitfield<17, 1> { };
struct Cebe : Register<OFFSET, 32>::template Bitfield<18, 1> { };
struct Cie : Register<OFFSET, 32>::template Bitfield<19, 1> { };
struct Dtoe : Register<OFFSET, 32>::template Bitfield<20, 1> { };
struct Dce : Register<OFFSET, 32>::template Bitfield<21, 1> { };
struct Debe : Register<OFFSET, 32>::template Bitfield<22, 1> { };
struct Ac12e : Register<OFFSET, 32>::template Bitfield<24, 1> { };
struct Dmae : Register<OFFSET, 32>::template Bitfield<28, 1> { };
};
struct Irq : Irq_tpl<0> { };
struct Irqstat : Irq_tpl<0x30> { };
struct Irqstaten : Irq_tpl<0x34> { };
struct Irqsigen : Irq_tpl<0x38> { };
struct Maxcurrent : Register<0x48, 32> { };
struct Adsaddr : Register<0x58, 32> { };
struct Hostver : Register<0xfc, 32>
{
struct Svn : Bitfield<0, 8> { };
struct Vvn : Bitfield<8, 8> { };
};
struct Wml : Register<0x44, 32>
{
struct Rd_wml : Bitfield<0, 8> { };
struct Rd_brst_len : Bitfield<8, 5> { };
struct Wr_wml : Bitfield<16, 8> { };
struct Wr_brst_len : Bitfield<24, 5> { };
};
struct Vendspec : Register<0xc0, 32>
{
struct Frc_sdclk_on : Bitfield<8, 1> { };
};
/************************
** Utility structures **
************************/
struct Timer_delayer : Timer::Connection, Mmio::Delayer
{
Timer_delayer(Genode::Env &env) : Timer::Connection(env) { }
void usleep(uint64_t us) override { Timer::Connection::usleep(us); }
};
struct Block_transfer
{
Block::Packet_descriptor packet { };
bool pending = false;
bool read = false;
};
Env &_env;
Block_transfer _block_transfer { };
Timer_delayer _delayer { _env };
Signal_handler<Driver> _irq_handler { _env.ep(), *this,
&Driver::_handle_irq };
Irq_connection _irq;
Card_info _card_info { _init() };
Adma2::Table _adma2_table { _env.ram(), _env.rm() };
static bool _supported_host_version(Hostver::access_t hostver);
static void _watermark_level(Wml::access_t &wml);
void _handle_irq();
void _detect_err(char const * const err);
void _disable_irqs();
void _enable_irqs();
void _bus_width(Bus_width bus_width);
void _disable_clock();
void _disable_clock_preparation();
void _enable_clock(Clock_divider divider);
void _enable_clock_finish();
void _clock(Clock clock);
void _clock_finish(Clock clock);
int _reset();
void _reset_amendments();
int _wait_for_cmd_allowed();
int _wait_for_cmd_complete();
int _wait_for_card_ready_mbw();
int _stop_transmission();
void _stop_transmission_finish_xfertyp(Xfertyp::access_t &xfertyp);
int _wait_for_cmd_complete_mb_finish(bool const reading);
int _prepare_dma_mb(Block::Packet_descriptor packet,
bool reading,
size_t blk_cnt,
addr_t buf_phys);
bool _issue_cmd_finish_xfertyp(Xfertyp::access_t &xfertyp,
bool const transfer,
bool const multiblock,
bool const reading);
Card_info _init();
/*********************
** Host_controller **
*********************/
Cid _read_cid() override;
Csd _read_csd() override;
unsigned _read_rca() override;
bool _issue_command(Command_base const & cmd) override;
Card_info card_info() const override { return _card_info; }
public:
using Block::Driver::read;
using Block::Driver::write;
Driver(Env &env);
/*******************
** Block::Driver **
*******************/
void read_dma(Block::sector_t block_number,
size_t block_count,
addr_t phys,
Block::Packet_descriptor &packet) override;
void write_dma(Block::sector_t block_number,
size_t block_count,
addr_t phys,
Block::Packet_descriptor &packet) override;
bool dma_enabled() override { return true; }
Ram_dataspace_capability alloc_dma_buffer(size_t size) override {
return _env.ram().alloc(size, UNCACHED); }
};
#endif /* _DRIVER_H_ */