mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-08 03:45:24 +00:00
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:
parent
70f98fcc44
commit
224f5907b2
@ -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}, [&] () {
|
||||
|
@ -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() { }
|
||||
|
||||
|
1
repos/os/include/spec/arm_64/platform_device/client.h
Normal file
1
repos/os/include/spec/arm_64/platform_device/client.h
Normal file
@ -0,0 +1 @@
|
||||
#include <spec/arm/platform_device/client.h>
|
@ -0,0 +1 @@
|
||||
#include <spec/arm/platform_device/platform_device.h>
|
1
repos/os/include/spec/arm_64/platform_session/client.h
Normal file
1
repos/os/include/spec/arm_64/platform_session/client.h
Normal file
@ -0,0 +1 @@
|
||||
#include <spec/arm/platform_session/client.h>
|
@ -0,0 +1 @@
|
||||
#include <spec/arm/platform_session/connection.h>
|
@ -0,0 +1 @@
|
||||
#include <spec/arm/platform_session/platform_session.h>
|
@ -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 \
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
420
repos/os/src/drivers/platform/imx8mq/ccm.cc
Normal file
420
repos/os/src/drivers/platform/imx8mq/ccm.cc
Normal 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);
|
||||
}
|
424
repos/os/src/drivers/platform/imx8mq/ccm.h
Normal file
424
repos/os/src/drivers/platform/imx8mq/ccm.h
Normal 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 };
|
||||
};
|
120
repos/os/src/drivers/platform/imx8mq/clock.h
Normal file
120
repos/os/src/drivers/platform/imx8mq/clock.h
Normal 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; }
|
||||
};
|
90
repos/os/src/drivers/platform/imx8mq/device_model_policy.cc
Normal file
90
repos/os/src/drivers/platform/imx8mq/device_model_policy.cc
Normal 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);
|
||||
}
|
||||
}
|
45
repos/os/src/drivers/platform/imx8mq/env.h
Normal file
45
repos/os/src/drivers/platform/imx8mq/env.h
Normal 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_ */
|
103
repos/os/src/drivers/platform/imx8mq/gpc.h
Normal file
103
repos/os/src/drivers/platform/imx8mq/gpc.h
Normal 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;
|
||||
}
|
||||
};
|
||||
};
|
76
repos/os/src/drivers/platform/imx8mq/imx_device.cc
Normal file
76
repos/os/src/drivers/platform/imx8mq/imx_device.cc
Normal 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);
|
||||
});
|
||||
});
|
||||
}
|
140
repos/os/src/drivers/platform/imx8mq/imx_device.h
Normal file
140
repos/os/src/drivers/platform/imx8mq/imx_device.h
Normal 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_ */
|
15
repos/os/src/drivers/platform/imx8mq/target.mk
Normal file
15
repos/os/src/drivers/platform/imx8mq/target.mk
Normal 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
|
@ -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); }
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
@ -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); }});
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"); }
|
||||
|
41
repos/os/src/drivers/platform/spec/arm/env.h
Normal file
41
repos/os/src/drivers/platform/spec/arm/env.h
Normal 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_ */
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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) { }
|
||||
|
@ -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_ */
|
||||
|
@ -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});
|
||||
}
|
||||
|
@ -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_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user