* [PATCH v2 01/44] media: ipu6: Add helpers for IPU runtime variation
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 02/44] media: ipu6: Rename pointer to firmware context Antti Laakso
` (42 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
And replace inline functions with defines.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-isys.c | 4 +--
drivers/media/pci/intel/ipu6/ipu6.c | 29 ++++++++--------
drivers/media/pci/intel/ipu6/ipu6.h | 42 +++++-------------------
3 files changed, 25 insertions(+), 50 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 24db2763de54..799e7b30e6a2 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -1104,9 +1104,9 @@ static int isys_probe(struct auxiliary_device *auxdev,
isys_iwake_watermark_init(isys);
- if (is_ipu6se(adev->isp->hw_ver))
+ if (IS_IPU6SE(adev->isp))
isys->phy_set_power = ipu6_isys_jsl_phy_set_power;
- else if (is_ipu6ep_mtl(adev->isp->hw_ver))
+ else if (IS_IPU6EP_MTL(adev->isp))
isys->phy_set_power = ipu6_isys_dwc_phy_set_power;
else
isys->phy_set_power = ipu6_isys_mcd_phy_set_power;
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 5449a2006bcc..6d3235352a1c 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -290,8 +290,6 @@ EXPORT_SYMBOL_NS_GPL(ipu6_configure_spc, "INTEL_IPU6");
static void ipu6_internal_pdata_init(struct ipu6_device *isp)
{
- u8 hw_ver = isp->hw_ver;
-
isys_ipdata.num_parallel_streams = IPU6_ISYS_NUM_STREAMS;
isys_ipdata.sram_gran_shift = IPU6_SRAM_GRANULARITY_SHIFT;
isys_ipdata.sram_gran_size = IPU6_SRAM_GRANULARITY_SIZE;
@@ -314,19 +312,19 @@ static void ipu6_internal_pdata_init(struct ipu6_device *isp)
IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_STATUS;
isys_ipdata.csi2.ctrl0_irq_lnp =
IPU6_REG_ISYS_CSI_TOP_CTRL0_IRQ_LEVEL_NOT_PULSE;
- isys_ipdata.enhanced_iwake = is_ipu6ep_mtl(hw_ver) || is_ipu6ep(hw_ver);
+ isys_ipdata.enhanced_iwake = IS_IPU6EP_MTL(isp) || IS_IPU6EP(isp);
psys_ipdata.hw_variant.spc_offset = IPU6_PSYS_SPC_OFFSET;
isys_ipdata.csi2.fw_access_port_ofs = CSI_REG_HUB_FW_ACCESS_PORT_OFS;
- if (is_ipu6ep(hw_ver)) {
+ if (IS_IPU6EP(isp)) {
isys_ipdata.ltr = IPU6EP_LTR_VALUE;
isys_ipdata.memopen_threshold = IPU6EP_MIN_MEMOPEN_TH;
}
- if (is_ipu6_tgl(hw_ver))
+ if (IS_IPU6_TGL(isp))
isys_ipdata.csi2.nports = IPU6_TGL_ISYS_CSI2_NPORTS;
- if (is_ipu6ep_mtl(hw_ver)) {
+ if (IS_IPU6EP_MTL(isp)) {
isys_ipdata.csi2.nports = IPU6EP_MTL_ISYS_CSI2_NPORTS;
isys_ipdata.csi2.ctrl0_irq_edge =
@@ -347,7 +345,7 @@ static void ipu6_internal_pdata_init(struct ipu6_device *isp)
isys_ipdata.memopen_threshold = IPU6EP_MTL_MIN_MEMOPEN_TH;
}
- if (is_ipu6se(hw_ver)) {
+ if (IS_IPU6SE(isp)) {
isys_ipdata.csi2.nports = IPU6SE_ISYS_CSI2_NPORTS;
isys_ipdata.csi2.irq_mask = IPU6SE_CSI_RX_ERROR_IRQ_MASK;
isys_ipdata.num_parallel_streams = IPU6SE_ISYS_NUM_STREAMS;
@@ -454,12 +452,13 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent,
return psys_adev;
}
-static int ipu6_pci_config_setup(struct pci_dev *dev, u8 hw_ver)
+static int ipu6_pci_config_setup(struct pci_dev *dev)
{
+ struct ipu6_device *isp = pci_get_drvdata(dev);
int ret;
/* No PCI msi capability for IPU6EP */
- if (is_ipu6ep(hw_ver) || is_ipu6ep_mtl(hw_ver)) {
+ if (IS_IPU6EP(isp) || IS_IPU6EP_MTL(isp)) {
/* likely do nothing as msi not enabled by default */
pci_disable_msi(dev);
return 0;
@@ -525,26 +524,26 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
isp->cpd_metadata_cmpnt_size = sizeof(struct ipu6_cpd_metadata_cmpnt);
switch (id->device) {
case PCI_DEVICE_ID_INTEL_IPU6:
- isp->hw_ver = IPU6_VER_6;
+ isp->hw_ver = IPU_VERSION_6;
isp->cpd_fw_name = IPU6_FIRMWARE_NAME;
break;
case PCI_DEVICE_ID_INTEL_IPU6SE:
- isp->hw_ver = IPU6_VER_6SE;
+ isp->hw_ver = IPU_VERSION_6SE;
isp->cpd_fw_name = IPU6SE_FIRMWARE_NAME;
isp->cpd_metadata_cmpnt_size =
sizeof(struct ipu6se_cpd_metadata_cmpnt);
break;
case PCI_DEVICE_ID_INTEL_IPU6EP_ADLP:
case PCI_DEVICE_ID_INTEL_IPU6EP_RPLP:
- isp->hw_ver = IPU6_VER_6EP;
+ isp->hw_ver = IPU_VERSION_6EP;
isp->cpd_fw_name = IPU6EP_FIRMWARE_NAME;
break;
case PCI_DEVICE_ID_INTEL_IPU6EP_ADLN:
- isp->hw_ver = IPU6_VER_6EP;
+ isp->hw_ver = IPU_VERSION_6EP;
isp->cpd_fw_name = IPU6EPADLN_FIRMWARE_NAME;
break;
case PCI_DEVICE_ID_INTEL_IPU6EP_MTL:
- isp->hw_ver = IPU6_VER_6EP_MTL;
+ isp->hw_ver = IPU_VERSION_6EP_MTL;
isp->cpd_fw_name = IPU6EPMTL_FIRMWARE_NAME;
break;
default:
@@ -564,7 +563,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dma_set_max_seg_size(dev, UINT_MAX);
- ret = ipu6_pci_config_setup(pdev, isp->hw_ver);
+ ret = ipu6_pci_config_setup(pdev);
if (ret)
return ret;
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index 92e3c3414c91..07ca59048f44 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -23,39 +23,15 @@ struct ipu6_bus_device;
#define IPU6EPMTL_FIRMWARE_NAME "intel/ipu/ipu6epmtl_fw.bin"
#define IPU6EPADLN_FIRMWARE_NAME "intel/ipu/ipu6epadln_fw.bin"
-enum ipu6_version {
- IPU6_VER_INVALID = 0,
- IPU6_VER_6 = 1,
- IPU6_VER_6SE = 3,
- IPU6_VER_6EP = 5,
- IPU6_VER_6EP_MTL = 6,
-};
-
-/*
- * IPU6 - TGL
- * IPU6SE - JSL
- * IPU6EP - ADL/RPL
- * IPU6EP_MTL - MTL
- */
-static inline bool is_ipu6se(u8 hw_ver)
-{
- return hw_ver == IPU6_VER_6SE;
-}
-
-static inline bool is_ipu6ep(u8 hw_ver)
-{
- return hw_ver == IPU6_VER_6EP;
-}
-
-static inline bool is_ipu6ep_mtl(u8 hw_ver)
-{
- return hw_ver == IPU6_VER_6EP_MTL;
-}
-
-static inline bool is_ipu6_tgl(u8 hw_ver)
-{
- return hw_ver == IPU6_VER_6;
-}
+#define IPU_VERSION_6 BIT(0) /* TGL */
+#define IPU_VERSION_6SE BIT(1) /* JSL */
+#define IPU_VERSION_6EP BIT(2) /* ADL/RPL */
+#define IPU_VERSION_6EP_MTL BIT(3) /* MTL */
+
+#define IS_IPU6_TGL(isp) ((isp)->hw_ver & IPU_VERSION_6)
+#define IS_IPU6SE(isp) ((isp)->hw_ver & IPU_VERSION_6SE)
+#define IS_IPU6EP(isp) ((isp)->hw_ver & IPU_VERSION_6EP)
+#define IS_IPU6EP_MTL(isp) ((isp)->hw_ver & IPU_VERSION_6EP_MTL)
/*
* ISYS DMA can overshoot. For higher resolutions over allocation is one line
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 02/44] media: ipu6: Rename pointer to firmware context
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
2026-08-21 11:42 ` [PATCH v2 01/44] media: ipu6: Add helpers for IPU runtime variation Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 03/44] media: ipu6: Rename buttress_ipc pointer Antti Laakso
` (41 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The name fwcom is used to refer firmware communication context
and firmware communication configuration. Try to avoid confusion
and rename context variable.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-fw-isys.c | 56 ++++++++++---------
.../media/pci/intel/ipu6/ipu6-isys-video.c | 4 +-
drivers/media/pci/intel/ipu6/ipu6-isys.c | 6 +-
drivers/media/pci/intel/ipu6/ipu6-isys.h | 5 +-
4 files changed, 36 insertions(+), 35 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
index 62ed92ff1d30..a65e9f1aa104 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
@@ -32,7 +32,7 @@ static int handle_proxy_response(struct ipu6_isys *isys, unsigned int req_id)
struct ipu6_fw_isys_proxy_resp_info_abi *resp;
int ret;
- resp = ipu6_recv_get_token(isys->fwcom, IPU6_BASE_PROXY_RECV_QUEUES);
+ resp = ipu6_recv_get_token(isys->fwctx, IPU6_BASE_PROXY_RECV_QUEUES);
if (!resp)
return 1;
@@ -42,7 +42,7 @@ static int handle_proxy_response(struct ipu6_isys *isys, unsigned int req_id)
ret = req_id == resp->request_id ? 0 : -EIO;
- ipu6_recv_put_token(isys->fwcom, IPU6_BASE_PROXY_RECV_QUEUES);
+ ipu6_recv_put_token(isys->fwctx, IPU6_BASE_PROXY_RECV_QUEUES);
return ret;
}
@@ -52,7 +52,7 @@ int ipu6_fw_isys_send_proxy_token(struct ipu6_isys *isys,
unsigned int index,
unsigned int offset, u32 value)
{
- struct ipu6_fw_com_context *ctx = isys->fwcom;
+ struct ipu6_fw_com_context *ctx = isys->fwctx;
struct device *dev = &isys->adev->auxdev.dev;
struct ipu6_fw_proxy_send_queue_token *token;
unsigned int timeout = 1000;
@@ -96,7 +96,7 @@ int ipu6_fw_isys_complex_cmd(struct ipu6_isys *isys,
dma_addr_t dma_mapped_buf,
size_t size, u16 send_type)
{
- struct ipu6_fw_com_context *ctx = isys->fwcom;
+ struct ipu6_fw_com_context *ctx = isys->fwctx;
struct device *dev = &isys->adev->auxdev.dev;
struct ipu6_fw_send_queue_token *token;
@@ -138,7 +138,7 @@ int ipu6_fw_isys_close(struct ipu6_isys *isys)
struct device *dev = &isys->adev->auxdev.dev;
int retry = IPU6_ISYS_CLOSE_RETRY;
unsigned long flags;
- void *fwcom;
+ void *fwctx;
int ret;
/*
@@ -148,9 +148,9 @@ int ipu6_fw_isys_close(struct ipu6_isys *isys)
* spinlock to wait the interrupt handler to be finished
*/
spin_lock_irqsave(&isys->power_lock, flags);
- ret = ipu6_fw_com_close(isys->fwcom);
- fwcom = isys->fwcom;
- isys->fwcom = NULL;
+ ret = ipu6_fw_com_close(isys->fwctx);
+ fwctx = isys->fwctx;
+ isys->fwctx = NULL;
spin_unlock_irqrestore(&isys->power_lock, flags);
if (ret)
dev_err(dev, "Device close failure: %d\n", ret);
@@ -158,14 +158,14 @@ int ipu6_fw_isys_close(struct ipu6_isys *isys)
/* release probably fails if the close failed. Let's try still */
do {
usleep_range(400, 500);
- ret = ipu6_fw_com_release(fwcom, 0);
+ ret = ipu6_fw_com_release(fwctx, 0);
retry--;
} while (ret && retry);
if (ret) {
dev_err(dev, "Device release time out %d\n", ret);
spin_lock_irqsave(&isys->power_lock, flags);
- isys->fwcom = fwcom;
+ isys->fwctx = fwctx;
spin_unlock_irqrestore(&isys->power_lock, flags);
}
@@ -176,11 +176,11 @@ void ipu6_fw_isys_cleanup(struct ipu6_isys *isys)
{
int ret;
- ret = ipu6_fw_com_release(isys->fwcom, 1);
+ ret = ipu6_fw_com_release(isys->fwctx, 1);
if (ret < 0)
dev_warn(&isys->adev->auxdev.dev,
"Device busy, fw_com release failed.");
- isys->fwcom = NULL;
+ isys->fwctx = NULL;
}
static void start_sp(struct ipu6_bus_device *adev)
@@ -212,7 +212,7 @@ static int query_sp(struct ipu6_bus_device *adev)
}
static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys *isys,
- struct ipu6_fw_com_cfg *fwcom,
+ struct ipu6_fw_com_cfg *fwcom_cfg,
unsigned int num_streams)
{
unsigned int max_send_queues, max_sram_blocks, max_devq_size;
@@ -258,14 +258,16 @@ static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys *isys,
if (!output_queue_cfg)
return -ENOMEM;
- fwcom->input = input_queue_cfg;
- fwcom->output = output_queue_cfg;
+ fwcom_cfg->input = input_queue_cfg;
+ fwcom_cfg->output = output_queue_cfg;
- fwcom->num_input_queues = isys_fw_cfg->num_send_queues[type_proxy] +
+ fwcom_cfg->num_input_queues =
+ isys_fw_cfg->num_send_queues[type_proxy] +
isys_fw_cfg->num_send_queues[type_dev] +
isys_fw_cfg->num_send_queues[type_msg];
- fwcom->num_output_queues = isys_fw_cfg->num_recv_queues[type_proxy] +
+ fwcom_cfg->num_output_queues =
+ isys_fw_cfg->num_recv_queues[type_proxy] +
isys_fw_cfg->num_recv_queues[type_dev] +
isys_fw_cfg->num_recv_queues[type_msg];
@@ -280,7 +282,7 @@ static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys *isys,
isys_fw_cfg->buffer_partition.num_gda_pages[i] = 0;
}
- /* FW assumes proxy interface at fwcom queue 0 */
+ /* FW assumes proxy interface at fwcom_cfg queue 0 */
for (i = 0; i < isys_fw_cfg->num_send_queues[type_proxy]; i++) {
input_queue_cfg[i].token_size =
sizeof(struct ipu6_fw_proxy_send_queue_token);
@@ -314,9 +316,9 @@ static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys *isys,
IPU6_ISYS_SIZE_RECV_QUEUE;
}
- fwcom->dmem_addr = isys->pdata->ipdata->hw_variant.dmem_offset;
- fwcom->specific_addr = isys_fw_cfg;
- fwcom->specific_size = sizeof(*isys_fw_cfg);
+ fwcom_cfg->dmem_addr = isys->pdata->ipdata->hw_variant.dmem_offset;
+ fwcom_cfg->specific_addr = isys_fw_cfg;
+ fwcom_cfg->specific_size = sizeof(*isys_fw_cfg);
return 0;
}
@@ -325,23 +327,23 @@ int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
{
struct device *dev = &isys->adev->auxdev.dev;
int retry = IPU6_ISYS_OPEN_RETRY;
- struct ipu6_fw_com_cfg fwcom = {
+ struct ipu6_fw_com_cfg fwcom_cfg = {
.cell_start = start_sp,
.cell_ready = query_sp,
.buttress_boot_offset = SYSCOM_BUTTRESS_FW_PARAMS_ISYS_OFFSET,
};
int ret;
- ipu6_isys_fwcom_cfg_init(isys, &fwcom, num_streams);
+ ipu6_isys_fwcom_cfg_init(isys, &fwcom_cfg, num_streams);
- isys->fwcom = ipu6_fw_com_prepare(&fwcom, isys->adev,
+ isys->fwctx = ipu6_fw_com_prepare(&fwcom_cfg, isys->adev,
isys->pdata->base);
- if (!isys->fwcom) {
+ if (!isys->fwctx) {
dev_err(dev, "isys fw com prepare failed\n");
return -EIO;
}
- ret = ipu6_fw_com_open(isys->fwcom);
+ ret = ipu6_fw_com_open(isys->fwctx);
if (ret) {
dev_err(dev, "isys fw com open failed %d\n", ret);
return ret;
@@ -349,7 +351,7 @@ int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
do {
usleep_range(400, 500);
- if (ipu6_fw_com_ready(isys->fwcom))
+ if (ipu6_fw_com_ready(isys->fwctx))
break;
retry--;
} while (retry > 0);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index 3ac48d2076da..89eb265737d7 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -1114,7 +1114,7 @@ int ipu6_isys_fw_open(struct ipu6_isys *isys)
*/
ipu6_cleanup_fw_msg_bufs(isys);
- if (isys->fwcom) {
+ if (isys->fwctx) {
/*
* Something went wrong in previous shutdown. As we are now
* restarting isys we can safely delete old context.
@@ -1147,7 +1147,7 @@ void ipu6_isys_fw_close(struct ipu6_isys *isys)
isys->ref_count--;
if (!isys->ref_count) {
ipu6_fw_isys_close(isys);
- if (isys->fwcom) {
+ if (isys->fwctx) {
isys->need_reset = true;
dev_warn(&isys->adev->auxdev.dev,
"failed to close fw isys\n");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 799e7b30e6a2..180a53f3d7ab 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -1212,10 +1212,10 @@ static int isys_isr_one(struct ipu6_bus_device *adev)
u32 index;
u64 ts;
- if (!isys->fwcom)
+ if (!isys->fwctx)
return 1;
- resp = ipu6_fw_isys_get_resp(isys->fwcom, IPU6_BASE_MSG_RECV_QUEUES);
+ resp = ipu6_fw_isys_get_resp(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
if (!resp)
return 1;
@@ -1324,7 +1324,7 @@ static int isys_isr_one(struct ipu6_bus_device *adev)
ipu6_isys_put_stream(stream);
leave:
- ipu6_fw_isys_put_resp(isys->fwcom, IPU6_BASE_MSG_RECV_QUEUES);
+ ipu6_fw_isys_put_resp(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
return 0;
}
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h
index 7fb8cb820912..0b139ab24431 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h
@@ -114,8 +114,7 @@ struct sensor_async_sd {
* @csi2_rx_ctrl_cached: cached shared value between all CSI2 receivers
* @streams_lock: serialise access to streams
* @streams: streams per firmware stream ID
- * @fwcom: fw communication layer private pointer
- * or optional external library private pointer
+ * @fwctx: fw communication layer context pointer
* @phy_termcal_val: the termination calibration value, only used for DWC PHY
* @need_reset: Isys requires d0i0->i3 transition
* @ref_count: total number of callers fw open
@@ -136,7 +135,7 @@ struct ipu6_isys {
spinlock_t streams_lock;
struct ipu6_isys_stream streams[IPU6_ISYS_MAX_STREAMS];
int streams_ref_count[IPU6_ISYS_MAX_STREAMS];
- void *fwcom;
+ void *fwctx;
u32 phy_termcal_val;
bool need_reset;
bool icache_prefetch;
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 03/44] media: ipu6: Rename buttress_ipc pointer
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
2026-08-21 11:42 ` [PATCH v2 01/44] media: ipu6: Add helpers for IPU runtime variation Antti Laakso
2026-08-21 11:42 ` [PATCH v2 02/44] media: ipu6: Rename pointer to firmware context Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 04/44] media: ipu6: Remove duplicate warnings in cpd validation Antti Laakso
` (40 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The ipu6_buttress_ipc structure is called as cse sometimes,
rename it to ipc for consistency.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-buttress.c | 33 ++++++++++----------
drivers/media/pci/intel/ipu6/ipu6-buttress.h | 2 +-
drivers/media/pci/intel/ipu6/ipu6.c | 4 +--
3 files changed, 20 insertions(+), 19 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index e0ecb4c8b081..cbe356589a9d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
@@ -221,7 +221,7 @@ static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp,
unsigned long tx_timeout_jiffies, rx_timeout_jiffies;
unsigned int i, retry = BUTTRESS_IPC_CMD_SEND_RETRY;
struct ipu6_buttress *b = &isp->buttress;
- struct ipu6_buttress_ipc *ipc = &b->cse;
+ struct ipu6_buttress_ipc *ipc = &b->ipc;
u32 val;
int ret;
int tout;
@@ -378,14 +378,15 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
if (irq_status & BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING) {
dev_dbg(&isp->pdev->dev,
"BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING\n");
- ipu6_buttress_ipc_recv(isp, &b->cse, &b->cse.recv_data);
- complete(&b->cse.recv_complete);
+
+ ipu6_buttress_ipc_recv(isp, &b->ipc, &b->ipc.recv_data);
+ complete(&b->ipc.recv_complete);
}
if (irq_status & BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE) {
dev_dbg(&isp->pdev->dev,
"BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE\n");
- complete(&b->cse.send_complete);
+ complete(&b->ipc.send_complete);
}
if (irq_status & BUTTRESS_ISR_SAI_VIOLATION &&
@@ -830,17 +831,17 @@ int ipu6_buttress_init(struct ipu6_device *isp)
mutex_init(&b->auth_mutex);
mutex_init(&b->cons_mutex);
mutex_init(&b->ipc_mutex);
- init_completion(&b->cse.send_complete);
- init_completion(&b->cse.recv_complete);
-
- b->cse.nack = BUTTRESS_CSE2IUDATA0_IPC_NACK;
- b->cse.nack_mask = BUTTRESS_CSE2IUDATA0_IPC_NACK_MASK;
- b->cse.csr_in = BUTTRESS_REG_CSE2IUCSR;
- b->cse.csr_out = BUTTRESS_REG_IU2CSECSR;
- b->cse.db0_in = BUTTRESS_REG_CSE2IUDB0;
- b->cse.db0_out = BUTTRESS_REG_IU2CSEDB0;
- b->cse.data0_in = BUTTRESS_REG_CSE2IUDATA0;
- b->cse.data0_out = BUTTRESS_REG_IU2CSEDATA0;
+ init_completion(&b->ipc.send_complete);
+ init_completion(&b->ipc.recv_complete);
+
+ b->ipc.nack = BUTTRESS_CSE2IUDATA0_IPC_NACK;
+ b->ipc.nack_mask = BUTTRESS_CSE2IUDATA0_IPC_NACK_MASK;
+ b->ipc.csr_in = BUTTRESS_REG_CSE2IUCSR;
+ b->ipc.csr_out = BUTTRESS_REG_IU2CSECSR;
+ b->ipc.db0_in = BUTTRESS_REG_CSE2IUDB0;
+ b->ipc.db0_out = BUTTRESS_REG_IU2CSEDB0;
+ b->ipc.data0_in = BUTTRESS_REG_CSE2IUDATA0;
+ b->ipc.data0_out = BUTTRESS_REG_IU2CSEDATA0;
INIT_LIST_HEAD(&b->constraints);
@@ -877,7 +878,7 @@ int ipu6_buttress_init(struct ipu6_device *isp)
/* Retry couple of times in case of CSE initialization is delayed */
do {
- ret = ipu6_buttress_ipc_reset(isp, &b->cse);
+ ret = ipu6_buttress_ipc_reset(isp, &b->ipc);
if (ret) {
dev_warn(&isp->pdev->dev,
"IPC reset protocol failed, retrying\n");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.h b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
index 51e5ad48db82..b1c1a10e3e6d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
@@ -44,7 +44,7 @@ struct ipu6_buttress_ipc {
struct ipu6_buttress {
struct mutex power_mutex, auth_mutex, cons_mutex, ipc_mutex;
- struct ipu6_buttress_ipc cse;
+ struct ipu6_buttress_ipc ipc;
struct list_head constraints;
u32 wdt_cached_value;
bool force_suspend;
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 6d3235352a1c..efb58bc4d127 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -765,7 +765,7 @@ static int ipu6_resume(struct device *dev)
ipu6_buttress_restore(isp);
- ret = ipu6_buttress_ipc_reset(isp, &b->cse);
+ ret = ipu6_buttress_ipc_reset(isp, &b->ipc);
if (ret)
dev_err(&isp->pdev->dev, "IPC reset protocol failed!\n");
@@ -797,7 +797,7 @@ static int ipu6_runtime_resume(struct device *dev)
struct ipu6_buttress *b = &isp->buttress;
isp->need_ipc_reset = false;
- ret = ipu6_buttress_ipc_reset(isp, &b->cse);
+ ret = ipu6_buttress_ipc_reset(isp, &b->ipc);
if (ret)
dev_err(&isp->pdev->dev, "IPC reset protocol failed\n");
}
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 04/44] media: ipu6: Remove duplicate warnings in cpd validation
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (2 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 03/44] media: ipu6: Rename buttress_ipc pointer Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 05/44] media: ipu6: Remove unused ipu6 firmware struct Antti Laakso
` (39 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
Some of the error paths printed same or similar errors twice,
once is enough.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-cpd.c | 29 ++++++-------------------
1 file changed, 7 insertions(+), 22 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-cpd.c b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
index b7013f6524ec..966a16a300f8 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-cpd.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
@@ -266,7 +266,6 @@ static int ipu6_cpd_validate_moduledata(struct ipu6_device *isp,
u32 moduledata_size)
{
const struct ipu6_cpd_module_data_hdr *mod_hdr = moduledata;
- int ret;
/* Ensure moduledata hdr is within moduledata */
if (moduledata_size < sizeof(*mod_hdr) ||
@@ -276,15 +275,9 @@ static int ipu6_cpd_validate_moduledata(struct ipu6_device *isp,
}
dev_dbg(&isp->pdev->dev, "FW version: %x\n", mod_hdr->fw_pkg_date);
- ret = ipu6_cpd_validate_cpd(isp, moduledata + mod_hdr->hdr_len,
- moduledata_size - mod_hdr->hdr_len,
- moduledata_size);
- if (ret) {
- dev_err(&isp->pdev->dev, "Invalid CPD in moduledata\n");
- return ret;
- }
-
- return 0;
+ return ipu6_cpd_validate_cpd(isp, moduledata + mod_hdr->hdr_len,
+ moduledata_size - mod_hdr->hdr_len,
+ moduledata_size);
}
static int ipu6_cpd_validate_metadata(struct ipu6_device *isp,
@@ -325,10 +318,8 @@ int ipu6_cpd_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
ret = ipu6_cpd_validate_cpd(isp, cpd_file, cpd_file_size,
cpd_file_size);
- if (ret) {
- dev_err(&isp->pdev->dev, "Invalid CPD in file\n");
+ if (ret)
return ret;
- }
/* Check for CPD file marker */
if (hdr->hdr_mark != CPD_HDR_MARK) {
@@ -346,17 +337,11 @@ int ipu6_cpd_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
/* Validate metadata */
ent = ipu6_cpd_get_metadata(cpd_file);
ret = ipu6_cpd_validate_metadata(isp, cpd_file + ent->offset, ent->len);
- if (ret) {
- dev_err(&isp->pdev->dev, "Invalid CPD metadata\n");
+ if (ret)
return ret;
- }
/* Validate moduledata */
ent = ipu6_cpd_get_moduledata(cpd_file);
- ret = ipu6_cpd_validate_moduledata(isp, cpd_file + ent->offset,
- ent->len);
- if (ret)
- dev_err(&isp->pdev->dev, "Invalid CPD moduledata\n");
-
- return ret;
+ return ipu6_cpd_validate_moduledata(isp, cpd_file + ent->offset,
+ ent->len);
}
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 05/44] media: ipu6: Remove unused ipu6 firmware struct
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (3 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 04/44] media: ipu6: Remove duplicate warnings in cpd validation Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 06/44] media: ipu6: Cleanup ipu6_mmu_init() Antti Laakso
` (38 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The struct ipu6_fw_proxy_write_queue_token is not used anywhere,
remove it.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-fw-isys.h | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
index b60f02076d8a..393245a633f4 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
@@ -511,21 +511,6 @@ struct ipu6_fw_isys_proxy_resp_info_abi {
struct ipu6_fw_isys_proxy_error_info_abi error_info;
};
-/**
- * struct ipu6_fw_proxy_write_queue_token - ISYS proxy write queue token
- * @request_id: update id for the specific proxy write request
- * @region_index: Region id for the proxy write request
- * @offset: Offset of the write request according to the base address
- * of the region
- * @value: Value that is requested to be written with the proxy write request
- */
-struct ipu6_fw_proxy_write_queue_token {
- u32 request_id;
- u32 region_index;
- u32 offset;
- u32 value;
-};
-
/**
* struct ipu6_fw_resp_queue_token - ISYS response queue token
* @resp_info: response info
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 06/44] media: ipu6: Cleanup ipu6_mmu_init()
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (4 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 05/44] media: ipu6: Remove unused ipu6 firmware struct Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 07/44] media: ipu6: Simplify firmware com arguments Antti Laakso
` (37 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The struct ipu6_mmu_pdata is used only in ipu6_mmu_init(),
and not really needed, remove it.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-mmu.c | 13 ++++++-------
drivers/media/pci/intel/ipu6/ipu6.h | 6 ------
2 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.c b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
index 0e6dca36b6ba..6b1a49ebbcc2 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
@@ -750,27 +750,26 @@ struct ipu6_mmu *ipu6_mmu_init(struct device *dev,
const struct ipu6_hw_variants *hw)
{
struct ipu6_device *isp = pci_get_drvdata(to_pci_dev(dev));
- struct ipu6_mmu_pdata *pdata;
+ struct ipu6_mmu_hw *mmu_hw;
struct ipu6_mmu *mmu;
unsigned int i;
if (hw->nr_mmus > IPU6_MMU_MAX_DEVICES)
return ERR_PTR(-EINVAL);
- pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
+ mmu_hw = devm_kcalloc(dev, sizeof(*mmu_hw), hw->nr_mmus, GFP_KERNEL);
+ if (!mmu_hw)
return ERR_PTR(-ENOMEM);
for (i = 0; i < hw->nr_mmus; i++) {
- struct ipu6_mmu_hw *pdata_mmu = &pdata->mmu_hw[i];
const struct ipu6_mmu_hw *src_mmu = &hw->mmu_hw[i];
if (src_mmu->nr_l1streams > IPU6_MMU_MAX_TLB_L1_STREAMS ||
src_mmu->nr_l2streams > IPU6_MMU_MAX_TLB_L2_STREAMS)
return ERR_PTR(-EINVAL);
- *pdata_mmu = *src_mmu;
- pdata_mmu->base = base + src_mmu->offset;
+ mmu_hw[i] = *src_mmu;
+ mmu_hw[i].base = base + src_mmu->offset;
}
mmu = devm_kzalloc(dev, sizeof(*mmu), GFP_KERNEL);
@@ -778,7 +777,7 @@ struct ipu6_mmu *ipu6_mmu_init(struct device *dev,
return ERR_PTR(-ENOMEM);
mmu->mmid = mmid;
- mmu->mmu_hw = pdata->mmu_hw;
+ mmu->mmu_hw = mmu_hw;
mmu->nr_mmus = hw->nr_mmus;
mmu->tlb_invalidate = tlb_invalidate;
mmu->ready = false;
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index 07ca59048f44..874b377a2e9a 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -239,12 +239,6 @@ struct ipu6_mmu_hw {
bool insert_read_before_invalidate;
};
-struct ipu6_mmu_pdata {
- u32 nr_mmus;
- struct ipu6_mmu_hw mmu_hw[IPU6_MMU_MAX_DEVICES];
- int mmid;
-};
-
struct ipu6_isys_csi2_pdata {
void __iomem *base;
};
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 07/44] media: ipu6: Simplify firmware com arguments
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (5 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 06/44] media: ipu6: Cleanup ipu6_mmu_init() Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 08/44] media: ipu6: Add helper to identify ipu7 Antti Laakso
` (36 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
We need only pointer to ipu6_isys struct, and queue number
can be removed as it is always the same.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-fw-isys.c | 8 ++++----
drivers/media/pci/intel/ipu6/ipu6-fw-isys.h | 4 ++--
drivers/media/pci/intel/ipu6/ipu6-isys.c | 4 ++--
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
index a65e9f1aa104..fc2f24c05de7 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
@@ -366,14 +366,14 @@ int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
}
struct ipu6_fw_isys_resp_info_abi *
-ipu6_fw_isys_get_resp(void *context, unsigned int queue)
+ipu6_fw_isys_get_resp(struct ipu6_isys *isys)
{
- return ipu6_recv_get_token(context, queue);
+ return ipu6_recv_get_token(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
}
-void ipu6_fw_isys_put_resp(void *context, unsigned int queue)
+void ipu6_fw_isys_put_resp(struct ipu6_isys *isys)
{
- ipu6_recv_put_token(context, queue);
+ ipu6_recv_put_token(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
}
void ipu6_fw_isys_dump_stream_cfg(struct device *dev,
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
index 393245a633f4..15d4ae355f28 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
@@ -576,6 +576,6 @@ int ipu6_fw_isys_send_proxy_token(struct ipu6_isys *isys,
unsigned int offset, u32 value);
void ipu6_fw_isys_cleanup(struct ipu6_isys *isys);
struct ipu6_fw_isys_resp_info_abi *
-ipu6_fw_isys_get_resp(void *context, unsigned int queue);
-void ipu6_fw_isys_put_resp(void *context, unsigned int queue);
+ipu6_fw_isys_get_resp(struct ipu6_isys *isys);
+void ipu6_fw_isys_put_resp(struct ipu6_isys *isys);
#endif
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 180a53f3d7ab..8af891081bd3 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -1215,7 +1215,7 @@ static int isys_isr_one(struct ipu6_bus_device *adev)
if (!isys->fwctx)
return 1;
- resp = ipu6_fw_isys_get_resp(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
+ resp = ipu6_fw_isys_get_resp(isys);
if (!resp)
return 1;
@@ -1324,7 +1324,7 @@ static int isys_isr_one(struct ipu6_bus_device *adev)
ipu6_isys_put_stream(stream);
leave:
- ipu6_fw_isys_put_resp(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
+ ipu6_fw_isys_put_resp(isys);
return 0;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 08/44] media: ipu6: Add helper to identify ipu7
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (6 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 07/44] media: ipu6: Simplify firmware com arguments Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 09/44] media: ipu6: Prepare buttress for ipu7 support Antti Laakso
` (35 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The ipu7 comes in two flavors as of now, ipu7 and ipu7p5.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index 874b377a2e9a..ebae876058ca 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -27,11 +27,17 @@ struct ipu6_bus_device;
#define IPU_VERSION_6SE BIT(1) /* JSL */
#define IPU_VERSION_6EP BIT(2) /* ADL/RPL */
#define IPU_VERSION_6EP_MTL BIT(3) /* MTL */
+#define IPU_VERSION_7 BIT(4) /* LNL */
+#define IPU_VERSION_7P5 BIT(5) /* PTL */
#define IS_IPU6_TGL(isp) ((isp)->hw_ver & IPU_VERSION_6)
#define IS_IPU6SE(isp) ((isp)->hw_ver & IPU_VERSION_6SE)
#define IS_IPU6EP(isp) ((isp)->hw_ver & IPU_VERSION_6EP)
#define IS_IPU6EP_MTL(isp) ((isp)->hw_ver & IPU_VERSION_6EP_MTL)
+#define IS_IPU7(isp) ((isp)->hw_ver & \
+ (IPU_VERSION_7 | IPU_VERSION_7P5))
+#define IS_IPU7_MTL(isp) ((isp)->hw_ver & IPU_VERSION_7)
+#define IS_IPU7P5(isp) ((isp)->hw_ver & IPU_VERSION_7P5)
/*
* ISYS DMA can overshoot. For higher resolutions over allocation is one line
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 09/44] media: ipu6: Prepare buttress for ipu7 support
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (7 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 08/44] media: ipu6: Add helper to identify ipu7 Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 10/44] media: ipu6: Use single struct for registers Antti Laakso
` (34 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
Introduce a struct to hold buttress registers and bitmasks that vary
across hardware versions beyond ipu6 to simplify support for future
hardware versions.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-buttress.c | 96 ++++++++++---------
drivers/media/pci/intel/ipu6/ipu6-buttress.h | 25 +++++
.../intel/ipu6/ipu6-platform-buttress-regs.h | 2 +-
drivers/media/pci/intel/ipu6/ipu6.c | 26 +++++
4 files changed, 101 insertions(+), 48 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index cbe356589a9d..3c5f4e407b7c 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
@@ -55,11 +55,6 @@
#define BUTTRESS_MAX_CONSECUTIVE_IRQS 100
-static const u32 ipu6_adev_irq_mask[2] = {
- BUTTRESS_ISR_IS_IRQ,
- BUTTRESS_ISR_PS_IRQ
-};
-
int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
struct ipu6_buttress_ipc *ipc)
{
@@ -337,7 +332,8 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
struct ipu6_device *isp = isp_ptr;
struct ipu6_bus_device *adev[] = { isp->isys, isp->psys };
struct ipu6_buttress *b = &isp->buttress;
- u32 reg_irq_sts = BUTTRESS_REG_ISR_STATUS;
+ const struct ipu6_buttress_registers *regs = b->regs;
+ const u32 adev_irq_mask[] = { regs->irq_is, regs->irq_ps };
irqreturn_t ret = IRQ_NONE;
u32 disable_irqs = 0;
u32 irq_status;
@@ -348,7 +344,7 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
if (!active)
return IRQ_NONE;
- irq_status = readl(isp->base + reg_irq_sts);
+ irq_status = readl(isp->base + regs->irq_status);
if (irq_status == 0 || WARN_ON_ONCE(irq_status == 0xffffffffu)) {
if (active > 0)
pm_runtime_put_noidle(&isp->pdev->dev);
@@ -356,26 +352,26 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
}
do {
- writel(irq_status, isp->base + BUTTRESS_REG_ISR_CLEAR);
+ writel(irq_status, isp->base + regs->irq_clear);
- for (i = 0; i < ARRAY_SIZE(ipu6_adev_irq_mask); i++) {
+ for (i = 0; i < ARRAY_SIZE(adev_irq_mask); i++) {
irqreturn_t r = ipu6_buttress_call_isr(adev[i]);
- if (!(irq_status & ipu6_adev_irq_mask[i]))
+ if (!(irq_status & adev_irq_mask[i]))
continue;
if (r == IRQ_WAKE_THREAD) {
ret = IRQ_WAKE_THREAD;
- disable_irqs |= ipu6_adev_irq_mask[i];
+ disable_irqs |= adev_irq_mask[i];
} else if (ret == IRQ_NONE && r == IRQ_HANDLED) {
ret = IRQ_HANDLED;
}
}
- if ((irq_status & BUTTRESS_EVENT) && ret == IRQ_NONE)
+ if ((irq_status & regs->irq_events) && ret == IRQ_NONE)
ret = IRQ_HANDLED;
- if (irq_status & BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING) {
+ if (irq_status & regs->irq_cse_ipc) {
dev_dbg(&isp->pdev->dev,
"BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING\n");
@@ -383,13 +379,13 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
complete(&b->ipc.recv_complete);
}
- if (irq_status & BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE) {
+ if (irq_status & regs->irq_exec_done) {
dev_dbg(&isp->pdev->dev,
"BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE\n");
complete(&b->ipc.send_complete);
}
- if (irq_status & BUTTRESS_ISR_SAI_VIOLATION &&
+ if (irq_status & regs->irq_sai &&
ipu6_buttress_get_secure_mode(isp))
dev_err(&isp->pdev->dev,
"BUTTRESS_ISR_SAI_VIOLATION\n");
@@ -408,12 +404,12 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
break;
}
- irq_status = readl(isp->base + reg_irq_sts);
+ irq_status = readl(isp->base + regs->irq_status);
} while (irq_status);
if (disable_irqs)
- writel(BUTTRESS_IRQS & ~disable_irqs,
- isp->base + BUTTRESS_REG_ISR_ENABLE);
+ writel(regs->irq_all & ~disable_irqs,
+ isp->base + regs->irq_enable);
if (active > 0)
pm_runtime_put(&isp->pdev->dev);
@@ -424,12 +420,13 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
irqreturn_t ipu6_buttress_isr_threaded(int irq, void *isp_ptr)
{
struct ipu6_device *isp = isp_ptr;
+ const struct ipu6_buttress_registers *regs = isp->buttress.regs;
struct ipu6_bus_device *adev[] = { isp->isys, isp->psys };
const struct ipu6_auxdrv_data *drv_data = NULL;
irqreturn_t ret = IRQ_NONE;
unsigned int i;
- for (i = 0; i < ARRAY_SIZE(ipu6_adev_irq_mask) && adev[i]; i++) {
+ for (i = 0; i < ARRAY_SIZE(adev) && adev[i]; i++) {
drv_data = adev[i]->auxdrv_data;
if (!drv_data)
continue;
@@ -439,7 +436,7 @@ irqreturn_t ipu6_buttress_isr_threaded(int irq, void *isp_ptr)
ret = IRQ_HANDLED;
}
- writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_ENABLE);
+ writel(regs->irq_all, isp->base + regs->irq_enable);
return ret;
}
@@ -472,7 +469,7 @@ int ipu6_buttress_power(struct device *dev,
writel(val, isp->base + ctrl->freq_ctl);
- ret = readl_poll_timeout(isp->base + BUTTRESS_REG_PWR_STATE,
+ ret = readl_poll_timeout(isp->base + isp->buttress.regs->pwr_status,
val, (val & ctrl->pwr_sts_mask) == pwr_sts,
100, BUTTRESS_POWER_TIMEOUT_US);
if (ret)
@@ -488,7 +485,7 @@ bool ipu6_buttress_get_secure_mode(struct ipu6_device *isp)
{
u32 val;
- val = readl(isp->base + BUTTRESS_REG_SECURITY_CTL);
+ val = readl(isp->base + isp->buttress.regs->security_ctl);
return val & BUTTRESS_SECURITY_CTL_FW_SECURE_MODE;
}
@@ -500,7 +497,7 @@ bool ipu6_buttress_auth_done(struct ipu6_device *isp)
if (!isp->secure_mode)
return true;
- val = readl(isp->base + BUTTRESS_REG_SECURITY_CTL);
+ val = readl(isp->base + isp->buttress.regs->security_ctl);
val = FIELD_GET(BUTTRESS_SECURITY_CTL_FW_SETUP_MASK, val);
return val == BUTTRESS_SECURITY_CTL_AUTH_DONE;
@@ -518,10 +515,10 @@ int ipu6_buttress_reset_authentication(struct ipu6_device *isp)
}
writel(BUTTRESS_FW_RESET_CTL_START, isp->base +
- BUTTRESS_REG_FW_RESET_CTL);
+ isp->buttress.regs->fw_reset_ctl);
- ret = readl_poll_timeout(isp->base + BUTTRESS_REG_FW_RESET_CTL, val,
- val & BUTTRESS_FW_RESET_CTL_DONE, 500,
+ ret = readl_poll_timeout(isp->base + isp->buttress.regs->fw_reset_ctl,
+ val, val & BUTTRESS_FW_RESET_CTL_DONE, 500,
BUTTRESS_CSE_FWRESET_TIMEOUT_US);
if (ret) {
dev_err(&isp->pdev->dev,
@@ -530,7 +527,8 @@ int ipu6_buttress_reset_authentication(struct ipu6_device *isp)
}
dev_dbg(&isp->pdev->dev, "FW reset for authentication done\n");
- writel(0, isp->base + BUTTRESS_REG_FW_RESET_CTL);
+ writel(0, isp->base + isp->buttress.regs->fw_reset_ctl);
+
/* leave some time for HW restore */
usleep_range(800, 1000);
@@ -660,7 +658,7 @@ int ipu6_buttress_authenticate(struct ipu6_device *isp)
mask = BUTTRESS_SECURITY_CTL_FW_SETUP_MASK;
done = BUTTRESS_SECURITY_CTL_FW_SETUP_DONE;
fail = BUTTRESS_SECURITY_CTL_AUTH_FAILED;
- ret = readl_poll_timeout(isp->base + BUTTRESS_REG_SECURITY_CTL, data,
+ ret = readl_poll_timeout(isp->base + b->regs->security_ctl, data,
((data & mask) == done ||
(data & mask) == fail), 500,
BUTTRESS_CSE_BOOTLOAD_TIMEOUT_US);
@@ -700,7 +698,7 @@ int ipu6_buttress_authenticate(struct ipu6_device *isp)
}
done = BUTTRESS_SECURITY_CTL_AUTH_DONE;
- ret = readl_poll_timeout(isp->base + BUTTRESS_REG_SECURITY_CTL, data,
+ ret = readl_poll_timeout(isp->base + b->regs->security_ctl, data,
((data & mask) == done ||
(data & mask) == fail), 500,
BUTTRESS_CSE_AUTHENTICATE_TIMEOUT_US);
@@ -725,15 +723,16 @@ int ipu6_buttress_authenticate(struct ipu6_device *isp)
static int ipu6_buttress_send_tsc_request(struct ipu6_device *isp)
{
+ const struct ipu6_buttress_registers *regs = isp->buttress.regs;
u32 val, mask, done;
int ret;
mask = BUTTRESS_PWR_STATE_HH_STATUS_MASK;
writel(BUTTRESS_FABRIC_CMD_START_TSC_SYNC,
- isp->base + BUTTRESS_REG_FABRIC_CMD);
+ isp->base + regs->fabric_cmd);
- val = readl(isp->base + BUTTRESS_REG_PWR_STATE);
+ val = readl(isp->base + regs->pwr_status);
val = FIELD_GET(mask, val);
if (val == BUTTRESS_PWR_STATE_HH_STATE_ERR) {
dev_err(&isp->pdev->dev, "Start tsc sync failed\n");
@@ -741,8 +740,8 @@ static int ipu6_buttress_send_tsc_request(struct ipu6_device *isp)
}
done = BUTTRESS_PWR_STATE_HH_STATE_DONE;
- ret = readl_poll_timeout(isp->base + BUTTRESS_REG_PWR_STATE, val,
- FIELD_GET(mask, val) == done, 500,
+ ret = readl_poll_timeout(isp->base + regs->pwr_status,
+ val, FIELD_GET(mask, val) == done, 500,
BUTTRESS_TSC_SYNC_TIMEOUT_US);
if (ret)
dev_err(&isp->pdev->dev, "Start tsc sync timeout\n");
@@ -762,11 +761,13 @@ int ipu6_buttress_start_tsc_sync(struct ipu6_device *isp)
if (ret != -ETIMEDOUT)
return ret;
- val = readl(isp->base + BUTTRESS_REG_TSW_CTL);
+ u32 tsw_ctl = isp->buttress.regs->tsw_ctl;
+
+ val = readl(isp->base + tsw_ctl);
val = val | BUTTRESS_TSW_CTL_SOFT_RESET;
- writel(val, isp->base + BUTTRESS_REG_TSW_CTL);
+ writel(val, isp->base + tsw_ctl);
val = val & ~BUTTRESS_TSW_CTL_SOFT_RESET;
- writel(val, isp->base + BUTTRESS_REG_TSW_CTL);
+ writel(val, isp->base + tsw_ctl);
}
dev_err(&isp->pdev->dev, "TSC sync failed (timeout)\n");
@@ -777,13 +778,14 @@ EXPORT_SYMBOL_NS_GPL(ipu6_buttress_start_tsc_sync, "INTEL_IPU6");
void ipu6_buttress_tsc_read(struct ipu6_device *isp, u64 *val)
{
+ void __iomem *tsc = isp->base + isp->buttress.regs->tsc_lo;
u32 tsc_hi_1, tsc_hi_2, tsc_lo;
unsigned long flags;
local_irq_save(flags);
- tsc_hi_1 = readl(isp->base + BUTTRESS_REG_TSC_HI);
- tsc_lo = readl(isp->base + BUTTRESS_REG_TSC_LO);
- tsc_hi_2 = readl(isp->base + BUTTRESS_REG_TSC_HI);
+ tsc_hi_1 = readl(tsc + BUTTRESS_TSC_HI_OFFSET);
+ tsc_lo = readl(tsc);
+ tsc_hi_2 = readl(tsc + BUTTRESS_TSC_HI_OFFSET);
if (tsc_hi_1 == tsc_hi_2) {
*val = (u64)tsc_hi_1 << 32 | tsc_lo;
} else {
@@ -816,9 +818,9 @@ void ipu6_buttress_restore(struct ipu6_device *isp)
{
struct ipu6_buttress *b = &isp->buttress;
- writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_CLEAR);
- writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_ENABLE);
- writel(b->wdt_cached_value, isp->base + BUTTRESS_REG_WDT);
+ writel(b->regs->irq_all, isp->base + b->regs->irq_clear);
+ writel(b->regs->irq_all, isp->base + b->regs->irq_enable);
+ writel(b->wdt_cached_value, isp->base + b->regs->wdt);
}
int ipu6_buttress_init(struct ipu6_device *isp)
@@ -851,12 +853,12 @@ int ipu6_buttress_init(struct ipu6_device *isp)
readl(isp->base + BUTTRESS_REG_SECURITY_TOUCH),
readl(isp->base + BUTTRESS_REG_CAMERA_MASK));
- b->wdt_cached_value = readl(isp->base + BUTTRESS_REG_WDT);
- writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_CLEAR);
- writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_ENABLE);
+ b->wdt_cached_value = readl(isp->base + b->regs->wdt);
+ writel(b->regs->irq_all, isp->base + b->regs->irq_clear);
+ writel(b->regs->irq_all, isp->base + b->regs->irq_enable);
/* get ref_clk frequency by reading the indication in btrs control */
- val = readl(isp->base + BUTTRESS_REG_BTRS_CTRL);
+ val = readl(isp->base + b->regs->btrs_ctrl);
val = FIELD_GET(BUTTRESS_REG_BTRS_CTRL_REF_CLK_IND, val);
switch (val) {
@@ -902,7 +904,7 @@ void ipu6_buttress_exit(struct ipu6_device *isp)
{
struct ipu6_buttress *b = &isp->buttress;
- writel(0, isp->base + BUTTRESS_REG_ISR_ENABLE);
+ writel(0, isp->base + b->regs->irq_enable);
mutex_destroy(&b->power_mutex);
mutex_destroy(&b->auth_mutex);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.h b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
index b1c1a10e3e6d..68586a32fda3 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
@@ -42,9 +42,34 @@ struct ipu6_buttress_ipc {
u32 data0_in;
};
+struct ipu6_buttress_registers {
+ /* Registers */
+ u32 irq_status;
+ u32 irq_clear;
+ u32 irq_enable;
+ u32 pwr_status;
+ u32 security_ctl;
+ u32 fw_reset_ctl;
+ u32 fabric_cmd;
+ u32 tsw_ctl;
+ u32 tsc_lo;
+ u32 wdt;
+ u32 btrs_ctrl;
+
+ /* Bitmasks */
+ u32 irq_is;
+ u32 irq_ps;
+ u32 irq_all;
+ u32 irq_events;
+ u32 irq_cse_ipc;
+ u32 irq_exec_done;
+ u32 irq_sai;
+};
+
struct ipu6_buttress {
struct mutex power_mutex, auth_mutex, cons_mutex, ipc_mutex;
struct ipu6_buttress_ipc ipc;
+ const struct ipu6_buttress_registers *regs;
struct list_head constraints;
u32 wdt_cached_value;
bool force_suspend;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
index efd65e494c16..5006cce74b23 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
@@ -212,7 +212,7 @@ enum {
#define BUTTRESS_TSW_CTL_SOFT_RESET BIT(8)
#define BUTTRESS_REG_TSC_LO 0x164
-#define BUTTRESS_REG_TSC_HI 0x168
+#define BUTTRESS_TSC_HI_OFFSET 4
#define BUTTRESS_IRQS (BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING | \
BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE | \
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index efb58bc4d127..55e660fda421 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -228,6 +228,30 @@ static const struct ipu6_buttress_ctrl psys_buttress_ctrl = {
.pwr_sts_off = IPU6_BUTTRESS_PWR_STATE_DN_DONE,
};
+static const struct ipu6_buttress_registers ipu6_buttress_regs = {
+ /* Registers */
+ .irq_status = BUTTRESS_REG_ISR_STATUS,
+ .irq_clear = BUTTRESS_REG_ISR_CLEAR,
+ .irq_enable = BUTTRESS_REG_ISR_ENABLE,
+ .pwr_status = BUTTRESS_REG_PWR_STATE,
+ .security_ctl = BUTTRESS_REG_SECURITY_CTL,
+ .fw_reset_ctl = BUTTRESS_REG_FW_RESET_CTL,
+ .fabric_cmd = BUTTRESS_REG_FABRIC_CMD,
+ .tsw_ctl = BUTTRESS_REG_TSW_CTL,
+ .tsc_lo = BUTTRESS_REG_TSC_LO,
+ .wdt = BUTTRESS_REG_WDT,
+ .btrs_ctrl = BUTTRESS_REG_BTRS_CTRL,
+
+ /* Bitmasks */
+ .irq_is = BUTTRESS_ISR_IS_IRQ,
+ .irq_ps = BUTTRESS_ISR_PS_IRQ,
+ .irq_all = BUTTRESS_IRQS,
+ .irq_events = BUTTRESS_EVENT,
+ .irq_cse_ipc = BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING,
+ .irq_exec_done = BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE,
+ .irq_sai = BUTTRESS_ISR_SAI_VIOLATION,
+};
+
static void
ipu6_pkg_dir_configure_spc(struct ipu6_device *isp,
const struct ipu6_hw_variants *hw_variant,
@@ -522,6 +546,8 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_set_master(pdev);
isp->cpd_metadata_cmpnt_size = sizeof(struct ipu6_cpd_metadata_cmpnt);
+ isp->buttress.regs = &ipu6_buttress_regs;
+
switch (id->device) {
case PCI_DEVICE_ID_INTEL_IPU6:
isp->hw_ver = IPU_VERSION_6;
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 10/44] media: ipu6: Use single struct for registers
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (8 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 09/44] media: ipu6: Prepare buttress for ipu7 support Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 11/44] media: ipu6: Rename IPU subsys ID Antti Laakso
` (33 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
Move register values from ipu6_buttress_ipc struct to
ipu6_buttress_registers as these are different in future
hardware versions as well.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-buttress.c | 86 +++++++++-----------
drivers/media/pci/intel/ipu6/ipu6-buttress.h | 17 ++--
drivers/media/pci/intel/ipu6/ipu6.c | 13 +--
3 files changed, 54 insertions(+), 62 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index 3c5f4e407b7c..e77a569bb97e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
@@ -55,11 +55,11 @@
#define BUTTRESS_MAX_CONSECUTIVE_IRQS 100
-int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
- struct ipu6_buttress_ipc *ipc)
+int ipu6_buttress_ipc_reset(struct ipu6_device *isp)
{
unsigned int retries = BUTTRESS_IPC_RESET_RETRY;
struct ipu6_buttress *b = &isp->buttress;
+ const struct ipu6_buttress_registers *regs = b->regs;
u32 val = 0, csr_in_clr;
if (!isp->secure_mode) {
@@ -70,11 +70,11 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
mutex_lock(&b->ipc_mutex);
/* Clear-by-1 CSR (all bits), corresponding internal states. */
- val = readl(isp->base + ipc->csr_in);
- writel(val, isp->base + ipc->csr_in);
+ val = readl(isp->base + regs->csr_in);
+ writel(val, isp->base + regs->csr_in);
/* Set peer CSR bit IPC_PEER_COMP_ACTIONS_RST_PHASE1 */
- writel(ENTRY, isp->base + ipc->csr_out);
+ writel(ENTRY, isp->base + regs->csr_out);
/*
* Clear-by-1 all CSR bits EXCEPT following
* bits:
@@ -89,7 +89,7 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
do {
usleep_range(400, 500);
- val = readl(isp->base + ipc->csr_in);
+ val = readl(isp->base + regs->csr_in);
switch (val) {
case ENTRY | EXIT:
case ENTRY | EXIT | QUERY:
@@ -100,8 +100,8 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
* 2) Set peer CSR bit
* IPC_PEER_QUERIED_IP_COMP_ACTIONS_RST_PHASE.
*/
- writel(ENTRY | EXIT, isp->base + ipc->csr_in);
- writel(QUERY, isp->base + ipc->csr_out);
+ writel(ENTRY | EXIT, isp->base + regs->csr_in);
+ writel(QUERY, isp->base + regs->csr_out);
break;
case ENTRY:
case ENTRY | QUERY:
@@ -112,8 +112,8 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
* 2) Set peer CSR bit
* IPC_PEER_COMP_ACTIONS_RST_PHASE1.
*/
- writel(ENTRY | QUERY, isp->base + ipc->csr_in);
- writel(ENTRY, isp->base + ipc->csr_out);
+ writel(ENTRY | QUERY, isp->base + regs->csr_in);
+ writel(ENTRY, isp->base + regs->csr_out);
break;
case EXIT:
case EXIT | QUERY:
@@ -130,17 +130,17 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
* 3) Set peer CSR bit
* IPC_PEER_COMP_ACTIONS_RST_PHASE2.
*/
- writel(EXIT, isp->base + ipc->csr_in);
- writel(0, isp->base + ipc->db0_in);
- writel(csr_in_clr, isp->base + ipc->csr_in);
- writel(EXIT, isp->base + ipc->csr_out);
+ writel(EXIT, isp->base + regs->csr_in);
+ writel(0, isp->base + regs->db0_in);
+ writel(csr_in_clr, isp->base + regs->csr_in);
+ writel(EXIT, isp->base + regs->csr_out);
/*
* Read csr_in again to make sure if RST_PHASE2 is done.
* If csr_in is QUERY, it should be handled again.
*/
usleep_range(200, 300);
- val = readl(isp->base + ipc->csr_in);
+ val = readl(isp->base + regs->csr_in);
if (val & QUERY) {
dev_dbg(&isp->pdev->dev,
"RST_PHASE2 retry csr_in = %x\n", val);
@@ -155,8 +155,8 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
* 2) Set peer CSR bit
* IPC_PEER_COMP_ACTIONS_RST_PHASE1
*/
- writel(QUERY, isp->base + ipc->csr_in);
- writel(ENTRY, isp->base + ipc->csr_out);
+ writel(QUERY, isp->base + regs->csr_in);
+ writel(ENTRY, isp->base + regs->csr_out);
break;
default:
dev_dbg_ratelimited(&isp->pdev->dev,
@@ -171,42 +171,42 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
return -ETIMEDOUT;
}
-static void ipu6_buttress_ipc_validity_close(struct ipu6_device *isp,
- struct ipu6_buttress_ipc *ipc)
+static void ipu6_buttress_ipc_validity_close(struct ipu6_device *isp)
{
writel(BUTTRESS_IU2CSECSR_IPC_PEER_DEASSERTED_REG_VALID_REQ,
- isp->base + ipc->csr_out);
+ isp->base + isp->buttress.regs->csr_out);
}
static int
-ipu6_buttress_ipc_validity_open(struct ipu6_device *isp,
- struct ipu6_buttress_ipc *ipc)
+ipu6_buttress_ipc_validity_open(struct ipu6_device *isp)
{
unsigned int mask = BUTTRESS_IU2CSECSR_IPC_PEER_ACKED_REG_VALID;
+ const struct ipu6_buttress_registers *regs = isp->buttress.regs;
void __iomem *addr;
int ret;
u32 val;
writel(BUTTRESS_IU2CSECSR_IPC_PEER_ASSERTED_REG_VALID_REQ,
- isp->base + ipc->csr_out);
+ isp->base + regs->csr_out);
- addr = isp->base + ipc->csr_in;
+ addr = isp->base + regs->csr_in;
ret = readl_poll_timeout(addr, val, val & mask, 200,
BUTTRESS_IPC_VALIDITY_TIMEOUT_US);
if (ret) {
dev_err(&isp->pdev->dev, "CSE validity timeout 0x%x\n", val);
- ipu6_buttress_ipc_validity_close(isp, ipc);
+ ipu6_buttress_ipc_validity_close(isp);
}
return ret;
}
-static void ipu6_buttress_ipc_recv(struct ipu6_device *isp,
- struct ipu6_buttress_ipc *ipc, u32 *ipc_msg)
+static void ipu6_buttress_ipc_recv(struct ipu6_device *isp, u32 *ipc_msg)
{
+ const struct ipu6_buttress_registers *regs = isp->buttress.regs;
+
if (ipc_msg)
- *ipc_msg = readl(isp->base + ipc->data0_in);
- writel(0, isp->base + ipc->db0_in);
+ *ipc_msg = readl(isp->base + regs->data0_in);
+ writel(0, isp->base + regs->db0_in);
}
static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp,
@@ -217,13 +217,14 @@ static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp,
unsigned int i, retry = BUTTRESS_IPC_CMD_SEND_RETRY;
struct ipu6_buttress *b = &isp->buttress;
struct ipu6_buttress_ipc *ipc = &b->ipc;
+ const struct ipu6_buttress_registers *regs = b->regs;
u32 val;
int ret;
int tout;
mutex_lock(&b->ipc_mutex);
- ret = ipu6_buttress_ipc_validity_open(isp, ipc);
+ ret = ipu6_buttress_ipc_validity_open(isp);
if (ret) {
dev_err(&isp->pdev->dev, "IPC validity open failed\n");
goto out;
@@ -239,9 +240,9 @@ static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp,
dev_dbg(&isp->pdev->dev, "bulk IPC command: 0x%x\n",
msgs[i].cmd);
- writel(msgs[i].cmd, isp->base + ipc->data0_out);
+ writel(msgs[i].cmd, isp->base + regs->data0_out);
val = BUTTRESS_IU2CSEDB0_BUSY | msgs[i].cmd_size;
- writel(val, isp->base + ipc->db0_out);
+ writel(val, isp->base + regs->db0_out);
tout = wait_for_completion_timeout(&ipc->send_complete,
tx_timeout_jiffies);
@@ -253,7 +254,7 @@ static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp,
}
/* Try again if CSE is not responding on first try */
- writel(0, isp->base + ipc->db0_out);
+ writel(0, isp->base + regs->db0_out);
i--;
continue;
}
@@ -271,8 +272,8 @@ static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp,
goto out;
}
- if (ipc->nack_mask &&
- (ipc->recv_data & ipc->nack_mask) == ipc->nack) {
+ if ((ipc->recv_data & BUTTRESS_CSE2IUDATA0_IPC_NACK_MASK) ==
+ BUTTRESS_CSE2IUDATA0_IPC_NACK) {
dev_err(&isp->pdev->dev,
"IPC NACK for cmd 0x%x\n", msgs[i].cmd);
ret = -EIO;
@@ -291,7 +292,7 @@ static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp,
dev_dbg(&isp->pdev->dev, "bulk IPC commands done\n");
out:
- ipu6_buttress_ipc_validity_close(isp, ipc);
+ ipu6_buttress_ipc_validity_close(isp);
mutex_unlock(&b->ipc_mutex);
return ret;
}
@@ -375,7 +376,7 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
dev_dbg(&isp->pdev->dev,
"BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING\n");
- ipu6_buttress_ipc_recv(isp, &b->ipc, &b->ipc.recv_data);
+ ipu6_buttress_ipc_recv(isp, &b->ipc.recv_data);
complete(&b->ipc.recv_complete);
}
@@ -836,15 +837,6 @@ int ipu6_buttress_init(struct ipu6_device *isp)
init_completion(&b->ipc.send_complete);
init_completion(&b->ipc.recv_complete);
- b->ipc.nack = BUTTRESS_CSE2IUDATA0_IPC_NACK;
- b->ipc.nack_mask = BUTTRESS_CSE2IUDATA0_IPC_NACK_MASK;
- b->ipc.csr_in = BUTTRESS_REG_CSE2IUCSR;
- b->ipc.csr_out = BUTTRESS_REG_IU2CSECSR;
- b->ipc.db0_in = BUTTRESS_REG_CSE2IUDB0;
- b->ipc.db0_out = BUTTRESS_REG_IU2CSEDB0;
- b->ipc.data0_in = BUTTRESS_REG_CSE2IUDATA0;
- b->ipc.data0_out = BUTTRESS_REG_IU2CSEDATA0;
-
INIT_LIST_HEAD(&b->constraints);
isp->secure_mode = ipu6_buttress_get_secure_mode(isp);
@@ -880,7 +872,7 @@ int ipu6_buttress_init(struct ipu6_device *isp)
/* Retry couple of times in case of CSE initialization is delayed */
do {
- ret = ipu6_buttress_ipc_reset(isp, &b->ipc);
+ ret = ipu6_buttress_ipc_reset(isp);
if (ret) {
dev_warn(&isp->pdev->dev,
"IPC reset protocol failed, retrying\n");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.h b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
index 68586a32fda3..a3c23adede7b 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
@@ -31,15 +31,7 @@ struct ipu6_buttress_ctrl {
struct ipu6_buttress_ipc {
struct completion send_complete;
struct completion recv_complete;
- u32 nack;
- u32 nack_mask;
u32 recv_data;
- u32 csr_out;
- u32 csr_in;
- u32 db0_in;
- u32 db0_out;
- u32 data0_out;
- u32 data0_in;
};
struct ipu6_buttress_registers {
@@ -55,6 +47,12 @@ struct ipu6_buttress_registers {
u32 tsc_lo;
u32 wdt;
u32 btrs_ctrl;
+ u32 csr_in;
+ u32 csr_out;
+ u32 db0_in;
+ u32 db0_out;
+ u32 data0_in;
+ u32 data0_out;
/* Bitmasks */
u32 irq_is;
@@ -83,8 +81,7 @@ struct ipu6_ipc_buttress_bulk_msg {
u8 cmd_size;
};
-int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
- struct ipu6_buttress_ipc *ipc);
+int ipu6_buttress_ipc_reset(struct ipu6_device *isp);
int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys,
const struct firmware *fw,
struct sg_table *sgt);
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 55e660fda421..7ac9c92744c0 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -241,6 +241,12 @@ static const struct ipu6_buttress_registers ipu6_buttress_regs = {
.tsc_lo = BUTTRESS_REG_TSC_LO,
.wdt = BUTTRESS_REG_WDT,
.btrs_ctrl = BUTTRESS_REG_BTRS_CTRL,
+ .csr_in = BUTTRESS_REG_CSE2IUCSR,
+ .csr_out = BUTTRESS_REG_IU2CSECSR,
+ .db0_in = BUTTRESS_REG_CSE2IUDB0,
+ .db0_out = BUTTRESS_REG_IU2CSEDB0,
+ .data0_in = BUTTRESS_REG_CSE2IUDATA0,
+ .data0_out = BUTTRESS_REG_IU2CSEDATA0,
/* Bitmasks */
.irq_is = BUTTRESS_ISR_IS_IRQ,
@@ -779,7 +785,6 @@ static int ipu6_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct ipu6_device *isp = pci_get_drvdata(pdev);
- struct ipu6_buttress *b = &isp->buttress;
int ret;
/* Configure the arbitration mechanisms for VC requests */
@@ -791,7 +796,7 @@ static int ipu6_resume(struct device *dev)
ipu6_buttress_restore(isp);
- ret = ipu6_buttress_ipc_reset(isp, &b->ipc);
+ ret = ipu6_buttress_ipc_reset(isp);
if (ret)
dev_err(&isp->pdev->dev, "IPC reset protocol failed!\n");
@@ -820,10 +825,8 @@ static int ipu6_runtime_resume(struct device *dev)
ipu6_buttress_restore(isp);
if (isp->need_ipc_reset) {
- struct ipu6_buttress *b = &isp->buttress;
-
isp->need_ipc_reset = false;
- ret = ipu6_buttress_ipc_reset(isp, &b->ipc);
+ ret = ipu6_buttress_ipc_reset(isp);
if (ret)
dev_err(&isp->pdev->dev, "IPC reset protocol failed\n");
}
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 11/44] media: ipu6: Rename IPU subsys ID
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (9 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 10/44] media: ipu6: Use single struct for registers Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 12/44] media: ipu6: Add ipu7 buttress support Antti Laakso
` (32 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
We will need subsys ID later elsewhere, so move it to
common header too.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-mmu.h | 3 ---
drivers/media/pci/intel/ipu6/ipu6.c | 5 ++---
drivers/media/pci/intel/ipu6/ipu6.h | 3 +++
3 files changed, 5 insertions(+), 6 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.h b/drivers/media/pci/intel/ipu6/ipu6-mmu.h
index 8e40b4a66d7d..35cac80d2d4e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.h
@@ -4,9 +4,6 @@
#ifndef IPU6_MMU_H
#define IPU6_MMU_H
-#define ISYS_MMID 1
-#define PSYS_MMID 0
-
#include <linux/list.h>
#include <linux/spinlock_types.h>
#include <linux/types.h>
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 7ac9c92744c0..c24e18520de6 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -424,8 +424,7 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent,
"ipu6_bus_initialize_device isys failed\n");
}
- isys_adev->mmu = ipu6_mmu_init(dev, base, ISYS_MMID,
- &ipdata->hw_variant);
+ isys_adev->mmu = ipu6_mmu_init(dev, base, IPU_ISYS, &ipdata->hw_variant);
if (IS_ERR(isys_adev->mmu)) {
put_device(&isys_adev->auxdev.dev);
return dev_err_cast_probe(dev, isys_adev->mmu,
@@ -465,7 +464,7 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent,
"ipu6_bus_initialize_device psys failed\n");
}
- psys_adev->mmu = ipu6_mmu_init(&pdev->dev, base, PSYS_MMID,
+ psys_adev->mmu = ipu6_mmu_init(&pdev->dev, base, IPU_PSYS,
&ipdata->hw_variant);
if (IS_ERR(psys_adev->mmu)) {
put_device(&psys_adev->auxdev.dev);
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index ebae876058ca..dc98a787612f 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -70,6 +70,9 @@ struct ipu6_device {
bool bus_ready_to_probe;
};
+#define IPU_PSYS 0
+#define IPU_ISYS 1
+
#define IPU6_ISYS_NAME "isys"
#define IPU6_PSYS_NAME "psys"
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 12/44] media: ipu6: Add ipu7 buttress support
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (10 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 11/44] media: ipu6: Rename IPU subsys ID Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 13/44] media: ipu6: Prepare mmu driver for hw variation Antti Laakso
` (31 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The ipu7 differs from ipu6 e.g. in power management, authentication,
interrupt handling and clock setup. Add support for ipu7 buttress.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-buttress.c | 292 +++++++++++++++---
drivers/media/pci/intel/ipu6/ipu6-buttress.h | 3 +
.../intel/ipu6/ipu6-platform-buttress-regs.h | 102 ++++++
drivers/media/pci/intel/ipu6/ipu6.c | 104 +++++--
drivers/media/pci/intel/ipu6/ipu6.h | 2 +
include/media/ipu6-pci-table.h | 2 +
6 files changed, 444 insertions(+), 61 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index e77a569bb97e..13fd7a083b25 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
@@ -345,6 +345,13 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
if (!active)
return IRQ_NONE;
+ if (IS_IPU7(isp)) {
+ u32 pb_irq;
+
+ pb_irq = readl(isp->pb_base + IPU7_PB_INTERRUPT_STATUS);
+ writel(pb_irq, isp->pb_base + IPU7_PB_INTERRUPT_STATUS);
+ }
+
irq_status = readl(isp->base + regs->irq_status);
if (irq_status == 0 || WARN_ON_ONCE(irq_status == 0xffffffffu)) {
if (active > 0)
@@ -442,28 +449,141 @@ irqreturn_t ipu6_buttress_isr_threaded(int irq, void *isp_ptr)
return ret;
}
-int ipu6_buttress_power(struct device *dev,
- const struct ipu6_buttress_ctrl *ctrl, bool on)
+static int ipu7_isys_d2d_power(struct ipu6_device *isp, bool on)
+{
+ u32 target = on ? IPU7_BUTTRESS_D2D_PWR_ACK : 0U;
+ u32 val;
+ int ret;
+
+ val = readl(isp->base + IPU7_BUTTRESS_REG_D2D_CTL);
+ if ((val & IPU7_BUTTRESS_D2D_PWR_ACK) == target)
+ return 0;
+
+ if (on)
+ val |= IPU7_BUTTRESS_D2D_PWR_EN;
+ else
+ val &= ~IPU7_BUTTRESS_D2D_PWR_EN;
+ writel(val, isp->base + IPU7_BUTTRESS_REG_D2D_CTL);
+
+ ret = readl_poll_timeout(isp->base + IPU7_BUTTRESS_REG_D2D_CTL, val,
+ (val & IPU7_BUTTRESS_D2D_PWR_ACK) == target,
+ 100, BUTTRESS_POWER_TIMEOUT_US);
+ if (ret)
+ dev_err(&isp->pdev->dev, "D2D power %s timeout: 0x%x\n",
+ on ? "up" : "down", val);
+
+ return ret;
+}
+
+static void ipu7_nde_control(struct ipu6_device *isp, bool on)
+{
+ u32 val;
+
+ val = FIELD_PREP(IPU7_NDE_VAL_MASK,
+ on ? IPU7_NDE_VAL_ACTIVE : IPU7_NDE_VAL_DEFAULT) |
+ FIELD_PREP(IPU7_NDE_SCALE_MASK,
+ on ? IPU7_NDE_SCALE_ACTIVE : IPU7_NDE_SCALE_DEFAULT) |
+ FIELD_PREP(IPU7_NDE_VALID_MASK,
+ on ? IPU7_NDE_VALID_ACTIVE : IPU7_NDE_VALID_DEFAULT) |
+ FIELD_PREP(IPU7_NDE_RESVEC_MASK, IPU7_NDE_RESVEC);
+ writel(val, isp->base + IPU7_BUTTRESS_REG_NDE_CONTROL);
+}
+
+static int __ipu7_power_on(struct device *dev,
+ const struct ipu6_buttress_ctrl *ctrl)
+{
+ struct ipu6_device *isp = to_ipu6_bus_device(dev)->isp;
+ bool is_isys = ctrl->subsys_id == IPU_ISYS;
+ u32 pwr_sts, val, ovrd_clk, slp, own_clk_ack;
+ int ret;
+
+ val = ctrl->ratio | (IPU7_FREQ_CTL_CDYN << IPU7_FREQ_CTL_CDYN_SHIFT);
+ pwr_sts = ctrl->pwr_sts_on << ctrl->pwr_sts_shift;
+
+ if (is_isys) {
+ ret = ipu7_isys_d2d_power(isp, true);
+ if (ret)
+ return ret;
+
+ ipu7_nde_control(isp, true);
+ }
+
+ /* Request clock ownership. */
+ ovrd_clk = is_isys ? IPU7_BUTTRESS_OVERRIDE_IS_CLK :
+ IPU7_BUTTRESS_OVERRIDE_PS_CLK;
+
+ slp = readl(isp->base + IPU7_BUTTRESS_REG_SLEEP_LEVEL_CFG);
+ writel(slp | ovrd_clk, isp->base + IPU7_BUTTRESS_REG_SLEEP_LEVEL_CFG);
+
+ own_clk_ack = is_isys ? IPU7_BUTTRESS_OWN_ACK_IS_CLK :
+ IPU7_BUTTRESS_OWN_ACK_PS_CLK;
+ ret = readl_poll_timeout(isp->base + IPU7_BUTTRESS_REG_SLEEP_LEVEL_STS,
+ slp, (slp & own_clk_ack),
+ 100, BUTTRESS_POWER_TIMEOUT_US);
+ if (ret)
+ dev_warn(&isp->pdev->dev, "clock ownership timeout: 0x%x\n",
+ slp);
+
+ writel(val, isp->base + ctrl->freq_ctl);
+
+ ret = readl_poll_timeout(isp->base + isp->buttress.regs->pwr_status,
+ val, (val & ctrl->pwr_sts_mask) == pwr_sts,
+ 100, BUTTRESS_POWER_TIMEOUT_US);
+ if (ret) {
+ dev_err(&isp->pdev->dev,
+ "Change power status timeout with 0x%x\n", val);
+ return ret;
+ }
+
+ slp = readl(isp->base + IPU7_BUTTRESS_REG_SLEEP_LEVEL_CFG);
+ writel(slp & ~ovrd_clk, isp->base + IPU7_BUTTRESS_REG_SLEEP_LEVEL_CFG);
+
+ return 0;
+}
+
+static int __ipu7_power_off(struct device *dev,
+ const struct ipu6_buttress_ctrl *ctrl)
{
struct ipu6_device *isp = to_ipu6_bus_device(dev)->isp;
u32 pwr_sts, val;
int ret;
- if (!ctrl)
- return 0;
+ writel(0x8U, isp->base + ctrl->freq_ctl);
- mutex_lock(&isp->buttress.power_mutex);
+ pwr_sts = ctrl->pwr_sts_off << ctrl->pwr_sts_shift;
+ ret = readl_poll_timeout(isp->base + isp->buttress.regs->pwr_status,
+ val, (val & ctrl->pwr_sts_mask) == pwr_sts,
+ 100, BUTTRESS_POWER_TIMEOUT_US);
+ if (ret) {
+ dev_err(&isp->pdev->dev,
+ "Change power status timeout with 0x%x\n", val);
+ return ret;
+ }
+
+ if (ctrl->subsys_id == IPU_ISYS) {
+ ipu7_isys_d2d_power(isp, false);
+ ipu7_nde_control(isp, false);
+ }
+
+ return 0;
+}
+
+static int __ipu6_power(struct device *dev,
+ const struct ipu6_buttress_ctrl *ctrl, bool on)
+{
+ struct ipu6_device *isp = to_ipu6_bus_device(dev)->isp;
+ u32 pwr_sts, val;
+ int ret;
if (!on) {
val = 0;
pwr_sts = ctrl->pwr_sts_off << ctrl->pwr_sts_shift;
} else {
val = BUTTRESS_FREQ_CTL_START |
- FIELD_PREP(BUTTRESS_FREQ_CTL_RATIO_MASK,
- ctrl->ratio) |
- FIELD_PREP(BUTTRESS_FREQ_CTL_QOS_FLOOR_MASK,
- ctrl->qos_floor) |
- BUTTRESS_FREQ_CTL_ICCMAX_LEVEL;
+ FIELD_PREP(BUTTRESS_FREQ_CTL_RATIO_MASK, ctrl->ratio) |
+ FIELD_PREP(BUTTRESS_FREQ_CTL_QOS_FLOOR_MASK,
+ ctrl->qos_floor) |
+ BUTTRESS_FREQ_CTL_ICCMAX_LEVEL;
pwr_sts = ctrl->pwr_sts_on << ctrl->pwr_sts_shift;
}
@@ -477,6 +597,26 @@ int ipu6_buttress_power(struct device *dev,
dev_err(&isp->pdev->dev,
"Change power status timeout with 0x%x\n", val);
+ return ret;
+}
+
+int ipu6_buttress_power(struct device *dev,
+ const struct ipu6_buttress_ctrl *ctrl, bool on)
+{
+ struct ipu6_device *isp = to_ipu6_bus_device(dev)->isp;
+ int ret;
+
+ if (!ctrl)
+ return 0;
+
+ mutex_lock(&isp->buttress.power_mutex);
+
+ if (IS_IPU7(isp))
+ ret = on ? __ipu7_power_on(dev, ctrl) :
+ __ipu7_power_off(dev, ctrl);
+ else
+ ret = __ipu6_power(dev, ctrl, on);
+
mutex_unlock(&isp->buttress.power_mutex);
return ret;
@@ -634,11 +774,18 @@ int ipu6_buttress_authenticate(struct ipu6_device *isp)
* Write address of FIT table to FW_SOURCE register
* Let's use fw address. I.e. not using FIT table yet
*/
- data = lower_32_bits(isp->psys->pkg_dir_dma_addr);
- writel(data, isp->base + BUTTRESS_REG_FW_SOURCE_BASE_LO);
+ if (IS_IPU7(isp)) {
+ writel(isp->cpd_fw->size,
+ isp->base + IPU7_BUTTRESS_REG_FW_SOURCE_SIZE);
+ writel(sg_dma_address(isp->psys->fw_sgt.sgl),
+ isp->base + IPU7_BUTTRESS_REG_FW_SOURCE_BASE);
+ } else {
+ data = lower_32_bits(isp->psys->pkg_dir_dma_addr);
+ writel(data, isp->base + BUTTRESS_REG_FW_SOURCE_BASE_LO);
- data = upper_32_bits(isp->psys->pkg_dir_dma_addr);
- writel(data, isp->base + BUTTRESS_REG_FW_SOURCE_BASE_HI);
+ data = upper_32_bits(isp->psys->pkg_dir_dma_addr);
+ writel(data, isp->base + BUTTRESS_REG_FW_SOURCE_BASE_HI);
+ }
/*
* Write boot_load into IU2CSEDATA0
@@ -674,8 +821,11 @@ int ipu6_buttress_authenticate(struct ipu6_device *isp)
goto out_unlock;
}
- ret = readl_poll_timeout(psys_pdata->base + BOOTLOADER_STATUS_OFFSET,
- data, data == BOOTLOADER_MAGIC_KEY, 500,
+ void __iomem *base = IS_IPU7(isp) ?
+ isp->base + IPU7_BUTTRESS_REG_FW_BOOT_PARAMS7 :
+ psys_pdata->base + BOOTLOADER_STATUS_OFFSET;
+
+ ret = readl_poll_timeout(base, data, data == BOOTLOADER_MAGIC_KEY, 500,
BUTTRESS_CSE_BOOTLOAD_TIMEOUT_US);
if (ret) {
dev_err(&isp->pdev->dev, "Unexpected magic number 0x%x\n",
@@ -815,12 +965,61 @@ u64 ipu6_buttress_tsc_ticks_to_ns(u64 ticks, const struct ipu6_device *isp)
}
EXPORT_SYMBOL_NS_GPL(ipu6_buttress_tsc_ticks_to_ns, "INTEL_IPU6");
-void ipu6_buttress_restore(struct ipu6_device *isp)
+/* trigger uc control to wakeup fw */
+void ipu7_buttress_wakeup_isys(const struct ipu6_device *isp)
+{
+ u32 val;
+
+ val = readl(isp->base + IPU7_BUTTRESS_REG_ISYS_UCX_CTRL_STATUS);
+ val |= IPU7_UCX_CTL_WAKEUP;
+ writel(val, isp->base + IPU7_BUTTRESS_REG_ISYS_UCX_CTRL_STATUS);
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_buttress_wakeup_isys, "INTEL_IPU6");
+
+u32 ipu7_buttress_get_isys_freq(struct ipu6_device *isp)
+{
+ u32 val;
+
+ val = readl(isp->base + IPU7_BUTTRESS_REG_IS_WORKPOINT_REQ);
+ val &= IPU7_BUTTRESS_IS_FREQ_CTL_RATIO_MASK;
+
+ return val * 50 / 3;
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_buttress_get_isys_freq, "INTEL_IPU6");
+
+static void ipu7_buttress_setup(struct ipu6_device *isp)
{
struct ipu6_buttress *b = &isp->buttress;
+ u32 val;
+
+ /* program PB BAR */
+ writel(0, isp->pb_base + IPU7_GLOBAL_INTERRUPT_MASK);
+ val = readl(isp->pb_base + IPU7_BAR2_MISC_CONFIG);
+ val |= 0x100U;
+
+ writel(val, isp->pb_base + IPU7_BAR2_MISC_CONFIG);
+
+ writel(BIT(22), isp->pb_base + IPU7_TLBID_HASH_ENABLE_63_32);
+ writel(BIT(1), isp->pb_base + IPU7_TLBID_HASH_ENABLE_127_96);
writel(b->regs->irq_all, isp->base + b->regs->irq_clear);
+ writel(b->regs->irq_all, isp->base + IPU7_BUTTRESS_REG_IRQ_MASK);
writel(b->regs->irq_all, isp->base + b->regs->irq_enable);
+
+ /* LNL SW workaround for PS PD hang when PS sub-domain during PD */
+ writel(IPU7_BUTTRESS_CG_CTRL_PS_FSM_CG, isp->base + IPU7_BUTTRESS_REG_CG_CTRL_BITS);
+}
+
+void ipu6_buttress_restore(struct ipu6_device *isp)
+{
+ struct ipu6_buttress *b = &isp->buttress;
+
+ if (IS_IPU7(isp)) {
+ ipu7_buttress_setup(isp);
+ } else {
+ writel(b->regs->irq_all, isp->base + b->regs->irq_clear);
+ writel(b->regs->irq_all, isp->base + b->regs->irq_enable);
+ }
writel(b->wdt_cached_value, isp->base + b->regs->wdt);
}
@@ -838,37 +1037,44 @@ int ipu6_buttress_init(struct ipu6_device *isp)
init_completion(&b->ipc.recv_complete);
INIT_LIST_HEAD(&b->constraints);
-
isp->secure_mode = ipu6_buttress_get_secure_mode(isp);
- dev_dbg(&isp->pdev->dev, "IPU6 in %s mode touch 0x%x mask 0x%x\n",
- isp->secure_mode ? "secure" : "non-secure",
- readl(isp->base + BUTTRESS_REG_SECURITY_TOUCH),
- readl(isp->base + BUTTRESS_REG_CAMERA_MASK));
- b->wdt_cached_value = readl(isp->base + b->regs->wdt);
- writel(b->regs->irq_all, isp->base + b->regs->irq_clear);
- writel(b->regs->irq_all, isp->base + b->regs->irq_enable);
+ dev_dbg(&isp->pdev->dev, "IPU in %s mode\n",
+ isp->secure_mode ? "secure" : "non-secure");
- /* get ref_clk frequency by reading the indication in btrs control */
- val = readl(isp->base + b->regs->btrs_ctrl);
- val = FIELD_GET(BUTTRESS_REG_BTRS_CTRL_REF_CLK_IND, val);
-
- switch (val) {
- case 0x0:
- b->ref_clk = 240;
- break;
- case 0x1:
- b->ref_clk = 192;
- break;
- case 0x2:
+ if (IS_IPU7(isp)) {
+ ipu7_buttress_setup(isp);
b->ref_clk = 384;
- break;
- default:
- dev_warn(&isp->pdev->dev,
- "Unsupported ref clock, use 19.2Mhz by default.\n");
- b->ref_clk = 192;
- break;
+ } else {
+ dev_dbg(&isp->pdev->dev, "IPU6 touch 0x%x mask 0x%x\n",
+ readl(isp->base + BUTTRESS_REG_SECURITY_TOUCH),
+ readl(isp->base + BUTTRESS_REG_CAMERA_MASK));
+
+ writel(b->regs->irq_all, isp->base + b->regs->irq_clear);
+ writel(b->regs->irq_all, isp->base + b->regs->irq_enable);
+
+ /* get ref_clk frequency by reading the indication in btrs control */
+ val = readl(isp->base + b->regs->btrs_ctrl);
+ val = FIELD_GET(BUTTRESS_REG_BTRS_CTRL_REF_CLK_IND, val);
+
+ switch (val) {
+ case 0x0:
+ b->ref_clk = 240;
+ break;
+ case 0x1:
+ b->ref_clk = 192;
+ break;
+ case 0x2:
+ b->ref_clk = 384;
+ break;
+ default:
+ dev_warn(&isp->pdev->dev,
+ "Unsupported ref clock, use 19.2Mhz by default.\n");
+ b->ref_clk = 192;
+ break;
+ }
}
+ b->wdt_cached_value = readl(isp->base + b->regs->wdt);
/* Retry couple of times in case of CSE initialization is delayed */
do {
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.h b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
index a3c23adede7b..af72de2b8729 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
@@ -26,6 +26,7 @@ struct ipu6_buttress_ctrl {
u32 freq_ctl, pwr_sts_shift, pwr_sts_mask, pwr_sts_on, pwr_sts_off;
unsigned int ratio;
unsigned int qos_floor;
+ int subsys_id;
};
struct ipu6_buttress_ipc {
@@ -104,4 +105,6 @@ void ipu6_buttress_exit(struct ipu6_device *isp);
void ipu6_buttress_csi_port_config(struct ipu6_device *isp,
u32 legacy, u32 combo);
void ipu6_buttress_restore(struct ipu6_device *isp);
+void ipu7_buttress_wakeup_isys(const struct ipu6_device *isp);
+u32 ipu7_buttress_get_isys_freq(struct ipu6_device *isp);
#endif /* IPU6_BUTTRESS_H */
diff --git a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
index 5006cce74b23..c4da72c6bd8f 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
@@ -221,4 +221,106 @@ enum {
#define BUTTRESS_EVENT (BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING | \
BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE | \
BUTTRESS_ISR_SAI_VIOLATION)
+
+/* IPU7 */
+
+/* IPU7 buttress register offsets */
+#define IPU7_BUTTRESS_REG_SKU 0x3030
+#define IPU7_BUTTRESS_REG_IRQ_STATUS 0x2000
+#define IPU7_BUTTRESS_REG_IRQ_ENABLE 0x2008
+#define IPU7_BUTTRESS_REG_IRQ_CLEAR 0x200c
+#define IPU7_BUTTRESS_REG_IRQ_MASK 0x2010
+#define IPU7_BUTTRESS_REG_TSC_CMD 0x2014
+#define IPU7_BUTTRESS_REG_TSC_CTL 0x2018
+#define IPU7_BUTTRESS_REG_TSC_LO 0x201c
+#define IPU7_BUTTRESS_REG_IS_WORKPOINT_REQ 0x2104
+#define IPU7_BUTTRESS_REG_PS_WORKPOINT_REQ 0x2100
+#define IPU7_BUTTRESS_REG_IDLE_WDT 0x218c
+#define IPU7_BUTTRESS_REG_ISYS_UCX_CTRL_STATUS 0x2200
+#define IPU7_BUTTRESS_REG_ISYS_UCX_START_ADDR 0x2204
+#define IPU7_BUTTRESS_REG_PSYS_UCX_CTRL_STATUS 0x2208
+#define IPU7_BUTTRESS_REG_PSYS_UCX_START_ADDR 0x220c
+#define IPU7_BUTTRESS_REG_SECURITY_CTL 0x2318
+#define IPU7_BUTTRESS_REG_FW_RESET_CTL 0x2334
+#define IPU7_BUTTRESS_REG_FW_SOURCE_SIZE 0x2338
+#define IPU7_BUTTRESS_REG_FW_SOURCE_BASE 0x233c
+#define IPU7_BUTTRESS_REG_CSE2IUDB0 0x2500
+#define IPU7_BUTTRESS_REG_CSE2IUDATA0 0x2504
+#define IPU7_BUTTRESS_REG_CSE2IUCSR 0x2508
+#define IPU7_BUTTRESS_REG_IU2CSEDB0 0x250c
+#define IPU7_BUTTRESS_REG_IU2CSEDATA0 0x2510
+#define IPU7_BUTTRESS_REG_IU2CSECSR 0x2514
+#define IPU7_BUTTRESS_REG_CG_CTRL_BITS 0x3014
+#define IPU7_BUTTRESS_REG_FW_BOOT_PARAMS0 0x4000
+#define IPU7_BUTTRESS_REG_FW_BOOT_PARAMS7 0x401c
+#define IPU7_BUTTRESS_REG_PWR_STATUS 0x2114
+
+#define IPU7_BUTTRESS_IRQ_IPC_EXEC_DONE_BY_CSE BIT(0)
+#define IPU7_BUTTRESS_IRQ_IPC_FROM_CSE_IS_WAITING BIT(1)
+#define IPU7_BUTTRESS_IRQ_CSE_CSR_SET BIT(2)
+#define IPU7_BUTTRESS_IRQ_SAI_VIOLATION BIT(4)
+#define IPU7_BUTTRESS_IRQ_IS_IRQ BIT(30)
+#define IPU7_BUTTRESS_IRQ_PS_IRQ BIT(31)
+
+#define IPU7_BUTTRESS_IRQS (IPU7_BUTTRESS_IRQ_IS_IRQ | \
+ IPU7_BUTTRESS_IRQ_PS_IRQ | \
+ IPU7_BUTTRESS_IRQ_IPC_FROM_CSE_IS_WAITING | \
+ IPU7_BUTTRESS_IRQ_CSE_CSR_SET | \
+ IPU7_BUTTRESS_IRQ_IPC_EXEC_DONE_BY_CSE)
+
+/* LNL SW workaround for PS PD hang */
+#define IPU7_BUTTRESS_CG_CTRL_PS_FSM_CG BIT(3)
+
+/* P-unit Bridge (PB) BAR registers */
+#define IPU7_PB_INTERRUPT_STATUS 0x0
+
+/* Frequency control encoding */
+#define IPU7_FREQ_CTL_CDYN 0x80
+#define IPU7_FREQ_CTL_CDYN_SHIFT 8
+#define IPU7_BUTTRESS_IS_FREQ_CTL_RATIO_MASK GENMASK(7, 0)
+#define IPU7_IS_FREQ_CTL_DEFAULT_RATIO 0x1b
+#define IPU7_PS_FREQ_CTL_DEFAULT_RATIO 0x14
+
+/* D2D power control */
+#define IPU7_BUTTRESS_REG_D2D_CTL 0x21d4
+#define IPU7_BUTTRESS_D2D_PWR_EN BIT(0)
+#define IPU7_BUTTRESS_D2D_PWR_ACK BIT(4)
+
+#define IPU7_BUTTRESS_PWR_STATE_IS_PWR_SHIFT 0
+#define IPU7_BUTTRESS_PWR_STATE_IS_PWR_MASK (0x3U << 0)
+#define IPU7_BUTTRESS_PWR_STATE_PS_PWR_SHIFT 4
+#define IPU7_BUTTRESS_PWR_STATE_PS_PWR_MASK (0x3U << 4)
+
+/* NDE */
+#define IPU7_BUTTRESS_REG_NDE_CONTROL 0x21a4
+#define IPU7_NDE_VAL_MASK GENMASK(9, 0)
+#define IPU7_NDE_SCALE_MASK GENMASK(12, 10)
+#define IPU7_NDE_VALID_MASK BIT(13)
+#define IPU7_NDE_RESVEC_MASK GENMASK(19, 16)
+#define IPU7_NDE_VAL_ACTIVE 48
+#define IPU7_NDE_SCALE_ACTIVE 2
+#define IPU7_NDE_VALID_ACTIVE 1
+#define IPU7_NDE_VAL_DEFAULT 1023
+#define IPU7_NDE_SCALE_DEFAULT 2
+#define IPU7_NDE_VALID_DEFAULT 0
+#define IPU7_NDE_RESVEC 0xe
+
+/* IS UCX control */
+#define IPU7_UCX_CTL_RESET BIT(0)
+#define IPU7_UCX_CTL_RUN BIT(1)
+#define IPU7_UCX_CTL_WAKEUP BIT(2)
+
+#define IPU7_BUTTRESS_REG_SLEEP_LEVEL_CFG 0x21b0
+#define IPU7_BUTTRESS_REG_SLEEP_LEVEL_STS 0x21b4
+#define IPU7_BUTTRESS_OVERRIDE_IS_CLK BIT(1)
+#define IPU7_BUTTRESS_OWN_ACK_IS_CLK BIT(9)
+#define IPU7_BUTTRESS_OVERRIDE_PS_CLK BIT(2)
+#define IPU7_BUTTRESS_OWN_ACK_PS_CLK BIT(10)
+
+/* PB registers */
+#define IPU7_GLOBAL_INTERRUPT_MASK 0x8
+#define IPU7_TLBID_HASH_ENABLE_63_32 0x34
+#define IPU7_TLBID_HASH_ENABLE_127_96 0x3c
+#define IPU7_BAR2_MISC_CONFIG 0x64
+
#endif /* IPU6_PLATFORM_BUTTRESS_REGS_H */
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index c24e18520de6..4af0b068e759 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -34,6 +34,7 @@
#include "ipu6-platform-regs.h"
#define IPU6_PCI_BAR 0
+#define IPU7_PCI_PBBAR 4
struct ipu6_cell_program {
u32 magic_number;
@@ -209,6 +210,7 @@ static struct ipu6_psys_internal_pdata psys_ipdata = {
};
static const struct ipu6_buttress_ctrl isys_buttress_ctrl = {
+ .subsys_id = IPU_ISYS,
.ratio = IPU6_IS_FREQ_CTL_DEFAULT_RATIO,
.qos_floor = IPU6_IS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO,
.freq_ctl = IPU6_BUTTRESS_REG_IS_FREQ_CTL,
@@ -219,6 +221,7 @@ static const struct ipu6_buttress_ctrl isys_buttress_ctrl = {
};
static const struct ipu6_buttress_ctrl psys_buttress_ctrl = {
+ .subsys_id = IPU_PSYS,
.ratio = IPU6_PS_FREQ_CTL_DEFAULT_RATIO,
.qos_floor = IPU6_PS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO,
.freq_ctl = IPU6_BUTTRESS_REG_PS_FREQ_CTL,
@@ -228,6 +231,28 @@ static const struct ipu6_buttress_ctrl psys_buttress_ctrl = {
.pwr_sts_off = IPU6_BUTTRESS_PWR_STATE_DN_DONE,
};
+static const struct ipu6_buttress_ctrl ipu7_isys_buttress_ctrl = {
+ .subsys_id = IPU_ISYS,
+ .ratio = IPU7_IS_FREQ_CTL_DEFAULT_RATIO,
+ .qos_floor = 0,
+ .freq_ctl = IPU7_BUTTRESS_REG_IS_WORKPOINT_REQ,
+ .pwr_sts_shift = IPU7_BUTTRESS_PWR_STATE_IS_PWR_SHIFT,
+ .pwr_sts_mask = IPU7_BUTTRESS_PWR_STATE_IS_PWR_MASK,
+ .pwr_sts_on = IPU6_BUTTRESS_PWR_STATE_UP_DONE,
+ .pwr_sts_off = IPU6_BUTTRESS_PWR_STATE_DN_DONE,
+};
+
+static const struct ipu6_buttress_ctrl ipu7_psys_buttress_ctrl = {
+ .subsys_id = IPU_PSYS,
+ .ratio = IPU7_PS_FREQ_CTL_DEFAULT_RATIO,
+ .qos_floor = 0,
+ .freq_ctl = IPU7_BUTTRESS_REG_PS_WORKPOINT_REQ,
+ .pwr_sts_shift = IPU7_BUTTRESS_PWR_STATE_PS_PWR_SHIFT,
+ .pwr_sts_mask = IPU7_BUTTRESS_PWR_STATE_PS_PWR_MASK,
+ .pwr_sts_on = IPU6_BUTTRESS_PWR_STATE_UP_DONE,
+ .pwr_sts_off = IPU6_BUTTRESS_PWR_STATE_DN_DONE,
+};
+
static const struct ipu6_buttress_registers ipu6_buttress_regs = {
/* Registers */
.irq_status = BUTTRESS_REG_ISR_STATUS,
@@ -258,6 +283,35 @@ static const struct ipu6_buttress_registers ipu6_buttress_regs = {
.irq_sai = BUTTRESS_ISR_SAI_VIOLATION,
};
+static const struct ipu6_buttress_registers ipu7_buttress_regs = {
+ /* Registers */
+ .irq_status = IPU7_BUTTRESS_REG_IRQ_STATUS,
+ .irq_clear = IPU7_BUTTRESS_REG_IRQ_CLEAR,
+ .irq_enable = IPU7_BUTTRESS_REG_IRQ_ENABLE,
+ .pwr_status = IPU7_BUTTRESS_REG_PWR_STATUS,
+ .security_ctl = IPU7_BUTTRESS_REG_SECURITY_CTL,
+ .fw_reset_ctl = IPU7_BUTTRESS_REG_FW_RESET_CTL,
+ .fabric_cmd = IPU7_BUTTRESS_REG_TSC_CMD,
+ .tsw_ctl = IPU7_BUTTRESS_REG_TSC_CTL,
+ .tsc_lo = IPU7_BUTTRESS_REG_TSC_LO,
+ .wdt = IPU7_BUTTRESS_REG_IDLE_WDT,
+ .csr_in = IPU7_BUTTRESS_REG_CSE2IUCSR,
+ .csr_out = IPU7_BUTTRESS_REG_IU2CSECSR,
+ .db0_in = IPU7_BUTTRESS_REG_CSE2IUDB0,
+ .db0_out = IPU7_BUTTRESS_REG_IU2CSEDB0,
+ .data0_in = IPU7_BUTTRESS_REG_CSE2IUDATA0,
+ .data0_out = IPU7_BUTTRESS_REG_IU2CSEDATA0,
+
+ /* Bitmasks */
+ .irq_is = IPU7_BUTTRESS_IRQ_IS_IRQ,
+ .irq_ps = IPU7_BUTTRESS_IRQ_PS_IRQ,
+ .irq_all = IPU7_BUTTRESS_IRQS,
+ .irq_events = IPU7_BUTTRESS_IRQS,
+ .irq_cse_ipc = IPU7_BUTTRESS_IRQ_IPC_FROM_CSE_IS_WAITING,
+ .irq_exec_done = IPU7_BUTTRESS_IRQ_IPC_EXEC_DONE_BY_CSE,
+ .irq_sai = IPU7_BUTTRESS_IRQ_SAI_VIOLATION,
+};
+
static void
ipu6_pkg_dir_configure_spc(struct ipu6_device *isp,
const struct ipu6_hw_variants *hw_variant,
@@ -532,24 +586,6 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (!isp)
return -ENOMEM;
- isp->pdev = pdev;
- INIT_LIST_HEAD(&isp->devices);
-
- ret = pcim_enable_device(pdev);
- if (ret)
- return dev_err_probe(dev, ret, "Enable PCI device failed\n");
-
- phys = pci_resource_start(pdev, IPU6_PCI_BAR);
- dev_dbg(dev, "IPU6 PCI bar[%u] = %pa\n", IPU6_PCI_BAR, &phys);
-
- isp->base = pcim_iomap_region(pdev, IPU6_PCI_BAR, IPU6_NAME);
- if (IS_ERR(isp->base))
- return dev_err_probe(dev, PTR_ERR(isp->base),
- "Failed to I/O mem remapping\n");
-
- pci_set_drvdata(pdev, isp);
- pci_set_master(pdev);
-
isp->cpd_metadata_cmpnt_size = sizeof(struct ipu6_cpd_metadata_cmpnt);
isp->buttress.regs = &ipu6_buttress_regs;
@@ -577,12 +613,44 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
isp->hw_ver = IPU_VERSION_6EP_MTL;
isp->cpd_fw_name = IPU6EPMTL_FIRMWARE_NAME;
break;
+ case PCI_DEVICE_ID_INTEL_IPU7:
+ isp->hw_ver = IPU_VERSION_7;
+ isp->cpd_fw_name = IPU7_FIRMWARE_NAME;
+ isp->buttress.regs = &ipu7_buttress_regs;
+ break;
default:
return dev_err_probe(dev, -ENODEV,
"Unsupported IPU6 device %x\n",
id->device);
}
+ isp->pdev = pdev;
+ INIT_LIST_HEAD(&isp->devices);
+
+ ret = pcim_enable_device(pdev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Enable PCI device failed\n");
+
+ phys = pci_resource_start(pdev, IPU6_PCI_BAR);
+ dev_dbg(dev, "IPU6 PCI bar[%u] = %pa\n", IPU6_PCI_BAR, &phys);
+
+ isp->base = pcim_iomap_region(pdev, IPU6_PCI_BAR, IPU6_NAME);
+ if (IS_ERR(isp->base))
+ return dev_err_probe(dev, PTR_ERR(isp->base),
+ "Failed to I/O mem remapping\n");
+
+ if (IS_IPU7(isp)) {
+ isp->pb_base = pcim_iomap_region(pdev, IPU7_PCI_PBBAR,
+ IPU6_NAME);
+ if (IS_ERR(isp->pb_base))
+ return dev_err_probe(dev, PTR_ERR(isp->pb_base),
+ "I/O remapping PB BAR %u failed\n",
+ IPU7_PCI_PBBAR);
+ }
+
+ pci_set_drvdata(pdev, isp);
+ pci_set_master(pdev);
+
ipu6_internal_pdata_init(isp);
isys_base = isp->base + isys_ipdata.hw_variant.offset;
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index dc98a787612f..a14b067f169f 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -22,6 +22,7 @@ struct ipu6_bus_device;
#define IPU6_FIRMWARE_NAME "intel/ipu/ipu6_fw.bin"
#define IPU6EPMTL_FIRMWARE_NAME "intel/ipu/ipu6epmtl_fw.bin"
#define IPU6EPADLN_FIRMWARE_NAME "intel/ipu/ipu6epadln_fw.bin"
+#define IPU7_FIRMWARE_NAME "intel/ipu/ipu7_fw.bin"
#define IPU_VERSION_6 BIT(0) /* TGL */
#define IPU_VERSION_6SE BIT(1) /* JSL */
@@ -64,6 +65,7 @@ struct ipu6_device {
u32 cpd_metadata_cmpnt_size;
void __iomem *base;
+ void __iomem *pb_base;
bool need_ipc_reset;
bool secure_mode;
u8 hw_ver;
diff --git a/include/media/ipu6-pci-table.h b/include/media/ipu6-pci-table.h
index 0899d9d2f978..cd5b941fb96c 100644
--- a/include/media/ipu6-pci-table.h
+++ b/include/media/ipu6-pci-table.h
@@ -14,6 +14,8 @@
#define PCI_DEVICE_ID_INTEL_IPU6EP_ADLN 0x462e
#define PCI_DEVICE_ID_INTEL_IPU6EP_RPLP 0xa75d
#define PCI_DEVICE_ID_INTEL_IPU6EP_MTL 0x7d19
+#define PCI_DEVICE_ID_INTEL_IPU7 0x645d
+#define PCI_DEVICE_ID_INTEL_IPU7P5 0xb05d
static const struct pci_device_id ipu6_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU6) },
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 13/44] media: ipu6: Prepare mmu driver for hw variation
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (11 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 12/44] media: ipu6: Add ipu7 buttress support Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 14/44] media: ipu6: Add ipu7 mmu support Antti Laakso
` (30 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
We are about to add support for ipu7 mmu. Split ipu6 mmu
hardware specific and common code to separate files.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/Makefile | 1 +
drivers/media/pci/intel/ipu6/ipu6-dma.c | 4 +-
drivers/media/pci/intel/ipu6/ipu6-mmu-hw.c | 296 +++++++++++++++++++++
drivers/media/pci/intel/ipu6/ipu6-mmu.c | 120 +--------
drivers/media/pci/intel/ipu6/ipu6-mmu.h | 149 ++++++++++-
drivers/media/pci/intel/ipu6/ipu6.c | 125 +--------
drivers/media/pci/intel/ipu6/ipu6.h | 132 +--------
7 files changed, 456 insertions(+), 371 deletions(-)
create mode 100644 drivers/media/pci/intel/ipu6/ipu6-mmu-hw.c
diff --git a/drivers/media/pci/intel/ipu6/Makefile b/drivers/media/pci/intel/ipu6/Makefile
index a821b0a1567f..2106ab84acde 100644
--- a/drivers/media/pci/intel/ipu6/Makefile
+++ b/drivers/media/pci/intel/ipu6/Makefile
@@ -4,6 +4,7 @@ intel-ipu6-y := ipu6.o \
ipu6-bus.o \
ipu6-dma.o \
ipu6-mmu.o \
+ ipu6-mmu-hw.o \
ipu6-buttress.o \
ipu6-cpd.o \
ipu6-fw-com.o
diff --git a/drivers/media/pci/intel/ipu6/ipu6-dma.c b/drivers/media/pci/intel/ipu6/ipu6-dma.c
index fdcdb15b073c..6e8295d9c3a3 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-dma.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-dma.c
@@ -286,7 +286,7 @@ void ipu6_dma_free(struct ipu6_bus_device *sys, size_t size, void *vaddr,
__free_buffer(pages, size, attrs);
- mmu->tlb_invalidate(mmu);
+ mmu->ops->tlb_invalidate(mmu);
__free_iova(&mmu->dmap->iovad, iova);
@@ -366,7 +366,7 @@ void ipu6_dma_unmap_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
ipu6_mmu_unmap(mmu->dmap->mmu_info, PFN_PHYS(iova->pfn_lo),
PFN_PHYS(iova_size(iova)));
- mmu->tlb_invalidate(mmu);
+ mmu->ops->tlb_invalidate(mmu);
__free_iova(&mmu->dmap->iovad, iova);
}
EXPORT_SYMBOL_NS_GPL(ipu6_dma_unmap_sg, "INTEL_IPU6");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu-hw.c b/drivers/media/pci/intel/ipu6/ipu6-mmu-hw.c
new file mode 100644
index 000000000000..2b395fbd5969
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu-hw.c
@@ -0,0 +1,296 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Intel Corporation
+ */
+#include <asm/barrier.h>
+
+#include <linux/bits.h>
+#include <linux/gfp.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "ipu6.h"
+#include "ipu6-dma.h"
+#include "ipu6-mmu.h"
+#include "ipu6-platform-regs.h"
+
+#define ISP_PAGE_SHIFT 12
+#define ISP_PAGE_SIZE BIT(ISP_PAGE_SHIFT)
+#define ISP_PAGE_MASK (~(ISP_PAGE_SIZE - 1))
+
+#define ISP_L1PT_SHIFT 22
+#define ISP_L1PT_MASK (~((1U << ISP_L1PT_SHIFT) - 1))
+
+#define ISP_L2PT_SHIFT 12
+#define ISP_L2PT_MASK (~(ISP_L1PT_MASK | (~(ISP_PAGE_MASK))))
+
+#define ISP_L1PT_PTES 1024
+#define ISP_L2PT_PTES 1024
+
+#define ISP_PADDR_SHIFT 12
+
+#define REG_TLB_INVALIDATE 0x0000
+
+#define REG_L1_PHYS 0x0004 /* 27-bit pfn */
+#define REG_INFO 0x0008
+
+#define TBL_PHYS_ADDR(a) ((phys_addr_t)(a) << ISP_PADDR_SHIFT)
+
+static struct ipu6_mmu_hw ipu6_isys_mmu_hwdata[] = {
+ {
+ .offset = IPU6_ISYS_IOMMU0_OFFSET,
+ .info_bits = IPU6_INFO_REQUEST_DESTINATION_IOSF,
+ .nr_l1streams = 16,
+ .l1_block_sz = {
+ 3, 8, 2, 2, 2, 2, 2, 2, 1, 1,
+ 1, 1, 1, 1, 1, 1
+ },
+ .nr_l2streams = 16,
+ .l2_block_sz = {
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2
+ },
+ .insert_read_before_invalidate = false,
+ .l1_stream_id_reg_offset =
+ IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
+ .l2_stream_id_reg_offset =
+ IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
+ },
+ {
+ .offset = IPU6_ISYS_IOMMU1_OFFSET,
+ .info_bits = 0,
+ .nr_l1streams = 16,
+ .l1_block_sz = {
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 1, 1, 4
+ },
+ .nr_l2streams = 16,
+ .l2_block_sz = {
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2
+ },
+ .insert_read_before_invalidate = false,
+ .l1_stream_id_reg_offset =
+ IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
+ .l2_stream_id_reg_offset =
+ IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
+ },
+ {
+ .offset = IPU6_ISYS_IOMMUI_OFFSET,
+ .info_bits = 0,
+ .nr_l1streams = 0,
+ .nr_l2streams = 0,
+ .insert_read_before_invalidate = false,
+ },
+};
+
+static struct ipu6_mmu_hw ipu6_psys_mmu_hwdata[] = {
+ {
+ .offset = IPU6_PSYS_IOMMU0_OFFSET,
+ .info_bits =
+ IPU6_INFO_REQUEST_DESTINATION_IOSF,
+ .nr_l1streams = 16,
+ .l1_block_sz = {
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2
+ },
+ .nr_l2streams = 16,
+ .l2_block_sz = {
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2
+ },
+ .insert_read_before_invalidate = false,
+ .l1_stream_id_reg_offset =
+ IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
+ .l2_stream_id_reg_offset =
+ IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
+ },
+ {
+ .offset = IPU6_PSYS_IOMMU1_OFFSET,
+ .info_bits = 0,
+ .nr_l1streams = 32,
+ .l1_block_sz = {
+ 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 10,
+ 5, 4, 14, 6, 4, 14, 6, 4, 8,
+ 4, 2, 1, 1, 1, 1, 14
+ },
+ .nr_l2streams = 32,
+ .l2_block_sz = {
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2
+ },
+ .insert_read_before_invalidate = false,
+ .l1_stream_id_reg_offset =
+ IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
+ .l2_stream_id_reg_offset =
+ IPU6_PSYS_MMU1W_L2_STREAM_ID_REG_OFFSET,
+ },
+ {
+ .offset = IPU6_PSYS_IOMMU1R_OFFSET,
+ .info_bits = 0,
+ .nr_l1streams = 16,
+ .l1_block_sz = {
+ 1, 4, 4, 4, 4, 16, 8, 4, 32,
+ 16, 16, 2, 2, 2, 1, 12
+ },
+ .nr_l2streams = 16,
+ .l2_block_sz = {
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2
+ },
+ .insert_read_before_invalidate = false,
+ .l1_stream_id_reg_offset =
+ IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
+ .l2_stream_id_reg_offset =
+ IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
+ },
+ {
+ .offset = IPU6_PSYS_IOMMUI_OFFSET,
+ .info_bits = 0,
+ .nr_l1streams = 0,
+ .nr_l2streams = 0,
+ .insert_read_before_invalidate = false,
+ },
+};
+
+struct ipu6_mmu_hwdata {
+ struct ipu6_mmu_hw *hwdata;
+ unsigned int nr_mmus;
+};
+
+static const struct ipu6_mmu_hwdata ipu6_mmu_hwdata_lookup[IPU_SUBSYS_NUM] = {
+ [IPU_PSYS] = {
+ .hwdata = ipu6_psys_mmu_hwdata,
+ .nr_mmus = ARRAY_SIZE(ipu6_psys_mmu_hwdata),
+ },
+ [IPU_ISYS] = {
+ .hwdata = ipu6_isys_mmu_hwdata,
+ .nr_mmus = ARRAY_SIZE(ipu6_isys_mmu_hwdata),
+ },
+};
+
+static void __ipu6_tlb_invalidate(struct ipu6_mmu *mmu)
+{
+ struct ipu6_mmu_hw *mmu_hw = mmu->ipu6_mmu_hw;
+ unsigned long flags;
+ unsigned int i;
+
+ spin_lock_irqsave(&mmu->ready_lock, flags);
+ if (!mmu->ready) {
+ spin_unlock_irqrestore(&mmu->ready_lock, flags);
+ return;
+ }
+
+ for (i = 0; i < mmu->nr_mmus; i++) {
+ /*
+ * To avoid the HW bug induced dead lock in some of the IPU6
+ * MMUs on successive invalidate calls, we need to first do a
+ * read to the page table base before writing the invalidate
+ * register. MMUs which need to implement this WA, will have
+ * the insert_read_before_invalidate flags set as true.
+ * Disregard the return value of the read.
+ */
+ if (mmu_hw[i].insert_read_before_invalidate)
+ readl(mmu_hw[i].base + REG_L1_PHYS);
+
+ writel(0xffffffff, mmu_hw[i].base + REG_TLB_INVALIDATE);
+ /*
+ * The TLB invalidation is a "single cycle" (IOMMU clock cycles)
+ * When the actual MMIO write reaches the IPU6 TLB Invalidate
+ * register, wmb() will force the TLB invalidate out if the CPU
+ * attempts to update the IOMMU page table (or sooner).
+ */
+ wmb();
+ }
+ spin_unlock_irqrestore(&mmu->ready_lock, flags);
+}
+
+static int __ipu6_mmu_hw_init(struct ipu6_mmu *mmu)
+{
+ struct ipu6_mmu_info *mmu_info = mmu->dmap->mmu_info;
+ struct ipu6_mmu_hw *mmu_hw = mmu->ipu6_mmu_hw;
+
+ /* Initialise the each MMU HW block */
+ for (unsigned int i = 0; i < mmu->nr_mmus; i++) {
+ unsigned int j;
+ u16 block_addr;
+
+ /* Write page table address per MMU */
+ writel((phys_addr_t)mmu_info->l1_pt_dma,
+ mmu_hw[i].base + REG_L1_PHYS);
+
+ /* Set info bits per MMU */
+ writel(mmu_hw[i].info_bits, mmu_hw[i].base + REG_INFO);
+
+ /* Configure MMU TLB stream configuration for L1 */
+ for (j = 0, block_addr = 0; j < mmu_hw[i].nr_l1streams;
+ block_addr += mmu_hw[i].l1_block_sz[j], j++) {
+ if (block_addr > IPU6_MAX_LI_BLOCK_ADDR) {
+ dev_err(mmu->dev, "invalid L1 configuration\n");
+ return -EINVAL;
+ }
+
+ /* Write block start address for each streams */
+ writel(block_addr, mmu_hw[i].base +
+ mmu_hw[i].l1_stream_id_reg_offset + 4 * j);
+ }
+
+ /* Configure MMU TLB stream configuration for L2 */
+ for (j = 0, block_addr = 0; j < mmu_hw[i].nr_l2streams;
+ block_addr += mmu_hw[i].l2_block_sz[j], j++) {
+ if (block_addr > IPU6_MAX_L2_BLOCK_ADDR) {
+ dev_err(mmu->dev, "invalid L2 configuration\n");
+ return -EINVAL;
+ }
+
+ writel(block_addr, mmu_hw[i].base +
+ mmu_hw[i].l2_stream_id_reg_offset + 4 * j);
+ }
+ }
+
+ return 0;
+}
+
+static int __ipu6_mmu_init_hw_data(struct ipu6_mmu *mmu, struct device *dev,
+ void __iomem *base)
+{
+ const struct ipu6_mmu_hwdata *lookup;
+ struct ipu6_mmu_hw *mmu_hw, *src;
+ unsigned int i, nr_mmus;
+
+ if (mmu->mmid >= IPU_SUBSYS_NUM)
+ return -EINVAL;
+
+ lookup = &ipu6_mmu_hwdata_lookup[mmu->mmid];
+ src = lookup->hwdata;
+ nr_mmus = lookup->nr_mmus;
+
+ mmu_hw = devm_kcalloc(dev, nr_mmus, sizeof(*mmu_hw), GFP_KERNEL);
+ if (!mmu_hw)
+ return -ENOMEM;
+
+ for (i = 0; i < nr_mmus; i++) {
+ if (src[i].nr_l1streams > IPU6_MMU_MAX_TLB_L1_STREAMS ||
+ src[i].nr_l2streams > IPU6_MMU_MAX_TLB_L2_STREAMS)
+ return -EINVAL;
+
+ mmu_hw[i] = src[i];
+ mmu_hw[i].base = base + src[i].offset;
+ }
+
+ mmu->nr_mmus = nr_mmus;
+ mmu->ipu6_mmu_hw = mmu_hw;
+
+ return 0;
+}
+
+const struct ipu6_mmu_hw_ops ipu6_mmu_ops = {
+ .init_hw_data = __ipu6_mmu_init_hw_data,
+ .hw_init = __ipu6_mmu_hw_init,
+ .tlb_invalidate = __ipu6_tlb_invalidate,
+};
diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.c b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
index 6b1a49ebbcc2..98ac59d00b78 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
@@ -5,7 +5,6 @@
#include <asm/barrier.h>
#include <linux/align.h>
-#include <linux/atomic.h>
#include <linux/bitops.h>
#include <linux/bits.h>
#include <linux/bug.h>
@@ -13,10 +12,8 @@
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/gfp.h>
-#include <linux/io.h>
#include <linux/iova.h>
#include <linux/math.h>
-#include <linux/minmax.h>
#include <linux/mm.h>
#include <linux/pfn.h>
#include <linux/slab.h>
@@ -51,42 +48,6 @@
#define TBL_PHYS_ADDR(a) ((phys_addr_t)(a) << ISP_PADDR_SHIFT)
-static void tlb_invalidate(struct ipu6_mmu *mmu)
-{
- unsigned long flags;
- unsigned int i;
-
- spin_lock_irqsave(&mmu->ready_lock, flags);
- if (!mmu->ready) {
- spin_unlock_irqrestore(&mmu->ready_lock, flags);
- return;
- }
-
- for (i = 0; i < mmu->nr_mmus; i++) {
- /*
- * To avoid the HW bug induced dead lock in some of the IPU6
- * MMUs on successive invalidate calls, we need to first do a
- * read to the page table base before writing the invalidate
- * register. MMUs which need to implement this WA, will have
- * the insert_read_before_invalidate flags set as true.
- * Disregard the return value of the read.
- */
- if (mmu->mmu_hw[i].insert_read_before_invalidate)
- readl(mmu->mmu_hw[i].base + REG_L1_PHYS);
-
- writel(0xffffffff, mmu->mmu_hw[i].base +
- REG_TLB_INVALIDATE);
- /*
- * The TLB invalidation is a "single cycle" (IOMMU clock cycles)
- * When the actual MMIO write reaches the IPU6 TLB Invalidate
- * register, wmb() will force the TLB invalidate out if the CPU
- * attempts to update the IOMMU page table (or sooner).
- */
- wmb();
- }
- spin_unlock_irqrestore(&mmu->ready_lock, flags);
-}
-
#ifdef DEBUG
static void page_table_dump(struct ipu6_mmu_info *mmu_info)
{
@@ -472,55 +433,14 @@ static int allocate_trash_buffer(struct ipu6_mmu *mmu)
int ipu6_mmu_hw_init(struct ipu6_mmu *mmu)
{
- struct ipu6_mmu_info *mmu_info;
unsigned long flags;
- unsigned int i;
-
- mmu_info = mmu->dmap->mmu_info;
-
- /* Initialise the each MMU HW block */
- for (i = 0; i < mmu->nr_mmus; i++) {
- struct ipu6_mmu_hw *mmu_hw = &mmu->mmu_hw[i];
- unsigned int j;
- u16 block_addr;
-
- /* Write page table address per MMU */
- writel((phys_addr_t)mmu_info->l1_pt_dma,
- mmu->mmu_hw[i].base + REG_L1_PHYS);
-
- /* Set info bits per MMU */
- writel(mmu->mmu_hw[i].info_bits,
- mmu->mmu_hw[i].base + REG_INFO);
-
- /* Configure MMU TLB stream configuration for L1 */
- for (j = 0, block_addr = 0; j < mmu_hw->nr_l1streams;
- block_addr += mmu->mmu_hw[i].l1_block_sz[j], j++) {
- if (block_addr > IPU6_MAX_LI_BLOCK_ADDR) {
- dev_err(mmu->dev, "invalid L1 configuration\n");
- return -EINVAL;
- }
-
- /* Write block start address for each streams */
- writel(block_addr, mmu_hw->base +
- mmu_hw->l1_stream_id_reg_offset + 4 * j);
- }
-
- /* Configure MMU TLB stream configuration for L2 */
- for (j = 0, block_addr = 0; j < mmu_hw->nr_l2streams;
- block_addr += mmu->mmu_hw[i].l2_block_sz[j], j++) {
- if (block_addr > IPU6_MAX_L2_BLOCK_ADDR) {
- dev_err(mmu->dev, "invalid L2 configuration\n");
- return -EINVAL;
- }
+ int ret;
- writel(block_addr, mmu_hw->base +
- mmu_hw->l2_stream_id_reg_offset + 4 * j);
- }
- }
+ ret = mmu->ops->hw_init(mmu);
+ if (ret)
+ return ret;
if (!mmu->trash_page) {
- int ret;
-
mmu->trash_page = alloc_page(GFP_KERNEL);
if (!mmu->trash_page) {
dev_err(mmu->dev, "insufficient memory for trash buffer\n");
@@ -746,44 +666,26 @@ static void ipu6_mmu_destroy(struct ipu6_mmu *mmu)
}
struct ipu6_mmu *ipu6_mmu_init(struct device *dev,
- void __iomem *base, int mmid,
- const struct ipu6_hw_variants *hw)
+ void __iomem *base, int mmid)
{
struct ipu6_device *isp = pci_get_drvdata(to_pci_dev(dev));
- struct ipu6_mmu_hw *mmu_hw;
struct ipu6_mmu *mmu;
- unsigned int i;
-
- if (hw->nr_mmus > IPU6_MMU_MAX_DEVICES)
- return ERR_PTR(-EINVAL);
-
- mmu_hw = devm_kcalloc(dev, sizeof(*mmu_hw), hw->nr_mmus, GFP_KERNEL);
- if (!mmu_hw)
- return ERR_PTR(-ENOMEM);
-
- for (i = 0; i < hw->nr_mmus; i++) {
- const struct ipu6_mmu_hw *src_mmu = &hw->mmu_hw[i];
-
- if (src_mmu->nr_l1streams > IPU6_MMU_MAX_TLB_L1_STREAMS ||
- src_mmu->nr_l2streams > IPU6_MMU_MAX_TLB_L2_STREAMS)
- return ERR_PTR(-EINVAL);
-
- mmu_hw[i] = *src_mmu;
- mmu_hw[i].base = base + src_mmu->offset;
- }
+ int ret;
mmu = devm_kzalloc(dev, sizeof(*mmu), GFP_KERNEL);
if (!mmu)
return ERR_PTR(-ENOMEM);
+ mmu->ops = &ipu6_mmu_ops;
mmu->mmid = mmid;
- mmu->mmu_hw = mmu_hw;
- mmu->nr_mmus = hw->nr_mmus;
- mmu->tlb_invalidate = tlb_invalidate;
mmu->ready = false;
INIT_LIST_HEAD(&mmu->vma_list);
spin_lock_init(&mmu->ready_lock);
+ ret = mmu->ops->init_hw_data(mmu, dev, base);
+ if (ret)
+ return ERR_PTR(ret);
+
mmu->dmap = alloc_dma_mapping(isp);
if (!mmu->dmap) {
dev_err(dev, "can't alloc dma mapping\n");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.h b/drivers/media/pci/intel/ipu6/ipu6-mmu.h
index 35cac80d2d4e..a741f1c0e284 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/* Copyright (C) 2013--2024 Intel Corporation */
+/* Copyright (C) 2013--2026 Intel Corporation */
#ifndef IPU6_MMU_H
#define IPU6_MMU_H
@@ -10,7 +10,6 @@
struct device;
struct page;
-struct ipu6_hw_variants;
struct ipu6_mmu_info {
struct device *dev;
@@ -32,10 +31,147 @@ struct ipu6_mmu_info {
struct ipu6_dma_mapping *dmap;
};
+/*
+ * MMU Invalidation HW bug workaround by ZLW mechanism
+ *
+ * Old IPU6 MMUV2 has a bug in the invalidation mechanism which might result in
+ * wrong translation or replication of the translation. This will cause data
+ * corruption. So we cannot directly use the MMU V2 invalidation registers
+ * to invalidate the MMU. Instead, whenever an invalidate is called, we need to
+ * clear the TLB by evicting all the valid translations by filling it with trash
+ * buffer (which is guaranteed not to be used by any other processes). ZLW is
+ * used to fill the L1 and L2 caches with the trash buffer translations. ZLW
+ * or Zero length write, is pre-fetch mechanism to pre-fetch the pages in
+ * advance to the L1 and L2 caches without triggering any memory operations.
+ *
+ * In MMU V2, L1 -> 16 streams and 64 blocks, maximum 16 blocks per stream
+ * One L1 block has 16 entries, hence points to 16 * 4K pages
+ * L2 -> 16 streams and 32 blocks. 2 blocks per streams
+ * One L2 block maps to 1024 L1 entries, hence points to 4MB address range
+ * 2 blocks per L2 stream means, 1 stream points to 8MB range
+ *
+ * As we need to clear the caches and 8MB being the biggest cache size, we need
+ * to have trash buffer which points to 8MB address range. As these trash
+ * buffers are not used for any memory transactions, we need only the least
+ * amount of physical memory. So we reserve 8MB IOVA address range but only
+ * one page is reserved from physical memory. Each of this 8MB IOVA address
+ * range is then mapped to the same physical memory page.
+ */
+/* One L2 entry maps 1024 L1 entries and one L1 entry per page */
+#define IPU6_MMUV2_L2_RANGE (1024 * PAGE_SIZE)
+/* Max L2 blocks per stream */
+#define IPU6_MMUV2_MAX_L2_BLOCKS 2
+/* Max L1 blocks per stream */
+#define IPU6_MMUV2_MAX_L1_BLOCKS 16
+#define IPU6_MMUV2_TRASH_RANGE (IPU6_MMUV2_L2_RANGE * IPU6_MMUV2_MAX_L2_BLOCKS)
+/* Entries per L1 block */
+#define MMUV2_ENTRIES_PER_L1_BLOCK 16
+#define MMUV2_TRASH_L1_BLOCK_OFFSET (MMUV2_ENTRIES_PER_L1_BLOCK * PAGE_SIZE)
+#define MMUV2_TRASH_L2_BLOCK_OFFSET IPU6_MMUV2_L2_RANGE
+
+/*
+ * In some of the IPU6 MMUs, there is provision to configure L1 and L2 page
+ * table caches. Both these L1 and L2 caches are divided into multiple sections
+ * called streams. There is maximum 16 streams for both caches. Each of these
+ * sections are subdivided into multiple blocks. When nr_l1streams = 0 and
+ * nr_l2streams = 0, means the MMU is of type MMU_V1 and do not support
+ * L1/L2 page table caches.
+ *
+ * L1 stream per block sizes are configurable and varies per usecase.
+ * L2 has constant block sizes - 2 blocks per stream.
+ *
+ * MMU1 support pre-fetching of the pages to have less cache lookup misses. To
+ * enable the pre-fetching, MMU1 AT (Address Translator) device registers
+ * need to be configured.
+ *
+ * There are four types of memory accesses which requires ZLW configuration.
+ * ZLW(Zero Length Write) is a mechanism to enable VT-d pre-fetching on IOMMU.
+ *
+ * 1. Sequential Access or 1D mode
+ * Set ZLW_EN -> 1
+ * set ZLW_PAGE_CROSS_1D -> 1
+ * Set ZLW_N to "N" pages so that ZLW will be inserte N pages ahead where
+ * N is pre-defined and hardcoded in the platform data
+ * Set ZLW_2D -> 0
+ *
+ * 2. ZLW 2D mode
+ * Set ZLW_EN -> 1
+ * set ZLW_PAGE_CROSS_1D -> 1,
+ * Set ZLW_N -> 0
+ * Set ZLW_2D -> 1
+ *
+ * 3. ZLW Enable (no 1D or 2D mode)
+ * Set ZLW_EN -> 1
+ * set ZLW_PAGE_CROSS_1D -> 0,
+ * Set ZLW_N -> 0
+ * Set ZLW_2D -> 0
+ *
+ * 4. ZLW disable
+ * Set ZLW_EN -> 0
+ * set ZLW_PAGE_CROSS_1D -> 0,
+ * Set ZLW_N -> 0
+ * Set ZLW_2D -> 0
+ *
+ * To configure the ZLW for the above memory access, four registers are
+ * available. Hence to track these four settings, we have the following entries
+ * in the struct ipu6_mmu_hw. Each of these entries are per stream and
+ * available only for the L1 streams.
+ *
+ * a. l1_zlw_en -> To track zlw enabled per stream (ZLW_EN)
+ * b. l1_zlw_1d_mode -> Track 1D mode per stream. ZLW inserted at page boundary
+ * c. l1_ins_zlw_ahead_pages -> to track how advance the ZLW need to be inserted
+ * Insert ZLW request N pages ahead address.
+ * d. l1_zlw_2d_mode -> To track 2D mode per stream (ZLW_2D)
+ *
+ *
+ * Currently L1/L2 streams, blocks, AT ZLW configurations etc. are pre-defined
+ * as per the usecase specific calculations. Any change to this pre-defined
+ * table has to happen in sync with IPU6 FW.
+ */
+
+struct ipu6_mmu_hw {
+ union {
+ unsigned long offset;
+ void __iomem *base;
+ };
+ u32 info_bits;
+ u8 nr_l1streams;
+ /*
+ * L1 has variable blocks per stream - total of 64 blocks and maximum of
+ * 16 blocks per stream. Configurable by using the block start address
+ * per stream. Block start address is calculated from the block size
+ */
+ u8 l1_block_sz[IPU6_MMU_MAX_TLB_L1_STREAMS];
+ /* Is ZLW is enabled in each stream */
+ bool l1_zlw_en[IPU6_MMU_MAX_TLB_L1_STREAMS];
+ bool l1_zlw_1d_mode[IPU6_MMU_MAX_TLB_L1_STREAMS];
+ u8 l1_ins_zlw_ahead_pages[IPU6_MMU_MAX_TLB_L1_STREAMS];
+ bool l1_zlw_2d_mode[IPU6_MMU_MAX_TLB_L1_STREAMS];
+
+ u32 l1_stream_id_reg_offset;
+ u32 l2_stream_id_reg_offset;
+
+ u8 nr_l2streams;
+ /*
+ * L2 has fixed 2 blocks per stream. Block address is calculated
+ * from the block size
+ */
+ u8 l2_block_sz[IPU6_MMU_MAX_TLB_L2_STREAMS];
+ /* flag to track if WA is needed for successive invalidate HW bug */
+ bool insert_read_before_invalidate;
+};
+
+struct ipu6_mmu_hw_ops {
+ int (*init_hw_data)(struct ipu6_mmu *mmu, struct device *dev,
+ void __iomem *base);
+ int (*hw_init)(struct ipu6_mmu *mmu);
+ void (*tlb_invalidate)(struct ipu6_mmu *mmu);
+};
+
struct ipu6_mmu {
struct list_head node;
- struct ipu6_mmu_hw *mmu_hw;
+ struct ipu6_mmu_hw *ipu6_mmu_hw;
unsigned int nr_mmus;
unsigned int mmid;
@@ -52,12 +188,13 @@ struct ipu6_mmu {
bool ready;
spinlock_t ready_lock; /* Serialize access to bool ready */
- void (*tlb_invalidate)(struct ipu6_mmu *mmu);
+ const struct ipu6_mmu_hw_ops *ops;
};
+extern const struct ipu6_mmu_hw_ops ipu6_mmu_ops;
+
struct ipu6_mmu *ipu6_mmu_init(struct device *dev,
- void __iomem *base, int mmid,
- const struct ipu6_hw_variants *hw);
+ void __iomem *base, int mmid);
void ipu6_mmu_cleanup(struct ipu6_mmu *mmu);
int ipu6_mmu_hw_init(struct ipu6_mmu *mmu);
void ipu6_mmu_hw_cleanup(struct ipu6_mmu *mmu);
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 4af0b068e759..51174cafb1b4 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -74,54 +74,6 @@ struct ipu6_cell_program {
static struct ipu6_isys_internal_pdata isys_ipdata = {
.hw_variant = {
.offset = IPU6_UNIFIED_OFFSET,
- .nr_mmus = 3,
- .mmu_hw = {
- {
- .offset = IPU6_ISYS_IOMMU0_OFFSET,
- .info_bits = IPU6_INFO_REQUEST_DESTINATION_IOSF,
- .nr_l1streams = 16,
- .l1_block_sz = {
- 3, 8, 2, 2, 2, 2, 2, 2, 1, 1,
- 1, 1, 1, 1, 1, 1
- },
- .nr_l2streams = 16,
- .l2_block_sz = {
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2
- },
- .insert_read_before_invalidate = false,
- .l1_stream_id_reg_offset =
- IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
- .l2_stream_id_reg_offset =
- IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
- },
- {
- .offset = IPU6_ISYS_IOMMU1_OFFSET,
- .info_bits = 0,
- .nr_l1streams = 16,
- .l1_block_sz = {
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 1, 1, 4
- },
- .nr_l2streams = 16,
- .l2_block_sz = {
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2
- },
- .insert_read_before_invalidate = false,
- .l1_stream_id_reg_offset =
- IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
- .l2_stream_id_reg_offset =
- IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
- },
- {
- .offset = IPU6_ISYS_IOMMUI_OFFSET,
- .info_bits = 0,
- .nr_l1streams = 0,
- .nr_l2streams = 0,
- .insert_read_before_invalidate = false,
- },
- },
.cdc_fifos = 3,
.cdc_fifo_threshold = {6, 8, 2},
.dmem_offset = IPU6_ISYS_DMEM_OFFSET,
@@ -133,78 +85,6 @@ static struct ipu6_isys_internal_pdata isys_ipdata = {
static struct ipu6_psys_internal_pdata psys_ipdata = {
.hw_variant = {
.offset = IPU6_UNIFIED_OFFSET,
- .nr_mmus = 4,
- .mmu_hw = {
- {
- .offset = IPU6_PSYS_IOMMU0_OFFSET,
- .info_bits =
- IPU6_INFO_REQUEST_DESTINATION_IOSF,
- .nr_l1streams = 16,
- .l1_block_sz = {
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2
- },
- .nr_l2streams = 16,
- .l2_block_sz = {
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2
- },
- .insert_read_before_invalidate = false,
- .l1_stream_id_reg_offset =
- IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
- .l2_stream_id_reg_offset =
- IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
- },
- {
- .offset = IPU6_PSYS_IOMMU1_OFFSET,
- .info_bits = 0,
- .nr_l1streams = 32,
- .l1_block_sz = {
- 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 10,
- 5, 4, 14, 6, 4, 14, 6, 4, 8,
- 4, 2, 1, 1, 1, 1, 14
- },
- .nr_l2streams = 32,
- .l2_block_sz = {
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2
- },
- .insert_read_before_invalidate = false,
- .l1_stream_id_reg_offset =
- IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
- .l2_stream_id_reg_offset =
- IPU6_PSYS_MMU1W_L2_STREAM_ID_REG_OFFSET,
- },
- {
- .offset = IPU6_PSYS_IOMMU1R_OFFSET,
- .info_bits = 0,
- .nr_l1streams = 16,
- .l1_block_sz = {
- 1, 4, 4, 4, 4, 16, 8, 4, 32,
- 16, 16, 2, 2, 2, 1, 12
- },
- .nr_l2streams = 16,
- .l2_block_sz = {
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2
- },
- .insert_read_before_invalidate = false,
- .l1_stream_id_reg_offset =
- IPU6_MMU_L1_STREAM_ID_REG_OFFSET,
- .l2_stream_id_reg_offset =
- IPU6_MMU_L2_STREAM_ID_REG_OFFSET,
- },
- {
- .offset = IPU6_PSYS_IOMMUI_OFFSET,
- .info_bits = 0,
- .nr_l1streams = 0,
- .nr_l2streams = 0,
- .insert_read_before_invalidate = false,
- },
- },
.dmem_offset = IPU6_PSYS_DMEM_OFFSET,
},
};
@@ -478,7 +358,7 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent,
"ipu6_bus_initialize_device isys failed\n");
}
- isys_adev->mmu = ipu6_mmu_init(dev, base, IPU_ISYS, &ipdata->hw_variant);
+ isys_adev->mmu = ipu6_mmu_init(dev, base, IPU_ISYS);
if (IS_ERR(isys_adev->mmu)) {
put_device(&isys_adev->auxdev.dev);
return dev_err_cast_probe(dev, isys_adev->mmu,
@@ -518,8 +398,7 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent,
"ipu6_bus_initialize_device psys failed\n");
}
- psys_adev->mmu = ipu6_mmu_init(&pdev->dev, base, IPU_PSYS,
- &ipdata->hw_variant);
+ psys_adev->mmu = ipu6_mmu_init(&pdev->dev, base, IPU_PSYS);
if (IS_ERR(psys_adev->mmu)) {
put_device(&psys_adev->auxdev.dev);
return dev_err_cast_probe(&pdev->dev, psys_adev->mmu,
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index a14b067f169f..debd571b6f6d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -74,6 +74,7 @@ struct ipu6_device {
#define IPU_PSYS 0
#define IPU_ISYS 1
+#define IPU_SUBSYS_NUM 2
#define IPU6_ISYS_NAME "isys"
#define IPU6_PSYS_NAME "psys"
@@ -121,135 +122,6 @@ struct ipu6_device {
#define IPU6_BTRS_ARB_STALL_MODE_VC1 \
IPU6_BTRS_ARB_MODE_TYPE_REARB
-/*
- * MMU Invalidation HW bug workaround by ZLW mechanism
- *
- * Old IPU6 MMUV2 has a bug in the invalidation mechanism which might result in
- * wrong translation or replication of the translation. This will cause data
- * corruption. So we cannot directly use the MMU V2 invalidation registers
- * to invalidate the MMU. Instead, whenever an invalidate is called, we need to
- * clear the TLB by evicting all the valid translations by filling it with trash
- * buffer (which is guaranteed not to be used by any other processes). ZLW is
- * used to fill the L1 and L2 caches with the trash buffer translations. ZLW
- * or Zero length write, is pre-fetch mechanism to pre-fetch the pages in
- * advance to the L1 and L2 caches without triggering any memory operations.
- *
- * In MMU V2, L1 -> 16 streams and 64 blocks, maximum 16 blocks per stream
- * One L1 block has 16 entries, hence points to 16 * 4K pages
- * L2 -> 16 streams and 32 blocks. 2 blocks per streams
- * One L2 block maps to 1024 L1 entries, hence points to 4MB address range
- * 2 blocks per L2 stream means, 1 stream points to 8MB range
- *
- * As we need to clear the caches and 8MB being the biggest cache size, we need
- * to have trash buffer which points to 8MB address range. As these trash
- * buffers are not used for any memory transactions, we need only the least
- * amount of physical memory. So we reserve 8MB IOVA address range but only
- * one page is reserved from physical memory. Each of this 8MB IOVA address
- * range is then mapped to the same physical memory page.
- */
-/* One L2 entry maps 1024 L1 entries and one L1 entry per page */
-#define IPU6_MMUV2_L2_RANGE (1024 * PAGE_SIZE)
-/* Max L2 blocks per stream */
-#define IPU6_MMUV2_MAX_L2_BLOCKS 2
-/* Max L1 blocks per stream */
-#define IPU6_MMUV2_MAX_L1_BLOCKS 16
-#define IPU6_MMUV2_TRASH_RANGE (IPU6_MMUV2_L2_RANGE * IPU6_MMUV2_MAX_L2_BLOCKS)
-/* Entries per L1 block */
-#define MMUV2_ENTRIES_PER_L1_BLOCK 16
-#define MMUV2_TRASH_L1_BLOCK_OFFSET (MMUV2_ENTRIES_PER_L1_BLOCK * PAGE_SIZE)
-#define MMUV2_TRASH_L2_BLOCK_OFFSET IPU6_MMUV2_L2_RANGE
-
-/*
- * In some of the IPU6 MMUs, there is provision to configure L1 and L2 page
- * table caches. Both these L1 and L2 caches are divided into multiple sections
- * called streams. There is maximum 16 streams for both caches. Each of these
- * sections are subdivided into multiple blocks. When nr_l1streams = 0 and
- * nr_l2streams = 0, means the MMU is of type MMU_V1 and do not support
- * L1/L2 page table caches.
- *
- * L1 stream per block sizes are configurable and varies per usecase.
- * L2 has constant block sizes - 2 blocks per stream.
- *
- * MMU1 support pre-fetching of the pages to have less cache lookup misses. To
- * enable the pre-fetching, MMU1 AT (Address Translator) device registers
- * need to be configured.
- *
- * There are four types of memory accesses which requires ZLW configuration.
- * ZLW(Zero Length Write) is a mechanism to enable VT-d pre-fetching on IOMMU.
- *
- * 1. Sequential Access or 1D mode
- * Set ZLW_EN -> 1
- * set ZLW_PAGE_CROSS_1D -> 1
- * Set ZLW_N to "N" pages so that ZLW will be inserte N pages ahead where
- * N is pre-defined and hardcoded in the platform data
- * Set ZLW_2D -> 0
- *
- * 2. ZLW 2D mode
- * Set ZLW_EN -> 1
- * set ZLW_PAGE_CROSS_1D -> 1,
- * Set ZLW_N -> 0
- * Set ZLW_2D -> 1
- *
- * 3. ZLW Enable (no 1D or 2D mode)
- * Set ZLW_EN -> 1
- * set ZLW_PAGE_CROSS_1D -> 0,
- * Set ZLW_N -> 0
- * Set ZLW_2D -> 0
- *
- * 4. ZLW disable
- * Set ZLW_EN -> 0
- * set ZLW_PAGE_CROSS_1D -> 0,
- * Set ZLW_N -> 0
- * Set ZLW_2D -> 0
- *
- * To configure the ZLW for the above memory access, four registers are
- * available. Hence to track these four settings, we have the following entries
- * in the struct ipu6_mmu_hw. Each of these entries are per stream and
- * available only for the L1 streams.
- *
- * a. l1_zlw_en -> To track zlw enabled per stream (ZLW_EN)
- * b. l1_zlw_1d_mode -> Track 1D mode per stream. ZLW inserted at page boundary
- * c. l1_ins_zlw_ahead_pages -> to track how advance the ZLW need to be inserted
- * Insert ZLW request N pages ahead address.
- * d. l1_zlw_2d_mode -> To track 2D mode per stream (ZLW_2D)
- *
- *
- * Currently L1/L2 streams, blocks, AT ZLW configurations etc. are pre-defined
- * as per the usecase specific calculations. Any change to this pre-defined
- * table has to happen in sync with IPU6 FW.
- */
-struct ipu6_mmu_hw {
- union {
- unsigned long offset;
- void __iomem *base;
- };
- u32 info_bits;
- u8 nr_l1streams;
- /*
- * L1 has variable blocks per stream - total of 64 blocks and maximum of
- * 16 blocks per stream. Configurable by using the block start address
- * per stream. Block start address is calculated from the block size
- */
- u8 l1_block_sz[IPU6_MMU_MAX_TLB_L1_STREAMS];
- /* Is ZLW is enabled in each stream */
- bool l1_zlw_en[IPU6_MMU_MAX_TLB_L1_STREAMS];
- bool l1_zlw_1d_mode[IPU6_MMU_MAX_TLB_L1_STREAMS];
- u8 l1_ins_zlw_ahead_pages[IPU6_MMU_MAX_TLB_L1_STREAMS];
- bool l1_zlw_2d_mode[IPU6_MMU_MAX_TLB_L1_STREAMS];
-
- u32 l1_stream_id_reg_offset;
- u32 l2_stream_id_reg_offset;
-
- u8 nr_l2streams;
- /*
- * L2 has fixed 2 blocks per stream. Block address is calculated
- * from the block size
- */
- u8 l2_block_sz[IPU6_MMU_MAX_TLB_L2_STREAMS];
- /* flag to track if WA is needed for successive invalidate HW bug */
- bool insert_read_before_invalidate;
-};
-
struct ipu6_isys_csi2_pdata {
void __iomem *base;
};
@@ -274,8 +146,6 @@ struct ipu6_isys_internal_tpg_pdata {
struct ipu6_hw_variants {
unsigned long offset;
- u32 nr_mmus;
- struct ipu6_mmu_hw mmu_hw[IPU6_MMU_MAX_DEVICES];
u8 cdc_fifos;
u8 cdc_fifo_threshold[IPU6_MAX_VC_IOSF_PORTS];
u32 dmem_offset;
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 14/44] media: ipu6: Add ipu7 mmu support
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (12 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 13/44] media: ipu6: Prepare mmu driver for hw variation Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 15/44] media: ipu6: Add ipu7 cpd handling Antti Laakso
` (29 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The ipu7 mmu have similar page tables as ipu6, but e.g. register interface
is different. Add own driver handling ipu7 mmu specifics.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/Makefile | 1 +
drivers/media/pci/intel/ipu6/ipu6-mmu.c | 14 +-
drivers/media/pci/intel/ipu6/ipu6-mmu.h | 8 +-
drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c | 599 +++++++++++++++++++++
drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h | 155 ++++++
5 files changed, 773 insertions(+), 4 deletions(-)
create mode 100644 drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c
create mode 100644 drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h
diff --git a/drivers/media/pci/intel/ipu6/Makefile b/drivers/media/pci/intel/ipu6/Makefile
index 2106ab84acde..c0daf0995b22 100644
--- a/drivers/media/pci/intel/ipu6/Makefile
+++ b/drivers/media/pci/intel/ipu6/Makefile
@@ -5,6 +5,7 @@ intel-ipu6-y := ipu6.o \
ipu6-dma.o \
ipu6-mmu.o \
ipu6-mmu-hw.o \
+ ipu7-mmu-hw.o \
ipu6-buttress.o \
ipu6-cpd.o \
ipu6-fw-com.o
diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.c b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
index 98ac59d00b78..243d438786ba 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
@@ -473,7 +473,12 @@ static struct ipu6_mmu_info *ipu6_mmu_alloc(struct ipu6_device *isp)
if (!mmu_info)
return NULL;
- mmu_info->aperture_start = 0;
+ if (IS_IPU7(isp))
+ mmu_info->aperture_start = isp->secure_mode ?
+ IPU7_FW_CODE_REGION_END : IPU7_FW_CODE_REGION_START;
+ else
+ mmu_info->aperture_start = 0;
+
mmu_info->aperture_end =
(dma_addr_t)DMA_BIT_MASK(isp->secure_mode ?
IPU6_MMU_ADDR_BITS :
@@ -532,6 +537,7 @@ EXPORT_SYMBOL_NS_GPL(ipu6_mmu_hw_cleanup, "INTEL_IPU6");
static struct ipu6_dma_mapping *alloc_dma_mapping(struct ipu6_device *isp)
{
struct ipu6_dma_mapping *dmap;
+ unsigned long base_pfn;
dmap = kzalloc_obj(*dmap);
if (!dmap)
@@ -543,7 +549,9 @@ static struct ipu6_dma_mapping *alloc_dma_mapping(struct ipu6_device *isp)
return NULL;
}
- init_iova_domain(&dmap->iovad, SZ_4K, 1);
+ base_pfn = max_t(unsigned long, 1,
+ PFN_DOWN(dmap->mmu_info->aperture_start));
+ init_iova_domain(&dmap->iovad, SZ_4K, base_pfn);
dmap->mmu_info->dmap = dmap;
dev_dbg(&isp->pdev->dev, "alloc mapping\n");
@@ -676,7 +684,7 @@ struct ipu6_mmu *ipu6_mmu_init(struct device *dev,
if (!mmu)
return ERR_PTR(-ENOMEM);
- mmu->ops = &ipu6_mmu_ops;
+ mmu->ops = IS_IPU7(isp) ? &ipu7_mmu_ops : &ipu6_mmu_ops;
mmu->mmid = mmid;
mmu->ready = false;
INIT_LIST_HEAD(&mmu->vma_list);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.h b/drivers/media/pci/intel/ipu6/ipu6-mmu.h
index a741f1c0e284..44880478d242 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.h
@@ -8,6 +8,8 @@
#include <linux/spinlock_types.h>
#include <linux/types.h>
+#include "ipu7-mmu-hw.h"
+
struct device;
struct page;
@@ -171,7 +173,10 @@ struct ipu6_mmu_hw_ops {
struct ipu6_mmu {
struct list_head node;
- struct ipu6_mmu_hw *ipu6_mmu_hw;
+ union {
+ struct ipu6_mmu_hw *ipu6_mmu_hw;
+ struct ipu7_mmu_hw *ipu7_mmu_hw;
+ };
unsigned int nr_mmus;
unsigned int mmid;
@@ -192,6 +197,7 @@ struct ipu6_mmu {
};
extern const struct ipu6_mmu_hw_ops ipu6_mmu_ops;
+extern const struct ipu6_mmu_hw_ops ipu7_mmu_ops;
struct ipu6_mmu *ipu6_mmu_init(struct device *dev,
void __iomem *base, int mmid);
diff --git a/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c
new file mode 100644
index 000000000000..3cd9a818733c
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c
@@ -0,0 +1,599 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Intel Corporation
+ */
+
+#include <linux/types.h>
+#include <linux/iopoll.h>
+
+#include "ipu6.h"
+#include "ipu6-dma.h"
+#include "ipu6-mmu.h"
+
+static struct ipu7_mmu_hw ipu7_isys_mmu_hwdata[] = {
+ {
+ .offset = IPU7_IS_MMU_FW_RD_OFFSET,
+ .zlx_offset = IPU7_IS_ZLX_UC_RD_OFFSET,
+ .uao_offset = IPU7_IS_UAO_UC_RD_OFFSET,
+ .info_bits = 0x20006701,
+ .refill = 0x00002726,
+ .collapse_en_bitmap = 0x0,
+ .l1_block = IPU7_IS_MMU_FW_RD_L1_BLOCKNR_REG,
+ .l2_block = IPU7_IS_MMU_FW_RD_L2_BLOCKNR_REG,
+ .nr_l1streams = IPU7_IS_MMU_FW_RD_STREAM_NUM,
+ .nr_l2streams = IPU7_IS_MMU_FW_RD_STREAM_NUM,
+ .l1_block_sz = { 0x0, 0x8, 0xa },
+ .l2_block_sz = { 0x0, 0x2, 0x4 },
+ .zlx_nr = IPU7_IS_ZLX_UC_RD_NUM,
+ .zlx_axi_pool = { 0x00000f30 },
+ .zlx_en = { 0, 0, 0, 0 },
+ .zlx_conf = { 0x0, 0x0, 0x0, 0x0 },
+ .uao_p_num = IPU7_IS_UAO_UC_RD_PLANENUM,
+ .uao_p2tlb = { 0x61, 0x64, 0x65 },
+ },
+ {
+ .offset = IPU7_IS_MMU_FW_WR_OFFSET,
+ .zlx_offset = IPU7_IS_ZLX_UC_WR_OFFSET,
+ .uao_offset = IPU7_IS_UAO_UC_WR_OFFSET,
+ .info_bits = 0x20006801,
+ .refill = 0x00002524,
+ .collapse_en_bitmap = 0x0,
+ .l1_block = IPU7_IS_MMU_FW_WR_L1_BLOCKNR_REG,
+ .l2_block = IPU7_IS_MMU_FW_WR_L2_BLOCKNR_REG,
+ .nr_l1streams = IPU7_IS_MMU_FW_WR_STREAM_NUM,
+ .nr_l2streams = IPU7_IS_MMU_FW_WR_STREAM_NUM,
+ .l1_block_sz = { 0x0, 0x8, 0xa },
+ .l2_block_sz = { 0x0, 0x2, 0x4 },
+ .zlx_nr = IPU7_IS_ZLX_UC_WR_NUM,
+ .zlx_axi_pool = { 0x00000f20 },
+ .zlx_en = { 0, 1, 1, 0 },
+ .zlx_conf = { 0x0, 0x00010101, 0x00010101 },
+ .uao_p_num = IPU7_IS_UAO_UC_WR_PLANENUM,
+ .uao_p2tlb = { 0x61, 0x62, 0x63 },
+ },
+ {
+ .offset = IPU7_IS_MMU_M0_OFFSET,
+ .zlx_offset = IPU7_IS_ZLX_M0_OFFSET,
+ .uao_offset = IPU7_IS_UAO_M0_WR_OFFSET,
+ .info_bits = 0x20006601,
+ .refill = 0x00002120,
+ .collapse_en_bitmap = 0x0,
+ .l1_block = IPU7_IS_MMU_M0_L1_BLOCKNR_REG,
+ .l2_block = IPU7_IS_MMU_M0_L2_BLOCKNR_REG,
+ .nr_l1streams = IPU7_IS_MMU_M0_STREAM_NUM,
+ .nr_l2streams = IPU7_IS_MMU_M0_STREAM_NUM,
+ .l1_block_sz = { 0x0, 0x3, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10 },
+ .l2_block_sz = { 0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe },
+ .zlx_nr = IPU7_IS_ZLX_M0_NUM,
+ .zlx_axi_pool = { 0x00000f10 },
+ .zlx_en = { 1, 1, 1, 1, 1, 1, 1, 1 },
+ .zlx_conf = {
+ 0x00010103,
+ 0x00010103,
+ 0x00010101,
+ 0x00010101,
+ 0x00010101,
+ 0x00010101,
+ 0x00010101,
+ 0x00010101,
+ },
+ .uao_p_num = IPU7_IS_UAO_M0_WR_PLANENUM,
+ .uao_p2tlb = {
+ 0x00000049,
+ 0x0000004a,
+ 0x0000004b,
+ 0x0000004c,
+ 0x0000004d,
+ 0x0000004e,
+ 0x0000004f,
+ 0x00000050,
+ },
+ },
+ {
+ .offset = IPU7_IS_MMU_M1_OFFSET,
+ .zlx_offset = IPU7_IS_ZLX_M1_OFFSET,
+ .uao_offset = IPU7_IS_UAO_M1_WR_OFFSET,
+ .info_bits = 0x20006901,
+ .refill = 0x00002322,
+ .collapse_en_bitmap = 0x0,
+ .l1_block = IPU7_IS_MMU_M1_L1_BLOCKNR_REG,
+ .l2_block = IPU7_IS_MMU_M1_L2_BLOCKNR_REG,
+ .nr_l1streams = IPU7_IS_MMU_M1_STREAM_NUM,
+ .nr_l2streams = IPU7_IS_MMU_M1_STREAM_NUM,
+ .l1_block_sz = {
+ 0x0, 0x3, 0x6, 0x9, 0xc,
+ 0xe, 0x10, 0x12, 0x14, 0x16,
+ 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22,
+ },
+ .l2_block_sz = {
+ 0x0, 0x2, 0x4, 0x6, 0x8,
+ 0xa, 0xc, 0xe, 0x10, 0x12,
+ 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
+ },
+ .zlx_nr = IPU7_IS_ZLX_M1_NUM,
+ .zlx_axi_pool = { 0x00000f20 },
+ .zlx_en = { 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ },
+ .zlx_conf = {
+ 0x00010103,
+ 0x00010103,
+ 0x00010103,
+ 0x00010103,
+ 0x00010103,
+ 0x00010103,
+ 0x00010103,
+ 0x00010103,
+ 0x00010101,
+ 0x00010101,
+ 0x00010101,
+ 0x00010101,
+ 0x00010101,
+ 0x00010101,
+ 0x00010101,
+ 0x00010101,
+ },
+ .uao_p_num = IPU7_IS_UAO_M1_WR_PLANENUM,
+ .uao_p2tlb = {
+ 0x00000051,
+ 0x00000052,
+ 0x00000053,
+ 0x00000054,
+ 0x00000055,
+ 0x00000056,
+ 0x00000057,
+ 0x00000058,
+ 0x00000059,
+ 0x0000005a,
+ 0x0000005b,
+ 0x0000005c,
+ 0x0000005d,
+ 0x0000005e,
+ 0x0000005f,
+ 0x00000060,
+ },
+ },
+};
+
+static struct ipu7_mmu_hw ipu7_psys_mmu_hwdata[] = {
+ {
+ .name = "PS_FW_RD",
+ .offset = IPU7_PS_MMU_FW_RD_OFFSET,
+ .zlx_offset = IPU7_PS_ZLX_FW_RD_OFFSET,
+ .uao_offset = IPU7_PS_UAO_FW_RD_OFFSET,
+ .info_bits = 0x20004801,
+ .refill = 0x00002726,
+ .collapse_en_bitmap = 0x0,
+ .l1_block = IPU7_PS_MMU_FW_RD_L1_BLOCKNR_REG,
+ .l2_block = IPU7_PS_MMU_FW_RD_L2_BLOCKNR_REG,
+ .nr_l1streams = IPU7_PS_MMU_FW_RD_STREAM_NUM,
+ .nr_l2streams = IPU7_PS_MMU_FW_RD_STREAM_NUM,
+ .l1_block_sz = {
+ 0, 0x8, 0xa, 0xc, 0xd,
+ 0xf, 0x11, 0x12, 0x13, 0x14,
+ 0x16, 0x18, 0x19, 0x1a, 0x1a,
+ 0x1a, 0x1a, 0x1a, 0x1a, 0x1a,
+ },
+ .l2_block_sz = {
+ 0x0, 0x2, 0x4, 0x6, 0x8,
+ 0xa, 0xc, 0xe, 0x10, 0x12,
+ 0x14, 0x16, 0x18, 0x1a, 0x1c,
+ 0x1e, 0x20, 0x22, 0x24, 0x26,
+ },
+ .zlx_nr = IPU7_PS_ZLX_FW_RD_NUM,
+ .zlx_axi_pool = { 0x00000f30 },
+ .zlx_en = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ },
+ .zlx_conf = { 0x0 },
+ .uao_p_num = IPU7_PS_UAO_FW_RD_PLANENUM,
+ .uao_p2tlb = {
+ 0x00000036,
+ 0x0000003d,
+ 0x0000003e,
+ 0x00000039,
+ 0x0000003f,
+ 0x00000040,
+ 0x00000041,
+ 0x0000003a,
+ 0x0000003b,
+ 0x00000042,
+ 0x00000043,
+ 0x00000044,
+ 0x0000003c,
+ },
+ },
+ {
+ .offset = IPU7_PS_MMU_FW_WR_OFFSET,
+ .zlx_offset = IPU7_PS_ZLX_FW_WR_OFFSET,
+ .uao_offset = IPU7_PS_UAO_FW_WR_OFFSET,
+ .info_bits = 0x20004601,
+ .refill = 0x00002322,
+ .collapse_en_bitmap = 0x0,
+ .l1_block = IPU7_PS_MMU_FW_WR_L1_BLOCKNR_REG,
+ .l2_block = IPU7_PS_MMU_FW_WR_L2_BLOCKNR_REG,
+ .nr_l1streams = IPU7_PS_MMU_FW_WR_STREAM_NUM,
+ .nr_l2streams = IPU7_PS_MMU_FW_WR_STREAM_NUM,
+ .l1_block_sz = {
+ 0, 0x8, 0xa, 0xc, 0xd,
+ 0xe, 0xf, 0x10, 0x10, 0x10,
+ },
+ .l2_block_sz = {
+ 0x0, 0x2, 0x4, 0x6, 0x8,
+ 0xa, 0xc, 0xe, 0x10, 0x12,
+ },
+ .zlx_nr = IPU7_PS_ZLX_FW_WR_NUM,
+ .zlx_axi_pool = { 0x00000f20 },
+ .zlx_en = { 0, 1, 1, 0, 0, 0, 0, 0, 0, 0 },
+ .zlx_conf = { 0x0, 0x00010101, 0x00010101 },
+ .uao_p_num = IPU7_PS_UAO_FW_WR_PLANENUM,
+ .uao_p2tlb = { 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c },
+ },
+ {
+ .offset = IPU7_PS_MMU_SRT_RD_OFFSET,
+ .zlx_offset = IPU7_PS_ZLX_DATA_RD_OFFSET,
+ .uao_offset = IPU7_PS_UAO_SRT_RD_OFFSET,
+ .info_bits = 0x20004701,
+ .refill = 0x00002120,
+ .collapse_en_bitmap = 0x0,
+ .l1_block = IPU7_PS_MMU_SRT_RD_L1_BLOCKNR_REG,
+ .l2_block = IPU7_PS_MMU_SRT_RD_L2_BLOCKNR_REG,
+ .nr_l1streams = IPU7_PS_MMU_SRT_RD_STREAM_NUM,
+ .nr_l2streams = IPU7_PS_MMU_SRT_RD_STREAM_NUM,
+ .l1_block_sz = {
+ 0x0, 0x4, 0x6, 0x8, 0xb,
+ 0xd, 0xf, 0x11, 0x13, 0x15,
+ 0x17, 0x23, 0x2b, 0x37, 0x3f,
+ 0x41, 0x43, 0x44, 0x45, 0x46,
+ 0x47, 0x48, 0x49, 0x4a, 0x4b,
+ 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
+ 0x51, 0x52, 0x53, 0x55, 0x57,
+ 0x59, 0x5b, 0x5d, 0x5f, 0x61,
+ },
+ .l2_block_sz = {
+ 0x0, 0x2, 0x4, 0x6, 0x8,
+ 0xa, 0xc, 0xe, 0x10, 0x12,
+ 0x14, 0x16, 0x18, 0x1a, 0x1c,
+ 0x1e, 0x20, 0x22, 0x24, 0x26,
+ 0x28, 0x2a, 0x2c, 0x2e, 0x30,
+ 0x32, 0x34, 0x36, 0x38, 0x3a,
+ 0x3c, 0x3e, 0x40, 0x42, 0x44,
+ 0x46, 0x48, 0x4a, 0x4c, 0x4e,
+ },
+ .zlx_nr = IPU7_PS_ZLX_DATA_RD_NUM,
+ .zlx_axi_pool = { 0x00000f30 },
+ .zlx_en = {
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ },
+ .zlx_conf = {
+ 0x00030303,
+ 0x00010101,
+ 0x00010101,
+ 0x00030202,
+ 0x00010101,
+ 0x00010101,
+ 0x00010101,
+ 0x00030800,
+ 0x00030500,
+ 0x00020101,
+ 0x00042000,
+ 0x00031000,
+ 0x00042000,
+ 0x00031000,
+ 0x00020400,
+ 0x00010101,
+ },
+ .uao_p_num = IPU7_PS_UAO_SRT_RD_PLANENUM,
+ .uao_p2tlb = {
+ 0x00000022,
+ 0x00000023,
+ 0x00000024,
+ 0x00000025,
+ 0x00000026,
+ 0x00000027,
+ 0x00000028,
+ 0x00000029,
+ 0x0000002a,
+ 0x0000002b,
+ 0x0000002c,
+ 0x0000002d,
+ 0x0000002e,
+ 0x0000002f,
+ 0x00000030,
+ 0x00000031,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0000001e,
+ 0x0000001f,
+ 0x00000020,
+ 0x00000021,
+ 0x00000032,
+ 0x00000033,
+ 0x00000034,
+ 0x00000035,
+ },
+ },
+ {
+ .offset = IPU7_PS_MMU_SRT_WR_OFFSET,
+ .zlx_offset = IPU7_PS_ZLX_DATA_WR_OFFSET,
+ .uao_offset = IPU7_PS_UAO_SRT_WR_OFFSET,
+ .info_bits = 0x20004501,
+ .refill = 0x00002120,
+ .collapse_en_bitmap = 0x0,
+ .l1_block = IPU7_PS_MMU_SRT_WR_L1_BLOCKNR_REG,
+ .l2_block = IPU7_PS_MMU_SRT_WR_L2_BLOCKNR_REG,
+ .nr_l1streams = IPU7_PS_MMU_SRT_WR_STREAM_NUM,
+ .nr_l2streams = IPU7_PS_MMU_SRT_WR_STREAM_NUM,
+ .l1_block_sz = {
+ 0x0, 0x2, 0x6, 0xa, 0xc,
+ 0xe, 0x10, 0x12, 0x14, 0x16,
+ 0x18, 0x1a, 0x1c, 0x1e, 0x20,
+ 0x22, 0x24, 0x26, 0x32, 0x3a,
+ 0x3c, 0x3e, 0x4a, 0x52, 0x58,
+ 0x64, 0x6c, 0x72, 0x7e, 0x86,
+ 0x8c, 0x8d, 0x8e, 0x8f, 0x90,
+ 0x91, 0x92, 0x94, 0x96, 0x98,
+ },
+ .l2_block_sz = {
+ 0x0, 0x2, 0x4, 0x6, 0x8,
+ 0xa, 0xc, 0xe, 0x10, 0x12,
+ 0x14, 0x16, 0x18, 0x1a, 0x1c,
+ 0x1e, 0x20, 0x22, 0x24, 0x26,
+ 0x28, 0x2a, 0x2c, 0x2e, 0x30,
+ 0x32, 0x34, 0x36, 0x38, 0x3a,
+ 0x3c, 0x3e, 0x40, 0x42, 0x44,
+ 0x46, 0x48, 0x4a, 0x4c, 0x4e,
+ },
+ .zlx_nr = IPU7_PS_ZLX_DATA_WR_NUM,
+ .zlx_axi_pool = { 0x00000f50 },
+ .zlx_en = {
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 0, 0,
+ },
+ .zlx_conf = {
+ 0x00010102,
+ 0x00030103,
+ 0x00030103,
+ 0x00010101,
+ 0x00010101,
+ 0x00030101,
+ 0x00010101,
+ 0x38010101,
+ 0x0,
+ 0x0,
+ 0x38010101,
+ 0x38010101,
+ 0x38010101,
+ 0x38010101,
+ 0x38010101,
+ 0x38010101,
+ 0x00010101,
+ 0x00042000,
+ 0x00031000,
+ 0x00010101,
+ 0x00010101,
+ 0x00042000,
+ 0x00031000,
+ 0x00031000,
+ 0x00042000,
+ 0x00031000,
+ 0x00031000,
+ 0x00042000,
+ 0x00031000,
+ 0x00031000,
+ 0x0,
+ 0x0,
+ },
+ .uao_p_num = IPU7_PS_UAO_SRT_WR_PLANENUM,
+ .uao_p2tlb = {
+ 0x00000000,
+ 0x00000001,
+ 0x00000002,
+ 0x00000003,
+ 0x00000004,
+ 0x00000005,
+ 0x00000006,
+ 0x00000007,
+ 0x00000008,
+ 0x00000009,
+ 0x0000000a,
+ 0x0000000b,
+ 0x0000000c,
+ 0x0000000d,
+ 0x0000000e,
+ 0x0000000f,
+ 0x00000010,
+ 0x00000011,
+ 0x00000012,
+ 0x00000013,
+ 0x00000014,
+ 0x00000015,
+ 0x00000016,
+ 0x00000017,
+ 0x00000018,
+ 0x00000019,
+ 0x0000001a,
+ 0x0000001b,
+ 0x0000001c,
+ 0x0000001d,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0000001e,
+ 0x0000001f,
+ 0x00000020,
+ 0x00000021,
+ },
+ },
+};
+
+static const struct ipu7_mmu_hwdata ipu7_mmu_hwdata_lookup[IPU_SUBSYS_NUM] = {
+ [IPU_PSYS] = {
+ .hwdata = ipu7_psys_mmu_hwdata,
+ .nr_mmus = ARRAY_SIZE(ipu7_psys_mmu_hwdata),
+ },
+ [IPU_ISYS] = {
+ .hwdata = ipu7_isys_mmu_hwdata,
+ .nr_mmus = ARRAY_SIZE(ipu7_isys_mmu_hwdata),
+ },
+};
+
+static void __ipu7_tlb_invalidate(struct ipu6_mmu *mmu)
+{
+ struct ipu7_mmu_hw *mmu_hw = mmu->ipu7_mmu_hw;
+ unsigned long flags;
+ unsigned int i;
+ int ret;
+ u32 val;
+
+ spin_lock_irqsave(&mmu->ready_lock, flags);
+ if (!mmu->ready) {
+ spin_unlock_irqrestore(&mmu->ready_lock, flags);
+ return;
+ }
+
+ for (i = 0; i < mmu->nr_mmus; i++) {
+ writel(0xffffffffU, mmu_hw[i].base +
+ IPU7_MMU_REG_INVALIDATE_0);
+
+ /* Need check with HW, use l1streams or l2streams */
+ if (mmu_hw[i].nr_l2streams > 32)
+ writel(0xffffffffU, mmu_hw[i].base +
+ IPU7_MMU_REG_INVALIDATE_1);
+
+ /*
+ * The TLB invalidation is a "single cycle" (IOMMU clock cycles)
+ * When the actual MMIO write reaches the IPU TLB Invalidate
+ * register, wmb() will force the TLB invalidate out if the CPU
+ * attempts to update the IOMMU page table (or sooner).
+ */
+ wmb();
+
+ /* wait invalidation done */
+ ret = readl_poll_timeout_atomic(mmu_hw[i].base +
+ IPU7_MMU_REG_INVALIDATION_STATUS,
+ val, !(val & 0x1U), 500,
+ IPU7_MMU_TLB_INVALIDATE_TIMEOUT);
+ if (ret)
+ dev_err(mmu->dev, "MMU[%u] TLB invalidate failed\n", i);
+ }
+
+ spin_unlock_irqrestore(&mmu->ready_lock, flags);
+}
+
+static int __ipu7_mmu_hw_init(struct ipu6_mmu *mmu)
+{
+ struct ipu6_mmu_info *mmu_info;
+ struct ipu7_mmu_hw *mmu_hw = mmu->ipu7_mmu_hw;
+ unsigned int i, j;
+
+ mmu_info = mmu->dmap->mmu_info;
+ for (i = 0; i < mmu->nr_mmus; i++) {
+ /* Write page table address per MMU */
+ writel((phys_addr_t)mmu_info->l1_pt_dma,
+ mmu_hw[i].base + IPU7_MMU_REG_PAGE_TABLE_BASE_ADDR);
+
+ /* Set info bits and axi_refill per MMU */
+ writel(mmu_hw[i].info_bits,
+ mmu_hw[i].base + IPU7_MMU_REG_USER_INFO_BITS);
+ writel(mmu_hw[i].refill, mmu_hw[i].base + IPU7_MMU_REG_AXI_REFILL_IF_ID);
+ writel(mmu_hw[i].collapse_en_bitmap,
+ mmu_hw[i].base + IPU7_MMU_REG_COLLAPSE_ENABLE_BITMAP);
+
+ if (mmu_hw[i].at_sp_arb_cfg)
+ writel(mmu_hw[i].at_sp_arb_cfg,
+ mmu_hw[i].base + IPU7_MMU_REG_AT_SP_ARB_CFG);
+
+ /* Default irq configuration */
+ writel(0x3ff, mmu_hw[i].base + IPU7_MMU_REG_IRQ_MASK);
+ writel(0x3ff, mmu_hw[i].base + IPU7_MMU_REG_IRQ_ENABLE);
+
+ /* Configure MMU TLB stream configuration for L1/L2 */
+ for (j = 0; j < mmu_hw[i].nr_l1streams; j++) {
+ writel(mmu_hw[i].l1_block_sz[j], mmu_hw[i].base +
+ mmu_hw[i].l1_block + 4U * j);
+ }
+
+ for (j = 0; j < mmu_hw[i].nr_l2streams; j++) {
+ writel(mmu_hw[i].l2_block_sz[j], mmu_hw[i].base +
+ mmu_hw[i].l2_block + 4U * j);
+ }
+
+ for (j = 0; j < mmu_hw[i].uao_p_num; j++) {
+ if (!mmu_hw[i].uao_p2tlb[j])
+ continue;
+ writel(mmu_hw[i].uao_p2tlb[j], mmu_hw[i].uao_base + 4U * j);
+ }
+ }
+
+ for (i = 0; i < mmu->nr_mmus; i++) {
+ for (j = 0; j < IPU7_ZLX_POOL_NUM; j++) {
+ if (!mmu_hw[i].zlx_axi_pool[j])
+ continue;
+ writel(mmu_hw[i].zlx_axi_pool[j],
+ mmu_hw[i].zlx_base + IPU7_ZLX_REG_AXI_POOL + j * 0x4U);
+ }
+
+ for (j = 0; j < mmu_hw[i].zlx_nr; j++) {
+ if (!mmu_hw[i].zlx_conf[j])
+ continue;
+
+ writel(mmu_hw[i].zlx_conf[j],
+ mmu_hw[i].zlx_base + IPU7_ZLX_REG_CONF + j * 0x8U);
+ }
+
+ for (j = 0; j < mmu_hw[i].zlx_nr; j++) {
+ if (!mmu_hw[i].zlx_en[j])
+ continue;
+
+ writel(mmu_hw[i].zlx_en[j],
+ mmu_hw[i].zlx_base + IPU7_ZLX_REG_EN + j * 0x8U);
+ }
+ }
+
+ return 0;
+}
+
+static int __ipu7_mmu_init_hw_data(struct ipu6_mmu *mmu, struct device *dev,
+ void __iomem *base)
+{
+ const struct ipu7_mmu_hwdata *lookup = ipu7_mmu_hwdata_lookup;
+ struct ipu7_mmu_hw *mmu_hw, *src;
+ unsigned int i, nr_mmus;
+
+ if (mmu->mmid >= IPU_SUBSYS_NUM)
+ return -EINVAL;
+
+ src = lookup[mmu->mmid].hwdata;
+ nr_mmus = lookup[mmu->mmid].nr_mmus;
+
+ mmu_hw = devm_kcalloc(dev, nr_mmus, sizeof(*mmu_hw), GFP_KERNEL);
+ if (!mmu_hw)
+ return -ENOMEM;
+
+ for (i = 0; i < nr_mmus; i++) {
+ if (src[i].nr_l1streams > IPU7_MMU_MAX_TLB_L1_STREAMS ||
+ src[i].nr_l2streams > IPU7_MMU_MAX_TLB_L2_STREAMS)
+ return -EINVAL;
+
+ mmu_hw[i] = src[i];
+ mmu_hw[i].base = base + src[i].offset;
+ mmu_hw[i].zlx_base = base + src[i].zlx_offset;
+ mmu_hw[i].uao_base = base + src[i].uao_offset;
+ }
+
+ mmu->nr_mmus = nr_mmus;
+ mmu->ipu7_mmu_hw = mmu_hw;
+
+ return 0;
+}
+
+const struct ipu6_mmu_hw_ops ipu7_mmu_ops = {
+ .init_hw_data = __ipu7_mmu_init_hw_data,
+ .hw_init = __ipu7_mmu_hw_init,
+ .tlb_invalidate = __ipu7_tlb_invalidate,
+};
diff --git a/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h
new file mode 100644
index 000000000000..68663057138a
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h
@@ -0,0 +1,155 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2026 Intel Corporation */
+
+#ifndef IPU7_MMU_HW_H
+#define IPU7_MMU_HW_H
+
+#define IPU7_MMU_REG_IRQ_MASK 0x2c
+#define IPU7_MMU_REG_IRQ_ENABLE 0x30
+#define IPU7_MMU_REG_PAGE_TABLE_BASE_ADDR 0x08
+#define IPU7_MMU_REG_USER_INFO_BITS 0x0c
+#define IPU7_MMU_REG_AXI_REFILL_IF_ID 0x10
+#define IPU7_MMU_REG_COLLAPSE_ENABLE_BITMAP 0x18
+#define IPU7_MMU_REG_AT_SP_ARB_CFG 0x20
+
+#define IPU7_ZLX_REG_AXI_POOL 0x0
+#define IPU7_ZLX_REG_EN 0x20
+#define IPU7_ZLX_REG_CONF 0x24
+#define IPU7_ZLX_POOL_NUM 8U
+
+#define IPU7_MMU_MAX_TLB_L1_STREAMS 40U
+#define IPU7_MMU_MAX_TLB_L2_STREAMS 40U
+#define IPU7_UAO_PLANE_MAX_NUM 64U
+#define IPU7_ZLX_MAX_NUM 32U
+
+#define IPU7_MMU_REG_INVALIDATE_0 0x00
+#define IPU7_MMU_REG_INVALIDATE_1 0x04
+#define IPU7_MMU_REG_INVALIDATION_STATUS 0x24
+#define IPU7_MMU_TLB_INVALIDATE_TIMEOUT 2000
+
+#define IPU7_FW_CODE_REGION_SIZE 0x1000000 /* 16MB */
+#define IPU7_FW_CODE_REGION_START 0x4000000 /* 64MB */
+#define IPU7_FW_CODE_REGION_END (IPU7_FW_CODE_REGION_START + \
+ IPU7_FW_CODE_REGION_SIZE) /* 80MB */
+
+#define IPU7_IS_MMU_FW_RD_OFFSET 0x274000
+#define IPU7_IS_MMU_FW_RD_STREAM_NUM 3
+#define IPU7_IS_MMU_FW_RD_L1_BLOCKNR_REG 0x54
+#define IPU7_IS_MMU_FW_RD_L2_BLOCKNR_REG 0x60
+
+#define IPU7_IS_MMU_FW_WR_OFFSET 0x275000
+#define IPU7_IS_MMU_FW_WR_STREAM_NUM 3
+#define IPU7_IS_MMU_FW_WR_L1_BLOCKNR_REG 0x54
+#define IPU7_IS_MMU_FW_WR_L2_BLOCKNR_REG 0x60
+
+#define IPU7_IS_MMU_M0_OFFSET 0x276000
+#define IPU7_IS_MMU_M0_STREAM_NUM 8
+#define IPU7_IS_MMU_M0_L1_BLOCKNR_REG 0x54
+#define IPU7_IS_MMU_M0_L2_BLOCKNR_REG 0x74
+
+#define IPU7_IS_MMU_M1_OFFSET 0x277000
+#define IPU7_IS_MMU_M1_STREAM_NUM 16
+#define IPU7_IS_MMU_M1_L1_BLOCKNR_REG 0x54
+#define IPU7_IS_MMU_M1_L2_BLOCKNR_REG 0x94
+
+#define IPU7_PS_MMU_FW_RD_OFFSET 0x148000
+#define IPU7_PS_MMU_FW_RD_STREAM_NUM 20
+#define IPU7_PS_MMU_FW_RD_L1_BLOCKNR_REG 0x54
+#define IPU7_PS_MMU_FW_RD_L2_BLOCKNR_REG 0xa4
+
+#define IPU7_PS_MMU_FW_WR_OFFSET 0x149000
+#define IPU7_PS_MMU_FW_WR_STREAM_NUM 10
+#define IPU7_PS_MMU_FW_WR_L1_BLOCKNR_REG 0x54
+#define IPU7_PS_MMU_FW_WR_L2_BLOCKNR_REG 0x7c
+
+#define IPU7_PS_MMU_SRT_RD_OFFSET 0x14a000
+#define IPU7_PS_MMU_SRT_RD_STREAM_NUM 40
+#define IPU7_PS_MMU_SRT_RD_L1_BLOCKNR_REG 0x54
+#define IPU7_PS_MMU_SRT_RD_L2_BLOCKNR_REG 0xf4
+
+#define IPU7_PS_MMU_SRT_WR_OFFSET 0x14b000
+#define IPU7_PS_MMU_SRT_WR_STREAM_NUM 40
+#define IPU7_PS_MMU_SRT_WR_L1_BLOCKNR_REG 0x54
+#define IPU7_PS_MMU_SRT_WR_L2_BLOCKNR_REG 0xf4
+
+#define IPU7_IS_UAO_UC_RD_OFFSET 0x27c000
+#define IPU7_IS_UAO_UC_RD_PLANENUM 4
+
+#define IPU7_IS_UAO_UC_WR_OFFSET 0x27d000
+#define IPU7_IS_UAO_UC_WR_PLANENUM 4
+
+#define IPU7_IS_UAO_M0_WR_OFFSET 0x27e000
+#define IPU7_IS_UAO_M0_WR_PLANENUM 8
+
+#define IPU7_IS_UAO_M1_WR_OFFSET 0x27f000
+#define IPU7_IS_UAO_M1_WR_PLANENUM 16
+
+#define IPU7_PS_UAO_FW_RD_OFFSET 0x156000
+#define IPU7_PS_UAO_FW_RD_PLANENUM 20
+
+#define IPU7_PS_UAO_FW_WR_OFFSET 0x157000
+#define IPU7_PS_UAO_FW_WR_PLANENUM 16
+
+#define IPU7_PS_UAO_SRT_RD_OFFSET 0x154000
+#define IPU7_PS_UAO_SRT_RD_PLANENUM 40
+
+#define IPU7_PS_UAO_SRT_WR_OFFSET 0x155000
+#define IPU7_PS_UAO_SRT_WR_PLANENUM 40
+
+#define IPU7_IS_ZLX_UC_RD_OFFSET 0x278000
+#define IPU7_IS_ZLX_UC_WR_OFFSET 0x279000
+#define IPU7_IS_ZLX_M0_OFFSET 0x27a000
+#define IPU7_IS_ZLX_M1_OFFSET 0x27b000
+#define IPU7_IS_ZLX_UC_RD_NUM 4
+#define IPU7_IS_ZLX_UC_WR_NUM 4
+#define IPU7_IS_ZLX_M0_NUM 8
+#define IPU7_IS_ZLX_M1_NUM 16
+
+#define IPU7_PS_ZLX_DATA_RD_OFFSET 0x14e000
+#define IPU7_PS_ZLX_DATA_WR_OFFSET 0x14f000
+#define IPU7_PS_ZLX_FW_RD_OFFSET 0x150000
+#define IPU7_PS_ZLX_FW_WR_OFFSET 0x151000
+#define IPU7_PS_ZLX_DATA_RD_NUM 32
+#define IPU7_PS_ZLX_DATA_WR_NUM 32
+#define IPU7_PS_ZLX_FW_RD_NUM 16
+#define IPU7_PS_ZLX_FW_WR_NUM 10
+
+struct ipu7_mmu_hw {
+ char name[32];
+
+ void __iomem *base;
+ void __iomem *zlx_base;
+ void __iomem *uao_base;
+
+ u32 offset;
+ u32 zlx_offset;
+ u32 uao_offset;
+
+ u32 info_bits;
+ u32 refill;
+ u32 collapse_en_bitmap;
+ u32 at_sp_arb_cfg;
+
+ u32 l1_block;
+ u32 l2_block;
+
+ u8 nr_l1streams;
+ u8 nr_l2streams;
+ u32 l1_block_sz[IPU7_MMU_MAX_TLB_L1_STREAMS];
+ u32 l2_block_sz[IPU7_MMU_MAX_TLB_L2_STREAMS];
+
+ u8 zlx_nr;
+ u32 zlx_axi_pool[IPU7_ZLX_POOL_NUM];
+ u32 zlx_en[IPU7_ZLX_MAX_NUM];
+ u32 zlx_conf[IPU7_ZLX_MAX_NUM];
+
+ u32 uao_p_num;
+ u32 uao_p2tlb[IPU7_UAO_PLANE_MAX_NUM];
+};
+
+struct ipu7_mmu_hwdata {
+ struct ipu7_mmu_hw *hwdata;
+ unsigned int nr_mmus;
+};
+
+#endif
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 15/44] media: ipu6: Add ipu7 cpd handling
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (13 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 14/44] media: ipu6: Add ipu7 mmu support Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 16/44] media: ipu6: Add check for pkg_dir before freeing Antti Laakso
` (28 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The firmware format differs slightly between ipu6 and ipu7.
Add support for ipu7 firmware validation and handling.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-cpd.c | 169 +++++++++++++++++++++---
drivers/media/pci/intel/ipu6/ipu6-cpd.h | 43 ++++++
2 files changed, 197 insertions(+), 15 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-cpd.c b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
index 966a16a300f8..8e59406a725c 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-cpd.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
@@ -16,6 +16,7 @@
#include "ipu6-bus.h"
#include "ipu6-cpd.h"
#include "ipu6-dma.h"
+#include "ipu7-mmu-hw.h"
/* 15 entries + header*/
#define MAX_PKG_DIR_ENT_CNT 16
@@ -62,6 +63,20 @@ static inline const struct ipu6_cpd_ent *ipu6_cpd_get_entry(const void *cpd,
#define ipu6_cpd_get_metadata(cpd) ipu6_cpd_get_entry(cpd, METADATA_IDX)
#define ipu6_cpd_get_moduledata(cpd) ipu6_cpd_get_entry(cpd, MODULEDATA_IDX)
+#define IPU7_CPD_BINARY_START_IDX 1U
+#define IPU7_CPD_METADATA_START_IDX 2U
+#define IPU7_CPD_BINARY_NUM 2U /* ISYS + PSYS */
+#define IPU7_CPD_METADATA_ATTR 0xa
+#define IPU7_CPD_METADATA_IPL 0x1c
+/*
+ * Entries include:
+ * 1 manifest entry.
+ * 1 metadata entry for each sub system(ISYS and PSYS).
+ * 1 binary entry for each sub system(ISYS and PSYS).
+ */
+#define IPU7_CPD_ENTRY_NUM (IPU7_CPD_BINARY_NUM * 2U + 1U)
+#define IPU7_MAX_MANIFEST_SIZE (SZ_4K * sizeof(u32))
+
static const struct ipu6_cpd_metadata_cmpnt_hdr *
ipu6_cpd_metadata_get_cmpnt(struct ipu6_device *isp, const void *metadata,
unsigned int metadata_size, u8 idx)
@@ -309,39 +324,163 @@ static int ipu6_cpd_validate_metadata(struct ipu6_device *isp,
return 0;
}
-int ipu6_cpd_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
- unsigned long cpd_file_size)
+static struct ipu7_cpd_metadata *ipu7_cpd_get_metadata(const void *cpd, int idx)
{
- const struct ipu6_cpd_hdr *hdr = cpd_file;
- const struct ipu6_cpd_ent *ent;
- int ret;
+ const struct ipu6_cpd_ent *cpd_ent =
+ ipu6_cpd_get_entry(cpd, IPU7_CPD_METADATA_START_IDX + idx * 2);
- ret = ipu6_cpd_validate_cpd(isp, cpd_file, cpd_file_size,
- cpd_file_size);
- if (ret)
- return ret;
+ return (struct ipu7_cpd_metadata *)((u8 *)cpd + cpd_ent->offset);
+}
- /* Check for CPD file marker */
- if (hdr->hdr_mark != CPD_HDR_MARK) {
- dev_err(&isp->pdev->dev, "Invalid CPD header\n");
+static int ipu7_cpd_validate_metadata(struct ipu6_device *isp,
+ const void *cpd, int idx)
+{
+ const struct ipu6_cpd_ent *cpd_ent =
+ ipu6_cpd_get_entry(cpd, IPU7_CPD_METADATA_START_IDX + idx * 2);
+ const struct ipu6_cpd_ent *bin_ent =
+ ipu6_cpd_get_entry(cpd, IPU7_CPD_BINARY_START_IDX + idx * 2);
+ const struct ipu7_cpd_metadata *metadata =
+ ipu7_cpd_get_metadata(cpd, idx);
+ struct device *dev = &isp->pdev->dev;
+ u32 offset;
+
+ /* Sanity check for metadata size */
+ if (cpd_ent->len != sizeof(struct ipu7_cpd_metadata)) {
+ dev_err(dev, "Invalid metadata size\n");
+ return -EINVAL;
+ }
+
+ /* Validate type and length of metadata sections */
+ if (metadata->attr.hdr.type != IPU7_CPD_METADATA_ATTR) {
+ dev_err(dev, "Invalid metadata attr type (%d)\n",
+ metadata->attr.hdr.type);
return -EINVAL;
}
+ if (metadata->attr.hdr.len != sizeof(struct ipu7_cpd_metadata_attr)) {
+ dev_err(dev, "Invalid metadata attr size (%d)\n",
+ metadata->attr.hdr.len);
+ return -EINVAL;
+ }
+ if (metadata->ipl.hdr.type != IPU7_CPD_METADATA_IPL) {
+ dev_err(dev, "Invalid metadata ipl type (%d)\n",
+ metadata->ipl.hdr.type);
+ return -EINVAL;
+ }
+ if (metadata->ipl.hdr.len != sizeof(struct ipu7_cpd_metadata_ipl)) {
+ dev_err(dev, "Invalid metadata ipl size (%d)\n",
+ metadata->ipl.hdr.len);
+ return -EINVAL;
+ }
+
+ offset = metadata->ipl.param[0];
+ if (offset > IPU7_FW_CODE_REGION_SIZE ||
+ bin_ent->len > IPU7_FW_CODE_REGION_SIZE - offset) {
+ dev_err(dev, "Incorrect binary size %u and offset %u\n",
+ bin_ent->len, offset);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int __ipu7_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
+ unsigned long cpd_file_size)
+{
+ const struct ipu6_cpd_ent *ent;
+ const struct ipu7_cpd_hdr *hdr = cpd_file;
+ unsigned int i;
- /* Sanity check for manifest size */
ent = ipu6_cpd_get_manifest(cpd_file);
- if (ent->len > MAX_MANIFEST_SIZE) {
+ if (ent->len > IPU7_MAX_MANIFEST_SIZE) {
dev_err(&isp->pdev->dev, "Invalid CPD manifest size\n");
return -EINVAL;
}
+ /* Sanity check for CPD entry header */
+ if (hdr->ent_cnt != IPU7_CPD_ENTRY_NUM) {
+ dev_err(&isp->pdev->dev, "Invalid CPD entry number %d\n",
+ hdr->ent_cnt);
+ return -EINVAL;
+ }
/* Validate metadata */
+ for (i = 0; i < IPU7_CPD_BINARY_NUM; i++) {
+ int ret = ipu7_cpd_validate_metadata(isp, cpd_file, i);
+
+ if (ret) {
+ dev_err(&isp->pdev->dev, "Invalid metadata(%d)\n", i);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int __ipu6_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
+ unsigned long cpd_file_size)
+{
+ const struct ipu6_cpd_ent *ent;
+ int ret;
+
+ ent = ipu6_cpd_get_manifest(cpd_file);
+ if (ent->len > MAX_MANIFEST_SIZE) {
+ dev_err(&isp->pdev->dev, "Invalid CPD manifest size\n");
+ return -EINVAL;
+ }
+
ent = ipu6_cpd_get_metadata(cpd_file);
ret = ipu6_cpd_validate_metadata(isp, cpd_file + ent->offset, ent->len);
if (ret)
return ret;
- /* Validate moduledata */
ent = ipu6_cpd_get_moduledata(cpd_file);
return ipu6_cpd_validate_moduledata(isp, cpd_file + ent->offset,
ent->len);
}
+
+int ipu6_cpd_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
+ unsigned long cpd_file_size)
+{
+ const struct ipu6_cpd_hdr *hdr = cpd_file;
+ int ret;
+
+ ret = ipu6_cpd_validate_cpd(isp, cpd_file, cpd_file_size,
+ cpd_file_size);
+ if (ret)
+ return ret;
+
+ /* Check for CPD file marker */
+ if (hdr->hdr_mark != CPD_HDR_MARK) {
+ dev_err(&isp->pdev->dev, "Invalid CPD header\n");
+ return -EINVAL;
+ }
+
+ if (IS_IPU7(isp))
+ return __ipu7_validate_cpd_file(isp, cpd_file, cpd_file_size);
+
+ return __ipu6_validate_cpd_file(isp, cpd_file, cpd_file_size);
+}
+
+int ipu7_cpd_copy_binary(const void *cpd, const char *name, void *dst,
+ u32 *entry)
+{
+ unsigned int i;
+
+ for (i = 0; i < IPU7_CPD_BINARY_NUM; i++) {
+ const struct ipu7_cpd_metadata *metadata;
+ u8 idx = IPU7_CPD_BINARY_START_IDX + i * 2U;
+ const struct ipu6_cpd_ent *ent =
+ ipu6_cpd_get_entry(cpd, idx);
+
+ if (strncmp(ent->name, name, sizeof(ent->name)))
+ continue;
+
+ metadata = ipu7_cpd_get_metadata(cpd, i);
+ memcpy(dst + metadata->ipl.param[0], cpd + ent->offset,
+ ent->len);
+ *entry = metadata->ipl.param[2];
+
+ return 0;
+ }
+
+ return -ENOENT;
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_cpd_copy_binary, "INTEL_IPU6");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-cpd.h b/drivers/media/pci/intel/ipu6/ipu6-cpd.h
index e0e4fdeca902..b614ed0004bb 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-cpd.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-cpd.h
@@ -98,8 +98,51 @@ struct ipu6_cpd_client_pkg_hdr {
u32 prog_bin_size;
} __packed;
+/* IPU7 */
+
+struct ipu7_cpd_hdr {
+ u32 hdr_mark;
+ u32 ent_cnt;
+ u8 hdr_ver;
+ u8 ent_ver;
+ u8 hdr_len;
+ u8 rsvd;
+ u8 partition_name[4];
+ u32 crc32;
+} __packed;
+
+struct ipu7_cpd_metadata_hdr {
+ u32 type;
+ u32 len;
+} __packed;
+
+struct ipu7_cpd_metadata_attr {
+ struct ipu7_cpd_metadata_hdr hdr;
+ u8 compression_type;
+ u8 encryption_type;
+ u8 rsvd[2];
+ u32 uncompressed_size;
+ u32 compressed_size;
+ u32 module_id;
+ u8 hash[48];
+} __packed;
+
+struct ipu7_cpd_metadata_ipl {
+ struct ipu7_cpd_metadata_hdr hdr;
+ u32 param[4];
+ u8 rsvd[8];
+} __packed;
+
+struct ipu7_cpd_metadata {
+ struct ipu7_cpd_metadata_attr attr;
+ struct ipu7_cpd_metadata_ipl ipl;
+} __packed;
+
int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src);
void ipu6_cpd_free_pkg_dir(struct ipu6_bus_device *adev);
int ipu6_cpd_validate_cpd_file(struct ipu6_device *isp, const void *cpd_file,
unsigned long cpd_file_size);
+int ipu7_cpd_copy_binary(const void *cpd, const char *name, void *dst,
+ u32 *entry);
+
#endif /* IPU6_CPD_H */
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 16/44] media: ipu6: Add check for pkg_dir before freeing
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (14 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 15/44] media: ipu6: Add ipu7 cpd handling Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 17/44] media: ipu6: Rename isys fw msg union Antti Laakso
` (27 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
We are adding support for mapping ipu7 firmware which doesn't have
pkg_dir.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-cpd.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-cpd.c b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
index 8e59406a725c..564461e0bb62 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-cpd.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
@@ -235,8 +235,9 @@ EXPORT_SYMBOL_NS_GPL(ipu6_cpd_create_pkg_dir, "INTEL_IPU6");
void ipu6_cpd_free_pkg_dir(struct ipu6_bus_device *adev)
{
- ipu6_dma_free(adev, adev->pkg_dir_size, adev->pkg_dir,
- adev->pkg_dir_dma_addr, 0);
+ if (adev->pkg_dir)
+ ipu6_dma_free(adev, adev->pkg_dir_size, adev->pkg_dir,
+ adev->pkg_dir_dma_addr, 0);
}
EXPORT_SYMBOL_NS_GPL(ipu6_cpd_free_pkg_dir, "INTEL_IPU6");
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 17/44] media: ipu6: Rename isys fw msg union
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (15 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 16/44] media: ipu6: Add check for pkg_dir before freeing Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 18/44] media: ipu6: Move isys isr handlers to fw file Antti Laakso
` (26 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
Later we need to abstract ipu7 firmware abi structs same way
we have it now for ipu6. Renaming union per ipu helps to make
the split more clear.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-isys-queue.c | 4 ++--
drivers/media/pci/intel/ipu6/ipu6-isys-video.c | 4 ++--
drivers/media/pci/intel/ipu6/ipu6-isys.c | 4 ++--
drivers/media/pci/intel/ipu6/ipu6-isys.h | 2 +-
4 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
index fabaed63df0c..529973860e9e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
@@ -316,7 +316,7 @@ static int ipu6_isys_stream_start(struct ipu6_isys_video *av,
if (!msg)
return -ENOMEM;
- buf = &msg->fw_msg.frame;
+ buf = &msg->ipu6.frame;
ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);
ipu6_fw_isys_dump_frame_buff_set(dev, buf,
stream->nr_output_pins);
@@ -396,7 +396,7 @@ static void buf_queue(struct vb2_buffer *vb)
goto out;
}
- buf = &msg->fw_msg.frame;
+ buf = &msg->ipu6.frame;
ipu6_isys_buf_to_fw_frame_buf(buf, stream, &bl);
ipu6_fw_isys_dump_frame_buff_set(dev, buf, stream->nr_output_pins);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index 89eb265737d7..c925386a1e98 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -533,7 +533,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
if (!msg)
return -ENOMEM;
- stream_cfg = &msg->fw_msg.stream;
+ stream_cfg = &msg->ipu6.stream;
stream_cfg->src = stream->stream_source;
stream_cfg->vc = stream->vc;
stream_cfg->isl_use = 0;
@@ -590,7 +590,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
ret = -ENOMEM;
goto out_put_stream_opened;
}
- buf = &msg->fw_msg.frame;
+ buf = &msg->ipu6.frame;
ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);
ipu6_isys_buffer_list_queue(bl,
IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 8af891081bd3..8f2d361b89f6 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -1003,7 +1003,7 @@ struct isys_fw_msgs *ipu6_get_fw_msg_buf(struct ipu6_isys_stream *stream)
msg = list_last_entry(&isys->framebuflist, struct isys_fw_msgs, head);
list_move(&msg->head, &isys->framebuflist_fw);
spin_unlock_irqrestore(&isys->listlock, flags);
- memset(&msg->fw_msg, 0, sizeof(msg->fw_msg));
+ memset(&msg->ipu6, 0, sizeof(msg->ipu6));
return msg;
}
@@ -1029,7 +1029,7 @@ void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, uintptr_t data)
return;
spin_lock_irqsave(&isys->listlock, flags);
- msg = container_of(ptr, struct isys_fw_msgs, fw_msg.dummy);
+ msg = container_of(ptr, struct isys_fw_msgs, ipu6.dummy);
list_move(&msg->head, &isys->framebuflist);
spin_unlock_irqrestore(&isys->listlock, flags);
}
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h
index 0b139ab24431..abcd5e1cbc2c 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h
@@ -169,7 +169,7 @@ struct isys_fw_msgs {
u64 dummy;
struct ipu6_fw_isys_frame_buff_set_abi frame;
struct ipu6_fw_isys_stream_cfg_data_abi stream;
- } fw_msg;
+ } ipu6;
struct list_head head;
dma_addr_t dma_addr;
};
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 18/44] media: ipu6: Move isys isr handlers to fw file
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (16 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 17/44] media: ipu6: Rename isys fw msg union Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 19/44] media: ipu6: Move hw specific buffer handling down Antti Laakso
` (25 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The ipu7 will have its own isr handlers. Move ipu6 isr
code to hardware specific file.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-fw-isys.c | 259 +++++++++++++++++++
drivers/media/pci/intel/ipu6/ipu6-fw-isys.h | 3 +
drivers/media/pci/intel/ipu6/ipu6-isys.c | 263 +-------------------
3 files changed, 263 insertions(+), 262 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
index fc2f24c05de7..7f7125202ffd 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
@@ -487,3 +487,262 @@ ipu6_fw_isys_dump_frame_buff_set(struct device *dev,
dev_dbg(dev, "-----------------------------------------------------\n");
}
+
+struct fwmsg {
+ int type;
+ char *msg;
+ bool valid_ts;
+};
+
+static const struct fwmsg fw_msg[] = {
+ {IPU6_FW_ISYS_RESP_TYPE_STREAM_OPEN_DONE, "STREAM_OPEN_DONE", 0},
+ {IPU6_FW_ISYS_RESP_TYPE_STREAM_CLOSE_ACK, "STREAM_CLOSE_ACK", 0},
+ {IPU6_FW_ISYS_RESP_TYPE_STREAM_START_ACK, "STREAM_START_ACK", 0},
+ {IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK,
+ "STREAM_START_AND_CAPTURE_ACK", 0},
+ {IPU6_FW_ISYS_RESP_TYPE_STREAM_STOP_ACK, "STREAM_STOP_ACK", 0},
+ {IPU6_FW_ISYS_RESP_TYPE_STREAM_FLUSH_ACK, "STREAM_FLUSH_ACK", 0},
+ {IPU6_FW_ISYS_RESP_TYPE_PIN_DATA_READY, "PIN_DATA_READY", 1},
+ {IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_ACK, "STREAM_CAPTURE_ACK", 0},
+ {IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE,
+ "STREAM_START_AND_CAPTURE_DONE", 1},
+ {IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_DONE, "STREAM_CAPTURE_DONE", 1},
+ {IPU6_FW_ISYS_RESP_TYPE_FRAME_SOF, "FRAME_SOF", 1},
+ {IPU6_FW_ISYS_RESP_TYPE_FRAME_EOF, "FRAME_EOF", 1},
+ {IPU6_FW_ISYS_RESP_TYPE_STATS_DATA_READY, "STATS_READY", 1},
+ {-1, "UNKNOWN MESSAGE", 0}
+};
+
+static u32 resp_type_to_index(int type)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(fw_msg); i++)
+ if (fw_msg[i].type == type)
+ return i;
+
+ return ARRAY_SIZE(fw_msg) - 1;
+}
+
+int ipu6_isys_isr_one(struct ipu6_bus_device *adev)
+{
+ struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
+ struct ipu6_fw_isys_resp_info_abi *resp;
+ struct ipu6_isys_stream *stream;
+ struct ipu6_isys_csi2 *csi2 = NULL;
+ u32 index;
+ u64 ts;
+
+ if (!isys->fwctx)
+ return 1;
+
+ resp = ipu6_fw_isys_get_resp(isys);
+ if (!resp)
+ return 1;
+
+ ts = (u64)resp->timestamp[1] << 32 | resp->timestamp[0];
+
+ index = resp_type_to_index(resp->type);
+ dev_dbg(&adev->auxdev.dev,
+ "FW resp %02d %s, stream %u, ts 0x%16.16llx, pin %d\n",
+ resp->type, fw_msg[index].msg, resp->stream_handle,
+ fw_msg[index].valid_ts ? ts : 0, resp->pin_id);
+
+ if (resp->error_info.error == IPU6_FW_ISYS_ERROR_STREAM_IN_SUSPENSION)
+ /* Suspension is kind of special case: not enough buffers */
+ dev_dbg(&adev->auxdev.dev,
+ "FW error resp SUSPENSION, details %d\n",
+ resp->error_info.error_details);
+ else if (resp->error_info.error)
+ dev_dbg(&adev->auxdev.dev,
+ "FW error resp error %d, details %d\n",
+ resp->error_info.error, resp->error_info.error_details);
+
+ if (resp->stream_handle >= IPU6_ISYS_MAX_STREAMS) {
+ dev_err(&adev->auxdev.dev, "bad stream handle %u\n",
+ resp->stream_handle);
+ goto leave;
+ }
+
+ stream = ipu6_isys_query_stream_by_handle(isys, resp->stream_handle);
+ if (!stream) {
+ dev_err(&adev->auxdev.dev, "stream of stream_handle %u is unused\n",
+ resp->stream_handle);
+ goto leave;
+ }
+ stream->error = resp->error_info.error;
+
+ csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
+
+ switch (resp->type) {
+ case IPU6_FW_ISYS_RESP_TYPE_STREAM_OPEN_DONE:
+ complete(&stream->stream_open_completion);
+ break;
+ case IPU6_FW_ISYS_RESP_TYPE_STREAM_CLOSE_ACK:
+ complete(&stream->stream_close_completion);
+ break;
+ case IPU6_FW_ISYS_RESP_TYPE_STREAM_START_ACK:
+ complete(&stream->stream_start_completion);
+ break;
+ case IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK:
+ complete(&stream->stream_start_completion);
+ break;
+ case IPU6_FW_ISYS_RESP_TYPE_STREAM_STOP_ACK:
+ complete(&stream->stream_stop_completion);
+ break;
+ case IPU6_FW_ISYS_RESP_TYPE_STREAM_FLUSH_ACK:
+ complete(&stream->stream_stop_completion);
+ break;
+ case IPU6_FW_ISYS_RESP_TYPE_PIN_DATA_READY:
+ /*
+ * firmware only release the capture msg until software
+ * get pin_data_ready event
+ */
+ ipu6_put_fw_msg_buf(ipu6_bus_get_drvdata(adev), resp->buf_id);
+ if (resp->pin_id < IPU6_ISYS_OUTPUT_PINS &&
+ stream->output_pins_queue[resp->pin_id])
+ ipu6_isys_queue_buf_ready(stream, resp);
+ else
+ dev_warn(&adev->auxdev.dev,
+ "%d:No queue for pin id %d\n",
+ resp->stream_handle, resp->pin_id);
+ if (csi2)
+ ipu6_isys_csi2_error(csi2);
+
+ break;
+ case IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_ACK:
+ break;
+ case IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE:
+ case IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_DONE:
+ break;
+ case IPU6_FW_ISYS_RESP_TYPE_FRAME_SOF:
+
+ ipu6_isys_csi2_sof_event_by_stream(stream);
+ stream->seq[stream->seq_index].sequence =
+ atomic_read(&stream->sequence) - 1;
+ stream->seq[stream->seq_index].timestamp = ts;
+ dev_dbg(&adev->auxdev.dev,
+ "sof: handle %d: (index %u), timestamp 0x%16.16llx\n",
+ resp->stream_handle,
+ stream->seq[stream->seq_index].sequence, ts);
+ stream->seq_index = (stream->seq_index + 1)
+ % IPU6_ISYS_MAX_PARALLEL_SOF;
+ break;
+ case IPU6_FW_ISYS_RESP_TYPE_FRAME_EOF:
+ ipu6_isys_csi2_eof_event_by_stream(stream);
+ dev_dbg(&adev->auxdev.dev,
+ "eof: handle %d: (index %u), timestamp 0x%16.16llx\n",
+ resp->stream_handle,
+ stream->seq[stream->seq_index].sequence, ts);
+ break;
+ case IPU6_FW_ISYS_RESP_TYPE_STATS_DATA_READY:
+ break;
+ default:
+ dev_err(&adev->auxdev.dev, "%d:unknown response type %u\n",
+ resp->stream_handle, resp->type);
+ break;
+ }
+
+ ipu6_isys_put_stream(stream);
+leave:
+ ipu6_fw_isys_put_resp(isys);
+ return 0;
+}
+
+static void ipu6_isys_csi2_isr(struct ipu6_isys_csi2 *csi2)
+{
+ struct ipu6_isys_stream *stream;
+ unsigned int i;
+ u32 status;
+ int source;
+
+ ipu6_isys_register_errors(csi2);
+
+ status = readl(csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
+ CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET);
+
+ writel(status, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
+ CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
+
+ source = csi2->asd.source;
+ for (i = 0; i < NR_OF_CSI2_VC; i++) {
+ if (status & IPU_CSI_RX_IRQ_FS_VC(i)) {
+ stream = ipu6_isys_query_stream_by_source(csi2->isys,
+ source, i);
+ if (stream) {
+ ipu6_isys_csi2_sof_event_by_stream(stream);
+ ipu6_isys_put_stream(stream);
+ }
+ }
+
+ if (status & IPU_CSI_RX_IRQ_FE_VC(i)) {
+ stream = ipu6_isys_query_stream_by_source(csi2->isys,
+ source, i);
+ if (stream) {
+ ipu6_isys_csi2_eof_event_by_stream(stream);
+ ipu6_isys_put_stream(stream);
+ }
+ }
+ }
+}
+
+irqreturn_t ipu6_isys_isr(struct ipu6_bus_device *adev)
+{
+ struct ipu6_isys *isys = ipu6_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;
+ }
+
+ ctrl0_status = isys->pdata->ipdata->csi2.ctrl0_irq_status;
+ ctrl0_clear = isys->pdata->ipdata->csi2.ctrl0_irq_clear;
+
+ status_csi = readl(isys->pdata->base + ctrl0_status);
+ status_sw = readl(isys->pdata->base +
+ IPU6_REG_ISYS_UNISPART_IRQ_STATUS);
+
+ writel(ISYS_UNISPART_IRQS & ~IPU6_ISYS_UNISPART_IRQ_SW,
+ base + IPU6_REG_ISYS_UNISPART_IRQ_MASK);
+
+ do {
+ writel(status_csi, isys->pdata->base + ctrl0_clear);
+
+ writel(status_sw, isys->pdata->base +
+ IPU6_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 & IPU6_ISYS_UNISPART_IRQ_CSI2(i))
+ ipu6_isys_csi2_isr(&isys->csi2[i]);
+ }
+ }
+
+ writel(0, base + IPU6_REG_ISYS_UNISPART_SW_IRQ_REG);
+
+ if (!ipu6_isys_isr_one(adev))
+ status_sw = IPU6_ISYS_UNISPART_IRQ_SW;
+ else
+ status_sw = 0;
+
+ status_csi = readl(isys->pdata->base + ctrl0_status);
+ status_sw |= readl(isys->pdata->base +
+ IPU6_REG_ISYS_UNISPART_IRQ_STATUS);
+ } while ((status_csi & isys->isr_csi2_bits) ||
+ (status_sw & IPU6_ISYS_UNISPART_IRQ_SW));
+
+ writel(ISYS_UNISPART_IRQS, base + IPU6_REG_ISYS_UNISPART_IRQ_MASK);
+
+ spin_unlock(&isys->power_lock);
+
+ return IRQ_HANDLED;
+}
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
index 15d4ae355f28..f65461a4c907 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
@@ -578,4 +578,7 @@ void ipu6_fw_isys_cleanup(struct ipu6_isys *isys);
struct ipu6_fw_isys_resp_info_abi *
ipu6_fw_isys_get_resp(struct ipu6_isys *isys);
void ipu6_fw_isys_put_resp(struct ipu6_isys *isys);
+int ipu6_isys_isr_one(struct ipu6_bus_device *adev);
+irqreturn_t ipu6_isys_isr(struct ipu6_bus_device *adev);
+
#endif
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 8f2d361b89f6..a58a35112ebd 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -100,8 +100,6 @@ enum ltr_did_type {
#define ISYS_PM_QOS_VALUE 300
-static int isys_isr_one(struct ipu6_bus_device *adev);
-
static int
isys_complete_ext_device_registration(struct ipu6_isys *isys,
struct v4l2_subdev *sd,
@@ -304,104 +302,6 @@ static void isys_setup_hw(struct ipu6_isys *isys)
writel(thd[i], base + IPU6_REG_ISYS_CDC_THRESHOLD(i));
}
-static void ipu6_isys_csi2_isr(struct ipu6_isys_csi2 *csi2)
-{
- struct ipu6_isys_stream *stream;
- unsigned int i;
- u32 status;
- int source;
-
- ipu6_isys_register_errors(csi2);
-
- status = readl(csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
- CSI_PORT_REG_BASE_IRQ_STATUS_OFFSET);
-
- writel(status, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
- CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
-
- source = csi2->asd.source;
- for (i = 0; i < NR_OF_CSI2_VC; i++) {
- if (status & IPU_CSI_RX_IRQ_FS_VC(i)) {
- stream = ipu6_isys_query_stream_by_source(csi2->isys,
- source, i);
- if (stream) {
- ipu6_isys_csi2_sof_event_by_stream(stream);
- ipu6_isys_put_stream(stream);
- }
- }
-
- if (status & IPU_CSI_RX_IRQ_FE_VC(i)) {
- stream = ipu6_isys_query_stream_by_source(csi2->isys,
- source, i);
- if (stream) {
- ipu6_isys_csi2_eof_event_by_stream(stream);
- ipu6_isys_put_stream(stream);
- }
- }
- }
-}
-
-static irqreturn_t isys_isr(struct ipu6_bus_device *adev)
-{
- struct ipu6_isys *isys = ipu6_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;
- }
-
- ctrl0_status = isys->pdata->ipdata->csi2.ctrl0_irq_status;
- ctrl0_clear = isys->pdata->ipdata->csi2.ctrl0_irq_clear;
-
- status_csi = readl(isys->pdata->base + ctrl0_status);
- status_sw = readl(isys->pdata->base +
- IPU6_REG_ISYS_UNISPART_IRQ_STATUS);
-
- writel(ISYS_UNISPART_IRQS & ~IPU6_ISYS_UNISPART_IRQ_SW,
- base + IPU6_REG_ISYS_UNISPART_IRQ_MASK);
-
- do {
- writel(status_csi, isys->pdata->base + ctrl0_clear);
-
- writel(status_sw, isys->pdata->base +
- IPU6_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 & IPU6_ISYS_UNISPART_IRQ_CSI2(i))
- ipu6_isys_csi2_isr(&isys->csi2[i]);
- }
- }
-
- writel(0, base + IPU6_REG_ISYS_UNISPART_SW_IRQ_REG);
-
- if (!isys_isr_one(adev))
- status_sw = IPU6_ISYS_UNISPART_IRQ_SW;
- else
- status_sw = 0;
-
- status_csi = readl(isys->pdata->base + ctrl0_status);
- status_sw |= readl(isys->pdata->base +
- IPU6_REG_ISYS_UNISPART_IRQ_STATUS);
- } while ((status_csi & isys->isr_csi2_bits) ||
- (status_sw & IPU6_ISYS_UNISPART_IRQ_SW));
-
- writel(ISYS_UNISPART_IRQS, base + IPU6_REG_ISYS_UNISPART_IRQ_MASK);
-
- spin_unlock(&isys->power_lock);
-
- return IRQ_HANDLED;
-}
-
static void get_lut_ltrdid(struct ipu6_isys *isys, struct ltr_did *pltr_did)
{
struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark;
@@ -1167,169 +1067,8 @@ static void isys_remove(struct auxiliary_device *auxdev)
mutex_destroy(&isys->mutex);
}
-struct fwmsg {
- int type;
- char *msg;
- bool valid_ts;
-};
-
-static const struct fwmsg fw_msg[] = {
- {IPU6_FW_ISYS_RESP_TYPE_STREAM_OPEN_DONE, "STREAM_OPEN_DONE", 0},
- {IPU6_FW_ISYS_RESP_TYPE_STREAM_CLOSE_ACK, "STREAM_CLOSE_ACK", 0},
- {IPU6_FW_ISYS_RESP_TYPE_STREAM_START_ACK, "STREAM_START_ACK", 0},
- {IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK,
- "STREAM_START_AND_CAPTURE_ACK", 0},
- {IPU6_FW_ISYS_RESP_TYPE_STREAM_STOP_ACK, "STREAM_STOP_ACK", 0},
- {IPU6_FW_ISYS_RESP_TYPE_STREAM_FLUSH_ACK, "STREAM_FLUSH_ACK", 0},
- {IPU6_FW_ISYS_RESP_TYPE_PIN_DATA_READY, "PIN_DATA_READY", 1},
- {IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_ACK, "STREAM_CAPTURE_ACK", 0},
- {IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE,
- "STREAM_START_AND_CAPTURE_DONE", 1},
- {IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_DONE, "STREAM_CAPTURE_DONE", 1},
- {IPU6_FW_ISYS_RESP_TYPE_FRAME_SOF, "FRAME_SOF", 1},
- {IPU6_FW_ISYS_RESP_TYPE_FRAME_EOF, "FRAME_EOF", 1},
- {IPU6_FW_ISYS_RESP_TYPE_STATS_DATA_READY, "STATS_READY", 1},
- {-1, "UNKNOWN MESSAGE", 0}
-};
-
-static u32 resp_type_to_index(int type)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(fw_msg); i++)
- if (fw_msg[i].type == type)
- return i;
-
- return ARRAY_SIZE(fw_msg) - 1;
-}
-
-static int isys_isr_one(struct ipu6_bus_device *adev)
-{
- struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
- struct ipu6_fw_isys_resp_info_abi *resp;
- struct ipu6_isys_stream *stream;
- struct ipu6_isys_csi2 *csi2 = NULL;
- u32 index;
- u64 ts;
-
- if (!isys->fwctx)
- return 1;
-
- resp = ipu6_fw_isys_get_resp(isys);
- if (!resp)
- return 1;
-
- ts = (u64)resp->timestamp[1] << 32 | resp->timestamp[0];
-
- index = resp_type_to_index(resp->type);
- dev_dbg(&adev->auxdev.dev,
- "FW resp %02d %s, stream %u, ts 0x%16.16llx, pin %d\n",
- resp->type, fw_msg[index].msg, resp->stream_handle,
- fw_msg[index].valid_ts ? ts : 0, resp->pin_id);
-
- if (resp->error_info.error == IPU6_FW_ISYS_ERROR_STREAM_IN_SUSPENSION)
- /* Suspension is kind of special case: not enough buffers */
- dev_dbg(&adev->auxdev.dev,
- "FW error resp SUSPENSION, details %d\n",
- resp->error_info.error_details);
- else if (resp->error_info.error)
- dev_dbg(&adev->auxdev.dev,
- "FW error resp error %d, details %d\n",
- resp->error_info.error, resp->error_info.error_details);
-
- if (resp->stream_handle >= IPU6_ISYS_MAX_STREAMS) {
- dev_err(&adev->auxdev.dev, "bad stream handle %u\n",
- resp->stream_handle);
- goto leave;
- }
-
- stream = ipu6_isys_query_stream_by_handle(isys, resp->stream_handle);
- if (!stream) {
- dev_err(&adev->auxdev.dev, "stream of stream_handle %u is unused\n",
- resp->stream_handle);
- goto leave;
- }
- stream->error = resp->error_info.error;
-
- csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
-
- switch (resp->type) {
- case IPU6_FW_ISYS_RESP_TYPE_STREAM_OPEN_DONE:
- complete(&stream->stream_open_completion);
- break;
- case IPU6_FW_ISYS_RESP_TYPE_STREAM_CLOSE_ACK:
- complete(&stream->stream_close_completion);
- break;
- case IPU6_FW_ISYS_RESP_TYPE_STREAM_START_ACK:
- complete(&stream->stream_start_completion);
- break;
- case IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK:
- complete(&stream->stream_start_completion);
- break;
- case IPU6_FW_ISYS_RESP_TYPE_STREAM_STOP_ACK:
- complete(&stream->stream_stop_completion);
- break;
- case IPU6_FW_ISYS_RESP_TYPE_STREAM_FLUSH_ACK:
- complete(&stream->stream_stop_completion);
- break;
- case IPU6_FW_ISYS_RESP_TYPE_PIN_DATA_READY:
- /*
- * firmware only release the capture msg until software
- * get pin_data_ready event
- */
- ipu6_put_fw_msg_buf(ipu6_bus_get_drvdata(adev), resp->buf_id);
- if (resp->pin_id < IPU6_ISYS_OUTPUT_PINS &&
- stream->output_pins_queue[resp->pin_id])
- ipu6_isys_queue_buf_ready(stream, resp);
- else
- dev_warn(&adev->auxdev.dev,
- "%d:No queue for pin id %d\n",
- resp->stream_handle, resp->pin_id);
- if (csi2)
- ipu6_isys_csi2_error(csi2);
-
- break;
- case IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_ACK:
- break;
- case IPU6_FW_ISYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE:
- case IPU6_FW_ISYS_RESP_TYPE_STREAM_CAPTURE_DONE:
- break;
- case IPU6_FW_ISYS_RESP_TYPE_FRAME_SOF:
-
- ipu6_isys_csi2_sof_event_by_stream(stream);
- stream->seq[stream->seq_index].sequence =
- atomic_read(&stream->sequence) - 1;
- stream->seq[stream->seq_index].timestamp = ts;
- dev_dbg(&adev->auxdev.dev,
- "sof: handle %d: (index %u), timestamp 0x%16.16llx\n",
- resp->stream_handle,
- stream->seq[stream->seq_index].sequence, ts);
- stream->seq_index = (stream->seq_index + 1)
- % IPU6_ISYS_MAX_PARALLEL_SOF;
- break;
- case IPU6_FW_ISYS_RESP_TYPE_FRAME_EOF:
- ipu6_isys_csi2_eof_event_by_stream(stream);
- dev_dbg(&adev->auxdev.dev,
- "eof: handle %d: (index %u), timestamp 0x%16.16llx\n",
- resp->stream_handle,
- stream->seq[stream->seq_index].sequence, ts);
- break;
- case IPU6_FW_ISYS_RESP_TYPE_STATS_DATA_READY:
- break;
- default:
- dev_err(&adev->auxdev.dev, "%d:unknown response type %u\n",
- resp->stream_handle, resp->type);
- break;
- }
-
- ipu6_isys_put_stream(stream);
-leave:
- ipu6_fw_isys_put_resp(isys);
- return 0;
-}
-
static const struct ipu6_auxdrv_data ipu6_isys_auxdrv_data = {
- .isr = isys_isr,
+ .isr = ipu6_isys_isr,
.isr_threaded = NULL,
.wake_isr_thread = false,
};
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 19/44] media: ipu6: Move hw specific buffer handling down
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (17 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 18/44] media: ipu6: Move isys isr handlers to fw file Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 20/44] media: ipu6: Isolate hw specific buffer handling Antti Laakso
` (24 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
Move handling of hardware specific buffers out of common code, like
ipu6-isys-video.c. Now the ipu6_put_fw_msg_buf() works with fw_msg_bufs,
like its counterpart ipu6_get_fw_msg_buf().
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-fw-isys.c | 11 ++++++++++-
drivers/media/pci/intel/ipu6/ipu6-isys-video.c | 6 +++---
drivers/media/pci/intel/ipu6/ipu6-isys.c | 7 ++-----
drivers/media/pci/intel/ipu6/ipu6-isys.h | 2 +-
4 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
index 7f7125202ffd..8906727ca84b 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
@@ -530,6 +530,7 @@ int ipu6_isys_isr_one(struct ipu6_bus_device *adev)
struct ipu6_fw_isys_resp_info_abi *resp;
struct ipu6_isys_stream *stream;
struct ipu6_isys_csi2 *csi2 = NULL;
+ struct isys_fw_msgs *isys_fw_msg = NULL;
u32 index;
u64 ts;
@@ -598,7 +599,15 @@ int ipu6_isys_isr_one(struct ipu6_bus_device *adev)
* firmware only release the capture msg until software
* get pin_data_ready event
*/
- ipu6_put_fw_msg_buf(ipu6_bus_get_drvdata(adev), resp->buf_id);
+ if (!resp->buf_id)
+ dev_warn(&adev->auxdev.dev, "%d: Invalid buf ID\n",
+ resp->stream_handle);
+ else
+ isys_fw_msg =
+ container_of((void *)(uintptr_t)resp->buf_id,
+ struct isys_fw_msgs, ipu6.dummy);
+
+ ipu6_put_fw_msg_buf(ipu6_bus_get_drvdata(adev), isys_fw_msg);
if (resp->pin_id < IPU6_ISYS_OUTPUT_PINS &&
stream->output_pins_queue[resp->pin_id])
ipu6_isys_queue_buf_ready(stream, resp);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index c925386a1e98..fabea6a75d7d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -544,7 +544,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
ret = ipu6_isys_fw_pin_cfg(__av, stream_cfg);
if (ret < 0) {
- ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
+ ipu6_put_fw_msg_buf(av->isys, msg);
return ret;
}
}
@@ -561,7 +561,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN);
if (ret < 0) {
dev_err(dev, "can't open stream (%d)\n", ret);
- ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
+ ipu6_put_fw_msg_buf(av->isys, msg);
return ret;
}
@@ -570,7 +570,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
tout = wait_for_completion_timeout(&stream->stream_open_completion,
IPU6_FW_CALL_TIMEOUT_JIFFIES);
- ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
+ ipu6_put_fw_msg_buf(av->isys, msg);
if (!tout) {
dev_err(dev, "stream open time out\n");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index a58a35112ebd..bb3c0d6bc6c9 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -919,17 +919,14 @@ void ipu6_cleanup_fw_msg_bufs(struct ipu6_isys *isys)
spin_unlock_irqrestore(&isys->listlock, flags);
}
-void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, uintptr_t data)
+void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, struct isys_fw_msgs *msg)
{
- struct isys_fw_msgs *msg;
unsigned long flags;
- void *ptr = (void *)data;
- if (!ptr)
+ if (!msg)
return;
spin_lock_irqsave(&isys->listlock, flags);
- msg = container_of(ptr, struct isys_fw_msgs, ipu6.dummy);
list_move(&msg->head, &isys->framebuflist);
spin_unlock_irqrestore(&isys->listlock, flags);
}
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h
index abcd5e1cbc2c..f39566513a87 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h
@@ -175,7 +175,7 @@ struct isys_fw_msgs {
};
struct isys_fw_msgs *ipu6_get_fw_msg_buf(struct ipu6_isys_stream *stream);
-void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, uintptr_t data);
+void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, struct isys_fw_msgs *msg);
void ipu6_cleanup_fw_msg_bufs(struct ipu6_isys *isys);
extern const struct v4l2_ioctl_ops ipu6_isys_ioctl_ops;
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 20/44] media: ipu6: Isolate hw specific buffer handling
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (18 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 19/44] media: ipu6: Move hw specific buffer handling down Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 21/44] media: ipu6: Add isys firmware ops Antti Laakso
` (23 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
Move ipu6 specific buffer and stream handling down to
hardware specific file, to make it possible to add ipu7
specific functionality.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-fw-isys.c | 241 ++++++++++++++++--
drivers/media/pci/intel/ipu6/ipu6-fw-isys.h | 42 ++-
.../media/pci/intel/ipu6/ipu6-isys-queue.c | 77 +-----
.../media/pci/intel/ipu6/ipu6-isys-queue.h | 4 -
.../media/pci/intel/ipu6/ipu6-isys-video.c | 128 +---------
5 files changed, 270 insertions(+), 222 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
index 8906727ca84b..9256ea3b68c1 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
@@ -90,11 +90,11 @@ int ipu6_fw_isys_send_proxy_token(struct ipu6_isys *isys,
return ret;
}
-int ipu6_fw_isys_complex_cmd(struct ipu6_isys *isys,
- const unsigned int stream_handle,
- void *cpu_mapped_buf,
- dma_addr_t dma_mapped_buf,
- size_t size, u16 send_type)
+static int ipu6_fw_isys_complex_cmd(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ void *cpu_mapped_buf,
+ dma_addr_t dma_mapped_buf,
+ size_t size, u16 send_type)
{
struct ipu6_fw_com_context *ctx = isys->fwctx;
struct device *dev = &isys->adev->auxdev.dev;
@@ -126,13 +126,6 @@ int ipu6_fw_isys_complex_cmd(struct ipu6_isys *isys,
return 0;
}
-int ipu6_fw_isys_simple_cmd(struct ipu6_isys *isys,
- const unsigned int stream_handle, u16 send_type)
-{
- return ipu6_fw_isys_complex_cmd(isys, stream_handle, NULL, 0, 0,
- send_type);
-}
-
int ipu6_fw_isys_close(struct ipu6_isys *isys)
{
struct device *dev = &isys->adev->auxdev.dev;
@@ -376,9 +369,9 @@ void ipu6_fw_isys_put_resp(struct ipu6_isys *isys)
ipu6_recv_put_token(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
}
-void ipu6_fw_isys_dump_stream_cfg(struct device *dev,
- struct ipu6_fw_isys_stream_cfg_data_abi *cfg)
+void ipu6_fw_isys_dump_stream_cfg(struct device *dev, struct isys_fw_msgs *msg)
{
+ struct ipu6_fw_isys_stream_cfg_data_abi *cfg = &msg->ipu6.stream;
unsigned int i;
dev_dbg(dev, "-----------------------------------------------------\n");
@@ -454,12 +447,14 @@ void ipu6_fw_isys_dump_stream_cfg(struct device *dev,
}
void
-ipu6_fw_isys_dump_frame_buff_set(struct device *dev,
- struct ipu6_fw_isys_frame_buff_set_abi *buf,
+ipu6_fw_isys_dump_frame_buff_set(struct device *dev, struct isys_fw_msgs *msg,
unsigned int outputs)
{
+ struct ipu6_fw_isys_frame_buff_set_abi *buf;
unsigned int i;
+ buf = &msg->ipu6.frame;
+
dev_dbg(dev, "-----------------------------------------------------\n");
dev_dbg(dev, "IPU6_FW_ISYS_FRAME_BUFF_SET\n");
@@ -596,16 +591,17 @@ int ipu6_isys_isr_one(struct ipu6_bus_device *adev)
break;
case IPU6_FW_ISYS_RESP_TYPE_PIN_DATA_READY:
/*
- * firmware only release the capture msg until software
+ * firmware only release the capture message until software
* get pin_data_ready event
*/
- if (!resp->buf_id)
+ if (!resp->buf_id) {
dev_warn(&adev->auxdev.dev, "%d: Invalid buf ID\n",
resp->stream_handle);
- else
- isys_fw_msg =
- container_of((void *)(uintptr_t)resp->buf_id,
- struct isys_fw_msgs, ipu6.dummy);
+ goto leave_put_stream;
+ }
+
+ isys_fw_msg = container_of((void *)(uintptr_t)resp->buf_id,
+ struct isys_fw_msgs, ipu6.dummy);
ipu6_put_fw_msg_buf(ipu6_bus_get_drvdata(adev), isys_fw_msg);
if (resp->pin_id < IPU6_ISYS_OUTPUT_PINS &&
@@ -652,6 +648,7 @@ int ipu6_isys_isr_one(struct ipu6_bus_device *adev)
break;
}
+leave_put_stream:
ipu6_isys_put_stream(stream);
leave:
ipu6_fw_isys_put_resp(isys);
@@ -755,3 +752,203 @@ irqreturn_t ipu6_isys_isr(struct ipu6_bus_device *adev)
return IRQ_HANDLED;
}
+
+static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av,
+ struct ipu6_fw_isys_stream_cfg_data_abi *cfg)
+{
+ struct media_pad *src_pad = media_pad_remote_pad_first(&av->pad);
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(src_pad->entity);
+ struct v4l2_subdev_state *state = v4l2_subdev_get_locked_active_state(sd);
+ struct ipu6_fw_isys_input_pin_info_abi *input_pin;
+ struct ipu6_fw_isys_output_pin_info_abi *output_pin;
+ struct ipu6_isys_stream *stream = av->stream;
+ struct ipu6_isys_queue *aq = &av->aq;
+ struct v4l2_mbus_framefmt fmt;
+ const struct ipu6_isys_pixelformat *pfmt =
+ ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
+ struct v4l2_rect v4l2_crop;
+ struct ipu6_isys *isys = av->isys;
+ int input_pins = cfg->nof_input_pins++;
+ int output_pins;
+ u32 src_stream;
+
+ src_stream = ipu6_isys_get_src_stream_by_src_pad(sd, src_pad->index);
+ fmt = *v4l2_subdev_state_get_format(state, src_pad->index, src_stream);
+ v4l2_crop = *v4l2_subdev_state_get_crop(state, src_pad->index, src_stream);
+
+ input_pin = &cfg->input_pins[input_pins];
+ input_pin->input_res.width = fmt.width;
+ input_pin->input_res.height = fmt.height;
+ input_pin->dt = av->dt;
+ input_pin->bits_per_pix = pfmt->bpp_packed;
+ input_pin->mapped_dt = 0x40; /* invalid mipi data type */
+ input_pin->mipi_decompression = 0;
+ input_pin->capture_mode = IPU6_FW_ISYS_CAPTURE_MODE_REGULAR;
+ input_pin->mipi_store_mode = pfmt->bpp == pfmt->bpp_packed ?
+ IPU6_FW_ISYS_MIPI_STORE_MODE_DISCARD_LONG_HEADER :
+ IPU6_FW_ISYS_MIPI_STORE_MODE_NORMAL;
+ input_pin->crop_first_and_last_lines = v4l2_crop.top & 1;
+
+ output_pins = cfg->nof_output_pins++;
+ aq->fw_output = output_pins;
+ stream->output_pins_queue[output_pins] = aq;
+
+ output_pin = &cfg->output_pins[output_pins];
+ output_pin->input_pin_id = input_pins;
+ output_pin->output_res.width = ipu6_isys_get_frame_width(av);
+ output_pin->output_res.height = ipu6_isys_get_frame_height(av);
+
+ output_pin->stride = ipu6_isys_get_bytes_per_line(av);
+ if (pfmt->bpp != pfmt->bpp_packed)
+ output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_RAW_SOC;
+ else
+ output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_MIPI;
+ output_pin->ft = pfmt->css_pixelformat;
+ output_pin->send_irq = 1;
+ memset(output_pin->ts_offsets, 0, sizeof(output_pin->ts_offsets));
+ output_pin->s2m_pixel_soc_pixel_remapping =
+ S2M_PIXEL_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING;
+ output_pin->csi_be_soc_pixel_remapping =
+ CSI_BE_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING;
+
+ output_pin->snoopable = true;
+ output_pin->error_handling_enable = false;
+ output_pin->sensor_type = isys->sensor_type++;
+ if (isys->sensor_type > isys->pdata->ipdata->sensor_type_end)
+ isys->sensor_type = isys->pdata->ipdata->sensor_type_start;
+
+ return 0;
+}
+
+int ipu6_fw_isys_prepare_stream_cfg(struct ipu6_isys_video *av,
+ struct isys_fw_msgs *msg)
+{
+ struct ipu6_fw_isys_stream_cfg_data_abi *stream_cfg;
+ struct device *dev = &av->isys->adev->auxdev.dev;
+ struct ipu6_isys_stream *stream = av->stream;
+ struct ipu6_isys_queue *aq;
+
+ stream_cfg = &msg->ipu6.stream;
+ stream_cfg->src = stream->stream_source;
+ stream_cfg->vc = stream->vc;
+ stream_cfg->isl_use = 0;
+ stream_cfg->sensor_type = IPU6_FW_ISYS_SENSOR_MODE_NORMAL;
+
+ list_for_each_entry(aq, &stream->queues, node) {
+ struct ipu6_isys_video *__av = ipu6_isys_queue_to_video(aq);
+ int ret;
+
+ ret = ipu6_isys_fw_pin_cfg(__av, stream_cfg);
+ if (ret < 0)
+ return ret;
+ }
+
+ ipu6_fw_isys_dump_stream_cfg(dev, msg);
+
+ stream->nr_output_pins = stream_cfg->nof_output_pins;
+
+ return 0;
+}
+
+int ipu6_fw_isys_stream_open(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ struct isys_fw_msgs *msg)
+{
+ return ipu6_fw_isys_complex_cmd(isys, stream_handle,
+ &msg->ipu6.stream, msg->dma_addr,
+ sizeof(msg->ipu6.stream),
+ IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN);
+}
+
+int ipu6_fw_isys_stream_close(struct ipu6_isys *isys,
+ const unsigned int stream_handle)
+{
+ return ipu6_fw_isys_complex_cmd(isys, stream_handle, NULL, 0, 0,
+ IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE);
+}
+
+int ipu6_fw_isys_stream_flush(struct ipu6_isys *isys,
+ const unsigned int stream_handle)
+{
+ return ipu6_fw_isys_complex_cmd(isys, stream_handle, NULL, 0, 0,
+ IPU6_FW_ISYS_SEND_TYPE_STREAM_FLUSH);
+}
+
+int ipu6_fw_isys_stream_start(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ struct isys_fw_msgs *msg, bool capture)
+{
+ u16 cmd_type;
+
+ if (capture)
+ cmd_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START_AND_CAPTURE;
+ else
+ cmd_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START;
+
+ return ipu6_fw_isys_complex_cmd(isys, stream_handle,
+ &msg->ipu6.stream, msg->dma_addr,
+ sizeof(msg->ipu6.stream), cmd_type);
+}
+
+int ipu6_fw_isys_stream_capture(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ struct isys_fw_msgs *msg)
+{
+ return ipu6_fw_isys_complex_cmd(isys, stream_handle,
+ &msg->ipu6.stream, msg->dma_addr,
+ sizeof(msg->ipu6.stream),
+ IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE);
+}
+
+static void
+ipu6_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb,
+ struct ipu6_fw_isys_frame_buff_set_abi *set)
+{
+ struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
+ struct ipu6_isys_video_buffer *ivb =
+ vb2_buffer_to_ipu6_isys_video_buffer(vvb);
+
+ set->output_pins[aq->fw_output].addr = ivb->dma_addr;
+ set->output_pins[aq->fw_output].out_buf_id = vb->index + 1;
+}
+
+/*
+ * Convert a buffer list to a isys fw ABI framebuffer set. The
+ * buffer list is not modified.
+ */
+#define IPU6_ISYS_FRAME_NUM_THRESHOLD (30)
+void
+ipu6_fw_isys_prepare_buf_set(struct isys_fw_msgs *msg,
+ struct ipu6_isys_stream *stream,
+ struct ipu6_isys_buffer_list *bl)
+{
+ struct ipu6_fw_isys_frame_buff_set_abi *set = &msg->ipu6.frame;
+ struct ipu6_isys_buffer *ib;
+
+ WARN_ON(!bl->nbufs);
+
+ set->send_irq_sof = 1;
+ set->send_resp_sof = 1;
+ set->send_irq_eof = 0;
+ set->send_resp_eof = 0;
+
+ if (stream->streaming)
+ set->send_irq_capture_ack = 0;
+ else
+ set->send_irq_capture_ack = 1;
+ set->send_irq_capture_done = 0;
+
+ set->send_resp_capture_ack = 1;
+ set->send_resp_capture_done = 1;
+ if (atomic_read(&stream->sequence) >= IPU6_ISYS_FRAME_NUM_THRESHOLD) {
+ set->send_resp_capture_ack = 0;
+ set->send_resp_capture_done = 0;
+ }
+
+ list_for_each_entry(ib, &bl->head, head) {
+ struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);
+
+ ipu6_isys_buf_to_fw_frame_buf_pin(vb, set);
+ }
+}
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
index f65461a4c907..b589ae7fbd4e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
@@ -8,6 +8,10 @@
struct device;
struct ipu6_isys;
+struct ipu6_isys_video;
+struct isys_fw_msgs;
+struct ipu6_isys_stream;
+struct ipu6_isys_buffer_list;
/* Max number of Input/Output Pins */
#define IPU6_MAX_IPINS 4
@@ -555,21 +559,8 @@ struct ipu6_fw_proxy_send_queue_token {
u32 value;
};
-void
-ipu6_fw_isys_dump_stream_cfg(struct device *dev,
- struct ipu6_fw_isys_stream_cfg_data_abi *cfg);
-void
-ipu6_fw_isys_dump_frame_buff_set(struct device *dev,
- struct ipu6_fw_isys_frame_buff_set_abi *buf,
- unsigned int outputs);
int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams);
int ipu6_fw_isys_close(struct ipu6_isys *isys);
-int ipu6_fw_isys_simple_cmd(struct ipu6_isys *isys,
- const unsigned int stream_handle, u16 send_type);
-int ipu6_fw_isys_complex_cmd(struct ipu6_isys *isys,
- const unsigned int stream_handle,
- void *cpu_mapped_buf, dma_addr_t dma_mapped_buf,
- size_t size, u16 send_type);
int ipu6_fw_isys_send_proxy_token(struct ipu6_isys *isys,
unsigned int req_id,
unsigned int index,
@@ -581,4 +572,29 @@ void ipu6_fw_isys_put_resp(struct ipu6_isys *isys);
int ipu6_isys_isr_one(struct ipu6_bus_device *adev);
irqreturn_t ipu6_isys_isr(struct ipu6_bus_device *adev);
+int ipu6_fw_isys_stream_open(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ struct isys_fw_msgs *msg);
+int ipu6_fw_isys_stream_close(struct ipu6_isys *isys,
+ const unsigned int stream_handle);
+int ipu6_fw_isys_stream_flush(struct ipu6_isys *isys,
+ const unsigned int stream_handle);
+int ipu6_fw_isys_stream_start(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ struct isys_fw_msgs *msg, bool capture);
+int ipu6_fw_isys_stream_capture(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ struct isys_fw_msgs *msg);
+int ipu6_fw_isys_prepare_stream_cfg(struct ipu6_isys_video *av,
+ struct isys_fw_msgs *msg);
+void
+ipu6_fw_isys_prepare_buf_set(struct isys_fw_msgs *msg,
+ struct ipu6_isys_stream *stream,
+ struct ipu6_isys_buffer_list *bl);
+void
+ipu6_fw_isys_dump_stream_cfg(struct device *dev, struct isys_fw_msgs *set);
+void
+ipu6_fw_isys_dump_frame_buff_set(struct device *dev, struct isys_fw_msgs *set,
+ unsigned int outputs);
+
#endif
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
index 529973860e9e..9f6f283600c8 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
@@ -233,58 +233,6 @@ static int buffer_list_get(struct ipu6_isys_stream *stream,
return 0;
}
-static void
-ipu6_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb,
- struct ipu6_fw_isys_frame_buff_set_abi *set)
-{
- struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
- struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
- struct ipu6_isys_video_buffer *ivb =
- vb2_buffer_to_ipu6_isys_video_buffer(vvb);
-
- set->output_pins[aq->fw_output].addr = ivb->dma_addr;
- set->output_pins[aq->fw_output].out_buf_id = vb->index + 1;
-}
-
-/*
- * Convert a buffer list to a isys fw ABI framebuffer set. The
- * buffer list is not modified.
- */
-#define IPU6_ISYS_FRAME_NUM_THRESHOLD (30)
-void
-ipu6_isys_buf_to_fw_frame_buf(struct ipu6_fw_isys_frame_buff_set_abi *set,
- struct ipu6_isys_stream *stream,
- struct ipu6_isys_buffer_list *bl)
-{
- struct ipu6_isys_buffer *ib;
-
- WARN_ON(!bl->nbufs);
-
- set->send_irq_sof = 1;
- set->send_resp_sof = 1;
- set->send_irq_eof = 0;
- set->send_resp_eof = 0;
-
- if (stream->streaming)
- set->send_irq_capture_ack = 0;
- else
- set->send_irq_capture_ack = 1;
- set->send_irq_capture_done = 0;
-
- set->send_resp_capture_ack = 1;
- set->send_resp_capture_done = 1;
- if (atomic_read(&stream->sequence) >= IPU6_ISYS_FRAME_NUM_THRESHOLD) {
- set->send_resp_capture_ack = 0;
- set->send_resp_capture_done = 0;
- }
-
- list_for_each_entry(ib, &bl->head, head) {
- struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);
-
- ipu6_isys_buf_to_fw_frame_buf_pin(vb, set);
- }
-}
-
/* Start streaming for real. The buffer list must be available. */
static int ipu6_isys_stream_start(struct ipu6_isys_video *av,
struct ipu6_isys_buffer_list *bl)
@@ -304,9 +252,7 @@ static int ipu6_isys_stream_start(struct ipu6_isys_video *av,
bl = &__bl;
do {
- struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL;
struct isys_fw_msgs *msg;
- u16 send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE;
ret = buffer_list_get(stream, bl);
if (ret < 0)
@@ -316,16 +262,14 @@ static int ipu6_isys_stream_start(struct ipu6_isys_video *av,
if (!msg)
return -ENOMEM;
- buf = &msg->ipu6.frame;
- ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);
- ipu6_fw_isys_dump_frame_buff_set(dev, buf,
+ ipu6_fw_isys_prepare_buf_set(msg, stream, bl);
+ ipu6_fw_isys_dump_frame_buff_set(dev, msg,
stream->nr_output_pins);
ipu6_isys_buffer_list_queue(bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE,
0);
- ret = ipu6_fw_isys_complex_cmd(stream->isys,
- stream->stream_handle, buf,
- msg->dma_addr, sizeof(*buf),
- send_type);
+
+ ret = ipu6_fw_isys_stream_capture(stream->isys,
+ stream->stream_handle, msg);
} while (!WARN_ON(ret));
return 0;
@@ -349,7 +293,6 @@ static void buf_queue(struct vb2_buffer *vb)
vb2_buffer_to_ipu6_isys_video_buffer(vvb);
struct ipu6_isys_buffer *ib = &ivb->ib;
struct device *dev = &av->isys->adev->auxdev.dev;
- struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL;
struct ipu6_isys_stream *stream = av->stream;
struct ipu6_isys_buffer_list bl;
struct isys_fw_msgs *msg;
@@ -396,9 +339,8 @@ static void buf_queue(struct vb2_buffer *vb)
goto out;
}
- buf = &msg->ipu6.frame;
- ipu6_isys_buf_to_fw_frame_buf(buf, stream, &bl);
- ipu6_fw_isys_dump_frame_buff_set(dev, buf, stream->nr_output_pins);
+ ipu6_fw_isys_prepare_buf_set(msg, stream, &bl);
+ ipu6_fw_isys_dump_frame_buff_set(dev, msg, stream->nr_output_pins);
/*
* We must queue the buffers in the buffer list to the
@@ -408,9 +350,8 @@ static void buf_queue(struct vb2_buffer *vb)
*/
ipu6_isys_buffer_list_queue(&bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
- ret = ipu6_fw_isys_complex_cmd(stream->isys, stream->stream_handle,
- buf, msg->dma_addr, sizeof(*buf),
- IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE);
+ ret = ipu6_fw_isys_stream_capture(stream->isys, stream->stream_handle,
+ msg);
if (ret < 0)
dev_err(dev, "send stream capture failed\n");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
index dec1fed44dd2..51de14183ccf 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
@@ -60,10 +60,6 @@ struct ipu6_isys_buffer_list {
void ipu6_isys_buffer_list_queue(struct ipu6_isys_buffer_list *bl,
unsigned long op_flags,
enum vb2_buffer_state state);
-void
-ipu6_isys_buf_to_fw_frame_buf(struct ipu6_fw_isys_frame_buff_set_abi *set,
- struct ipu6_isys_stream *stream,
- struct ipu6_isys_buffer_list *bl);
void ipu6_isys_queue_buf_ready(struct ipu6_isys_stream *stream,
struct ipu6_fw_isys_resp_info_abi *info);
int ipu6_isys_queue_init(struct ipu6_isys_queue *aq);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index fabea6a75d7d..a6e50263f8da 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -450,115 +450,28 @@ static void put_stream_opened(struct ipu6_isys_video *av)
spin_unlock_irqrestore(&av->isys->streams_lock, flags);
}
-static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av,
- struct ipu6_fw_isys_stream_cfg_data_abi *cfg)
-{
- struct media_pad *src_pad = media_pad_remote_pad_first(&av->pad);
- struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(src_pad->entity);
- struct v4l2_subdev_state *state = v4l2_subdev_get_locked_active_state(sd);
- struct ipu6_fw_isys_input_pin_info_abi *input_pin;
- struct ipu6_fw_isys_output_pin_info_abi *output_pin;
- struct ipu6_isys_stream *stream = av->stream;
- struct ipu6_isys_queue *aq = &av->aq;
- struct v4l2_mbus_framefmt fmt;
- const struct ipu6_isys_pixelformat *pfmt =
- ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
- struct v4l2_rect v4l2_crop;
- struct ipu6_isys *isys = av->isys;
- int input_pins = cfg->nof_input_pins++;
- int output_pins;
- u32 src_stream;
-
- src_stream = ipu6_isys_get_src_stream_by_src_pad(sd, src_pad->index);
- fmt = *v4l2_subdev_state_get_format(state, src_pad->index, src_stream);
- v4l2_crop = *v4l2_subdev_state_get_crop(state, src_pad->index, src_stream);
-
- input_pin = &cfg->input_pins[input_pins];
- input_pin->input_res.width = fmt.width;
- input_pin->input_res.height = fmt.height;
- input_pin->dt = av->dt;
- input_pin->bits_per_pix = pfmt->bpp_packed;
- input_pin->mapped_dt = 0x40; /* invalid mipi data type */
- input_pin->mipi_decompression = 0;
- input_pin->capture_mode = IPU6_FW_ISYS_CAPTURE_MODE_REGULAR;
- input_pin->mipi_store_mode = pfmt->bpp == pfmt->bpp_packed ?
- IPU6_FW_ISYS_MIPI_STORE_MODE_DISCARD_LONG_HEADER :
- IPU6_FW_ISYS_MIPI_STORE_MODE_NORMAL;
- input_pin->crop_first_and_last_lines = v4l2_crop.top & 1;
-
- output_pins = cfg->nof_output_pins++;
- aq->fw_output = output_pins;
- stream->output_pins_queue[output_pins] = aq;
-
- output_pin = &cfg->output_pins[output_pins];
- output_pin->input_pin_id = input_pins;
- output_pin->output_res.width = ipu6_isys_get_frame_width(av);
- output_pin->output_res.height = ipu6_isys_get_frame_height(av);
-
- output_pin->stride = ipu6_isys_get_bytes_per_line(av);
- if (pfmt->bpp != pfmt->bpp_packed)
- output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_RAW_SOC;
- else
- output_pin->pt = IPU6_FW_ISYS_PIN_TYPE_MIPI;
- output_pin->ft = pfmt->css_pixelformat;
- output_pin->send_irq = 1;
- memset(output_pin->ts_offsets, 0, sizeof(output_pin->ts_offsets));
- output_pin->s2m_pixel_soc_pixel_remapping =
- S2M_PIXEL_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING;
- output_pin->csi_be_soc_pixel_remapping =
- CSI_BE_SOC_PIXEL_REMAPPING_FLAG_NO_REMAPPING;
-
- output_pin->snoopable = true;
- output_pin->error_handling_enable = false;
- output_pin->sensor_type = isys->sensor_type++;
- if (isys->sensor_type > isys->pdata->ipdata->sensor_type_end)
- isys->sensor_type = isys->pdata->ipdata->sensor_type_start;
-
- return 0;
-}
-
static int start_stream_firmware(struct ipu6_isys_video *av,
struct ipu6_isys_buffer_list *bl)
{
- struct ipu6_fw_isys_stream_cfg_data_abi *stream_cfg;
- struct ipu6_fw_isys_frame_buff_set_abi *buf = NULL;
struct ipu6_isys_stream *stream = av->stream;
struct device *dev = &av->isys->adev->auxdev.dev;
struct isys_fw_msgs *msg = NULL;
- struct ipu6_isys_queue *aq;
int ret, retout, tout;
- u16 send_type;
+ bool capture = bl ? true : false;
msg = ipu6_get_fw_msg_buf(stream);
if (!msg)
return -ENOMEM;
- stream_cfg = &msg->ipu6.stream;
- stream_cfg->src = stream->stream_source;
- stream_cfg->vc = stream->vc;
- stream_cfg->isl_use = 0;
- stream_cfg->sensor_type = IPU6_FW_ISYS_SENSOR_MODE_NORMAL;
-
- list_for_each_entry(aq, &stream->queues, node) {
- struct ipu6_isys_video *__av = ipu6_isys_queue_to_video(aq);
-
- ret = ipu6_isys_fw_pin_cfg(__av, stream_cfg);
- if (ret < 0) {
- ipu6_put_fw_msg_buf(av->isys, msg);
- return ret;
- }
+ ret = ipu6_fw_isys_prepare_stream_cfg(av, msg);
+ if (ret < 0) {
+ ipu6_put_fw_msg_buf(av->isys, msg);
+ return ret;
}
- ipu6_fw_isys_dump_stream_cfg(dev, stream_cfg);
-
- stream->nr_output_pins = stream_cfg->nof_output_pins;
-
reinit_completion(&stream->stream_open_completion);
- ret = ipu6_fw_isys_complex_cmd(av->isys, stream->stream_handle,
- stream_cfg, msg->dma_addr,
- sizeof(*stream_cfg),
- IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN);
+ ret = ipu6_fw_isys_stream_open(av->isys, stream->stream_handle, msg);
if (ret < 0) {
dev_err(dev, "can't open stream (%d)\n", ret);
ipu6_put_fw_msg_buf(av->isys, msg);
@@ -590,26 +503,16 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
ret = -ENOMEM;
goto out_put_stream_opened;
}
- buf = &msg->ipu6.frame;
- ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);
+
+ ipu6_fw_isys_prepare_buf_set(msg, stream, bl);
ipu6_isys_buffer_list_queue(bl,
IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
}
reinit_completion(&stream->stream_start_completion);
- if (bl) {
- send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START_AND_CAPTURE;
- ipu6_fw_isys_dump_frame_buff_set(dev, buf,
- stream_cfg->nof_output_pins);
- ret = ipu6_fw_isys_complex_cmd(av->isys, stream->stream_handle,
- buf, msg->dma_addr,
- sizeof(*buf), send_type);
- } else {
- send_type = IPU6_FW_ISYS_SEND_TYPE_STREAM_START;
- ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
- send_type);
- }
+ ret = ipu6_fw_isys_stream_start(av->isys, stream->stream_handle, msg,
+ capture);
if (ret < 0) {
dev_err(dev, "can't start streaming (%d)\n", ret);
@@ -635,9 +538,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
out_stream_close:
reinit_completion(&stream->stream_close_completion);
- retout = ipu6_fw_isys_simple_cmd(av->isys,
- stream->stream_handle,
- IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE);
+ retout = ipu6_fw_isys_stream_close(av->isys, stream->stream_handle);
if (retout < 0) {
dev_dbg(dev, "can't close stream (%d)\n", retout);
goto out_put_stream_opened;
@@ -666,9 +567,7 @@ static void stop_streaming_firmware(struct ipu6_isys_video *av)
reinit_completion(&stream->stream_stop_completion);
- ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
- IPU6_FW_ISYS_SEND_TYPE_STREAM_FLUSH);
-
+ ret = ipu6_fw_isys_stream_flush(av->isys, stream->stream_handle);
if (ret < 0) {
dev_err(dev, "can't stop stream (%d)\n", ret);
return;
@@ -692,8 +591,7 @@ static void close_streaming_firmware(struct ipu6_isys_video *av)
reinit_completion(&stream->stream_close_completion);
- ret = ipu6_fw_isys_simple_cmd(av->isys, stream->stream_handle,
- IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE);
+ ret = ipu6_fw_isys_stream_close(av->isys, stream->stream_handle);
if (ret < 0) {
dev_err(dev, "can't close stream (%d)\n", ret);
return;
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 21/44] media: ipu6: Add isys firmware ops
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (19 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 20/44] media: ipu6: Isolate hw specific buffer handling Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 22/44] media: ipu6: Add ipu7 fw start/stop functionality Antti Laakso
` (22 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
Add struct for ipu6 firmware ops. This is a preparation to
add support for ipu7 firmware communication.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-bus.h | 3 +
drivers/media/pci/intel/ipu6/ipu6-fw-isys.c | 71 +++++++++++--------
drivers/media/pci/intel/ipu6/ipu6-fw-isys.h | 38 +---------
.../media/pci/intel/ipu6/ipu6-isys-queue.c | 24 ++++---
.../media/pci/intel/ipu6/ipu6-isys-video.c | 35 +++++----
drivers/media/pci/intel/ipu6/ipu6-isys.c | 1 +
drivers/media/pci/intel/ipu6/ipu6-isys.h | 32 +++++++++
7 files changed, 116 insertions(+), 88 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-bus.h b/drivers/media/pci/intel/ipu6/ipu6-bus.h
index a08c5468d536..62aa2b090699 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-bus.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-bus.h
@@ -37,6 +37,7 @@ struct ipu6_auxdrv_data {
irqreturn_t (*isr)(struct ipu6_bus_device *adev);
irqreturn_t (*isr_threaded)(struct ipu6_bus_device *adev);
bool wake_isr_thread;
+ const struct ipu6_fw_isys_ops *fw_ops;
};
#define to_ipu6_bus_device(_dev) \
@@ -45,6 +46,8 @@ struct ipu6_auxdrv_data {
container_of(_auxdev, struct ipu6_bus_device, auxdev)
#define ipu6_bus_get_drvdata(adev) dev_get_drvdata(&(adev)->auxdev.dev)
+extern const struct ipu6_fw_isys_ops ipu6_fw_isys_ops;
+
struct ipu6_bus_device *
ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent,
void *pdata, const struct ipu6_buttress_ctrl *ctrl,
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
index 9256ea3b68c1..4ee5137f310e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
@@ -126,7 +126,7 @@ static int ipu6_fw_isys_complex_cmd(struct ipu6_isys *isys,
return 0;
}
-int ipu6_fw_isys_close(struct ipu6_isys *isys)
+static int ipu6_fw_isys_close(struct ipu6_isys *isys)
{
struct device *dev = &isys->adev->auxdev.dev;
int retry = IPU6_ISYS_CLOSE_RETRY;
@@ -165,7 +165,7 @@ int ipu6_fw_isys_close(struct ipu6_isys *isys)
return ret;
}
-void ipu6_fw_isys_cleanup(struct ipu6_isys *isys)
+static void ipu6_fw_isys_cleanup(struct ipu6_isys *isys)
{
int ret;
@@ -316,7 +316,7 @@ static int ipu6_isys_fwcom_cfg_init(struct ipu6_isys *isys,
return 0;
}
-int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
+static int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
{
struct device *dev = &isys->adev->auxdev.dev;
int retry = IPU6_ISYS_OPEN_RETRY;
@@ -358,18 +358,19 @@ int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
return ret;
}
-struct ipu6_fw_isys_resp_info_abi *
+static struct ipu6_fw_isys_resp_info_abi *
ipu6_fw_isys_get_resp(struct ipu6_isys *isys)
{
return ipu6_recv_get_token(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
}
-void ipu6_fw_isys_put_resp(struct ipu6_isys *isys)
+static void ipu6_fw_isys_put_resp(struct ipu6_isys *isys)
{
ipu6_recv_put_token(isys->fwctx, IPU6_BASE_MSG_RECV_QUEUES);
}
-void ipu6_fw_isys_dump_stream_cfg(struct device *dev, struct isys_fw_msgs *msg)
+static void ipu6_fw_isys_dump_stream_cfg(struct device *dev,
+ struct isys_fw_msgs *msg)
{
struct ipu6_fw_isys_stream_cfg_data_abi *cfg = &msg->ipu6.stream;
unsigned int i;
@@ -446,9 +447,9 @@ void ipu6_fw_isys_dump_stream_cfg(struct device *dev, struct isys_fw_msgs *msg)
dev_dbg(dev, "-----------------------------------------------------\n");
}
-void
-ipu6_fw_isys_dump_frame_buff_set(struct device *dev, struct isys_fw_msgs *msg,
- unsigned int outputs)
+static void
+ipu6_fw_isys_dump_frame_buf_set(struct device *dev, struct isys_fw_msgs *msg,
+ unsigned int outputs)
{
struct ipu6_fw_isys_frame_buff_set_abi *buf;
unsigned int i;
@@ -820,8 +821,8 @@ static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av,
return 0;
}
-int ipu6_fw_isys_prepare_stream_cfg(struct ipu6_isys_video *av,
- struct isys_fw_msgs *msg)
+static int ipu6_fw_isys_prepare_stream_cfg(struct ipu6_isys_video *av,
+ struct isys_fw_msgs *msg)
{
struct ipu6_fw_isys_stream_cfg_data_abi *stream_cfg;
struct device *dev = &av->isys->adev->auxdev.dev;
@@ -850,9 +851,9 @@ int ipu6_fw_isys_prepare_stream_cfg(struct ipu6_isys_video *av,
return 0;
}
-int ipu6_fw_isys_stream_open(struct ipu6_isys *isys,
- const unsigned int stream_handle,
- struct isys_fw_msgs *msg)
+static int ipu6_fw_isys_stream_open(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ struct isys_fw_msgs *msg)
{
return ipu6_fw_isys_complex_cmd(isys, stream_handle,
&msg->ipu6.stream, msg->dma_addr,
@@ -860,23 +861,23 @@ int ipu6_fw_isys_stream_open(struct ipu6_isys *isys,
IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN);
}
-int ipu6_fw_isys_stream_close(struct ipu6_isys *isys,
- const unsigned int stream_handle)
+static int ipu6_fw_isys_stream_close(struct ipu6_isys *isys,
+ const unsigned int stream_handle)
{
return ipu6_fw_isys_complex_cmd(isys, stream_handle, NULL, 0, 0,
IPU6_FW_ISYS_SEND_TYPE_STREAM_CLOSE);
}
-int ipu6_fw_isys_stream_flush(struct ipu6_isys *isys,
- const unsigned int stream_handle)
+static int ipu6_fw_isys_stream_flush(struct ipu6_isys *isys,
+ const unsigned int stream_handle)
{
return ipu6_fw_isys_complex_cmd(isys, stream_handle, NULL, 0, 0,
IPU6_FW_ISYS_SEND_TYPE_STREAM_FLUSH);
}
-int ipu6_fw_isys_stream_start(struct ipu6_isys *isys,
- const unsigned int stream_handle,
- struct isys_fw_msgs *msg, bool capture)
+static int ipu6_fw_isys_stream_start(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ struct isys_fw_msgs *msg, bool capture)
{
u16 cmd_type;
@@ -890,9 +891,9 @@ int ipu6_fw_isys_stream_start(struct ipu6_isys *isys,
sizeof(msg->ipu6.stream), cmd_type);
}
-int ipu6_fw_isys_stream_capture(struct ipu6_isys *isys,
- const unsigned int stream_handle,
- struct isys_fw_msgs *msg)
+static int ipu6_fw_isys_stream_capture(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ struct isys_fw_msgs *msg)
{
return ipu6_fw_isys_complex_cmd(isys, stream_handle,
&msg->ipu6.stream, msg->dma_addr,
@@ -918,10 +919,9 @@ ipu6_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb,
* buffer list is not modified.
*/
#define IPU6_ISYS_FRAME_NUM_THRESHOLD (30)
-void
-ipu6_fw_isys_prepare_buf_set(struct isys_fw_msgs *msg,
- struct ipu6_isys_stream *stream,
- struct ipu6_isys_buffer_list *bl)
+static void ipu6_fw_isys_prepare_buf_set(struct isys_fw_msgs *msg,
+ struct ipu6_isys_stream *stream,
+ struct ipu6_isys_buffer_list *bl)
{
struct ipu6_fw_isys_frame_buff_set_abi *set = &msg->ipu6.frame;
struct ipu6_isys_buffer *ib;
@@ -952,3 +952,18 @@ ipu6_fw_isys_prepare_buf_set(struct isys_fw_msgs *msg,
ipu6_isys_buf_to_fw_frame_buf_pin(vb, set);
}
}
+
+const struct ipu6_fw_isys_ops ipu6_fw_isys_ops = {
+ .init = ipu6_fw_isys_init,
+ .close = ipu6_fw_isys_close,
+ .cleanup = ipu6_fw_isys_cleanup,
+ .prepare_stream_cfg = ipu6_fw_isys_prepare_stream_cfg,
+ .prepare_buf_set = ipu6_fw_isys_prepare_buf_set,
+ .stream_open = ipu6_fw_isys_stream_open,
+ .stream_start = ipu6_fw_isys_stream_start,
+ .stream_capture = ipu6_fw_isys_stream_capture,
+ .stream_flush = ipu6_fw_isys_stream_flush,
+ .stream_close = ipu6_fw_isys_stream_close,
+ .dump_stream_cfg = ipu6_fw_isys_dump_stream_cfg,
+ .dump_frame_buf_set = ipu6_fw_isys_dump_frame_buf_set,
+};
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
index b589ae7fbd4e..2a679d995961 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.h
@@ -559,42 +559,10 @@ struct ipu6_fw_proxy_send_queue_token {
u32 value;
};
-int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams);
-int ipu6_fw_isys_close(struct ipu6_isys *isys);
-int ipu6_fw_isys_send_proxy_token(struct ipu6_isys *isys,
- unsigned int req_id,
- unsigned int index,
- unsigned int offset, u32 value);
-void ipu6_fw_isys_cleanup(struct ipu6_isys *isys);
-struct ipu6_fw_isys_resp_info_abi *
-ipu6_fw_isys_get_resp(struct ipu6_isys *isys);
-void ipu6_fw_isys_put_resp(struct ipu6_isys *isys);
+int ipu6_fw_isys_send_proxy_token(struct ipu6_isys *isys, unsigned int req_id,
+ unsigned int index, unsigned int offset,
+ u32 value);
int ipu6_isys_isr_one(struct ipu6_bus_device *adev);
irqreturn_t ipu6_isys_isr(struct ipu6_bus_device *adev);
-int ipu6_fw_isys_stream_open(struct ipu6_isys *isys,
- const unsigned int stream_handle,
- struct isys_fw_msgs *msg);
-int ipu6_fw_isys_stream_close(struct ipu6_isys *isys,
- const unsigned int stream_handle);
-int ipu6_fw_isys_stream_flush(struct ipu6_isys *isys,
- const unsigned int stream_handle);
-int ipu6_fw_isys_stream_start(struct ipu6_isys *isys,
- const unsigned int stream_handle,
- struct isys_fw_msgs *msg, bool capture);
-int ipu6_fw_isys_stream_capture(struct ipu6_isys *isys,
- const unsigned int stream_handle,
- struct isys_fw_msgs *msg);
-int ipu6_fw_isys_prepare_stream_cfg(struct ipu6_isys_video *av,
- struct isys_fw_msgs *msg);
-void
-ipu6_fw_isys_prepare_buf_set(struct isys_fw_msgs *msg,
- struct ipu6_isys_stream *stream,
- struct ipu6_isys_buffer_list *bl);
-void
-ipu6_fw_isys_dump_stream_cfg(struct device *dev, struct isys_fw_msgs *set);
-void
-ipu6_fw_isys_dump_frame_buff_set(struct device *dev, struct isys_fw_msgs *set,
- unsigned int outputs);
-
#endif
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
index 9f6f283600c8..4cb1741445c6 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
@@ -237,8 +237,10 @@ static int buffer_list_get(struct ipu6_isys_stream *stream,
static int ipu6_isys_stream_start(struct ipu6_isys_video *av,
struct ipu6_isys_buffer_list *bl)
{
+ struct ipu6_bus_device *adev = av->isys->adev;
+ const struct ipu6_fw_isys_ops *fw_ops = adev->auxdrv_data->fw_ops;
struct ipu6_isys_stream *stream = av->stream;
- struct device *dev = &stream->isys->adev->auxdev.dev;
+ struct device *dev = &adev->auxdev.dev;
struct ipu6_isys_buffer_list __bl;
int ret;
@@ -262,14 +264,13 @@ static int ipu6_isys_stream_start(struct ipu6_isys_video *av,
if (!msg)
return -ENOMEM;
- ipu6_fw_isys_prepare_buf_set(msg, stream, bl);
- ipu6_fw_isys_dump_frame_buff_set(dev, msg,
- stream->nr_output_pins);
+ fw_ops->prepare_buf_set(msg, stream, bl);
+ fw_ops->dump_frame_buf_set(dev, msg, stream->nr_output_pins);
ipu6_isys_buffer_list_queue(bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE,
0);
- ret = ipu6_fw_isys_stream_capture(stream->isys,
- stream->stream_handle, msg);
+ ret = fw_ops->stream_capture(stream->isys,
+ stream->stream_handle, msg);
} while (!WARN_ON(ret));
return 0;
@@ -288,11 +289,13 @@ static void buf_queue(struct vb2_buffer *vb)
{
struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
+ struct ipu6_bus_device *adev = av->isys->adev;
+ const struct ipu6_fw_isys_ops *fw_ops = adev->auxdrv_data->fw_ops;
struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
struct ipu6_isys_video_buffer *ivb =
vb2_buffer_to_ipu6_isys_video_buffer(vvb);
struct ipu6_isys_buffer *ib = &ivb->ib;
- struct device *dev = &av->isys->adev->auxdev.dev;
+ struct device *dev = &adev->auxdev.dev;
struct ipu6_isys_stream *stream = av->stream;
struct ipu6_isys_buffer_list bl;
struct isys_fw_msgs *msg;
@@ -339,8 +342,8 @@ static void buf_queue(struct vb2_buffer *vb)
goto out;
}
- ipu6_fw_isys_prepare_buf_set(msg, stream, &bl);
- ipu6_fw_isys_dump_frame_buff_set(dev, msg, stream->nr_output_pins);
+ fw_ops->prepare_buf_set(msg, stream, &bl);
+ fw_ops->dump_frame_buf_set(dev, msg, stream->nr_output_pins);
/*
* We must queue the buffers in the buffer list to the
@@ -350,8 +353,7 @@ static void buf_queue(struct vb2_buffer *vb)
*/
ipu6_isys_buffer_list_queue(&bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
- ret = ipu6_fw_isys_stream_capture(stream->isys, stream->stream_handle,
- msg);
+ ret = fw_ops->stream_capture(stream->isys, stream->stream_handle, msg);
if (ret < 0)
dev_err(dev, "send stream capture failed\n");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index a6e50263f8da..803450b0156e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -453,8 +453,10 @@ static void put_stream_opened(struct ipu6_isys_video *av)
static int start_stream_firmware(struct ipu6_isys_video *av,
struct ipu6_isys_buffer_list *bl)
{
+ struct ipu6_bus_device *adev = av->isys->adev;
+ const struct ipu6_fw_isys_ops *fw_ops = adev->auxdrv_data->fw_ops;
struct ipu6_isys_stream *stream = av->stream;
- struct device *dev = &av->isys->adev->auxdev.dev;
+ struct device *dev = &adev->auxdev.dev;
struct isys_fw_msgs *msg = NULL;
int ret, retout, tout;
bool capture = bl ? true : false;
@@ -463,7 +465,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
if (!msg)
return -ENOMEM;
- ret = ipu6_fw_isys_prepare_stream_cfg(av, msg);
+ ret = fw_ops->prepare_stream_cfg(av, msg);
if (ret < 0) {
ipu6_put_fw_msg_buf(av->isys, msg);
return ret;
@@ -471,7 +473,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
reinit_completion(&stream->stream_open_completion);
- ret = ipu6_fw_isys_stream_open(av->isys, stream->stream_handle, msg);
+ ret = fw_ops->stream_open(av->isys, stream->stream_handle, msg);
if (ret < 0) {
dev_err(dev, "can't open stream (%d)\n", ret);
ipu6_put_fw_msg_buf(av->isys, msg);
@@ -504,15 +506,15 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
goto out_put_stream_opened;
}
- ipu6_fw_isys_prepare_buf_set(msg, stream, bl);
+ fw_ops->prepare_buf_set(msg, stream, bl);
ipu6_isys_buffer_list_queue(bl,
IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
}
reinit_completion(&stream->stream_start_completion);
- ret = ipu6_fw_isys_stream_start(av->isys, stream->stream_handle, msg,
- capture);
+ ret = fw_ops->stream_start(av->isys, stream->stream_handle, msg,
+ capture);
if (ret < 0) {
dev_err(dev, "can't start streaming (%d)\n", ret);
@@ -538,7 +540,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
out_stream_close:
reinit_completion(&stream->stream_close_completion);
- retout = ipu6_fw_isys_stream_close(av->isys, stream->stream_handle);
+ retout = fw_ops->stream_close(av->isys, stream->stream_handle);
if (retout < 0) {
dev_dbg(dev, "can't close stream (%d)\n", retout);
goto out_put_stream_opened;
@@ -561,13 +563,15 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
static void stop_streaming_firmware(struct ipu6_isys_video *av)
{
- struct device *dev = &av->isys->adev->auxdev.dev;
+ struct ipu6_bus_device *adev = av->isys->adev;
+ const struct ipu6_fw_isys_ops *fw_ops = adev->auxdrv_data->fw_ops;
+ struct device *dev = &adev->auxdev.dev;
struct ipu6_isys_stream *stream = av->stream;
int ret, tout;
reinit_completion(&stream->stream_stop_completion);
- ret = ipu6_fw_isys_stream_flush(av->isys, stream->stream_handle);
+ ret = fw_ops->stream_flush(av->isys, stream->stream_handle);
if (ret < 0) {
dev_err(dev, "can't stop stream (%d)\n", ret);
return;
@@ -585,13 +589,15 @@ static void stop_streaming_firmware(struct ipu6_isys_video *av)
static void close_streaming_firmware(struct ipu6_isys_video *av)
{
+ struct ipu6_bus_device *adev = av->isys->adev;
+ const struct ipu6_fw_isys_ops *fw_ops = adev->auxdrv_data->fw_ops;
struct ipu6_isys_stream *stream = av->stream;
- struct device *dev = &av->isys->adev->auxdev.dev;
+ struct device *dev = &adev->auxdev.dev;
int ret, tout;
reinit_completion(&stream->stream_close_completion);
- ret = ipu6_fw_isys_stream_close(av->isys, stream->stream_handle);
+ ret = fw_ops->stream_close(av->isys, stream->stream_handle);
if (ret < 0) {
dev_err(dev, "can't close stream (%d)\n", ret);
return;
@@ -990,6 +996,7 @@ static const struct v4l2_file_operations isys_fops = {
int ipu6_isys_fw_open(struct ipu6_isys *isys)
{
struct ipu6_bus_device *adev = isys->adev;
+ const struct ipu6_fw_isys_ops *fw_ops = adev->auxdrv_data->fw_ops;
const struct ipu6_isys_internal_pdata *ipdata = isys->pdata->ipdata;
int ret;
@@ -1018,10 +1025,10 @@ int ipu6_isys_fw_open(struct ipu6_isys *isys)
* restarting isys we can safely delete old context.
*/
dev_warn(&adev->auxdev.dev, "clearing old context\n");
- ipu6_fw_isys_cleanup(isys);
+ fw_ops->cleanup(isys);
}
- ret = ipu6_fw_isys_init(isys, ipdata->num_parallel_streams);
+ ret = fw_ops->init(isys, ipdata->num_parallel_streams);
if (ret < 0)
goto out;
@@ -1044,7 +1051,7 @@ void ipu6_isys_fw_close(struct ipu6_isys *isys)
isys->ref_count--;
if (!isys->ref_count) {
- ipu6_fw_isys_close(isys);
+ isys->adev->auxdrv_data->fw_ops->close(isys);
if (isys->fwctx) {
isys->need_reset = true;
dev_warn(&isys->adev->auxdev.dev,
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index bb3c0d6bc6c9..159e769931b7 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -1068,6 +1068,7 @@ static const struct ipu6_auxdrv_data ipu6_isys_auxdrv_data = {
.isr = ipu6_isys_isr,
.isr_threaded = NULL,
.wake_isr_thread = false,
+ .fw_ops = &ipu6_fw_isys_ops,
};
static const struct auxiliary_device_id ipu6_isys_id_table[] = {
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h
index f39566513a87..fa9bc2730d64 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h
@@ -174,6 +174,38 @@ struct isys_fw_msgs {
dma_addr_t dma_addr;
};
+struct ipu6_fw_isys_ops {
+ int (*init)(struct ipu6_isys *isys, unsigned int num_streams);
+ int (*close)(struct ipu6_isys *isys);
+ int (*send_cmd)(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ void *cpu_mapped_buf,
+ dma_addr_t dma_mapped_buf,
+ size_t size, u16 send_type);
+ void (*cleanup)(struct ipu6_isys *isys);
+ int (*prepare_stream_cfg)(struct ipu6_isys_video *av,
+ struct isys_fw_msgs *msg);
+ void (*prepare_buf_set)(struct isys_fw_msgs *msg,
+ struct ipu6_isys_stream *stream,
+ struct ipu6_isys_buffer_list *bl);
+ int (*stream_open)(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ struct isys_fw_msgs *msg);
+ int (*stream_start)(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ struct isys_fw_msgs *msg, bool capture);
+ int (*stream_capture)(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ struct isys_fw_msgs *msg);
+ int (*stream_flush)(struct ipu6_isys *isys,
+ const unsigned int stream_handle);
+ int (*stream_close)(struct ipu6_isys *isys,
+ const unsigned int stream_handle);
+ void (*dump_stream_cfg)(struct device *dev, struct isys_fw_msgs *msg);
+ void (*dump_frame_buf_set)(struct device *dev, struct isys_fw_msgs *msg,
+ unsigned int outputs);
+};
+
struct isys_fw_msgs *ipu6_get_fw_msg_buf(struct ipu6_isys_stream *stream);
void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, struct isys_fw_msgs *msg);
void ipu6_cleanup_fw_msg_bufs(struct ipu6_isys *isys);
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 22/44] media: ipu6: Add ipu7 fw start/stop functionality
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (20 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 21/44] media: ipu6: Add isys firmware ops Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 23/44] media: ipu6: Add ipu7 fw com methods Antti Laakso
` (21 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The ipu7 firmware start/stop sequence differs from ipu6. Add
ipu7-specific functions to handle this.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu7-boot.c | 405 ++++++++++++++++++
drivers/media/pci/intel/ipu6/ipu7-boot.h | 46 ++
.../media/pci/intel/ipu6/ipu7-platform-regs.h | 12 +
3 files changed, 463 insertions(+)
create mode 100644 drivers/media/pci/intel/ipu6/ipu7-boot.c
create mode 100644 drivers/media/pci/intel/ipu6/ipu7-boot.h
create mode 100644 drivers/media/pci/intel/ipu6/ipu7-platform-regs.h
diff --git a/drivers/media/pci/intel/ipu6/ipu7-boot.c b/drivers/media/pci/intel/ipu6/ipu7-boot.c
new file mode 100644
index 000000000000..5bd5281ec107
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-boot.c
@@ -0,0 +1,405 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 - 2026 Intel Corporation
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/iopoll.h>
+#include <linux/types.h>
+
+#include "ipu6.h"
+#include "ipu6-bus.h"
+#include "ipu6-buttress.h"
+#include "ipu6-dma.h"
+#include "ipu6-isys.h"
+#include "ipu6-platform-buttress-regs.h"
+#include "ipu7-boot.h"
+#include "ipu7-platform-regs.h"
+
+#define IPU7_FW_START_STOP_TIMEOUT 2000
+#define IPU7_BOOT_CELL_RESET_TIMEOUT (2 * USEC_PER_SEC)
+#define IPU7_BOOT_STATE_CRITICAL(s) (((s) & 0xffff0000U) == 0xdead0000U)
+#define IPU7_BOOT_STATE_READY(s) ((s) == 0x57a7e100U)
+#define IPU7_BOOT_STATE_INACTIVE(s) ((s) == 0x57a7e300U)
+#define IPU7_BUTTRESS_REG_FW_BOOT_PARAMS0 0x4000
+#define IPU7_BUTTRESS_FW_BOOT_PARAMS_ENTRY(i) \
+ (IPU7_BUTTRESS_REG_FW_BOOT_PARAMS0 + ((i) * 4U))
+
+struct boot_regs {
+ u32 base;
+ u32 dmem_address;
+ u32 status_ctrl_reg;
+ u32 fw_start_address_reg;
+ u32 fw_code_base_reg;
+};
+
+enum ipu7_boot_reg_id {
+ IPU7_FW_BOOT_CONFIG_ID = 0,
+ IPU7_FW_BOOT_STATE_ID = 1,
+ IPU7_FW_BOOT_SYSCOM_QUEUE_INDICES_BASE_ID = 2,
+ IPU7_FW_BOOT_UNTRUSTED_ADDR_MIN_ID = 3,
+ IPU7_FW_BOOT_MESSAGING_VERSION_ID = 4,
+ IPU7_FW_BOOT_ID_MAX,
+};
+
+enum ipu7_boot_state {
+ IPU7_FW_BOOT_STATE_UNINIT = 0x57a7e000U,
+ IPU7_FW_BOOT_STATE_READY = 0x57a7e100U,
+ IPU7_FW_BOOT_STATE_SHUTDOWN_CMD = 0x57a7f001U,
+ IPU7_FW_BOOT_STATE_INACTIVE = 0x57a7e300U,
+};
+
+static const struct boot_regs boot_regs[IPU_SUBSYS_NUM] = {
+ [IPU_ISYS] = {
+ .dmem_address = IPU7_ISYS_DMEM_OFFSET,
+ .status_ctrl_reg = IPU7_BUTTRESS_REG_ISYS_UCX_CTRL_STATUS,
+ .fw_start_address_reg = IPU7_BUTTRESS_REG_ISYS_UCX_START_ADDR,
+ .fw_code_base_reg = IPU7_IS_UC_CTRL_BASE
+ },
+ [IPU_PSYS] = {
+ .dmem_address = IPU7_PSYS_DMEM_OFFSET,
+ .status_ctrl_reg = IPU7_BUTTRESS_REG_PSYS_UCX_CTRL_STATUS,
+ .fw_start_address_reg = IPU7_BUTTRESS_REG_PSYS_UCX_START_ADDR,
+ .fw_code_base_reg = IPU7_PS_UC_CTRL_BASE
+ }
+};
+
+static u32 get_fw_boot_reg_addr(const struct ipu6_bus_device *adev,
+ enum ipu7_boot_reg_id reg)
+{
+ u32 base = (adev->ctrl->subsys_id == IPU_ISYS) ?
+ 0U : (u32)IPU7_FW_BOOT_ID_MAX;
+
+ return IPU7_BUTTRESS_FW_BOOT_PARAMS_ENTRY(base + (u32)reg);
+}
+
+static void write_fw_boot_param(const struct ipu6_bus_device *adev,
+ enum ipu7_boot_reg_id reg,
+ u32 val)
+{
+ void __iomem *base = adev->isp->base;
+
+ dev_dbg(&adev->auxdev.dev,
+ "write boot param reg: %d addr: %x val: 0x%x\n",
+ reg, get_fw_boot_reg_addr(adev, reg), val);
+ writel(val, base + get_fw_boot_reg_addr(adev, reg));
+}
+
+static u32 read_fw_boot_param(const struct ipu6_bus_device *adev,
+ enum ipu7_boot_reg_id reg)
+{
+ void __iomem *base = adev->isp->base;
+
+ return readl(base + get_fw_boot_reg_addr(adev, reg));
+}
+
+static int ipu7_boot_cell_reset(const struct ipu6_bus_device *adev)
+{
+ const struct device *dev = &adev->auxdev.dev;
+ const struct boot_regs *regs = &boot_regs[adev->ctrl->subsys_id];
+ u32 ucx_ctrl_status = regs->status_ctrl_reg;
+ u32 timeout = IPU7_BOOT_CELL_RESET_TIMEOUT;
+ void __iomem *base = adev->isp->base;
+ u32 val, val2;
+ int ret;
+
+ val = readl(base + ucx_ctrl_status);
+ val |= IPU7_UCX_CTL_RESET;
+ val &= ~IPU7_UCX_CTL_RUN;
+
+ writel(val, base + ucx_ctrl_status);
+
+ ret = readl_poll_timeout(base + ucx_ctrl_status, val2,
+ (val2 & 0x3U) == (val & 0x3U), 100, timeout);
+ if (ret) {
+ dev_err(dev, "cell enter reset timeout. status: 0x%x\n", val2);
+ return -ETIMEDOUT;
+ }
+
+ val = readl(base + ucx_ctrl_status);
+ val &= ~(IPU7_UCX_CTL_RESET | IPU7_UCX_CTL_RUN);
+ writel(val, base + ucx_ctrl_status);
+
+ ret = readl_poll_timeout(base + ucx_ctrl_status, val2,
+ (val2 & 0x3U) == (val & 0x3U), 100, timeout);
+ if (ret) {
+ dev_err(dev, "cell exit reset timeout. status: 0x%x\n", val2);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static void ipu7_boot_cell_start(const struct ipu6_bus_device *adev)
+{
+ const struct boot_regs *regs = &boot_regs[adev->ctrl->subsys_id];
+ void __iomem *base = adev->isp->base;
+ u32 val;
+
+ val = readl(base + regs->status_ctrl_reg);
+ WARN_ON(val & (IPU7_UCX_CTL_RESET | IPU7_UCX_CTL_RUN));
+
+ val &= ~IPU7_UCX_CTL_RESET;
+ val |= IPU7_UCX_CTL_RUN;
+ writel(val, base + regs->status_ctrl_reg);
+}
+
+static void ipu7_boot_cell_stop(const struct ipu6_bus_device *adev)
+{
+ const struct boot_regs *regs = &boot_regs[adev->ctrl->subsys_id];
+ void __iomem *base = adev->isp->base;
+ u32 val;
+
+ val = readl(base + regs->status_ctrl_reg);
+ val &= ~IPU7_UCX_CTL_RUN;
+ writel(val, base + regs->status_ctrl_reg);
+
+ /* Wait for uC transactions complete */
+ usleep_range(10, 20);
+
+ val = readl(base + regs->status_ctrl_reg);
+ val |= IPU7_UCX_CTL_RESET;
+ writel(val, base + regs->status_ctrl_reg);
+}
+
+static int ipu7_boot_cell_init(const struct ipu6_bus_device *adev)
+{
+ const struct boot_regs *regs = &boot_regs[adev->ctrl->subsys_id];
+ struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
+ struct ipu7_fw_com_context *fwctx = isys->fwctx;
+ void __iomem *base = adev->isp->base;
+
+ writel(fwctx->fw_entry, base + regs->fw_start_address_reg);
+
+ return ipu7_boot_cell_reset(adev);
+}
+
+static void init_cfg_versions(struct ipu7_boot_abi_cfg *boot_cfg, u32 length, u8 major)
+{
+ boot_cfg->length = length;
+ boot_cfg->config_version.major = 1U;
+ boot_cfg->config_version.minor = 0U;
+ boot_cfg->config_version.subminor = 0U;
+ boot_cfg->config_version.patch = 0U;
+
+ boot_cfg->client_version_support.num_versions = 1U;
+ boot_cfg->client_version_support.versions[0].major = major;
+ boot_cfg->client_version_support.versions[0].minor = 0U;
+ boot_cfg->client_version_support.versions[0].subminor = 0U;
+ boot_cfg->client_version_support.versions[0].patch = 0U;
+}
+
+int ipu7_init_boot_config(struct ipu6_bus_device *adev,
+ struct ipu7_fw_com_queue_config *qconfigs,
+ int num_queues, u32 uc_freq,
+ dma_addr_t subsys_config, u8 major)
+{
+ struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
+ struct ipu7_fw_com_context *fwctx = isys->fwctx;
+ struct ipu7_boot_abi_cfg *boot_config;
+ struct ipu7_fw_com_queue_params_config *cfgs;
+ struct device *dev = &adev->auxdev.dev;
+ u32 total_queue_size_aligned = 0;
+ dma_addr_t queue_mem_dma_ptr;
+ void *queue_mem_ptr;
+ unsigned int i;
+
+ /* Allocate boot config. */
+ fwctx->boot_config_size =
+ sizeof(*cfgs) * num_queues + sizeof(*boot_config);
+ fwctx->boot_config = ipu6_dma_alloc(adev, fwctx->boot_config_size,
+ &fwctx->boot_config_dma_addr,
+ GFP_KERNEL, 0);
+ if (!fwctx->boot_config) {
+ dev_err(dev, "Failed to allocate boot config.\n");
+ return -ENOMEM;
+ }
+
+ boot_config = fwctx->boot_config;
+ memset(boot_config, 0, sizeof(*boot_config));
+ init_cfg_versions(boot_config, fwctx->boot_config_size, major);
+ boot_config->subsys_config = subsys_config;
+
+ boot_config->uc_tile_frequency = uc_freq;
+ boot_config->uc_tile_frequency_units = 0;
+ boot_config->fw_com_config.max_output_queues =
+ fwctx->num_output_queues;
+ boot_config->fw_com_config.max_input_queues =
+ fwctx->num_input_queues;
+
+ ipu6_dma_sync_single(adev, fwctx->boot_config_dma_addr,
+ fwctx->boot_config_size);
+
+ for (i = 0; i < num_queues; i++) {
+ u32 queue_size = qconfigs[i].max_capacity *
+ qconfigs[i].token_size_in_bytes;
+
+ queue_size = ALIGN(queue_size, 64U);
+ total_queue_size_aligned += queue_size;
+ qconfigs[i].queue_size = queue_size;
+ }
+
+ /* Allocate queue memory */
+ fwctx->queue_mem = ipu6_dma_alloc(adev, total_queue_size_aligned,
+ &fwctx->queue_mem_dma_addr,
+ GFP_KERNEL, 0);
+ if (!fwctx->queue_mem) {
+ dev_err(dev, "Failed to allocate queue memory.\n");
+ return -ENOMEM;
+ }
+ fwctx->queue_mem_size = total_queue_size_aligned;
+
+ cfgs = ipu7_fw_com_get_queue_config(&boot_config->fw_com_config);
+ queue_mem_ptr = fwctx->queue_mem;
+ queue_mem_dma_ptr = fwctx->queue_mem_dma_addr;
+ for (i = 0; i < num_queues; i++) {
+ cfgs[i].token_array_mem = queue_mem_dma_ptr;
+ cfgs[i].max_capacity = qconfigs[i].max_capacity;
+ cfgs[i].token_size_in_bytes = qconfigs[i].token_size_in_bytes;
+ qconfigs[i].token_array_mem = queue_mem_ptr;
+ queue_mem_dma_ptr += qconfigs[i].queue_size;
+ queue_mem_ptr += qconfigs[i].queue_size;
+ }
+
+ ipu6_dma_sync_single(adev, fwctx->queue_mem_dma_addr,
+ total_queue_size_aligned);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_init_boot_config, "INTEL_IPU6");
+
+void ipu7_release_boot_config(struct ipu6_bus_device *adev)
+{
+ struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
+ struct ipu7_fw_com_context *fwctx;
+
+ if (!isys || !isys->fwctx)
+ return;
+
+ fwctx = isys->fwctx;
+
+ if (fwctx->queue_mem) {
+ ipu6_dma_free(adev, fwctx->queue_mem_size,
+ fwctx->queue_mem,
+ fwctx->queue_mem_dma_addr, 0);
+ fwctx->queue_mem = NULL;
+ fwctx->queue_mem_dma_addr = 0;
+ }
+
+ if (fwctx->boot_config) {
+ ipu6_dma_free(adev, fwctx->boot_config_size,
+ fwctx->boot_config,
+ fwctx->boot_config_dma_addr, 0);
+ fwctx->boot_config = NULL;
+ fwctx->boot_config_dma_addr = 0;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_release_boot_config, "INTEL_IPU6");
+
+int ipu7_boot_start_fw(const struct ipu6_bus_device *adev)
+{
+ const struct device *dev = &adev->auxdev.dev;
+ struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
+ struct ipu7_fw_com_context *fwctx = isys->fwctx;
+ u32 timeout = IPU7_FW_START_STOP_TIMEOUT;
+ void __iomem *base = adev->isp->base;
+ u32 boot_state, last_boot_state;
+ u32 indices_addr, msg_ver, id;
+ int ret;
+
+ ret = ipu7_boot_cell_init(adev);
+ if (ret)
+ return ret;
+
+ /* store "uninit" state to boot state reg */
+ write_fw_boot_param(adev, IPU7_FW_BOOT_STATE_ID,
+ IPU7_FW_BOOT_STATE_UNINIT);
+ /* Set registers to zero, recommended for diagnostics. */
+ write_fw_boot_param(adev,
+ IPU7_FW_BOOT_SYSCOM_QUEUE_INDICES_BASE_ID, 0);
+ write_fw_boot_param(adev, IPU7_FW_BOOT_MESSAGING_VERSION_ID, 0);
+ /* store firmware configuration address */
+ write_fw_boot_param(adev, IPU7_FW_BOOT_CONFIG_ID,
+ fwctx->boot_config_dma_addr);
+
+ ipu7_boot_cell_start(adev);
+
+ last_boot_state = IPU7_FW_BOOT_STATE_UNINIT;
+ while (timeout--) {
+ boot_state = read_fw_boot_param(adev,
+ IPU7_FW_BOOT_STATE_ID);
+ if (boot_state != last_boot_state) {
+ dev_dbg(dev, "boot state changed from 0x%x to 0x%x\n",
+ last_boot_state, boot_state);
+ last_boot_state = boot_state;
+ }
+ if (IPU7_BOOT_STATE_CRITICAL(boot_state) ||
+ IPU7_BOOT_STATE_READY(boot_state))
+ break;
+ usleep_range(1000, 1200);
+ }
+
+ if (IPU7_BOOT_STATE_CRITICAL(boot_state)) {
+ dev_err(dev, "critical boot state error 0x%x\n", boot_state);
+ return -EINVAL;
+ } else if (!IPU7_BOOT_STATE_READY(boot_state)) {
+ dev_err(dev, "fw boot timeout. state: 0x%x\n", boot_state);
+ return -ETIMEDOUT;
+ }
+ dev_dbg(dev, "fw boot done.\n");
+
+ id = IPU7_FW_BOOT_SYSCOM_QUEUE_INDICES_BASE_ID;
+ indices_addr = read_fw_boot_param(adev, id);
+ fwctx->queue_indices = base + indices_addr;
+ dev_dbg(dev, "fw queue indices offset is 0x%x\n", indices_addr);
+
+ msg_ver = read_fw_boot_param(adev,
+ IPU7_FW_BOOT_MESSAGING_VERSION_ID);
+ dev_dbg(dev, "ipu message version is 0x%08x\n", msg_ver);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_boot_start_fw, "INTEL_IPU6");
+
+int ipu7_boot_stop_fw(const struct ipu6_bus_device *adev)
+{
+ const struct device *dev = &adev->auxdev.dev;
+ u32 timeout = IPU7_FW_START_STOP_TIMEOUT;
+ u32 boot_state;
+
+ boot_state = read_fw_boot_param(adev, IPU7_FW_BOOT_STATE_ID);
+ if (IPU7_BOOT_STATE_CRITICAL(boot_state) ||
+ !IPU7_BOOT_STATE_READY(boot_state)) {
+ dev_err(dev, "fw not ready for shutdown, state 0x%x\n",
+ boot_state);
+ return -EBUSY;
+ }
+
+ /* Issue shutdown to start shutdown process */
+ dev_dbg(dev, "stopping fw...\n");
+ write_fw_boot_param(adev, IPU7_FW_BOOT_STATE_ID,
+ IPU7_FW_BOOT_STATE_SHUTDOWN_CMD);
+ while (timeout--) {
+ boot_state = read_fw_boot_param(adev,
+ IPU7_FW_BOOT_STATE_ID);
+ if (IPU7_BOOT_STATE_CRITICAL(boot_state) ||
+ IPU7_BOOT_STATE_INACTIVE(boot_state))
+ break;
+ usleep_range(1000, 1200);
+ }
+
+ if (IPU7_BOOT_STATE_CRITICAL(boot_state)) {
+ dev_err(dev, "critical boot state error 0x%x\n", boot_state);
+ return -EINVAL;
+ } else if (!IPU7_BOOT_STATE_INACTIVE(boot_state)) {
+ dev_err(dev, "stop fw timeout. state: 0x%x\n", boot_state);
+ return -ETIMEDOUT;
+ }
+
+ ipu7_boot_cell_stop(adev);
+ dev_dbg(dev, "stop fw done.\n");
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_boot_stop_fw, "INTEL_IPU6");
diff --git a/drivers/media/pci/intel/ipu6/ipu7-boot.h b/drivers/media/pci/intel/ipu6/ipu7-boot.h
new file mode 100644
index 000000000000..242ad70a385d
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-boot.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2026 Intel Corporation */
+
+#ifndef IPU7_BOOT_H
+#define IPU7_BOOT_H
+
+#include "ipu7-fw-com.h"
+
+#define IPU7_BOOT_MSG_VER_MAX_ENTRIES 3U
+
+struct ipu7_boot_abi_version {
+ u8 patch;
+ u8 subminor;
+ u8 minor;
+ u8 major;
+};
+
+struct ipu7_boot_abi_msg_versions {
+ u8 num_versions;
+ u8 reserved[3];
+ struct ipu7_boot_abi_version versions[IPU7_BOOT_MSG_VER_MAX_ENTRIES];
+};
+
+struct ipu7_boot_abi_cfg {
+ u32 length;
+ struct ipu7_boot_abi_version config_version;
+ struct ipu7_boot_abi_msg_versions client_version_support;
+ u32 pkg_dir;
+ u32 subsys_config;
+ u32 uc_tile_frequency;
+ u16 checksum;
+ u8 uc_tile_frequency_units;
+ u8 padding[1];
+ u32 reserved[58];
+ struct ipu7_fw_com_config fw_com_config;
+} __packed;
+
+int ipu7_init_boot_config(struct ipu6_bus_device *adev,
+ struct ipu7_fw_com_queue_config *qconfigs,
+ int num_queues, u32 uc_freq,
+ dma_addr_t subsys_config, u8 major);
+void ipu7_release_boot_config(struct ipu6_bus_device *adev);
+int ipu7_boot_start_fw(const struct ipu6_bus_device *adev);
+int ipu7_boot_stop_fw(const struct ipu6_bus_device *adev);
+
+#endif
diff --git a/drivers/media/pci/intel/ipu6/ipu7-platform-regs.h b/drivers/media/pci/intel/ipu6/ipu7-platform-regs.h
new file mode 100644
index 000000000000..3ca9d65e58b9
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-platform-regs.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2026 Intel Corporation */
+
+#ifndef IPU7_PLATFORM_REGS_H
+#define IPU7_PLATFORM_REGS_H
+
+#define IPU7_IS_UC_CTRL_BASE 0x230000
+#define IPU7_ISYS_DMEM_OFFSET 0x200000
+#define IPU7_PS_UC_CTRL_BASE 0x130000
+#define IPU7_PSYS_DMEM_OFFSET 0x100000
+
+#endif
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 23/44] media: ipu6: Add ipu7 fw com methods
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (21 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 22/44] media: ipu6: Add ipu7 fw start/stop functionality Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 24/44] media: ipu6: Add ipu7 fw isys ops Antti Laakso
` (20 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The get/put token methods read/write to ipu7 firmware message queues.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/Makefile | 4 +-
drivers/media/pci/intel/ipu6/ipu7-fw-com.c | 74 ++++++++++++++++++++++
drivers/media/pci/intel/ipu6/ipu7-fw-com.h | 51 +++++++++++++++
3 files changed, 128 insertions(+), 1 deletion(-)
create mode 100644 drivers/media/pci/intel/ipu6/ipu7-fw-com.c
create mode 100644 drivers/media/pci/intel/ipu6/ipu7-fw-com.h
diff --git a/drivers/media/pci/intel/ipu6/Makefile b/drivers/media/pci/intel/ipu6/Makefile
index c0daf0995b22..406e2e19df17 100644
--- a/drivers/media/pci/intel/ipu6/Makefile
+++ b/drivers/media/pci/intel/ipu6/Makefile
@@ -8,7 +8,9 @@ intel-ipu6-y := ipu6.o \
ipu7-mmu-hw.o \
ipu6-buttress.o \
ipu6-cpd.o \
- ipu6-fw-com.o
+ ipu6-fw-com.o \
+ ipu7-fw-com.o \
+ ipu7-boot.o
obj-$(CONFIG_VIDEO_INTEL_IPU6) += intel-ipu6.o
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-com.c b/drivers/media/pci/intel/ipu6/ipu7-fw-com.c
new file mode 100644
index 000000000000..7dd1e683aa92
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-com.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Intel Corporation
+ */
+
+#include <linux/io.h>
+
+#include "ipu7-fw-com.h"
+
+static void __iomem *ipu7_fw_com_get_indices(struct ipu7_fw_com_context *ctx,
+ u32 q)
+{
+ return ctx->queue_indices + (q * sizeof(struct ipu7_fw_com_queue_indices));
+}
+
+void *ipu7_fw_com_get_token(struct ipu7_fw_com_context *ctx, int q)
+{
+ struct ipu7_fw_com_queue_config *queue_params = &ctx->queue_configs[q];
+ void __iomem *queue_indices = ipu7_fw_com_get_indices(ctx, q);
+ u32 write_index = readl(queue_indices +
+ offsetof(struct ipu7_fw_com_queue_indices,
+ write_index));
+ u32 read_index = readl(queue_indices +
+ offsetof(struct ipu7_fw_com_queue_indices,
+ read_index));
+ void *token = NULL;
+
+ if (q < ctx->num_output_queues) {
+ /* Output queue */
+ bool empty = (write_index == read_index);
+
+ if (!empty)
+ token = queue_params->token_array_mem +
+ read_index *
+ queue_params->token_size_in_bytes;
+ } else {
+ /* Input queue */
+ bool full = (read_index == ((write_index + 1U) %
+ (u32)queue_params->max_capacity));
+
+ if (!full)
+ token = queue_params->token_array_mem +
+ write_index * queue_params->token_size_in_bytes;
+ }
+ return token;
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_fw_com_get_token, "INTEL_IPU6");
+
+void ipu7_fw_com_put_token(struct ipu7_fw_com_context *ctx, int q)
+{
+ struct ipu7_fw_com_queue_config *queue_params = &ctx->queue_configs[q];
+ void __iomem *queue_indices = ipu7_fw_com_get_indices(ctx, q);
+ u32 offset, index;
+
+ if (q < ctx->num_output_queues)
+ /* Output queue */
+ offset = offsetof(struct ipu7_fw_com_queue_indices, read_index);
+
+ else
+ /* Input queue */
+ offset = offsetof(struct ipu7_fw_com_queue_indices, write_index);
+
+ index = readl(queue_indices + offset);
+ writel((index + 1U) % queue_params->max_capacity,
+ queue_indices + offset);
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_fw_com_put_token, "INTEL_IPU6");
+
+struct ipu7_fw_com_queue_params_config *
+ipu7_fw_com_get_queue_config(struct ipu7_fw_com_config *config)
+{
+ return (struct ipu7_fw_com_queue_params_config *)(&config[1]);
+}
+EXPORT_SYMBOL_NS_GPL(ipu7_fw_com_get_queue_config, "INTEL_IPU6");
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-com.h b/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
new file mode 100644
index 000000000000..10c09e759bed
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2026 Intel Corporation */
+
+#ifndef IPU7_FW_COM_H
+#define IPU7_FW_COM_H
+
+#include <linux/types.h>
+
+struct ipu7_fw_com_queue_config {
+ void *token_array_mem;
+ u32 queue_size;
+ u16 token_size_in_bytes;
+ u16 max_capacity;
+};
+
+struct ipu7_fw_com_context {
+ u16 num_input_queues;
+ u16 num_output_queues;
+ struct ipu7_fw_com_queue_config *queue_configs;
+ void __iomem *queue_indices;
+ dma_addr_t queue_mem_dma_addr;
+ void *queue_mem;
+ u32 queue_mem_size;
+ struct ipu7_boot_abi_cfg *boot_config;
+ dma_addr_t boot_config_dma_addr;
+ u32 boot_config_size;
+ u32 fw_entry;
+};
+
+struct ipu7_fw_com_queue_params_config {
+ u32 token_array_mem;
+ u16 token_size_in_bytes;
+ u16 max_capacity;
+};
+
+struct ipu7_fw_com_config {
+ u16 max_output_queues;
+ u16 max_input_queues;
+};
+
+struct ipu7_fw_com_queue_indices {
+ u32 read_index;
+ u32 write_index;
+};
+
+void ipu7_fw_com_put_token(struct ipu7_fw_com_context *ctx, int q);
+void *ipu7_fw_com_get_token(struct ipu7_fw_com_context *ctx, int q);
+struct ipu7_fw_com_queue_params_config *
+ipu7_fw_com_get_queue_config(struct ipu7_fw_com_config *config);
+
+#endif /* IPU7_FW_COM_H */
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 24/44] media: ipu6: Add ipu7 fw isys ops
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (22 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 23/44] media: ipu6: Add ipu7 fw com methods Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 25/44] media: ipu6: Add ipu7 csi2 register definitions Antti Laakso
` (19 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The ipu7 isys firmware functions handle messaging
with ipu7 hardware.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/Makefile | 1 +
drivers/media/pci/intel/ipu6/ipu6-bus.h | 2 +
drivers/media/pci/intel/ipu6/ipu6-fw-isys.c | 3 +-
.../media/pci/intel/ipu6/ipu6-isys-queue.c | 2 +-
.../media/pci/intel/ipu6/ipu6-isys-queue.h | 2 +
.../media/pci/intel/ipu6/ipu6-isys-video.c | 1 +
.../media/pci/intel/ipu6/ipu6-isys-video.h | 1 +
drivers/media/pci/intel/ipu6/ipu6-isys.c | 15 +-
drivers/media/pci/intel/ipu6/ipu6-isys.h | 13 +-
drivers/media/pci/intel/ipu6/ipu7-fw-com.h | 2 +
drivers/media/pci/intel/ipu6/ipu7-fw-isys.c | 465 ++++++++++++++++++
drivers/media/pci/intel/ipu6/ipu7-fw-isys.h | 258 ++++++++++
12 files changed, 757 insertions(+), 8 deletions(-)
create mode 100644 drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
create mode 100644 drivers/media/pci/intel/ipu6/ipu7-fw-isys.h
diff --git a/drivers/media/pci/intel/ipu6/Makefile b/drivers/media/pci/intel/ipu6/Makefile
index 406e2e19df17..66986d5709ae 100644
--- a/drivers/media/pci/intel/ipu6/Makefile
+++ b/drivers/media/pci/intel/ipu6/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_VIDEO_INTEL_IPU6) += intel-ipu6.o
intel-ipu6-isys-y := ipu6-isys.o \
ipu6-isys-csi2.o \
ipu6-fw-isys.o \
+ ipu7-fw-isys.o \
ipu6-isys-video.o \
ipu6-isys-queue.o \
ipu6-isys-subdev.o \
diff --git a/drivers/media/pci/intel/ipu6/ipu6-bus.h b/drivers/media/pci/intel/ipu6/ipu6-bus.h
index 62aa2b090699..aef8e4a66c4a 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-bus.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-bus.h
@@ -31,6 +31,7 @@ struct ipu6_bus_device {
u64 *pkg_dir;
dma_addr_t pkg_dir_dma_addr;
unsigned int pkg_dir_size;
+ u32 fw_entry;
};
struct ipu6_auxdrv_data {
@@ -47,6 +48,7 @@ struct ipu6_auxdrv_data {
#define ipu6_bus_get_drvdata(adev) dev_get_drvdata(&(adev)->auxdev.dev)
extern const struct ipu6_fw_isys_ops ipu6_fw_isys_ops;
+extern const struct ipu6_fw_isys_ops ipu7_fw_isys_ops;
struct ipu6_bus_device *
ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent,
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
index 4ee5137f310e..3cad7d8f9ca9 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
@@ -15,6 +15,7 @@
#include "ipu6-isys.h"
#include "ipu6-platform-isys-csi2-reg.h"
#include "ipu6-platform-regs.h"
+#include "ipu7-fw-isys.h"
static const char send_msg_types[N_IPU6_FW_ISYS_SEND_TYPE][32] = {
"STREAM_OPEN",
@@ -602,7 +603,7 @@ int ipu6_isys_isr_one(struct ipu6_bus_device *adev)
}
isys_fw_msg = container_of((void *)(uintptr_t)resp->buf_id,
- struct isys_fw_msgs, ipu6.dummy);
+ struct isys_fw_msgs, dummy);
ipu6_put_fw_msg_buf(ipu6_bus_get_drvdata(adev), isys_fw_msg);
if (resp->pin_id < IPU6_ISYS_OUTPUT_PINS &&
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
index 4cb1741445c6..38db162d64ca 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
@@ -684,7 +684,7 @@ static void ipu6_isys_queue_buf_done(struct ipu6_isys_buffer *ib)
}
}
-static void
+void
ipu6_stream_buf_ready(struct ipu6_isys_stream *stream, u8 pin_id, u32 pin_addr,
u64 time, bool error_check)
{
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
index 51de14183ccf..5df47be0c181 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
@@ -63,4 +63,6 @@ void ipu6_isys_buffer_list_queue(struct ipu6_isys_buffer_list *bl,
void ipu6_isys_queue_buf_ready(struct ipu6_isys_stream *stream,
struct ipu6_fw_isys_resp_info_abi *info);
int ipu6_isys_queue_init(struct ipu6_isys_queue *aq);
+void ipu6_stream_buf_ready(struct ipu6_isys_stream *stream, u8 pin_id,
+ u32 pin_addr, u64 time, bool error_check);
#endif /* IPU6_ISYS_QUEUE_H */
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index 803450b0156e..560524e6e624 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -627,6 +627,7 @@ int ipu6_isys_video_prepare_stream(struct ipu6_isys_video *av,
stream->nr_queues = nr_queues;
atomic_set(&stream->sequence, 0);
+ atomic_set(&stream->buf_id, 0);
stream->seq_index = 0;
memset(stream->seq, 0, sizeof(stream->seq));
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.h b/drivers/media/pci/intel/ipu6/ipu6-isys-video.h
index 2ff53315d7b9..a7157646d563 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.h
@@ -44,6 +44,7 @@ struct sequence_info {
struct ipu6_isys_stream {
struct mutex mutex;
atomic_t sequence;
+ atomic_t buf_id;
unsigned int seq_index;
struct sequence_info seq[IPU6_ISYS_MAX_PARALLEL_SOF];
int stream_source;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 159e769931b7..086c0f01ccda 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -931,6 +931,9 @@ void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, struct isys_fw_msgs *msg)
spin_unlock_irqrestore(&isys->listlock, flags);
}
+static const struct ipu6_auxdrv_data ipu6_isys_auxdrv_data;
+static const struct ipu6_auxdrv_data ipu7_isys_auxdrv_data;
+
static int isys_probe(struct auxiliary_device *auxdev,
const struct auxiliary_device_id *auxdev_id)
{
@@ -949,8 +952,8 @@ static int isys_probe(struct auxiliary_device *auxdev,
if (!isys)
return -ENOMEM;
- adev->auxdrv_data =
- (const struct ipu6_auxdrv_data *)auxdev_id->driver_data;
+ adev->auxdrv_data = IS_IPU7(isp) ? &ipu7_isys_auxdrv_data :
+ &ipu6_isys_auxdrv_data;
adev->auxdrv = to_auxiliary_drv(auxdev->dev.driver);
isys->adev = adev;
isys->pdata = adev->pdata;
@@ -1071,10 +1074,16 @@ static const struct ipu6_auxdrv_data ipu6_isys_auxdrv_data = {
.fw_ops = &ipu6_fw_isys_ops,
};
+static const struct ipu6_auxdrv_data ipu7_isys_auxdrv_data = {
+ .isr = ipu6_isys_isr,
+ .isr_threaded = NULL,
+ .wake_isr_thread = false,
+ .fw_ops = &ipu7_fw_isys_ops,
+};
+
static const struct auxiliary_device_id ipu6_isys_id_table[] = {
{
.name = "intel_ipu6.isys",
- .driver_data = (kernel_ulong_t)&ipu6_isys_auxdrv_data,
},
{ }
};
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h
index fa9bc2730d64..697c090cc3b1 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h
@@ -17,6 +17,7 @@
#include "ipu6.h"
#include "ipu6-fw-isys.h"
+#include "ipu7-fw-isys.h"
#include "ipu6-isys-csi2.h"
#include "ipu6-isys-video.h"
@@ -167,9 +168,15 @@ struct ipu6_isys {
struct isys_fw_msgs {
union {
u64 dummy;
- struct ipu6_fw_isys_frame_buff_set_abi frame;
- struct ipu6_fw_isys_stream_cfg_data_abi stream;
- } ipu6;
+ union {
+ struct ipu6_fw_isys_frame_buff_set_abi frame;
+ struct ipu6_fw_isys_stream_cfg_data_abi stream;
+ } ipu6;
+ union {
+ struct ipu7_fw_isys_frame_buff_set frame;
+ struct ipu7_fw_isys_stream_cfg stream;
+ } ipu7;
+ };
struct list_head head;
dma_addr_t dma_addr;
};
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-com.h b/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
index 10c09e759bed..097eaab99547 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
@@ -25,6 +25,8 @@ struct ipu7_fw_com_context {
dma_addr_t boot_config_dma_addr;
u32 boot_config_size;
u32 fw_entry;
+ struct ipu7_insys_config *fw_config;
+ dma_addr_t fw_config_dma_addr;
};
struct ipu7_fw_com_queue_params_config {
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
new file mode 100644
index 000000000000..d35684a2cb58
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
@@ -0,0 +1,465 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Intel Corporation
+ */
+
+#include "ipu6-bus.h"
+#include "ipu6-dma.h"
+#include "ipu6-isys.h"
+#include "ipu7-boot.h"
+#include "ipu7-fw-com.h"
+#include "ipu7-fw-isys.h"
+
+static void ipu7_fw_isys_cleanup(struct ipu6_isys *isys)
+{
+ struct ipu6_bus_device *adev = isys->adev;
+ struct ipu7_fw_com_context *fwctx = isys->fwctx;
+
+ if (!fwctx)
+ return;
+
+ ipu7_release_boot_config(adev);
+
+ if (fwctx->fw_config) {
+ ipu6_dma_free(adev, sizeof(*fwctx->fw_config), fwctx->fw_config,
+ fwctx->fw_config_dma_addr, 0);
+ fwctx->fw_config = NULL;
+ fwctx->fw_config_dma_addr = 0;
+ }
+
+ isys->fwctx = NULL;
+}
+
+static int ipu7_fw_isys_open(struct ipu6_isys *isys)
+{
+ return ipu7_boot_start_fw(isys->adev);
+}
+
+static int ipu7_fw_isys_close(struct ipu6_isys *isys)
+{
+ int ret;
+
+ ret = ipu7_boot_stop_fw(isys->adev);
+ if (ret)
+ return ret;
+
+ ipu7_fw_isys_cleanup(isys);
+
+ return ret;
+}
+
+static int ipu7_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
+{
+ struct ipu7_fw_com_queue_config *queue_configs;
+ struct ipu6_bus_device *adev = isys->adev;
+ struct device *dev = &adev->auxdev.dev;
+ struct ipu7_insys_config *fw_config;
+ struct ipu7_fw_com_context *fwctx;
+ dma_addr_t fw_config_dma_addr;
+ unsigned int i, num_queues;
+ u32 freq;
+ int ret;
+
+ /* Allocate and init firmware context. */
+ fwctx = devm_kzalloc(dev, sizeof(struct ipu7_fw_com_context),
+ GFP_KERNEL);
+ if (!fwctx)
+ return -ENOMEM;
+
+ fwctx->num_input_queues = IPU7_INSYS_MAX_INPUT_QUEUES;
+ fwctx->num_output_queues = IPU7_INSYS_MAX_OUTPUT_QUEUES;
+ num_queues = fwctx->num_input_queues + fwctx->num_output_queues;
+
+ queue_configs = devm_kcalloc(dev, num_queues, sizeof(*queue_configs),
+ GFP_KERNEL);
+ if (!queue_configs) {
+ ipu7_fw_isys_cleanup(isys);
+ return -ENOMEM;
+ }
+ fwctx->fw_entry = adev->fw_entry;
+ fwctx->queue_configs = queue_configs;
+ queue_configs[IPU7_INSYS_OUTPUT_MSG_QUEUE].max_capacity =
+ IPU7_ISYS_SIZE_RECV_QUEUE;
+ queue_configs[IPU7_INSYS_OUTPUT_MSG_QUEUE].token_size_in_bytes =
+ sizeof(struct ipu7_insys_resp);
+ queue_configs[IPU7_INSYS_OUTPUT_LOG_QUEUE].max_capacity =
+ IPU7_ISYS_SIZE_LOG_QUEUE;
+ queue_configs[IPU7_INSYS_OUTPUT_LOG_QUEUE].token_size_in_bytes =
+ sizeof(struct ipu7_insys_resp);
+ queue_configs[IPU7_INSYS_OUTPUT_RESERVED_QUEUE].max_capacity = 0;
+ queue_configs[IPU7_INSYS_OUTPUT_RESERVED_QUEUE].token_size_in_bytes = 0;
+
+ queue_configs[IPU7_INSYS_INPUT_DEV_QUEUE].max_capacity =
+ IPU7_ISYS_MAX_STREAMS;
+ queue_configs[IPU7_INSYS_INPUT_DEV_QUEUE].token_size_in_bytes =
+ sizeof(struct ipu7_insys_send_queue_token);
+
+ for (i = IPU7_INSYS_INPUT_MSG_QUEUE; i < num_queues; i++) {
+ queue_configs[i].max_capacity = IPU7_ISYS_SIZE_SEND_QUEUE;
+ queue_configs[i].token_size_in_bytes =
+ sizeof(struct ipu7_insys_send_queue_token);
+ }
+
+ /* Allocate ISYS subsys config. */
+ fw_config = ipu6_dma_alloc(adev, sizeof(*fw_config),
+ &fw_config_dma_addr, GFP_KERNEL, 0);
+ if (!fw_config) {
+ dev_err(dev, "Failed to allocate isys subsys config.\n");
+ ipu7_fw_isys_cleanup(isys);
+ return -ENOMEM;
+ }
+ fwctx->fw_config = fw_config;
+ fwctx->fw_config_dma_addr = fw_config_dma_addr;
+ memset(fw_config, 0, sizeof(*fw_config));
+ fw_config->logger_config.use_source_severity = 0;
+ fw_config->logger_config.use_channels_enable_bitmask = 1;
+ fw_config->logger_config.channels_enable_bitmask =
+ IPU7_LOGGER_CFG_CHANNEL_ENABLE_SYSCOM;
+ fw_config->logger_config.hw_printf_buffer_base_addr = 0U;
+ fw_config->logger_config.hw_printf_buffer_size_bytes = 0U;
+ fw_config->wdt_config.wdt_timer1_us = 0;
+ fw_config->wdt_config.wdt_timer2_us = 0;
+ freq = ipu7_buttress_get_isys_freq(adev->isp);
+
+ ipu6_dma_sync_single(adev, fw_config_dma_addr,
+ sizeof(struct ipu7_insys_config));
+
+ isys->fwctx = fwctx;
+
+ ret = ipu7_init_boot_config(adev, queue_configs, num_queues,
+ freq, fw_config_dma_addr, 1U);
+ if (ret) {
+ ipu7_fw_isys_cleanup(isys);
+ return ret;
+ }
+
+ ret = ipu7_fw_isys_open(isys);
+ if (ret)
+ ipu7_fw_isys_cleanup(isys);
+
+ return ret;
+}
+
+static struct ipu7_insys_resp *ipu7_fw_isys_get_resp(struct ipu6_isys *isys)
+{
+ return ipu7_fw_com_get_token(isys->fwctx, IPU7_INSYS_OUTPUT_MSG_QUEUE);
+}
+
+static void ipu7_fw_isys_put_resp(struct ipu6_isys *isys)
+{
+ ipu7_fw_com_put_token(isys->fwctx, IPU7_INSYS_OUTPUT_MSG_QUEUE);
+}
+
+static int ipu7_isys_fw_pin_cfg(struct ipu6_isys_video *av,
+ struct ipu7_fw_isys_stream_cfg *cfg)
+{
+ struct media_pad *src_pad = media_pad_remote_pad_first(&av->pad);
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(src_pad->entity);
+ struct v4l2_subdev_state *state = v4l2_subdev_get_locked_active_state(sd);
+ struct ipu7_fw_isys_input_pin *input_pin;
+ struct ipu7_fw_isys_output_pin *output_pin;
+ struct ipu6_isys_stream *stream = av->stream;
+ struct ipu6_isys_queue *aq = &av->aq;
+ struct v4l2_mbus_framefmt fmt;
+ const struct ipu6_isys_pixelformat *pfmt =
+ ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
+ int input_pins = cfg->nof_input_pins++;
+ int output_pins;
+ u32 src_stream;
+
+ src_stream = ipu6_isys_get_src_stream_by_src_pad(sd, src_pad->index);
+ fmt = *v4l2_subdev_state_get_format(state, src_pad->index, src_stream);
+
+ input_pin = &cfg->input_pins[input_pins];
+ input_pin->input_res.width = fmt.width;
+ input_pin->input_res.height = fmt.height;
+ input_pin->dt = av->dt;
+ input_pin->disable_mipi_unpacking = 0;
+ if (pfmt->bpp == pfmt->bpp_packed && pfmt->bpp % BITS_PER_BYTE)
+ input_pin->disable_mipi_unpacking = 1;
+ input_pin->mapped_dt = IPU7_N_INSYS_MIPI_DATA_TYPE;
+ input_pin->dt_rename_mode = IPU7_INSYS_MIPI_DT_NO_RENAME;
+ input_pin->sync_msg_map =
+ IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF |
+ IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF_DISCARDED |
+ IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF |
+ IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF_DISCARDED;
+
+ output_pins = cfg->nof_output_pins++;
+ aq->fw_output = output_pins;
+ stream->output_pins_queue[output_pins] = aq;
+
+ output_pin = &cfg->output_pins[output_pins];
+ memset(output_pin, 0, sizeof(*output_pin));
+ output_pin->link.buffer_lines = 0;
+ output_pin->link.foreign_key = IPU7_MSG_LINK_FOREIGN_KEY_NONE;
+ output_pin->link.pbk_id = IPU7_MSG_LINK_PBK_ID_DONT_CARE;
+ output_pin->link.pbk_slot_id = IPU7_MSG_LINK_PBK_SLOT_ID_DONT_CARE;
+ output_pin->link.dest = 0; /* IPU_INSYS_OUTPUT_LINK_DEST_MEM */
+ output_pin->link.use_sw_managed = 1;
+ output_pin->crop.line_top = 0;
+ output_pin->crop.line_bottom = 0;
+ output_pin->dpcm.enable = 0;
+ output_pin->ft = pfmt->css_pixelformat;
+ output_pin->stride = ipu6_isys_get_bytes_per_line(av);
+ output_pin->send_irq = 1;
+ output_pin->input_pin_id = input_pins;
+
+ return 0;
+}
+
+static int
+ipu7_fw_isys_send_cmd(struct ipu6_isys *isys, const unsigned int stream_handle,
+ void *cpu_mapped_buf, dma_addr_t dma_mapped_buf,
+ size_t size, u16 send_type)
+{
+ struct ipu7_fw_com_context *ctx = isys->fwctx;
+ /*struct device *dev = &isys->adev->auxdev.dev;*/
+ struct ipu7_insys_send_queue_token *token;
+
+ if (send_type >= N_IPU7_INSYS_SEND_TYPE)
+ return -EINVAL;
+
+ if (cpu_mapped_buf)
+ clflush_cache_range(cpu_mapped_buf, size);
+
+ token = ipu7_fw_com_get_token(ctx, stream_handle +
+ IPU7_INSYS_INPUT_MSG_QUEUE);
+ if (!token)
+ return -EBUSY;
+
+ token->addr = dma_mapped_buf;
+ token->buf_handle = (unsigned long)cpu_mapped_buf;
+ token->send_type = send_type;
+ token->stream_id = stream_handle;
+ token->flag = IPU7_INSYS_SEND_QUEUE_TOKEN_FLAG_NONE;
+
+ ipu7_fw_com_put_token(ctx, stream_handle + IPU7_INSYS_INPUT_MSG_QUEUE);
+ /* now wakeup FW */
+ ipu7_buttress_wakeup_isys(isys->adev->isp);
+
+ return 0;
+}
+
+static void ipu7_fw_isys_dump_stream_cfg(struct device *dev,
+ struct isys_fw_msgs *msg)
+{
+ struct ipu7_fw_isys_stream_cfg *cfg = &msg->ipu7.stream;
+ unsigned int i;
+
+ dev_dbg(dev, "---------------------------\n");
+ dev_dbg(dev, "IPU_FW_ISYS_STREAM_CFG_DATA\n");
+
+ dev_dbg(dev, ".port id %d\n", cfg->port_id);
+ dev_dbg(dev, ".vc %d\n", cfg->vc);
+ dev_dbg(dev, ".nof_input_pins = %d\n", cfg->nof_input_pins);
+ dev_dbg(dev, ".nof_output_pins = %d\n", cfg->nof_output_pins);
+ dev_dbg(dev, ".stream_msg_map = 0x%x\n", cfg->stream_msg_map);
+
+ for (i = 0; i < cfg->nof_input_pins; i++) {
+ dev_dbg(dev, ".input_pin[%d]:\n", i);
+ dev_dbg(dev, "\t.dt = 0x%0x\n",
+ cfg->input_pins[i].dt);
+ dev_dbg(dev, "\t.disable_mipi_unpacking = %d\n",
+ cfg->input_pins[i].disable_mipi_unpacking);
+ dev_dbg(dev, "\t.dt_rename_mode = %d\n",
+ cfg->input_pins[i].dt_rename_mode);
+ dev_dbg(dev, "\t.mapped_dt = 0x%0x\n",
+ cfg->input_pins[i].mapped_dt);
+ dev_dbg(dev, "\t.input_res = %d x %d\n",
+ cfg->input_pins[i].input_res.width,
+ cfg->input_pins[i].input_res.height);
+ dev_dbg(dev, "\t.sync_msg_map = 0x%x\n",
+ cfg->input_pins[i].sync_msg_map);
+ }
+
+ for (i = 0; i < cfg->nof_output_pins; i++) {
+ dev_dbg(dev, ".output_pin[%d]:\n", i);
+ dev_dbg(dev, "\t.input_pin_id = %d\n",
+ cfg->output_pins[i].input_pin_id);
+ dev_dbg(dev, "\t.stride = %d\n", cfg->output_pins[i].stride);
+ dev_dbg(dev, "\t.send_irq = %d\n",
+ cfg->output_pins[i].send_irq);
+ dev_dbg(dev, "\t.ft = %d\n", cfg->output_pins[i].ft);
+
+ dev_dbg(dev, "\t.link.buffer_lines = %d\n",
+ cfg->output_pins[i].link.buffer_lines);
+ dev_dbg(dev, "\t.link.foreign_key = %d\n",
+ cfg->output_pins[i].link.foreign_key);
+ dev_dbg(dev, "\t.link.granularity_pointer_update = %d\n",
+ cfg->output_pins[i].link.granularity_pointer_update);
+ dev_dbg(dev, "\t.link.msg_link_streaming_mode = %d\n",
+ cfg->output_pins[i].link.msg_link_streaming_mode);
+ dev_dbg(dev, "\t.link.pbk_id = %d\n",
+ cfg->output_pins[i].link.pbk_id);
+ dev_dbg(dev, "\t.link.pbk_slot_id = %d\n",
+ cfg->output_pins[i].link.pbk_slot_id);
+ dev_dbg(dev, "\t.link.dest = %d\n",
+ cfg->output_pins[i].link.dest);
+ dev_dbg(dev, "\t.link.use_sw_managed = %d\n",
+ cfg->output_pins[i].link.use_sw_managed);
+ dev_dbg(dev, "\t.link.is_snoop = %d\n",
+ cfg->output_pins[i].link.is_snoop);
+
+ dev_dbg(dev, "\t.crop.line_top = %d\n",
+ cfg->output_pins[i].crop.line_top);
+ dev_dbg(dev, "\t.crop.line_bottom = %d\n",
+ cfg->output_pins[i].crop.line_bottom);
+
+ dev_dbg(dev, "\t.dpcm_enable = %d\n",
+ cfg->output_pins[i].dpcm.enable);
+ dev_dbg(dev, "\t.dpcm.type = %d\n",
+ cfg->output_pins[i].dpcm.type);
+ dev_dbg(dev, "\t.dpcm.predictor = %d\n",
+ cfg->output_pins[i].dpcm.predictor);
+ }
+ dev_dbg(dev, "---------------------------\n");
+}
+
+static void ipu7_fw_isys_dump_frame_buf_set(struct device *dev,
+ struct isys_fw_msgs *msg,
+ unsigned int outputs)
+{
+ struct ipu7_fw_isys_frame_buff_set *buf = &msg->ipu7.frame;
+ unsigned int i;
+
+ dev_dbg(dev, "--------------------------\n");
+ dev_dbg(dev, "IPU_ISYS_BUFF_SET\n");
+ dev_dbg(dev, ".capture_msg_map = %d\n", buf->capture_msg_map);
+ dev_dbg(dev, ".frame_id = %d\n", buf->frame_id);
+ dev_dbg(dev, ".skip_frame = %d\n", buf->skip_frame);
+
+ for (i = 0; i < outputs; i++) {
+ dev_dbg(dev, ".output_pin[%d]:\n", i);
+ dev_dbg(dev, "\t.user_token = %llx\n",
+ buf->output_pins[i].user_token);
+ dev_dbg(dev, "\t.addr = 0x%x\n", buf->output_pins[i].addr);
+ }
+ dev_dbg(dev, "---------------------------\n");
+}
+
+static int ipu7_fw_isys_prepare_stream_cfg(struct ipu6_isys_video *av,
+ struct isys_fw_msgs *msg)
+{
+ struct ipu7_fw_isys_stream_cfg *cfg = &msg->ipu7.stream;
+ struct device *dev = &av->isys->adev->auxdev.dev;
+ struct ipu6_isys_stream *stream = av->stream;
+ struct ipu6_isys_queue *aq;
+
+ memset(cfg, 0, sizeof(*cfg));
+ cfg->port_id = stream->stream_source;
+ cfg->vc = stream->vc;
+ cfg->stream_msg_map = IPU7_INSYS_STREAM_ENABLE_MSG_SEND_RESP |
+ IPU7_INSYS_STREAM_ENABLE_MSG_SEND_IRQ;
+
+ list_for_each_entry(aq, &stream->queues, node) {
+ struct ipu6_isys_video *__av = ipu6_isys_queue_to_video(aq);
+ int ret = ipu7_isys_fw_pin_cfg(__av, cfg);
+
+ if (ret < 0)
+ return ret;
+ }
+
+ stream->nr_output_pins = cfg->nof_output_pins;
+
+ ipu7_fw_isys_dump_stream_cfg(dev, msg);
+
+ return 0;
+}
+
+static void
+ipu7_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb,
+ struct ipu7_fw_isys_frame_buff_set *set)
+{
+ struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
+ struct ipu6_isys_video_buffer *ivb =
+ vb2_buffer_to_ipu6_isys_video_buffer(vvb);
+
+ set->output_pins[aq->fw_output].addr = ivb->dma_addr;
+ set->output_pins[aq->fw_output].user_token = (u64)(uintptr_t)set;
+}
+
+static void
+ipu7_fw_isys_prepare_buf_set(struct isys_fw_msgs *msg,
+ struct ipu6_isys_stream *stream,
+ struct ipu6_isys_buffer_list *bl)
+{
+ struct ipu7_fw_isys_frame_buff_set *set = &msg->ipu7.frame;
+ struct ipu6_isys_buffer *ib;
+
+ WARN_ON(!bl->nbufs);
+
+ memset(set, 0, sizeof(*set));
+ set->capture_msg_map = IPU7_INSYS_FRAME_ENABLE_MSG_SEND_RESP |
+ IPU7_INSYS_FRAME_ENABLE_MSG_SEND_IRQ;
+ set->frame_id = atomic_fetch_inc(&stream->buf_id) % 256;
+
+ list_for_each_entry(ib, &bl->head, head) {
+ struct vb2_buffer *vb = ipu6_isys_buffer_to_vb2_buffer(ib);
+
+ ipu7_isys_buf_to_fw_frame_buf_pin(vb, set);
+ }
+
+ dev_dbg(&stream->isys->adev->auxdev.dev,
+ "ipu7 frame_buf: cap_map=0x%x fid=%u opin[0].addr=0x%x token=0x%llx\n",
+ set->capture_msg_map, set->frame_id,
+ set->output_pins[0].addr, set->output_pins[0].user_token);
+}
+
+static int ipu7_fw_isys_stream_open(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ struct isys_fw_msgs *msg)
+{
+ return ipu7_fw_isys_send_cmd(isys, stream_handle, &msg->ipu7.stream,
+ msg->dma_addr, sizeof(msg->ipu7.stream),
+ IPU7_INSYS_SEND_TYPE_STREAM_OPEN);
+}
+
+static int ipu7_fw_isys_stream_close(struct ipu6_isys *isys,
+ const unsigned int stream_handle)
+{
+ return ipu7_fw_isys_send_cmd(isys, stream_handle, NULL, 0, 0,
+ IPU7_INSYS_SEND_TYPE_STREAM_CLOSE);
+}
+
+static int ipu7_fw_isys_stream_flush(struct ipu6_isys *isys,
+ const unsigned int stream_handle)
+{
+ return ipu7_fw_isys_send_cmd(isys, stream_handle, NULL, 0, 0,
+ IPU7_INSYS_SEND_TYPE_STREAM_FLUSH);
+}
+
+static int ipu7_fw_isys_stream_start(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ struct isys_fw_msgs *msg, bool capture)
+{
+ return ipu7_fw_isys_send_cmd(isys, stream_handle, &msg->ipu7.frame,
+ msg->dma_addr, sizeof(msg->ipu7.frame),
+ IPU7_INSYS_SEND_TYPE_STREAM_START_AND_CAPTURE);
+}
+
+static int ipu7_fw_isys_stream_capture(struct ipu6_isys *isys,
+ const unsigned int stream_handle,
+ struct isys_fw_msgs *msg)
+{
+ return ipu7_fw_isys_send_cmd(isys, stream_handle, &msg->ipu7.frame,
+ msg->dma_addr, sizeof(msg->ipu7.frame),
+ IPU7_INSYS_SEND_TYPE_STREAM_CAPTURE);
+}
+
+const struct ipu6_fw_isys_ops ipu7_fw_isys_ops = {
+ .init = ipu7_fw_isys_init,
+ .close = ipu7_fw_isys_close,
+ .send_cmd = ipu7_fw_isys_send_cmd,
+ .cleanup = ipu7_fw_isys_cleanup,
+ .prepare_stream_cfg = ipu7_fw_isys_prepare_stream_cfg,
+ .prepare_buf_set = ipu7_fw_isys_prepare_buf_set,
+ .stream_open = ipu7_fw_isys_stream_open,
+ .stream_start = ipu7_fw_isys_stream_start,
+ .stream_capture = ipu7_fw_isys_stream_capture,
+ .stream_flush = ipu7_fw_isys_stream_flush,
+ .stream_close = ipu7_fw_isys_stream_close,
+ .dump_stream_cfg = ipu7_fw_isys_dump_stream_cfg,
+ .dump_frame_buf_set = ipu7_fw_isys_dump_frame_buf_set,
+};
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h
new file mode 100644
index 000000000000..122531065362
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h
@@ -0,0 +1,258 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2026 Intel Corporation */
+
+#ifndef IPU7_FW_ISYS_H
+#define IPU7_FW_ISYS_H
+
+#define IPU7_FWLOG_MAX_LOGGER_SOURCES (64U)
+#define IPU7_INSYS_MAX_OUTPUT_QUEUES 3U
+#define IPU7_INSYS_STREAM_ID_MAX 16U
+#define IPU7_INSYS_MAX_INPUT_QUEUES (IPU7_INSYS_STREAM_ID_MAX + 1U)
+#define IPU7_INSYS_OUTPUT_MSG_QUEUE 0U
+#define IPU7_INSYS_OUTPUT_LOG_QUEUE 1U
+#define IPU7_INSYS_OUTPUT_RESERVED_QUEUE 2U
+#define IPU7_INSYS_INPUT_DEV_QUEUE 3U
+
+#define IPU7_INSYS_INPUT_FIRST_QUEUE 3U
+#define IPU7_INSYS_INPUT_MSG_QUEUE 4U
+#define IPU7_INSYS_INPUT_MSG_MAX_QUEUE 16U
+
+#define IPU7_MSG_ERR_MAX_DETAILS 4U
+#define IPU7_ISYS_SIZE_RECV_QUEUE 40U
+#define IPU7_ISYS_SIZE_LOG_QUEUE 256U
+#define IPU7_ISYS_SIZE_SEND_QUEUE 40U
+#define IPU7_ISYS_NUM_RECV_QUEUE 1U
+#define IPU7_INSYS_SEND_QUEUE_TOKEN_FLAG_NONE 0U
+
+#define IPU7_LOGGER_CFG_CHANNEL_ENABLE_SYSCOM BIT(1)
+
+#define IPU7_ISYS_MAX_STREAMS 16U
+#define IPU7_MAX_OPINS 4
+#define IPU7_MAX_IPINS 4
+
+#define IPU7_N_INSYS_MIPI_DATA_TYPE 0x40
+
+#define IPU7_MSG_LINK_FOREIGN_KEY_NONE (65535U)
+#define IPU7_MSG_LINK_PBK_ID_DONT_CARE (255U)
+#define IPU7_MSG_LINK_PBK_SLOT_ID_DONT_CARE (255U)
+
+#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF BIT(0)
+#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_EOF BIT(1)
+#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF BIT(2)
+#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_EOF BIT(3)
+#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_SOF_DISCARDED BIT(4)
+#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_RESP_EOF_DISCARDED BIT(5)
+#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_SOF_DISCARDED BIT(6)
+#define IPU7_INSYS_STREAM_SYNC_MSG_SEND_IRQ_EOF_DISCARDED BIT(7)
+
+#define IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_OPEN_DONE BIT(0)
+#define IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_OPEN_DONE BIT(1)
+#define IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_START_ACK BIT(2)
+#define IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_START_ACK BIT(3)
+#define IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_CLOSE_ACK BIT(4)
+#define IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_CLOSE_ACK BIT(5)
+#define IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_FLUSH_ACK BIT(6)
+#define IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_FLUSH_ACK BIT(7)
+#define IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_ABORT_ACK BIT(8)
+#define IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_ABORT_ACK BIT(9)
+
+#define IPU7_INSYS_STREAM_ENABLE_MSG_SEND_RESP ( \
+ IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_OPEN_DONE | \
+ IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_START_ACK | \
+ IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_CLOSE_ACK | \
+ IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_FLUSH_ACK | \
+ IPU7_INSYS_STREAM_MSG_SEND_RESP_STREAM_ABORT_ACK)
+#define IPU7_INSYS_STREAM_ENABLE_MSG_SEND_IRQ ( \
+ IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_OPEN_DONE | \
+ IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_START_ACK | \
+ IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_CLOSE_ACK | \
+ IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_FLUSH_ACK | \
+ IPU7_INSYS_STREAM_MSG_SEND_IRQ_STREAM_ABORT_ACK)
+
+#define IPU7_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_ACK BIT(0)
+#define IPU7_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_ACK BIT(1)
+#define IPU7_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_DONE BIT(2)
+#define IPU7_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_DONE BIT(3)
+#define IPU7_INSYS_FRAME_MSG_SEND_RESP_PIN_DATA_READY BIT(4)
+#define IPU7_INSYS_FRAME_MSG_SEND_IRQ_PIN_DATA_READY BIT(5)
+
+#define IPU7_INSYS_FRAME_ENABLE_MSG_SEND_RESP ( \
+ IPU7_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_ACK | \
+ IPU7_INSYS_FRAME_MSG_SEND_RESP_CAPTURE_DONE | \
+ IPU7_INSYS_FRAME_MSG_SEND_RESP_PIN_DATA_READY)
+#define IPU7_INSYS_FRAME_ENABLE_MSG_SEND_IRQ ( \
+ IPU7_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_ACK | \
+ IPU7_INSYS_FRAME_MSG_SEND_IRQ_CAPTURE_DONE | \
+ IPU7_INSYS_FRAME_MSG_SEND_IRQ_PIN_DATA_READY)
+
+enum ipu7_insys_send_type {
+ IPU7_INSYS_SEND_TYPE_STREAM_OPEN = 0,
+ IPU7_INSYS_SEND_TYPE_STREAM_START_AND_CAPTURE = 1,
+ IPU7_INSYS_SEND_TYPE_STREAM_CAPTURE = 2,
+ IPU7_INSYS_SEND_TYPE_STREAM_ABORT = 3,
+ IPU7_INSYS_SEND_TYPE_STREAM_FLUSH = 4,
+ IPU7_INSYS_SEND_TYPE_STREAM_CLOSE = 5,
+ N_IPU7_INSYS_SEND_TYPE
+};
+
+enum ipu7_insys_resp_type {
+ IPU7_INSYS_RESP_TYPE_STREAM_OPEN_DONE = 0,
+ IPU7_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK = 1,
+ IPU7_INSYS_RESP_TYPE_STREAM_CAPTURE_ACK = 2,
+ IPU7_INSYS_RESP_TYPE_STREAM_ABORT_ACK = 3,
+ IPU7_INSYS_RESP_TYPE_STREAM_FLUSH_ACK = 4,
+ IPU7_INSYS_RESP_TYPE_STREAM_CLOSE_ACK = 5,
+ IPU7_INSYS_RESP_TYPE_PIN_DATA_READY = 6,
+ IPU7_INSYS_RESP_TYPE_FRAME_SOF = 7,
+ IPU7_INSYS_RESP_TYPE_FRAME_EOF = 8,
+ IPU7_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE = 9,
+ IPU7_INSYS_RESP_TYPE_STREAM_CAPTURE_DONE = 10,
+ IPU7_INSYS_RESP_TYPE_PWM_IRQ = 11,
+ N_IPU7_INSYS_RESP_TYPE
+};
+
+enum ipu7_insys_mipi_dt_rename_mode {
+ IPU7_INSYS_MIPI_DT_NO_RENAME = 0,
+ IPU7_INSYS_MIPI_DT_RENAMED_MODE = 1,
+ N_IPU7_INSYS_MIPI_DT_MODE
+};
+
+struct ipu7_fw_isys_logger_config {
+ u8 use_source_severity;
+ u8 source_severity[IPU7_FWLOG_MAX_LOGGER_SOURCES];
+ u8 use_channels_enable_bitmask;
+ u8 channels_enable_bitmask;
+ u8 padding[1];
+ u32 hw_printf_buffer_base_addr;
+ u32 hw_printf_buffer_size_bytes;
+};
+
+struct ipu7_wdt_abi {
+ u32 wdt_timer1_us;
+ u32 wdt_timer2_us;
+};
+
+struct ipu7_insys_config {
+ u32 timeout_val_ms;
+ struct ipu7_fw_isys_logger_config logger_config;
+ struct ipu7_wdt_abi wdt_config;
+};
+
+struct ipu7_insys_capture_output_pin_payload {
+ u64 user_token;
+ u32 addr;
+ u8 pad[4];
+};
+
+struct ipu7_fw_isys_msg_err {
+ u32 err_group;
+ u32 err_code;
+ u32 err_detail[IPU7_MSG_ERR_MAX_DETAILS];
+};
+
+struct ipu7_insys_resp {
+ u64 buf_id;
+ struct ipu7_insys_capture_output_pin_payload pin;
+ struct ipu7_fw_isys_msg_err error_info;
+ u32 timestamp[2];
+ u8 type;
+ u8 msg_link_streaming_mode;
+ u8 stream_id;
+ u8 pin_id;
+ u8 frame_id;
+ u8 skip_frame;
+ u8 pad[2];
+};
+
+struct ipu7_insys_resp_queue_token {
+ struct ipu7_insys_resp resp_info;
+};
+
+struct ipu7_insys_send_queue_token {
+ u64 buf_handle;
+ u32 addr;
+ u16 stream_id;
+ u8 send_type;
+ u8 flag;
+};
+
+struct ipu7_fw_isys_output_link {
+ u32 buffer_lines;
+ u16 foreign_key;
+ u16 granularity_pointer_update;
+ u8 msg_link_streaming_mode;
+ u8 pbk_id;
+ u8 pbk_slot_id;
+ u8 dest;
+ u8 use_sw_managed;
+ u8 is_snoop;
+ u8 pad[2];
+} __packed;
+
+struct ipu7_fw_isys_output_cropping {
+ u16 line_top;
+ u16 line_bottom;
+} __packed;
+
+struct ipu7_fw_isys_output_dpcm {
+ u8 enable;
+ u8 type;
+ u8 predictor;
+ u8 pad;
+} __packed;
+
+struct ipu7_fw_isys_output_pin {
+ struct ipu7_fw_isys_output_link link;
+ struct ipu7_fw_isys_output_cropping crop;
+ struct ipu7_fw_isys_output_dpcm dpcm;
+ u32 stride;
+ u16 ft;
+ u8 send_irq;
+ u8 input_pin_id;
+ u8 early_ack_en;
+ u8 pad[3];
+} __packed;
+
+struct ipu7_fw_isys_resolution {
+ u32 width;
+ u32 height;
+} __packed;
+
+struct ipu7_fw_isys_input_pin {
+ struct ipu7_fw_isys_resolution input_res;
+ u16 sync_msg_map;
+ u8 dt;
+ u8 disable_mipi_unpacking;
+ u8 dt_rename_mode;
+ u8 mapped_dt;
+ u8 pad[2];
+} __packed;
+
+struct ipu7_fw_isys_stream_cfg {
+ struct ipu7_fw_isys_input_pin input_pins[IPU7_MAX_IPINS];
+ struct ipu7_fw_isys_output_pin output_pins[IPU7_MAX_OPINS];
+ u16 stream_msg_map;
+ u8 port_id;
+ u8 vc;
+ u8 nof_input_pins;
+ u8 nof_output_pins;
+ u8 pad[2];
+} __packed;
+
+struct ipu7_fw_isys_capture_output_pin {
+ u64 user_token;
+ u32 addr;
+ u8 pad[4];
+} __packed;
+
+struct ipu7_fw_isys_frame_buff_set {
+ struct ipu7_fw_isys_capture_output_pin output_pins[IPU7_MAX_OPINS];
+ u8 capture_msg_map;
+ u8 frame_id;
+ u8 skip_frame;
+ u8 pad[5];
+} __packed;
+
+struct ipu6_fw_isys_ops *ipu7_fw_isys_get_ops(void);
+
+#endif
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 25/44] media: ipu6: Add ipu7 csi2 register definitions
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (23 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 24/44] media: ipu6: Add ipu7 fw isys ops Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 26/44] media: ipu6: Add ipu7 isr handler Antti Laakso
` (18 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
This is needed later when adding support for the ipu7 csi2
receiver.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
.../pci/intel/ipu6/ipu7-isys-csi2-regs.h | 1189 +++++++++++++++++
1 file changed, 1189 insertions(+)
create mode 100644 drivers/media/pci/intel/ipu6/ipu7-isys-csi2-regs.h
diff --git a/drivers/media/pci/intel/ipu6/ipu7-isys-csi2-regs.h b/drivers/media/pci/intel/ipu6/ipu7-isys-csi2-regs.h
new file mode 100644
index 000000000000..3859401d4802
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-isys-csi2-regs.h
@@ -0,0 +1,1189 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2020 - 2026 Intel Corporation
+ */
+
+#ifndef IPU7_ISYS_CSI2_REG_H
+#define IPU7_ISYS_CSI2_REG_H
+
+/* IS main regs base */
+#define IPU7_IS_MAIN_BASE 0x240000
+#define IPU7_IS_MAIN_S2B_BASE (IPU7_IS_MAIN_BASE + 0x22000)
+#define IPU7_IS_MAIN_B2O_BASE (IPU7_IS_MAIN_BASE + 0x26000)
+#define IPU7_IS_MAIN_ISD_M0_BASE (IPU7_IS_MAIN_BASE + 0x2b000)
+#define IPU7_IS_MAIN_ISD_M1_BASE (IPU7_IS_MAIN_BASE + 0x2b100)
+#define IPU7_IS_MAIN_ISD_INT_BASE (IPU7_IS_MAIN_BASE + 0x2b200)
+#define IPU7_IS_MAIN_GDA_BASE (IPU7_IS_MAIN_BASE + 0x32000)
+#define IPU7_IS_MAIN_GPREGS_MAIN_BASE (IPU7_IS_MAIN_BASE + 0x32500)
+#define IPU7_IS_MAIN_IRQ_CTRL_BASE (IPU7_IS_MAIN_BASE + 0x32700)
+#define IPU7_IS_MAIN_PWM_CTRL_BASE (IPU7_IS_MAIN_BASE + 0x32b00)
+
+#define IPU7_S2B_IRQ_COMMON_0_CTL_STATUS (IPU7_IS_MAIN_S2B_BASE + 0x1c)
+#define IPU7_S2B_IRQ_COMMON_0_CTL_CLEAR (IPU7_IS_MAIN_S2B_BASE + 0x20)
+#define IPU7_S2B_IRQ_COMMON_0_CTL_ENABLE (IPU7_IS_MAIN_S2B_BASE + 0x24)
+#define IPU7_S2B_IID_IRQ_CTL_STATUS(iid) (IPU7_IS_MAIN_S2B_BASE + 0x94 + \
+ 0x100 * (iid))
+
+#define IPU7_B2O_IRQ_COMMON_0_CTL_STATUS (IPU7_IS_MAIN_B2O_BASE + 0x30)
+#define IPU7_B2O_IRQ_COMMON_0_CTL_CLEAR (IPU7_IS_MAIN_B2O_BASE + 0x34)
+#define IPU7_B2O_IRQ_COMMON_0_CTL_ENABLE (IPU7_IS_MAIN_B2O_BASE + 0x38)
+#define IPU7_B2O_IID_IRQ_CTL_STATUS(oid) (IPU7_IS_MAIN_B2O_BASE + 0x3dc + \
+ 0x200 * (oid))
+
+#define IPU7_ISD_M0_IRQ_CTL_STATUS (IPU7_IS_MAIN_ISD_M0_BASE + 0x1c)
+#define IPU7_ISD_M0_IRQ_CTL_CLEAR (IPU7_IS_MAIN_ISD_M0_BASE + 0x20)
+#define IPU7_ISD_M0_IRQ_CTL_ENABLE (IPU7_IS_MAIN_ISD_M0_BASE + 0x24)
+
+#define IPU7_ISD_M1_IRQ_CTL_STATUS (IPU7_IS_MAIN_ISD_M1_BASE + 0x1c)
+#define IPU7_ISD_M1_IRQ_CTL_CLEAR (IPU7_IS_MAIN_ISD_M1_BASE + 0x20)
+#define IPU7_ISD_M1_IRQ_CTL_ENABLE (IPU7_IS_MAIN_ISD_M1_BASE + 0x24)
+
+#define IPU7_ISD_INT_IRQ_CTL_STATUS (IPU7_IS_MAIN_ISD_INT_BASE + 0x1c)
+#define IPU7_ISD_INT_IRQ_CTL_CLEAR (IPU7_IS_MAIN_ISD_INT_BASE + 0x20)
+#define IPU7_ISD_INT_IRQ_CTL_ENABLE (IPU7_IS_MAIN_ISD_INT_BASE + 0x24)
+
+#define IPU7_GDA_IRQ_CTL_STATUS (IPU7_IS_MAIN_GDA_BASE + 0x1c)
+#define IPU7_GDA_IRQ_CTL_CLEAR (IPU7_IS_MAIN_GDA_BASE + 0x20)
+#define IPU7_GDA_IRQ_CTL_ENABLE (IPU7_IS_MAIN_GDA_BASE + 0x24)
+
+#define IPU7_IS_MAIN_IRQ_CTL_EDGE IPU7_IS_MAIN_IRQ_CTRL_BASE
+#define IPU7_IS_MAIN_IRQ_CTL_MASK (IPU7_IS_MAIN_IRQ_CTRL_BASE + 0x4)
+#define IPU7_IS_MAIN_IRQ_CTL_STATUS (IPU7_IS_MAIN_IRQ_CTRL_BASE + 0x8)
+#define IPU7_IS_MAIN_IRQ_CTL_CLEAR (IPU7_IS_MAIN_IRQ_CTRL_BASE + 0xc)
+#define IPU7_IS_MAIN_IRQ_CTL_ENABLE (IPU7_IS_MAIN_IRQ_CTRL_BASE + 0x10)
+#define IPU7_IS_MAIN_IRQ_CTL_LEVEL_NOT_PULSE (IPU7_IS_MAIN_IRQ_CTRL_BASE + 0x14)
+
+/* IS IO regs base */
+#define IPU7_IS_PHY_NUM 4U
+#define IPU7_IS_IO_BASE 0x280000
+
+/* dwc csi cdphy registers */
+#define IPU7_IS_IO_CDPHY_BASE(i) (IPU7_IS_IO_BASE + 0x10000 * (i))
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_0 0x1800
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_1 0x1802
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_2 0x1804
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_3 0x1806
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_4 0x1808
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_5 0x180a
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_6 0x180c
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_7 0x180e
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_8 0x1810
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_9 0x1812
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_A 0x1814
+#define IPU7_PPI_STARTUP_RW_COMMON_DPHY_10 0x1820
+#define IPU7_PPI_STARTUP_RW_COMMON_STARTUP_1_1 0x1822
+#define IPU7_PPI_STARTUP_RW_COMMON_STARTUP_1_2 0x1824
+#define IPU7_PPI_CALIBCTRL_RW_COMMON_CALIBCTRL_2_0 0x1840
+#define IPU7_PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_1 0x1842
+#define IPU7_PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_2 0x1844
+#define IPU7_PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_3 0x1846
+#define IPU7_PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_4 0x1848
+#define IPU7_PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_5 0x184a
+#define IPU7_PPI_CALIBCTRL_RW_COMMON_BG_0 0x184c
+#define IPU7_PPI_CALIBCTRL_RW_COMMON_CALIBCTRL_2_7 0x184e
+#define IPU7_PPI_CALIBCTRL_RW_ADC_CFG_0 0x1850
+#define IPU7_PPI_CALIBCTRL_RW_ADC_CFG_1 0x1852
+#define IPU7_PPI_CALIBCTRL_R_ADC_DEBUG 0x1854
+#define IPU7_PPI_RW_LPDCOCAL_TOP_OVERRIDE 0x1c00
+#define IPU7_PPI_RW_LPDCOCAL_TIMEBASE 0x1c02
+#define IPU7_PPI_RW_LPDCOCAL_NREF 0x1c04
+#define IPU7_PPI_RW_LPDCOCAL_NREF_RANGE 0x1c06
+#define IPU7_PPI_RW_LPDCOCAL_NREF_TRIGGER_MAN 0x1c08
+#define IPU7_PPI_RW_LPDCOCAL_TWAIT_CONFIG 0x1c0a
+#define IPU7_PPI_RW_LPDCOCAL_VT_CONFIG 0x1c0c
+#define IPU7_PPI_R_LPDCOCAL_DEBUG_RB 0x1c0e
+#define IPU7_PPI_RW_LPDCOCAL_COARSE_CFG 0x1c10
+#define IPU7_PPI_R_LPDCOCAL_DEBUG_COARSE_RB 0x1c12
+#define IPU7_PPI_R_LPDCOCAL_DEBUG_COARSE_MEAS_0_RB 0x1c14
+#define IPU7_PPI_R_LPDCOCAL_DEBUG_COARSE_MEAS_1_RB 0x1c16
+#define IPU7_PPI_R_LPDCOCAL_DEBUG_COARSE_FWORD_RB 0x1c18
+#define IPU7_PPI_R_LPDCOCAL_DEBUG_MEASURE_CURR_ERROR 0x1c1a
+#define IPU7_PPI_R_LPDCOCAL_DEBUG_MEASURE_LAST_ERROR 0x1c1c
+#define IPU7_PPI_R_LPDCOCAL_DEBUG_VT 0x1c1e
+#define IPU7_PPI_RW_LB_TIMEBASE_CONFIG 0x1c20
+#define IPU7_PPI_RW_LB_STARTCMU_CONFIG 0x1c22
+#define IPU7_PPI_R_LBPULSE_COUNTER_RB 0x1c24
+#define IPU7_PPI_R_LB_START_CMU_RB 0x1c26
+#define IPU7_PPI_RW_LB_DPHY_BURST_START 0x1c28
+#define IPU7_PPI_RW_LB_CPHY_BURST_START 0x1c2a
+#define IPU7_PPI_RW_DDLCAL_CFG_0 0x1c40
+#define IPU7_PPI_RW_DDLCAL_CFG_1 0x1c42
+#define IPU7_PPI_RW_DDLCAL_CFG_2 0x1c44
+#define IPU7_PPI_RW_DDLCAL_CFG_3 0x1c46
+#define IPU7_PPI_RW_DDLCAL_CFG_4 0x1c48
+#define IPU7_PPI_RW_DDLCAL_CFG_5 0x1c4a
+#define IPU7_PPI_RW_DDLCAL_CFG_6 0x1c4c
+#define IPU7_PPI_RW_DDLCAL_CFG_7 0x1c4e
+#define IPU7_PPI_R_DDLCAL_DEBUG_0 0x1c50
+#define IPU7_PPI_R_DDLCAL_DEBUG_1 0x1c52
+#define IPU7_PPI_RW_PARITY_TEST 0x1c60
+#define IPU7_PPI_RW_STARTUP_OVR_0 0x1c62
+#define IPU7_PPI_RW_STARTUP_STATE_OVR_1 0x1c64
+#define IPU7_PPI_RW_DTB_SELECTOR 0x1c66
+#define IPU7_PPI_RW_DPHY_CLK_SPARE 0x1c6a
+#define IPU7_PPI_RW_COMMON_CFG 0x1c6c
+#define IPU7_PPI_RW_TERMCAL_CFG_0 0x1c80
+#define IPU7_PPI_R_TERMCAL_DEBUG_0 0x1c82
+#define IPU7_PPI_RW_TERMCAL_CTRL_0 0x1c84
+#define IPU7_PPI_RW_OFFSETCAL_CFG_0 0x1ca0
+#define IPU7_PPI_R_OFFSETCAL_DEBUG_LANE0 0x1ca2
+#define IPU7_PPI_R_OFFSETCAL_DEBUG_LANE1 0x1ca4
+#define IPU7_PPI_R_OFFSETCAL_DEBUG_LANE2 0x1ca6
+#define IPU7_PPI_R_OFFSETCAL_DEBUG_LANE3 0x1ca8
+#define IPU7_PPI_R_OFFSETCAL_DEBUG_LANE4 0x1caa
+#define IPU7_PPI_RW_HSDCOCAL_CFG_O 0x1d00
+#define IPU7_PPI_RW_HSDCOCAL_CFG_1 0x1d02
+#define IPU7_PPI_RW_HSDCOCAL_CFG_2 0x1d04
+#define IPU7_PPI_RW_HSDCOCAL_CFG_3 0x1d06
+#define IPU7_PPI_RW_HSDCOCAL_CFG_4 0x1d08
+#define IPU7_PPI_RW_HSDCOCAL_CFG_5 0x1d0a
+#define IPU7_PPI_RW_HSDCOCAL_CFG_6 0x1d0c
+#define IPU7_PPI_RW_HSDCOCAL_CFG_7 0x1d0e
+#define IPU7_PPI_RW_HSDCOCAL_CFG_8 0x1d10
+#define IPU7_PPI_R_HSDCOCAL_DEBUG_RB 0x1d12
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_0 0x2000
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_1 0x2002
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_2 0x2004
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_3 0x2006
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_4 0x2008
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_5 0x200a
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_6 0x200c
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_7 0x200e
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE0_OVR_0_8 0x2010
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_9 0x2012
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_10 0x2014
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_11 0x2016
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_12 0x2018
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_13 0x201a
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_14 0x201c
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE0_OVR_0_15 0x201e
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_0 0x2020
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_1 0x2022
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_2 0x2024
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_3 0x2026
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_4 0x2028
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_5 0x202a
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_6 0x202c
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_7 0x202e
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_8 0x2030
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_1_9 0x2032
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_10 0x2034
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_11 0x2036
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_12 0x2038
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_13 0x203a
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_14 0x203c
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_1_15 0x203e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_0 0x2040
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_1 0x2042
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_2 0x2044
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_3 0x2046
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_4 0x2048
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_5 0x204a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_6 0x204c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_7 0x204e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_8 0x2050
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9 0x2052
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_10 0x2054
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_11 0x2056
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_12 0x2058
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_13 0x205a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_14 0x205c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_15 0x205e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_0 0x2060
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_1 0x2062
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_2 0x2064
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_3 0x2066
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_4 0x2068
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_5 0x206a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_6 0x206c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_3_7 0x206e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_8 0x2070
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_9 0x2072
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_10 0x2074
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_11 0x2076
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_12 0x2078
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_13 0x207a
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_14 0x207c
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_3_15 0x207e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_0 0x2080
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_1 0x2082
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_2 0x2084
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_3 0x2086
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE0_CTRL_4_4 0x2088
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_5_0 0x20a0
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_5_1 0x20a2
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_5_2 0x20a4
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE0_OVR_5_3 0x20a6
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE0_OVR_5_4 0x20a8
+#define IPU7_CORE_DIG_RW_TRIO0_0 0x2100
+#define IPU7_CORE_DIG_RW_TRIO0_1 0x2102
+#define IPU7_CORE_DIG_RW_TRIO0_2 0x2104
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_0 0x2400
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_1 0x2402
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_2 0x2404
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_3 0x2406
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_4 0x2408
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_5 0x240a
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_6 0x240c
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_7 0x240e
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE1_OVR_0_8 0x2410
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_9 0x2412
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_10 0x2414
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_11 0x2416
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_12 0x2418
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_13 0x241a
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_14 0x241c
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE1_OVR_0_15 0x241e
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_0 0x2420
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_1 0x2422
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_2 0x2424
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_3 0x2426
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_4 0x2428
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_5 0x242a
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_6 0x242c
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_7 0x242e
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_8 0x2430
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_1_9 0x2432
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_10 0x2434
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_11 0x2436
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_12 0x2438
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_13 0x243a
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_14 0x243c
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_1_15 0x243e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_0 0x2440
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_1 0x2442
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2 0x2444
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_3 0x2446
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_4 0x2448
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_5 0x244a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_6 0x244c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_7 0x244e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_8 0x2450
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9 0x2452
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_10 0x2454
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_11 0x2456
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_12 0x2458
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_13 0x245a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_14 0x245c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_15 0x245e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_0 0x2460
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_1 0x2462
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_2 0x2464
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_3 0x2466
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_4 0x2468
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_5 0x246a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_6 0x246c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_3_7 0x246e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_8 0x2470
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_9 0x2472
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_10 0x2474
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_11 0x2476
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_12 0x2478
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_13 0x247a
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_14 0x247c
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_3_15 0x247e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_0 0x2480
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_1 0x2482
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_2 0x2484
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_3 0x2486
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE1_CTRL_4_4 0x2488
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_5_0 0x24a0
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_5_1 0x24a2
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_5_2 0x24a4
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE1_OVR_5_3 0x24a6
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE1_OVR_5_4 0x24a8
+#define IPU7_CORE_DIG_RW_TRIO1_0 0x2500
+#define IPU7_CORE_DIG_RW_TRIO1_1 0x2502
+#define IPU7_CORE_DIG_RW_TRIO1_2 0x2504
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_0 0x2800
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_1 0x2802
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_2 0x2804
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_3 0x2806
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_4 0x2808
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_5 0x280a
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_6 0x280c
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_7 0x280e
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE2_OVR_0_8 0x2810
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_9 0x2812
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_10 0x2814
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_11 0x2816
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_12 0x2818
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_13 0x281a
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_14 0x281c
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE2_OVR_0_15 0x281e
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_0 0x2820
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_1 0x2822
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_2 0x2824
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_3 0x2826
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_4 0x2828
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_5 0x282a
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_6 0x282c
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_7 0x282e
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_8 0x2830
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_1_9 0x2832
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_10 0x2834
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_11 0x2836
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_12 0x2838
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_13 0x283a
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_14 0x283c
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_1_15 0x283e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_0 0x2840
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_1 0x2842
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2 0x2844
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_3 0x2846
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_4 0x2848
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_5 0x284a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_6 0x284c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_7 0x284e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_8 0x2850
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9 0x2852
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_10 0x2854
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_11 0x2856
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_12 0x2858
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_13 0x285a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_14 0x285c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_15 0x285e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_0 0x2860
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_1 0x2862
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_2 0x2864
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_3 0x2866
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_4 0x2868
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_5 0x286a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_6 0x286c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_3_7 0x286e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_8 0x2870
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_9 0x2872
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_10 0x2874
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_11 0x2876
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_12 0x2878
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_13 0x287a
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_14 0x287c
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_3_15 0x287e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_0 0x2880
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_1 0x2882
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_2 0x2884
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_3 0x2886
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE2_CTRL_4_4 0x2888
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_5_0 0x28a0
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_5_1 0x28a2
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_5_2 0x28a4
+#define IPU7_CORE_DIG_IOCTRL_RW_CPHY_PPI_LANE2_OVR_5_3 0x28a6
+#define IPU7_CORE_DIG_IOCTRL_R_CPHY_PPI_LANE2_OVR_5_4 0x28a8
+#define IPU7_CORE_DIG_RW_TRIO2_0 0x2900
+#define IPU7_CORE_DIG_RW_TRIO2_1 0x2902
+#define IPU7_CORE_DIG_RW_TRIO2_2 0x2904
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_0 0x2c00
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_1 0x2c02
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_2 0x2c04
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_3 0x2c06
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_4 0x2c08
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_5 0x2c0a
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_6 0x2c0c
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_7 0x2c0e
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_LANE3_OVR_0_8 0x2c10
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_9 0x2c12
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_10 0x2c14
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_11 0x2c16
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_12 0x2c18
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_13 0x2c1a
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_14 0x2c1c
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_LANE3_OVR_0_15 0x2c1e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_0 0x2c40
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_1 0x2c42
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_2 0x2c44
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_3 0x2c46
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_4 0x2c48
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_5 0x2c4a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_6 0x2c4c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_7 0x2c4e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_8 0x2c50
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_9 0x2c52
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_10 0x2c54
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_11 0x2c56
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_12 0x2c58
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_13 0x2c5a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_14 0x2c5c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_15 0x2c5e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_0 0x2c60
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_1 0x2c62
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_2 0x2c64
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_3 0x2c66
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_4 0x2c68
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_5 0x2c6a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_6 0x2c6c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_3_7 0x2c6e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_8 0x2c70
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_9 0x2c72
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_10 0x2c74
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_11 0x2c76
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_12 0x2c78
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_13 0x2c7a
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_14 0x2c7c
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_3_15 0x2c7e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_0 0x2c80
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_1 0x2c82
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_2 0x2c84
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_3 0x2c86
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE3_CTRL_4_4 0x2c88
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_0 0x3040
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_1 0x3042
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_2 0x3044
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_3 0x3046
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_4 0x3048
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_5 0x304a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_6 0x304c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_7 0x304e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_8 0x3050
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_9 0x3052
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_10 0x3054
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_11 0x3056
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_12 0x3058
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_13 0x305a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_14 0x305c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_15 0x305e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_0 0x3060
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_1 0x3062
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_2 0x3064
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_3 0x3066
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_4 0x3068
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_5 0x306a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_6 0x306c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_3_7 0x306e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_8 0x3070
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_9 0x3072
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_10 0x3074
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_11 0x3076
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_12 0x3078
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_13 0x307a
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_14 0x307c
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_3_15 0x307e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_0 0x3080
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_1 0x3082
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_2 0x3084
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_3 0x3086
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_LANE4_CTRL_4_4 0x3088
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_CLK_OVR_0_0 0x3400
+#define IPU7_CORE_DIG_IOCTRL_RW_DPHY_PPI_CLK_OVR_0_1 0x3402
+#define IPU7_CORE_DIG_IOCTRL_R_DPHY_PPI_CLK_OVR_0_2 0x3404
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_0 0x3800
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_1 0x3802
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_2 0x3804
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_3 0x3806
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_4 0x3808
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_5 0x380a
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_6 0x380c
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_7 0x380e
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_8 0x3810
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_9 0x3812
+#define IPU7_CORE_DIG_IOCTRL_RW_COMMON_PPI_OVR_0_10 0x3814
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_11 0x3816
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_12 0x3818
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_13 0x381a
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_14 0x381c
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_0_15 0x381e
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_0 0x3820
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_1 0x3822
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_2 0x3824
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_3 0x3826
+#define IPU7_CORE_DIG_IOCTRL_R_COMMON_PPI_OVR_1_4 0x3828
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_0 0x3840
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_1 0x3842
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_2 0x3844
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_3 0x3846
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_4 0x3848
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_5 0x384a
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_6 0x384c
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7 0x384e
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_8 0x3850
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_9 0x3852
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_10 0x3854
+#define IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_11 0x3856
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_12 0x3858
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_13 0x385a
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_14 0x385c
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_15 0x385e
+#define IPU7_CORE_DIG_IOCTRL_R_AFE_CB_CTRL_3_0 0x3860
+#define IPU7_CORE_DIG_RW_COMMON_0 0x3880
+#define IPU7_CORE_DIG_RW_COMMON_1 0x3882
+#define IPU7_CORE_DIG_RW_COMMON_2 0x3884
+#define IPU7_CORE_DIG_RW_COMMON_3 0x3886
+#define IPU7_CORE_DIG_RW_COMMON_4 0x3888
+#define IPU7_CORE_DIG_RW_COMMON_5 0x388a
+#define IPU7_CORE_DIG_RW_COMMON_6 0x388c
+#define IPU7_CORE_DIG_RW_COMMON_7 0x388e
+#define IPU7_CORE_DIG_RW_COMMON_8 0x3890
+#define IPU7_CORE_DIG_RW_COMMON_9 0x3892
+#define IPU7_CORE_DIG_RW_COMMON_10 0x3894
+#define IPU7_CORE_DIG_RW_COMMON_11 0x3896
+#define IPU7_CORE_DIG_RW_COMMON_12 0x3898
+#define IPU7_CORE_DIG_RW_COMMON_13 0x389a
+#define IPU7_CORE_DIG_RW_COMMON_14 0x389c
+#define IPU7_CORE_DIG_RW_COMMON_15 0x389e
+#define IPU7_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_0 0x39e0
+#define IPU7_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_1 0x39e2
+#define IPU7_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2 0x39e4
+#define IPU7_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_3 0x39e6
+#define IPU7_CORE_DIG_COMMON_RW_DESKEW_FINE_MEM 0x3fe0
+#define IPU7_CORE_DIG_COMMON_R_DESKEW_FINE_MEM 0x3fe2
+#define IPU7_PPI_RW_DPHY_LANE0_LBERT_0 0x4000
+#define IPU7_PPI_RW_DPHY_LANE0_LBERT_1 0x4002
+#define IPU7_PPI_R_DPHY_LANE0_LBERT_0 0x4004
+#define IPU7_PPI_R_DPHY_LANE0_LBERT_1 0x4006
+#define IPU7_PPI_RW_DPHY_LANE0_SPARE 0x4008
+#define IPU7_PPI_RW_DPHY_LANE1_LBERT_0 0x4400
+#define IPU7_PPI_RW_DPHY_LANE1_LBERT_1 0x4402
+#define IPU7_PPI_R_DPHY_LANE1_LBERT_0 0x4404
+#define IPU7_PPI_R_DPHY_LANE1_LBERT_1 0x4406
+#define IPU7_PPI_RW_DPHY_LANE1_SPARE 0x4408
+#define IPU7_PPI_RW_DPHY_LANE2_LBERT_0 0x4800
+#define IPU7_PPI_RW_DPHY_LANE2_LBERT_1 0x4802
+#define IPU7_PPI_R_DPHY_LANE2_LBERT_0 0x4804
+#define IPU7_PPI_R_DPHY_LANE2_LBERT_1 0x4806
+#define IPU7_PPI_RW_DPHY_LANE2_SPARE 0x4808
+#define IPU7_PPI_RW_DPHY_LANE3_LBERT_0 0x4c00
+#define IPU7_PPI_RW_DPHY_LANE3_LBERT_1 0x4c02
+#define IPU7_PPI_R_DPHY_LANE3_LBERT_0 0x4c04
+#define IPU7_PPI_R_DPHY_LANE3_LBERT_1 0x4c06
+#define IPU7_PPI_RW_DPHY_LANE3_SPARE 0x4c08
+#define IPU7_CORE_DIG_DLANE_0_RW_CFG_0 0x6000
+#define IPU7_CORE_DIG_DLANE_0_RW_CFG_1 0x6002
+#define IPU7_CORE_DIG_DLANE_0_RW_CFG_2 0x6004
+#define IPU7_CORE_DIG_DLANE_0_RW_LP_0 0x6080
+#define IPU7_CORE_DIG_DLANE_0_RW_LP_1 0x6082
+#define IPU7_CORE_DIG_DLANE_0_RW_LP_2 0x6084
+#define IPU7_CORE_DIG_DLANE_0_R_LP_0 0x60a0
+#define IPU7_CORE_DIG_DLANE_0_R_LP_1 0x60a2
+#define IPU7_CORE_DIG_DLANE_0_R_HS_TX_0 0x60e0
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_0 0x6100
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_1 0x6102
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_2 0x6104
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_3 0x6106
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_4 0x6108
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_5 0x610a
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_6 0x610c
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_7 0x610e
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_8 0x6110
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_RX_9 0x6112
+#define IPU7_CORE_DIG_DLANE_0_R_HS_RX_0 0x6120
+#define IPU7_CORE_DIG_DLANE_0_R_HS_RX_1 0x6122
+#define IPU7_CORE_DIG_DLANE_0_R_HS_RX_2 0x6124
+#define IPU7_CORE_DIG_DLANE_0_R_HS_RX_3 0x6126
+#define IPU7_CORE_DIG_DLANE_0_R_HS_RX_4 0x6128
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_0 0x6200
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_1 0x6202
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_2 0x6204
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_3 0x6206
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_4 0x6208
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_5 0x620a
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_6 0x620c
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_7 0x620e
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_8 0x6210
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_9 0x6212
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_10 0x6214
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_11 0x6216
+#define IPU7_CORE_DIG_DLANE_0_RW_HS_TX_12 0x6218
+#define IPU7_CORE_DIG_DLANE_1_RW_CFG_0 0x6400
+#define IPU7_CORE_DIG_DLANE_1_RW_CFG_1 0x6402
+#define IPU7_CORE_DIG_DLANE_1_RW_CFG_2 0x6404
+#define IPU7_CORE_DIG_DLANE_1_RW_LP_0 0x6480
+#define IPU7_CORE_DIG_DLANE_1_RW_LP_1 0x6482
+#define IPU7_CORE_DIG_DLANE_1_RW_LP_2 0x6484
+#define IPU7_CORE_DIG_DLANE_1_R_LP_0 0x64a0
+#define IPU7_CORE_DIG_DLANE_1_R_LP_1 0x64a2
+#define IPU7_CORE_DIG_DLANE_1_R_HS_TX_0 0x64e0
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_0 0x6500
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_1 0x6502
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_2 0x6504
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_3 0x6506
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_4 0x6508
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_5 0x650a
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_6 0x650c
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_7 0x650e
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_8 0x6510
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_RX_9 0x6512
+#define IPU7_CORE_DIG_DLANE_1_R_HS_RX_0 0x6520
+#define IPU7_CORE_DIG_DLANE_1_R_HS_RX_1 0x6522
+#define IPU7_CORE_DIG_DLANE_1_R_HS_RX_2 0x6524
+#define IPU7_CORE_DIG_DLANE_1_R_HS_RX_3 0x6526
+#define IPU7_CORE_DIG_DLANE_1_R_HS_RX_4 0x6528
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_0 0x6600
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_1 0x6602
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_2 0x6604
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_3 0x6606
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_4 0x6608
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_5 0x660a
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_6 0x660c
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_7 0x660e
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_8 0x6610
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_9 0x6612
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_10 0x6614
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_11 0x6616
+#define IPU7_CORE_DIG_DLANE_1_RW_HS_TX_12 0x6618
+#define IPU7_CORE_DIG_DLANE_2_RW_CFG_0 0x6800
+#define IPU7_CORE_DIG_DLANE_2_RW_CFG_1 0x6802
+#define IPU7_CORE_DIG_DLANE_2_RW_CFG_2 0x6804
+#define IPU7_CORE_DIG_DLANE_2_RW_LP_0 0x6880
+#define IPU7_CORE_DIG_DLANE_2_RW_LP_1 0x6882
+#define IPU7_CORE_DIG_DLANE_2_RW_LP_2 0x6884
+#define IPU7_CORE_DIG_DLANE_2_R_LP_0 0x68a0
+#define IPU7_CORE_DIG_DLANE_2_R_LP_1 0x68a2
+#define IPU7_CORE_DIG_DLANE_2_R_HS_TX_0 0x68e0
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_0 0x6900
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_1 0x6902
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_2 0x6904
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_3 0x6906
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_4 0x6908
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_5 0x690a
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_6 0x690c
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_7 0x690e
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_8 0x6910
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_RX_9 0x6912
+#define IPU7_CORE_DIG_DLANE_2_R_HS_RX_0 0x6920
+#define IPU7_CORE_DIG_DLANE_2_R_HS_RX_1 0x6922
+#define IPU7_CORE_DIG_DLANE_2_R_HS_RX_2 0x6924
+#define IPU7_CORE_DIG_DLANE_2_R_HS_RX_3 0x6926
+#define IPU7_CORE_DIG_DLANE_2_R_HS_RX_4 0x6928
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_0 0x6a00
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_1 0x6a02
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_2 0x6a04
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_3 0x6a06
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_4 0x6a08
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_5 0x6a0a
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_6 0x6a0c
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_7 0x6a0e
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_8 0x6a10
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_9 0x6a12
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_10 0x6a14
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_11 0x6a16
+#define IPU7_CORE_DIG_DLANE_2_RW_HS_TX_12 0x6a18
+#define IPU7_CORE_DIG_DLANE_3_RW_CFG_0 0x6c00
+#define IPU7_CORE_DIG_DLANE_3_RW_CFG_1 0x6c02
+#define IPU7_CORE_DIG_DLANE_3_RW_CFG_2 0x6c04
+#define IPU7_CORE_DIG_DLANE_3_RW_LP_0 0x6c80
+#define IPU7_CORE_DIG_DLANE_3_RW_LP_1 0x6c82
+#define IPU7_CORE_DIG_DLANE_3_RW_LP_2 0x6c84
+#define IPU7_CORE_DIG_DLANE_3_R_LP_0 0x6ca0
+#define IPU7_CORE_DIG_DLANE_3_R_LP_1 0x6ca2
+#define IPU7_CORE_DIG_DLANE_3_R_HS_TX_0 0x6ce0
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_0 0x6d00
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_1 0x6d02
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_2 0x6d04
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_3 0x6d06
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_4 0x6d08
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_5 0x6d0a
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_6 0x6d0c
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_7 0x6d0e
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_8 0x6d10
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_RX_9 0x6d12
+#define IPU7_CORE_DIG_DLANE_3_R_HS_RX_0 0x6d20
+#define IPU7_CORE_DIG_DLANE_3_R_HS_RX_1 0x6d22
+#define IPU7_CORE_DIG_DLANE_3_R_HS_RX_2 0x6d24
+#define IPU7_CORE_DIG_DLANE_3_R_HS_RX_3 0x6d26
+#define IPU7_CORE_DIG_DLANE_3_R_HS_RX_4 0x6d28
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_0 0x6e00
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_1 0x6e02
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_2 0x6e04
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_3 0x6e06
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_4 0x6e08
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_5 0x6e0a
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_6 0x6e0c
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_7 0x6e0e
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_8 0x6e10
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_9 0x6e12
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_10 0x6e14
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_11 0x6e16
+#define IPU7_CORE_DIG_DLANE_3_RW_HS_TX_12 0x6e18
+#define IPU7_CORE_DIG_DLANE_CLK_RW_CFG_0 0x7000
+#define IPU7_CORE_DIG_DLANE_CLK_RW_CFG_1 0x7002
+#define IPU7_CORE_DIG_DLANE_CLK_RW_CFG_2 0x7004
+#define IPU7_CORE_DIG_DLANE_CLK_RW_LP_0 0x7080
+#define IPU7_CORE_DIG_DLANE_CLK_RW_LP_1 0x7082
+#define IPU7_CORE_DIG_DLANE_CLK_RW_LP_2 0x7084
+#define IPU7_CORE_DIG_DLANE_CLK_R_LP_0 0x70a0
+#define IPU7_CORE_DIG_DLANE_CLK_R_LP_1 0x70a2
+#define IPU7_CORE_DIG_DLANE_CLK_R_HS_TX_0 0x70e0
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_0 0x7100
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_1 0x7102
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_2 0x7104
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_3 0x7106
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_4 0x7108
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_5 0x710a
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_6 0x710c
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_7 0x710e
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_8 0x7110
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_9 0x7112
+#define IPU7_CORE_DIG_DLANE_CLK_R_HS_RX_0 0x7120
+#define IPU7_CORE_DIG_DLANE_CLK_R_HS_RX_1 0x7122
+#define IPU7_CORE_DIG_DLANE_CLK_R_HS_RX_2 0x7124
+#define IPU7_CORE_DIG_DLANE_CLK_R_HS_RX_3 0x7126
+#define IPU7_CORE_DIG_DLANE_CLK_R_HS_RX_4 0x7128
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_0 0x7200
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_1 0x7202
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_2 0x7204
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_3 0x7206
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_4 0x7208
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_5 0x720a
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_6 0x720c
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_7 0x720e
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_8 0x7210
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_9 0x7212
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_10 0x7214
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_11 0x7216
+#define IPU7_CORE_DIG_DLANE_CLK_RW_HS_TX_12 0x7218
+#define IPU7_PPI_RW_CPHY_TRIO0_LBERT_0 0x8000
+#define IPU7_PPI_RW_CPHY_TRIO0_LBERT_1 0x8002
+#define IPU7_PPI_R_CPHY_TRIO0_LBERT_0 0x8004
+#define IPU7_PPI_R_CPHY_TRIO0_LBERT_1 0x8006
+#define IPU7_PPI_RW_CPHY_TRIO0_SPARE 0x8008
+#define IPU7_PPI_RW_CPHY_TRIO1_LBERT_0 0x8400
+#define IPU7_PPI_RW_CPHY_TRIO1_LBERT_1 0x8402
+#define IPU7_PPI_R_CPHY_TRIO1_LBERT_0 0x8404
+#define IPU7_PPI_R_CPHY_TRIO1_LBERT_1 0x8406
+#define IPU7_PPI_RW_CPHY_TRIO1_SPARE 0x8408
+#define IPU7_PPI_RW_CPHY_TRIO2_LBERT_0 0x8800
+#define IPU7_PPI_RW_CPHY_TRIO2_LBERT_1 0x8802
+#define IPU7_PPI_R_CPHY_TRIO2_LBERT_0 0x8804
+#define IPU7_PPI_R_CPHY_TRIO2_LBERT_1 0x8806
+#define IPU7_PPI_RW_CPHY_TRIO2_SPARE 0x8808
+#define IPU7_CORE_DIG_CLANE_0_RW_CFG_0 0xa000
+#define IPU7_CORE_DIG_CLANE_0_RW_CFG_2 0xa004
+#define IPU7_CORE_DIG_CLANE_0_RW_LP_0 0xa080
+#define IPU7_CORE_DIG_CLANE_0_RW_LP_1 0xa082
+#define IPU7_CORE_DIG_CLANE_0_RW_LP_2 0xa084
+#define IPU7_CORE_DIG_CLANE_0_R_LP_0 0xa0a0
+#define IPU7_CORE_DIG_CLANE_0_R_LP_1 0xa0a2
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_RX_0 0xa100
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_RX_1 0xa102
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_RX_2 0xa104
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_RX_3 0xa106
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_RX_4 0xa108
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_RX_5 0xa10a
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_RX_6 0xa10c
+#define IPU7_CORE_DIG_CLANE_0_R_RX_0 0xa120
+#define IPU7_CORE_DIG_CLANE_0_R_RX_1 0xa122
+#define IPU7_CORE_DIG_CLANE_0_R_TX_0 0xa124
+#define IPU7_CORE_DIG_CLANE_0_R_RX_2 0xa126
+#define IPU7_CORE_DIG_CLANE_0_R_RX_3 0xa128
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_0 0xa200
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_1 0xa202
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_2 0xa204
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_3 0xa206
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_4 0xa208
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_5 0xa20a
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_6 0xa20c
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_7 0xa20e
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_8 0xa210
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_9 0xa212
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_10 0xa214
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_11 0xa216
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_12 0xa218
+#define IPU7_CORE_DIG_CLANE_0_RW_HS_TX_13 0xa21a
+#define IPU7_CORE_DIG_CLANE_1_RW_CFG_0 0xa400
+#define IPU7_CORE_DIG_CLANE_1_RW_CFG_2 0xa404
+#define IPU7_CORE_DIG_CLANE_1_RW_LP_0 0xa480
+#define IPU7_CORE_DIG_CLANE_1_RW_LP_1 0xa482
+#define IPU7_CORE_DIG_CLANE_1_RW_LP_2 0xa484
+#define IPU7_CORE_DIG_CLANE_1_R_LP_0 0xa4a0
+#define IPU7_CORE_DIG_CLANE_1_R_LP_1 0xa4a2
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_RX_0 0xa500
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_RX_1 0xa502
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_RX_2 0xa504
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_RX_3 0xa506
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_RX_4 0xa508
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_RX_5 0xa50a
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_RX_6 0xa50c
+#define IPU7_CORE_DIG_CLANE_1_R_RX_0 0xa520
+#define IPU7_CORE_DIG_CLANE_1_R_RX_1 0xa522
+#define IPU7_CORE_DIG_CLANE_1_R_TX_0 0xa524
+#define IPU7_CORE_DIG_CLANE_1_R_RX_2 0xa526
+#define IPU7_CORE_DIG_CLANE_1_R_RX_3 0xa528
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_0 0xa600
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_1 0xa602
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_2 0xa604
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_3 0xa606
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_4 0xa608
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_5 0xa60a
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_6 0xa60c
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_7 0xa60e
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_8 0xa610
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_9 0xa612
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_10 0xa614
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_11 0xa616
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_12 0xa618
+#define IPU7_CORE_DIG_CLANE_1_RW_HS_TX_13 0xa61a
+#define IPU7_CORE_DIG_CLANE_2_RW_CFG_0 0xa800
+#define IPU7_CORE_DIG_CLANE_2_RW_CFG_2 0xa804
+#define IPU7_CORE_DIG_CLANE_2_RW_LP_0 0xa880
+#define IPU7_CORE_DIG_CLANE_2_RW_LP_1 0xa882
+#define IPU7_CORE_DIG_CLANE_2_RW_LP_2 0xa884
+#define IPU7_CORE_DIG_CLANE_2_R_LP_0 0xa8a0
+#define IPU7_CORE_DIG_CLANE_2_R_LP_1 0xa8a2
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_RX_0 0xa900
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_RX_1 0xa902
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_RX_2 0xa904
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_RX_3 0xa906
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_RX_4 0xa908
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_RX_5 0xa90a
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_RX_6 0xa90c
+#define IPU7_CORE_DIG_CLANE_2_R_RX_0 0xa920
+#define IPU7_CORE_DIG_CLANE_2_R_RX_1 0xa922
+#define IPU7_CORE_DIG_CLANE_2_R_TX_0 0xa924
+#define IPU7_CORE_DIG_CLANE_2_R_RX_2 0xa926
+#define IPU7_CORE_DIG_CLANE_2_R_RX_3 0xa928
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_0 0xaa00
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_1 0xaa02
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_2 0xaa04
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_3 0xaa06
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_4 0xaa08
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_5 0xaa0a
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_6 0xaa0c
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_7 0xaa0e
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_8 0xaa10
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_9 0xaa12
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_10 0xaa14
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_11 0xaa16
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_12 0xaa18
+#define IPU7_CORE_DIG_CLANE_2_RW_HS_TX_13 0xaa1a
+
+/* dwc csi host controller registers */
+#define IPU7_IS_IO_CSI2_HOST_BASE(i) (IPU7_IS_IO_BASE + 0x40000 + \
+ 0x2000 * (i))
+#define IPU7_VERSION 0x0
+#define IPU7_N_LANES 0x4
+#define IPU7_CSI2_RESETN 0x8
+#define IPU7_INT_ST_MAIN 0xc
+#define IPU7_DATA_IDS_1 0x10
+#define IPU7_DATA_IDS_2 0x14
+#define IPU7_CDPHY_MODE 0x1c
+#define IPU7_DATA_IDS_VC_1 0x30
+#define IPU7_DATA_IDS_VC_2 0x34
+#define IPU7_PHY_SHUTDOWNZ 0x40
+#define IPU7_DPHY_RSTZ 0x44
+#define IPU7_PHY_RX 0x48
+#define IPU7_PHY_STOPSTATE 0x4c
+#define IPU7_PHY_TEST_CTRL0 0x50
+#define IPU7_PHY_TEST_CTRL1 0x54
+#define IPU7_PPI_PG_PATTERN_VRES 0x60
+#define IPU7_PPI_PG_PATTERN_HRES 0x64
+#define IPU7_PPI_PG_CONFIG 0x68
+#define IPU7_PPI_PG_ENABLE 0x6c
+#define IPU7_PPI_PG_STATUS 0x70
+#define IPU7_VC_EXTENSION 0xc8
+#define IPU7_PHY_CAL 0xcc
+#define IPU7_INT_ST_PHY_FATAL 0xe0
+#define IPU7_INT_MSK_PHY_FATAL 0xe4
+#define IPU7_INT_FORCE_PHY_FATAL 0xe8
+#define IPU7_INT_ST_PKT_FATAL 0xf0
+#define IPU7_INT_MSK_PKT_FATAL 0xf4
+#define IPU7_INT_FORCE_PKT_FATAL 0xf8
+#define IPU7_INT_ST_PHY 0x110
+#define IPU7_INT_MSK_PHY 0x114
+#define IPU7_INT_FORCE_PHY 0x118
+#define IPU7_INT_ST_LINE 0x130
+#define IPU7_INT_MSK_LINE 0x134
+#define IPU7_INT_FORCE_LINE 0x138
+#define IPU7_INT_ST_BNDRY_FRAME_FATAL 0x280
+#define IPU7_INT_MSK_BNDRY_FRAME_FATAL 0x284
+#define IPU7_INT_FORCE_BNDRY_FRAME_FATAL 0x288
+#define IPU7_INT_ST_SEQ_FRAME_FATAL 0x290
+#define IPU7_INT_MSK_SEQ_FRAME_FATAL 0x294
+#define IPU7_INT_FORCE_SEQ_FRAME_FATAL 0x298
+#define IPU7_INT_ST_CRC_FRAME_FATAL 0x2a0
+#define IPU7_INT_MSK_CRC_FRAME_FATAL 0x2a4
+#define IPU7_INT_FORCE_CRC_FRAME_FATAL 0x2a8
+#define IPU7_INT_ST_PLD_CRC_FATAL 0x2b0
+#define IPU7_INT_MSK_PLD_CRC_FATAL 0x2b4
+#define IPU7_INT_FORCE_PLD_CRC_FATAL 0x2b8
+#define IPU7_INT_ST_DATA_ID 0x2c0
+#define IPU7_INT_MSK_DATA_ID 0x2c4
+#define IPU7_INT_FORCE_DATA_ID 0x2c8
+#define IPU7_INT_ST_ECC_CORRECTED 0x2d0
+#define IPU7_INT_MSK_ECC_CORRECTED 0x2d4
+#define IPU7_INT_FORCE_ECC_CORRECTED 0x2d8
+#define IPU7_SCRAMBLING 0x300
+#define IPU7_SCRAMBLING_SEED1 0x304
+#define IPU7_SCRAMBLING_SEED2 0x308
+#define IPU7_SCRAMBLING_SEED3 0x30c
+#define IPU7_SCRAMBLING_SEED4 0x310
+#define IPU7_SCRAMBLING 0x300
+
+#define IPU7_IS_IO_CSI2_ADPL_PORT_BASE(i) (IPU7_IS_IO_BASE + 0x40800 + \
+ 0x2000 * (i))
+#define IPU7_CSI2_ADPL_INPUT_MODE 0x0
+#define IPU7_CSI2_ADPL_CSI_RX_ERR_IRQ_CLEAR_EN 0x4
+#define IPU7_CSI2_ADPL_CSI_RX_ERR_IRQ_CLEAR_ADDR 0x8
+#define IPU7_CSI2_ADPL_CSI_RX_ERR_IRQ_STATUS 0xc
+#define IPU7_CSI2_ADPL_IRQ_CTL_COMMON_STATUS 0xa4
+#define IPU7_CSI2_ADPL_IRQ_CTL_COMMON_CLEAR 0xa8
+#define IPU7_CSI2_ADPL_IRQ_CTL_COMMON_ENABLE 0xac
+#define IPU7_CSI2_ADPL_IRQ_CTL_FS_STATUS 0xbc
+#define IPU7_CSI2_ADPL_IRQ_CTL_FS_CLEAR 0xc0
+#define IPU7_CSI2_ADPL_IRQ_CTL_FS_ENABLE 0xc4
+#define IPU7_CSI2_ADPL_IRQ_CTL_FE_STATUS 0xc8
+#define IPU7_CSI2_ADPL_IRQ_CTL_FE_CLEAR 0xcc
+#define IPU7_CSI2_ADPL_IRQ_CTL_FE_ENABLE 0xd0
+
+/* software control the legacy csi irq */
+#define IPU7_IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(i) (IPU7_IS_IO_BASE + \
+ 0x40c00 + 0x2000 * (i))
+#define IPU7_IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(i) (IPU7_IS_IO_BASE + \
+ 0x40d00 + 0x2000 * (i))
+#define IPU7_IS_IO_CSI2_LEGACY_IRQ_CTRL_BASE (IPU7_IS_IO_BASE + \
+ 0x49000)
+#define IPU7_IS_IO_CSI2_IRQ_CTRL_BASE (IPU7_IS_IO_BASE + 0x4e100)
+
+#define IPU7_IRQ_CTL_EDGE 0x0
+#define IPU7_IRQ_CTL_MASK 0x4
+#define IPU7_IRQ_CTL_STATUS 0x8
+#define IPU7_IRQ_CTL_CLEAR 0xc
+#define IPU7_IRQ_CTL_ENABLE 0x10
+/* FE irq for PTL */
+#define IPU7_IRQ1_CTL_MASK 0x14
+#define IPU7_IRQ1_CTL_STATUS 0x18
+#define IPU7_IRQ1_CTL_CLEAR 0x1c
+#define IPU7_IRQ1_CTL_ENABLE 0x20
+
+/* software to set the clock gate to use the port or mgc */
+#define IPU7_IS_IO_GPREGS_BASE (IPU7_IS_IO_BASE + 0x49200)
+#define IPU7_SRST_PORT_ARB 0x0
+#define IPU7_SRST_MGC 0x4
+#define IPU7_SRST_WIDTH_CONV 0x8
+#define IPU7_SRST_CSI_IRQ 0xc
+#define IPU7_SRST_CSI_LEGACY_IRQ 0x10
+#define IPU7_CLK_EN_TXCLKESC 0x14
+#define IPU7_CLK_DIV_FACTOR_IS_CLK 0x18
+#define IPU7_CLK_DIV_FACTOR_APB_CLK 0x1c
+#define IPU7_CSI_PORT_CLK_GATE 0x20
+#define IPU7_CSI_PORTAB_AGGREGATION 0x24
+#define IPU7_MGC_CLK_GATE 0x2c
+#define IPU7_CG_CTRL_BITS 0x3c
+#define IPU7_SPARE_RW 0xf8
+#define IPU7_SPARE_RO 0xfc
+
+#define IPU7_IS_IO_CSI2_MPF_PORT_BASE(i) (IPU7_IS_IO_BASE + 0x53000 + \
+ 0x1000 * (i))
+#define IPU7_MPF_16_IRQ_CNTRL_STATUS 0x238
+#define IPU7_MPF_16_IRQ_CNTRL_CLEAR 0x23c
+#define IPU7_MPF_16_IRQ_CNTRL_ENABLE 0x240
+
+/* software config the phy */
+#define IPU7_IS_IO_CSI2_GPREGS_BASE (IPU7_IS_IO_BASE + 0x53400)
+#define IPU8_IS_IO_CSI2_GPREGS_BASE (IPU7_IS_IO_BASE + 0x40e00)
+#define IPU7_CSI_ADAPT_LAYER_SRST 0x0
+#define IPU7_MPF_SRST_RST 0x4
+#define IPU7_CSI_ERR_IRQ_CTRL_SRST 0x8
+#define IPU7_CSI_SYNC_RC_SRST 0xc
+#define IPU7_CSI_CG_CTRL_BITS 0x10
+#define IPU7_SOC_CSI2HOST_SELECT 0x14
+#define IPU7_PHY_RESET 0x18
+#define IPU7_PHY_SHUTDOWN 0x1c
+#define IPU7_PHY_MODE 0x20
+#define IPU7_PHY_READY 0x24
+#define IPU7_PHY_CLK_LANE_FORCE_CONTROL 0x28
+#define IPU7_PHY_CLK_LANE_CONTROL 0x2c
+#define IPU7_PHY_CLK_LANE_STATUS 0x30
+#define IPU7_PHY_LANE_RX_ESC_REQ 0x34
+#define IPU7_PHY_LANE_RX_ESC_DATA 0x38
+#define IPU7_PHY_LANE_TURNDISABLE 0x3c
+#define IPU7_PHY_LANE_DIRECTION 0x40
+#define IPU7_PHY_LANE_FORCE_CONTROL 0x44
+#define IPU7_PHY_LANE_CONTROL_EN 0x48
+#define IPU7_PHY_LANE_CONTROL_DATAWIDTH 0x4c
+#define IPU7_PHY_LANE_STATUS 0x50
+#define IPU7_PHY_LANE_ERR 0x54
+#define IPU7_PHY_LANE_RXALP 0x58
+#define IPU7_PHY_LANE_RXALP_NIBBLE 0x5c
+#define IPU7_PHY_PARITY_ERROR 0x60
+#define IPU7_PHY_DEBUG_REGS_CLK_GATE_EN 0x64
+#define IPU7_SPARE_RW 0xf8
+#define IPU7_SPARE_RO 0xfc
+
+/* software not touch */
+#define IPU7_PORT_ARB_BASE (IPU7_IS_IO_BASE + 0x4e000)
+#define IPU7_PORT_ARB_IRQ_CTL_STATUS 0x4
+#define IPU7_PORT_ARB_IRQ_CTL_CLEAR 0x8
+#define IPU7_PORT_ARB_IRQ_CTL_ENABLE 0xc
+
+#define IPU7_MGC_PPC 4U
+#define IPU7_MGC_DTYPE_RAW(i) (((i) - 8) / 2)
+#define IPU7_IS_IO_MGC_BASE (IPU7_IS_IO_BASE + 0x48000)
+#define IPU7_MGC_KICK 0x0
+#define IPU7_MGC_ASYNC_STOP 0x4
+#define IPU7_MGC_PORT_OFFSET 0x100
+#define IPU7_MGC_CSI_PORT_MAP(i) (0x8 + (i) * 0x4)
+#define IPU7_MGC_MG_PORT(i) (IPU7_IS_IO_MGC_BASE + \
+ (i) * IPU7_MGC_PORT_OFFSET)
+/* per mgc instance */
+#define IPU7_MGC_MG_CSI_ADAPT_LAYER_TYPE 0x28
+#define IPU7_MGC_MG_MODE 0x2c
+#define IPU7_MGC_MG_INIT_COUNTER 0x30
+#define IPU7_MGC_MG_MIPI_VC 0x34
+#define IPU7_MGC_MG_MIPI_DTYPES 0x38
+#define IPU7_MGC_MG_MULTI_DTYPES_MODE 0x3c
+#define IPU7_MGC_MG_NOF_FRAMES 0x40
+#define IPU7_MGC_MG_FRAME_DIM 0x44
+#define IPU7_MGC_MG_HBLANK 0x48
+#define IPU7_MGC_MG_VBLANK 0x4c
+#define IPU7_MGC_MG_TPG_MODE 0x50
+#define IPU7_MGC_MG_TPG_R0 0x54
+#define IPU7_MGC_MG_TPG_G0 0x58
+#define IPU7_MGC_MG_TPG_B0 0x5c
+#define IPU7_MGC_MG_TPG_R1 0x60
+#define IPU7_MGC_MG_TPG_G1 0x64
+#define IPU7_MGC_MG_TPG_B1 0x68
+#define IPU7_MGC_MG_TPG_FACTORS 0x6c
+#define IPU7_MGC_MG_TPG_MASKS 0x70
+#define IPU7_MGC_MG_TPG_XY_MASK 0x74
+#define IPU7_MGC_MG_TPG_TILE_DIM 0x78
+#define IPU7_MGC_MG_PRBS_LFSR_INIT_0 0x7c
+#define IPU7_MGC_MG_PRBS_LFSR_INIT_1 0x80
+#define IPU7_MGC_MG_SYNC_STOP_POINT 0x84
+#define IPU7_MGC_MG_SYNC_STOP_POINT_LOC 0x88
+#define IPU7_MGC_MG_ERR_INJECT 0x8c
+#define IPU7_MGC_MG_ERR_LOCATION 0x90
+#define IPU7_MGC_MG_DTO_SPEED_CTRL_EN 0x94
+#define IPU7_MGC_MG_DTO_SPEED_CTRL_INCR_VAL 0x98
+#define IPU7_MGC_MG_HOR_LOC_STTS 0x9c
+#define IPU7_MGC_MG_VER_LOC_STTS 0xa0
+#define IPU7_MGC_MG_FRAME_NUM_STTS 0xa4
+#define IPU7_MGC_MG_BUSY_STTS 0xa8
+#define IPU7_MGC_MG_STOPPED_STTS 0xac
+/* tile width and height in pixels for Chess board and Color palette */
+#define IPU7_MGC_TPG_TILE_WIDTH 64U
+#define IPU7_MGC_TPG_TILE_HEIGHT 64U
+
+#define IPU7_CSI_PORT_A_ADDR_OFFSET 0x0
+#define IPU7_CSI_PORT_B_ADDR_OFFSET 0x0
+#define IPU7_CSI_PORT_C_ADDR_OFFSET 0x0
+#define IPU7_CSI_PORT_D_ADDR_OFFSET 0x0
+
+/*
+ * 0 - CSI RX Port 0 interrupt;
+ * 1 - MPF Port 0 interrupt;
+ * 2 - CSI RX Port 1 interrupt;
+ * 3 - MPF Port 1 interrupt;
+ * 4 - CSI RX Port 2 interrupt;
+ * 5 - MPF Port 2 interrupt;
+ * 6 - CSI RX Port 3 interrupt;
+ * 7 - MPF Port 3 interrupt;
+ * 8 - Port ARB FIFO 0 overflow;
+ * 9 - Port ARB FIFO 1 overflow;
+ * 10 - Port ARB FIFO 2 overflow;
+ * 11 - Port ARB FIFO 3 overflow;
+ * 12 - isys_cfgnoc_err_probe_intl;
+ * 13-15 - reserved
+ */
+#define IPU7_CSI_IS_IO_IRQ_MASK 0xffff
+
+/* Adapter layer irq */
+#define IPU7_CSI_ADPL_IRQ_MASK 0xffff
+
+/* sw irq from legacy irq control
+ * legacy irq status
+ * IPU7
+ * 0 - CSI Port 0 error interrupt
+ * 1 - CSI Port 0 sync interrupt
+ * 2 - CSI Port 1 error interrupt
+ * 3 - CSI Port 1 sync interrupt
+ * 4 - CSI Port 2 error interrupt
+ * 5 - CSI Port 2 sync interrupt
+ * 6 - CSI Port 3 error interrupt
+ * 7 - CSI Port 3 sync interrupt
+ * IPU7P5
+ * 0 - CSI Port 0 error interrupt
+ * 1 - CSI Port 0 fs interrupt
+ * 2 - CSI Port 0 fe interrupt
+ * 3 - CSI Port 1 error interrupt
+ * 4 - CSI Port 1 fs interrupt
+ * 5 - CSI Port 1 fe interrupt
+ * 6 - CSI Port 2 error interrupt
+ * 7 - CSI Port 2 fs interrupt
+ * 8 - CSI Port 2 fe interrupt
+ */
+#define IPU7_CSI_RX_LEGACY_IRQ_MASK 0x1ff
+
+/* legacy error status per port
+ * 0 - Error handler FIFO full;
+ * 1 - Reserved Short Packet encoding detected;
+ * 2 - Reserved Long Packet encoding detected;
+ * 3 - Received packet is too short (fewer data words than specified in header);
+ * 4 - Received packet is too long (more data words than specified in header);
+ * 5 - Short packet discarded due to errors;
+ * 6 - Long packet discarded due to errors;
+ * 7 - CSI Combo Rx interrupt;
+ * 8 - IDI CDC FIFO overflow; remaining bits are reserved and tied to 0;
+ */
+#define IPU7_CSI_RX_ERROR_IRQ_MASK 0xfff
+
+/*
+ * 0 - VC0 frame start received
+ * 1 - VC0 frame end received
+ * 2 - VC1 frame start received
+ * 3 - VC1 frame end received
+ * 4 - VC2 frame start received
+ * 5 - VC2 frame end received
+ * 6 - VC3 frame start received
+ * 7 - VC3 frame end received
+ * 8 - VC4 frame start received
+ * 9 - VC4 frame end received
+ * 10 - VC5 frame start received
+ * 11 - VC5 frame end received
+ * 12 - VC6 frame start received
+ * 13 - VC6 frame end received
+ * 14 - VC7 frame start received
+ * 15 - VC7 frame end received
+ * 16 - VC8 frame start received
+ * 17 - VC8 frame end received
+ * 18 - VC9 frame start received
+ * 19 - VC9 frame end received
+ * 20 - VC10 frame start received
+ * 21 - VC10 frame end received
+ * 22 - VC11 frame start received
+ * 23 - VC11 frame end received
+ * 24 - VC12 frame start received
+ * 25 - VC12 frame end received
+ * 26 - VC13 frame start received
+ * 27 - VC13 frame end received
+ * 28 - VC14 frame start received
+ * 29 - VC14 frame end received
+ * 30 - VC15 frame start received
+ * 31 - VC15 frame end received
+ */
+
+#define IPU7_CSI_RX_SYNC_IRQ_MASK 0x0
+#define IPU7P5_CSI_RX_SYNC_FE_IRQ_MASK 0x0
+
+#define IPU7_CSI_RX_NUM_ERRORS_IN_IRQ 12U
+#define IPU7_CSI_RX_NUM_SYNC_IN_IRQ 32U
+
+enum IPU7_MGC_CSI_ADPL_TYPE {
+ IPU7_MGC_MAPPED_2_LANES = 0,
+ IPU7_MGC_MAPPED_4_LANES = 1,
+};
+
+enum IPU7_CSI2HOST_SELECTION {
+ IPU7_CSI2HOST_SEL_SOC = 0,
+ IPU7_CSI2HOST_SEL_CSI2HOST = 1,
+};
+
+#define IPU7_CSI_LEGACY_IRQ_MASK(port) (0x3 << ((port) * 2))
+#define IPU7P5_CSI_LEGACY_IRQ_MASK(port) (0x7 << ((port) * 3))
+
+#define IPU7_ISYS_LEGACY_IRQ_CSI2(port) (0x3 << (port))
+#define IPU7P5_ISYS_LEGACY_IRQ_CSI2(port) (0x7 << (port))
+
+/* ---------------------------------------------------------------- */
+#define IPU7_CSI_REG_BASE 0x220000
+#define IPU7_CSI_REG_BASE_PORT(id) ((id) * 0x1000)
+
+/* CSI Port General Purpose Registers */
+#define IPU7_CSI_REG_PORT_GPREG_SRST 0x0
+#define IPU7_CSI_REG_PORT_GPREG_CSI2_SLV_REG_SRST 0x4
+#define IPU7_CSI_REG_PORT_GPREG_CSI2_PORT_CONTROL 0x8
+
+#define IPU7_CSI_RX_SYNC_FS_VC 0x55555555
+#define IPU7_CSI_RX_SYNC_FE_VC 0xaaaaaaaa
+#define IPU7P5_CSI_RX_SYNC_FS_VC 0xffff
+#define IPU7P5_CSI_RX_SYNC_FE_VC 0xffff
+
+#endif /* IPU7_ISYS_CSI2_REG_H */
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 26/44] media: ipu6: Add ipu7 isr handler
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (24 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 25/44] media: ipu6: Add ipu7 csi2 register definitions Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 27/44] media: ipu6: Add ipu7 csi phy driver Antti Laakso
` (17 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
Add ipu7 interrupt handler for software and CSI events.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h | 1 +
drivers/media/pci/intel/ipu6/ipu6-isys.c | 2 +-
drivers/media/pci/intel/ipu6/ipu7-fw-isys.c | 330 +++++++++++++++++-
drivers/media/pci/intel/ipu6/ipu7-fw-isys.h | 38 ++
.../media/pci/intel/ipu6/ipu7-platform-regs.h | 20 ++
5 files changed, 386 insertions(+), 5 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
index ce8eed91065c..ef367c7dc0fa 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
@@ -43,6 +43,7 @@ struct ipu6_isys_csi2 {
u32 receiver_errors;
unsigned int nlanes;
unsigned int port;
+ u32 legacy_irq_mask;
};
struct ipu6_isys_csi2_timing {
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 086c0f01ccda..bcdaf96e9350 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -1075,7 +1075,7 @@ static const struct ipu6_auxdrv_data ipu6_isys_auxdrv_data = {
};
static const struct ipu6_auxdrv_data ipu7_isys_auxdrv_data = {
- .isr = ipu6_isys_isr,
+ .isr = ipu7_isys_isr,
.isr_threaded = NULL,
.wake_isr_thread = false,
.fw_ops = &ipu7_fw_isys_ops,
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
index d35684a2cb58..b2f37aaf0a10 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
@@ -3,12 +3,17 @@
* Copyright (C) 2026 Intel Corporation
*/
+#include <linux/cleanup.h>
+
#include "ipu6-bus.h"
#include "ipu6-dma.h"
#include "ipu6-isys.h"
+#include "ipu6-platform-regs.h"
#include "ipu7-boot.h"
#include "ipu7-fw-com.h"
#include "ipu7-fw-isys.h"
+#include "ipu7-isys-csi2-regs.h"
+#include "ipu7-platform-regs.h"
static void ipu7_fw_isys_cleanup(struct ipu6_isys *isys)
{
@@ -56,7 +61,7 @@ static int ipu7_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
struct ipu7_insys_config *fw_config;
struct ipu7_fw_com_context *fwctx;
dma_addr_t fw_config_dma_addr;
- unsigned int i, num_queues;
+ unsigned int num_queues;
u32 freq;
int ret;
@@ -94,7 +99,7 @@ static int ipu7_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
queue_configs[IPU7_INSYS_INPUT_DEV_QUEUE].token_size_in_bytes =
sizeof(struct ipu7_insys_send_queue_token);
- for (i = IPU7_INSYS_INPUT_MSG_QUEUE; i < num_queues; i++) {
+ for (unsigned int i = IPU7_INSYS_INPUT_MSG_QUEUE; i < num_queues; i++) {
queue_configs[i].max_capacity = IPU7_ISYS_SIZE_SEND_QUEUE;
queue_configs[i].token_size_in_bytes =
sizeof(struct ipu7_insys_send_queue_token);
@@ -321,7 +326,6 @@ static void ipu7_fw_isys_dump_frame_buf_set(struct device *dev,
unsigned int outputs)
{
struct ipu7_fw_isys_frame_buff_set *buf = &msg->ipu7.frame;
- unsigned int i;
dev_dbg(dev, "--------------------------\n");
dev_dbg(dev, "IPU_ISYS_BUFF_SET\n");
@@ -329,7 +333,7 @@ static void ipu7_fw_isys_dump_frame_buf_set(struct device *dev,
dev_dbg(dev, ".frame_id = %d\n", buf->frame_id);
dev_dbg(dev, ".skip_frame = %d\n", buf->skip_frame);
- for (i = 0; i < outputs; i++) {
+ for (unsigned int i = 0; i < outputs; i++) {
dev_dbg(dev, ".output_pin[%d]:\n", i);
dev_dbg(dev, "\t.user_token = %llx\n",
buf->output_pins[i].user_token);
@@ -463,3 +467,321 @@ const struct ipu6_fw_isys_ops ipu7_fw_isys_ops = {
.dump_stream_cfg = ipu7_fw_isys_dump_stream_cfg,
.dump_frame_buf_set = ipu7_fw_isys_dump_frame_buf_set,
};
+
+static const struct ipu7_csi2_error {
+ const char *error_string;
+ bool is_info_only;
+} dphy_rx_errors[] = {
+ { "Error handler FIFO full", false },
+ { "Reserved Short Packet encoding detected", true },
+ { "Reserved Long Packet encoding detected", true },
+ { "Received packet is too short", false},
+ { "Received packet is too long", false},
+ { "Short packet discarded due to errors", false },
+ { "Long packet discarded due to errors", false },
+ { "CSI Combo Rx interrupt", false },
+ { "IDI CDC FIFO overflow(remaining bits are reserved as 0)", false },
+ { "Received NULL packet", true },
+ { "Received blanking packet", true },
+ { "Tie to 0", true },
+};
+
+static void ipu7_isys_register_errors(struct ipu6_isys_csi2 *csi2)
+{
+ u32 offset = IPU7_IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(csi2->port);
+ u32 status = readl(csi2->base + offset + IPU7_IRQ_CTL_STATUS);
+ u32 mask = IPU7_CSI_RX_ERROR_IRQ_MASK;
+
+ if (!status)
+ return;
+
+ dev_dbg(&csi2->isys->adev->auxdev.dev, "csi2-%u error status 0x%08x\n",
+ csi2->port, status);
+
+ writel(status & mask, csi2->base + offset + IPU7_IRQ_CTL_CLEAR);
+ csi2->receiver_errors |= status & mask;
+}
+
+static void ipu7_isys_csi2_error(struct ipu6_isys_csi2 *csi2)
+{
+ u32 status;
+
+ /* Register errors once more in case of error interrupts are disabled */
+ ipu7_isys_register_errors(csi2);
+ status = csi2->receiver_errors;
+ csi2->receiver_errors = 0;
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(dphy_rx_errors); i++) {
+ if (status & BIT(i))
+ dev_err_ratelimited(&csi2->isys->adev->auxdev.dev,
+ "csi2-%i error: %s\n",
+ csi2->port,
+ dphy_rx_errors[i].error_string);
+ }
+}
+
+static const struct resp_to_msg {
+ enum ipu7_insys_resp_type type;
+ const char *msg;
+} is_fw_msg[] = {
+ { IPU7_INSYS_RESP_TYPE_STREAM_OPEN_DONE, "STREAM_OPEN_DONE" },
+ { IPU7_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK,
+ "STREAM_START_AND_CAPTURE_ACK" },
+ { IPU7_INSYS_RESP_TYPE_STREAM_CAPTURE_ACK, "STREAM_CAPTURE_ACK" },
+ { IPU7_INSYS_RESP_TYPE_STREAM_ABORT_ACK, "STREAM_ABORT_ACK" },
+ { IPU7_INSYS_RESP_TYPE_STREAM_FLUSH_ACK, "STREAM_FLUSH_ACK" },
+ { IPU7_INSYS_RESP_TYPE_STREAM_CLOSE_ACK, "STREAM_CLOSE_ACK" },
+ { IPU7_INSYS_RESP_TYPE_PIN_DATA_READY, "PIN_DATA_READY" },
+ { IPU7_INSYS_RESP_TYPE_FRAME_SOF, "FRAME_SOF" },
+ { IPU7_INSYS_RESP_TYPE_FRAME_EOF, "FRAME_EOF" },
+ { IPU7_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE,
+ "STREAM_START_AND_CAPTURE_DONE" },
+ { IPU7_INSYS_RESP_TYPE_STREAM_CAPTURE_DONE, "STREAM_CAPTURE_DONE" },
+ { N_IPU7_INSYS_RESP_TYPE, "N_IPU7_INSYS_RESP_TYPE" },
+};
+
+static int ipu7_isys_isr_one(struct ipu6_bus_device *adev)
+{
+ struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
+ struct ipu6_isys_stream *stream = NULL;
+ struct device *dev = &adev->auxdev.dev;
+ struct ipu6_isys_csi2 *csi2 = NULL;
+ struct ipu7_fw_isys_msg_err err_info;
+ struct isys_fw_msgs *isys_fw_msg;
+ struct ipu7_insys_resp *resp;
+ u64 ts;
+
+ if (!isys->fwctx)
+ return 1;
+
+ resp = ipu7_fw_isys_get_resp(isys);
+ if (!resp)
+ return 1;
+
+ if (resp->type >= N_IPU7_INSYS_RESP_TYPE) {
+ dev_err(dev, "Unknown response type %u stream %u\n",
+ resp->type, resp->stream_id);
+ ipu7_fw_isys_put_resp(isys);
+ return 1;
+ }
+
+ err_info = resp->error_info;
+ ts = ((u64)resp->timestamp[1] << 32) | resp->timestamp[0];
+
+ if (err_info.err_group == INSYS_MSG_ERR_GROUP_CAPTURE &&
+ err_info.err_code == INSYS_MSG_ERR_CAPTURE_SYNC_FRAME_DROP) {
+ /* receive a sp w/o command, firmware drop it */
+ dev_dbg(dev, "FRAME DROP: %02u %s stream %u\n",
+ resp->type, is_fw_msg[resp->type].msg,
+ resp->stream_id);
+ dev_dbg(dev, "\tpin %u buf_id %llx frame %u\n",
+ resp->pin_id, resp->buf_id, resp->frame_id);
+ dev_dbg(dev, "\terror group %u code %u details [%u %u]\n",
+ err_info.err_group, err_info.err_code,
+ err_info.err_detail[0], err_info.err_detail[1]);
+ } else if (err_info.err_code) {
+ dev_err(dev, "%02u %s stream %u pin %u buf_id %llx frame %u\n",
+ resp->type, is_fw_msg[resp->type].msg, resp->stream_id,
+ resp->pin_id, resp->buf_id, resp->frame_id);
+ dev_err(dev, "\terror group %u code %u details [%u %u]\n",
+ err_info.err_group, err_info.err_code,
+ err_info.err_detail[0], err_info.err_detail[1]);
+ } else {
+ dev_dbg(dev, "%02u %s stream %u pin %u buf_id %llx frame %u\n",
+ resp->type, is_fw_msg[resp->type].msg, resp->stream_id,
+ resp->pin_id, resp->buf_id, resp->frame_id);
+ dev_dbg(dev, "\tts %llu\n", ts);
+ }
+
+ if (resp->stream_id >= IPU7_ISYS_MAX_STREAMS) {
+ dev_err(dev, "bad stream handle %u\n",
+ resp->stream_id);
+ goto leave;
+ }
+
+ stream = ipu6_isys_query_stream_by_handle(isys, resp->stream_id);
+ if (!stream) {
+ dev_err(dev, "stream of stream_handle %u is unused\n",
+ resp->stream_id);
+ goto leave;
+ }
+
+ stream->error = err_info.err_code;
+
+ if (stream->asd)
+ csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
+
+ switch (resp->type) {
+ case IPU7_INSYS_RESP_TYPE_STREAM_OPEN_DONE:
+ complete(&stream->stream_open_completion);
+ break;
+ case IPU7_INSYS_RESP_TYPE_STREAM_CLOSE_ACK:
+ complete(&stream->stream_close_completion);
+ break;
+ case IPU7_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_ACK:
+ complete(&stream->stream_start_completion);
+ break;
+ case IPU7_INSYS_RESP_TYPE_STREAM_ABORT_ACK:
+ complete(&stream->stream_stop_completion);
+ break;
+ case IPU7_INSYS_RESP_TYPE_STREAM_FLUSH_ACK:
+ complete(&stream->stream_stop_completion);
+ break;
+ case IPU7_INSYS_RESP_TYPE_PIN_DATA_READY:
+ /*
+ * firmware only release the capture msg until software
+ * get pin_data_ready event
+ */
+ isys_fw_msg = container_of((void *)(uintptr_t)resp->buf_id,
+ struct isys_fw_msgs, dummy);
+
+ ipu6_put_fw_msg_buf(ipu6_bus_get_drvdata(adev), isys_fw_msg);
+ if (resp->pin_id < IPU6_ISYS_OUTPUT_PINS)
+ ipu6_stream_buf_ready(stream, resp->pin_id,
+ resp->pin.addr, ts, 0);
+ else
+ dev_err(dev, "No handler for pin %u ready\n",
+ resp->pin_id);
+ if (csi2)
+ ipu7_isys_csi2_error(csi2);
+
+ break;
+ case IPU7_INSYS_RESP_TYPE_STREAM_CAPTURE_ACK:
+ break;
+ case IPU7_INSYS_RESP_TYPE_STREAM_START_AND_CAPTURE_DONE:
+ case IPU7_INSYS_RESP_TYPE_STREAM_CAPTURE_DONE:
+ break;
+ case IPU7_INSYS_RESP_TYPE_FRAME_SOF:
+ if (csi2)
+ ipu6_isys_csi2_sof_event_by_stream(stream);
+
+ stream->seq[stream->seq_index].sequence =
+ atomic_read(&stream->sequence) - 1U;
+ stream->seq[stream->seq_index].timestamp = ts;
+ dev_dbg(dev,
+ "SOF: stream %u frame %u (index %u), ts 0x%16.16llx\n",
+ resp->stream_id, resp->frame_id,
+ stream->seq[stream->seq_index].sequence, ts);
+ stream->seq_index = (stream->seq_index + 1U)
+ % IPU6_ISYS_MAX_PARALLEL_SOF;
+ break;
+ case IPU7_INSYS_RESP_TYPE_FRAME_EOF:
+ if (csi2)
+ ipu6_isys_csi2_eof_event_by_stream(stream);
+
+ dev_dbg(dev, "eof: stream %d(index %u) ts 0x%16.16llx\n",
+ resp->stream_id,
+ stream->seq[stream->seq_index].sequence, ts);
+ break;
+ default:
+ dev_err(dev, "Unknown response type %u stream %u\n",
+ resp->type, resp->stream_id);
+ break;
+ }
+
+ ipu6_isys_put_stream(stream);
+leave:
+ ipu7_fw_isys_put_resp(isys);
+
+ return 0;
+}
+
+#define IPU7_NR_OF_CSI2_VC 16U
+static void ipu7_isys_csi2_isr(struct ipu6_isys_csi2 *csi2)
+{
+ struct device *dev = &csi2->isys->adev->auxdev.dev;
+ struct ipu6_device *isp = csi2->isys->adev->isp;
+ struct ipu6_isys_stream *s;
+ u32 sync, offset;
+ u32 fe = 0;
+ u8 vc;
+
+ ipu7_isys_register_errors(csi2);
+
+ offset = IPU7_IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(csi2->port);
+ sync = readl(csi2->base + offset + IPU7_IRQ_CTL_STATUS);
+ writel(sync, csi2->base + offset + IPU7_IRQ_CTL_CLEAR);
+ dev_dbg(dev, "csi2-%u sync status 0x%08x\n", csi2->port, sync);
+
+ if (!IS_IPU7_MTL(isp)) {
+ fe = readl(csi2->base + offset + IPU7_IRQ1_CTL_STATUS);
+ writel(fe, csi2->base + offset + IPU7_IRQ1_CTL_CLEAR);
+ dev_dbg(dev, "csi2-%u FE status 0x%08x\n", csi2->port, fe);
+ }
+
+ for (vc = 0; vc < IPU7_NR_OF_CSI2_VC && (sync || fe); vc++) {
+ s = ipu6_isys_query_stream_by_source(csi2->isys,
+ csi2->asd.source, vc);
+ if (!s)
+ continue;
+
+ if (!IS_IPU7_MTL(isp)) {
+ if (sync & IPU7P5_CSI_RX_SYNC_FS_VC & (1U << vc))
+ ipu6_isys_csi2_sof_event_by_stream(s);
+
+ if (fe & IPU7P5_CSI_RX_SYNC_FE_VC & (1U << vc))
+ ipu6_isys_csi2_eof_event_by_stream(s);
+ } else {
+ if (sync & IPU7_CSI_RX_SYNC_FS_VC & (1U << (vc * 2)))
+ ipu6_isys_csi2_sof_event_by_stream(s);
+
+ if (sync & IPU7_CSI_RX_SYNC_FE_VC & (2U << (vc * 2)))
+ ipu6_isys_csi2_eof_event_by_stream(s);
+ }
+ }
+}
+
+static void ipu7_dispatch_csi2_isr(struct ipu6_isys *isys, u32 status)
+{
+ for (unsigned int i = 0; i < isys->pdata->ipdata->csi2.nports; i++) {
+ if (!isys->csi2[i].base)
+ continue;
+ if (status & isys->csi2[i].legacy_irq_mask)
+ ipu7_isys_csi2_isr(&isys->csi2[i]);
+ }
+}
+
+irqreturn_t ipu7_isys_isr(struct ipu6_bus_device *adev)
+{
+ struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
+ void __iomem *base = isys->pdata->base;
+ u32 status_sw, status_csi;
+ u32 csi_offset, sw_offset;
+
+ guard(spinlock)(&isys->power_lock);
+
+ if (!isys->power)
+ return IRQ_NONE;
+
+ csi_offset = IPU7_IS_IO_CSI2_LEGACY_IRQ_CTRL_BASE;
+ sw_offset = IPU7_IS_UC_CTRL_BASE;
+
+ status_csi = readl(base + csi_offset + IPU7_IRQ_CTL_STATUS);
+ status_sw = readl(base + sw_offset + IPU7_TO_SW_IRQ_CNTL_STATUS);
+
+ if (!status_csi && !status_sw)
+ return IRQ_NONE;
+
+ do {
+ writel(status_sw, base + sw_offset + IPU7_TO_SW_IRQ_CNTL_CLEAR);
+ writel(status_csi, base + csi_offset + IPU7_IRQ_CTL_CLEAR);
+
+ if (isys->isr_csi2_bits & status_csi)
+ ipu7_dispatch_csi2_isr(isys, status_csi);
+
+ if (!ipu7_isys_isr_one(adev))
+ status_sw = IPU7_TO_SW_IRQ_FW;
+ else
+ status_sw = 0;
+
+ status_csi = readl(base + csi_offset + IPU7_IRQ_CTL_STATUS);
+ status_sw |= readl(base + sw_offset +
+ IPU7_TO_SW_IRQ_CNTL_STATUS);
+ } while ((status_csi & isys->isr_csi2_bits) ||
+ (status_sw & IPU7_TO_SW_IRQ_FW));
+
+ writel(IPU7_IS_UC_TO_SW_IRQ_MASK,
+ base + sw_offset + IPU7_TO_SW_IRQ_CNTL_MASK_N);
+
+ return IRQ_HANDLED;
+}
diff --git a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h
index 122531065362..d5289f6add8c 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h
@@ -117,6 +117,43 @@ enum ipu7_insys_mipi_dt_rename_mode {
N_IPU7_INSYS_MIPI_DT_MODE
};
+enum insys_msg_err_capture {
+ INSYS_MSG_ERR_CAPTURE_OK = 0,
+ INSYS_MSG_ERR_CAPTURE_STREAM_ID = 1,
+ INSYS_MSG_ERR_CAPTURE_PAYLOAD_PTR = 2,
+ INSYS_MSG_ERR_CAPTURE_MEM_SLOT = 3,
+ INSYS_MSG_ERR_CAPTURE_STREAMING_MODE = 4,
+ INSYS_MSG_ERR_CAPTURE_AVAILABLE_CMD_SLOT = 5,
+ INSYS_MSG_ERR_CAPTURE_CONSUMED_CMD_SLOT = 6,
+ INSYS_MSG_ERR_CAPTURE_CMD_SLOT_PAYLOAD_PTR = 7,
+ INSYS_MSG_ERR_CAPTURE_CMD_PREPARE = 8,
+ INSYS_MSG_ERR_CAPTURE_OUTPUT_PIN = 9,
+ INSYS_MSG_ERR_CAPTURE_SYNC_FRAME_DROP = 10,
+ INSYS_MSG_ERR_CAPTURE_FRAME_MESSAGES_MAP = 11,
+ INSYS_MSG_ERR_CAPTURE_TIMEOUT = 12,
+ INSYS_MSG_ERR_CAPTURE_INVALID_STREAM_STATE = 13,
+ INSYS_MSG_ERR_CAPTURE_HW_ERR_MULTIBIT_PH_ERROR_DETECTED = 14,
+ INSYS_MSG_ERR_CAPTURE_HW_ERR_PAYLOAD_CRC_ERROR = 15,
+ INSYS_MSG_ERR_CAPTURE_HW_ERR_INPUT_DATA_LOSS_ELASTIC_FIFO_OVFL = 16,
+ INSYS_MSG_ERR_CAPTURE_HW_ERR_PIXEL_BUFFER_OVERFLOW = 17,
+ INSYS_MSG_ERR_CAPTURE_HW_ERR_BAD_FRAME_DIM = 18,
+ INSYS_MSG_ERR_CAPTURE_HW_ERR_PHY_SYNC_ERR = 19,
+ INSYS_MSG_ERR_CAPTURE_HW_ERR_SECURE_TOUCH = 20,
+ INSYS_MSG_ERR_CAPTURE_HW_ERR_MASTER_SLAVE_SYNC_ERR = 21,
+ INSYS_MSG_ERR_CAPTURE_FRAME_SKIP_ERR = 22,
+ INSYS_MSG_ERR_CAPTURE_FE_INPUT_FIFO_OVERFLOW_ERR = 23,
+ INSYS_MSG_ERR_CAPTURE_CMD_SUBMIT_TO_HW = 24,
+ INSYS_MSG_ERR_CAPTURE_N
+};
+
+enum insys_msg_err_groups {
+ INSYS_MSG_ERR_GROUP_RESERVED = 0,
+ INSYS_MSG_ERR_GROUP_GENERAL = 1,
+ INSYS_MSG_ERR_GROUP_STREAM = 2,
+ INSYS_MSG_ERR_GROUP_CAPTURE = 3,
+ INSYS_MSG_ERR_GROUP_N,
+};
+
struct ipu7_fw_isys_logger_config {
u8 use_source_severity;
u8 source_severity[IPU7_FWLOG_MAX_LOGGER_SOURCES];
@@ -254,5 +291,6 @@ struct ipu7_fw_isys_frame_buff_set {
} __packed;
struct ipu6_fw_isys_ops *ipu7_fw_isys_get_ops(void);
+irqreturn_t ipu7_isys_isr(struct ipu6_bus_device *adev);
#endif
diff --git a/drivers/media/pci/intel/ipu6/ipu7-platform-regs.h b/drivers/media/pci/intel/ipu6/ipu7-platform-regs.h
index 3ca9d65e58b9..39cd5c0890e5 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-platform-regs.h
+++ b/drivers/media/pci/intel/ipu6/ipu7-platform-regs.h
@@ -9,4 +9,24 @@
#define IPU7_PS_UC_CTRL_BASE 0x130000
#define IPU7_PSYS_DMEM_OFFSET 0x100000
+#define IPU7_IS_IO_BASE 0x280000
+#define IPU7_IS_IO_CSI2_GPREGS_BASE (IPU7_IS_IO_BASE + 0x53400)
+
+#define IPU7_IS_IO_CSI2_LEGACY_IRQ_CTRL_BASE (IPU7_IS_IO_BASE + 0x49000)
+#define IPU7_IRQ_CTL_EDGE 0x0
+#define IPU7_IRQ_CTL_MASK 0x4
+#define IPU7_IRQ_CTL_STATUS 0x8
+#define IPU7_IRQ_CTL_CLEAR 0xc
+#define IPU7_IRQ_CTL_ENABLE 0x10
+#define IPU7_CSI_RX_LEGACY_IRQ_MASK 0x1ff
+
+#define IPU7_TO_SW_IRQ_CNTL_EDGE 0x4000
+#define IPU7_TO_SW_IRQ_CNTL_MASK_N 0x4004
+#define IPU7_TO_SW_IRQ_CNTL_STATUS 0x4008
+#define IPU7_TO_SW_IRQ_CNTL_CLEAR 0x400c
+#define IPU7_TO_SW_IRQ_CNTL_ENABLE 0x4010
+#define IPU7_IS_UC_TO_SW_IRQ_MASK 0xf
+#define IPU7_TO_SW_IRQ_FW BIT(0)
+#define IPU7_REG_PRINTF_AXI_CNTL 0x301c
+
#endif
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 27/44] media: ipu6: Add ipu7 csi phy driver
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (25 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 26/44] media: ipu6: Add ipu7 isr handler Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 28/44] media: ipu6: Split ipu6 csi2 stream enable/disable Antti Laakso
` (16 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The csi receiver is completely different in ipu7 compared to ipu6,
add a driver for it.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/Makefile | 3 +-
drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h | 4 +
drivers/media/pci/intel/ipu6/ipu6-isys.c | 7 +-
drivers/media/pci/intel/ipu6/ipu6-isys.h | 1 +
drivers/media/pci/intel/ipu6/ipu6.c | 6 +
drivers/media/pci/intel/ipu6/ipu6.h | 2 +
.../media/pci/intel/ipu6/ipu7-isys-csi-phy.c | 1072 +++++++++++++++++
.../media/pci/intel/ipu6/ipu7-isys-csi-phy.h | 16 +
8 files changed, 1109 insertions(+), 2 deletions(-)
create mode 100644 drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.c
create mode 100644 drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.h
diff --git a/drivers/media/pci/intel/ipu6/Makefile b/drivers/media/pci/intel/ipu6/Makefile
index 66986d5709ae..676bc978b972 100644
--- a/drivers/media/pci/intel/ipu6/Makefile
+++ b/drivers/media/pci/intel/ipu6/Makefile
@@ -23,6 +23,7 @@ intel-ipu6-isys-y := ipu6-isys.o \
ipu6-isys-subdev.o \
ipu6-isys-mcd-phy.o \
ipu6-isys-jsl-phy.o \
- ipu6-isys-dwc-phy.o
+ ipu6-isys-dwc-phy.o \
+ ipu7-isys-csi-phy.o
obj-$(CONFIG_VIDEO_INTEL_IPU6) += intel-ipu6-isys.o
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
index ef367c7dc0fa..dbaaf00af623 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
@@ -16,6 +16,9 @@ struct ipu6_isys_video;
struct ipu6_isys;
struct ipu6_isys_stream;
+#define PHY_MODE_DPHY 0
+#define PHY_MODE_CPHY 1
+
#define NR_OF_CSI2_VC 16
#define INVALID_VC_ID -1
#define NR_OF_CSI2_SINK_PADS 1
@@ -44,6 +47,7 @@ struct ipu6_isys_csi2 {
unsigned int nlanes;
unsigned int port;
u32 legacy_irq_mask;
+ unsigned int phy_mode;
};
struct ipu6_isys_csi2_timing {
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index bcdaf96e9350..5de5fd16ca30 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -41,6 +41,9 @@
#include "ipu6-platform-buttress-regs.h"
#include "ipu6-platform-isys-csi2-reg.h"
#include "ipu6-platform-regs.h"
+#include "ipu7-isys-csi-phy.h"
+#include "ipu7-isys-csi2-regs.h"
+#include "ipu7-platform-regs.h"
#define IPU6_BUTTRESS_FABIC_CONTROL 0x68
#define GDA_ENABLE_IWAKE_INDEX 2
@@ -1004,7 +1007,9 @@ static int isys_probe(struct auxiliary_device *auxdev,
isys_iwake_watermark_init(isys);
- if (IS_IPU6SE(adev->isp))
+ if (IS_IPU7(adev->isp))
+ isys->phy_set_power = ipu7_isys_csi_phy_set_power;
+ else if (IS_IPU6SE(adev->isp))
isys->phy_set_power = ipu6_isys_jsl_phy_set_power;
else if (IS_IPU6EP_MTL(adev->isp))
isys->phy_set_power = ipu6_isys_dwc_phy_set_power;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h
index 697c090cc3b1..30539ea5f826 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h
@@ -138,6 +138,7 @@ struct ipu6_isys {
int streams_ref_count[IPU6_ISYS_MAX_STREAMS];
void *fwctx;
u32 phy_termcal_val;
+ u32 phy_rext_cal;
bool need_reset;
bool icache_prefetch;
bool csi2_cse_ipc_not_supported;
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 51174cafb1b4..fd7888a011a5 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -32,6 +32,7 @@
#include "ipu6-platform-buttress-regs.h"
#include "ipu6-platform-isys-csi2-reg.h"
#include "ipu6-platform-regs.h"
+#include "ipu7-isys-csi2-regs.h"
#define IPU6_PCI_BAR 0
#define IPU7_PCI_PBBAR 4
@@ -325,6 +326,11 @@ static void ipu6_internal_pdata_init(struct ipu6_device *isp)
isys_ipdata.max_devq_size = IPU6SE_DEV_SEND_QUEUE_SIZE;
psys_ipdata.hw_variant.spc_offset = IPU6SE_PSYS_SPC_OFFSET;
}
+
+ if (IS_IPU7(isp)) {
+ isys_ipdata.csi2.gpreg = IPU7_IS_IO_CSI2_GPREGS_BASE;
+ isys_ipdata.csi2.nports = 4;
+ }
}
static struct ipu6_bus_device *
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index debd571b6f6d..6bef45a02c2b 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -136,6 +136,8 @@ struct ipu6_isys_internal_csi2_pdata {
u32 ctrl0_irq_lnp;
u32 ctrl0_irq_status;
u32 fw_access_port_ofs;
+ /* IPU7-specific field */
+ u32 gpreg;
};
struct ipu6_isys_internal_tpg_pdata {
diff --git a/drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.c b/drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.c
new file mode 100644
index 000000000000..10273c687faa
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.c
@@ -0,0 +1,1072 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2013 - 2026 Intel Corporation
+ */
+
+#include <linux/bitmap.h>
+#include <linux/bug.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include <media/mipi-csi2.h>
+#include <media/v4l2-device.h>
+
+#include "ipu6.h"
+#include "ipu6-bus.h"
+#include "ipu6-isys.h"
+#include "ipu6-isys-csi2.h"
+#include "ipu7-isys-csi2-regs.h"
+#include "ipu7-isys-csi-phy.h"
+
+#define PORT_A 0U
+#define PORT_B 1U
+#define PORT_C 2U
+#define PORT_D 3U
+
+#define N_DATA_IDS 8U
+static DECLARE_BITMAP(data_ids, N_DATA_IDS);
+
+struct ddlcal_counter_ref_s {
+ u16 min_mbps;
+ u16 max_mbps;
+
+ u16 ddlcal_counter_ref;
+};
+
+struct ddlcal_params {
+ u16 min_mbps;
+ u16 max_mbps;
+ u16 oa_lanex_hsrx_cdphy_sel_fast;
+ u16 ddlcal_max_phase;
+ u16 phase_bound;
+ u16 ddlcal_dll_fbk;
+ u16 ddlcal_ddl_coarse_bank;
+ u16 fjump_deskew;
+ u16 min_eye_opening_deskew;
+};
+
+struct i_thssettle_params {
+ u16 min_mbps;
+ u16 max_mbps;
+ u16 i_thssettle;
+};
+
+/* lane2 for 4l3t, lane1 for 2l2t */
+struct oa_lane_clk_div_params {
+ u16 min_mbps;
+ u16 max_mbps;
+ u16 oa_lane_hsrx_hs_clk_div;
+};
+
+struct cdr_fbk_cap_prog_params {
+ u16 min_mbps;
+ u16 max_mbps;
+ u16 val;
+};
+
+static const struct ddlcal_counter_ref_s table0[] = {
+ { 1500, 1999, 118 },
+ { 2000, 2499, 157 },
+ { 2500, 3499, 196 },
+ { 3500, 4499, 274 },
+ { 4500, 4500, 352 },
+ { }
+};
+
+static const struct ddlcal_params table1[] = {
+ { 1500, 1587, 0, 143, 167, 17, 3, 4, 29 },
+ { 1588, 1687, 0, 135, 167, 15, 3, 4, 27 },
+ { 1688, 1799, 0, 127, 135, 15, 2, 4, 26 },
+ { 1800, 1928, 0, 119, 135, 13, 2, 3, 24 },
+ { 1929, 2076, 0, 111, 135, 13, 2, 3, 23 },
+ { 2077, 2249, 0, 103, 135, 11, 2, 3, 21 },
+ { 2250, 2454, 0, 95, 103, 11, 1, 3, 19 },
+ { 2455, 2699, 0, 87, 103, 9, 1, 3, 18 },
+ { 2700, 2999, 0, 79, 103, 9, 1, 2, 16 },
+ { 3000, 3229, 0, 71, 71, 7, 1, 2, 15 },
+ { 3230, 3599, 1, 87, 103, 9, 1, 3, 18 },
+ { 3600, 3999, 1, 79, 103, 9, 1, 2, 16 },
+ { 4000, 4499, 1, 71, 103, 7, 1, 2, 15 },
+ { 4500, 4500, 1, 63, 71, 7, 0, 2, 13 },
+ { }
+};
+
+static const struct i_thssettle_params table2[] = {
+ { 80, 124, 24 },
+ { 125, 249, 20 },
+ { 250, 499, 16 },
+ { 500, 749, 14 },
+ { 750, 1499, 13 },
+ { 1500, 4500, 12 },
+ { }
+};
+
+static const struct oa_lane_clk_div_params table6[] = {
+ { 80, 159, 0x1 },
+ { 160, 319, 0x2 },
+ { 320, 639, 0x3 },
+ { 640, 1279, 0x4 },
+ { 1280, 2560, 0x5 },
+ { 2561, 4500, 0x6 },
+ { }
+};
+
+static const struct cdr_fbk_cap_prog_params table7[] = {
+ { 80, 919, 0 },
+ { 920, 1029, 1 },
+ { 1030, 1169, 2 },
+ { 1170, 1349, 3 },
+ { 1350, 1589, 4 },
+ { 1590, 1949, 5 },
+ { 1950, 2499, 6 },
+ { 2500, 3500, 7 },
+ { }
+};
+
+static void dwc_phy_write(struct ipu6_isys *isys, u32 id, u32 addr, u16 data)
+{
+ void __iomem *isys_base = isys->pdata->base;
+ void __iomem *base = isys_base + IPU7_IS_IO_CDPHY_BASE(id);
+
+ dev_dbg(&isys->adev->auxdev.dev, "phy write: reg 0x%lx = data 0x%04x",
+ (unsigned long)(base + addr - isys_base), data);
+ writew(data, base + addr);
+}
+
+static u16 dwc_phy_read(struct ipu6_isys *isys, u32 id, u32 addr)
+{
+ void __iomem *isys_base = isys->pdata->base;
+ void __iomem *base = isys_base + IPU7_IS_IO_CDPHY_BASE(id);
+ u16 data;
+
+ data = readw(base + addr);
+ dev_dbg(&isys->adev->auxdev.dev, "phy read: reg 0x%lx = data 0x%04x",
+ (unsigned long)(base + addr - isys_base), data);
+
+ return data;
+}
+
+static void dwc_csi_write(struct ipu6_isys *isys, u32 id, u32 addr, u32 data)
+{
+ void __iomem *isys_base = isys->pdata->base;
+ void __iomem *base = isys_base + IPU7_IS_IO_CSI2_HOST_BASE(id);
+ struct device *dev = &isys->adev->auxdev.dev;
+
+ dev_dbg(dev, "csi write: reg 0x%lx = data 0x%08x",
+ (unsigned long)(base + addr - isys_base), data);
+ writel(data, base + addr);
+ dev_dbg(dev, "csi read: reg 0x%lx = data 0x%08x",
+ (unsigned long)(base + addr - isys_base),
+ readl(base + addr));
+}
+
+static void gpreg_write(struct ipu6_isys *isys, u32 id, u32 addr, u32 data)
+{
+ void __iomem *isys_base = isys->pdata->base;
+ u32 gpreg = isys->pdata->ipdata->csi2.gpreg;
+ void __iomem *base = isys_base + gpreg + 0x1000 * id;
+ struct device *dev = &isys->adev->auxdev.dev;
+
+ dev_dbg(dev, "gpreg write: reg 0x%lx = data 0x%08x",
+ (unsigned long)(base + addr - isys_base), data);
+ writel(data, base + addr);
+ dev_dbg(dev, "gpreg read: reg 0x%lx = data 0x%08x",
+ (unsigned long)(base + addr - isys_base),
+ readl(base + addr));
+}
+
+static u32 dwc_csi_read(struct ipu6_isys *isys, u32 id, u32 addr)
+{
+ void __iomem *isys_base = isys->pdata->base;
+ void __iomem *base = isys_base + IPU7_IS_IO_CSI2_HOST_BASE(id);
+ u32 data;
+
+ data = readl(base + addr);
+ dev_dbg(&isys->adev->auxdev.dev, "csi read: reg 0x%lx = data 0x%x",
+ (unsigned long)(base + addr - isys_base), data);
+
+ return data;
+}
+
+static void dwc_phy_write_mask(struct ipu6_isys *isys, u32 id, u32 addr,
+ u16 val, u8 lo, u8 hi)
+{
+ u32 temp, mask;
+
+ WARN_ON(lo > hi);
+ WARN_ON(hi > 15);
+
+ mask = ((~0U - (1U << lo) + 1U)) & (~0U >> (31 - hi));
+ temp = dwc_phy_read(isys, id, addr);
+ temp &= ~mask;
+ temp |= (val << lo) & mask;
+ dwc_phy_write(isys, id, addr, temp);
+}
+
+static void dwc_csi_write_mask(struct ipu6_isys *isys, u32 id, u32 addr,
+ u32 val, u8 hi, u8 lo)
+{
+ u32 temp, mask;
+
+ WARN_ON(lo > hi);
+
+ mask = ((~0U - (1U << lo) + 1U)) & (~0U >> (31 - hi));
+ temp = dwc_csi_read(isys, id, addr);
+ temp &= ~mask;
+ temp |= (val << lo) & mask;
+ dwc_csi_write(isys, id, addr, temp);
+}
+
+static void ipu7_isys_csi_ctrl_cfg(struct ipu6_isys_csi2 *csi2)
+{
+ struct ipu6_isys *isys = csi2->isys;
+ struct device *dev = &isys->adev->auxdev.dev;
+ u32 id, lanes, phy_mode;
+ u32 val;
+
+ id = csi2->port;
+ lanes = csi2->nlanes;
+ phy_mode = csi2->phy_mode;
+ dev_dbg(dev, "csi-%d controller init with %u lanes, phy mode %u",
+ id, lanes, phy_mode);
+
+ val = dwc_csi_read(isys, id, IPU7_VERSION);
+ dev_dbg(dev, "csi-%d controller version = 0x%x", id, val);
+
+ /* num of active data lanes */
+ dwc_csi_write(isys, id, IPU7_N_LANES, lanes - 1);
+ dwc_csi_write(isys, id, IPU7_CDPHY_MODE, phy_mode);
+ dwc_csi_write(isys, id, IPU7_VC_EXTENSION, 0);
+
+ /* only mask PHY_FATAL and PKT_FATAL interrupts */
+ dwc_csi_write(isys, id, IPU7_INT_MSK_PHY_FATAL, 0xff);
+ dwc_csi_write(isys, id, IPU7_INT_MSK_PKT_FATAL, 0x3);
+ dwc_csi_write(isys, id, IPU7_INT_MSK_PHY, 0x0);
+ dwc_csi_write(isys, id, IPU7_INT_MSK_LINE, 0x0);
+ dwc_csi_write(isys, id, IPU7_INT_MSK_BNDRY_FRAME_FATAL, 0x0);
+ dwc_csi_write(isys, id, IPU7_INT_MSK_SEQ_FRAME_FATAL, 0x0);
+ dwc_csi_write(isys, id, IPU7_INT_MSK_CRC_FRAME_FATAL, 0x0);
+ dwc_csi_write(isys, id, IPU7_INT_MSK_PLD_CRC_FATAL, 0x0);
+ dwc_csi_write(isys, id, IPU7_INT_MSK_DATA_ID, 0x0);
+ dwc_csi_write(isys, id, IPU7_INT_MSK_ECC_CORRECTED, 0x0);
+}
+
+static void ipu7_isys_csi_phy_reset(struct ipu6_isys *isys, u32 id)
+{
+ dwc_csi_write(isys, id, IPU7_PHY_SHUTDOWNZ, 0);
+ dwc_csi_write(isys, id, IPU7_DPHY_RSTZ, 0);
+ dwc_csi_write(isys, id, IPU7_CSI2_RESETN, 0);
+ gpreg_write(isys, id, IPU7_PHY_RESET, 0);
+ gpreg_write(isys, id, IPU7_PHY_SHUTDOWN, 0);
+}
+
+/* 8 Data ID monitors, each Data ID is composed by pair of VC and data type */
+static int __dids_config(struct ipu6_isys_csi2 *csi2, u32 id, u8 vc, u8 dt)
+{
+ struct ipu6_isys *isys = csi2->isys;
+ u32 reg, n;
+ u8 lo, hi;
+ int ret;
+
+ dev_dbg(&isys->adev->auxdev.dev,
+ "config CSI-%u with vc:%u dt:0x%02x\n", id, vc, dt);
+
+ dwc_csi_write(isys, id, IPU7_VC_EXTENSION, 0x0);
+ n = find_first_zero_bit(data_ids, N_DATA_IDS);
+ if (n == N_DATA_IDS)
+ return -ENOSPC;
+
+ ret = test_and_set_bit(n, data_ids);
+ if (ret)
+ return -EBUSY;
+
+ reg = n < 4 ? IPU7_DATA_IDS_VC_1 : IPU7_DATA_IDS_VC_2;
+ lo = (n % 4) * 8;
+ hi = lo + 4;
+ dwc_csi_write_mask(isys, id, reg, vc & GENMASK(4, 0), hi, lo);
+
+ reg = n < 4 ? IPU7_DATA_IDS_1 : IPU7_DATA_IDS_2;
+ lo = (n % 4) * 8;
+ hi = lo + 5;
+ dwc_csi_write_mask(isys, id, reg, dt & GENMASK(5, 0), hi, lo);
+
+ return 0;
+}
+
+static int ipu7_isys_csi_ctrl_dids_config(struct ipu6_isys_csi2 *csi2, u32 id)
+{
+ struct v4l2_mbus_frame_desc_entry *desc_entry = NULL;
+ struct device *dev = &csi2->isys->adev->auxdev.dev;
+ struct v4l2_mbus_frame_desc desc;
+ struct v4l2_subdev *ext_sd;
+ struct media_pad *pad;
+ int ret;
+
+ pad = media_entity_remote_source_pad_unique(&csi2->asd.sd.entity);
+ if (IS_ERR(pad)) {
+ dev_warn(dev, "can't get remote source pad of %s (%pe)\n",
+ csi2->asd.sd.name, pad);
+ return PTR_ERR(pad);
+ }
+
+ ext_sd = media_entity_to_v4l2_subdev(pad->entity);
+ if (WARN(!ext_sd, "Failed to get subdev for entity %s\n",
+ pad->entity->name))
+ return -ENODEV;
+
+ ret = v4l2_subdev_call(ext_sd, pad, get_frame_desc, pad->index, &desc);
+ if (ret)
+ return ret;
+
+ if (desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
+ dev_warn(dev, "Unsupported frame descriptor type\n");
+ return -EINVAL;
+ }
+
+ for (unsigned int i = 0; i < desc.num_entries; i++) {
+ desc_entry = &desc.entry[i];
+ if (desc_entry->bus.csi2.vc < NR_OF_CSI2_VC) {
+ ret = __dids_config(csi2, id, desc_entry->bus.csi2.vc,
+ desc_entry->bus.csi2.dt);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+#define CDPHY_TIMEOUT 5000000U
+static int ipu7_isys_phy_ready(struct ipu6_isys *isys, u32 id)
+{
+ void __iomem *isys_base = isys->pdata->base;
+ u32 gpreg_offset = isys->pdata->ipdata->csi2.gpreg;
+ void __iomem *gpreg = isys_base + gpreg_offset + 0x1000 * id;
+ struct device *dev = &isys->adev->auxdev.dev;
+ u32 phy_ready;
+ u32 reg, rext;
+ int ret;
+
+ dev_dbg(dev, "waiting phy ready...\n");
+ ret = readl_poll_timeout(gpreg + IPU7_PHY_READY, phy_ready,
+ phy_ready & BIT(0) && phy_ready != ~0U,
+ 100, CDPHY_TIMEOUT);
+ dev_dbg(dev, "phy %u ready = 0x%08x\n",
+ id, readl(gpreg + IPU7_PHY_READY));
+ dev_dbg(dev, "csi %u IPU7_PHY_RX = 0x%08x\n", id,
+ dwc_csi_read(isys, id, IPU7_PHY_RX));
+ dev_dbg(dev, "csi %u IPU7_PHY_STOPSTATE = 0x%08x\n", id,
+ dwc_csi_read(isys, id, IPU7_PHY_STOPSTATE));
+ dev_dbg(dev, "csi %u IPU7_PHY_CAL = 0x%08x\n", id,
+ dwc_csi_read(isys, id, IPU7_PHY_CAL));
+ for (unsigned int i = 0; i < 4U; i++) {
+ reg = IPU7_CORE_DIG_DLANE_0_R_HS_RX_0 + (i * 0x400U);
+ dev_dbg(dev, "phy %u DLANE%u skewcal = 0x%04x\n",
+ id, i, dwc_phy_read(isys, id, reg));
+ }
+ dev_dbg(dev, "phy %u DDLCAL = 0x%04x\n", id,
+ dwc_phy_read(isys, id,
+ IPU7_PPI_CALIBCTRL_R_COMMON_CALIBCTRL_2_5));
+ dev_dbg(dev, "phy %u TERMCAL = 0x%04x\n", id,
+ dwc_phy_read(isys, id, IPU7_PPI_R_TERMCAL_DEBUG_0));
+ dev_dbg(dev, "phy %u LPDCOCAL = 0x%04x\n", id,
+ dwc_phy_read(isys, id, IPU7_PPI_R_LPDCOCAL_DEBUG_RB));
+ dev_dbg(dev, "phy %u HSDCOCAL = 0x%04x\n", id,
+ dwc_phy_read(isys, id, IPU7_PPI_R_HSDCOCAL_DEBUG_RB));
+ dev_dbg(dev, "phy %u LPDCOCAL_VT = 0x%04x\n", id,
+ dwc_phy_read(isys, id, IPU7_PPI_R_LPDCOCAL_DEBUG_VT));
+
+ if (!ret) {
+ if (id) {
+ dev_dbg(dev, "ignore phy %u rext\n", id);
+ return 0;
+ }
+
+ rext = dwc_phy_read(isys, id,
+ IPU7_CORE_DIG_IOCTRL_R_AFE_CB_CTRL_2_15) &
+ 0xfU;
+ dev_dbg(dev, "phy %u rext value = %u\n", id, rext);
+ isys->phy_rext_cal = (rext ? rext : 5);
+
+ return 0;
+ }
+
+ dev_err(dev, "wait phy ready timeout!\n");
+
+ return ret;
+}
+
+static int lookup_table1(u64 mbps)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(table1); i++) {
+ if (mbps >= table1[i].min_mbps && mbps <= table1[i].max_mbps)
+ return i;
+ }
+
+ return -ENXIO;
+}
+
+static const u16 deskew_fine_mem[] = {
+ 0x0404, 0x040c, 0x0414, 0x041c,
+ 0x0423, 0x0429, 0x0430, 0x043a,
+ 0x0445, 0x044a, 0x0450, 0x045a,
+ 0x0465, 0x0469, 0x0472, 0x047a,
+ 0x0485, 0x0489, 0x0490, 0x049a,
+ 0x04a4, 0x04ac, 0x04b4, 0x04bc,
+ 0x04c4, 0x04cc, 0x04d4, 0x04dc,
+ 0x04e4, 0x04ec, 0x04f4, 0x04fc,
+ 0x0504, 0x050c, 0x0514, 0x051c,
+ 0x0523, 0x0529, 0x0530, 0x053a,
+ 0x0545, 0x054a, 0x0550, 0x055a,
+ 0x0565, 0x0569, 0x0572, 0x057a,
+ 0x0585, 0x0589, 0x0590, 0x059a,
+ 0x05a4, 0x05ac, 0x05b4, 0x05bc,
+ 0x05c4, 0x05cc, 0x05d4, 0x05dc,
+ 0x05e4, 0x05ec, 0x05f4, 0x05fc,
+ 0x0604, 0x060c, 0x0614, 0x061c,
+ 0x0623, 0x0629, 0x0632, 0x063a,
+ 0x0645, 0x064a, 0x0650, 0x065a,
+ 0x0665, 0x0669, 0x0672, 0x067a,
+ 0x0685, 0x0689, 0x0690, 0x069a,
+ 0x06a4, 0x06ac, 0x06b4, 0x06bc,
+ 0x06c4, 0x06cc, 0x06d4, 0x06dc,
+ 0x06e4, 0x06ec, 0x06f4, 0x06fc,
+ 0x0704, 0x070c, 0x0714, 0x071c,
+ 0x0723, 0x072a, 0x0730, 0x073a,
+ 0x0745, 0x074a, 0x0750, 0x075a,
+ 0x0765, 0x0769, 0x0772, 0x077a,
+ 0x0785, 0x0789, 0x0790, 0x079a,
+ 0x07a4, 0x07ac, 0x07b4, 0x07bc,
+ 0x07c4, 0x07cc, 0x07d4, 0x07dc,
+ 0x07e4, 0x07ec, 0x07f4, 0x07fc,
+};
+
+static void ipu7_isys_dphy_config(struct ipu6_isys *isys, u8 id, u8 lanes,
+ bool aggregation, u64 mbps)
+{
+ struct ipu6_device *isp = isys->adev->isp;
+ u16 hsrxval0 = 0;
+ u16 hsrxval1 = 0;
+ u16 hsrxval2 = 0;
+ int index;
+ u16 reg;
+ u16 val;
+ u32 i;
+
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_RW_COMMON_7, 0, 0, 9);
+ if (mbps > 1500)
+ dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_DPHY_7,
+ 40, 0, 7);
+ else
+ dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_DPHY_7,
+ 104, 0, 7);
+
+ dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_DPHY_8,
+ 80, 0, 7);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_0, 191, 0, 9);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_7, 34, 7, 12);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_1, 38, 8, 15);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_2, 4, 12, 15);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_2, 2, 10, 11);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_2, 1, 8, 8);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_2, 38, 0, 7);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_2, 1, 9, 9);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_4, 10, 0, 9);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_6, 20, 0, 9);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_7, 19, 0, 6);
+
+ for (i = 0; i < ARRAY_SIZE(table0); i++) {
+ if (mbps >= table0[i].min_mbps && mbps <= table0[i].max_mbps) {
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_3,
+ table0[i].ddlcal_counter_ref,
+ 0, 9);
+ break;
+ }
+ }
+
+ index = lookup_table1(mbps);
+ if (index >= 0) {
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_1,
+ table1[index].phase_bound, 0, 7);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_5,
+ table1[index].ddlcal_dll_fbk, 4, 9);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_DDLCAL_CFG_5,
+ table1[index].ddlcal_ddl_coarse_bank, 0, 3);
+
+ reg = IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_8;
+ val = table1[index].oa_lanex_hsrx_cdphy_sel_fast;
+ for (i = 0; i < lanes + 1; i++)
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), val,
+ 12, 12);
+ }
+
+ reg = IPU7_CORE_DIG_DLANE_0_RW_LP_0;
+ for (i = 0; i < lanes; i++)
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 6, 8, 11);
+
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_2,
+ 0, 0, 0);
+ if (!IS_IPU7_MTL(isp) || id == PORT_B || id == PORT_C) {
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2,
+ 1, 0, 0);
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2,
+ 0, 0, 0);
+ } else {
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2,
+ 0, 0, 0);
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2,
+ 1, 0, 0);
+ }
+
+ if (lanes == 4 && IS_IPU7_MTL(isp)) {
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_2,
+ 0, 0, 0);
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_2,
+ 0, 0, 0);
+ }
+
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_RW_COMMON_6, 1, 0, 2);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_RW_COMMON_6, 1, 3, 5);
+
+ reg = IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_12;
+ val = (mbps > 1500) ? 0 : 1;
+ for (i = 0; i < lanes + 1; i++) {
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 1, 1);
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), !val, 3, 3);
+ }
+
+ reg = IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_13;
+ val = (mbps > 1500) ? 0 : 1;
+ for (i = 0; i < lanes + 1; i++) {
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 1, 1);
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 3, 3);
+ }
+
+ if (!IS_IPU7_MTL(isp) || id == PORT_B || id == PORT_C)
+ reg = IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9;
+ else
+ reg = IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9;
+
+ for (i = 0; i < ARRAY_SIZE(table6); i++) {
+ if (mbps >= table6[i].min_mbps && mbps <= table6[i].max_mbps) {
+ dwc_phy_write_mask(isys, id, reg,
+ table6[i].oa_lane_hsrx_hs_clk_div,
+ 5, 7);
+ break;
+ }
+ }
+
+ if (aggregation) {
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_RW_COMMON_0, 1,
+ 1, 1);
+
+ reg = IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_15;
+ dwc_phy_write_mask(isys, id, reg, 3, 3, 4);
+
+ val = (id == PORT_A) ? 3 : 0;
+ reg = IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_15;
+ dwc_phy_write_mask(isys, id, reg, val, 3, 4);
+
+ reg = IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_15;
+ dwc_phy_write_mask(isys, id, reg, 3, 3, 4);
+ }
+
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_0,
+ 28, 0, 7);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_DLANE_CLK_RW_HS_RX_7,
+ 6, 0, 7);
+
+ reg = IPU7_CORE_DIG_DLANE_0_RW_HS_RX_0;
+ for (i = 0; i < ARRAY_SIZE(table2); i++) {
+ if (mbps >= table2[i].min_mbps && mbps <= table2[i].max_mbps) {
+ u8 j;
+
+ for (j = 0; j < lanes; j++)
+ dwc_phy_write_mask(isys, id, reg + (j * 0x400),
+ table2[i].i_thssettle,
+ 8, 15);
+ break;
+ }
+ }
+
+ /* deskew */
+ for (i = 0; i < lanes; i++) {
+ reg = IPU7_CORE_DIG_DLANE_0_RW_CFG_1;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400),
+ ((mbps > 1500) ? 0x1 : 0x2), 2, 3);
+
+ reg = IPU7_CORE_DIG_DLANE_0_RW_HS_RX_2;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400),
+ ((mbps > 2500) ? 0 : 1), 15, 15);
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 13, 13);
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 7, 9, 12);
+
+ reg = IPU7_CORE_DIG_DLANE_0_RW_LP_0;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 12, 15);
+
+ reg = IPU7_CORE_DIG_DLANE_0_RW_LP_2;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 0, 0);
+
+ reg = IPU7_CORE_DIG_DLANE_0_RW_HS_RX_1;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 16, 0, 7);
+
+ reg = IPU7_CORE_DIG_DLANE_0_RW_HS_RX_3;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 2, 0, 2);
+ index = lookup_table1(mbps);
+ if (index >= 0) {
+ val = table1[index].fjump_deskew;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), val,
+ 3, 8);
+ }
+
+ reg = IPU7_CORE_DIG_DLANE_0_RW_HS_RX_4;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 150, 0, 15);
+
+ reg = IPU7_CORE_DIG_DLANE_0_RW_HS_RX_5;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 0, 7);
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 8, 15);
+
+ reg = IPU7_CORE_DIG_DLANE_0_RW_HS_RX_6;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 2, 0, 7);
+ index = lookup_table1(mbps);
+ if (index >= 0) {
+ val = table1[index].min_eye_opening_deskew;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), val,
+ 8, 15);
+ }
+ reg = IPU7_CORE_DIG_DLANE_0_RW_HS_RX_7;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 13, 13);
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 0, 15, 15);
+
+ reg = IPU7_CORE_DIG_DLANE_0_RW_HS_RX_9;
+ index = lookup_table1(mbps);
+ if (index >= 0) {
+ val = table1[index].ddlcal_max_phase;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400),
+ val, 0, 7);
+ }
+ }
+
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_DLANE_CLK_RW_LP_0,
+ 1, 12, 15);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_DLANE_CLK_RW_LP_2, 0, 0, 0);
+
+ for (i = 0; i < ARRAY_SIZE(deskew_fine_mem); i++)
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_COMMON_RW_DESKEW_FINE_MEM,
+ deskew_fine_mem[i], 0, 15);
+
+ if (mbps > 1500) {
+ hsrxval0 = 4;
+ hsrxval2 = 3;
+ }
+
+ if (mbps > 2500)
+ hsrxval1 = 2;
+
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9,
+ hsrxval0, 0, 2);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9,
+ hsrxval0, 0, 2);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9,
+ hsrxval0, 0, 2);
+ if (lanes == 4 && IS_IPU7_MTL(isp)) {
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_9,
+ hsrxval0, 0, 2);
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_9,
+ hsrxval0, 0, 2);
+ }
+
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9,
+ hsrxval1, 3, 4);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_9,
+ hsrxval1, 3, 4);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_9,
+ hsrxval1, 3, 4);
+ if (lanes == 4 && IS_IPU7_MTL(isp)) {
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_9,
+ hsrxval1, 3, 4);
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_9,
+ hsrxval1, 3, 4);
+ }
+
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_15,
+ hsrxval2, 0, 2);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_15,
+ hsrxval2, 0, 2);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_15,
+ hsrxval2, 0, 2);
+ if (lanes == 4 && IS_IPU7_MTL(isp)) {
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_15,
+ hsrxval2, 0, 2);
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_15,
+ hsrxval2, 0, 2);
+ }
+
+ /* force and override rext */
+ if (isys->phy_rext_cal && id) {
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_8,
+ isys->phy_rext_cal, 0, 3);
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7,
+ 1, 11, 11);
+ }
+}
+
+static void ipu7_isys_cphy_config(struct ipu6_isys *isys, u8 id, u8 lanes,
+ bool aggregation, u64 mbps)
+{
+ struct ipu6_device *isp = isys->adev->isp;
+ u8 trios = 2;
+ u16 coarse_target;
+ u16 deass_thresh;
+ u16 delay_thresh;
+ u16 reset_thresh;
+ u16 cap_prog = 6U;
+ u16 reg;
+ u16 val;
+ u32 i;
+ u64 r64;
+ u32 r;
+
+ if (IS_IPU7P5(isp))
+ val = 0x15;
+ else
+ val = 0x155;
+
+ if (IS_IPU7_MTL(isp))
+ trios = 3;
+
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_RW_COMMON_7, val, 0, 9);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_DPHY_7,
+ 104, 0, 7);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_DPHY_8,
+ 16, 0, 7);
+
+ reg = IPU7_CORE_DIG_CLANE_0_RW_LP_0;
+ for (i = 0; i < trios; i++)
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 6, 8, 11);
+
+ val = (mbps > 900U) ? 1U : 0U;
+ for (i = 0; i < trios; i++) {
+ reg = IPU7_CORE_DIG_CLANE_0_RW_HS_RX_0;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 1, 0, 0);
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), val, 1, 1);
+
+ reg = IPU7_CORE_DIG_CLANE_0_RW_HS_RX_1;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 38, 0, 15);
+
+ reg = IPU7_CORE_DIG_CLANE_0_RW_HS_RX_5;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 38, 0, 15);
+
+ reg = IPU7_CORE_DIG_CLANE_0_RW_HS_RX_6;
+ dwc_phy_write_mask(isys, id, reg + (i * 0x400), 10, 0, 15);
+ }
+
+ /*
+ * Below 900Msps, always use the same value.
+ * The formula is suitable for data rate 80-3500Msps.
+ * Timebase (us) = 1, DIV = 32, TDDL (UI) = 0.5
+ */
+ if (mbps >= 80U)
+ coarse_target = DIV_ROUND_UP_ULL(mbps, 16) - 1;
+ else
+ coarse_target = 56;
+
+ for (i = 0; i < trios; i++) {
+ reg = IPU7_CORE_DIG_CLANE_0_RW_HS_RX_2 + i * 0x400;
+ dwc_phy_write_mask(isys, id, reg, coarse_target, 0, 15);
+ }
+
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_2, 1, 0, 0);
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_2, 0, 0, 0);
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_2, 1, 0, 0);
+
+ if (!IS_IPU7P5(isp) && lanes == 4) {
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_2,
+ 1, 0, 0);
+ dwc_phy_write_mask(isys, id,
+ IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_2,
+ 0, 0, 0);
+ }
+
+ for (i = 0; i < trios; i++) {
+ reg = IPU7_CORE_DIG_RW_TRIO0_0 + i * 0x400;
+ dwc_phy_write_mask(isys, id, reg, 1, 6, 8);
+ dwc_phy_write_mask(isys, id, reg, 1, 3, 5);
+ dwc_phy_write_mask(isys, id, reg, 2, 0, 2);
+ }
+
+ deass_thresh = (u16)div64_u64_rem(7 * 1000 * 6, mbps * 5U, &r64) + 1;
+ if (r64 != 0)
+ deass_thresh++;
+
+ reg = IPU7_CORE_DIG_RW_TRIO0_2;
+ for (i = 0; i < trios; i++)
+ dwc_phy_write_mask(isys, id, reg + 0x400 * i,
+ deass_thresh, 0, 7);
+
+ delay_thresh = div64_u64((224U - (9U * 7U)) * 1000U, 5U * mbps) - 7u;
+
+ if (delay_thresh < 1)
+ delay_thresh = 1;
+
+ reg = IPU7_CORE_DIG_RW_TRIO0_1;
+ for (i = 0; i < trios; i++)
+ dwc_phy_write_mask(isys, id, reg + 0x400 * i,
+ delay_thresh, 0, 15);
+
+ reset_thresh = (u16)div_u64_rem(2U * 5U * mbps, 7U * 1000U, &r);
+ if (!r)
+ reset_thresh--;
+
+ if (reset_thresh < 1)
+ reset_thresh = 1;
+
+ reg = IPU7_CORE_DIG_RW_TRIO0_0;
+ for (i = 0; i < trios; i++)
+ dwc_phy_write_mask(isys, id, reg + 0x400 * i,
+ reset_thresh, 9, 11);
+
+ /* Tuning ITMINRX to 2 for CPHY */
+ reg = IPU7_CORE_DIG_CLANE_0_RW_LP_0;
+ for (i = 0; i < trios; i++)
+ dwc_phy_write_mask(isys, id, reg + 0x400 * i, 2, 12, 15);
+
+ reg = IPU7_CORE_DIG_CLANE_0_RW_LP_2;
+ for (i = 0; i < trios; i++)
+ dwc_phy_write_mask(isys, id, reg + 0x400 * i, 0, 0, 0);
+
+ reg = IPU7_CORE_DIG_CLANE_0_RW_HS_RX_0;
+ for (i = 0; i < trios; i++)
+ dwc_phy_write_mask(isys, id, reg + 0x400 * i, 12, 2, 6);
+
+ for (i = 0; i < ARRAY_SIZE(table7); i++) {
+ if (mbps >= table7[i].min_mbps && mbps <= table7[i].max_mbps) {
+ cap_prog = table7[i].val;
+ break;
+ }
+ }
+
+ for (i = 0; i < (lanes + 1); i++) {
+ reg = IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_9 + 0x400 * i;
+ dwc_phy_write_mask(isys, id, reg, 4U, 0, 2);
+ /* Set GMODE to 2 when CPHY >= 1.5Gsps */
+ if (mbps >= 1500)
+ dwc_phy_write_mask(isys, id, reg, 2U, 3, 4);
+ else
+ dwc_phy_write_mask(isys, id, reg, 0U, 3, 4);
+
+ reg = IPU7_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_7 + 0x400 * i;
+ dwc_phy_write_mask(isys, id, reg, cap_prog, 10, 12);
+ }
+}
+
+static int ipu7_isys_phy_config(struct ipu6_isys *isys, u8 id, u8 lanes,
+ bool aggregation)
+{
+ struct device *dev = &isys->adev->auxdev.dev;
+ u32 phy_mode;
+ s64 link_freq;
+ u64 mbps;
+
+ if (aggregation)
+ link_freq = ipu6_isys_csi2_get_link_freq(&isys->csi2[0]);
+ else
+ link_freq = ipu6_isys_csi2_get_link_freq(&isys->csi2[id]);
+
+ if (link_freq < 0) {
+ dev_err(dev, "get link freq failed (%lld)\n", link_freq);
+ return link_freq;
+ }
+
+ mbps = div_u64(link_freq, 500000);
+ dev_dbg(dev, "config phy %u with lanes %u aggregation %d mbps %lld\n",
+ id, lanes, aggregation, mbps);
+
+ dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_DPHY_10,
+ 48, 0, 7);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_2,
+ 1, 12, 13);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_0,
+ 63, 2, 7);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_STARTUP_1_1,
+ 563, 0, 11);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_DPHY_2,
+ 5, 0, 7);
+ /* bypass the RCAL state (bit6) */
+ if (aggregation && id != PORT_A)
+ dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_DPHY_2,
+ 0x45, 0, 7);
+
+ dwc_phy_write_mask(isys, id, IPU7_PPI_STARTUP_RW_COMMON_DPHY_6,
+ 39, 0, 7);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_CALIBCTRL_RW_COMMON_BG_0,
+ 500, 0, 8);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_TERMCAL_CFG_0, 38, 0, 6);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_OFFSETCAL_CFG_0, 7, 0, 4);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_TIMEBASE, 153, 0, 9);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_NREF, 800, 0, 10);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_NREF_RANGE,
+ 27, 0, 4);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_TWAIT_CONFIG,
+ 47, 0, 8);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_TWAIT_CONFIG,
+ 127, 9, 15);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_VT_CONFIG, 47, 7, 15);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_VT_CONFIG, 27, 2, 6);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_VT_CONFIG, 3, 0, 1);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_LPDCOCAL_COARSE_CFG, 1, 0, 1);
+ dwc_phy_write_mask(isys, id, IPU7_PPI_RW_COMMON_CFG, 3, 0, 1);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_0,
+ 0, 10, 10);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_1,
+ 1, 10, 10);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_1,
+ 0, 15, 15);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_3,
+ 3, 8, 9);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_0,
+ 0, 15, 15);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_6,
+ 7, 12, 14);
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_7,
+ 0, 8, 10);
+ /* resistance tuning: 1 for 45ohm, 0 for 50ohm */
+ dwc_phy_write_mask(isys, id, IPU7_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_5,
+ 1, 8, 8);
+
+ if (aggregation)
+ phy_mode = isys->csi2[0].phy_mode;
+ else
+ phy_mode = isys->csi2[id].phy_mode;
+
+ if (phy_mode == PHY_MODE_DPHY) {
+ ipu7_isys_dphy_config(isys, id, lanes, aggregation, mbps);
+ } else if (phy_mode == PHY_MODE_CPHY) {
+ ipu7_isys_cphy_config(isys, id, lanes, aggregation, mbps);
+ } else {
+ dev_err(dev, "unsupported phy mode %d!\n",
+ isys->csi2[id].phy_mode);
+ }
+
+ return 0;
+}
+
+static int ipu7_isys_csi_phy_powerup(struct ipu6_isys_csi2 *csi2)
+{
+ struct ipu6_isys *isys = csi2->isys;
+ u32 lanes = csi2->nlanes;
+ bool aggregation = false;
+ u32 id = csi2->port;
+ int ret;
+
+ /* lanes remapping for aggregation (port AB) mode */
+ if (!IS_IPU7_MTL(isys->adev->isp) && lanes > 2 && id == PORT_A) {
+ aggregation = true;
+ lanes = 2;
+ }
+
+ ipu7_isys_csi_phy_reset(isys, id);
+ gpreg_write(isys, id, IPU7_PHY_CLK_LANE_CONTROL, 0x1);
+ gpreg_write(isys, id, IPU7_PHY_CLK_LANE_FORCE_CONTROL, 0x2);
+ gpreg_write(isys, id, IPU7_PHY_LANE_CONTROL_EN, (1U << lanes) - 1U);
+ gpreg_write(isys, id, IPU7_PHY_LANE_FORCE_CONTROL, 0xf);
+ gpreg_write(isys, id, IPU7_PHY_MODE, csi2->phy_mode);
+
+ /* config PORT_B if aggregation mode */
+ if (aggregation) {
+ ipu7_isys_csi_phy_reset(isys, PORT_B);
+ gpreg_write(isys, PORT_B, IPU7_PHY_CLK_LANE_CONTROL, 0x0);
+ gpreg_write(isys, PORT_B, IPU7_PHY_LANE_CONTROL_EN, 0x3);
+ gpreg_write(isys, PORT_B, IPU7_PHY_CLK_LANE_FORCE_CONTROL, 0x2);
+ gpreg_write(isys, PORT_B, IPU7_PHY_LANE_FORCE_CONTROL, 0xf);
+ gpreg_write(isys, PORT_B, IPU7_PHY_MODE, csi2->phy_mode);
+ }
+
+ ipu7_isys_csi_ctrl_cfg(csi2);
+ ipu7_isys_csi_ctrl_dids_config(csi2, id);
+
+ ret = ipu7_isys_phy_config(isys, id, lanes, aggregation);
+ if (ret < 0)
+ return ret;
+
+ gpreg_write(isys, id, IPU7_PHY_RESET, 1);
+ gpreg_write(isys, id, IPU7_PHY_SHUTDOWN, 1);
+ dwc_csi_write(isys, id, IPU7_DPHY_RSTZ, 1);
+ dwc_csi_write(isys, id, IPU7_PHY_SHUTDOWNZ, 1);
+ dwc_csi_write(isys, id, IPU7_CSI2_RESETN, 1);
+
+ ret = ipu7_isys_phy_ready(isys, id);
+ if (ret < 0)
+ return ret;
+
+ gpreg_write(isys, id, IPU7_PHY_LANE_FORCE_CONTROL, 0);
+ gpreg_write(isys, id, IPU7_PHY_CLK_LANE_FORCE_CONTROL, 0);
+
+ /* config PORT_B if aggregation mode */
+ if (aggregation) {
+ ret = ipu7_isys_phy_config(isys, PORT_B, 2, aggregation);
+ if (ret < 0)
+ return ret;
+
+ gpreg_write(isys, PORT_B, IPU7_PHY_RESET, 1);
+ gpreg_write(isys, PORT_B, IPU7_PHY_SHUTDOWN, 1);
+ dwc_csi_write(isys, PORT_B, IPU7_DPHY_RSTZ, 1);
+ dwc_csi_write(isys, PORT_B, IPU7_PHY_SHUTDOWNZ, 1);
+ dwc_csi_write(isys, PORT_B, IPU7_CSI2_RESETN, 1);
+ ret = ipu7_isys_phy_ready(isys, PORT_B);
+ if (ret < 0)
+ return ret;
+
+ gpreg_write(isys, PORT_B, IPU7_PHY_LANE_FORCE_CONTROL, 0);
+ gpreg_write(isys, PORT_B, IPU7_PHY_CLK_LANE_FORCE_CONTROL, 0);
+ }
+
+ return 0;
+}
+
+static void ipu7_isys_csi_phy_powerdown(struct ipu6_isys_csi2 *csi2)
+{
+ struct ipu6_isys *isys = csi2->isys;
+
+ ipu7_isys_csi_phy_reset(isys, csi2->port);
+ if (!IS_IPU7_MTL(isys->adev->isp) &&
+ csi2->nlanes > 2U && csi2->port == PORT_A)
+ ipu7_isys_csi_phy_reset(isys, PORT_B);
+}
+
+int ipu7_isys_csi_phy_set_power(struct ipu6_isys *isys,
+ struct ipu6_isys_csi2_config *cfg,
+ const struct ipu6_isys_csi2_timing *timing,
+ bool on)
+{
+ struct ipu6_isys_csi2 *csi2 = &isys->csi2[cfg->port];
+
+ if (on)
+ return ipu7_isys_csi_phy_powerup(csi2);
+
+ ipu7_isys_csi_phy_powerdown(csi2);
+
+ return 0;
+}
diff --git a/drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.h b/drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.h
new file mode 100644
index 000000000000..849fe888db07
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2026 Intel Corporation */
+
+#ifndef IPU7_ISYS_CSI_PHY_H
+#define IPU7_ISYS_CSI_PHY_H
+
+struct ipu6_isys;
+struct ipu6_isys_csi2_config;
+struct ipu6_isys_csi2_timing;
+
+int ipu7_isys_csi_phy_set_power(struct ipu6_isys *isys,
+ struct ipu6_isys_csi2_config *cfg,
+ const struct ipu6_isys_csi2_timing *timing,
+ bool on);
+
+#endif /* IPU7_ISYS_CSI_PHY_H */
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 28/44] media: ipu6: Split ipu6 csi2 stream enable/disable
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (26 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 27/44] media: ipu6: Add ipu7 csi phy driver Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 29/44] media: ipu6: Add support for ipu7 csi2 receiver Antti Laakso
` (15 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
Instead of single function, split csi2 receiver stream enable and
disable into own functions. This make it easier to add ipu7 support.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c | 98 ++++++++-----------
1 file changed, 43 insertions(+), 55 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
index 7e539a0c6c92..7b63b08f5c54 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
@@ -228,64 +228,55 @@ void ipu6_isys_csi2_error(struct ipu6_isys_csi2 *csi2)
}
}
-static int ipu6_isys_csi2_set_stream(struct v4l2_subdev *sd,
- const struct ipu6_isys_csi2_timing *timing,
- unsigned int nlanes, int enable)
+static void ipu6_isys_csi2_stream_disable(struct ipu6_isys_csi2 *csi2)
{
- struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
- struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
struct ipu6_isys *isys = csi2->isys;
- struct device *dev = &isys->adev->auxdev.dev;
struct ipu6_isys_csi2_config cfg;
- unsigned int nports;
- int ret = 0;
- u32 mask = 0;
- u32 i;
+ u32 mask = isys->pdata->ipdata->csi2.irq_mask;
+
+ cfg.port = csi2->port;
+ cfg.nlanes = csi2->nlanes;
+
+ writel(0, csi2->base + CSI_REG_CSI_FE_ENABLE);
+ writel(0, csi2->base + CSI_REG_PPI2CSI_ENABLE);
+ writel(0, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
+ CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET);
+ writel(mask, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
+ CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
+ writel(0, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
+ CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET);
+ writel(0xffffffff, csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
+ CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
- dev_dbg(dev, "stream %s CSI2-%u with %u lanes\n", enable ? "on" : "off",
- csi2->port, nlanes);
+ isys->phy_set_power(isys, &cfg, NULL, false);
+
+ writel(0, isys->pdata->base + CSI_REG_HUB_FW_ACCESS_PORT
+ (isys->pdata->ipdata->csi2.fw_access_port_ofs, csi2->port));
+ writel(0, isys->pdata->base + CSI_REG_HUB_DRV_ACCESS_PORT(csi2->port));
+}
+
+static int ipu6_isys_csi2_stream_enable(struct ipu6_isys_csi2 *csi2)
+{
+ struct ipu6_isys *isys = csi2->isys;
+ struct ipu6_isys_csi2_timing timing = { };
+ struct ipu6_isys_csi2_config cfg;
+ unsigned int nports;
+ u32 mask;
+ int ret;
cfg.port = csi2->port;
- cfg.nlanes = nlanes;
+ cfg.nlanes = csi2->nlanes;
mask = isys->pdata->ipdata->csi2.irq_mask;
nports = isys->pdata->ipdata->csi2.nports;
- if (!enable) {
- writel(0, csi2->base + CSI_REG_CSI_FE_ENABLE);
- writel(0, csi2->base + CSI_REG_PPI2CSI_ENABLE);
-
- writel(0,
- csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
- CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET);
- writel(mask,
- csi2->base + CSI_PORT_REG_BASE_IRQ_CSI +
- CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
- writel(0,
- csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
- CSI_PORT_REG_BASE_IRQ_ENABLE_OFFSET);
- writel(0xffffffff,
- csi2->base + CSI_PORT_REG_BASE_IRQ_CSI_SYNC +
- CSI_PORT_REG_BASE_IRQ_CLEAR_OFFSET);
-
- isys->phy_set_power(isys, &cfg, timing, false);
-
- writel(0, isys->pdata->base + CSI_REG_HUB_FW_ACCESS_PORT
- (isys->pdata->ipdata->csi2.fw_access_port_ofs,
- csi2->port));
- writel(0, isys->pdata->base +
- CSI_REG_HUB_DRV_ACCESS_PORT(csi2->port));
-
- return ret;
- }
-
/* reset port reset */
writel(0x1, csi2->base + CSI_REG_PORT_GPREG_SRST);
usleep_range(100, 200);
writel(0x0, csi2->base + CSI_REG_PORT_GPREG_SRST);
/* enable port clock */
- for (i = 0; i < nports; i++) {
+ for (unsigned int i = 0; i < nports; i++) {
writel(1, isys->pdata->base + CSI_REG_HUB_DRV_ACCESS_PORT(i));
writel(1, isys->pdata->base + CSI_REG_HUB_FW_ACCESS_PORT
(isys->pdata->ipdata->csi2.fw_access_port_ofs, i));
@@ -329,18 +320,18 @@ static int ipu6_isys_csi2_set_stream(struct v4l2_subdev *sd,
writel(CSI_SENSOR_INPUT, csi2->base + CSI_REG_CSI_FE_MUX_CTRL);
writel(CSI_CNTR_SENSOR_LINE_ID | CSI_CNTR_SENSOR_FRAME_ID,
csi2->base + CSI_REG_CSI_FE_SYNC_CNTR_SEL);
- writel(FIELD_PREP(PPI_INTF_CONFIG_NOF_ENABLED_DLANES_MASK, nlanes - 1),
+ writel(FIELD_PREP(PPI_INTF_CONFIG_NOF_ENABLED_DLANES_MASK,
+ csi2->nlanes - 1),
csi2->base + CSI_REG_PPI2CSI_CONFIG_PPI_INTF);
writel(1, csi2->base + CSI_REG_PPI2CSI_ENABLE);
writel(1, csi2->base + CSI_REG_CSI_FE_ENABLE);
- ret = isys->phy_set_power(isys, &cfg, timing, true);
+ ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV);
if (ret)
- dev_err(dev, "csi-%d phy power up failed %d\n", csi2->port,
- ret);
+ return ret;
- return ret;
+ return isys->phy_set_power(isys, &cfg, &timing, true);
}
static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
@@ -349,7 +340,6 @@ static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
{
struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
- struct ipu6_isys_csi2_timing timing = { };
struct v4l2_subdev *remote_sd;
struct media_pad *remote_pad;
u64 sink_streams;
@@ -362,18 +352,14 @@ static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
v4l2_subdev_state_xlate_streams(state, pad, CSI2_PAD_SINK,
&streams_mask);
- ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV);
- if (ret)
- return ret;
-
- ret = ipu6_isys_csi2_set_stream(sd, &timing, csi2->nlanes, true);
+ ret = ipu6_isys_csi2_stream_enable(csi2);
if (ret)
return ret;
ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index,
sink_streams);
if (ret) {
- ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
+ ipu6_isys_csi2_stream_disable(csi2);
return ret;
}
@@ -384,6 +370,8 @@ static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
u32 pad, u64 streams_mask)
{
+ struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
+ struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
struct v4l2_subdev *remote_sd;
struct media_pad *remote_pad;
u64 sink_streams;
@@ -395,7 +383,7 @@ static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
- ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
+ ipu6_isys_csi2_stream_disable(csi2);
v4l2_subdev_disable_streams(remote_sd, remote_pad->index, sink_streams);
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 29/44] media: ipu6: Add support for ipu7 csi2 receiver
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (27 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 28/44] media: ipu6: Split ipu6 csi2 stream enable/disable Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 30/44] media: ipu6: Parse bus type for ipu7 Antti Laakso
` (14 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The csi2 receiver is different in ipu7, add support for it.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c | 119 +++++++++++++++++-
1 file changed, 114 insertions(+), 5 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
index 7b63b08f5c54..160eace947f4 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
@@ -24,6 +24,7 @@
#include "ipu6-isys-csi2.h"
#include "ipu6-isys-subdev.h"
#include "ipu6-platform-isys-csi2-reg.h"
+#include "ipu7-isys-csi2-regs.h"
static const u32 csi2_supported_codes[] = {
MEDIA_BUS_FMT_RGB565_1X16,
@@ -267,6 +268,10 @@ static int ipu6_isys_csi2_stream_enable(struct ipu6_isys_csi2 *csi2)
cfg.port = csi2->port;
cfg.nlanes = csi2->nlanes;
+ ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV);
+ if (ret)
+ return ret;
+
mask = isys->pdata->ipdata->csi2.irq_mask;
nports = isys->pdata->ipdata->csi2.nports;
@@ -327,11 +332,106 @@ static int ipu6_isys_csi2_stream_enable(struct ipu6_isys_csi2 *csi2)
writel(1, csi2->base + CSI_REG_PPI2CSI_ENABLE);
writel(1, csi2->base + CSI_REG_CSI_FE_ENABLE);
- ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV);
+ return isys->phy_set_power(isys, &cfg, &timing, true);
+}
+
+static void ipu7_csi2_irq_enable(struct ipu6_isys_csi2 *csi2)
+{
+ struct ipu6_isys *isys = csi2->isys;
+ unsigned int offset, mask;
+
+ /* enable CSI2 legacy error irq */
+ offset = IPU7_IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(csi2->port);
+ mask = IPU7_CSI_RX_ERROR_IRQ_MASK;
+ writel(mask, csi2->base + offset + IPU7_IRQ_CTL_CLEAR);
+ writel(mask, csi2->base + offset + IPU7_IRQ_CTL_MASK);
+ writel(mask, csi2->base + offset + IPU7_IRQ_CTL_ENABLE);
+
+ /* enable CSI2 legacy sync irq */
+ offset = IPU7_IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(csi2->port);
+ mask = IPU7_CSI_RX_SYNC_IRQ_MASK;
+ writel(mask, csi2->base + offset + IPU7_IRQ_CTL_CLEAR);
+ writel(mask, csi2->base + offset + IPU7_IRQ_CTL_MASK);
+ writel(mask, csi2->base + offset + IPU7_IRQ_CTL_ENABLE);
+
+ if (!IS_IPU7_MTL(isys->adev->isp)) {
+ mask = IPU7P5_CSI_RX_SYNC_FE_IRQ_MASK;
+ writel(mask, csi2->base + offset + IPU7_IRQ1_CTL_CLEAR);
+ writel(mask, csi2->base + offset + IPU7_IRQ1_CTL_MASK);
+ writel(mask, csi2->base + offset + IPU7_IRQ1_CTL_ENABLE);
+ }
+}
+
+static void ipu7_csi2_irq_disable(struct ipu6_isys_csi2 *csi2)
+{
+ struct ipu6_isys *isys = csi2->isys;
+ unsigned int offset, mask;
+
+ /* disable CSI2 legacy error irq */
+ offset = IPU7_IS_IO_CSI2_ERR_LEGACY_IRQ_CTL_BASE(csi2->port);
+ mask = IPU7_CSI_RX_ERROR_IRQ_MASK;
+ writel(mask, csi2->base + offset + IPU7_IRQ_CTL_CLEAR);
+ writel(0, csi2->base + offset + IPU7_IRQ_CTL_MASK);
+ writel(0, csi2->base + offset + IPU7_IRQ_CTL_ENABLE);
+
+ /* disable CSI2 legacy sync irq */
+ offset = IPU7_IS_IO_CSI2_SYNC_LEGACY_IRQ_CTL_BASE(csi2->port);
+ mask = IPU7_CSI_RX_SYNC_IRQ_MASK;
+ writel(mask, csi2->base + offset + IPU7_IRQ_CTL_CLEAR);
+ writel(0, csi2->base + offset + IPU7_IRQ_CTL_MASK);
+ writel(0, csi2->base + offset + IPU7_IRQ_CTL_ENABLE);
+
+ if (!IS_IPU7_MTL(isys->adev->isp)) {
+ writel(mask, csi2->base + offset + IPU7_IRQ1_CTL_CLEAR);
+ writel(0, csi2->base + offset + IPU7_IRQ1_CTL_MASK);
+ writel(0, csi2->base + offset + IPU7_IRQ1_CTL_ENABLE);
+ }
+}
+
+static void ipu7_isys_csi2_stream_disable(struct ipu6_isys_csi2 *csi2)
+{
+ struct ipu6_isys *isys = csi2->isys;
+ void __iomem *base = isys->pdata->base;
+ struct ipu6_isys_csi2_config cfg;
+
+ cfg.port = csi2->port;
+ cfg.nlanes = csi2->nlanes;
+
+ isys->phy_set_power(isys, &cfg, NULL, false);
+
+ writel(0x4,
+ base + IPU7_IS_IO_GPREGS_BASE + IPU7_CLK_DIV_FACTOR_APB_CLK);
+ ipu7_csi2_irq_disable(csi2);
+}
+
+static int ipu7_isys_csi2_stream_enable(struct ipu6_isys_csi2 *csi2)
+{
+ struct ipu6_isys *isys = csi2->isys;
+ void __iomem *base = isys->pdata->base;
+ struct ipu6_isys_csi2_config cfg;
+ unsigned int offset = IPU7_IS_IO_GPREGS_BASE;
+ int ret;
+
+ writel(0x2, base + offset + IPU7_CLK_DIV_FACTOR_APB_CLK);
+ if (csi2->port == 0U && csi2->nlanes == 4U &&
+ !IS_IPU7_MTL(isys->adev->isp))
+ writel(0x1, base + offset + IPU7_CSI_PORTAB_AGGREGATION);
+
+ /* input is coming from CSI receiver (sensor) */
+ offset = IPU7_IS_IO_CSI2_ADPL_PORT_BASE(csi2->port);
+ writel(CSI_SENSOR_INPUT, base + offset + IPU7_CSI2_ADPL_INPUT_MODE);
+ writel(1, base + offset + IPU7_CSI2_ADPL_CSI_RX_ERR_IRQ_CLEAR_EN);
+
+ cfg.port = csi2->port;
+ cfg.nlanes = csi2->nlanes;
+
+ ret = isys->phy_set_power(isys, &cfg, NULL, true);
if (ret)
return ret;
- return isys->phy_set_power(isys, &cfg, &timing, true);
+ ipu7_csi2_irq_enable(csi2);
+
+ return 0;
}
static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
@@ -340,6 +440,7 @@ static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
{
struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
+ struct ipu6_device *isp = asd->isys->adev->isp;
struct v4l2_subdev *remote_sd;
struct media_pad *remote_pad;
u64 sink_streams;
@@ -352,14 +453,18 @@ static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
v4l2_subdev_state_xlate_streams(state, pad, CSI2_PAD_SINK,
&streams_mask);
- ret = ipu6_isys_csi2_stream_enable(csi2);
+ ret = IS_IPU7(isp) ? ipu7_isys_csi2_stream_enable(csi2) :
+ ipu6_isys_csi2_stream_enable(csi2);
if (ret)
return ret;
ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index,
sink_streams);
if (ret) {
- ipu6_isys_csi2_stream_disable(csi2);
+ if IS_IPU7(isp)
+ ipu7_isys_csi2_stream_disable(csi2);
+ else
+ ipu6_isys_csi2_stream_disable(csi2);
return ret;
}
@@ -372,6 +477,7 @@ static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
{
struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
+ struct ipu6_device *isp = asd->isys->adev->isp;
struct v4l2_subdev *remote_sd;
struct media_pad *remote_pad;
u64 sink_streams;
@@ -383,7 +489,10 @@ static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
- ipu6_isys_csi2_stream_disable(csi2);
+ if IS_IPU7(isp)
+ ipu7_isys_csi2_stream_disable(csi2);
+ else
+ ipu6_isys_csi2_stream_disable(csi2);
v4l2_subdev_disable_streams(remote_sd, remote_pad->index, sink_streams);
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 30/44] media: ipu6: Parse bus type for ipu7
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (28 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 29/44] media: ipu6: Add support for ipu7 csi2 receiver Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 31/44] media: ipu6: Enable ipu7 isys interrupts Antti Laakso
` (13 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
For ipu7 bus type can be CPHY or DPHY.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-isys.c | 8 ++++++++
drivers/media/pci/intel/ipu6/ipu6-isys.h | 2 ++
2 files changed, 10 insertions(+)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 5de5fd16ca30..976ed064f262 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -133,6 +133,9 @@ isys_complete_ext_device_registration(struct ipu6_isys *isys,
}
isys->csi2[csi2->port].nlanes = csi2->nlanes;
+ isys->csi2[csi2->port].phy_mode =
+ csi2->bus_type == V4L2_MBUS_CSI2_DPHY ?
+ PHY_MODE_DPHY : PHY_MODE_CPHY;
return 0;
@@ -639,6 +642,10 @@ static int isys_notifier_init(struct ipu6_isys *isys)
continue;
ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+ if (ret && IS_IPU7(isp)) {
+ vep.bus_type = V4L2_MBUS_CSI2_CPHY;
+ ret = v4l2_fwnode_endpoint_parse(ep, &vep);
+ }
if (ret) {
dev_err(dev, "fwnode endpoint parse failed: %d\n", ret);
goto err_parse;
@@ -654,6 +661,7 @@ static int isys_notifier_init(struct ipu6_isys *isys)
s_asd->csi2.port = vep.base.port;
s_asd->csi2.nlanes = vep.bus.mipi_csi2.num_data_lanes;
+ s_asd->csi2.bus_type = vep.bus_type;
dev_dbg(dev, "remote endpoint port %d with %d lanes added\n",
s_asd->csi2.port, s_asd->csi2.nlanes);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h
index 30539ea5f826..8674c041b994 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h
@@ -14,6 +14,7 @@
#include <media/media-device.h>
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
#include "ipu6.h"
#include "ipu6-fw-isys.h"
@@ -96,6 +97,7 @@ struct isys_iwake_watermark {
struct ipu6_isys_csi2_config {
u32 nlanes;
u32 port;
+ enum v4l2_mbus_type bus_type;
};
struct sensor_async_sd {
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 31/44] media: ipu6: Enable ipu7 isys interrupts
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (29 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 30/44] media: ipu6: Parse bus type for ipu7 Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 32/44] media: ipu6: Skip watermark configuration for ipu7 Antti Laakso
` (12 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
Add ipu7 specific isys initialization of clocks and
enabling interrupts.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-isys.c | 56 +++++++++++++++++++++---
1 file changed, 49 insertions(+), 7 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 976ed064f262..622f74021f6d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -180,13 +180,23 @@ static int isys_csi2_register_subdevices(struct ipu6_isys *isys)
int ret;
for (i = 0; i < csi2_pdata->nports; i++) {
- ret = ipu6_isys_csi2_init(&isys->csi2[i], isys,
- isys->pdata->base +
- CSI_REG_PORT_BASE(i), i);
+ void __iomem *base = isys->pdata->base;
+
+ if (IS_IPU7(isys->adev->isp)) {
+ u32 mask = IS_IPU7_MTL(isys->adev->isp) ?
+ IPU7_CSI_LEGACY_IRQ_MASK(i) :
+ IPU7P5_CSI_LEGACY_IRQ_MASK(i);
+
+ isys->isr_csi2_bits |= mask;
+ isys->csi2[i].legacy_irq_mask = mask;
+ } else {
+ base += CSI_REG_PORT_BASE(i);
+ isys->isr_csi2_bits |= IPU6_ISYS_UNISPART_IRQ_CSI2(i);
+ }
+
+ ret = ipu6_isys_csi2_init(&isys->csi2[i], isys, base, i);
if (ret)
goto fail;
-
- isys->isr_csi2_bits |= IPU6_ISYS_UNISPART_IRQ_CSI2(i);
}
return 0;
@@ -273,7 +283,36 @@ static int isys_register_video_devices(struct ipu6_isys *isys)
return ret;
}
-static void isys_setup_hw(struct ipu6_isys *isys)
+static void ipu7_isys_setup_hw(struct ipu6_isys *isys)
+{
+ u32 offset, mask;
+ void __iomem *base = isys->pdata->base;
+
+ offset = IPU7_IS_IO_GPREGS_BASE;
+
+ writel(0x0, base + offset + IPU7_CLK_EN_TXCLKESC);
+ /* Update if ISYS freq updated (0: 400/1, 1:400/2, 63:400/64) */
+ writel(0x0, base + offset + IPU7_CLK_DIV_FACTOR_IS_CLK);
+ /* correct the initial printf configuration */
+ writel(0x200, base + IPU7_IS_UC_CTRL_BASE + IPU7_REG_PRINTF_AXI_CNTL);
+
+ offset = IPU7_IS_UC_CTRL_BASE;
+ mask = IPU7_IS_UC_TO_SW_IRQ_MASK;
+
+ writel(mask, base + offset + IPU7_TO_SW_IRQ_CNTL_CLEAR);
+ writel(mask, base + offset + IPU7_TO_SW_IRQ_CNTL_MASK_N);
+ writel(mask, base + offset + IPU7_TO_SW_IRQ_CNTL_ENABLE);
+
+ offset = IPU7_IS_IO_CSI2_LEGACY_IRQ_CTRL_BASE;
+ mask = IPU7_CSI_RX_LEGACY_IRQ_MASK;
+
+ writel(mask, base + offset + IPU7_IRQ_CTL_EDGE);
+ writel(mask, base + offset + IPU7_IRQ_CTL_CLEAR);
+ writel(mask, base + offset + IPU7_IRQ_CTL_MASK);
+ writel(mask, base + offset + IPU7_IRQ_CTL_ENABLE);
+}
+
+static void ipu6_isys_setup_hw(struct ipu6_isys *isys)
{
void __iomem *base = isys->pdata->base;
const u8 *thd = isys->pdata->ipdata->hw_variant.cdc_fifo_threshold;
@@ -783,7 +822,10 @@ static int isys_runtime_pm_resume(struct device *dev)
isys->power = 1;
spin_unlock_irqrestore(&isys->power_lock, flags);
- isys_setup_hw(isys);
+ if (IS_IPU7(isp))
+ ipu7_isys_setup_hw(isys);
+ else
+ ipu6_isys_setup_hw(isys);
set_iwake_ltrdid(isys, 0, 0, LTR_ISYS_ON);
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 32/44] media: ipu6: Skip watermark configuration for ipu7
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (30 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 31/44] media: ipu6: Enable ipu7 isys interrupts Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 33/44] media: ipu6: The SPC init is valid only for ipu6 Antti Laakso
` (11 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The ipu7 don't have watermark nor LTR support, skip it.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-isys-video.c | 4 +++-
drivers/media/pci/intel/ipu6/ipu6-isys.c | 12 +++++++-----
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index 560524e6e624..9634b4f232bd 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -727,8 +727,10 @@ void ipu6_isys_update_stream_watermark(struct ipu6_isys_video *av, bool state)
{
struct isys_iwake_watermark *iwake_watermark =
&av->isys->iwake_watermark;
+ struct ipu6_device *isp = av->isys->adev->isp;
- if (!av->watermark.pixel_rate)
+ if (IS_IPU7(isp) ||
+ !av->watermark.pixel_rate)
return;
if (state) {
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 622f74021f6d..5a3ba5007249 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -822,12 +822,12 @@ static int isys_runtime_pm_resume(struct device *dev)
isys->power = 1;
spin_unlock_irqrestore(&isys->power_lock, flags);
- if (IS_IPU7(isp))
+ if (IS_IPU7(isp)) {
ipu7_isys_setup_hw(isys);
- else
+ } else {
ipu6_isys_setup_hw(isys);
-
- set_iwake_ltrdid(isys, 0, 0, LTR_ISYS_ON);
+ set_iwake_ltrdid(isys, 0, 0, LTR_ISYS_ON);
+ }
return 0;
}
@@ -836,6 +836,7 @@ static int isys_runtime_pm_suspend(struct device *dev)
{
struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
struct ipu6_isys *isys = dev_get_drvdata(dev);
+ struct ipu6_device *isp = adev->isp;
unsigned long flags;
spin_lock_irqsave(&isys->power_lock, flags);
@@ -849,7 +850,8 @@ static int isys_runtime_pm_suspend(struct device *dev)
isys->phy_termcal_val = 0;
cpu_latency_qos_update_request(&isys->pm_qos, PM_QOS_DEFAULT_VALUE);
- set_iwake_ltrdid(isys, 0, 0, LTR_ISYS_OFF);
+ if (!IS_IPU7(isp))
+ set_iwake_ltrdid(isys, 0, 0, LTR_ISYS_OFF);
ipu6_mmu_hw_cleanup(adev->mmu);
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 33/44] media: ipu6: The SPC init is valid only for ipu6
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (31 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 32/44] media: ipu6: Skip watermark configuration for ipu7 Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 34/44] media: ipu6: The VC arbitration mechanism is ipu6 only Antti Laakso
` (10 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The ipu7 don't have SPC.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index fd7888a011a5..cb1145080460 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -232,10 +232,16 @@ void ipu6_configure_spc(struct ipu6_device *isp,
int pkg_dir_idx, void __iomem *base, u64 *pkg_dir,
dma_addr_t pkg_dir_dma_addr)
{
- void __iomem *dmem_base = base + hw_variant->dmem_offset;
- void __iomem *spc_regs_base = base + hw_variant->spc_offset;
+ void __iomem *dmem_base;
+ void __iomem *spc_regs_base;
u32 val;
+ if (IS_IPU7(isp))
+ return;
+
+ dmem_base = base + hw_variant->dmem_offset;
+ spc_regs_base = base + hw_variant->spc_offset;
+
val = readl(spc_regs_base + IPU6_PSYS_REG_SPC_STATUS_CTRL);
val |= IPU6_PSYS_SPC_STATUS_CTRL_ICACHE_INVALIDATE;
writel(val, spc_regs_base + IPU6_PSYS_REG_SPC_STATUS_CTRL);
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 34/44] media: ipu6: The VC arbitration mechanism is ipu6 only
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (32 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 33/44] media: ipu6: The SPC init is valid only for ipu6 Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 35/44] media: ipu6: Move buttress mem alloc out from probe Antti Laakso
` (9 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The ipu7 doesn't support the VC arbitration mechanism that exist in
ipu6.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index cb1145080460..7d1c3713a69b 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -447,7 +447,12 @@ static int ipu6_pci_config_setup(struct pci_dev *dev)
static void ipu6_configure_vc_mechanism(struct ipu6_device *isp)
{
- u32 val = readl(isp->base + BUTTRESS_REG_BTRS_CTRL);
+ u32 val;
+
+ if (IS_IPU7(isp))
+ return;
+
+ val = readl(isp->base + BUTTRESS_REG_BTRS_CTRL);
if (IPU6_BTRS_ARB_STALL_MODE_VC0 == IPU6_BTRS_ARB_MODE_TYPE_STALL)
val |= BUTTRESS_REG_BTRS_CTRL_STALL_MODE_VC0;
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 35/44] media: ipu6: Move buttress mem alloc out from probe
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (33 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 34/44] media: ipu6: The VC arbitration mechanism is ipu6 only Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 36/44] media: ipu6: Read correct SKU ID for ipu7 Antti Laakso
` (8 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
Buttress registers are stored in separate buffer, which is passed
down to bus driver. Move allocation of this buffer to subsystem init
to cleanup pci probe function a bit.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6.c | 43 +++++++++++++++--------------
1 file changed, 22 insertions(+), 21 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 7d1c3713a69b..4e4f32723904 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -90,7 +90,7 @@ static struct ipu6_psys_internal_pdata psys_ipdata = {
},
};
-static const struct ipu6_buttress_ctrl isys_buttress_ctrl = {
+static const struct ipu6_buttress_ctrl ipu6_isys_buttress_ctrl = {
.subsys_id = IPU_ISYS,
.ratio = IPU6_IS_FREQ_CTL_DEFAULT_RATIO,
.qos_floor = IPU6_IS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO,
@@ -101,7 +101,7 @@ static const struct ipu6_buttress_ctrl isys_buttress_ctrl = {
.pwr_sts_off = IPU6_BUTTRESS_PWR_STATE_DN_DONE,
};
-static const struct ipu6_buttress_ctrl psys_buttress_ctrl = {
+static const struct ipu6_buttress_ctrl ipu6_psys_buttress_ctrl = {
.subsys_id = IPU_PSYS,
.ratio = IPU6_PS_FREQ_CTL_DEFAULT_RATIO,
.qos_floor = IPU6_PS_FREQ_CTL_DEFAULT_QOS_FLOOR_RATIO,
@@ -341,11 +341,12 @@ static void ipu6_internal_pdata_init(struct ipu6_device *isp)
static struct ipu6_bus_device *
ipu6_isys_init(struct pci_dev *pdev, struct device *parent,
- struct ipu6_buttress_ctrl *ctrl, void __iomem *base,
+ const struct ipu6_buttress_ctrl *ctrl, void __iomem *base,
const struct ipu6_isys_internal_pdata *ipdata)
{
struct device *dev = &pdev->dev;
struct ipu6_bus_device *isys_adev;
+ struct ipu6_buttress_ctrl *devm_ctrl;
struct ipu6_isys_pdata *pdata;
int ret;
@@ -355,6 +356,10 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent,
return ERR_PTR(ret);
}
+ devm_ctrl = devm_kmemdup(dev, ctrl, sizeof(*ctrl), GFP_KERNEL);
+ if (!devm_ctrl)
+ return ERR_PTR(-ENOMEM);
+
pdata = kzalloc_obj(*pdata);
if (!pdata)
return ERR_PTR(-ENOMEM);
@@ -362,7 +367,7 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent,
pdata->base = base;
pdata->ipdata = ipdata;
- isys_adev = ipu6_bus_initialize_device(pdev, parent, pdata, ctrl,
+ isys_adev = ipu6_bus_initialize_device(pdev, parent, pdata, devm_ctrl,
IPU6_ISYS_NAME);
if (IS_ERR(isys_adev)) {
kfree(pdata);
@@ -388,13 +393,19 @@ ipu6_isys_init(struct pci_dev *pdev, struct device *parent,
static struct ipu6_bus_device *
ipu6_psys_init(struct pci_dev *pdev, struct device *parent,
- struct ipu6_buttress_ctrl *ctrl, void __iomem *base,
+ const struct ipu6_buttress_ctrl *ctrl, void __iomem *base,
const struct ipu6_psys_internal_pdata *ipdata)
{
+ struct device *dev = &pdev->dev;
struct ipu6_bus_device *psys_adev;
+ struct ipu6_buttress_ctrl *devm_ctrl;
struct ipu6_psys_pdata *pdata;
int ret;
+ devm_ctrl = devm_kmemdup(dev, ctrl, sizeof(*ctrl), GFP_KERNEL);
+ if (!devm_ctrl)
+ return ERR_PTR(-ENOMEM);
+
pdata = kzalloc_obj(*pdata);
if (!pdata)
return ERR_PTR(-ENOMEM);
@@ -402,7 +413,7 @@ ipu6_psys_init(struct pci_dev *pdev, struct device *parent,
pdata->base = base;
pdata->ipdata = ipdata;
- psys_adev = ipu6_bus_initialize_device(pdev, parent, pdata, ctrl,
+ psys_adev = ipu6_bus_initialize_device(pdev, parent, pdata, devm_ctrl,
IPU6_PSYS_NAME);
if (IS_ERR(psys_adev)) {
kfree(pdata);
@@ -469,7 +480,7 @@ static void ipu6_configure_vc_mechanism(struct ipu6_device *isp)
static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
- struct ipu6_buttress_ctrl *isys_ctrl = NULL, *psys_ctrl = NULL;
+ const struct ipu6_buttress_ctrl *isys_ctrl, *psys_ctrl;
struct device *dev = &pdev->dev;
void __iomem *isys_base = NULL;
void __iomem *psys_base = NULL;
@@ -484,6 +495,8 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
isp->cpd_metadata_cmpnt_size = sizeof(struct ipu6_cpd_metadata_cmpnt);
isp->buttress.regs = &ipu6_buttress_regs;
+ isys_ctrl = &ipu6_isys_buttress_ctrl;
+ psys_ctrl = &ipu6_psys_buttress_ctrl;
switch (id->device) {
case PCI_DEVICE_ID_INTEL_IPU6:
@@ -513,6 +526,8 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
isp->hw_ver = IPU_VERSION_7;
isp->cpd_fw_name = IPU7_FIRMWARE_NAME;
isp->buttress.regs = &ipu7_buttress_regs;
+ isys_ctrl = &ipu7_isys_buttress_ctrl;
+ psys_ctrl = &ipu7_psys_buttress_ctrl;
break;
default:
return dev_err_probe(dev, -ENODEV,
@@ -582,13 +597,6 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_ipu6_bus_del_devices;
}
- isys_ctrl = devm_kmemdup(dev, &isys_buttress_ctrl,
- sizeof(isys_buttress_ctrl), GFP_KERNEL);
- if (!isys_ctrl) {
- ret = -ENOMEM;
- goto out_ipu6_bus_del_devices;
- }
-
isp->isys = ipu6_isys_init(pdev, dev, isys_ctrl, isys_base,
&isys_ipdata);
if (IS_ERR(isp->isys)) {
@@ -596,13 +604,6 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_ipu6_bus_del_devices;
}
- psys_ctrl = devm_kmemdup(dev, &psys_buttress_ctrl,
- sizeof(psys_buttress_ctrl), GFP_KERNEL);
- if (!psys_ctrl) {
- ret = -ENOMEM;
- goto out_ipu6_bus_del_devices;
- }
-
isp->psys = ipu6_psys_init(pdev, &isp->isys->auxdev.dev, psys_ctrl,
psys_base, &psys_ipdata);
if (IS_ERR(isp->psys)) {
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 36/44] media: ipu6: Read correct SKU ID for ipu7
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (34 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 35/44] media: ipu6: Move buttress mem alloc out from probe Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 37/44] media: ipu6: Add support for fixed iova region Antti Laakso
` (7 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
Add SKU ID to buttress register map to get correct ID for both IPUs.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-buttress.h | 1 +
drivers/media/pci/intel/ipu6/ipu6.c | 4 +++-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.h b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
index af72de2b8729..47a49e961945 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
@@ -54,6 +54,7 @@ struct ipu6_buttress_registers {
u32 db0_out;
u32 data0_in;
u32 data0_out;
+ u32 sku_id;
/* Bitmasks */
u32 irq_is;
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 4e4f32723904..428ad046e239 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -153,6 +153,7 @@ static const struct ipu6_buttress_registers ipu6_buttress_regs = {
.db0_out = BUTTRESS_REG_IU2CSEDB0,
.data0_in = BUTTRESS_REG_CSE2IUDATA0,
.data0_out = BUTTRESS_REG_IU2CSEDATA0,
+ .sku_id = BUTTRESS_REG_SKU,
/* Bitmasks */
.irq_is = BUTTRESS_ISR_IS_IRQ,
@@ -182,6 +183,7 @@ static const struct ipu6_buttress_registers ipu7_buttress_regs = {
.db0_out = IPU7_BUTTRESS_REG_IU2CSEDB0,
.data0_in = IPU7_BUTTRESS_REG_CSE2IUDATA0,
.data0_out = IPU7_BUTTRESS_REG_IU2CSEDATA0,
+ .sku_id = IPU7_BUTTRESS_REG_SKU,
/* Bitmasks */
.irq_is = IPU7_BUTTRESS_IRQ_IS_IRQ,
@@ -657,7 +659,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* Configure the arbitration mechanisms for VC requests */
ipu6_configure_vc_mechanism(isp);
- val = readl(isp->base + BUTTRESS_REG_SKU);
+ val = readl(isp->base + isp->buttress.regs->sku_id);
sku_id = FIELD_GET(GENMASK(6, 4), val);
version = FIELD_GET(GENMASK(3, 0), val);
dev_info(dev, "IPU%u-v%u[%x] hardware version %d\n", version, sku_id,
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 37/44] media: ipu6: Add support for fixed iova region
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (35 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 36/44] media: ipu6: Read correct SKU ID for ipu7 Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 38/44] media: ipu6: Make fw mapping function reusable Antti Laakso
` (6 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The ipu7 need specific region for firmware in non-secure mode,
add support for it.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-dma.c | 20 +++++++++++++++++---
drivers/media/pci/intel/ipu6/ipu6-dma.h | 2 ++
2 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-dma.c b/drivers/media/pci/intel/ipu6/ipu6-dma.c
index 6e8295d9c3a3..90f530a93779 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-dma.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-dma.c
@@ -371,6 +371,17 @@ void ipu6_dma_unmap_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
}
EXPORT_SYMBOL_NS_GPL(ipu6_dma_unmap_sg, "INTEL_IPU6");
+static struct iova *ipu7_get_fw_code_region(struct ipu6_bus_device *sys)
+{
+ struct ipu6_mmu *mmu = sys->mmu;
+ unsigned long lo, hi;
+
+ lo = iova_pfn(&mmu->dmap->iovad, IPU7_FW_CODE_REGION_START);
+ hi = iova_pfn(&mmu->dmap->iovad, IPU7_FW_CODE_REGION_END) - 1U;
+
+ return reserve_iova(&mmu->dmap->iovad, lo, hi);
+}
+
int ipu6_dma_map_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
int nents, enum dma_data_direction dir,
unsigned long attrs)
@@ -397,10 +408,13 @@ int ipu6_dma_map_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
dev_dbg(dev, "dmamap trying to map %d ents %zu pages\n",
nents, npages);
- iova = alloc_iova(&mmu->dmap->iovad, npages,
- PHYS_PFN(mmu->dmap->mmu_info->aperture_end), 0);
+ if (attrs & DMA_ATTR_RESERVE_REGION)
+ iova = ipu7_get_fw_code_region(sys);
+ else
+ iova = alloc_iova(&mmu->dmap->iovad, npages,
+ PHYS_PFN(mmu->dmap->mmu_info->aperture_end), 0);
if (!iova)
- return 0;
+ return -ENOMEM;
dev_dbg(dev, "dmamap: iova low pfn %lu, high pfn %lu\n", iova->pfn_lo,
iova->pfn_hi);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-dma.h b/drivers/media/pci/intel/ipu6/ipu6-dma.h
index ae9b9a5df57f..e5e0e7860423 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-dma.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-dma.h
@@ -10,6 +10,8 @@
#include "ipu6-bus.h"
+#define DMA_ATTR_RESERVE_REGION BIT(31)
+
struct ipu6_mmu_info;
struct ipu6_dma_mapping {
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 38/44] media: ipu6: Make fw mapping function reusable
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (36 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 37/44] media: ipu6: Add support for fixed iova region Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:42 ` [PATCH v2 39/44] media: ipu6: Move isys fw mapping to pci_probe Antti Laakso
` (5 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
Make ipu6_map_fw_region reusable as for ipu7 we want to map other
buffers too, not only firmware. Also add DMA data direction and mapping
attributes as arguments as these are different for ipu7.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-buttress.c | 40 ++++++++++----------
drivers/media/pci/intel/ipu6/ipu6-buttress.h | 10 ++---
drivers/media/pci/intel/ipu6/ipu6-isys.c | 7 ++--
drivers/media/pci/intel/ipu6/ipu6.c | 8 ++--
4 files changed, 33 insertions(+), 32 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index 13fd7a083b25..74db0a37561e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
@@ -676,55 +676,55 @@ int ipu6_buttress_reset_authentication(struct ipu6_device *isp)
return 0;
}
-int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys,
- const struct firmware *fw, struct sg_table *sgt)
+int ipu6_map_fw_region(struct ipu6_bus_device *sys, const void *data,
+ size_t size, enum dma_data_direction dir,
+ unsigned long attrs)
{
- bool is_vmalloc = is_vmalloc_addr(fw->data);
+ bool is_vmalloc = is_vmalloc_addr(data);
struct pci_dev *pdev = sys->isp->pdev;
+ struct sg_table *sgt = &sys->fw_sgt;
struct page **pages;
- const void *addr;
unsigned long n_pages;
unsigned int i;
int ret;
- if (!is_vmalloc && !virt_addr_valid(fw->data))
+ if (!is_vmalloc && !virt_addr_valid(data))
return -EDOM;
- n_pages = PFN_UP(fw->size);
+ n_pages = PFN_UP(size);
pages = kmalloc_objs(*pages, n_pages);
if (!pages)
return -ENOMEM;
- addr = fw->data;
for (i = 0; i < n_pages; i++) {
struct page *p = is_vmalloc ?
- vmalloc_to_page(addr) : virt_to_page(addr);
+ vmalloc_to_page(data) : virt_to_page(data);
if (!p) {
ret = -ENOMEM;
goto out;
}
pages[i] = p;
- addr += PAGE_SIZE;
+ data += PAGE_SIZE;
}
- ret = sg_alloc_table_from_pages(sgt, pages, n_pages, 0, fw->size,
+ ret = sg_alloc_table_from_pages(sgt, pages, n_pages, 0, size,
GFP_KERNEL);
if (ret) {
ret = -ENOMEM;
goto out;
}
- ret = dma_map_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0);
+ ret = dma_map_sgtable(&pdev->dev, sgt, dir, 0);
if (ret) {
sg_free_table(sgt);
goto out;
}
- ret = ipu6_dma_map_sgtable(sys, sgt, DMA_TO_DEVICE, 0);
+ ret = ipu6_dma_map_sgtable(sys, sgt, dir, attrs);
if (ret) {
- dma_unmap_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0);
+ dma_unmap_sgtable(&pdev->dev, sgt, dir, 0);
sg_free_table(sgt);
goto out;
}
@@ -736,18 +736,18 @@ int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys,
return ret;
}
-EXPORT_SYMBOL_NS_GPL(ipu6_buttress_map_fw_image, "INTEL_IPU6");
+EXPORT_SYMBOL_NS_GPL(ipu6_map_fw_region, "INTEL_IPU6");
-void ipu6_buttress_unmap_fw_image(struct ipu6_bus_device *sys,
- struct sg_table *sgt)
+void ipu6_unmap_fw_region(struct ipu6_bus_device *sys,
+ enum dma_data_direction dir)
{
struct pci_dev *pdev = sys->isp->pdev;
- ipu6_dma_unmap_sgtable(sys, sgt, DMA_TO_DEVICE, 0);
- dma_unmap_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0);
- sg_free_table(sgt);
+ ipu6_dma_unmap_sgtable(sys, &sys->fw_sgt, dir, 0);
+ dma_unmap_sgtable(&pdev->dev, &sys->fw_sgt, dir, 0);
+ sg_free_table(&sys->fw_sgt);
}
-EXPORT_SYMBOL_NS_GPL(ipu6_buttress_unmap_fw_image, "INTEL_IPU6");
+EXPORT_SYMBOL_NS_GPL(ipu6_unmap_fw_region, "INTEL_IPU6");
int ipu6_buttress_authenticate(struct ipu6_device *isp)
{
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.h b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
index 47a49e961945..79d8f5893686 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
@@ -84,11 +84,11 @@ struct ipu6_ipc_buttress_bulk_msg {
};
int ipu6_buttress_ipc_reset(struct ipu6_device *isp);
-int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys,
- const struct firmware *fw,
- struct sg_table *sgt);
-void ipu6_buttress_unmap_fw_image(struct ipu6_bus_device *sys,
- struct sg_table *sgt);
+int ipu6_map_fw_region(struct ipu6_bus_device *sys, const void *data,
+ size_t size, enum dma_data_direction dir,
+ unsigned long attrs);
+void ipu6_unmap_fw_region(struct ipu6_bus_device *sys,
+ enum dma_data_direction dir);
int ipu6_buttress_power(struct device *dev,
const struct ipu6_buttress_ctrl *ctrl, bool on);
bool ipu6_buttress_get_secure_mode(struct ipu6_device *isp);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 5a3ba5007249..459121e6c1cb 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -1042,7 +1042,8 @@ static int isys_probe(struct auxiliary_device *auxdev,
if (!isp->secure_mode) {
fw = isp->cpd_fw;
- ret = ipu6_buttress_map_fw_image(adev, fw, &adev->fw_sgt);
+ ret = ipu6_map_fw_region(adev, fw->data, fw->size,
+ DMA_TO_DEVICE, 0);
if (ret)
goto release_firmware;
@@ -1082,7 +1083,7 @@ static int isys_probe(struct auxiliary_device *auxdev,
ipu6_cpd_free_pkg_dir(adev);
remove_shared_buffer:
if (!isp->secure_mode)
- ipu6_buttress_unmap_fw_image(adev, &adev->fw_sgt);
+ ipu6_unmap_fw_region(adev, DMA_TO_DEVICE);
release_firmware:
if (!isp->secure_mode)
release_firmware(adev->fw);
@@ -1112,7 +1113,7 @@ static void isys_remove(struct auxiliary_device *auxdev)
if (!isp->secure_mode) {
ipu6_cpd_free_pkg_dir(adev);
- ipu6_buttress_unmap_fw_image(adev, &adev->fw_sgt);
+ ipu6_unmap_fw_region(adev, DMA_TO_DEVICE);
release_firmware(adev->fw);
}
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 428ad046e239..af5581da7149 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -624,8 +624,8 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_ipu6_rpm_put;
}
- ret = ipu6_buttress_map_fw_image(isp->psys, isp->cpd_fw,
- &isp->psys->fw_sgt);
+ ret = ipu6_map_fw_region(isp->psys, isp->cpd_fw->data,
+ isp->cpd_fw->size, DMA_TO_DEVICE, 0);
if (ret) {
dev_err_probe(&isp->pdev->dev, ret, "failed to map fw image\n");
goto out_ipu6_rpm_put;
@@ -679,7 +679,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
out_ipu6_bus_del_devices:
if (!IS_ERR_OR_NULL(isp->psys)) {
ipu6_cpd_free_pkg_dir(isp->psys);
- ipu6_buttress_unmap_fw_image(isp->psys, &isp->psys->fw_sgt);
+ ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
}
if (!IS_ERR_OR_NULL(isp->psys) && !IS_ERR_OR_NULL(isp->psys->mmu))
ipu6_mmu_cleanup(isp->psys->mmu);
@@ -702,7 +702,7 @@ static void ipu6_pci_remove(struct pci_dev *pdev)
devm_free_irq(&pdev->dev, pdev->irq, isp);
ipu6_cpd_free_pkg_dir(isp->psys);
- ipu6_buttress_unmap_fw_image(isp->psys, &isp->psys->fw_sgt);
+ ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
ipu6_buttress_exit(isp);
ipu6_bus_del_devices(pdev);
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 39/44] media: ipu6: Move isys fw mapping to pci_probe
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (37 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 38/44] media: ipu6: Make fw mapping function reusable Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 18:17 ` Sakari Ailus
2026-08-21 11:42 ` [PATCH v2 40/44] media: ipu6: Map ipu7 firmware Antti Laakso
` (4 subsequent siblings)
43 siblings, 1 reply; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
We are bout to add ipu7 firmware mapping. It is slightly different from
ipu6. Handling this and possible errors is easier when both isys and
psys mapping is in one place.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-bus.h | 1 -
drivers/media/pci/intel/ipu6/ipu6-isys.c | 29 -----------
drivers/media/pci/intel/ipu6/ipu6.c | 63 +++++++++++++++++++-----
3 files changed, 50 insertions(+), 43 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-bus.h b/drivers/media/pci/intel/ipu6/ipu6-bus.h
index aef8e4a66c4a..d2f93eb03dea 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-bus.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-bus.h
@@ -26,7 +26,6 @@ struct ipu6_bus_device {
struct ipu6_mmu *mmu;
struct ipu6_device *isp;
const struct ipu6_buttress_ctrl *ctrl;
- const struct firmware *fw;
struct sg_table fw_sgt;
u64 *pkg_dir;
dma_addr_t pkg_dir_dma_addr;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 459121e6c1cb..3fb34d2d189c 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -995,7 +995,6 @@ static int isys_probe(struct auxiliary_device *auxdev,
const struct ipu6_isys_internal_csi2_pdata *csi2_pdata;
struct ipu6_bus_device *adev = auxdev_to_adev(auxdev);
struct ipu6_device *isp = adev->isp;
- const struct firmware *fw;
struct ipu6_isys *isys;
unsigned int i;
int ret;
@@ -1040,18 +1039,6 @@ static int isys_probe(struct auxiliary_device *auxdev,
isys_stream_init(isys);
- if (!isp->secure_mode) {
- fw = isp->cpd_fw;
- ret = ipu6_map_fw_region(adev, fw->data, fw->size,
- DMA_TO_DEVICE, 0);
- if (ret)
- goto release_firmware;
-
- ret = ipu6_cpd_create_pkg_dir(adev, isp->cpd_fw->data);
- if (ret)
- goto remove_shared_buffer;
- }
-
cpu_latency_qos_add_request(&isys->pm_qos, PM_QOS_DEFAULT_VALUE);
ret = alloc_fw_msg_bufs(isys, 20);
@@ -1079,14 +1066,6 @@ static int isys_probe(struct auxiliary_device *auxdev,
free_fw_msg_bufs(isys);
out_remove_pkg_dir_shared_buffer:
cpu_latency_qos_remove_request(&isys->pm_qos);
- if (!isp->secure_mode)
- ipu6_cpd_free_pkg_dir(adev);
-remove_shared_buffer:
- if (!isp->secure_mode)
- ipu6_unmap_fw_region(adev, DMA_TO_DEVICE);
-release_firmware:
- if (!isp->secure_mode)
- release_firmware(adev->fw);
for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++)
mutex_destroy(&isys->streams[i].mutex);
@@ -1099,9 +1078,7 @@ static int isys_probe(struct auxiliary_device *auxdev,
static void isys_remove(struct auxiliary_device *auxdev)
{
- struct ipu6_bus_device *adev = auxdev_to_adev(auxdev);
struct ipu6_isys *isys = dev_get_drvdata(&auxdev->dev);
- struct ipu6_device *isp = adev->isp;
unsigned int i;
free_fw_msg_bufs(isys);
@@ -1111,12 +1088,6 @@ static void isys_remove(struct auxiliary_device *auxdev)
cpu_latency_qos_remove_request(&isys->pm_qos);
- if (!isp->secure_mode) {
- ipu6_cpd_free_pkg_dir(adev);
- ipu6_unmap_fw_region(adev, DMA_TO_DEVICE);
- release_firmware(adev->fw);
- }
-
for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++)
mutex_destroy(&isys->streams[i].mutex);
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index af5581da7149..d27ffd7ac6f0 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -480,6 +480,40 @@ static void ipu6_configure_vc_mechanism(struct ipu6_device *isp)
writel(val, isp->base + BUTTRESS_REG_BTRS_CTRL);
}
+static int __ipu6_map_fw_by_sys(struct ipu6_device *isp, struct ipu6_bus_device *adev)
+{
+ int ret = ipu6_map_fw_region(adev, isp->cpd_fw->data, isp->cpd_fw->size,
+ DMA_TO_DEVICE, 0);
+
+ if (ret) {
+ dev_err_probe(&isp->pdev->dev, ret,
+ "Firmware mapping failed\n");
+ return ret;
+ }
+
+ ret = ipu6_cpd_create_pkg_dir(adev, isp->cpd_fw->data);
+ if (ret) {
+ dev_err_probe(&isp->pdev->dev, ret,
+ "failed to create pkg dir\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ipu6_map_fw(struct ipu6_device *isp)
+{
+ int ret = __ipu6_map_fw_by_sys(isp, isp->psys);
+
+ if (ret)
+ return ret;
+
+ if (!isp->secure_mode)
+ return __ipu6_map_fw_by_sys(isp, isp->isys);
+
+ return 0;
+}
+
static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
const struct ipu6_buttress_ctrl *isys_ctrl, *psys_ctrl;
@@ -624,19 +658,9 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_ipu6_rpm_put;
}
- ret = ipu6_map_fw_region(isp->psys, isp->cpd_fw->data,
- isp->cpd_fw->size, DMA_TO_DEVICE, 0);
- if (ret) {
- dev_err_probe(&isp->pdev->dev, ret, "failed to map fw image\n");
- goto out_ipu6_rpm_put;
- }
-
- ret = ipu6_cpd_create_pkg_dir(isp->psys, isp->cpd_fw->data);
- if (ret) {
- dev_err_probe(&isp->pdev->dev, ret,
- "failed to create pkg dir\n");
+ ret = ipu6_map_fw(isp);
+ if (ret)
goto out_ipu6_rpm_put;
- }
ret = devm_request_threaded_irq(dev, pdev->irq, ipu6_buttress_isr,
ipu6_buttress_isr_threaded,
@@ -679,7 +703,13 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
out_ipu6_bus_del_devices:
if (!IS_ERR_OR_NULL(isp->psys)) {
ipu6_cpd_free_pkg_dir(isp->psys);
- ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
+ if (isp->psys->fw_sgt.nents)
+ ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
+ }
+ if (!IS_ERR_OR_NULL(isp->isys)) {
+ ipu6_cpd_free_pkg_dir(isp->isys);
+ if (isp->isys->fw_sgt.nents)
+ ipu6_unmap_fw_region(isp->isys, DMA_TO_DEVICE);
}
if (!IS_ERR_OR_NULL(isp->psys) && !IS_ERR_OR_NULL(isp->psys->mmu))
ipu6_mmu_cleanup(isp->psys->mmu);
@@ -703,6 +733,13 @@ static void ipu6_pci_remove(struct pci_dev *pdev)
ipu6_cpd_free_pkg_dir(isp->psys);
ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
+
+ if (isp->isys) {
+ ipu6_cpd_free_pkg_dir(isp->isys);
+ if (isp->isys->fw_sgt.nents)
+ ipu6_unmap_fw_region(isp->isys, DMA_TO_DEVICE);
+ }
+
ipu6_buttress_exit(isp);
ipu6_bus_del_devices(pdev);
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH v2 39/44] media: ipu6: Move isys fw mapping to pci_probe
2026-08-21 11:42 ` [PATCH v2 39/44] media: ipu6: Move isys fw mapping to pci_probe Antti Laakso
@ 2026-08-21 18:17 ` Sakari Ailus
0 siblings, 0 replies; 47+ messages in thread
From: Sakari Ailus @ 2026-08-21 18:17 UTC (permalink / raw)
To: Antti Laakso; +Cc: linux-media, mchehab, daxing.li, ong.hock.yu
Moi,
Thanks for the update!
On Fri, Aug 21, 2026 at 02:42:57PM +0300, Antti Laakso wrote:
> We are bout to add ipu7 firmware mapping. It is slightly different from
s/bout/about/
> ipu6. Handling this and possible errors is easier when both isys and
> psys mapping is in one place.
>
> Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
> ---
> drivers/media/pci/intel/ipu6/ipu6-bus.h | 1 -
> drivers/media/pci/intel/ipu6/ipu6-isys.c | 29 -----------
> drivers/media/pci/intel/ipu6/ipu6.c | 63 +++++++++++++++++++-----
> 3 files changed, 50 insertions(+), 43 deletions(-)
>
> diff --git a/drivers/media/pci/intel/ipu6/ipu6-bus.h b/drivers/media/pci/intel/ipu6/ipu6-bus.h
> index aef8e4a66c4a..d2f93eb03dea 100644
> --- a/drivers/media/pci/intel/ipu6/ipu6-bus.h
> +++ b/drivers/media/pci/intel/ipu6/ipu6-bus.h
> @@ -26,7 +26,6 @@ struct ipu6_bus_device {
> struct ipu6_mmu *mmu;
> struct ipu6_device *isp;
> const struct ipu6_buttress_ctrl *ctrl;
> - const struct firmware *fw;
> struct sg_table fw_sgt;
> u64 *pkg_dir;
> dma_addr_t pkg_dir_dma_addr;
> diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
> index 459121e6c1cb..3fb34d2d189c 100644
> --- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
> +++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
> @@ -995,7 +995,6 @@ static int isys_probe(struct auxiliary_device *auxdev,
> const struct ipu6_isys_internal_csi2_pdata *csi2_pdata;
> struct ipu6_bus_device *adev = auxdev_to_adev(auxdev);
> struct ipu6_device *isp = adev->isp;
> - const struct firmware *fw;
> struct ipu6_isys *isys;
> unsigned int i;
> int ret;
> @@ -1040,18 +1039,6 @@ static int isys_probe(struct auxiliary_device *auxdev,
>
> isys_stream_init(isys);
>
> - if (!isp->secure_mode) {
> - fw = isp->cpd_fw;
> - ret = ipu6_map_fw_region(adev, fw->data, fw->size,
> - DMA_TO_DEVICE, 0);
> - if (ret)
> - goto release_firmware;
> -
> - ret = ipu6_cpd_create_pkg_dir(adev, isp->cpd_fw->data);
> - if (ret)
> - goto remove_shared_buffer;
> - }
> -
> cpu_latency_qos_add_request(&isys->pm_qos, PM_QOS_DEFAULT_VALUE);
>
> ret = alloc_fw_msg_bufs(isys, 20);
> @@ -1079,14 +1066,6 @@ static int isys_probe(struct auxiliary_device *auxdev,
> free_fw_msg_bufs(isys);
> out_remove_pkg_dir_shared_buffer:
> cpu_latency_qos_remove_request(&isys->pm_qos);
> - if (!isp->secure_mode)
> - ipu6_cpd_free_pkg_dir(adev);
> -remove_shared_buffer:
> - if (!isp->secure_mode)
> - ipu6_unmap_fw_region(adev, DMA_TO_DEVICE);
> -release_firmware:
> - if (!isp->secure_mode)
> - release_firmware(adev->fw);
>
> for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++)
> mutex_destroy(&isys->streams[i].mutex);
> @@ -1099,9 +1078,7 @@ static int isys_probe(struct auxiliary_device *auxdev,
>
> static void isys_remove(struct auxiliary_device *auxdev)
> {
> - struct ipu6_bus_device *adev = auxdev_to_adev(auxdev);
> struct ipu6_isys *isys = dev_get_drvdata(&auxdev->dev);
> - struct ipu6_device *isp = adev->isp;
> unsigned int i;
>
> free_fw_msg_bufs(isys);
> @@ -1111,12 +1088,6 @@ static void isys_remove(struct auxiliary_device *auxdev)
>
> cpu_latency_qos_remove_request(&isys->pm_qos);
>
> - if (!isp->secure_mode) {
> - ipu6_cpd_free_pkg_dir(adev);
> - ipu6_unmap_fw_region(adev, DMA_TO_DEVICE);
> - release_firmware(adev->fw);
> - }
> -
> for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++)
> mutex_destroy(&isys->streams[i].mutex);
>
> diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
> index af5581da7149..d27ffd7ac6f0 100644
> --- a/drivers/media/pci/intel/ipu6/ipu6.c
> +++ b/drivers/media/pci/intel/ipu6/ipu6.c
> @@ -480,6 +480,40 @@ static void ipu6_configure_vc_mechanism(struct ipu6_device *isp)
> writel(val, isp->base + BUTTRESS_REG_BTRS_CTRL);
> }
>
> +static int __ipu6_map_fw_by_sys(struct ipu6_device *isp, struct ipu6_bus_device *adev)
> +{
> + int ret = ipu6_map_fw_region(adev, isp->cpd_fw->data, isp->cpd_fw->size,
Please avoid assigning variables in declaration block when there are errors
to check.
> + DMA_TO_DEVICE, 0);
> +
> + if (ret) {
> + dev_err_probe(&isp->pdev->dev, ret,
> + "Firmware mapping failed\n");
> + return ret;
> + }
> +
> + ret = ipu6_cpd_create_pkg_dir(adev, isp->cpd_fw->data);
> + if (ret) {
> + dev_err_probe(&isp->pdev->dev, ret,
> + "failed to create pkg dir\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int ipu6_map_fw(struct ipu6_device *isp)
> +{
> + int ret = __ipu6_map_fw_by_sys(isp, isp->psys);
Ditto.
> +
> + if (ret)
> + return ret;
> +
> + if (!isp->secure_mode)
> + return __ipu6_map_fw_by_sys(isp, isp->isys);
> +
> + return 0;
> +}
> +
> static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> {
> const struct ipu6_buttress_ctrl *isys_ctrl, *psys_ctrl;
> @@ -624,19 +658,9 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> goto out_ipu6_rpm_put;
> }
>
> - ret = ipu6_map_fw_region(isp->psys, isp->cpd_fw->data,
> - isp->cpd_fw->size, DMA_TO_DEVICE, 0);
> - if (ret) {
> - dev_err_probe(&isp->pdev->dev, ret, "failed to map fw image\n");
> - goto out_ipu6_rpm_put;
> - }
> -
> - ret = ipu6_cpd_create_pkg_dir(isp->psys, isp->cpd_fw->data);
> - if (ret) {
> - dev_err_probe(&isp->pdev->dev, ret,
> - "failed to create pkg dir\n");
> + ret = ipu6_map_fw(isp);
> + if (ret)
> goto out_ipu6_rpm_put;
> - }
>
> ret = devm_request_threaded_irq(dev, pdev->irq, ipu6_buttress_isr,
> ipu6_buttress_isr_threaded,
> @@ -679,7 +703,13 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> out_ipu6_bus_del_devices:
> if (!IS_ERR_OR_NULL(isp->psys)) {
> ipu6_cpd_free_pkg_dir(isp->psys);
> - ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
> + if (isp->psys->fw_sgt.nents)
> + ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
> + }
> + if (!IS_ERR_OR_NULL(isp->isys)) {
> + ipu6_cpd_free_pkg_dir(isp->isys);
> + if (isp->isys->fw_sgt.nents)
> + ipu6_unmap_fw_region(isp->isys, DMA_TO_DEVICE);
> }
> if (!IS_ERR_OR_NULL(isp->psys) && !IS_ERR_OR_NULL(isp->psys->mmu))
> ipu6_mmu_cleanup(isp->psys->mmu);
> @@ -703,6 +733,13 @@ static void ipu6_pci_remove(struct pci_dev *pdev)
> ipu6_cpd_free_pkg_dir(isp->psys);
>
> ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
> +
> + if (isp->isys) {
> + ipu6_cpd_free_pkg_dir(isp->isys);
> + if (isp->isys->fw_sgt.nents)
> + ipu6_unmap_fw_region(isp->isys, DMA_TO_DEVICE);
> + }
> +
> ipu6_buttress_exit(isp);
>
> ipu6_bus_del_devices(pdev);
--
Terveisin,
Sakari Ailus
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH v2 40/44] media: ipu6: Map ipu7 firmware
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (38 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 39/44] media: ipu6: Move isys fw mapping to pci_probe Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 18:23 ` Sakari Ailus
2026-08-21 11:42 ` [PATCH v2 41/44] media: ipu6: Set model name for ipu7 Antti Laakso
` (3 subsequent siblings)
43 siblings, 1 reply; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
Mapping of ipu7 firmware is slightly different compared to ipu6. Add
helpers for it and call them similar to ipu6.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6.c | 75 ++++++++++++++++++++++++++---
drivers/media/pci/intel/ipu6/ipu6.h | 1 +
2 files changed, 70 insertions(+), 6 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index d27ffd7ac6f0..93f28ec9a74d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -19,6 +19,7 @@
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <linux/vmalloc.h>
#include <media/ipu-bridge.h>
#include <media/ipu6-pci-table.h>
@@ -27,6 +28,7 @@
#include "ipu6-bus.h"
#include "ipu6-buttress.h"
#include "ipu6-cpd.h"
+#include "ipu6-dma.h"
#include "ipu6-isys.h"
#include "ipu6-mmu.h"
#include "ipu6-platform-buttress-regs.h"
@@ -514,6 +516,57 @@ static int ipu6_map_fw(struct ipu6_device *isp)
return 0;
}
+static int __ipu7_map_fw_non_secure(struct ipu6_device *isp)
+{
+ int ret;
+
+ /*
+ * Allocate and map memory for running the firmware. Not
+ * required in secure mode, in which firmware runs in IMR.
+ */
+ isp->fw_code_region = vmalloc(IPU7_FW_CODE_REGION_SIZE);
+ if (!isp->fw_code_region)
+ return -ENOMEM;
+
+ ret = ipu7_cpd_copy_binary(isp->cpd_fw->data, "isys",
+ isp->fw_code_region, &isp->isys->fw_entry);
+ if (ret)
+ return ret;
+
+ ret = ipu6_map_fw_region(isp->isys, isp->fw_code_region,
+ IPU7_FW_CODE_REGION_SIZE, DMA_BIDIRECTIONAL,
+ DMA_ATTR_RESERVE_REGION);
+ if (ret)
+ return ret;
+
+ ret = ipu7_cpd_copy_binary(isp->cpd_fw->data, "psys",
+ isp->fw_code_region, &isp->psys->fw_entry);
+ if (ret)
+ return ret;
+
+ return ipu6_map_fw_region(isp->psys, isp->fw_code_region,
+ IPU7_FW_CODE_REGION_SIZE, DMA_BIDIRECTIONAL,
+ DMA_ATTR_RESERVE_REGION);
+}
+
+static int ipu7_map_fw(struct ipu6_device *isp)
+{
+ int ret;
+
+ ret = isp->secure_mode ?
+ ipu6_map_fw_region(isp->psys, isp->cpd_fw->data,
+ isp->cpd_fw->size, DMA_BIDIRECTIONAL, 0) :
+ __ipu7_map_fw_non_secure(isp);
+
+ if (ret) {
+ dev_err_probe(&isp->pdev->dev, ret,
+ "Failed to init ipu7 firmware region\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
const struct ipu6_buttress_ctrl *isys_ctrl, *psys_ctrl;
@@ -523,6 +576,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct ipu6_device *isp;
phys_addr_t phys;
u32 val, version, sku_id;
+ unsigned long dir;
int ret;
isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
@@ -658,7 +712,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto out_ipu6_rpm_put;
}
- ret = ipu6_map_fw(isp);
+ ret = IS_IPU7(isp) ? ipu7_map_fw(isp) : ipu6_map_fw(isp);
if (ret)
goto out_ipu6_rpm_put;
@@ -701,15 +755,20 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
out_ipu6_rpm_put:
pm_runtime_put_sync(&isp->psys->auxdev.dev);
out_ipu6_bus_del_devices:
+ dir = IS_IPU7(isp) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
if (!IS_ERR_OR_NULL(isp->psys)) {
ipu6_cpd_free_pkg_dir(isp->psys);
if (isp->psys->fw_sgt.nents)
- ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
+ ipu6_unmap_fw_region(isp->psys, dir);
}
if (!IS_ERR_OR_NULL(isp->isys)) {
ipu6_cpd_free_pkg_dir(isp->isys);
if (isp->isys->fw_sgt.nents)
- ipu6_unmap_fw_region(isp->isys, DMA_TO_DEVICE);
+ ipu6_unmap_fw_region(isp->isys, dir);
+ }
+ if (isp->fw_code_region) {
+ vfree(isp->fw_code_region);
+ isp->fw_code_region = NULL;
}
if (!IS_ERR_OR_NULL(isp->psys) && !IS_ERR_OR_NULL(isp->psys->mmu))
ipu6_mmu_cleanup(isp->psys->mmu);
@@ -728,18 +787,22 @@ static void ipu6_pci_remove(struct pci_dev *pdev)
struct ipu6_device *isp = pci_get_drvdata(pdev);
struct ipu6_mmu *isys_mmu = isp->isys->mmu;
struct ipu6_mmu *psys_mmu = isp->psys->mmu;
+ unsigned long dir;
devm_free_irq(&pdev->dev, pdev->irq, isp);
- ipu6_cpd_free_pkg_dir(isp->psys);
- ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
+ dir = IS_IPU7(isp) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
+ ipu6_cpd_free_pkg_dir(isp->psys);
+ ipu6_unmap_fw_region(isp->psys, dir);
if (isp->isys) {
ipu6_cpd_free_pkg_dir(isp->isys);
if (isp->isys->fw_sgt.nents)
- ipu6_unmap_fw_region(isp->isys, DMA_TO_DEVICE);
+ ipu6_unmap_fw_region(isp->isys, dir);
}
+ vfree(isp->fw_code_region);
+
ipu6_buttress_exit(isp);
ipu6_bus_del_devices(pdev);
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index 6bef45a02c2b..a2992ffe8e3c 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -70,6 +70,7 @@ struct ipu6_device {
bool secure_mode;
u8 hw_ver;
bool bus_ready_to_probe;
+ u32 *fw_code_region;
};
#define IPU_PSYS 0
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* Re: [PATCH v2 40/44] media: ipu6: Map ipu7 firmware
2026-08-21 11:42 ` [PATCH v2 40/44] media: ipu6: Map ipu7 firmware Antti Laakso
@ 2026-08-21 18:23 ` Sakari Ailus
0 siblings, 0 replies; 47+ messages in thread
From: Sakari Ailus @ 2026-08-21 18:23 UTC (permalink / raw)
To: Antti Laakso; +Cc: linux-media, mchehab, daxing.li, ong.hock.yu
Moi,
On Fri, Aug 21, 2026 at 02:42:58PM +0300, Antti Laakso wrote:
> Mapping of ipu7 firmware is slightly different compared to ipu6. Add
> helpers for it and call them similar to ipu6.
>
> Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
> ---
> drivers/media/pci/intel/ipu6/ipu6.c | 75 ++++++++++++++++++++++++++---
> drivers/media/pci/intel/ipu6/ipu6.h | 1 +
> 2 files changed, 70 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
> index d27ffd7ac6f0..93f28ec9a74d 100644
> --- a/drivers/media/pci/intel/ipu6/ipu6.c
> +++ b/drivers/media/pci/intel/ipu6/ipu6.c
> @@ -19,6 +19,7 @@
> #include <linux/scatterlist.h>
> #include <linux/slab.h>
> #include <linux/types.h>
> +#include <linux/vmalloc.h>
>
> #include <media/ipu-bridge.h>
> #include <media/ipu6-pci-table.h>
> @@ -27,6 +28,7 @@
> #include "ipu6-bus.h"
> #include "ipu6-buttress.h"
> #include "ipu6-cpd.h"
> +#include "ipu6-dma.h"
> #include "ipu6-isys.h"
> #include "ipu6-mmu.h"
> #include "ipu6-platform-buttress-regs.h"
> @@ -514,6 +516,57 @@ static int ipu6_map_fw(struct ipu6_device *isp)
> return 0;
> }
>
> +static int __ipu7_map_fw_non_secure(struct ipu6_device *isp)
> +{
> + int ret;
> +
> + /*
> + * Allocate and map memory for running the firmware. Not
> + * required in secure mode, in which firmware runs in IMR.
> + */
> + isp->fw_code_region = vmalloc(IPU7_FW_CODE_REGION_SIZE);
> + if (!isp->fw_code_region)
> + return -ENOMEM;
> +
> + ret = ipu7_cpd_copy_binary(isp->cpd_fw->data, "isys",
> + isp->fw_code_region, &isp->isys->fw_entry);
> + if (ret)
> + return ret;
> +
> + ret = ipu6_map_fw_region(isp->isys, isp->fw_code_region,
> + IPU7_FW_CODE_REGION_SIZE, DMA_BIDIRECTIONAL,
> + DMA_ATTR_RESERVE_REGION);
> + if (ret)
> + return ret;
> +
> + ret = ipu7_cpd_copy_binary(isp->cpd_fw->data, "psys",
> + isp->fw_code_region, &isp->psys->fw_entry);
> + if (ret)
> + return ret;
> +
> + return ipu6_map_fw_region(isp->psys, isp->fw_code_region,
> + IPU7_FW_CODE_REGION_SIZE, DMA_BIDIRECTIONAL,
> + DMA_ATTR_RESERVE_REGION);
> +}
> +
> +static int ipu7_map_fw(struct ipu6_device *isp)
> +{
> + int ret;
> +
> + ret = isp->secure_mode ?
> + ipu6_map_fw_region(isp->psys, isp->cpd_fw->data,
> + isp->cpd_fw->size, DMA_BIDIRECTIONAL, 0) :
> + __ipu7_map_fw_non_secure(isp);
> +
No newline needed here.
> + if (ret) {
> + dev_err_probe(&isp->pdev->dev, ret,
> + "Failed to init ipu7 firmware region\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> {
> const struct ipu6_buttress_ctrl *isys_ctrl, *psys_ctrl;
> @@ -523,6 +576,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> struct ipu6_device *isp;
> phys_addr_t phys;
> u32 val, version, sku_id;
> + unsigned long dir;
> int ret;
>
> isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
> @@ -658,7 +712,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> goto out_ipu6_rpm_put;
> }
>
> - ret = ipu6_map_fw(isp);
> + ret = IS_IPU7(isp) ? ipu7_map_fw(isp) : ipu6_map_fw(isp);
> if (ret)
> goto out_ipu6_rpm_put;
>
> @@ -701,15 +755,20 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
> out_ipu6_rpm_put:
> pm_runtime_put_sync(&isp->psys->auxdev.dev);
> out_ipu6_bus_del_devices:
> + dir = IS_IPU7(isp) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
> if (!IS_ERR_OR_NULL(isp->psys)) {
> ipu6_cpd_free_pkg_dir(isp->psys);
> if (isp->psys->fw_sgt.nents)
> - ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
> + ipu6_unmap_fw_region(isp->psys, dir);
> }
> if (!IS_ERR_OR_NULL(isp->isys)) {
> ipu6_cpd_free_pkg_dir(isp->isys);
> if (isp->isys->fw_sgt.nents)
> - ipu6_unmap_fw_region(isp->isys, DMA_TO_DEVICE);
> + ipu6_unmap_fw_region(isp->isys, dir);
> + }
> + if (isp->fw_code_region) {
> + vfree(isp->fw_code_region);
> + isp->fw_code_region = NULL;
This can be done unconditionally -- as in the remove callback.
> }
> if (!IS_ERR_OR_NULL(isp->psys) && !IS_ERR_OR_NULL(isp->psys->mmu))
> ipu6_mmu_cleanup(isp->psys->mmu);
> @@ -728,18 +787,22 @@ static void ipu6_pci_remove(struct pci_dev *pdev)
> struct ipu6_device *isp = pci_get_drvdata(pdev);
> struct ipu6_mmu *isys_mmu = isp->isys->mmu;
> struct ipu6_mmu *psys_mmu = isp->psys->mmu;
> + unsigned long dir;
>
> devm_free_irq(&pdev->dev, pdev->irq, isp);
> - ipu6_cpd_free_pkg_dir(isp->psys);
>
> - ipu6_unmap_fw_region(isp->psys, DMA_TO_DEVICE);
> + dir = IS_IPU7(isp) ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
Why is there a need for a bi-directional mapping for ipu7?
> + ipu6_cpd_free_pkg_dir(isp->psys);
> + ipu6_unmap_fw_region(isp->psys, dir);
>
> if (isp->isys) {
> ipu6_cpd_free_pkg_dir(isp->isys);
> if (isp->isys->fw_sgt.nents)
> - ipu6_unmap_fw_region(isp->isys, DMA_TO_DEVICE);
> + ipu6_unmap_fw_region(isp->isys, dir);
> }
>
> + vfree(isp->fw_code_region);
> +
> ipu6_buttress_exit(isp);
>
> ipu6_bus_del_devices(pdev);
> diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
> index 6bef45a02c2b..a2992ffe8e3c 100644
> --- a/drivers/media/pci/intel/ipu6/ipu6.h
> +++ b/drivers/media/pci/intel/ipu6/ipu6.h
> @@ -70,6 +70,7 @@ struct ipu6_device {
> bool secure_mode;
> u8 hw_ver;
> bool bus_ready_to_probe;
> + u32 *fw_code_region;
> };
>
> #define IPU_PSYS 0
--
Terveisin,
Sakari Ailus
^ permalink raw reply [flat|nested] 47+ messages in thread
* [PATCH v2 41/44] media: ipu6: Set model name for ipu7
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (39 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 40/44] media: ipu6: Map ipu7 firmware Antti Laakso
@ 2026-08-21 11:42 ` Antti Laakso
2026-08-21 11:43 ` [PATCH v2 42/44] media: ipu6: Add ipu7.5 buttress support Antti Laakso
` (2 subsequent siblings)
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:42 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
We are about to enable support for ipu7 hardware, set model name
accordingly.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-isys.c | 2 +-
drivers/media/pci/intel/ipu6/ipu6.c | 2 ++
drivers/media/pci/intel/ipu6/ipu6.h | 3 +++
3 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 3fb34d2d189c..08f29b678d1b 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -739,7 +739,7 @@ static int isys_register_devices(struct ipu6_isys *isys)
isys->media_dev.dev = dev;
media_device_pci_init(&isys->media_dev,
- pdev, IPU6_MEDIA_DEV_MODEL_NAME);
+ pdev, isys->adev->isp->model_name);
strscpy(isys->v4l2_dev.name, isys->media_dev.model,
sizeof(isys->v4l2_dev.name));
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 93f28ec9a74d..a4fd7333c68b 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -585,6 +585,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
isp->cpd_metadata_cmpnt_size = sizeof(struct ipu6_cpd_metadata_cmpnt);
isp->buttress.regs = &ipu6_buttress_regs;
+ isp->model_name = IPU6_MEDIA_DEV_MODEL_NAME;
isys_ctrl = &ipu6_isys_buttress_ctrl;
psys_ctrl = &ipu6_psys_buttress_ctrl;
@@ -615,6 +616,7 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
case PCI_DEVICE_ID_INTEL_IPU7:
isp->hw_ver = IPU_VERSION_7;
isp->cpd_fw_name = IPU7_FIRMWARE_NAME;
+ isp->model_name = IPU7_MEDIA_DEV_MODEL_NAME;
isp->buttress.regs = &ipu7_buttress_regs;
isys_ctrl = &ipu7_isys_buttress_ctrl;
psys_ctrl = &ipu7_psys_buttress_ctrl;
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index a2992ffe8e3c..8a696caf4b88 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -16,6 +16,8 @@ struct ipu6_bus_device;
#define IPU6_NAME "intel-ipu6"
#define IPU6_MEDIA_DEV_MODEL_NAME "ipu6"
+#define IPU7_MEDIA_DEV_MODEL_NAME "ipu7"
+#define IPU7P5_MEDIA_DEV_MODEL_NAME "ipu7.5"
#define IPU6SE_FIRMWARE_NAME "intel/ipu/ipu6se_fw.bin"
#define IPU6EP_FIRMWARE_NAME "intel/ipu/ipu6ep_fw.bin"
@@ -63,6 +65,7 @@ struct ipu6_device {
const struct firmware *cpd_fw;
const char *cpd_fw_name;
u32 cpd_metadata_cmpnt_size;
+ const char *model_name;
void __iomem *base;
void __iomem *pb_base;
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 42/44] media: ipu6: Add ipu7.5 buttress support
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (40 preceding siblings ...)
2026-08-21 11:42 ` [PATCH v2 41/44] media: ipu6: Set model name for ipu7 Antti Laakso
@ 2026-08-21 11:43 ` Antti Laakso
2026-08-21 11:43 ` [PATCH v2 43/44] media: ipu6: Add ipu7.5 mmu initialization data Antti Laakso
2026-08-21 11:43 ` [PATCH v2 44/44] media: ipu6: Enable ipu7 and ipu7.5 Antti Laakso
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:43 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The ipu7.5 buttress differs from ipu7 slightly,
add support for ipu7.5.
Also set hardware version, firmware and model names
for ipu7.5.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-buttress.c | 53 +++++++++++++++++--
.../intel/ipu6/ipu6-platform-buttress-regs.h | 7 +++
drivers/media/pci/intel/ipu6/ipu6.c | 38 +++++++++++++
drivers/media/pci/intel/ipu6/ipu6.h | 1 +
4 files changed, 94 insertions(+), 5 deletions(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index 74db0a37561e..105de1744dff 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
@@ -3,6 +3,7 @@
* Copyright (C) 2013--2024 Intel Corporation
*/
+#include <asm/cpu_device_id.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/completion.h>
@@ -900,11 +901,30 @@ static int ipu6_buttress_send_tsc_request(struct ipu6_device *isp)
return ret;
}
-int ipu6_buttress_start_tsc_sync(struct ipu6_device *isp)
+static int __ipu7p5_start_tsc_sync(struct ipu6_device *isp)
{
- unsigned int i;
+ u32 val;
+
+ val = readl(isp->base + IPU7_BUTTRESS_REG_TSC_CTL);
+ val |= IPU7_BUTTRESS_SEL_PB_TIMESTAMP;
+ writel(val, isp->base + IPU7_BUTTRESS_REG_TSC_CTL);
+
+ for (unsigned int i = 0; i < BUTTRESS_TSC_SYNC_RESET_TRIAL_MAX; i++) {
+ val = readl(isp->base + IPU7_BUTTRESS_REG_PB_TIMESTAMP_VALID);
+ if (val == 1)
+ return 0;
+
+ usleep_range(40, 50);
+ }
+
+ dev_err(&isp->pdev->dev, "TSC sync failed (timeout)\n");
+
+ return -ETIMEDOUT;
+}
- for (i = 0; i < BUTTRESS_TSC_SYNC_RESET_TRIAL_MAX; i++) {
+static int __ipu6_start_tsc_sync(struct ipu6_device *isp)
+{
+ for (unsigned int i = 0; i < BUTTRESS_TSC_SYNC_RESET_TRIAL_MAX; i++) {
u32 val;
int ret;
@@ -925,6 +945,14 @@ int ipu6_buttress_start_tsc_sync(struct ipu6_device *isp)
return -ETIMEDOUT;
}
+
+int ipu6_buttress_start_tsc_sync(struct ipu6_device *isp)
+{
+ if (IS_IPU7P5(isp))
+ return __ipu7p5_start_tsc_sync(isp);
+
+ return __ipu6_start_tsc_sync(isp);
+}
EXPORT_SYMBOL_NS_GPL(ipu6_buttress_start_tsc_sync, "INTEL_IPU6");
void ipu6_buttress_tsc_read(struct ipu6_device *isp, u64 *val)
@@ -987,6 +1015,13 @@ u32 ipu7_buttress_get_isys_freq(struct ipu6_device *isp)
}
EXPORT_SYMBOL_NS_GPL(ipu7_buttress_get_isys_freq, "INTEL_IPU6");
+static const struct x86_cpu_id ipu7_misc_cfg_exclusion[] = {
+ X86_MATCH_VFM_STEPS(INTEL_PANTHERLAKE_L, 0x1, 0x1, 0),
+ {},
+};
+
+#define IPU7_WRXREQOP_OVRD_VAL_MASK GENMASK(22, 19)
+
static void ipu7_buttress_setup(struct ipu6_device *isp)
{
struct ipu6_buttress *b = &isp->buttress;
@@ -995,12 +1030,20 @@ static void ipu7_buttress_setup(struct ipu6_device *isp)
/* program PB BAR */
writel(0, isp->pb_base + IPU7_GLOBAL_INTERRUPT_MASK);
val = readl(isp->pb_base + IPU7_BAR2_MISC_CONFIG);
+
val |= 0x100U;
+ if (!IS_IPU7_MTL(isp) && !x86_match_cpu(ipu7_misc_cfg_exclusion))
+ val |= FIELD_PREP(IPU7_WRXREQOP_OVRD_VAL_MASK, 0xf) | BIT(18);
writel(val, isp->pb_base + IPU7_BAR2_MISC_CONFIG);
- writel(BIT(22), isp->pb_base + IPU7_TLBID_HASH_ENABLE_63_32);
- writel(BIT(1), isp->pb_base + IPU7_TLBID_HASH_ENABLE_127_96);
+ if (IS_IPU7P5(isp)) {
+ writel(BIT(14), isp->pb_base + IPU7_TLBID_HASH_ENABLE_63_32);
+ writel(BIT(9), isp->pb_base + IPU7_TLBID_HASH_ENABLE_95_64);
+ } else {
+ writel(BIT(22), isp->pb_base + IPU7_TLBID_HASH_ENABLE_63_32);
+ writel(BIT(1), isp->pb_base + IPU7_TLBID_HASH_ENABLE_127_96);
+ }
writel(b->regs->irq_all, isp->base + b->regs->irq_clear);
writel(b->regs->irq_all, isp->base + IPU7_BUTTRESS_REG_IRQ_MASK);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
index c4da72c6bd8f..57e661cc2177 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
@@ -233,6 +233,8 @@ enum {
#define IPU7_BUTTRESS_REG_TSC_CMD 0x2014
#define IPU7_BUTTRESS_REG_TSC_CTL 0x2018
#define IPU7_BUTTRESS_REG_TSC_LO 0x201c
+#define IPU7_BUTTRESS_REG_PB_TIMESTAMP_LO 0x2030
+#define IPU7_BUTTRESS_REG_PB_TIMESTAMP_VALID 0x2038
#define IPU7_BUTTRESS_REG_IS_WORKPOINT_REQ 0x2104
#define IPU7_BUTTRESS_REG_PS_WORKPOINT_REQ 0x2100
#define IPU7_BUTTRESS_REG_IDLE_WDT 0x218c
@@ -319,8 +321,13 @@ enum {
/* PB registers */
#define IPU7_GLOBAL_INTERRUPT_MASK 0x8
+#define IPU7_TLBID_HASH_ENABLE_31_0 0x30
#define IPU7_TLBID_HASH_ENABLE_63_32 0x34
+#define IPU7_TLBID_HASH_ENABLE_95_64 0x38
#define IPU7_TLBID_HASH_ENABLE_127_96 0x3c
#define IPU7_BAR2_MISC_CONFIG 0x64
+/* IPU7.5 */
+#define IPU7_BUTTRESS_SEL_PB_TIMESTAMP BIT(9)
+
#endif /* IPU6_PLATFORM_BUTTRESS_REGS_H */
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index a4fd7333c68b..14cd54da2022 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -197,6 +197,36 @@ static const struct ipu6_buttress_registers ipu7_buttress_regs = {
.irq_sai = IPU7_BUTTRESS_IRQ_SAI_VIOLATION,
};
+static const struct ipu6_buttress_registers ipu7p5_buttress_regs = {
+ /* Registers */
+ .irq_status = IPU7_BUTTRESS_REG_IRQ_STATUS,
+ .irq_clear = IPU7_BUTTRESS_REG_IRQ_CLEAR,
+ .irq_enable = IPU7_BUTTRESS_REG_IRQ_ENABLE,
+ .pwr_status = IPU7_BUTTRESS_REG_PWR_STATUS,
+ .security_ctl = IPU7_BUTTRESS_REG_SECURITY_CTL,
+ .fw_reset_ctl = IPU7_BUTTRESS_REG_FW_RESET_CTL,
+ .fabric_cmd = IPU7_BUTTRESS_REG_TSC_CMD,
+ .tsw_ctl = IPU7_BUTTRESS_REG_TSC_CTL,
+ .tsc_lo = IPU7_BUTTRESS_REG_PB_TIMESTAMP_LO,
+ .wdt = IPU7_BUTTRESS_REG_IDLE_WDT,
+ .csr_in = IPU7_BUTTRESS_REG_CSE2IUCSR,
+ .csr_out = IPU7_BUTTRESS_REG_IU2CSECSR,
+ .db0_in = IPU7_BUTTRESS_REG_CSE2IUDB0,
+ .db0_out = IPU7_BUTTRESS_REG_IU2CSEDB0,
+ .data0_in = IPU7_BUTTRESS_REG_CSE2IUDATA0,
+ .data0_out = IPU7_BUTTRESS_REG_IU2CSEDATA0,
+ .sku_id = IPU7_BUTTRESS_REG_SKU,
+
+ /* Bitmasks */
+ .irq_is = IPU7_BUTTRESS_IRQ_IS_IRQ,
+ .irq_ps = IPU7_BUTTRESS_IRQ_PS_IRQ,
+ .irq_all = IPU7_BUTTRESS_IRQS,
+ .irq_events = IPU7_BUTTRESS_IRQS,
+ .irq_cse_ipc = IPU7_BUTTRESS_IRQ_IPC_FROM_CSE_IS_WAITING,
+ .irq_exec_done = IPU7_BUTTRESS_IRQ_IPC_EXEC_DONE_BY_CSE,
+ .irq_sai = IPU7_BUTTRESS_IRQ_SAI_VIOLATION,
+};
+
static void
ipu6_pkg_dir_configure_spc(struct ipu6_device *isp,
const struct ipu6_hw_variants *hw_variant,
@@ -621,6 +651,14 @@ static int ipu6_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
isys_ctrl = &ipu7_isys_buttress_ctrl;
psys_ctrl = &ipu7_psys_buttress_ctrl;
break;
+ case PCI_DEVICE_ID_INTEL_IPU7P5:
+ isp->hw_ver = IPU_VERSION_7P5;
+ isp->cpd_fw_name = IPU7P5_FIRMWARE_NAME;
+ isp->model_name = IPU7P5_MEDIA_DEV_MODEL_NAME;
+ isp->buttress.regs = &ipu7p5_buttress_regs;
+ isys_ctrl = &ipu7_isys_buttress_ctrl;
+ psys_ctrl = &ipu7_psys_buttress_ctrl;
+ break;
default:
return dev_err_probe(dev, -ENODEV,
"Unsupported IPU6 device %x\n",
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index 8a696caf4b88..72c5063d5198 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -25,6 +25,7 @@ struct ipu6_bus_device;
#define IPU6EPMTL_FIRMWARE_NAME "intel/ipu/ipu6epmtl_fw.bin"
#define IPU6EPADLN_FIRMWARE_NAME "intel/ipu/ipu6epadln_fw.bin"
#define IPU7_FIRMWARE_NAME "intel/ipu/ipu7_fw.bin"
+#define IPU7P5_FIRMWARE_NAME "intel/ipu/ipu7ptl_fw.bin"
#define IPU_VERSION_6 BIT(0) /* TGL */
#define IPU_VERSION_6SE BIT(1) /* JSL */
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 43/44] media: ipu6: Add ipu7.5 mmu initialization data
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (41 preceding siblings ...)
2026-08-21 11:43 ` [PATCH v2 42/44] media: ipu6: Add ipu7.5 buttress support Antti Laakso
@ 2026-08-21 11:43 ` Antti Laakso
2026-08-21 11:43 ` [PATCH v2 44/44] media: ipu6: Enable ipu7 and ipu7.5 Antti Laakso
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:43 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The ipu7.5 mmu is different compared to ipu7.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c | 261 ++++++++++++++++++++-
drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h | 99 ++++++++
2 files changed, 359 insertions(+), 1 deletion(-)
diff --git a/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c
index 3cd9a818733c..c9b015e89ee6 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c
+++ b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c
@@ -431,6 +431,250 @@ static struct ipu7_mmu_hw ipu7_psys_mmu_hwdata[] = {
},
};
+static struct ipu7_mmu_hw ipu7p5_isys_mmu_hwdata[] = {
+ {
+ .name = "IS_FW_RD",
+ .offset = IPU7P5_IS_MMU_FW_RD_OFFSET,
+ .zlx_offset = IPU7P5_IS_ZLX_UC_RD_OFFSET,
+ .uao_offset = IPU7P5_IS_UAO_UC_RD_OFFSET,
+ .info_bits = 0x20005101,
+ .refill = 0x00002726,
+ .collapse_en_bitmap = 0x1,
+ .at_sp_arb_cfg = 0x1,
+ .l1_block = IPU7P5_IS_MMU_FW_RD_L1_BLOCKNR_REG,
+ .l2_block = IPU7P5_IS_MMU_FW_RD_L2_BLOCKNR_REG,
+ .nr_l1streams = IPU7P5_IS_MMU_FW_RD_STREAM_NUM,
+ .nr_l2streams = IPU7P5_IS_MMU_FW_RD_STREAM_NUM,
+ .l1_block_sz = { 0x0, 0x8, 0xa },
+ .l2_block_sz = { 0x0, 0x2, 0x4 },
+ .zlx_nr = IPU7P5_IS_ZLX_UC_RD_NUM,
+ .zlx_axi_pool = { 0x00000f30 },
+ .zlx_en = { 0, 1, 0, 0 },
+ .zlx_conf = { 0x0 },
+ .uao_p_num = IPU7P5_IS_UAO_UC_RD_PLANENUM,
+ .uao_p2tlb = { 0x49, 0x4c, 0x4d, 0x0 },
+ },
+ {
+ .name = "IS_FW_WR",
+ .offset = IPU7P5_IS_MMU_FW_WR_OFFSET,
+ .zlx_offset = IPU7P5_IS_ZLX_UC_WR_OFFSET,
+ .uao_offset = IPU7P5_IS_UAO_UC_WR_OFFSET,
+ .info_bits = 0x20005001,
+ .refill = 0x00002524,
+ .collapse_en_bitmap = 0x1,
+ .at_sp_arb_cfg = 0x1,
+ .l1_block = IPU7P5_IS_MMU_FW_WR_L1_BLOCKNR_REG,
+ .l2_block = IPU7P5_IS_MMU_FW_WR_L2_BLOCKNR_REG,
+ .nr_l1streams = IPU7P5_IS_MMU_FW_WR_STREAM_NUM,
+ .nr_l2streams = IPU7P5_IS_MMU_FW_WR_STREAM_NUM,
+ .l1_block_sz = { 0x0, 0x8, 0xa },
+ .l2_block_sz = { 0x0, 0x2, 0x4 },
+ .zlx_nr = IPU7P5_IS_ZLX_UC_WR_NUM,
+ .zlx_axi_pool = { 0x00000f20 },
+ .zlx_en = { 0, 1, 1, 0 },
+ .zlx_conf = { 0x0, 0x00010101, 0x00010101, 0x0 },
+ .uao_p_num = IPU7P5_IS_UAO_UC_WR_PLANENUM,
+ .uao_p2tlb = { 0x49, 0x4a, 0x4b, 0x0 },
+ },
+ {
+ .name = "IS_DATA_WR_ISOC",
+ .offset = IPU7P5_IS_MMU_M0_OFFSET,
+ .zlx_offset = IPU7P5_IS_ZLX_M0_OFFSET,
+ .uao_offset = IPU7P5_IS_UAO_M0_WR_OFFSET,
+ .info_bits = 0x20004e01,
+ .refill = 0x00002120,
+ .collapse_en_bitmap = 0x1,
+ .at_sp_arb_cfg = 0x1,
+ .l1_block = IPU7P5_IS_MMU_M0_L1_BLOCKNR_REG,
+ .l2_block = IPU7P5_IS_MMU_M0_L2_BLOCKNR_REG,
+ .nr_l1streams = IPU7P5_IS_MMU_M0_STREAM_NUM,
+ .nr_l2streams = IPU7P5_IS_MMU_M0_STREAM_NUM,
+ .l1_block_sz = { 0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10,
+ 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x01e },
+ .l2_block_sz = { 0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10,
+ 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e },
+ .zlx_nr = IPU7P5_IS_ZLX_M0_NUM,
+ .zlx_axi_pool = { 0x00000f10 },
+ .zlx_en = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ .zlx_conf = { 0x00010103, 0x00010103, 0x00010103, 0x00010103,
+ 0x00010103, 0x00010103, 0x00010103, 0x00010103,
+ 0x00010103, 0x00010103, 0x00010103, 0x00010103,
+ 0x00010103, 0x00010103, 0x00010103, 0x00010103 },
+ .uao_p_num = IPU7P5_IS_UAO_M0_WR_PLANENUM,
+ .uao_p2tlb = { 0x00000041, 0x00000042, 0x00000043, 0x00000044,
+ 0x00000041, 0x00000042, 0x00000043, 0x00000044,
+ 0x00000041, 0x00000042, 0x00000043, 0x00000044,
+ 0x00000041, 0x00000042, 0x00000043, 0x00000044 },
+ },
+ {
+ .name = "IS_DATA_WR_SNOOP",
+ .offset = IPU7P5_IS_MMU_M1_OFFSET,
+ .zlx_offset = IPU7P5_IS_ZLX_M1_OFFSET,
+ .uao_offset = IPU7P5_IS_UAO_M1_WR_OFFSET,
+ .info_bits = 0x20004f01,
+ .refill = 0x00002322,
+ .collapse_en_bitmap = 0x1,
+ .at_sp_arb_cfg = 0x1,
+ .l1_block = IPU7P5_IS_MMU_M1_L1_BLOCKNR_REG,
+ .l2_block = IPU7P5_IS_MMU_M1_L2_BLOCKNR_REG,
+ .nr_l1streams = IPU7P5_IS_MMU_M1_STREAM_NUM,
+ .nr_l2streams = IPU7P5_IS_MMU_M1_STREAM_NUM,
+ .l1_block_sz = { 0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10,
+ 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e },
+ .l2_block_sz = { 0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10,
+ 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e },
+ .zlx_nr = IPU7P5_IS_ZLX_M1_NUM,
+ .zlx_axi_pool = { 0x00000f20 },
+ .zlx_en = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
+ .zlx_conf = { 0x00010103, 0x00010103, 0x00010103, 0x00010103,
+ 0x00010103, 0x00010103, 0x00010103, 0x00010103,
+ 0x00010103, 0x00010103, 0x00010103, 0x00010103,
+ 0x00010103, 0x00010103, 0x00010103, 0x00010103 },
+ .uao_p_num = IPU7P5_IS_UAO_M1_WR_PLANENUM,
+ .uao_p2tlb = { 0x00000045, 0x00000046, 0x00000047, 0x00000048,
+ 0x00000045, 0x00000046, 0x00000047, 0x00000048,
+ 0x00000045, 0x00000046, 0x00000047, 0x00000048,
+ 0x00000045, 0x00000046, 0x00000047, 0x00000048 },
+ },
+};
+
+static struct ipu7_mmu_hw ipu7p5_psys_mmu_hwdata[] = {
+ {
+ .name = "PS_FW_RD",
+ .offset = IPU7P5_PS_MMU_FW_RD_OFFSET,
+ .zlx_offset = IPU7P5_PS_ZLX_FW_RD_OFFSET,
+ .uao_offset = IPU7P5_PS_UAO_FW_RD_OFFSET,
+ .info_bits = 0x20004001,
+ .refill = 0x00002726,
+ .collapse_en_bitmap = 0x1,
+ .at_sp_arb_cfg = 0x1,
+ .l1_block = IPU7P5_PS_MMU_FW_RD_L1_BLOCKNR_REG,
+ .l2_block = IPU7P5_PS_MMU_FW_RD_L2_BLOCKNR_REG,
+ .nr_l1streams = IPU7P5_PS_MMU_FW_RD_STREAM_NUM,
+ .nr_l2streams = IPU7P5_PS_MMU_FW_RD_STREAM_NUM,
+ .l1_block_sz = { 0x00, 0x08, 0x0a, 0x0c, 0x0d, 0x0f, 0x11,
+ 0x12, 0x13, 0x14, 0x16, 0x18, 0x19, 0x1a,
+ 0x1a, 0x1a },
+ .l2_block_sz = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c,
+ 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a,
+ 0x1c, 0x1e },
+ .zlx_nr = IPU7P5_PS_ZLX_FW_RD_NUM,
+ .zlx_axi_pool = { 0x00000f30 },
+ .zlx_en = { 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
+ .zlx_conf = { 0x00000000, 0x00010101, 0x00000000, 0x00000000,
+ 0x00010101, 0x00010101, 0x00000000, 0x00000000,
+ 0x00000000, 0x00010101, 0x00010101, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ .uao_p_num = IPU7P5_PS_UAO_FW_RD_PLANENUM,
+ .uao_p2tlb = { 0x2e, 0x35, 0x36, 0x31, 0x37, 0x38, 0x39, 0x32,
+ 0x33, 0x3a, 0x3b, 0x3c, 0x34, 0x00, 0x00, 0x00 },
+ },
+ {
+ .name = "PS_FW_WR",
+ .offset = IPU7P5_PS_MMU_FW_WR_OFFSET,
+ .zlx_offset = IPU7P5_PS_ZLX_FW_WR_OFFSET,
+ .uao_offset = IPU7P5_PS_UAO_FW_WR_OFFSET,
+ .info_bits = 0x20003e01,
+ .refill = 0x00002322,
+ .collapse_en_bitmap = 0x1,
+ .at_sp_arb_cfg = 0x1,
+ .l1_block = IPU7P5_PS_MMU_FW_WR_L1_BLOCKNR_REG,
+ .l2_block = IPU7P5_PS_MMU_FW_WR_L2_BLOCKNR_REG,
+ .nr_l1streams = IPU7P5_PS_MMU_FW_WR_STREAM_NUM,
+ .nr_l2streams = IPU7P5_PS_MMU_FW_WR_STREAM_NUM,
+ .l1_block_sz = { 0x00, 0x08, 0x0a, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x10, 0x10 },
+ .l2_block_sz = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
+ 0x10, 0x12 },
+ .zlx_nr = IPU7P5_PS_ZLX_FW_WR_NUM,
+ .zlx_axi_pool = { 0x00000f20 },
+ .zlx_en = { 0, 1, 1, 0, 0, 0, 0, 0, 0, 0 },
+ .zlx_conf = { 0x00000000, 0x00010101, 0x00010101, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000 },
+ .uao_p_num = IPU7P5_PS_UAO_FW_WR_PLANENUM,
+ .uao_p2tlb = { 0x0000002e, 0x0000002f, 0x00000030, 0x00000031,
+ 0x00000032, 0x00000033, 0x00000034, 0x00000000,
+ 0x00000000, 0x00000000 },
+ },
+ {
+ .name = "PS_DATA_RD",
+ .offset = IPU7P5_PS_MMU_SRT_RD_OFFSET,
+ .zlx_offset = IPU7P5_PS_ZLX_DATA_RD_OFFSET,
+ .uao_offset = IPU7P5_PS_UAO_SRT_RD_OFFSET,
+ .info_bits = 0x20003f01,
+ .refill = 0x00002524,
+ .collapse_en_bitmap = 0x1,
+ .at_sp_arb_cfg = 0x1,
+ .l1_block = IPU7P5_PS_MMU_SRT_RD_L1_BLOCKNR_REG,
+ .l2_block = IPU7P5_PS_MMU_SRT_RD_L2_BLOCKNR_REG,
+ .nr_l1streams = IPU7P5_PS_MMU_SRT_RD_STREAM_NUM,
+ .nr_l2streams = IPU7P5_PS_MMU_SRT_RD_STREAM_NUM,
+ .l1_block_sz = { 0x00, 0x04, 0x06, 0x08, 0x0b, 0x0d, 0x0f, 0x13,
+ 0x17, 0x19, 0x1b, 0x1d, 0x1f, 0x2b, 0x33, 0x3f,
+ 0x47, 0x49, 0x4b, 0x4c, 0x4d, 0x4e },
+ .l2_block_sz = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
+ 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
+ 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a },
+ .zlx_nr = IPU7P5_PS_ZLX_DATA_RD_NUM,
+ .zlx_axi_pool = { 0x00000f30 },
+ .zlx_en = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 0, 0, 0, 0 },
+ .zlx_conf = { 0x00030303, 0x00010101, 0x00010101, 0x00030202,
+ 0x00010101, 0x00010101, 0x00030303, 0x00030303,
+ 0x00010101, 0x00030800, 0x00030500, 0x00020101,
+ 0x00042000, 0x00031000, 0x00042000, 0x00031000,
+ 0x00020400, 0x00010101, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000 },
+ .uao_p_num = IPU7P5_PS_UAO_SRT_RD_PLANENUM,
+ .uao_p2tlb = { 0x0000001c, 0x0000001d, 0x0000001e, 0x0000001f,
+ 0x00000020, 0x00000021, 0x00000022, 0x00000023,
+ 0x00000024, 0x00000025, 0x00000026, 0x00000027,
+ 0x00000028, 0x00000029, 0x0000002a, 0x0000002b,
+ 0x0000002c, 0x0000002d, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000 },
+ },
+ {
+ .name = "PS_DATA_WR",
+ .offset = IPU7P5_PS_MMU_SRT_WR_OFFSET,
+ .zlx_offset = IPU7P5_PS_ZLX_DATA_WR_OFFSET,
+ .uao_offset = IPU7P5_PS_UAO_SRT_WR_OFFSET,
+ .info_bits = 0x20003d01,
+ .refill = 0x00002120,
+ .collapse_en_bitmap = 0x1,
+ .at_sp_arb_cfg = 0x1,
+ .l1_block = IPU7P5_PS_MMU_SRT_WR_L1_BLOCKNR_REG,
+ .l2_block = IPU7P5_PS_MMU_SRT_WR_L2_BLOCKNR_REG,
+ .nr_l1streams = IPU7P5_PS_MMU_SRT_WR_STREAM_NUM,
+ .nr_l2streams = IPU7P5_PS_MMU_SRT_WR_STREAM_NUM,
+ .l1_block_sz = { 0x00, 0x02, 0x06, 0x0a, 0x0c, 0x0e, 0x10, 0x12,
+ 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22,
+ 0x24, 0x28, 0x2a, 0x36, 0x3e, 0x40, 0x42, 0x4e,
+ 0x56, 0x5c, 0x68, 0x70, 0x76, 0x77, 0x78, 0x79 },
+ .l2_block_sz = { 0x00, 0x02, 0x06, 0x0a, 0x0c, 0x0e, 0x10, 0x12,
+ 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22,
+ 0x24, 0x28, 0x2a, 0x36, 0x3e, 0x40, 0x42, 0x4e,
+ 0x56, 0x5c, 0x68, 0x70, 0x76, 0x77, 0x78, 0x79 },
+ .zlx_nr = IPU7P5_PS_ZLX_DATA_WR_NUM,
+ .zlx_axi_pool = { 0x00000f50 },
+ .zlx_en = { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
+ .zlx_conf = { 0x00010102, 0x00030103, 0x00030103, 0x00010101,
+ 0x00010101, 0x00030101, 0x00010101, 0x38010101,
+ 0x00000000, 0x00000000, 0x38010101, 0x38010101,
+ 0x38010101, 0x38010101, 0x38010101, 0x38010101,
+ 0x00030303, 0x00010101, 0x00042000, 0x00031000,
+ 0x00010101, 0x00010101, 0x00042000, 0x00031000,
+ 0x00031000, 0x00042000, 0x00031000, 0x00031000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+ .uao_p_num = IPU7P5_PS_UAO_SRT_WR_PLANENUM,
+ .uao_p2tlb = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x00, 0x00, 0x00, 0x00 },
+ },
+};
+
static const struct ipu7_mmu_hwdata ipu7_mmu_hwdata_lookup[IPU_SUBSYS_NUM] = {
[IPU_PSYS] = {
.hwdata = ipu7_psys_mmu_hwdata,
@@ -442,6 +686,17 @@ static const struct ipu7_mmu_hwdata ipu7_mmu_hwdata_lookup[IPU_SUBSYS_NUM] = {
},
};
+static const struct ipu7_mmu_hwdata ipu7p5_mmu_hwdata_lookup[IPU_SUBSYS_NUM] = {
+ [IPU_PSYS] = {
+ .hwdata = ipu7p5_psys_mmu_hwdata,
+ .nr_mmus = ARRAY_SIZE(ipu7p5_psys_mmu_hwdata),
+ },
+ [IPU_ISYS] = {
+ .hwdata = ipu7p5_isys_mmu_hwdata,
+ .nr_mmus = ARRAY_SIZE(ipu7p5_isys_mmu_hwdata),
+ },
+};
+
static void __ipu7_tlb_invalidate(struct ipu6_mmu *mmu)
{
struct ipu7_mmu_hw *mmu_hw = mmu->ipu7_mmu_hw;
@@ -561,13 +816,17 @@ static int __ipu7_mmu_hw_init(struct ipu6_mmu *mmu)
static int __ipu7_mmu_init_hw_data(struct ipu6_mmu *mmu, struct device *dev,
void __iomem *base)
{
- const struct ipu7_mmu_hwdata *lookup = ipu7_mmu_hwdata_lookup;
+ struct ipu6_device *isp = pci_get_drvdata(to_pci_dev(dev));
+ const struct ipu7_mmu_hwdata *lookup;
struct ipu7_mmu_hw *mmu_hw, *src;
unsigned int i, nr_mmus;
if (mmu->mmid >= IPU_SUBSYS_NUM)
return -EINVAL;
+ lookup = IS_IPU7P5(isp) ? ipu7p5_mmu_hwdata_lookup :
+ ipu7_mmu_hwdata_lookup;
+
src = lookup[mmu->mmid].hwdata;
nr_mmus = lookup[mmu->mmid].nr_mmus;
diff --git a/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h
index 68663057138a..ba31ed31b245 100644
--- a/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h
+++ b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h
@@ -114,6 +114,105 @@
#define IPU7_PS_ZLX_FW_RD_NUM 16
#define IPU7_PS_ZLX_FW_WR_NUM 10
+/* IPU7P5 */
+/* IS MMU Cmd RD */
+#define IPU7P5_IS_MMU_FW_RD_OFFSET 0x274000
+#define IPU7P5_IS_MMU_FW_RD_STREAM_NUM 3
+#define IPU7P5_IS_MMU_FW_RD_L1_BLOCKNR_REG 0x54
+#define IPU7P5_IS_MMU_FW_RD_L2_BLOCKNR_REG 0x60
+
+/* IS MMU Cmd WR */
+#define IPU7P5_IS_MMU_FW_WR_OFFSET 0x275000
+#define IPU7P5_IS_MMU_FW_WR_STREAM_NUM 3
+#define IPU7P5_IS_MMU_FW_WR_L1_BLOCKNR_REG 0x54
+#define IPU7P5_IS_MMU_FW_WR_L2_BLOCKNR_REG 0x60
+
+/* IS MMU Data WR Snoop */
+#define IPU7P5_IS_MMU_M0_OFFSET 0x276000
+#define IPU7P5_IS_MMU_M0_STREAM_NUM 16
+#define IPU7P5_IS_MMU_M0_L1_BLOCKNR_REG 0x54
+#define IPU7P5_IS_MMU_M0_L2_BLOCKNR_REG 0x94
+
+/* IS MMU Data WR ISOC */
+#define IPU7P5_IS_MMU_M1_OFFSET 0x277000
+#define IPU7P5_IS_MMU_M1_STREAM_NUM 16
+#define IPU7P5_IS_MMU_M1_L1_BLOCKNR_REG 0x54
+#define IPU7P5_IS_MMU_M1_L2_BLOCKNR_REG 0x94
+
+/* PS MMU FW RD */
+#define IPU7P5_PS_MMU_FW_RD_OFFSET 0x148000
+#define IPU7P5_PS_MMU_FW_RD_STREAM_NUM 16
+#define IPU7P5_PS_MMU_FW_RD_L1_BLOCKNR_REG 0x54
+#define IPU7P5_PS_MMU_FW_RD_L2_BLOCKNR_REG 0x94
+
+/* PS MMU FW WR */
+#define IPU7P5_PS_MMU_FW_WR_OFFSET 0x149000
+#define IPU7P5_PS_MMU_FW_WR_STREAM_NUM 10
+#define IPU7P5_PS_MMU_FW_WR_L1_BLOCKNR_REG 0x54
+#define IPU7P5_PS_MMU_FW_WR_L2_BLOCKNR_REG 0x7c
+
+/* PS MMU FW Data RD VC0 */
+#define IPU7P5_PS_MMU_SRT_RD_OFFSET 0x14a000
+#define IPU7P5_PS_MMU_SRT_RD_STREAM_NUM 22
+#define IPU7P5_PS_MMU_SRT_RD_L1_BLOCKNR_REG 0x54
+#define IPU7P5_PS_MMU_SRT_RD_L2_BLOCKNR_REG 0xac
+
+/* PS MMU FW Data WR VC0 */
+#define IPU7P5_PS_MMU_SRT_WR_OFFSET 0x14b000
+#define IPU7P5_PS_MMU_SRT_WR_STREAM_NUM 32
+#define IPU7P5_PS_MMU_SRT_WR_L1_BLOCKNR_REG 0x54
+#define IPU7P5_PS_MMU_SRT_WR_L2_BLOCKNR_REG 0xd4
+
+/* IS UAO UC RD */
+#define IPU7P5_IS_UAO_UC_RD_OFFSET 0x27c000
+#define IPU7P5_IS_UAO_UC_RD_PLANENUM 4
+
+/* IS UAO UC WR */
+#define IPU7P5_IS_UAO_UC_WR_OFFSET 0x27d000
+#define IPU7P5_IS_UAO_UC_WR_PLANENUM 4
+
+/* IS UAO M0 WR */
+#define IPU7P5_IS_UAO_M0_WR_OFFSET 0x27e000
+#define IPU7P5_IS_UAO_M0_WR_PLANENUM 16
+
+/* IS UAO M1 WR */
+#define IPU7P5_IS_UAO_M1_WR_OFFSET 0x27f000
+#define IPU7P5_IS_UAO_M1_WR_PLANENUM 16
+
+/* PS UAO FW RD */
+#define IPU7P5_PS_UAO_FW_RD_OFFSET 0x156000
+#define IPU7P5_PS_UAO_FW_RD_PLANENUM 16
+
+/* PS UAO FW WR */
+#define IPU7P5_PS_UAO_FW_WR_OFFSET 0x157000
+#define IPU7P5_PS_UAO_FW_WR_PLANENUM 10
+
+/* PS UAO SRT RD */
+#define IPU7P5_PS_UAO_SRT_RD_OFFSET 0x154000
+#define IPU7P5_PS_UAO_SRT_RD_PLANENUM 22
+
+/* PS UAO SRT WR */
+#define IPU7P5_PS_UAO_SRT_WR_OFFSET 0x155000
+#define IPU7P5_PS_UAO_SRT_WR_PLANENUM 32
+
+#define IPU7P5_IS_ZLX_UC_RD_OFFSET 0x278000
+#define IPU7P5_IS_ZLX_UC_WR_OFFSET 0x279000
+#define IPU7P5_IS_ZLX_M0_OFFSET 0x27a000
+#define IPU7P5_IS_ZLX_M1_OFFSET 0x27b000
+#define IPU7P5_IS_ZLX_UC_RD_NUM 4
+#define IPU7P5_IS_ZLX_UC_WR_NUM 4
+#define IPU7P5_IS_ZLX_M0_NUM 16
+#define IPU7P5_IS_ZLX_M1_NUM 16
+
+#define IPU7P5_PS_ZLX_DATA_RD_OFFSET 0x14e000
+#define IPU7P5_PS_ZLX_DATA_WR_OFFSET 0x14f000
+#define IPU7P5_PS_ZLX_FW_RD_OFFSET 0x150000
+#define IPU7P5_PS_ZLX_FW_WR_OFFSET 0x151000
+#define IPU7P5_PS_ZLX_DATA_RD_NUM 22
+#define IPU7P5_PS_ZLX_DATA_WR_NUM 32
+#define IPU7P5_PS_ZLX_FW_RD_NUM 16
+#define IPU7P5_PS_ZLX_FW_WR_NUM 10
+
struct ipu7_mmu_hw {
char name[32];
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread* [PATCH v2 44/44] media: ipu6: Enable ipu7 and ipu7.5
2026-08-21 11:42 [PATCH v2 00/44] media: ipu6: Add support for ipu7 hardware Antti Laakso
` (42 preceding siblings ...)
2026-08-21 11:43 ` [PATCH v2 43/44] media: ipu6: Add ipu7.5 mmu initialization data Antti Laakso
@ 2026-08-21 11:43 ` Antti Laakso
43 siblings, 0 replies; 47+ messages in thread
From: Antti Laakso @ 2026-08-21 11:43 UTC (permalink / raw)
To: linux-media, mchehab, sakari.ailus; +Cc: daxing.li, ong.hock.yu, antti.laakso
The driver have now support for ipu7 and 7.5.
Signed-off-by: Antti Laakso <antti.laakso@linux.intel.com>
---
include/media/ipu6-pci-table.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/include/media/ipu6-pci-table.h b/include/media/ipu6-pci-table.h
index cd5b941fb96c..cacb8a3170d0 100644
--- a/include/media/ipu6-pci-table.h
+++ b/include/media/ipu6-pci-table.h
@@ -24,6 +24,8 @@ static const struct pci_device_id ipu6_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU6EP_ADLN) },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU6EP_RPLP) },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU6EP_MTL) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU7) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IPU7P5) },
{ }
};
--
2.55.0
^ permalink raw reply related [flat|nested] 47+ messages in thread