261 lines
8.3 KiB
C
261 lines
8.3 KiB
C
|
/*
|
||
|
* Copyright 2017, 2019-2020 NXP
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
*
|
||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||
|
*/
|
||
|
|
||
|
#include "fsl_mipi_csi2rx.h"
|
||
|
|
||
|
/*
|
||
|
* The MIPI CSI2 peripheral can not work independently, some other control and
|
||
|
* status registers must be used together. There are two integration methods
|
||
|
* with these registers.
|
||
|
*
|
||
|
* 1. The registers are collected in one dedicated module: CSR.
|
||
|
* 2. The registers are scattered in multiple modules.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/*******************************************************************************
|
||
|
* Definitions
|
||
|
******************************************************************************/
|
||
|
|
||
|
/* Component ID definition, used by tools. */
|
||
|
#ifndef FSL_COMPONENT_ID
|
||
|
#define FSL_COMPONENT_ID "platform.drivers.mipi_csi2rx"
|
||
|
#endif
|
||
|
|
||
|
#if (defined(FSL_FEATURE_CSI2RX_CSR_OFFSET) && FSL_FEATURE_CSI2RX_CSR_OFFSET)
|
||
|
#define CSI2RX_GET_CSR(csi_base) (MIPI_CSI_CSR_Type *)((uint32_t)(csi_base) - (uint32_t)FSL_FEATURE_CSI2RX_CSR_OFFSET)
|
||
|
#define MIPI_CSI2RX_HAS_CSR 1
|
||
|
#else
|
||
|
#define MIPI_CSI2RX_HAS_CSR 0
|
||
|
#include "fsl_soc_mipi_csi2rx.h"
|
||
|
#endif
|
||
|
|
||
|
#if MIPI_CSI2RX_HAS_CSR
|
||
|
|
||
|
/* Macro Map */
|
||
|
#ifndef MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK
|
||
|
#define MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK \
|
||
|
MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CONTROLLER_CLOCK_RESET_CONTROL(2U)
|
||
|
#define MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_SW_RESET_MASK \
|
||
|
MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CONTROLLER_CLOCK_RESET_CONTROL(1U)
|
||
|
#endif
|
||
|
|
||
|
#ifndef MIPI_CSI_CSR_PHY_CTRL_CONTI_CLK_MODE_MASK
|
||
|
#define MIPI_CSI_CSR_PHY_CTRL_CONTI_CLK_MODE_MASK MIPI_CSI_CSR_PHY_CTRL_CONT_CLK_MODE_MASK
|
||
|
#endif
|
||
|
|
||
|
#ifndef MIPI_CSI_CSR_PHY_CTRL_PRG_RXHS_SETTLE
|
||
|
#define MIPI_CSI_CSR_PHY_CTRL_PRG_RXHS_SETTLE(x) MIPI_CSI_CSR_PHY_CTRL_S_PRG_RXHS_SETTLE(x)
|
||
|
#endif
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/*******************************************************************************
|
||
|
* Prototypes
|
||
|
******************************************************************************/
|
||
|
|
||
|
/*!
|
||
|
* @brief Returns an instance number given a base address.
|
||
|
*
|
||
|
* If an invalid base address is passed, debug builds will assert. Release builds will just return
|
||
|
* instance number 0.
|
||
|
*
|
||
|
* @param base The CSI2RX peripheral base address.
|
||
|
* @return CSI2RX instance number starting from 0.
|
||
|
*/
|
||
|
uint32_t CSI2RX_GetInstance(MIPI_CSI2RX_Type *base);
|
||
|
|
||
|
#if MIPI_CSI2RX_HAS_CSR
|
||
|
|
||
|
/*!
|
||
|
* @brief Perform CSI2RX resource reset in system level.
|
||
|
*
|
||
|
* @param base The CSI2RX peripheral base address.
|
||
|
* @param reset Pass in true to set to reset state, false to release reset.
|
||
|
*/
|
||
|
static void MIPI_CSI2RX_SoftwareReset(MIPI_CSI2RX_Type *base, bool reset);
|
||
|
|
||
|
/*!
|
||
|
* @brief Initialize the CSI2RX interface.
|
||
|
*
|
||
|
* @param base The CSI2RX peripheral base address.
|
||
|
* @param tHsSettle_EscClk t-HS_SETTLE in esc clock period.
|
||
|
*/
|
||
|
static void MIPI_CSI2RX_InitInterface(MIPI_CSI2RX_Type *base, uint8_t tHsSettle_EscClk);
|
||
|
|
||
|
/*!
|
||
|
* @brief Deinitialize the CSI2RX interface.
|
||
|
*
|
||
|
* @param base The CSI2RX peripheral base address.
|
||
|
*/
|
||
|
static void MIPI_CSI2RX_DeinitInterface(MIPI_CSI2RX_Type *base);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/*******************************************************************************
|
||
|
* Variables
|
||
|
******************************************************************************/
|
||
|
|
||
|
/*! @brief Array to map MIPI CSI2RX instance number to base address. */
|
||
|
static const uint32_t s_csi2rxBaseAddrs[] = MIPI_CSI2RX_BASE_ADDRS;
|
||
|
|
||
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
||
|
/*! @brief Pointers to MPI CSI2RX clocks for each instance. */
|
||
|
static const clock_ip_name_t s_csi2rxClocks[] = MIPI_CSI2RX_CLOCKS;
|
||
|
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
||
|
|
||
|
/*******************************************************************************
|
||
|
* Code
|
||
|
******************************************************************************/
|
||
|
|
||
|
#if MIPI_CSI2RX_HAS_CSR
|
||
|
static void MIPI_CSI2RX_SoftwareReset(MIPI_CSI2RX_Type *base, bool reset)
|
||
|
{
|
||
|
MIPI_CSI_CSR_Type *csr = CSI2RX_GET_CSR(base);
|
||
|
|
||
|
if (reset)
|
||
|
{
|
||
|
csr->CONTROLLER_CLOCK_RESET_CONTROL = MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
csr->CONTROLLER_CLOCK_RESET_CONTROL = MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK;
|
||
|
csr->CONTROLLER_CLOCK_RESET_CONTROL = MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_SW_RESET_MASK |
|
||
|
MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void MIPI_CSI2RX_InitInterface(MIPI_CSI2RX_Type *base, uint8_t tHsSettle_EscClk)
|
||
|
{
|
||
|
MIPI_CSI_CSR_Type *csr = CSI2RX_GET_CSR(base);
|
||
|
|
||
|
/* Pixel link control */
|
||
|
csr->PLM_CTRL = 0;
|
||
|
|
||
|
/* Configure the PHY. */
|
||
|
csr->PHY_CTRL = MIPI_CSI_CSR_PHY_CTRL_RX_ENABLE_MASK | /* Enable RX. */
|
||
|
MIPI_CSI_CSR_PHY_CTRL_AUTO_PD_EN_MASK | /* Auto power down unused lanes. */
|
||
|
MIPI_CSI_CSR_PHY_CTRL_PD_MASK | MIPI_CSI_CSR_PHY_CTRL_DDRCLK_EN_MASK | /* Enable the DDR clock. */
|
||
|
MIPI_CSI_CSR_PHY_CTRL_CONTI_CLK_MODE_MASK | /* Continue clock. */
|
||
|
MIPI_CSI_CSR_PHY_CTRL_RTERM_SEL_MASK | /* LPRX voltage level enable HS termination */
|
||
|
MIPI_CSI_CSR_PHY_CTRL_PRG_RXHS_SETTLE(tHsSettle_EscClk - 1UL); /* T(HS-SETTLE) */
|
||
|
|
||
|
/* Don't support interlace currently. */
|
||
|
csr->VC_INTERLACED = 0U;
|
||
|
|
||
|
/* Don't mask any data type */
|
||
|
#if defined(MIPI_CSI_CSR_DATA_TYPE_DISABLE_BF_DATA_TYPE_DISABLE_MASK)
|
||
|
csr->DATA_TYPE_DISABLE_BF = 0U;
|
||
|
#else
|
||
|
csr->DATA_TYPE_DIS = 0U;
|
||
|
#endif
|
||
|
|
||
|
/* VC fence. */
|
||
|
#if defined(MIPI_CSI_CSR_STREAM_FENCING_CONTROL_STREAM_FENCING_CONTROL_MASK)
|
||
|
csr->STREAM_FENCING_CONTROL = 0U;
|
||
|
#else
|
||
|
csr->STREAM_FENCING_CTRL = 0U;
|
||
|
#endif
|
||
|
|
||
|
#if defined(MIPI_CSI_CSR_PLM_CTRL_PL_CLOCK_RUNNING_MASK)
|
||
|
/* Wait for PL clock active. */
|
||
|
while (0UL != (csr->PLM_CTRL & MIPI_CSI_CSR_PLM_CTRL_PL_CLOCK_RUNNING_MASK))
|
||
|
{
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/* Enable pixel link master. */
|
||
|
csr->PLM_CTRL |= (MIPI_CSI_CSR_PLM_CTRL_ENABLE_MASK | MIPI_CSI_CSR_PLM_CTRL_VALID_OVERRIDE_MASK);
|
||
|
|
||
|
/* Power up PHY. */
|
||
|
csr->PHY_CTRL &= ~MIPI_CSI_CSR_PHY_CTRL_PD_MASK;
|
||
|
|
||
|
/* Start clock. */
|
||
|
csr->CONTROLLER_CLOCK_RESET_CONTROL = MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_SW_RESET_MASK;
|
||
|
}
|
||
|
|
||
|
static void MIPI_CSI2RX_DeinitInterface(MIPI_CSI2RX_Type *base)
|
||
|
{
|
||
|
MIPI_CSI_CSR_Type *csr = CSI2RX_GET_CSR(base);
|
||
|
|
||
|
/* Disable the PHY. */
|
||
|
csr->PHY_CTRL = 0;
|
||
|
|
||
|
/* Disable the pixel link master. */
|
||
|
csr->PLM_CTRL = 0;
|
||
|
|
||
|
/* Stop the clock and assert reset. */
|
||
|
csr->CONTROLLER_CLOCK_RESET_CONTROL = MIPI_CSI_CSR_CONTROLLER_CLOCK_RESET_CONTROL_CTL_CLK_OFF_MASK;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
uint32_t CSI2RX_GetInstance(MIPI_CSI2RX_Type *base)
|
||
|
{
|
||
|
uint32_t i;
|
||
|
|
||
|
for (i = 0U; i < ARRAY_SIZE(s_csi2rxBaseAddrs); i++)
|
||
|
{
|
||
|
if ((uint32_t)base == s_csi2rxBaseAddrs[i])
|
||
|
{
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
assert(false);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* brief Enables and configures the CSI2RX peripheral module.
|
||
|
*
|
||
|
* param base CSI2RX peripheral address.
|
||
|
* param config CSI2RX module configuration structure.
|
||
|
*/
|
||
|
void CSI2RX_Init(MIPI_CSI2RX_Type *base, const csi2rx_config_t *config)
|
||
|
{
|
||
|
assert(NULL != config);
|
||
|
|
||
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
||
|
/* un-gate clock */
|
||
|
(void)CLOCK_EnableClock(s_csi2rxClocks[CSI2RX_GetInstance(base)]);
|
||
|
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
||
|
|
||
|
MIPI_CSI2RX_SoftwareReset(base, false);
|
||
|
|
||
|
CSI2RX_REG_CFG_NUM_LANES(base) = config->laneNum - 1UL;
|
||
|
CSI2RX_REG_CFG_DISABLE_DATA_LANES(base) =
|
||
|
MIPI_CSI2RX_CSI2RX_CFG_NUM_LANES_csi2rx_cfg_num_lanes_MASK & ~((1UL << (uint32_t)config->laneNum) - 1UL);
|
||
|
|
||
|
/* Don't disable data types. */
|
||
|
CSI2RX_REG_CFG_DISABLE_PAYLOAD_0(base) = 0;
|
||
|
CSI2RX_REG_CFG_DISABLE_PAYLOAD_1(base) = 0;
|
||
|
|
||
|
/* Disable all interrupts. */
|
||
|
CSI2RX_REG_IRQ_MASK(base) = MIPI_CSI2RX_CSI2RX_IRQ_MASK_csi2rx_irq_mask_MASK;
|
||
|
|
||
|
MIPI_CSI2RX_InitInterface(base, config->tHsSettle_EscClk);
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
* brief Disables the CSI2RX peripheral module.
|
||
|
*
|
||
|
* param base CSI2RX peripheral address.
|
||
|
*/
|
||
|
void CSI2RX_Deinit(MIPI_CSI2RX_Type *base)
|
||
|
{
|
||
|
MIPI_CSI2RX_DeinitInterface(base);
|
||
|
|
||
|
MIPI_CSI2RX_SoftwareReset(base, true);
|
||
|
|
||
|
#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
|
||
|
/* gate clock */
|
||
|
(void)CLOCK_DisableClock(s_csi2rxClocks[CSI2RX_GetInstance(base)]);
|
||
|
#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
|
||
|
}
|