1// Copyright 2018 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 "platform-proxy-device.h"
8
9#include <ddk/protocol/clk.h>
10#include <ddk/protocol/gpio.h>
11#include <ddk/protocol/i2c.h>
12#include <ddktl/device.h>
13#include <ddktl/protocol/platform-device.h>
14#include <fbl/array.h>
15#include <fbl/ref_ptr.h>
16#include <fbl/unique_ptr.h>
17#include <fbl/vector.h>
18#include <lib/zx/channel.h>
19#include <lib/zx/handle.h>
20
21#include "proxy-protocol.h"
22
23namespace platform_bus {
24
25class PlatformProxy;
26class ProxyDevice;
27using ProxyDeviceType = ddk::FullDevice<ProxyDevice>;
28
29class ProxyDevice : public ProxyDeviceType, public ddk::PlatformDevProtocol<ProxyDevice> {
30public:
31    explicit ProxyDevice(zx_device_t* parent, uint32_t device_id, fbl::RefPtr<PlatformProxy> proxy);
32
33    // Creates a ProxyDevice to be the root platform device.
34    static zx_status_t CreateRoot(zx_device_t* parent, fbl::RefPtr<PlatformProxy> proxy);
35
36    // Creates a ProxyDevice to be a child platform device or a proxy client device.
37    static zx_status_t CreateChild(zx_device_t* parent, uint32_t device_id,
38                                   fbl::RefPtr<PlatformProxy> proxy, device_add_args_t* args);
39
40    // Full device protocol implementation.
41    // For child devices, these call through to the device protocol passed via pdev_device_add().
42    zx_status_t DdkGetProtocol(uint32_t proto_id, void* out);
43    zx_status_t DdkOpen(zx_device_t** dev_out, uint32_t flags);
44    zx_status_t DdkOpenAt(zx_device_t** dev_out, const char* path, uint32_t flags);
45    zx_status_t DdkClose(uint32_t flags);
46    void DdkUnbind();
47    void DdkRelease();
48    zx_status_t DdkRead(void* buf, size_t count, zx_off_t off, size_t* actual);
49    zx_status_t DdkWrite(const void* buf, size_t count, zx_off_t off, size_t* actual);
50    zx_off_t DdkGetSize();
51    zx_status_t DdkIoctl(uint32_t op, const void* in_buf, size_t in_len, void* out_buf,
52                         size_t out_len, size_t* actual);
53    zx_status_t DdkSuspend(uint32_t flags);
54    zx_status_t DdkResume(uint32_t flags);
55    zx_status_t DdkRxrpc(zx_handle_t channel);
56
57    // Platform device protocol implementation.
58    zx_status_t GetMmio(uint32_t index, pdev_mmio_t* out_mmio);
59    zx_status_t MapMmio(uint32_t index, uint32_t cache_policy, void** out_vaddr, size_t* out_size,
60                        zx_paddr_t* out_paddr, zx_handle_t* out_handle);
61    zx_status_t MapInterrupt(uint32_t index, uint32_t flags, zx_handle_t* out_handle);
62    zx_status_t GetBti(uint32_t index, zx_handle_t* out_handle);
63    zx_status_t GetDeviceInfo(pdev_device_info_t* out_info);
64    zx_status_t GetBoardInfo(pdev_board_info_t* out_info);
65    zx_status_t DeviceAdd(uint32_t index, device_add_args_t* args, zx_device_t** out);
66    zx_status_t GetProtocol(uint32_t proto_id, uint32_t index, void* out_protocol);
67
68    // Clock protocol implementation.
69    static zx_status_t ClkEnable(void* ctx, uint32_t index);
70    static zx_status_t ClkDisable(void* ctx, uint32_t index);
71
72    // GPIO protocol implementation.
73    static zx_status_t GpioConfigIn(void* ctx, uint32_t flags);
74    static zx_status_t GpioConfigOut(void* ctx, uint8_t initial_value);
75    static zx_status_t GpioSetAltFunction(void* ctx, uint64_t function);
76    static zx_status_t GpioRead(void* ctx, uint8_t* out_value);
77    static zx_status_t GpioWrite(void* ctx, uint8_t value);
78    static zx_status_t GpioGetInterrupt(void* ctx, uint32_t flags,
79                                        zx_handle_t* out_handle);
80    static zx_status_t GpioReleaseInterrupt(void* ctx);
81    static zx_status_t GpioSetPolarity(void* ctx, uint32_t polarity);
82
83    // I2C protocol implementation.
84    static zx_status_t I2cTransact(void* ctx, i2c_op_t* ops, size_t cnt,
85                                   i2c_transact_cb transact_cb, void* cookie);
86    static zx_status_t I2cGetMaxTransferSize(void* ctx, size_t* out_size);
87    static zx_status_t I2cGetInterrupt(void* ctx, uint32_t flags, zx_handle_t* out_handle);
88
89private:
90    struct Mmio {
91        zx_paddr_t base;
92        size_t length;
93        zx::handle resource;
94    };
95    struct Irq {
96        uint32_t irq;
97        // ZX_INTERRUPT_MODE_* flags
98        uint32_t mode;
99        zx::handle resource;
100    };
101    struct GpioCtx {
102        ProxyDevice* thiz;
103        uint32_t index;
104    };
105    struct I2cCtx {
106        ProxyDevice* thiz;
107        uint32_t index;
108    };
109
110    zx_status_t InitCommon();
111    zx_status_t InitRoot();
112    zx_status_t InitChild(device_add_args_t* args);
113
114    DISALLOW_COPY_ASSIGN_AND_MOVE(ProxyDevice);
115
116    const uint32_t device_id_;
117    fbl::RefPtr<PlatformProxy> proxy_;
118    fbl::Vector<Mmio> mmios_;
119    fbl::Vector<Irq> irqs_;
120    char name_[ZX_MAX_NAME_LEN];
121    uint32_t metadata_count_;
122
123    // We can't used ddktl for these because ddktl only allows a device to implement one protocol,
124    // and we are using ddktl for the platform device protocol.
125    clk_protocol_ops_t clk_proto_ops_;
126    gpio_protocol_ops_t gpio_proto_ops_;
127    i2c_protocol_ops_t i2c_proto_ops_;
128
129    // Contexts
130    fbl::Array<GpioCtx> gpio_ctxs_;
131    fbl::Array<I2cCtx> i2c_ctxs_;
132
133    // These fields are saved values from the device_add_args_t passed to pdev_device_add().
134    // These are unused for top level devices created via pbus_device_add().
135    void* ctx_ = nullptr;
136    zx_protocol_device_t* device_ops_ = nullptr;
137    uint32_t proto_id_ = 0;
138    void* proto_ops_ = nullptr;
139};
140
141} // namespace platform_bus
142