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

221 lines
5.8 KiB
C++

/*
* \brief Raspberry Pi SDHCI driver
* \author Norman Feske
* \author Timo Wischer
* \author Martin Stein
* \date 2014-09-21
*/
/*
* Copyright (C) 2014-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 <drivers/defs/rpi.h>
#include <os/attached_mmio.h>
#include <irq_session/connection.h>
/* local includes */
#include <driver_base.h>
namespace Sd_card { class Driver; }
class Sd_card::Driver : public Driver_base,
private Attached_mmio
{
private:
struct Blksizecnt : Register<0x4, 32>
{
struct Blkcnt : Bitfield<16, 16> { };
struct Blksize : Bitfield<0, 10> { };
};
struct Resp0 : Register<0x10, 32> { };
struct Resp1 : Register<0x14, 32> { };
struct Resp2 : Register<0x18, 32> { };
struct Resp3 : Register<0x1c, 32> { };
/*
* Handle the SDHCI quirk that responses of 136-bit requests are
* shifted by 8 bits.
*/
template <off_t OFFSET>
struct Cmdresp_tpl : Register<OFFSET, 32>
{
struct Resp_8_24 : Register<OFFSET, 32>::template Bitfield<0, 24> { };
struct Resp_0_8 : Register<OFFSET, 32>::template Bitfield<24, 8> { };
};
struct Cmdresp0 : Cmdresp_tpl<0x10> { };
struct Cmdresp1 : Cmdresp_tpl<0x14> { };
struct Cmdresp2 : Cmdresp_tpl<0x18> { };
struct Cmdresp3 : Cmdresp_tpl<0x1c> { };
struct Resp0_136 : Bitset_2<Cmdresp3::Resp_0_8, Cmdresp0::Resp_8_24> { };
struct Resp1_136 : Bitset_2<Cmdresp0::Resp_0_8, Cmdresp1::Resp_8_24> { };
struct Resp2_136 : Bitset_2<Cmdresp1::Resp_0_8, Cmdresp2::Resp_8_24> { };
struct Resp3_136 : Bitset_2<Cmdresp2::Resp_0_8, Cmdresp3::Resp_8_24> { };
struct Data : Register<0x20, 32> { };
struct Control0 : Register<0x28, 32>
{
struct Hctl_dwidth : Bitfield<1, 1> { };
struct Hctl_hs_en : Bitfield<2, 1> { };
};
struct Control1 : Register<0x2c, 32>
{
struct Clk_internal_en : Bitfield<0, 1> { };
struct Clk_internal_stable : Bitfield<1, 1> { };
struct Clk_en : Bitfield<2, 1> { };
struct Clk_freq8 : Bitfield<8, 8> { };
struct Clk_freq_ms2 : Bitfield<6, 2> { };
struct Data_tounit : Bitfield<16, 4> { };
struct Srst_hc : Bitfield<24, 1> { };
struct Srst_cmd : Bitfield<25, 1> { };
struct Srst_data : Bitfield<26, 1> { };
};
struct Status : Register<0x24, 32>
{
struct Inhibit : Bitfield<0, 2> { };
struct Bwe : Bitfield<10, 1> { };
struct Bre : Bitfield<11, 1> { };
};
struct Host_ctrl : Register<0x28, 32>
{
struct Voltage : Bitfield<9, 3> {
enum {
V18 = 0b101,
V30 = 0b110,
V33 = 0b111,
};
};
struct Power : Bitfield<8, 1> { };
};
struct Arg1 : Register<0x8, 32> { };
struct Cmdtm : Register<0xc, 32>
{
struct Index : Bitfield<24, 6> { };
struct Isdata : Bitfield<21, 1> { };
struct Tm_blkcnt_en : Bitfield<1, 1> { };
struct Tm_multi_block : Bitfield<5, 1> { };
struct Tm_auto_cmd_en : Bitfield<2, 2>
{
enum { CMD12 = 1 };
};
struct Tm_dat_dir : Bitfield<4, 1>
{
enum { WRITE = 0, READ = 1 };
};
struct Rsp_type : Bitfield<16, 2>
{
enum Response { RESPONSE_NONE = 0,
RESPONSE_136_BIT = 1,
RESPONSE_48_BIT = 2,
RESPONSE_48_BIT_WITH_BUSY = 3 };
};
};
struct Interrupt : Register<0x30, 32>
{
struct Cmd_done : Bitfield<0, 1> { };
struct Data_done : Bitfield<1, 1> { };
};
struct Irpt_mask : Register<0x34, 32> { };
struct Irpt_en : Register<0x38, 32> { };
struct Capabilities : Register<0x40, 32> { };
struct Host_version : Register<0xFE, 16>
{
struct Spec : Bitfield<0, 8> { };
struct Vendor : Bitfield<8, 8> { };
};
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); }
};
Env &_env;
Timer_delayer _delayer { _env };
Irq_connection _irq { _env, Rpi::SDHCI_IRQ };
Card_info _card_info { _init() };
template <typename REG>
bool _poll_and_wait_for(unsigned value)
{
/* poll for a while */
try { wait_for(Attempts(5000), Microseconds(0), _delayer,
typename REG::Equal(value)); }
catch (Polling_timeout) {
/* if the value was not reached while polling, start sleeping */
try { wait_for(_delayer, typename REG::Equal(value)); }
catch (Polling_timeout) { return false; }
}
return true;
}
Card_info _init();
void _set_and_enable_clock(unsigned divider);
void _set_block_count(size_t block_count);
size_t _block_to_command_address(size_t block_number);
/*********************
** Host_controller **
*********************/
bool _issue_command(Command_base const &command) override;
Cid _read_cid() override;
Csd _read_csd() override;
Card_info card_info() const override { return _card_info; }
unsigned _read_rca() override {
return Send_relative_addr::Response::Rca::get(Mmio::read<Resp0>()); }
public:
Driver(Env &env);
/*******************
** Block::Driver **
*******************/
void read(Block::sector_t block_number,
size_t block_count,
char *buffer,
Block::Packet_descriptor &packet) override;
void write(Block::sector_t block_number,
size_t block_count,
char const *buffer,
Block::Packet_descriptor &packet) override;
Ram_dataspace_capability alloc_dma_buffer(size_t size) override {
return _env.ram().alloc(size, UNCACHED); }
};
#endif /* _DRIVER_H_ */