blob: 3a3381a9e72c40b07511576da73c1ce0b7f841d0 [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.gpioimpl/cpp/driver/fidl.h>
#include <fidl/fuchsia.hardware.platform.device/cpp/fidl.h>
#include <lib/async/cpp/executor.h>
#include <lib/driver/compat/cpp/device_server.h>
#include <lib/driver/component/cpp/driver_base.h>
#include <lib/fpromise/promise.h>
#include <lib/mmio/mmio.h>
#include <lib/stdcompat/span.h>
#include <cstdint>
#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;
};
class AmlGpio : public fdf::WireServer<fuchsia_hardware_gpioimpl::GpioImpl> {
public:
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<uint16_t> 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;
fidl::ProtocolHandler<fuchsia_hardware_gpioimpl::GpioImpl> CreateHandler() {
return bindings_.CreateHandler(this, fdf::Dispatcher::GetCurrent()->get(),
fidl::kIgnoreBindingClosure);
}
void handle_unknown_method(
fidl::UnknownMethodMetadata<fuchsia_hardware_gpioimpl::GpioImpl> metadata,
fidl::UnknownMethodCompleter::Sync& completer) override {
FDF_LOG(ERROR, "Unexpected gpioimpl FIDL call: 0x%lx", metadata.method_ordinal);
}
void ConfigIn(fuchsia_hardware_gpioimpl::wire::GpioImplConfigInRequest* request,
fdf::Arena& arena, ConfigInCompleter::Sync& completer) override;
void ConfigOut(fuchsia_hardware_gpioimpl::wire::GpioImplConfigOutRequest* request,
fdf::Arena& arena, ConfigOutCompleter::Sync& completer) override;
void SetAltFunction(fuchsia_hardware_gpioimpl::wire::GpioImplSetAltFunctionRequest* request,
fdf::Arena& arena, SetAltFunctionCompleter::Sync& completer) override;
void Read(fuchsia_hardware_gpioimpl::wire::GpioImplReadRequest* request, fdf::Arena& arena,
ReadCompleter::Sync& completer) override;
void Write(fuchsia_hardware_gpioimpl::wire::GpioImplWriteRequest* request, fdf::Arena& arena,
WriteCompleter::Sync& completer) override;
void SetPolarity(fuchsia_hardware_gpioimpl::wire::GpioImplSetPolarityRequest* request,
fdf::Arena& arena, SetPolarityCompleter::Sync& completer) override;
void SetDriveStrength(fuchsia_hardware_gpioimpl::wire::GpioImplSetDriveStrengthRequest* request,
fdf::Arena& arena, SetDriveStrengthCompleter::Sync& completer) override;
void GetDriveStrength(fuchsia_hardware_gpioimpl::wire::GpioImplGetDriveStrengthRequest* request,
fdf::Arena& arena, GetDriveStrengthCompleter::Sync& completer) override;
void GetInterrupt(fuchsia_hardware_gpioimpl::wire::GpioImplGetInterruptRequest* request,
fdf::Arena& arena, GetInterruptCompleter::Sync& completer) override;
void ReleaseInterrupt(fuchsia_hardware_gpioimpl::wire::GpioImplReleaseInterruptRequest* request,
fdf::Arena& arena, ReleaseInterruptCompleter::Sync& completer) override;
void GetPins(fdf::Arena& arena, GetPinsCompleter::Sync& completer) override;
void GetInitSteps(fdf::Arena& arena, GetInitStepsCompleter::Sync& completer) override;
void GetControllerId(fdf::Arena& arena, GetControllerIdCompleter::Sync& completer) override;
zx_status_t AmlPinToBlock(uint32_t pin, const AmlGpioBlock** out_block,
uint32_t* out_pin_index) const;
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<uint16_t> irq_info_;
uint8_t irq_status_{};
fdf::ServerBindingGroup<fuchsia_hardware_gpioimpl::GpioImpl> 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:
void OnCompatServerInitialized(fdf::StartCompleter completer);
void OnGetNodeDeviceInfo(const fuchsia_hardware_platform_device::wire::NodeDeviceInfo& info,
fdf::StartCompleter completer);
void OnGetBoardInfo(const fuchsia_hardware_platform_device::wire::BoardInfo& board_info,
uint32_t irq_count, fdf::StartCompleter completer);
void MapMmios(uint32_t pid, uint32_t irq_count, fdf::StartCompleter completer);
void AddNode(uint32_t pid, uint32_t irq_count, std::vector<fdf::MmioBuffer> mmios,
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_;
compat::AsyncInitializedDeviceServer compat_server_;
std::unique_ptr<AmlGpio> device_;
async::Executor executor_;
};
} // namespace gpio
#endif // SRC_DEVICES_GPIO_DRIVERS_AML_GPIO_AML_GPIO_H_