221 lines
5.8 KiB
C++
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_ */
|