kernel-brax3-ubuntu-touch/drivers/misc/mediatek/cameraisp/pda/isp_71/camera_pda.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

2667 lines
75 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2021 MediaTek Inc.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/jiffies.h>
#include <linux/time.h> //do_gettimeofday()
#include "mtk-interconnect.h"
// --------- DMA-BUF ----------
#include <linux/dma-heap.h>
#include <linux/dma-direction.h>
#include <linux/scatterlist.h>
#include <linux/dma-buf.h>
// ----------------------------
#include <soc/mediatek/smi.h> // mtk_smi_larb_get()
#include "camera_pda.h"
// --------- define region --------
// #define FPGA_UT
// #define GET_PDA_TIME
// #define FOR_DEBUG
// #define SMI_LOG
#define CHECK_IRQ_COUNT
#define PDA_MMQOS
// --------------------------------
#ifdef PDA_TF_DUMP_71_1
#include "iommu_debug.h"
#include <dt-bindings/memory/mt6983-larb-port.h>
#endif
#define PDA_DEV_NAME "camera-pda"
#define LOG_INF(format, args...) \
pr_info(PDA_DEV_NAME " [%s] " format, __func__, ##args)
#ifndef MTRUE
#define MTRUE 1
#endif
#ifndef MFALSE
#define MFALSE 0
#endif
//define the write register function
#define mt_reg_sync_writel(v, a) \
do { \
*(unsigned int *)(a) = (v); \
mb(); /*make sure register access in order */ \
} while (0)
#define PDA_WR32(addr, data) mt_reg_sync_writel(data, addr)
#define PDA_RD32(addr) ioread32(addr)
#ifdef FPGA_UT
void __iomem *CAMSYS_CONFIG_BASE;
#define CAMSYS_MAIN_BASE_ADDR CAMSYS_CONFIG_BASE
#define REG_CAMSYS_CG_SET (CAMSYS_MAIN_BASE_ADDR + 0x4)
#define REG_CAMSYS_CG_CLR (CAMSYS_MAIN_BASE_ADDR + 0x8)
#endif
void __iomem *MRAW_BASE;
#define MRAW_BASE_ADDR MRAW_BASE
#define REG_CAMSYS_SW_RST (MRAW_BASE_ADDR + 0xA0)
#define PDA_DONE 0x00000001
#define PDA_ERROR 0x00000002
#define PDA_STATUS_REG 0x00000001
#define PDA_CLEAR_REG 0x00000000
#define PDA_TRIGGER 0x00000003
#define PDA_DOUBLE_BUFFER 0x00000009
#define PDA_MAKE_RESET 0x00000002
#define MASK_BIT_ZERO 0x00000001
#define PDA_RESET_VALUE 0x00000001
#define PDA_HW_RESET 0x00000004
struct device *g_dev1, *g_dev2;
struct device *larb1;
struct device *larb2;
static spinlock_t g_PDA_SpinLock;
wait_queue_head_t g_wait_queue_head;
// PDA HW quantity
static unsigned int g_PDA_quantity;
#ifdef CHECK_IRQ_COUNT
// Calculate reasonable irq counts
static unsigned int g_reasonable_IRQCount;
static int g_PDA0_IRQCount;
static int g_PDA1_IRQCount;
#endif
static struct PDA_Data_t_v2 g_pda_Pdadata;
// pda device information
// static struct PDA_device *PDA_devs;
static struct PDA_device PDA_devs[PDA_MAX_QUANTITY];
// clock relate
static const char * const clk_names[] = {
"camsys_mraw_pda0",
"camsys_mraw_pda1",
"mraw_larbx",
"cam_main_cam2mm0_gals_cg_con",
"cam_main_cam2mm1_gals_cg_con",
"cam_main_cam_cg_con",
};
#define PDA_CLK_NUM ARRAY_SIZE(clk_names)
struct PDA_CLK_STRUCT pda_clk[PDA_CLK_NUM];
#ifdef PDA_MMQOS
// mmqos relate
static const char * const mmqos_names_rdma[] = {
"l25_pdai_a0",
"l25_pdai_a1",
"l26_pdai_b0",
"l26_pdai_b1"
};
#define PDA_MMQOS_RDMA_NUM ARRAY_SIZE(mmqos_names_rdma)
struct icc_path *icc_path_pda_rdma[PDA_MMQOS_RDMA_NUM];
static const char * const mmqos_names_wdma[] = {
"l25_pdao_a",
"l26_pdao_b"
};
#define PDA_MMQOS_WDMA_NUM ARRAY_SIZE(mmqos_names_wdma)
struct icc_path *icc_path_pda_wdma[PDA_MMQOS_WDMA_NUM];
#endif
// Enable clock count
static unsigned int g_u4EnableClockCount;
#ifdef GET_PDA_TIME
// Get PDA process time
struct timespec64 time_end;
struct timespec64 total_time_begin, total_time_end;
struct timespec64 pda1_done_b, pda1_done_e;
struct timespec64 pda2_done_b, pda2_done_e;
#endif
// calculate 1024 roi data
unsigned int g_rgn_x_buf[PDA_MAXROI_PER_ROUND];
unsigned int g_rgn_y_buf[PDA_MAXROI_PER_ROUND];
unsigned int g_rgn_h_buf[PDA_MAXROI_PER_ROUND];
unsigned int g_rgn_w_buf[PDA_MAXROI_PER_ROUND];
unsigned int g_rgn_iw_buf[PDA_MAXROI_PER_ROUND];
// buffer mmu
struct pda_mmu g_image_mmu;
struct pda_mmu g_table_mmu;
struct pda_mmu g_output_mmu;
// Output buffer
unsigned long g_Address_LI;
unsigned long g_Address_RI;
unsigned long g_Address_LT;
unsigned long g_Address_RT;
static unsigned long g_OutputBufferAddr;
static unsigned long g_OutputBufferOffset;
#ifdef FOR_DEBUG
// buffer address
unsigned int *g_buf_LI_va;
unsigned int *g_buf_RI_va;
unsigned int *g_buf_LT_va;
unsigned int *g_buf_RT_va;
unsigned int *g_buf_Out_va;
#endif
// current Process ROI number
unsigned int g_CurrentProcRoiNum[PDA_MAX_QUANTITY];
#ifdef PDA_MMQOS
static void pda_mmqos_init(void)
{
int i = 0;
// get interconnect path for MMQOS
for (i = 0; i < PDA_MMQOS_RDMA_NUM; ++i) {
LOG_INF("rdma index: %d, mmqos name: %s\n", i, mmqos_names_rdma[i]);
icc_path_pda_rdma[i] = of_mtk_icc_get(g_dev1, mmqos_names_rdma[i]);
}
// get interconnect path for MMQOS
for (i = 0; i < PDA_MMQOS_WDMA_NUM; ++i) {
LOG_INF("wdma index: %d, mmqos name: %s\n", i, mmqos_names_wdma[i]);
icc_path_pda_wdma[i] = of_mtk_icc_get(g_dev1, mmqos_names_wdma[i]);
}
}
static void pda_mmqos_bw_set(void)
{
int i = 0;
// int Inter_ROI_Max_Width = 1024;
// int Inter_ROI_Max_Height = 96;
int Inter_Frame_Size_Width = 2048;
int Inter_Frame_Size_Height = 192;
int Mach_ROI_Max_Width = 2048;
int Mach_ROI_Max_Height = 96;
int Mach_Frame_Size_Width = 4096;
int Mach_Frame_Size_Height = 192;
double Freqency = 360.0;
int FOV = 100;
int ROI_Number = 45;
int Frame_Rate = 30;
// int Expected_HW_Compute_time = 15;
int Search_Range = 40;
// Intermediate data
double Operation_Margin = 1.2;
int Inter_Frame_Size = Inter_Frame_Size_Width * Inter_Frame_Size_Height;
int Mach_Frame_Size = Mach_Frame_Size_Width * Mach_Frame_Size_Height;
// int Inter_Factor = 8;
int Inter_Frame_Size_FOV = Inter_Frame_Size * FOV / 100;
int Mach_Frame_Size_FOV = Mach_Frame_Size * FOV / 100;
int Inter_Input_Total_pixel_Itar = Inter_Frame_Size_FOV;
int Inter_Input_Total_pixel_Iref = Inter_Frame_Size_FOV;
int Mach_Input_Total_pixel_Itar =
(ROI_Number*Search_Range*Mach_ROI_Max_Height) +
Mach_Frame_Size_FOV +
(1*Mach_ROI_Max_Width);
// int Mach_Input_Total_pixel_Iref = Mach_Frame_Size_FOV;
int Required_Operation_Cycle =
(int)(Mach_Input_Total_pixel_Itar *
Operation_Margin *
(Search_Range+1)) /
Search_Range + 1;
int WDMA_Data = OUT_BYTE_PER_ROI*ROI_Number;
int temp = Inter_Input_Total_pixel_Itar+Inter_Input_Total_pixel_Iref;
int RDMA_Data = temp*20/8;
double OperationTime = (double)Required_Operation_Cycle / Freqency / 1000.0;
// WDMA BW estimate
double WDMA_PEAK_BW = (double)WDMA_Data / (double)OperationTime / 1000.0;
double WDMA_AVG_BW = (double)WDMA_Data * Frame_Rate * (1.33) / 1000000.0;
// RDMA BW estimate
double RDMA_PEAK_BW = (double)RDMA_Data / (double)OperationTime / 1000.0;
double RDMA_AVG_BW = (double)RDMA_Data / (1000000.0/(double)Frame_Rate);
// Left/Right RDMA BW
double IMAGE_TABLE_RDMA_PEAK_BW = RDMA_PEAK_BW / 2;
double IMAGE_TABLE_RDMA_AVG_BW = RDMA_AVG_BW * (1.33) / 2;
// pda is not HRT engine, no need to set HRT bw
IMAGE_TABLE_RDMA_PEAK_BW = 0;
WDMA_PEAK_BW = 0;
LOG_INF("RDMA_BW AVG/PEAK: %d/%d, WDMA_BW AVG/PEAK: %d/%d\n",
(int)MBps_to_icc(IMAGE_TABLE_RDMA_AVG_BW),
(int)MBps_to_icc(IMAGE_TABLE_RDMA_PEAK_BW),
(int)MBps_to_icc(WDMA_AVG_BW),
(int)MBps_to_icc(WDMA_PEAK_BW));
// MMQOS set bw
for (i = 0; i < PDA_MMQOS_RDMA_NUM; ++i) {
if (icc_path_pda_rdma[i]) {
mtk_icc_set_bw(icc_path_pda_rdma[i],
(int)MBps_to_icc(IMAGE_TABLE_RDMA_AVG_BW),
(int)MBps_to_icc(IMAGE_TABLE_RDMA_PEAK_BW));
}
}
for (i = 0; i < PDA_MMQOS_WDMA_NUM; ++i) {
if (icc_path_pda_wdma[i]) {
mtk_icc_set_bw(icc_path_pda_wdma[i],
(int)MBps_to_icc(WDMA_AVG_BW),
(int)MBps_to_icc(WDMA_PEAK_BW));
}
}
}
static void pda_mmqos_bw_reset(void)
{
int i = 0;
#ifdef FOR_DEBUG
LOG_INF("mmqos reset\n");
#endif
// MMQOS set bw
for (i = 0; i < PDA_MMQOS_RDMA_NUM; ++i) {
if (icc_path_pda_rdma[i])
mtk_icc_set_bw(icc_path_pda_rdma[i], 0, 0);
}
for (i = 0; i < PDA_MMQOS_WDMA_NUM; ++i) {
if (icc_path_pda_wdma[i])
mtk_icc_set_bw(icc_path_pda_wdma[i], 0, 0);
}
}
#endif
struct device *pda_init_larb(struct platform_device *pdev, int idx)
{
struct device_node *node;
struct platform_device *larb_pdev;
struct device_link *link;
/* get larb node from dts */
node = of_parse_phandle(pdev->dev.of_node, "mediatek,larbs", idx);
if (!node) {
LOG_INF("fail to parse mediatek,larb\n");
return NULL;
}
larb_pdev = of_find_device_by_node(node);
if (WARN_ON(!larb_pdev)) {
of_node_put(node);
LOG_INF("no larb for idx %d\n", idx);
return NULL;
}
of_node_put(node);
link = device_link_add(&pdev->dev, &larb_pdev->dev,
DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS);
if (!link)
LOG_INF("unable to link smi larb%d\n", idx);
LOG_INF("pdev %p idx %d\n", pdev, idx);
return &larb_pdev->dev;
}
static inline void PDA_Prepare_Enable_ccf_clock(void)
{
int ret, i;
#if IS_ENABLED(CONFIG_OF)
/* consumer device starting work*/
if (g_PDA_quantity > 0)
pm_runtime_get_sync(g_dev1); //Note: Its not larb's device.
if (g_PDA_quantity > 1)
pm_runtime_get_sync(g_dev2); //Note: Its not larb's device.
#ifdef FOR_DEBUG
LOG_INF("pm_runtime_get_sync done\n");
#endif
#endif
for (i = 0; i < PDA_CLK_NUM; i++) {
ret = clk_prepare_enable(pda_clk[i].CG_PDA_TOP_MUX);
if (ret)
LOG_INF("cannot enable clock (%s)\n", clk_names[i]);
#ifdef FOR_DEBUG
LOG_INF("clk_prepare_enable (%s) done", clk_names[i]);
#endif
}
#ifdef FOR_DEBUG
LOG_INF("clk_prepare_enable done");
#endif
}
static inline void PDA_Disable_Unprepare_ccf_clock(void)
{
int i;
for (i = 0; i < PDA_CLK_NUM; i++) {
clk_disable_unprepare(pda_clk[i].CG_PDA_TOP_MUX);
#ifdef FOR_DEBUG
LOG_INF("clk_disable_unprepare (%s) done\n", clk_names[i]);
#endif
}
#if IS_ENABLED(CONFIG_OF)
if (g_PDA_quantity > 1)
pm_runtime_put_sync(g_dev2);
if (g_PDA_quantity > 0)
pm_runtime_put_sync(g_dev1);
#ifdef FOR_DEBUG
LOG_INF("pm_runtime_put_sync done\n");
#endif
#endif
}
/**************************************************************
*
**************************************************************/
static void EnableClock(bool En)
{
if (En) { /* Enable clock. */
// Enable clock count
spin_lock(&g_PDA_SpinLock);
switch (g_u4EnableClockCount) {
case 0:
g_u4EnableClockCount++;
spin_unlock(&g_PDA_SpinLock);
#ifndef FPGA_UT
#ifdef FOR_DEBUG
LOG_INF("It's real ic load, Enable Clock");
#endif
PDA_Prepare_Enable_ccf_clock();
#else
// Enable clock by hardcode:
LOG_INF("It's LDVT load, Enable Clock");
PDA_WR32(REG_CAMSYS_CG_CLR, 0xFFFFFFFF);
#endif
break;
default:
g_u4EnableClockCount++;
spin_unlock(&g_PDA_SpinLock);
break;
}
} else { /* Disable clock. */
// Disable clock count
spin_lock(&g_PDA_SpinLock);
g_u4EnableClockCount--;
switch (g_u4EnableClockCount) {
case 0:
spin_unlock(&g_PDA_SpinLock);
#ifndef FPGA_UT
#ifdef FOR_DEBUG
LOG_INF("It's real ic load, Disable Clock");
#endif
PDA_Disable_Unprepare_ccf_clock();
#else
// Disable clock by hardcode:
LOG_INF("It's LDVT load, Disable Clock");
PDA_WR32(REG_CAMSYS_CG_SET, 0xFFFFFFFF);
#endif
break;
default:
spin_unlock(&g_PDA_SpinLock);
break;
}
}
}
static void pda_reset(unsigned int PDA_Index)
{
unsigned long end = 0;
end = jiffies + msecs_to_jiffies(100);
// reset HW status
PDA_devs[PDA_Index].HWstatus = 0;
// clear dma_soft_rst_stat
PDA_WR32(PDA_devs[PDA_Index].m_pda_base + PDA_PDA_DMA_RST_REG,
PDA_CLEAR_REG);
// make reset
PDA_WR32(PDA_devs[PDA_Index].m_pda_base + PDA_PDA_DMA_RST_REG,
PDA_MAKE_RESET);
wmb(); /* TBC */
while (time_before(jiffies, end)) {
if ((PDA_RD32(PDA_devs[PDA_Index].m_pda_base + PDA_PDA_DMA_RST_REG) &
MASK_BIT_ZERO)) {
// equivalent to hardware reset
PDA_WR32(PDA_devs[PDA_Index].m_pda_base + PDA_PDA_TOP_CTL_REG,
PDA_HW_RESET);
// clear reset signal
PDA_WR32(PDA_devs[PDA_Index].m_pda_base + PDA_PDA_DMA_RST_REG,
PDA_CLEAR_REG);
wmb(); /* TBC */
// clear hardware reset signal
PDA_WR32(PDA_devs[PDA_Index].m_pda_base + PDA_PDA_TOP_CTL_REG,
PDA_CLEAR_REG);
// LOG_INF("reset PDA%d hw success\n", PDA_Index);
return;
}
LOG_INF("PDA%d Wait EMI request, DMA_RST:0x%x\n",
PDA_Index,
PDA_RD32(PDA_devs[PDA_Index].m_pda_base + PDA_PDA_DMA_RST_REG));
usleep_range(10, 20);
}
LOG_INF("reset PDA%d hw timeout\n", PDA_Index);
}
static void pda_nontransaction_reset(unsigned int PDA_Index)
{
unsigned int MRAW_reset_value = 0;
unsigned int Reset_Bitmask = 0;
// equivalent to hardware reset
PDA_WR32(PDA_devs[PDA_Index].m_pda_base + PDA_PDA_TOP_CTL_REG,
PDA_HW_RESET);
// clear hardware reset signal
PDA_WR32(PDA_devs[PDA_Index].m_pda_base + PDA_PDA_TOP_CTL_REG,
PDA_CLEAR_REG);
//MRAW PDA reset
MRAW_reset_value = PDA_RD32(REG_CAMSYS_SW_RST);
if (PDA_Index == 0)
Reset_Bitmask = BIT(12) | BIT(13);
else if (PDA_Index == 1)
Reset_Bitmask = BIT(14) | BIT(15);
// LOG_INF("before, MRAW_reset_value: %x\n", MRAW_reset_value);
MRAW_reset_value |= Reset_Bitmask;
PDA_WR32(REG_CAMSYS_SW_RST, MRAW_reset_value);
// LOG_INF("after, MRAW_reset_value: %x\n", PDA_RD32(REG_CAMSYS_SW_RST));
MRAW_reset_value &= (!Reset_Bitmask);
PDA_WR32(REG_CAMSYS_SW_RST, MRAW_reset_value);
// LOG_INF("clear bit, MRAW_reset_value: %x\n", PDA_RD32(REG_CAMSYS_SW_RST));
}
static int pda_get_dma_buffer(struct pda_mmu *mmu, int fd)
{
struct dma_buf *buf;
#ifdef FOR_DEBUG
LOG_INF("get_dma_buffer_fd= %d\n", fd);
#endif
if (fd < 0)
return -1;
buf = dma_buf_get(fd);
if (IS_ERR(buf))
return -1;
mmu->dma_buf = buf;
mmu->attach = dma_buf_attach(mmu->dma_buf, g_dev1);
if (IS_ERR(mmu->attach))
goto err_attach;
#ifdef FOR_DEBUG
LOG_INF("mmu->attach = %x\n", mmu->attach);
#endif
mmu->sgt = dma_buf_map_attachment(mmu->attach, DMA_BIDIRECTIONAL);
if (IS_ERR(mmu->sgt))
goto err_map;
#ifdef FOR_DEBUG
LOG_INF("mmu->sgt = %x\n", mmu->sgt);
#endif
return 0;
err_map:
dma_buf_detach(mmu->dma_buf, mmu->attach);
LOG_INF("err_map!\n");
err_attach:
LOG_INF("err_attach!\n");
dma_buf_put(mmu->dma_buf);
return -1;
}
static void pda_put_dma_buffer(struct pda_mmu *mmu)
{
if (mmu->attach == NULL || mmu->sgt == NULL) {
LOG_INF("attach or sgt is null, no need to free iova\n");
return;
}
if (mmu->dma_buf) {
dma_buf_unmap_attachment(mmu->attach, mmu->sgt, DMA_BIDIRECTIONAL);
dma_buf_detach(mmu->dma_buf, mmu->attach);
dma_buf_put(mmu->dma_buf);
}
}
static int Get_Input_Addr_From_DMABUF(struct PDA_Data_t_v2 *pda_PdaConfig)
{
int ret = 0;
unsigned int i = 0;
// Left image buffer
ret = pda_get_dma_buffer(&g_image_mmu, pda_PdaConfig->FD_L_Image);
if (ret < 0) {
LOG_INF("Left image, pda_get_dma_buffer fail!\n");
return ret;
}
g_Address_LI = (unsigned long) sg_dma_address(g_image_mmu.sgt->sgl);
pda_PdaConfig->PDA_PDAI_P1_BASE_ADDR = (unsigned int)g_Address_LI;
for (i = 0; i < g_PDA_quantity; i++) {
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_BASE_ADDR_MSB_REG,
(unsigned int)(g_Address_LI >> 32));
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_BASE_ADDR_REG,
(unsigned int)(g_Address_LI));
}
#ifdef FOR_DEBUG
LOG_INF("Left image MVA MSB = 0x%lx\n", g_Address_LI);
for (i = 0; i < g_PDA_quantity; i++) {
LOG_INF("Left image MVA MSB = 0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_BASE_ADDR_MSB_REG));
LOG_INF("Left image MVA = 0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_BASE_ADDR_REG));
}
#endif
// Right image buffer
g_Address_RI = g_Address_LI + pda_PdaConfig->ImageSize;
pda_PdaConfig->PDA_PDAI_P2_BASE_ADDR = (unsigned int)(g_Address_RI);
for (i = 0; i < g_PDA_quantity; i++) {
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_BASE_ADDR_MSB_REG,
(unsigned int)(g_Address_RI >> 32));
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_BASE_ADDR_REG,
(unsigned int)(g_Address_RI));
}
#ifdef FOR_DEBUG
LOG_INF("Right image MVA MSB = 0x%lx\n", g_Address_RI);
for (i = 0; i < g_PDA_quantity; i++) {
LOG_INF("Right image MVA MSB = 0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_BASE_ADDR_MSB_REG));
LOG_INF("Right image MVA = 0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_BASE_ADDR_REG));
}
#endif
// Left table buffer
ret = pda_get_dma_buffer(&g_table_mmu, pda_PdaConfig->FD_L_Table);
if (ret < 0) {
LOG_INF("Left table, pda_get_dma_buffer fail!\n");
return ret;
}
g_Address_LT = (unsigned long) sg_dma_address(g_table_mmu.sgt->sgl);
pda_PdaConfig->PDA_PDATI_P1_BASE_ADDR = (unsigned int)g_Address_LT;
for (i = 0; i < g_PDA_quantity; i++) {
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_BASE_ADDR_MSB_REG,
(unsigned int)(g_Address_LT >> 32));
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_BASE_ADDR_REG,
(unsigned int)(g_Address_LT));
}
#ifdef FOR_DEBUG
LOG_INF("Left table MVA MSB = 0x%lx\n", g_Address_LT);
for (i = 0; i < g_PDA_quantity; i++) {
LOG_INF("Left table MVA MSB = 0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_BASE_ADDR_MSB_REG));
LOG_INF("Left table MVA = 0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_BASE_ADDR_REG));
}
#endif
// Right table buffer
g_Address_RT = g_Address_LT + pda_PdaConfig->TableSize;
pda_PdaConfig->PDA_PDATI_P2_BASE_ADDR = (unsigned int)(g_Address_RT);
for (i = 0; i < g_PDA_quantity; i++) {
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_BASE_ADDR_MSB_REG,
(unsigned int)(g_Address_RT >> 32));
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_BASE_ADDR_REG,
(unsigned int)(g_Address_RT));
}
#ifdef FOR_DEBUG
LOG_INF("Right table MVA MSB = 0x%lx\n", g_Address_RT);
for (i = 0; i < g_PDA_quantity; i++) {
LOG_INF("Right table MVA MSB = 0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_BASE_ADDR_MSB_REG));
LOG_INF("Right table MVA = 0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_BASE_ADDR_REG));
}
#endif
return ret;
}
static int Get_Output_Addr_From_DMABUF(struct PDA_Data_t_v2 *pda_PdaConfig)
{
int ret = 0;
unsigned int i = 0;
// Output buffer
ret = pda_get_dma_buffer(&g_output_mmu, pda_PdaConfig->FD_Output);
if (ret < 0) {
LOG_INF("Output, pda_get_dma_buffer fail!\n");
return ret;
}
g_OutputBufferAddr = (unsigned long) sg_dma_address(g_output_mmu.sgt->sgl);
pda_PdaConfig->PDA_PDAO_P1_BASE_ADDR = (unsigned int)g_OutputBufferAddr;
for (i = 0; i < g_PDA_quantity; i++) {
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_BASE_ADDR_MSB_REG,
(unsigned int)(g_OutputBufferAddr >> 32));
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_BASE_ADDR_REG,
(unsigned int)(g_OutputBufferAddr));
}
#ifdef FOR_DEBUG
LOG_INF("Output buffer MVA MSB = 0x%lx\n", g_OutputBufferAddr);
for (i = 0; i < g_PDA_quantity; i++) {
LOG_INF("Output buffer MVA MSB = 0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_BASE_ADDR_MSB_REG));
LOG_INF("Output buffer MVA = 0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_BASE_ADDR_REG));
}
#endif
return ret;
}
static void HWDMASettings(struct PDA_Data_t_v2 *pda_PdaConfig)
{
unsigned int i;
for (i = 0; i < g_PDA_quantity; i++) {
// --------- Frame setting part -----------
PDA_WR32(PDA_devs[i].m_pda_base + PDA_CFG_0_REG,
pda_PdaConfig->PDA_FrameSetting.PDA_CFG_0.Raw);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_CFG_1_REG,
pda_PdaConfig->PDA_FrameSetting.PDA_CFG_1.Raw);
// need set roi number every process
// PDA_WR32(PDA_devs[i].m_pda_base + PDA_CFG_2_REG,
// pda_PdaConfig->PDA_FrameSetting.PDA_CFG_2.Raw);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_CFG_3_REG,
pda_PdaConfig->PDA_FrameSetting.PDA_CFG_3.Raw);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_CFG_4_REG,
pda_PdaConfig->PDA_FrameSetting.PDA_CFG_4.Raw);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_CFG_5_REG,
pda_PdaConfig->PDA_FrameSetting.PDA_CFG_5.Raw);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_CFG_6_REG,
pda_PdaConfig->PDA_FrameSetting.PDA_CFG_6.Raw);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_CFG_7_REG,
pda_PdaConfig->PDA_FrameSetting.PDA_CFG_7.Raw);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_CFG_8_REG,
pda_PdaConfig->PDA_FrameSetting.PDA_CFG_8.Raw);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_CFG_9_REG,
pda_PdaConfig->PDA_FrameSetting.PDA_CFG_9.Raw);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_CFG_10_REG,
pda_PdaConfig->PDA_FrameSetting.PDA_CFG_10.Raw);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_CFG_11_REG,
pda_PdaConfig->PDA_FrameSetting.PDA_CFG_11.Raw);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_CFG_12_REG,
pda_PdaConfig->PDA_FrameSetting.PDA_CFG_12.Raw);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_CFG_13_REG,
pda_PdaConfig->PDA_FrameSetting.PDA_CFG_13.Raw);
// --------- Input buffer address -------------
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_BASE_ADDR_REG,
pda_PdaConfig->PDA_PDAI_P1_BASE_ADDR);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_BASE_ADDR_REG,
pda_PdaConfig->PDA_PDATI_P1_BASE_ADDR);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_BASE_ADDR_REG,
pda_PdaConfig->PDA_PDAI_P2_BASE_ADDR);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_BASE_ADDR_REG,
pda_PdaConfig->PDA_PDATI_P2_BASE_ADDR);
// --------- DMA Secure part -------------
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDA_SECURE_REG, 0x9daf851f);
// --------- config setting hard code part --------------
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_STRIDE_REG, 0x580);
// Left image
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_CON0_REG, 0x10000134);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_CON1_REG, 0x104d004d);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_CON2_REG, 0x009a009a);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_CON3_REG, 0x00e700e7);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_CON4_REG, 0x009a009a);
// Left table
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_CON0_REG, 0x1000004c);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_CON1_REG, 0x10130013);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_CON2_REG, 0x00260026);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_CON3_REG, 0x00390039);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_CON4_REG, 0x00260026);
// Right image
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_CON0_REG, 0x10000134);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_CON1_REG, 0x104d004d);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_CON2_REG, 0x009a009a);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_CON3_REG, 0x00e700e7);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_CON4_REG, 0x009a009a);
// Right table
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_CON0_REG, 0x1000004c);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_CON1_REG, 0x10130013);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_CON2_REG, 0x00260026);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_CON3_REG, 0x00390039);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_CON4_REG, 0x00260026);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_XSIZE_REG, 0x0000057f);
// Output
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_CON0_REG, 0x10000040);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_CON1_REG, 0x10100010);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_CON2_REG, 0x00200020);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_CON3_REG, 0x00300030);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_CON4_REG, 0x00200020);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDA_DMA_EN_REG, 0x0000001f);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDA_DMA_RST_REG, 0x1);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDA_DMA_TOP_REG, 0x407);
// DCM all off: 0x0000007F
// DCM all on: 0x00000000
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDA_DCM_DIS_REG, 0x0000007F);
//disable dma error irq: 0x00000000
//enable dma error irq: 0xffff0000
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_ERR_STAT_REG,
0x00000000);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_ERR_STAT_REG,
0x00000000);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_ERR_STAT_REG,
0x00000000);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_ERR_STAT_REG,
0x00000000);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_ERR_STAT_REG,
0x00000000);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDA_TOP_CTL_REG, 0x00000000);
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDA_IRQ_TRIG_REG, 0x0);
// setting read clear
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDA_ERR_STAT_EN_REG, 0x00000001);
// read 0x3b4, avoid the impact of previous data
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDA_ERR_STAT_REG);
// read clear dma status
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_ERR_STAT_REG);
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_ERR_STAT_REG);
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_ERR_STAT_REG);
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_ERR_STAT_REG);
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_ERR_STAT_REG);
}
}
static int ProcessROIData(struct PDA_Data_t_v2 *pda_data,
unsigned int RoiProcNum,
unsigned int ROIIndex,
unsigned int isFixROI,
unsigned int p_index)
{
unsigned int i = 0, j = 0;
unsigned int xnum = 0, ynum = 0;
unsigned int woverlap = 0, hoverlap = 0;
unsigned int x_p, y_p, w_p, h_p;
unsigned int nWidth = 0, nHeight = 0;
int nLocalBufIndex = 0;
unsigned int nXDirLoopCount = 0;
if (isFixROI) {
#ifdef FOR_DEBUG
LOG_INF("Sequential ROI\n");
#endif
xnum = pda_data->xnum[p_index];
ynum = pda_data->ynum[p_index];
woverlap = (int)pda_data->woverlap[p_index];
hoverlap = (int)pda_data->hoverlap[p_index];
x_p = pda_data->fix_rgn_x[p_index];
y_p = pda_data->fix_rgn_y[p_index];
w_p = pda_data->fix_rgn_w[p_index];
h_p = pda_data->fix_rgn_h[p_index];
if (xnum <= 0 || ynum <= 0) {
LOG_INF("xnum(%d) or ynum(%d) value is invalid\n", xnum, ynum);
return -1;
}
nWidth = w_p / xnum;
nHeight = h_p / ynum;
#ifdef FOR_DEBUG
LOG_INF("p_index(%d), nWidth(%d), nHeight(%d)\n", p_index, nWidth, nHeight);
LOG_INF("xnum(%d), ynum(%d)\n", xnum, ynum);
LOG_INF("woverlap(%d), hoverlap(%d)\n", woverlap, hoverlap);
LOG_INF("x_p(%d), y_p(%d), w_p(%d), h_p(%d)\n", x_p, y_p, w_p, h_p);
#endif
if (w_p < xnum || h_p < ynum) {
LOG_INF("w_p(%d)/h_p(%d) can't less than xnum(%d)/ynum(%d)\n",
w_p, h_p, xnum, ynum);
return -1;
}
if (pda_data->PDA_FrameSetting.PDA_CFG_1.Bits.PDA_PR_XNUM == 0) {
LOG_INF("Fail: PDA_PR_XNUM is zero\n");
return -1;
}
for (j = (ROIIndex / xnum); j < ynum; j++) {
i = (nXDirLoopCount == 0 ? (ROIIndex % xnum) : 0);
for (; i < xnum; i++) {
nLocalBufIndex = j * xnum + i - ROIIndex;
if (nLocalBufIndex >= PDA_MAXROI_PER_ROUND || nLocalBufIndex < 0) {
LOG_INF("nLocalBufIndex out of range (%d)\n",
nLocalBufIndex);
return -1;
}
if (i != 0 && i != xnum - 1) {
g_rgn_x_buf[nLocalBufIndex] =
x_p + nWidth * i - nWidth * woverlap / 100;
g_rgn_w_buf[nLocalBufIndex] =
nWidth + 2 * nWidth * woverlap / 100;
} else if (i == 0) {
g_rgn_x_buf[nLocalBufIndex] = x_p + nWidth * i;
g_rgn_w_buf[nLocalBufIndex] =
nWidth + nWidth * woverlap / 100;
} else {
g_rgn_x_buf[nLocalBufIndex] =
x_p + nWidth * i - nWidth * woverlap / 100;
g_rgn_w_buf[nLocalBufIndex] =
nWidth + nWidth * woverlap / 100;
}
if (j != 0 && j != ynum - 1) {
g_rgn_y_buf[nLocalBufIndex] =
y_p + nHeight * j - nHeight * hoverlap / 100;
g_rgn_h_buf[nLocalBufIndex] =
nHeight + 2 * nHeight * hoverlap / 100;
} else if (j == 0) {
g_rgn_y_buf[nLocalBufIndex] = y_p + nHeight * j;
g_rgn_h_buf[nLocalBufIndex] =
nHeight + nHeight * hoverlap / 100;
} else {
g_rgn_y_buf[nLocalBufIndex] =
y_p + nHeight * j - nHeight * hoverlap / 100;
g_rgn_h_buf[nLocalBufIndex] =
nHeight + nHeight * hoverlap / 100;
}
g_rgn_iw_buf[nLocalBufIndex] =
g_rgn_w_buf[nLocalBufIndex] *
(pda_data->PDA_FrameSetting.PDA_CFG_1.Bits.PDA_PAT_WIDTH /
pda_data->PDA_FrameSetting.PDA_CFG_1.Bits.PDA_PR_XNUM);
#ifdef FOR_DEBUG
LOG_INF("ROI_IW_%d, iw:%d, w:%d, pat_width:%d\n",
nLocalBufIndex,
g_rgn_iw_buf[nLocalBufIndex],
g_rgn_w_buf[nLocalBufIndex],
pda_data->PDA_FrameSetting.PDA_CFG_1.Bits.PDA_PAT_WIDTH);
#endif
// calculate done
if (nLocalBufIndex >= (RoiProcNum-1))
goto CALDONE;
} // for i
// use for check if first x direction loop or not
nXDirLoopCount++;
} // for j
} else {
#ifdef FOR_DEBUG
LOG_INF("Random ROI\n");
#endif
for (i = 0; i < RoiProcNum; i++) {
g_rgn_x_buf[i] = pda_data->rgn_x[ROIIndex+i];
g_rgn_y_buf[i] = pda_data->rgn_y[ROIIndex+i];
g_rgn_w_buf[i] = pda_data->rgn_w[ROIIndex+i];
g_rgn_h_buf[i] = pda_data->rgn_h[ROIIndex+i];
g_rgn_iw_buf[i] = pda_data->rgn_iw[ROIIndex+i];
}
}
CALDONE:
#ifdef FOR_DEBUG
LOG_INF("Calculate ROI done\n");
#endif
return 0;
}
static int CheckDesignLimitation(struct PDA_Data_t_v2 *PDA_Data,
unsigned int RoiProcNum,
unsigned int ROIIndex)
{
unsigned int i = 0;
int nROIIndex = 0;
int nTempVar = 0;
#ifdef FOR_DEBUG
LOG_INF("Check Design Limitation\n");
#endif
// frame constraint
if (PDA_Data->PDA_FrameSetting.PDA_CFG_0.Bits.PDA_WIDTH % 4 != 0) {
LOG_INF("Frame width must be multiple of 4\n");
PDA_Data->Status = -4;
return -1;
}
// ROI constraint
for (i = 0; i < RoiProcNum; i++) {
nROIIndex = i + ROIIndex;
#ifdef FOR_DEBUG
LOG_INF("nROIIndex:%d, i:%d\n", nROIIndex, i);
#endif
if (g_rgn_w_buf[i] % 4 != 0) {
LOG_INF("ROI_%d width(%d) must be multiple of 4\n",
nROIIndex,
g_rgn_w_buf[i]);
PDA_Data->Status = -5;
return -1;
}
if (g_rgn_w_buf[i] > 3280) {
LOG_INF("ROI_%d width(%d) must be less than 3280\n",
nROIIndex,
g_rgn_w_buf[i]);
PDA_Data->Status = -6;
return -1;
}
if (g_rgn_x_buf[i] % 2 != 0) {
LOG_INF("ROI_%d xoffset(%d) must be multiple of 2\n",
nROIIndex,
g_rgn_x_buf[i]);
PDA_Data->Status = -7;
return -1;
}
if (g_rgn_iw_buf[i] < 41) {
LOG_INF("ROI_%d IW(%d) must be greater than 41\n",
nROIIndex,
g_rgn_iw_buf[i]);
PDA_Data->Status = -8;
return -1;
}
nTempVar = (1 << PDA_Data->PDA_FrameSetting.PDA_CFG_1.Bits.PDA_BIN_FCTR);
if (g_rgn_h_buf[i] % nTempVar != 0) {
LOG_INF("ROI_%d height(%d) must be multiple of Binning number(%d)\n",
i,
g_rgn_h_buf[i],
nTempVar);
PDA_Data->Status = -9;
return -1;
}
// ROI boundary must be on the boundary of patch
nTempVar = PDA_Data->PDA_FrameSetting.PDA_CFG_1.Bits.PDA_PR_XNUM;
if (g_rgn_x_buf[i] % nTempVar != 0) {
LOG_INF("ROI_%d ROI boundary must be on the boundary of patch\n",
nROIIndex);
LOG_INF("ROI_%d_x: %d, PDA_PR_XNUM: %d\n",
nROIIndex,
g_rgn_x_buf[i],
nTempVar);
PDA_Data->Status = -10;
return -1;
}
if (g_rgn_w_buf[i] % nTempVar != 0) {
LOG_INF("ROI_%d ROI boundary must be on the boundary of patch\n",
nROIIndex);
LOG_INF("ROI_%d_w: %d, PDA_PR_XNUM: %d\n",
nROIIndex,
g_rgn_w_buf[i],
nTempVar);
PDA_Data->Status = -10;
return -1;
}
nTempVar = PDA_Data->PDA_FrameSetting.PDA_CFG_1.Bits.PDA_PR_YNUM;
if (g_rgn_y_buf[i] % nTempVar != 0) {
LOG_INF("ROI_%d ROI boundary must be on the boundary of patch\n",
nROIIndex);
LOG_INF("ROI_%d_y: %d, PDA_PR_YNUM: %d\n",
nROIIndex,
g_rgn_y_buf[i],
nTempVar);
PDA_Data->Status = -10;
return -1;
}
if (g_rgn_h_buf[i] % nTempVar != 0) {
LOG_INF("ROI_%d ROI boundary must be on the boundary of patch\n",
nROIIndex);
LOG_INF("ROI_%d_h: %d, PDA_PR_YNUM: %d\n",
nROIIndex,
g_rgn_h_buf[i],
nTempVar);
PDA_Data->Status = -10;
return -1;
}
// ROI can't exceed the image region
nTempVar = PDA_Data->PDA_FrameSetting.PDA_CFG_0.Bits.PDA_WIDTH;
if ((g_rgn_x_buf[i]+g_rgn_w_buf[i]) > nTempVar) {
LOG_INF("ROI_%d ROI exceed the image region\n", nROIIndex);
PDA_Data->Status = -11;
return -1;
}
nTempVar = PDA_Data->PDA_FrameSetting.PDA_CFG_0.Bits.PDA_HEIGHT;
if ((g_rgn_y_buf[i]+g_rgn_h_buf[i]) > nTempVar) {
LOG_INF("ROI_%d ROI exceed the image region\n", nROIIndex);
PDA_Data->Status = -11;
return -1;
}
// Register Range Limitation check
if (g_rgn_x_buf[i] > 8191) {
LOG_INF("ROI_X_%d (%d) out of range\n", nROIIndex, g_rgn_x_buf[i]);
PDA_Data->Status = -19;
return -1;
}
if (g_rgn_y_buf[i] > 8191) {
LOG_INF("ROI_Y_%d (%d) out of range\n", nROIIndex, g_rgn_y_buf[i]);
PDA_Data->Status = -20;
return -1;
}
if (g_rgn_w_buf[i] < 20) {
LOG_INF("ROI_W_%d (%d) out of range\n", nROIIndex, g_rgn_w_buf[i]);
PDA_Data->Status = -21;
return -1;
}
if (g_rgn_h_buf[i] < 4 || g_rgn_h_buf[i] > 4092) {
LOG_INF("ROI_H_%d (%d) out of range\n", nROIIndex, g_rgn_h_buf[i]);
PDA_Data->Status = -22;
return -1;
}
if (g_rgn_iw_buf[i] > 3280) {
LOG_INF("ROI_IW_%d (%d) out of range, w:%d, pat_width:%d\n",
nROIIndex,
g_rgn_iw_buf[i],
g_rgn_w_buf[i],
PDA_Data->PDA_FrameSetting.PDA_CFG_1.Bits.PDA_PAT_WIDTH);
PDA_Data->Status = -23;
return -1;
}
}
// Register Range Limitation check
nTempVar = PDA_Data->PDA_FrameSetting.PDA_CFG_0.Bits.PDA_WIDTH;
if (nTempVar < 20 || nTempVar > 8191) {
LOG_INF("Frame width (%d) out of range\n", nTempVar);
PDA_Data->Status = -12;
return -1;
}
nTempVar = PDA_Data->PDA_FrameSetting.PDA_CFG_0.Bits.PDA_HEIGHT;
if (nTempVar < 4 || nTempVar > 8191) {
LOG_INF("Frame height (%d) out of range\n", nTempVar);
PDA_Data->Status = -13;
return -1;
}
nTempVar = PDA_Data->PDA_FrameSetting.PDA_CFG_1.Bits.PDA_PR_XNUM;
if (nTempVar < 1 || nTempVar > 16) {
LOG_INF("PDA_PR_XNUM (%d) out of range\n", nTempVar);
PDA_Data->Status = -14;
return -1;
}
nTempVar = PDA_Data->PDA_FrameSetting.PDA_CFG_1.Bits.PDA_PR_YNUM;
if (nTempVar < 1 || nTempVar > 16) {
LOG_INF("PDA_PR_YNUM (%d) out of range\n", nTempVar);
PDA_Data->Status = -15;
return -1;
}
nTempVar = PDA_Data->PDA_FrameSetting.PDA_CFG_1.Bits.PDA_PAT_WIDTH;
if (nTempVar < 1 || nTempVar > 512) {
LOG_INF("PDA_PAT_WIDTH (%d) out of range\n", nTempVar);
PDA_Data->Status = -16;
return -1;
}
nTempVar = PDA_Data->PDA_FrameSetting.PDA_CFG_1.Bits.PDA_RNG_ST;
if (nTempVar > 40) {
LOG_INF("PDA_RNG_ST (%d) out of range\n", nTempVar);
PDA_Data->Status = -17;
return -1;
}
nTempVar = PDA_Data->PDA_FrameSetting.PDA_CFG_2.Bits.PDA_TBL_STRIDE;
if (nTempVar < 5 || nTempVar > 2048) {
LOG_INF("PDA_TBL_STRIDE (%d) out of range\n", nTempVar);
PDA_Data->Status = -18;
return -1;
}
return 0;
}
static void FillRegSettings(struct PDA_Data_t_v2 *pda_PdaConfig,
unsigned int RoiProcNum,
unsigned long OuputAddr,
unsigned int PDA_Index)
{
unsigned int RegIndex = 14;
unsigned int ROI_MAX_INDEX = RoiProcNum-1;
unsigned int pair = 0;
// modify roi number register, change [11:6] bit to RoiProcNum
pda_PdaConfig->PDA_FrameSetting.PDA_CFG_2.Bits.PDA_RGN_NUM = RoiProcNum;
// roi number register setting
PDA_WR32(PDA_devs[PDA_Index].m_pda_base + PDA_CFG_2_REG,
pda_PdaConfig->PDA_FrameSetting.PDA_CFG_2.Raw);
// 1024 ROI data sequentially fill to PDA_CFG[14] ~ PDA_CFG[126]
for (pair = 0; pair <= ROI_MAX_INDEX; pair += 2) {
PDA_WR32((PDA_devs[PDA_Index].m_pda_base + 0x004*(RegIndex++)),
g_rgn_y_buf[pair]*65536 + g_rgn_x_buf[pair]);
PDA_WR32((PDA_devs[PDA_Index].m_pda_base + 0x004*(RegIndex++)),
g_rgn_h_buf[pair]*65536 + g_rgn_w_buf[pair]);
if (pair == ROI_MAX_INDEX && pair%2 == 0) {
PDA_WR32((PDA_devs[PDA_Index].m_pda_base + 0x004*(RegIndex++)),
g_rgn_iw_buf[pair]);
} else {
PDA_WR32((PDA_devs[PDA_Index].m_pda_base + 0x004*(RegIndex++)),
g_rgn_x_buf[pair+1]*65536 + g_rgn_iw_buf[pair]);
PDA_WR32((PDA_devs[PDA_Index].m_pda_base + 0x004*(RegIndex++)),
g_rgn_w_buf[pair+1]*65536 + g_rgn_y_buf[pair+1]);
PDA_WR32((PDA_devs[PDA_Index].m_pda_base + 0x004*(RegIndex++)),
g_rgn_iw_buf[pair+1]*65536 + g_rgn_h_buf[pair+1]);
}
}
// output buffer address setting
PDA_WR32(PDA_devs[PDA_Index].m_pda_base + PDA_PDAO_P1_BASE_ADDR_MSB_REG,
(unsigned int)(OuputAddr >> 32));
PDA_WR32(PDA_devs[PDA_Index].m_pda_base + PDA_PDAO_P1_BASE_ADDR_REG,
(unsigned int)(OuputAddr));
#ifdef FOR_DEBUG
LOG_INF("Fill Register Settings done\n");
#endif
}
static void LOGHWRegister(unsigned int i)
{
LOG_INF("CFG_0/1/2/3/4/5/6: 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_0_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_1_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_2_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_3_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_4_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_5_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_6_REG));
LOG_INF("CFG_7/8/9/10/11/12/13: 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_7_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_8_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_9_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_10_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_11_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_12_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_13_REG));
LOG_INF("CFG_14/15/16/17/18/19/20: 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_14_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_15_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_16_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_17_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_18_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_19_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_20_REG));
LOG_INF("CFG_21/22/23/24/25/26/27/28: 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_21_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_22_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_23_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_24_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_25_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_26_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_27_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_CFG_28_REG));
LOG_INF("I_P1/TI_P1/I_P2/TI_P2/Out: 0x%x/0x%x/0x%x/0x%x/0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_BASE_ADDR_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_BASE_ADDR_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_BASE_ADDR_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_BASE_ADDR_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_BASE_ADDR_REG));
LOG_INF("SECURE/I_STRIDE/O_P1_XSIZE/TILE_STATUS: 0x%x/0x%x/0x%x/0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDA_SECURE_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_STRIDE_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_XSIZE_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDA_TILE_STATUS_REG));
LOG_INF("PDAI_P1_CON0/CON1/CON2/CON3/CON4: 0x%x/0x%x/0x%x/0x%x/0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_CON0_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_CON1_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_CON2_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_CON3_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_CON4_REG));
LOG_INF("PDATI_P1_CON0/CON1/CON2/CON3/CON4: 0x%x/0x%x/0x%x/0x%x/0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_CON0_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_CON1_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_CON2_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_CON3_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_CON4_REG));
LOG_INF("PDAI_P2_CON0/CON1/CON2/CON3/CON4: 0x%x/0x%x/0x%x/0x%x/0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_CON0_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_CON1_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_CON2_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_CON3_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_CON4_REG));
LOG_INF("PDATI_P2_CON0/CON1/CON2/CON3/CON4: 0x%x/0x%x/0x%x/0x%x/0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_CON0_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_CON1_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_CON2_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_CON3_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_CON4_REG));
LOG_INF("PDAO_P1_CON0/CON1/CON2/CON3/CON4: 0x%x/0x%x/0x%x/0x%x/0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_CON0_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_CON1_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_CON2_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_CON3_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_CON4_REG));
LOG_INF("DMA_EN/DMA_RST/DMA_TOP/DCM_DIS/DCM_ST: 0x%x/0x%x/0x%x/0x%x/0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDA_DMA_EN_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDA_DMA_RST_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDA_DMA_TOP_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDA_DCM_DIS_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDA_DCM_ST_REG));
LOG_INF("[ERR_STAT]I_P1/TI_P1/I_P2/TI_P2/O_P1: 0x%x/0x%x/0x%x/0x%x/0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_ERR_STAT_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_ERR_STAT_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_ERR_STAT_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_ERR_STAT_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_ERR_STAT_REG));
LOG_INF("ERR_STAT_EN/ERR_STAT/TOP_CTL: 0x%x/0x%x/0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDA_ERR_STAT_EN_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDA_ERR_STAT_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDA_TOP_CTL_REG));
LOG_INF("IRQ_TRIG/PDAO_DMA_EXISTED_ECO: 0x%x/0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDA_IRQ_TRIG_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_DMA_EXISTED_ECO_REG));
LOG_INF("[MSB]I_P1/TI_P1/I_P2/TI_P2/O_P1: 0x%x/0x%x/0x%x/0x%x/0x%x\n",
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_BASE_ADDR_MSB_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_BASE_ADDR_MSB_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_BASE_ADDR_MSB_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_BASE_ADDR_MSB_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_BASE_ADDR_MSB_REG));
}
static void TF_dump_log(unsigned int hw_trigger_num)
{
unsigned int i = 0;
unsigned int sel_index = 0;
unsigned int Debug_Sel[] = {0x00008120, 0x0000400e, 0x0000c000,
0x11000000, 0x12000000, 0x13000000, 0x14000000, 0x15000000, 0x16000000,
0x14000000, 0x14100000, 0x14200000, 0x14300000, 0x14400000, 0x14500000,
0x21000000, 0x22000000, 0x23000000, 0x24000000, 0x25000000,
0x24000000, 0x24100000, 0x24200000, 0x24300000, 0x24400000, 0x24500000,
0x31000000, 0x32000000, 0x33000000, 0x34000000, 0x35000000,
0x34000000, 0x34100000, 0x34200000, 0x34300000, 0x34400000, 0x34500000,
0x41000000, 0x42000000, 0x43000000, 0x44000000, 0x45000000,
0x44000000, 0x44100000, 0x44200000, 0x44300000, 0x44400000, 0x44500000,
0x51000000, 0x52000000, 0x53000000, 0x54000000, 0x55000000,
0x54000000, 0x54100000, 0x54200000, 0x54300000, 0x54400000, 0x54500000};
unsigned int Length_Arr = sizeof(Debug_Sel)/sizeof(*Debug_Sel);
#ifdef SMI_LOG
// SMI log
mtk_smi_dbg_hang_detect("PDA device");
#endif
// check debug data
for (i = 0; i < hw_trigger_num; i++) {
for (sel_index = 0; sel_index < Length_Arr; ++sel_index) {
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDA_DEBUG_SEL_REG,
Debug_Sel[sel_index]);
LOG_INF("PDA_%d DEBUG_SEL/DEBUG_DATA: 0x%x/0x%x\n",
i, PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDA_DEBUG_SEL_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDA_DEBUG_DATA_REG));
}
}
// check hw register setting
for (i = 0; i < hw_trigger_num; i++) {
LOG_INF("[outer] PDA_%d register LOG +++++\n", i);
LOGHWRegister(i);
}
}
static void TimeoutHandler(unsigned int hw_trigger_num)
{
unsigned int i = 0;
TF_dump_log(hw_trigger_num);
// reset flow
for (i = 0; i < hw_trigger_num; i++) {
pda_reset(i);
pda_nontransaction_reset(i);
}
}
#ifdef PDA_TF_DUMP_71_1
int pda_tfault_callback(int port,
dma_addr_t mva, void *data)
{
unsigned int i = 0;
LOG_INF("User:PDA_PDAI_P1_BASE_ADDR: 0x%lx\n", g_Address_LI);
for (i = 0; i < g_PDA_quantity; i++) {
LOG_INF("PDA%d:I_P1_MSB/I_P1: 0x%x/0x%x\n", i,
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_BASE_ADDR_MSB_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_BASE_ADDR_REG));
}
LOG_INF("User:PDA_PDATI_P1_BASE_ADDR: 0x%lx\n", g_Address_LT);
for (i = 0; i < g_PDA_quantity; i++) {
LOG_INF("PDA%d:TI_P1_MSB/TI_P1: 0x%x/0x%x\n", i,
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_BASE_ADDR_MSB_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_BASE_ADDR_REG));
}
LOG_INF("User:PDA_PDAI_P2_BASE_ADDR: 0x%lx\n", g_Address_RI);
for (i = 0; i < g_PDA_quantity; i++) {
LOG_INF("PDA%d:I_P2_MSB/I_P2: 0x%x/0x%x\n", i,
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_BASE_ADDR_MSB_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_BASE_ADDR_REG));
}
LOG_INF("User:PDA_PDATI_P2_BASE_ADDR: 0x%lx\n", g_Address_RT);
for (i = 0; i < g_PDA_quantity; i++) {
LOG_INF("PDA%d:TI_P2_MSB/TI_P2: 0x%x/0x%x\n", i,
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_BASE_ADDR_MSB_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_BASE_ADDR_REG));
}
LOG_INF("User:PDA_PDAO_P1_BASE_ADDR: 0x%lx\n", g_OutputBufferAddr);
for (i = 0; i < g_PDA_quantity; i++) {
LOG_INF("PDA%d:O_P1_MSB/O_P1: 0x%x/0x%x\n", i,
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_BASE_ADDR_MSB_REG),
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_BASE_ADDR_REG));
}
LOG_INF("ImageSize/TableSize/OutputSize/ROInumber: %d/%d/%d/%d\n",
g_pda_Pdadata.ImageSize,
g_pda_Pdadata.TableSize,
g_pda_Pdadata.OutputSize,
g_pda_Pdadata.ROInumber);
LOG_INF("FD_L_Img/R_Img/L_Tbl/R_Tbl/Out: %d/%d/%d/%d/%d\n",
g_pda_Pdadata.FD_L_Image,
g_pda_Pdadata.FD_R_Image,
g_pda_Pdadata.FD_L_Table,
g_pda_Pdadata.FD_R_Table,
g_pda_Pdadata.FD_Output);
LOG_INF("Status/Timeout/nNumerousROI: %d/%d/%d\n",
g_pda_Pdadata.Status,
g_pda_Pdadata.Timeout,
g_pda_Pdadata.nNumerousROI);
LOG_INF("PDA_CFG_0/1/2/3/4/5/6: 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n",
g_pda_Pdadata.PDA_FrameSetting.PDA_CFG_0.Raw,
g_pda_Pdadata.PDA_FrameSetting.PDA_CFG_1.Raw,
g_pda_Pdadata.PDA_FrameSetting.PDA_CFG_2.Raw,
g_pda_Pdadata.PDA_FrameSetting.PDA_CFG_3.Raw,
g_pda_Pdadata.PDA_FrameSetting.PDA_CFG_4.Raw,
g_pda_Pdadata.PDA_FrameSetting.PDA_CFG_5.Raw,
g_pda_Pdadata.PDA_FrameSetting.PDA_CFG_6.Raw);
LOG_INF("PDA_CFG_7/8/9/10/11/12/13: 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x/0x%x\n",
g_pda_Pdadata.PDA_FrameSetting.PDA_CFG_7.Raw,
g_pda_Pdadata.PDA_FrameSetting.PDA_CFG_8.Raw,
g_pda_Pdadata.PDA_FrameSetting.PDA_CFG_9.Raw,
g_pda_Pdadata.PDA_FrameSetting.PDA_CFG_10.Raw,
g_pda_Pdadata.PDA_FrameSetting.PDA_CFG_11.Raw,
g_pda_Pdadata.PDA_FrameSetting.PDA_CFG_12.Raw,
g_pda_Pdadata.PDA_FrameSetting.PDA_CFG_13.Raw);
for (i = 0; i < g_pda_Pdadata.ROInumber; ++i) {
LOG_INF("rgn_x/y/h/w/iw[%d]: 0x%x/0x%x/0x%x/0x%x/0x%x\n", i,
g_pda_Pdadata.rgn_x[i],
g_pda_Pdadata.rgn_y[i],
g_pda_Pdadata.rgn_h[i],
g_pda_Pdadata.rgn_w[i],
g_pda_Pdadata.rgn_iw[i]);
}
// dump data
TF_dump_log(g_PDA_quantity);
return 1;
}
#endif
static void pda_execute(unsigned int hw_trigger_num)
{
unsigned int i;
#ifdef FOR_DEBUG
LOG_INF("+\n");
#endif
for (i = 0; i < hw_trigger_num; i++) {
// PDA_TOP_CTL set 1'b1 to bit3, to load register from double buffer
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDA_TOP_CTL_REG, PDA_DOUBLE_BUFFER);
// make sure all the pda setting take effect
wmb();
// PDA_TOP_CTL set 1'b1 to bit1, to trigger sof
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDA_TOP_CTL_REG, PDA_TRIGGER);
// make sure all the pda setting take effect
wmb();
// write 0 after trigger
PDA_WR32(PDA_devs[i].m_pda_base + PDA_PDA_TOP_CTL_REG, PDA_CLEAR_REG);
#ifdef GET_PDA_TIME
if (i == 0)
ktime_get_real_ts64(&pda1_done_b);
else
ktime_get_real_ts64(&pda2_done_b);
#endif
}
#ifdef FOR_DEBUG
LOG_INF("-\n");
#endif
}
static int check_pda_status(unsigned int hw_trigger_num)
{
unsigned int i = 0;
for (i = 0; i < hw_trigger_num; i++) {
if (PDA_devs[i].HWstatus == 0) {
#ifdef FOR_DEBUG
LOG_INF("PDA%d HWstatus = %d\n", i, PDA_devs[i].HWstatus);
#endif
return 0;
}
}
return 1;
}
static inline unsigned int pda_ms_to_jiffies(unsigned int ms)
{
return ((ms * HZ + 512) >> 10);
}
static signed int pda_wait_irq(struct PDA_Data_t_v2 *pda_data, unsigned int hw_trigger_num)
{
int ret = 0;
unsigned int i = 0;
/* start to wait signal */
ret = wait_event_interruptible_timeout(g_wait_queue_head,
check_pda_status(hw_trigger_num),
pda_ms_to_jiffies(pda_data->Timeout));
if (ret == 0) {
TimeoutHandler(hw_trigger_num);
// timeout error
LOG_INF("wait_event_interruptible_timeout Fail\n");
pda_data->Status = -2;
return -1;
} else if (ret < 0) {
LOG_INF("wait_event return value:%d\n", ret);
if (ret == -ERESTARTSYS)
LOG_INF("Interrupted by a signal\n");
pda_data->Status = -3;
for (i = 0; i < hw_trigger_num; i++) {
pda_reset(i);
pda_nontransaction_reset(i);
}
return -1;
}
#ifdef GET_PDA_TIME
ktime_get_real_ts64(&time_end);
#endif
// pda status
pda_data->Status = 1;
// update status to user
for (i = 0; i < hw_trigger_num; i++) {
if (PDA_devs[i].HWstatus < 0) {
pda_data->Status = PDA_devs[i].HWstatus;
LOG_INF("PDA%d HW error (%d)", i, PDA_devs[i].HWstatus);
LOG_INF("PDA%d PDA_PDAI_P1_ERR_STAT_REG = 0x%x",
i, PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_ERR_STAT_REG));
LOG_INF("PDA%d PDA_PDATI_P1_ERR_STAT_REG = 0x%x",
i, PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_ERR_STAT_REG));
LOG_INF("PDA%d PDA_PDAI_P2_ERR_STAT_REG = 0x%x",
i, PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_ERR_STAT_REG));
LOG_INF("PDA%d PDA_PDATI_P2_ERR_STAT_REG = 0x%x",
i, PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_ERR_STAT_REG));
LOG_INF("PDA%d PDA_PDAO_P1_ERR_STAT_REG = 0x%x",
i, PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_ERR_STAT_REG));
// reset flow
pda_nontransaction_reset(i);
}
}
return ret;
}
static irqreturn_t pda_irqhandle(signed int Irq, void *DeviceId)
{
unsigned int nPdaStatus = 0;
if (g_u4EnableClockCount > 0) {
// read pda status
nPdaStatus = PDA_RD32(PDA_devs[0].m_pda_base + PDA_PDA_ERR_STAT_REG) &
PDA_STATUS_REG;
}
#ifdef FOR_DEBUG
LOG_INF("PDA0 PDA_PDA_ERR_STAT_REG = 0x%x", nPdaStatus);
#endif
// for WCL=1 case, write 1 to clear pda done status
// PDA_WR32(PDA_devs[0].m_pda_base + PDA_PDA_ERR_STAT_REG, 0x00000001);
PDA_devs[0].HWstatus = 1;
#ifdef GET_PDA_TIME
ktime_get_real_ts64(&pda1_done_e);
#endif
#ifdef CHECK_IRQ_COUNT
++g_PDA0_IRQCount;
if (g_PDA0_IRQCount > g_reasonable_IRQCount) {
PDA_devs[0].HWstatus = -29;
pda_nontransaction_reset(0);
}
#endif
// wake up user space WAIT_IRQ flag
wake_up_interruptible(&g_wait_queue_head);
return IRQ_HANDLED;
}
static irqreturn_t pda2_irqhandle(signed int Irq, void *DeviceId)
{
unsigned int nPdaStatus = 0;
if (g_u4EnableClockCount > 0) {
// read pda status
nPdaStatus = PDA_RD32(PDA_devs[1].m_pda_base + PDA_PDA_ERR_STAT_REG) &
PDA_STATUS_REG;
}
#ifdef FOR_DEBUG
LOG_INF("PDA1 PDA_PDA_ERR_STAT_REG = 0x%x", nPdaStatus);
#endif
// for WCL=1 case, write 1 to clear pda done status
// PDA_WR32(PDA_devs[1].m_pda_base + PDA_PDA_ERR_STAT_REG, 0x00000001);
PDA_devs[1].HWstatus = 1;
#ifdef GET_PDA_TIME
ktime_get_real_ts64(&pda2_done_e);
#endif
#ifdef CHECK_IRQ_COUNT
++g_PDA1_IRQCount;
if (g_PDA1_IRQCount > g_reasonable_IRQCount) {
PDA_devs[1].HWstatus = -29;
pda_nontransaction_reset(1);
}
#endif
// wake up user space WAIT_IRQ flag
wake_up_interruptible(&g_wait_queue_head);
return IRQ_HANDLED;
}
static int PDAProcessFunction(unsigned int nUserROINumber,
unsigned int nROIcount,
unsigned int isFixROI,
unsigned int p_index)
{
unsigned int i = 0;
unsigned int nOneRoundProcROI = 0;
unsigned int hw_trigger_num = 0;
unsigned int nRemainder = 0, nFactor = 0;
unsigned int nCurrentProcRoiIndex = 0;
unsigned long nOutputAddr = 0;
int nirqRet = 0;
unsigned int CheckAddress = 0, CheckAddressMSB = 0;
while (nROIcount > 0) {
// read 0x3b4, avoid the impact of previous data
// LOG_INF("PDA status before process = %d\n",
// PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDA_ERR_STAT_REG));
#ifdef FOR_DEBUG
LOG_INF("nROIcount = %d\n", nROIcount);
#endif
// reset HW status
for (i = 0; i < g_PDA_quantity; i++)
PDA_devs[i].HWstatus = 0;
// reset local variable
nOneRoundProcROI = 0;
//reset hw trigger number
hw_trigger_num = g_PDA_quantity;
// assign strategy, used for multi-engine
if (nROIcount >= (PDA_MAXROI_PER_ROUND * g_PDA_quantity)) {
for (i = 0; i < g_PDA_quantity; i++) {
g_CurrentProcRoiNum[i] = PDA_MAXROI_PER_ROUND;
nOneRoundProcROI += g_CurrentProcRoiNum[i];
#ifdef FOR_DEBUG
LOG_INF("g_CurrentProcRoiNum[%d] = %d\n",
i, g_CurrentProcRoiNum[i]);
LOG_INF("OneRoundProcROI = %d\n", nOneRoundProcROI);
#endif
}
} else {
if (g_PDA_quantity == 0) {
LOG_INF("Fail: g_PDA_quantity is zero\n");
return -1;
}
nRemainder = nROIcount % g_PDA_quantity;
nFactor = nROIcount / g_PDA_quantity;
for (i = 0; i < g_PDA_quantity; i++) {
g_CurrentProcRoiNum[i] = nFactor;
if (nRemainder > 0) {
g_CurrentProcRoiNum[i]++;
nRemainder--;
}
nOneRoundProcROI += g_CurrentProcRoiNum[i];
#ifdef FOR_DEBUG
LOG_INF("g_CurrentProcRoiNum[%d] = %d\n",
i, g_CurrentProcRoiNum[i]);
LOG_INF("OneRoundProcROI = %d\n", nOneRoundProcROI);
#endif
}
}
// data preparing
for (i = 0; i < g_PDA_quantity; i++) {
// current process ROI index
if (i == 0)
nCurrentProcRoiIndex = (nUserROINumber - nROIcount);
else if (i > 0)
nCurrentProcRoiIndex += g_CurrentProcRoiNum[i - 1];
else
LOG_INF("Index is out of range, i = %d\n", i);
#ifdef FOR_DEBUG
LOG_INF("nCurrentProcRoiIndex = %d\n",
nCurrentProcRoiIndex);
#endif
if (g_CurrentProcRoiNum[i] == 0) {
hw_trigger_num = i;
#ifdef FOR_DEBUG
LOG_INF("assign roi number is zero, no need to process\n");
#endif
break;
}
#ifdef FOR_DEBUG
LOG_INF("i:%d, g_CurrentProcRoiNum:%d, nCurrentProcRoiIndex:%d\n",
i,
g_CurrentProcRoiNum[i],
nCurrentProcRoiIndex);
#endif
// calculate 1024 ROI data
if (ProcessROIData(&g_pda_Pdadata,
g_CurrentProcRoiNum[i],
nCurrentProcRoiIndex,
isFixROI,
p_index) < 0) {
LOG_INF("ProcessROIData Fail\n");
g_pda_Pdadata.Status = -24;
return -1;
}
if (CheckDesignLimitation(&g_pda_Pdadata,
g_CurrentProcRoiNum[i],
nCurrentProcRoiIndex) < 0) {
LOG_INF("CheckDesignLimitation Fail\n");
return -1;
}
// output address is equal to
// total ROI number multiple by 1408
nOutputAddr = g_OutputBufferAddr;
nOutputAddr += nCurrentProcRoiIndex * OUT_BYTE_PER_ROI;
if (g_OutputBufferOffset + (g_CurrentProcRoiNum[i]*OUT_BYTE_PER_ROI) >
g_pda_Pdadata.OutputSize) {
LOG_INF("fail, output buffer out of range\n");
LOG_INF("Current output buffer addr: 0x%lx\n",
nOutputAddr);
LOG_INF("Base output buffer addr: 0x%lx\n",
nOutputAddr);
LOG_INF("PDA%d ROI process num: %d\n",
i, g_CurrentProcRoiNum[i]);
LOG_INF("Output buffer size: %d\n",
g_pda_Pdadata.OutputSize);
LOG_INF("Current process ROI index: %d\n",
nCurrentProcRoiIndex);
LOG_INF("nUserROINumber: %d\n",
nUserROINumber);
LOG_INF("nROIcount: %d\n", nROIcount);
g_pda_Pdadata.Status = -30;
return -1;
}
#ifdef FOR_DEBUG
LOG_INF("(nOutputAddr+g_OutputBufferOffset): 0x%lx\n",
(nOutputAddr+g_OutputBufferOffset));
#endif
FillRegSettings(&g_pda_Pdadata,
g_CurrentProcRoiNum[i],
(nOutputAddr+g_OutputBufferOffset),
i);
}
// check input/output buffer address is valid
for (i = 0; i < hw_trigger_num; i++) {
CheckAddress =
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_BASE_ADDR_REG);
CheckAddressMSB =
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P1_BASE_ADDR_MSB_REG);
if (CheckAddress == 0 && CheckAddressMSB == 0) {
LOG_INF("PDA_%d PDA_PDAI_P1_BASE_ADDR is zero\n", i);
g_pda_Pdadata.Status = -30;
return -1;
}
CheckAddress =
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_BASE_ADDR_REG);
CheckAddressMSB =
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P1_BASE_ADDR_MSB_REG);
if (CheckAddress == 0 && CheckAddressMSB == 0) {
LOG_INF("PDA_%d PDA_PDATI_P1_BASE_ADDR is zero\n", i);
g_pda_Pdadata.Status = -30;
return -1;
}
CheckAddress =
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_BASE_ADDR_REG);
CheckAddressMSB =
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAI_P2_BASE_ADDR_MSB_REG);
if (CheckAddress == 0 && CheckAddressMSB == 0) {
LOG_INF("PDA_%d PDA_PDAI_P2_BASE_ADDR is zero\n", i);
g_pda_Pdadata.Status = -30;
return -1;
}
CheckAddress =
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_BASE_ADDR_REG);
CheckAddressMSB =
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDATI_P2_BASE_ADDR_MSB_REG);
if (CheckAddress == 0 && CheckAddressMSB == 0) {
LOG_INF("PDA_%d PDA_PDATI_P2_BASE_ADDR is zero\n", i);
g_pda_Pdadata.Status = -30;
return -1;
}
CheckAddress =
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_BASE_ADDR_REG);
CheckAddressMSB =
PDA_RD32(PDA_devs[i].m_pda_base + PDA_PDAO_P1_BASE_ADDR_MSB_REG);
if (CheckAddress == 0 && CheckAddressMSB == 0) {
LOG_INF("PDA_%d PDA_PDAO_P1_BASE_ADDR is zero\n", i);
g_pda_Pdadata.Status = -30;
return -1;
}
}
// trigger PDA work
pda_execute(hw_trigger_num);
nirqRet = pda_wait_irq(&g_pda_Pdadata, hw_trigger_num);
if (nirqRet < 0) {
LOG_INF("pda_wait_irq Fail (%d)\n", nirqRet);
return -1;
}
// update roi count which needed to process
nROIcount -= nOneRoundProcROI;
}
return 1;
}
static long PDA_Ioctl(struct file *a_pstFile,
unsigned int a_u4Command,
unsigned long a_u4Param)
{
long nRet = 0;
int nROIcount = 0;
unsigned int nUserROINumber = 0;
unsigned int i;
int ret = 0;
struct PDA_Init_Data Init_Data;
if (g_PDA_quantity == 0) {
LOG_INF("no PDA support\n");
return -1;
}
switch (a_u4Command) {
case PDA_RESET:
for (i = 0; i < g_PDA_quantity; i++)
pda_reset(i);
break;
case PDA_GET_VERSION:
if (copy_from_user(&Init_Data,
(void *)a_u4Param,
sizeof(struct PDA_Init_Data)) != 0) {
LOG_INF("PDA_GET_VERSION copy_from_user failed\n");
nRet = -EFAULT;
break;
}
Init_Data.Kversion = KERNEL_VERSION;
LOG_INF("kernel version: %d\n", Init_Data.Kversion);
if (copy_to_user((void *)a_u4Param,
&Init_Data,
sizeof(struct PDA_Init_Data)) != 0) {
LOG_INF("PDA_GET_VERSION copy_to_user failed\n");
nRet = -EFAULT;
}
break;
case PDA_ENQUE_WAITIRQ_V2:
spin_lock(&g_PDA_SpinLock);
if (g_u4EnableClockCount == 0) {
LOG_INF("Cannot process without enable pda clock\n");
spin_unlock(&g_PDA_SpinLock);
return -1;
}
spin_unlock(&g_PDA_SpinLock);
#ifdef GET_PDA_TIME
ktime_get_real_ts64(&total_time_begin);
#endif
// MRAW PDA reset
for (i = 0; i < g_PDA_quantity; i++)
pda_nontransaction_reset(i);
// reset HW status
for (i = 0; i < g_PDA_quantity; i++)
PDA_devs[i].HWstatus = 0;
#ifdef CHECK_IRQ_COUNT
// reset PDA0/PDA1 IRQ count
g_PDA0_IRQCount = 0;
g_PDA1_IRQCount = 0;
#ifdef FOR_DEBUG
LOG_INF("PDA0_IRQCount = %d, PDA1_IRQCount = %d\n",
g_PDA0_IRQCount, g_PDA1_IRQCount);
#endif
#endif
// reset output buffer address offset
g_OutputBufferOffset = 0;
if (copy_from_user(&g_pda_Pdadata,
(void *)a_u4Param,
sizeof(struct PDA_Data_t_v2)) != 0) {
LOG_INF("PDA_ENQUE_WAITIRQ copy_from_user failed\n");
nRet = -EFAULT;
break;
}
ret = g_pda_Pdadata.ROInumber == 0 && g_pda_Pdadata.nNumerousROI == 0;
if (g_pda_Pdadata.ROInumber > PDAROIARRAYMAX || ret) {
g_pda_Pdadata.Status = -28;
LOG_INF("ROI number out of range, ROInumber/nNumerousROI:%d/%d\n",
g_pda_Pdadata.ROInumber,
g_pda_Pdadata.nNumerousROI);
LOG_INF("rgn:%d,fix:%d,xnum:%d,siz:%d,FD:%d,cfg0:0x%x,sta:%d/%d\n",
g_pda_Pdadata.rgn_h[0],
g_pda_Pdadata.fix_rgn_h[0],
g_pda_Pdadata.xnum[0],
g_pda_Pdadata.OutputSize,
g_pda_Pdadata.FD_Output,
g_pda_Pdadata.PDA_FrameSetting.PDA_CFG_0.Raw,
g_pda_Pdadata.Status,
g_pda_Pdadata.Timeout);
goto EXIT_WITHOUT_FREE_IOVA;
}
if (Get_Input_Addr_From_DMABUF(&g_pda_Pdadata) < 0) {
g_pda_Pdadata.Status = -26;
LOG_INF("Get_Input_Addr_From_DMABUF fail\n");
goto EXIT_WITHOUT_FREE_IOVA;
}
// output buffer mapping iova
if (Get_Output_Addr_From_DMABUF(&g_pda_Pdadata) < 0) {
g_pda_Pdadata.Status = -27;
LOG_INF("Get_Output_Addr_From_DMABUF fail\n");
goto INPUT_BUFFER_FREE_IOVA;
}
// PDA HW and DMA setting
HWDMASettings(&g_pda_Pdadata);
// ------------------------ PDA pre-process done -----------------
// Process flexible roi
nUserROINumber = g_pda_Pdadata.ROInumber;
#ifdef FOR_DEBUG
LOG_INF("nUserROINumber = %d\n", nUserROINumber);
LOG_INF("g_PDA_quantity = %d\n", g_PDA_quantity);
#endif
if (nUserROINumber == 0) {
#ifdef FOR_DEBUG
LOG_INF("no flexible roi needed\n");
#endif
goto FIX_ROI;
}
#ifdef CHECK_IRQ_COUNT
// setting reasonable IRQ count
g_reasonable_IRQCount = 1 +
(int)((nUserROINumber-1)/(PDA_MAXROI_PER_ROUND*g_PDA_quantity));
// reset PDA0/PDA1 IRQ count
g_PDA0_IRQCount = 0;
g_PDA1_IRQCount = 0;
#ifdef FOR_DEBUG
LOG_INF("g_reasonable_IRQCount = %d\n", g_reasonable_IRQCount);
#endif
#endif
// Init ROI count which needed to process
nROIcount = nUserROINumber;
if (PDAProcessFunction(nUserROINumber, nROIcount, MFALSE, 0) < 0) {
LOG_INF("Flexible ROI, PDA process fail\n");
goto EXIT;
}
g_OutputBufferOffset += nUserROINumber*OUT_BYTE_PER_ROI;
#ifdef FOR_DEBUG
LOG_INF("g_OutputBufferOffset: %d\n", g_OutputBufferOffset);
#endif
FIX_ROI:
// Process fix roi
#ifdef FOR_DEBUG
LOG_INF("nNumerousROI:%d\n", g_pda_Pdadata.nNumerousROI);
#endif
if (g_pda_Pdadata.nNumerousROI > FIXROIARRAYMAX) {
g_pda_Pdadata.Status = -28;
LOG_INF("ROI number out of range,nNumerousROI:%d\n",
g_pda_Pdadata.nNumerousROI);
goto EXIT;
}
for (i = 0; i < g_pda_Pdadata.nNumerousROI; ++i) {
nUserROINumber = g_pda_Pdadata.xnum[i]*g_pda_Pdadata.ynum[i];
#ifdef FOR_DEBUG
LOG_INF("nUserROINumber = %d\n", nUserROINumber);
#endif
if (nUserROINumber == 0 || nUserROINumber > 1024) {
g_pda_Pdadata.Status = -28;
LOG_INF("ROI number out of range,idx/ROI/x/ynum:%d/%d/%d/%d\n",
i,
nUserROINumber,
g_pda_Pdadata.xnum[i],
g_pda_Pdadata.ynum[i]);
goto EXIT;
}
#ifdef CHECK_IRQ_COUNT
// setting reasonable IRQ count
g_reasonable_IRQCount = 1 +
(int)((nUserROINumber-1)/(PDA_MAXROI_PER_ROUND*g_PDA_quantity));
// reset PDA0/PDA1 IRQ count
g_PDA0_IRQCount = 0;
g_PDA1_IRQCount = 0;
#ifdef FOR_DEBUG
LOG_INF("g_reasonable_IRQCount = %d\n", g_reasonable_IRQCount);
#endif
#endif
// Init ROI count which needed to process
nROIcount = nUserROINumber;
if (PDAProcessFunction(nUserROINumber, nROIcount, MTRUE, i) < 0) {
LOG_INF("Fix ROI, PDA process fail\n");
goto EXIT;
}
g_OutputBufferOffset += nUserROINumber*OUT_BYTE_PER_ROI;
#ifdef FOR_DEBUG
LOG_INF("g_OutputBufferOffset: %d\n", g_OutputBufferOffset);
#endif
}
//////////////////////////////////////////////////////////////////////////////
EXIT:
// free output iova
#ifdef FOR_DEBUG
LOG_INF("free output iova\n");
#endif
pda_put_dma_buffer(&g_output_mmu);
INPUT_BUFFER_FREE_IOVA:
//free input iova
#ifdef FOR_DEBUG
LOG_INF("free input iova\n");
#endif
pda_put_dma_buffer(&g_image_mmu);
pda_put_dma_buffer(&g_table_mmu);
EXIT_WITHOUT_FREE_IOVA:
#ifdef FOR_DEBUG
LOG_INF("Exit\n");
#endif
// reset flow
for (i = 0; i < g_PDA_quantity; i++) {
pda_reset(i);
pda_nontransaction_reset(i);
}
#ifdef GET_PDA_TIME
// for compute pda process time
ktime_get_real_ts64(&total_time_end);
LOG_INF("PDA 1 execute time (%d)\n",
(pda1_done_e.tv_nsec - pda1_done_b.tv_nsec)/1000);
LOG_INF("PDA 2 execute time (%d)\n",
(pda2_done_e.tv_nsec - pda2_done_b.tv_nsec)/1000);
LOG_INF("SW wait time (%d)\n",
(time_end.tv_nsec - pda1_done_b.tv_nsec)/1000);
LOG_INF("kernel total cost time (%d)\n",
(total_time_end.tv_nsec-total_time_begin.tv_nsec)/1000);
#endif
if (copy_to_user((void *)a_u4Param,
&g_pda_Pdadata,
sizeof(struct PDA_Data_t_v2)) != 0) {
LOG_INF("copy_to_user failed\n");
nRet = -EFAULT;
}
break;
default:
LOG_INF("Unknown Cmd(%d)\n", a_u4Command);
break;
}
return nRet;
}
#if IS_ENABLED(CONFIG_COMPAT)
static long PDA_Ioctl_Compat(struct file *a_pstFile, unsigned int a_u4Command,
unsigned long a_u4Param)
{
long i4RetValue = 0;
return i4RetValue;
}
#endif
static int PDA_Open(struct inode *a_pstInode, struct file *a_pstFile)
{
//Enable clock
EnableClock(MTRUE);
LOG_INF("PDA open g_u4EnableClockCount: %d", g_u4EnableClockCount);
#ifdef PDA_MMQOS
pda_mmqos_bw_set();
#endif
#ifdef CHECK_IRQ_COUNT
g_reasonable_IRQCount = 0;
g_PDA0_IRQCount = 0;
g_PDA1_IRQCount = 0;
#ifdef FOR_DEBUG
LOG_INF("IRQCount, Reasonable = %d, PDA0 = %d, PDA1 = %d\n",
g_reasonable_IRQCount, g_PDA0_IRQCount, g_PDA1_IRQCount);
#endif
#endif
return 0;
}
static int PDA_Release(struct inode *a_pstInode, struct file *a_pstFile)
{
#ifdef PDA_MMQOS
pda_mmqos_bw_reset();
#endif
//Disable clock
EnableClock(MFALSE);
LOG_INF("PDA release g_u4EnableClockCount: %d", g_u4EnableClockCount);
return 0;
}
/*****************************************************************************
*
****************************************************************************/
static dev_t g_PDA_devno;
static struct cdev *g_pPDA_CharDrv;
static struct class *actuator_class;
static struct device *lens_device;
static const struct file_operations g_stPDA_fops = {
.owner = THIS_MODULE,
.open = PDA_Open,
.release = PDA_Release,
.unlocked_ioctl = PDA_Ioctl,
#if IS_ENABLED(CONFIG_COMPAT)
.compat_ioctl = PDA_Ioctl_Compat,
#endif
};
static inline int PDA_RegCharDev(void)
{
int nRet = 0;
LOG_INF("Register char driver Start\n");
/* Allocate char driver no. */
nRet = alloc_chrdev_region(&g_PDA_devno, 0, 1, PDA_DEV_NAME);
if (nRet < 0) {
LOG_INF("Allocate device no failed\n");
return nRet;
}
/* Allocate driver */
g_pPDA_CharDrv = cdev_alloc();
if (g_pPDA_CharDrv == NULL) {
unregister_chrdev_region(g_PDA_devno, 1);
LOG_INF("cdev_alloc failed\n");
return nRet;
}
/* Attach file operation. */
cdev_init(g_pPDA_CharDrv, &g_stPDA_fops);
g_pPDA_CharDrv->owner = THIS_MODULE;
/* Add to system */
nRet = cdev_add(g_pPDA_CharDrv, g_PDA_devno, 1);
if (nRet < 0) {
LOG_INF("Attach file operation failed\n");
unregister_chrdev_region(g_PDA_devno, 1);
return nRet;
}
actuator_class = class_create(THIS_MODULE, "PDAdrv");
if (IS_ERR(actuator_class)) {
int ret = PTR_ERR(actuator_class);
LOG_INF("Unable to create class, err = %d\n", ret);
// unregister_chrdev_region(g_PDA_devno, 1);
return ret;
}
lens_device = device_create(actuator_class, NULL, g_PDA_devno, NULL,
PDA_DEV_NAME);
if (IS_ERR(lens_device)) {
int ret = PTR_ERR(lens_device);
LOG_INF("create dev err: /dev/%s, err = %d\n", PDA_DEV_NAME, ret);
// unregister_chrdev_region(g_PDA_devno, 1);
return ret;
}
LOG_INF("Register char driver End\n");
return nRet;
}
static inline void PDA_UnRegCharDev(void)
{
LOG_INF("UnRegCharDev Start\n");
/* Release char driver */
cdev_del(g_pPDA_CharDrv);
unregister_chrdev_region(g_PDA_devno, 1);
device_destroy(actuator_class, g_PDA_devno);
class_destroy(actuator_class);
LOG_INF("UnRegCharDev End\n");
}
/*****************************************************************************
*
****************************************************************************/
static int PDA_probe(struct platform_device *pdev)
{
int nRet = 0;
unsigned int irq_info[3]; /* Record interrupts info from device tree */
struct device_node *node;
int i;
int larbs;
struct device_node *mraw_node;
#ifdef FPGA_UT
struct device_node *camsys_node;
#endif
LOG_INF("probe Start\n");
// init pda quantity
g_PDA_quantity = 0;
/* Register char driver */
nRet = PDA_RegCharDev();
if (nRet < 0) {
LOG_INF(" register char device failed!\n");
return nRet;
}
LOG_INF("probe - register char driver\n");
spin_lock_init(&g_PDA_SpinLock);
LOG_INF("spin_lock_init done\n");
init_waitqueue_head(&g_wait_queue_head);
LOG_INF("init_waitqueue_head done\n");
// get PDA node
node = of_find_compatible_node(NULL, NULL, "mediatek,camera-pda");
if (!node) {
LOG_INF("find camera-pda node failed\n");
return -1;
}
LOG_INF("find camera-pda node done\n");
// must porting in dts
larbs = of_count_phandle_with_args(
pdev->dev.of_node, "mediatek,larbs", NULL);
LOG_INF("larb_num:%d\n", larbs);
for (i = 0; i < larbs; i++)
larb1 = pda_init_larb(pdev, i);
#if IS_ENABLED(CONFIG_OF)
g_dev1 = &pdev->dev;
if (dma_set_mask_and_coherent(g_dev1, DMA_BIT_MASK(34)))
LOG_INF("No suitable DMA available\n");
//power on smi
/* consumer driver probe*/
pm_runtime_enable(g_dev1); //Note: Its not larb's device.
LOG_INF("pm_runtime_enable pda1 done\n");
#endif
for (i = 0; i < PDA_CLK_NUM; ++i) {
// CCF: Grab clock pointer (struct clk*)
LOG_INF("index: %d, clock name: %s\n", i, clk_names[i]);
pda_clk[i].CG_PDA_TOP_MUX = devm_clk_get(&pdev->dev, clk_names[i]);
if (IS_ERR(pda_clk[i].CG_PDA_TOP_MUX)) {
LOG_INF("cannot get %s clock\n", clk_names[i]);
return PTR_ERR(pda_clk[i].CG_PDA_TOP_MUX);
}
}
// get PDA address, and PDA quantity
PDA_devs[0].m_pda_base = of_iomap(node, 0);
if (!PDA_devs[0].m_pda_base)
LOG_INF("PDA0 base m_pda_base failed\n");
// get IRQ ID and request IRQ
PDA_devs[0].irq = irq_of_parse_and_map(node, 0);
LOG_INF("PDA_dev[0]->irq: %d", PDA_devs[0].irq);
if (PDA_devs[0].irq != 0)
g_PDA_quantity++;
LOG_INF("PDA quantity: %d\n", g_PDA_quantity);
#ifdef FPGA_UT
// camsys node
camsys_node = of_find_compatible_node(NULL, NULL, "mediatek,isp_unit_test");
if (!camsys_node) {
LOG_INF("find camsys_config node failed\n");
return -1;
}
LOG_INF("find camsys_config node done\n");
CAMSYS_CONFIG_BASE = of_iomap(camsys_node, 2);
if (!CAMSYS_CONFIG_BASE)
LOG_INF("base CAMSYS_CONFIG_BASE failed\n");
#endif
// mraw node
mraw_node = of_find_compatible_node(NULL, NULL, "mediatek,mt6983-camsys_mraw");
if (!mraw_node) {
LOG_INF("find mraw_node failed\n");
return -1;
}
LOG_INF("find mraw_node done\n");
MRAW_BASE = of_iomap(mraw_node, 0);
if (!MRAW_BASE)
LOG_INF("base MRAW_BASE failed\n");
// ======================== here need to be modified =====================
if (PDA_devs[0].irq > 0) {
if (PDA_devs[0].irq > 0 && g_PDA_quantity > 0) {
// Get IRQ Flag from device node
nRet = of_property_read_u32_array(node,
"interrupts",
irq_info,
ARRAY_SIZE(irq_info));
if (nRet) {
LOG_INF("PDA1 get irq flags from DTS fail!!\n");
return -ENODEV;
}
LOG_INF("PDA1 irq_info: %d\n", irq_info[2]);
nRet = request_irq(PDA_devs[0].irq,
(irq_handler_t) pda_irqhandle,
irq_info[2],
(const char *)node->name,
NULL);
if (nRet) {
LOG_INF("PDA1 request_irq Fail: %d\n", nRet);
return nRet;
}
} else {
LOG_INF("PDA1 get IRQ ID Fail or No IRQ: %d\n", PDA_devs[0].irq);
}
}
#ifdef PDA_MMQOS
pda_mmqos_init();
#endif
LOG_INF("Attached!!\n");
LOG_INF("probe End\n");
return nRet;
}
static int PDA_remove(struct platform_device *pdev)
{
PDA_UnRegCharDev();
pm_runtime_disable(&pdev->dev);
return 0;
}
static int PDA_suspend(struct platform_device *pdev, pm_message_t mesg)
{
return 0;
}
static int PDA_resume(struct platform_device *pdev)
{
return 0;
}
static int PDA2_probe(struct platform_device *pdev)
{
int nRet = 0;
struct device_node *node;
unsigned int irq_info[3];
int i, larbs;
LOG_INF("PDA2 probe Start\n");
// get PDA node
node = of_find_compatible_node(NULL, NULL, "mediatek,camera-pda2");
if (!node) {
LOG_INF("find camera-pda node failed\n");
return -1;
}
LOG_INF("find camera-pda node done\n");
// must porting in dts
larbs = of_count_phandle_with_args(
pdev->dev.of_node, "mediatek,larbs", NULL);
LOG_INF("larb_num:%d\n", larbs);
for (i = 0; i < larbs; i++)
larb2 = pda_init_larb(pdev, i);
#if IS_ENABLED(CONFIG_OF)
g_dev2 = &pdev->dev;
if (dma_set_mask_and_coherent(g_dev2, DMA_BIT_MASK(34)))
LOG_INF("No suitable DMA available\n");
//power on smi
// consumer driver probe
pm_runtime_enable(g_dev2); //Note: Its not larb's device.
LOG_INF("pm_runtime_enable pda2 done\n");
#endif
// get PDA address, and PDA quantity
PDA_devs[1].m_pda_base = of_iomap(node, 0);
if (!PDA_devs[1].m_pda_base)
LOG_INF("base m_pda_base failed, index: %d\n", 1);
// get IRQ ID and request IRQ
PDA_devs[1].irq = irq_of_parse_and_map(node, 0);
LOG_INF("PDA_dev[1]->irq: %d", PDA_devs[1].irq);
if (PDA_devs[1].irq != 0)
g_PDA_quantity++;
LOG_INF("PDA quantity: %d\n", g_PDA_quantity);
if (PDA_devs[1].irq > 0) {
if (PDA_devs[1].irq > 0 && g_PDA_quantity > 1) {
// Get IRQ Flag from device node
nRet = of_property_read_u32_array(node,
"interrupts",
irq_info,
ARRAY_SIZE(irq_info));
if (nRet) {
LOG_INF("PDA2 get irq flags from DTS fail!!\n");
return -ENODEV;
}
LOG_INF("PDA2 irq_info: %d\n", irq_info[2]);
nRet = request_irq(PDA_devs[1].irq,
(irq_handler_t) pda2_irqhandle,
irq_info[2],
(const char *)node->name,
NULL);
if (nRet) {
LOG_INF("PDA2 request_irq Fail: %d\n", nRet);
return nRet;
}
} else {
LOG_INF("PDA2 get IRQ ID Fail or No IRQ: %d\n", PDA_devs[1].irq);
}
}
LOG_INF("PDA2 probe End\n");
return nRet;
}
static int PDA2_remove(struct platform_device *pdev)
{
pm_runtime_disable(&pdev->dev);
return 0;
}
//////////////////////////////////////// PDA driver //////////////////////////
#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id gpda_of_device_id[] = {
{.compatible = "mediatek,camera-pda",},
{}
};
#endif
MODULE_DEVICE_TABLE(of, gpda_of_device_id);
static struct platform_driver PDADriver = {
.probe = PDA_probe,
.remove = PDA_remove,
.suspend = PDA_suspend,
.resume = PDA_resume,
.driver = {
.name = PDA_DEV_NAME,
.owner = THIS_MODULE,
#if IS_ENABLED(CONFIG_OF)
.of_match_table = of_match_ptr(gpda_of_device_id),
#endif
}
};
//////////////////////////////////////// PDA 2 driver ////////////////////////
#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id gpda2_of_device_id[] = {
{.compatible = "mediatek,camera-pda2",},
{}
};
#endif
MODULE_DEVICE_TABLE(of, gpda2_of_device_id);
static struct platform_driver PDA2Driver = {
.probe = PDA2_probe,
.remove = PDA2_remove,
.driver = {
.name = "camera-pda2",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(gpda2_of_device_id),
}
};
static int __init camera_pda_init(void)
{
int ret = 0;
ret = platform_driver_register(&PDADriver);
if (ret < 0) {
LOG_INF("platform_driver_register PDADriver\n");
return ret;
}
ret = platform_driver_register(&PDA2Driver);
if (ret < 0) {
LOG_INF("platform_driver_register PDADriver\n");
return ret;
}
#ifdef PDA_TF_DUMP_71_1
// PDA 0
mtk_iommu_register_fault_callback(M4U_PORT_L25_CAM_PDAI_A0,
(mtk_iommu_fault_callback_t)pda_tfault_callback,
NULL, false);
mtk_iommu_register_fault_callback(M4U_PORT_L25_CAM_PDAI_A1,
(mtk_iommu_fault_callback_t)pda_tfault_callback,
NULL, false);
mtk_iommu_register_fault_callback(M4U_PORT_L25_CAM_PDAO_A,
(mtk_iommu_fault_callback_t)pda_tfault_callback,
NULL, false);
// PDA 1
mtk_iommu_register_fault_callback(M4U_PORT_L26_CAM_PDAI_B0,
(mtk_iommu_fault_callback_t)pda_tfault_callback,
NULL, false);
mtk_iommu_register_fault_callback(M4U_PORT_L26_CAM_PDAI_B1,
(mtk_iommu_fault_callback_t)pda_tfault_callback,
NULL, false);
mtk_iommu_register_fault_callback(M4U_PORT_L26_CAM_PDAO_B,
(mtk_iommu_fault_callback_t)pda_tfault_callback,
NULL, false);
#endif
return ret;
}
static void __exit camera_pda_exit(void)
{
platform_driver_unregister(&PDADriver);
platform_driver_unregister(&PDA2Driver);
}
/****************************************************************************
*
****************************************************************************/
module_init(camera_pda_init);
module_exit(camera_pda_exit);
MODULE_DESCRIPTION("Camera PDA driver");
MODULE_AUTHOR("MM6SW3");
MODULE_LICENSE("GPL");