blob: 4d8318999efbfa27d160c9f653d66727cdcb7301 [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.
#include <fidl/fuchsia.hardware.platform.bus/cpp/driver/fidl.h>
#include <fidl/fuchsia.hardware.platform.bus/cpp/fidl.h>
#include <lib/ddk/debug.h>
#include <lib/ddk/device.h>
#include <lib/ddk/metadata.h>
#include <lib/ddk/platform-defs.h>
#include <lib/driver/component/cpp/composite_node_spec.h>
#include <lib/driver/component/cpp/node_add_args.h>
#include <bind/fuchsia/amlogic/platform/cpp/bind.h>
#include <bind/fuchsia/amlogic/platform/meson/cpp/bind.h>
#include <bind/fuchsia/amlogic/platform/t931/cpp/bind.h>
#include <bind/fuchsia/arm/platform/cpp/bind.h>
#include <bind/fuchsia/camera/cpp/bind.h>
#include <bind/fuchsia/clock/cpp/bind.h>
#include <bind/fuchsia/cpp/bind.h>
#include <bind/fuchsia/gpio/cpp/bind.h>
#include <bind/fuchsia/hardware/amlogiccanvas/cpp/bind.h>
#include <bind/fuchsia/hardware/clock/cpp/bind.h>
#include <bind/fuchsia/hardware/gpio/cpp/bind.h>
#include <bind/fuchsia/hardware/i2c/cpp/bind.h>
#include <bind/fuchsia/hardware/registers/cpp/bind.h>
#include <bind/fuchsia/hardware/sysmem/cpp/bind.h>
#include <bind/fuchsia/i2c/cpp/bind.h>
#include <bind/fuchsia/isp/cpp/bind.h>
#include <bind/fuchsia/register/cpp/bind.h>
#include <bind/fuchsia/sony/platform/cpp/bind.h>
#include <soc/aml-common/aml-registers.h>
#include <soc/aml-meson/g12b-clk.h>
#include <soc/aml-t931/t931-gpio.h>
#include <soc/aml-t931/t931-hw.h>
#include "sherlock-gpios.h"
#include "sherlock.h"
namespace sherlock {
namespace fpbus = fuchsia_hardware_platform_bus;
namespace {
constexpr uint32_t kClk24MAltFunc = 7;
constexpr uint32_t kClkGpioDriveStrengthUa = 4000;
static const std::vector<fpbus::Mmio> ge2d_mmios{
{{
.base = T931_GE2D_BASE,
.length = T931_GE2D_LENGTH,
}},
};
static const std::vector<fpbus::Bti> ge2d_btis{
{{
.iommu_index = 0,
.bti_id = BTI_GE2D,
}},
};
// IRQ for GE2D
static const std::vector<fpbus::Irq> ge2d_irqs{
{{
.irq = T931_MALI_GE2D_IRQ,
.mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
}},
};
static const fpbus::Node ge2d_dev = []() {
// GE2D
fpbus::Node dev = {};
dev.name() = "ge2d";
dev.vid() = bind_fuchsia_amlogic_platform::BIND_PLATFORM_DEV_VID_AMLOGIC;
dev.pid() = bind_fuchsia_amlogic_platform::BIND_PLATFORM_DEV_PID_T931;
dev.did() = bind_fuchsia_amlogic_platform::BIND_PLATFORM_DEV_DID_GE2D;
dev.mmio() = ge2d_mmios;
dev.bti() = ge2d_btis;
dev.irq() = ge2d_irqs;
return dev;
}();
static const std::vector<fpbus::Mmio> gdc_mmios{
{{
.base = T931_HIU_BASE,
.length = T931_HIU_LENGTH,
}},
{{
.base = T931_GDC_BASE,
.length = T931_GDC_LENGTH,
}},
};
static const std::vector<fpbus::Bti> gdc_btis{
{{
.iommu_index = 0,
.bti_id = BTI_GDC,
}},
};
// IRQ for ISP
static const std::vector<fpbus::Irq> gdc_irqs{
{{
.irq = T931_MALI_GDC_IRQ,
.mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
}},
};
static const fpbus::Node gdc_dev = []() {
// GDC
fpbus::Node dev = {};
dev.name() = "gdc";
dev.vid() = bind_fuchsia_arm_platform::BIND_PLATFORM_DEV_VID_ARM;
dev.pid() = bind_fuchsia_arm_platform::BIND_PLATFORM_DEV_PID_GDC;
dev.did() = bind_fuchsia_arm_platform::BIND_PLATFORM_DEV_DID_MALI_IV010;
dev.mmio() = gdc_mmios;
dev.bti() = gdc_btis;
dev.irq() = gdc_irqs;
return dev;
}();
static const std::vector<fpbus::Bti> isp_btis{
{{
.iommu_index = 0,
.bti_id = BTI_ISP,
}},
};
static const std::vector<fpbus::Mmio> isp_mmios{
{{
.base = T931_HIU_BASE,
.length = T931_HIU_LENGTH,
}},
{{
.base = T931_POWER_DOMAIN_BASE,
.length = T931_POWER_DOMAIN_LENGTH,
}},
{{
.base = T931_MEMORY_PD_BASE,
.length = T931_MEMORY_PD_LENGTH,
}},
{{
.base = T931_ISP_BASE,
.length = T931_ISP_LENGTH,
}},
};
// IRQ for ISP
static const std::vector<fpbus::Irq> isp_irqs{
{{
.irq = T931_MALI_ISP_IRQ,
.mode = ZX_INTERRUPT_MODE_LEVEL_HIGH,
}},
};
static const fpbus::Node isp_dev = []() {
// ISP
fpbus::Node dev = {};
dev.name() = "isp";
dev.vid() = PDEV_VID_ARM;
dev.pid() = PDEV_PID_ARM_ISP;
dev.did() = PDEV_DID_ARM_MALI_IV009;
dev.mmio() = isp_mmios;
dev.bti() = isp_btis;
dev.irq() = isp_irqs;
return dev;
}();
static const std::vector<fpbus::Mmio> mipi_mmios{
{{
.base = T931_CSI_PHY0_BASE,
.length = T931_CSI_PHY0_LENGTH,
}},
{{
.base = T931_APHY_BASE,
.length = T931_APHY_LENGTH,
}},
{{
.base = T931_CSI_HOST0_BASE,
.length = T931_CSI_HOST0_LENGTH,
}},
{{
.base = T931_MIPI_ADAPTER_BASE,
.length = T931_MIPI_ADAPTER_LENGTH,
}},
{{
.base = T931_HIU_BASE,
.length = T931_HIU_LENGTH,
}},
};
static const std::vector<fpbus::Bti> mipi_btis{
{{
.iommu_index = 0,
.bti_id = BTI_MIPI,
}},
};
static const std::vector<fpbus::Irq> mipi_irqs{
{{
.irq = T931_MIPI_ADAPTER_IRQ,
.mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
}},
};
// Binding rules for MIPI Driver
static const fpbus::Node mipi_dev = []() {
// MIPI CSI PHY ADAPTER
fpbus::Node dev = {};
dev.name() = "mipi-csi2";
dev.vid() = PDEV_VID_AMLOGIC;
dev.pid() = PDEV_PID_AMLOGIC_T931;
dev.did() = PDEV_DID_AMLOGIC_MIPI_CSI;
dev.mmio() = mipi_mmios;
dev.bti() = mipi_btis;
dev.irq() = mipi_irqs;
return dev;
}();
// Binding rules for Sensor Driver
static const fpbus::Node sensor_dev_sherlock = []() {
fpbus::Node dev = {};
dev.name() = "imx227-sensor";
dev.vid() = bind_fuchsia_sony_platform::BIND_PLATFORM_DEV_VID_SONY;
dev.pid() = bind_fuchsia_sony_platform::BIND_PLATFORM_DEV_PID_IMX227;
dev.did() = bind_fuchsia_sony_platform::BIND_PLATFORM_DEV_DID_CAMERA_SENSOR;
return dev;
}();
} // namespace
// Refer to camera design document for driver
// design and layout details.
zx_status_t Sherlock::CameraInit() {
// Set GPIO alternate functions.
gpio_init_steps_.push_back({T931_GPIOAO(10), GpioSetAltFunction(kClk24MAltFunc)});
gpio_init_steps_.push_back({T931_GPIOAO(10), GpioSetDriveStrength(kClkGpioDriveStrengthUa)});
fidl::Arena<> fidl_arena;
fdf::Arena arena('CAME');
{
auto result = pbus_.buffer(arena)->NodeAdd(fidl::ToWire(fidl_arena, mipi_dev));
if (!result.ok()) {
zxlogf(ERROR, "%s: NodeAdd Camera(mipi_dev) request failed: %s", __func__,
result.FormatDescription().data());
return result.status();
}
if (result->is_error()) {
zxlogf(ERROR, "%s: NodeAdd Camera(mipi_dev) failed: %s", __func__,
zx_status_get_string(result->error_value()));
return result->error_value();
}
}
auto imx227_sensor_mipicsi_spec = fuchsia_driver_framework::ParentSpec{{
.bind_rules = std::vector{fdf::MakeAcceptBindRule(
bind_fuchsia::PROTOCOL, bind_fuchsia_camera::BIND_PROTOCOL_MIPICSI)},
.properties = {fdf::MakeProperty(bind_fuchsia::PROTOCOL,
bind_fuchsia_camera::BIND_PROTOCOL_MIPICSI)},
}};
auto imx227_sensor_i2c_spec = fuchsia_driver_framework::ParentSpec{{
.bind_rules =
{
fdf::MakeAcceptBindRule(bind_fuchsia_hardware_i2c::SERVICE,
bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
fdf::MakeAcceptBindRule(bind_fuchsia::I2C_BUS_ID,
bind_fuchsia_i2c::BIND_I2C_BUS_ID_I2C_3),
fdf::MakeAcceptBindRule(bind_fuchsia::I2C_ADDRESS,
bind_fuchsia_i2c::BIND_I2C_ADDRESS_SHERLOCK),
},
.properties =
{
fdf::MakeProperty(bind_fuchsia_hardware_i2c::SERVICE,
bind_fuchsia_hardware_i2c::SERVICE_ZIRCONTRANSPORT),
},
}};
auto imx227_sensor_gpio_reset_spec = fuchsia_driver_framework::ParentSpec{{
.bind_rules =
{
fdf::MakeAcceptBindRule(bind_fuchsia_hardware_gpio::SERVICE,
bind_fuchsia_hardware_gpio::SERVICE_ZIRCONTRANSPORT),
fdf::MakeAcceptBindRule(bind_fuchsia::GPIO_PIN,
bind_fuchsia_amlogic_platform_t931::GPIOZ_PIN_ID_PIN_0),
},
.properties =
{
fdf::MakeProperty(bind_fuchsia_hardware_gpio::SERVICE,
bind_fuchsia_hardware_gpio::SERVICE_ZIRCONTRANSPORT),
fdf::MakeProperty(bind_fuchsia_gpio::FUNCTION, bind_fuchsia_gpio::FUNCTION_CAM_RESET),
},
}};
auto imx227_sensor_gpio_vana_spec = fuchsia_driver_framework::ParentSpec{{
.bind_rules =
{
fdf::MakeAcceptBindRule(bind_fuchsia_hardware_gpio::SERVICE,
bind_fuchsia_hardware_gpio::SERVICE_ZIRCONTRANSPORT),
fdf::MakeAcceptBindRule(bind_fuchsia::GPIO_PIN,
bind_fuchsia_amlogic_platform_t931::GPIOA_PIN_ID_PIN_6),
},
.properties =
{
fdf::MakeProperty(bind_fuchsia_hardware_gpio::SERVICE,
bind_fuchsia_hardware_gpio::SERVICE_ZIRCONTRANSPORT),
fdf::MakeProperty(bind_fuchsia_gpio::FUNCTION,
bind_fuchsia_gpio::FUNCTION_VANA_ENABLE),
},
}};
auto imx227_sensor_gpio_vdig_spec = fuchsia_driver_framework::ParentSpec{{
.bind_rules =
{
fdf::MakeAcceptBindRule(bind_fuchsia_hardware_gpio::SERVICE,
bind_fuchsia_hardware_gpio::SERVICE_ZIRCONTRANSPORT),
fdf::MakeAcceptBindRule(bind_fuchsia::GPIO_PIN,
bind_fuchsia_amlogic_platform_t931::GPIOZ_PIN_ID_PIN_12),
},
.properties =
{
fdf::MakeProperty(bind_fuchsia_hardware_gpio::SERVICE,
bind_fuchsia_hardware_gpio::SERVICE_ZIRCONTRANSPORT),
fdf::MakeProperty(bind_fuchsia_gpio::FUNCTION,
bind_fuchsia_gpio::FUNCTION_VDIG_ENABLE),
},
}};
auto imx227_sensor_clock_sensor_spec = fuchsia_driver_framework::ParentSpec{{
.bind_rules =
{
fdf::MakeAcceptBindRule(bind_fuchsia_hardware_clock::SERVICE,
bind_fuchsia_hardware_clock::SERVICE_ZIRCONTRANSPORT),
fdf::MakeAcceptBindRule(
bind_fuchsia::CLOCK_ID,
bind_fuchsia_amlogic_platform_meson::G12B_CLK_ID_CLK_CAM_INCK_24M),
},
.properties =
{
fdf::MakeProperty(bind_fuchsia_hardware_clock::SERVICE,
bind_fuchsia_hardware_clock::SERVICE_ZIRCONTRANSPORT),
fdf::MakeProperty(bind_fuchsia_clock::FUNCTION,
bind_fuchsia_clock::FUNCTION_CAMERA_SENSOR),
},
}};
auto imx227_sensor_gpio_init_spec = fuchsia_driver_framework::ParentSpec{{
.bind_rules =
{
fdf::MakeAcceptBindRule(bind_fuchsia::INIT_STEP,
bind_fuchsia_gpio::BIND_INIT_STEP_GPIO),
},
.properties =
{
fdf::MakeProperty(bind_fuchsia::INIT_STEP, bind_fuchsia_gpio::BIND_INIT_STEP_GPIO),
},
}};
auto composite_spec = fuchsia_driver_framework::CompositeNodeSpec{{
.name = "imx227_sensor",
.parents = {{
imx227_sensor_mipicsi_spec,
imx227_sensor_i2c_spec,
imx227_sensor_gpio_reset_spec,
imx227_sensor_gpio_vana_spec,
imx227_sensor_gpio_vdig_spec,
imx227_sensor_clock_sensor_spec,
imx227_sensor_gpio_init_spec,
}},
}};
fdf::WireUnownedResult spec_result = pbus_.buffer(arena)->AddCompositeNodeSpec(
fidl::ToWire(fidl_arena, sensor_dev_sherlock), fidl::ToWire(fidl_arena, composite_spec));
if (!spec_result.ok()) {
zxlogf(ERROR, "%s: AddCompositeNodeSpec Camera(sensor_dev_sherlock) request failed: %s",
__func__, spec_result.FormatDescription().data());
return spec_result.status();
}
if (spec_result->is_error()) {
zxlogf(ERROR, "%s: AddCompositeNodeSpec Camera(sensor_dev_sherlock) failed: %s", __func__,
zx_status_get_string(spec_result->error_value()));
return spec_result->error_value();
}
auto bind_rules = std::vector{
fdf::MakeAcceptBindRule(bind_fuchsia::PROTOCOL,
bind_fuchsia_camera::BIND_PROTOCOL_CAMERA_SENSOR_2),
};
auto properties = std::vector{
fdf::MakeProperty(bind_fuchsia::PROTOCOL, bind_fuchsia_camera::BIND_PROTOCOL_CAMERA_SENSOR_2),
};
auto parents = std::vector{
fuchsia_driver_framework::ParentSpec{{
.bind_rules = bind_rules,
.properties = properties,
}},
};
composite_spec = fuchsia_driver_framework::CompositeNodeSpec{{.name = "gdc", .parents = parents}};
spec_result = pbus_.buffer(arena)->AddCompositeNodeSpec(fidl::ToWire(fidl_arena, gdc_dev),
fidl::ToWire(fidl_arena, composite_spec));
if (!spec_result.ok()) {
zxlogf(ERROR, "%s: AddCompositeNodeSpec Camera(gdc_dev) request failed: %s", __func__,
spec_result.FormatDescription().data());
return spec_result.status();
}
if (spec_result->is_error()) {
zxlogf(ERROR, "%s: AddCompositeNodeSpec Camera(gdc_dev) failed: %s", __func__,
zx_status_get_string(spec_result->error_value()));
return spec_result->error_value();
}
auto ge2d_sensor_node = fuchsia_driver_framework::ParentSpec{{
.bind_rules =
{
fdf::MakeAcceptBindRule(bind_fuchsia::PROTOCOL,
bind_fuchsia_camera::BIND_PROTOCOL_CAMERA_SENSOR_2),
},
.properties =
{
fdf::MakeProperty(bind_fuchsia::PROTOCOL,
bind_fuchsia_camera::BIND_PROTOCOL_CAMERA_SENSOR_2),
},
}};
auto ge2d_canvas_node = fuchsia_driver_framework::ParentSpec{{
.bind_rules =
{
fdf::MakeAcceptBindRule(bind_fuchsia_hardware_amlogiccanvas::SERVICE,
bind_fuchsia_hardware_amlogiccanvas::SERVICE_ZIRCONTRANSPORT),
},
.properties =
{
fdf::MakeProperty(bind_fuchsia_hardware_amlogiccanvas::SERVICE,
bind_fuchsia_hardware_amlogiccanvas::SERVICE_ZIRCONTRANSPORT),
},
}};
composite_spec = fuchsia_driver_framework::CompositeNodeSpec{{
.name = "ge2d",
.parents = {{ge2d_sensor_node, ge2d_canvas_node}},
}};
spec_result = pbus_.buffer(arena)->AddCompositeNodeSpec(fidl::ToWire(fidl_arena, ge2d_dev),
fidl::ToWire(fidl_arena, composite_spec));
if (!spec_result.ok()) {
zxlogf(ERROR, "%s: AddCompositeNodeSpec Camera(ge2d_dev) request failed: %s", __func__,
spec_result.FormatDescription().data());
return spec_result.status();
}
if (spec_result->is_error()) {
zxlogf(ERROR, "%s: AddCompositeNodeSpec Camera(ge2d_dev) failed: %s", __func__,
zx_status_get_string(spec_result->error_value()));
return spec_result->error_value();
}
auto isp_sensor_node = fuchsia_driver_framework::ParentSpec{{
.bind_rules =
{
fdf::MakeAcceptBindRule(bind_fuchsia::PROTOCOL,
bind_fuchsia_camera::BIND_PROTOCOL_CAMERA_SENSOR_2),
},
.properties =
{
fdf::MakeProperty(bind_fuchsia::PROTOCOL,
bind_fuchsia_camera::BIND_PROTOCOL_CAMERA_SENSOR_2),
},
}};
auto isp_reset_node = fuchsia_driver_framework::ParentSpec{{
.bind_rules =
{
fdf::MakeAcceptBindRule(bind_fuchsia_hardware_registers::SERVICE,
bind_fuchsia_hardware_registers::SERVICE_ZIRCONTRANSPORT),
fdf::MakeAcceptBindRule(bind_fuchsia_register::NAME,
bind_fuchsia_amlogic_platform::NAME_REGISTER_ISP_RESET),
},
.properties =
{
fdf::MakeProperty(bind_fuchsia_hardware_registers::SERVICE,
bind_fuchsia_hardware_registers::SERVICE_ZIRCONTRANSPORT),
fdf::MakeProperty(bind_fuchsia_register::NAME,
bind_fuchsia_amlogic_platform::NAME_REGISTER_ISP_RESET),
},
}};
composite_spec = fuchsia_driver_framework::CompositeNodeSpec{
{.name = "isp", .parents = {{isp_sensor_node, isp_reset_node}}}};
// Add a composite device for ARM ISP
spec_result = pbus_.buffer(arena)->AddCompositeNodeSpec(fidl::ToWire(fidl_arena, isp_dev),
fidl::ToWire(fidl_arena, composite_spec));
if (!spec_result.ok()) {
zxlogf(ERROR, "AddCompositeNodeSpec Camera(isp_dev) request failed: %s",
spec_result.FormatDescription().data());
return spec_result.status();
}
if (spec_result->is_error()) {
zxlogf(ERROR, "AddCompositeNodeSpec Camera(isp_dev) failed: %s",
zx_status_get_string(spec_result->error_value()));
return spec_result->error_value();
}
const ddk::BindRule kIspRules[] = {
ddk::MakeAcceptBindRule(bind_fuchsia::PROTOCOL, bind_fuchsia_isp::BIND_PROTOCOL_DEVICE),
};
const ddk::BindRule kGdcRules[] = {
ddk::MakeAcceptBindRule(bind_fuchsia::PROTOCOL, bind_fuchsia_camera::BIND_PROTOCOL_GDC),
};
const ddk::BindRule kGe2dRules[] = {
ddk::MakeAcceptBindRule(bind_fuchsia::PROTOCOL, bind_fuchsia_camera::BIND_PROTOCOL_GE2D),
};
const ddk::BindRule kSysmemRules[] = {
ddk::MakeAcceptBindRule(bind_fuchsia_hardware_sysmem::SERVICE,
bind_fuchsia_hardware_sysmem::SERVICE_ZIRCONTRANSPORT),
};
const device_bind_prop_t kIspProperties[] = {
ddk::MakeProperty(bind_fuchsia::PROTOCOL, bind_fuchsia_isp::BIND_PROTOCOL_DEVICE),
};
const device_bind_prop_t kGdcProperties[] = {
ddk::MakeProperty(bind_fuchsia::PROTOCOL, bind_fuchsia_camera::BIND_PROTOCOL_GDC),
};
const device_bind_prop_t kGe2dProperties[] = {
ddk::MakeProperty(bind_fuchsia::PROTOCOL, bind_fuchsia_camera::BIND_PROTOCOL_GE2D),
};
const device_bind_prop_t kSysmemProperties[] = {
ddk::MakeProperty(bind_fuchsia_hardware_sysmem::SERVICE,
bind_fuchsia_hardware_sysmem::SERVICE_ZIRCONTRANSPORT),
};
auto node_group = ddk::CompositeNodeSpec(kIspRules, kIspProperties)
.AddParentSpec(kGdcRules, kGdcProperties)
.AddParentSpec(kGe2dRules, kGe2dProperties)
.AddParentSpec(kSysmemRules, kSysmemProperties);
zx_status_t status = DdkAddCompositeNodeSpec("camera_controller", node_group);
if (status != ZX_OK) {
zxlogf(ERROR, "%s: Camera Controller DdkAddCompositeNodeSpec failed %d", __func__, status);
return status;
}
return status;
}
} // namespace sherlock