| // 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 <fuchsia/hardware/clockimpl/cpp/banjo.h> |
| #include <fuchsia/hardware/gpioimpl/cpp/banjo.h> |
| #include <lib/ddk/binding.h> |
| #include <lib/ddk/debug.h> |
| #include <lib/ddk/device.h> |
| #include <lib/ddk/metadata.h> |
| #include <lib/ddk/platform-defs.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" |
| #include "src/devices/board/drivers/sherlock/camera-controller-bind.h" |
| #include "src/devices/board/drivers/sherlock/camera-gdc-bind.h" |
| #include "src/devices/board/drivers/sherlock/camera-ge2d-bind.h" |
| #include "src/devices/board/drivers/sherlock/camera-isp-bind.h" |
| #include "src/devices/board/drivers/sherlock/imx227-sensor-bind.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; |
| }(); |
| |
| 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; |
| }(); |
| |
| } // 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; |
| } |
| |
| status = |
| pbus_.AddComposite(&sensor_dev_sherlock, reinterpret_cast<uint64_t>(imx227_sensor_fragments), |
| countof(imx227_sensor_fragments), "mipicsi"); |
| if (status != ZX_OK) { |
| zxlogf(ERROR, "%s: Camera Sensor DeviceAdd failed %d", __func__, status); |
| return status; |
| } |
| |
| status = pbus_.AddComposite(&gdc_dev, reinterpret_cast<uint64_t>(gdc_fragments), |
| countof(gdc_fragments), "camera-sensor"); |
| if (status != ZX_OK) { |
| zxlogf(ERROR, "%s: GDC DeviceAdd failed %d", __func__, status); |
| return status; |
| } |
| |
| status = pbus_.AddComposite(&ge2d_dev, reinterpret_cast<uint64_t>(ge2d_fragments), |
| countof(ge2d_fragments), "camera-sensor"); |
| if (status != ZX_OK) { |
| zxlogf(ERROR, "%s: GE2D DeviceAdd failed %d", __func__, status); |
| return status; |
| } |
| |
| // Add a composite device for ARM ISP |
| status = pbus_.AddComposite(&isp_dev, reinterpret_cast<uint64_t>(isp_fragments), |
| countof(isp_fragments), "camera-sensor"); |
| |
| 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), |
| .primary_fragment = "isp", |
| .spawn_colocated = true, |
| .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 |