blob: 48ffc2bd2d0ec44f3f8b2fd6e883e7cc370cf85e [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2020 Intel Corporation
#include <linux/module.h>
#include <media/v4l2-event.h>
#include "ipu.h"
#include "ipu-platform-regs.h"
#include "ipu-trace.h"
#include "ipu-isys.h"
#include "ipu-platform-isys-csi2-reg.h"
const struct ipu_isys_pixelformat ipu_isys_pfmts[] = {
{V4L2_PIX_FMT_SBGGR12, 16, 12, 0, MEDIA_BUS_FMT_SBGGR12_1X12,
IPU_FW_ISYS_FRAME_FORMAT_RAW16},
{V4L2_PIX_FMT_SGBRG12, 16, 12, 0, MEDIA_BUS_FMT_SGBRG12_1X12,
IPU_FW_ISYS_FRAME_FORMAT_RAW16},
{V4L2_PIX_FMT_SGRBG12, 16, 12, 0, MEDIA_BUS_FMT_SGRBG12_1X12,
IPU_FW_ISYS_FRAME_FORMAT_RAW16},
{V4L2_PIX_FMT_SRGGB12, 16, 12, 0, MEDIA_BUS_FMT_SRGGB12_1X12,
IPU_FW_ISYS_FRAME_FORMAT_RAW16},
{V4L2_PIX_FMT_SBGGR10, 16, 10, 0, MEDIA_BUS_FMT_SBGGR10_1X10,
IPU_FW_ISYS_FRAME_FORMAT_RAW16},
{V4L2_PIX_FMT_SGBRG10, 16, 10, 0, MEDIA_BUS_FMT_SGBRG10_1X10,
IPU_FW_ISYS_FRAME_FORMAT_RAW16},
{V4L2_PIX_FMT_SGRBG10, 16, 10, 0, MEDIA_BUS_FMT_SGRBG10_1X10,
IPU_FW_ISYS_FRAME_FORMAT_RAW16},
{V4L2_PIX_FMT_SRGGB10, 16, 10, 0, MEDIA_BUS_FMT_SRGGB10_1X10,
IPU_FW_ISYS_FRAME_FORMAT_RAW16},
{V4L2_PIX_FMT_SBGGR8, 8, 8, 0, MEDIA_BUS_FMT_SBGGR8_1X8,
IPU_FW_ISYS_FRAME_FORMAT_RAW8},
{V4L2_PIX_FMT_SGBRG8, 8, 8, 0, MEDIA_BUS_FMT_SGBRG8_1X8,
IPU_FW_ISYS_FRAME_FORMAT_RAW8},
{V4L2_PIX_FMT_SGRBG8, 8, 8, 0, MEDIA_BUS_FMT_SGRBG8_1X8,
IPU_FW_ISYS_FRAME_FORMAT_RAW8},
{V4L2_PIX_FMT_SRGGB8, 8, 8, 0, MEDIA_BUS_FMT_SRGGB8_1X8,
IPU_FW_ISYS_FRAME_FORMAT_RAW8},
{}
};
struct ipu_trace_block isys_trace_blocks[] = {
{
.offset = IPU_TRACE_REG_IS_TRACE_UNIT_BASE,
.type = IPU_TRACE_BLOCK_TUN,
},
{
.offset = IPU_TRACE_REG_IS_SP_EVQ_BASE,
.type = IPU_TRACE_BLOCK_TM,
},
{
.offset = IPU_TRACE_REG_IS_SP_GPC_BASE,
.type = IPU_TRACE_BLOCK_GPC,
},
{
.offset = IPU_TRACE_REG_IS_ISL_GPC_BASE,
.type = IPU_TRACE_BLOCK_GPC,
},
{
.offset = IPU_TRACE_REG_IS_MMU_GPC_BASE,
.type = IPU_TRACE_BLOCK_GPC,
},
{
/* Note! this covers all 8 blocks */
.offset = IPU_TRACE_REG_CSI2_TM_BASE(0),
.type = IPU_TRACE_CSI2,
},
{
/* Note! this covers all 11 blocks */
.offset = IPU_TRACE_REG_CSI2_PORT_SIG2SIO_GR_BASE(0),
.type = IPU_TRACE_SIG2CIOS,
},
{
.offset = IPU_TRACE_REG_IS_GPREG_TRACE_TIMER_RST_N,
.type = IPU_TRACE_TIMER_RST,
},
{
.type = IPU_TRACE_BLOCK_END,
}
};
void isys_setup_hw(struct ipu_isys *isys)
{
void __iomem *base = isys->pdata->base;
const u8 *thd = isys->pdata->ipdata->hw_variant.cdc_fifo_threshold;
u32 irqs = 0;
unsigned int i, nr;
nr = (ipu_ver == IPU_VER_6 || ipu_ver == IPU_VER_6EP ||
ipu_ver == IPU_VER_6EP_MTL) ?
IPU6_ISYS_CSI_PORT_NUM : IPU6SE_ISYS_CSI_PORT_NUM;
/* Enable irqs for all MIPI ports */
for (i = 0; i < nr; i++)
irqs |= IPU_ISYS_UNISPART_IRQ_CSI2(i);
if (ipu_ver == IPU_VER_6EP_MTL) {
writel(irqs, base + IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_EDGE);
writel(irqs, base + IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_LEVEL_NOT_PULSE);
writel(0xffffffff, base + IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_CLEAR);
writel(irqs, base + IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_MASK);
writel(irqs, base + IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_ENABLE);
} else {
writel(irqs, base + IPU_REG_ISYS_CSI_TOP_CTRL0_IRQ_EDGE);
writel(irqs, base + IPU_REG_ISYS_CSI_TOP_CTRL0_IRQ_LEVEL_NOT_PULSE);
writel(0xffffffff, base + IPU_REG_ISYS_CSI_TOP_CTRL0_IRQ_CLEAR);
writel(irqs, base + IPU_REG_ISYS_CSI_TOP_CTRL0_IRQ_MASK);
writel(irqs, base + IPU_REG_ISYS_CSI_TOP_CTRL0_IRQ_ENABLE);
}
irqs = ISYS_UNISPART_IRQS;
writel(irqs, base + IPU_REG_ISYS_UNISPART_IRQ_EDGE);
writel(irqs, base + IPU_REG_ISYS_UNISPART_IRQ_LEVEL_NOT_PULSE);
writel(0xffffffff, base + IPU_REG_ISYS_UNISPART_IRQ_CLEAR);
writel(irqs, base + IPU_REG_ISYS_UNISPART_IRQ_MASK);
writel(irqs, base + IPU_REG_ISYS_UNISPART_IRQ_ENABLE);
writel(0, base + IPU_REG_ISYS_UNISPART_SW_IRQ_REG);
writel(0, base + IPU_REG_ISYS_UNISPART_SW_IRQ_MUX_REG);
/* Write CDC FIFO threshold values for isys */
for (i = 0; i < isys->pdata->ipdata->hw_variant.cdc_fifos; i++)
writel(thd[i], base + IPU_REG_ISYS_CDC_THRESHOLD(i));
}
irqreturn_t isys_isr(struct ipu_bus_device *adev)
{
struct ipu_isys *isys = ipu_bus_get_drvdata(adev);
void __iomem *base = isys->pdata->base;
u32 status_sw, status_csi;
u32 ctrl0_status, ctrl0_clear;
spin_lock(&isys->power_lock);
if (!isys->power) {
spin_unlock(&isys->power_lock);
return IRQ_NONE;
}
if (ipu_ver == IPU_VER_6EP_MTL) {
ctrl0_status = IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_STATUS;
ctrl0_clear = IPU6V6_REG_ISYS_CSI_TOP_CTRL0_IRQ_CLEAR;
} else {
ctrl0_status = IPU_REG_ISYS_CSI_TOP_CTRL0_IRQ_STATUS;
ctrl0_clear = IPU_REG_ISYS_CSI_TOP_CTRL0_IRQ_CLEAR;
}
status_csi = readl(isys->pdata->base + ctrl0_status);
status_sw = readl(isys->pdata->base + IPU_REG_ISYS_UNISPART_IRQ_STATUS);
writel(ISYS_UNISPART_IRQS & ~IPU_ISYS_UNISPART_IRQ_SW,
base + IPU_REG_ISYS_UNISPART_IRQ_MASK);
do {
writel(status_csi, isys->pdata->base + ctrl0_clear);
writel(status_sw, isys->pdata->base +
IPU_REG_ISYS_UNISPART_IRQ_CLEAR);
if (isys->isr_csi2_bits & status_csi) {
unsigned int i;
for (i = 0; i < isys->pdata->ipdata->csi2.nports; i++) {
/* irq from not enabled port */
if (!isys->csi2[i].base)
continue;
if (status_csi & IPU_ISYS_UNISPART_IRQ_CSI2(i))
ipu_isys_csi2_isr(&isys->csi2[i]);
}
}
writel(0, base + IPU_REG_ISYS_UNISPART_SW_IRQ_REG);
if (!isys_isr_one(adev))
status_sw = IPU_ISYS_UNISPART_IRQ_SW;
else
status_sw = 0;
status_csi = readl(isys->pdata->base + ctrl0_status);
status_sw |= readl(isys->pdata->base +
IPU_REG_ISYS_UNISPART_IRQ_STATUS);
} while (((status_csi & isys->isr_csi2_bits) ||
(status_sw & IPU_ISYS_UNISPART_IRQ_SW)) &&
!isys->adev->isp->flr_done);
writel(ISYS_UNISPART_IRQS, base + IPU_REG_ISYS_UNISPART_IRQ_MASK);
spin_unlock(&isys->power_lock);
return IRQ_HANDLED;
}