From 1f2ef6588e26e4455ca61d92d6ce27618453c3b4 Mon Sep 17 00:00:00 2001 From: Akihiro Mizusawa Date: Wed, 13 Mar 2024 13:31:44 -0500 Subject: [PATCH] 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 Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3095788 GVS: buildbot_gerritrpt Reviewed-by: Laxman Dewangan Reviewed-by: Chinniah Poosapadi --- drivers/media/platform/tegra/camera/Makefile | 6 +- .../camera/fusa-capture/capture-isp-channel.c | 110 +++++++----------- .../tegra/camera/fusa-capture/capture-isp.c | 53 ++++++++- .../camera/fusa-capture/capture-vi-channel.c | 2 +- .../tegra/host/capture/capture-support.c | 24 +++- drivers/video/tegra/host/isp/isp5.c | 68 ++++++----- .../media/fusa-capture/capture-isp-channel.h | 21 +++- include/media/fusa-capture/capture-isp.h | 18 ++- 8 files changed, 198 insertions(+), 104 deletions(-) diff --git a/drivers/media/platform/tegra/camera/Makefile b/drivers/media/platform/tegra/camera/Makefile index 7ad93167..a3c79b78 100644 --- a/drivers/media/platform/tegra/camera/Makefile +++ b/drivers/media/platform/tegra/camera/Makefile @@ -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 diff --git a/drivers/media/platform/tegra/camera/fusa-capture/capture-isp-channel.c b/drivers/media/platform/tegra/camera/fusa-capture/capture-isp-channel.c index b6ef7b53..6a51a45a 100644 --- a/drivers/media/platform/tegra/camera/fusa-capture/capture-isp-channel.c +++ b/drivers/media/platform/tegra/camera/fusa-capture/capture-isp-channel.c @@ -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 #include -/** - * @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) { diff --git a/drivers/media/platform/tegra/camera/fusa-capture/capture-isp.c b/drivers/media/platform/tegra/camera/fusa-capture/capture-isp.c index 54ee6463..f135a11b 100644 --- a/drivers/media/platform/tegra/camera/fusa-capture/capture-isp.c +++ b/drivers/media/platform/tegra/camera/fusa-capture/capture-isp.c @@ -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"); diff --git a/drivers/media/platform/tegra/camera/fusa-capture/capture-vi-channel.c b/drivers/media/platform/tegra/camera/fusa-capture/capture-vi-channel.c index b5487bf2..8eb82211 100644 --- a/drivers/media/platform/tegra/camera/fusa-capture/capture-vi-channel.c +++ b/drivers/media/platform/tegra/camera/fusa-capture/capture-vi-channel.c @@ -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; diff --git a/drivers/video/tegra/host/capture/capture-support.c b/drivers/video/tegra/host/capture/capture-support.c index df0c4fec..9e9af30b 100644 --- a/drivers/video/tegra/host/capture/capture-support.c +++ b/drivers/video/tegra/host/capture/capture-support.c @@ -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 #include #include +#include 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); diff --git a/drivers/video/tegra/host/isp/isp5.c b/drivers/video/tegra/host/isp/isp5.c index 90064569..ba734000 100644 --- a/drivers/video/tegra/host/isp/isp5.c +++ b/drivers/video/tegra/host/isp/isp5.c @@ -30,6 +30,7 @@ #include "isp5.h" #include "capture/capture-support.h" #include +#include #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"); diff --git a/include/media/fusa-capture/capture-isp-channel.h b/include/media/fusa-capture/capture-isp-channel.h index 4d3fe1d1..cae1cf7d 100644 --- a/include/media/fusa-capture/capture-isp-channel.h +++ b/include/media/fusa-capture/capture-isp-channel.h @@ -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__ */ diff --git a/include/media/fusa-capture/capture-isp.h b/include/media/fusa-capture/capture-isp.h index 6a55f1b2..68bed631 100644 --- a/include/media/fusa-capture/capture-isp.h +++ b/include/media/fusa-capture/capture-isp.h @@ -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.