blob: 0abb9a20c49f48cbe05864bae287d763c09fb7a2 [file] [log] [blame]
// Copyright 2019 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 SRC_DEVICES_GPIO_DRIVERS_AML_GPIO_AML_GPIO_H_
#define SRC_DEVICES_GPIO_DRIVERS_AML_GPIO_AML_GPIO_H_
#include <fidl/fuchsia.hardware.pinimpl/cpp/driver/fidl.h>
#include <fidl/fuchsia.hardware.platform.device/cpp/fidl.h>
#include <fidl/fuchsia.scheduler/cpp/fidl.h>
#include <lib/async/cpp/executor.h>
#include <lib/driver/component/cpp/driver_base.h>
#include <lib/driver/metadata/cpp/metadata_server.h>
#include <lib/driver/mmio/cpp/mmio.h>
#include <lib/fpromise/promise.h>
#include <lib/stdcompat/span.h>
#include <array>
#include <cstdint>
#include <optional>
#include <fbl/array.h>
namespace gpio {
struct AmlGpioBlock {
uint32_t start_pin;
uint32_t pin_block;
uint32_t pin_count;
uint32_t mux_offset;
uint32_t oen_offset;
uint32_t input_offset;
uint32_t output_offset;
uint32_t output_shift; // Used for GPIOAO block
uint32_t pull_offset;
uint32_t pull_en_offset;
uint32_t mmio_index;
uint32_t pin_start;
uint32_t ds_offset;
};
struct AmlGpioInterrupt {
uint32_t pin_select_offset;
uint32_t edge_polarity_offset;
uint32_t filter_select_offset;
};
// TODO(42082459): Rename to AmlPin now that it implements the pinimpl protocol.
class AmlGpio : public fdf::WireServer<fuchsia_hardware_pinimpl::PinImpl> {
public:
struct InterruptInfo {
uint16_t pin = kMaxGpioIndex + 1;
zx::interrupt interrupt;
};
AmlGpio(fidl::ClientEnd<fuchsia_hardware_platform_device::Device> pdev, fdf::MmioBuffer mmio_gpio,
fdf::MmioBuffer mmio_gpio_ao, fdf::MmioBuffer mmio_interrupt,
cpp20::span<const AmlGpioBlock> gpio_blocks, const AmlGpioInterrupt* gpio_interrupt,
uint32_t pid, fbl::Array<InterruptInfo> irq_info)
: pdev_(std::move(pdev), fdf::Dispatcher::GetCurrent()->async_dispatcher()),
mmios_{std::move(mmio_gpio), std::move(mmio_gpio_ao)},
mmio_interrupt_(std::move(mmio_interrupt)),
gpio_blocks_(gpio_blocks),
gpio_interrupt_(gpio_interrupt),
pid_(pid),
irq_info_(std::move(irq_info)) {}
private:
friend class AmlGpioDriver;
static constexpr int kMaxGpioIndex = 255;
fidl::ProtocolHandler<fuchsia_hardware_pinimpl::PinImpl> CreateHandler() {
return bindings_.CreateHandler(this, fdf::Dispatcher::GetCurrent()->get(),
fidl::kIgnoreBindingClosure);
}
void handle_unknown_method(
fidl::UnknownMethodMetadata<fuchsia_hardware_pinimpl::PinImpl> metadata,
fidl::UnknownMethodCompleter::Sync& completer) override {
FDF_LOG(ERROR, "Unexpected pinimpl FIDL call: 0x%lx", metadata.method_ordinal);
}
void Read(fuchsia_hardware_pinimpl::wire::PinImplReadRequest* request, fdf::Arena& arena,
ReadCompleter::Sync& completer) override;
void SetBufferMode(fuchsia_hardware_pinimpl::wire::PinImplSetBufferModeRequest* request,
fdf::Arena& arena, SetBufferModeCompleter::Sync& completer) override;
void GetInterrupt(fuchsia_hardware_pinimpl::wire::PinImplGetInterruptRequest* request,
fdf::Arena& arena, GetInterruptCompleter::Sync& completer) override;
void ConfigureInterrupt(fuchsia_hardware_pinimpl::wire::PinImplConfigureInterruptRequest* request,
fdf::Arena& arena, ConfigureInterruptCompleter::Sync& completer) override;
void ReleaseInterrupt(fuchsia_hardware_pinimpl::wire::PinImplReleaseInterruptRequest* request,
fdf::Arena& arena, ReleaseInterruptCompleter::Sync& completer) override;
void Configure(fuchsia_hardware_pinimpl::wire::PinImplConfigureRequest* request,
fdf::Arena& arena, ConfigureCompleter::Sync& completer) override;
fuchsia_hardware_pin::Pull GetPull(const AmlGpioBlock* block, uint32_t pinindex);
void SetPull(const AmlGpioBlock* block, uint32_t pinindex, fuchsia_hardware_pin::Pull pull);
uint64_t GetFunction(uint32_t index, const AmlGpioBlock* block);
void SetFunction(uint32_t index, const AmlGpioBlock* block, uint64_t function);
uint64_t GetDriveStrength(uint32_t index, const AmlGpioBlock* block);
void SetDriveStrength(uint32_t index, const AmlGpioBlock* block, uint64_t drive_strength_ua);
zx_status_t AmlPinToBlock(uint32_t pin, const AmlGpioBlock** out_block,
uint32_t* out_pin_index) const;
void SetInterruptMode(uint32_t irq_index, fuchsia_hardware_gpio::InterruptMode mode);
fidl::WireClient<fuchsia_hardware_platform_device::Device> pdev_;
std::array<fdf::MmioBuffer, 2> mmios_; // separate MMIO for AO domain
fdf::MmioBuffer mmio_interrupt_;
const cpp20::span<const AmlGpioBlock> gpio_blocks_;
const AmlGpioInterrupt* gpio_interrupt_;
const uint32_t pid_;
fbl::Array<InterruptInfo> irq_info_;
uint8_t irq_status_{};
std::array<std::optional<fuchsia_hardware_gpio::InterruptMode>, kMaxGpioIndex + 1> pin_irq_modes_;
fdf::ServerBindingGroup<fuchsia_hardware_pinimpl::PinImpl> bindings_;
};
class AmlGpioDriver : public fdf::DriverBase {
public:
AmlGpioDriver(fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher dispatcher)
: fdf::DriverBase("aml-gpio", std::move(start_args), std::move(dispatcher)),
executor_(fdf::DriverBase::dispatcher()) {}
void Start(fdf::StartCompleter completer) override;
protected:
// MapMmio can be overridden by a test in order to provide an fdf::MmioBuffer backed by a fake.
virtual fpromise::promise<fdf::MmioBuffer, zx_status_t> MapMmio(
fidl::WireClient<fuchsia_hardware_platform_device::Device>& pdev, uint32_t mmio_id);
private:
fpromise::promise<void, zx_status_t> InitResources();
void OnGetNodeDeviceInfo(const fuchsia_hardware_platform_device::wire::NodeDeviceInfo& info,
fpromise::completer<void, zx_status_t> completer);
void OnGetBoardInfo(const fuchsia_hardware_platform_device::wire::BoardInfo& board_info,
uint32_t irq_count, fpromise::completer<void, zx_status_t> completer);
void MapMmios(uint32_t pid, uint32_t irq_count, fpromise::completer<void, zx_status_t> completer);
void InitDevice(uint32_t pid, uint32_t irq_count, std::vector<fdf::MmioBuffer> mmios,
fpromise::completer<void, zx_status_t> completer);
void AddNode(fdf::StartCompleter completer);
fidl::WireClient<fuchsia_driver_framework::Node> parent_;
fidl::WireClient<fuchsia_driver_framework::NodeController> controller_;
fidl::WireClient<fuchsia_hardware_platform_device::Device> pdev_;
std::unique_ptr<AmlGpio> device_;
async::Executor executor_;
fdf_metadata::MetadataServer<fuchsia_hardware_pinimpl::Metadata> pin_metadata_server_;
fdf_metadata::MetadataServer<fuchsia_scheduler::RoleName> scheduler_role_name_metadata_server_;
};
} // namespace gpio
#endif // SRC_DEVICES_GPIO_DRIVERS_AML_GPIO_AML_GPIO_H_