From 7f6f710bd2a48cd424ccbf1bee598494d71fc969 Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Tue, 25 May 2021 14:19:37 +0200 Subject: [PATCH] imx8mq_platform_drv: introduce reset domains A reset domain can consist of one or several reset-pins denoted by name that are assigned to a device. When the device gets acquired via the Platform RPC API, the pins are de-asserted, and asserted again when the device gets released. A configuration looks like the following: ... Fixes #4171 --- .../platform/imx8mq/device_model_policy.cc | 10 ++++ repos/os/src/drivers/platform/imx8mq/env.h | 2 + .../src/drivers/platform/imx8mq/imx_device.cc | 4 ++ .../src/drivers/platform/imx8mq/imx_device.h | 42 ++++++++++++++ repos/os/src/drivers/platform/imx8mq/src.h | 58 +++++++++++++++++++ 5 files changed, 116 insertions(+) create mode 100644 repos/os/src/drivers/platform/imx8mq/src.h diff --git a/repos/os/src/drivers/platform/imx8mq/device_model_policy.cc b/repos/os/src/drivers/platform/imx8mq/device_model_policy.cc index 900ef59e88..d8dc8d5f59 100644 --- a/repos/os/src/drivers/platform/imx8mq/device_model_policy.cc +++ b/repos/os/src/drivers/platform/imx8mq/device_model_policy.cc @@ -47,6 +47,11 @@ void Device_model::destroy_element(Device & dev) device._power_domain_list.destroy_all_elements(policy); } + { + Reset_domain_update_policy policy(_env.heap); + device._reset_domain_list.destroy_all_elements(policy); + } + Genode::destroy(_env.heap, &device); } @@ -88,4 +93,9 @@ void Device_model::update_element(Device & dev, Power_domain_update_policy policy(_env.heap); device._power_domain_list.update_from_xml(policy, node); } + + { + Reset_domain_update_policy policy(_env.heap); + device._reset_domain_list.update_from_xml(policy, node); + } } diff --git a/repos/os/src/drivers/platform/imx8mq/env.h b/repos/os/src/drivers/platform/imx8mq/env.h index 0e59716ada..b345048c1c 100644 --- a/repos/os/src/drivers/platform/imx8mq/env.h +++ b/repos/os/src/drivers/platform/imx8mq/env.h @@ -20,6 +20,7 @@ #include #include +#include #include namespace Driver { @@ -37,6 +38,7 @@ struct Driver::Env Attached_rom_dataspace config { env, "config" }; Ccm ccm { env }; Gpc gpc { env }; + Src src { env }; Device_model devices { *this }; Env(Genode::Env &env) : env(env) { } diff --git a/repos/os/src/drivers/platform/imx8mq/imx_device.cc b/repos/os/src/drivers/platform/imx8mq/imx_device.cc index adaebebf87..cee01649fe 100644 --- a/repos/os/src/drivers/platform/imx8mq/imx_device.cc +++ b/repos/os/src/drivers/platform/imx8mq/imx_device.cc @@ -23,6 +23,8 @@ bool Driver::Imx_device::acquire(Driver::Session_component & sc) if (ret) { _power_domain_list.for_each([&] (Power_domain & p) { sc.env().gpc.enable(p.name); }); + _reset_domain_list.for_each([&] (Reset_domain & r) { + sc.env().src.enable(r.name); }); _clock_list.for_each([&] (Clock & c) { Avl_string_base * asb = sc.env().ccm.tree.first()->find_by_name(c.name.string()); @@ -46,6 +48,8 @@ bool Driver::Imx_device::acquire(Driver::Session_component & sc) void Driver::Imx_device::release(Session_component & sc) { + _reset_domain_list.for_each([&] (Reset_domain & r) { + sc.env().src.disable(r.name); }); _power_domain_list.for_each([&] (Power_domain & p) { sc.env().gpc.disable(p.name); }); _clock_list.for_each([&] (Clock & c) { diff --git a/repos/os/src/drivers/platform/imx8mq/imx_device.h b/repos/os/src/drivers/platform/imx8mq/imx_device.h index 0c60225aef..6e2debfeff 100644 --- a/repos/os/src/drivers/platform/imx8mq/imx_device.h +++ b/repos/os/src/drivers/platform/imx8mq/imx_device.h @@ -22,6 +22,7 @@ namespace Driver { class Imx_device; struct Clock_update_policy; struct Power_domain_update_policy; + struct Reset_domain_update_policy; } @@ -55,6 +56,15 @@ class Driver::Imx_device : public Driver::Device Power_domain(Name name) : name(name) {} }; + struct Reset_domain : List_model::Element + { + using Name = Genode::String<64>; + + Name name; + + Reset_domain(Name name) : name(name) {} + }; + bool acquire(Session_component &) override; void release(Session_component &) override; @@ -71,6 +81,7 @@ class Driver::Imx_device : public Driver::Device List_model _clock_list {}; List_model _power_domain_list {}; + List_model _reset_domain_list {}; }; @@ -138,4 +149,35 @@ struct Driver::Power_domain_update_policy } }; + +struct Driver::Reset_domain_update_policy +: Genode::List_model::Update_policy +{ + Genode::Allocator & alloc; + + Reset_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("reset-domain"); + } +}; + #endif /* _SRC__DRIVERS__PLATFORM__IMX8MQ__IMX_DEVICE_H_ */ diff --git a/repos/os/src/drivers/platform/imx8mq/src.h b/repos/os/src/drivers/platform/imx8mq/src.h new file mode 100644 index 0000000000..abca921128 --- /dev/null +++ b/repos/os/src/drivers/platform/imx8mq/src.h @@ -0,0 +1,58 @@ +/* + * \brief System reset controller for i.MX8 + * \author Stefan Kalkowski + * \date 2021-05-21 + */ + +/* + * Copyright (C) 2021 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 +#include +#include +#include + +struct Src : Genode::Attached_mmio +{ + struct Mipi_phy : Register<0x28, 32> + { + struct Byte : Bitfield<1, 1> {}; + struct Reset : Bitfield<2, 1> {}; + struct Dpi : Bitfield<3, 1> {}; + struct Esc : Bitfield<4, 1> {}; + struct Pclk : Bitfield<5, 1> {}; + }; + + void enable(Genode::String<64> name) + { + if (name == "mipi_dsi_byte") { write(1); return; } + if (name == "mipi_dsi_dpi") { write(1); return; } + if (name == "mipi_dsi_esc") { write(1); return; } + if (name == "mipi_dsi_pclk") { write(1); return; } + warning("Reset domain ", name, " is unknown!"); + } + + void disable(Genode::String<64> name) + { + if (name == "mipi_dsi_byte") { write(0); return; } + if (name == "mipi_dsi_dpi") { write(0); return; } + if (name == "mipi_dsi_esc") { write(0); return; } + if (name == "mipi_dsi_pclk") { write(0); return; } + warning("Reset domain ", name, " is unknown!"); + } + + enum { + SRC_MMIO_BASE = 0x30390000, + SRC_MMIO_SIZE = 0x10000, + }; + + Src(Genode::Env & env) + : Attached_mmio(env, SRC_MMIO_BASE, SRC_MMIO_SIZE) { }; +}; +