blob: 0c429e6fb62b0bbd4a9db01f9d223dcdb4a9ac1b [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.
#include "arm-isp.h"
#include "arm-isp-regs.h"
#include <ddk/binding.h>
#include <ddk/debug.h>
#include <ddk/metadata.h>
#include <fbl/alloc_checker.h>
#include <fbl/auto_call.h>
#include <fbl/unique_ptr.h>
#include <hw/reg.h>
#include <memory>
#include <stdlib.h>
#include <threads.h>
#include <unistd.h>
#include <zircon/types.h>
namespace camera {
namespace {
constexpr uint32_t kHiu = 0;
constexpr uint32_t kPowerDomain = 1;
constexpr uint32_t kMemoryDomain = 2;
constexpr uint32_t kReset = 3;
} // namespace
void ArmIspDevice::IspHWReset(bool reset) {
if (reset) {
reset_mmio_->ClearBits32(1 << 1, RESET4_LEVEL);
} else {
reset_mmio_->SetBits32(1 << 1, RESET4_LEVEL);
}
}
void ArmIspDevice::PowerUpIsp() {
// set bit[18-19]=0
power_mmio_->ClearBits32(1 << 18 | 1 << 19, AO_RTI_GEN_PWR_SLEEP0);
zx_nanosleep(zx_deadline_after(ZX_MSEC(5)));
// set bit[18-19]=0
power_mmio_->ClearBits32(1 << 18 | 1 << 19, AO_RTI_GEN_PWR_ISO0);
// MEM_PD_REG0 set 0
memory_pd_mmio_->Write32(0, HHI_ISP_MEM_PD_REG0);
// MEM_PD_REG1 set 0
memory_pd_mmio_->Write32(0, HHI_ISP_MEM_PD_REG1);
// Refer to reference source code
hiu_mmio_->Write32(0x5b446585, HHI_CSI_PHY_CNTL0);
hiu_mmio_->Write32(0x803f4321, HHI_CSI_PHY_CNTL1);
}
zx_status_t ArmIspDevice::InitIsp() {
// The ISP and MIPI module is in same power domain.
// So if we don't call the power sequence of ISP, the mipi module
// won't work and it will block accesses to the mipi register block.
PowerUpIsp();
IspHWReset(true);
// TODO(braval@): Interrupt Init()
IspHWReset(false);
return ZX_OK;
}
zx_status_t ArmIspDevice::InitPdev(zx_device_t* parent) {
if (!pdev_.is_valid()) {
return ZX_ERR_NO_RESOURCES;
}
zx_status_t status = pdev_.MapMmio(kHiu, &hiu_mmio_);
if (status != ZX_OK) {
zxlogf(ERROR, "%s: pdev_.MapMmio failed %d\n", __func__, status);
return status;
}
status = pdev_.MapMmio(kPowerDomain, &power_mmio_);
if (status != ZX_OK) {
zxlogf(ERROR, "%s: pdev_.MapMmio failed %d\n", __func__, status);
return status;
}
status = pdev_.MapMmio(kMemoryDomain, &memory_pd_mmio_);
if (status != ZX_OK) {
zxlogf(ERROR, "%s: pdev_.MapMmio failed %d\n", __func__, status);
return status;
}
status = pdev_.MapMmio(kReset, &reset_mmio_);
if (status != ZX_OK) {
zxlogf(ERROR, "%s: pdev_.MapMmio failed %d\n", __func__, status);
return status;
}
return status;
}
// static
zx_status_t ArmIspDevice::Create(zx_device_t* parent) {
fbl::AllocChecker ac;
auto isp_device = std::unique_ptr<ArmIspDevice>(new (&ac) ArmIspDevice(parent));
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
zx_status_t status = isp_device->InitPdev(parent);
if (status != ZX_OK) {
return status;
}
status = isp_device->DdkAdd("arm-isp");
if (status != ZX_OK) {
zxlogf(ERROR, "arm-isp: Could not create arm-isp device: %d\n", status);
return status;
} else {
zxlogf(INFO, "arm-isp: Added arm-isp device\n");
}
// isp_device intentionally leaked as it is now held by DevMgr.
__UNUSED auto ptr = isp_device.release();
return status;
}
ArmIspDevice::~ArmIspDevice() {
}
void ArmIspDevice::DdkUnbind() {
ShutDown();
DdkRemove();
}
void ArmIspDevice::DdkRelease() {
delete this;
}
void ArmIspDevice::ShutDown() {
}
} // namespace camera