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

247 lines
6.9 KiB
C++

/*
* \brief Exynos5-specific implementation of the Block::Driver interface
* \author Sebastian Sumpf
* \author Martin Stein
* \date 2013-03-22
*/
/*
* 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 <os/attached_mmio.h>
#include <timer_session/connection.h>
#include <drivers/defs/exynos5.h>
#include <regulator_session/connection.h>
#include <irq_session/connection.h>
#include <base/attached_ram_dataspace.h>
/* local includes */
#include <driver_base.h>
namespace Sd_card { class Driver; }
class Sd_card::Driver : public Driver_base,
private Attached_mmio
{
private:
/*
* Noncopyable
*/
Driver(Driver const &);
Driver &operator = (Driver const &);
enum {
HOST_FREQ = 52000000,
CLK_FREQ = 400000000,
CLK_DIV_52Mhz = 4,
CLK_DIV_400Khz = 0xff,
MSH_BASE = 0x12200000,
MSH_SIZE = 0x10000,
IDMAC_DESC_MAX_ENTRIES = 1024
};
enum Bus_width {
BUS_WIDTH_1 = 0,
BUS_WIDTH_4 = 1,
BUS_WIDTH_8 = 1 << 16,
};
template <off_t OFFSET, bool STRICT_WRITE = false>
struct Register : Mmio::Register<OFFSET, 32, STRICT_WRITE> { };
struct Ctrl : Register<0x0>
{
struct Reset : Bitfield<0, 3> { };
struct Global_interrupt : Bitfield<4, 1> { };
struct Dma_enable : Bitfield<5, 1> { };
struct Use_internal_dmac : Bitfield<25, 1> { };
};
struct Pwren : Register<0x4> { };
struct Clkdiv : Register<0x8> { };
struct Clkena : Register<0x10> { };
struct Tmout : Register<0x14> { };
struct Ctype : Register<0x18, true> { };
struct Blksize : Register<0x1c> { };
struct Bytcnt : Register<0x20> { };
struct Intmask : Register<0x24> { };
struct Cmdarg : Register<0x28> { };
struct Cmd : Register<0x2c>
{
struct Index : Bitfield<0, 6> { };
struct Rsp_type : Bitfield<6, 3>
{
enum Response { RESPONSE_NONE = 0,
RESPONSE_48_BIT = 1,
RESPONSE_48_BIT_WITH_BUSY = 5,
RESPONSE_136_BIT = 7,
};
};
struct Data_expected : Bitfield<9, 1> { };
struct Write : Bitfield<10, 1> { };
struct Wait_prvdata_complete : Bitfield<13, 1> { };
struct Init_sequence : Bitfield<15, 1> { };
struct Update_clock_registers_only : Bitfield<21, 1> { };
struct Use_hold_reg : Bitfield<29, 1> { };
struct Start_cmd : Bitfield<31, 1> { };
};
struct Rsp0 : Register<0x30> { };
struct Rsp1 : Register<0x34> { };
struct Rsp2 : Register<0x38> { };
struct Rsp3 : Register<0x3c> { };
struct Mintsts : Register<0x40> { };
struct Rintsts : Register<0x44, true>
{
struct Response_error : Bitfield<1, 1> { };
struct Data_transfer_over : Bitfield<3, 1> { };
struct Command_done : Bitfield<2, 1> { };
struct Data_crc_error : Bitfield<7, 1> { };
struct Response_timeout : Bitfield<8, 1> { };
struct Data_read_timeout : Bitfield<9, 1> { };
};
struct Status : Register<0x48>
{
struct Data_busy : Bitfield<9, 1> { };
};
struct Fifoth : Register<0x4c> { };
struct Bmod : Register<0x80, true>
{
struct Fixed_burst : Bitfield<1, 1> { };
struct Idmac_enable : Bitfield<7, 1> { };
};
struct Pldmnd : Register<0x84> { };
struct Idsts : Register<0x8c> { };
struct Idinten : Register<0x90, true> { };
struct Dbaddr : Register<0x88> { };
struct Clksel : Register<0x9c> { };
struct Emmc_ddr_req : Register<0x10c, true> { };
struct Idmac_desc
{
enum Flags {
NONE = 0,
DIC = 1 << 1,
LD = 1 << 2,
FS = 1 << 3,
CH = 1 << 4,
ER = 1 << 5,
OWN = 1 << 31,
};
unsigned flags;
unsigned bytes;
unsigned addr;
unsigned next;
size_t set(size_t block_count,
size_t block_size,
addr_t phys_addr,
Flags flag);
};
struct Clock_regulator
{
Regulator::Connection regulator;
Clock_regulator(Env &env) : regulator(env, Regulator::CLK_MMC0) {
regulator.state(true); }
};
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;
};
Env &_env;
Timer_delayer _delayer { _env };
Block_transfer _block_transfer { };
Clock_regulator _clock_regulator { _env };
Signal_handler<Driver> _irq_handler { _env.ep(), *this, &Driver::_handle_irq };
Irq_connection _irq { _env, Exynos5::SDMMC0_IRQ };
Attached_ram_dataspace _idmac_desc_ds { _env.ram(), _env.rm(),
IDMAC_DESC_MAX_ENTRIES * sizeof(Idmac_desc),
UNCACHED };
Idmac_desc *const _idmac_desc { _idmac_desc_ds.local_addr<Idmac_desc>() };
addr_t const _idmac_desc_phys { Dataspace_client(_idmac_desc_ds.cap())
.phys_addr() };
Card_info _card_info { _init() };
bool _reset();
void _reset_fifo();
void _disable_irq();
bool _update_clock_registers();
bool _setup_bus(unsigned clock_div);
void _handle_irq();
Card_info _init();
bool _setup_idmac_descriptor_table(size_t block_count,
addr_t phys_addr);
/*********************
** Host_controller **
*********************/
bool _issue_command(Command_base const &command) override;
Cid _read_cid() override ;
Csd _read_csd() override ;
size_t _read_ext_csd() override;
unsigned _read_rca() override { return 0; }
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 buf_phys,
Block::Packet_descriptor &pkt) override;
void write_dma(Block::sector_t block_number,
size_t block_count,
addr_t buf_phys,
Block::Packet_descriptor &pkt) 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_ */