blob: cc805fb3d0b61973dc0e77dcb412fb1774bfd0e6 [file] [log] [blame]
// Copyright 2023 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIB_DRIVER_DEVICETREE_MANAGER_NODE_H_
#define LIB_DRIVER_DEVICETREE_MANAGER_NODE_H_
#include <fidl/fuchsia.driver.framework/cpp/fidl.h>
#include <fidl/fuchsia.hardware.platform.bus/cpp/driver/fidl.h>
#include <fidl/fuchsia.hardware.power/cpp/fidl.h>
#include <lib/devicetree/devicetree.h>
#include <lib/zx/result.h>
#include <zircon/errors.h>
#include <cstdint>
#include <optional>
#include <string_view>
#include <unordered_map>
#include <utility>
#include <vector>
namespace fdf_devicetree {
using Phandle = uint32_t;
using NodeID = uint32_t;
class Visitor;
class ReferenceNode;
class ParentNode;
class ChildNode;
// Helper to select return type for GetProperty.
template <typename T>
struct GetPropertyReturn {
using type = zx::result<T>;
};
template <>
struct GetPropertyReturn<bool> {
using type = bool;
};
// Represents who provides the `reg` property for this node. This information will be set and used
// by the visitors. By default `reg` property of all nodes are considered mmio.
enum class RegisterType : uint8_t {
kMmio, // Default. Parsed by the mmio visitor.
kI2c, // Register used to represent i2c device address.
kSpi, // Register used to represent spi device address.
kSpmi, // Register used to represent spmi target id and device registers (sub target id).
};
// Defines interface that an entity managing the Node should implement.
class NodeManager {
public:
// Returns node with phandle |id|.
virtual zx::result<ReferenceNode> GetReferenceNode(Phandle id) = 0;
virtual uint32_t GetPublishIndex(uint32_t node_id) = 0;
virtual zx::result<> ChangePublishOrder(uint32_t node_id, uint32_t new_index) = 0;
virtual ~NodeManager();
};
// Node represents the nodes in the device tree along with it's properties.
class Node {
public:
explicit Node(Node* parent, std::string_view name, devicetree::Properties properties, uint32_t id,
NodeManager* manager);
// Add |prop| as a bind property of the device, when it is eventually published.
void AddBindProperty(fuchsia_driver_framework::NodeProperty2 prop);
void AddMmio(fuchsia_hardware_platform_bus::Mmio mmio);
void AddBti(fuchsia_hardware_platform_bus::Bti bti);
void AddIrq(fuchsia_hardware_platform_bus::Irq irq);
void AddMetadata(fuchsia_hardware_platform_bus::Metadata metadata);
void AddBootMetadata(fuchsia_hardware_platform_bus::BootMetadata boot_metadata);
void AddNodeSpec(const fuchsia_driver_framework::ParentSpec2& spec);
void AddSmc(fuchsia_hardware_platform_bus::Smc smc);
void AddPowerConfig(fuchsia_hardware_power::PowerElementConfiguration config);
// Returns the index of the node in the nodes publish list.
uint32_t GetPublishIndex() const;
// Move this node up/down in the publish list.
// Returns error if the index is out of range.
zx::result<> ChangePublishOrder(uint32_t new_index);
// Publish this node.
// TODO(https://fxbug.dev/42059490): Switch to fdf::SyncClient when it's available.
zx::result<> Publish(fdf::WireSyncClient<fuchsia_hardware_platform_bus::PlatformBus>& pbus,
fidl::SyncClient<fuchsia_driver_framework::CompositeNodeManager>& mgr,
fidl::SyncClient<fuchsia_driver_framework::Node>& fdf_node);
const std::string& name() const { return name_; }
const std::string& fdf_name() const { return fdf_name_; }
ParentNode parent() const;
std::vector<ChildNode> children();
const std::unordered_map<std::string_view, devicetree::PropertyValue>& properties() const {
return properties_;
}
template <typename T>
typename GetPropertyReturn<T>::type GetProperty(std::string_view property_name) const;
zx::result<ReferenceNode> GetReferenceNode(Phandle parent);
std::optional<Phandle> phandle() const { return phandle_; }
NodeID id() const { return id_; }
RegisterType register_type() const { return register_type_; }
void set_register_type(RegisterType type) { register_type_ = type; }
private:
Node* parent_;
std::string name_;
std::string fdf_name_;
std::unordered_map<std::string_view, devicetree::PropertyValue> properties_;
std::optional<Phandle> phandle_;
std::vector<Node*> children_;
// Platform bus node.
fuchsia_hardware_platform_bus::Node pbus_node_;
// Properties of the nodes after they have been transformed in the device group.
std::vector<fuchsia_driver_framework::NodeProperty2> node_properties_;
// Parent specifications.
std::vector<fuchsia_driver_framework::ParentSpec2> parents_;
// This is a unique ID we use to match our device group with the correct
// platform bus node. It is generated at runtime and not stable across boots.
NodeID id_;
// Boolean to indicate if a composite node spec needs to added.
bool composite_ = false;
// Boolean to indicate if a platform device needs to added.
bool add_platform_device_ = false;
// Storing handle to manager. This is ok as the manager always outlives the node instance.
NodeManager* manager_;
// Valid only when a non platform bus node is published.
fidl::SyncClient<fuchsia_driver_framework::NodeController> node_controller_;
RegisterType register_type_ = RegisterType::kMmio;
};
class ReferenceNode {
public:
explicit ReferenceNode(Node* node) : node_(node) {}
const std::unordered_map<std::string_view, devicetree::PropertyValue>& properties() const {
return node_->properties();
}
template <typename T>
typename GetPropertyReturn<T>::type GetProperty(std::string_view property_name) {
return node_->GetProperty<T>(property_name);
}
const std::string& name() const { return node_->name(); }
const std::string& fdf_name() const { return node_->fdf_name(); }
uint32_t id() const { return node_->id(); }
std::optional<Phandle> phandle() const { return node_->phandle(); }
Node* GetNode() const { return node_; }
ParentNode parent() const;
explicit operator bool() const { return (node_ != nullptr); }
private:
Node* node_;
};
class ParentNode {
public:
explicit ParentNode(Node* node) : node_(node) {}
const std::string& name() const { return node_->name(); }
const std::string& fdf_name() const { return node_->fdf_name(); }
uint32_t id() const { return node_->id(); }
explicit operator bool() const { return (node_ != nullptr); }
const std::unordered_map<std::string_view, devicetree::PropertyValue>& properties() const {
return node_->properties();
}
template <typename T>
typename GetPropertyReturn<T>::type GetProperty(std::string_view property_name) {
return node_->GetProperty<T>(property_name);
}
Node* GetNode() const { return node_; }
ParentNode parent() const { return node_->parent(); }
ReferenceNode MakeReferenceNode() const { return ReferenceNode(node_); }
private:
Node* node_;
};
class ChildNode {
public:
explicit ChildNode(Node* node) : node_(node) {}
const std::string& name() const { return node_->name(); }
const std::string& fdf_name() const { return node_->fdf_name(); }
uint32_t id() const { return node_->id(); }
explicit operator bool() const { return (node_ != nullptr); }
const std::unordered_map<std::string_view, devicetree::PropertyValue>& properties() const {
return node_->properties();
}
template <typename T>
typename GetPropertyReturn<T>::type GetProperty(std::string_view property_name) const {
return node_->GetProperty<T>(property_name);
}
Node* GetNode() const { return node_; }
void AddNodeSpec(const fuchsia_driver_framework::ParentSpec2& spec) { node_->AddNodeSpec(spec); }
void set_register_type(RegisterType type) { node_->set_register_type(type); }
RegisterType register_type() const { return node_->register_type(); }
private:
Node* node_;
};
} // namespace fdf_devicetree
#endif // LIB_DRIVER_DEVICETREE_MANAGER_NODE_H_