blob: 373e2b7cc3f6e55e077a0e78047e22ba8c3baad2 [file] [log] [blame]
// Copyright 2018 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 <ddktl/device.h>
#include <ddk/protocol/canvas.h>
#include <ddk/protocol/scpi.h>
#include <ddk/protocol/usb-mode-switch.h>
#include <ddktl/protocol/platform-bus.h>
#include <ddktl/protocol/platform-device.h>
#include <fbl/unique_ptr.h>
#include <fbl/vector.h>
#include "proxy-protocol.h"
// An overview of PlatformDevice and PlatformProxy.
//
// Both this class and PlatformProxy implement the platform device protocol.
// At this time, this protocol provides the following methods:
// map_mmio
// map_interrupt
// get_bti
// get_device_info
// The implementation in this file implements the platform device protocol for drivers that
// exist within the platform bus process. The implementation of the protocol
// in PlatformProxy is for drivers that live in their own devhost and perform
// RPC calls to the platform bus over a channel. In that case, RPC calls are
// handled by PlatformDevice::DdkRxrpc and then handled by relevant Rpc* methods.
// Any resource handles passed back to the proxy are then used to create/map mmio
// and irq objects within the proxy process. This ensures if the proxy driver dies
// we will release their address space resources back to the kernel if necessary.
namespace platform_bus {
class PlatformBus;
class PlatformDevice;
using PlatformDeviceType = ddk::Device<PlatformDevice, ddk::GetProtocolable, ddk::Rxrpcable>;
// This class represents a platform device attached to the platform bus.
// Instances of this class are created by PlatformBus at boot time when the board driver
// calls the platform bus protocol method pbus_device_add().
class PlatformDevice : public PlatformDeviceType, public ddk::PlatformDevProtocol<PlatformDevice> {
public:
// Creates a new PlatformDevice instance.
// *flags* contains zero or more PDEV_ADD_* flags from the platform bus protocol.
static zx_status_t Create(const pbus_dev_t* pdev, zx_device_t* parent, PlatformBus* bus,
uint32_t flags, fbl::unique_ptr<platform_bus::PlatformDevice>* out);
inline uint32_t vid() const { return vid_; }
inline uint32_t pid() const { return pid_; }
inline uint32_t did() const { return did_; }
// Device protocol implementation.
zx_status_t DdkGetProtocol(uint32_t proto_id, void* out);
void DdkRelease();
zx_status_t DdkRxrpc(zx_handle_t channel);
// Platform device protocol implementation.
zx_status_t MapMmio(uint32_t index, uint32_t cache_policy, void** out_vaddr, size_t* out_size,
zx_paddr_t* out_paddr, zx_handle_t* out_handle);
zx_status_t MapInterrupt(uint32_t index, uint32_t flags, zx_handle_t* out_handle);
zx_status_t GetBti(uint32_t index, zx_handle_t* out_handle);
zx_status_t GetDeviceInfo(pdev_device_info_t* out_info);
zx_status_t GetBoardInfo(pdev_board_info_t* out_info);
// Adds the underlying devmgr device.
zx_status_t DeviceAdd();
private:
// *flags* contains zero or more PDEV_ADD_* flags from the platform bus protocol.
explicit PlatformDevice(zx_device_t* parent, PlatformBus* bus, uint32_t flags,
const pbus_dev_t* pdev);
zx_status_t Init(const pbus_dev_t* pdev);
// Handlers for RPCs from PlatformProxy.
zx_status_t RpcGetMmio(uint32_t index, zx_paddr_t* out_paddr, size_t *out_length,
zx_handle_t* out_handle, uint32_t* out_handle_count);
zx_status_t RpcGetInterrupt(uint32_t index, uint32_t* out_irq, uint32_t* out_mode,
zx_handle_t* out_handle, uint32_t* out_handle_count);
zx_status_t RpcGetBti(uint32_t index, zx_handle_t* out_handle, uint32_t* out_handle_count);
zx_status_t RpcUmsSetMode(usb_mode_t mode);
zx_status_t RpcGpioConfig(uint32_t index, uint32_t flags);
zx_status_t RpcGpioSetAltFunction(uint32_t index, uint64_t function);
zx_status_t RpcGpioRead(uint32_t index, uint8_t* out_value);
zx_status_t RpcGpioWrite(uint32_t index, uint8_t value);
zx_status_t RpcGpioGetInterrupt(uint32_t index, uint32_t flags, zx_handle_t* out_handle,
uint32_t* out_handle_count);
zx_status_t RpcGpioReleaseInterrupt(uint32_t index);
zx_status_t RpcGpioSetPolarity(uint32_t index, uint32_t flags);
zx_status_t RpcCanvasConfig(zx_handle_t vmo, size_t offset, canvas_info_t* info,
uint8_t* canvas_idx);
zx_status_t RpcCanvasFree(uint8_t canvas_idx);
zx_status_t RpcScpiGetSensor(char* name, uint32_t *sensor_id);
zx_status_t RpcScpiGetSensorValue(uint32_t sensor_id, uint32_t* sensor_value);
zx_status_t RpcScpiGetDvfsInfo(uint8_t power_domain, scpi_opp_t* opps);
zx_status_t RpcScpiGetDvfsIdx(uint8_t power_domain, uint16_t* idx);
zx_status_t RpcScpiSetDvfsIdx(uint8_t power_domain, uint16_t idx);
zx_status_t RpcI2cTransact(uint32_t txid, rpc_i2c_req_t* req, uint8_t* data,
zx_handle_t channel);
zx_status_t RpcI2cGetMaxTransferSize(uint32_t index, size_t* out_size);
zx_status_t RpcClkEnable(uint32_t index);
zx_status_t RpcDisable(uint32_t index);
zx_status_t AddMetaData(const pbus_metadata_t& pbm);
PlatformBus* bus_;
char name_[ZX_DEVICE_NAME_MAX + 1];
const uint32_t flags_;
const uint32_t vid_;
const uint32_t pid_;
const uint32_t did_;
const serial_port_info_t serial_port_info_;
fbl::Vector<pbus_mmio_t> mmios_;
fbl::Vector<pbus_irq_t> irqs_;
fbl::Vector<pbus_gpio_t> gpios_;
fbl::Vector<pbus_i2c_channel_t> i2c_channels_;
fbl::Vector<pbus_clk_t> clks_;
fbl::Vector<pbus_bti_t> btis_;
fbl::Vector<pbus_metadata_t> metadata_;
};
} // namespace platform_bus