Retire Exynos 5 support (fix #3725)

This commit is contained in:
Stefan Kalkowski
2020-04-07 00:42:50 +02:00
committed by Christian Helmuth
parent 941e918b46
commit 0e49336b96
106 changed files with 15 additions and 7551 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,108 +0,0 @@
/*
* \brief Framebuffer driver for Exynos5 HDMI
* \author Martin Stein
* \date 2013-08-09
*/
/*
* Copyright (C) 2013-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 <base/component.h>
#include <base/stdint.h>
#include <base/log.h>
namespace Framebuffer
{
using namespace Genode;
/**
* Framebuffer driver
*/
class Driver;
}
class Framebuffer::Driver
{
public:
enum Format { FORMAT_RGB565 };
enum Output { OUTPUT_LCD, OUTPUT_HDMI };
private:
Genode::Env &_env;
size_t _fb_width;
size_t _fb_height;
Format _fb_format;
public:
/**
* Constructor
*/
Driver(Genode::Env &env)
:
_env(env),
_fb_width(0),
_fb_height(0),
_fb_format(FORMAT_RGB565)
{ }
/**
* Return amount of bytes that is used for one pixel descriptor
*
* \param format pixel format
*
* \retval 0 failed
* \retval >0 succeeded
*/
static size_t bytes_per_pixel(Format format)
{
switch (format) {
case FORMAT_RGB565:
return 2;
default:
error("unknown pixel format");
return 0;
}
}
/**
* Return size of framebuffer in bytes
*
* \param width width of framebuffer in pixel
* \param height height of framebuffer in pixel
* \param format pixel format of framebuffer
*
* \retval 0 failed
* \retval >0 succeeded
*/
size_t buffer_size(size_t width, size_t height, Format format)
{
return bytes_per_pixel(format) * width * height;
}
/**
* Initialize driver for HDMI output
*
* \param width width of screen and framebuffer in pixel
* \param height height of screen and framebuffer in pixel
* \param format pixel format of framebuffer
* \param fb_phys physical base of framebuffer
*
* \retval -1 failed
* \retval 0 succeeded
*/
int init(size_t width, size_t height, Format format, addr_t fb_phys);
};
#endif /* _DRIVER_H_ */

View File

@ -1,147 +0,0 @@
/*
* \brief Framebuffer driver for Exynos5 HDMI
* \author Martin Stein
* \date 2013-08-09
*/
/*
* Copyright (C) 2013-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.
*/
/* Genode includes */
#include <base/attached_rom_dataspace.h>
#include <base/component.h>
#include <framebuffer_session/framebuffer_session.h>
#include <timer_session/connection.h>
#include <dataspace/client.h>
#include <base/log.h>
#include <os/static_root.h>
#include <util/string.h>
/* local includes */
#include <driver.h>
namespace Framebuffer
{
using namespace Genode;
/**
* Framebuffer session backend
*/
class Session_component;
struct Main;
};
class Framebuffer::Session_component
:
public Genode::Rpc_object<Framebuffer::Session>
{
private:
Genode::Env &_env;
unsigned _width;
unsigned _height;
Driver::Format _format;
size_t _size;
Dataspace_capability _ds;
addr_t _phys_base;
Timer::Connection _timer { _env };
/**
* Convert Driver::Format to Framebuffer::Mode::Format
*/
static Mode::Format _convert_format(Driver::Format driver_format)
{
switch (driver_format) {
case Driver::FORMAT_RGB565: return Mode::RGB565;
}
return Mode::INVALID;
}
public:
/**
* Constructor
*
* \param driver driver backend that communicates with hardware
* \param width width of framebuffer in pixel
* \param height height of framebuffer in pixel
* \param output targeted output device
*/
Session_component(Genode::Env &env, Driver &driver,
unsigned width, unsigned height)
:
_env(env),
_width(width),
_height(height),
_format(Driver::FORMAT_RGB565),
_size(driver.buffer_size(width, height, _format)),
_ds(_env.ram().alloc(_size, WRITE_COMBINED)),
_phys_base(Dataspace_client(_ds).phys_addr())
{
if (driver.init(width, height, _format, _phys_base)) {
error("could not initialize display");
struct Could_not_initialize_display : Exception { };
throw Could_not_initialize_display();
}
}
/************************************
** Framebuffer::Session interface **
************************************/
Dataspace_capability dataspace() override { return _ds; }
Mode mode() const override
{
return Mode(_width, _height, _convert_format(_format));
}
void mode_sigh(Genode::Signal_context_capability) override { }
void sync_sigh(Genode::Signal_context_capability sigh) override
{
_timer.sigh(sigh);
_timer.trigger_periodic(10*1000);
}
void refresh(int, int, int, int) override { }
};
static unsigned config_dimension(Genode::Xml_node node, char const *attr,
unsigned default_value)
{
return node.attribute_value(attr, default_value);
}
struct Main
{
Genode::Env &_env;
Genode::Entrypoint &_ep;
Genode::Attached_rom_dataspace _config { _env, "config" };
Framebuffer::Driver _driver { _env };
Framebuffer::Session_component _fb_session { _env, _driver,
config_dimension(_config.xml(), "width", 1920),
config_dimension(_config.xml(), "height", 1080)
};
Genode::Static_root<Framebuffer::Session> _fb_root { _ep.manage(_fb_session) };
Main(Genode::Env &env) : _env(env), _ep(_env.ep())
{
/* announce service and relax */
_env.parent().announce(_ep.manage(_fb_root));
}
};
void Component::construct(Genode::Env &env) { static Main main(env); }

View File

@ -1,8 +0,0 @@
TARGET = exynos5_fb_drv
REQUIRES = arm_v7
SRC_CC += main.cc driver.cc
LIBS += base
INC_DIR += $(PRG_DIR)
INC_DIR += $(call select_from_repositories,include/spec/exynos5)
CC_CXX_WARN_STRICT :=

View File

@ -1,220 +0,0 @@
/*
* \brief Gpio driver for the Odroid-x2
* \author Alexy Gallardo Segura <alexy@uclv.cu>
* \author Humberto Lopéz Leon <humberto@uclv.cu>
* \author Reinier Millo Sánchez <rmillo@uclv.cu>
* \date 2015-07-03
*/
/*
* Copyright (C) 2012 Ksys Labs LLC
* Copyright (C) 2012-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 <gpio/driver.h>
#include <irq_session/connection.h>
#include <timer_session/connection.h>
/* local includes */
#include <gpio.h>
namespace Gpio { class Odroid_x2_driver; }
class Gpio::Odroid_x2_driver : public Driver
{
private:
Reg _reg1;
Reg _reg2;
Reg _reg3;
Reg _reg4;
Genode::Irq_connection _irq;
Genode::Signal_handler<Odroid_x2_driver> _dispatcher;
Genode::Signal_context_capability _sig_cap[MAX_PINS];
bool _irq_enabled[MAX_PINS];
bool _async;
void _handle()
{
handle_irq();
}
void handle_irq() { }
Gpio::Reg *_gpio_reg(int gpio_pin)
{
int pos = gpio_bank_index(gpio_pin, true);
switch(pos) {
case 0 ... 13:
return &_reg1;
case 14 ... 38:
return &_reg2;
case 39:
return &_reg3;
case 40 ... 46:
return &_reg4;
default:
Genode::error("no Gpio_bank for pin ", gpio_pin, " available");
return 0;
}
}
int _gpio_index(int gpio) { return gpio & 0x1f; }
Odroid_x2_driver(Genode::Env &env)
:
_reg1(env, 0x11400000, 1000),
_reg2(env, 0x11000000, 1000),
_reg3(env, 0x03860000, 1000),
_reg4(env, 0x106E0000, 1000),
_irq(env, 104),
_dispatcher(env.ep(), *this, &Odroid_x2_driver::_handle),
_async(false)
{
_irq.sigh(_dispatcher);
_irq.ack_irq();
}
public:
static Odroid_x2_driver& factory(Genode::Env &env);
/******************************
** Gpio::Driver interface **
******************************/
void direction(unsigned gpio_pin, bool input) override
{
int pos_gpio = gpio_bank_index(gpio_pin, true);
int sum_gpio = gpio_bank_index(gpio_pin, false);
Genode::off_t offset = _bank_offset[pos_gpio];
int gpio = gpio_pin - sum_gpio;
Reg* reg = _gpio_reg(gpio_pin);
reg->set_direction(gpio, input, offset);
}
void write(unsigned gpio_pin, bool level) override
{
int pos_gpio = gpio_bank_index(gpio_pin, true);
int sum_gpio = gpio_bank_index(gpio_pin, false);
Genode::off_t offset = _bank_offset[pos_gpio];
int gpio = gpio_pin - sum_gpio;
Reg* reg = _gpio_reg(gpio_pin);
reg->write_pin(gpio, level, offset);
}
bool read(unsigned gpio_pin) override
{
int pos_gpio = gpio_bank_index(gpio_pin, true);
int sum_gpio = gpio_bank_index(gpio_pin, false);
Genode::off_t offset = _bank_offset[pos_gpio];
int gpio = gpio_pin - sum_gpio;
Reg* reg = _gpio_reg(gpio_pin);
return reg->read_pin(gpio, offset) ;
}
void debounce_enable(unsigned /* gpio */, bool /* enable */) override {
Genode::warning("debounce_enable not supported!"); }
void debounce_time(unsigned /* gpio */, unsigned long /* us */) override {
Genode::warning("debounce_time not supported!"); }
void falling_detect(unsigned gpio_pin) override
{
int pos_gpio = gpio_bank_index(gpio_pin, true);
int sum_gpio = gpio_bank_index(gpio_pin, false);
Genode::off_t offset = _irq_offset[pos_gpio];
int gpio = gpio_pin - sum_gpio;
Reg* reg = _gpio_reg(gpio_pin);
reg->set_enable_triggers(gpio, offset, FALLING);
}
void rising_detect(unsigned gpio_pin) override
{
int pos_gpio = gpio_bank_index(gpio_pin, true);
int sum_gpio = gpio_bank_index(gpio_pin, false);
Genode::off_t offset = _irq_offset[pos_gpio];
int gpio = gpio_pin - sum_gpio;
Reg* reg = _gpio_reg(gpio_pin);
reg->set_enable_triggers(gpio, offset, RISING);
}
void high_detect(unsigned gpio_pin) override
{
int pos_gpio = gpio_bank_index(gpio_pin, true);
int sum_gpio = gpio_bank_index(gpio_pin, false);
Genode::off_t offset = _irq_offset[pos_gpio];
int gpio = gpio_pin-sum_gpio;
Reg* reg = _gpio_reg(gpio_pin);
reg->set_enable_triggers(gpio, offset, HIGH);
}
void low_detect(unsigned gpio_pin) override
{
int pos_gpio = gpio_bank_index(gpio_pin, true);
int sum_gpio = gpio_bank_index(gpio_pin, false);
Genode::off_t offset = _irq_offset[pos_gpio];
int gpio = gpio_pin - sum_gpio;
Reg* reg = _gpio_reg(gpio_pin);
reg->set_enable_triggers(gpio, offset, LOW);
}
void irq_enable(unsigned gpio_pin, bool enable) override
{
_irq_enabled[gpio_pin] = enable;
}
void ack_irq(unsigned /* gpio_pin */) override
{
_irq.ack_irq();
}
void register_signal(unsigned gpio_pin,
Genode::Signal_context_capability cap) override
{
_sig_cap[gpio_pin] = cap;
}
void unregister_signal(unsigned gpio_pin) override
{
Genode::Signal_context_capability cap;
_sig_cap[gpio_pin] = cap;
}
int gpio_bank_index(int pin, bool pos)
{
int i = 0 ,sum = 0;
while (i<MAX_BANKS && ((sum + _bank_sizes[i]) <= pin)) {
sum += 1 + _bank_sizes[i++];
}
return pos ? i : sum;
}
bool gpio_valid(unsigned gpio) override { return gpio < (MAX_PINS); }
};
#endif /* _DRIVER_H_ */

View File

@ -1,185 +0,0 @@
/*
* \brief Odroid-x2 GPIO definitions
* \author Alexy Gallardo Segura <alexy@uclv.cu>
* \author Humberto Lopéz Leon <humberto@uclv.cu>
* \author Reinier Millo Sánchez <rmillo@uclv.cu>
* \date 2015-07-03
*/
/*
* Copyright (C) 2012 Ksys Labs LLC
* Copyright (C) 2012-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 _GPIO_H_
#define _GPIO_H_
/* Genode includes */
#include <base/attached_io_mem_dataspace.h>
#include <util/mmio.h>
namespace Gpio {
class Reg;
using namespace Genode;
}
struct Gpio::Reg : Attached_io_mem_dataspace, Mmio
{
struct Regs : Genode::Mmio
{
struct Con : Register<0x00, 32> {};
struct Dat : Register<0x04, 8> {};
Regs(Genode::addr_t base) : Genode::Mmio(base) {}
void set_con(unsigned int con) { write<Con>(con); }
void set_dat(unsigned int dat) { write<Dat>(dat); }
unsigned int get_con() { return read<Con>();}
unsigned int get_dat() { return read<Dat>();}
};
struct Irq_regs : Genode::Mmio
{
struct Int_con : Register <0x00,32>
{
struct Con0 : Bitfield<0, 3> {};
struct Con1 : Bitfield<4, 3> {};
struct Con2 : Bitfield<8, 3> {};
struct Con3 : Bitfield<12, 3> {};
struct Con4 : Bitfield<16, 3> {};
struct Con5 : Bitfield<20, 3> {};
struct Con6 : Bitfield<24, 3> {};
struct Con7 : Bitfield<28, 3> {};
};
Irq_regs(Genode::addr_t base) : Genode::Mmio(base) {}
void enable_triggers(unsigned gpio, unsigned value)
{
write<Int_con>(0);
switch(gpio) {
case 0: write<Int_con::Con0>(value); break;
case 1: write<Int_con::Con1>(value); break;
case 2: write<Int_con::Con2>(value); break;
case 3: write<Int_con::Con3>(value); break;
case 4: write<Int_con::Con4>(value); break;
case 5: write<Int_con::Con5>(value); break;
case 6: write<Int_con::Con6>(value); break;
case 7: write<Int_con::Con7>(value); break;
default: warning("Not is valid irq con!");
}
}
};
Reg(Genode::Env &env, addr_t base, size_t size)
: Attached_io_mem_dataspace(env, base, size),
Mmio((addr_t)local_addr<Reg>()) { }
void set_direction(int gpio, bool input, Genode::off_t offset)
{
Regs _reg((Genode::addr_t)local_addr<void>() + offset);
unsigned int value;
int id = (input ? 0 : 0x1);
value = _reg.get_con();
value &= ~(0xf << (gpio << 2));
value |= (id << (gpio << 2));
_reg.set_con(value);
}
void write_pin(unsigned gpio, bool level, Genode::off_t offset)
{
Regs _reg((Genode::addr_t)local_addr<void>() + offset);
unsigned int value;
value = _reg.get_dat();
value &= ~(0x1 << gpio);
if (level)
value |= 0x1 << gpio;
_reg.set_dat(value);
}
bool read_pin(unsigned gpio, Genode::off_t offset)
{
Regs _reg((Genode::addr_t)local_addr<void>() + offset);
return (_reg.get_dat() & (1 << gpio)) !=0;
}
void set_enable_triggers(unsigned gpio, Genode::off_t offset,unsigned value)
{
Irq_regs _irq_regs((Genode::addr_t)local_addr<void>() + offset);
_irq_regs.enable_triggers(gpio,value);
}
};
enum {
MAX_BANKS = 48,
MAX_PINS = 361
};
enum Irqs_triggers {
LOW = 0x0,
HIGH = 0x1,
FALLING = 0x2,
RISING = 0x3,
BOTH = 0x4
};
const int _bank_sizes[MAX_PINS] = {
/* TODO check value of registes type ETC. */
/* GPIO Part1 */
/* GPA0 GPA1 GPB GPC0 GPC1 GPD0 GPD1 GPF0 GPF1 GPF2 GPF3 ETC1 GPJ0 GPJ1 */
8, 6, 8, 5, 5, 4, 4, 8, 8, 8, 6, 6, 8, 5,
/* GPIO Part2 */ /* index 14 */
/* GPK0 GPK1 GPK2 GPK3 GPL0 GPL1 GPL2 GPY0 GPY1 GPY2 GPY3 GPY4 GPY5 GPY6 */
7, 7, 7, 7, 7, 2, 8, 6, 4, 6, 8, 8, 8, 8,
/* ETC0 ETC6 GPM0 GPM1 GPM2 GPM3 GPM4 GPX0 GPX1 GPX2 GPX3 */
6, 8, 8, 7, 5, 8, 8, 8, 8, 8, 8, /* index 35,36,37 */
/* GPIO Part3 */
/* GPZ */ /* index 39 */
7,
/* GPIO Part4 */ //index 40
/* GPV0 GPV1 ETC7 GPV2 GPV3 ETC8 GPV4 */
8, 8, 2, 8, 8, 2, 8
};
const Genode::off_t _bank_offset[MAX_BANKS]=
{
/* Part1 */
/* GPA0 GPA1 GPB GPC0 GPC1 GPD0 GPD1 GPF0 GPF1 GPF2 GPF3 ETC1 GPJ0 GPJ1 */
0x0000, 0x0020, 0x0040, 0x0060, 0x0080, 0x00A0, 0x00C0, 0x0180, 0x01A0, 0x01C0, 0x01E0, 0x0228, 0x0240, 0x0260,
/* Part2 */
/* GPK0 GPK1 GPK2 GPK3 GPL0 GPL1 GPL2 GPY0 GPY1 GPY2 GPY3 GPY4 GPY5 GPY6 */
0x0040, 0x0060, 0x0080, 0x00A0, 0x00C0, 0x00E0, 0x0100, 0x0120, 0x0140, 0x0160, 0x0180, 0x01A0, 0x01C0, 0x01E0,
/* ETC0 ETC6 GPM0 GPM1 GPM2 GPM3 GPM4 GPX0 GPX1 GPX2 GPX3 */
0x0208, 0x0228, 0x0260, 0x0280, 0x02A0, 0x02C0, 0x02E0, 0x0C00, 0x0C20, 0x0C40, 0x0C60,
/* Part3 */
0x0000, /*GPZ */
/* Part4 */
/* GPV0 GPV1 ETC7 GPV2 GPV3 ETC8 GPV4 */
0x0000, 0x0020, 0x0048, 0x0060, 0x0080, 0x00A8, 0x00C0,
};
const Genode::off_t _irq_offset[MAX_BANKS]=
{
/* Bank 1 irq */
/* con1 con2 con3 con4 con5 con6 con7 con13 con14 con15 con16 ETC con21 con22 */
0x0700, 0x0704, 0x0708, 0x070C, 0x0710, 0x0714, 0x0718, 0x0730, 0x0734, 0x0738, 0x073C, -1, 0x0740, 0x0744,
/* Bank 2 irq */
/* con23 con24 con25 con26 con27 con28 con29 */
0x0708, 0x070C, 0x0710, 0x0714, 0x0718, 0x071C, 0x0720, -1, -1, -1, -1, -1, -1, -1,
/* con8 con9 con10 con11 con12 x0 x1 x2 x3 */
-1, -1, 0x0724, 0x0728, 0x072C, 0x0730, 0x0734, 0x0E00, 0x0E04, 0x0E08, 0x0E0C, //TODO Check values de x0-x3.
/* Bank 3 irq */
/* con50 */
0x0700,
/* Bank 4 irq */
/* con30 con31 con32 con33 con34 */
0x0700, 0x0704, -1, 0x0708, 0x070C, -1, 0x0710,
};
#endif /* _GPIO_H_ */

View File

@ -1,64 +0,0 @@
/*
* \brief Gpio driver for the Odroid-x2
* \author Alexy Gallardo Segura <alexy@uclv.cu>
* \author Humberto Lopéz Leon <humberto@uclv.cu>
* \author Reinier Millo Sánchez <rmillo@uclv.cu>
* \date 2015-07-03
*/
/*
* 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.
*/
/* Genode includes */
#include <base/attached_rom_dataspace.h>
#include <base/component.h>
#include <base/heap.h>
#include <base/log.h>
#include <gpio/component.h>
#include <gpio/config.h>
/* local includes */
#include <driver.h>
Gpio::Odroid_x2_driver& Gpio::Odroid_x2_driver::factory(Genode::Env &env)
{
static Odroid_x2_driver driver(env);
return driver;
}
struct Main
{
Genode::Env &env;
Genode::Sliced_heap sliced_heap;
Gpio::Odroid_x2_driver &driver;
Gpio::Root root;
Genode::Attached_rom_dataspace config_rom { env, "config" };
Main(Genode::Env &env)
: env(env),
sliced_heap(env.ram(), env.rm()),
driver(Gpio::Odroid_x2_driver::factory(env)),
root(&env.ep().rpc_ep(), &sliced_heap, driver)
{
using namespace Genode;
log("--- Odroid_x2 gpio driver ---");
Gpio::process_config(config_rom.xml(), driver);
/*
* Announce service
*/
env.parent().announce(env.ep().manage(root));
}
};
void Component::construct(Genode::Env &env) { static Main main(env); }

View File

@ -1,7 +0,0 @@
TARGET = exynos4_gpio_drv
REQUIRES = arm_v7
SRC_CC = main.cc
LIBS = base
INC_DIR += $(PRG_DIR)
vpath main.cc $(PRG_DIR)

View File

@ -1,542 +0,0 @@
/*
* \brief Regulator driver for clock management unit of Exynos5250 SoC
* \author Stefan Kalkowski <stefan.kalkowski@genode-labs.com>
* \date 2013-06-13
*/
/*
* Copyright (C) 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 _DRIVERS__PLATFORM__SPEC__ARNDALE__CMU_H_
#define _DRIVERS__PLATFORM__SPEC__ARNDALE__CMU_H_
#include <base/log.h>
#include <regulator/consts.h>
#include <regulator/driver.h>
#include <drivers/defs/arndale.h>
#include <os/attached_mmio.h>
using namespace Regulator;
using Genode::warning;
class Cmu : public Regulator::Driver,
private Genode::Attached_mmio
{
private:
static const Genode::uint16_t m_values[]; /* M values for frequencies */
static const Genode::uint8_t p_values[]; /* P values for frequencies */
static const Genode::uint8_t s_values[]; /* S values for frequencies */
template <unsigned OFF>
struct Pll_lock : Register<OFF, 32>
{
struct Pll_locktime : Register<OFF, 32>::template Bitfield<0, 20> { };
static Genode::uint32_t max_lock_time(Genode::uint8_t pdiv) {
return pdiv * 250; };
};
template <unsigned OFF>
struct Pll_con0 : Register<OFF, 32>
{
struct S : Register<OFF, 32>::template Bitfield < 0, 3> { };
struct P : Register<OFF, 32>::template Bitfield < 8, 6> { };
struct M : Register<OFF, 32>::template Bitfield <16, 10> { };
struct Locked : Register<OFF, 32>::template Bitfield <29, 1> { };
struct Enable : Register<OFF, 32>::template Bitfield <31, 1> { };
};
/***********************
** CMU CPU registers **
***********************/
typedef Pll_lock<0> Apll_lock;
typedef Pll_con0<0x100> Apll_con0;
struct Clk_src_cpu : Register<0x200, 32>
{
struct Mux_cpu_sel : Bitfield<16, 1>
{
enum { MOUT_APLL, SCLK_MPLL};
};
};
struct Clk_mux_stat_cpu : Register<0x400, 32>
{
struct Cpu_sel : Bitfield<16, 3>
{
enum { MOUT_APLL = 0b1, SCLK_MPLL = 0b10 };
};
};
struct Clk_div_cpu0 : Register<0x500, 32>
{
/* Cpu0 divider values for frequencies 200 - 1700 */
static const Genode::uint32_t values[];
};
struct Clk_div_cpu1 : Register<0x504, 32>
{
/* Divider for cpu1 doesn't change */
enum { FIX_VALUE = 32 };
};
struct Clk_div_stat_cpu0 : Register<0x600, 32>
{
struct Div_arm : Bitfield< 0, 1> {};
struct Div_cpud : Bitfield< 4, 1> {};
struct Div_acp : Bitfield< 8, 1> {};
struct Div_pheriph : Bitfield<12, 1> {};
struct Div_atb : Bitfield<16, 1> {};
struct Div_pclk_dbg : Bitfield<20, 1> {};
struct Div_apll : Bitfield<24, 1> {};
struct Div_arm2 : Bitfield<28, 1> {};
static bool in_progress(access_t stat_word)
{
return stat_word & (Div_arm::bits(1) |
Div_cpud::bits(1) |
Div_acp::bits(1) |
Div_pheriph::bits(1) |
Div_atb::bits(1) |
Div_pclk_dbg::bits(1) |
Div_apll::bits(1) |
Div_arm2::bits(1));
}
};
struct Clk_div_stat_cpu1 : Register<0x604, 32>
{
struct Div_copy : Bitfield<0, 1> { };
struct Div_hpm : Bitfield<4, 1> { };
static bool in_progress(access_t stat_word)
{
return stat_word & (Div_copy::bits(1) |
Div_hpm::bits(1));
}
};
/************************
** CMU CORE registers **
************************/
typedef Pll_lock<0x4000> Mpll_lock;
typedef Pll_con0<0x4100> Mpll_con0;
struct Clk_src_core1 : Register<0x4204, 32>
{
struct Mux_mpll_sel : Bitfield<8, 1> { enum { XXTI, MPLL_FOUT_RGT }; };
};
struct Clk_gate_ip_acp : Register<0x8800, 32> { };
struct Clk_gate_ip_isp0 : Register<0xc800, 32> { };
struct Clk_gate_ip_isp1 : Register<0xc804, 32> { };
struct Clk_gate_sclk_isp : Register<0xc900, 32> { };
/***********************
** CMU TOP registers **
***********************/
typedef Pll_lock<0x10020> Cpll_lock;
typedef Pll_lock<0x10030> Epll_lock;
typedef Pll_lock<0x10040> Vpll_lock;
typedef Pll_lock<0x10050> Gpll_lock;
typedef Pll_con0<0x10120> Cpll_con0;
typedef Pll_con0<0x10130> Epll_con0;
typedef Pll_con0<0x10140> Vpll_con0;
typedef Pll_con0<0x10150> Gpll_con0;
struct Clk_src_top2 : Register<0x10218, 32>
{
struct Mux_mpll_user_sel : Bitfield<20, 1> { enum { XXTI, MOUT_MPLL}; };
};
struct Clk_src_fsys : Register<0x10244, 32>
{
struct Sata_sel : Bitfield<24, 1> {
enum { SCLK_MPLL_USER, SCLK_BPLL_USER }; };
struct Usbdrd30_sel : Bitfield<28, 1> {
enum { SCLK_MPLL_USER, SCLK_CPLL }; };
};
struct Clk_src_mask_fsys : Register<0x10340, 32>
{
struct Mmc0_mask : Bitfield<0, 1> { enum { MASK, UNMASK }; };
struct Sata_mask : Bitfield<24, 1> { enum { MASK, UNMASK }; };
struct Usbdrd30_mask : Bitfield<28, 1> { enum { MASK, UNMASK }; };
};
struct Clk_div_fsys0 : Register<0x10548, 32>
{
struct Sata_ratio : Bitfield<20, 4> { };
struct Usbdrd30_ratio : Bitfield<24, 4> { };
};
struct Clk_div_stat_fsys0 : Register<0x10648, 32>
{
struct Div_sata : Bitfield<20, 1> {};
struct Div_usbdrd30 : Bitfield<24, 1> {};
};
struct Clk_gate_ip_gscl : Register<0x10920, 32> { };
struct Clk_gate_ip_disp1 : Register<0x10928, 32>
{
struct Clk_mixer : Bitfield<5, 1> { };
struct Clk_hdmi : Bitfield<6, 1> { };
};
struct Clk_gate_ip_mfc : Register<0x1092c, 32> { };
struct Clk_gate_ip_g3d : Register<0x10930, 32> { };
struct Clk_gate_ip_gen : Register<0x10934, 32> { };
struct Clk_gate_ip_fsys : Register<0x10944, 32>
{
struct Pdma0 : Bitfield<1, 1> { };
struct Pdma1 : Bitfield<2, 1> { };
struct Sata : Bitfield<6, 1> { };
struct Sdmmc0 : Bitfield<12, 1> { };
struct Usbhost20 : Bitfield<18, 1> { };
struct Usbdrd30 : Bitfield<19, 1> { };
struct Sata_phy_ctrl : Bitfield<24, 1> { };
struct Sata_phy_i2c : Bitfield<25, 1> { };
};
struct Clk_src_disp1_0 : Register<0x1022c, 32>
{
struct Hdmi_sel : Bitfield<20, 1> { };
};
struct Clk_src_mask_disp1_0 : Register<0x1032c, 32>
{
struct Hdmi_mask : Bitfield<20, 1> { };
};
struct Clk_gate_ip_peric : Register<0x10950, 32>
{
struct Clk_uart2 : Bitfield<2, 1> { };
struct Clk_i2chdmi : Bitfield<14, 1> { };
struct Clk_pwm : Bitfield<24, 1> { };
};
struct Clk_gate_block : Register<0x10980, 32>
{
struct Clk_disp1 : Bitfield<5, 1> { };
struct Clk_gen : Bitfield<2, 1> { };
};
/*************************
** CMU CDREX registers **
*************************/
typedef Pll_lock<0x20010> Bpll_lock;
typedef Pll_con0<0x20110> Bpll_con0;
struct Pll_div2_sel : Register<0x20a24, 32>
{
struct Mpll_fout_sel : Bitfield<4, 1> {
enum { MPLL_FOUT_HALF, MPLL_FOUT }; };
};
/*******************
** CPU functions **
*******************/
Cpu_clock_freq _cpu_freq;
void _cpu_clk_freq(unsigned long level)
{
unsigned freq;
switch (level) {
case CPU_FREQ_200:
freq = 0;
break;
case CPU_FREQ_400:
freq = 1;
break;
case CPU_FREQ_600:
freq = 2;
break;
case CPU_FREQ_800:
freq = 3;
break;
case CPU_FREQ_1000:
freq = 4;
break;
case CPU_FREQ_1200:
freq = 5;
break;
case CPU_FREQ_1400:
freq = 6;
break;
case CPU_FREQ_1600:
freq = 7;
break;
case CPU_FREQ_1700:
freq = 8;
break;
default:
warning("Unsupported CPU frequency level ", level);
warning("Supported values are 200, 400, 600, 800 MHz");
warning("and 1, 1.2, 1.4, 1.6, 1.7 GHz");
return;
};
/**
* change clock divider values
*/
/* cpu0 divider */
write<Clk_div_cpu0>(Clk_div_cpu0::values[freq]);
while (Clk_div_stat_cpu0::in_progress(read<Clk_div_stat_cpu0>())) ;
/* cpu1 divider */
write<Clk_div_cpu1>(Clk_div_cpu1::FIX_VALUE);
while (Clk_div_stat_cpu1::in_progress(read<Clk_div_stat_cpu1>())) ;
/**
* change APLL frequency
*/
/* change reference clock to MPLL */
write<Clk_src_cpu::Mux_cpu_sel>(Clk_src_cpu::Mux_cpu_sel::SCLK_MPLL);
while (read<Clk_mux_stat_cpu::Cpu_sel>()
!= Clk_mux_stat_cpu::Cpu_sel::SCLK_MPLL) ;
/* set lock time */
unsigned pdiv = p_values[freq];
write<Apll_lock::Pll_locktime>(Apll_lock::max_lock_time(pdiv));
/* change P, M, S values of APLL */
write<Apll_con0::P>(p_values[freq]);
write<Apll_con0::M>(m_values[freq]);
write<Apll_con0::S>(s_values[freq]);
while (!read<Apll_con0::Locked>()) ;
/* change reference clock back to APLL */
write<Clk_src_cpu::Mux_cpu_sel>(Clk_src_cpu::Mux_cpu_sel::MOUT_APLL);
while (read<Clk_mux_stat_cpu::Cpu_sel>()
!= Clk_mux_stat_cpu::Cpu_sel::MOUT_APLL) ;
_cpu_freq = static_cast<Cpu_clock_freq>(level);
}
/**********************
** Device functions **
**********************/
void _hdmi_enable()
{
write<Clk_gate_ip_peric::Clk_i2chdmi>(1);
Clk_gate_ip_disp1::access_t gd1 = read<Clk_gate_ip_disp1>();
Clk_gate_ip_disp1::Clk_mixer::set(gd1, 1);
Clk_gate_ip_disp1::Clk_hdmi::set(gd1, 1);
write<Clk_gate_ip_disp1>(gd1);
write<Clk_gate_block::Clk_disp1>(1);
write<Clk_src_mask_disp1_0::Hdmi_mask>(1);
write<Clk_src_disp1_0::Hdmi_sel>(1);
}
void _sata_enable()
{
/* enable I2C for SATA */
write<Clk_gate_ip_fsys::Sata_phy_i2c>(1);
/**
* set SATA clock to 66 MHz (nothing else supported)
* assuming 800 MHz from sclk_mpll_user, formula: sclk / (divider + 1)
*/
write<Clk_div_fsys0::Sata_ratio>(11); /* */
while (read<Clk_div_stat_fsys0::Div_sata>()) ;
/* enable SATA and SATA Phy */
write<Clk_gate_ip_fsys::Sata>(1);
write<Clk_gate_ip_fsys::Sata_phy_ctrl>(1);
write<Clk_src_mask_fsys::Sata_mask>(1);
}
void _usb30_enable()
{
/**
* set USBDRD30 clock to 66 MHz
* assuming 800 MHz from sclk_mpll_user, formula: sclk / (divider + 1)
*/
write<Clk_div_fsys0::Usbdrd30_ratio>(11);
while (read<Clk_div_stat_fsys0::Div_usbdrd30>()) ;
/* enable USBDRD30 clock */
write<Clk_gate_ip_fsys::Usbdrd30>(1);
write<Clk_src_mask_fsys::Usbdrd30_mask>(1);
}
void _enable(Regulator_id id)
{
switch (id) {
case CLK_SATA:
_sata_enable();
break;
case CLK_HDMI:
_hdmi_enable();
break;
case CLK_USB30:
_usb30_enable();
break;
case CLK_USB20:
return write<Clk_gate_ip_fsys::Usbhost20>(1);
case CLK_MMC0:
write<Clk_gate_ip_fsys::Sdmmc0>(1);
write<Clk_src_mask_fsys::Mmc0_mask>(1);
break;
default:
warning("Unsupported for ", names[id].name);
}
}
void _disable(Regulator_id id)
{
switch (id) {
case CLK_SATA:
write<Clk_gate_ip_fsys::Sata_phy_i2c>(0);
write<Clk_gate_ip_fsys::Sata>(0);
write<Clk_gate_ip_fsys::Sata_phy_ctrl>(0);
write<Clk_src_mask_fsys::Sata_mask>(0);
break;
case CLK_USB30:
write<Clk_gate_ip_fsys::Usbdrd30>(0);
write<Clk_src_mask_fsys::Usbdrd30_mask>(0);
break;
case CLK_USB20:
return write<Clk_gate_ip_fsys::Usbhost20>(0);
case CLK_MMC0:
write<Clk_gate_ip_fsys::Sdmmc0>(0);
write<Clk_src_mask_fsys::Mmc0_mask>(0);
break;
default:
warning("Unsupported for ", names[id].name);
}
}
public:
/**
* Constructor
*/
Cmu(Genode::Env &env)
: Genode::Attached_mmio(env, Arndale::CMU_MMIO_BASE,
Arndale::CMU_MMIO_SIZE),
_cpu_freq(CPU_FREQ_1600)
{
/**
* Close certain clock gates by default (~ 0.7 Watt reduction)
*/
write<Clk_gate_ip_acp>(0);
write<Clk_gate_ip_isp0>(0);
write<Clk_gate_ip_isp1>(0);
write<Clk_gate_sclk_isp>(0);
write<Clk_gate_ip_gscl>(0);
write<Clk_gate_ip_disp1>(0);
write<Clk_gate_ip_mfc>(0);
write<Clk_gate_ip_g3d>(0);
write<Clk_gate_ip_gen>(0);
write<Clk_gate_ip_fsys>(0);
write<Clk_gate_ip_peric>(Clk_gate_ip_peric::Clk_uart2::bits(1) |
Clk_gate_ip_peric::Clk_pwm::bits(1));
write<Clk_gate_block>(Clk_gate_block::Clk_gen::bits(1));
/**
* Set default CPU frequency
*/
_cpu_clk_freq(_cpu_freq);
/**
* Hard wiring of certain reference clocks
*/
write<Pll_div2_sel::Mpll_fout_sel>(Pll_div2_sel::Mpll_fout_sel::MPLL_FOUT_HALF);
write<Clk_src_core1::Mux_mpll_sel>(Clk_src_core1::Mux_mpll_sel::MPLL_FOUT_RGT);
write<Clk_src_top2::Mux_mpll_user_sel>(Clk_src_top2::Mux_mpll_user_sel::MOUT_MPLL);
write<Clk_src_fsys::Sata_sel>(Clk_src_fsys::Sata_sel::SCLK_MPLL_USER);
write<Clk_src_fsys::Usbdrd30_sel>(Clk_src_fsys::Usbdrd30_sel::SCLK_MPLL_USER);
}
/********************************
** Regulator driver interface **
********************************/
void level(Regulator_id id, unsigned long level) override
{
switch (id) {
case CLK_CPU:
_cpu_clk_freq(level);
break;
default:
warning("Unsupported for ", names[id].name);
}
}
unsigned long level(Regulator_id id) override
{
switch (id) {
case CLK_CPU:
return _cpu_freq;
case CLK_USB30:
case CLK_SATA:
return 66666666; /* 66 MHz */
default:
warning("Unsupported for ", names[id].name);
}
return 0;
}
void state(Regulator_id id, bool enable) override
{
if (enable)
_enable(id);
else
_disable(id);
}
bool state(Regulator_id id) override
{
switch (id) {
case CLK_SATA:
return read<Clk_gate_ip_fsys::Sata>() &&
read<Clk_gate_ip_fsys::Sata_phy_ctrl>() &&
read<Clk_src_mask_fsys::Sata_mask>();
case CLK_USB30:
return read<Clk_gate_ip_fsys::Usbdrd30>() &&
read<Clk_src_mask_fsys::Usbdrd30_mask>();
case CLK_USB20:
return read<Clk_gate_ip_fsys::Usbhost20>();
case CLK_MMC0:
return read<Clk_gate_ip_fsys::Sdmmc0>() &&
read<Clk_src_mask_fsys::Mmc0_mask>();
default:
warning("Unsupported for ", names[id].name);
}
return true;
}
};
const Genode::uint8_t Cmu::s_values[] = { 2, 1, 1, 0, 0, 0, 0, 0, 0 };
const Genode::uint16_t Cmu::m_values[] = { 100, 100, 200, 100, 125,
150, 175, 200, 425 };
const Genode::uint8_t Cmu::p_values[] = { 3, 3, 4, 3, 3, 3, 3, 3, 6 };
const Genode::uint32_t Cmu::Clk_div_cpu0::values[] = { 0x1117710, 0x1127710, 0x1137710,
0x2147710, 0x2147710, 0x3157720,
0x4167720, 0x4177730, 0x5377730 };
#endif /* _DRIVERS__PLATFORM__SPEC__ARNDALE__CMU_H_ */

View File

@ -1,72 +0,0 @@
/*
* \brief Driver for Arndale specific platform devices (clocks, power, etc.)
* \author Stefan Kalkowski <stefan.kalkowski@genode-labs.com>
* \date 2013-06-13
*/
/*
* Copyright (C) 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.
*/
#include <base/log.h>
#include <base/heap.h>
#include <base/component.h>
#include <regulator/component.h>
#include <regulator/consts.h>
#include <cmu.h>
#include <pmu.h>
struct Driver_factory : Regulator::Driver_factory
{
Cmu _cmu;
Pmu _pmu;
Driver_factory(Genode::Env &env) : _cmu(env), _pmu(env) { }
Regulator::Driver &create(Regulator::Regulator_id id) override
{
switch (id) {
case Regulator::CLK_CPU:
case Regulator::CLK_SATA:
case Regulator::CLK_USB30:
case Regulator::CLK_USB20:
case Regulator::CLK_MMC0:
case Regulator::CLK_HDMI:
return _cmu;
case Regulator::PWR_SATA:
case Regulator::PWR_USB30:
case Regulator::PWR_USB20:
case Regulator::PWR_HDMI:
return _pmu;
default:
throw Genode::Service_denied(); /* invalid regulator */
};
}
void destroy(Regulator::Driver &) override { }
};
struct Main
{
Genode::Env & env;
Genode::Heap heap { env.ram(), env.rm() };
::Driver_factory factory { env };
Regulator::Root root { env, heap, factory };
Main(Genode::Env & env) : env(env) {
env.parent().announce(env.ep().manage(root)); }
};
void Component::construct(Genode::Env &env)
{
Genode::log("--- Arndale platform driver ---");
static Main main(env);
}

View File

@ -1,234 +0,0 @@
/*
* \brief Regulator driver for power management unit of Exynos5250 SoC
* \author Stefan Kalkowski <stefan.kalkowski@genode-labs.com>
* \date 2013-06-18
*/
/*
* Copyright (C) 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 _DRIVERS__PLATFORM__SPEC__ARNDALE__PMU_H_
#define _DRIVERS__PLATFORM__SPEC__ARNDALE__PMU_H_
#include <base/log.h>
#include <regulator/consts.h>
#include <regulator/driver.h>
#include <drivers/defs/arndale.h>
#include <os/attached_mmio.h>
using namespace Regulator;
using Genode::warning;
class Pmu : public Regulator::Driver,
private Genode::Attached_mmio
{
private:
template <unsigned OFFSET>
struct Control : Register <OFFSET, 32>
{
struct Enable : Register<OFFSET, 32>::template Bitfield<0, 1> { };
};
template <unsigned OFFSET>
struct Configuration : Register <OFFSET, 32>
{
struct Local_pwr_cfg : Register<OFFSET, 32>::template Bitfield<0, 3> { };
};
template <unsigned OFFSET>
struct Status : Register <OFFSET, 32>
{
struct Stat : Register<OFFSET, 32>::template Bitfield<0, 3> { };
};
template <unsigned OFFSET>
struct Sysclk_configuration : Register <OFFSET, 32>
{
struct Local_pwr_cfg : Register<OFFSET, 32>::template Bitfield<0, 1> { };
};
template <unsigned OFFSET>
struct Sysclk_status : Register <OFFSET, 32>
{
struct Stat : Register<OFFSET, 32>::template Bitfield<0, 1> { };
};
struct Hdmi_phy_control : Register<0x700, 32>
{
struct Enable : Bitfield<0, 1> { };
struct Div_ratio : Bitfield<16, 10> { };
};
typedef Control<0x704> Usbdrd_phy_control;
typedef Control<0x708> Usbhost_phy_control;
typedef Control<0x70c> Efnand_phy_control;
typedef Control<0x718> Adc_phy_control;
typedef Control<0x71c> Mtcadc_phy_control;
typedef Control<0x720> Dptx_phy_control;
typedef Control<0x724> Sata_phy_control;
typedef Sysclk_configuration<0x2a40> Vpll_sysclk_configuration;
typedef Sysclk_status<0x2a44> Vpll_sysclk_status;
typedef Sysclk_configuration<0x2a60> Epll_sysclk_configuration;
typedef Sysclk_status<0x2a64> Epll_sysclk_status;
typedef Sysclk_configuration<0x2aa0> Cpll_sysclk_configuration;
typedef Sysclk_status<0x2aa4> Cpll_sysclk_status;
typedef Sysclk_configuration<0x2ac0> Gpll_sysclk_configuration;
typedef Sysclk_status<0x2ac4> Gpll_sysclk_status;
typedef Configuration<0x4000> Gscl_configuration;
typedef Status<0x4004> Gscl_status;
typedef Configuration<0x4020> Isp_configuration;
typedef Status<0x4024> Isp_status;
typedef Configuration<0x4040> Mfc_configuration;
typedef Status<0x4044> Mfc_status;
typedef Configuration<0x4060> G3d_configuration;
typedef Status<0x4064> G3d_status;
typedef Configuration<0x40A0> Disp1_configuration;
typedef Status<0x40A4> Disp1_status;
typedef Configuration<0x40C0> Mau_configuration;
typedef Status<0x40C4> Mau_status;
template <typename C, typename S>
void _disable_domain()
{
if (read<typename S::Stat>() == 0)
return;
write<typename C::Local_pwr_cfg>(0);
while (read<typename S::Stat>() != 0) ;
}
template <typename C, typename S>
void _enable_domain()
{
if (read<typename S::Stat>() == 7)
return;
write<typename C::Local_pwr_cfg>(7);
while (read<typename S::Stat>() != 7) ;
}
void _enable(unsigned long id)
{
switch (id) {
case PWR_USB30:
write<Usbdrd_phy_control::Enable>(1);
break;
case PWR_USB20:
write<Usbhost_phy_control::Enable>(1);
break;
case PWR_SATA :
write<Sata_phy_control::Enable>(1);
break;
case PWR_HDMI: {
_enable_domain<Disp1_configuration, Disp1_status>();
Hdmi_phy_control::access_t hpc = read<Hdmi_phy_control>();
Hdmi_phy_control::Div_ratio::set(hpc, 150);
Hdmi_phy_control::Enable::set(hpc, 1);
write<Hdmi_phy_control>(hpc);
break; }
default:
warning("Unsupported for ", names[id].name);
}
}
void _disable(unsigned long id)
{
switch (id) {
case PWR_USB30:
write<Usbdrd_phy_control::Enable>(0);
break;
case PWR_USB20:
write<Usbhost_phy_control::Enable>(0);
break;
case PWR_SATA :
write<Sata_phy_control::Enable>(0);
break;
default:
warning("Unsupported for ", names[id].name);
}
}
public:
/**
* Constructor
*/
Pmu(Genode::Env &env)
: Genode::Attached_mmio(env, Arndale::PMU_MMIO_BASE,
Arndale::PMU_MMIO_SIZE)
{
write<Hdmi_phy_control ::Enable>(0);
write<Usbdrd_phy_control ::Enable>(0);
write<Usbhost_phy_control::Enable>(0);
write<Efnand_phy_control ::Enable>(0);
write<Adc_phy_control ::Enable>(0);
write<Mtcadc_phy_control ::Enable>(0);
write<Dptx_phy_control ::Enable>(0);
write<Sata_phy_control ::Enable>(0);
_disable_domain<Gscl_configuration, Gscl_status>();
_disable_domain<Isp_configuration, Isp_status>();
_disable_domain<Mfc_configuration, Mfc_status>();
_disable_domain<G3d_configuration, G3d_status>();
_disable_domain<Disp1_configuration, Disp1_status>();
_disable_domain<Mau_configuration, Mau_status>();
_disable_domain<Vpll_sysclk_configuration, Vpll_sysclk_status>();
_disable_domain<Epll_sysclk_configuration, Epll_sysclk_status>();
_disable_domain<Cpll_sysclk_configuration, Cpll_sysclk_status>();
_disable_domain<Gpll_sysclk_configuration, Gpll_sysclk_status>();
}
/********************************
** Regulator driver interface **
********************************/
void level(Regulator_id id, unsigned long /* level */) override
{
switch (id) {
default:
warning("Unsupported for ", names[id].name);
}
}
unsigned long level(Regulator_id id) override
{
switch (id) {
default:
warning("Unsupported for ", names[id].name);
}
return 0;
}
void state(Regulator_id id, bool enable) override
{
if (enable)
_enable(id);
else
_disable(id);
}
bool state(Regulator_id id) override
{
switch (id) {
case PWR_USB30:
return read<Usbdrd_phy_control::Enable>();
case PWR_USB20:
return read<Usbhost_phy_control::Enable>();
case PWR_SATA:
return read<Sata_phy_control::Enable>();
default:
warning("Unsupported for ", names[id].name);
}
return true;
}
};
#endif /* _DRIVERS__PLATFORM__SPEC__ARNDALE__PMU_H_ */

View File

@ -1,5 +0,0 @@
TARGET = arndale_platform_drv
REQUIRES = arm_v7
SRC_CC = main.cc
INC_DIR += ${PRG_DIR} $(call select_from_repositories,include/spec/exynos5)
LIBS = base

View File

@ -1,389 +0,0 @@
/*
* \brief Regulator driver for clock management unit of Exynos4412 SoC
* \author Alexy Gallardo Segura <alexy@uclv.cu>
* \author Humberto Lopez Leon <humberto@uclv.cu>
* \author Reinier Millo Sanchez <rmillo@uclv.cu>
* \date 2015-07-08
*/
/*
* 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 _DRIVERS__PLATFORM__SPEC__ODROID_X2__CMU_H_
#define _DRIVERS__PLATFORM__SPEC__ODROID_X2__CMU_H_
#include <regulator/consts.h>
#include <regulator/driver.h>
#include <drivers/defs/odroid_x2.h>
#include <os/attached_mmio.h>
#include <base/log.h>
using namespace Regulator;
class Cmu : public Regulator::Driver,
private Genode::Attached_mmio
{
private:
static const Genode::uint16_t m_values[]; /* M values for frequencies */
static const Genode::uint8_t p_values[]; /* P values for frequencies */
static const Genode::uint8_t s_values[]; /* S values for frequencies */
template <unsigned OFF>
struct Pll_lock : Register<OFF, 32>
{
struct Pll_locktime : Register<OFF, 32>::template Bitfield<0, 20> { };
static Genode::uint32_t max_lock_time(Genode::uint8_t pdiv) {
return pdiv * 250; };
};
template <unsigned OFF>
struct Pll_con0 : Register<OFF, 32>
{
struct S : Register<OFF, 32>::template Bitfield < 0, 3> { };
struct P : Register<OFF, 32>::template Bitfield < 8, 6> { };
struct M : Register<OFF, 32>::template Bitfield <16, 10> { };
struct Locked : Register<OFF, 32>::template Bitfield <29, 1> { };
struct Enable : Register<OFF, 32>::template Bitfield <31, 1> { };
};
/***********************
** CMU CPU registers **
***********************/
typedef Pll_lock<4000> Apll_lock;
typedef Pll_con0<0x14100> Apll_con0;
struct Clk_src_cpu : Register<0x14200, 32>
{
struct Mux_core_sel : Bitfield<16, 1>
{
enum { MOUT_APLL, SCLK_MPLL};
};
};
struct Clk_mux_stat_cpu : Register<0x14400, 32>
{
struct Core_sel : Bitfield<16, 3>
{
enum { MOUT_APLL = 0b1, SCLK_MPLL = 0b10 };
};
};
struct Clk_div_cpu0 : Register<0x14500, 32>
{
/* Cpu0 divider values for frequencies 200 - 1400 */
static const Genode::uint32_t values[];
};
struct Clk_div_cpu1 : Register<0x14504, 32>
{
/* Divider for cpu1 doesn't change */
enum { FIX_VALUE = 32 };
};
struct Clk_div_stat_cpu0 : Register<0x14600, 32>
{
struct Div_core : Bitfield< 0, 1> {};
struct Div_corem0 : Bitfield< 4, 1> {};
struct Div_corem1 : Bitfield< 8, 1> {};
struct Div_pheriph : Bitfield<12, 1> {};
struct Div_atb : Bitfield<16, 1> {};
struct Div_pclk_dbg : Bitfield<20, 1> {};
struct Div_apll : Bitfield<24, 1> {};
struct Div_core2 : Bitfield<28, 1> {};
static bool in_progress(access_t stat_word)
{
return stat_word & (Div_core::bits(1) |
Div_corem0::bits(1) |
Div_corem1::bits(1) |
Div_pheriph::bits(1) |
Div_atb::bits(1) |
Div_pclk_dbg::bits(1) |
Div_apll::bits(1) |
Div_core2::bits(1));
}
};
struct Clk_div_stat_cpu1 : Register<0x14604, 32>
{
struct Div_copy : Bitfield<0, 1> { };
struct Div_hpm : Bitfield<4, 1> { };
static bool in_progress(access_t stat_word)
{
return stat_word & (Div_copy::bits(1) |
Div_hpm::bits(1));
}
};
/************************
** CMU CORE registers **
************************/
typedef Pll_lock<0x0008> Mpll_lock;
typedef Pll_con0<0x0108> Mpll_con0;
/***********************
** CMU TOP registers **
***********************/
struct Clk_gate_ip_tv : Register<0x10928, 32>
{
struct Clk_mixer : Bitfield<1, 1> { };
struct Clk_hdmi : Bitfield<3, 1> { };
};
struct Clk_gate_ip_fsys : Register<0xC940, 32>
{
struct Usbhost20 : Bitfield<12, 1> { };
struct Usbdevice : Bitfield<13, 1> { };
};
struct Clk_src_tv : Register<0xC224, 32> /* old name Clk_src_disp1_0 */
{
struct Hdmi_sel : Bitfield<0, 1> { };
};
struct Clk_src_mask_tv : Register<0xC324, 32>
{
struct Hdmi_mask : Bitfield<0, 1> { };
};
struct Clk_gate_ip_peric : Register<0xC950, 32>
{
struct Clk_uart2 : Bitfield<2, 1> { };
struct Clk_i2chdmi : Bitfield<14, 1> { };
struct Clk_pwm : Bitfield<24, 1> { };
};
struct Clk_gate_block : Register<0xC970, 32>
{
struct Clk_tv : Bitfield<1, 1> { };
};
/*******************
** CPU functions **
*******************/
Cpu_clock_freq _cpu_freq;
void _cpu_clk_freq(unsigned long level)
{
using namespace Genode;
log("Changing CPU frequency to ",level);
unsigned freq;
switch (level) {
case CPU_FREQ_200:
freq = 0;
break;
case CPU_FREQ_400:
freq = 1;
break;
case CPU_FREQ_600:
freq = 2;
break;
case CPU_FREQ_800:
freq = 3;
break;
case CPU_FREQ_1000:
freq = 4;
break;
case CPU_FREQ_1200:
freq = 5;
break;
case CPU_FREQ_1400:
freq = 6;
break;
default:
warning("Unsupported CPU frequency level ", level);
warning("Supported values are 200, 400, 600, 800, 1000, 1200, 14000 MHz");
warning("and 1, 1.2, 1.4, 1.6, 1.7 GHz");
return;
};
/**
* change clock divider values
*/
/* cpu0 divider */
write<Clk_div_cpu0>(Clk_div_cpu0::values[freq]);
while (Clk_div_stat_cpu0::in_progress(read<Clk_div_stat_cpu0>())) ;
/* cpu1 divider */
write<Clk_div_cpu1>(Clk_div_cpu1::FIX_VALUE);
while (Clk_div_stat_cpu1::in_progress(read<Clk_div_stat_cpu1>())) ;
/**
* change APLL frequency
*/
/* change reference clock to MPLL */
write<Clk_src_cpu::Mux_core_sel>(Clk_src_cpu::Mux_core_sel::SCLK_MPLL);
while (read<Clk_mux_stat_cpu::Core_sel>()
!= Clk_mux_stat_cpu::Core_sel::SCLK_MPLL) ;
/* set lock time */
unsigned pdiv = p_values[freq];
write<Apll_lock::Pll_locktime>(Apll_lock::max_lock_time(pdiv));
/* change P, M, S values of APLL */
write<Apll_con0::P>(p_values[freq]);
write<Apll_con0::M>(m_values[freq]);
write<Apll_con0::S>(s_values[freq]);
while (!read<Apll_con0::Locked>()) ;
/* change reference clock back to APLL */
write<Clk_src_cpu::Mux_core_sel>(Clk_src_cpu::Mux_core_sel::MOUT_APLL);
while (read<Clk_mux_stat_cpu::Core_sel>()
!= Clk_mux_stat_cpu::Core_sel::MOUT_APLL) ;
_cpu_freq = static_cast<Cpu_clock_freq>(level);
Genode::log("changed CPU frequency to ",level);
}
/**********************
** Device functions **
**********************/
void _hdmi_enable()
{
write<Clk_gate_ip_peric::Clk_i2chdmi>(1);
Clk_gate_ip_tv::access_t gd1 = read<Clk_gate_ip_tv>();
Clk_gate_ip_tv::Clk_mixer::set(gd1, 1);
Clk_gate_ip_tv::Clk_hdmi::set(gd1, 1);
write<Clk_gate_ip_tv>(gd1);
write<Clk_gate_block::Clk_tv>(1);
write<Clk_src_mask_tv::Hdmi_mask>(1);
write<Clk_src_tv::Hdmi_sel>(1);
}
void _enable(Regulator_id id)
{
switch (id) {
case CLK_USB20:
{
write<Clk_gate_ip_fsys::Usbdevice>(1);
return write<Clk_gate_ip_fsys::Usbhost20>(1);
}
case CLK_HDMI:
_hdmi_enable();
break;
default:
Genode::warning("enabling regulator unsupported for ", names[id].name);
}
}
void _disable(Regulator_id id)
{
switch (id) {
case CLK_USB20:
{
write<Clk_gate_ip_fsys::Usbdevice>(0);
return write<Clk_gate_ip_fsys::Usbhost20>(0);
}
default:
Genode::warning("disabling regulator unsupported for ", names[id].name);
}
}
public:
/**
* Constructor
*/
Cmu(Genode::Env &env)
: Genode::Attached_mmio(env, Odroid_x2::CMU_MMIO_BASE,
Odroid_x2::CMU_MMIO_SIZE),
_cpu_freq(CPU_FREQ_1400)
{
/**
* Close certain clock gates by default (~ 0.7 Watt reduction)
*/
write<Clk_gate_ip_fsys>(0);
write<Clk_gate_ip_peric::Clk_uart2>(1);
write<Clk_gate_ip_peric::Clk_pwm>(1);
/**
* Set default CPU frequency
*/
_cpu_clk_freq(_cpu_freq);
}
virtual ~Cmu() { }
/********************************
** Regulator driver interface **
********************************/
void level(Regulator_id id, unsigned long level) override
{
switch (id) {
case CLK_CPU:
_cpu_clk_freq(level);
break;
default:
Genode::warning("level setting unsupported for ", names[id].name);
}
}
unsigned long level(Regulator_id id) override
{
switch (id) {
case CLK_CPU:
return _cpu_freq;
default:
Genode::warning("level requesting unsupported for ", names[id].name);
}
return 0;
}
void state(Regulator_id id, bool enable) override
{
if (enable)
_enable(id);
else
_disable(id);
}
bool state(Regulator_id id) override
{
switch (id) {
case CLK_USB20:
return read<Clk_gate_ip_fsys::Usbhost20>();
default:
Genode::warning("state request unsupported for ", names[id].name);
}
return true;
}
};
const Genode::uint8_t Cmu::s_values[] = { 2, 1, 1, 0, 0, 0, 0, 0, 0 };
const Genode::uint16_t Cmu::m_values[] = { 100, 100, 200, 100, 125,
150, 175, 200, 425 };
const Genode::uint8_t Cmu::p_values[] = { 3, 3, 4, 3, 3, 3, 3, 3, 6 };
const Genode::uint32_t Cmu::Clk_div_cpu0::values[] = { 0x1117710, 0x1127710, 0x1137710,
0x2147710, 0x2147710, 0x3157720,
0x4167720};
#endif /* _DRIVERS__PLATFORM__SPEC__ODROID_X2__CMU_H_ */

View File

@ -1,71 +0,0 @@
/*
* \brief Driver for Odroid-x2 specific platform devices (clocks, power, etc.)
* \author Alexy Gallardo Segura <alexy@uclv.cu>
* \author Humberto Lopez Leon <humberto@uclv.cu>
* \author Reinier Millo Sanchez <rmillo@uclv.cu>
* \date 2015-07-08
*/
/*
* 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.
*/
#include <base/log.h>
#include <base/heap.h>
#include <base/component.h>
#include <regulator/component.h>
#include <regulator/consts.h>
#include <cmu.h>
#include <pmu.h>
struct Driver_factory : Regulator::Driver_factory
{
Cmu _cmu;
Pmu _pmu;
Driver_factory(Genode::Env &env) : _cmu(env), _pmu(env) { }
Regulator::Driver &create(Regulator::Regulator_id id) override
{
switch (id) {
case Regulator::CLK_CPU:
case Regulator::CLK_USB20:
case Regulator::CLK_HDMI:
return _cmu;
case Regulator::PWR_USB20:
case Regulator::PWR_HDMI:
return _pmu;
default:
throw Genode::Service_denied(); /* invalid regulator */
}
}
void destroy(Regulator::Driver &) override { }
};
struct Main
{
Genode::Env & env;
Genode::Heap heap { env.ram(), env.rm() };
::Driver_factory factory { env };
Regulator::Root root { env, heap, factory };
Main(Genode::Env & env) : env(env) {
env.parent().announce(env.ep().manage(root)); }
};
void Component::construct(Genode::Env &env)
{
Genode::log("--- Odroid X2 platform driver ---");
static Main main(env);
}

View File

@ -1,167 +0,0 @@
/*
* \brief Regulator driver for power management unit of Exynos4412 SoC
* \author Alexy Gallardo Segura <alexy@uclv.cu>
* \author Humberto Lopez Leon <humberto@uclv.cu>
* \author Reinier Millo Sanchez <rmillo@uclv.cu>
* \date 2015-07-08
*/
/*
* 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 _DRIVERS__PLATFORM__SPEC__ODROID_X2__PMU_H_
#define _DRIVERS__PLATFORM__SPEC__ODROID_X2__PMU_H_
#include <base/log.h>
#include <regulator/consts.h>
#include <regulator/driver.h>
#include <drivers/defs/odroid_x2.h>
#include <os/attached_mmio.h>
using Genode::warning;
using namespace Regulator;
class Pmu : public Regulator::Driver,
private Genode::Attached_mmio
{
private:
template <unsigned OFFSET>
struct Control : Register <OFFSET, 32>
{
struct Enable : Register<OFFSET, 32>::template Bitfield<0, 1> { };
};
template <unsigned OFFSET>
struct Configuration : Register <OFFSET, 32>
{
struct Local_pwr_cfg : Register<OFFSET, 32>::template Bitfield<0, 3> { };
};
template <unsigned OFFSET>
struct Status : Register <OFFSET, 32>
{
struct Stat : Register<OFFSET, 32>::template Bitfield<0, 3> { };
};
template <unsigned OFFSET>
struct Sysclk_configuration : Register <OFFSET, 32>
{
struct Local_pwr_cfg : Register<OFFSET, 32>::template Bitfield<0, 1> { };
};
template <unsigned OFFSET>
struct Sysclk_status : Register <OFFSET, 32>
{
struct Stat : Register<OFFSET, 32>::template Bitfield<0, 1> { };
};
struct Hdmi_phy_control : Register<0x700, 32>
{
struct Enable : Bitfield<0, 1> { };
struct Div_ratio : Bitfield<16, 10> { };
};
typedef Control<0x0704> Usbdrd_phy_control;
typedef Control<0x0708> Usbhost_phy1_control;
typedef Control<0x70c> Usbhost_phy2_control;
void _enable(unsigned long id)
{
switch (id) {
case PWR_USB20:
write<Usbdrd_phy_control::Enable>(1);
write<Usbhost_phy1_control::Enable>(1);
write<Usbhost_phy2_control::Enable>(1);
break;
case PWR_HDMI: {
Hdmi_phy_control::access_t hpc = read<Hdmi_phy_control>();
Hdmi_phy_control::Div_ratio::set(hpc, 150);
Hdmi_phy_control::Enable::set(hpc, 1);
write<Hdmi_phy_control>(hpc);
break; }
default:
warning("Unsupported for ", names[id].name);
}
}
void _disable(unsigned long id)
{
switch (id) {
case PWR_USB20:
write<Usbdrd_phy_control::Enable>(0);
write<Usbhost_phy1_control::Enable>(0);
write<Usbhost_phy2_control::Enable>(0);
break;
case PWR_HDMI:
write<Hdmi_phy_control::Enable>(0);
break;
default:
warning("Unsupported for ", names[id].name);
}
}
public:
/**
* Constructor
*/
Pmu(Genode::Env &env)
: Genode::Attached_mmio(env, Odroid_x2::PMU_MMIO_BASE,
Odroid_x2::PMU_MMIO_SIZE)
{
write<Usbdrd_phy_control::Enable>(0);
write<Usbhost_phy1_control::Enable>(0);
write<Usbhost_phy2_control::Enable>(0);
write<Hdmi_phy_control::Enable>(0);
}
/********************************
** Regulator driver interface **
********************************/
void level(Regulator_id id, unsigned long /* level */) override
{
switch (id) {
default:
warning("Unsupported for ", names[id].name);
}
}
unsigned long level(Regulator_id id) override
{
switch (id) {
default:
warning("Unsupported for ", names[id].name);
}
return 0;
}
void state(Regulator_id id, bool enable) override
{
if (enable)
_enable(id);
else
_disable(id);
}
bool state(Regulator_id id) override
{
switch (id) {
case PWR_USB20:
return read<Usbdrd_phy_control::Enable>();
default:
warning("Unsupported for ", names[id].name);
}
return true;
}
};
#endif /* _DRIVERS__PLATFORM__SPEC__ODROID_X2__PMU_H_ */

View File

@ -1,5 +0,0 @@
TARGET = odroid_x2_platform_drv
REQUIRES = arm_v7
SRC_CC = main.cc
INC_DIR += ${PRG_DIR} $(call select_from_repositories,include/spec/exynos4)
LIBS = base

View File

@ -1,443 +0,0 @@
/*
* \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.
*/
/* local includes */
#include <driver.h>
using namespace Genode;
using namespace Sd_card;
Driver::Driver(Env &env)
:
Driver_base(env.ram()),
Attached_mmio(env, MSH_BASE, MSH_SIZE), _env(env)
{
_irq.sigh(_irq_handler);
_irq.ack_irq();
log("SD/MMC card detected");
log("capacity: ", _card_info.capacity_mb(), " MiB");
}
void Driver::read_dma(Block::sector_t block_number,
size_t block_count,
addr_t buf_phys,
Block::Packet_descriptor &pkt)
{
if (_block_transfer.pending) {
throw Request_congestion(); }
if (!_setup_idmac_descriptor_table(block_count, buf_phys))
throw Io_error();
_block_transfer.packet = pkt;
_block_transfer.pending = true;
if (!_issue_command(Read_multiple_block(block_number))) {
error("Read_multiple_block failed");
throw Io_error();
}
}
void Driver::write_dma(Block::sector_t block_number,
size_t block_count,
addr_t buf_phys,
Block::Packet_descriptor &pkt)
{
if (_block_transfer.pending) {
throw Request_congestion(); }
if (!_setup_idmac_descriptor_table(block_count, buf_phys))
throw Io_error();
_block_transfer.packet = pkt;
_block_transfer.pending = true;
if (!_issue_command(Write_multiple_block(block_number))) {
error("Read_multiple_block failed");
throw Io_error();
}
}
bool Driver::_reset()
{
Mmio::write<Ctrl::Reset>(0x7);
try { wait_for(Attempts(100), Microseconds(1000), _delayer,
Ctrl::Reset::Equal(0)); }
catch (Polling_timeout) {
error("Could not reset host contoller");
return false;
}
return true;
}
void Driver::_reset_fifo()
{
Mmio::write<Ctrl::Reset>(0x2);
try { wait_for(Attempts(100), Microseconds(1000), _delayer,
Ctrl::Reset::Equal(0)); }
catch (Polling_timeout) {
error("Could not reset fifo"); }
}
void Driver::_disable_irq()
{
Mmio::write<Rintsts>(~0U);
Mmio::write<Intmask>(0);
}
bool Driver::_update_clock_registers()
{
Cmd::access_t cmd = 0;
Cmd::Wait_prvdata_complete::set(cmd, 1);
Cmd::Update_clock_registers_only::set(cmd, 1);
Cmd::Start_cmd::set(cmd, 1);
Mmio::write<Cmd>(cmd);
try { wait_for(_delayer, Cmd::Start_cmd::Equal(0)); }
catch (Polling_timeout) {
error("Update clock registers failed");
return false;
}
return true;
}
bool Driver::_setup_bus(unsigned clock_div)
{
/* set host clock divider */
Mmio::write<Clkdiv>(clock_div);
if (!_update_clock_registers())
return false;
/* enable clock for card 1 */
Mmio::write<Clkena>(0x1);
if (!_update_clock_registers())
return false;
_delayer.usleep(10 * 1000);
return true;
}
Card_info Driver::_init()
{
Mmio::write<Pwren>(1);
if (!_reset())
throw Detection_failed();
Mmio::write<Emmc_ddr_req>(0x1);
_disable_irq();
Mmio::write<Tmout>(~0U);
Mmio::write<Idinten>(0);
Mmio::write<Bmod>(1);
Mmio::write<Bytcnt>(0);
Mmio::write<Fifoth>(0x203f0040);
/* set to one bit transfer Bit */
if (!_setup_bus(CLK_DIV_400Khz))
throw Detection_failed();
Mmio::write<Ctype>(BUS_WIDTH_1);
if (!issue_command(Go_idle_state())) {
warning("Go_idle_state command failed");
throw Detection_failed();
}
_delayer.usleep(2000);
if (!issue_command(Send_if_cond())) {
warning("Send_if_cond command failed");
throw Detection_failed();
}
/* if this succeeds it is an SD card */
if ((Mmio::read<Rsp0>() & 0xff) == 0xaa)
log("Found SD card");
/*
* We need to issue the same Mmc_send_op_cond command multiple
* times. The first time, we receive the status information. On
* subsequent attempts, the response tells us that the card is
* busy. Usually, the command is issued twice. We give up if the
* card is not reaching busy state after one second.
*/
unsigned i = 1000;
unsigned voltages = 0x300080;
unsigned arg = 0;
for (; i > 0; --i) {
if (!issue_command(Mmc_send_op_cond(arg, true))) {
warning("Sd_send_op_cond command failed");
throw Detection_failed();
}
arg = Mmio::read<Rsp0>();
arg = (voltages & (arg & 0x007FFF80)) | (arg & 0x60000000);
_delayer.usleep(1000);
if (Ocr::Busy::get(Mmio::read<Rsp0>()))
break;
}
if (i == 0) {
error("Send_op_cond timed out, could no power-on SD/MMC card");
throw Detection_failed();
}
Card_info card_info = _detect_mmc();
/* switch frequency to high speed */
enum { EXT_CSD_HS_TIMING = 185 };
if (!issue_command(Mmc_switch(EXT_CSD_HS_TIMING, 1))) {
error("Error setting high speed frequency");
throw Detection_failed();
}
enum { EXT_CSD_BUS_WIDTH = 183 };
/* set card to 8 bit */
if (!issue_command(Mmc_switch(EXT_CSD_BUS_WIDTH, 2))) {
error("Error setting card bus width");
throw Detection_failed();
}
Mmio::write<Ctype>(BUS_WIDTH_8);
/* set to eight bit transfer Bit */
if (!_setup_bus(CLK_DIV_52Mhz)) {
error("Error setting bus to high speed");
throw Detection_failed();
}
/* Enable IRQs data read timeout, data transfer done, resp error */
Mmio::write<Intmask>(0x28a);
Mmio::write<Ctrl::Global_interrupt>(1);
return card_info;
}
bool Driver::_setup_idmac_descriptor_table(size_t block_count,
addr_t phys_addr)
{
size_t const max_idmac_block_count = IDMAC_DESC_MAX_ENTRIES * 8;
if (block_count > max_idmac_block_count) {
error("Block request too large");
return false;
}
_reset_fifo();
Idmac_desc::Flags flags = Idmac_desc::FS;
size_t b = block_count;
int index = 0;
for (index = 0; b; index++, phys_addr += 0x1000, flags = Idmac_desc::NONE) {
b = _idmac_desc[index].set(b, _block_size(), phys_addr, flags);
_idmac_desc[index].next =
_idmac_desc_phys + ((index + 1) * sizeof(Idmac_desc));
}
_idmac_desc[index].next = (unsigned)_idmac_desc;
_idmac_desc[index].flags |= Idmac_desc::ER;
Mmio::write<Dbaddr>(_idmac_desc_phys);
Mmio::write<Ctrl::Dma_enable>(1);
Mmio::write<Ctrl::Use_internal_dmac>(1);
Mmio::write<Bmod::Fixed_burst>(1);
Mmio::write<Bmod::Idmac_enable>(1);
Mmio::write<Blksize>(_block_size());
Mmio::write<Bytcnt>(_block_size() * block_count);
Mmio::write<Pldmnd>(1);
return true;
}
void Driver::_handle_irq()
{
_irq.ack_irq();
if (!_block_transfer.pending) {
return; }
bool success = false;
if (Mmio::read<Rintsts::Response_error>()) {
error("Response error");
}
if (Mmio::read<Rintsts::Data_read_timeout>()) {
error("Data read timeout");
}
if (Mmio::read<Rintsts::Data_crc_error>()) {
error("CRC error");
}
if (Mmio::read<Rintsts::Data_transfer_over>()) {
Mmio::write<Rintsts>(~0U);
if (!_issue_command(Stop_transmission())) {
error("unable to stop transmission");
} else {
success = true;
}
}
_block_transfer.pending = false;
ack_packet(_block_transfer.packet, success);
}
bool Driver::_issue_command(Command_base const &command)
{
try { wait_for(Attempts(10000), Microseconds(100), _delayer,
Status::Data_busy::Equal(0)); }
catch (Polling_timeout) {
error("wait for State::Data_busy timed out ",
Hex(Mmio::read<Status>()));
return false;
}
Mmio::write<Rintsts>(~0UL);
/* write command argument */
Mmio::write<Cmdarg>(command.arg);
Cmd::access_t cmd = 0;
Cmd::Index::set(cmd, command.index);
if (command.transfer != TRANSFER_NONE) {
/* set data-direction bit depending on the command */
bool const write = command.transfer == TRANSFER_WRITE;
Cmd::Data_expected::set(cmd, 1);
Cmd::Write::set(cmd, write ? 1 : 0);
}
Cmd::access_t rsp_type = 0;
switch (command.rsp_type) {
case RESPONSE_NONE: rsp_type = Cmd::Rsp_type::RESPONSE_NONE; break;
case RESPONSE_136_BIT: rsp_type = Cmd::Rsp_type::RESPONSE_136_BIT; break;
case RESPONSE_48_BIT: rsp_type = Cmd::Rsp_type::RESPONSE_48_BIT; break;
case RESPONSE_48_BIT_WITH_BUSY: rsp_type = Cmd::Rsp_type::RESPONSE_48_BIT_WITH_BUSY; break;
}
Cmd::Rsp_type::set(cmd, rsp_type);
Cmd::Start_cmd::set(cmd, 1);
Cmd::Use_hold_reg::set(cmd ,1);
Cmd::Wait_prvdata_complete::set(cmd, 1);
if (command.index == 0)
Cmd::Init_sequence::set(cmd, 1);
/* issue command */
Mmio::write<Cmd>(cmd);
try { wait_for(Attempts(10000), Microseconds(100), _delayer,
Rintsts::Command_done::Equal(1)); }
catch (Polling_timeout) {
error("command failed "
"Rintst: ", Mmio::read<Rintsts>(), " "
"Mintst: ", Mmio::read<Mintsts>(), " "
"Status: ", Mmio::read<Status>());
if (Mmio::read<Rintsts::Response_timeout>())
warning("timeout");
if (Mmio::read<Rintsts::Response_error>())
warning("repsonse error");
return false;
}
/* acknowledge interrupt */
Mmio::write<Rintsts::Command_done>(1);
_delayer.usleep(100);
return true;
}
Cid Driver::_read_cid()
{
Cid cid;
cid.raw_0 = Mmio::read<Rsp0>();
cid.raw_1 = Mmio::read<Rsp1>();
cid.raw_2 = Mmio::read<Rsp2>();
cid.raw_3 = Mmio::read<Rsp3>();
return cid;
}
Csd Driver::_read_csd()
{
Csd csd;
csd.csd0 = Mmio::read<Rsp0>();
csd.csd1 = Mmio::read<Rsp1>();
csd.csd2 = Mmio::read<Rsp2>();
csd.csd3 = Mmio::read<Rsp3>();
return csd;
}
size_t Driver::_read_ext_csd()
{
Attached_ram_dataspace ds(_env.ram(), _env.rm(), 0x1000, UNCACHED);
addr_t phys = Dataspace_client(ds.cap()).phys_addr();
_setup_idmac_descriptor_table(1, phys);
if (!issue_command(Mmc_send_ext_csd()))
throw Detection_failed();
try { wait_for(_delayer, Rintsts::Data_transfer_over::Equal(1)); }
catch (Polling_timeout) {
error("cannot retrieve extented CSD");
throw Detection_failed();
}
/* clear IRQ */
Mmio::write<Rintsts::Data_transfer_over>(1);
/* contruct extented CSD */
Ext_csd csd((addr_t)ds.local_addr<addr_t>());
/* read revision */
if (csd.Mmio::read<Ext_csd::Revision>() < 2) {
error("extented CSD revision is < 2");
throw Detection_failed();
}
/* return sector count */
uint64_t capacity = csd.Mmio::read<Ext_csd::Sector_count>() * _block_size();
/* to MB */
return capacity / (1024 * 1024);
}
size_t Driver::Idmac_desc::set(size_t block_count,
size_t block_size,
addr_t phys_addr,
Flags flag)
{
constexpr size_t MAX_BLOCKS = 8;
flags = OWN | flag |
(block_count <= MAX_BLOCKS ? LD : (CH | DIC));
bytes = ((block_count < MAX_BLOCKS) ? block_count : MAX_BLOCKS) *
block_size;
addr = phys_addr;
return block_count < MAX_BLOCKS ?
0 : block_count - MAX_BLOCKS;
}

View File

@ -1,246 +0,0 @@
/*
* \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_ */

View File

@ -1,5 +0,0 @@
TARGET = exynos5_sd_card_drv
REQUIRES = arm_v7
INC_DIR = $(call select_from_repositories,include/spec/exynos5)
include $(REP_DIR)/src/drivers/sd_card/target.inc

View File

@ -1,4 +0,0 @@
TARGET = arndale_uart_drv
REQUIRES = arm_v7
include $(REP_DIR)/src/drivers/uart/target.inc

View File

@ -1,88 +0,0 @@
/*
* \brief Driver for EXYNOS5 UARTs
* \author Stefan Kalkowski <stefan.kalkowski@genode-labs.com>
* \author Ivan Loskutov <ivan.loskutov@ksyslabs.org>
* \date 2013-06-05
*/
/*
* Copyright (C) 2013-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 _UART_DRIVER_H_
#define _UART_DRIVER_H_
/* Genode includes */
#include <base/attached_io_mem_dataspace.h>
#include <base/env.h>
#include <drivers/uart/exynos.h>
#include <drivers/defs/arndale.h>
enum { UARTS_NUM = 2 }; /* needed by base class definitions */
/* local includes */
#include <uart_driver_base.h>
class Uart::Driver : private Genode::Attached_io_mem_dataspace,
private Genode::Exynos_uart,
public Uart::Driver_base
{
private:
enum { BAUD_115200 = 115200 };
struct Uart {
Genode::addr_t mmio_base;
Genode::size_t mmio_size;
int irq_number;
};
Uart & _config(unsigned index)
{
using namespace Genode;
static Uart cfg[UARTS_NUM] = {
/*
* temporary workaround having first UART twice
* (most run-scripts have first UART reserved for the kernel)
*/
{ Exynos5::UART_2_MMIO_BASE, 4096, Exynos5::UART_2_IRQ },
{ Exynos5::UART_2_MMIO_BASE, 4096, Exynos5::UART_2_IRQ },
};
return cfg[index];
}
unsigned _baud_rate(unsigned baud_rate)
{
if (baud_rate != BAUD_115200)
Genode::warning("baud_rate ", baud_rate,
" not supported, set to default");
return BAUD_115200;
}
public:
Driver(Genode::Env &env, unsigned index,
unsigned baud_rate, Char_avail_functor &func)
: Genode::Attached_io_mem_dataspace(env, _config(index).mmio_base,
_config(index).mmio_size),
Exynos_uart((Genode::addr_t)local_addr<void>(),
Arndale::UART_2_CLOCK, _baud_rate(baud_rate)),
Driver_base(env, _config(index).irq_number, func) {
_rx_enable(); }
/***************************
** UART driver interface **
***************************/
void put_char(char c) override { Exynos_uart::put_char(c); }
bool char_avail() override { return _rx_avail(); }
char get_char() override { return _rx_char(); }
};
#endif /* _UART_DRIVER_H_ */