diff --git a/drivers/media/platform/tegra/cam_fsync/cam_fsync.c b/drivers/media/platform/tegra/cam_fsync/cam_fsync.c index d59aca51..65d34fdc 100644 --- a/drivers/media/platform/tegra/cam_fsync/cam_fsync.c +++ b/drivers/media/platform/tegra/cam_fsync/cam_fsync.c @@ -1,5 +1,7 @@ -/* Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. - * SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0-only +/* + * SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. + * All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -1174,6 +1176,11 @@ static int cam_fsync_create_default_group(struct cam_fsync_controller *controlle return err; } } + err = cam_fsync_group_verify_generators_lcm(group); + if (err != 0) { + dev_err(controller->dev, "Generator LCM check failed"); + return err; + } list_add_tail(&group->list, &controller->groups); return err; @@ -1238,6 +1245,10 @@ static int cam_fsync_find_and_add_groups(struct cam_fsync_controller *controller num_generators = of_property_count_elems_of_size(np, "generators", sizeof(u32)); + if (num_generators < 0) { + dev_err(controller->dev, "Unable to parse generators: %d\n", num_generators); + return num_generators; + } for (i = 0; i < num_generators; i++) { gen = of_parse_phandle(np, "generators", i); err = cam_fsync_add_generator(group, gen); diff --git a/drivers/media/platform/tegra/camera/camera_common.c b/drivers/media/platform/tegra/camera/camera_common.c index 50345f24..afd1a4b5 100644 --- a/drivers/media/platform/tegra/camera/camera_common.c +++ b/drivers/media/platform/tegra/camera/camera_common.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. + * SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. * All rights reserved. * * This program is free software; you can redistribute it and/or modify it @@ -271,6 +271,10 @@ int camera_common_parse_clocks(struct device *dev, } err = of_property_read_u32(np, "parent-clk-index", &parentclk_index); + if (err) { + dev_err(dev, "Failed to find parent clk index\n"); + return err; + } } for (i = 0; i < numclocks; i++) { 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 6365e63f..d3b4479f 100644 --- a/drivers/media/platform/tegra/camera/fusa-capture/capture-isp.c +++ b/drivers/media/platform/tegra/camera/fusa-capture/capture-isp.c @@ -1,5 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-only -// SPDX-FileCopyrightText: Copyright (c) 2017-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +/* SPDX-FileCopyrightText: Copyright (c) 2017-2025 NVIDIA CORPORATION & AFFILIATES. + * All rights reserved. + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ /** * @file drivers/media/platform/tegra/camera/fusa-capture/capture-isp.c @@ -36,15 +48,18 @@ #define CAPTURE_CHANNEL_ISP_INVALID_ID U16_C(0xFFFF) /** - * @brief The default number of ISP channels to be used if not specified in - * the device tree. + * @brief Maximum number of ISP channels supported by KMD */ -#define DEFAULT_ISP_CHANNELS U32_C(16) +#define NUM_ISP_CHANNELS U32_C(16) +/** + * @brief Maximum number of ISP channels supported by KMD for T26x + */ +#define NUM_ISP_CHANNELS_T26x U32_C(32) /** * @brief Maximum number of ISP devices supported. */ -#define MAX_ISP_UNITS U32_C(0x2) +#define MAX_ISP_UNITS U32_C(0x2) /** * @brief The Capture-ISP standalone driver context. @@ -2330,6 +2345,36 @@ int isp_capture_buffer_request( return err; } +/** + * @brief Helper to parse isp-devices Chip ID + * + * @param[in] of_node Pointer to @ref device_node + * containing isp-devices phandle + * @returns true If isp-devices is configured for T26X. + * @returns false If T26X not mentioned. + */ +static inline bool isp_capture_is_t26x(struct device_node *of_node) +{ + struct device_node *node; + const char *compatible; + int ret = 0; + bool is_t26x = false; + + node = of_parse_phandle(of_node, "nvidia,isp-devices", 0); + if (node == NULL) + return false; + + ret = of_property_read_string(node, "compatible", &compatible); + if (ret != 0) { + of_node_put(node); + return false; + } + + is_t26x = (strstr(compatible, "tegra26") != NULL); + of_node_put(node); + return is_t26x; +} + static int capture_isp_probe(struct platform_device *pdev) { uint32_t i; @@ -2345,10 +2390,23 @@ static int capture_isp_probe(struct platform_device *pdev) info->num_isp_devices = 0; - (void)of_property_read_u32(dev->of_node, "nvidia,isp-max-channels", + err = of_property_read_u32(dev->of_node, "nvidia,isp-max-channels", &info->max_isp_channels); - if (info->max_isp_channels == 0) - info->max_isp_channels = DEFAULT_ISP_CHANNELS; + if (err < 0) { + err = -EINVAL; + goto cleanup; + } + if (isp_capture_is_t26x(dev->of_node)) { + if (info->max_isp_channels > NUM_ISP_CHANNELS_T26x) { + err = -EINVAL; + goto cleanup; + } + } else { + if ((info->max_isp_channels == 0) || (info->max_isp_channels > NUM_ISP_CHANNELS)) { + err = -EINVAL; + goto cleanup; + } + } for (i = 0; ; i++) { struct device_node *node; diff --git a/drivers/media/platform/tegra/camera/fusa-capture/capture-vi.c b/drivers/media/platform/tegra/camera/fusa-capture/capture-vi.c index 997047f7..e8074d30 100644 --- a/drivers/media/platform/tegra/camera/fusa-capture/capture-vi.c +++ b/drivers/media/platform/tegra/camera/fusa-capture/capture-vi.c @@ -70,6 +70,11 @@ */ #define DEFAULT_VI_CHANNELS U32_C(64) +/** + * @brief Maximum number of VI channels supported by KMD in total + */ +#define NUM_VI_CHANNELS U32_C(72) + /** * @brief Maximum number of VI devices supported. */ @@ -1621,6 +1626,7 @@ EXPORT_SYMBOL_GPL(vi_capture_set_progress_status_notifier); static int csi_vi_get_mapping_table(struct platform_device *pdev) { uint32_t index = 0; + int err = 0; struct device *dev = &pdev->dev; struct tegra_capture_vi_data *info = platform_get_drvdata(pdev); @@ -1659,10 +1665,16 @@ static int csi_vi_get_mapping_table(struct platform_device *pdev) uint32_t stream_index = NVCSI_STREAM_INVALID_ID; uint32_t vi_unit_id = INVALID_VI_UNIT_ID; - (void)of_property_read_u32_index(np, + err = of_property_read_u32_index(np, "nvidia,vi-mapping", 2 * index, &stream_index); + if (err) { + dev_err(dev, + "%s: ERR %d: missing property nvidia,vi-mapping or csi_stream_id at index %d", + __func__, err, index); + return err; + } /* Check for valid/duplicate csi-stream-id */ if (stream_index >= MAX_NVCSI_STREAM_IDS || @@ -1672,10 +1684,16 @@ static int csi_vi_get_mapping_table(struct platform_device *pdev) return -EINVAL; } - (void)of_property_read_u32_index(np, + err = of_property_read_u32_index(np, "nvidia,vi-mapping", 2 * index + 1, &vi_unit_id); + if (err) { + dev_err(dev, + "%s: ERR %d: missing property nvidia,vi-mapping or vi_unit_id at index %d", + __func__, err, index); + return err; + } /* check for valid vi-unit-id */ if (vi_unit_id >= MAX_VI_UNITS) { @@ -1713,8 +1731,13 @@ static int capture_vi_probe(struct platform_device *pdev) info->num_vi_devices = 0; - (void)of_property_read_u32(dev->of_node, "nvidia,vi-max-channels", + err = of_property_read_u32(dev->of_node, "nvidia,vi-max-channels", &info->max_vi_channels); + if (err || info->max_vi_channels > NUM_VI_CHANNELS) { + err = -EINVAL; + goto cleanup; + } + if (info->max_vi_channels == 0) info->max_vi_channels = DEFAULT_VI_CHANNELS; diff --git a/drivers/media/platform/tegra/cdi/cdi-tca-priv.h b/drivers/media/platform/tegra/cdi/cdi-tca-priv.h index 8bbeee5f..10145018 100644 --- a/drivers/media/platform/tegra/cdi/cdi-tca-priv.h +++ b/drivers/media/platform/tegra/cdi/cdi-tca-priv.h @@ -1,5 +1,17 @@ // SPDX-License-Identifier: GPL-2.0 -// Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. +/* SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. + * All rights reserved. + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ #ifndef __CDI_TCA9539_PRIV_H__ #define __CDI_TCA9539_PRIV_H__ @@ -31,19 +43,15 @@ static int tca9539_raw_wr( dev_dbg(dev, "%s\n", __func__); - if (tca9539->reg_len == 2) { - data[0] = (u8)((offset >> 8) & 0xff); - data[1] = (u8)(offset & 0xff); - data[2] = val; - size += 2; - } else if (tca9539->reg_len == 1) { - data[0] = (u8)(offset & 0xff); - data[1] = val; - size += 1; - } else if ((tca9539->reg_len == 0) || - (tca9539->reg_len > 3)) { - return 0; - } + if (tca9539->dat_len != 1) + return -EINVAL; + + if (tca9539->reg_len != 1) + return -EINVAL; + + data[0] = (u8)(offset & 0xff); + data[1] = val; + size += 1; num_msgs = size / MAX_MSG_SIZE; num_msgs += (size % MAX_MSG_SIZE) ? 1 : 0; @@ -96,11 +104,13 @@ static int tca9539_raw_rd( dev_dbg(dev, "%s\n", __func__); - if (tca9539->reg_len == 2) { - data[0] = (u8)((offset >> 8) & 0xff); - data[1] = (u8)(offset & 0xff); - } else if (tca9539->reg_len == 1) - data[0] = (u8)(offset & 0xff); + if (tca9539->dat_len != 1) + return -EINVAL; + + if (tca9539->reg_len != 1) + return -EINVAL; + + data[0] = (u8)(offset & 0xff); i2cmsg[0].addr = tca9539->addr; i2cmsg[0].len = tca9539->reg_len; diff --git a/drivers/media/platform/tegra/cdi/cdi_mgr.c b/drivers/media/platform/tegra/cdi/cdi_mgr.c index 5252ae78..42b3d53a 100644 --- a/drivers/media/platform/tegra/cdi/cdi_mgr.c +++ b/drivers/media/platform/tegra/cdi/cdi_mgr.c @@ -1,5 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-only -// SPDX-FileCopyrightText: Copyright (C) 2015-2024 NVIDIA CORPORATION. All rights reserved. +/* SPDX-FileCopyrightText: Copyright (c) 2015-2025 NVIDIA CORPORATION & AFFILIATES. + * All rights reserved. + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ #include @@ -1794,10 +1806,13 @@ static int cdi_mgr_probe(struct platform_device *pdev) if (pd->num_pwr_gpios > 0) { for (i = 0; i < pd->num_pwr_gpios; i++) { - if (!gpio_is_valid(pd->pwr_gpios[i])) + if (!gpio_is_valid(pd->pwr_gpios[i])) { + err = -EINVAL; goto err_probe; + } - if (gpio_request(pd->pwr_gpios[i], "pwdn-gpios")) { + err = gpio_request(pd->pwr_gpios[i], "pwdn-gpios"); + if (err) { dev_err(&pdev->dev, "failed to req GPIO: %d\n", pd->pwr_gpios[i]); goto err_probe; @@ -1905,14 +1920,18 @@ static int cdi_mgr_probe(struct platform_device *pdev) if (child_tca9539 != NULL) { err = of_property_read_u32(child_tca9539, "i2c-bus", &cdi_mgr->tca9539.bus); - if (err) - cdi_mgr->tca9539.bus = pd->bus; + if (err) { + dev_err(&pdev->dev, "%s: ERROR %d failed to find IOExpander i2c-bus property\n", + __func__, err); + goto err_probe; + } err = of_property_read_u32(child_tca9539, "addr", &cdi_mgr->tca9539.addr); if (err || !cdi_mgr->tca9539.addr) { dev_err(&pdev->dev, "%s: ERROR %d addr = %d\n", __func__, err, cdi_mgr->tca9539.addr); + err = -EINVAL; goto err_probe; } err = of_property_read_u32(child_tca9539, "reg_len", @@ -1921,6 +1940,7 @@ static int cdi_mgr_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s: ERROR %d reg_len = %d\n", __func__, err, cdi_mgr->tca9539.reg_len); + err = -EINVAL; goto err_probe; } err = of_property_read_u32(child_tca9539, "dat_len", @@ -1929,6 +1949,7 @@ static int cdi_mgr_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s: ERROR %d dat_len = %d\n", __func__, err, cdi_mgr->tca9539.dat_len); + err = -EINVAL; goto err_probe; } err = of_property_read_u32(child_tca9539->parent, @@ -1954,11 +1975,19 @@ static int cdi_mgr_probe(struct platform_device *pdev) cdi_mgr->tca9539.reg_len /= 8; cdi_mgr->tca9539.dat_len /= 8; + if (cdi_mgr->tca9539.reg_len != 1 || cdi_mgr->tca9539.dat_len != 1) { + dev_err(&pdev->dev, "%s invalid reg_len = %d or dat_len = %d\n", + __func__, cdi_mgr->tca9539.reg_len, + cdi_mgr->tca9539.dat_len); + err = -EINVAL; + goto err_probe; + } cdi_mgr->tca9539.enable = 1; cdi_mgr->tca9539.adap = i2c_get_adapter(cdi_mgr->tca9539.bus); if (!cdi_mgr->tca9539.adap) { dev_err(&pdev->dev, "%s no such i2c bus %d\n", __func__, cdi_mgr->tca9539.bus); + err = -EINVAL; goto err_probe; } @@ -1969,27 +1998,31 @@ static int cdi_mgr_probe(struct platform_device *pdev) /* the registers in TCA9539 */ /* Use the IO expander to control PWDN signals */ if (cdi_mgr->cim_ver == 1U) { /* P3714 A01 */ - if (tca9539_wr(cdi_mgr, 0x6, 0x0E) != 0) { + err = tca9539_wr(cdi_mgr, 0x6, 0x0E); + if (err != 0) { dev_err(&pdev->dev, "%s: ERR %d: TCA9539: Failed to select PWDN signal source\n", __func__, err); goto err_probe; } /* Output low for AGGA/B/C/D_PWRDN */ - if (tca9539_wr(cdi_mgr, 0x2, 0x0E) != 0) { + err = tca9539_wr(cdi_mgr, 0x2, 0x0E); + if (err != 0) { dev_err(&pdev->dev, "%s: ERR %d: TCA9539: Failed to set the output level\n", __func__, err); goto err_probe; } } else if (cdi_mgr->cim_ver == 2U) { /* P3714 A02 */ - if (tca9539_wr(cdi_mgr, 0x6, 0xC0) != 0) { + err = tca9539_wr(cdi_mgr, 0x6, 0xC0); + if (err != 0) { dev_err(&pdev->dev, "%s: ERR %d: TCA9539: Failed to select FS selection signal source\n", __func__, err); goto err_probe; } - if (tca9539_wr(cdi_mgr, 0x7, 0x70) != 0) { + err = tca9539_wr(cdi_mgr, 0x7, 0x70); + if (err != 0) { dev_err(&pdev->dev, "%s: ERR %d: TCA9539: Failed to select PWDN signal source\n", __func__, err); @@ -2002,17 +2035,19 @@ static int cdi_mgr_probe(struct platform_device *pdev) cdi_mgr->cim_frsync[0], cdi_mgr->cim_frsync[1], cdi_mgr->cim_frsync[2]); - if (tca9539_wr(cdi_mgr, 0x2, + err = tca9539_wr(cdi_mgr, 0x2, (cdi_mgr->cim_frsync[2] << 4) | (cdi_mgr->cim_frsync[1] << 2) | - (cdi_mgr->cim_frsync[0])) < 0) { + (cdi_mgr->cim_frsync[0])); + if (err < 0) { dev_err(&pdev->dev, "%s: ERR %d: TCA9539: Failed to set FRSYNC control logic\n", __func__, err); goto err_probe; } /* Output low for AGGA/B/C/D_PWRDN */ - if (tca9539_wr(cdi_mgr, 0x3, 0x00) != 0) { + err = tca9539_wr(cdi_mgr, 0x3, 0x00); + if (err != 0) { dev_err(&pdev->dev, "%s: ERR %d: TCA9539: Failed to set the output level\n", __func__, err); diff --git a/drivers/platform/tegra/rtcpu/tegra-camera-rtcpu-base.c b/drivers/platform/tegra/rtcpu/tegra-camera-rtcpu-base.c index 0e403d1b..1addf76d 100644 --- a/drivers/platform/tegra/rtcpu/tegra-camera-rtcpu-base.c +++ b/drivers/platform/tegra/rtcpu/tegra-camera-rtcpu-base.c @@ -1,5 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-only -// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +/* SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. + * All rights reserved. + * + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ #include #include @@ -832,7 +844,9 @@ static int tegra_cam_rtcpu_probe(struct platform_device *pdev) } name = pdata->name; - of_property_read_string(dev->of_node, "nvidia,cpu-name", &name); + ret = of_property_read_string(dev->of_node, "nvidia,cpu-name", &name); + if (ret) + dev_dbg(dev, "no device property, cpu-name, setting to parent name\n"); dev_dbg(dev, "probing RTCPU on %s\n", name); @@ -854,11 +868,15 @@ static int tegra_cam_rtcpu_probe(struct platform_device *pdev) goto fail; rtcpu->max_reboot_retry = 3; - (void)of_property_read_u32(dev->of_node, NV(max-reboot), + ret = of_property_read_u32(dev->of_node, NV(max-reboot), &rtcpu->max_reboot_retry); + if (ret) + dev_dbg(dev, "no device property, max-reboot, setting to default (3)\n"); timeout = 2000; - (void)of_property_read_u32(dev->of_node, "nvidia,cmd-timeout", &timeout); + ret = of_property_read_u32(dev->of_node, "nvidia,cmd-timeout", &timeout); + if (ret) + dev_dbg(dev, "no device property, cmd-timeout, setting to default (2000)\n"); rtcpu->cmd_timeout = msecs_to_jiffies(timeout);