summaryrefslogtreecommitdiff
path: root/drivers/media/pci
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/pci')
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c8
-rw-r--r--drivers/media/pci/cobalt/cobalt-driver.c8
-rw-r--r--drivers/media/pci/cobalt/cobalt-v4l2.c10
-rw-r--r--drivers/media/pci/cx18/cx18-av-core.c1
-rw-r--r--drivers/media/pci/cx18/cx18-controls.c2
-rw-r--r--drivers/media/pci/cx18/cx18-driver.c9
-rw-r--r--drivers/media/pci/cx18/cx18-ioctl.c2
-rw-r--r--drivers/media/pci/cx18/cx18-queue.c5
-rw-r--r--drivers/media/pci/cx18/cx23418.h2
-rw-r--r--drivers/media/pci/cx23885/cx23885-core.c4
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c14
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c4
-rw-r--r--drivers/media/pci/cx88/cx88-input.c22
-rw-r--r--drivers/media/pci/cx88/cx88-mpeg.c9
-rw-r--r--drivers/media/pci/cx88/cx88-video.c8
-rw-r--r--drivers/media/pci/hws/hws.h4
-rw-r--r--drivers/media/pci/hws/hws_pci.c6
-rw-r--r--drivers/media/pci/hws/hws_reg.h10
-rw-r--r--drivers/media/pci/hws/hws_v4l2_ioctl.c5
-rw-r--r--drivers/media/pci/hws/hws_video.c6
-rw-r--r--drivers/media/pci/intel/ipu-bridge.c148
-rw-r--r--drivers/media/pci/intel/ipu3/ipu3-cio2.c1
-rw-r--r--drivers/media/pci/intel/ipu6/Kconfig9
-rw-r--r--drivers/media/pci/intel/ipu6/Makefile10
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-bus.h6
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-buttress.c568
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-buttress.h50
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-cpd.c195
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-cpd.h43
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-dma.c24
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-dma.h2
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-fw-isys.c586
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-fw-isys.h48
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c576
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h18
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys-queue.c215
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys-queue.h6
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys-subdev.c23
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys-subdev.h3
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys-video.c750
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys-video.h62
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys.c605
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys.h105
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-mmu-hw.c296
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-mmu.c133
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-mmu.h158
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h111
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6.c556
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6.h200
-rw-r--r--drivers/media/pci/intel/ipu6/ipu7-boot.c405
-rw-r--r--drivers/media/pci/intel/ipu6/ipu7-boot.h46
-rw-r--r--drivers/media/pci/intel/ipu6/ipu7-fw-com.c74
-rw-r--r--drivers/media/pci/intel/ipu6/ipu7-fw-com.h53
-rw-r--r--drivers/media/pci/intel/ipu6/ipu7-fw-isys.c796
-rw-r--r--drivers/media/pci/intel/ipu6/ipu7-fw-isys.h296
-rw-r--r--drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.c1072
-rw-r--r--drivers/media/pci/intel/ipu6/ipu7-isys-csi-phy.h16
-rw-r--r--drivers/media/pci/intel/ipu6/ipu7-isys-csi2-regs.h1189
-rw-r--r--drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c858
-rw-r--r--drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h254
-rw-r--r--drivers/media/pci/intel/ipu6/ipu7-platform-regs.h32
-rw-r--r--drivers/media/pci/intel/ivsc/mei_ace.c4
-rw-r--r--drivers/media/pci/intel/ivsc/mei_csi.c8
-rw-r--r--drivers/media/pci/ivtv/ivtv-controls.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-ioctl.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c8
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c4
-rw-r--r--drivers/media/pci/saa7134/saa7134-input.c7
-rw-r--r--drivers/media/pci/saa7146/mxb.c4
-rw-r--r--drivers/media/pci/saa7164/saa7164-core.c32
-rw-r--r--drivers/media/pci/saa7164/saa7164.h1
-rw-r--r--drivers/media/pci/tw68/tw68-core.c10
72 files changed, 8480 insertions, 2339 deletions
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index c631b8bbd386..8b9ca59f9434 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -3504,7 +3504,7 @@ static void bttv_remove(struct pci_dev *pci_dev)
return;
}
-static int __maybe_unused bttv_suspend(struct device *dev)
+static int bttv_suspend(struct device *dev)
{
struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
struct bttv *btv = to_bttv(v4l2_dev);
@@ -3535,7 +3535,7 @@ static int __maybe_unused bttv_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused bttv_resume(struct device *dev)
+static int bttv_resume(struct device *dev)
{
struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
struct bttv *btv = to_bttv(v4l2_dev);
@@ -3573,7 +3573,7 @@ static const struct pci_device_id bttv_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, bttv_pci_tbl);
-static SIMPLE_DEV_PM_OPS(bttv_pm_ops,
+static DEFINE_SIMPLE_DEV_PM_OPS(bttv_pm_ops,
bttv_suspend,
bttv_resume);
@@ -3582,7 +3582,7 @@ static struct pci_driver bttv_pci_driver = {
.id_table = bttv_pci_tbl,
.probe = bttv_probe,
.remove = bttv_remove,
- .driver.pm = &bttv_pm_ops,
+ .driver.pm = pm_sleep_ptr(&bttv_pm_ops),
};
static int __init bttv_init_module(void)
diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c
index 7b1ca1238c8d..ca96cbe4f194 100644
--- a/drivers/media/pci/cobalt/cobalt-driver.c
+++ b/drivers/media/pci/cobalt/cobalt-driver.c
@@ -524,8 +524,8 @@ static int cobalt_subdevs_init(struct cobalt *cobalt)
&cobalt_edid);
if (err)
return err;
- err = v4l2_subdev_call(s[i].sd, pad, set_fmt, NULL,
- &sd_fmt);
+ err = v4l2_subdev_call(s[i].sd, pad, set_fmt, NULL, NULL,
+ &sd_fmt);
if (err)
return err;
/* Reset channel video module */
@@ -608,8 +608,8 @@ static int cobalt_subdevs_hsma_init(struct cobalt *cobalt)
if (err)
return err;
- err = v4l2_subdev_call(s->sd, pad, set_fmt, NULL,
- &sd_fmt);
+ err = v4l2_subdev_call(s->sd, pad, set_fmt, NULL, NULL,
+ &sd_fmt);
if (err)
return err;
cobalt->have_hsma_rx = true;
diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c
index 51fd9576c6c2..ad89e62a2747 100644
--- a/drivers/media/pci/cobalt/cobalt-v4l2.c
+++ b/drivers/media/pci/cobalt/cobalt-v4l2.c
@@ -172,7 +172,7 @@ static void cobalt_enable_output(struct cobalt_stream *s)
sd_fmt.format.code = MEDIA_BUS_FMT_RGB888_1X24;
break;
}
- v4l2_subdev_call(s->sd, pad, set_fmt, NULL, &sd_fmt);
+ v4l2_subdev_call(s->sd, pad, set_fmt, NULL, NULL, &sd_fmt);
iowrite32(0, &vo->control);
/* 1080p60 */
@@ -223,14 +223,14 @@ static void cobalt_enable_input(struct cobalt_stream *s)
iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK |
(1 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST),
&packer->control);
- v4l2_subdev_call(s->sd, pad, set_fmt, NULL,
+ v4l2_subdev_call(s->sd, pad, set_fmt, NULL, NULL,
&sd_fmt_yuyv);
break;
case V4L2_PIX_FMT_RGB24:
iowrite32(M00235_CONTROL_BITMAP_ENABLE_MSK |
(2 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST),
&packer->control);
- v4l2_subdev_call(s->sd, pad, set_fmt, NULL,
+ v4l2_subdev_call(s->sd, pad, set_fmt, NULL, NULL,
&sd_fmt_rgb);
break;
case V4L2_PIX_FMT_BGR32:
@@ -238,7 +238,7 @@ static void cobalt_enable_input(struct cobalt_stream *s)
M00235_CONTROL_BITMAP_ENDIAN_FORMAT_MSK |
(3 << M00235_CONTROL_BITMAP_PACK_FORMAT_OFST),
&packer->control);
- v4l2_subdev_call(s->sd, pad, set_fmt, NULL,
+ v4l2_subdev_call(s->sd, pad, set_fmt, NULL, NULL,
&sd_fmt_rgb);
break;
}
@@ -938,7 +938,7 @@ static int cobalt_s_fmt_vid_out(struct file *file, void *priv,
s->ycbcr_enc = pix->ycbcr_enc;
s->quantization = pix->quantization;
v4l2_fill_mbus_format(&sd_fmt.format, pix, code);
- v4l2_subdev_call(s->sd, pad, set_fmt, NULL, &sd_fmt);
+ v4l2_subdev_call(s->sd, pad, set_fmt, NULL, NULL, &sd_fmt);
return 0;
}
diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c
index 4fb19d26ee29..f5961853eeae 100644
--- a/drivers/media/pci/cx18/cx18-av-core.c
+++ b/drivers/media/pci/cx18/cx18-av-core.c
@@ -930,6 +930,7 @@ static int cx18_av_s_ctrl(struct v4l2_ctrl *ctrl)
}
static int cx18_av_set_fmt(struct v4l2_subdev *sd,
+ const struct v4l2_subdev_client_info *ci,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
diff --git a/drivers/media/pci/cx18/cx18-controls.c b/drivers/media/pci/cx18/cx18-controls.c
index 78eadad8b6e8..41f388ba22ab 100644
--- a/drivers/media/pci/cx18/cx18-controls.c
+++ b/drivers/media/pci/cx18/cx18-controls.c
@@ -85,7 +85,7 @@ static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
fmt->width = cxhdl->width / (is_mpeg1 ? 2 : 1);
fmt->height = cxhdl->height;
fmt->code = MEDIA_BUS_FMT_FIXED;
- v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, &format);
+ v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, NULL, &format);
return 0;
}
diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c
index 214fac7af61e..ac90ce6cd044 100644
--- a/drivers/media/pci/cx18/cx18-driver.c
+++ b/drivers/media/pci/cx18/cx18-driver.c
@@ -805,12 +805,12 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
}
if (dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(32))) {
CX18_ERR("No suitable DMA available, card %d\n", cx->instance);
- return -EIO;
+ goto err_disable_device;
}
if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) {
CX18_ERR("Cannot request encoder memory region, card %d\n",
cx->instance);
- return -EIO;
+ goto err_disable_device;
}
/* Enable bus mastering and memory mapped IO for the CX23418 */
@@ -834,6 +834,10 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev,
cx->pci_dev->irq, pci_latency, (u64)cx->base_addr);
return 0;
+
+err_disable_device:
+ pci_disable_device(pci_dev);
+ return -EIO;
}
static void cx18_init_subdevs(struct cx18 *cx)
@@ -1120,6 +1124,7 @@ free_map:
cx18_iounmap(cx);
free_mem:
release_mem_region(cx->base_addr, CX18_MEM_SIZE);
+ pci_disable_device(pci_dev);
free_workqueues:
destroy_workqueue(cx->in_work_queue);
err:
diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c
index 0d676a57e24e..6f8d7f700016 100644
--- a/drivers/media/pci/cx18/cx18-ioctl.c
+++ b/drivers/media/pci/cx18/cx18-ioctl.c
@@ -150,7 +150,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
format.format.width = cx->cxhdl.width = w;
format.format.height = cx->cxhdl.height = h;
format.format.code = MEDIA_BUS_FMT_FIXED;
- v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, &format);
+ v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, NULL, &format);
return cx18_g_fmt_vid_cap(file, fh, fmt);
}
diff --git a/drivers/media/pci/cx18/cx18-queue.c b/drivers/media/pci/cx18/cx18-queue.c
index 04d6828f0259..a973367d4cde 100644
--- a/drivers/media/pci/cx18/cx18-queue.c
+++ b/drivers/media/pci/cx18/cx18-queue.c
@@ -114,7 +114,10 @@ static inline void cx18_mdl_update_bufs_for_cpu(struct cx18_stream *s,
if (list_is_singular(&mdl->buf_list)) {
buf = list_first_entry(&mdl->buf_list, struct cx18_buffer,
list);
- buf->bytesused = mdl->bytesused;
+ if (mdl->bytesused > s->buf_size)
+ buf->bytesused = s->buf_size;
+ else
+ buf->bytesused = mdl->bytesused;
buf->readpos = 0;
cx18_buf_sync_for_cpu(s, buf);
} else {
diff --git a/drivers/media/pci/cx18/cx23418.h b/drivers/media/pci/cx18/cx23418.h
index 22486f39bcda..4ee45be757cb 100644
--- a/drivers/media/pci/cx18/cx23418.h
+++ b/drivers/media/pci/cx18/cx23418.h
@@ -24,7 +24,7 @@
#define CX18_CREATE_TASK (MGR_CMD_MASK | 0x0001)
/* Description: This command destroys an instance of a task
- IN[0] - Task handle. Hanlde of the task to destroy
+ IN[0] - Task handle. Handle of the task to destroy
ReturnCode - One of the ERR_SYS_... */
#define CX18_DESTROY_TASK (MGR_CMD_MASK | 0x0002)
diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
index 5fb26285e4af..7498091176b7 100644
--- a/drivers/media/pci/cx23885/cx23885-core.c
+++ b/drivers/media/pci/cx23885/cx23885-core.c
@@ -2246,6 +2246,10 @@ static void cx23885_finidev(struct pci_dev *pci_dev)
/* unregister stuff */
free_irq(pci_dev->irq, dev);
+ cancel_work_sync(&dev->cx25840_work);
+ cancel_work_sync(&dev->ir_rx_work);
+ cancel_work_sync(&dev->ir_tx_work);
+
pci_disable_device(pci_dev);
cx23885_dev_unregister(dev);
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index f240ccda40ed..348abde0ba26 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -1158,8 +1158,12 @@ static int dvb_register_ci_mac(struct cx23885_tsport *port)
info.platform_data = &sp2_config;
request_module(info.type);
client_ci = i2c_new_client_device(&i2c_bus->i2c_adap, &info);
- if (!i2c_client_has_driver(client_ci))
+ if (IS_ERR(client_ci))
+ return PTR_ERR(client_ci);
+ if (!client_ci->dev.driver) {
+ i2c_unregister_device(client_ci);
return -ENODEV;
+ }
if (!try_module_get(client_ci->dev.driver->owner)) {
i2c_unregister_device(client_ci);
return -ENODEV;
@@ -1202,7 +1206,7 @@ static int dvb_register(struct cx23885_tsport *port)
int (*p_set_voltage)(struct dvb_frontend *fe,
enum fe_sec_voltage voltage) = NULL;
int mfe_shared = 0; /* bus not shared by default */
- int ret;
+ int ret = -EINVAL;
/* Get the first frontend */
fe0 = vb2_dvb_get_frontend(&port->frontends, 1);
@@ -2586,8 +2590,10 @@ static int dvb_register(struct cx23885_tsport *port)
goto frontend_detach;
ret = dvb_register_ci_mac(port);
- if (ret)
+ if (ret) {
+ vb2_dvb_unregister_bus(&port->frontends);
goto frontend_detach;
+ }
return 0;
@@ -2618,7 +2624,7 @@ frontend_detach:
port->gate_ctrl = NULL;
vb2_dvb_dealloc_frontends(&port->frontends);
- return -EINVAL;
+ return ret;
}
int cx23885_dvb_register(struct cx23885_tsport *port)
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index 14d219fd1d8a..94ce00154e1f 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -134,7 +134,7 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
format.format.width = dev->width;
format.format.height = dev->height;
format.format.field = dev->field;
- call_all(dev, pad, set_fmt, NULL, &format);
+ call_all(dev, pad, set_fmt, NULL, NULL, &format);
return 0;
}
@@ -619,7 +619,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
dprintk(2, "%s() width=%d height=%d field=%d\n", __func__,
dev->width, dev->height, dev->field);
v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED);
- call_all(dev, pad, set_fmt, NULL, &format);
+ call_all(dev, pad, set_fmt, NULL, NULL, &format);
v4l2_fill_pix_format(&f->fmt.pix, &format.format);
/* set_fmt overwrites f->fmt.pix.field, restore it */
f->fmt.pix.field = dev->field;
diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
index 5d9ce4f9af01..c96d289e5ab7 100644
--- a/drivers/media/pci/cx88/cx88-input.c
+++ b/drivers/media/pci/cx88/cx88-input.c
@@ -259,7 +259,7 @@ static void cx88_ir_close(struct rc_dev *rc)
int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
{
struct cx88_IR *ir;
- struct rc_dev *dev;
+ struct rc_dev *dev = NULL;
char *ir_codes = NULL;
u64 rc_proto = RC_PROTO_BIT_OTHER;
int err = -ENOMEM;
@@ -268,11 +268,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
*/
ir = kzalloc_obj(*ir);
- dev = rc_allocate_device(RC_DRIVER_IR_RAW);
- if (!ir || !dev)
- goto err_out_free;
-
- ir->dev = dev;
+ if (!ir)
+ return -ENOMEM;
/* detect & configure */
switch (core->boardnr) {
@@ -439,6 +436,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
goto err_out_free;
}
+ dev = rc_allocate_device(ir->sampling ?
+ RC_DRIVER_IR_RAW : RC_DRIVER_SCANCODE);
+ if (!dev)
+ goto err_out_free;
+
+ ir->dev = dev;
+
/*
* The usage of mask_keycode were very convenient, due to several
* reasons. Among others, the scancode tables were using the scancode
@@ -477,12 +481,10 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
dev->close = cx88_ir_close;
dev->scancode_mask = hardware_mask;
- if (ir->sampling) {
+ if (ir->sampling)
dev->timeout = MS_TO_US(10); /* 10 ms */
- } else {
- dev->driver_type = RC_DRIVER_SCANCODE;
+ else
dev->allowed_protocols = rc_proto;
- }
ir->core = core;
core->ir = ir;
diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c
index 0c07ad335799..cd2366768f4a 100644
--- a/drivers/media/pci/cx88/cx88-mpeg.c
+++ b/drivers/media/pci/cx88/cx88-mpeg.c
@@ -392,7 +392,8 @@ static int cx8802_init_common(struct cx8802_dev *dev)
err = dma_set_mask(&dev->pci->dev, DMA_BIT_MASK(32));
if (err) {
pr_err("Oops: no 32bit PCI DMA ???\n");
- return -EIO;
+ err = -EIO;
+ goto fail_disable_device;
}
dev->pci_rev = dev->pci->revision;
@@ -413,13 +414,17 @@ static int cx8802_init_common(struct cx8802_dev *dev)
IRQF_SHARED, dev->core->name, dev);
if (err < 0) {
pr_err("can't get IRQ %d\n", dev->pci->irq);
- return err;
+ goto fail_disable_device;
}
cx_set(MO_PCI_INTMSK, core->pci_irqmask);
/* everything worked */
pci_set_drvdata(dev->pci, dev);
return 0;
+
+fail_disable_device:
+ pci_disable_device(dev->pci);
+ return err;
}
static void cx8802_fini_common(struct cx8802_dev *dev)
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index eaa46a2f92e7..f8f2843495f3 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -1549,7 +1549,7 @@ static void cx8800_finidev(struct pci_dev *pci_dev)
kfree(dev);
}
-static int __maybe_unused cx8800_suspend(struct device *dev_d)
+static int cx8800_suspend(struct device *dev_d)
{
struct cx8800_dev *dev = dev_get_drvdata(dev_d);
struct cx88_core *core = dev->core;
@@ -1576,7 +1576,7 @@ static int __maybe_unused cx8800_suspend(struct device *dev_d)
return 0;
}
-static int __maybe_unused cx8800_resume(struct device *dev_d)
+static int cx8800_resume(struct device *dev_d)
{
struct cx8800_dev *dev = dev_get_drvdata(dev_d);
struct cx88_core *core = dev->core;
@@ -1617,14 +1617,14 @@ static const struct pci_device_id cx8800_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, cx8800_pci_tbl);
-static SIMPLE_DEV_PM_OPS(cx8800_pm_ops, cx8800_suspend, cx8800_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(cx8800_pm_ops, cx8800_suspend, cx8800_resume);
static struct pci_driver cx8800_pci_driver = {
.name = "cx8800",
.id_table = cx8800_pci_tbl,
.probe = cx8800_initdev,
.remove = cx8800_finidev,
- .driver.pm = &cx8800_pm_ops,
+ .driver.pm = pm_sleep_ptr(&cx8800_pm_ops),
};
module_pci_driver(cx8800_pci_driver);
diff --git a/drivers/media/pci/hws/hws.h b/drivers/media/pci/hws/hws.h
index 8fbe1fe27844..d87d52674b69 100644
--- a/drivers/media/pci/hws/hws.h
+++ b/drivers/media/pci/hws/hws.h
@@ -33,8 +33,8 @@ struct hws_pix_state {
u32 sizeimage; /* full frame */
enum v4l2_field field; /* V4L2_FIELD_NONE or INTERLACED */
enum v4l2_colorspace colorspace; /* e.g., REC709 */
- enum v4l2_ycbcr_encoding ycbcr_enc; /* V4L2_YCBCR_ENC_DEFAULT */
- enum v4l2_quantization quantization; /* V4L2_QUANTIZATION_LIM_RANGE */
+ enum v4l2_ycbcr_encoding ycbcr_enc; /* V4L2_YCBCR_ENC_601 */
+ enum v4l2_quantization quantization; /* V4L2_QUANTIZATION_FULL_RANGE */
enum v4l2_xfer_func xfer_func; /* V4L2_XFER_FUNC_DEFAULT */
bool interlaced; /* cached hardware state */
u32 half_size; /* hardware half-frame size */
diff --git a/drivers/media/pci/hws/hws_pci.c b/drivers/media/pci/hws/hws_pci.c
index 30bb7d34465b..f06e60dc2ee6 100644
--- a/drivers/media/pci/hws/hws_pci.c
+++ b/drivers/media/pci/hws/hws_pci.c
@@ -33,8 +33,8 @@ static unsigned long long hws_elapsed_us(u64 start_ns)
}
/* register layout inside HWS_REG_DEVICE_INFO */
-#define DEVINFO_VER GENMASK(7, 0)
-#define DEVINFO_SUBVER GENMASK(15, 8)
+#define DEVINFO_VER GENMASK(15, 8)
+#define DEVINFO_SUBVER GENMASK(23, 16)
#define DEVINFO_YV12 GENMASK(31, 28)
#define DEVINFO_HWKEY GENMASK(27, 24)
#define DEVINFO_PORTID GENMASK(25, 24) /* low 2 bits of HW-key */
@@ -441,7 +441,7 @@ static int hws_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
hws_init_video_sys(hws, false);
/* 5) Init channels (video state, locks, vb2, ctrls) */
- for (i = 0; i < hws->max_channels; i++) {
+ for (i = 0; i < hws->cur_max_video_ch; i++) {
ret = hws_video_init_channel(hws, i);
if (ret) {
dev_err(&pdev->dev, "video channel init failed (ch=%d)\n", i);
diff --git a/drivers/media/pci/hws/hws_reg.h b/drivers/media/pci/hws/hws_reg.h
index e4fb4af44434..ba1d22f4376c 100644
--- a/drivers/media/pci/hws/hws_reg.h
+++ b/drivers/media/pci/hws/hws_reg.h
@@ -70,7 +70,8 @@
#define HWS_CTL_IRQ_ENABLE_BIT BIT(0) /* Global interrupt enable bit */
/* Write 0x00 to fully reset decoder,
* set bit 31=1 to "start run",
- * low byte=0x13 selects YUYV/BT.709/etc,
+ * low byte=0x13 is the vendor baseline capture-mode value; its individual
+ * bit meanings are not documented,
* in ReadChipId() we also write 0x00 and 0x10 here for chip-ID sequencing.
*/
@@ -121,9 +122,10 @@
#define HWS_REG_DEVICE_INFO (CVBS_IN_BASE + 88 * PCIE_BARADDROFSIZE)
/*
* Reading this 32-bit word returns:
- * bits 7:0 = "device version"
- * bits 15:8 = "device sub-version"
- * bits 23:24 = "HW key / port ID" etc.
+ * bits 7:0 = unused by the baseline driver
+ * bits 15:8 = device version
+ * bits 23:16 = device sub-version
+ * bits 27:24 = HW key (port ID in bits 25:24)
* bits 31:28 = "support YV12" flags
*/
diff --git a/drivers/media/pci/hws/hws_v4l2_ioctl.c b/drivers/media/pci/hws/hws_v4l2_ioctl.c
index 0303e311ee4a..ce396b7225d2 100644
--- a/drivers/media/pci/hws/hws_v4l2_ioctl.c
+++ b/drivers/media/pci/hws/hws_v4l2_ioctl.c
@@ -511,8 +511,9 @@ static inline void hws_set_colorimetry_state(struct hws_pix_state *p)
{
bool sd = p->height <= 576;
+ /* Captured samples use full-range BT.601 Y'CbCr at every resolution. */
p->colorspace = sd ? V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709;
- p->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ p->ycbcr_enc = V4L2_YCBCR_ENC_601;
p->quantization = V4L2_QUANTIZATION_FULL_RANGE;
p->xfer_func = V4L2_XFER_FUNC_DEFAULT;
}
@@ -736,7 +737,7 @@ static inline void hws_set_colorimetry_fmt(struct v4l2_pix_format *p)
bool sd = p->height <= 576;
p->colorspace = sd ? V4L2_COLORSPACE_SMPTE170M : V4L2_COLORSPACE_REC709;
- p->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ p->ycbcr_enc = V4L2_YCBCR_ENC_601;
p->quantization = V4L2_QUANTIZATION_FULL_RANGE;
p->xfer_func = V4L2_XFER_FUNC_DEFAULT;
}
diff --git a/drivers/media/pci/hws/hws_video.c b/drivers/media/pci/hws/hws_video.c
index 18e4bc6901d3..dbe0fc2a66b5 100644
--- a/drivers/media/pci/hws/hws_video.c
+++ b/drivers/media/pci/hws/hws_video.c
@@ -327,7 +327,7 @@ int hws_video_init_channel(struct hws_pcie_dev *pdev, int ch)
vid->pix.sizeimage = vid->pix.bytesperline * vid->pix.height;
vid->pix.field = V4L2_FIELD_NONE;
vid->pix.colorspace = V4L2_COLORSPACE_REC709;
- vid->pix.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ vid->pix.ycbcr_enc = V4L2_YCBCR_ENC_601;
vid->pix.quantization = V4L2_QUANTIZATION_FULL_RANGE;
vid->pix.xfer_func = V4L2_XFER_FUNC_DEFAULT;
vid->pix.interlaced = false;
@@ -895,6 +895,8 @@ static void hws_video_apply_mode_change(struct hws_pcie_dev *pdx,
v->pix.width = w;
v->pix.height = h;
v->pix.interlaced = interlaced;
+ v->pix.colorspace = h <= 576 ? V4L2_COLORSPACE_SMPTE170M :
+ V4L2_COLORSPACE_REC709;
hws_set_current_dv_timings(v, w, h, interlaced);
v->current_fps = fps;
@@ -1292,6 +1294,8 @@ static void hws_stop_streaming(struct vb2_queue *q)
WRITE_ONCE(v->stop_requested, true);
hws_enable_video_capture(v->parent, v->channel_index, false);
+ if (hws->irq >= 0)
+ synchronize_irq(hws->irq);
/* 2) Collect in-flight + queued under the IRQ lock */
spin_lock_irqsave(&v->irq_lock, flags);
diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c
index bd64c0400c0d..e476e269a50a 100644
--- a/drivers/media/pci/intel/ipu-bridge.c
+++ b/drivers/media/pci/intel/ipu-bridge.c
@@ -8,6 +8,7 @@
#include <linux/dmi.h>
#include <linux/i2c.h>
#include <linux/mei_cl_bus.h>
+#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
@@ -15,6 +16,7 @@
#include <linux/workqueue.h>
#include <media/ipu-bridge.h>
+#include <media/ipu6-pci-table.h>
#include <media/v4l2-fwnode.h>
#define ADEV_DEV(adev) ACPI_PTR(&((adev)->dev))
@@ -48,6 +50,14 @@
*
* Please keep the list sorted by ACPI HID.
*/
+/* IPU6 variants whose CSI-2 receiver needs the ov5693 clock lane gated */
+static const u16 ipu6_ov5693_ncont_clk[] = {
+ PCI_DEVICE_ID_INTEL_IPU6, /* Tiger Lake */
+ PCI_DEVICE_ID_INTEL_IPU6EP_ADLP, /* Alder Lake-P */
+ PCI_DEVICE_ID_INTEL_IPU6EP_ADLN, /* Alder Lake-N */
+ 0
+};
+
static const struct ipu_sensor_config ipu_supported_sensors[] = {
/* Himax HM1092 */
IPU_SENSOR_CONFIG("HIMX1092", 2, 180000000, 180480000),
@@ -60,6 +70,9 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = {
/* GalaxyCore GC0310 */
IPU_SENSOR_CONFIG("INT0310", 1, 55692000),
/* Omnivision OV5693 */
+ IPU_SENSOR_CONFIG_MATCH_FL("INT33BE", ipu6_ov5693_ncont_clk,
+ IPU_BR_FL_CSI2_CLK_NONCONTINUOUS,
+ 1, 419200000),
IPU_SENSOR_CONFIG("INT33BE", 1, 419200000),
/* Onsemi MT9M114 */
IPU_SENSOR_CONFIG("INT33F0", 1, 384000000),
@@ -75,19 +88,22 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = {
IPU_SENSOR_CONFIG("INT3537", 1, 437000000),
/* Lontium lt6911uxe */
IPU_SENSOR_CONFIG("INTC10C5", 0),
- /* Omnivision OV01A10 / OV01A1S */
+ /* Omnivision OV01A10 / OV01A1B / OV01A1S */
IPU_SENSOR_CONFIG("OVTI01A0", 1, 400000000),
+ IPU_SENSOR_CONFIG("OVTI01AB", 1, 400000000),
IPU_SENSOR_CONFIG("OVTI01AS", 1, 400000000),
/* Omnivision OV02C10 */
IPU_SENSOR_CONFIG("OVTI02C1", 1, 400000000),
/* Omnivision OV02E10 */
IPU_SENSOR_CONFIG("OVTI02E1", 1, 360000000),
/* Omnivision ov05c10 */
- IPU_SENSOR_CONFIG("OVTI05C1", 1, 480000000),
+ IPU_SENSOR_CONFIG("OVTI05C1", 2, 480000000, 900000000),
/* Omnivision OV08A10 */
IPU_SENSOR_CONFIG("OVTI08A1", 1, 500000000),
/* Omnivision OV08x40 */
IPU_SENSOR_CONFIG("OVTI08F4", 3, 400000000, 749000000, 800000000),
+ /* Omnivision OV13858 */
+ IPU_SENSOR_CONFIG("OVTID858", 2, 540000000, 270000000),
/* Omnivision OV13B10 */
IPU_SENSOR_CONFIG("OVTI13B1", 1, 560000000),
IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000),
@@ -95,6 +111,11 @@ static const struct ipu_sensor_config ipu_supported_sensors[] = {
IPU_SENSOR_CONFIG("OVTI2680", 1, 331200000),
/* Omnivision OV5675 */
IPU_SENSOR_CONFIG("OVTI5675", 1, 450000000),
+ /* Omnivision OV5693 */
+ IPU_SENSOR_CONFIG_MATCH_FL("OVTI5693", ipu6_ov5693_ncont_clk,
+ IPU_BR_FL_CSI2_CLK_NONCONTINUOUS,
+ 1, 419200000),
+ IPU_SENSOR_CONFIG("OVTI5693", 1, 419200000),
/* Omnivision OV8856 */
IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000),
/* Sony IMX471 */
@@ -127,6 +148,13 @@ static const struct dmi_system_id upside_down_sensor_dmi_ids[] = {
{
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "XPS 14 (Dell 14 Premium) DA14250"),
+ },
+ .driver_data = "OVTI02C1",
+ },
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "XPS 14 9440"),
},
.driver_data = "OVTI02C1",
@@ -145,6 +173,13 @@ static const struct dmi_system_id upside_down_sensor_dmi_ids[] = {
},
.driver_data = "OVTI02C1",
},
+ {
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Dell Pro 14 Premium PA14260"),
+ },
+ .driver_data = "OVTI08F4",
+ },
/*
* The first four characters of DMI_BOARD_NAME identify the Lenovo
* machine type/model. For example, a DMI_BOARD_NAME starting with
@@ -185,6 +220,14 @@ static const struct dmi_system_id upside_down_sensor_dmi_ids[] = {
.driver_data = "SONY471A",
},
{
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME,
+ "Surface Pro for Business 11th Edition with Intel"),
+ },
+ .driver_data = "OVTID858",
+ },
+ {
/* Samsung Galaxy Book5 Pro 360 */
.matches = {
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
@@ -192,6 +235,14 @@ static const struct dmi_system_id upside_down_sensor_dmi_ids[] = {
},
.driver_data = "OVTI02E1",
},
+ {
+ /* Samsung Galaxy Book3 Ultra */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "960XFH"),
+ },
+ .driver_data = "OVTI02C1",
+ },
{} /* Terminating entry */
};
@@ -326,8 +377,8 @@ static int ipu_bridge_check_ivsc_dev(struct ipu_sensor *sensor,
if (adev) {
csi_dev = ipu_bridge_get_ivsc_csi_dev(adev);
if (!csi_dev) {
- acpi_dev_put(adev);
dev_err(ADEV_DEV(adev), "Failed to find MEI or CVS CSI dev\n");
+ acpi_dev_put(adev);
return -ENODEV;
}
@@ -436,6 +487,7 @@ static enum v4l2_fwnode_orientation ipu_bridge_parse_orientation(struct acpi_dev
int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor)
{
+ acpi_handle handle = acpi_device_handle(ACPI_PTR(adev));
struct ipu_sensor_ssdb ssdb = {};
int ret;
@@ -459,8 +511,15 @@ int ipu_bridge_parse_ssdb(struct acpi_device *adev, struct ipu_sensor *sensor)
sensor->rotation = ipu_bridge_parse_rotation(adev, &ssdb);
sensor->orientation = ipu_bridge_parse_orientation(adev);
- if (ssdb.vcmtype)
+ acpi_handle_debug(handle,
+ "CSI-2 port %u, lanes %u, mclkspeed %u, rotation %u (SSDB %u), orientation %u\n",
+ sensor->link, sensor->lanes, sensor->mclkspeed,
+ sensor->rotation, ssdb.degree, sensor->orientation);
+
+ if (ssdb.vcmtype) {
sensor->vcm_type = ipu_vcm_types[ssdb.vcmtype - 1];
+ acpi_handle_debug(handle, "VCM %s\n", sensor->vcm_type);
+ }
return 0;
}
@@ -473,6 +532,7 @@ static void ipu_bridge_create_fwnode_properties(
{
struct ipu_property_names *names = &sensor->prop_names;
struct software_node *nodes = sensor->swnodes;
+ unsigned int i = 0;
sensor->prop_names = prop_names;
@@ -530,21 +590,25 @@ static void ipu_bridge_create_fwnode_properties(
PROPERTY_ENTRY_REF_ARRAY("lens-focus", sensor->vcm_ref);
}
- sensor->ep_properties[0] = PROPERTY_ENTRY_U32(
- sensor->prop_names.bus_type,
- V4L2_FWNODE_BUS_TYPE_CSI2_DPHY);
- sensor->ep_properties[1] = PROPERTY_ENTRY_U32_ARRAY_LEN(
- sensor->prop_names.data_lanes,
- bridge->data_lanes, sensor->lanes);
- sensor->ep_properties[2] = PROPERTY_ENTRY_REF_ARRAY(
- sensor->prop_names.remote_endpoint,
- sensor->local_ref);
+ sensor->ep_properties[IPU_BRIDGE_NEXT_PROPERTY(i, EP_BUS_TYPE)] =
+ PROPERTY_ENTRY_U32(names->bus_type,
+ V4L2_FWNODE_BUS_TYPE_CSI2_DPHY);
+ sensor->ep_properties[IPU_BRIDGE_NEXT_PROPERTY(i, EP_DATA_LANES)] =
+ PROPERTY_ENTRY_U32_ARRAY_LEN(names->data_lanes,
+ bridge->data_lanes, sensor->lanes);
+ sensor->ep_properties[IPU_BRIDGE_NEXT_PROPERTY(i, EP_REMOTE_EP)] =
+ PROPERTY_ENTRY_REF_ARRAY(names->remote_endpoint,
+ sensor->local_ref);
if (cfg->nr_link_freqs > 0)
- sensor->ep_properties[3] = PROPERTY_ENTRY_U64_ARRAY_LEN(
- sensor->prop_names.link_frequencies,
- cfg->link_freqs,
- cfg->nr_link_freqs);
+ sensor->ep_properties[IPU_BRIDGE_NEXT_PROPERTY(i, EP_LINK_FREQUENCIES)] =
+ PROPERTY_ENTRY_U64_ARRAY_LEN(names->link_frequencies,
+ cfg->link_freqs,
+ cfg->nr_link_freqs);
+
+ if (cfg->flags & IPU_BR_FL_CSI2_CLK_NONCONTINUOUS)
+ sensor->ep_properties[IPU_BRIDGE_NEXT_PROPERTY(i, EP_CLOCK_NONCONTINUOUS)] =
+ PROPERTY_ENTRY_BOOL("clock-noncontinuous");
sensor->ipu_properties[0] = PROPERTY_ENTRY_U32_ARRAY_LEN(
sensor->prop_names.data_lanes,
@@ -856,8 +920,8 @@ static int ipu_bridge_connect_sensor(const struct ipu_sensor_config *cfg,
if (ret)
goto err_free_swnodes;
- dev_info(bridge->dev, "Found supported sensor %s\n",
- acpi_dev_name(adev));
+ dev_info(bridge->dev, "Found supported sensor %s (%pfw)\n",
+ acpi_dev_name(adev), primary);
bridge->n_sensors++;
}
@@ -874,8 +938,28 @@ err_put_adev:
return ret;
}
+/*
+ * Whether a sensor config applies to the IPU this bridge sits on. A config
+ * listing PCI product IDs only applies to those IPUs.
+ */
+static bool ipu_bridge_config_matches(const struct ipu_sensor_config *cfg,
+ struct ipu_bridge *bridge)
+{
+ const u16 *id;
+
+ if (!cfg->pci_ids)
+ return true;
+
+ for (id = cfg->pci_ids; *id; id++)
+ if (*id == bridge->pci_id)
+ return true;
+
+ return false;
+}
+
static int ipu_bridge_connect_sensors(struct ipu_bridge *bridge)
{
+ const char *done_hid = NULL;
unsigned int i;
int ret;
@@ -883,9 +967,22 @@ static int ipu_bridge_connect_sensors(struct ipu_bridge *bridge)
const struct ipu_sensor_config *cfg =
&ipu_supported_sensors[i];
+ /*
+ * Entries for one HID are adjacent, IPU-specific ones first,
+ * so the generic entry is skipped once a specific one has
+ * matched and the sensor is not connected twice.
+ */
+ if (done_hid && !strcmp(cfg->hid, done_hid))
+ continue;
+
+ if (!ipu_bridge_config_matches(cfg, bridge))
+ continue;
+
ret = ipu_bridge_connect_sensor(cfg, bridge);
if (ret)
goto err_unregister_sensors;
+
+ done_hid = cfg->hid;
}
return 0;
@@ -942,6 +1039,18 @@ static int ipu_bridge_check_fwnode_graph(struct fwnode_handle *fwnode)
return ipu_bridge_check_fwnode_graph(fwnode->secondary);
}
+struct pci_dev *ipu_bridge_get_ipu6(void)
+{
+ struct pci_dev *ipu = NULL;
+
+ for (unsigned int i = 0; !ipu && ipu6_pci_tbl[i].vendor; i++)
+ ipu = pci_get_device(ipu6_pci_tbl[i].vendor,
+ ipu6_pci_tbl[i].device, NULL);
+
+ return ipu;
+}
+EXPORT_SYMBOL_NS_GPL(ipu_bridge_get_ipu6, "INTEL_IPU_BRIDGE");
+
static DEFINE_MUTEX(ipu_bridge_mutex);
int ipu_bridge_init(struct device *dev,
@@ -969,6 +1078,7 @@ int ipu_bridge_init(struct device *dev,
sizeof(bridge->ipu_node_name));
bridge->ipu_hid_node.name = bridge->ipu_node_name;
bridge->dev = dev;
+ bridge->pci_id = dev_is_pci(dev) ? to_pci_dev(dev)->device : 0;
bridge->parse_sensor_fwnode = parse_sensor_fwnode;
ret = software_node_register(&bridge->ipu_hid_node);
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
index eb1824ee86fd..4d2b231291f5 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
@@ -1229,6 +1229,7 @@ static int cio2_subdev_init_state(struct v4l2_subdev *sd,
}
static int cio2_subdev_set_fmt(struct v4l2_subdev *sd,
+ const struct v4l2_subdev_client_info *ci,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
diff --git a/drivers/media/pci/intel/ipu6/Kconfig b/drivers/media/pci/intel/ipu6/Kconfig
index 1129e2beb4be..a1d036a78b57 100644
--- a/drivers/media/pci/intel/ipu6/Kconfig
+++ b/drivers/media/pci/intel/ipu6/Kconfig
@@ -16,3 +16,12 @@ config VIDEO_INTEL_IPU6
To compile this driver, say Y here! It contains 2 modules -
intel_ipu6 and intel_ipu6_isys.
+
+config VIDEO_INTEL_IPU6_IPU7
+ bool "Support IPU 7 and IPU 7.5 in ipu6 driver by default"
+ depends on VIDEO_INTEL_IPU6
+ default y
+ help
+ Support Intel IPU 7 and IPU 7.5 in ipu6 driver by default, instead of
+ the ipu7 staging driver. This behaviour can be changed at runtime with
+ module parameters in the respective drivers.
diff --git a/drivers/media/pci/intel/ipu6/Makefile b/drivers/media/pci/intel/ipu6/Makefile
index a821b0a1567f..676bc978b972 100644
--- a/drivers/media/pci/intel/ipu6/Makefile
+++ b/drivers/media/pci/intel/ipu6/Makefile
@@ -4,20 +4,26 @@ intel-ipu6-y := ipu6.o \
ipu6-bus.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
+ ipu6-fw-com.o \
+ ipu7-fw-com.o \
+ ipu7-boot.o
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 \
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-bus.h b/drivers/media/pci/intel/ipu6/ipu6-bus.h
index a08c5468d536..d2f93eb03dea 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-bus.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-bus.h
@@ -26,17 +26,18 @@ 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;
unsigned int pkg_dir_size;
+ u32 fw_entry;
};
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,9 @@ 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;
+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,
void *pdata, const struct ipu6_buttress_ctrl *ctrl,
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index e0ecb4c8b081..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>
@@ -55,16 +56,11 @@
#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)
+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) {
@@ -75,11 +71,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:
@@ -94,7 +90,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:
@@ -105,8 +101,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:
@@ -117,8 +113,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:
@@ -135,17 +131,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);
@@ -160,8 +156,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,
@@ -176,42 +172,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,
@@ -221,14 +217,15 @@ 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;
+ 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;
@@ -244,9 +241,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);
@@ -258,7 +255,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;
}
@@ -276,8 +273,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;
@@ -296,7 +293,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;
}
@@ -337,7 +334,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 +346,14 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
if (!active)
return IRQ_NONE;
- irq_status = readl(isp->base + reg_irq_sts);
+ 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)
pm_runtime_put_noidle(&isp->pdev->dev);
@@ -356,39 +361,40 @@ 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");
- ipu6_buttress_ipc_recv(isp, &b->cse, &b->cse.recv_data);
- complete(&b->cse.recv_complete);
+
+ ipu6_buttress_ipc_recv(isp, &b->ipc.recv_data);
+ 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->cse.send_complete);
+ 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");
@@ -407,12 +413,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);
@@ -423,12 +429,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;
@@ -438,46 +445,179 @@ 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;
}
-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;
}
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)
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;
@@ -487,7 +627,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;
}
@@ -499,7 +639,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;
@@ -517,10 +657,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,
@@ -529,62 +669,63 @@ 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);
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;
}
@@ -596,18 +737,18 @@ out:
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)
{
@@ -634,11 +775,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
@@ -659,7 +807,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);
@@ -674,8 +822,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",
@@ -699,7 +850,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);
@@ -724,15 +875,16 @@ out_unlock:
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");
@@ -740,8 +892,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");
@@ -749,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");
- for (i = 0; i < BUTTRESS_TSC_SYNC_RESET_TRIAL_MAX; i++) {
+ return -ETIMEDOUT;
+}
+
+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;
@@ -761,28 +932,39 @@ 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");
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)
{
+ 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 {
@@ -811,13 +993,77 @@ 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");
+/* 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 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;
+ 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;
+ 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);
+
+ 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);
+ 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;
- 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);
+ 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);
}
int ipu6_buttress_init(struct ipu6_device *isp)
@@ -830,54 +1076,52 @@ 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);
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 + BUTTRESS_REG_WDT);
- writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_CLEAR);
- writel(BUTTRESS_IRQS, isp->base + BUTTRESS_REG_ISR_ENABLE);
-
- /* get ref_clk frequency by reading the indication in btrs control */
- val = readl(isp->base + BUTTRESS_REG_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:
+
+ dev_dbg(&isp->pdev->dev, "IPU in %s mode\n",
+ isp->secure_mode ? "secure" : "non-secure");
+
+ 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 {
- ret = ipu6_buttress_ipc_reset(isp, &b->cse);
+ ret = ipu6_buttress_ipc_reset(isp);
if (ret) {
dev_warn(&isp->pdev->dev,
"IPC reset protocol failed, retrying\n");
@@ -901,7 +1145,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 51e5ad48db82..79d8f5893686 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
@@ -26,25 +26,50 @@ 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 {
struct completion send_complete;
struct completion recv_complete;
- u32 nack;
- u32 nack_mask;
u32 recv_data;
- u32 csr_out;
+};
+
+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;
u32 csr_in;
+ u32 csr_out;
u32 db0_in;
u32 db0_out;
- u32 data0_out;
u32 data0_in;
+ u32 data0_out;
+ u32 sku_id;
+
+ /* 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 cse;
+ struct ipu6_buttress_ipc ipc;
+ const struct ipu6_buttress_registers *regs;
struct list_head constraints;
u32 wdt_cached_value;
bool force_suspend;
@@ -58,13 +83,12 @@ 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_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_buttress_ipc_reset(struct ipu6_device *isp);
+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);
@@ -82,4 +106,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-cpd.c b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
index b7013f6524ec..1fadb0f2f6c1 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)
@@ -220,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");
@@ -266,7 +282,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 +291,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,
@@ -316,47 +325,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) {
- dev_err(&isp->pdev->dev, "Invalid CPD in file\n");
- return ret;
+ return (struct ipu7_cpd_metadata *)((u8 *)cpd + cpd_ent->offset);
+}
+
+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;
}
- /* Check for CPD file marker */
- if (hdr->hdr_mark != CPD_HDR_MARK) {
- dev_err(&isp->pdev->dev, "Invalid CPD header\n");
+ /* 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;
}
- /* Sanity check for manifest size */
+ 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;
+
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) {
- 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);
+ 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)
- dev_err(&isp->pdev->dev, "Invalid CPD moduledata\n");
+ 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 ipu6_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 ret;
+ return -ENOENT;
}
+EXPORT_SYMBOL_NS_GPL(ipu6_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..c3a4859d8e79 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 ipu6_ipu7_cpd_copy_binary(const void *cpd, const char *name, void *dst,
+ u32 *entry);
+
#endif /* IPU6_CPD_H */
diff --git a/drivers/media/pci/intel/ipu6/ipu6-dma.c b/drivers/media/pci/intel/ipu6/ipu6-dma.c
index fdcdb15b073c..90f530a93779 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,11 +366,22 @@ 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");
+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 {
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
index 62ed92ff1d30..f4f1cf7c86d2 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-isys.c
@@ -7,6 +7,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/io.h>
+#include <linux/pm_runtime.h>
#include <linux/spinlock.h>
#include <linux/types.h>
@@ -15,6 +16,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",
@@ -32,7 +34,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 +44,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 +54,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;
@@ -90,13 +92,13 @@ 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->fwcom;
+ struct ipu6_fw_com_context *ctx = isys->fwctx;
struct device *dev = &isys->adev->auxdev.dev;
struct ipu6_fw_send_queue_token *token;
@@ -126,19 +128,11 @@ 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)
+static 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;
/*
@@ -147,40 +141,36 @@ int ipu6_fw_isys_close(struct ipu6_isys *isys)
* to SP icache.
* 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;
- spin_unlock_irqrestore(&isys->power_lock, flags);
+ ret = ipu6_fw_com_close(isys->fwctx);
+ fwctx = isys->fwctx;
+ isys->fwctx = NULL;
if (ret)
dev_err(dev, "Device close failure: %d\n", ret);
/* 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;
- spin_unlock_irqrestore(&isys->power_lock, flags);
+ isys->fwctx = fwctx;
}
return ret;
}
-void ipu6_fw_isys_cleanup(struct ipu6_isys *isys)
+static 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 +202,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 +248,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 +272,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,34 +306,34 @@ 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;
}
-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;
- 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 +341,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);
@@ -363,20 +355,21 @@ int ipu6_fw_isys_init(struct ipu6_isys *isys, unsigned int num_streams)
return ret;
}
-struct ipu6_fw_isys_resp_info_abi *
-ipu6_fw_isys_get_resp(void *context, unsigned int queue)
+static struct ipu6_fw_isys_resp_info_abi *
+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)
+static 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,
- struct ipu6_fw_isys_stream_cfg_data_abi *cfg)
+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;
dev_dbg(dev, "-----------------------------------------------------\n");
@@ -451,13 +444,15 @@ void ipu6_fw_isys_dump_stream_cfg(struct device *dev,
dev_dbg(dev, "-----------------------------------------------------\n");
}
-void
-ipu6_fw_isys_dump_frame_buff_set(struct device *dev,
- struct ipu6_fw_isys_frame_buff_set_abi *buf,
- 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;
+ buf = &msg->ipu6.frame;
+
dev_dbg(dev, "-----------------------------------------------------\n");
dev_dbg(dev, "IPU6_FW_ISYS_FRAME_BUFF_SET\n");
@@ -485,3 +480,478 @@ 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;
+ struct isys_fw_msgs *isys_fw_msg = NULL;
+ u32 index;
+ u64 ts;
+
+ 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);
+
+ guard(spinlock_irqsave)(&isys->streams_lock);
+
+ if (resp->stream_handle >= IPU6_ISYS_MAX_STREAMS) {
+ dev_err(&adev->auxdev.dev, "bad stream handle %u\n",
+ resp->stream_handle);
+ goto leave;
+ }
+
+ stream = resp->stream_handle < IPU6_ISYS_MAX_STREAMS ?
+ isys->streams_by_handle[resp->stream_handle] : NULL;
+ 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 message until software
+ * get pin_data_ready event
+ */
+ if (!resp->buf_id) {
+ dev_warn(&adev->auxdev.dev, "%d: Invalid buf ID\n",
+ resp->stream_handle);
+ goto leave;
+ }
+
+ 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 &&
+ 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;
+ }
+
+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;
+
+ 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);
+
+ scoped_guard(spinlock, &csi2->isys->streams_lock) {
+ for (i = 0; i < NR_OF_CSI2_VC; i++) {
+ if (status & IPU_CSI_RX_IRQ_FS_VC(i)) {
+ stream = csi2->streams_by_vc[i];
+ if (!stream)
+ continue;
+
+ ipu6_isys_csi2_sof_event_by_stream(stream);
+ }
+
+ if (status & IPU_CSI_RX_IRQ_FE_VC(i)) {
+ stream = csi2->streams_by_vc[i];
+ if (!stream)
+ continue;
+
+ ipu6_isys_csi2_eof_event_by_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;
+ int pm_status;
+
+ pm_status = pm_runtime_get_if_active(&adev->auxdev.dev);
+ if (!pm_status)
+ return 0;
+
+ 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);
+
+ if (pm_status > 0)
+ pm_runtime_put(&adev->auxdev.dev);
+
+ return IRQ_HANDLED;
+}
+
+static int ipu6_isys_fw_pin_cfg(struct ipu6_isys_video *av,
+ struct ipu6_isys_stream *stream,
+ struct media_pad *src_pad,
+ struct v4l2_mbus_frame_desc_entry *entry,
+ void *__cfg)
+{
+ 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_stream_cfg_data_abi *cfg = __cfg;
+ struct ipu6_fw_isys_input_pin_info_abi *input_pin;
+ struct ipu6_fw_isys_output_pin_info_abi *output_pin;
+ 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(state, 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 = entry->bus.csi2.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 ipu6_fw_isys_prepare_stream_cfg(struct ipu6_isys_stream *stream,
+ struct v4l2_mbus_frame_desc *desc,
+ struct isys_fw_msgs *msg)
+{
+ struct ipu6_fw_isys_stream_cfg_data_abi *stream_cfg;
+ struct device *dev = &stream->isys->adev->auxdev.dev;
+ int ret;
+
+ stream_cfg = &msg->ipu6.stream;
+ stream_cfg->src = stream->asd->source;
+ stream_cfg->vc = stream->vc;
+ stream_cfg->isl_use = 0;
+ stream_cfg->sensor_type = IPU6_FW_ISYS_SENSOR_MODE_NORMAL;
+
+ ret = ipu6_isys_fw_pins_prepare(stream, desc, ipu6_isys_fw_pin_cfg,
+ stream_cfg);
+ if (ret)
+ return ret;
+
+ ipu6_fw_isys_dump_stream_cfg(dev, msg);
+
+ stream->nr_output_pins = stream_cfg->nof_output_pins;
+
+ return 0;
+}
+
+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,
+ sizeof(msg->ipu6.stream),
+ IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN);
+}
+
+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);
+}
+
+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);
+}
+
+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;
+
+ 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);
+}
+
+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,
+ 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)
+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;
+
+ WARN_ON(!bl->nbufs);
+
+ set->send_irq_sof = 1;
+ set->send_resp_sof = 1;
+ set->send_irq_eof = 0;
+ set->send_resp_eof = 0;
+
+ 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);
+ }
+}
+
+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 b60f02076d8a..2a679d995961 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
@@ -512,21 +516,6 @@ struct ipu6_fw_isys_proxy_resp_info_abi {
};
/**
- * 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
*/
@@ -570,27 +559,10 @@ 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,
- 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);
+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);
+
#endif
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
index 7e539a0c6c92..0db6971d8d3e 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
@@ -11,9 +11,12 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/minmax.h>
+#include <linux/pm_runtime.h>
#include <linux/sprintf.h>
+#include <linux/string_choices.h>
#include <media/media-entity.h>
+#include <media/mipi-csi2.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
@@ -23,7 +26,9 @@
#include "ipu6-isys.h"
#include "ipu6-isys-csi2.h"
#include "ipu6-isys-subdev.h"
+#include "ipu6-isys-video.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,
@@ -228,56 +233,124 @@ 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_setup_watermark(struct ipu6_isys_csi2 *csi2,
+ struct v4l2_subdev_state *csi2_state,
+ struct v4l2_subdev *remote_sd)
+{
+ struct device *dev = &csi2->isys->adev->auxdev.dev;
+ struct v4l2_control hb = { .id = V4L2_CID_HBLANK, .value = 0 };
+ struct v4l2_subdev_route *route;
+ u32 max_stream_data_rate = 0, hblank = 0;
+ s64 link_freq;
+ int ret;
+
+ if (IS_IPU7(csi2->asd.isys->adev->isp))
+ return;
+
+ ret = v4l2_g_ctrl(remote_sd->ctrl_handler, &hb);
+ if (!ret)
+ hblank = max(0, hb.value);
+
+ link_freq = ipu6_isys_csi2_get_link_freq(csi2);
+ if (link_freq <= 0) {
+ csi2->watermark.force_iwake_disable = true;
+ dev_warn(dev, "unexpected link_freq %lld (source %s)\n",
+ link_freq, remote_sd->entity.name);
+ ipu6_isys_update_watermark_setting(csi2->isys);
+ return;
+ }
+
+ for_each_active_route(&csi2_state->routing, route) {
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = v4l2_subdev_state_get_format(csi2_state, CSI2_PAD_SINK,
+ route->sink_stream);
+ if (WARN_ON(!fmt))
+ continue;
+
+ u32 bpp = ipu6_isys_mbus_code_to_bpp(fmt->code);
+ u64 pixel_rate = mul_u64_u32_div(link_freq, csi2->nlanes * 2,
+ bpp);
+ u32 pixels_per_line = fmt->width + hblank;
+ u64 line_time_ns = div_u64(pixels_per_line * NSEC_PER_SEC,
+ pixel_rate);
+ u32 bytes_per_line = fmt->width * bpp / 8;
+ u32 pages_per_line =
+ DIV_ROUND_UP(bytes_per_line,
+ csi2->isys->pdata->ipdata->sram_gran_size);
+ u32 pb_bytes_per_line =
+ pages_per_line << csi2->isys->pdata->ipdata->sram_gran_shift;
+ u64 stream_data_rate =
+ div64_u64(pb_bytes_per_line * 1000, line_time_ns);
+
+ dev_dbg(dev, "stream %u:%u -> %u:%u data rate %lld\n",
+ route->sink_pad, route->sink_stream, route->source_pad,
+ route->source_stream, stream_data_rate);
+
+ max_stream_data_rate = max(max_stream_data_rate,
+ stream_data_rate);
+ }
+
+ csi2->watermark.stream_data_rate = max_stream_data_rate;
+
+ ipu6_isys_update_watermark_setting(csi2->isys);
+}
+
+static void ipu6_isys_csi2_clear_watermark(struct ipu6_isys_csi2 *csi2)
+{
+ if (IS_IPU7(csi2->asd.isys->adev->isp))
+ return;
+
+ csi2->watermark.force_iwake_disable = false;
+ csi2->watermark.stream_data_rate = 0;
+ ipu6_isys_update_watermark_setting(csi2->isys);
+}
+
+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;
-
- dev_dbg(dev, "stream %s CSI2-%u with %u lanes\n", enable ? "on" : "off",
- csi2->port, nlanes);
+ u32 mask = isys->pdata->ipdata->csi2.irq_mask;
cfg.port = csi2->port;
- cfg.nlanes = nlanes;
+ cfg.nlanes = csi2->nlanes;
- mask = isys->pdata->ipdata->csi2.irq_mask;
- nports = isys->pdata->ipdata->csi2.nports;
+ 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);
- 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));
+ 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 = 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;
/* reset port reset */
writel(0x1, csi2->base + CSI_REG_PORT_GPREG_SRST);
@@ -285,7 +358,7 @@ static int ipu6_isys_csi2_set_stream(struct v4l2_subdev *sd,
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 +402,217 @@ 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);
+ 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)
- dev_err(dev, "csi-%d phy power up failed %d\n", csi2->port,
- ret);
+ return ret;
- return ret;
+ ipu7_csi2_irq_enable(csi2);
+
+ return 0;
+}
+
+static int ipu6_isys_csi2_streaming_change(struct ipu6_isys_subdev *asd,
+ struct v4l2_subdev_state *state,
+ u32 pad,
+ struct v4l2_mbus_frame_desc *desc,
+ u8 *vc, bool enable)
+{
+ struct v4l2_mbus_frame_desc_entry *this_entry = NULL;
+ struct v4l2_subdev_route *route, *this_route = NULL;
+ u32 streams_enabled = 0, nodes_streaming = 0;
+
+ for_each_active_route(&state->routing, this_route)
+ if (pad == this_route->source_pad)
+ break;
+ if (!this_route) {
+ dev_dbg(asd->sd.dev, "no route found for pad %u\n", pad);
+ return -EINVAL;
+ }
+
+ for (unsigned int i = 0; i < desc->num_entries; i++) {
+ if (desc->entry[i].stream == this_route->sink_stream) {
+ this_entry = &desc->entry[i];
+ break;
+ }
+ }
+ if (!this_entry) {
+ dev_dbg(asd->sd.dev,
+ "no frame descriptor entry found for stream %u\n",
+ this_route->sink_stream);
+ return -EINVAL;
+ }
+
+ for_each_active_route(&state->routing, route) {
+ struct v4l2_mbus_frame_desc_entry *entry = NULL;
+
+ for (unsigned int i = 0; i < desc->num_entries; i++) {
+ if (desc->entry[i].stream == route->sink_stream) {
+ entry = &desc->entry[i];
+ break;
+ }
+ }
+
+ if (!entry) {
+ dev_dbg(asd->sd.dev, "cannot find stream %u from frame descriptor\n",
+ route->sink_stream);
+ return -EINVAL;
+ }
+
+ if (entry->bus.csi2.vc != this_entry->bus.csi2.vc)
+ continue;
+
+ struct media_pad *video_pad =
+ media_pad_remote_pad_first(&asd->sd.entity.pads[route->source_pad]);
+ if (!video_pad)
+ return -EINVAL;
+
+ struct ipu6_isys_video *av =
+ container_of_const(video_pad, struct ipu6_isys_video,
+ pad);
+
+ streams_enabled++;
+ if (av->streaming || (enable && pad == route->source_pad))
+ nodes_streaming++;
+ }
+
+ if (vc)
+ *vc = this_entry->bus.csi2.vc;
+
+ if (streams_enabled == nodes_streaming) {
+ dev_dbg(asd->sd.dev,
+ "changing streaming state to %s on \"%s\"\n",
+ str_enabled_disabled(enable), asd->sd.entity.name);
+ return 1;
+ }
+
+ dev_dbg(asd->sd.dev, "not setting streaming %s %s (%u/%u)\n",
+ str_enabled_disabled(enable), enable ? "yet" : "anymore",
+ nodes_streaming, streams_enabled);
+
+ return 0;
+}
+
+static int ipu6_isys_get_frame_desc(struct v4l2_subdev *remote_sd,
+ unsigned int pad,
+ struct v4l2_mbus_frame_desc *desc)
+{
+ struct v4l2_subdev_format fmt = { .which = V4L2_SUBDEV_FORMAT_ACTIVE };
+ int ret;
+
+ ret = v4l2_subdev_call(remote_sd, pad, get_frame_desc, pad, desc);
+ if (!ret || ret != -ENOIOCTLCMD)
+ return ret;
+
+ ret = v4l2_subdev_call_state_active(remote_sd, pad, get_fmt, &fmt);
+ if (ret)
+ return ret;
+
+ desc->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2;
+ desc->num_entries = 1;
+ desc->entry[0].pixelcode = fmt.format.code;
+ desc->entry[0].bus.csi2.dt = ipu6_isys_mbus_code_to_mipi(fmt.format.code);
+
+ return 0;
}
static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
@@ -349,60 +621,174 @@ 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;
+ struct ipu6_device *isp = asd->isys->adev->isp;
+ struct media_pad *remote_pad =
+ media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]),
+ *vdev_pad = media_pad_remote_pad_unique(&sd->entity.pads[pad]);
+ struct ipu6_isys_video *av =
+ container_of_const(vdev_pad, struct ipu6_isys_video, pad);
+ struct v4l2_subdev *remote_sd =
+ media_entity_to_v4l2_subdev(remote_pad->entity);
+ struct v4l2_mbus_frame_desc desc = { 0 };
+ struct ipu6_isys_stream *stream;
+ struct ipu6_isys_buffer_list bl;
u64 sink_streams;
int ret;
+ u8 vc;
- remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
- remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+ lockdep_assert_held(&csi2->isys->stream_mutex);
+
+ ret = ipu6_isys_get_frame_desc(remote_sd, remote_pad->index, &desc);
+ if (ret)
+ return ret;
+
+ list_add(&av->csi2_entry, &csi2->av_head);
sink_streams =
v4l2_subdev_state_xlate_streams(state, pad, CSI2_PAD_SINK,
&streams_mask);
+ csi2->stream_ids |= sink_streams;
- ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV);
- if (ret)
+ ret = ipu6_isys_csi2_streaming_change(asd, state, pad, &desc, &vc,
+ true);
+ if (!ret)
return ret;
+ if (ret < 0)
+ goto err_av_del;
+
+ ret = pm_runtime_resume_and_get(sd->dev);
+ if (ret < 0)
+ goto err_del_av;
- ret = ipu6_isys_csi2_set_stream(sd, &timing, csi2->nlanes, true);
+ ipu6_isys_csi2_setup_watermark(csi2, state, remote_sd);
+
+ stream = ipu6_isys_alloc_stream_firmware(csi2, state, &desc, vc);
+ if (IS_ERR(stream)) {
+ ret = PTR_ERR(stream);
+ dev_err(sd->dev, "allocating firmware stream failed\n");
+ goto err_clear_watermark;
+ }
+
+ ret = ipu6_isys_buffer_list_get(stream, &bl);
+ if (ret < 0) {
+ dev_warn(sd->dev, "no buffer available, DRIVER BUG?\n");
+ goto err_free_stream_firmware;
+ }
+
+ ret = ipu6_isys_start_stream_firmware(stream, &bl, &desc);
if (ret)
- return ret;
+ goto err_requeue_buffers;
- ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index,
- sink_streams);
- if (ret) {
- ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
- return ret;
+ if (!csi2->streaming_vc) {
+ ret = IS_IPU7(isp) ? ipu7_isys_csi2_stream_enable(csi2) :
+ ipu6_isys_csi2_stream_enable(csi2);
+ if (ret)
+ goto err_stop_stream_firmware;
}
+ ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index,
+ csi2->stream_ids);
+ if (ret)
+ goto err_stop_stream_csi2;
+
+ csi2->streaming_vc |= BIT(vc);
+
return 0;
+
+err_stop_stream_csi2:
+ if (IS_IPU7(isp))
+ ipu7_isys_csi2_stream_disable(csi2);
+ else
+ ipu6_isys_csi2_stream_disable(csi2);
+
+err_requeue_buffers:
+ ipu6_isys_buffer_list_queue(&bl, IPU6_ISYS_BUFFER_LIST_FL_INCOMING, 0);
+
+err_stop_stream_firmware:
+ ipu6_isys_stop_stream_firmware(stream);
+ ipu6_isys_close_stream_firmware(stream);
+
+err_free_stream_firmware:
+ ipu6_isys_free_stream_firmware(stream);
+
+err_clear_watermark:
+ ipu6_isys_csi2_clear_watermark(csi2);
+ pm_runtime_put(sd->dev);
+
+err_del_av:
+ ipu6_isys_csi2_streaming_change(asd, state, pad, &desc, NULL, false);
+ csi2->stream_ids &= ~sink_streams;
+err_av_del:
+ list_del(&av->csi2_entry);
+
+ return ret;
}
static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
u32 pad, u64 streams_mask)
{
- struct v4l2_subdev *remote_sd;
- struct media_pad *remote_pad;
+ struct media_pad *remote_pad =
+ media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]),
+ *vdev_pad = media_pad_remote_pad_unique(&sd->entity.pads[pad]);
+ struct ipu6_isys_video *av =
+ container_of_const(vdev_pad, struct ipu6_isys_video, pad);
+ struct v4l2_subdev *remote_sd =
+ media_entity_to_v4l2_subdev(remote_pad->entity);
+ 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_mbus_frame_desc desc = { 0 };
u64 sink_streams;
+ int ret;
+ u8 vc;
+
+ lockdep_assert_held(&csi2->isys->stream_mutex);
+
+ ret = ipu6_isys_get_frame_desc(remote_sd, remote_pad->index, &desc);
+ if (ret)
+ return ret;
sink_streams =
v4l2_subdev_state_xlate_streams(state, pad, CSI2_PAD_SINK,
&streams_mask);
- remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
- remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+ csi2->stream_ids &= ~sink_streams;
+
+ ret = ipu6_isys_csi2_streaming_change(asd, state, pad, &desc, &vc,
+ false);
+ if (ret <= 0)
+ goto out_del_csi2_entry;
+
+ csi2->streaming_vc &= ~BIT(vc);
+
+ struct ipu6_isys_stream *stream =
+ ipu6_isys_find_stream_firmware(csi2, vc);
+ ipu6_isys_stop_stream_firmware(stream);
- ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
+ 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);
+ v4l2_subdev_disable_streams(remote_sd, remote_pad->index,
+ csi2->stream_ids | sink_streams);
+
+ ipu6_isys_close_stream_firmware(stream);
+ ipu6_isys_free_stream_firmware(stream);
+
+ ipu6_isys_csi2_clear_watermark(csi2);
+
+ pm_runtime_put(sd->dev);
+
+out_del_csi2_entry:
+ list_del(&av->csi2_entry);
return 0;
}
static int ipu6_isys_csi2_set_sel(struct v4l2_subdev *sd,
+ const struct v4l2_subdev_client_info *ci,
struct v4l2_subdev_state *state,
struct v4l2_subdev_selection *sel)
{
@@ -454,6 +840,7 @@ static int ipu6_isys_csi2_set_sel(struct v4l2_subdev *sd,
}
static int ipu6_isys_csi2_get_sel(struct v4l2_subdev *sd,
+ const struct v4l2_subdev_client_info *ci,
struct v4l2_subdev_state *state,
struct v4l2_subdev_selection *sel)
{
@@ -542,6 +929,8 @@ int ipu6_isys_csi2_init(struct ipu6_isys_csi2 *csi2,
if (ret)
goto fail;
+ INIT_LIST_HEAD(&csi2->av_head);
+ INIT_LIST_HEAD(&csi2->streams);
csi2->asd.source = IPU6_FW_ISYS_STREAM_SRC_CSI2_PORT0 + index;
csi2->asd.supported_codes = csi2_supported_codes;
snprintf(csi2->asd.sd.name, sizeof(csi2->asd.sd.name),
@@ -592,56 +981,3 @@ void ipu6_isys_csi2_eof_event_by_stream(struct ipu6_isys_stream *stream)
dev_dbg(dev, "eof_event::csi2-%i sequence: %i\n",
csi2->port, frame_sequence);
}
-
-int ipu6_isys_csi2_get_remote_desc(u32 source_stream,
- struct ipu6_isys_csi2 *csi2,
- struct media_entity *source_entity,
- struct v4l2_mbus_frame_desc_entry *entry)
-{
- 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 *source;
- struct media_pad *pad;
- unsigned int i;
- int ret;
-
- source = media_entity_to_v4l2_subdev(source_entity);
- if (!source)
- return -EPIPE;
-
- pad = media_pad_remote_pad_first(&csi2->asd.pad[CSI2_PAD_SINK]);
- if (!pad)
- return -EPIPE;
-
- ret = v4l2_subdev_call(source, pad, get_frame_desc, pad->index, &desc);
- if (ret)
- return ret;
-
- if (desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
- dev_err(dev, "Unsupported frame descriptor type\n");
- return -EINVAL;
- }
-
- for (i = 0; i < desc.num_entries; i++) {
- if (source_stream == desc.entry[i].stream) {
- desc_entry = &desc.entry[i];
- break;
- }
- }
-
- if (!desc_entry) {
- dev_err(dev, "Failed to find stream %u from remote subdev\n",
- source_stream);
- return -EINVAL;
- }
-
- if (desc_entry->bus.csi2.vc >= NR_OF_CSI2_VC) {
- dev_err(dev, "invalid vc %d\n", desc_entry->bus.csi2.vc);
- return -EINVAL;
- }
-
- *entry = *desc_entry;
-
- return 0;
-}
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
index ce8eed91065c..1620ac16f90d 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
@@ -38,11 +41,22 @@ struct ipu6_isys_csi2 {
struct ipu6_isys_subdev asd;
struct ipu6_isys *isys;
struct ipu6_isys_video av[NR_OF_CSI2_SRC_PADS];
+ struct list_head av_head;
+ struct list_head streams;
+ struct ipu6_isys_stream *streams_by_vc[NR_OF_CSI2_VC];
void __iomem *base;
u32 receiver_errors;
unsigned int nlanes;
unsigned int port;
+ u32 legacy_irq_mask;
+ unsigned int phy_mode;
+ struct {
+ u32 stream_data_rate;
+ bool force_iwake_disable;
+ } watermark;
+ u32 streaming_vc;
+ u64 stream_ids;
};
struct ipu6_isys_csi2_timing {
@@ -70,9 +84,5 @@ void ipu6_isys_csi2_sof_event_by_stream(struct ipu6_isys_stream *stream);
void ipu6_isys_csi2_eof_event_by_stream(struct ipu6_isys_stream *stream);
void ipu6_isys_register_errors(struct ipu6_isys_csi2 *csi2);
void ipu6_isys_csi2_error(struct ipu6_isys_csi2 *csi2);
-int ipu6_isys_csi2_get_remote_desc(u32 source_stream,
- struct ipu6_isys_csi2 *csi2,
- struct media_entity *source_entity,
- struct v4l2_mbus_frame_desc_entry *entry);
#endif /* IPU6_ISYS_CSI2_H */
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
index fabaed63df0c..2608e3b91acb 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
@@ -21,6 +21,7 @@
#include "ipu6-dma.h"
#include "ipu6-fw-isys.h"
#include "ipu6-isys.h"
+#include "ipu6-isys-queue.h"
#include "ipu6-isys-video.h"
static int ipu6_isys_buf_init(struct vb2_buffer *vb)
@@ -191,8 +192,8 @@ static void flush_firmware_streamon_fail(struct ipu6_isys_stream *stream)
* that contains one entry from each video buffer queue. If a buffer can't be
* obtained from every queue, the buffers are returned back to the queue.
*/
-static int buffer_list_get(struct ipu6_isys_stream *stream,
- struct ipu6_isys_buffer_list *bl)
+int ipu6_isys_buffer_list_get(struct ipu6_isys_stream *stream,
+ struct ipu6_isys_buffer_list *bl)
{
struct device *dev = &stream->isys->adev->auxdev.dev;
struct ipu6_isys_queue *aq;
@@ -233,106 +234,53 @@ 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)
+static int ipu6_isys_stream_start(struct ipu6_isys_video *av)
{
- struct ipu6_isys_stream *stream = av->stream;
- struct device *dev = &stream->isys->adev->auxdev.dev;
- 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 device *dev = &adev->auxdev.dev;
+ struct ipu6_isys_buffer_list bl;
+ struct isys_fw_msgs *msg;
int ret;
- guard(mutex)(&stream->isys->stream_mutex);
- ret = ipu6_isys_video_set_streaming(av, 1, bl);
+ guard(mutex)(&av->isys->stream_mutex);
+ ret = ipu6_isys_video_set_streaming(av, 1);
if (ret)
- goto out_requeue;
+ return ret;
- stream->streaming = 1;
+ if (!av->stream || !(BIT(av->stream->vc) & av->csi2->streaming_vc))
+ return 0;
+
+ struct ipu6_isys_stream *stream = av->stream;
- bl = &__bl;
+ guard(mutex)(&stream->mutex);
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);
+ ret = ipu6_isys_buffer_list_get(stream, &bl);
if (ret < 0)
- break;
+ return 0;
msg = ipu6_get_fw_msg_buf(stream);
- if (!msg)
- return -ENOMEM;
-
- buf = &msg->fw_msg.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_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);
- } while (!WARN_ON(ret));
+ if (WARN_ON(!msg))
+ goto out_requeue;
+
+ 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 = fw_ops->stream_capture(stream->isys,
+ stream->stream_handle, msg);
+ if (WARN_ON(ret))
+ break;
+ } while (true);
- return 0;
+ /* Error handling begins here. */
+ ipu6_put_fw_msg_buf(stream->isys, msg);
out_requeue:
- if (bl && bl->nbufs)
- ipu6_isys_buffer_list_queue(bl,
+ if (bl.nbufs)
+ ipu6_isys_buffer_list_queue(&bl,
IPU6_ISYS_BUFFER_LIST_FL_INCOMING,
VB2_BUF_STATE_QUEUED);
flush_firmware_streamon_fail(stream);
@@ -344,13 +292,15 @@ 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 ipu6_fw_isys_frame_buff_set_abi *buf = NULL;
+ struct device *dev = &adev->auxdev.dev;
struct ipu6_isys_stream *stream = av->stream;
+ struct ipu6_isys_csi2 *csi2;
struct ipu6_isys_buffer_list bl;
struct isys_fw_msgs *msg;
unsigned long flags;
@@ -374,7 +324,8 @@ static void buf_queue(struct vb2_buffer *vb)
mutex_lock(&stream->mutex);
- if (stream->nr_streaming != stream->nr_queues) {
+ csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
+ if (!(BIT(stream->vc) & csi2->streaming_vc)) {
dev_dbg(dev, "not streaming yet, adding to incoming\n");
goto out;
}
@@ -384,7 +335,7 @@ static void buf_queue(struct vb2_buffer *vb)
* (above). Let's see whether all queues in the pipeline would
* have a buffer.
*/
- ret = buffer_list_get(stream, &bl);
+ ret = ipu6_isys_buffer_list_get(stream, &bl);
if (ret < 0) {
dev_dbg(dev, "No buffers available\n");
goto out;
@@ -396,9 +347,8 @@ static void buf_queue(struct vb2_buffer *vb)
goto out;
}
- buf = &msg->fw_msg.frame;
- ipu6_isys_buf_to_fw_frame_buf(buf, stream, &bl);
- ipu6_fw_isys_dump_frame_buff_set(dev, buf, 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
@@ -408,9 +358,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_complex_cmd(stream->isys, stream->stream_handle,
- buf, msg->dma_addr, sizeof(*buf),
- IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE);
+ ret = fw_ops->stream_capture(stream->isys, stream->stream_handle, msg);
if (ret < 0)
dev_err(dev, "send stream capture failed\n");
@@ -525,7 +473,6 @@ static void return_buffers(struct ipu6_isys_queue *aq,
static void ipu6_isys_stream_cleanup(struct ipu6_isys_video *av)
{
video_device_pipeline_stop(&av->vdev);
- ipu6_isys_put_stream(av->stream);
av->stream = NULL;
}
@@ -536,10 +483,8 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
struct device *dev = &av->isys->adev->auxdev.dev;
const struct ipu6_isys_pixelformat *pfmt =
ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
- struct ipu6_isys_buffer_list __bl, *bl = NULL;
- struct ipu6_isys_stream *stream;
struct media_pad *source_pad, *remote_pad;
- int nr_queues, ret;
+ int ret;
dev_dbg(dev, "stream: %s: width %u, height %u, css pixelformat %u\n",
av->vdev.name, ipu6_isys_get_frame_width(av),
@@ -559,11 +504,9 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
goto out_return_buffers;
}
- ret = ipu6_isys_setup_video(av, remote_pad, source_pad, &nr_queues);
- if (ret < 0) {
- dev_dbg(dev, "failed to setup video\n");
+ ret = video_device_pipeline_alloc_start(&av->vdev);
+ if (ret < 0)
goto out_return_buffers;
- }
ret = ipu6_isys_link_fmt_validate(aq);
if (ret) {
@@ -573,55 +516,12 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
goto out_pipeline_stop;
}
- ret = ipu6_isys_fw_open(av->isys);
+ ret = ipu6_isys_stream_start(av);
if (ret)
goto out_pipeline_stop;
- stream = av->stream;
- mutex_lock(&stream->mutex);
- if (!stream->nr_streaming) {
- ret = ipu6_isys_video_prepare_stream(av, source_pad->entity,
- nr_queues);
- if (ret)
- goto out_fw_close;
- }
-
- stream->nr_streaming++;
- dev_dbg(dev, "queue %u of %u\n", stream->nr_streaming,
- stream->nr_queues);
-
- list_add(&aq->node, &stream->queues);
- ipu6_isys_configure_stream_watermark(av, source_pad->entity);
- ipu6_isys_update_stream_watermark(av, true);
-
- if (stream->nr_streaming != stream->nr_queues)
- goto out;
-
- bl = &__bl;
- ret = buffer_list_get(stream, bl);
- if (ret < 0) {
- dev_warn(dev, "no buffer available, DRIVER BUG?\n");
- goto out;
- }
-
- ret = ipu6_isys_stream_start(av, bl);
- if (ret)
- goto out_stream_start;
-
-out:
- mutex_unlock(&stream->mutex);
-
return 0;
-out_stream_start:
- ipu6_isys_update_stream_watermark(av, false);
- list_del(&aq->node);
- stream->nr_streaming--;
-
-out_fw_close:
- mutex_unlock(&stream->mutex);
- ipu6_isys_fw_close(av->isys);
-
out_pipeline_stop:
ipu6_isys_stream_cleanup(av);
@@ -635,27 +535,14 @@ static void stop_streaming(struct vb2_queue *q)
{
struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q);
struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
- struct ipu6_isys_stream *stream = av->stream;
-
- mutex_lock(&stream->mutex);
-
- ipu6_isys_update_stream_watermark(av, false);
mutex_lock(&av->isys->stream_mutex);
- if (stream->nr_streaming == stream->nr_queues && stream->streaming)
- ipu6_isys_video_set_streaming(av, 0, NULL);
- list_del(&aq->node);
+ ipu6_isys_video_set_streaming(av, 0);
mutex_unlock(&av->isys->stream_mutex);
- stream->nr_streaming--;
- stream->streaming = 0;
- mutex_unlock(&stream->mutex);
-
ipu6_isys_stream_cleanup(av);
return_buffers(aq, VB2_BUF_STATE_ERROR);
-
- ipu6_isys_fw_close(av->isys);
}
static unsigned int
@@ -741,7 +628,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 dec1fed44dd2..0e0886f59150 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
@@ -60,11 +60,11 @@ 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,
+int ipu6_isys_buffer_list_get(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);
+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-subdev.c b/drivers/media/pci/intel/ipu6/ipu6-isys-subdev.c
index dbd6f76a066d..60070842ee68 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-subdev.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-subdev.c
@@ -160,6 +160,7 @@ u32 ipu6_isys_convert_bayer_order(u32 code, int x, int y)
}
int ipu6_isys_subdev_set_fmt(struct v4l2_subdev *sd,
+ const struct v4l2_subdev_client_info *ci,
struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format)
{
@@ -265,17 +266,13 @@ static int subdev_set_routing(struct v4l2_subdev *sd,
return v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
}
-u32 ipu6_isys_get_src_stream_by_src_pad(struct v4l2_subdev *sd, u32 pad)
+u32 __ipu6_isys_get_src_stream_by_src_pad(struct v4l2_subdev_state *state,
+ u32 pad)
{
- struct v4l2_subdev_state *state;
struct v4l2_subdev_route *routes;
unsigned int i;
u32 source_stream = 0;
- state = v4l2_subdev_lock_and_get_active_state(sd);
- if (!state)
- return 0;
-
routes = state->routing.routes;
for (i = 0; i < state->routing.num_routes; i++) {
if (routes[i].source_pad == pad) {
@@ -284,6 +281,20 @@ u32 ipu6_isys_get_src_stream_by_src_pad(struct v4l2_subdev *sd, u32 pad)
}
}
+ return source_stream;
+}
+
+u32 ipu6_isys_get_src_stream_by_src_pad(struct v4l2_subdev *sd, u32 pad)
+{
+ struct v4l2_subdev_state *state;
+ u32 source_stream = 0;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+ if (!state)
+ return 0;
+
+ source_stream = __ipu6_isys_get_src_stream_by_src_pad(state, pad);
+
v4l2_subdev_unlock_state(state);
return source_stream;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-subdev.h b/drivers/media/pci/intel/ipu6/ipu6-isys-subdev.h
index 35069099c364..b892d96992af 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-subdev.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-subdev.h
@@ -31,12 +31,15 @@ bool ipu6_isys_is_bayer_format(u32 code);
u32 ipu6_isys_convert_bayer_order(u32 code, int x, int y);
int ipu6_isys_subdev_set_fmt(struct v4l2_subdev *sd,
+ const struct v4l2_subdev_client_info *ci,
struct v4l2_subdev_state *state,
struct v4l2_subdev_format *fmt);
int ipu6_isys_subdev_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_mbus_code_enum
*code);
+u32 __ipu6_isys_get_src_stream_by_src_pad(struct v4l2_subdev_state *state,
+ u32 pad);
u32 ipu6_isys_get_src_stream_by_src_pad(struct v4l2_subdev *sd, u32 pad);
int ipu6_isys_subdev_set_routing(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index 3ac48d2076da..129016e57446 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -432,185 +432,110 @@ unlock:
return ret;
}
-static void get_stream_opened(struct ipu6_isys_video *av)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&av->isys->streams_lock, flags);
- av->isys->stream_opened++;
- spin_unlock_irqrestore(&av->isys->streams_lock, flags);
-}
+int ipu6_isys_fw_pins_prepare(struct ipu6_isys_stream *stream,
+ struct v4l2_mbus_frame_desc *desc,
+ int (*fw_pin_cfg)(struct ipu6_isys_video *av,
+ struct ipu6_isys_stream *stream,
+ struct media_pad *src_pad,
+ struct v4l2_mbus_frame_desc_entry *entry,
+ void *__cfg), void *stream_cfg)
+{
+ struct v4l2_subdev_state *csi2_state =
+ v4l2_subdev_get_locked_active_state(&stream->asd->sd);
+ struct device *dev = &stream->isys->adev->auxdev.dev;
+ struct ipu6_isys_queue *aq;
-static void put_stream_opened(struct ipu6_isys_video *av)
-{
- unsigned long flags;
+ list_for_each_entry(aq, &stream->queues, node) {
+ struct ipu6_isys_video *__av = ipu6_isys_queue_to_video(aq);
+ struct media_pad *remote_pad =
+ media_pad_remote_pad_first(&__av->pad);
+ u64 source_streams = 1;
+ unsigned int sink_stream =
+ __ffs(v4l2_subdev_state_xlate_streams(csi2_state,
+ remote_pad->index,
+ CSI2_PAD_SINK,
+ &source_streams));
+ struct v4l2_mbus_frame_desc_entry *entry = NULL;
+ int ret;
+
+ for (unsigned int i = 0; i < desc->num_entries; i++) {
+ if (desc->entry[i].stream == sink_stream) {
+ entry = &desc->entry[i];
+ break;
+ }
+ }
- spin_lock_irqsave(&av->isys->streams_lock, flags);
- av->isys->stream_opened--;
- spin_unlock_irqrestore(&av->isys->streams_lock, flags);
-}
+ if (!entry) {
+ dev_err(dev, "cannot find frame desc entry for sink stream %u\n",
+ sink_stream);
+ return -EINVAL;
+ }
-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;
+ ret = fw_pin_cfg(__av, stream, remote_pad, entry, stream_cfg);
+ if (ret < 0)
+ return ret;
+ }
return 0;
}
-static int start_stream_firmware(struct ipu6_isys_video *av,
- struct ipu6_isys_buffer_list *bl)
+int ipu6_isys_start_stream_firmware(struct ipu6_isys_stream *stream,
+ struct ipu6_isys_buffer_list *bl,
+ struct v4l2_mbus_frame_desc *desc)
{
- 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 ipu6_bus_device *adev = stream->asd->isys->adev;
+ const struct ipu6_fw_isys_ops *fw_ops = adev->auxdrv_data->fw_ops;
+ struct device *dev = &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->fw_msg.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, (uintptr_t)stream_cfg);
- return ret;
- }
+ ret = fw_ops->prepare_stream_cfg(stream, desc, msg);
+ if (ret < 0) {
+ ipu6_put_fw_msg_buf(stream->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 = fw_ops->stream_open(stream->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, (uintptr_t)stream_cfg);
+ ipu6_put_fw_msg_buf(stream->isys, msg);
return ret;
}
- get_stream_opened(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(stream->isys, msg);
if (!tout) {
dev_err(dev, "stream open time out\n");
- ret = -ETIMEDOUT;
- goto out_put_stream_opened;
+ return -ETIMEDOUT;
}
if (stream->error) {
dev_err(dev, "stream open error: %d\n", stream->error);
- ret = -EIO;
- goto out_put_stream_opened;
+ return -EIO;
}
dev_dbg(dev, "start stream: open complete\n");
- if (bl) {
- msg = ipu6_get_fw_msg_buf(stream);
- if (!msg) {
- ret = -ENOMEM;
- goto out_put_stream_opened;
- }
- buf = &msg->fw_msg.frame;
- ipu6_isys_buf_to_fw_frame_buf(buf, stream, bl);
- ipu6_isys_buffer_list_queue(bl,
- IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
+ msg = ipu6_get_fw_msg_buf(stream);
+ if (!msg) {
+ return -ENOMEM;
}
- reinit_completion(&stream->stream_start_completion);
+ fw_ops->prepare_buf_set(msg, stream, bl);
+ ipu6_isys_buffer_list_queue(bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
- 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);
- }
+ reinit_completion(&stream->stream_start_completion);
+ ret = fw_ops->stream_start(stream->isys, stream->stream_handle, msg,
+ capture);
if (ret < 0) {
dev_err(dev, "can't start streaming (%d)\n", ret);
goto out_stream_close;
@@ -635,12 +560,10 @@ 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 = fw_ops->stream_close(stream->isys, stream->stream_handle);
if (retout < 0) {
dev_dbg(dev, "can't close stream (%d)\n", retout);
- goto out_put_stream_opened;
+ return retout;
}
tout = wait_for_completion_timeout(&stream->stream_close_completion,
@@ -652,23 +575,19 @@ out_stream_close:
else
dev_dbg(dev, "stream close complete\n");
-out_put_stream_opened:
- put_stream_opened(av);
-
return ret;
}
-static void stop_streaming_firmware(struct ipu6_isys_video *av)
+void ipu6_isys_stop_stream_firmware(struct ipu6_isys_stream *stream)
{
- struct device *dev = &av->isys->adev->auxdev.dev;
- struct ipu6_isys_stream *stream = av->stream;
+ struct ipu6_bus_device *adev = stream->asd->isys->adev;
+ const struct ipu6_fw_isys_ops *fw_ops = adev->auxdrv_data->fw_ops;
+ struct device *dev = &adev->auxdev.dev;
int ret, tout;
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 = fw_ops->stream_flush(stream->isys, stream->stream_handle);
if (ret < 0) {
dev_err(dev, "can't stop stream (%d)\n", ret);
return;
@@ -684,16 +603,17 @@ static void stop_streaming_firmware(struct ipu6_isys_video *av)
dev_dbg(dev, "stop stream: complete\n");
}
-static void close_streaming_firmware(struct ipu6_isys_video *av)
+void ipu6_isys_close_stream_firmware(struct ipu6_isys_stream *stream)
{
- struct ipu6_isys_stream *stream = av->stream;
- struct device *dev = &av->isys->adev->auxdev.dev;
+ struct ipu6_bus_device *adev = stream->asd->isys->adev;
+ const struct ipu6_fw_isys_ops *fw_ops = adev->auxdrv_data->fw_ops;
+ struct device *dev = &adev->auxdev.dev;
+ struct ipu6_isys_csi2 *csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
int ret, tout;
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 = fw_ops->stream_close(stream->isys, stream->stream_handle);
if (ret < 0) {
dev_err(dev, "can't close stream (%d)\n", ret);
return;
@@ -708,349 +628,153 @@ static void close_streaming_firmware(struct ipu6_isys_video *av)
else
dev_dbg(dev, "close stream: complete\n");
- put_stream_opened(av);
+ scoped_guard(spinlock_irqsave, &stream->isys->streams_lock) {
+ stream->isys->streams_by_handle[stream->stream_handle] = NULL;
+ csi2->streams_by_vc[stream->vc] = NULL;
+ }
}
-int ipu6_isys_video_prepare_stream(struct ipu6_isys_video *av,
- struct media_entity *source_entity,
- int nr_queues)
+struct ipu6_isys_stream *
+ipu6_isys_find_stream_firmware(struct ipu6_isys_csi2 *csi2, u8 vc)
{
- struct ipu6_isys_stream *stream = av->stream;
- struct ipu6_isys_csi2 *csi2;
+ struct ipu6_isys_stream *stream;
- if (WARN_ON(stream->nr_streaming))
- return -EINVAL;
+ list_for_each_entry(stream, &csi2->streams, csi2_entry)
+ if (stream->vc == vc)
+ return stream;
- stream->nr_queues = nr_queues;
- atomic_set(&stream->sequence, 0);
-
- stream->seq_index = 0;
- memset(stream->seq, 0, sizeof(stream->seq));
-
- if (WARN_ON(!list_empty(&stream->queues)))
- return -EINVAL;
-
- stream->stream_source = stream->asd->source;
- csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
- csi2->receiver_errors = 0;
-
- dev_dbg(&av->isys->adev->auxdev.dev,
- "prepare stream: external entity %s\n",
- source_entity->name);
-
- return 0;
+ return NULL;
}
-void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av,
- struct media_entity *source)
+void ipu6_isys_free_stream_firmware(struct ipu6_isys_stream *stream)
{
- struct ipu6_isys *isys = av->isys;
- struct ipu6_isys_csi2 *csi2 = NULL;
- struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark;
- struct device *dev = &isys->adev->auxdev.dev;
- struct v4l2_mbus_framefmt format;
- struct v4l2_subdev *esd;
- struct v4l2_control hb = { .id = V4L2_CID_HBLANK, .value = 0 };
- unsigned int bpp, lanes;
- s64 link_freq = 0;
- u64 pixel_rate = 0;
- int ret;
-
- esd = media_entity_to_v4l2_subdev(source);
-
- av->watermark.width = ipu6_isys_get_frame_width(av);
- av->watermark.height = ipu6_isys_get_frame_height(av);
- av->watermark.sram_gran_shift = isys->pdata->ipdata->sram_gran_shift;
- av->watermark.sram_gran_size = isys->pdata->ipdata->sram_gran_size;
-
- ret = v4l2_g_ctrl(esd->ctrl_handler, &hb);
- if (!ret && hb.value >= 0)
- av->watermark.hblank = hb.value;
- else
- av->watermark.hblank = 0;
-
- csi2 = ipu6_isys_subdev_to_csi2(av->stream->asd);
- link_freq = ipu6_isys_csi2_get_link_freq(csi2);
- if (link_freq > 0) {
- struct v4l2_subdev_state *state =
- v4l2_subdev_lock_and_get_active_state(&csi2->asd.sd);
-
- lanes = csi2->nlanes;
- format = *v4l2_subdev_state_get_format(state, 0,
- av->source_stream);
- bpp = ipu6_isys_mbus_code_to_bpp(format.code);
- pixel_rate = mul_u64_u32_div(link_freq, lanes * 2, bpp);
+ struct ipu6_isys_csi2 *csi2 = ipu6_isys_subdev_to_csi2(stream->asd);
+ struct ipu6_isys_queue *aq, *aq_safe;
- v4l2_subdev_unlock_state(state);
- }
-
- av->watermark.pixel_rate = pixel_rate;
+ list_for_each_entry_safe(aq, aq_safe, &stream->queues, node) {
+ struct ipu6_isys_video *av =
+ container_of_const(aq, struct ipu6_isys_video, aq);
- if (!pixel_rate) {
- mutex_lock(&iwake_watermark->mutex);
- iwake_watermark->force_iwake_disable = true;
- mutex_unlock(&iwake_watermark->mutex);
- dev_warn(dev, "unexpected pixel_rate from %s, disable iwake.\n",
- source->name);
+ list_del(&aq->node);
+ av->stream = NULL;
}
-}
-static void calculate_stream_datarate(struct ipu6_isys_video *av)
-{
- struct video_stream_watermark *watermark = &av->watermark;
- const struct ipu6_isys_pixelformat *pfmt =
- ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
- u32 pages_per_line, pb_bytes_per_line, pixels_per_line, bytes_per_line;
- u64 line_time_ns, stream_data_rate;
- u16 shift, size;
-
- shift = watermark->sram_gran_shift;
- size = watermark->sram_gran_size;
-
- pixels_per_line = watermark->width + watermark->hblank;
- line_time_ns = div_u64(pixels_per_line * NSEC_PER_SEC,
- watermark->pixel_rate);
- bytes_per_line = watermark->width * pfmt->bpp / 8;
- pages_per_line = DIV_ROUND_UP(bytes_per_line, size);
- pb_bytes_per_line = pages_per_line << shift;
- stream_data_rate = div64_u64(pb_bytes_per_line * 1000, line_time_ns);
-
- watermark->stream_data_rate = stream_data_rate;
+ list_del(&stream->csi2_entry);
+ ida_free(&csi2->isys->streams, stream->stream_handle);
+ kfree(stream);
}
-void ipu6_isys_update_stream_watermark(struct ipu6_isys_video *av, bool state)
-{
- struct isys_iwake_watermark *iwake_watermark =
- &av->isys->iwake_watermark;
-
- if (!av->watermark.pixel_rate)
- return;
+struct ipu6_isys_stream *
+ipu6_isys_alloc_stream_firmware(struct ipu6_isys_csi2 *csi2,
+ struct v4l2_subdev_state *csi2_state,
+ struct v4l2_mbus_frame_desc *desc,
+ u8 vc)
+{
+ struct device *dev = &csi2->isys->adev->auxdev.dev;
+ struct ipu6_isys_stream *stream;
+ struct v4l2_subdev_route *route;
+ int ret;
- if (state) {
- calculate_stream_datarate(av);
- mutex_lock(&iwake_watermark->mutex);
- list_add(&av->watermark.stream_node,
- &iwake_watermark->video_list);
- mutex_unlock(&iwake_watermark->mutex);
- } else {
- av->watermark.stream_data_rate = 0;
- mutex_lock(&iwake_watermark->mutex);
- list_del(&av->watermark.stream_node);
- mutex_unlock(&iwake_watermark->mutex);
- }
+ stream = kzalloc_obj(*stream);
+ if (!stream)
+ return ERR_PTR(-ENOMEM);
- update_watermark_setting(av->isys);
-}
+ ret = ida_alloc_max(&csi2->isys->streams, IPU6_ISYS_MAX_STREAMS - 1,
+ GFP_KERNEL);
+ if (ret < 0)
+ goto err_free_stream;
-void ipu6_isys_put_stream(struct ipu6_isys_stream *stream)
-{
- struct device *dev;
- unsigned int i;
- unsigned long flags;
+ stream->stream_handle = ret;
+ mutex_init(&stream->mutex);
+ init_completion(&stream->stream_open_completion);
+ init_completion(&stream->stream_close_completion);
+ init_completion(&stream->stream_start_completion);
+ init_completion(&stream->stream_stop_completion);
+ INIT_LIST_HEAD(&stream->queues);
+ stream->isys = csi2->asd.isys;
+ stream->asd = &csi2->asd;
+ stream->vc = vc;
- if (!stream) {
- pr_err("ipu6-isys: no available stream\n");
- return;
+ scoped_guard(spinlock_irqsave, &stream->isys->streams_lock) {
+ stream->isys->streams_by_handle[stream->stream_handle] = stream;
+ csi2->streams_by_vc[stream->vc] = stream;
}
- dev = &stream->isys->adev->auxdev.dev;
-
- spin_lock_irqsave(&stream->isys->streams_lock, flags);
- for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
- if (&stream->isys->streams[i] == stream) {
- if (stream->isys->streams_ref_count[i] > 0)
- stream->isys->streams_ref_count[i]--;
- else
- dev_warn(dev, "invalid stream %d\n", i);
-
- break;
- }
- }
- spin_unlock_irqrestore(&stream->isys->streams_lock, flags);
-}
+ list_add(&stream->csi2_entry, &csi2->streams);
-static struct ipu6_isys_stream *
-ipu6_isys_get_stream(struct ipu6_isys_video *av, struct ipu6_isys_subdev *asd)
-{
- struct ipu6_isys_stream *stream = NULL;
- struct ipu6_isys *isys = av->isys;
- unsigned long flags;
- unsigned int i;
- u8 vc = av->vc;
+ for_each_active_route(&csi2_state->routing, route) {
+ struct media_pad *vdev_pad =
+ media_pad_remote_pad_first(&csi2->asd.pad[route->source_pad]);
+ struct v4l2_mbus_frame_desc_entry *entry = NULL;
- if (!isys)
- return NULL;
+ for (unsigned int i = 0; i < desc->num_entries; i++) {
+ if (desc->entry[i].stream != route->sink_stream)
+ continue;
- spin_lock_irqsave(&isys->streams_lock, flags);
- for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
- if (isys->streams_ref_count[i] && isys->streams[i].vc == vc &&
- isys->streams[i].asd == asd) {
- isys->streams_ref_count[i]++;
- stream = &isys->streams[i];
+ entry = &desc->entry[i];
break;
}
- }
- if (!stream) {
- for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
- if (!isys->streams_ref_count[i]) {
- isys->streams_ref_count[i]++;
- stream = &isys->streams[i];
- stream->vc = vc;
- stream->asd = asd;
- break;
- }
+ if (!entry) {
+ dev_dbg(dev, "cannot find stream %u in frame desc\n",
+ route->sink_stream);
+ ret = -EINVAL;
+ goto err_ida_free;
}
- }
- spin_unlock_irqrestore(&isys->streams_lock, flags);
-
- return stream;
-}
-struct ipu6_isys_stream *
-ipu6_isys_query_stream_by_handle(struct ipu6_isys *isys, u8 stream_handle)
-{
- unsigned long flags;
- struct ipu6_isys_stream *stream = NULL;
-
- if (!isys)
- return NULL;
-
- if (stream_handle >= IPU6_ISYS_MAX_STREAMS) {
- dev_err(&isys->adev->auxdev.dev,
- "stream_handle %d is invalid\n", stream_handle);
- return NULL;
- }
-
- spin_lock_irqsave(&isys->streams_lock, flags);
- if (isys->streams_ref_count[stream_handle] > 0) {
- isys->streams_ref_count[stream_handle]++;
- stream = &isys->streams[stream_handle];
- }
- spin_unlock_irqrestore(&isys->streams_lock, flags);
-
- return stream;
-}
-
-struct ipu6_isys_stream *
-ipu6_isys_query_stream_by_source(struct ipu6_isys *isys, int source, u8 vc)
-{
- struct ipu6_isys_stream *stream = NULL;
- unsigned long flags;
- unsigned int i;
-
- if (!isys)
- return NULL;
+ if (entry->bus.csi2.vc != vc)
+ continue;
- if (source < 0) {
- dev_err(&isys->adev->auxdev.dev,
- "query stream with invalid port number\n");
- return NULL;
- }
+ struct ipu6_isys_video *av =
+ container_of_const(vdev_pad, struct ipu6_isys_video,
+ pad);
- spin_lock_irqsave(&isys->streams_lock, flags);
- for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
- if (!isys->streams_ref_count[i])
- continue;
+ list_add(&av->aq.node, &stream->queues);
- if (isys->streams[i].stream_source == source &&
- isys->streams[i].vc == vc) {
- stream = &isys->streams[i];
- isys->streams_ref_count[i]++;
- break;
- }
+ stream->nr_output_pins++;
+ av->stream = stream;
}
- spin_unlock_irqrestore(&isys->streams_lock, flags);
return stream;
-}
-
-static u64 get_stream_mask_by_pipeline(struct ipu6_isys_video *__av)
-{
- struct media_pipeline *pipeline =
- media_entity_pipeline(&__av->vdev.entity);
- unsigned int i;
- u64 stream_mask = 0;
- for (i = 0; i < NR_OF_CSI2_SRC_PADS; i++) {
- struct ipu6_isys_video *av = &__av->csi2->av[i];
+err_ida_free:
+ list_del(&stream->csi2_entry);
+ ida_free(&csi2->isys->streams, stream->stream_handle);
- if (pipeline == media_entity_pipeline(&av->vdev.entity))
- stream_mask |= BIT_ULL(av->source_stream);
- }
+err_free_stream:
+ kfree(stream);
- return stream_mask;
+ return ERR_PTR(ret);
}
-int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
- struct ipu6_isys_buffer_list *bl)
+int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state)
{
- struct v4l2_subdev_krouting *routing;
- struct ipu6_isys_stream *stream = av->stream;
- struct v4l2_subdev_state *subdev_state;
struct device *dev = &av->isys->adev->auxdev.dev;
struct v4l2_subdev *sd;
struct media_pad *r_pad;
- u32 sink_pad, sink_stream;
- u64 r_stream;
- u64 stream_mask = 0;
int ret = 0;
- dev_dbg(dev, "set stream: %d\n", state);
-
- sd = &stream->asd->sd;
+ sd = &av->csi2->asd.sd;
r_pad = media_pad_remote_pad_first(&av->pad);
- r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index);
-
- subdev_state = v4l2_subdev_lock_and_get_active_state(sd);
- routing = &subdev_state->routing;
- ret = v4l2_subdev_routing_find_opposite_end(routing, r_pad->index,
- r_stream, &sink_pad,
- &sink_stream);
- v4l2_subdev_unlock_state(subdev_state);
- if (ret)
- return ret;
- stream_mask = get_stream_mask_by_pipeline(av);
if (!state) {
- stop_streaming_firmware(av);
-
/* stop sub-device which connects with video */
- dev_dbg(dev, "stream off entity %s pad:%d mask:0x%llx\n",
- sd->name, r_pad->index, stream_mask);
- ret = v4l2_subdev_disable_streams(sd, r_pad->index,
- stream_mask);
+ dev_dbg(dev, "stream off %s pad:%d\n", sd->name, r_pad->index);
+ ret = v4l2_subdev_disable_streams(sd, r_pad->index, 1);
if (ret)
dev_err(dev, "stream off %s failed with %d\n", sd->name,
ret);
-
- close_streaming_firmware(av);
} else {
- ret = start_stream_firmware(av, bl);
- if (ret) {
- dev_err(dev, "start stream of firmware failed\n");
- return ret;
- }
-
/* start sub-device which connects with video */
- dev_dbg(dev, "stream on %s pad %d mask 0x%llx\n", sd->name,
- r_pad->index, stream_mask);
- ret = v4l2_subdev_enable_streams(sd, r_pad->index, stream_mask);
- if (ret) {
+ dev_dbg(dev, "stream on %s pad %d\n", sd->name, r_pad->index);
+ ret = v4l2_subdev_enable_streams(sd, r_pad->index, 1);
+ if (ret)
dev_err(dev, "stream on %s failed with %d\n", sd->name,
ret);
- goto out_media_entity_stop_streaming_firmware;
- }
}
av->streaming = state;
- return 0;
-
-out_media_entity_stop_streaming_firmware:
- stop_streaming_firmware(av);
- close_streaming_firmware(av);
-
return ret;
}
@@ -1089,148 +813,6 @@ static const struct v4l2_file_operations isys_fops = {
.release = vb2_fop_release,
};
-int ipu6_isys_fw_open(struct ipu6_isys *isys)
-{
- struct ipu6_bus_device *adev = isys->adev;
- const struct ipu6_isys_internal_pdata *ipdata = isys->pdata->ipdata;
- int ret;
-
- ret = pm_runtime_resume_and_get(&adev->auxdev.dev);
- if (ret < 0)
- return ret;
-
- mutex_lock(&isys->mutex);
-
- if (isys->ref_count++)
- goto unlock;
-
- ipu6_configure_spc(adev->isp, &ipdata->hw_variant,
- IPU6_CPD_PKG_DIR_ISYS_SERVER_IDX, isys->pdata->base,
- adev->pkg_dir, adev->pkg_dir_dma_addr);
-
- /*
- * Buffers could have been left to wrong queue at last closure.
- * Move them now back to empty buffer queue.
- */
- ipu6_cleanup_fw_msg_bufs(isys);
-
- if (isys->fwcom) {
- /*
- * Something went wrong in previous shutdown. As we are now
- * restarting isys we can safely delete old context.
- */
- dev_warn(&adev->auxdev.dev, "clearing old context\n");
- ipu6_fw_isys_cleanup(isys);
- }
-
- ret = ipu6_fw_isys_init(isys, ipdata->num_parallel_streams);
- if (ret < 0)
- goto out;
-
-unlock:
- mutex_unlock(&isys->mutex);
-
- return 0;
-
-out:
- isys->ref_count--;
- mutex_unlock(&isys->mutex);
- pm_runtime_put(&adev->auxdev.dev);
-
- return ret;
-}
-
-void ipu6_isys_fw_close(struct ipu6_isys *isys)
-{
- mutex_lock(&isys->mutex);
-
- isys->ref_count--;
- if (!isys->ref_count) {
- ipu6_fw_isys_close(isys);
- if (isys->fwcom) {
- isys->need_reset = true;
- dev_warn(&isys->adev->auxdev.dev,
- "failed to close fw isys\n");
- }
- }
-
- mutex_unlock(&isys->mutex);
-
- if (isys->need_reset)
- pm_runtime_put_sync(&isys->adev->auxdev.dev);
- else
- pm_runtime_put(&isys->adev->auxdev.dev);
-}
-
-int ipu6_isys_setup_video(struct ipu6_isys_video *av,
- struct media_pad *remote_pad,
- struct media_pad *source_pad, int *nr_queues)
-{
- const struct ipu6_isys_pixelformat *pfmt =
- ipu6_isys_get_isys_format(ipu6_isys_get_format(av), 0);
- struct device *dev = &av->isys->adev->auxdev.dev;
- struct v4l2_mbus_frame_desc_entry entry;
- struct v4l2_subdev_route *route = NULL;
- struct v4l2_subdev_route *r;
- struct v4l2_subdev_state *state;
- struct v4l2_subdev *remote_sd =
- media_entity_to_v4l2_subdev(remote_pad->entity);
- struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(remote_sd);
- int ret = -EINVAL;
-
- *nr_queues = 0;
-
- /* Find the root */
- state = v4l2_subdev_lock_and_get_active_state(remote_sd);
- for_each_active_route(&state->routing, r) {
- (*nr_queues)++;
-
- if (r->source_pad == remote_pad->index)
- route = r;
- }
-
- if (!route) {
- v4l2_subdev_unlock_state(state);
- dev_dbg(dev, "Failed to find route\n");
- return -ENODEV;
- }
- av->source_stream = route->sink_stream;
- v4l2_subdev_unlock_state(state);
-
- ret = ipu6_isys_csi2_get_remote_desc(av->source_stream,
- to_ipu6_isys_csi2(asd),
- source_pad->entity, &entry);
- if (ret == -ENOIOCTLCMD) {
- av->vc = 0;
- av->dt = ipu6_isys_mbus_code_to_mipi(pfmt->code);
- } else if (!ret) {
- dev_dbg(dev, "Framedesc: stream %u, len %u, vc %u, dt %#x\n",
- entry.stream, entry.length, entry.bus.csi2.vc,
- entry.bus.csi2.dt);
-
- av->vc = entry.bus.csi2.vc;
- av->dt = entry.bus.csi2.dt;
- } else {
- dev_err(dev, "failed to get remote frame desc\n");
- return ret;
- }
-
- ret = video_device_pipeline_alloc_start(&av->vdev);
- if (ret < 0) {
- dev_dbg(dev, "media pipeline start failed\n");
- return ret;
- }
-
- av->stream = ipu6_isys_get_stream(av, asd);
- if (!av->stream) {
- video_device_pipeline_stop(&av->vdev);
- dev_err(dev, "no available stream for firmware\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
/*
* Do everything that's needed to initialise things related to video
* buffer queue, video node, and the related media entity. The caller
@@ -1262,7 +844,7 @@ int ipu6_isys_video_init(struct ipu6_isys_video *av)
ret = ipu6_isys_queue_init(&av->aq);
if (ret)
- goto out_free_watermark;
+ goto out_mutex_destroy;
av->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
ret = media_entity_pads_init(&av->vdev.entity, 1, &av->pad);
@@ -1299,7 +881,7 @@ out_media_entity_cleanup:
out_vb2_queue_release:
vb2_queue_release(&av->aq.vbq);
-out_free_watermark:
+out_mutex_destroy:
mutex_destroy(&av->mutex);
return ret;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.h b/drivers/media/pci/intel/ipu6/ipu6-isys-video.h
index 2ff53315d7b9..2821b9b1b943 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.h
@@ -22,6 +22,7 @@ struct file;
struct ipu6_isys;
struct ipu6_isys_csi2;
struct ipu6_isys_subdev;
+struct v4l2_mbus_frame_desc;
struct ipu6_isys_pixelformat {
u32 pixelformat;
@@ -44,17 +45,15 @@ 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;
int stream_handle;
unsigned int nr_output_pins;
struct ipu6_isys_subdev *asd;
-
- int nr_queues; /* Number of capture queues */
- int nr_streaming;
- int streaming; /* Has streaming been really started? */
struct list_head queues;
+ struct list_head csi2_entry;
+
struct completion stream_open_completion;
struct completion stream_close_completion;
struct completion stream_start_completion;
@@ -66,20 +65,9 @@ struct ipu6_isys_stream {
u8 vc;
};
-struct video_stream_watermark {
- u32 width;
- u32 height;
- u32 hblank;
- u32 frame_rate;
- u64 pixel_rate;
- u64 stream_data_rate;
- u16 sram_gran_shift;
- u16 sram_gran_size;
- struct list_head stream_node;
-};
-
struct ipu6_isys_video {
struct ipu6_isys_queue aq;
+ struct list_head csi2_entry;
/* Serialise access to other fields in the struct. */
struct mutex mutex;
struct media_pad pad;
@@ -90,10 +78,7 @@ struct ipu6_isys_video {
struct ipu6_isys_csi2 *csi2;
struct ipu6_isys_stream *stream;
unsigned int streaming;
- struct video_stream_watermark watermark;
u32 source_stream;
- u8 vc;
- u8 dt;
};
#define ipu6_isys_queue_to_video(__aq) \
@@ -104,27 +89,34 @@ extern const struct ipu6_isys_pixelformat ipu6_isys_pfmts_packed[];
const struct ipu6_isys_pixelformat *
ipu6_isys_get_isys_format(u32 pixelformat, u32 code);
-int ipu6_isys_video_prepare_stream(struct ipu6_isys_video *av,
- struct media_entity *source_entity,
- int nr_queues);
-int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
- struct ipu6_isys_buffer_list *bl);
+int ipu6_isys_fw_pins_prepare(struct ipu6_isys_stream *stream,
+ struct v4l2_mbus_frame_desc *desc,
+ int (*fw_pin_cfg)(struct ipu6_isys_video *av,
+ struct ipu6_isys_stream *stream,
+ struct media_pad *src_pad,
+ struct v4l2_mbus_frame_desc_entry *entry,
+ void *__cfg), void *stream_cfg);
+int ipu6_isys_start_stream_firmware(struct ipu6_isys_stream *stream,
+ struct ipu6_isys_buffer_list *bl,
+ struct v4l2_mbus_frame_desc *desc);
+void ipu6_isys_stop_stream_firmware(struct ipu6_isys_stream *stream);
+void ipu6_isys_close_stream_firmware(struct ipu6_isys_stream *stream);
+struct ipu6_isys_stream *
+ipu6_isys_find_stream_firmware(struct ipu6_isys_csi2 *csi2, u8 vc);
+void ipu6_isys_free_stream_firmware(struct ipu6_isys_stream *stream);
+struct ipu6_isys_stream *
+ipu6_isys_alloc_stream_firmware(struct ipu6_isys_csi2 *csi2,
+ struct v4l2_subdev_state *state,
+ struct v4l2_mbus_frame_desc *desc,
+ u8 vc);
+int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state);
int ipu6_isys_fw_open(struct ipu6_isys *isys);
void ipu6_isys_fw_close(struct ipu6_isys *isys);
int ipu6_isys_setup_video(struct ipu6_isys_video *av,
struct media_pad *remote_pad,
- struct media_pad *source_pad, int *nr_queues);
+ struct media_pad *source_pad);
int ipu6_isys_video_init(struct ipu6_isys_video *av);
void ipu6_isys_video_cleanup(struct ipu6_isys_video *av);
-void ipu6_isys_put_stream(struct ipu6_isys_stream *stream);
-struct ipu6_isys_stream *
-ipu6_isys_query_stream_by_handle(struct ipu6_isys *isys, u8 stream_handle);
-struct ipu6_isys_stream *
-ipu6_isys_query_stream_by_source(struct ipu6_isys *isys, int source, u8 vc);
-
-void ipu6_isys_configure_stream_watermark(struct ipu6_isys_video *av,
- struct media_entity *source);
-void ipu6_isys_update_stream_watermark(struct ipu6_isys_video *av, bool state);
u32 ipu6_isys_get_format(struct ipu6_isys_video *av);
u32 ipu6_isys_get_data_size(struct ipu6_isys_video *av);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index 24db2763de54..60f5f9ea2910 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
@@ -98,9 +101,28 @@ enum ltr_did_type {
LTR_TYPE_MAX
};
-#define ISYS_PM_QOS_VALUE 300
+struct ltr_did {
+ union {
+ u32 value;
+ struct {
+ u8 val0;
+ u8 val1;
+ u8 val2;
+ u8 val3;
+ } bits;
+ } lut_ltr;
+ union {
+ u32 value;
+ struct {
+ u8 th0;
+ u8 th1;
+ u8 th2;
+ u8 th3;
+ } bits;
+ } lut_fill_time;
+};
-static int isys_isr_one(struct ipu6_bus_device *adev);
+#define ISYS_PM_QOS_VALUE 300
static int
isys_complete_ext_device_registration(struct ipu6_isys *isys,
@@ -132,6 +154,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;
@@ -141,23 +166,6 @@ unregister_subdev:
return ret;
}
-static void isys_stream_init(struct ipu6_isys *isys)
-{
- u32 i;
-
- for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++) {
- mutex_init(&isys->streams[i].mutex);
- init_completion(&isys->streams[i].stream_open_completion);
- init_completion(&isys->streams[i].stream_close_completion);
- init_completion(&isys->streams[i].stream_start_completion);
- init_completion(&isys->streams[i].stream_stop_completion);
- INIT_LIST_HEAD(&isys->streams[i].queues);
- isys->streams[i].isys = isys;
- isys->streams[i].stream_handle = i;
- isys->streams[i].vc = INVALID_VC_ID;
- }
-}
-
static void isys_csi2_unregister_subdevices(struct ipu6_isys *isys)
{
const struct ipu6_isys_internal_csi2_pdata *csi2 =
@@ -176,13 +184,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;
@@ -269,7 +287,36 @@ fail:
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;
@@ -304,118 +351,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;
- struct ltr_did ltrdid_default;
-
- ltrdid_default.lut_ltr.value = LTR_DEFAULT_VALUE;
- ltrdid_default.lut_fill_time.value = FILL_TIME_DEFAULT_VALUE;
-
- if (iwake_watermark->ltrdid.lut_ltr.value)
- *pltr_did = iwake_watermark->ltrdid;
- else
- *pltr_did = ltrdid_default;
-}
-
static int set_iwake_register(struct ipu6_isys *isys, u32 index, u32 value)
{
struct device *dev = &isys->adev->auxdev.dev;
@@ -511,69 +446,57 @@ static void set_iwake_ltrdid(struct ipu6_isys *isys, u16 ltr, u16 did,
*/
static void enable_iwake(struct ipu6_isys *isys, bool enable)
{
- struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark;
int ret;
- mutex_lock(&iwake_watermark->mutex);
-
- if (iwake_watermark->iwake_enabled == enable) {
- mutex_unlock(&iwake_watermark->mutex);
+ if (isys->iwake_watermark_enabled == enable)
return;
- }
ret = set_iwake_register(isys, GDA_ENABLE_IWAKE_INDEX, enable);
if (!ret)
- iwake_watermark->iwake_enabled = enable;
-
- mutex_unlock(&iwake_watermark->mutex);
+ isys->iwake_watermark_enabled = enable;
}
-void update_watermark_setting(struct ipu6_isys *isys)
+void ipu6_isys_update_watermark_setting(struct ipu6_isys *isys)
{
- struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark;
u32 iwake_threshold, iwake_critical_threshold, page_num;
struct device *dev = &isys->adev->auxdev.dev;
u32 calc_fill_time_us = 0, ltr = 0, did = 0;
- struct video_stream_watermark *p_watermark;
enum ltr_did_type ltr_did_type;
- struct list_head *stream_node;
u64 isys_pb_datarate_mbs = 0;
u32 mem_open_threshold = 0;
struct ltr_did ltrdid;
u64 threshold_bytes;
u32 max_sram_size;
u32 shift;
+ bool force_iwake_disable = false;
+
+ lockdep_assert_held(&isys->stream_mutex);
shift = isys->pdata->ipdata->sram_gran_shift;
max_sram_size = isys->pdata->ipdata->max_sram_size;
- mutex_lock(&iwake_watermark->mutex);
- if (iwake_watermark->force_iwake_disable) {
+ for (unsigned int i = 0; i < isys->pdata->ipdata->csi2.nports; i++) {
+ isys_pb_datarate_mbs +=
+ isys->csi2[i].watermark.stream_data_rate;
+ force_iwake_disable |=
+ isys->csi2[i].watermark.force_iwake_disable;
+ }
+
+ if (force_iwake_disable) {
+ dev_dbg(dev, "watermark: forcing iwake disabled\n");
set_iwake_ltrdid(isys, 0, 0, LTR_IWAKE_OFF);
set_iwake_register(isys, GDA_IRQ_CRITICAL_THRESHOLD_INDEX,
CRITICAL_THRESHOLD_IWAKE_DISABLE);
- goto unlock_exit;
- }
-
- if (list_empty(&iwake_watermark->video_list)) {
- isys_pb_datarate_mbs = 0;
- } else {
- list_for_each(stream_node, &iwake_watermark->video_list) {
- p_watermark = list_entry(stream_node,
- struct video_stream_watermark,
- stream_node);
- isys_pb_datarate_mbs += p_watermark->stream_data_rate;
- }
+ return;
}
- mutex_unlock(&iwake_watermark->mutex);
if (!isys_pb_datarate_mbs) {
+ dev_dbg(dev, "watermark: disabled iwake\n");
enable_iwake(isys, false);
set_iwake_ltrdid(isys, 0, 0, LTR_IWAKE_OFF);
- mutex_lock(&iwake_watermark->mutex);
set_iwake_register(isys, GDA_IRQ_CRITICAL_THRESHOLD_INDEX,
CRITICAL_THRESHOLD_IWAKE_DISABLE);
- goto unlock_exit;
+ return;
}
enable_iwake(isys, true);
@@ -584,7 +507,8 @@ void update_watermark_setting(struct ipu6_isys *isys)
did = calc_fill_time_us * DEFAULT_DID_RATIO / 100;
ltr_did_type = LTR_ENHANNCE_IWAKE;
} else {
- get_lut_ltrdid(isys, &ltrdid);
+ ltrdid.lut_ltr.value = LTR_DEFAULT_VALUE;
+ ltrdid.lut_fill_time.value = FILL_TIME_DEFAULT_VALUE;
if (calc_fill_time_us <= ltrdid.lut_fill_time.bits.th0)
ltr = 0;
@@ -608,7 +532,6 @@ void update_watermark_setting(struct ipu6_isys *isys)
iwake_threshold = max_t(u32, 1, threshold_bytes >> shift);
iwake_threshold = min_t(u32, iwake_threshold, max_sram_size);
- mutex_lock(&iwake_watermark->mutex);
if (isys->pdata->ipdata->enhanced_iwake) {
set_iwake_register(isys, GDA_IWAKE_THRESHOLD_INDEX,
DEFAULT_IWAKE_THRESHOLD);
@@ -630,7 +553,7 @@ void update_watermark_setting(struct ipu6_isys *isys)
iwake_critical_threshold = iwake_threshold +
(IS_PIXEL_BUFFER_PAGES - iwake_threshold) / 2;
- dev_dbg(dev, "threshold: %u critical: %u\n", iwake_threshold,
+ dev_dbg(dev, "watermark: threshold: %u critical: %u\n", iwake_threshold,
iwake_critical_threshold);
set_iwake_register(isys, GDA_IRQ_CRITICAL_THRESHOLD_INDEX,
@@ -640,32 +563,6 @@ void update_watermark_setting(struct ipu6_isys *isys)
isys->adev->isp->base + REG_PKGC_PMON_CFG);
writel(VAL_PKGC_PMON_CFG_START,
isys->adev->isp->base + REG_PKGC_PMON_CFG);
-unlock_exit:
- mutex_unlock(&iwake_watermark->mutex);
-}
-
-static void isys_iwake_watermark_init(struct ipu6_isys *isys)
-{
- struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark;
-
- INIT_LIST_HEAD(&iwake_watermark->video_list);
- mutex_init(&iwake_watermark->mutex);
-
- iwake_watermark->ltrdid.lut_ltr.value = 0;
- iwake_watermark->isys = isys;
- iwake_watermark->iwake_enabled = false;
- iwake_watermark->force_iwake_disable = false;
-}
-
-static void isys_iwake_watermark_cleanup(struct ipu6_isys *isys)
-{
- struct isys_iwake_watermark *iwake_watermark = &isys->iwake_watermark;
-
- mutex_lock(&iwake_watermark->mutex);
- list_del(&iwake_watermark->video_list);
- mutex_unlock(&iwake_watermark->mutex);
-
- mutex_destroy(&iwake_watermark->mutex);
}
/* The .bound() notifier callback when a match is found */
@@ -736,6 +633,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;
@@ -751,6 +652,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);
@@ -789,7 +691,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));
@@ -853,9 +755,10 @@ static void isys_unregister_devices(struct ipu6_isys *isys)
static int isys_runtime_pm_resume(struct device *dev)
{
struct ipu6_bus_device *adev = to_ipu6_bus_device(dev);
+ const struct ipu6_fw_isys_ops *fw_ops = adev->auxdrv_data->fw_ops;
struct ipu6_isys *isys = ipu6_bus_get_drvdata(adev);
+ const struct ipu6_isys_internal_pdata *ipdata = isys->pdata->ipdata;
struct ipu6_device *isp = adev->isp;
- unsigned long flags;
int ret;
ret = ipu6_mmu_hw_init(adev->mmu);
@@ -866,49 +769,82 @@ static int isys_runtime_pm_resume(struct device *dev)
ret = ipu6_buttress_start_tsc_sync(isp);
if (ret)
- return ret;
+ goto err_mmu_hw_cleanup;
- spin_lock_irqsave(&isys->power_lock, flags);
- isys->power = 1;
- spin_unlock_irqrestore(&isys->power_lock, flags);
+ if (IS_IPU7(isp)) {
+ ipu7_isys_setup_hw(isys);
+ } else {
+ ipu6_isys_setup_hw(isys);
+ set_iwake_ltrdid(isys, 0, 0, LTR_ISYS_ON);
+ }
- isys_setup_hw(isys);
+ ipu6_configure_spc(adev->isp, &ipdata->hw_variant,
+ IPU6_CPD_PKG_DIR_ISYS_SERVER_IDX, isys->pdata->base,
+ adev->pkg_dir, adev->pkg_dir_dma_addr);
- set_iwake_ltrdid(isys, 0, 0, LTR_ISYS_ON);
+ /*
+ * Buffers could have been left to wrong queue at last closure.
+ * Move them now back to empty buffer queue.
+ */
+ ipu6_cleanup_fw_msg_bufs(isys);
- return 0;
+ if (isys->fwctx) {
+ /*
+ * Something went wrong in previous shutdown. As we are now
+ * restarting isys we can safely delete old context.
+ */
+ dev_warn(&adev->auxdev.dev, "clearing old context\n");
+ fw_ops->cleanup(isys);
+ }
+
+ ret = fw_ops->init(isys, ipdata->num_parallel_streams);
+ if (!ret)
+ return 0;
+
+ isys->phy_termcal_val = 0;
+ cpu_latency_qos_update_request(&isys->pm_qos, PM_QOS_DEFAULT_VALUE);
+
+ if (!IS_IPU7(isp))
+ set_iwake_ltrdid(isys, 0, 0, LTR_ISYS_OFF);
+
+err_mmu_hw_cleanup:
+ ipu6_mmu_hw_cleanup(adev->mmu);
+
+ return ret;
}
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);
- unsigned long flags;
-
- spin_lock_irqsave(&isys->power_lock, flags);
- isys->power = 0;
- spin_unlock_irqrestore(&isys->power_lock, flags);
+ struct ipu6_device *isp = adev->isp;
+ int ret = 0;
- mutex_lock(&isys->mutex);
- isys->need_reset = false;
- mutex_unlock(&isys->mutex);
+ isys->adev->auxdrv_data->fw_ops->close(isys);
+ if (isys->fwctx) {
+ dev_warn(&isys->adev->auxdev.dev, "failed to close fw isys\n");
+ ret = -EIO;
+ }
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);
- return 0;
+ return ret;
}
static int isys_suspend(struct device *dev)
{
struct ipu6_isys *isys = dev_get_drvdata(dev);
+ guard(mutex)(&isys->stream_mutex);
+
/* If stream is open, refuse to suspend */
- if (isys->stream_opened)
+ if (!ida_is_empty(&isys->streams))
return -EBUSY;
return 0;
@@ -1003,7 +939,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;
}
@@ -1019,30 +955,28 @@ 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, fw_msg.dummy);
list_move(&msg->head, &isys->framebuflist);
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)
{
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;
if (!isp->bus_ready_to_probe)
@@ -1052,8 +986,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;
@@ -1068,8 +1002,6 @@ static int isys_probe(struct auxiliary_device *auxdev,
isys->sensor_type = isys->pdata->ipdata->sensor_type_start;
spin_lock_init(&isys->streams_lock);
- spin_lock_init(&isys->power_lock);
- isys->power = 0;
isys->phy_termcal_val = 0;
mutex_init(&isys->mutex);
@@ -1083,18 +1015,7 @@ static int isys_probe(struct auxiliary_device *auxdev,
dev_set_drvdata(&auxdev->dev, isys);
- isys_stream_init(isys);
-
- if (!isp->secure_mode) {
- fw = isp->cpd_fw;
- ret = ipu6_buttress_map_fw_image(adev, fw, &adev->fw_sgt);
- if (ret)
- goto release_firmware;
-
- ret = ipu6_cpd_create_pkg_dir(adev, isp->cpd_fw->data);
- if (ret)
- goto remove_shared_buffer;
- }
+ ida_init(&isys->streams);
cpu_latency_qos_add_request(&isys->pm_qos, PM_QOS_DEFAULT_VALUE);
@@ -1102,11 +1023,11 @@ static int isys_probe(struct auxiliary_device *auxdev,
if (ret < 0)
goto out_remove_pkg_dir_shared_buffer;
- isys_iwake_watermark_init(isys);
-
- if (is_ipu6se(adev->isp->hw_ver))
+ 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->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;
@@ -1121,17 +1042,6 @@ free_fw_msg_bufs:
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_buttress_unmap_fw_image(adev, &adev->fw_sgt);
-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);
mutex_destroy(&isys->mutex);
mutex_destroy(&isys->stream_mutex);
@@ -1141,10 +1051,9 @@ release_firmware:
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;
+
+ ida_destroy(&isys->streams);
free_fw_msg_bufs(isys);
@@ -1153,191 +1062,27 @@ 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_buttress_unmap_fw_image(adev, &adev->fw_sgt);
- release_firmware(adev->fw);
- }
-
- for (i = 0; i < IPU6_ISYS_MAX_STREAMS; i++)
- mutex_destroy(&isys->streams[i].mutex);
-
- isys_iwake_watermark_cleanup(isys);
mutex_destroy(&isys->stream_mutex);
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 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 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->fwcom)
- return 1;
-
- resp = ipu6_fw_isys_get_resp(isys->fwcom, IPU6_BASE_MSG_RECV_QUEUES);
- 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->fwcom, IPU6_BASE_MSG_RECV_QUEUES);
- return 0;
-}
-
-static const struct ipu6_auxdrv_data ipu6_isys_auxdrv_data = {
- .isr = isys_isr,
+static const struct ipu6_auxdrv_data ipu7_isys_auxdrv_data = {
+ .isr = ipu7_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 7fb8cb820912..2af20f56a965 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h
@@ -4,6 +4,7 @@
#ifndef IPU6_ISYS_H
#define IPU6_ISYS_H
+#include <linux/idr.h>
#include <linux/irqreturn.h>
#include <linux/list.h>
#include <linux/mutex.h>
@@ -14,9 +15,11 @@
#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"
+#include "ipu7-fw-isys.h"
#include "ipu6-isys-csi2.h"
#include "ipu6-isys-video.h"
@@ -60,41 +63,10 @@ struct ipu6_bus_device;
#define IPU6EP_MTL_LTR_VALUE 1023
#define IPU6EP_MTL_MIN_MEMOPEN_TH 0xc
-struct ltr_did {
- union {
- u32 value;
- struct {
- u8 val0;
- u8 val1;
- u8 val2;
- u8 val3;
- } bits;
- } lut_ltr;
- union {
- u32 value;
- struct {
- u8 th0;
- u8 th1;
- u8 th2;
- u8 th3;
- } bits;
- } lut_fill_time;
-};
-
-struct isys_iwake_watermark {
- bool iwake_enabled;
- bool force_iwake_disable;
- u32 iwake_threshold;
- u64 isys_pixelbuffer_datarate;
- struct ltr_did ltrdid;
- struct mutex mutex; /* protect whole struct */
- struct ipu6_isys *isys;
- struct list_head video_list;
-};
-
struct ipu6_isys_csi2_config {
u32 nlanes;
u32 port;
+ enum v4l2_mbus_type bus_type;
};
struct sensor_async_sd {
@@ -108,17 +80,12 @@ struct sensor_async_sd {
* @media_dev: Media device
* @v4l2_dev: V4L2 device
* @adev: ISYS bus device
- * @power: Is ISYS powered on or not?
- * @isr_bits: Which bits does the ISR handle?
- * @power_lock: Serialise access to power (power state in general)
* @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
* @mutex: serialise access isys video open/release related operations
* @stream_mutex: serialise stream start and stop, queueing requests
* @pdata: platform data pointer
@@ -129,20 +96,17 @@ struct ipu6_isys {
struct v4l2_device v4l2_dev;
struct ipu6_bus_device *adev;
- int power;
- spinlock_t power_lock;
u32 isr_csi2_bits;
u32 csi2_rx_ctrl_cached;
spinlock_t streams_lock;
- struct ipu6_isys_stream streams[IPU6_ISYS_MAX_STREAMS];
- int streams_ref_count[IPU6_ISYS_MAX_STREAMS];
- void *fwcom;
+ struct ipu6_isys_stream *streams_by_handle[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;
- unsigned int ref_count;
- unsigned int stream_opened;
+ bool iwake_watermark_enabled;
unsigned int sensor_type;
struct mutex mutex;
@@ -162,26 +126,65 @@ struct ipu6_isys {
struct list_head framebuflist;
struct list_head framebuflist_fw;
struct v4l2_async_notifier notifier;
- struct isys_iwake_watermark iwake_watermark;
+ struct ida streams;
};
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;
- } fw_msg;
+ 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;
};
+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_stream *stream,
+ struct v4l2_mbus_frame_desc *desc,
+ 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, 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;
-void update_watermark_setting(struct ipu6_isys *isys);
+void ipu6_isys_update_watermark_setting(struct ipu6_isys *isys);
int ipu6_isys_mcd_phy_set_power(struct ipu6_isys *isys,
struct ipu6_isys_csi2_config *cfg,
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 0e6dca36b6ba..243d438786ba 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 @@ out_free_iova:
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");
@@ -553,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 :
@@ -612,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)
@@ -623,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");
@@ -746,45 +674,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_pdata *pdata;
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)
- 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;
- }
+ int ret;
mmu = devm_kzalloc(dev, sizeof(*mmu), GFP_KERNEL);
if (!mmu)
return ERR_PTR(-ENOMEM);
+ mmu->ops = IS_IPU7(isp) ? &ipu7_mmu_ops : &ipu6_mmu_ops;
mmu->mmid = mmid;
- mmu->mmu_hw = pdata->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 8e40b4a66d7d..44880478d242 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.h
@@ -1,19 +1,17 @@
/* 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
-#define ISYS_MMID 1
-#define PSYS_MMID 0
-
#include <linux/list.h>
#include <linux/spinlock_types.h>
#include <linux/types.h>
+#include "ipu7-mmu-hw.h"
+
struct device;
struct page;
-struct ipu6_hw_variants;
struct ipu6_mmu_info {
struct device *dev;
@@ -35,10 +33,150 @@ 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;
+ union {
+ struct ipu6_mmu_hw *ipu6_mmu_hw;
+ struct ipu7_mmu_hw *ipu7_mmu_hw;
+ };
unsigned int nr_mmus;
unsigned int mmid;
@@ -55,12 +193,14 @@ 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;
+extern const struct ipu6_mmu_hw_ops ipu7_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-platform-buttress-regs.h b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
index efd65e494c16..57e661cc2177 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 | \
@@ -221,4 +221,113 @@ 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_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
+#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_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 5449a2006bcc..43d951735f72 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,13 +28,20 @@
#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"
#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
+
+static int force_no_probe_ipu7 = !IS_BUILTIN(CONFIG_VIDEO_INTEL_IPU6_IPU7);
+module_param(force_no_probe_ipu7, int, 0644);
+MODULE_PARM_DESC(force_no_probe_ipu7, "Don't probe ipu7 and ipu7.5 devices");
struct ipu6_cell_program {
u32 magic_number;
@@ -73,54 +81,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,
@@ -132,83 +92,12 @@ 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,
},
};
-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,
.freq_ctl = IPU6_BUTTRESS_REG_IS_FREQ_CTL,
@@ -218,7 +107,8 @@ 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,
.freq_ctl = IPU6_BUTTRESS_REG_PS_FREQ_CTL,
@@ -228,6 +118,119 @@ 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,
+ .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,
+ .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,
+ .sku_id = BUTTRESS_REG_SKU,
+
+ /* 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 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,
+ .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 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,
@@ -267,10 +270,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);
@@ -290,8 +299,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 +321,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 +354,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;
@@ -363,15 +370,21 @@ 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 *
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;
@@ -381,6 +394,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);
@@ -388,7 +405,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);
@@ -396,8 +413,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);
if (IS_ERR(isys_adev->mmu)) {
put_device(&isys_adev->auxdev.dev);
return dev_err_cast_probe(dev, isys_adev->mmu,
@@ -415,13 +431,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);
@@ -429,7 +451,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);
@@ -437,8 +459,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,
- &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,
@@ -454,12 +475,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;
@@ -474,7 +496,12 @@ static int ipu6_pci_config_setup(struct pci_dev *dev, u8 hw_ver)
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;
@@ -489,70 +516,193 @@ 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;
+
+ 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;
+
+ 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 __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 = ipu6_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 = ipu6_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)
{
- 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;
struct ipu6_device *isp;
phys_addr_t phys;
u32 val, version, sku_id;
+ unsigned long dir;
int ret;
+ if ((id->device == PCI_DEVICE_ID_INTEL_IPU7 ||
+ id->device == PCI_DEVICE_ID_INTEL_IPU7P5) && force_no_probe_ipu7)
+ return -ENODEV;
+
isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
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;
+ isp->model_name = IPU6_MEDIA_DEV_MODEL_NAME;
+ isys_ctrl = &ipu6_isys_buttress_ctrl;
+ psys_ctrl = &ipu6_psys_buttress_ctrl;
+
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;
+ 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;
+ 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",
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;
@@ -564,7 +714,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;
@@ -588,13 +738,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)) {
@@ -602,13 +745,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)) {
@@ -627,19 +763,9 @@ 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);
- 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 = IS_IPU7(isp) ? ipu7_map_fw(isp) : 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,
@@ -662,7 +788,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,
@@ -680,10 +806,21 @@ out_free_irq:
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);
- ipu6_buttress_unmap_fw_image(isp->psys, &isp->psys->fw_sgt);
+ if (isp->psys->fw_sgt.nents)
+ 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, dir);
}
+
+ 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);
if (!IS_ERR_OR_NULL(isp->isys) && !IS_ERR_OR_NULL(isp->isys->mmu))
@@ -699,13 +836,23 @@ buttress_exit:
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);
+
+ 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, dir);
+ }
+
+ vfree(isp->fw_code_region);
+ isp->fw_code_region = NULL;
- ipu6_buttress_unmap_fw_image(isp->psys, &isp->psys->fw_sgt);
ipu6_buttress_exit(isp);
ipu6_bus_del_devices(pdev);
@@ -715,8 +862,10 @@ static void ipu6_pci_remove(struct pci_dev *pdev)
release_firmware(isp->cpd_fw);
- ipu6_mmu_cleanup(psys_mmu);
- ipu6_mmu_cleanup(isys_mmu);
+ if (isp->psys)
+ ipu6_mmu_cleanup(isp->psys->mmu);
+ if (isp->isys)
+ ipu6_mmu_cleanup(isp->isys->mmu);
}
static void ipu6_pci_reset_prepare(struct pci_dev *pdev)
@@ -754,7 +903,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 */
@@ -766,7 +914,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);
if (ret)
dev_err(&isp->pdev->dev, "IPC reset protocol failed!\n");
@@ -795,10 +943,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->cse);
+ ret = ipu6_buttress_ipc_reset(isp);
if (ret)
dev_err(&isp->pdev->dev, "IPC reset protocol failed\n");
}
diff --git a/drivers/media/pci/intel/ipu6/ipu6.h b/drivers/media/pci/intel/ipu6/ipu6.h
index 92e3c3414c91..72c5063d5198 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.h
+++ b/drivers/media/pci/intel/ipu6/ipu6.h
@@ -16,46 +16,32 @@ 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"
#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"
-
-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 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 */
+#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
@@ -80,14 +66,21 @@ 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;
bool need_ipc_reset;
bool secure_mode;
u8 hw_ver;
bool bus_ready_to_probe;
+ u32 *fw_code_region;
};
+#define IPU_PSYS 0
+#define IPU_ISYS 1
+#define IPU_SUBSYS_NUM 2
+
#define IPU6_ISYS_NAME "isys"
#define IPU6_PSYS_NAME "psys"
@@ -134,141 +127,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_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;
};
@@ -283,6 +141,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 {
@@ -293,8 +153,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;
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..952c73efd237
--- /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 ipu6_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(ipu6_ipu7_init_boot_config, "INTEL_IPU6");
+
+void ipu6_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(ipu6_ipu7_release_boot_config, "INTEL_IPU6");
+
+int ipu6_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(ipu6_ipu7_boot_start_fw, "INTEL_IPU6");
+
+int ipu6_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(ipu6_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..f2172b53bed5
--- /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 ipu6_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 ipu6_ipu7_release_boot_config(struct ipu6_bus_device *adev);
+int ipu6_ipu7_boot_start_fw(const struct ipu6_bus_device *adev);
+int ipu6_ipu7_boot_stop_fw(const struct ipu6_bus_device *adev);
+
+#endif
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..097eaab99547
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-com.h
@@ -0,0 +1,53 @@
+/* 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_insys_config *fw_config;
+ dma_addr_t fw_config_dma_addr;
+};
+
+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 */
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..0876cc54faa7
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.c
@@ -0,0 +1,796 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Intel Corporation
+ */
+
+#include <linux/cleanup.h>
+#include <linux/cacheflush.h>
+#include <linux/pm_runtime.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)
+{
+ struct ipu6_bus_device *adev = isys->adev;
+ struct ipu7_fw_com_context *fwctx = isys->fwctx;
+
+ if (!fwctx)
+ return;
+
+ ipu6_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 ipu6_ipu7_boot_start_fw(isys->adev);
+}
+
+static int ipu7_fw_isys_close(struct ipu6_isys *isys)
+{
+ int ret;
+
+ ret = ipu6_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 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 (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);
+ }
+
+ /* 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 = ipu6_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 ipu6_isys_stream *stream,
+ struct media_pad *src_pad,
+ struct v4l2_mbus_frame_desc_entry *entry,
+ void *__cfg)
+{
+ 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_stream_cfg *cfg = __cfg;
+ struct ipu7_fw_isys_input_pin *input_pin;
+ struct ipu7_fw_isys_output_pin *output_pin;
+ 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(state, 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 = entry->bus.csi2.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;
+ av->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;
+
+ 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 (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);
+ 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_stream *stream,
+ struct v4l2_mbus_frame_desc *desc,
+ struct isys_fw_msgs *msg)
+{
+ struct ipu7_fw_isys_stream_cfg *cfg = &msg->ipu7.stream;
+ struct device *dev = &stream->isys->adev->auxdev.dev;
+ int ret;
+
+ memset(cfg, 0, sizeof(*cfg));
+ cfg->port_id = stream->asd->source;
+ cfg->vc = stream->vc;
+ cfg->stream_msg_map = IPU7_INSYS_STREAM_ENABLE_MSG_SEND_RESP |
+ IPU7_INSYS_STREAM_ENABLE_MSG_SEND_IRQ;
+
+ ret = ipu6_isys_fw_pins_prepare(stream, desc, ipu7_isys_fw_pin_cfg,
+ cfg);
+ if (ret)
+ 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,
+};
+
+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;
+ unsigned long flags;
+ u64 ts;
+
+ 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_nounlock;
+ }
+
+ spin_lock_irqsave(&isys->streams_lock, flags);
+
+ stream = resp->stream_id < IPU6_ISYS_MAX_STREAMS ?
+ isys->streams_by_handle[resp->stream_id] : NULL;
+ 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;
+ }
+
+leave:
+ spin_unlock_irqrestore(&isys->streams_lock, flags);
+
+leave_nounlock:
+ 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 = csi2->streams_by_vc[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;
+ int pm_status;
+
+ pm_status = pm_runtime_get_if_active(&adev->auxdev.dev);
+ if (!pm_status)
+ return 0;
+
+ 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) {
+ if (pm_status > 0)
+ pm_runtime_put(&adev->auxdev.dev);
+ 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);
+
+ if (pm_status > 0)
+ pm_runtime_put(&adev->auxdev.dev);
+
+ 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
new file mode 100644
index 000000000000..d5289f6add8c
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-fw-isys.h
@@ -0,0 +1,296 @@
+/* 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
+};
+
+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];
+ 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);
+irqreturn_t ipu7_isys_isr(struct ipu6_bus_device *adev);
+
+#endif
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 */
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 */
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..c9b015e89ee6
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.c
@@ -0,0 +1,858 @@
+// 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 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,
+ .nr_mmus = ARRAY_SIZE(ipu7_psys_mmu_hwdata),
+ },
+ [IPU_ISYS] = {
+ .hwdata = ipu7_isys_mmu_hwdata,
+ .nr_mmus = ARRAY_SIZE(ipu7_isys_mmu_hwdata),
+ },
+};
+
+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;
+ 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)
+{
+ 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;
+
+ 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..ba31ed31b245
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-mmu-hw.h
@@ -0,0 +1,254 @@
+/* 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
+
+/* 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];
+
+ 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
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..39cd5c0890e5
--- /dev/null
+++ b/drivers/media/pci/intel/ipu6/ipu7-platform-regs.h
@@ -0,0 +1,32 @@
+/* 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
+
+#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
diff --git a/drivers/media/pci/intel/ivsc/mei_ace.c b/drivers/media/pci/intel/ivsc/mei_ace.c
index b306a320b70f..bb57656fc85a 100644
--- a/drivers/media/pci/intel/ivsc/mei_ace.c
+++ b/drivers/media/pci/intel/ivsc/mei_ace.c
@@ -414,13 +414,13 @@ static int mei_ace_setup_dev_link(struct mei_ace *ace)
/* setup link between mei_ace and mei_csi */
ace->csi_link = device_link_add(csi_dev, dev, DL_FLAG_PM_RUNTIME |
DL_FLAG_RPM_ACTIVE | DL_FLAG_STATELESS);
- put_device(csi_dev);
if (!ace->csi_link) {
ret = -EINVAL;
dev_err(dev, "failed to link to %s\n", dev_name(csi_dev));
- goto err;
+ goto err_put;
}
+ put_device(csi_dev);
ace->csi_dev = csi_dev;
return 0;
diff --git a/drivers/media/pci/intel/ivsc/mei_csi.c b/drivers/media/pci/intel/ivsc/mei_csi.c
index c2917e156345..005b1414a252 100644
--- a/drivers/media/pci/intel/ivsc/mei_csi.c
+++ b/drivers/media/pci/intel/ivsc/mei_csi.c
@@ -27,7 +27,6 @@
#include <linux/workqueue.h>
#include <media/ipu-bridge.h>
-#include <media/ipu6-pci-table.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fwnode.h>
@@ -338,6 +337,7 @@ static int mei_csi_init_state(struct v4l2_subdev *sd,
}
static int mei_csi_set_fmt(struct v4l2_subdev *sd,
+ const struct v4l2_subdev_client_info *ci,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
{
@@ -644,13 +644,9 @@ static int mei_csi_probe(struct mei_cl_device *cldev,
struct device *dev = &cldev->dev;
struct pci_dev *ipu;
struct mei_csi *csi;
- unsigned int i;
int ret;
- for (i = 0, ipu = NULL; !ipu && ipu6_pci_tbl[i].vendor; i++)
- ipu = pci_get_device(ipu6_pci_tbl[i].vendor,
- ipu6_pci_tbl[i].device, NULL);
-
+ ipu = ipu_bridge_get_ipu6();
if (!ipu)
return -ENODEV;
diff --git a/drivers/media/pci/ivtv/ivtv-controls.c b/drivers/media/pci/ivtv/ivtv-controls.c
index f087a12c4ebd..816e634de1eb 100644
--- a/drivers/media/pci/ivtv/ivtv-controls.c
+++ b/drivers/media/pci/ivtv/ivtv-controls.c
@@ -60,7 +60,7 @@ static int ivtv_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
format.format.width = cxhdl->width / (is_mpeg1 ? 2 : 1);
format.format.height = cxhdl->height;
format.format.code = MEDIA_BUS_FMT_FIXED;
- v4l2_subdev_call(itv->sd_video, pad, set_fmt, NULL, &format);
+ v4l2_subdev_call(itv->sd_video, pad, set_fmt, NULL, NULL, &format);
return 0;
}
diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c
index fc95f0bf48d5..aba55fcc1e22 100644
--- a/drivers/media/pci/ivtv/ivtv-ioctl.c
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.c
@@ -587,7 +587,7 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
format.format.width = fmt->fmt.pix.width;
format.format.height = h;
format.format.code = MEDIA_BUS_FMT_FIXED;
- v4l2_subdev_call(itv->sd_video, pad, set_fmt, NULL, &format);
+ v4l2_subdev_call(itv->sd_video, pad, set_fmt, NULL, NULL, &format);
return ivtv_g_fmt_vid_cap(file, fh, fmt);
}
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index 2f5b258d682b..507ad23776e0 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -1368,7 +1368,7 @@ static int __maybe_unused saa7134_buffer_requeue(struct saa7134_dev *dev,
return 0;
}
-static int __maybe_unused saa7134_suspend(struct device *dev_d)
+static int saa7134_suspend(struct device *dev_d)
{
struct pci_dev *pci_dev = to_pci_dev(dev_d);
struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
@@ -1400,7 +1400,7 @@ static int __maybe_unused saa7134_suspend(struct device *dev_d)
return 0;
}
-static int __maybe_unused saa7134_resume(struct device *dev_d)
+static int saa7134_resume(struct device *dev_d)
{
struct v4l2_device *v4l2_dev = dev_get_drvdata(dev_d);
struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
@@ -1484,14 +1484,14 @@ EXPORT_SYMBOL(saa7134_ts_unregister);
/* ----------------------------------------------------------- */
-static SIMPLE_DEV_PM_OPS(saa7134_pm_ops, saa7134_suspend, saa7134_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(saa7134_pm_ops, saa7134_suspend, saa7134_resume);
static struct pci_driver saa7134_pci_driver = {
.name = "saa7134",
.id_table = saa7134_pci_tbl,
.probe = saa7134_initdev,
.remove = saa7134_finidev,
- .driver.pm = &saa7134_pm_ops,
+ .driver.pm = pm_sleep_ptr(&saa7134_pm_ops),
};
static int __init saa7134_init(void)
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
index 8c4f70e4177d..d04a68bb05d8 100644
--- a/drivers/media/pci/saa7134/saa7134-empress.c
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -122,7 +122,7 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv,
};
v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED);
- saa_call_all(dev, pad, set_fmt, NULL, &format);
+ saa_call_all(dev, pad, set_fmt, NULL, NULL, &format);
v4l2_fill_pix_format(&f->fmt.pix, &format.format);
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
@@ -145,7 +145,7 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv,
};
v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED);
- saa_call_all(dev, pad, set_fmt, &pad_state, &format);
+ saa_call_all(dev, pad, set_fmt, NULL, &pad_state, &format);
v4l2_fill_pix_format(&f->fmt.pix, &format.format);
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c
index 7f6680de3156..b2a2372d149a 100644
--- a/drivers/media/pci/saa7134/saa7134-input.c
+++ b/drivers/media/pci/saa7134/saa7134-input.c
@@ -769,7 +769,8 @@ int saa7134_input_init1(struct saa7134_dev *dev)
}
ir = kzalloc_obj(*ir);
- rc = rc_allocate_device(RC_DRIVER_SCANCODE);
+ rc = rc_allocate_device(raw_decode ?
+ RC_DRIVER_IR_RAW : RC_DRIVER_SCANCODE);
if (!ir || !rc) {
err = -ENOMEM;
goto err_out_free;
@@ -792,10 +793,8 @@ int saa7134_input_init1(struct saa7134_dev *dev)
rc->priv = dev;
rc->open = saa7134_ir_open;
rc->close = saa7134_ir_close;
- if (raw_decode) {
- rc->driver_type = RC_DRIVER_IR_RAW;
+ if (raw_decode)
rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
- }
rc->device_name = saa7134_boards[dev->board].name;
rc->input_phys = ir->phys;
diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c
index d759e8a87e24..129d41c1862b 100644
--- a/drivers/media/pci/saa7146/mxb.c
+++ b/drivers/media/pci/saa7146/mxb.c
@@ -37,7 +37,7 @@
/* global variable */
static int mxb_num;
-/* initial frequence the tuner will be tuned to.
+/* initial frequency the tuner will be tuned to.
in verden (lower saxony, germany) 4148 is a
channel called "phoenix" */
static int freq = 4148;
@@ -429,7 +429,7 @@ err:
/* some stuff is done via direct write to the registers */
/* this is ugly, but because of the fact that this is completely
- hardware dependend, it should be done directly... */
+ hardware dependent, it should be done directly... */
saa7146_write(dev, DD1_STREAM_B, 0x00000000);
saa7146_write(dev, DD1_INIT, 0x02000200);
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c
index ac5eb6b923e2..debcfaaf36dc 100644
--- a/drivers/media/pci/saa7164/saa7164-core.c
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -742,35 +742,6 @@ u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev)
return reg;
}
-/* TODO: Debugging func, remove */
-void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr)
-{
- int i;
-
- dprintk(1, "--------------------> 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
-
- for (i = 0; i < 0x100; i += 16)
- dprintk(1, "region0[0x%08x] = %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- i,
- (u8)saa7164_readb(addr + i + 0),
- (u8)saa7164_readb(addr + i + 1),
- (u8)saa7164_readb(addr + i + 2),
- (u8)saa7164_readb(addr + i + 3),
- (u8)saa7164_readb(addr + i + 4),
- (u8)saa7164_readb(addr + i + 5),
- (u8)saa7164_readb(addr + i + 6),
- (u8)saa7164_readb(addr + i + 7),
- (u8)saa7164_readb(addr + i + 8),
- (u8)saa7164_readb(addr + i + 9),
- (u8)saa7164_readb(addr + i + 10),
- (u8)saa7164_readb(addr + i + 11),
- (u8)saa7164_readb(addr + i + 12),
- (u8)saa7164_readb(addr + i + 13),
- (u8)saa7164_readb(addr + i + 14),
- (u8)saa7164_readb(addr + i + 15)
- );
-}
-
static void saa7164_dump_hwdesc(struct saa7164_dev *dev)
{
dprintk(1, "@0x%p hwdesc sizeof(struct tmComResHWDescr) = %d bytes\n",
@@ -856,7 +827,7 @@ static void saa7164_get_descriptors(struct saa7164_dev *dev)
saa7164_dump_hwdesc(dev);
if (dev->intfdesc.bLength != sizeof(struct tmComResInterfaceDescr)) {
- printk(KERN_ERR "struct struct tmComResInterfaceDescr is mangled\n");
+ printk(KERN_ERR "struct tmComResInterfaceDescr is mangled\n");
printk(KERN_ERR "Need %x got %d\n", dev->intfdesc.bLength,
(u32)sizeof(struct tmComResInterfaceDescr));
} else
@@ -1344,7 +1315,6 @@ static int saa7164_initdev(struct pci_dev *pci_dev,
}
saa7164_get_descriptors(dev);
- saa7164_dumpregs(dev, 0);
saa7164_getcurrentfirmwareversion(dev);
saa7164_getfirmwarestatus(dev);
err = saa7164_bus_setup(dev);
diff --git a/drivers/media/pci/saa7164/saa7164.h b/drivers/media/pci/saa7164/saa7164.h
index 94e987e7b5e5..53ef9c3343ba 100644
--- a/drivers/media/pci/saa7164/saa7164.h
+++ b/drivers/media/pci/saa7164/saa7164.h
@@ -490,7 +490,6 @@ extern unsigned int vbi_buffers;
/* ----------------------------------------------------------- */
/* saa7164-core.c */
-void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr);
void saa7164_getfirmwarestatus(struct saa7164_dev *dev);
u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev);
void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val);
diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c
index 509d7ddec150..0909b2d9fcdd 100644
--- a/drivers/media/pci/tw68/tw68-core.c
+++ b/drivers/media/pci/tw68/tw68-core.c
@@ -228,7 +228,7 @@ static int tw68_initdev(struct pci_dev *pci_dev,
/* pci init */
dev->pci = pci_dev;
- if (pci_enable_device(pci_dev)) {
+ if (pcim_enable_device(pci_dev)) {
err = -EIO;
goto fail1;
}
@@ -359,7 +359,7 @@ static void tw68_finidev(struct pci_dev *pci_dev)
v4l2_device_unregister(&dev->v4l2_dev);
}
-static int __maybe_unused tw68_suspend(struct device *dev_d)
+static int tw68_suspend(struct device *dev_d)
{
struct pci_dev *pci_dev = to_pci_dev(dev_d);
struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
@@ -377,7 +377,7 @@ static int __maybe_unused tw68_suspend(struct device *dev_d)
return 0;
}
-static int __maybe_unused tw68_resume(struct device *dev_d)
+static int tw68_resume(struct device *dev_d)
{
struct v4l2_device *v4l2_dev = dev_get_drvdata(dev_d);
struct tw68_dev *dev = container_of(v4l2_dev,
@@ -405,14 +405,14 @@ static int __maybe_unused tw68_resume(struct device *dev_d)
/* ----------------------------------------------------------- */
-static SIMPLE_DEV_PM_OPS(tw68_pm_ops, tw68_suspend, tw68_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(tw68_pm_ops, tw68_suspend, tw68_resume);
static struct pci_driver tw68_pci_driver = {
.name = "tw68",
.id_table = tw68_pci_tbl,
.probe = tw68_initdev,
.remove = tw68_finidev,
- .driver.pm = &tw68_pm_ops,
+ .driver.pm = pm_sleep_ptr(&tw68_pm_ops),
};
module_pci_driver(tw68_pci_driver);