blob: 4714e95e01af27f768a4a5ba006068a4888adeea [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 <ddk/binding.h>
#include <ddk/debug.h>
#include <ddk/device.h>
#include <ddk/metadata.h>
#include <ddk/platform-defs.h>
#include <ddktl/protocol/clockimpl.h>
#include <ddktl/protocol/gpioimpl.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 {
constexpr uint32_t kClk24MAltFunc = 7;
constexpr uint32_t kClkGpioDriveStrengthUa = 4000;
constexpr pbus_mmio_t ge2d_mmios[] = {
// GE2D Base
{
.base = T931_GE2D_BASE,
.length = T931_GE2D_LENGTH,
},
};
constexpr pbus_bti_t ge2d_btis[] = {
{
.iommu_index = 0,
.bti_id = BTI_GE2D,
},
};
// IRQ for GE2D
constexpr pbus_irq_t ge2d_irqs[] = {
{
.irq = T931_MALI_GE2D_IRQ,
.mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
},
};
static pbus_dev_t ge2d_dev = []() {
// GE2D
pbus_dev_t dev = {};
dev.name = "ge2d";
dev.vid = PDEV_VID_AMLOGIC;
dev.pid = PDEV_PID_AMLOGIC_T931;
dev.did = PDEV_DID_AMLOGIC_GE2D;
dev.mmio_list = ge2d_mmios;
dev.mmio_count = countof(ge2d_mmios);
dev.bti_list = ge2d_btis;
dev.bti_count = countof(ge2d_btis);
dev.irq_list = ge2d_irqs;
dev.irq_count = countof(ge2d_irqs);
return dev;
}();
constexpr pbus_mmio_t gdc_mmios[] = {
// HIU for clocks.
{
.base = T931_HIU_BASE,
.length = T931_HIU_LENGTH,
},
// GDC Base
{
.base = T931_GDC_BASE,
.length = T931_GDC_LENGTH,
},
};
constexpr pbus_bti_t gdc_btis[] = {
{
.iommu_index = 0,
.bti_id = BTI_GDC,
},
};
// IRQ for ISP
constexpr pbus_irq_t gdc_irqs[] = {
{
.irq = T931_MALI_GDC_IRQ,
.mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
},
};
static pbus_dev_t gdc_dev = []() {
// GDC
pbus_dev_t dev = {};
dev.name = "gdc";
dev.vid = PDEV_VID_ARM;
dev.pid = PDEV_PID_GDC;
dev.did = PDEV_DID_ARM_MALI_IV010;
dev.mmio_list = gdc_mmios;
dev.mmio_count = countof(gdc_mmios);
dev.bti_list = gdc_btis;
dev.bti_count = countof(gdc_btis);
dev.irq_list = gdc_irqs;
dev.irq_count = countof(gdc_irqs);
return dev;
}();
constexpr pbus_bti_t isp_btis[] = {
{
.iommu_index = 0,
.bti_id = BTI_ISP,
},
};
constexpr pbus_mmio_t isp_mmios[] = {
// HIU for clocks.
{
.base = T931_HIU_BASE,
.length = T931_HIU_LENGTH,
},
// Power domain
{
.base = T931_POWER_DOMAIN_BASE,
.length = T931_POWER_DOMAIN_LENGTH,
},
// Memory PD
{
.base = T931_MEMORY_PD_BASE,
.length = T931_MEMORY_PD_LENGTH,
},
// ISP Base
{
.base = T931_ISP_BASE,
.length = T931_ISP_LENGTH,
},
};
// IRQ for ISP
static const pbus_irq_t isp_irqs[] = {
{
.irq = T931_MALI_ISP_IRQ,
.mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
},
};
static pbus_dev_t isp_dev = []() {
// ISP
pbus_dev_t dev = {};
dev.name = "isp";
dev.vid = PDEV_VID_ARM;
dev.pid = PDEV_PID_ARM_ISP;
dev.did = PDEV_DID_ARM_MALI_IV009;
dev.mmio_list = isp_mmios;
dev.mmio_count = countof(isp_mmios);
dev.bti_list = isp_btis;
dev.bti_count = countof(isp_btis);
dev.irq_list = isp_irqs;
dev.irq_count = countof(isp_irqs);
return dev;
}();
// Composite binding rules for ARM ISP
static const zx_bind_inst_t root_match[] = {
BI_MATCH(),
};
static const zx_bind_inst_t reset_register_match[] = {
BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_REGISTERS),
BI_MATCH_IF(EQ, BIND_REGISTER_ID, aml_registers::REGISTER_ISP_RESET),
};
static const zx_bind_inst_t camera_sensor_match[] = {
BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_CAMERA_SENSOR2),
};
static const zx_bind_inst_t amlogiccanvas_match[] = {
BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_AMLOGIC_CANVAS),
};
static const device_fragment_part_t reset_register_fragment[] = {
{countof(root_match), root_match},
{countof(reset_register_match), reset_register_match},
};
static const device_fragment_part_t camera_sensor_fragment[] = {
{countof(root_match), root_match},
{countof(camera_sensor_match), camera_sensor_match},
};
static const device_fragment_t isp_fragments[] = {
{"camera-sensor", countof(camera_sensor_fragment), camera_sensor_fragment},
{"register-reset", countof(reset_register_fragment), reset_register_fragment},
};
// Compisite binding rules for GDC
static const device_fragment_t gdc_fragments[] = {
{"camera-sensor", countof(camera_sensor_fragment), camera_sensor_fragment},
};
static const device_fragment_part_t amlogiccanvas_fragment[] = {
{countof(root_match), root_match},
{countof(amlogiccanvas_match), amlogiccanvas_match},
};
// Composite binding rules for GE2D
static const device_fragment_t ge2d_fragments[] = {
{"camera-sensor", countof(camera_sensor_fragment), camera_sensor_fragment},
{"canvas", countof(amlogiccanvas_fragment), amlogiccanvas_fragment},
};
// Composite binding rules for camera modules.
static const zx_bind_inst_t i2c_match[] = {
BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_I2C),
BI_ABORT_IF(NE, BIND_I2C_BUS_ID, SHERLOCK_I2C_3),
BI_MATCH_IF(EQ, BIND_I2C_ADDRESS, 0x36), // sherlock
BI_MATCH_IF(EQ, BIND_I2C_ADDRESS, 0x1a), // luis camera sensor
};
static const zx_bind_inst_t gpio_reset_match[] = {
BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
BI_MATCH_IF(EQ, BIND_GPIO_PIN, GPIO_CAM_RESET),
};
static const zx_bind_inst_t gpio_vana_match[] = {
BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
BI_MATCH_IF(EQ, BIND_GPIO_PIN, GPIO_VANA_ENABLE),
};
static const zx_bind_inst_t gpio_vdig_match[] = {
BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
BI_MATCH_IF(EQ, BIND_GPIO_PIN, GPIO_VDIG_ENABLE),
};
// Additional definitions for Luis.
// The reset and digital voltage enables are the same
static const zx_bind_inst_t gpio_cam_mute_match[] = {
BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
BI_MATCH_IF(EQ, BIND_GPIO_PIN, GPIO_CAM_MUTE),
};
static const zx_bind_inst_t gpio_cam_vif_match[] = {
BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
BI_MATCH_IF(EQ, BIND_GPIO_PIN, GPIO_CAM_VIF_ENABLE),
};
static const zx_bind_inst_t gpio_cam_vana_match[] = {
BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
BI_MATCH_IF(EQ, BIND_GPIO_PIN, GPIO_CAM_VANA_ENABLE),
};
static const zx_bind_inst_t i2c_eeprom_match[] = {
BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_I2C),
BI_ABORT_IF(NE, BIND_I2C_BUS_ID, SHERLOCK_I2C_3),
BI_MATCH_IF(EQ, BIND_I2C_ADDRESS, 0x51), // luis camera module EEPROM
};
static const zx_bind_inst_t clk_sensor_match[] = {
BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_CLOCK),
BI_MATCH_IF(EQ, BIND_CLOCK_ID, g12b_clk::G12B_CLK_CAM_INCK_24M),
};
static const zx_bind_inst_t mipicsi_match[] = {
BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_MIPI_CSI),
};
static const device_fragment_part_t i2c_fragment[] = {
{countof(root_match), root_match},
{countof(i2c_match), i2c_match},
};
static const device_fragment_part_t gpio_reset_fragment[] = {
{countof(root_match), root_match},
{countof(gpio_reset_match), gpio_reset_match},
};
static const device_fragment_part_t gpio_vana_fragment[] = {
{countof(root_match), root_match},
{countof(gpio_vana_match), gpio_vana_match},
};
static const device_fragment_part_t gpio_vdig_fragment[] = {
{countof(root_match), root_match},
{countof(gpio_vdig_match), gpio_vdig_match},
};
// Additions for Luis
static const device_fragment_part_t gpio_cam_mute_fragment[] = {
{countof(root_match), root_match},
{countof(gpio_cam_mute_match), gpio_cam_mute_match},
};
static const device_fragment_part_t gpio_cam_vif_fragment[] = {
{countof(root_match), root_match},
{countof(gpio_cam_vif_match), gpio_cam_vif_match},
};
static const device_fragment_part_t gpio_cam_vana_fragment[] = {
{countof(root_match), root_match},
{countof(gpio_cam_vana_match), gpio_cam_vana_match},
};
static const device_fragment_part_t i2c_eeprom_fragment[] = {
{countof(root_match), root_match},
{countof(i2c_eeprom_match), i2c_eeprom_match},
};
static const device_fragment_part_t clk_sensor_fragment[] = {
{countof(root_match), root_match},
{countof(clk_sensor_match), clk_sensor_match},
};
static const device_fragment_part_t mipicsi_fragment[] = {
{countof(root_match), root_match},
{countof(mipicsi_match), mipicsi_match},
};
static const device_fragment_t imx227_sensor_fragments[] = {
{"mipicsi", countof(mipicsi_fragment), mipicsi_fragment},
{"i2c", countof(i2c_fragment), i2c_fragment},
{"gpio-vana", countof(gpio_vana_fragment), gpio_vana_fragment},
{"gpio-vdig", countof(gpio_vdig_fragment), gpio_vdig_fragment},
{"gpio-reset", countof(gpio_reset_fragment), gpio_reset_fragment},
{"clock-sensor", countof(clk_sensor_fragment), clk_sensor_fragment},
};
static const device_fragment_t imx355_sensor_fragments[] = {
{"mipicsi", countof(mipicsi_fragment), mipicsi_fragment},
{"i2c", countof(i2c_fragment), i2c_fragment},
{"i2c-eeprom", countof(i2c_eeprom_fragment), i2c_eeprom_fragment},
{"gpio-cam-mute", countof(gpio_cam_mute_fragment), gpio_cam_mute_fragment},
{"gpio-cam-reset", countof(gpio_reset_fragment), gpio_reset_fragment},
{"gpio-cam-vana", countof(gpio_cam_vana_fragment), gpio_cam_vana_fragment},
{"gpio-vdig", countof(gpio_vdig_fragment), gpio_vdig_fragment},
{"gpio-cam-vif", countof(gpio_cam_vif_fragment), gpio_cam_vif_fragment},
{"clock-sensor", countof(clk_sensor_fragment), clk_sensor_fragment},
};
// Composite device binding rules for Camera Controller
static const zx_bind_inst_t isp_match[] = {
BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_ISP),
};
static const zx_bind_inst_t gdc_match[] = {
BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_GDC),
};
static const zx_bind_inst_t ge2d_match[] = {
BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_GE2D),
};
static const zx_bind_inst_t sysmem_match[] = {
BI_MATCH_IF(EQ, BIND_PROTOCOL, ZX_PROTOCOL_SYSMEM),
};
static const device_fragment_part_t isp_fragment[] = {
{countof(root_match), root_match},
{countof(isp_match), isp_match},
};
static const device_fragment_part_t gdc_fragment[] = {
{countof(root_match), root_match},
{countof(gdc_match), gdc_match},
};
static const device_fragment_part_t ge2d_fragment[] = {
{countof(root_match), root_match},
{countof(ge2d_match), ge2d_match},
};
static const device_fragment_part_t sysmem_fragment[] = {
{countof(root_match), root_match},
{countof(sysmem_match), sysmem_match},
};
static const device_fragment_t camera_controller_fragments[] = {
{"isp", countof(isp_fragment), isp_fragment},
{"gdc", countof(gdc_fragment), gdc_fragment},
{"ge2d", countof(ge2d_fragment), ge2d_fragment},
{"sysmem", countof(sysmem_fragment), sysmem_fragment},
};
constexpr pbus_mmio_t mipi_mmios[] = {
// CSI PHY0
{
.base = T931_CSI_PHY0_BASE,
.length = T931_CSI_PHY0_LENGTH,
},
// Analog PHY
{
.base = T931_APHY_BASE,
.length = T931_APHY_LENGTH,
},
// CSI HOST0
{
.base = T931_CSI_HOST0_BASE,
.length = T931_CSI_HOST0_LENGTH,
},
// MIPI Adapter
{
.base = T931_MIPI_ADAPTER_BASE,
.length = T931_MIPI_ADAPTER_LENGTH,
},
// HIU for clocks.
{
.base = T931_HIU_BASE,
.length = T931_HIU_LENGTH,
},
};
constexpr pbus_bti_t mipi_btis[] = {
{
.iommu_index = 0,
.bti_id = BTI_MIPI,
},
};
constexpr pbus_irq_t mipi_irqs[] = {
{
.irq = T931_MIPI_ADAPTER_IRQ,
.mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
},
};
// Binding rules for MIPI Driver
static const pbus_dev_t mipi_dev = []() {
// MIPI CSI PHY ADAPTER
pbus_dev_t 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_list = mipi_mmios;
dev.mmio_count = countof(mipi_mmios);
dev.bti_list = mipi_btis;
dev.bti_count = countof(mipi_btis);
dev.irq_list = mipi_irqs;
dev.irq_count = countof(mipi_irqs);
return dev;
}();
// Binding rules for Sensor Driver
const pbus_dev_t sensor_dev_sherlock = []() {
pbus_dev_t dev = {};
dev.name = "imx227-sensor";
dev.vid = PDEV_VID_SONY;
dev.pid = PDEV_PID_SONY_IMX227;
dev.did = PDEV_DID_CAMERA_SENSOR;
return dev;
}();
const pbus_dev_t sensor_dev_luis = []() {
pbus_dev_t dev = {};
dev.name = "imx355-sensor";
dev.vid = PDEV_VID_SONY;
dev.pid = PDEV_PID_SONY_IMX355;
dev.did = PDEV_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_impl_.SetAltFunction(T931_GPIOAO(10), kClk24MAltFunc);
gpio_impl_.SetDriveStrength(T931_GPIOAO(10), kClkGpioDriveStrengthUa, nullptr);
zx_status_t status = pbus_.DeviceAdd(&mipi_dev);
if (status != ZX_OK) {
zxlogf(ERROR, "%s: Mipi_Device DeviceAdd failed %d", __func__, status);
return status;
}
if (pid_ == PDEV_PID_LUIS) {
status = pbus_.CompositeDeviceAdd(&sensor_dev_luis, imx355_sensor_fragments,
countof(imx355_sensor_fragments), 1);
} else {
status = pbus_.CompositeDeviceAdd(&sensor_dev_sherlock, imx227_sensor_fragments,
countof(imx227_sensor_fragments), 1);
}
if (status != ZX_OK) {
zxlogf(ERROR, "%s: Camera Sensor DeviceAdd failed %d", __func__, status);
return status;
}
status = pbus_.CompositeDeviceAdd(&gdc_dev, gdc_fragments, countof(gdc_fragments), 1);
if (status != ZX_OK) {
zxlogf(ERROR, "%s: GDC DeviceAdd failed %d", __func__, status);
return status;
}
status = pbus_.CompositeDeviceAdd(&ge2d_dev, ge2d_fragments, countof(ge2d_fragments), 1);
if (status != ZX_OK) {
zxlogf(ERROR, "%s: GE2D DeviceAdd failed %d", __func__, status);
return status;
}
// Add a composite device for ARM ISP
status = pbus_.CompositeDeviceAdd(&isp_dev, isp_fragments, countof(isp_fragments), 1);
if (status != ZX_OK) {
zxlogf(ERROR, "%s: ISP DeviceAdd failed %d", __func__, status);
return status;
}
constexpr zx_device_prop_t camera_controller_props[] = {
{BIND_PLATFORM_DEV_DID, 0, PDEV_DID_CAMERA_CONTROLLER},
};
const composite_device_desc_t camera_comp_desc = {
.props = camera_controller_props,
.props_count = countof(camera_controller_props),
.fragments = camera_controller_fragments,
.fragments_count = countof(camera_controller_fragments),
.coresident_device_index = 0,
.metadata_list = nullptr,
.metadata_count = 0,
};
status = DdkAddComposite("camera-controller", &camera_comp_desc);
if (status != ZX_OK) {
zxlogf(ERROR, "%s: Camera Controller DeviceAdd failed %d", __func__, status);
return status;
}
return status;
}
} // namespace sherlock