blob: c7ee308d7f4f0dc65a0028365f999e3d59cb91f0 [file] [log] [blame]
// Copyright 2017 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.
#pragma once
#include <ddk/device.h>
#include <ddktl/device.h>
#include <ddktl/protocol/amlogiccanvas.h>
#include <ddktl/protocol/clock.h>
#include <ddktl/protocol/gpioimpl.h>
#include <ddktl/protocol/powerimpl.h>
#include <ddktl/protocol/i2cimpl.h>
#include <ddktl/protocol/iommu.h>
#include <ddktl/protocol/platform/bus.h>
#include <ddktl/protocol/sysmem.h>
#include <fbl/array.h>
#include <fbl/intrusive_wavl_tree.h>
#include <fbl/mutex.h>
#include <fbl/unique_ptr.h>
#include <fbl/vector.h>
#include <lib/sync/completion.h>
#include <lib/zx/iommu.h>
#include <lib/zx/resource.h>
#include <lib/zx/vmo.h>
#include <stdint.h>
#include <threads.h>
#include <zircon/types.h>
#include <optional>
#include "platform-device.h"
#include "platform-protocol-device.h"
#include "platform-i2c.h"
#include "proxy-protocol.h"
namespace platform_bus {
class PlatformBus;
using PlatformBusType = ddk::Device<PlatformBus, ddk::GetProtocolable>;
// This is the main class for the platform bus driver.
class PlatformBus : public PlatformBusType,
public ddk::PBusProtocol<PlatformBus, ddk::base_protocol>,
public ddk::IommuProtocol<PlatformBus> {
public:
static zx_status_t Create(zx_device_t* parent, const char* name, zx::vmo zbi);
zx_status_t Proxy(
const void* req_buffer, size_t req_size, const zx_handle_t* req_handle_list,
size_t req_handle_count, void* out_resp_buffer, size_t resp_size, size_t* out_resp_actual,
zx_handle_t* out_resp_handle_list, size_t resp_handle_count,
size_t* out_resp_handle_actual);
// Device protocol implementation.
zx_status_t DdkGetProtocol(uint32_t proto_id, void* out);
void DdkRelease();
// Platform bus protocol implementation.
zx_status_t PBusDeviceAdd(const pbus_dev_t* dev);
zx_status_t PBusProtocolDeviceAdd(uint32_t proto_id, const pbus_dev_t* dev);
zx_status_t PBusRegisterProtocol(uint32_t proto_id, const void* protocol, size_t protocol_size,
const platform_proxy_cb_t* proxy_cb);
zx_status_t PBusGetBoardInfo(pdev_board_info_t* out_info);
zx_status_t PBusSetBoardInfo(const pbus_board_info_t* info);
zx_status_t PBusRegisterSysSuspendCallback(const pbus_sys_suspend_t* suspend_cbin);
// IOMMU protocol implementation.
zx_status_t IommuGetBti(uint32_t iommu_index, uint32_t bti_id, zx::bti* out_bti);
// Returns the resource handle to be used for creating MMIO regions, IRQs, and SMC ranges.
// Currently this just returns the root resource, but we may change this to a more
// limited resource in the future.
zx::unowned_resource GetResource() const { return zx::unowned_resource(get_root_resource()); }
// Used by PlatformDevice to queue I2C transactions on an I2C bus.
zx_status_t I2cTransact(uint32_t txid, rpc_i2c_req_t* req, const pbus_i2c_channel_t* channel,
zx_handle_t channel_handle);
zx_status_t GetZbiMetadata(uint32_t type, uint32_t extra, const void** out_metadata,
uint32_t* out_size);
// Protocol accessors for PlatformDevice.
inline ddk::AmlogicCanvasProtocolClient* canvas() { return &*canvas_; }
inline ddk::ClockProtocolClient* clk() { return &*clk_; }
inline ddk::GpioImplProtocolClient* gpio() { return &*gpio_; }
inline ddk::I2cImplProtocolClient* i2c() { return &*i2c_; }
inline ddk::PowerImplProtocolClient* power() { return &*power_; }
inline ddk::SysmemProtocolClient* sysmem() { return &*sysmem_; }
pbus_sys_suspend_t suspend_cb() { return suspend_cb_; }
private:
pbus_sys_suspend_t suspend_cb_ = {};
// This class is a wrapper for a platform_proxy_cb_t added via pbus_register_protocol().
// It also is the element type for the proto_proxys_ WAVL tree.
class ProtoProxy : public fbl::WAVLTreeContainable<fbl::unique_ptr<ProtoProxy>> {
public:
ProtoProxy(uint32_t proto_id, const ddk::AnyProtocol* protocol,
const platform_proxy_cb_t& proxy_cb)
: proto_id_(proto_id), protocol_(*protocol), proxy_cb_(proxy_cb) {}
inline uint32_t GetKey() const { return proto_id_; }
inline void GetProtocol(void* out) const { memcpy(out, &protocol_, sizeof(protocol_)); }
inline void Proxy(const void* req_buffer, size_t req_size,
const zx_handle_t* req_handle_list, size_t req_handle_count,
void* out_resp_buffer, size_t resp_size, size_t* out_resp_actual,
zx_handle_t* out_resp_handle_list, size_t resp_handle_count,
size_t* out_resp_handle_actual) {
proxy_cb_.callback(proxy_cb_.ctx, req_buffer, req_size,
req_handle_list, req_handle_count,
out_resp_buffer, resp_size, out_resp_actual,
out_resp_handle_list, resp_handle_count,
out_resp_handle_actual);
}
private:
const uint32_t proto_id_;
const ddk::AnyProtocol protocol_;
platform_proxy_cb_t proxy_cb_;
};
explicit PlatformBus(zx_device_t* parent);
DISALLOW_COPY_ASSIGN_AND_MOVE(PlatformBus);
zx_status_t Init(zx::vmo zbi);
// Reads the platform ID and driver metadata records from the boot image.
zx_status_t ReadZbi(zx::vmo zbi);
zx_status_t I2cInit(const i2c_impl_protocol_t* i2c);
pdev_board_info_t board_info_;
// Protocols that are optionally provided by the board driver.
std::optional<ddk::AmlogicCanvasProtocolClient> canvas_;
std::optional<ddk::ClockProtocolClient> clk_;
std::optional<ddk::GpioImplProtocolClient> gpio_;
std::optional<ddk::IommuProtocolClient> iommu_;
std::optional<ddk::I2cImplProtocolClient> i2c_;
std::optional<ddk::PowerImplProtocolClient> power_;
std::optional<ddk::SysmemProtocolClient> sysmem_;
// Completion used by WaitProtocol().
sync_completion_t proto_completion_ __TA_GUARDED(proto_completion_mutex_);
// Protects proto_completion_.
fbl::Mutex proto_completion_mutex_;
// Metadata extracted from ZBI.
fbl::Array<uint8_t> metadata_;
// List of I2C buses.
fbl::Vector<fbl::unique_ptr<PlatformI2cBus>> i2c_buses_;
// Dummy IOMMU.
zx::iommu iommu_handle_;
fbl::WAVLTree<uint32_t, fbl::unique_ptr<ProtoProxy>> proto_proxys_
__TA_GUARDED(proto_proxys_mutex_);
// Protects proto_proxys_.
fbl::Mutex proto_proxys_mutex_;
};
} // namespace platform_bus
__BEGIN_CDECLS
zx_status_t platform_bus_create(void* ctx, zx_device_t* parent, const char* name,
const char* args, zx_handle_t rpc_channel);
__END_CDECLS