video: tegra: add support for T264 isp

Move capture-isp-channel registration from host to
capture-isp driver.

Make tegra-capture-isp a separate driver module.

Implement support for T264.

Add isp_unit affinity to ISP_CAPTURE_SETUP ioctl.

CT26X-468
CT26X-469
CT26X-467
CT26X-466
CT26X-464
CT26X-465

Change-Id: If644d6aa0ad1b12d34457dc94249ed09f9f9f720
Signed-off-by: Akihiro Mizusawa <amizusawa@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3095788
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Reviewed-by: Chinniah Poosapadi <cpoosapadi@nvidia.com>
This commit is contained in:
Akihiro Mizusawa
2024-03-13 13:31:44 -05:00
committed by mobile promotions
parent c37b941d16
commit 1f2ef6588e
8 changed files with 198 additions and 104 deletions

View File

@@ -28,9 +28,11 @@ tegra-camera-objs += nvcsi/csi5_fops.o
tegra-camera-objs += fusa-capture/capture-vi.o
tegra-camera-objs += fusa-capture/capture-common.o
tegra-camera-objs += fusa-capture/capture-vi-channel.o
tegra-camera-objs += fusa-capture/capture-isp-channel.o
tegra-camera-objs += fusa-capture/capture-isp.o
obj-m += tegra-camera.o
obj-m += tests/
tegra-capture-isp-objs += fusa-capture/capture-isp-channel.o
tegra-capture-isp-objs += fusa-capture/capture-isp.o
obj-m += tegra-capture-isp.o
endif
endif

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017-2023 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2017-2023 NVIDIA Corporation. All rights reserved.
/**
* @file drivers/media/platform/tegra/camera/fusa-capture/capture-isp-channel.c
@@ -23,17 +23,13 @@
#include <media/fusa-capture/capture-isp.h>
#include <media/fusa-capture/capture-isp-channel.h>
/**
* @todo This parameter is platform-dependent and should be retrieved from the
* Device Tree.
*/
#define MAX_ISP_CHANNELS 64
/**
* @brief ISP channel character device driver context.
*/
struct isp_channel_drv {
struct device *dev; /**< ISP kernel @em device */
struct platform_device *isp_capture_pdev;
/**< Capture ISP driver platform device */
u8 num_channels; /**< No. of ISP channel character devices */
struct mutex lock; /**< ISP channel driver context lock. */
struct platform_device *ndev; /**< ISP kernel @em platform_device */
@@ -198,49 +194,6 @@ struct isp_channel_drv {
/** @} */
/**
* @brief Power on ISP via Host1x. The ISP channel is registered as an NvHost
* ISP client and the reference count is incremented by one.
*
* @param[in] chan ISP channel context
* @returns 0 (success), neg. errno (failure)
*/
static int isp_channel_power_on(
struct tegra_isp_channel *chan)
{
int ret = 0;
dev_dbg(chan->isp_dev, "isp_channel_power_on\n");
ret = nvhost_module_add_client(chan->ndev, chan->priv);
if (ret < 0) {
dev_err(chan->isp_dev,
"%s: failed to add isp client\n", __func__);
return ret;
}
ret = nvhost_module_busy(chan->ndev);
if (ret < 0) {
dev_err(chan->isp_dev,
"%s: failed to power on isp\n", __func__);
return ret;
}
return 0;
}
/**
* @brief Power off ISP via Host1x. The NvHost module reference count is
* decreased by one and the ISP channel is unregistered as a client.
*
* @param[in] chan ISP channel context
*/
static void isp_channel_power_off(
struct tegra_isp_channel *chan)
{
dev_dbg(chan->isp_dev, "isp_channel_power_off\n");
nvhost_module_idle(chan->ndev);
nvhost_module_remove_client(chan->ndev, chan->priv);
}
static struct isp_channel_drv *chdrv_;
static DEFINE_MUTEX(chdrv_lock);
@@ -287,12 +240,9 @@ static int isp_channel_open(
chan->isp_dev = chan_drv->dev;
chan->ndev = chan_drv->ndev;
chan->ops = chan_drv->ops;
chan->isp_capture_pdev = chan_drv->isp_capture_pdev;
chan->priv = file;
err = isp_channel_power_on(chan);
if (err < 0)
goto error;
err = isp_capture_init(chan);
if (err < 0)
goto init_err;
@@ -314,8 +264,6 @@ static int isp_channel_open(
chan_err:
isp_capture_shutdown(chan);
init_err:
isp_channel_power_off(chan);
error:
kfree(chan);
return err;
}
@@ -343,7 +291,6 @@ static int isp_channel_release(
struct isp_channel_drv *chan_drv = chan->drv;
isp_capture_shutdown(chan);
isp_channel_power_off(chan);
mutex_lock(&chan_drv->lock);
@@ -392,6 +339,13 @@ static long isp_channel_ioctl(
if (copy_from_user(&setup, ptr, sizeof(setup)))
break;
isp_get_nvhost_device(chan, &setup);
if (chan->isp_dev == NULL) {
dev_err(&chan->isp_capture_pdev->dev,
"%s: channel device is NULL",
__func__);
return -EINVAL;
}
err = isp_capture_setup(chan, &setup);
if (err)
dev_err(chan->isp_dev, "isp capture setup failed\n");
@@ -534,24 +488,24 @@ static const struct file_operations isp_channel_fops = {
/* Character device */
static struct class *isp_channel_class;
static int isp_channel_major;
static int isp_channel_major = -1;
int isp_channel_drv_register(
struct platform_device *ndev,
const struct isp_channel_drv_ops *ops)
unsigned int max_isp_channels)
{
struct isp_channel_drv *chan_drv;
unsigned int i;
chan_drv = kzalloc(offsetof(struct isp_channel_drv,
channels[MAX_ISP_CHANNELS]), GFP_KERNEL);
channels[max_isp_channels]), GFP_KERNEL);
if (unlikely(chan_drv == NULL))
return -ENOMEM;
chan_drv->dev = &ndev->dev;
chan_drv->ndev = ndev;
chan_drv->ops = ops;
chan_drv->num_channels = MAX_ISP_CHANNELS;
chan_drv->dev = NULL;
chan_drv->ndev = NULL;
chan_drv->isp_capture_pdev = ndev;
chan_drv->num_channels = max_isp_channels;
mutex_init(&chan_drv->lock);
mutex_lock(&chdrv_lock);
@@ -566,7 +520,7 @@ int isp_channel_drv_register(
for (i = 0; i < chan_drv->num_channels; i++) {
dev_t devt = MKDEV(isp_channel_major, i);
device_create(isp_channel_class, chan_drv->dev, devt, NULL,
device_create(isp_channel_class, &chan_drv->isp_capture_pdev->dev, devt, NULL,
"capture-isp-channel%u", i);
}
@@ -574,6 +528,32 @@ int isp_channel_drv_register(
}
EXPORT_SYMBOL(isp_channel_drv_register);
int isp_channel_drv_fops_register(
const struct isp_channel_drv_ops *ops)
{
int err = 0;
struct isp_channel_drv *chan_drv;
chan_drv = chdrv_;
if (chan_drv == NULL) {
err = -EPROBE_DEFER;
goto error;
}
mutex_lock(&chdrv_lock);
if (chan_drv->ops == NULL)
chan_drv->ops = ops;
else
dev_dbg(chan_drv->dev, "isp fops function table already registered\n");
mutex_unlock(&chdrv_lock);
return 0;
error:
return err;
}
EXPORT_SYMBOL(isp_channel_drv_fops_register);
void isp_channel_drv_unregister(
struct device *dev)
{

View File

@@ -988,6 +988,19 @@ void isp_capture_shutdown(
chan->capture_data = NULL;
}
void isp_get_nvhost_device(
struct tegra_isp_channel *chan,
struct isp_capture_setup *setup)
{
uint32_t isp_inst = setup->isp_unit;
struct tegra_capture_isp_data *info =
platform_get_drvdata(chan->isp_capture_pdev);
chan->isp_dev = &info->isp_pdevices[isp_inst]->dev;
chan->ndev = info->isp_pdevices[isp_inst];
}
int isp_capture_setup(
struct tegra_isp_channel *chan,
struct isp_capture_setup *setup)
@@ -1004,6 +1017,9 @@ int isp_capture_setup(
int i;
#endif
struct tegra_capture_isp_data *info =
platform_get_drvdata(chan->isp_capture_pdev);
nv_camera_log(chan->ndev,
__arch_counter_get_cntvct(),
NVHOST_CAMERA_ISP_CAPTURE_SETUP);
@@ -1023,10 +1039,12 @@ int isp_capture_setup(
dev_dbg(chan->isp_dev, "chan flags %u\n", setup->channel_flags);
dev_dbg(chan->isp_dev, "queue depth %u\n", setup->queue_depth);
dev_dbg(chan->isp_dev, "request size %u\n", setup->request_size);
dev_dbg(chan->isp_dev, "isp unit %u\n", setup->isp_unit);
if (setup->channel_flags == 0 ||
setup->queue_depth == 0 ||
setup->request_size == 0)
setup->request_size == 0 ||
setup->isp_unit >= info->num_isp_devices)
return -EINVAL;
buffer_ctx = create_buffer_table(chan->isp_dev);
@@ -1158,6 +1176,8 @@ int isp_capture_setup(
config->channel_flags = setup->channel_flags;
config->isp_unit_id = setup->isp_unit;
config->request_queue_depth = setup->queue_depth;
config->request_size = setup->request_size;
config->requests = capture->capture_desc_ctx.requests.iova;
@@ -2062,6 +2082,10 @@ static int capture_isp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, info);
err = isp_channel_drv_register(pdev, info->max_isp_channels);
if (err)
goto cleanup;
return 0;
cleanup:
@@ -2103,4 +2127,29 @@ static struct platform_driver capture_isp_driver = {
}
};
module_platform_driver(capture_isp_driver);
static int __init capture_isp_init(void)
{
int err;
err = isp_channel_drv_init();
if (err)
return err;
err = platform_driver_register(&capture_isp_driver);
if (err) {
isp_channel_drv_exit();
return err;
}
return 0;
}
static void __exit capture_isp_exit(void)
{
isp_channel_drv_exit();
platform_driver_unregister(&capture_isp_driver);
}
module_init(capture_isp_init);
module_exit(capture_isp_exit);
MODULE_IMPORT_NS(DMA_BUF);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("tegra capture-isp driver");

View File

@@ -691,7 +691,7 @@ int vi_channel_drv_fops_register(
if (chan_drv->ops == NULL)
chan_drv->ops = ops;
else
dev_warn(chan_drv->dev, "fops function table already registered\n");
dev_dbg(chan_drv->dev, "vi fops function table already registered\n");
mutex_unlock(&chdrv_lock);
return 0;

View File

@@ -2,7 +2,7 @@
/*
* Capture support for syncpoint and GoS management
*
* Copyright (c) 2017-2022, NVIDIA Corporation. All rights reserved.
* Copyright (c) 2017-2024, NVIDIA Corporation. All rights reserved.
*/
#include "capture-support.h"
@@ -19,6 +19,7 @@
#include <linux/version.h>
#include <soc/tegra/fuse.h>
#include <linux/nvhost.h>
#include <uapi/linux/nvhost_ioctl.h>
int capture_alloc_syncpt(struct platform_device *pdev,
const char *name,
@@ -164,6 +165,17 @@ struct nvhost_device_data t23x_vi1_thi_info = {
.moduleid = 3, //NVHOST_MODULE_VI2,
};
struct nvhost_device_data t264_isp_thi_info = {
.devfs_name = "isp-thi",
.moduleid = 4, //NVHOST_MODULE_ISP
};
struct nvhost_device_data t264_isp1_thi_info = {
.devfs_name = "isp1-thi",
.moduleid = 5, //NVHOST_MODULE_ISPB
};
static const struct of_device_id capture_support_match[] = {
{
.compatible = "nvidia,tegra194-isp-thi",
@@ -183,6 +195,16 @@ static const struct of_device_id capture_support_match[] = {
.compatible = "nvidia,tegra234-vi-thi",
.data = &t23x_vi1_thi_info,
},
{
.name = "isp-thi",
.compatible = "nvidia,tegra264-isp-thi",
.data = &t264_isp_thi_info,
},
{
.name = "isp1-thi",
.compatible = "nvidia,tegra264-isp-thi",
.data = &t264_isp1_thi_info,
},
{ },
};
MODULE_DEVICE_TABLE(of, capture_support_match);

View File

@@ -30,6 +30,7 @@
#include "isp5.h"
#include "capture/capture-support.h"
#include <uapi/linux/nvhost_isp_ioctl.h>
#include <uapi/linux/nvhost_ioctl.h>
#define ISP_PPC 2
/* 20% overhead */
@@ -125,6 +126,11 @@ int isp5_priv_early_probe(struct platform_device *pdev)
goto error;
}
err = isp_channel_drv_fops_register(&isp5_channel_drv_ops);
if (err) {
goto error;
}
if (thi->dev.driver == NULL) {
platform_device_put(thi);
return -EPROBE_DEFER;
@@ -188,10 +194,6 @@ int isp5_priv_late_probe(struct platform_device *pdev)
if (err)
goto device_release;
err = isp_channel_drv_register(pdev, &isp5_channel_drv_ops);
if (err)
goto device_release;
return 0;
device_release:
@@ -335,7 +337,41 @@ struct nvhost_device_data t19_isp5_info = {
.class = ISP_CLASS_ID,
};
struct nvhost_device_data t264_isp_info = {
.devfs_name = "isp",
.moduleid = NVHOST_MODULE_ISP,
.clocks = {
{"isp", UINT_MAX},
},
.pre_virt_init = isp5_priv_early_probe,
.post_virt_init = isp5_priv_late_probe,
.can_powergate = false,
.class = ISP_CLASS_ID,
};
struct nvhost_device_data t264_isp1_info = {
.devfs_name = "isp1",
.moduleid = NVHOST_MODULE_ISPB,
.clocks = {
{"isp1", UINT_MAX},
},
.pre_virt_init = isp5_priv_early_probe,
.post_virt_init = isp5_priv_late_probe,
.can_powergate = false,
.class = ISP_CLASS_ID,
};
static const struct of_device_id tegra_isp5_of_match[] = {
{
.name = "isp",
.compatible = "nvidia,tegra264-isp",
.data = &t264_isp_info,
},
{
.name = "isp1",
.compatible = "nvidia,tegra264-isp",
.data = &t264_isp1_info,
},
{
.compatible = "nvidia,tegra194-isp",
.data = &t19_isp5_info,
@@ -359,28 +395,6 @@ static struct platform_driver isp5_driver = {
},
};
static int __init capture_isp_init(void)
{
int err;
module_platform_driver(isp5_driver);
err = isp_channel_drv_init();
if (err)
return err;
err = platform_driver_register(&isp5_driver);
if (err) {
isp_channel_drv_exit();
return err;
}
return 0;
}
static void __exit capture_isp_exit(void)
{
isp_channel_drv_exit();
platform_driver_unregister(&isp5_driver);
}
module_init(capture_isp_init);
module_exit(capture_isp_exit);
MODULE_LICENSE("GPL");

View File

@@ -81,7 +81,9 @@ struct isp_channel_drv_ops {
*/
struct tegra_isp_channel {
struct device *isp_dev; /**< ISP device */
struct platform_device *ndev; /**< ISP platform_device */
struct platform_device *ndev; /**< ISP nvhost platform_device */
struct platform_device *isp_capture_pdev;
/**< Capture ISP driver platform device */
struct isp_channel_drv *drv; /**< ISP channel driver context */
void *priv; /**< ISP channel private context */
struct isp_capture *capture_data; /**< ISP channel capture context */
@@ -90,19 +92,19 @@ struct tegra_isp_channel {
/**
* @brief Create the ISP channels driver contexts, and instantiate
* MAX_ISP_CHANNELS many channel character device nodes.
* channel character device nodes as specified in the device tree.
*
* ISP channel nodes appear in the filesystem as:
* /dev/capture-isp-channel{0..MAX_ISP_CHANNELS-1}
* /dev/capture-isp-channel{0..max_isp_channels-1}
*
* @param[in] ndev ISP platform_device context
* @param[in] ops isp_channel_drv_ops fops
* @param[in] max_isp_channels Maximum number of ISP channels
*
* @returns 0 (success), neg. errno (failure)
*/
int isp_channel_drv_register(
struct platform_device *pdev,
const struct isp_channel_drv_ops *ops);
unsigned int max_isp_channels);
/**
* @brief Destroy the ISP channels driver and all character device nodes.
@@ -115,6 +117,15 @@ int isp_channel_drv_register(
void isp_channel_drv_unregister(
struct device *dev);
/**
* @brief Register the chip specific syncpt/gos related function table
*
* @param[in] ops isp_channel_drv_ops fops
* @returns 0 (success), neg. errno (failure)
*/
int isp_channel_drv_fops_register(
const struct isp_channel_drv_ops *ops);
int isp_channel_drv_init(void);
void isp_channel_drv_exit(void);
#endif /* __FUSA_CAPTURE_ISP_CHANNEL_H__ */

View File

@@ -47,7 +47,9 @@ struct isp_capture_setup {
/**<
* Bitmask for channel flags, see @ref CAPTURE_ISP_CHANNEL_FLAGS
*/
uint32_t __pad_flags;
/* ISP unit index */
uint8_t isp_unit;
uint8_t __pad[3];
/* ISP process capture descriptor queue (ring buffer) */
uint32_t queue_depth;
@@ -186,6 +188,20 @@ int isp_capture_init(
void isp_capture_shutdown(
struct tegra_isp_channel *chan);
/**
* @brief Select the NvHost ISP client instance platform driver to be
* associated with the channel.
* Only used in the case where ISP standalone driver is used
* to enumerate the ISP channel character drivers
*
* @param[in/out] chan ISP channel context
* @param[in] setup ISP channel setup config
*
*/
void isp_get_nvhost_device(
struct tegra_isp_channel *chan,
struct isp_capture_setup *setup);
/**
* @brief Open an ISP channel in RCE, sending channel configuration to request a
* SW channel allocation. Syncpts are allocated by the KMD in this subroutine.