1 // Copyright 2017 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #pragma once 6 7 #include <ddk/device.h> 8 #include <ddktl/device.h> 9 #include <ddktl/protocol/clk.h> 10 #include <ddktl/protocol/gpioimpl.h> 11 #include <ddktl/protocol/i2cimpl.h> 12 #include <ddktl/protocol/iommu.h> 13 #include <ddktl/protocol/platform/bus.h> 14 #include <fbl/array.h> 15 #include <fbl/intrusive_wavl_tree.h> 16 #include <fbl/mutex.h> 17 #include <fbl/unique_ptr.h> 18 #include <fbl/vector.h> 19 #include <lib/sync/completion.h> 20 #include <lib/zx/iommu.h> 21 #include <lib/zx/resource.h> 22 #include <lib/zx/vmo.h> 23 #include <stdint.h> 24 #include <threads.h> 25 #include <zircon/types.h> 26 27 #include <optional> 28 29 #include "platform-device.h" 30 #include "platform-protocol-device.h" 31 #include "platform-i2c.h" 32 #include "proxy-protocol.h" 33 34 namespace platform_bus { 35 36 class PlatformBus; 37 using PlatformBusType = ddk::Device<PlatformBus, ddk::GetProtocolable>; 38 39 // This is the main class for the platform bus driver. 40 class PlatformBus : public PlatformBusType, 41 public ddk::PBusProtocol<PlatformBus, ddk::base_protocol>, 42 public ddk::IommuProtocol<PlatformBus> { 43 public: 44 static zx_status_t Create(zx_device_t* parent, const char* name, zx::vmo zbi); 45 46 zx_status_t Proxy( 47 const void* req_buffer, size_t req_size, const zx_handle_t* req_handle_list, 48 size_t req_handle_count, void* out_resp_buffer, size_t resp_size, size_t* out_resp_actual, 49 zx_handle_t* out_resp_handle_list, size_t resp_handle_count, 50 size_t* out_resp_handle_actual); 51 52 // Device protocol implementation. 53 zx_status_t DdkGetProtocol(uint32_t proto_id, void* out); 54 void DdkRelease(); 55 56 // Platform bus protocol implementation. 57 zx_status_t PBusDeviceAdd(const pbus_dev_t* dev); 58 zx_status_t PBusProtocolDeviceAdd(uint32_t proto_id, const pbus_dev_t* dev); 59 zx_status_t PBusRegisterProtocol(uint32_t proto_id, const void* protocol, size_t protocol_size, 60 const platform_proxy_cb_t* proxy_cb); 61 zx_status_t PBusGetBoardInfo(pdev_board_info_t* out_info); 62 zx_status_t PBusSetBoardInfo(const pbus_board_info_t* info); 63 64 // IOMMU protocol implementation. 65 zx_status_t IommuGetBti(uint32_t iommu_index, uint32_t bti_id, zx::bti* out_bti); 66 67 // Returns the resource handle to be used for creating MMIO regions, IRQs, and SMC ranges. 68 // Currently this just returns the root resource, but we may change this to a more 69 // limited resource in the future. GetResource()70 zx::unowned_resource GetResource() const { return zx::unowned_resource(get_root_resource()); } 71 72 // Used by PlatformDevice to queue I2C transactions on an I2C bus. 73 zx_status_t I2cTransact(uint32_t txid, rpc_i2c_req_t* req, const pbus_i2c_channel_t* channel, 74 zx_handle_t channel_handle); 75 76 zx_status_t GetZbiMetadata(uint32_t type, uint32_t extra, const void** out_metadata, 77 uint32_t* out_size); 78 79 // Protocol accessors for PlatformDevice. clk()80 inline ddk::ClkProtocolClient* clk() { return &*clk_; } gpio()81 inline ddk::GpioImplProtocolClient* gpio() { return &*gpio_; } i2c()82 inline ddk::I2cImplProtocolClient* i2c() { return &*i2c_; } 83 84 private: 85 // This class is a wrapper for a platform_proxy_cb_t added via pbus_register_protocol(). 86 // It also is the element type for the proto_proxys_ WAVL tree. 87 class ProtoProxy : public fbl::WAVLTreeContainable<fbl::unique_ptr<ProtoProxy>> { 88 public: ProtoProxy(uint32_t proto_id,const ddk::AnyProtocol * protocol,const platform_proxy_cb_t & proxy_cb)89 ProtoProxy(uint32_t proto_id, const ddk::AnyProtocol* protocol, 90 const platform_proxy_cb_t& proxy_cb) 91 : proto_id_(proto_id), protocol_(*protocol), proxy_cb_(proxy_cb) {} 92 GetKey()93 inline uint32_t GetKey() const { return proto_id_; } GetProtocol(void * out)94 inline void GetProtocol(void* out) const { memcpy(out, &protocol_, sizeof(protocol_)); } 95 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)96 inline void Proxy(const void* req_buffer, size_t req_size, 97 const zx_handle_t* req_handle_list, size_t req_handle_count, 98 void* out_resp_buffer, size_t resp_size, size_t* out_resp_actual, 99 zx_handle_t* out_resp_handle_list, size_t resp_handle_count, 100 size_t* out_resp_handle_actual) { 101 proxy_cb_.callback(proxy_cb_.ctx, req_buffer, req_size, 102 req_handle_list, req_handle_count, 103 out_resp_buffer, resp_size, out_resp_actual, 104 out_resp_handle_list, resp_handle_count, 105 out_resp_handle_actual); 106 } 107 108 private: 109 const uint32_t proto_id_; 110 const ddk::AnyProtocol protocol_; 111 platform_proxy_cb_t proxy_cb_; 112 }; 113 114 115 explicit PlatformBus(zx_device_t* parent); 116 117 DISALLOW_COPY_ASSIGN_AND_MOVE(PlatformBus); 118 119 zx_status_t Init(zx::vmo zbi); 120 121 // Reads the platform ID and driver metadata records from the boot image. 122 zx_status_t ReadZbi(zx::vmo zbi); 123 124 zx_status_t I2cInit(const i2c_impl_protocol_t* i2c); 125 126 pdev_board_info_t board_info_; 127 128 // Protocols that are optionally provided by the board driver. 129 std::optional<ddk::ClkProtocolClient> clk_; 130 std::optional<ddk::GpioImplProtocolClient> gpio_; 131 std::optional<ddk::IommuProtocolClient> iommu_; 132 std::optional<ddk::I2cImplProtocolClient> i2c_; 133 134 // Completion used by WaitProtocol(). 135 sync_completion_t proto_completion_ __TA_GUARDED(proto_completion_mutex_); 136 // Protects proto_completion_. 137 fbl::Mutex proto_completion_mutex_; 138 139 // Metadata extracted from ZBI. 140 fbl::Array<uint8_t> metadata_; 141 142 // List of I2C buses. 143 fbl::Vector<fbl::unique_ptr<PlatformI2cBus>> i2c_buses_; 144 145 // Dummy IOMMU. 146 zx::iommu iommu_handle_; 147 148 fbl::WAVLTree<uint32_t, fbl::unique_ptr<ProtoProxy>> proto_proxys_ 149 __TA_GUARDED(proto_proxys_mutex_); 150 // Protects proto_proxys_. 151 fbl::Mutex proto_proxys_mutex_; 152 }; 153 154 } // namespace platform_bus 155 156 __BEGIN_CDECLS 157 zx_status_t platform_bus_create(void* ctx, zx_device_t* parent, const char* name, 158 const char* args, zx_handle_t rpc_channel); 159 __END_CDECLS 160