/* * \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 #include #include #include #include #include /* local includes */ #include 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 struct Register : Mmio::Register { }; 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 _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() }; 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_ */