os: add platform driver for i.MX 8M Quad SoC

The new platform driver supports clock and power-domain settings per device.
IOMUX constroller settings are not part of the driver yet.

Fix #3863
This commit is contained in:
Stefan Kalkowski 2020-07-17 18:28:06 +02:00 committed by Norman Feske
parent 70f98fcc44
commit 224f5907b2
30 changed files with 1790 additions and 314 deletions

View File

@ -50,6 +50,14 @@ class Platform::Connection : public Genode::Connection<Session>,
Client(cap()),
_rm(env.rm()) { _try_attach(); }
void update()
{
if (_ds.constructed() && _rom.update() == true) { return; }
_try_attach();
}
void sigh(Signal_context_capability sigh) { _rom.sigh(sigh); }
Device_capability acquire_device(String const &device) override
{
return retry_with_upgrade(Ram_quota{6*1024}, Cap_quota{6}, [&] () {

View File

@ -42,7 +42,7 @@ struct Platform::Session : Genode::Session
*/
static const char *service_name() { return "Platform"; }
enum { RAM_QUOTA = 16 * 1024, CAP_QUOTA = 6 };
enum { RAM_QUOTA = 32 * 1024, CAP_QUOTA = 6 };
virtual ~Session() { }

View File

@ -0,0 +1 @@
#include <spec/arm/platform_device/client.h>

View File

@ -0,0 +1 @@
#include <spec/arm/platform_device/platform_device.h>

View File

@ -0,0 +1 @@
#include <spec/arm/platform_session/client.h>

View File

@ -0,0 +1 @@
#include <spec/arm/platform_session/connection.h>

View File

@ -0,0 +1 @@
#include <spec/arm/platform_session/platform_session.h>

View File

@ -1,5 +1,7 @@
INCLUDE_SUB_DIRS := platform_session \
platform_device \
spec/arm_64/platform_session \
spec/arm_64/platform_device \
spec/arm/platform_session \
spec/arm/platform_device \
spec/imx53/platform_session \

View File

@ -22,24 +22,24 @@
<!-- device resource declarations -->
<device name="clcd">
<resource name="IO_MEM" address="0x10020000" size="0x1000"/>
<io_mem address="0x10020000" size="0x1000"/>
<property name="compatible" value="arm,pl111"/>
</device>
<device name="sp810_syscon0">
<resource name="IO_MEM" address="0x10001000" size="0x1000"/>
<io_mem address="0x10001000" size="0x1000"/>
<property name="compatible" value="arm,sp810"/>
</device>
<device name="kmi0">
<resource name="IO_MEM" address="0x10006000" size="0x1000"/>
<resource name="IRQ" number="52"/>
<io_mem address="0x10006000" size="0x1000"/>
<irq number="52"/>
<property name="compatible" value="arm,pl050"/>
</device>
<device name="kmi1">
<resource name="IO_MEM" address="0x10007000" size="0x1000"/>
<resource name="IRQ" number="53"/>
<io_mem address="0x10007000" size="0x1000"/>
<irq number="53"/>
<property name="compatible" value="arm,pl050"/>
</device>

View File

@ -24,8 +24,8 @@
<!-- device resource declarations -->
<device name="ethernet">
<resource name="IO_MEM" address="0x4e000000" size="0x1000"/>
<resource name="IRQ" number="60"/>
<io_mem address="0x4e000000" size="0x1000"/>
<irq number="60"/>
<property name="compatible" value="smsc,lan9118"/>
</device>

View File

@ -0,0 +1,420 @@
/*
* \brief Central clock module for i.MX8MQ
* \author Stefan Kalkowski
* \date 2020-06-12
*/
/*
* Copyright (C) 2020 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 <ccm.h>
/******************************
** Frac_pll immplementation **
******************************/
void Driver::Ccm::Frac_pll::disable()
{
write<Config_reg_0::Power_down>(1);
}
void Driver::Ccm::Frac_pll::enable()
{
if (!read<Config_reg_0::Power_down>()) return;
write<Config_reg_0::Power_down>(0);
for (unsigned i = 0; i < 0xfffff; i++) {
if (read<Config_reg_0::Lock_status>()) { break; }
}
}
Driver::Clock & Driver::Ccm::Frac_pll::_parent() const
{
Name pname;
switch (read<Config_reg_0::Ref_sel>()) {
case Config_reg_0::Ref_sel::REF_CLK_25M: pname = "25m_ref_clk"; break;
case Config_reg_0::Ref_sel::REF_CLK_27M: pname = "27m_ref_clk"; break;
case Config_reg_0::Ref_sel::HDMI_PHY_27M: pname = "hdmi_phy_27m_clk"; break;
case Config_reg_0::Ref_sel::CLK_P_N: pname = "no_clk"; break;
};
return static_cast<Clock_tree_element*>(_tree.first()->find_by_name(pname.string()))->object();
};
void Driver::Ccm::Frac_pll::set_parent(Name parent)
{
if (parent == "25m_ref_clk") {
write<Config_reg_0::Ref_sel>(Config_reg_0::Ref_sel::REF_CLK_25M);
return;
}
if (parent == "27m_ref_clk") {
write<Config_reg_0::Ref_sel>(Config_reg_0::Ref_sel::REF_CLK_27M);
return;
}
if (parent == "hdmi_phy_27m_clk") {
write<Config_reg_0::Ref_sel>(Config_reg_0::Ref_sel::HDMI_PHY_27M);
return;
}
write<Config_reg_0::Ref_sel>(Config_reg_0::Ref_sel::CLK_P_N);
}
void Driver::Ccm::Frac_pll::set_rate(unsigned long rate)
{
static constexpr uint32_t fixed_frac = 1 << 24;
uint64_t r = rate * 2;
uint64_t pr = _parent().get_rate() * 8;
uint32_t div_int = (uint32_t)((r / pr) & 0b1111111);
uint32_t div_frac = (uint32_t)((r - div_int * pr) * fixed_frac) / pr;
Config_reg_1::access_t v = 0;
Config_reg_1::Int_div_ctl::set(v, div_int);
Config_reg_1::Frac_div_ctl::set(v, div_frac);
write<Config_reg_1>(v);
write<Config_reg_0::Refclk_div_value>(0);
write<Config_reg_0::Output_div_value>(0);
write<Config_reg_0::Newdiv_val>(1);
/* wait for ack, if powered and not bypassed */
if (!(read<Config_reg_0::Bypass>() ||
read<Config_reg_0::Power_down>())) {
for (unsigned i = 0; i < 0xfffff; i++) {
if (read<Config_reg_0::Newdiv_ack>()) { break; }
}
}
write<Config_reg_0::Newdiv_val>(0);
}
unsigned long Driver::Ccm::Frac_pll::get_rate() const
{
static constexpr uint32_t fixed_frac = 1 << 24;
uint32_t divq = (read<Config_reg_0::Output_div_value>() + 1) * 2;
uint32_t divr = read<Config_reg_0::Refclk_div_value>();
uint32_t divff = read<Config_reg_1::Frac_div_ctl>();
uint32_t divfi = read<Config_reg_1::Int_div_ctl>();
uint64_t ref = _parent().get_rate() * 8 / divr;
Genode::log("Frac_pll clock ", name(), " parent-rate ", _parent().get_rate());
return (ref * (divfi + 1) / divq) +
(ref * divff / fixed_frac / divq);
}
Driver::Ccm::Frac_pll::Frac_pll(Name name, addr_t const base, Clock_tree & tree)
: Clock(name, tree), Mmio(base), _tree(tree)
{
write<Config_reg_0::Bypass>(0);
write<Config_reg_0::Out_enable>(1);
}
/******************************
** Sccg_pll immplementation **
******************************/
Driver::Clock & Driver::Ccm::Sccg_pll::_parent() const
{
Name pname;
switch (read<Config_reg_0::Ref_sel>()) {
case Config_reg_0::Ref_sel::REF_CLK_25M: pname = "25m_ref_clk"; break;
case Config_reg_0::Ref_sel::REF_CLK_27M: pname = "27m_ref_clk"; break;
case Config_reg_0::Ref_sel::HDMI_PHY_27M: pname = "hdmi_phy_27m_clk"; break;
case Config_reg_0::Ref_sel::CLK_P_N: pname = "no_clk"; break;
};
return static_cast<Clock_tree_element*>(_tree.first()->find_by_name(pname.string()))->object();
};
void Driver::Ccm::Sccg_pll::set_parent(Name parent)
{
if (parent == "25m_ref_clk") {
write<Config_reg_0::Ref_sel>(Config_reg_0::Ref_sel::REF_CLK_25M);
return;
}
if (parent == "27m_ref_clk") {
write<Config_reg_0::Ref_sel>(Config_reg_0::Ref_sel::REF_CLK_27M);
return;
}
if (parent == "hdmi_phy_27m_clk") {
write<Config_reg_0::Ref_sel>(Config_reg_0::Ref_sel::HDMI_PHY_27M);
return;
}
write<Config_reg_0::Ref_sel>(Config_reg_0::Ref_sel::CLK_P_N);
}
void Driver::Ccm::Sccg_pll::set_rate(unsigned long)
{
Genode::error(__func__," not implemented yet!");
}
unsigned long Driver::Ccm::Sccg_pll::get_rate() const
{
unsigned factor = read<Config_reg_1::Sse>() ? 8 : 2;
unsigned divf1 = read<Config_reg_2::Feedback_divf1>() + 1;
unsigned divf2 = read<Config_reg_2::Feedback_divf2>() + 1;
unsigned divr1 = read<Config_reg_2::Ref_divr1>() + 1;
unsigned divr2 = read<Config_reg_2::Ref_divr2>() + 1;
unsigned divq = read<Config_reg_2::Output_div_val>() + 1;
unsigned long parent_rate = _parent().get_rate();
if (read<Config_reg_0::Bypass2>()) {
return parent_rate;
}
if (read<Config_reg_0::Bypass1>()) {
return (parent_rate * divf2) / (divr2 * divq);
}
return parent_rate * factor * divf1 * divf2 / (divr1*divr2*divq);
}
void Driver::Ccm::Sccg_pll::enable()
{
if (!read<Config_reg_0::Power_down>()) return;
write<Config_reg_0::Power_down>(0);
for (unsigned i = 0; i < 0xfffff; i++) {
if (read<Config_reg_0::Lock_status>()) { break; }
}
}
void Driver::Ccm::Sccg_pll::disable()
{
write<Config_reg_0::Power_down>(1);
}
/********************************
** Root_clock immplementation **
********************************/
void Driver::Ccm::Root_clock::set_rate(unsigned long rate)
{
uint32_t pre_div = 0;
uint32_t post_div = 0;
int deviation = (int)(~0U >> 1);
unsigned long parent_rate =
_ref_clks[read<Target_reg::Ref_sel>()].ref.get_rate();
for (unsigned pre = 0; pre < (1<<3); pre++) {
for (unsigned post = 0; post < (1<<6); post++) {
int diff = (parent_rate / (pre+1)) / (post+1) - rate;
if (abs(diff) < abs(deviation)) {
pre_div = pre;
post_div = post;
deviation = diff;
}
}
}
write<Target_reg::Pre_div>(pre_div);
write<Target_reg::Post_div>(post_div);
};
void Driver::Ccm::Root_clock::set_parent(Name name)
{
for (unsigned i = 0; i < REF_CLK_MAX; i++) {
if (_ref_clks[i].ref.name() == name) {
write<Target_reg::Ref_sel>(i);
return;
}
}
warning("Reference clock ", name, " cannot be set");
}
unsigned long Driver::Ccm::Root_clock::get_rate() const
{
unsigned long parent_rate =
_ref_clks[read<Target_reg::Ref_sel>()].ref.get_rate();
unsigned pre = read<Target_reg::Pre_div>()+1;
unsigned post = read<Target_reg::Post_div>()+1;
return parent_rate / pre / post;
}
void Driver::Ccm::Root_clock::enable() { write<Target_reg::Enable>(1); }
void Driver::Ccm::Root_clock::disable() { write<Target_reg::Enable>(0); }
/**************************
** Gate immplementation **
**************************/
void Driver::Ccm::Root_clock_divider::set_rate(unsigned long)
{
warning(__func__, " not implemented yet!");
}
unsigned long Driver::Ccm::Root_clock_divider::get_rate() const
{
return _parent.get_rate() / read<Target_reg::Post_div>();
};
/**************************
** Gate immplementation **
**************************/
void Driver::Ccm::Gate::enable() { write<Ccgr>(0x3); }
void Driver::Ccm::Gate::disable() { write<Ccgr>(0x0); }
/*******************
** CCM interface **
*******************/
Driver::Ccm::Ccm(Genode::Env & env) : env(env)
{
video_pll1_clk.enable();
/* set VIDEO PLL */
video_pll1_clk.set_parent(m27_ref_clk.name());
video_pll1_clk.set_rate(593999999);
audio_pll1_clk.disable();
audio_pll2_clk.disable();
video_pll1_clk.disable();
gpu_pll_clk.disable();
vpu_pll_clk.disable();
system_pll3_clk.disable();
video_pll2_clk.disable();
usb_ctrl1_gate.disable();
usb_ctrl2_gate.disable();
usb_phy1_gate.disable();
usb_phy2_gate.disable();
/* turn off all unnecessary root clocks */
arm_m4_clk_root.disable();
vpu_a53_clk_root.disable();
gpu_core_clk_root.disable();
gpu_shader_clk_root.disable();
enet_axi_clk_root.disable();
nand_usdhc_bus_clk_root.disable();
vpu_bus_clk_root.disable();
display_axi_clk_root.disable();
display_apb_clk_root.disable();
display_rtrm_clk_root.disable();
usb_bus_clk_root.disable();
gpu_axi_clk_root.disable();
gpu_ahb_clk_root.disable();
audio_ahb_clk_root.disable();
mipi_dsi_esc_rx_clk_root.disable();
vpu_g1_clk_root.disable();
vpu_g2_clk_root.disable();
display_dtrc_clk_root.disable();
display_dc8000_clk_root.disable();
pcie1_ctrl_clk_root.disable();
pcie1_phy_clk_root.disable();
pcie1_aux_clk_root.disable();
dc_pixel_clk_root.disable();
lcdif_pixel_clk_root.disable();
sai1_clk_root.disable();
sai2_clk_root.disable();
sai3_clk_root.disable();
sai4_clk_root.disable();
sai5_clk_root.disable();
sai6_clk_root.disable();
spdif1_clk_root.disable();
spdif2_clk_root.disable();
enet_ref_clk_root.disable();
enet_timer_clk_root.disable();
enet_phy_ref_clk_root.disable();
nand_clk_root.disable();
qspi_clk_root.disable();
usdhc1_clk_root.disable();
usdhc2_clk_root.disable();
i2c1_clk_root.disable();
i2c2_clk_root.disable();
i2c3_clk_root.disable();
i2c4_clk_root.disable();
uart2_clk_root.disable();
uart3_clk_root.disable();
uart4_clk_root.disable();
usb_core_ref_clk_root.disable();
usb_phy_ref_clk_root.disable();
ecspi1_clk_root.disable();
ecspi2_clk_root.disable();
pwm1_clk_root.disable();
pwm2_clk_root.disable();
pwm3_clk_root.disable();
pwm4_clk_root.disable();
gpt1_clk_root.disable();
gpt2_clk_root.disable();
gpt3_clk_root.disable();
gpt4_clk_root.disable();
gpt5_clk_root.disable();
gpt6_clk_root.disable();
trace_clk_root.disable();
wdog_clk_root.disable();
wrclk_clk_root.disable();
ipp_do_clko1clk_root.disable();
ipp_do_clko2_clk_root.disable();
mipi_dsi_core_clk_root.disable();
mipi_dsi_phy_ref_clk_root.disable();
mipi_dsi_dbi_clk_root.disable();
old_mipi_dsi_esc_clk_root.disable();
mipi_csi1_core_clk_root.disable();
mipi_csi1_phy_ref_clk_root.disable();
mipi_csi1_esc_clk_root.disable();
mipi_csi2_core_clk_root.disable();
mipi_csi2_phy_ref_clk_root.disable();
mipi_csi2_esc_clk_root.disable();
pcie2_ctrl_clk_root.disable();
pcie2_phy_clk_root.disable();
pcie2_aux_clk_root.disable();
ecspi3_clk_root.disable();
old_mipi_dsi_esc_rx_clk_root.disable();
display_hdmi_clk_root.disable();
/* set certain reference clocks */
ahb_clk_root.set_parent("system_pll1_div6");
nand_usdhc_bus_clk_root.set_parent("system_pll1_div3");
audio_ahb_clk_root.set_parent("system_pll2_div2");
pcie1_ctrl_clk_root.set_parent("system_pll2_div5");
pcie1_phy_clk_root.set_parent("system_pll2_div10");
pcie2_ctrl_clk_root.set_parent("system_pll2_div5");
pcie2_phy_clk_root.set_parent("system_pll2_div10");
mipi_csi1_core_clk_root.set_parent("system_pll1_div3");
mipi_csi1_phy_ref_clk_root.set_parent("system_pll2_clk");
mipi_csi1_esc_clk_root.set_parent("system_pll1_clk");
mipi_csi2_core_clk_root.set_parent("system_pll1_div3");
mipi_csi2_phy_ref_clk_root.set_parent("system_pll2_clk");
mipi_csi2_esc_clk_root.set_parent("system_pll1_clk");
/* increase NOC clock for better DDR performance */
noc_clk_root.set_parent("system_pll1_clk");
noc_clk_root.set_rate(800000000);
}

View File

@ -0,0 +1,424 @@
/*
* \brief Central clock module for i.MX8MQ
* \author Stefan Kalkowski
* \date 2020-06-12
*/
/*
* Copyright (C) 2020 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.
*/
#pragma once
#include <os/attached_mmio.h>
#include <clock.h>
namespace Driver {
using namespace Genode;
struct Ccm;
};
struct Driver::Ccm
{
class Frac_pll : public Driver::Clock, Mmio
{
struct Config_reg_0 : Register<0x0, 32>
{
struct Output_div_value : Bitfield<0, 5> {};
struct Refclk_div_value : Bitfield<5, 6> {};
struct Newdiv_ack : Bitfield<11,1> {};
struct Newdiv_val : Bitfield<12,1> {};
struct Bypass : Bitfield<14,1> {};
struct Ref_sel : Bitfield<16,2>
{
enum Ref_clk {
REF_CLK_25M, REF_CLK_27M, HDMI_PHY_27M, CLK_P_N };
};
struct Power_down : Bitfield<19,1> {};
struct Out_enable : Bitfield<21,1> {};
struct Lock_status : Bitfield<31,1> {};
};
struct Config_reg_1 : Register<0x4, 32>
{
struct Int_div_ctl : Bitfield<0, 7> {};
struct Frac_div_ctl : Bitfield<7, 24> {};
};
Clock_tree & _tree;
Clock & _parent() const;
public:
Frac_pll(Name name,
addr_t const base,
Clock_tree & tree);
void set_parent(Name name) override;
void set_rate(unsigned long) override;
unsigned long get_rate() const override;
void enable() override;
void disable() override;
};
class Sccg_pll : public Driver::Clock, Mmio
{
struct Config_reg_0 : Register<0x0, 32>
{
struct Ref_sel : Bitfield<0,2> {
enum Ref_clk {
REF_CLK_25M, REF_CLK_27M, HDMI_PHY_27M, CLK_P_N };
};
struct Bypass2 : Bitfield<4, 1> {};
struct Bypass1 : Bitfield<5, 1> {};
struct Power_down : Bitfield<7, 1> {};
struct Out_enable : Bitfield<25,1> {};
struct Lock_status : Bitfield<31,1> {};
};
struct Config_reg_1 : Register<0x4, 32>
{
struct Sse : Bitfield<0,1> {};
};
struct Config_reg_2 : Register<0x8, 32>
{
struct Output_div_val : Bitfield<1, 6> {};
struct Feedback_divf2 : Bitfield<7, 6> {};
struct Feedback_divf1 : Bitfield<13,6> {};
struct Ref_divr2 : Bitfield<19,6> {};
struct Ref_divr1 : Bitfield<25,3> {};
};
Clock_tree & _tree;
Clock & _parent() const;
public:
Sccg_pll(Name name,
addr_t const base,
Clock_tree & tree)
: Clock(name, tree), Mmio(base), _tree(tree) {}
void set_parent(Name name) override;
void set_rate(unsigned long) override;
unsigned long get_rate() const override;
void enable() override;
void disable() override;
};
class Root_clock : public Clock, Mmio
{
struct Target_reg : Register<0x0, 32>
{
struct Post_div : Bitfield<0,6> {};
struct Pre_div : Bitfield<16,3> {};
struct Ref_sel : Bitfield<24,3> {};
struct Enable : Bitfield<28,1> {};
};
struct Clock_ref {
Clock & ref;
Clock_ref(Clock & c) : ref(c) {}
};
enum { REF_CLK_MAX = 8 };
Clock_tree & _tree;
Clock_ref _ref_clks[REF_CLK_MAX];
Clock & _parent() const;
public:
Root_clock(Name name,
addr_t const base,
Clock & ref_clk0,
Clock & ref_clk1,
Clock & ref_clk2,
Clock & ref_clk3,
Clock & ref_clk4,
Clock & ref_clk5,
Clock & ref_clk6,
Clock & ref_clk7,
Clock_tree & tree)
: Clock(name, tree), Mmio(base), _tree(tree),
_ref_clks { ref_clk0, ref_clk1, ref_clk2, ref_clk3,
ref_clk4, ref_clk5, ref_clk6, ref_clk7 }{}
void set_parent(Name name) override;
void set_rate(unsigned long) override;
unsigned long get_rate() const override;
void enable() override;
void disable() override;
};
class Root_clock_divider : public Clock, Mmio
{
struct Target_reg : Register<0x0, 32>
{
struct Post_div : Bitfield<0,6> {};
};
Clock & _parent;
Clock_tree & _tree;
public:
Root_clock_divider(Name name,
addr_t const base,
Clock & parent,
Clock_tree & tree)
: Clock(name, tree), Mmio(base),
_parent(parent), _tree(tree) {}
void set_rate(unsigned long) override;
unsigned long get_rate() const override;
};
class Gate : public Clock, Mmio
{
struct Ccgr : Register<0x0, 32> { };
Clock & _parent;
public:
Gate(Name name,
addr_t const base,
Clock & parent,
Clock_tree & tree)
: Clock(name, tree), Mmio(base), _parent(parent) {}
void set_rate(unsigned long) override {}
unsigned long get_rate() const override {
return _parent.get_rate(); }
void enable() override;
void disable() override;
};
enum {
CCM_MMIO_BASE = 0x30380000,
CCM_MMIO_SIZE = 0x10000,
CCM_ANALOG_MMIO_BASE = 0x30360000,
CCM_ANALOG_MMIO_SIZE = 0x10000,
};
Ccm(Genode::Env & env);
Genode::Env & env;
Attached_mmio ccm_regs { env, CCM_MMIO_BASE, CCM_MMIO_SIZE };
Attached_mmio ccm_analog_regs { env, CCM_ANALOG_MMIO_BASE, CCM_ANALOG_MMIO_SIZE };
Clock::Clock_tree tree { };
addr_t frac_pll_base(unsigned pll) {
return (addr_t)ccm_analog_regs.local_addr<const void>() + pll*0x8; }
addr_t sccg_pll_base(unsigned pll) {
return (addr_t)ccm_analog_regs.local_addr<const void>() + 0x30 + pll*0xc; }
addr_t gate_base(unsigned nr) {
return (addr_t)ccm_regs.local_addr<const void>() + 0x4000 + nr*0x10; }
addr_t root_base(unsigned nr) {
return (addr_t)ccm_regs.local_addr<const void>() + 0x8000 + nr*0x80; }
Fixed_clock no_clk { "no_clk", 0, tree };
Fixed_clock k32_ref_clk { "32k_ref_clk", 32 * 1000, tree };
Fixed_clock m25_ref_clk { "25m_ref_clk", 25 * 1000 * 1000, tree };
Fixed_clock m27_ref_clk { "27m_ref_clk", 27 * 1000 * 1000, tree };
Fixed_clock hdmi_phy_m27_clk { "hdmi_phy_27m_clk", 27 * 1000 * 1000, tree };
Fixed_clock ext_clk_1 { "ext_clk_1", 133 * 1000 * 1000, tree };
Fixed_clock ext_clk_2 { "ext_clk_2", 133 * 1000 * 1000, tree };
Fixed_clock ext_clk_3 { "ext_clk_3", 133 * 1000 * 1000, tree };
Fixed_clock ext_clk_4 { "ext_clk_4", 133 * 1000 * 1000, tree };
Frac_pll audio_pll1_clk { "audio_pll1_clk", frac_pll_base(0), tree };
Frac_pll audio_pll2_clk { "audio_pll2_clk", frac_pll_base(1), tree };
Frac_pll video_pll1_clk { "video_pll1_clk", frac_pll_base(2), tree };
Frac_pll gpu_pll_clk { "gpu_pll_clk", frac_pll_base(3), tree };
Frac_pll vpu_pll_clk { "vpu_pll_clk", frac_pll_base(4), tree };
Frac_pll arm_pll_clk { "arm_pll_clk", frac_pll_base(5), tree };
Sccg_pll system_pll1_clk { "system_pll1_clk", sccg_pll_base(0), tree };
Sccg_pll system_pll2_clk { "system_pll2_clk", sccg_pll_base(1), tree };
Sccg_pll system_pll3_clk { "system_pll3_clk", sccg_pll_base(2), tree };
Sccg_pll video_pll2_clk { "video2_pll2_clk", sccg_pll_base(3), tree };
Sccg_pll dram_pll_clk { "dram_pll_clk", sccg_pll_base(4), tree };
Fixed_divider system_pll1_div20 { "system_pll1_div20", system_pll1_clk, 20, tree };
Fixed_divider system_pll1_div10 { "system_pll1_div10", system_pll1_clk, 10, tree };
Fixed_divider system_pll1_div8 { "system_pll1_div8", system_pll1_clk, 8, tree };
Fixed_divider system_pll1_div6 { "system_pll1_div6", system_pll1_clk, 6, tree };
Fixed_divider system_pll1_div5 { "system_pll1_div5", system_pll1_clk, 5, tree };
Fixed_divider system_pll1_div4 { "system_pll1_div4", system_pll1_clk, 4, tree };
Fixed_divider system_pll1_div3 { "system_pll1_div3", system_pll1_clk, 3, tree };
Fixed_divider system_pll1_div2 { "system_pll1_div2", system_pll1_clk, 2, tree };
Fixed_divider system_pll2_div20 { "system_pll2_div20", system_pll2_clk, 20, tree };
Fixed_divider system_pll2_div10 { "system_pll2_div10", system_pll2_clk, 10, tree };
Fixed_divider system_pll2_div8 { "system_pll2_div8", system_pll2_clk, 8, tree };
Fixed_divider system_pll2_div6 { "system_pll2_div6", system_pll2_clk, 6, tree };
Fixed_divider system_pll2_div5 { "system_pll2_div5", system_pll2_clk, 5, tree };
Fixed_divider system_pll2_div4 { "system_pll2_div4", system_pll2_clk, 4, tree };
Fixed_divider system_pll2_div3 { "system_pll2_div3", system_pll2_clk, 3, tree };
Fixed_divider system_pll2_div2 { "system_pll2_div2", system_pll2_clk, 2, tree };
Root_clock arm_a53_clk_root { "arm_a53_clk_root", root_base(0), m25_ref_clk, arm_pll_clk, system_pll2_div2, system_pll2_clk, system_pll1_clk, system_pll1_div2, audio_pll1_clk, system_pll3_clk, tree };
Root_clock arm_m4_clk_root { "arm_m4_clk_root", root_base(1), m25_ref_clk, system_pll2_div5, system_pll2_div4, system_pll1_div3, system_pll1_clk, audio_pll1_clk, video_pll1_clk, system_pll3_clk, tree };
Root_clock vpu_a53_clk_root { "vpu_a53_clk_root", root_base(2), m25_ref_clk, arm_pll_clk, system_pll2_div2, system_pll2_clk, system_pll1_clk, system_pll1_div2, audio_pll1_clk, vpu_pll_clk, tree };
Root_clock gpu_core_clk_root { "gpu_core_clk_root", root_base(3), m25_ref_clk, gpu_pll_clk, system_pll1_clk, system_pll3_clk, system_pll2_clk, audio_pll1_clk, video_pll1_clk, audio_pll2_clk, tree };
Root_clock gpu_shader_clk_root { "gpu_shader_clk", root_base(4), m25_ref_clk, gpu_pll_clk, system_pll1_clk, system_pll3_clk, system_pll2_clk, audio_pll1_clk, video_pll1_clk, audio_pll2_clk, tree };
Root_clock main_axi_clk_root { "main_axi_clk_root", root_base(16), m25_ref_clk, system_pll2_div3, system_pll1_clk, system_pll2_div4, system_pll2_clk, audio_pll1_clk, video_pll1_clk, system_pll1_div8, tree };
Root_clock enet_axi_clk_root { "enet_axi_clk_root", root_base(17), m25_ref_clk, system_pll1_div3, system_pll1_clk, system_pll2_div4, system_pll2_div5, audio_pll1_clk, video_pll1_clk, system_pll3_clk, tree };
Root_clock nand_usdhc_bus_clk_root { "nand_usdhc_bus_clk_root", root_base(18), m25_ref_clk, system_pll1_div3, system_pll1_clk, system_pll2_div5, system_pll1_div6, system_pll3_clk, system_pll2_div4, audio_pll1_clk, tree };
Root_clock vpu_bus_clk_root { "vpu_bus_clk_root", root_base(19), m25_ref_clk, system_pll1_clk, vpu_pll_clk, audio_pll2_clk, system_pll3_clk, system_pll2_clk, system_pll2_div5, system_pll1_div8, tree };
Root_clock display_axi_clk_root { "display_axi_clk_root", root_base(20), m25_ref_clk, system_pll2_div8, system_pll1_clk, system_pll3_clk, system_pll1_div20, audio_pll2_clk, ext_clk_1, ext_clk_4, tree };
Root_clock display_apb_clk_root { "display_apb_clk_root", root_base(21), m25_ref_clk, system_pll2_div8, system_pll1_clk, system_pll3_clk, system_pll1_div20, audio_pll2_clk, ext_clk_1, ext_clk_3, tree };
Root_clock display_rtrm_clk_root { "display_rtrm_clk_root", root_base(22), m25_ref_clk, system_pll1_clk, system_pll2_div5, system_pll1_div2, audio_pll1_clk, video_pll1_clk, ext_clk_2, ext_clk_3, tree };
Root_clock usb_bus_clk_root { "usb_bus_clk_root", root_base(23), m25_ref_clk, system_pll2_div2, system_pll1_clk, system_pll2_div10, system_pll2_div5, ext_clk_2, ext_clk_4, audio_pll2_clk, tree };
Root_clock gpu_axi_clk_root { "gpu_axi_clk_root", root_base(24), m25_ref_clk, system_pll1_clk, gpu_pll_clk, system_pll3_clk, system_pll2_clk, audio_pll1_clk, video_pll1_clk, audio_pll2_clk, tree };
Root_clock gpu_ahb_clk_root { "gpu_ahb_clk_root", root_base(25), m25_ref_clk, system_pll1_clk, gpu_pll_clk, system_pll3_clk, system_pll2_clk, audio_pll1_clk, video_pll1_clk, audio_pll2_clk, tree };
Root_clock noc_clk_root { "noc_clk_root", root_base(26), m25_ref_clk, system_pll1_clk, system_pll3_clk, system_pll2_clk, system_pll2_div2, audio_pll1_clk, video_pll1_clk, audio_pll2_clk, tree };
Root_clock noc_apb_clk_root { "noc_apb_clk_root", root_base(27), m25_ref_clk, system_pll1_div2, system_pll3_clk, system_pll2_div3, system_pll2_div5, system_pll1_clk, audio_pll1_clk, video_pll1_clk, tree };
Root_clock ahb_clk_root { "ahb_clk_root", root_base(32), m25_ref_clk, system_pll1_div6, system_pll1_clk, system_pll1_div2, system_pll2_div8, system_pll3_clk, audio_pll1_clk, video_pll1_clk, tree };
Root_clock audio_ahb_clk_root { "audio_ahb_clk_root", root_base(34), m25_ref_clk, system_pll2_div2, system_pll1_clk, system_pll2_clk, system_pll2_div6, system_pll3_clk, audio_pll1_clk, video_pll1_clk, tree };
Root_clock mipi_dsi_esc_rx_clk_root { "mipi_dsi_esc_rx_clk_root", root_base(36), m25_ref_clk, system_pll2_div10, system_pll1_div10, system_pll1_clk, system_pll2_clk, system_pll3_clk, ext_clk_3, audio_pll2_clk, tree };
Root_clock dram_alt_clk_root { "dram_alt_clk_root", root_base(64), m25_ref_clk, system_pll1_clk, system_pll1_div8, system_pll2_div2, system_pll2_div4, system_pll1_div2, audio_pll1_clk, system_pll1_div3, tree };
Root_clock dram_apb_clk_root { "dram_apb_clk_root", root_base(65), m25_ref_clk, system_pll2_div5, system_pll1_div20, system_pll1_div5, system_pll1_clk, system_pll3_clk, system_pll2_div4, audio_pll2_clk, tree };
Root_clock vpu_g1_clk_root { "vpu_g1_clk_root", root_base(66), m25_ref_clk, vpu_pll_clk, system_pll1_clk, system_pll2_clk, system_pll1_div8, system_pll2_div8, system_pll3_clk, audio_pll1_clk, tree };
Root_clock vpu_g2_clk_root { "vpu_g2_clk_root", root_base(67), m25_ref_clk, vpu_pll_clk, system_pll1_clk, system_pll2_clk, system_pll1_div8, system_pll2_div8, system_pll3_clk, audio_pll1_clk, tree };
Root_clock display_dtrc_clk_root { "display_dtrc_clk_root", root_base(68), m25_ref_clk, video_pll2_clk, system_pll1_clk, system_pll2_clk, system_pll1_div5, video_pll1_clk, system_pll3_clk, audio_pll2_clk, tree };
Root_clock display_dc8000_clk_root { "display_dc8000_clk_root", root_base(69), m25_ref_clk, video_pll2_clk, system_pll1_clk, system_pll2_clk, system_pll1_div5, video_pll1_clk, system_pll3_clk, audio_pll2_clk, tree };
Root_clock pcie1_ctrl_clk_root { "pcie1_ctrl_clk_root", root_base(70), m25_ref_clk, system_pll2_div4, system_pll2_div5, system_pll1_div3, system_pll1_clk, system_pll2_div2, system_pll2_div3, system_pll3_clk, tree };
Root_clock pcie1_phy_clk_root { "pcie1_phy_clk_root", root_base(71), m25_ref_clk, system_pll2_div10, system_pll2_div2, ext_clk_1, ext_clk_2, ext_clk_3, ext_clk_4, system_pll1_div2, tree };
Root_clock pcie1_aux_clk_root { "pcie1_aux_clk_root", root_base(72), m25_ref_clk, system_pll2_div5, system_pll2_div20, system_pll3_clk, system_pll2_div10, system_pll1_div10, system_pll1_div5, system_pll1_div4, tree };
Root_clock dc_pixel_clk_root { "dc_pixel_clk_root", root_base(73), m25_ref_clk, video_pll1_clk, audio_pll2_clk, audio_pll1_clk, system_pll1_clk, system_pll2_clk, system_pll3_clk, ext_clk_4, tree };
Root_clock lcdif_pixel_clk_root { "lcdif_pixel_clk_root", root_base(74), m25_ref_clk, video_pll1_clk, audio_pll2_clk, audio_pll1_clk, system_pll1_clk, system_pll2_clk, system_pll3_clk, ext_clk_4, tree };
Root_clock sai1_clk_root { "sai1_clk_root", root_base(75), m25_ref_clk, audio_pll1_clk, audio_pll2_clk, video_pll1_clk, system_pll1_div6, m27_ref_clk, ext_clk_1, ext_clk_2, tree };
Root_clock sai2_clk_root { "sai2_clk_root", root_base(76), m25_ref_clk, audio_pll1_clk, audio_pll2_clk, video_pll1_clk, system_pll1_div6, m27_ref_clk, ext_clk_2, ext_clk_3, tree };
Root_clock sai3_clk_root { "sai3_clk_root", root_base(77), m25_ref_clk, audio_pll1_clk, audio_pll2_clk, video_pll1_clk, system_pll1_div6, m27_ref_clk, ext_clk_3, ext_clk_4, tree };
Root_clock sai4_clk_root { "sai4_clk_root", root_base(78), m25_ref_clk, audio_pll1_clk, audio_pll2_clk, video_pll1_clk, system_pll1_div6, m27_ref_clk, ext_clk_1, ext_clk_2, tree };
Root_clock sai5_clk_root { "sai5_clk_root", root_base(79), m25_ref_clk, audio_pll1_clk, audio_pll2_clk, video_pll1_clk, system_pll1_div6, m27_ref_clk, ext_clk_2, ext_clk_3, tree };
Root_clock sai6_clk_root { "sai6_clk_root", root_base(80), m25_ref_clk, audio_pll1_clk, audio_pll2_clk, video_pll1_clk, system_pll1_div6, m27_ref_clk, ext_clk_3, ext_clk_4, tree };
Root_clock spdif1_clk_root { "spdif1_clk_root", root_base(81), m25_ref_clk, audio_pll1_clk, audio_pll2_clk, video_pll1_clk, system_pll1_div6, m27_ref_clk, ext_clk_2, ext_clk_3, tree };
Root_clock spdif2_clk_root { "spdif2_clk_root", root_base(82), m25_ref_clk, audio_pll1_clk, audio_pll2_clk, video_pll1_clk, system_pll1_div6, m27_ref_clk, ext_clk_3, ext_clk_4, tree };
Root_clock enet_ref_clk_root { "enet_ref_clk_root", root_base(83), m25_ref_clk, system_pll2_div8, system_pll2_div20, system_pll2_div10, system_pll1_div5, audio_pll1_clk, video_pll1_clk, ext_clk_4, tree };
Root_clock enet_timer_clk_root { "enet_timer_clk_root", root_base(84), m25_ref_clk, system_pll2_div10, audio_pll1_clk, ext_clk_1, ext_clk_2, ext_clk_3, ext_clk_4, video_pll1_clk, tree };
Root_clock enet_phy_ref_clk_root { "enet_phy_ref_clk_root", root_base(85), m25_ref_clk, system_pll2_div20, system_pll2_div8, system_pll2_div5, system_pll2_div2, audio_pll1_clk, video_pll1_clk, audio_pll2_clk, tree };
Root_clock nand_clk_root { "nand_clk_root", root_base(86), m25_ref_clk, system_pll2_div2, audio_pll1_clk, system_pll1_div2, audio_pll2_clk, system_pll3_clk, system_pll2_div4, video_pll1_clk, tree };
Root_clock qspi_clk_root { "qspi_clk_root", root_base(87), m25_ref_clk, system_pll1_div2, system_pll1_clk, system_pll2_div2, audio_pll2_clk, system_pll1_div3, system_pll3_clk, system_pll1_div8, tree };
Root_clock usdhc1_clk_root { "usdhc1_clk_root", root_base(88), m25_ref_clk, system_pll1_div2, system_pll1_clk, system_pll2_div2, system_pll3_clk, system_pll1_div3, audio_pll2_clk, system_pll1_div8, tree };
Root_clock usdhc2_clk_root { "usdhc2_clk_root", root_base(89), m25_ref_clk, system_pll1_div2, system_pll1_clk, system_pll2_div2, system_pll3_clk, system_pll1_div3, audio_pll2_clk, system_pll1_div8, tree };
Root_clock i2c1_clk_root { "i2c1_clk_root", root_base(90), m25_ref_clk, system_pll1_div5, system_pll2_div20, system_pll3_clk, audio_pll1_clk, video_pll1_clk, audio_pll2_clk, system_pll1_div6, tree };
Root_clock i2c2_clk_root { "i2c2_clk_root", root_base(91), m25_ref_clk, system_pll1_div5, system_pll2_div20, system_pll3_clk, audio_pll1_clk, video_pll1_clk, audio_pll2_clk, system_pll1_div6, tree };
Root_clock i2c3_clk_root { "i2c3_clk_root", root_base(92), m25_ref_clk, system_pll1_div5, system_pll2_div20, system_pll3_clk, audio_pll1_clk, video_pll1_clk, audio_pll2_clk, system_pll1_div6, tree };
Root_clock i2c4_clk_root { "i2c4_clk_root", root_base(93), m25_ref_clk, system_pll1_div5, system_pll2_div20, system_pll3_clk, audio_pll1_clk, video_pll1_clk, audio_pll2_clk, system_pll1_div6, tree };
Root_clock uart1_clk_root { "uart1_clk_root", root_base(94), m25_ref_clk, system_pll1_div10, system_pll2_div5, system_pll2_div10, system_pll3_clk, ext_clk_2, ext_clk_4, audio_pll2_clk, tree };
Root_clock uart2_clk_root { "uart2_clk_root", root_base(95), m25_ref_clk, system_pll1_div10, system_pll2_div5, system_pll2_div10, system_pll3_clk, ext_clk_2, ext_clk_3, audio_pll2_clk, tree };
Root_clock uart3_clk_root { "uart3_clk_root", root_base(96), m25_ref_clk, system_pll1_div10, system_pll2_div5, system_pll2_div10, system_pll3_clk, ext_clk_2, ext_clk_4, audio_pll2_clk, tree };
Root_clock uart4_clk_root { "uart4_clk_root", root_base(97), m25_ref_clk, system_pll1_div10, system_pll2_div5, system_pll2_div10, system_pll3_clk, ext_clk_2, ext_clk_3, audio_pll2_clk, tree };
Root_clock usb_core_ref_clk_root { "usb_core_ref_clk_root", root_base(98), m25_ref_clk, system_pll1_div8, system_pll1_div20, system_pll2_div10, system_pll2_div5, ext_clk_2, ext_clk_3, audio_pll2_clk, tree };
Root_clock usb_phy_ref_clk_root { "usb_phy_ref_clk_root", root_base(99), m25_ref_clk, system_pll1_div8, system_pll1_div20, system_pll2_div10, system_pll2_div5, ext_clk_2, ext_clk_3, audio_pll2_clk, tree };
Root_clock gic_clk_root { "gic_clk_root", root_base(100), m25_ref_clk, system_pll2_div5, system_pll1_div20, system_pll2_div10, system_pll1_clk, ext_clk_2, ext_clk_4, audio_pll2_clk, tree };
Root_clock ecspi1_clk_root { "ecspi1_clk_root", root_base(101), m25_ref_clk, system_pll2_div5, system_pll1_div20, system_pll1_div5, system_pll1_clk, system_pll3_clk, system_pll2_div4, audio_pll2_clk, tree };
Root_clock ecspi2_clk_root { "ecspi2_clk_root", root_base(102), m25_ref_clk, system_pll2_div5, system_pll1_div20, system_pll1_div5, system_pll1_clk, system_pll3_clk, system_pll2_div4, audio_pll2_clk, tree };
Root_clock pwm1_clk_root { "pwm1_clk_root", root_base(103), m25_ref_clk, system_pll2_div10, system_pll1_div5, system_pll1_div20, system_pll3_clk, ext_clk_1, system_pll1_div10, video_pll1_clk, tree };
Root_clock pwm2_clk_root { "pwm2_clk_root", root_base(104), m25_ref_clk, system_pll2_div10, system_pll1_div5, system_pll1_div20, system_pll3_clk, ext_clk_1, system_pll1_div10, video_pll1_clk, tree };
Root_clock pwm3_clk_root { "pwm3_clk_root", root_base(105), m25_ref_clk, system_pll2_div10, system_pll1_div5, system_pll1_div20, system_pll3_clk, ext_clk_2, system_pll1_div10, video_pll1_clk, tree };
Root_clock pwm4_clk_root { "pwm4_clk_root", root_base(106), m25_ref_clk, system_pll2_div10, system_pll1_div5, system_pll1_div20, system_pll3_clk, ext_clk_2, system_pll1_div10, video_pll1_clk, tree };
Root_clock gpt1_clk_root { "gpt1_clk_root", root_base(107), m25_ref_clk, system_pll2_div10, system_pll1_div2, system_pll1_div20, video_pll1_clk, system_pll1_div10, audio_pll1_clk, ext_clk_1, tree };
Root_clock gpt2_clk_root { "gpt2_clk_root", root_base(108), m25_ref_clk, system_pll2_div10, system_pll1_div2, system_pll1_div20, video_pll1_clk, system_pll1_div10, audio_pll1_clk, ext_clk_2, tree };
Root_clock gpt3_clk_root { "gpt3_clk_root", root_base(109), m25_ref_clk, system_pll2_div10, system_pll1_div2, system_pll1_div20, video_pll1_clk, system_pll1_div10, audio_pll1_clk, ext_clk_3, tree };
Root_clock gpt4_clk_root { "gpt4_clk_root", root_base(110), m25_ref_clk, system_pll2_div10, system_pll1_div2, system_pll1_div20, video_pll1_clk, system_pll1_div10, audio_pll1_clk, ext_clk_1, tree };
Root_clock gpt5_clk_root { "gpt5_clk_root", root_base(111), m25_ref_clk, system_pll2_div10, system_pll1_div2, system_pll1_div20, video_pll1_clk, system_pll1_div10, audio_pll1_clk, ext_clk_2, tree };
Root_clock gpt6_clk_root { "gpt6_clk_root", root_base(112), m25_ref_clk, system_pll2_div10, system_pll1_div2, system_pll1_div20, video_pll1_clk, system_pll1_div10, audio_pll1_clk, ext_clk_3, tree };
Root_clock trace_clk_root { "trace_clk_root", root_base(113), m25_ref_clk, system_pll1_div6, system_pll1_div5, vpu_pll_clk, system_pll2_div8, system_pll3_clk, ext_clk_1, ext_clk_3, tree };
Root_clock wdog_clk_root { "wdog_clk_root", root_base(114), m25_ref_clk, system_pll1_div6, system_pll1_div5, vpu_pll_clk, system_pll2_div8, system_pll3_clk, system_pll1_div10, system_pll2_div6, tree };
Root_clock wrclk_clk_root { "wrclk_clk_root", root_base(115), m25_ref_clk, system_pll1_div20, vpu_pll_clk, system_pll3_clk, system_pll2_div5, system_pll1_div3, system_pll2_div2, system_pll1_div8, tree };
Root_clock ipp_do_clko1clk_root { "ipp_do_clko1_clk_root", root_base(116), m25_ref_clk, system_pll1_clk, m27_ref_clk, system_pll1_div4, audio_pll2_clk, system_pll2_div2, vpu_pll_clk, system_pll1_div10, tree };
Root_clock ipp_do_clko2_clk_root { "ipp_do_clko2_clk_root", root_base(117), m25_ref_clk, system_pll2_div5, system_pll1_div2, system_pll2_div6, system_pll3_clk, audio_pll1_clk, video_pll1_clk, k32_ref_clk, tree };
Root_clock mipi_dsi_core_clk_root { "mipi_dsi_core_clk_root", root_base(118), m25_ref_clk, system_pll1_div3, system_pll2_div4, system_pll1_clk, system_pll2_clk, system_pll3_clk, audio_pll2_clk, video_pll1_clk, tree };
Root_clock mipi_dsi_phy_ref_clk_root { "mipi_dsi_phy_ref_clk_root", root_base(119), m25_ref_clk, system_pll2_div8, system_pll2_div10, system_pll1_clk, system_pll2_clk, ext_clk_2, audio_pll2_clk, video_pll1_clk, tree };
Root_clock mipi_dsi_dbi_clk_root { "mipi_dsi_dbi_clk_root", root_base(120), m25_ref_clk, system_pll1_div3, system_pll2_div10, system_pll1_clk, system_pll2_clk, system_pll3_clk, audio_pll2_clk, video_pll1_clk, tree };
Root_clock old_mipi_dsi_esc_clk_root { "old_mipi_dsi_esc_clk_root", root_base(121), m25_ref_clk, system_pll2_div10, system_pll1_div10, system_pll1_clk, system_pll2_clk, system_pll3_clk, ext_clk_3, audio_pll2_clk, tree };
Root_clock mipi_csi1_core_clk_root { "mipi_csi1_core_clk_root", root_base(122), m25_ref_clk, system_pll1_div3, system_pll2_div4, system_pll1_clk, system_pll2_clk, system_pll3_clk, audio_pll2_clk, video_pll1_clk, tree };
Root_clock mipi_csi1_phy_ref_clk_root { "mipi_csi1_phy_ref_clk_root", root_base(123), m25_ref_clk, system_pll2_div3, system_pll2_div10, system_pll1_clk, system_pll2_clk, ext_clk_2, audio_pll2_clk, video_pll1_clk, tree };
Root_clock mipi_csi1_esc_clk_root { "mipi_csi1_esc_clk_root", root_base(124), m25_ref_clk, system_pll2_div10, system_pll1_div10, system_pll1_clk, system_pll2_clk, system_pll3_clk, ext_clk_3, audio_pll2_clk, tree };
Root_clock mipi_csi2_core_clk_root { "mipi_csi2_core_clk_root", root_base(125), m25_ref_clk, system_pll1_div3, system_pll2_div4, system_pll1_clk, system_pll2_clk, system_pll3_clk, audio_pll2_clk, video_pll1_clk, tree };
Root_clock mipi_csi2_phy_ref_clk_root { "mipi_csi2_phy_ref_clk_root", root_base(126), m25_ref_clk, system_pll2_div3, system_pll2_div10, system_pll1_clk, system_pll2_clk, ext_clk_2, audio_pll2_clk, video_pll1_clk, tree };
Root_clock mipi_csi2_esc_clk_root { "mipi_csi2_esc_clk_root", root_base(127), m25_ref_clk, system_pll2_div10, system_pll1_div10, system_pll1_clk, system_pll2_clk, system_pll3_clk, ext_clk_3, audio_pll2_clk, tree };
Root_clock pcie2_ctrl_clk_root { "pcie2_ctrl_clk_root", root_base(128), m25_ref_clk, system_pll2_div4, system_pll2_div5, system_pll1_div3, system_pll1_clk, system_pll2_div2, system_pll2_div3, system_pll3_clk, tree };
Root_clock pcie2_phy_clk_root { "pcie2_phy_clk_root", root_base(129), m25_ref_clk, system_pll2_div10, system_pll2_div2, ext_clk_1, ext_clk_2, ext_clk_3, ext_clk_4, system_pll1_div2, tree };
Root_clock pcie2_aux_clk_root { "pcie2_aux_clk_root", root_base(130), m25_ref_clk, system_pll2_div5, system_pll2_div20, system_pll3_clk, system_pll2_div10, system_pll1_div10, system_pll1_div5, system_pll1_div4, tree };
Root_clock ecspi3_clk_root { "ecspi3_clk_root", root_base(131), m25_ref_clk, system_pll2_div5, system_pll1_div20, system_pll1_div5, system_pll1_clk, system_pll3_clk, system_pll2_div4, audio_pll2_clk, tree };
Root_clock old_mipi_dsi_esc_rx_clk_root { "old_mipi_dsi_esc_rx_clk_root", root_base(132), m25_ref_clk, system_pll2_div10, system_pll1_div10, system_pll1_clk, system_pll2_clk, system_pll3_clk, ext_clk_3, audio_pll2_clk, tree };
Root_clock display_hdmi_clk_root { "display_hdmi_clk_root", root_base(133), m25_ref_clk, system_pll1_div4, system_pll2_div5, vpu_pll_clk, system_pll1_clk, system_pll2_clk, system_pll3_clk, ext_clk_4, tree };
Root_clock_divider ipg_clk_root { "ipg_clk_root", root_base(33), ahb_clk_root, tree };
Root_clock_divider ipg_audio_clk_root { "ipg_audio_clk_root", root_base(35), audio_ahb_clk_root, tree };
Root_clock_divider mipi_dsi_esc_clk_root { "mipi_dsi_esc_clk_root", root_base(37), mipi_dsi_esc_rx_clk_root, tree };
Gate ecspi1_gate { "ecspi1_gate", gate_base(7), ecspi1_clk_root, tree };
Gate ecspi2_gate { "ecspi2_gate", gate_base(8), ecspi2_clk_root, tree };
Gate ecspi3_gate { "ecspi3_gate", gate_base(9), ecspi3_clk_root, tree };
Gate enet1_gate { "enet1_gate", gate_base(10), enet_axi_clk_root, tree };
Gate gpt1_gate { "gpt1_gate", gate_base(16), gpt1_clk_root, tree };
Gate i2c1_gate { "i2c1_gate", gate_base(23), i2c1_clk_root, tree };
Gate i2c2_gate { "i2c2_gate", gate_base(24), i2c2_clk_root, tree };
Gate i2c3_gate { "i2c3_gate", gate_base(25), i2c3_clk_root, tree };
Gate i2c4_gate { "i2c4_gate", gate_base(26), i2c4_clk_root, tree };
Gate mu_gate { "mu_gate", gate_base(33), ipg_clk_root, tree };
Gate ocotp_gate { "ocotp_gate", gate_base(34), ipg_clk_root, tree };
Gate pcie_gate { "pcie_gate", gate_base(37), pcie1_ctrl_clk_root, tree };
Gate pwm1_gate { "pwm1_gate", gate_base(40), pwm1_clk_root, tree };
Gate pwm2_gate { "pwm2_gate", gate_base(41), pwm2_clk_root, tree };
Gate pwm3_gate { "pwm3_gate", gate_base(42), pwm3_clk_root, tree };
Gate pwm4_gate { "pwm4_gate", gate_base(43), pwm4_clk_root, tree };
Gate qspi_gate { "qspi_gate", gate_base(47), qspi_clk_root, tree };
Gate nand_gate { "nand_gate", gate_base(48), nand_clk_root, tree };
Gate sai1_gate { "sai1_gate", gate_base(51), sai1_clk_root, tree };
Gate sai2_gate { "sai2_gate", gate_base(52), sai2_clk_root, tree };
Gate sai3_gate { "sai3_gate", gate_base(53), sai3_clk_root, tree };
Gate sai4_gate { "sai4_gate", gate_base(54), sai4_clk_root, tree };
Gate sai5_gate { "sai5_gate", gate_base(55), sai5_clk_root, tree };
Gate sai6_gate { "sai6_gate", gate_base(56), sai6_clk_root, tree };
Gate sdma1_gate { "sdma1_gate", gate_base(58), ipg_clk_root, tree };
Gate sdma2_gate { "sdma2_gate", gate_base(59), ipg_audio_clk_root, tree };
Gate uart1_gate { "uart1_gate", gate_base(73), uart1_clk_root, tree };
Gate uart2_gate { "uart2_gate", gate_base(74), uart2_clk_root, tree };
Gate uart3_gate { "uart3_gate", gate_base(75), uart3_clk_root, tree };
Gate uart4_gate { "uart4_gate", gate_base(76), uart4_clk_root, tree };
Gate usb_ctrl1_gate { "usb_ctrl1_gate", gate_base(77), usb_core_ref_clk_root, tree };
Gate usb_ctrl2_gate { "usb_ctrl2_gate", gate_base(78), usb_core_ref_clk_root, tree };
Gate usb_phy1_gate { "usb_phy1_gate", gate_base(79), usb_phy_ref_clk_root, tree };
Gate usb_phy2_gate { "usb_phy2_gate", gate_base(80), usb_phy_ref_clk_root, tree };
Gate usdhc1_gate { "usdhc1_gate", gate_base(81), usdhc1_clk_root, tree };
Gate usdhc2_gate { "usdhc2_gate", gate_base(82), usdhc2_clk_root, tree };
Gate wdog1_gate { "wdog1_gate", gate_base(83), wdog_clk_root, tree };
Gate wdog2_gate { "wdog2_gate", gate_base(84), wdog_clk_root, tree };
Gate wdog3_gate { "wdog3_gate", gate_base(85), wdog_clk_root, tree };
Gate va53_gate { "va53_gate", gate_base(86), vpu_g1_clk_root, tree };
Gate gpu_gate { "gpu_gate", gate_base(87), gpu_core_clk_root, tree };
Gate vp9_gate { "vp9_gate", gate_base(90), vpu_g2_clk_root, tree };
Gate display_gate { "display_gate", gate_base(93), display_dc8000_clk_root, tree };
Gate tempsensor_gate { "tempsensor_gate", gate_base(98), ipg_clk_root, tree };
Gate vpu_dec_gate { "vpu_dec_gate", gate_base(99), vpu_bus_clk_root, tree };
Gate pcie2_gate { "pcie2_gate", gate_base(100), pcie2_ctrl_clk_root, tree };
Gate mipi_csi1_gate { "mipi_csi1_gate", gate_base(101), mipi_csi1_core_clk_root, tree };
Gate mipi_csi2_gate { "mipi_csi2_gate", gate_base(102), mipi_csi2_core_clk_root, tree };
};

View File

@ -0,0 +1,120 @@
/*
* \brief Clock tree for platform driver
* \author Stefan Kalkowski
* \date 2020-06-12
*/
/*
* Copyright (C) 2020 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.
*/
#pragma once
#include <util/avl_string.h>
namespace Driver {
template <unsigned, typename> class Avl_string_element;
class Clock;
class Fixed_clock;
class Fixed_divider;
using namespace Genode;
}
template <unsigned STRING_LEN, typename T>
class Driver::Avl_string_element : public String<STRING_LEN>,
public Avl_string_base
{
T & _object;
public:
Avl_string_element(String<STRING_LEN> name, T & o)
: String<STRING_LEN>(name),
Avl_string_base(this->string()),
_object(o) {}
String<STRING_LEN> name() const { return *this; }
T & object() const { return _object; }
};
class Driver::Clock
{
protected:
enum { NAME_LEN = 64 };
using Node = Avl_string_element<NAME_LEN, Clock>;
Node _tree_elem;
/*
* Noncopyable
*/
Clock(Clock const &);
Clock &operator = (Clock const &);
public:
using Name = Genode::String<NAME_LEN>;
using Clock_tree = Avl_tree<Avl_string_base>;
using Clock_tree_element = Avl_string_element<NAME_LEN, Clock>;
Clock(Name name,
Clock_tree & tree)
: _tree_elem(name, *this) { tree.insert(&_tree_elem); }
virtual ~Clock() {}
virtual void set_rate(unsigned long rate) = 0;
virtual unsigned long get_rate() const = 0;
virtual void enable() {}
virtual void disable() {}
virtual void set_parent(Name) {}
Name name() const { return _tree_elem.name(); }
};
class Driver::Fixed_clock : public Driver::Clock
{
private:
unsigned long _rate;
public:
Fixed_clock(Name name,
unsigned long rate,
Clock_tree & tree)
: Clock(name, tree), _rate(rate) {}
void set_rate(unsigned long) override {}
unsigned long get_rate() const override { return _rate; }
};
class Driver::Fixed_divider : public Driver::Clock
{
private:
Clock & _parent;
unsigned _divider;
public:
Fixed_divider(Name name,
Clock & parent,
unsigned divider,
Clock_tree & tree)
: Clock(name, tree), _parent(parent), _divider(divider) {}
void set_rate(unsigned long) override {}
unsigned long get_rate() const override {
return _parent.get_rate() / _divider; }
};

View File

@ -0,0 +1,90 @@
/*
* \brief Platform driver - Device model policy for i.MX
* \author Stefan Kalkowski
* \date 2020-08-16
*/
/*
* Copyright (C) 2020 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 <env.h>
#include <imx_device.h>
using Driver::Device_model;
using Driver::Device;
using Driver::Imx_device;
void Device_model::destroy_element(Device & dev)
{
Imx_device & device = static_cast<Imx_device&>(dev);
{
Irq_update_policy policy(_env.heap);
device._irq_list.destroy_all_elements(policy);
}
{
Io_mem_update_policy policy(_env.heap);
device._io_mem_list.destroy_all_elements(policy);
}
{
Property_update_policy policy(_env.heap);
device._property_list.destroy_all_elements(policy);
}
{
Clock_update_policy policy(_env.heap);
device._clock_list.destroy_all_elements(policy);
}
{
Power_domain_update_policy policy(_env.heap);
device._power_domain_list.destroy_all_elements(policy);
}
Genode::destroy(_env.heap, &device);
}
Device & Device_model::create_element(Genode::Xml_node node)
{
Device::Name name = node.attribute_value("name", Device::Name());
return *(new (_env.heap) Imx_device(name));
}
void Device_model::update_element(Device & dev,
Genode::Xml_node node)
{
Imx_device & device = static_cast<Imx_device&>(dev);
{
Irq_update_policy policy(_env.heap);
device._irq_list.update_from_xml(policy, node);
}
{
Io_mem_update_policy policy(_env.heap);
device._io_mem_list.update_from_xml(policy, node);
}
{
Property_update_policy policy(_env.heap);
device._property_list.update_from_xml(policy, node);
}
{
Clock_update_policy policy(_env.heap);
device._clock_list.update_from_xml(policy, node);
}
{
Power_domain_update_policy policy(_env.heap);
device._power_domain_list.update_from_xml(policy, node);
}
}

View File

@ -0,0 +1,45 @@
/*
* \brief Platform driver for ARM
* \author Stefan Kalkowski
* \date 2020-04-12
*/
/*
* Copyright (C) 2020 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 _SRC__DRIVERS__PLATFORM__SPEC__ARM__ENV_H_
#define _SRC__DRIVERS__PLATFORM__SPEC__ARM__ENV_H_
#include <base/attached_rom_dataspace.h>
#include <base/env.h>
#include <base/heap.h>
#include <ccm.h>
#include <gpc.h>
#include <device.h>
namespace Driver {
using namespace Genode;
struct Env;
};
struct Driver::Env
{
Genode::Env & env;
Heap heap { env.ram(), env.rm() };
Sliced_heap sliced_heap { env.ram(), env.rm() };
Attached_rom_dataspace config { env, "config" };
Ccm ccm { env };
Gpc gpc { env };
Device_model devices { *this };
Env(Genode::Env &env) : env(env) { }
};
#endif /* _SRC__DRIVERS__PLATFORM__SPEC__ARM__ENV_H_ */

View File

@ -0,0 +1,103 @@
/*
* \brief Global power controller for i.MX8
* \author Stefan Kalkowski
* \date 2020-06-12
*/
/*
* Copyright (C) 2020 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.
*/
#pragma once
#include <base/env.h>
#include <util/string.h>
struct Gpc
{
enum Pu {
MIPI = 0,
PCIE_1 = 1,
USB_OTG_1 = 2,
USB_OTG_2 = 3,
GPU = 4,
VPU = 5,
HDMI = 6,
DISP = 7,
CSI_1 = 8,
CSI_2 = 9,
PCIE_2 = 10,
INVALID,
};
enum {
SIP_SERVICE_FUNC = 0xc2000000,
GPC_PM_DOMAIN = 0x3,
ON = 1,
OFF = 0
};
Genode::Env & env;
Pu pu(Genode::String<64> name)
{
if (name == "mipi") { return MIPI; }
if (name == "pcie_1") { return PCIE_1; }
if (name == "usb_otg_1") { return USB_OTG_1; }
if (name == "usb_otg_2") { return USB_OTG_2; }
if (name == "gpu") { return GPU; }
if (name == "vpu") { return VPU; }
if (name == "hdmi") { return HDMI; }
if (name == "disp") { return DISP; }
if (name == "csi_1") { return CSI_1; }
if (name == "csi_2") { return CSI_2; }
if (name == "pcie_2") { return PCIE_2; }
return INVALID;
}
void enable(Genode::String<64> name)
{
Genode::Pd_session::Managing_system_state state;
state.r[0] = SIP_SERVICE_FUNC;
state.r[1] = GPC_PM_DOMAIN;
state.r[2] = pu(name);
state.r[3] = ON;
if (state.r[2] == INVALID) {
Genode::warning("Power domain ", name.string(), " is not valid!");
return;
}
env.pd().managing_system(state);
}
void disable(Genode::String<64> name)
{
Genode::Pd_session::Managing_system_state state;
state.r[0] = SIP_SERVICE_FUNC;
state.r[1] = GPC_PM_DOMAIN;
state.r[2] = pu(name);
state.r[3] = OFF;
if (state.r[2] == INVALID) {
Genode::warning("Power domain ", name.string(), " is not valid!");
return;
}
env.pd().managing_system(state);
}
Gpc(Genode::Env & env) : env(env)
{
for (unsigned domain = MIPI; domain <= PCIE_2; domain++) {
Genode::Pd_session::Managing_system_state state;
state.r[0] = SIP_SERVICE_FUNC;
state.r[1] = GPC_PM_DOMAIN;
state.r[2] = domain;
state.r[3] = OFF;
}
};
};

View File

@ -0,0 +1,76 @@
/*
* \brief Platform driver - Device abstraction for i.MX
* \author Stefan Kalkowski
* \date 2020-08-17
*/
/*
* Copyright (C) 2020 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 <imx_device.h>
#include <clock.h>
#include <session_component.h>
bool Driver::Imx_device::acquire(Driver::Session_component & sc)
{
bool ret = Driver::Device::acquire(sc);
if (ret) {
_power_domain_list.for_each([&] (Power_domain & p) {
sc.env().gpc.enable(p.name); });
_clock_list.for_each([&] (Clock & c) {
Avl_string_base * asb =
sc.env().ccm.tree.first()->find_by_name(c.name.string());
if (!asb) {
Genode::warning("Clock ", c.name, " is unknown! ");
return;
}
Driver::Clock & clock =
static_cast<Driver::Clock::Clock_tree_element*>(asb)->object();
if (c.parent.valid()) { clock.set_parent(c.parent); }
if (c.rate) { clock.set_rate(c.rate); }
clock.enable();
});
sc.update_devices_rom();
}
return ret;
}
void Driver::Imx_device::release(Session_component & sc)
{
_power_domain_list.for_each([&] (Power_domain & p) {
sc.env().gpc.disable(p.name); });
_clock_list.for_each([&] (Clock & c) {
Avl_string_base * asb =
sc.env().ccm.tree.first()->find_by_name(c.name.string());
if (!asb) { return; }
static_cast<Driver::Clock::Clock_tree_element*>(asb)->object().disable();
});
return Driver::Device::release(sc);
}
void Driver::Imx_device::_report_platform_specifics(Genode::Xml_generator & xml,
Driver::Session_component & sc)
{
_clock_list.for_each([&] (Clock & c) {
Avl_string_base * asb =
sc.env().ccm.tree.first()->find_by_name(c.name.string());
if (!asb || !c.driver_name.valid()) { return; }
Driver::Clock & clock =
static_cast<Driver::Clock::Clock_tree_element*>(asb)->object();
xml.node("clock", [&] () {
xml.attribute("rate", clock.get_rate());
xml.attribute("name", c.driver_name);
});
});
}

View File

@ -0,0 +1,140 @@
/*
* \brief Platform driver - Device abstraction for i.MX
* \author Stefan Kalkowski
* \date 2020-08-17
*/
/*
* Copyright (C) 2020 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 _SRC__DRIVERS__PLATFORM__IMX8MQ__IMX_DEVICE_H_
#define _SRC__DRIVERS__PLATFORM__IMX8MQ__IMX_DEVICE_H_
#include <device.h>
namespace Driver {
using namespace Genode;
class Imx_device;
struct Clock_update_policy;
struct Power_domain_update_policy;
}
class Driver::Imx_device : public Driver::Device
{
public:
struct Clock : List_model<Clock>::Element
{
using Name = Genode::String<64>;
Name name;
Name parent;
Name driver_name;
unsigned long rate;
Clock(Name name,
Name parent,
Name driver_name,
unsigned long rate)
: name(name), parent(parent),
driver_name(driver_name), rate(rate) {}
};
struct Power_domain : List_model<Power_domain>::Element
{
using Name = Genode::String<64>;
Name name;
Power_domain(Name name) : name(name) {}
};
bool acquire(Session_component &) override;
void release(Session_component &) override;
Imx_device(Device::Name name) : Device(name) {}
protected:
friend class Driver::Device_model;
friend class List_model<Device>;
void _report_platform_specifics(Xml_generator &,
Session_component &) override;
List_model<Clock> _clock_list {};
List_model<Power_domain> _power_domain_list {};
};
struct Driver::Clock_update_policy
: Genode::List_model<Imx_device::Clock>::Update_policy
{
Genode::Allocator & alloc;
Clock_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
void destroy_element(Element & clock) {
Genode::destroy(alloc, &clock); }
Element & create_element(Genode::Xml_node node)
{
Element::Name name = node.attribute_value("name", Element::Name());
Element::Name parent = node.attribute_value("parent", Element::Name());
Element::Name driver = node.attribute_value("driver_name", Element::Name());
unsigned long rate = node.attribute_value<unsigned long >("rate", 0);
return *(new (alloc) Element(name, parent, driver, rate));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & clock, Genode::Xml_node node)
{
Element::Name name = node.attribute_value("name", Element::Name());
return name == clock.name;
}
static bool node_is_element(Genode::Xml_node node)
{
return node.has_type("clock");
}
};
struct Driver::Power_domain_update_policy
: Genode::List_model<Imx_device::Power_domain>::Update_policy
{
Genode::Allocator & alloc;
Power_domain_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
void destroy_element(Element & pd) {
Genode::destroy(alloc, &pd); }
Element & create_element(Genode::Xml_node node)
{
Element::Name name = node.attribute_value("name", Element::Name());
return *(new (alloc) Element(name));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & pd, Genode::Xml_node node)
{
Element::Name name = node.attribute_value("name", Element::Name());
return name == pd.name;
}
static bool node_is_element(Genode::Xml_node node)
{
return node.has_type("power-domain");
}
};
#endif /* _SRC__DRIVERS__PLATFORM__IMX8MQ__IMX_DEVICE_H_ */

View File

@ -0,0 +1,15 @@
TARGET = imx8mq_platform_drv
REQUIRES = arm_v8
SRC_CC = ccm.cc
SRC_CC += device.cc
SRC_CC += device_component.cc
SRC_CC += device_model_policy.cc
SRC_CC += imx_device.cc
SRC_CC += main.cc
SRC_CC += session_component.cc
SRC_CC += root.cc
INC_DIR = $(PRG_DIR) $(REP_DIR)/src/drivers/platform/spec/arm
LIBS = base
vpath %.cc $(PRG_DIR)
vpath %.cc $(REP_DIR)/src/drivers/platform/spec/arm

View File

@ -19,8 +19,6 @@ Driver::Device::Name Driver::Device::name() const { return _name; }
bool Driver::Device::acquire(Session_component & sc)
{
using namespace Genode;
if (_session.valid() && _session != sc.label()) { return false; }
/**
@ -50,18 +48,18 @@ void Driver::Device::release(Session_component & sc)
{
if (_session != sc.label()) { return; }
sc.replenish(Genode::Cap_quota{_cap_quota_required()});
sc.replenish(Genode::Ram_quota{_ram_quota_required()});
sc.replenish(Cap_quota{_cap_quota_required()});
sc.replenish(Ram_quota{_ram_quota_required()});
_io_mem_list.for_each([&] (Io_mem & io_mem) {
if (io_mem.io_mem) {
Genode::destroy(sc.heap(), io_mem.io_mem);
destroy(sc.heap(), io_mem.io_mem);
}
});
_irq_list.for_each([&] (Irq & irq) {
if (irq.irq) {
Genode::destroy(sc.heap(), irq.irq);
destroy(sc.heap(), irq.irq);
}
});
@ -72,7 +70,7 @@ void Driver::Device::release(Session_component & sc)
Genode::Irq_session_capability Driver::Device::irq(unsigned idx,
Session_component & sc)
{
Genode::Irq_session_capability cap;
Irq_session_capability cap;
if (_session != sc.label()) { return cap; }
@ -83,7 +81,7 @@ Genode::Irq_session_capability Driver::Device::irq(unsigned idx,
if (!irq.irq) {
irq.irq = new (sc.heap())
Genode::Irq_connection(sc.env(), irq.number);
Irq_connection(sc.env().env, irq.number);
}
cap = irq.irq->cap();
});
@ -93,10 +91,10 @@ Genode::Irq_session_capability Driver::Device::irq(unsigned idx,
Genode::Io_mem_session_capability
Driver::Device::io_mem(unsigned idx, Genode::Cache_attribute attr,
Driver::Device::io_mem(unsigned idx, Cache_attribute attr,
Session_component & sc)
{
Genode::Io_mem_session_capability cap;
Io_mem_session_capability cap;
if (_session != sc.label()) return cap;
@ -107,8 +105,8 @@ Driver::Device::io_mem(unsigned idx, Genode::Cache_attribute attr,
if (!io_mem.io_mem) {
io_mem.io_mem = new (sc.heap())
Genode::Io_mem_connection(sc.env(), io_mem.base, io_mem.size,
(attr == Genode::WRITE_COMBINED));
Io_mem_connection(sc.env().env, io_mem.base, io_mem.size,
(attr == WRITE_COMBINED));
}
cap = io_mem.io_mem->cap();
});
@ -117,32 +115,50 @@ Driver::Device::io_mem(unsigned idx, Genode::Cache_attribute attr,
}
void Driver::Device::report(Genode::Xml_generator & xml)
void Driver::Device::report(Xml_generator & xml, Session_component & sc)
{
unsigned io_mem_id = 0;
unsigned irq_id = 0;
static constexpr addr_t page_off_mask = (addr_t)((1 << 12) - 1);
xml.node("device", [&] () {
xml.attribute("name", name());
_io_mem_list.for_each([&] (Io_mem & io_mem) {
xml.node("io_mem", [&] () {
xml.attribute("id", io_mem_id++);
xml.attribute("size", io_mem.size);
xml.attribute("page_offset",
io_mem.base & page_off_mask);
});
});
_irq_list.for_each([&] (Irq &) {
xml.node("irq", [&] () {
xml.attribute("id", irq_id++); });
});
_property_list.for_each([&] (Property & p) {
xml.node("property", [&] () {
xml.attribute("name", p.name);
xml.attribute("value", p.value);
});
});
_report_platform_specifics(xml, sc);
});
}
Genode::size_t Driver::Device::_cap_quota_required()
{
Genode::size_t total = 0;
size_t total = 0;
_io_mem_list.for_each([&] (Io_mem &) {
total += Genode::Io_mem_session::CAP_QUOTA; });
total += Io_mem_session::CAP_QUOTA; });
return total;
}
Genode::size_t Driver::Device::_ram_quota_required()
{
Genode::size_t total = 0;
size_t total = 0;
_io_mem_list.for_each([&] (Io_mem & io_mem) {
total += io_mem.size + 2*1024; });
return total;
@ -156,7 +172,6 @@ Driver::Device::Device(Name name)
Driver::Device::~Device()
{
if (_session.valid()) {
Genode::error("Device to be destroyed, still obtained by session ",
_session);
}
error("Device to be destroyed, still obtained by session ",
_session); }
}

View File

@ -24,35 +24,41 @@
#include <util/xml_generator.h>
namespace Driver {
using namespace Genode;
class Env;
class Device;
struct Device_model;
class Session_component;
struct Irq_update_policy;
struct Io_mem_update_policy;
struct Property_update_policy;
}
class Driver::Device : public Genode::List_model<Device>::Element
class Driver::Device : private List_model<Device>::Element
{
public:
struct Io_mem : Genode::List_model<Io_mem>::Element
struct Io_mem : List_model<Io_mem>::Element
{
Genode::addr_t base;
Genode::size_t size;
Genode::Io_mem_connection * io_mem { nullptr };
addr_t base;
size_t size;
Io_mem_connection * io_mem { nullptr };
Io_mem(Genode::addr_t base, Genode::size_t size)
Io_mem(addr_t base, size_t size)
: base(base), size(size) {}
};
struct Irq : Genode::List_model<Irq>::Element
struct Irq : List_model<Irq>::Element
{
unsigned number;
Genode::Irq_connection * irq { nullptr };
unsigned number;
Irq_connection * irq { nullptr };
Irq(unsigned number) : number(number) {}
};
struct Property : Genode::List_model<Property>::Element
struct Property : List_model<Property>::Element
{
using Name = Genode::String<64>;
using Value = Genode::String<64>;
@ -67,33 +73,37 @@ class Driver::Device : public Genode::List_model<Device>::Element
using Name = Genode::String<64>;
Device(Name name);
~Device();
virtual ~Device();
Name name() const;
bool acquire(Session_component &);
void release(Session_component &);
virtual bool acquire(Session_component &);
virtual void release(Session_component &);
Genode::Irq_session_capability irq(unsigned idx,
Session_component & session);
Genode::Io_mem_session_capability io_mem(unsigned idx,
Genode::Cache_attribute,
Session_component & session);
Irq_session_capability irq(unsigned idx,
Session_component & session);
Io_mem_session_capability io_mem(unsigned idx, Cache_attribute,
Session_component & session);
void report(Genode::Xml_generator &);
void report(Xml_generator &, Session_component &);
private:
protected:
Genode::size_t _cap_quota_required();
Genode::size_t _ram_quota_required();
virtual void _report_platform_specifics(Xml_generator &,
Session_component &) {}
size_t _cap_quota_required();
size_t _ram_quota_required();
friend class Driver::Device_model;
friend class List_model<Device>;
friend class List<Device>;
Name _name;
Platform::Session::Label _session {};
Genode::List_model<Io_mem> _io_mem_list {};
Genode::List_model<Irq> _irq_list {};
Genode::List_model<Property> _property_list {};
Name _name;
Platform::Session::Label _session {};
List_model<Io_mem> _io_mem_list {};
List_model<Irq> _irq_list {};
List_model<Property> _property_list {};
/*
* Noncopyable
@ -104,27 +114,25 @@ class Driver::Device : public Genode::List_model<Device>::Element
class Driver::Device_model :
public Genode::List_model<Device>::Update_policy
public List_model<Device>::Update_policy
{
private:
Genode::Allocator & _alloc;
Genode::List_model<Device> _model {};
Driver::Env & _env;
List_model<Device> _model {};
public:
void update(Genode::Xml_node const & node) {
void update(Xml_node const & node) {
_model.update_from_xml(*this, node);
}
Device_model(Genode::Allocator & alloc,
Genode::Xml_node const & node)
: _alloc(alloc) { update(node); }
Device_model(Driver::Env & env)
: _env(env) { }
~Device_model() {
_model.destroy_all_elements(*this); }
template <typename FN>
void for_each(FN const & fn) { _model.for_each(fn); }
@ -134,11 +142,106 @@ class Driver::Device_model :
***********************/
void destroy_element(Device & device);
Device & create_element(Genode::Xml_node node);
void update_element(Device & device, Genode::Xml_node node);
static bool element_matches_xml_node(Device const &,
Genode::Xml_node);
static bool node_is_element(Genode::Xml_node);
Device & create_element(Xml_node node);
void update_element(Device & device, Xml_node node);
static bool element_matches_xml_node(Device const & dev,
Genode::Xml_node n) {
return dev.name() == n.attribute_value("name", Device::Name()); }
static bool node_is_element(Genode::Xml_node node) {
return node.has_type("device"); }
};
struct Driver::Irq_update_policy : Genode::List_model<Device::Irq>::Update_policy
{
Genode::Allocator & alloc;
Irq_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
void destroy_element(Element & irq) {
Genode::destroy(alloc, &irq); }
Element & create_element(Genode::Xml_node node)
{
unsigned number = node.attribute_value<unsigned>("number", 0);
return *(new (alloc) Element(number));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & irq, Genode::Xml_node node)
{
unsigned number = node.attribute_value<unsigned>("number", 0);
return number == irq.number;
}
static bool node_is_element(Genode::Xml_node node)
{
return node.has_type("irq");
}
};
struct Driver::Io_mem_update_policy : Genode::List_model<Device::Io_mem>::Update_policy
{
Genode::Allocator & alloc;
Io_mem_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
void destroy_element(Element & iomem) {
Genode::destroy(alloc, &iomem); }
Element & create_element(Genode::Xml_node node)
{
Genode::addr_t base = node.attribute_value<Genode::addr_t>("address", 0);
Genode::size_t size = node.attribute_value<Genode::size_t>("size", 0);
return *(new (alloc) Element(base, size));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & iomem, Genode::Xml_node node)
{
Genode::addr_t base = node.attribute_value<Genode::addr_t>("address", 0);
Genode::size_t size = node.attribute_value<Genode::size_t>("size", 0);
return (base == iomem.base) && (size == iomem.size);
}
static bool node_is_element(Genode::Xml_node node)
{
return node.has_type("io_mem");
}
};
struct Driver::Property_update_policy : Genode::List_model<Device::Property>::Update_policy
{
Genode::Allocator & alloc;
Property_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
void destroy_element(Element & p) {
Genode::destroy(alloc, &p); }
Element & create_element(Genode::Xml_node node)
{
return *(new (alloc)
Element(node.attribute_value("name", Element::Name()),
node.attribute_value("value", Element::Value())));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & prop, Genode::Xml_node node)
{
Element::Name n = node.attribute_value("name", Element::Name());
Element::Value v = node.attribute_value("value", Element::Value());
return (n == prop.name) && (v == prop.value);
}
static bool node_is_element(Genode::Xml_node node) {
return node.has_type("property"); }
};
#endif /* _SRC__DRIVERS__PLATFORM__SPEC__ARM__DEVICE_H_ */

View File

@ -26,7 +26,7 @@ Driver::Session_component & Device_component::session() { return _session; }
bool Driver::Device_component::acquire()
{
bool acquired = false;
_session.devices().for_each([&] (Driver::Device & device) {
_session.env().devices.for_each([&] (Driver::Device & device) {
if (device.name() == _device) {
acquired = device.acquire(_session); }});
return acquired;
@ -35,16 +35,16 @@ bool Driver::Device_component::acquire()
void Driver::Device_component::release()
{
_session.devices().for_each([&] (Driver::Device & device) {
_session.env().devices.for_each([&] (Driver::Device & device) {
if (device.name() == _device) { device.release(_session); }});
}
Genode::Io_mem_session_capability
Device_component::io_mem(unsigned idx, Genode::Cache_attribute attr)
Device_component::io_mem(unsigned idx, Cache_attribute attr)
{
Genode::Io_mem_session_capability cap;
_session.devices().for_each([&] (Driver::Device & device) {
Io_mem_session_capability cap;
_session.env().devices.for_each([&] (Driver::Device & device) {
if (device.name() == _device) {
cap = device.io_mem(idx, attr, _session); }});
return cap;
@ -53,17 +53,17 @@ Device_component::io_mem(unsigned idx, Genode::Cache_attribute attr)
Genode::Irq_session_capability Device_component::irq(unsigned idx)
{
Genode::Irq_session_capability cap;
_session.devices().for_each([&] (Driver::Device & device) {
Irq_session_capability cap;
_session.env().devices.for_each([&] (Driver::Device & device) {
if (device.name() == _device) { cap = device.irq(idx, _session); }});
return cap;
}
void Driver::Device_component::report(Genode::Xml_generator & xml)
void Driver::Device_component::report(Xml_generator & xml)
{
_session.devices().for_each([&] (Driver::Device & device) {
if (device.name() == _device) { device.report(xml); }});
_session.env().devices.for_each([&] (Driver::Device & device) {
if (device.name() == _device) { device.report(xml, _session); }});
}

View File

@ -18,6 +18,7 @@
#include <platform_session/platform_session.h>
#include <platform_device/platform_device.h>
#include <env.h>
#include <device.h>
namespace Driver {
@ -26,7 +27,7 @@ namespace Driver {
}
class Driver::Device_component : public Genode::Rpc_object<Platform::Device>
class Driver::Device_component : public Rpc_object<Platform::Device>
{
public:
@ -40,17 +41,15 @@ class Driver::Device_component : public Genode::Rpc_object<Platform::Device>
bool acquire();
void release();
void report(Genode::Xml_generator&);
void report(Xml_generator&);
/**************************
** Platform::Device API **
**************************/
Genode::Irq_session_capability irq(unsigned) override;
Genode::Io_mem_session_capability
io_mem(unsigned, Genode::Cache_attribute) override;
Irq_session_capability irq(unsigned) override;
Io_mem_session_capability io_mem(unsigned, Cache_attribute) override;
private:
@ -59,7 +58,7 @@ class Driver::Device_component : public Genode::Rpc_object<Platform::Device>
Session_component & _session;
Driver::Device::Name const _device;
Platform::Device_capability _cap {};
Genode::List_element<Device_component> _list_elem { this };
List_element<Device_component> _list_elem { this };
/*
* Noncopyable

View File

@ -11,132 +11,37 @@
* under the terms of the GNU Affero General Public License version 3.
*/
#include <env.h>
#include <device.h>
using Driver::Device_model;
using Driver::Device;
struct Irq_update_policy : Genode::List_model<Device::Irq>::Update_policy
{
Genode::Allocator & alloc;
Irq_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
void destroy_element(Element & irq) {
Genode::destroy(alloc, &irq); }
Element & create_element(Genode::Xml_node node)
{
unsigned number = node.attribute_value<unsigned>("number", 0);
return *(new (alloc) Element(number));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & irq, Genode::Xml_node node)
{
unsigned number = node.attribute_value<unsigned>("number", 0);
return number == irq.number;
}
static bool node_is_element(Genode::Xml_node node)
{
using Name = Genode::String<16>;
return node.has_type("resource") &&
(node.attribute_value("name", Name()) == "IRQ");
}
};
struct Io_mem_update_policy : Genode::List_model<Device::Io_mem>::Update_policy
{
Genode::Allocator & alloc;
Io_mem_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
void destroy_element(Element & iomem) {
Genode::destroy(alloc, &iomem); }
Element & create_element(Genode::Xml_node node)
{
Genode::addr_t base = node.attribute_value<Genode::addr_t>("address", 0);
Genode::size_t size = node.attribute_value<Genode::size_t>("size", 0);
return *(new (alloc) Element(base, size));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & iomem, Genode::Xml_node node)
{
Genode::addr_t base = node.attribute_value<Genode::addr_t>("address", 0);
Genode::size_t size = node.attribute_value<Genode::size_t>("size", 0);
return (base == iomem.base) && (size == iomem.size);
}
static bool node_is_element(Genode::Xml_node node)
{
bool iomem = node.attribute_value("name", Genode::String<16>())
== "IO_MEM";
return node.has_type("resource") && iomem;
}
};
struct Property_update_policy : Genode::List_model<Device::Property>::Update_policy
{
Genode::Allocator & alloc;
Property_update_policy(Genode::Allocator & alloc) : alloc(alloc) {}
void destroy_element(Element & p) {
Genode::destroy(alloc, &p); }
Element & create_element(Genode::Xml_node node)
{
return *(new (alloc)
Element(node.attribute_value("name", Element::Name()),
node.attribute_value("value", Element::Value())));
}
void update_element(Element &, Genode::Xml_node) {}
static bool element_matches_xml_node(Element const & prop, Genode::Xml_node node)
{
Element::Name n = node.attribute_value("name", Element::Name());
Element::Value v = node.attribute_value("value", Element::Value());
return (n == prop.name) && (v == prop.value);
}
static bool node_is_element(Genode::Xml_node node) {
return node.has_type("property"); }
};
void Device_model::destroy_element(Device & device)
{
{
Irq_update_policy policy(_alloc);
Irq_update_policy policy(_env.heap);
device._irq_list.destroy_all_elements(policy);
}
{
Io_mem_update_policy policy(_alloc);
Io_mem_update_policy policy(_env.heap);
device._io_mem_list.destroy_all_elements(policy);
}
{
Property_update_policy policy(_alloc);
Property_update_policy policy(_env.heap);
device._property_list.destroy_all_elements(policy);
}
Genode::destroy(_alloc, &device);
Genode::destroy(_env.heap, &device);
}
Device & Device_model::create_element(Genode::Xml_node node)
{
Device::Name name = node.attribute_value("name", Device::Name());
return *(new (_alloc) Device(name));
return *(new (_env.heap) Device(name));
}
@ -144,26 +49,17 @@ void Device_model::update_element(Device & device,
Genode::Xml_node node)
{
{
Irq_update_policy policy(_alloc);
Irq_update_policy policy(_env.heap);
device._irq_list.update_from_xml(policy, node);
}
{
Io_mem_update_policy policy(_alloc);
Io_mem_update_policy policy(_env.heap);
device._io_mem_list.update_from_xml(policy, node);
}
{
Property_update_policy policy(_alloc);
Property_update_policy policy(_env.heap);
device._property_list.update_from_xml(policy, node);
}
}
bool Device_model::element_matches_xml_node(Device const & dev,
Genode::Xml_node n) {
return dev.name() == n.attribute_value("name", Device::Name()); }
bool Device_model::node_is_element(Genode::Xml_node node) {
return node.has_type("device"); }

View File

@ -0,0 +1,41 @@
/*
* \brief Platform driver for ARM
* \author Stefan Kalkowski
* \date 2020-04-12
*/
/*
* Copyright (C) 2020 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 _SRC__DRIVERS__PLATFORM__SPEC__ARM__ENV_H_
#define _SRC__DRIVERS__PLATFORM__SPEC__ARM__ENV_H_
#include <base/attached_rom_dataspace.h>
#include <base/env.h>
#include <base/heap.h>
#include <device.h>
namespace Driver {
using namespace Genode;
struct Env;
};
struct Driver::Env
{
Genode::Env & env;
Heap heap { env.ram(), env.rm() };
Sliced_heap sliced_heap { env.ram(), env.rm() };
Attached_rom_dataspace config { env, "config" };
Device_model devices { *this };
Env(Genode::Env &env) : env(env) {}
};
#endif /* _SRC__DRIVERS__PLATFORM__SPEC__ARM__ENV_H_ */

View File

@ -12,9 +12,7 @@
*/
#include <base/component.h>
#include <base/env.h>
#include <base/heap.h>
#include <env.h>
#include <root.h>
namespace Driver { struct Main; };
@ -23,29 +21,25 @@ struct Driver::Main
{
void update_config();
Genode::Env & env;
Genode::Heap heap { env.ram(), env.rm() };
Genode::Sliced_heap sliced_heap { env.ram(), env.rm() };
Genode::Attached_rom_dataspace config { env, "config" };
Genode::Signal_handler<Main> config_handler { env.ep(), *this,
&Main::update_config };
Driver::Device_model devices { heap, config.xml() };
Driver::Root root { env, sliced_heap,
config, devices };
Driver::Env env;
Signal_handler<Main> config_handler { env.env.ep(), *this,
&Main::update_config };
Driver::Root root { env };
Main(Genode::Env &env)
: env(env)
Main(Genode::Env & e)
: env(e)
{
config.sigh(config_handler);
env.parent().announce(env.ep().manage(root));
env.devices.update(env.config.xml());
env.config.sigh(config_handler);
env.env.parent().announce(env.env.ep().manage(root));
}
};
void Driver::Main::update_config()
{
config.update();
devices.update(config.xml());
env.config.update();
env.devices.update(env.config.xml());
root.update_policy();
}

View File

@ -21,9 +21,9 @@ void Driver::Root::update_policy()
unsigned device_count = 0;
try {
Genode::Session_policy const policy { sc._label, _config.xml() };
Session_policy const policy { sc._label, _env.config.xml() };
policy.for_each_sub_node("device", [&] (Genode::Xml_node node) {
policy.for_each_sub_node("device", [&] (Xml_node node) {
device_count++;
if (!sc.has_device(node.attribute_value("name",
Device::Name()))) {
@ -32,10 +32,10 @@ void Driver::Root::update_policy()
if (device_count != sc.devices_count()) { policy_changed = true; }
}
catch (Genode::Session_policy::No_policy_defined) {
catch (Session_policy::No_policy_defined) {
policy_changed = true;
Genode::error("No matching policy for '", sc._label.string(),
"' anymore, will close the session!");
error("No matching policy for '", sc._label.string(),
"' anymore, will close the session!");
}
if (policy_changed) { close(sc.cap()); }
@ -45,25 +45,22 @@ void Driver::Root::update_policy()
Driver::Session_component * Driver::Root::_create_session(const char *args)
{
using namespace Genode;
Session_component * sc = nullptr;
try {
sc = new (md_alloc()) Session_component(_env,
_devices,
_sessions,
session_label_from_args(args),
session_resources_from_args(args),
session_diag_from_args(args));
Session_policy const policy { sc->_label, _config.xml() };
Session_policy const policy { sc->_label, _env.config.xml() };
policy.for_each_sub_node("device", [&] (Xml_node node) {
sc->add(node.attribute_value("name", Driver::Device::Name())); });
} catch (Session_policy::No_policy_defined) {
if (sc) { Genode::destroy(md_alloc(), sc); }
error("Invalid session request, no matching policy for ",
"'", Genode::label_from_args(args).string(), "'");
"'", label_from_args(args).string(), "'");
throw Service_denied();
} catch (...) {
if (sc) { Genode::destroy(md_alloc(), sc); }
@ -76,14 +73,11 @@ Driver::Session_component * Driver::Root::_create_session(const char *args)
void Driver::Root::_upgrade_session(Session_component * sc, const char * args)
{
sc->upgrade(Genode::ram_quota_from_args(args));
sc->upgrade(Genode::cap_quota_from_args(args));
sc->upgrade(ram_quota_from_args(args));
sc->upgrade(cap_quota_from_args(args));
}
Driver::Root::Root(Genode::Env & env,
Genode::Allocator & alloc,
Genode::Attached_rom_dataspace & config,
Driver::Device_model & devices)
: Genode::Root_component<Session_component>(env.ep(), alloc),
_env(env), _config(config), _devices(devices) { }
Driver::Root::Root(Driver::Env & env)
: Root_component<Session_component>(env.env.ep(), env.sliced_heap),
_env(env) { }

View File

@ -23,14 +23,11 @@
namespace Driver { class Root; }
class Driver::Root : public Genode::Root_component<Driver::Session_component>
class Driver::Root : public Root_component<Session_component>
{
public:
Root(Genode::Env & env,
Genode::Allocator & alloc,
Genode::Attached_rom_dataspace & config,
Device_model & devices);
Root(Driver::Env & env);
void update_policy();
@ -40,10 +37,8 @@ class Driver::Root : public Genode::Root_component<Driver::Session_component>
void _upgrade_session(Session_component *, const char *) override;
Genode::Env & _env;
Genode::Attached_rom_dataspace & _config;
Driver::Device_model & _devices;
Genode::Registry<Session_component> _sessions {};
Driver::Env & _env;
Registry<Session_component> _sessions {};
};
#endif /* _SRC__DRIVERS__PLATFORM__SPEC__ARM__ROOT_H_ */

View File

@ -18,7 +18,7 @@
using Driver::Session_component;
void Session_component::produce_xml(Genode::Xml_generator &xml)
void Session_component::produce_xml(Xml_generator &xml)
{
for (Device_list_element * e = _device_list.first(); e; e = e->next()) {
e->object()->report(xml); }
@ -28,10 +28,7 @@ void Session_component::produce_xml(Genode::Xml_generator &xml)
Genode::Heap & Session_component::heap() { return _md_alloc; }
Genode::Env & Session_component::env() { return _env; }
Driver::Device_model & Session_component::devices() { return _device_model; }
Driver::Env & Session_component::env() { return _env; }
void Session_component::add(Device::Name const & device)
@ -67,6 +64,12 @@ unsigned Session_component::devices_count() const
}
void Session_component::update_devices_rom()
{
_rom_session.trigger_update();
}
Genode::Rom_session_capability Session_component::devices_rom() {
return _rom_session.cap(); }
@ -78,15 +81,15 @@ Session_component::acquire_device(Platform::Session::String const &name)
if (e->object()->device() != name.string()) { continue; }
if (!e->object()->acquire()) {
Genode::error("Device ", e->object()->device(),
error("Device ", e->object()->device(),
" already acquired!");
break;
}
/* account one device capability needed */
_cap_quota_guard().replenish(Genode::Cap_quota{1});
_cap_quota_guard().replenish(Cap_quota{1});
return _env.ep().rpc_ep().manage(e->object());
return _env.env.ep().rpc_ep().manage(e->object());
}
return Platform::Device_capability();
@ -95,28 +98,27 @@ Session_component::acquire_device(Platform::Session::String const &name)
void Session_component::release_device(Platform::Device_capability device_cap)
{
_env.ep().rpc_ep().apply(device_cap, [&] (Device_component * dc) {
_env.ep().rpc_ep().dissolve(dc);
_cap_quota_guard().replenish(Genode::Cap_quota{1});
_env.env.ep().rpc_ep().apply(device_cap, [&] (Device_component * dc) {
_env.env.ep().rpc_ep().dissolve(dc);
_cap_quota_guard().replenish(Cap_quota{1});
dc->release();
});
}
Genode::Ram_dataspace_capability
Session_component::alloc_dma_buffer(Genode::size_t const size)
Session_component::alloc_dma_buffer(size_t const size)
{
Genode::Ram_dataspace_capability ram_cap =
_env_ram.alloc(size, Genode::UNCACHED);
Ram_dataspace_capability ram_cap = _env_ram.alloc(size, UNCACHED);
if (!ram_cap.valid()) return ram_cap;
try {
_buffer_list.insert(new (_md_alloc) Dma_buffer(ram_cap));
} catch (Genode::Out_of_ram) {
} catch (Out_of_ram) {
_env_ram.free(ram_cap);
throw;
} catch (Genode::Out_of_caps) {
} catch (Out_of_caps) {
_env_ram.free(ram_cap);
throw;
}
@ -125,7 +127,7 @@ Session_component::alloc_dma_buffer(Genode::size_t const size)
}
void Session_component::free_dma_buffer(Genode::Ram_dataspace_capability ram_cap)
void Session_component::free_dma_buffer(Ram_dataspace_capability ram_cap)
{
if (!ram_cap.valid()) { return; }
@ -149,7 +151,7 @@ Genode::addr_t Session_component::bus_addr_dma_buffer(Ram_dataspace_capability r
if (buf->cap.local_name() != ram_cap.local_name()) continue;
Genode::Dataspace_client dsc(buf->cap);
Dataspace_client dsc(buf->cap);
return dsc.phys_addr();
}
@ -157,18 +159,15 @@ Genode::addr_t Session_component::bus_addr_dma_buffer(Ram_dataspace_capability r
}
Session_component::Session_component(Genode::Env & env,
Device_model & devices,
Registry & registry,
Session_component::Session_component(Driver::Env & env,
Session_registry & registry,
Label const & label,
Resources const & resources,
Diag const & diag)
: Genode::Session_object<Platform::Session>(env.ep(), resources,
label, diag),
Registry::Element(registry, *this),
Genode::Dynamic_rom_session::Xml_producer("devices"),
_env(env),
_device_model(devices)
: Session_object<Platform::Session>(env.env.ep(), resources, label, diag),
Session_registry::Element(registry, *this),
Dynamic_rom_session::Xml_producer("devices"),
_env(env)
{
/*
* FIXME: As the ROM session does not propagate Out_of_*
@ -179,8 +178,8 @@ Session_component::Session_component(Genode::Env & env,
* we account the costs here until the ROM session interface
* changes.
*/
_cap_quota_guard().withdraw(Genode::Cap_quota{1});
_ram_quota_guard().withdraw(Genode::Ram_quota{5*1024});
_cap_quota_guard().withdraw(Cap_quota{1});
_ram_quota_guard().withdraw(Ram_quota{5*1024});
}
@ -193,6 +192,6 @@ Session_component::~Session_component()
}
/* replenish quota for rom sessions, see constructor for explanation */
_cap_quota_guard().replenish(Genode::Cap_quota{1});
_ram_quota_guard().replenish(Genode::Ram_quota{5*1024});
_cap_quota_guard().replenish(Cap_quota{1});
_ram_quota_guard().replenish(Ram_quota{5*1024});
}

View File

@ -32,79 +32,71 @@ namespace Driver {
class Driver::Session_component :
public Genode::Session_object<Platform::Session>,
private Genode::Registry<Driver::Session_component>::Element,
private Genode::Dynamic_rom_session::Xml_producer
public Session_object<Platform::Session>,
private Registry<Driver::Session_component>::Element,
private Dynamic_rom_session::Xml_producer
{
public:
using Registry = Genode::Registry<Session_component>;
using Session_registry = Registry<Session_component>;
Session_component(Genode::Env & env,
Device_model & devices,
Registry & registry,
Label const & label,
Resources const & resources,
Diag const & diag);
Session_component(Driver::Env & env,
Session_registry & registry,
Label const & label,
Resources const & resources,
Diag const & diag);
~Session_component();
Genode::Heap & heap();
Genode::Env & env();
Device_model & devices();
Heap & heap();
Driver::Env & env();
void add(Device::Name const &);
bool has_device(Device::Name const &) const;
unsigned devices_count() const;
void update_devices_rom();
Genode::Ram_quota_guard &ram_quota_guard() {
return _ram_quota_guard(); }
Genode::Cap_quota_guard &cap_quota_guard() {
return _cap_quota_guard(); }
Ram_quota_guard & ram_quota_guard() { return _ram_quota_guard(); }
Cap_quota_guard & cap_quota_guard() { return _cap_quota_guard(); }
/**************************
** Platform Session API **
**************************/
using Rom_session_capability = Genode::Rom_session_capability;
using Device_capability = Platform::Device_capability;
using Ram_dataspace_capability = Genode::Ram_dataspace_capability;
using String = Platform::Session::String;
using size_t = Genode::size_t;
using Device_capability = Platform::Device_capability;
using String = Platform::Session::String;
Rom_session_capability devices_rom() override;
Device_capability acquire_device(String const &) override;
void release_device(Device_capability) override;
Ram_dataspace_capability alloc_dma_buffer(size_t const) override;
void free_dma_buffer(Ram_dataspace_capability ram_cap) override;
Genode::addr_t bus_addr_dma_buffer(Ram_dataspace_capability) override;
addr_t bus_addr_dma_buffer(Ram_dataspace_capability) override;
private:
friend class Root;
struct Dma_buffer : Genode::List<Dma_buffer>::Element
struct Dma_buffer : List<Dma_buffer>::Element
{
Genode::Ram_dataspace_capability const cap;
Ram_dataspace_capability const cap;
Dma_buffer(Genode::Ram_dataspace_capability const cap)
Dma_buffer(Ram_dataspace_capability const cap)
: cap(cap) {}
};
using Device_list_element = Genode::List_element<Device_component>;
using Device_list = Genode::List<Device_list_element>;
using Device_list_element = List_element<Device_component>;
using Device_list = List<Device_list_element>;
Genode::Env & _env;
Genode::Constrained_ram_allocator _env_ram { _env.pd(),
_ram_quota_guard(),
_cap_quota_guard() };
Genode::Heap _md_alloc { _env_ram, _env.rm() };
Device_list _device_list { };
Genode::List<Dma_buffer> _buffer_list { };
Genode::Dynamic_rom_session _rom_session { _env.ep(), _env.ram(),
_env.rm(), *this };
Device_model & _device_model;
Driver::Env & _env;
Constrained_ram_allocator _env_ram { _env.env.pd(),
_ram_quota_guard(),
_cap_quota_guard() };
Heap _md_alloc { _env_ram, _env.env.rm() };
Device_list _device_list { };
List<Dma_buffer> _buffer_list { };
Dynamic_rom_session _rom_session { _env.env.ep(), _env.env.ram(),
_env.env.rm(), *this };
/*
* Noncopyable
@ -117,7 +109,7 @@ class Driver::Session_component :
** Dynamic_rom_session::Xml_producer API **
*******************************************/
void produce_xml(Genode::Xml_generator &xml) override;
void produce_xml(Xml_generator &xml) override;
};
#endif /* _SRC__DRIVERS__PLATFORM__SPEC__ARM__SESSION_COMPONENT_H_ */