Re: [RFC PATCH 2/7] media: ipu7: add Intel IPU7 PCI device driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



+Cc Bjorn, PCI

On Thu, 2025-02-27 at 12:06 +0800, Bingbu Cao wrote:
> 
> 
> On 2/24/25 10:38 PM, Philipp Stanner wrote:
> > Hi,
> > 
> > see below
> > 
> > On Fri, 2025-02-21 at 15:52 +0800, bingbu.cao@xxxxxxxxx wrote:
> > > From: Bingbu Cao <bingbu.cao@xxxxxxxxx>
> > > 
> > > Intel Image Processing Unit 7th Gen includes input and processing
> > > systems
> > > and the hardware presents itself as a single PCI device in system
> > > same
> > > as IPU6.
> > > 
> > > The IPU7 PCI device driver basically does PCI configurations,
> > > basic
> > > hardware configuration by its buttress interfaces, loads the
> > > firmware binary, register the auxiliary device which serve for
> > > the
> > > ISYS
> > > device driver.
> > > 
> > > Signed-off-by: Bingbu Cao <bingbu.cao@xxxxxxxxx>
> > > ---
> > >  drivers/media/pci/intel/ipu7/ipu7-bus.c       |  158 +
> > >  drivers/media/pci/intel/ipu7/ipu7-bus.h       |   69 +
> > >  .../media/pci/intel/ipu7/ipu7-buttress-regs.h |  465 +++
> > >  drivers/media/pci/intel/ipu7/ipu7-buttress.c  | 1187 +++++++
> > >  drivers/media/pci/intel/ipu7/ipu7-buttress.h  |   84 +
> > >  .../media/pci/intel/ipu7/ipu7-platform-regs.h |  146 +
> > >  drivers/media/pci/intel/ipu7/ipu7.c           | 2791
> > > +++++++++++++++++
> > >  drivers/media/pci/intel/ipu7/ipu7.h           |  244 ++
> > >  8 files changed, 5144 insertions(+)
> > >  create mode 100644 drivers/media/pci/intel/ipu7/ipu7-bus.c
> > >  create mode 100644 drivers/media/pci/intel/ipu7/ipu7-bus.h
> > >  create mode 100644 drivers/media/pci/intel/ipu7/ipu7-buttress-
> > > regs.h
> > >  create mode 100644 drivers/media/pci/intel/ipu7/ipu7-buttress.c
> > >  create mode 100644 drivers/media/pci/intel/ipu7/ipu7-buttress.h
> > >  create mode 100644 drivers/media/pci/intel/ipu7/ipu7-platform-
> > > regs.h
> > >  create mode 100644 drivers/media/pci/intel/ipu7/ipu7.c
> > >  create mode 100644 drivers/media/pci/intel/ipu7/ipu7.h
> > > 
> 
> ---snip---
> 
> > > +static int ipu7_pci_probe(struct pci_dev *pdev, const struct
> > > pci_device_id *id)
> > > +{
> > > +	struct ipu_buttress_ctrl *isys_ctrl = NULL, *psys_ctrl =
> > > NULL;
> > > +	struct fwnode_handle *fwnode = dev_fwnode(&pdev->dev);
> > > +	const struct ipu_buttress_ctrl *isys_buttress_ctrl;
> > > +	const struct ipu_buttress_ctrl *psys_buttress_ctrl;
> > > +	struct ipu_isys_internal_pdata *isys_ipdata;
> > > +	struct ipu_psys_internal_pdata *psys_ipdata;
> > > +	unsigned int dma_mask = IPU_DMA_MASK;
> > > +	struct device *dev = &pdev->dev;
> > > +	void __iomem *isys_base = NULL;
> > > +	void __iomem *psys_base = NULL;
> > > +	void __iomem *const *iomap;
> > > +	phys_addr_t phys, pb_phys;
> > > +	struct ipu7_device *isp;
> > > +	u32 is_es;
> > > +	int ret;
> > > +
> > > +	if (!fwnode || fwnode_property_read_u32(fwnode, "is_es",
> > > &is_es))
> > > +		is_es = 0;
> > > +
> > > +	isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
> > > +	if (!isp)
> > > +		return -ENOMEM;
> > > +
> > > +	dev_set_name(dev, "intel-ipu7");
> > > +	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");
> > > +
> > > +	dev_info(dev, "Device 0x%x (rev: 0x%x)\n",
> > > +		 pdev->device, pdev->revision);
> > > +
> > > +	phys = pci_resource_start(pdev, IPU_PCI_BAR);
> > > +	pb_phys = pci_resource_start(pdev, IPU_PCI_PBBAR);
> > > +	dev_info(dev, "IPU7 PCI BAR0 base %llx BAR2 base
> > > %llx\n",
> > > +		 phys, pb_phys);
> > > +
> > > +	ret = pcim_iomap_regions(pdev, BIT(IPU_PCI_BAR) |
> > > BIT(IPU_PCI_PBBAR),
> > > +				 pci_name(pdev));
> > > +	if (ret)
> > > +		return dev_err_probe(dev, ret,
> > > +				     "Failed to I/O memory
> > > remapping
> > > (%d)\n",
> > > +				     ret);
> > > +
> > > +	iomap = pcim_iomap_table(pdev);
> > 
> > pcim_iomap_table() and pcim_iomap_regions() have been deprecated
> > last
> > year. That's also documented in those functions' docstrings. Please
> > don't use them anymore.
> > 
> > You can achieve all you need with the simpler pcim_iomap_region()
> 
> Philipp,
> 
> I see that pcim_iomap_regions() and
> pcim_add_mapping_to_legacy_table()
> have simple 'bar' checking, how does pcim_iomap_region() check that?

You mean the BAR index range check I suppose.

That's a good question. It seems to me that the ultimately used
pci_resource_start() will just overflow the device's array and you get
UB – again.

He.
Damn.

We might wanna fix that. But we can ask ourselves: where. At the lowest
point in those PCI region accessor macros which then bubble an EINVAL
or similar upwards, or at the higher point, as in pcim_iomap_region().

This seems a PCI-wide problem. It seems to me that pci_iomap() &
partners are also not safeguarded against overflowing.

Bjorn, shall we solve that? How? do you have a preference?


P.


PS: That is actually embarrassing since I complained in my talk about
pcim_iomap_table() having no possibility for bounds checking.
Ah, let's hope no one will notice that I said that ^_^

> 
> > 
> > 
> > > +	if (!iomap)
> > > +		return dev_err_probe(dev, -ENODEV, "Failed to
> > > iomap
> > > table\n");
> > > +
> > > +	isp->base = iomap[IPU_PCI_BAR];
> > > +	isp->pb_base = iomap[IPU_PCI_PBBAR];
> > > +	dev_info(dev, "IPU7 PCI BAR0 mapped at %p\n BAR2 mapped
> > > at
> > > %p\n",
> > > +		 isp->base, isp->pb_base);
> > > +
> > > +	pci_set_drvdata(pdev, isp);
> > > +	pci_set_master(pdev);
> > > +
> > > +	switch (id->device) {
> > > +	case IPU7_PCI_ID:
> > > +		isp->hw_ver = IPU_VER_7;
> > > +		isp->cpd_fw_name = IPU7_FIRMWARE_NAME;
> > > +		isys_ipdata = &ipu7_isys_ipdata;
> > > +		psys_ipdata = &ipu7_psys_ipdata;
> > > +		isys_buttress_ctrl = &ipu7_isys_buttress_ctrl;
> > > +		psys_buttress_ctrl = &ipu7_psys_buttress_ctrl;
> > > +		break;
> > > +	case IPU7P5_PCI_ID:
> > > +		isp->hw_ver = IPU_VER_7P5;
> > > +		isp->cpd_fw_name = IPU7P5_FIRMWARE_NAME;
> > > +		isys_ipdata = &ipu7p5_isys_ipdata;
> > > +		psys_ipdata = &ipu7p5_psys_ipdata;
> > > +		isys_buttress_ctrl = &ipu7_isys_buttress_ctrl;
> > > +		psys_buttress_ctrl = &ipu7_psys_buttress_ctrl;
> > > +		break;
> > > +	case IPU8_PCI_ID:
> > > +		isp->hw_ver = IPU_VER_8;
> > > +		isp->cpd_fw_name = IPU8_FIRMWARE_NAME;
> > > +		isys_ipdata = &ipu8_isys_ipdata;
> > > +		psys_ipdata = &ipu8_psys_ipdata;
> > > +		isys_buttress_ctrl = &ipu8_isys_buttress_ctrl;
> > > +		psys_buttress_ctrl = &ipu8_psys_buttress_ctrl;
> > > +		break;
> > > +	default:
> > > +		WARN(1, "Unsupported IPU device");
> > > +		return -ENODEV;
> > > +	}
> > > +
> > > +	ipu_internal_pdata_init(isys_ipdata, psys_ipdata);
> > > +
> > > +	isys_base = isp->base + isys_ipdata->hw_variant.offset;
> > > +	psys_base = isp->base + psys_ipdata->hw_variant.offset;
> > > +
> > > +	ret = dma_set_mask_and_coherent(dev,
> > > DMA_BIT_MASK(dma_mask));
> > > +	if (ret)
> > > +		return dev_err_probe(dev, ret, "Failed to set
> > > DMA
> > > mask\n");
> > > +
> > > +	dma_set_max_seg_size(dev, UINT_MAX);
> > > +
> > > +	ret = ipu7_pci_config_setup(pdev);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	ret = ipu_buttress_init(isp);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	dev_info(dev, "firmware cpd file: %s\n", isp-
> > > >cpd_fw_name);
> > > +
> > > +	ret = request_firmware(&isp->cpd_fw, isp->cpd_fw_name,
> > > dev);
> > > +	if (ret) {
> > > +		dev_err_probe(dev, ret,
> > > +			      "Requesting signed firmware %s
> > > failed\n",
> > > +			      isp->cpd_fw_name);
> > > +		goto buttress_exit;
> > > +	}
> > > +
> > > +	ret = ipu7_cpd_validate_cpd_file(isp, isp->cpd_fw->data,
> > > +					 isp->cpd_fw->size);
> > > +	if (ret) {
> > > +		dev_err_probe(dev, ret, "Failed to validate
> > > cpd\n");
> > > +		goto out_ipu_bus_del_devices;
> > > +	}
> > > +
> > > +	isys_ctrl = devm_kmemdup(dev, isys_buttress_ctrl,
> > > +				 sizeof(*isys_buttress_ctrl),
> > > GFP_KERNEL);
> > > +	if (!isys_ctrl) {
> > > +		ret = -ENOMEM;
> > > +		goto out_ipu_bus_del_devices;
> > > +	}
> > > +
> > > +	isp->isys = ipu7_isys_init(pdev, dev, isys_ctrl,
> > > isys_base,
> > > +				   isys_ipdata, 0);
> > > +	if (IS_ERR(isp->isys)) {
> > > +		ret = PTR_ERR(isp->isys);
> > > +		goto out_ipu_bus_del_devices;
> > > +	}
> > > +
> > > +	psys_ctrl = devm_kmemdup(dev, psys_buttress_ctrl,
> > > +				 sizeof(*psys_buttress_ctrl),
> > > GFP_KERNEL);
> > > +	if (!psys_ctrl) {
> > > +		ret = -ENOMEM;
> > > +		goto out_ipu_bus_del_devices;
> > > +	}
> > > +
> > > +	isp->psys = ipu7_psys_init(pdev, &isp->isys->auxdev.dev,
> > > +				   psys_ctrl, psys_base,
> > > +				   psys_ipdata, 0);
> > > +	if (IS_ERR(isp->psys)) {
> > > +		ret = PTR_ERR(isp->psys);
> > > +		goto out_ipu_bus_del_devices;
> > > +	}
> > > +
> > > +	ret = devm_request_threaded_irq(dev, pdev->irq,
> > > +					ipu_buttress_isr,
> > > +					ipu_buttress_isr_threade
> > > d,
> > > +					IRQF_SHARED, IPU_NAME,
> > > isp);
> > > +	if (ret)
> > > +		goto out_ipu_bus_del_devices;
> > > +
> > > +	if (!isp->secure_mode) {
> > > +		ret = ipu7_init_fw_code_region(isp);
> > > +		if (ret)
> > > +			goto out_ipu_bus_del_devices;
> > > +	} else {
> > > +		ret = pm_runtime_get_sync(&isp->psys-
> > > >auxdev.dev);
> > > +		if (ret < 0) {
> > > +			dev_err(&isp->psys->auxdev.dev,
> > > +				"Failed to get runtime PM\n");
> > > +			goto out_ipu_bus_del_devices;
> > > +		}
> > > +
> > > +		ret = ipu7_mmu_hw_init(isp->psys->mmu);
> > > +		if (ret) {
> > > +			dev_err_probe(&isp->pdev->dev, ret,
> > > +				      "Failed to init MMU
> > > hardware\n");
> > > +			goto out_ipu_bus_del_devices;
> > > +		}
> > > +
> > > +		ret = ipu7_map_fw_code_region(isp->psys,
> > > +					      (void *)isp-
> > > >cpd_fw-
> > > > data,
> > > +					      isp->cpd_fw-
> > > >size);
> > > +		if (ret) {
> > > +			dev_err_probe(&isp->pdev->dev, ret,
> > > +				      "failed to map fw
> > > image\n");
> > > +			goto out_ipu_bus_del_devices;
> > > +		}
> > > +
> > > +		ret = ipu_buttress_authenticate(isp);
> > > +		if (ret) {
> > > +			dev_err_probe(&isp->pdev->dev, ret,
> > > +				      "FW authentication
> > > failed\n");
> > > +			goto out_ipu_bus_del_devices;
> > > +		}
> > > +
> > > +		ipu7_mmu_hw_cleanup(isp->psys->mmu);
> > > +		pm_runtime_put(&isp->psys->auxdev.dev);
> > > +	}
> > > +
> > > +	pm_runtime_put_noidle(dev);
> > > +	pm_runtime_allow(dev);
> > > +
> > > +	isp->ipu7_bus_ready_to_probe = true;
> > > +
> > > +	return 0;
> > > +
> > > +out_ipu_bus_del_devices:
> > > +	if (!IS_ERR_OR_NULL(isp->isys) && isp->isys-
> > > >fw_sgt.nents)
> > > +		ipu7_unmap_fw_code_region(isp->isys);
> > > +	if (!IS_ERR_OR_NULL(isp->psys) && isp->psys-
> > > >fw_sgt.nents)
> > > +		ipu7_unmap_fw_code_region(isp->psys);
> > > +	if (!IS_ERR_OR_NULL(isp->psys) && !IS_ERR_OR_NULL(isp-
> > > >psys-
> > > > mmu))
> > > +		ipu7_mmu_cleanup(isp->psys->mmu);
> > > +	if (!IS_ERR_OR_NULL(isp->isys) && !IS_ERR_OR_NULL(isp-
> > > >isys-
> > > > mmu))
> > > +		ipu7_mmu_cleanup(isp->isys->mmu);
> > > +	if (!IS_ERR_OR_NULL(isp->psys))
> > > +		pm_runtime_put(&isp->psys->auxdev.dev);
> > > +	ipu7_bus_del_devices(pdev);
> > > +	release_firmware(isp->cpd_fw);
> > > +buttress_exit:
> > > +	ipu_buttress_exit(isp);
> > > +
> > > +	return ret;
> > > +}
> > > +
> > > +static void ipu7_pci_remove(struct pci_dev *pdev)
> > > +{
> > > +	struct ipu7_device *isp = pci_get_drvdata(pdev);
> > > +
> > > +	if (!IS_ERR_OR_NULL(isp->isys) && isp->isys-
> > > >fw_sgt.nents)
> > > +		ipu7_unmap_fw_code_region(isp->isys);
> > > +	if (!IS_ERR_OR_NULL(isp->psys) && isp->psys-
> > > >fw_sgt.nents)
> > > +		ipu7_unmap_fw_code_region(isp->psys);
> > > +
> > > +	if (!IS_ERR_OR_NULL(isp->fw_code_region))
> > > +		vfree(isp->fw_code_region);
> > > +
> > > +	ipu7_bus_del_devices(pdev);
> > > +
> > > +	pm_runtime_forbid(&pdev->dev);
> > > +	pm_runtime_get_noresume(&pdev->dev);
> > > +
> > > +	pci_release_regions(pdev);
> > 
> > You don't need this if you request with a pcim_ function. The 'm'
> > stands for "managed". Those are devres functions that will clean up
> > automatically if probe() fails or once remove() is invoked.
> > 
> > Furthermore, you should not mix pcim_ and pci_ functions; at least
> > not
> > those.
> > 
> > And even if the pcim_ functions wouldn't do a cleanup, you would
> > leak
> > the IO mappings above, since pci_release_regions() just removes the
> > region requests, but not the mapping cookies.
> > 
> > I recommend taking a look to the PCI subystem's documentation.
> > 
> > > +	pci_disable_device(pdev);
> > 
> > You also don't need this since you used pcim_enable_device(), which
> > will disable the device automatically on driver-detach.
> > 
> > 
> > P.
> > 
> > > +
> > > +	ipu_buttress_exit(isp);
> > > +
> > > +	release_firmware(isp->cpd_fw);
> > > +
> > > +	ipu7_mmu_cleanup(isp->psys->mmu);
> > > +	ipu7_mmu_cleanup(isp->isys->mmu);
> > > +}
> > > +
> > > +static void ipu7_pci_reset_prepare(struct pci_dev *pdev)
> > > +{
> > > +	struct ipu7_device *isp = pci_get_drvdata(pdev);
> > > +
> > > +	dev_warn(&pdev->dev, "FLR prepare\n");
> > > +	pm_runtime_forbid(&isp->pdev->dev);
> > > +}
> > > +
> > > +static void ipu7_pci_reset_done(struct pci_dev *pdev)
> > > +{
> > > +	struct ipu7_device *isp = pci_get_drvdata(pdev);
> > > +
> > > +	ipu_buttress_restore(isp);
> > > +	if (isp->secure_mode)
> > > +		ipu_buttress_reset_authentication(isp);
> > > +
> > > +	isp->ipc_reinit = true;
> > > +	pm_runtime_allow(&isp->pdev->dev);
> > > +
> > > +	dev_warn(&pdev->dev, "FLR completed\n");
> > > +}
> > > +
> > > +/*
> > > + * PCI base driver code requires driver to provide these to
> > > enable
> > > + * PCI device level PM state transitions (D0<->D3)
> > > + */
> > > +static int ipu7_suspend(struct device *dev)
> > > +{
> > > +	return 0;
> > > +}
> > > +
> > > +static int ipu7_resume(struct device *dev)
> > > +{
> > > +	struct pci_dev *pdev = to_pci_dev(dev);
> > > +	struct ipu7_device *isp = pci_get_drvdata(pdev);
> > > +	struct ipu_buttress *b = &isp->buttress;
> > > +	int ret;
> > > +
> > > +	isp->secure_mode = ipu_buttress_get_secure_mode(isp);
> > > +	dev_info(dev, "IPU7 in %s mode\n",
> > > +		 isp->secure_mode ? "secure" : "non-secure");
> > > +
> > > +	ipu_buttress_restore(isp);
> > > +
> > > +	ret = ipu_buttress_ipc_reset(isp, &b->cse);
> > > +	if (ret)
> > > +		dev_err(dev, "IPC reset protocol failed!\n");
> > > +
> > > +	ret = pm_runtime_get_sync(&isp->psys->auxdev.dev);
> > > +	if (ret < 0) {
> > > +		dev_err(dev, "Failed to get runtime PM\n");
> > > +		return 0;
> > > +	}
> > > +
> > > +	ret = ipu_buttress_authenticate(isp);
> > > +	if (ret)
> > > +		dev_err(dev, "FW authentication failed(%d)\n",
> > > ret);
> > > +
> > > +	pm_runtime_put(&isp->psys->auxdev.dev);
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static int ipu7_runtime_resume(struct device *dev)
> > > +{
> > > +	struct pci_dev *pdev = to_pci_dev(dev);
> > > +	struct ipu7_device *isp = pci_get_drvdata(pdev);
> > > +	int ret;
> > > +
> > > +	ipu_buttress_restore(isp);
> > > +
> > > +	if (isp->ipc_reinit) {
> > > +		struct ipu_buttress *b = &isp->buttress;
> > > +
> > > +		isp->ipc_reinit = false;
> > > +		ret = ipu_buttress_ipc_reset(isp, &b->cse);
> > > +		if (ret)
> > > +			dev_err(dev, "IPC reset protocol
> > > failed!\n");
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +static const struct dev_pm_ops ipu7_pm_ops = {
> > > +	SET_SYSTEM_SLEEP_PM_OPS(&ipu7_suspend, &ipu7_resume)
> > > +	SET_RUNTIME_PM_OPS(&ipu7_suspend,	/* Same as in
> > > suspend flow */
> > > +			   &ipu7_runtime_resume,
> > > +			   NULL)
> > > +};
> > > +
> > > +static const struct pci_device_id ipu7_pci_tbl[] = {
> > > +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU7_PCI_ID)},
> > > +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU7P5_PCI_ID)},
> > > +	{PCI_DEVICE(PCI_VENDOR_ID_INTEL, IPU8_PCI_ID)},
> > > +	{0,}
> > > +};
> > > +MODULE_DEVICE_TABLE(pci, ipu7_pci_tbl);
> > > +
> > > +static const struct pci_error_handlers pci_err_handlers = {
> > > +	.reset_prepare = ipu7_pci_reset_prepare,
> > > +	.reset_done = ipu7_pci_reset_done,
> > > +};
> > > +
> > > +static struct pci_driver ipu7_pci_driver = {
> > > +	.name = IPU_NAME,
> > > +	.id_table = ipu7_pci_tbl,
> > > +	.probe = ipu7_pci_probe,
> > > +	.remove = ipu7_pci_remove,
> > > +	.driver = {
> > > +		.pm = &ipu7_pm_ops,
> > > +	},
> > > +	.err_handler = &pci_err_handlers,
> > > +};
> > > +
> > > +module_pci_driver(ipu7_pci_driver);
> > > +
> > > +MODULE_IMPORT_NS("INTEL_IPU_BRIDGE");
> > > +MODULE_AUTHOR("Bingbu Cao <bingbu.cao@xxxxxxxxx>");
> > > +MODULE_AUTHOR("Tianshu Qiu <tian.shu.qiu@xxxxxxxxx>");
> > > +MODULE_AUTHOR("Qingwu Zhang <qingwu.zhang@xxxxxxxxx>");
> > > +MODULE_AUTHOR("Intel");
> > > +MODULE_LICENSE("GPL");
> > > +MODULE_DESCRIPTION("Intel ipu7 pci driver");
> > > diff --git a/drivers/media/pci/intel/ipu7/ipu7.h
> > > b/drivers/media/pci/intel/ipu7/ipu7.h
> > > new file mode 100644
> > > index 000000000000..6f5705f403b7
> > > --- /dev/null
> > > +++ b/drivers/media/pci/intel/ipu7/ipu7.h
> > > @@ -0,0 +1,244 @@
> > > +/* SPDX-License-Identifier: GPL-2.0-only */
> > > +/*
> > > + * Copyright (C) 2013 - 2024 Intel Corporation
> > > + */
> > > +
> > > +#ifndef IPU7_H
> > > +#define IPU7_H
> > > +
> > > +#include <linux/list.h>
> > > +#include <linux/pci.h>
> > > +#include <linux/types.h>
> > > +
> > > +#include "ipu7-buttress.h"
> > > +
> > > +struct ipu7_bus_device;
> > > +struct pci_dev;
> > > +struct firmware;
> > > +
> > > +#define IPU_NAME			"intel-ipu7"
> > > +#define IPU_MEDIA_DEV_MODEL_NAME	"ipu7"
> > > +
> > > +#define IPU7_FIRMWARE_NAME		"intel/ipu/ipu7_fw.bin"
> > > +#define
> > > IPU7P5_FIRMWARE_NAME		"intel/ipu/ipu7ptl_fw.bin"
> > > +#define IPU8_FIRMWARE_NAME		"intel/ipu/ipu8_fw.bin"
> > > +
> > > +#define IPU7_ISYS_NUM_STREAMS		12
> > > +
> > > +#define IPU7_PCI_ID			0x645d
> > > +#define IPU7P5_PCI_ID			0xb05d
> > > +#define IPU8_PCI_ID			0xd719
> > > +
> > > +#define FW_LOG_BUF_SIZE			(2 * 1024 *
> > > 1024)
> > > +
> > > +enum ipu_version {
> > > +	IPU_VER_INVALID = 0,
> > > +	IPU_VER_7 = 1,
> > > +	IPU_VER_7P5 = 2,
> > > +	IPU_VER_8 = 3,
> > > +};
> > > +
> > > +static inline bool is_ipu7p5(u8 hw_ver)
> > > +{
> > > +	return hw_ver == IPU_VER_7P5;
> > > +}
> > > +
> > > +static inline bool is_ipu7(u8 hw_ver)
> > > +{
> > > +	return hw_ver == IPU_VER_7;
> > > +}
> > > +
> > > +static inline bool is_ipu8(u8 hw_ver)
> > > +{
> > > +	return hw_ver == IPU_VER_8;
> > > +}
> > > +
> > > +#define IPU_UNIFIED_OFFSET		0
> > > +
> > > +/*
> > > + * ISYS DMA can overshoot. For higher resolutions over
> > > allocation is
> > > one line
> > > + * but it must be at minimum 1024 bytes. Value could be
> > > different in
> > > + * different versions / generations thus provide it via platform
> > > data.
> > > + */
> > > +#define IPU_ISYS_OVERALLOC_MIN		1024
> > > +
> > > +#define IPU_FW_CODE_REGION_SIZE		0x1000000 /*
> > > 16MB */
> > > +#define IPU_FW_CODE_REGION_START	0x4000000 /* 64MB */
> > > +#define
> > > IPU_FW_CODE_REGION_END		(IPU_FW_CODE_REGION_START
> > > +	\
> > > +					
> > > IPU_FW_CODE_REGION_SIZE) /*
> > > 80MB */
> > > +
> > > +struct ipu7_device {
> > > +	struct pci_dev *pdev;
> > > +	struct list_head devices;
> > > +	struct ipu7_bus_device *isys;
> > > +	struct ipu7_bus_device *psys;
> > > +	struct ipu_buttress buttress;
> > > +
> > > +	const struct firmware *cpd_fw;
> > > +	const char *cpd_fw_name;
> > > +	/* Only for non-secure mode. */
> > > +	void *fw_code_region;
> > > +
> > > +	void __iomem *base;
> > > +	void __iomem *pb_base;
> > > +	u8 hw_ver;
> > > +	bool ipc_reinit;
> > > +	bool secure_mode;
> > > +	bool ipu7_bus_ready_to_probe;
> > > +};
> > > +
> > > +#define IPU_DMA_MASK			39
> > > +#define IPU_LIB_CALL_TIMEOUT_MS		2000
> > > +#define IPU_PSYS_CMD_TIMEOUT_MS		2000
> > > +#define IPU_PSYS_OPEN_CLOSE_TIMEOUT_US	50
> > > +#define IPU_PSYS_OPEN_CLOSE_RETRY	(10000 /
> > > IPU_PSYS_OPEN_CLOSE_TIMEOUT_US)
> > > +
> > > +#define IPU_ISYS_NAME "isys"
> > > +#define IPU_PSYS_NAME "psys"
> > > +
> > > +#define IPU_MMU_ADDR_BITS		32
> > > +/* FW is accessible within the first 2 GiB only in non-secure
> > > mode.
> > > */
> > > +#define IPU_MMU_ADDR_BITS_NON_SECURE	31
> > > +
> > > +#define IPU7_IS_MMU_NUM			4
> > > +#define IPU7_PS_MMU_NUM			4
> > > +#define IPU7P5_IS_MMU_NUM		4
> > > +#define IPU7P5_PS_MMU_NUM		4
> > > +#define IPU8_IS_MMU_NUM			5
> > > +#define IPU8_PS_MMU_NUM			4
> > > +#define IPU_MMU_MAX_NUM			5 /* max(IS, PS)
> > > */
> > > +#define IPU_MMU_MAX_TLB_L1_STREAMS	40
> > > +#define IPU_MMU_MAX_TLB_L2_STREAMS	40
> > > +#define IPU_ZLX_MAX_NUM			32
> > > +#define IPU_ZLX_POOL_NUM		8
> > > +#define IPU_UAO_PLANE_MAX_NUM		64
> > > +
> > > +/*
> > > + * To maximize the IOSF utlization, IPU need to send requests in
> > > bursts.
> > > + * At the DMA interface with the buttress, there are CDC FIFOs
> > > with
> > > burst
> > > + * collection capability. CDC FIFO burst collectors have a
> > > configurable
> > > + * threshold and is configured based on the outcome of
> > > performance
> > > measurements.
> > > + *
> > > + * isys has 3 ports with IOSF interface for VC0, VC1 and VC2
> > > + * psys has 4 ports with IOSF interface for VC0, VC1w, VC1r and
> > > VC2
> > > + *
> > > + * Threshold values are pre-defined and are arrived at after
> > > performance
> > > + * evaluations on a type of IPU
> > > + */
> > > +#define IPU_MAX_VC_IOSF_PORTS		4
> > > +
> > > +/*
> > > + * IPU must configure correct arbitration mechanism related to
> > > the
> > > IOSF VC
> > > + * requests. There are two options per VC0 and VC1 - > 0 means
> > > rearbitrate on
> > > + * stall and 1 means stall until the request is completed.
> > > + */
> > > +#define IPU_BTRS_ARB_MODE_TYPE_REARB	0
> > > +#define IPU_BTRS_ARB_MODE_TYPE_STALL	1
> > > +
> > > +/* Currently chosen arbitration mechanism for VC0 */
> > > +#define
> > > IPU_BTRS_ARB_STALL_MODE_VC0	IPU_BTRS_ARB_MODE_TYPE_REARB
> > > +
> > > +/* Currently chosen arbitration mechanism for VC1 */
> > > +#define
> > > IPU_BTRS_ARB_STALL_MODE_VC1	IPU_BTRS_ARB_MODE_TYPE_REARB
> > > +
> > > +struct ipu7_isys_subdev_pdata;
> > > +
> > > +/* One L2 entry maps 1024 L1 entries and one L1 entry per page
> > > */
> > > +#define IPU_MMUV2_L2_RANGE		(1024 * PAGE_SIZE)
> > > +/* Max L2 blocks per stream */
> > > +#define IPU_MMUV2_MAX_L2_BLOCKS		2
> > > +/* Max L1 blocks per stream */
> > > +#define IPU_MMUV2_MAX_L1_BLOCKS		16
> > > +#define IPU_MMUV2_TRASH_RANGE		(IPU_MMUV2_L2_RANGE
> > > *	\
> > > +					
> > > IPU_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	IPU_MMUV2_L2_RANGE
> > > +
> > > +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[IPU_MMU_MAX_TLB_L1_STREAMS];
> > > +	u32 l2_block_sz[IPU_MMU_MAX_TLB_L2_STREAMS];
> > > +
> > > +	u8 zlx_nr;
> > > +	u32 zlx_axi_pool[IPU_ZLX_POOL_NUM];
> > > +	u32 zlx_en[IPU_ZLX_MAX_NUM];
> > > +	u32 zlx_conf[IPU_ZLX_MAX_NUM];
> > > +
> > > +	u32 uao_p_num;
> > > +	u32 uao_p2tlb[IPU_UAO_PLANE_MAX_NUM];
> > > +};
> > > +
> > > +struct ipu7_mmu_pdata {
> > > +	u32 nr_mmus;
> > > +	struct ipu7_mmu_hw mmu_hw[IPU_MMU_MAX_NUM];
> > > +	int mmid;
> > > +};
> > > +
> > > +struct ipu7_isys_csi2_pdata {
> > > +	void __iomem *base;
> > > +};
> > > +
> > > +struct ipu7_isys_internal_csi2_pdata {
> > > +	u32 nports;
> > > +	u32 *offsets;
> > > +	u32 gpreg;
> > > +};
> > > +
> > > +struct ipu7_hw_variants {
> > > +	unsigned long offset;
> > > +	u32 nr_mmus;
> > > +	struct ipu7_mmu_hw mmu_hw[IPU_MMU_MAX_NUM];
> > > +	u8 cdc_fifos;
> > > +	u8 cdc_fifo_threshold[IPU_MAX_VC_IOSF_PORTS];
> > > +	u32 dmem_offset;
> > > +	u32 spc_offset;	/* SPC offset from psys base */
> > > +};
> > > +
> > > +struct ipu_isys_internal_pdata {
> > > +	struct ipu7_isys_internal_csi2_pdata csi2;
> > > +	struct ipu7_hw_variants hw_variant;
> > > +	u32 num_parallel_streams;
> > > +	u32 isys_dma_overshoot;
> > > +};
> > > +
> > > +struct ipu7_isys_pdata {
> > > +	void __iomem *base;
> > > +	const struct ipu_isys_internal_pdata *ipdata;
> > > +};
> > > +
> > > +struct ipu_psys_internal_pdata {
> > > +	struct ipu7_hw_variants hw_variant;
> > > +};
> > > +
> > > +struct ipu7_psys_pdata {
> > > +	void __iomem *base;
> > > +	const struct ipu_psys_internal_pdata *ipdata;
> > > +};
> > > +
> > > +int request_cpd_fw(const struct firmware **firmware_p, const
> > > char
> > > *name,
> > > +		   struct device *device);
> > > +void ipu_internal_pdata_init(struct ipu_isys_internal_pdata
> > > *isys_ipdata,
> > > +			     struct ipu_psys_internal_pdata
> > > *psys_ipdata);
> > > +void ipu7_dump_fw_error_log(const struct ipu7_bus_device *adev);
> > > +#endif /* IPU7_H */
> > 
> 






[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux