Compare commits

..

6 Commits

Author SHA1 Message Date
Ketan Patil
1f703af3e0 video: tegra: nvmap: Avoid double updation of RSS counter
The RSS counter is updated during buffer allocation as well as mmap,
which is leading to double updation. Fix this by decrementing the RSS
counter during page fault while increment it back during unmap flow.

Bug 5222690

Change-Id: I77972185f20d9d710571cc07ae1c5188060bfa1f
Signed-off-by: Ketan Patil <ketanp@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3442670
(cherry picked from commit 1c59063ce7)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3453103
(cherry picked from commit b27a1a79ee)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3454644
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Tested-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
2025-09-23 10:55:17 -07:00
Ketan Patil
033c964778 video: tegra: nvmap: Remove use of add_mm_counter
add_mm_counter is not an exported function, so instead use
atomic_long_add_return/percpu_counter_add to directly modify RSS stat
counters.

Bug 5222690

Change-Id: I51a68d932aeb04f96e51a4a3c286ee5c8efc789a
Signed-off-by: Ketan Patil <ketanp@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3446982
(cherry picked from commit 8e1a6b2dd1)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3453099
(cherry picked from commit e488812038)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3454643
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Tested-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
2025-09-23 10:55:05 -07:00
Ketan Patil
3b830eb8a7 video: tegra: nvmap: Account NvMap memory for OOM Decisions
Account NvMap allocated memory into both RSS and CG tracking to make
efficient OOM kill decisions during memory pressure.

NvMap allocates memory via kernel APIs like alloc_pages, the kernel
memory is not accounted on behalf of process who requests the
allocation. Hence in case OOM, the OOM killer never kills the process
who has allocated memory via NvMap even though this process might be
holding most of the memory.

Solve this issue using following approach:
- Use __GFP_ACCOUNT and __GFP_NORETRY flag
-  __GFP_NORETRY will not let the current allocation flow to go into OOM
path, so that it will never trigger OOM.
- __GFP_ACCOUNT causes the allocation to be accounted to kmemcg. So any
allocation done by NvMap will be definitely accounted to kmemcg and
cgroups can be used to define memory limits.
- Add RSS counting for the process which allocates by NvMap, so that OOM
score for that process will get updated and OOM killer can pick this
process based upon the OOM score.
- Every process that has a reference to NvMap Handle would have the
memory size accounted into its RSS. On releasing the reference to
handle, the RSS would be reduced.

Bug 5222690

Change-Id: I3fa9b76ec9fc8d7f805111cb96e11e2ab1db42ce
Signed-off-by: Ketan Patil <ketanp@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3427871
(cherry picked from commit 2ca91098aa)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3453101
(cherry picked from commit cfe6242c8c)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3454642
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
Tested-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
2025-09-23 10:54:56 -07:00
Revanth Kumar Uppala
3ebca7545e rtl8822ce: Remove pr_debug redefinition
Issue: pr_debug is redfined to printk causing unwanted
       log prints in dmesg

Fix: Remove pr_debug redefintion in rtl8822ce driver

Bug 3844473

Change-Id: I4177f8c3fa245a881cd35c206f8d3caa4b811b32
Signed-off-by: Revanth Kumar Uppala <ruppala@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3121450
(cherry picked from commit 564ce2a709)
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
Reviewed-by: Brad Griffis <bgriffis@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3140027
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
2024-05-18 14:55:37 -07:00
Shobek Attupurath
c79de35fb0 rtl8822ce: Add Nvidia changes on v5.14.0.4-217
1. Add custom roam parameters
2. Add path for power file
3. Add source tree path for Makefile
4. Add section in Makefile for TEGRA platform
5. Update permissions from 0755 to 0644 for files
6. Move roaming debug prints to RTW_INFO

Bug 4320751
Bug 4556940
Bug 4568390

Change-Id: I842f150781652b3b54949aef8f982903c8d7991e
Signed-off-by: Revanth Kumar Uppala <ruppala@nvidia.com>
Signed-off-by: Shobek Attupurath <sattupurath@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3108666
(cherry picked from commit 4e544f3b3a)
Reviewed-by: Brad Griffis <bgriffis@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3140025
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
2024-05-18 14:55:29 -07:00
Revanth Kumar Uppala
c5d97870d1 rtl8822ce: Fix TLP/EAPOL/TXFIFO issues
Issue: Observing the EAPOL packet after a second in 1/10 roams

       Observing TLP Malform packets on SC7

       Observing TXFIFO error when connected to serving AP

       Compilation errors for K6.x

Fix:   Add exact base driver released by realtek with EAPOL/TLP/TXFIFO
       fixes and also resolve some compilation errors.

DRIVERVERSION   v5.14.0.4-217-g7a0377e61.20240410_COEX20240327-2727_beta
BTCOEXVERSION   COEX20240327-2727

Bug 4320751
Bug 4556940
Bug 4568390

Change-Id: Ib02056ea388300dab2364b2bd6ceaf0a2096d3f4
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3115032
(cherry picked from commit ed30eb40ff)
Reviewed-by: Revanth Kumar Uppala <ruppala@nvidia.com>
Reviewed-by: Brad Griffis <bgriffis@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3139878
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Tested-by: Revanth Kumar Uppala <ruppala@nvidia.com>
2024-05-18 14:54:38 -07:00
1397 changed files with 14621 additions and 1249275 deletions

25
.gitignore vendored
View File

@@ -1,25 +0,0 @@
# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: GPL-2.0
#
# Use command 'git ls-files -i --exclude-standard' to ensure that no
# tracked files are ignored.
#
*.o
*.o.*
*.a
*.s
*.ko
*.so
*.so.dbg
*.mod.c
*.i
*.symtypes
*.order
*.patch
modules.builtin
Module.symvers
*.dwo
*.mod
*.cmd
*mods.dtb*

View File

@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
LINUXINCLUDE += -I$(srctree.nvidia-oot)/include
LINUXINCLUDE += -I$(srctree.nvidia-oot)/drivers/gpu/host1x/hw/
@@ -12,10 +12,8 @@ ifdef CONFIG_PSTORE
obj-m += block/tegra_oops_virt_storage/
endif
ifdef CONFIG_BT
ifneq ($(NV_OOT_BLUETOOTH_REALTEK_SKIP_BUILD),y)
obj-m += bluetooth/realtek/
endif
endif
obj-m += c2c/
obj-m += clink/
obj-m += cpuidle/

View File

@@ -1,10 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2023-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <nvidia/conftest.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -804,21 +802,9 @@ static const struct of_device_id tegra_hv_vblk_oops_match[] = {
MODULE_DEVICE_TABLE(of, tegra_hv_vblk_oops_match);
#endif /* CONFIG_OF */
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_hv_vblk_oops_remove_wrapper(struct platform_device *pdev)
{
tegra_hv_vblk_oops_remove(pdev);
}
#else
static int tegra_hv_vblk_oops_remove_wrapper(struct platform_device *pdev)
{
return tegra_hv_vblk_oops_remove(pdev);
}
#endif
static struct platform_driver tegra_hv_vblk_oops_driver = {
.probe = tegra_hv_vblk_oops_probe,
.remove = tegra_hv_vblk_oops_remove_wrapper,
.remove = tegra_hv_vblk_oops_remove,
.driver = {
.name = OOPS_DRV_NAME,
.owner = THIS_MODULE,

View File

@@ -1,21 +1,13 @@
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Makefile for Virtual Storage Driver
#
LINUX_VERSION := $(shell expr $(VERSION) \* 256 + $(PATCHLEVEL))
LINUX_VERSION_6_11 := $(shell expr 6 \* 256 + 11)
ifneq ($(NV_OOT_BLOCK_TEGRA_VIRT_STORAGE_SKIP_BUILD),y)
# Use dummy driver for Kernel versions greater than or equal to Linux v6.11
ifeq ($(shell test $(LINUX_VERSION) -lt $(LINUX_VERSION_6_11); echo $$?),0)
tegra_vblk-y += tegra_hv_vblk.o
tegra_vblk-y += tegra_hv_ioctl.o
tegra_vblk-y += tegra_hv_mmc.o
tegra_vblk-y += tegra_hv_scsi.o
tegra_vblk-y += tegra_hv_ufs.o
obj-m += tegra_vblk.o
endif
endif

View File

@@ -1,8 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <linux/kernel.h> /* printk() */
#include <linux/vmalloc.h> /* kmalloc() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/fcntl.h> /* O_ACCMODE */

View File

@@ -1,7 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <linux/vmalloc.h> /* kmalloc() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/errno.h> /* error codes */
#include <linux/delay.h> /* For msleep and usleep_range */
#include <uapi/scsi/ufs/ioctl.h>

View File

@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <nvidia/conftest.h>
@@ -145,11 +147,7 @@ static void vblk_put_req(struct vsc_request *req)
(vblkdev->queue_state == VBLK_QUEUE_SUSPENDED)) {
complete(&vblkdev->req_queue_empty);
}
#if defined(NV_TIMER_DELETE_PRESENT) /* Linux v6.15 */
timer_delete(&req->timer);
#else
del_timer(&req->timer);
#endif
}
}
@@ -538,12 +536,8 @@ static bool submit_bio_req(struct vblk_dev *vblkdev)
}
sg_init_table(vsc_req->sg_lst,
bio_req->nr_phys_segments);
#if defined(NV_BLK_RQ_MAP_SG_HAS_NO_QUEUE_ARG) /* Linux v6.15 */
sg_cnt = blk_rq_map_sg(bio_req, vsc_req->sg_lst);
#else
sg_cnt = blk_rq_map_sg(vblkdev->queue, bio_req,
vsc_req->sg_lst);
#endif
vsc_req->sg_num_ents = sg_nents(vsc_req->sg_lst);
if (dma_map_sg(vblkdev->device, vsc_req->sg_lst,
vsc_req->sg_num_ents, DMA_BIDIRECTIONAL) == 0) {
@@ -1003,11 +997,7 @@ static void setup_device(struct vblk_dev *vblkdev)
if (ret)
return;
#if defined(NV_BLK_MQ_ALLOC_QUEUE_PRESENT)
vblkdev->queue = blk_mq_alloc_queue(&vblkdev->tag_set, NULL, NULL);
#else
vblkdev->queue = blk_mq_init_queue(&vblkdev->tag_set);
#endif
if (IS_ERR(vblkdev->queue)) {
dev_err(vblkdev->device, "failed to init blk queue\n");
blk_mq_free_tag_set(&vblkdev->tag_set);
@@ -1172,9 +1162,7 @@ static void setup_device(struct vblk_dev *vblkdev)
vblkdev->max_requests = max_requests;
vblkdev->max_ioctl_requests = max_ioctl_requests;
#if defined(NV_BLK_QUEUE_MAX_HW_SECTORS_PRESENT) /* Removed in Linux v6.10 */
blk_queue_max_hw_sectors(vblkdev->queue, max_io_bytes / SECTOR_SIZE);
#endif
blk_queue_flag_set(QUEUE_FLAG_NONROT, vblkdev->queue);
if ((vblkdev->config.blk_config.req_ops_supported & VS_BLK_SECURE_ERASE_OP_F)
@@ -1571,21 +1559,9 @@ static struct of_device_id tegra_hv_vblk_match[] = {
MODULE_DEVICE_TABLE(of, tegra_hv_vblk_match);
#endif /* CONFIG_OF */
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_hv_vblk_remove_wrapper(struct platform_device *pdev)
{
tegra_hv_vblk_remove(pdev);
}
#else
static int tegra_hv_vblk_remove_wrapper(struct platform_device *pdev)
{
return tegra_hv_vblk_remove(pdev);
}
#endif
static struct platform_driver tegra_hv_vblk_driver = {
.probe = tegra_hv_vblk_probe,
.remove = tegra_hv_vblk_remove_wrapper,
.remove = tegra_hv_vblk_remove,
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,

View File

@@ -1,15 +1,22 @@
ifneq ($(KERNELRELEASE),)
obj-m := rtk_btusb.o
rtk_btusb-y = rtk_coex.o rtk_misc.o rtk_bt.o
else
PWD := $(shell pwd)
KVER := $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
clean:
rm -rf *.o *.mod.c *.mod.o *.ko *.symvers *.order *.a
endif
# SPDX-License-Identifier: GPL-2.0
CONFIG_BTUSB_AUTOSUSPEND = n
CONFIG_BTUSB_WAKEUP_HOST = n
CONFIG_BTCOEX = y
ifeq ($(CONFIG_BTUSB_AUTOSUSPEND), y)
EXTRA_CFLAGS += -DCONFIG_BTUSB_AUTOSUSPEND
endif
ifeq ($(CONFIG_BTUSB_WAKEUP_HOST), y)
EXTRA_CFLAGS += -DCONFIG_BTUSB_WAKEUP_HOST
endif
ifeq ($(CONFIG_BTCOEX), y)
EXTRA_CFLAGS += -DCONFIG_BTCOEX
endif
obj-m := rtk_btusb.o
rtk_btusb-objs := rtk_coex.o \
rtk_misc.o \
rtk_bt.o

View File

@@ -1,22 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
*
* Realtek Bluetooth USB driver
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/kernel.h>
@@ -31,11 +17,12 @@
#include <linux/dcache.h>
#include <linux/reboot.h>
#include <net/sock.h>
#include <asm/unaligned.h>
#include "rtk_bt.h"
#include "rtk_misc.h"
#define VERSION "3.1.65ab490.20240531-141726"
#define VERSION "3.1.6fd4e69.20220818-105856"
#ifdef BTCOEX
#include "rtk_coex.h"
@@ -48,64 +35,95 @@ static DEFINE_SEMAPHORE(switch_sem);
#endif
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 7, 1)
static bool reset = true;
static bool reset = 0;
#endif
static struct usb_driver btusb_driver;
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
static u16 iso_min_conn_handle = 0x1b;
#endif
static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
/* Generic Bluetooth USB interface */
{ USB_INTERFACE_INFO(0xe0, 0x01, 0x01) },
{}
};
static const struct usb_device_id blacklist_table[] = {
static struct usb_device_id btusb_table[] = {
{
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x0bda,
.bInterfaceClass = 0xe0,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01
}, {
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x13d3,
.bInterfaceClass = 0xe0,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01
}, {
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x0489,
.bInterfaceClass = 0xe0,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01
}, {
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x1358,
.bInterfaceClass = 0xe0,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01
}, {
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x04ca,
.bInterfaceClass = 0xe0,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01
}, {
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x2ff8,
.bInterfaceClass = 0xe0,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01
}, {
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x0b05,
.bInterfaceClass = 0xe0,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01
}, {
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x0930,
.bInterfaceClass = 0xe0,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01
}, {
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x10ec,
.bInterfaceClass = 0xe0,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01
}, {
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x04c5,
.bInterfaceClass = 0xe0,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01
}, {
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x0cb5,
.bInterfaceClass = 0xe0,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01
}, {
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x0cb8,
}, {
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
.idVendor = 0x04b8,
.bInterfaceClass = 0xe0,
.bInterfaceSubClass = 0x01,
.bInterfaceProtocol = 0x01
}, { }
};
@@ -130,6 +148,20 @@ static struct btusb_data *rtk_alloc(struct usb_interface *intf)
MODULE_DEVICE_TABLE(usb, btusb_table);
static int inc_tx(struct btusb_data *data)
{
unsigned long flags;
int rv;
spin_lock_irqsave(&data->txlock, flags);
rv = test_bit(BTUSB_SUSPENDING, &data->flags);
if (!rv)
data->tx_in_flight++;
spin_unlock_irqrestore(&data->txlock, flags);
return rv;
}
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
static inline void btusb_free_frags(struct btusb_data *data)
{
@@ -172,11 +204,7 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
}
len = min_t(uint, bt_cb(skb)->expect, count);
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
skb_put_data(skb, buffer, len);
#else
memcpy(skb_put(skb, len), buffer, len);
#endif
count -= len;
buffer += len;
@@ -231,26 +259,15 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
}
len = min_t(uint, bt_cb(skb)->expect, count);
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
skb_put_data(skb, buffer, len);
#else
memcpy(skb_put(skb, len), buffer, len);
#endif
count -= len;
buffer += len;
bt_cb(skb)->expect -= len;
if (skb->len == HCI_ACL_HDR_SIZE) {
struct hci_acl_hdr *h = hci_acl_hdr(skb);
__le16 dlen = h->dlen;
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
__u16 handle = __le16_to_cpu(h->handle) & 0xfff;
__le16 dlen = hci_acl_hdr(skb)->dlen;
if(handle >= iso_min_conn_handle) {
bt_cb(skb)->pkt_type = HCI_ISODATA_PKT;
}
#endif
/* Complete ACL header */
bt_cb(skb)->expect = __le16_to_cpu(dlen);
@@ -276,42 +293,10 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
return err;
}
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
static int btrtl_usb_recv_isoc(u16 pos, u8 *data, u8 *p, int len,
u16 wMaxPacketSize)
{
u8 *prev;
if (pos >= HCI_SCO_HDR_SIZE && pos >= wMaxPacketSize &&
len == wMaxPacketSize && !(pos % wMaxPacketSize) &&
wMaxPacketSize >= 10 && p[0] == data[0] && p[1] == data[1]) {
prev = data + (pos - wMaxPacketSize);
/* Detect the sco data of usb isoc pkt duplication. */
if (!memcmp(p + 2, prev + 2, 8))
return -EILSEQ;
if (wMaxPacketSize >= 12 &&
p[2] == prev[6] && p[3] == prev[7] &&
p[4] == prev[4] && p[5] == prev[5] &&
p[6] == prev[10] && p[7] == prev[11] &&
p[8] == prev[8] && p[9] == prev[9]) {
return -EILSEQ;
}
}
return 0;
}
#endif
static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
{
struct sk_buff *skb;
int err = 0;
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
u16 wMaxPacketSize = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize);
#endif
spin_lock(&data->rxlock);
skb = data->sco_skb;
@@ -331,24 +316,7 @@ static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
}
len = min_t(uint, bt_cb(skb)->expect, count);
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
/* Gaps in audio could be heard while streaming WBS using USB
* alt settings 3 on some platforms.
* Add the function to detect it.
*/
if (test_bit(BTUSB_USE_ALT3_FOR_WBS, &data->flags)) {
err = btrtl_usb_recv_isoc(skb->len, skb->data, buffer,
len, wMaxPacketSize);
if (err)
break;
}
#endif
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
skb_put_data(skb, buffer, len);
#else
memcpy(skb_put(skb, len), buffer, len);
#endif
count -= len;
buffer += len;
@@ -379,21 +347,6 @@ static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
return err;
}
#else
static int inc_tx(struct btusb_data *data)
{
unsigned long flags;
int rv;
spin_lock_irqsave(&data->txlock, flags);
rv = test_bit(BTUSB_SUSPENDING, &data->flags);
if (!rv)
data->tx_in_flight++;
spin_unlock_irqrestore(&data->txlock, flags);
return rv;
}
#endif
static void btusb_intr_complete(struct urb *urb)
@@ -673,51 +626,6 @@ retry:
}
}
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
static inline void __fill_isoc_descriptor_msbc(struct urb *urb, int len,
int mtu, struct btusb_data *data)
{
int i = 0, offset = 0;
unsigned int interval;
BT_DBG("len %d mtu %d", len, mtu);
/* For mSBC ALT 6 settings some Realtek chips need to transmit the data
* continuously without the zero length of USB packets.
*/
if (btrealtek_test_flag(data->hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP))
goto ignore_usb_alt6_packet_flow;
/* For mSBC ALT 6 setting the host will send the packet at continuous
* flow. As per core spec 5, vol 4, part B, table 2.1. For ALT setting
* 6 the HCI PACKET INTERVAL should be 7.5ms for every usb packets.
* To maintain the rate we send 63bytes of usb packets alternatively for
* 7ms and 8ms to maintain the rate as 7.5ms.
*/
if (data->usb_alt6_packet_flow) {
interval = 7;
data->usb_alt6_packet_flow = false;
} else {
interval = 6;
data->usb_alt6_packet_flow = true;
}
for (i = 0; i < interval; i++) {
urb->iso_frame_desc[i].offset = offset;
urb->iso_frame_desc[i].length = offset;
}
ignore_usb_alt6_packet_flow:
if (len && i < BTUSB_MAX_ISOC_FRAMES) {
urb->iso_frame_desc[i].offset = offset;
urb->iso_frame_desc[i].length = len;
i++;
}
urb->number_of_packets = i;
}
#endif
static inline void __fill_isoc_descriptor(struct urb *urb, int len, int mtu)
{
int i, offset = 0;
@@ -767,12 +675,6 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress);
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 2, 14)
usb_fill_int_urb(urb, data->udev, pipe, buf, size, btusb_isoc_complete,
hdev, data->isoc_rx_ep->bInterval);
urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP;
#else
urb->dev = data->udev;
urb->pipe = pipe;
urb->context = hdev;
@@ -782,7 +684,6 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP;
urb->transfer_buffer = buf;
urb->transfer_buffer_length = size;
#endif
__fill_isoc_descriptor(urb, size,
le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize));
@@ -833,8 +734,8 @@ static void btusb_isoc_tx_complete(struct urb *urb)
struct sk_buff *skb = urb->context;
struct hci_dev *hdev = (struct hci_dev *)skb->dev;
RTKBT_DBG("%s: urb %p status %d count %d", __func__,
urb, urb->status, urb->actual_length);
RTKBT_DBG("%s: urb %p status %d count %d",__func__,
urb, urb->status, urb->actual_length);
if (!test_bit(HCI_RUNNING, &hdev->flags))
goto done;
@@ -850,49 +751,6 @@ done:
kfree_skb(skb);
}
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
static int rtl_read_iso_handle_range(struct hci_dev *hdev)
{
struct sk_buff *skb;
struct __rp {
u8 status;
u8 min_handle[2];
} *rp;
int ret = -EIO;
skb = __hci_cmd_sync(hdev, 0xfdab, 0, NULL, HCI_CMD_TIMEOUT);
if (IS_ERR(skb)) {
return PTR_ERR(skb);
}
/* FIXME: if the return status is not zero, __hci_cmd_sync() would
* return an error and we would not reach here.
*/
if (skb->data[0]) {
RTKBT_ERR("%s: Read failed, status %0x", hdev->name,
skb->data[0]);
goto err;
}
if (skb->len < sizeof(*rp)) {
RTKBT_WARN("%s: The len %u of rp is too short", __func__,
skb->len);
goto err;
}
rp = (void *)skb->data;
iso_min_conn_handle = (u16)rp->min_handle[1] << 8 | rp->min_handle[0];
RTKBT_DBG("ISO handle range (handle >= %04x)", iso_min_conn_handle);
kfree_skb(skb);
return 0;
err:
kfree_skb(skb);
return ret;
}
#endif
static int btusb_open(struct hci_dev *hdev)
{
struct btusb_data *data = GET_DRV_DATA(hdev);
@@ -917,10 +775,6 @@ static int btusb_open(struct hci_dev *hdev)
goto failed;
/*******************************/
err = setup_btrealtek_flag(data->intf, hdev);
if (err < 0)
RTKBT_WARN("setup_btrealtek_flag incorrect!");
RTKBT_INFO("%s set HCI UP RUNNING", __func__);
if (test_and_set_bit(HCI_UP, &hdev->flags))
goto done;
@@ -963,32 +817,6 @@ failed:
return err;
}
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
static int btusb_setup(struct hci_dev *hdev)
{
rtl_read_iso_handle_range(hdev);
return 0;
}
#endif
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
static int btusb_shutdown(struct hci_dev *hdev)
{
struct sk_buff *skb;
int ret;
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
ret = PTR_ERR(skb);
bt_dev_err(hdev, "HCI reset during shutdown failed");
return ret;
}
kfree_skb(skb);
return 0;
}
#endif
static void btusb_stop_traffic(struct btusb_data *data)
{
mdelay(URB_CANCELING_DELAY_MS); // Added by Realtek
@@ -1092,152 +920,8 @@ static const char pkt_ind[][8] = {
[HCI_COMMAND_PKT] = "cmd",
[HCI_ACLDATA_PKT] = "acl",
[HCI_SCODATA_PKT] = "sco",
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
[HCI_ISODATA_PKT] = "iso",
#endif
};
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
static struct urb *alloc_ctrl_urb(struct hci_dev *hdev, struct sk_buff *skb)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct usb_ctrlrequest *dr;
struct urb *urb;
unsigned int pipe;
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return ERR_PTR(-ENOMEM);
dr = kmalloc(sizeof(*dr), GFP_KERNEL);
if (!dr) {
usb_free_urb(urb);
return ERR_PTR(-ENOMEM);
}
dr->bRequestType = data->cmdreq_type;
dr->bRequest = 0;
dr->wIndex = 0;
dr->wValue = 0;
dr->wLength = __cpu_to_le16(skb->len);
pipe = usb_sndctrlpipe(data->udev, 0x00);
usb_fill_control_urb(urb, data->udev, pipe, (void *)dr,
skb->data, skb->len, btusb_tx_complete, skb);
skb->dev = (void *)hdev;
return urb;
}
static struct urb *alloc_bulk_urb(struct hci_dev *hdev, struct sk_buff *skb)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct urb *urb;
unsigned int pipe;
if (!data->bulk_tx_ep)
return ERR_PTR(-ENODEV);
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return ERR_PTR(-ENOMEM);
pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress);
usb_fill_bulk_urb(urb, data->udev, pipe,
skb->data, skb->len, btusb_tx_complete, skb);
skb->dev = (void *)hdev;
return urb;
}
static struct urb *alloc_isoc_urb(struct hci_dev *hdev, struct sk_buff *skb)
{
struct btusb_data *data = hci_get_drvdata(hdev);
struct urb *urb;
unsigned int pipe;
if (!data->isoc_tx_ep)
return ERR_PTR(-ENODEV);
urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL);
if (!urb)
return ERR_PTR(-ENOMEM);
pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress);
usb_fill_int_urb(urb, data->udev, pipe,
skb->data, skb->len, btusb_isoc_tx_complete,
skb, data->isoc_tx_ep->bInterval);
urb->transfer_flags = URB_ISO_ASAP;
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
if (data->isoc_altsetting == 6)
__fill_isoc_descriptor_msbc(urb, skb->len,
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize),
data);
else
__fill_isoc_descriptor(urb, skb->len,
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
#else
__fill_isoc_descriptor(urb, skb->len,
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
#endif
skb->dev = (void *)hdev;
return urb;
}
static int submit_tx_urb(struct hci_dev *hdev, struct urb *urb)
{
struct btusb_data *data = hci_get_drvdata(hdev);
int err;
usb_anchor_urb(urb, &data->tx_anchor);
err = usb_submit_urb(urb, GFP_KERNEL);
if (err < 0) {
if (err != -EPERM && err != -ENODEV)
RTKBT_ERR("%s urb %p submission failed (%d)",
hdev->name, urb, -err);
kfree(urb->setup_packet);
usb_unanchor_urb(urb);
} else {
usb_mark_last_busy(data->udev);
}
usb_free_urb(urb);
return err;
}
static int submit_or_queue_tx_urb(struct hci_dev *hdev, struct urb *urb)
{
struct btusb_data *data = hci_get_drvdata(hdev);
unsigned long flags;
bool suspending;
spin_lock_irqsave(&data->txlock, flags);
suspending = test_bit(BTUSB_SUSPENDING, &data->flags);
if (!suspending)
data->tx_in_flight++;
spin_unlock_irqrestore(&data->txlock, flags);
if (!suspending)
return submit_tx_urb(hdev, urb);
usb_anchor_urb(urb, &data->deferred);
schedule_work(&data->waker);
usb_free_urb(urb);
return 0;
}
#endif
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
@@ -1247,20 +931,14 @@ int btusb_send_frame(struct sk_buff *skb)
struct hci_dev *hdev = (struct hci_dev *)skb->dev;
#endif
struct urb *urb;
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
struct btusb_data *data = GET_DRV_DATA(hdev);
struct usb_ctrlrequest *dr;
struct urb *urb;
unsigned int pipe;
int err;
#endif
// RTKBT_DBG("%s", hdev->name);
//RTKBT_DBG("%s", hdev->name);
/* After Kernel version 4.4.0, move the check into the
* hci_send_frame function before calling hdev->send
*/
#if HCI_VERSION_CODE < KERNEL_VERSION(4, 4, 0)
if (!test_bit(HCI_RUNNING, &hdev->flags)) {
/* If the parameter is wrong, the hdev isn't the correct
* one. Then no HCI commands can be sent.
@@ -1268,15 +946,13 @@ int btusb_send_frame(struct sk_buff *skb)
RTKBT_ERR("HCI is not running");
return -EBUSY;
}
#endif
/* Before kernel/hci version 3.13.0, the skb->dev is set before
* entering btusb_send_frame(). So there is no need to set it here.
*
* The skb->dev will be used in the callbacks when urb transfer
* completes. See btusb_tx_complete() and btusb_isoc_tx_complete() */
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) && \
HCI_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
skb->dev = (void *)hdev;
#endif
@@ -1287,14 +963,6 @@ int btusb_send_frame(struct sk_buff *skb)
#ifdef BTCOEX
rtk_btcoex_parse_cmd(skb->data, skb->len);
#endif
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
urb = alloc_ctrl_urb(hdev, skb);
if (IS_ERR(urb))
return PTR_ERR(urb);
hdev->stat.cmd_tx++;
return submit_or_queue_tx_urb(hdev, urb);
#else
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb)
return -ENOMEM;
@@ -1320,24 +988,11 @@ int btusb_send_frame(struct sk_buff *skb)
hdev->stat.cmd_tx++;
break;
#endif
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
case HCI_ISODATA_PKT:
#endif
case HCI_ACLDATA_PKT:
print_acl(skb, 1);
#ifdef BTCOEX
if(bt_cb(skb)->pkt_type == HCI_ACLDATA_PKT)
rtk_btcoex_parse_l2cap_data_tx(skb->data, skb->len);
rtk_btcoex_parse_l2cap_data_tx(skb->data, skb->len);
#endif
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
urb = alloc_bulk_urb(hdev, skb);
if (IS_ERR(urb))
return PTR_ERR(urb);
hdev->stat.acl_tx++;
return submit_or_queue_tx_urb(hdev, urb);
#else
if (!data->bulk_tx_ep)
return -ENODEV;
@@ -1354,22 +1009,7 @@ int btusb_send_frame(struct sk_buff *skb)
hdev->stat.acl_tx++;
break;
#endif
case HCI_SCODATA_PKT:
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
if (hci_conn_num(hdev, SCO_LINK) < 1)
return -ENODEV;
urb = alloc_isoc_urb(hdev, skb);
if (IS_ERR(urb))
return PTR_ERR(urb);
hdev->stat.sco_tx++;
return submit_tx_urb(hdev, urb);
}
return -EILSEQ;
#else
if (!data->isoc_tx_ep || SCO_NUM < 1)
return -ENODEV;
@@ -1395,7 +1035,6 @@ int btusb_send_frame(struct sk_buff *skb)
default:
return -EILSEQ;
}
err = inc_tx(data);
@@ -1418,14 +1057,12 @@ skip_waking:
} else {
usb_mark_last_busy(data->udev);
}
usb_free_urb(urb);
done:
usb_free_urb(urb);
return err;
#endif
}
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
static void btusb_destruct(struct hci_dev *hdev)
{
@@ -1544,9 +1181,6 @@ static struct usb_host_interface *btusb_find_altsetting(struct btusb_data *data,
BT_DBG("Looking for Alt no :%d", alt);
if (!intf)
return NULL;
for (i = 0; i < intf->num_altsetting; i++) {
if (intf->altsetting[i].desc.bAlternateSetting == alt)
return &intf->altsetting[i];
@@ -1587,14 +1221,7 @@ static void btusb_work(struct work_struct *work)
new_alts = data->sco_num;
}
} else if (data->air_mode == HCI_NOTIFY_ENABLE_SCO_TRANSP) {
if (btusb_find_altsetting(data, 6))
new_alts = 6;
else if (btusb_find_altsetting(data, 3) &&
hdev->sco_mtu >= 72 &&
test_bit(BTUSB_USE_ALT3_FOR_WBS, &data->flags))
new_alts = 3;
else
new_alts = 1;
new_alts = btusb_find_altsetting(data, 6) ? 6 : 1;
}
if (btusb_switch_alt_setting(hdev, new_alts) < 0)
@@ -1794,7 +1421,7 @@ static int rtkbt_pm_notify(struct notifier_block *notifier,
result = __rtk_send_hci_cmd(udev, cmd, 3);
kfree(cmd);
msleep(100); /* From FW colleague's recommendation */
result = download_special_patch(intf, "lps_");
result = download_lps_patch(intf);
#endif
#ifdef RTKBT_TV_POWERON_WHITELIST
@@ -1913,23 +1540,13 @@ static int btusb_probe(struct usb_interface *intf,
struct usb_device *udev;
udev = interface_to_usbdev(intf);
RTKBT_INFO("btusb_probe intf->cur_altsetting->desc.bInterfaceNumber %d",
RTKBT_DBG("btusb_probe intf->cur_altsetting->desc.bInterfaceNumber %d",
intf->cur_altsetting->desc.bInterfaceNumber);
/* interface numbers are hardcoded in the spec */
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
return -ENODEV;
if (!id->driver_info) {
const struct usb_device_id *match;
match = usb_match_id(intf, blacklist_table);
if (match)
id = match;
else
return -ENODEV;
}
/*******************************/
flag1 = device_can_wakeup(&udev->dev);
flag2 = device_may_wakeup(&udev->dev);
@@ -2019,13 +1636,6 @@ static int btusb_probe(struct usb_interface *intf,
hdev->flush = btusb_flush;
hdev->send = btusb_send_frame;
hdev->notify = btusb_notify;
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
hdev->setup = btusb_setup;
#endif
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
hdev->shutdown = btusb_shutdown;
#endif
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
hci_set_drvdata(hdev, data);
@@ -2035,14 +1645,10 @@ static int btusb_probe(struct usb_interface *intf,
hdev->owner = THIS_MODULE;
#endif
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
set_bit(BTUSB_USE_ALT3_FOR_WBS, &data->flags);
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
#endif
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 7, 1)
if (!reset)
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
RTKBT_DBG("set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);");
#endif
/* Interface numbers are hardcoded in the specification */

View File

@@ -1,23 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
*
* Realtek Bluetooth USB driver
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __RTK_BT_H__
#define __RTK_BT_H__
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -41,17 +30,14 @@
/* #define HCI_VERSION_CODE KERNEL_VERSION(3, 14, 41) */
#define HCI_VERSION_CODE LINUX_VERSION_CODE
#define CONFIG_BTCOEX 1
#define CONFIG_BTUSB_WAKEUP_HOST 0
#if CONFIG_BTCOEX
#ifdef CONFIG_BTCOEX
#define BTCOEX
#endif
/***********************************
** Realtek - For rtk_btusb driver **
***********************************/
#if CONFIG_BTUSB_WAKEUP_HOST
#ifdef CONFIG_BTUSB_WAKEUP_HOST
#define BTUSB_WAKEUP_HOST
#endif
@@ -98,7 +84,6 @@ int btusb_send_frame(struct sk_buff *skb);
#define BTUSB_ISOC_RUNNING 2
#define BTUSB_SUSPENDING 3
#define BTUSB_DID_ISO_RESUME 4
#define BTUSB_USE_ALT3_FOR_WBS 15
struct btusb_data {
struct hci_dev *hdev;
@@ -140,7 +125,6 @@ struct btusb_data {
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
unsigned int air_mode;
bool usb_alt6_packet_flow;
#endif
int isoc_altsetting;
int suspend_count;
@@ -152,3 +136,6 @@ struct btusb_data {
struct notifier_block shutdown_notifier;
void *context;
};
#endif /* __RTK_BT_H__ */

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,23 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
*
* Realtek Bluetooth USB driver
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __RTK_COEX_H__
#define __RTK_COEX_H__
#include <net/bluetooth/hci_core.h>
#include <linux/list.h>
@@ -49,13 +38,6 @@
#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03
#define HCI_EV_LE_ENHANCED_CONN_COMPLETE 0x0a
#define HCI_EV_LE_CIS_EST 0x19
#define HCI_EV_LE_CREATE_BIG_CPL 0x1b
#define HCI_EV_LE_TERM_BIG_CPL 0x1c
#define HCI_EV_LE_BIG_SYNC_EST 0x1d
#define HCI_EV_LE_BIG_SYNC_LOST 0x1e
#define HCI_EV_LE_REMOVE_ISO_DATA_PATH 0x23
//vendor cmd to fw
#define HCI_VENDOR_ENABLE_PROFILE_REPORT_COMMAND 0xfc18
#define HCI_VENDOR_SET_PROFILE_REPORT_LEGACY_COMMAND 0xfc19
@@ -158,11 +140,7 @@ enum {
profile_hogp = 5,
profile_voice = 6,
profile_sink = 7,
profile_lea_src = 8,
profile_opprx = 9,
profile_lea_snk = 10,
profile_a2dpsink = 11,
profile_max = 12
profile_max = 8
};
#define A2DP_SIGNAL 0x01
@@ -181,10 +159,7 @@ typedef struct {
//profile info for each connection
typedef struct rtl_hci_conn {
struct list_head list;
u16 big_handle;
u16 handle;
u8 direction;
u8 remove_path;
uint16_t handle;
struct delayed_work a2dp_count_work;
struct delayed_work pan_count_work;
struct delayed_work hogp_count_work;
@@ -195,7 +170,7 @@ typedef struct rtl_hci_conn {
uint8_t type; // 0:l2cap, 1:sco/esco, 2:le
uint16_t profile_bitmap;
uint16_t profile_status;
int8_t profile_refcount[profile_max];
int8_t profile_refcount[8];
} rtk_conn_prof, *prtk_conn_prof;
#ifdef RTB_SOFTWARE_MAILBOX
@@ -229,40 +204,21 @@ struct rtl_btinfo_ctl {
};
#endif /* RTB_SOFTWARE_MAILBOX */
#define HCI_PT_CMD 0x01
#define HCI_PT_EVT 0x02
#define HCI_PT_L2SIG_RX 0x03
#define HCI_PT_L2SIG_TX 0x04
#define HCI_PT_L2DATA_RX 0x05
#define HCI_PT_L2DATA_TX 0x06
struct rtl_hci_hdr {
struct list_head list;
u8 type;
u16 len;
};
#define MAX_LEN_OF_HCI_EV 32
#define NUM_RTL_HCI_EV 32
struct rtl_hci_ev {
struct list_head list;
u8 type;
u16 len;
/* private */
__u8 data[MAX_LEN_OF_HCI_EV];
__u16 len;
struct list_head list;
};
#define L2_MAX_SUBSEC_LEN 128
#define L2_MAX_PKTS 16
struct rtl_l2_buff {
struct list_head list;
u8 type;
u16 len;
/* private */
__u8 data[L2_MAX_SUBSEC_LEN];
__u16 len;
__u16 out;
struct list_head list;
};
struct rtl_coex_struct {
@@ -280,18 +236,18 @@ struct rtl_coex_struct {
struct delayed_work sock_work;
#endif
struct workqueue_struct *fw_wq;
struct workqueue_struct *timer_wq;
struct delayed_work fw_work;
struct delayed_work cmd_work;
struct delayed_work l2_work;
#ifdef RTB_SOFTWARE_MAILBOX
struct sock *sk;
#endif
struct urb *urb;
spinlock_t spin_lock_sock;
struct mutex profile_mutex;
struct mutex conn_mutex;
spinlock_t spin_lock_profile;
uint16_t profile_bitmap;
uint16_t profile_status;
int8_t profile_refcount[profile_max];
int8_t profile_refcount[8];
uint8_t ispairing;
uint8_t isinquirying;
uint8_t ispaging;
@@ -310,9 +266,12 @@ struct rtl_coex_struct {
uint8_t wifi_on;
uint8_t sock_open;
#endif
unsigned long cmd_last_tx;
/* hci ev buff */
struct list_head ev_used_list;
struct list_head ev_free_list;
spinlock_t rxlock;
__u8 pkt_type;
__u16 expect;
@@ -320,18 +279,16 @@ struct rtl_coex_struct {
__u16 elen;
__u8 back_buff[HCI_MAX_EVENT_SIZE];
struct list_head ev_free_list;
/* l2cap rx buff */
struct list_head l2_used_list;
struct list_head l2_free_list;
struct list_head hci_pkt_list;
/* buff addr and size */
spinlock_t buff_lock;
unsigned long pages_addr;
unsigned long buff_size;
#define RTL_COEX_RUNNING 1
#define RTL_COEX_PKT_COUNTING 2
#define RTL_COEX_CONN_REMOVING 3
#define RTL_COEX_RUNNING (1 << 0)
unsigned long flags;
};
@@ -406,3 +363,6 @@ void rtk_btcoex_close(void);
void rtk_btcoex_probe(struct hci_dev *hdev);
void rtk_btcoex_init(void);
void rtk_btcoex_exit(void);
#endif /* __RTK_COEX_H__ */

View File

@@ -1,22 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
*
* Realtek Bluetooth USB download firmware driver
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/kernel.h>
@@ -30,14 +16,8 @@
#include <linux/usb.h>
#include <linux/dcache.h>
#include <linux/in.h>
#include <linux/version.h>
#include <net/sock.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
#include <linux/unaligned.h>
#else
#include <asm/unaligned.h>
#endif
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -50,7 +30,8 @@
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/poll.h>
#include <linux/vmalloc.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
#include <linux/pm_runtime.h>
@@ -73,7 +54,7 @@ struct cfg_list_item {
struct list_head list;
u16 offset;
u8 len;
u8 data[];
u8 data[0];
};
static struct list_head list_configs;
@@ -103,7 +84,6 @@ static struct list_head list_extracfgs;
#define HCI_VENDOR_READ_RTK_ROM_VERISION 0xfc6d
#define HCI_VENDOR_READ_LMP_VERISION 0x1001
#define HCI_VENDOR_READ_CMD 0xfc61
#define HCI_VENDOR_WRITE_CMD 0xfc62
#define ROM_LMP_NONE 0x0000
#define ROM_LMP_8723a 0x1200
@@ -112,9 +92,6 @@ static struct list_head list_extracfgs;
#define ROM_LMP_8761a 0X8761
#define ROM_LMP_8822b 0X8822
#define ROM_LMP_8852a 0x8852
#define ROM_LMP_8851b 0x8851
#define ROM_LMP_8922a 0x8922
#define ROM_LMP_8723c 0x8703
#define PATCH_SNIPPETS 0x01
#define PATCH_DUMMY_HEADER 0x02
@@ -186,30 +163,41 @@ static const uint8_t RTK_EPATCH_SIGNATURE_NEW[8] =
//Extension Section IGNATURE:0x77FD0451
static const uint8_t Extension_Section_SIGNATURE[4] = { 0x51, 0x04, 0xFD, 0x77 };
static const struct {
__u16 lmp_subver;
__u8 id;
} project_id_to_lmp_subver[] = {
{ ROM_LMP_8723a, 0 },
{ ROM_LMP_8723b, 1 },
{ ROM_LMP_8821a, 2 },
{ ROM_LMP_8761a, 3 },
{ ROM_LMP_8723c, 7 },
{ ROM_LMP_8822b, 8 }, /* 8822B */
{ ROM_LMP_8723b, 9 }, /* 8723D */
{ ROM_LMP_8821a, 10 }, /* 8821C */
{ ROM_LMP_8822b, 13 }, /* 8822C */
{ ROM_LMP_8761a, 14 }, /* 8761B */
{ ROM_LMP_8852a, 18 }, /* 8852A */
{ ROM_LMP_8723b, 19 }, /* 8733B */
{ ROM_LMP_8852a, 20 }, /* 8852B */
{ ROM_LMP_8852a, 25 }, /* 8852C */
{ ROM_LMP_8822b, 33 }, /* 8822E */
{ ROM_LMP_8851b, 36 }, /* 8851B */
{ ROM_LMP_8852a, 42 }, /* 8852D */
{ ROM_LMP_8922a, 44 }, /* 8922A */
{ ROM_LMP_8852a, 47 }, /* 8852BT */
{ ROM_LMP_8761a, 51 }, /* 8761C */
static uint16_t project_id[] = {
ROM_LMP_8723a,
ROM_LMP_8723b,
ROM_LMP_8821a,
ROM_LMP_8761a,
ROM_LMP_NONE,
ROM_LMP_NONE,
ROM_LMP_NONE,
ROM_LMP_NONE,
ROM_LMP_8822b,
ROM_LMP_8723b, /* RTL8723DU */
ROM_LMP_8821a, /* RTL8821CU */
ROM_LMP_NONE,
ROM_LMP_NONE,
ROM_LMP_8822b, /* RTL8822CU */
ROM_LMP_8761a, /* index 14 for 8761BU */
ROM_LMP_NONE,
ROM_LMP_NONE,
ROM_LMP_NONE,
ROM_LMP_8852a, /* index 18 for 8852AU */
ROM_LMP_8723b, /* index 19 for 8723FU */
ROM_LMP_8852a, /* index 20 for 8852BU */
ROM_LMP_NONE,
ROM_LMP_NONE,
ROM_LMP_NONE,
ROM_LMP_NONE,
ROM_LMP_8852a, /* index 25 for 8852CU */
ROM_LMP_NONE,
ROM_LMP_NONE,
ROM_LMP_NONE,
ROM_LMP_NONE,
ROM_LMP_NONE,
ROM_LMP_NONE,
ROM_LMP_NONE,
ROM_LMP_8822b, /* index 33 for 8822EU */
};
enum rtk_endpoit {
@@ -227,16 +215,10 @@ enum rtk_endpoit {
#define RTL8822CU 0x73
#define RTL8761BU 0x74
#define RTL8852AU 0x75
#define RTL8733BU 0x76
#define RTL8723FU 0x76
#define RTL8852BU 0x77
#define RTL8852CU 0x78
#define RTL8822EU 0x79
#define RTL8851BU 0x7A
#define RTL8852DU 0x7B
#define RTL8922AU 0x7C
#define RTL8852BTU 0x7D
#define RTL8761CU 0x80
#define RTL8723CU 0x81
typedef struct {
uint16_t prod_id;
@@ -297,7 +279,7 @@ static uint8_t g_key_id = 0;
static dev_data *dev_data_find(struct usb_interface *intf);
static patch_info *get_patch_entry(struct usb_device *udev);
static int load_firmware(dev_data *dev_entry, xchange_data *xdata);
static int load_firmware(dev_data * dev_entry, uint8_t ** buff);
static void init_xdata(xchange_data * xdata, dev_data * dev_entry);
static int check_fw_version(xchange_data * xdata);
static int download_data(xchange_data * xdata);
@@ -362,8 +344,6 @@ static patch_info fw_patch_table[] = {
{0xb009, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", RTL8723DU}, /* RTL8723DU */
{0x0231, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", RTL8723DU}, /* RTL8723DU for LiteOn */
{0xb703, 0x8703, "mp_rtl8723cu_fw", "rtl8723cu_fw", "rtl8723cu_config", RTL8723CU}, /* RTL8723CU */
{0xb820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CU */
{0xc820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CU */
{0xc821, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
@@ -397,7 +377,6 @@ static patch_info fw_patch_table[] = {
{0xc82e, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CU */
{0xc81d, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CU */
{0xd820, 0x8822, "mp_rtl8821du_fw", "rtl8821du_fw", "rtl8821du_config", RTL8822CU}, /* RTL8821DU */
{0x053b, 0x8822, "mp_rtl8821du_fw", "rtl8821du_fw", "rtl8821du_config", RTL8822CU}, /* RTL8821DU for Epson*/
{0xc822, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
{0xc82b, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
@@ -426,7 +405,6 @@ static patch_info fw_patch_table[] = {
{0xc03f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE-VS */
{0x8771, 0x8761, "mp_rtl8761b_fw", "rtl8761bu_fw", "rtl8761bu_config", RTL8761BU}, /* RTL8761BU only */
{0x876e, 0x8761, "mp_rtl8761b_fw", "rtl8761bu_fw", "rtl8761bu_config", RTL8761BU}, /* RTL8761BUE */
{0xa725, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", RTL8761BU}, /* RTL8725AU */
{0xa72A, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", RTL8761BU}, /* RTL8725AU BT only */
@@ -447,13 +425,14 @@ static patch_info fw_patch_table[] = {
{0xc125, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
{0xe852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
{0xb852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
{0xc852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
{0xc549, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
{0xc127, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
{0x3565, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
{0xb733, 0x8723, "mp_rtl8733bu_fw", "rtl8733bu_fw", "rtl8733bu_config", RTL8733BU}, /* RTL8733BU */
{0xb73a, 0x8723, "mp_rtl8733bu_fw", "rtl8733bu_fw", "rtl8733bu_config", RTL8733BU}, /* RTL8733BU */
{0xf72b, 0x8723, "mp_rtl8733bu_fw", "rtl8733bu_fw", "rtl8733bu_config", RTL8733BU}, /* RTL8733BU */
{0xb733, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
{0xb73a, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
{0xf72b, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
{0x8851, 0x8852, "mp_rtl8851au_fw", "rtl8851au_fw", "rtl8851au_config", RTL8852BU}, /* RTL8851AU */
{0xa85b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", RTL8852BU}, /* RTL8852BU */
@@ -474,7 +453,6 @@ static patch_info fw_patch_table[] = {
{0x1670, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", RTL8852BU}, /* RTL8852BE */
{0xc85a, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CU */
{0xc85d, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CU */
{0x0852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
{0x5852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
{0xc85c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
@@ -482,29 +460,10 @@ static patch_info fw_patch_table[] = {
{0x886c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
{0x887c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
{0x4007, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
{0x1675, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
{0x3586, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
{0xe822, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", RTL8822EU}, /* RTL8822EU */
{0xa82a, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", RTL8822EU}, /* RTL8822EU */
{0xb851, 0x8851, "mp_rtl8851bu_fw", "rtl8851bu_fw", "rtl8851bu_config", RTL8851BU}, /* RTL8851BU */
{0xd85a, 0x8852, "mp_rtl8852du_fw", "rtl8852du_fw", "rtl8852du_config", RTL8852DU}, /* RTL8852DU */
{0x892a, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AU */
{0x8922, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
{0xa890, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
{0xa891, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
{0xa892, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
{0xd922, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
{0xb85f, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
{0xc852, 0x8852, "mp_rtl8852btu_fw", "rtl8852btu_fw", "rtl8852btu_config", RTL8852BTU}, /* RTL8852BTU */
{0x8520, 0x8852, "mp_rtl8852btu_fw", "rtl8852btu_fw", "rtl8852btu_config", RTL8852BTU}, /* RTL8852BTE */
{0xc761, 0x8761, "mp_rtl8761cu_fw", "rtl8761cu_mx_fw", "rtl8761cu_mx_config", RTL8761CU}, /* RTL8761CU */
/* NOTE: must append patch entries above the null entry */
{0, 0, NULL, NULL, NULL, 0}
};
@@ -787,7 +746,6 @@ static inline int get_max_patch_size(u8 chip_type)
max_patch_size = 25 * 1024;
break;
case RTL8723DU:
case RTL8723CU:
case RTL8822CU:
case RTL8761BU:
case RTL8821CU:
@@ -796,11 +754,10 @@ static inline int get_max_patch_size(u8 chip_type)
case RTL8852AU:
max_patch_size = 0x114D0 + 529; /* 69.2KB */
break;
case RTL8733BU:
case RTL8723FU:
max_patch_size = 0xC4Cf + 529; /* 49.2KB */
break;
case RTL8852BU:
case RTL8851BU:
max_patch_size = 0x104D0 + 529; /* 65KB */
break;
case RTL8852CU:
@@ -809,18 +766,6 @@ static inline int get_max_patch_size(u8 chip_type)
case RTL8822EU:
max_patch_size = 0x24620 + 529; /* 145KB */
break;
case RTL8852DU:
max_patch_size = 0x20D90 + 529; /* 131KB */
break;
case RTL8922AU:
max_patch_size = 0x23810 + 529; /* 142KB */
break;
case RTL8852BTU:
max_patch_size = 0x27E00 + 529; /* 159.5KB */
break;
case RTL8761CU:
max_patch_size = 1024 * 1024; /* 1MB */
break;
default:
max_patch_size = 40 * 1024;
break;
@@ -829,64 +774,11 @@ static inline int get_max_patch_size(u8 chip_type)
return max_patch_size;
}
static int rtk_vendor_write(dev_data * dev_entry)
{
int ret_val;
xchange_data *xdata = NULL;
unsigned char cmd_buf[] = {0x31, 0x90, 0xd0, 0x29, 0x80, 0x00, 0x00,
0x00, 0x00};
xdata = kzalloc(sizeof(xchange_data), GFP_KERNEL);
if (NULL == xdata) {
ret_val = 0xFE;
RTKBT_DBG("NULL == xdata");
return -1;
}
init_xdata(xdata, dev_entry);
xdata->cmd_hdr->opcode = cpu_to_le16(HCI_VENDOR_WRITE_CMD);
xdata->cmd_hdr->plen = 9;
memcpy(xdata->send_pkt, &(xdata->cmd_hdr->opcode), 2);
memcpy(xdata->send_pkt+2, &(xdata->cmd_hdr->plen), 1);
memcpy(xdata->send_pkt+3, cmd_buf, sizeof(cmd_buf));
xdata->pkt_len = CMD_HDR_LEN + 9;
ret_val = send_hci_cmd(xdata);
if (ret_val < 0) {
RTKBT_ERR("%s: Failed to send HCI command.", __func__);
goto end;
}
ret_val = rcv_hci_evt(xdata);
if (ret_val < 0) {
RTKBT_ERR("%s: Failed to receive HCI event.", __func__);
goto end;
}
ret_val = 0;
end:
if (xdata != NULL) {
if (xdata->send_pkt)
kfree(xdata->send_pkt);
if (xdata->rcv_pkt)
kfree(xdata->rcv_pkt);
kfree(xdata);
}
return ret_val;
}
static int check_fw_chip_ver(dev_data * dev_entry, xchange_data * xdata)
{
int ret_val;
uint16_t chip = 0;
uint16_t chip_ver = 0;
uint16_t lmp_subver, hci_rev;
patch_info *patch_entry;
struct hci_rp_read_local_version *read_ver_rsp;
chip = rtk_vendor_read(dev_entry, READ_CHIP_TYPE);
if(chip == 0x8822) {
@@ -909,16 +801,9 @@ static int check_fw_chip_ver(dev_data * dev_entry, xchange_data * xdata)
gEVersion = rtk_get_eversion(dev_entry);
}
return ret_val;
} else {
patch_entry = xdata->dev_entry->patch_entry;
read_ver_rsp = (struct hci_rp_read_local_version *)(xdata->rsp_para);
lmp_subver = le16_to_cpu(read_ver_rsp->lmp_subver);
hci_rev = le16_to_cpu(read_ver_rsp->hci_rev);
if (lmp_subver == 0x8852 && hci_rev == 0x000d)
ret_val = rtk_vendor_write(dev_entry);
}
return ret_val;
return 0;
}
int download_patch(struct usb_interface *intf)
@@ -951,7 +836,7 @@ int download_patch(struct usb_interface *intf)
if (ret_val != 0 )
goto patch_end;
xdata->fw_len = load_firmware(dev_entry, xdata);
xdata->fw_len = load_firmware(dev_entry, &xdata->fw_data);
if (xdata->fw_len <= 0) {
RTKBT_ERR("load firmware failed!");
ret_val = -1;
@@ -990,7 +875,7 @@ int download_patch(struct usb_interface *intf)
ret_val = 0;
patch_fail:
vfree(fw_buf);
kfree(fw_buf);
patch_end:
if (xdata != NULL) {
if (xdata->send_pkt)
@@ -1008,7 +893,7 @@ patch_end:
* -1: error
* 0: download patch successfully
* >0: patch already exists */
int download_special_patch(struct usb_interface *intf, const char *special_name)
int download_lps_patch(struct usb_interface *intf)
{
dev_data *dev_entry;
patch_info *pinfo;
@@ -1050,18 +935,15 @@ int download_special_patch(struct usb_interface *intf, const char *special_name)
}
goto patch_end;
}
memset(name1, 0, sizeof(name1));
memset(name2, 0, sizeof(name2));
origin_name1 = dev_entry->patch_entry->patch_name;
origin_name2 = dev_entry->patch_entry->config_name;
memcpy(name1, special_name, strlen(special_name));
strncat(name1, origin_name1, sizeof(name1) - 1 - strlen(special_name));
memcpy(name2, special_name, strlen(special_name));
strncat(name2, origin_name2, sizeof(name2) - 1 - strlen(special_name));
snprintf(name1, sizeof(name1), "lps_%s", origin_name1);
snprintf(name2, sizeof(name2), "lps_%s", origin_name2);
dev_entry->patch_entry->patch_name = name1;
dev_entry->patch_entry->config_name = name2;
RTKBT_INFO("Loading %s and %s", name1, name2);
xdata->fw_len = load_firmware(dev_entry, xdata);
xdata->fw_len = load_firmware(dev_entry, &xdata->fw_data);
dev_entry->patch_entry->patch_name = origin_name1;
dev_entry->patch_entry->config_name = origin_name2;
if (xdata->fw_len <= 0) {
@@ -1073,13 +955,11 @@ int download_special_patch(struct usb_interface *intf, const char *special_name)
fw_buf = xdata->fw_data;
pinfo = dev_entry->patch_entry;
/*
if (!pinfo) {
RTKBT_ERR("%s: No patch entry", __func__);
result = -1;
goto patch_fail;
}
*/
max_patch_size = get_max_patch_size(pinfo->chip_type);
if (xdata->fw_len > max_patch_size) {
result = -1;
@@ -1118,39 +998,6 @@ patch_end:
}
#endif
int setup_btrealtek_flag(struct usb_interface *intf, struct hci_dev *hdev)
{
dev_data *dev_entry;
patch_info *pinfo;
int ret_val = 0;
dev_entry = dev_data_find(intf);
if (NULL == dev_entry) {
ret_val = -1;
RTKBT_ERR("%s: NULL == dev_entry", __func__);
return ret_val;
}
pinfo = dev_entry->patch_entry;
if (!pinfo) {
RTKBT_ERR("%s: No patch entry", __func__);
ret_val = -1;
return ret_val;
}
switch (pinfo->chip_type){
case RTL8852CU:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
btrealtek_set_flag(hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP);
#endif
break;
default:
break;
}
return ret_val;
}
#if defined RTKBT_SUSPEND_WAKEUP || defined RTKBT_SHUTDOWN_WAKEUP || defined RTKBT_SWITCH_PATCH
int set_scan(struct usb_interface *intf)
{
@@ -1198,7 +1045,7 @@ end:
dev_data *dev_data_find(struct usb_interface * intf)
{
dev_data *dev_entry = NULL;
dev_data *dev_entry;
list_for_each_entry(dev_entry, &dev_data_list, list_node) {
if (dev_entry->intf == intf) {
@@ -1241,7 +1088,6 @@ static int is_mac(u8 chip_type, u16 offset)
switch (chip_type) {
case RTL8822BU:
case RTL8723DU:
case RTL8723CU:
case RTL8821CU:
if (offset == 0x0044)
return 1;
@@ -1249,15 +1095,10 @@ static int is_mac(u8 chip_type, u16 offset)
case RTL8822CU:
case RTL8761BU:
case RTL8852AU:
case RTL8733BU:
case RTL8723FU:
case RTL8852BU:
case RTL8852CU:
case RTL8822EU:
case RTL8851BU:
case RTL8852DU:
case RTL8922AU:
case RTL8852BTU:
case RTL8761CU:
if (offset == 0x0030)
return 1;
break;
@@ -1275,21 +1116,15 @@ static uint16_t get_mac_offset(u8 chip_type)
switch (chip_type) {
case RTL8822BU:
case RTL8723DU:
case RTL8723CU:
case RTL8821CU:
return 0x0044;
case RTL8822CU:
case RTL8761BU:
case RTL8852AU:
case RTL8733BU:
case RTL8723FU:
case RTL8852BU:
case RTL8852CU:
case RTL8822EU:
case RTL8851BU:
case RTL8852DU:
case RTL8922AU:
case RTL8852BTU:
case RTL8761CU:
return 0x0030;
case RTLPREVIOUS:
return 0x003c;
@@ -1617,12 +1452,14 @@ static uint8_t *rtb_get_patch_header(int *len,
}
break;
default:
RTKBT_INFO("Unknown Opcode. Ignore");
RTKBT_ERR("Wrong Opcode");
goto wrong_opcode;
}
section_pos += (SECTION_HEADER_SIZE + section_hdr.section_len);
}
*len = patch_len;
wrong_opcode:
return NULL;
}
@@ -1906,7 +1743,7 @@ static int rtk_vendor_read(dev_data * dev_entry, uint8_t class)
xchange_data *xdata = NULL;
unsigned char cmd_ct_buf[] = {0x10, 0x38, 0x04, 0x28, 0x80};
unsigned char cmd_cv_buf[] = {0x10, 0x3A, 0x04, 0x28, 0x80};
unsigned char cmd_sec_buf[] = {0x10, 0xA4, 0xAD, 0x00, 0xb0};
unsigned char cmd_sec_buf[] = {0x10, 0xA4, 0x0D, 0x00, 0xb0};
xdata = kzalloc(sizeof(xchange_data), GFP_KERNEL);
if (NULL == xdata) {
@@ -1974,6 +1811,7 @@ static int rtk_vendor_read(dev_data * dev_entry, uint8_t class)
}
}
read_end:
if (xdata != NULL) {
if (xdata->send_pkt)
@@ -1985,57 +1823,7 @@ read_end:
return ret_val;
}
static int needs_hci_upgrade(xchange_data *xdata, u8 *buf, u32 buf_len)
{
struct {
u8 status;
u8 subopcode;
u8 ota;
} __attribute__((packed)) *evt_params;
#define UPG_DL_BLOCK_SIZE 128
#define UPG_SUBCMD_CODE 0x01
u8 len = UPG_DL_BLOCK_SIZE;
u8 *cmd_params;
int ret;
cmd_params = xdata->req_para;
evt_params = (void *)xdata->rsp_para;
xdata->cmd_hdr->opcode = cpu_to_le16(0xfdbb);
if (buf_len < len)
len = buf_len;
xdata->cmd_hdr->plen = 1 + len;
xdata->pkt_len = sizeof(*xdata->cmd_hdr) + xdata->cmd_hdr->plen;
*cmd_params++ = UPG_SUBCMD_CODE;
memcpy(cmd_params, buf, len);
ret = send_hci_cmd(xdata);
if (ret < 0)
return ret;
ret = rcv_hci_evt(xdata);
if (ret < 0)
return ret;
if (evt_params->status) {
RTKBT_ERR("needs_hci_upgrade: status %02x", evt_params->status);
return -1;
}
if (evt_params->subopcode != UPG_SUBCMD_CODE) {
RTKBT_ERR("needs_hci_upgrade: return subopcode %02x",
evt_params->subopcode);
return -2;
}
RTKBT_INFO("needs_hci_upgrade: state %02x", evt_params->ota);
return evt_params->ota;
}
/* buff: points to the allocated buffer that stores extracted fw and config
* This function returns the total length of extracted fw and config
*/
int load_firmware(dev_data *dev_entry, xchange_data *xdata)
int load_firmware(dev_data * dev_entry, uint8_t ** buff)
{
const struct firmware *fw;
struct usb_device *udev;
@@ -2047,13 +1835,12 @@ int load_firmware(dev_data *dev_entry, xchange_data *xdata)
uint8_t need_download_fw = 1;
uint16_t lmp_version;
struct rtk_epatch_entry current_entry = { 0 };
struct list_head *pos, *next;
struct patch_node *tmp;
struct patch_node patch_node_hdr;
int i;
RTKBT_DBG("load_firmware start");
udev = dev_entry->udev;
patch_entry = dev_entry->patch_entry;
lmp_version = patch_entry->lmp_sub;
@@ -2066,13 +1853,16 @@ int load_firmware(dev_data *dev_entry, xchange_data *xdata)
ret_val = request_firmware(&fw, fw_name, &udev->dev);
if (ret_val < 0) {
RTKBT_ERR("request_firmware error");
fw_len = 0;
kfree(config_file_buf);
config_file_buf = NULL;
goto fw_fail;
}
INIT_LIST_HEAD(&patch_node_hdr.list);
epatch_buf = vzalloc(fw->size);
if (!epatch_buf)
epatch_buf = kzalloc(fw->size, GFP_KERNEL);
if (NULL == epatch_buf)
goto alloc_fail;
memcpy(epatch_buf, fw->data, fw->size);
@@ -2084,174 +1874,137 @@ int load_firmware(dev_data *dev_entry, xchange_data *xdata)
if (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) == 0) {
RTKBT_ERR("8723a Check signature error!");
need_download_fw = 0;
goto sign_err;
}
buf = vzalloc(buf_len);
if (!buf) {
RTKBT_ERR("Can't alloc memory for fw&config");
buf_len = -1;
goto alloc_buf_err;
} else {
if (!(buf = kzalloc(buf_len, GFP_KERNEL))) {
RTKBT_ERR("Can't alloc memory for fw&config");
buf_len = -1;
} else {
RTKBT_DBG("8723a, fw copy direct");
memcpy(buf, epatch_buf, fw->size);
if (config_len) {
memcpy(&buf[buf_len - config_len],
config_file_buf, config_len);
}
}
}
} else {
RTKBT_ERR("This is not 8723a, use new patch style!");
RTKBT_DBG("8723a, fw copy direct");
memcpy(buf, epatch_buf, fw->size);
if (config_len)
memcpy(&buf[buf_len - config_len], config_file_buf,
config_len);
goto done;
}
RTKBT_ERR("This is not 8723a, use new patch style!");
/* Get version from ROM */
gEVersion = rtk_get_eversion(dev_entry);
RTKBT_DBG("%s: New gEVersion %d", __func__, gEVersion);
if (gEVersion == 0xFE) {
RTKBT_ERR("%s: Read ROM version failure", __func__);
need_download_fw = 0;
goto alloc_fail;
}
/* check Signature and Extension Section Field */
if ((memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) &&
memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8)) ||
memcmp(epatch_buf + buf_len - config_len - 4,
Extension_Section_SIGNATURE, 4) != 0) {
RTKBT_ERR("Check SIGNATURE error! do not download fw");
need_download_fw = 0;
goto sign_err;
}
proj_id = rtk_get_fw_project_id(epatch_buf + buf_len - config_len - 5);
for (i = 0; i < ARRAY_SIZE(project_id_to_lmp_subver); i++) {
if (proj_id == project_id_to_lmp_subver[i].id &&
lmp_version == project_id_to_lmp_subver[i].lmp_subver) {
break;
}
}
if (i >= ARRAY_SIZE(project_id_to_lmp_subver)) {
RTKBT_ERR("lmp_version %04x, project_id %u, does not match!!!",
lmp_version, proj_id);
need_download_fw = 0;
goto proj_id_err;
}
RTKBT_DBG("lmp_version is %04x, project_id is %u, match!",
lmp_version, proj_id);
if (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8) == 0) {
int key_id = rtk_vendor_read(dev_entry, READ_SEC_PROJ);
int tmp_len = 0;
RTKBT_DBG("%s: key id %d", __func__, key_id);
if (key_id < 0) {
RTKBT_ERR("%s: Read key id failure", __func__);
/* Get version from ROM */
gEVersion = rtk_get_eversion(dev_entry);
RTKBT_DBG("%s: New gEVersion %d", __func__, gEVersion);
if (gEVersion == 0xFE) {
RTKBT_ERR("%s: Read ROM version failure", __func__);
need_download_fw = 0;
fw_len = 0;
goto extract_err;
}
rtb_get_patch_header(&buf_len, &patch_node_hdr, epatch_buf,
key_id);
if (!buf_len)
goto extract_err;
RTKBT_DBG("buf_len = 0x%x", buf_len);
buf_len += config_len;
buf = vzalloc(buf_len);
if (!buf) {
RTKBT_ERR("Can't alloc memory for multi fw&config");
buf_len = -1;
goto alloc_buf_err;
goto alloc_fail;
}
list_for_each_safe(pos, next, &patch_node_hdr.list) {
tmp = list_entry(pos, struct patch_node, list);
RTKBT_DBG("len = 0x%x", tmp->len);
memcpy(buf + tmp_len, tmp->payload, tmp->len);
tmp_len += tmp->len;
list_del_init(pos);
kfree(tmp);
}
if (config_len)
memcpy(&buf[buf_len - config_len], config_file_buf,
config_len);
} else {
rtk_get_patch_entry(epatch_buf, &current_entry);
if (current_entry.patch_length == 0)
goto extract_err;
buf_len = current_entry.patch_length + config_len;
RTKBT_DBG("buf_len = 0x%x", buf_len);
buf = vzalloc(buf_len);
if (!buf) {
RTKBT_ERR("Can't alloc memory for multi fw&config");
buf_len = -1;
goto alloc_buf_err;
}
memcpy(buf, epatch_buf + current_entry.start_offset,
current_entry.patch_length);
/* Copy fw version */
memcpy(buf + current_entry.patch_length - 4, epatch_buf + 8, 4);
if (config_len)
memcpy(&buf[buf_len - config_len], config_file_buf,
config_len);
}
if (patch_entry->chip_type == RTL8761CU) {
if (needs_hci_upgrade(xdata, buf, buf_len) <= 0) {
if (config_len > 0) {
memmove(buf, buf + buf_len - config_len,
config_len);
buf_len = config_len;
} else {
#define FAKE_SEG_LEN 16
if (buf_len > FAKE_SEG_LEN)
buf_len = FAKE_SEG_LEN;
memset(buf, 0, buf_len);
}
/* check Signature and Extension Section Field */
if (((memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) != 0) && (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8) != 0))||
memcmp(epatch_buf + buf_len - config_len - 4,
Extension_Section_SIGNATURE, 4) != 0) {
RTKBT_ERR("Check SIGNATURE error! do not download fw");
need_download_fw = 0;
} else {
/* It does not need to download config when upgrading */
buf_len -= config_len;
proj_id =
rtk_get_fw_project_id(epatch_buf + buf_len -
config_len - 5);
if (lmp_version != project_id[proj_id]) {
RTKBT_ERR
("lmp_version is %x, project_id is %x, does not match!!!",
lmp_version, project_id[proj_id]);
need_download_fw = 0;
} else {
RTKBT_DBG
("lmp_version is %x, project_id is %x, match!",
lmp_version, project_id[proj_id]);
if(memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8) == 0) {
int key_id = rtk_vendor_read(dev_entry, READ_SEC_PROJ);
RTKBT_DBG("%s: key id %d", __func__, key_id);
if (key_id < 0) {
RTKBT_ERR("%s: Read key id failure", __func__);
need_download_fw = 0;
fw_len = 0;
goto alloc_fail;
}
rtb_get_patch_header(&buf_len, &patch_node_hdr, epatch_buf, key_id);
if(buf_len == 0)
goto alloc_fail;
RTKBT_DBG("buf_len = 0x%x", buf_len);
buf_len += config_len;
} else {
rtk_get_patch_entry(epatch_buf, &current_entry);
if (current_entry.patch_length == 0)
goto alloc_fail;
buf_len = current_entry.patch_length + config_len;
RTKBT_DBG("buf_len = 0x%x", buf_len);
}
if (!(buf = kzalloc(buf_len, GFP_KERNEL))) {
RTKBT_ERR
("Can't alloc memory for multi fw&config");
buf_len = -1;
} else {
if(memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8) == 0) {
int tmp_len = 0;
list_for_each_safe(pos, next, &patch_node_hdr.list)
{
tmp = list_entry(pos, struct patch_node, list);
RTKBT_DBG("len = 0x%x", tmp->len);
memcpy(buf + tmp_len, tmp->payload, tmp->len);
tmp_len += tmp->len;
list_del_init(pos);
kfree(tmp);
}
if (config_len) {
memcpy(&buf
[buf_len - config_len],
config_file_buf,
config_len);
}
} else {
memcpy(buf,
epatch_buf +
current_entry.start_offset,
current_entry.patch_length);
memcpy(buf + current_entry.patch_length - 4, epatch_buf + 8, 4); /*fw version */
if (config_len) {
memcpy(&buf
[buf_len - config_len],
config_file_buf,
config_len);
}
}
}
}
}
}
done:
RTKBT_DBG("fw:%s exists, config file:%s exists",
buf_len > 0 ? "" : "not", config_len > 0 ? "" : "not");
if (buf && buf_len > 0 && need_download_fw) {
(buf_len > 0) ? "" : "not", (config_len > 0) ? "" : "not");
if (buf && (buf_len > 0) && (need_download_fw)) {
fw_len = buf_len;
xdata->fw_data = buf;
*buff = buf;
}
RTKBT_DBG("load_firmware done");
alloc_buf_err:
extract_err:
/* Make sure all the patch nodes freed */
list_for_each_safe(pos, next, &patch_node_hdr.list) {
tmp = list_entry(pos, struct patch_node, list);
list_del_init(pos);
kfree(tmp);
}
proj_id_err:
sign_err:
alloc_fail:
release_firmware(fw);
if (epatch_buf)
vfree(epatch_buf);
kfree(epatch_buf);
fw_fail:
if (config_file_buf)
kfree(config_file_buf);
fw_fail:
if (fw_len == 0)
vfree(buf);
kfree(buf);
return fw_len;
}
@@ -2396,7 +2149,7 @@ int download_data(xchange_data * xdata)
uint8_t *pcur;
int pkt_len, frag_num, frag_len;
int i, ret_val;
int j = 0;
int j;
RTKBT_DBG("download_data start");
@@ -2408,11 +2161,12 @@ int download_data(xchange_data * xdata)
frag_len = PATCH_SEG_MAX;
for (i = 0; i < frag_num; i++) {
cmd_para->index = j++;
if(cmd_para->index == 0x7f)
j = 1;
if (i > 0x7f)
j = (i & 0x7f) + 1;
else
j = i;
cmd_para->index = j;
if (i == (frag_num - 1)) {
cmd_para->index |= DATA_END;
frag_len = xdata->fw_len % PATCH_SEG_MAX;

View File

@@ -1,23 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
*
* Realtek Bluetooth USB download firmware driver
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __RTK_MISC_H__
#define __RTK_MISC_H__
#include <linux/kernel.h>
#include <linux/module.h>
@@ -26,8 +14,6 @@
#include <linux/usb.h>
#include <linux/suspend.h>
#define CONFIG_BTUSB_AUTOSUSPEND 0
/* Download LPS patch when host suspends or power off
* LPS patch name: lps_rtl8xxx_fw
* LPS config name: lps_rtl8xxx_config
@@ -59,9 +45,7 @@
#endif
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 33)
#define USB_RPM 1
#else
#define USB_RPM 0
#define USB_RPM
#endif
#define CONFIG_NEEDS_BINDING
@@ -72,7 +56,7 @@
#endif
/* USB SS */
#if (CONFIG_BTUSB_AUTOSUSPEND && USB_RPM)
#if (defined CONFIG_BTUSB_AUTOSUSPEND) && (defined USB_RPM)
#define BTUSB_RPM
#endif
@@ -98,41 +82,12 @@ struct api_context {
int status;
};
int download_special_patch(struct usb_interface *intf, const char *special_name);
int download_lps_patch(struct usb_interface *intf);
#endif
int setup_btrealtek_flag(struct usb_interface *intf, struct hci_dev *hdev);
enum {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
REALTEK_ALT6_CONTINUOUS_TX_CHIP,
#endif
__REALTEK_NUM_FLAGS,
};
struct btrealtek_data {
DECLARE_BITMAP(flags, __REALTEK_NUM_FLAGS);
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)
static inline void *hci_get_priv(struct hci_dev *hdev)
{
return (char *)hdev + sizeof(*hdev);
}
#endif
#define btrealtek_set_flag(hdev, nr) \
do { \
struct btrealtek_data *realtek = hci_get_priv((hdev)); \
set_bit((nr), realtek->flags); \
} while (0)
#define btrealtek_get_flag(hdev) \
(((struct btrealtek_data *)hci_get_priv(hdev))->flags)
#define btrealtek_test_flag(hdev, nr) test_bit((nr), btrealtek_get_flag(hdev))
#if defined RTKBT_SUSPEND_WAKEUP || defined RTKBT_SHUTDOWN_WAKEUP || defined RTKBT_SWITCH_PATCH
int set_scan(struct usb_interface *intf);
#endif
#endif /* __RTK_MISC_H__ */

View File

@@ -1,10 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
*
* Module to force cpuidle states through debugfs files.
*
*/
#include <nvidia/conftest.h>
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/irqdesc.h>
@@ -26,16 +26,9 @@ static void suspend_all_device_irqs(void)
{
struct irq_data *data;
struct irq_desc *desc;
unsigned int nirqs;
int irq;
#if defined(NV_IRQ_GET_NR_IRQS_PRESENT) /* Linux v6.13 */
nirqs = irq_get_nr_irqs();
#else
nirqs = nr_irqs;
#endif
for (irq = 0, data = irq_get_irq_data(irq); irq < nirqs;
for (irq = 0, data = irq_get_irq_data(irq); irq < nr_irqs;
irq++, data = irq_get_irq_data(irq)) {
if (!data)
continue;
@@ -51,16 +44,9 @@ static void resume_all_device_irqs(void)
{
struct irq_data *data;
struct irq_desc *desc;
unsigned int nirqs;
int irq;
#if defined(NV_IRQ_GET_NR_IRQS_PRESENT)
nirqs = irq_get_nr_irqs();
#else
nirqs = nr_irqs;
#endif
for (irq = 0, data = irq_get_irq_data(irq); irq < nirqs;
for (irq = 0, data = irq_get_irq_data(irq); irq < nr_irqs;
irq++, data = irq_get_irq_data(irq)) {
if (!data)
continue;

View File

@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
#include <linux/cpu_cooling.h>
#include <linux/cpuidle.h>
@@ -228,21 +226,9 @@ static const struct of_device_id tegra_auto_cpuidle_of[] = {
{ },
};
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_auto_cpuidle_remove_wrapper(struct platform_device *pdev)
{
tegra_auto_cpuidle_remove(pdev);
}
#else
static int tegra_auto_cpuidle_remove_wrapper(struct platform_device *pdev)
{
return tegra_auto_cpuidle_remove(pdev);
}
#endif
static struct platform_driver tegra_auto_cpuidle_driver __refdata = {
.probe = tegra_auto_cpuidle_probe,
.remove = tegra_auto_cpuidle_remove_wrapper,
.remove = tegra_auto_cpuidle_remove,
.driver = {
.owner = THIS_MODULE,
.name = "cpuidle_tegra_auto",

View File

@@ -5,7 +5,9 @@ ifdef CONFIG_TEGRA_HOST1X
obj-m += tegra-hv-vse-safety.o
obj-m += tegra-nvvse-cryptodev.o
ifdef CONFIG_CRYPTO_ENGINE
ifndef CONFIG_SKIP_CRYPTO
obj-m += tegra/
endif
endif
endif
obj-m += tegra-se-nvrng.o

View File

@@ -1,11 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2019-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Copyright (c) 2019-2024, NVIDIA Corporation. All Rights Reserved.
*
* Cryptographic API.
*/
#include <nvidia/conftest.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
@@ -5210,21 +5209,9 @@ static const struct dev_pm_ops tegra_hv_pm_ops = {
};
#endif /* CONFIG_PM */
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_hv_vse_safety_remove_wrapper(struct platform_device *pdev)
{
tegra_hv_vse_safety_remove(pdev);
}
#else
static int tegra_hv_vse_safety_remove_wrapper(struct platform_device *pdev)
{
return tegra_hv_vse_safety_remove(pdev);
}
#endif
static struct platform_driver tegra_hv_vse_safety_driver = {
.probe = tegra_hv_vse_safety_probe,
.remove = tegra_hv_vse_safety_remove_wrapper,
.remove = tegra_hv_vse_safety_remove,
.shutdown = tegra_hv_vse_safety_shutdown,
.driver = {
.name = "tegra_hv_vse_safety",

View File

@@ -1,12 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (c) 2020-2023, NVIDIA CORPORATION. All rights reserved.
*
* Support for Tegra NVRNG Engine Error Handling.
*/
#include <nvidia/conftest.h>
#include <asm/io.h>
#include <linux/acpi.h>
#include <linux/clk.h>
@@ -359,21 +357,9 @@ static const struct of_device_id tegra_se_nvrng_of_match[] = {
};
MODULE_DEVICE_TABLE(of, tegra_se_nvrng_of_match);
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_se_nvrng_remove_wrapper(struct platform_device *pdev)
{
tegra_se_nvrng_remove(pdev);
}
#else
static int tegra_se_nvrng_remove_wrapper(struct platform_device *pdev)
{
return tegra_se_nvrng_remove(pdev);
}
#endif
static struct platform_driver tegra_se_nvrng_driver = {
.probe = tegra_se_nvrng_probe,
.remove = tegra_se_nvrng_remove_wrapper,
.remove = tegra_se_nvrng_remove,
.driver = {
.name = "tegra-se-nvrng",
.owner = THIS_MODULE,

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
ccflags-y += -I$(srctree.nvidia)/drivers/gpu/host1x/include

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Crypto driver to handle HASH algorithms using NVIDIA Security Engine.
*/
@@ -7,6 +7,7 @@
#include <nvidia/conftest.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/host1x-next.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
@@ -23,17 +24,18 @@
#include "tegra-se.h"
struct tegra_sha_ctx {
#ifndef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifndef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
struct crypto_engine_ctx enginectx;
#endif
struct crypto_ahash *fallback_tfm;
struct tegra_se *se;
unsigned int alg;
bool fallback;
u32 key_id;
struct crypto_ahash *fallback_tfm;
};
struct tegra_sha_reqctx {
struct ahash_request fallback_req;
struct scatterlist *src_sg;
struct tegra_se_datbuf datbuf;
struct tegra_se_datbuf residue;
@@ -44,8 +46,6 @@ struct tegra_sha_reqctx {
unsigned int blk_size;
unsigned int task;
u32 key_id;
u32 result[HASH_RESULT_REG_COUNT];
struct ahash_request fallback_req;
};
static int tegra_sha_get_config(u32 alg)
@@ -216,13 +216,13 @@ static int tegra_sha_fallback_export(struct ahash_request *req, void *out)
}
static int tegra_sha_prep_cmd(struct tegra_se *se, u32 *cpuvaddr,
struct tegra_sha_reqctx *rctx)
struct tegra_sha_reqctx *rctx)
{
u64 msg_len, msg_left;
int i = 0;
msg_len = rctx->total_len * 8;
msg_left = rctx->datbuf.size * 8;
msg_len = (u64)rctx->total_len * 8;
msg_left = (u64)rctx->datbuf.size * 8;
/*
* If IN_ADDR_HI_0.SZ > SHA_MSG_LEFT_[0-3] to the HASH engine,
@@ -236,7 +236,7 @@ static int tegra_sha_prep_cmd(struct tegra_se *se, u32 *cpuvaddr,
}
cpuvaddr[i++] = host1x_opcode_setpayload(8);
cpuvaddr[i++] = se_host1x_opcode_incr_w(SE_SHA_MSG_LENGTH);
cpuvaddr[i++] = host1x_opcode_incr_w(SE_SHA_MSG_LENGTH);
cpuvaddr[i++] = lower_32_bits(msg_len);
cpuvaddr[i++] = upper_32_bits(msg_len);
cpuvaddr[i++] = 0;
@@ -246,15 +246,14 @@ static int tegra_sha_prep_cmd(struct tegra_se *se, u32 *cpuvaddr,
cpuvaddr[i++] = 0;
cpuvaddr[i++] = 0;
cpuvaddr[i++] = host1x_opcode_setpayload(6);
cpuvaddr[i++] = se_host1x_opcode_incr_w(SE_SHA_CFG);
cpuvaddr[i++] = host1x_opcode_incr_w(SE_SHA_CFG);
cpuvaddr[i++] = rctx->config;
if (rctx->task & SHA_FIRST) {
cpuvaddr[i++] = SE_SHA_TASK_HASH_INIT;
rctx->task &= ~SHA_FIRST;
} else {
} else
cpuvaddr[i++] = 0;
}
cpuvaddr[i++] = rctx->datbuf.addr;
cpuvaddr[i++] = (u32)(SE_ADDR_HI_MSB(upper_32_bits(rctx->datbuf.addr)) |
@@ -264,47 +263,30 @@ static int tegra_sha_prep_cmd(struct tegra_se *se, u32 *cpuvaddr,
SE_ADDR_HI_SZ(rctx->digest.size));
if (rctx->key_id) {
cpuvaddr[i++] = host1x_opcode_setpayload(1);
cpuvaddr[i++] = se_host1x_opcode_nonincr_w(SE_SHA_CRYPTO_CFG);
cpuvaddr[i++] = host1x_opcode_nonincr_w(SE_SHA_CRYPTO_CFG);
cpuvaddr[i++] = SE_AES_KEY_INDEX(rctx->key_id);
}
cpuvaddr[i++] = host1x_opcode_setpayload(1);
cpuvaddr[i++] = se_host1x_opcode_nonincr_w(SE_SHA_OPERATION);
cpuvaddr[i++] = host1x_opcode_nonincr_w(SE_SHA_OPERATION);
cpuvaddr[i++] = SE_SHA_OP_WRSTALL |
SE_SHA_OP_START |
SE_SHA_OP_LASTBUF;
cpuvaddr[i++] = se_host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
cpuvaddr[i++] = host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
cpuvaddr[i++] = host1x_uclass_incr_syncpt_cond_f(1) |
host1x_uclass_incr_syncpt_indx_f(se->syncpt_id);
dev_dbg(se->dev, "msg len %llu msg left %llu cfg %#x",
msg_len, msg_left, rctx->config);
msg_len, msg_left, rctx->config);
return i;
}
static void tegra_sha_copy_hash_result(struct tegra_se *se, struct tegra_sha_reqctx *rctx)
{
int i;
for (i = 0; i < HASH_RESULT_REG_COUNT; i++)
rctx->result[i] = readl(se->base + se->hw->regs->result + (i * 4));
}
static void tegra_sha_paste_hash_result(struct tegra_se *se, struct tegra_sha_reqctx *rctx)
{
int i;
for (i = 0; i < HASH_RESULT_REG_COUNT; i++)
writel(rctx->result[i],
se->base + se->hw->regs->result + (i * 4));
}
static int tegra_sha_do_update(struct ahash_request *req)
{
struct tegra_sha_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
struct tegra_sha_reqctx *rctx = ahash_request_ctx(req);
unsigned int nblks, nresidue, size, ret;
unsigned int nblks, nresidue, size;
u32 *cpuvaddr = ctx->se->cmdbuf->addr;
nresidue = (req->nbytes + rctx->residue.size) % rctx->blk_size;
@@ -329,26 +311,21 @@ static int tegra_sha_do_update(struct ahash_request *req)
*/
if (nblks < 1) {
scatterwalk_map_and_copy(rctx->residue.buf + rctx->residue.size,
rctx->src_sg, 0, req->nbytes, 0);
rctx->src_sg, 0, req->nbytes, 0);
rctx->residue.size += req->nbytes;
return 0;
}
rctx->datbuf.buf = dma_alloc_coherent(ctx->se->dev, rctx->datbuf.size,
&rctx->datbuf.addr, GFP_KERNEL);
if (!rctx->datbuf.buf)
return -ENOMEM;
/* Copy the previous residue first */
if (rctx->residue.size)
memcpy(rctx->datbuf.buf, rctx->residue.buf, rctx->residue.size);
scatterwalk_map_and_copy(rctx->datbuf.buf + rctx->residue.size,
rctx->src_sg, 0, req->nbytes - nresidue, 0);
rctx->src_sg, 0, req->nbytes - nresidue, 0);
scatterwalk_map_and_copy(rctx->residue.buf, rctx->src_sg,
req->nbytes - nresidue, nresidue, 0);
req->nbytes - nresidue, nresidue, 0);
/* Update residue value with the residue after current block */
rctx->residue.size = nresidue;
@@ -356,30 +333,9 @@ static int tegra_sha_do_update(struct ahash_request *req)
rctx->config = tegra_sha_get_config(rctx->alg) |
SE_SHA_DST_HASH_REG;
/*
* If this is not the first 'update' call, paste the previous copied
* intermediate results to the registers so that it gets picked up.
* This is to support the import/export functionality.
*/
if (!(rctx->task & SHA_FIRST))
tegra_sha_paste_hash_result(ctx->se, rctx);
size = tegra_sha_prep_cmd(ctx->se, cpuvaddr, rctx);
ret = tegra_se_host1x_submit(ctx->se, ctx->se->cmdbuf, size);
/*
* If this is not the final update, copy the intermediate results
* from the registers so that it can be used in the next 'update'
* call. This is to support the import/export functionality.
*/
if (!(rctx->task & SHA_FINAL))
tegra_sha_copy_hash_result(ctx->se, rctx);
dma_free_coherent(ctx->se->dev, rctx->datbuf.size,
rctx->datbuf.buf, rctx->datbuf.addr);
return ret;
return tegra_se_host1x_submit(ctx->se, size);
}
static int tegra_sha_do_final(struct ahash_request *req)
@@ -391,25 +347,16 @@ static int tegra_sha_do_final(struct ahash_request *req)
u32 *cpuvaddr = se->cmdbuf->addr;
int size, ret = 0;
memcpy(rctx->datbuf.buf, rctx->residue.buf, rctx->residue.size);
rctx->datbuf.size = rctx->residue.size;
rctx->total_len += rctx->residue.size;
rctx->config = tegra_sha_get_config(rctx->alg) |
SE_SHA_DST_MEMORY;
if (rctx->residue.size) {
rctx->datbuf.buf = dma_alloc_coherent(se->dev, rctx->residue.size,
&rctx->datbuf.addr, GFP_KERNEL);
if (!rctx->datbuf.buf) {
ret = -ENOMEM;
goto out_free;
}
memcpy(rctx->datbuf.buf, rctx->residue.buf, rctx->residue.size);
}
size = tegra_sha_prep_cmd(se, cpuvaddr, rctx);
ret = tegra_se_host1x_submit(se, se->cmdbuf, size);
ret = tegra_se_host1x_submit(se, size);
if (ret)
goto out;
@@ -417,14 +364,12 @@ static int tegra_sha_do_final(struct ahash_request *req)
memcpy(req->result, rctx->digest.buf, rctx->digest.size);
out:
if (rctx->residue.size)
dma_free_coherent(se->dev, rctx->datbuf.size,
rctx->datbuf.buf, rctx->datbuf.addr);
out_free:
dma_free_coherent(se->dev, SE_SHA_BUFLEN,
rctx->datbuf.buf, rctx->datbuf.addr);
dma_free_coherent(se->dev, crypto_ahash_blocksize(tfm),
rctx->residue.buf, rctx->residue.addr);
rctx->residue.buf, rctx->residue.addr);
dma_free_coherent(se->dev, rctx->digest.size, rctx->digest.buf,
rctx->digest.addr);
rctx->digest.addr);
return ret;
}
@@ -435,7 +380,7 @@ static int tegra_sha_do_one_req(struct crypto_engine *engine, void *areq)
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);
struct tegra_se *se = ctx->se;
int ret = 0;
int ret = -EINVAL;
if (rctx->task & SHA_UPDATE) {
ret = tegra_sha_do_update(req);
@@ -449,73 +394,50 @@ static int tegra_sha_do_one_req(struct crypto_engine *engine, void *areq)
crypto_finalize_hash_request(se->engine, req, ret);
return 0;
return ret;
}
static void tegra_sha_init_fallback(struct crypto_ahash *tfm, struct tegra_sha_ctx *ctx,
const char *algname)
static void tegra_sha_init_fallback(struct tegra_sha_ctx *ctx, const char *algname)
{
unsigned int statesize;
ctx->fallback_tfm = crypto_alloc_ahash(algname, 0, CRYPTO_ALG_ASYNC |
CRYPTO_ALG_NEED_FALLBACK);
if (IS_ERR(ctx->fallback_tfm)) {
dev_warn(ctx->se->dev,
"failed to allocate fallback for %s\n", algname);
dev_warn(ctx->se->dev, "failed to allocate fallback for %s %ld\n",
algname, PTR_ERR(ctx->fallback_tfm));
ctx->fallback_tfm = NULL;
return;
}
statesize = crypto_ahash_statesize(ctx->fallback_tfm);
if (statesize > sizeof(struct tegra_sha_reqctx))
crypto_hash_alg_common(tfm)->statesize = statesize;
/* Update reqsize if fallback is added */
crypto_ahash_set_reqsize(tfm,
sizeof(struct tegra_sha_reqctx) +
crypto_ahash_reqsize(ctx->fallback_tfm));
}
static int tegra_sha_cra_init(struct crypto_tfm *tfm)
{
struct tegra_sha_ctx *ctx = crypto_tfm_ctx(tfm);
struct crypto_ahash *ahash_tfm = __crypto_ahash_cast(tfm);
struct ahash_alg *alg = __crypto_ahash_alg(tfm->__crt_alg);
struct tegra_se_alg *se_alg;
const char *algname;
int ret;
algname = crypto_tfm_alg_name(tfm);
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
se_alg = container_of(alg, struct tegra_se_alg, alg.ahash.base);
#else
se_alg = container_of(alg, struct tegra_se_alg, alg.ahash);
#endif
crypto_ahash_set_reqsize(ahash_tfm, sizeof(struct tegra_sha_reqctx));
crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
sizeof(struct tegra_sha_reqctx));
ctx->se = se_alg->se_dev;
ctx->fallback = false;
ctx->key_id = 0;
ret = se_algname_to_algid(algname);
if (ret < 0) {
dev_err(ctx->se->dev, "invalid algorithm\n");
return ret;
}
ctx->alg = se_algname_to_algid(algname);
#ifndef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
ctx->enginectx.op.prepare_request = NULL;
ctx->enginectx.op.do_one_request = tegra_sha_do_one_req;
ctx->enginectx.op.unprepare_request = NULL;
#endif
if (se_alg->alg_base)
tegra_sha_init_fallback(ahash_tfm, ctx, algname);
ctx->alg = ret;
#ifndef NV_CRYPTO_ENGINE_OPS_PRESENT
ctx->enginectx.op.prepare_request = NULL;
ctx->enginectx.op.unprepare_request = NULL;
ctx->enginectx.op.do_one_request = tegra_sha_do_one_req;
#endif
tegra_sha_init_fallback(ctx, algname);
return 0;
}
@@ -527,7 +449,7 @@ static void tegra_sha_cra_exit(struct crypto_tfm *tfm)
if (ctx->fallback_tfm)
crypto_free_ahash(ctx->fallback_tfm);
tegra_key_invalidate(ctx->se, ctx->key_id, ctx->alg);
tegra_key_invalidate(ctx->se, ctx->key_id);
}
static int tegra_sha_init(struct ahash_request *req)
@@ -536,34 +458,45 @@ static int tegra_sha_init(struct ahash_request *req)
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);
struct tegra_se *se = ctx->se;
const char *algname;
if (ctx->fallback)
return tegra_sha_fallback_init(req);
algname = crypto_tfm_alg_name(&tfm->base);
rctx->total_len = 0;
rctx->datbuf.size = 0;
rctx->residue.size = 0;
rctx->key_id = ctx->key_id;
rctx->task = SHA_FIRST;
rctx->alg = ctx->alg;
rctx->alg = se_algname_to_algid(algname);
rctx->blk_size = crypto_ahash_blocksize(tfm);
rctx->digest.size = crypto_ahash_digestsize(tfm);
rctx->digest.buf = dma_alloc_coherent(se->dev, rctx->digest.size,
&rctx->digest.addr, GFP_KERNEL);
&rctx->digest.addr, GFP_KERNEL);
if (!rctx->digest.buf)
goto digbuf_fail;
rctx->residue.buf = dma_alloc_coherent(se->dev, rctx->blk_size,
&rctx->residue.addr, GFP_KERNEL);
&rctx->residue.addr, GFP_KERNEL);
if (!rctx->residue.buf)
goto resbuf_fail;
rctx->datbuf.buf = dma_alloc_coherent(se->dev, SE_SHA_BUFLEN,
&rctx->datbuf.addr, GFP_KERNEL);
if (!rctx->datbuf.buf)
goto datbuf_fail;
return 0;
datbuf_fail:
dma_free_coherent(se->dev, rctx->blk_size, rctx->residue.buf,
rctx->residue.addr);
resbuf_fail:
dma_free_coherent(se->dev, rctx->digest.size, rctx->digest.buf,
rctx->digest.addr);
dma_free_coherent(se->dev, SE_SHA_BUFLEN, rctx->datbuf.buf,
rctx->datbuf.addr);
digbuf_fail:
return -ENOMEM;
}
@@ -572,7 +505,7 @@ static int tegra_hmac_fallback_setkey(struct tegra_sha_ctx *ctx, const u8 *key,
unsigned int keylen)
{
if (!ctx->fallback_tfm) {
dev_dbg(ctx->se->dev, "invalid key length (%d)\n", keylen);
dev_err(ctx->se->dev, "invalid key length\n");
return -EINVAL;
}
@@ -584,18 +517,13 @@ static int tegra_hmac_setkey(struct crypto_ahash *tfm, const u8 *key,
unsigned int keylen)
{
struct tegra_sha_ctx *ctx = crypto_ahash_ctx(tfm);
int ret;
if (aes_check_keylen(keylen))
return tegra_hmac_fallback_setkey(ctx, key, keylen);
ctx->fallback = false;
ret = tegra_key_submit(ctx->se, key, keylen, ctx->alg, &ctx->key_id);
if (ret)
return tegra_hmac_fallback_setkey(ctx, key, keylen);
return 0;
return tegra_key_submit(ctx->se, key, keylen, ctx->alg, &ctx->key_id);
}
static int tegra_sha_update(struct ahash_request *req)
@@ -665,6 +593,9 @@ static int tegra_sha_export(struct ahash_request *req, void *out)
return tegra_sha_fallback_export(req, out);
memcpy(out, rctx, sizeof(*rctx));
/*
* TODO: Copy HASH_RESULT registers as well.
*/
return 0;
}
@@ -686,7 +617,7 @@ static int tegra_sha_import(struct ahash_request *req, const void *in)
static struct tegra_se_alg tegra_hash_algs[] = {
{
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
.base = {
#endif
.init = tegra_sha_init,
@@ -698,6 +629,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.import = tegra_sha_import,
.halg.digestsize = SHA1_DIGEST_SIZE,
.halg.statesize = sizeof(struct tegra_sha_reqctx),
.halg.base = {
.cra_name = "sha1",
.cra_driver_name = "tegra-se-sha1",
@@ -710,14 +642,14 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_init = tegra_sha_cra_init,
.cra_exit = tegra_sha_cra_exit,
}
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
.base = {
#endif
.init = tegra_sha_init,
@@ -729,6 +661,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.import = tegra_sha_import,
.halg.digestsize = SHA224_DIGEST_SIZE,
.halg.statesize = sizeof(struct tegra_sha_reqctx),
.halg.base = {
.cra_name = "sha224",
.cra_driver_name = "tegra-se-sha224",
@@ -741,14 +674,14 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_init = tegra_sha_cra_init,
.cra_exit = tegra_sha_cra_exit,
}
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
.base = {
#endif
.init = tegra_sha_init,
@@ -760,6 +693,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.import = tegra_sha_import,
.halg.digestsize = SHA256_DIGEST_SIZE,
.halg.statesize = sizeof(struct tegra_sha_reqctx),
.halg.base = {
.cra_name = "sha256",
.cra_driver_name = "tegra-se-sha256",
@@ -772,14 +706,14 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_init = tegra_sha_cra_init,
.cra_exit = tegra_sha_cra_exit,
}
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
.base = {
#endif
.init = tegra_sha_init,
@@ -791,6 +725,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.import = tegra_sha_import,
.halg.digestsize = SHA384_DIGEST_SIZE,
.halg.statesize = sizeof(struct tegra_sha_reqctx),
.halg.base = {
.cra_name = "sha384",
.cra_driver_name = "tegra-se-sha384",
@@ -803,14 +738,14 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_init = tegra_sha_cra_init,
.cra_exit = tegra_sha_cra_exit,
}
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
.base = {
#endif
.init = tegra_sha_init,
@@ -822,6 +757,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.import = tegra_sha_import,
.halg.digestsize = SHA512_DIGEST_SIZE,
.halg.statesize = sizeof(struct tegra_sha_reqctx),
.halg.base = {
.cra_name = "sha512",
.cra_driver_name = "tegra-se-sha512",
@@ -834,14 +770,14 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_init = tegra_sha_cra_init,
.cra_exit = tegra_sha_cra_exit,
}
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
.base = {
#endif
.init = tegra_sha_init,
@@ -853,6 +789,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.import = tegra_sha_import,
.halg.digestsize = SHA3_224_DIGEST_SIZE,
.halg.statesize = sizeof(struct tegra_sha_reqctx),
.halg.base = {
.cra_name = "sha3-224",
.cra_driver_name = "tegra-se-sha3-224",
@@ -865,14 +802,14 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_init = tegra_sha_cra_init,
.cra_exit = tegra_sha_cra_exit,
}
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
.base = {
#endif
.init = tegra_sha_init,
@@ -884,6 +821,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.import = tegra_sha_import,
.halg.digestsize = SHA3_256_DIGEST_SIZE,
.halg.statesize = sizeof(struct tegra_sha_reqctx),
.halg.base = {
.cra_name = "sha3-256",
.cra_driver_name = "tegra-se-sha3-256",
@@ -896,14 +834,14 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_init = tegra_sha_cra_init,
.cra_exit = tegra_sha_cra_exit,
}
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
.base = {
#endif
.init = tegra_sha_init,
@@ -915,6 +853,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.import = tegra_sha_import,
.halg.digestsize = SHA3_384_DIGEST_SIZE,
.halg.statesize = sizeof(struct tegra_sha_reqctx),
.halg.base = {
.cra_name = "sha3-384",
.cra_driver_name = "tegra-se-sha3-384",
@@ -927,14 +866,14 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_init = tegra_sha_cra_init,
.cra_exit = tegra_sha_cra_exit,
}
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
.base = {
#endif
.init = tegra_sha_init,
@@ -946,6 +885,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.import = tegra_sha_import,
.halg.digestsize = SHA3_512_DIGEST_SIZE,
.halg.statesize = sizeof(struct tegra_sha_reqctx),
.halg.base = {
.cra_name = "sha3-512",
.cra_driver_name = "tegra-se-sha3-512",
@@ -958,7 +898,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_init = tegra_sha_cra_init,
.cra_exit = tegra_sha_cra_exit,
}
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
@@ -966,7 +906,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
}, {
.alg_base = "sha224",
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
.base = {
#endif
.init = tegra_sha_init,
@@ -979,6 +919,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.setkey = tegra_hmac_setkey,
.halg.digestsize = SHA224_DIGEST_SIZE,
.halg.statesize = sizeof(struct tegra_sha_reqctx),
.halg.base = {
.cra_name = "hmac(sha224)",
.cra_driver_name = "tegra-se-hmac-sha224",
@@ -991,7 +932,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_init = tegra_sha_cra_init,
.cra_exit = tegra_sha_cra_exit,
}
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
@@ -999,7 +940,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
}, {
.alg_base = "sha256",
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
.base = {
#endif
.init = tegra_sha_init,
@@ -1012,6 +953,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.setkey = tegra_hmac_setkey,
.halg.digestsize = SHA256_DIGEST_SIZE,
.halg.statesize = sizeof(struct tegra_sha_reqctx),
.halg.base = {
.cra_name = "hmac(sha256)",
.cra_driver_name = "tegra-se-hmac-sha256",
@@ -1024,7 +966,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_init = tegra_sha_cra_init,
.cra_exit = tegra_sha_cra_exit,
}
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
@@ -1032,7 +974,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
}, {
.alg_base = "sha384",
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
.base = {
#endif
.init = tegra_sha_init,
@@ -1045,6 +987,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.setkey = tegra_hmac_setkey,
.halg.digestsize = SHA384_DIGEST_SIZE,
.halg.statesize = sizeof(struct tegra_sha_reqctx),
.halg.base = {
.cra_name = "hmac(sha384)",
.cra_driver_name = "tegra-se-hmac-sha384",
@@ -1057,7 +1000,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_init = tegra_sha_cra_init,
.cra_exit = tegra_sha_cra_exit,
}
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
@@ -1065,7 +1008,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
}, {
.alg_base = "sha512",
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
.base = {
#endif
.init = tegra_sha_init,
@@ -1078,6 +1021,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.setkey = tegra_hmac_setkey,
.halg.digestsize = SHA512_DIGEST_SIZE,
.halg.statesize = sizeof(struct tegra_sha_reqctx),
.halg.base = {
.cra_name = "hmac(sha512)",
.cra_driver_name = "tegra-se-hmac-sha512",
@@ -1090,7 +1034,7 @@ static struct tegra_se_alg tegra_hash_algs[] = {
.cra_init = tegra_sha_cra_init,
.cra_exit = tegra_sha_cra_exit,
}
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
@@ -1133,32 +1077,28 @@ static int tegra_hash_kac_manifest(u32 user, u32 alg, u32 keylen)
int tegra_init_hash(struct tegra_se *se)
{
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
struct ahash_engine_alg *alg;
#else
struct ahash_alg *alg;
#endif
int i, ret;
se->manifest = tegra_hash_kac_manifest;
for (i = 0; i < ARRAY_SIZE(tegra_hash_algs); i++) {
tegra_hash_algs[i].se_dev = se;
alg = &tegra_hash_algs[i].alg.ahash;
ret = CRYPTO_REGISTER(ahash, alg);
tegra_hash_algs[i].se_dev = se;
ret = CRYPTO_REGISTER(ahash, &tegra_hash_algs[i].alg.ahash);
if (ret) {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
dev_err(se->dev, "failed to register %s\n",
alg->base.halg.base.cra_name);
tegra_hash_algs[i].alg.ahash.base.halg.base.cra_name);
#else
dev_err(se->dev, "failed to register %s\n",
alg->halg.base.cra_name);
tegra_hash_algs[i].alg.ahash.halg.base.cra_name);
#endif
goto sha_err;
}
}
dev_info(se->dev, "registered HASH algorithms\n");
return 0;
sha_err:
@@ -1168,7 +1108,8 @@ sha_err:
return ret;
}
void tegra_deinit_hash(struct tegra_se *se)
void tegra_deinit_hash(void)
{
int i;

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Crypto driver file to manage keys of NVIDIA Security Engine.
*/
@@ -16,77 +16,66 @@
#define SE_KEY_RSVD_MASK (BIT(0) | BIT(14) | BIT(15))
#define SE_KEY_VALID_MASK (SE_KEY_FULL_MASK & ~SE_KEY_RSVD_MASK)
/* Mutex lock to guard keyslots */
static DEFINE_MUTEX(kslt_lock);
/* Keyslot bitmask (0 = available, 1 = in use/not available) */
static u16 tegra_se_keyslots = SE_KEY_RSVD_MASK;
static u16 tegra_keyslot_alloc(void)
{
u16 keyid;
mutex_lock(&kslt_lock);
/* Check if all key slots are full */
if (tegra_se_keyslots == GENMASK(SE_MAX_KEYSLOT, 0)) {
mutex_unlock(&kslt_lock);
if (tegra_se_keyslots == GENMASK(SE_MAX_KEYSLOT, 0))
return 0;
}
keyid = ffz(tegra_se_keyslots);
tegra_se_keyslots |= BIT(keyid);
mutex_unlock(&kslt_lock);
return keyid;
}
static void tegra_keyslot_free(u16 slot)
{
mutex_lock(&kslt_lock);
tegra_se_keyslots &= ~(BIT(slot));
mutex_unlock(&kslt_lock);
}
static unsigned int tegra_key_prep_ins_cmd(struct tegra_se *se, u32 *cpuvaddr,
const u32 *key, u32 keylen, u16 slot, u32 alg)
const u32 *key, u32 keylen, u16 slot, u32 alg)
{
int i = 0, j;
cpuvaddr[i++] = host1x_opcode_setpayload(1);
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->op);
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->op);
cpuvaddr[i++] = SE_AES_OP_WRSTALL | SE_AES_OP_DUMMY;
cpuvaddr[i++] = host1x_opcode_setpayload(1);
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->manifest);
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->manifest);
cpuvaddr[i++] = se->manifest(se->owner, alg, keylen);
cpuvaddr[i++] = host1x_opcode_setpayload(1);
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_dst);
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->key_dst);
cpuvaddr[i++] = SE_AES_KEY_DST_INDEX(slot);
for (j = 0; j < keylen / 4; j++) {
/* Set key address */
cpuvaddr[i++] = host1x_opcode_setpayload(1);
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_addr);
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->key_addr);
cpuvaddr[i++] = j;
/* Set key data */
cpuvaddr[i++] = host1x_opcode_setpayload(1);
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_data);
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->key_data);
cpuvaddr[i++] = key[j];
}
cpuvaddr[i++] = host1x_opcode_setpayload(1);
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->config);
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->config);
cpuvaddr[i++] = SE_CFG_INS;
cpuvaddr[i++] = host1x_opcode_setpayload(1);
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->op);
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->op);
cpuvaddr[i++] = SE_AES_OP_WRSTALL | SE_AES_OP_START |
SE_AES_OP_LASTBUF;
cpuvaddr[i++] = se_host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
cpuvaddr[i++] = host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
cpuvaddr[i++] = host1x_uclass_incr_syncpt_cond_f(1) |
host1x_uclass_incr_syncpt_indx_f(se->syncpt_id);
@@ -98,44 +87,29 @@ static unsigned int tegra_key_prep_ins_cmd(struct tegra_se *se, u32 *cpuvaddr,
static bool tegra_key_in_kslt(u32 keyid)
{
bool ret;
if (keyid > SE_MAX_KEYSLOT)
return false;
mutex_lock(&kslt_lock);
ret = ((BIT(keyid) & SE_KEY_VALID_MASK) &&
return ((BIT(keyid) & SE_KEY_VALID_MASK) &&
(BIT(keyid) & tegra_se_keyslots));
mutex_unlock(&kslt_lock);
return ret;
}
static int tegra_key_insert(struct tegra_se *se, const u8 *key,
u32 keylen, u16 slot, u32 alg)
u32 keylen, u16 slot, u32 alg)
{
const u32 *keyval = (u32 *)key;
u32 *addr = se->keybuf->addr, size;
int ret;
u32 *addr = se->cmdbuf->addr, size;
mutex_lock(&kslt_lock);
size = tegra_key_prep_ins_cmd(se, addr, keyval, keylen, slot, alg);
ret = tegra_se_host1x_submit(se, se->keybuf, size);
mutex_unlock(&kslt_lock);
return ret;
return tegra_se_host1x_submit(se, size);
}
void tegra_key_invalidate(struct tegra_se *se, u32 keyid, u32 alg)
void tegra_key_invalidate(struct tegra_se *se, u32 keyid)
{
u8 zkey[AES_MAX_KEY_SIZE] = {0};
if (!keyid)
return;
/* Overwrite the key with 0s */
tegra_key_insert(se, zkey, AES_MAX_KEY_SIZE, keyid, alg);
tegra_keyslot_free(keyid);
}
@@ -146,10 +120,8 @@ int tegra_key_submit(struct tegra_se *se, const u8 *key, u32 keylen, u32 alg, u3
/* Use the existing slot if it is already allocated */
if (!tegra_key_in_kslt(*keyid)) {
*keyid = tegra_keyslot_alloc();
if (!(*keyid)) {
dev_dbg(se->dev, "failed to allocate key slot\n");
if (!(*keyid))
return -ENOMEM;
}
}
ret = tegra_key_insert(se, key, keylen, *keyid, alg);
@@ -158,20 +130,3 @@ int tegra_key_submit(struct tegra_se *se, const u8 *key, u32 keylen, u32 alg, u3
return 0;
}
void tegra_key_invalidate_reserved(struct tegra_se *se, u32 keyid, u32 alg)
{
u8 zkey[AES_MAX_KEY_SIZE] = {0};
if (!keyid)
return;
/* Overwrite the key with 0s */
tegra_key_insert(se, zkey, AES_MAX_KEY_SIZE, keyid, alg);
}
inline int tegra_key_submit_reserved(struct tegra_se *se, const u8 *key,
u32 keylen, u32 alg, u32 *keyid)
{
return tegra_key_insert(se, key, keylen, *keyid, alg);
}

View File

@@ -1,13 +1,12 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Crypto driver for NVIDIA Security Engine in Tegra Chips
*/
#include <nvidia/conftest.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/host1x-next.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
@@ -125,7 +124,7 @@ static struct tegra_se_cmdbuf *tegra_se_host1x_bo_alloc(struct tegra_se *se, ssi
struct tegra_se_cmdbuf *cmdbuf;
struct device *dev = se->dev->parent;
cmdbuf = kzalloc(sizeof(*cmdbuf), GFP_KERNEL);
cmdbuf = kzalloc(sizeof(struct tegra_se_cmdbuf), GFP_KERNEL);
if (!cmdbuf)
return NULL;
@@ -143,7 +142,7 @@ static struct tegra_se_cmdbuf *tegra_se_host1x_bo_alloc(struct tegra_se *se, ssi
return cmdbuf;
}
int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf, u32 size)
int tegra_se_host1x_submit(struct tegra_se *se, u32 size)
{
struct host1x_job *job;
int ret;
@@ -154,7 +153,7 @@ int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf,
return -ENOMEM;
}
job->syncpt = host1x_syncpt_get(se->syncpt);
job->syncpt = host1x_syncpt_get(se->syncpt);
job->syncpt_incrs = 1;
job->client = &se->client;
job->class = se->client.class;
@@ -162,24 +161,24 @@ int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf,
job->engine_fallback_streamid = se->stream_id;
job->engine_streamid_offset = SE_STREAM_ID;
cmdbuf->words = size;
se->cmdbuf->words = size;
host1x_job_add_gather(job, &cmdbuf->bo, size, 0);
host1x_job_add_gather(job, &se->cmdbuf->bo, size, 0);
ret = host1x_job_pin(job, se->dev);
if (ret) {
dev_err(se->dev, "failed to pin host1x job\n");
goto job_put;
goto err_job_pin;
}
ret = host1x_job_submit(job);
if (ret) {
dev_err(se->dev, "failed to submit host1x job\n");
goto job_unpin;
goto err_job_submit;
}
ret = host1x_syncpt_wait(job->syncpt, job->syncpt_end,
MAX_SCHEDULE_TIMEOUT, NULL);
MAX_SCHEDULE_TIMEOUT, NULL);
if (ret) {
dev_err(se->dev, "host1x job timed out\n");
return ret;
@@ -188,9 +187,9 @@ int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf,
host1x_job_put(job);
return 0;
job_unpin:
err_job_submit:
host1x_job_unpin(job);
job_put:
err_job_pin:
host1x_job_put(job);
return ret;
@@ -211,7 +210,7 @@ static int tegra_se_client_init(struct host1x_client *client)
if (!se->syncpt) {
dev_err(se->dev, "host1x syncpt allocation failed\n");
ret = -EINVAL;
goto channel_put;
goto err_syncpt;
}
se->syncpt_id = host1x_syncpt_id(se->syncpt);
@@ -219,30 +218,22 @@ static int tegra_se_client_init(struct host1x_client *client)
se->cmdbuf = tegra_se_host1x_bo_alloc(se, SZ_4K);
if (!se->cmdbuf) {
ret = -ENOMEM;
goto syncpt_put;
}
se->keybuf = tegra_se_host1x_bo_alloc(se, SZ_4K);
if (!se->cmdbuf) {
ret = -ENOMEM;
goto cmdbuf_put;
goto err_bo;
}
ret = se->hw->init_alg(se);
if (ret) {
dev_err(se->dev, "failed to register algorithms\n");
goto keybuf_put;
goto err_alg_reg;
}
return 0;
keybuf_put:
tegra_se_cmdbuf_put(&se->keybuf->bo);
cmdbuf_put:
err_alg_reg:
tegra_se_cmdbuf_put(&se->cmdbuf->bo);
syncpt_put:
err_bo:
host1x_syncpt_put(se->syncpt);
channel_put:
err_syncpt:
host1x_channel_put(se->channel);
return ret;
@@ -252,7 +243,7 @@ static int tegra_se_client_deinit(struct host1x_client *client)
{
struct tegra_se *se = container_of(client, struct tegra_se, client);
se->hw->deinit_alg(se);
se->hw->deinit_alg();
tegra_se_cmdbuf_put(&se->cmdbuf->bo);
host1x_syncpt_put(se->syncpt);
host1x_channel_put(se->channel);
@@ -265,7 +256,7 @@ static const struct host1x_client_ops tegra_se_client_ops = {
.exit = tegra_se_client_deinit,
};
static int tegra_se_host1x_register(struct tegra_se *se)
int tegra_se_host1x_register(struct tegra_se *se)
{
INIT_LIST_HEAD(&se->client.list);
se->client.dev = se->dev;
@@ -278,6 +269,38 @@ static int tegra_se_host1x_register(struct tegra_se *se)
return 0;
}
static int tegra_se_clk_init(struct tegra_se *se)
{
int i, ret;
se->num_clks = devm_clk_bulk_get_all(se->dev, &se->clks);
if (se->num_clks < 0) {
dev_err(se->dev, "failed to get clocks\n");
return se->num_clks;
}
for (i = 0; i < se->num_clks; i++) {
ret = clk_set_rate(se->clks[i].clk, ULONG_MAX);
if (ret) {
dev_err(se->dev, "failed to set %d clock rate", i);
return ret;
}
}
ret = clk_bulk_prepare_enable(se->num_clks, se->clks);
if (ret) {
dev_err(se->dev, "failed to enable clocks\n");
return ret;
}
return 0;
}
static void tegra_se_clk_deinit(struct tegra_se *se)
{
clk_bulk_disable_unprepare(se->num_clks, se->clks);
}
static int tegra_se_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -289,45 +312,61 @@ static int tegra_se_probe(struct platform_device *pdev)
return -ENOMEM;
se->dev = dev;
se->owner = TEGRA_GPSE_ID;
se->hw = device_get_match_data(&pdev->dev);
se->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(se->base))
return PTR_ERR(se->base);
se->owner = TEGRA_GPSE_ID;
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(39));
platform_set_drvdata(pdev, se);
se->clk = devm_clk_get_enabled(se->dev, NULL);
if (IS_ERR(se->clk))
return dev_err_probe(dev, PTR_ERR(se->clk),
"failed to enable clocks\n");
ret = tegra_se_clk_init(se);
if (ret) {
dev_err(dev, "failed to init clocks\n");
return ret;
}
if (!tegra_dev_iommu_get_stream_id(dev, &se->stream_id))
return dev_err_probe(dev, -ENODEV,
"failed to get IOMMU stream ID\n");
if (!tegra_dev_iommu_get_stream_id(dev, &se->stream_id)) {
dev_err(dev, "failed to get IOMMU stream ID\n");
goto err_iommu_spec;
}
writel(se->stream_id, se->base + SE_STREAM_ID);
se_writel(se, se->stream_id, SE_STREAM_ID);
se->engine = crypto_engine_alloc_init(dev, 0);
if (!se->engine)
return dev_err_probe(dev, -ENOMEM, "failed to init crypto engine\n");
if (!se->engine) {
dev_err(dev, "failed to init crypto engine\n");
ret = -ENOMEM;
goto err_engine_alloc;
}
ret = crypto_engine_start(se->engine);
if (ret) {
crypto_engine_exit(se->engine);
return dev_err_probe(dev, ret, "failed to start crypto engine\n");
dev_err(dev, "failed to start crypto engine\n");
goto err_engine_start;
}
ret = tegra_se_host1x_register(se);
if (ret) {
crypto_engine_stop(se->engine);
crypto_engine_exit(se->engine);
return dev_err_probe(dev, ret, "failed to init host1x params\n");
dev_err(dev, "failed to init host1x params\n");
goto err_host1x_init;
}
return 0;
err_host1x_init:
crypto_engine_stop(se->engine);
err_engine_start:
crypto_engine_exit(se->engine);
err_engine_alloc:
iommu_fwspec_free(se->dev);
err_iommu_spec:
tegra_se_clk_deinit(se);
return ret;
}
static int tegra_se_remove(struct platform_device *pdev)
@@ -338,6 +377,7 @@ static int tegra_se_remove(struct platform_device *pdev)
crypto_engine_exit(se->engine);
iommu_fwspec_free(se->dev);
host1x_client_unregister(&se->client);
tegra_se_clk_deinit(se);
return 0;
}
@@ -384,35 +424,23 @@ static const struct tegra_se_hw tegra234_hash_hw = {
static const struct of_device_id tegra_se_of_match[] = {
{
.compatible = "nvidia,tegra234-se-aes",
.compatible = "nvidia,tegra234-se2-aes",
.data = &tegra234_aes_hw
}, {
.compatible = "nvidia,tegra234-se-hash",
.compatible = "nvidia,tegra234-se4-hash",
.data = &tegra234_hash_hw,
},
{ },
};
MODULE_DEVICE_TABLE(of, tegra_se_of_match);
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_se_remove_wrapper(struct platform_device *pdev)
{
tegra_se_remove(pdev);
}
#else
static int tegra_se_remove_wrapper(struct platform_device *pdev)
{
return tegra_se_remove(pdev);
}
#endif
static struct platform_driver tegra_se_driver = {
.driver = {
.name = "tegra-se",
.of_match_table = tegra_se_of_match,
},
.probe = tegra_se_probe,
.remove = tegra_se_remove_wrapper,
.remove = tegra_se_remove,
};
static int tegra_se_host1x_probe(struct host1x_device *dev)
@@ -458,4 +486,4 @@ module_exit(tegra_se_module_exit);
MODULE_DESCRIPTION("NVIDIA Tegra Security Engine Driver");
MODULE_AUTHOR("Akhil R <akhilrajeev@nvidia.com>");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Header file for NVIDIA Security Engine driver.
*/
@@ -7,18 +7,22 @@
#ifndef _TEGRA_SE_H
#define _TEGRA_SE_H
#include <nvidia/conftest.h>
#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/iommu.h>
#include <linux/host1x-next.h>
#include <linux/version.h>
#include <crypto/aead.h>
#include <crypto/engine.h>
#include <crypto/hash.h>
#include <crypto/sha1.h>
#include <crypto/sha3.h>
#include <crypto/sm3.h>
#include <crypto/skcipher.h>
#include <nvidia/conftest.h>
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
#include <crypto/engine.h>
#endif
#define SE_MAX_INSTANCES 3
#define SE_OWNERSHIP 0x14
#define SE_OWNERSHIP_UID(x) FIELD_GET(GENMASK(7, 0), x)
#define TEGRA_GPSE_ID 3
@@ -63,8 +67,11 @@
#define SE_SHA_ENC_ALG_HMAC SE_SHA_CFG_ENC_ALG(7)
#define SE_SHA_ENC_ALG_KDF SE_SHA_CFG_ENC_ALG(8)
#define SE_SHA_ENC_ALG_KEY_INVLD SE_SHA_CFG_ENC_ALG(10)
#define SE_SHA_ENC_ALG_KEY_MOV SE_SHA_CFG_ENC_ALG(11)
#define SE_SHA_ENC_ALG_KEY_INQUIRE SE_SHA_CFG_ENC_ALG(12)
#define SE_SHA_ENC_ALG_INS SE_SHA_CFG_ENC_ALG(13)
#define SE_SHA_ENC_ALG_CLONE SE_SHA_CFG_ENC_ALG(14)
#define SE_SHA_ENC_ALG_LOCK SE_SHA_CFG_ENC_ALG(15)
#define SE_SHA_OP_LASTBUF FIELD_PREP(BIT(16), 1)
#define SE_SHA_OP_WRSTALL FIELD_PREP(BIT(15), 1)
@@ -304,6 +311,12 @@
SE_AES_CORE_SEL_DECRYPT | \
SE_AES_IV_SEL_REG)
#define SE_CRYPTO_CFG_OFB (SE_AES_INPUT_SEL_AESOUT | \
SE_AES_VCTRAM_SEL_MEMORY | \
SE_AES_XOR_POS_BOTTOM | \
SE_AES_CORE_SEL_ENCRYPT | \
SE_AES_IV_SEL_REG)
#define SE_CRYPTO_CFG_CTR (SE_AES_INPUT_SEL_LINEAR_CTR | \
SE_AES_VCTRAM_SEL_MEMORY | \
SE_AES_XOR_POS_BOTTOM | \
@@ -342,26 +355,25 @@
#define SE_CRYPTO_CTR_REG_COUNT 4
#define SE_MAX_KEYSLOT 15
#define SE_MAX_MEM_ALLOC SZ_4M
#define TEGRA_AES_RESERVED_KSLT 14
#define TEGRA_XTS_RESERVED_KSLT 15
#define SE_AES_BUFLEN 0x8000
#define SE_SHA_BUFLEN SZ_4M
#define SHA_FIRST BIT(0)
#define SHA_UPDATE BIT(1)
#define SHA_FINAL BIT(2)
#if NV_IS_EXPORT_SYMBOL_PRESENT_crypto_engine_register_aead /* Linux v6.6 */
#define NV_CRYPTO_ENGINE_OPS_PRESENT
#endif
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
#define CRYPTO_REGISTER(alg, x) \
crypto_engine_register_##alg(x)
#define CRYPTO_UNREGISTER(alg, x) \
crypto_engine_unregister_##alg(x)
#else
#define CRYPTO_REGISTER(alg, x) \
crypto_register_##alg(x)
#endif
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
#define CRYPTO_UNREGISTER(alg, x) \
crypto_engine_unregister_##alg(x)
#else
#define CRYPTO_UNREGISTER(alg, x) \
crypto_unregister_##alg(x)
#endif
@@ -371,6 +383,7 @@ enum se_aes_alg {
SE_ALG_CBC, /* Cipher Block Chaining (CBC) mode */
SE_ALG_ECB, /* Electronic Codebook (ECB) mode */
SE_ALG_CTR, /* Counter (CTR) mode */
SE_ALG_OFB, /* Output feedback (CFB) mode */
SE_ALG_XTS, /* XTS mode */
SE_ALG_GMAC, /* GMAC mode */
SE_ALG_GCM, /* GCM mode */
@@ -403,14 +416,14 @@ struct tegra_se_alg {
const char *alg_base;
union {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
struct skcipher_engine_alg skcipher;
struct aead_engine_alg aead;
struct ahash_engine_alg ahash;
#ifndef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
struct skcipher_alg skcipher;
struct aead_alg aead;
struct ahash_alg ahash;
#else
struct skcipher_alg skcipher;
struct aead_alg aead;
struct ahash_alg ahash;
struct skcipher_engine_alg skcipher;
struct aead_engine_alg aead;
struct ahash_engine_alg ahash;
#endif
} alg;
};
@@ -433,7 +446,7 @@ struct tegra_se_regs {
struct tegra_se_hw {
const struct tegra_se_regs *regs;
int (*init_alg)(struct tegra_se *se);
void (*deinit_alg)(struct tegra_se *se);
void (*deinit_alg)(void);
bool support_sm_alg;
u32 host1x_class;
u32 kac_ver;
@@ -442,18 +455,18 @@ struct tegra_se_hw {
struct tegra_se {
int (*manifest)(u32 user, u32 alg, u32 keylen);
const struct tegra_se_hw *hw;
struct host1x_client client;
struct host1x_channel *channel;
struct tegra_se_cmdbuf *cmdbuf;
struct tegra_se_cmdbuf *keybuf;
struct crypto_engine *engine;
struct host1x_channel *channel;
struct host1x_client client;
struct host1x_syncpt *syncpt;
struct clk_bulk_data *clks;
struct tegra_se_cmdbuf *cmdbuf;
struct device *dev;
struct clk *clk;
unsigned int opcode_addr;
unsigned int stream_id;
unsigned int syncpt_id;
void __iomem *base;
int num_clks;
u32 owner;
};
@@ -463,8 +476,8 @@ struct tegra_se_cmdbuf {
struct device *dev;
struct kref ref;
struct host1x_bo bo;
ssize_t size;
u32 words;
ssize_t size;
};
struct tegra_se_datbuf {
@@ -479,6 +492,8 @@ static inline int se_algname_to_algid(const char *name)
return SE_ALG_CBC;
else if (!strcmp(name, "ecb(aes)"))
return SE_ALG_ECB;
else if (!strcmp(name, "ofb(aes)"))
return SE_ALG_OFB;
else if (!strcmp(name, "ctr(aes)"))
return SE_ALG_CTR;
else if (!strcmp(name, "xts(aes)"))
@@ -521,85 +536,87 @@ static inline int se_algname_to_algid(const char *name)
}
/* Functions */
int tegra_init_aead(struct tegra_se *se);
int tegra_init_aes(struct tegra_se *se);
int tegra_init_hash(struct tegra_se *se);
void tegra_deinit_aes(struct tegra_se *se);
void tegra_deinit_hash(struct tegra_se *se);
int tegra_key_submit(struct tegra_se *se, const u8 *key,
u32 keylen, u32 alg, u32 *keyid);
void tegra_key_invalidate(struct tegra_se *se, u32 keyid, u32 alg);
int tegra_key_submit_reserved(struct tegra_se *se, const u8 *key,
u32 keylen, u32 alg, u32 *keyid);
void tegra_key_invalidate_reserved(struct tegra_se *se, u32 keyid, u32 alg);
int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf, u32 size);
void tegra_deinit_aead(void);
void tegra_deinit_aes(void);
void tegra_deinit_hash(void);
int tegra_key_submit(struct tegra_se *se, const u8 *key, u32 keylen, u32 alg, u32 *keyid);
unsigned int tegra_key_get_idx(struct tegra_se *se, u32 keyid);
void tegra_key_invalidate(struct tegra_se *se, u32 keyid);
static inline int tegra_key_submit_reserved_aes(struct tegra_se *se, const u8 *key,
u32 keylen, u32 alg, u32 *keyid)
int tegra_se_host1x_register(struct tegra_se *se);
int tegra_se_host1x_submit(struct tegra_se *se, u32 size);
static inline void se_writel(struct tegra_se *se, unsigned int val,
unsigned int offset)
{
*keyid = TEGRA_AES_RESERVED_KSLT;
return tegra_key_submit_reserved(se, key, keylen, alg, keyid);
writel_relaxed(val, se->base + offset);
}
static inline int tegra_key_submit_reserved_xts(struct tegra_se *se, const u8 *key,
u32 keylen, u32 alg, u32 *keyid)
static inline u32 se_readl(struct tegra_se *se, unsigned int offset)
{
*keyid = TEGRA_XTS_RESERVED_KSLT;
return tegra_key_submit_reserved(se, key, keylen, alg, keyid);
return readl_relaxed(se->base + offset);
}
static inline bool tegra_key_is_reserved(u32 keyid)
{
return ((keyid == TEGRA_AES_RESERVED_KSLT) ||
(keyid == TEGRA_XTS_RESERVED_KSLT));
}
/* HOST1x OPCODES */
/****
*
* HOST1x OPCODES
*
****/
static inline u32 host1x_opcode_setpayload(unsigned int payload)
{
return (9 << 28) | payload;
}
static inline u32 host1x_opcode_incr_w(unsigned int offset)
#define host1x_opcode_incr_w(x) __host1x_opcode_incr_w((x) / 4)
static inline u32 __host1x_opcode_incr_w(unsigned int offset)
{
/* 22-bit offset supported */
return (10 << 28) | offset;
}
static inline u32 host1x_opcode_nonincr_w(unsigned int offset)
#define host1x_opcode_nonincr_w(x) __host1x_opcode_nonincr_w((x) / 4)
static inline u32 __host1x_opcode_nonincr_w(unsigned int offset)
{
/* 22-bit offset supported */
return (11 << 28) | offset;
}
static inline u32 host1x_opcode_incr(unsigned int offset, unsigned int count)
#define host1x_opcode_incr(x, y) __host1x_opcode_incr((x) / 4, y)
static inline u32 __host1x_opcode_incr(unsigned int offset, unsigned int count)
{
return (1 << 28) | (offset << 16) | count;
return (1 << 28) | (offset << 16) | count;
}
static inline u32 host1x_opcode_nonincr(unsigned int offset, unsigned int count)
#define host1x_opcode_nonincr(x, y) __host1x_opcode_nonincr((x) / 4, y)
static inline u32 __host1x_opcode_nonincr(unsigned int offset, unsigned int count)
{
return (2 << 28) | (offset << 16) | count;
return (2 << 28) | (offset << 16) | count;
}
static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v)
{
return (v & 0xff) << 10;
return (v & 0xff) << 10;
}
static inline u32 host1x_uclass_incr_syncpt_indx_f(u32 v)
{
return (v & 0x3ff) << 0;
return (v & 0x3ff) << 0;
}
static inline u32 host1x_uclass_wait_syncpt_r(void)
{
return 0x8;
return 0x8;
}
static inline u32 host1x_uclass_incr_syncpt_r(void)
{
return 0x0;
return 0x0;
}
#if !defined(NV_TEGRA_DEV_IOMMU_GET_STREAM_ID_PRESENT)
@@ -618,9 +635,4 @@ static inline bool tegra_dev_iommu_get_stream_id(struct device *dev, u32 *stream
}
#endif
#define se_host1x_opcode_incr_w(x) host1x_opcode_incr_w((x) / 4)
#define se_host1x_opcode_nonincr_w(x) host1x_opcode_nonincr_w((x) / 4)
#define se_host1x_opcode_incr(x, y) host1x_opcode_incr((x) / 4, y)
#define se_host1x_opcode_nonincr(x, y) host1x_opcode_nonincr((x) / 4, y)
#endif /*_TEGRA_SE_H*/

View File

@@ -1,10 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (c) 2023, NVIDIA Corporation. All rights reserved.
*/
#include <nvidia/conftest.h>
#include <linux/devfreq.h>
#include <linux/devfreq/tegra_wmark.h>
#include <linux/device.h>
@@ -15,7 +13,11 @@
#include <linux/slab.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0)
#include <drivers-private/devfreq/k519/governor.h>
#else
#include <drivers-private/devfreq/governor.h>
#endif
/**
* struct tegra_wmark_data - governor private data stored in struct devfreq
@@ -63,12 +65,12 @@ struct tegra_wmark_data {
static int devfreq_get_freq_index(struct devfreq *df, unsigned long freq)
{
#if defined(NV_DEVFREQ_HAS_FREQ_TABLE)
unsigned long *freq_table = df->freq_table;
unsigned int max_state = df->max_state;
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0)
unsigned long *freq_table = df->profile->freq_table;
unsigned int max_state = df->profile->max_state;
#else
unsigned long *freq_table = df->freq_table;
unsigned int max_state = df->max_state;
#endif
int i;
@@ -84,12 +86,12 @@ static int devfreq_tegra_wmark_target_freq(struct devfreq *df, unsigned long *fr
{
struct tegra_wmark_data *govdata = df->governor_data;
struct devfreq_tegra_wmark_data *drvdata = df->data;
#if defined(NV_DEVFREQ_HAS_FREQ_TABLE)
unsigned long *freq_table = df->freq_table;
unsigned int max_state = df->max_state;
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0)
unsigned long *freq_table = df->profile->freq_table;
unsigned int max_state = df->profile->max_state;
#else
unsigned long *freq_table = df->freq_table;
unsigned int max_state = df->max_state;
#endif
int target_index = 0;
@@ -117,6 +119,7 @@ static int devfreq_tegra_wmark_target_freq(struct devfreq *df, unsigned long *fr
return 0;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0)
static s32 devfreq_pm_qos_read_value(struct devfreq *df, enum dev_pm_qos_req_type type)
{
struct device *dev = df->dev.parent;
@@ -150,13 +153,8 @@ static void devfreq_get_freq_range(struct devfreq *df,
{
s32 qos_min_freq, qos_max_freq;
#if defined(NV_DEVFREQ_HAS_FREQ_TABLE)
*min_freq = df->freq_table[0];
*max_freq = df->freq_table[df->max_state - 1];
#else
*min_freq = df->profile->freq_table[0];
*max_freq = df->profile->freq_table[df->profile->max_state - 1];
#endif
qos_min_freq = devfreq_pm_qos_read_value(df, DEV_PM_QOS_MIN_FREQUENCY);
qos_max_freq = devfreq_pm_qos_read_value(df, DEV_PM_QOS_MAX_FREQUENCY);
@@ -170,6 +168,7 @@ static void devfreq_get_freq_range(struct devfreq *df,
*min_freq = max(*min_freq, df->scaling_min_freq);
*max_freq = min(*max_freq, df->scaling_max_freq);
}
#endif
static void devfreq_update_wmark_threshold(struct devfreq *df)
{
@@ -177,10 +176,10 @@ static void devfreq_update_wmark_threshold(struct devfreq *df)
struct devfreq_tegra_wmark_data *drvdata = df->data;
struct devfreq_tegra_wmark_config wmark_config;
unsigned long curr_freq, prev_freq, min_freq, max_freq;
#if defined(NV_DEVFREQ_HAS_FREQ_TABLE)
unsigned long *freq_table = df->freq_table;
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0)
unsigned long *freq_table = df->profile->freq_table;
#else
unsigned long *freq_table = df->freq_table;
#endif
int err;
@@ -226,10 +225,10 @@ static ssize_t up_freq_margin_store(struct device *dev,
struct devfreq *df = to_devfreq(dev);
struct tegra_wmark_data *govdata;
unsigned int freq_margin;
#if defined(NV_DEVFREQ_HAS_FREQ_TABLE)
unsigned int max_state = df->max_state;
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0)
unsigned int max_state = df->profile->max_state;
#else
unsigned int max_state = df->max_state;
#endif
int ret;
@@ -271,10 +270,10 @@ static ssize_t down_freq_margin_store(struct device *dev,
struct devfreq *df = to_devfreq(dev);
struct tegra_wmark_data *govdata;
unsigned int freq_margin;
#if defined(NV_DEVFREQ_HAS_FREQ_TABLE)
unsigned int max_state = df->max_state;
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0)
unsigned int max_state = df->profile->max_state;
#else
unsigned int max_state = df->max_state;
#endif
int ret;

View File

@@ -197,7 +197,7 @@ static inline int tegra_ivc_check_read(struct tegra_ivc *ivc)
tegra_ivc_invalidate(ivc, ivc->rx.phys + offset);
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP)
if (tegra_ivc_empty(ivc, &ivc->rx.map))
if (!tegra_ivc_empty(ivc, &ivc->rx.map))
#else
if (tegra_ivc_empty(ivc, ivc->rx.channel))
#endif
@@ -229,7 +229,7 @@ static inline int tegra_ivc_check_write(struct tegra_ivc *ivc)
tegra_ivc_invalidate(ivc, ivc->tx.phys + offset);
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP)
if (tegra_ivc_full(ivc, &ivc->tx.map))
if (!tegra_ivc_full(ivc, &ivc->tx.map))
#else
if (tegra_ivc_full(ivc, ivc->tx.channel))
#endif

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Avionic Design GmbH
* SPDX-FileCopyrightText: Copyright (c) 2012-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
*/
#include <nvidia/conftest.h>
@@ -3295,23 +3295,11 @@ static int tegra_dc_remove(struct platform_device *pdev)
return 0;
}
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_dc_remove_wrapper(struct platform_device *pdev)
{
tegra_dc_remove(pdev);
}
#else
static int tegra_dc_remove_wrapper(struct platform_device *pdev)
{
return tegra_dc_remove(pdev);
}
#endif
struct platform_driver tegra_dc_driver = {
.driver = {
.name = "tegra-dc",
.of_match_table = tegra_dc_of_match,
},
.probe = tegra_dc_probe,
.remove = tegra_dc_remove_wrapper,
.remove = tegra_dc_remove,
};

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2013-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (C) 2013 NVIDIA Corporation
*/
#include <nvidia/conftest.h>
@@ -708,18 +708,6 @@ static const struct of_device_id tegra_dpaux_of_match[] = {
};
MODULE_DEVICE_TABLE(of, tegra_dpaux_of_match);
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_dpaux_remove_wrapper(struct platform_device *pdev)
{
tegra_dpaux_remove(pdev);
}
#else
static int tegra_dpaux_remove_wrapper(struct platform_device *pdev)
{
return tegra_dpaux_remove(pdev);
}
#endif
struct platform_driver tegra_dpaux_driver = {
.driver = {
.name = "tegra-dpaux",
@@ -727,7 +715,7 @@ struct platform_driver tegra_dpaux_driver = {
.pm = &tegra_dpaux_pm_ops,
},
.probe = tegra_dpaux_probe,
.remove = tegra_dpaux_remove_wrapper,
.remove = tegra_dpaux_remove,
};
struct drm_dp_aux *drm_dp_aux_find_by_of_node(struct device_node *np)

View File

@@ -16,11 +16,7 @@
#include <linux/pm_runtime.h>
#include <linux/version.h>
#if defined(NV_APERTURE_REMOVE_ALL_CONFLICTING_DEVICES_PRESENT) /* Linux v6.0 */
#include <linux/aperture.h>
#else
#include <drm/drm_aperture.h>
#endif
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_debugfs.h>
@@ -65,6 +61,9 @@ static int tegra_atomic_check(struct drm_device *drm,
static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = {
.fb_create = tegra_fb_create,
#ifdef CONFIG_DRM_FBDEV_EMULATION
.output_poll_changed = drm_fb_helper_output_poll_changed,
#endif
.atomic_check = tegra_atomic_check,
.atomic_commit = drm_atomic_helper_commit,
};
@@ -806,9 +805,6 @@ static const struct file_operations tegra_drm_fops = {
.read = drm_read,
.compat_ioctl = drm_compat_ioctl,
.llseek = noop_llseek,
#if defined(NV_FOP_UNSIGNED_OFFSET_PRESENT) /* Linux v6.12 */
.fop_flags = FOP_UNSIGNED_OFFSET,
#endif
};
static int tegra_drm_context_cleanup(int id, void *p, void *data)
@@ -890,6 +886,7 @@ static const struct drm_driver tegra_drm_driver = {
DRIVER_ATOMIC | DRIVER_RENDER | DRIVER_SYNCOBJ,
.open = tegra_drm_open,
.postclose = tegra_drm_postclose,
.lastclose = drm_fb_helper_lastclose,
#if defined(CONFIG_DEBUG_FS)
.debugfs_init = tegra_debugfs_init,
@@ -911,9 +908,7 @@ static const struct drm_driver tegra_drm_driver = {
.name = DRIVER_NAME,
.desc = DRIVER_DESC,
#if defined(NV_DRM_DRIVER_STRUCT_HAS_DATE) /* Linux v6.14 */
.date = DRIVER_DATE,
#endif
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
.patchlevel = DRIVER_PATCHLEVEL,
@@ -1188,9 +1183,6 @@ static bool host1x_drm_wants_iommu(struct host1x_device *dev)
static int host1x_drm_probe(struct host1x_device *dev)
{
#if defined(NV_IOMMU_PAGING_DOMAIN_ALLOC_PRESENT) /* Linux v6.11 */
struct device *dma_dev = dev->dev.parent;
#endif
struct tegra_drm *tegra;
struct drm_device *drm;
int err;
@@ -1205,13 +1197,8 @@ static int host1x_drm_probe(struct host1x_device *dev)
goto put;
}
#if defined(NV_IOMMU_PAGING_DOMAIN_ALLOC_PRESENT) /* Linux v6.11 */
if (host1x_drm_wants_iommu(dev) && device_iommu_mapped(dma_dev)) {
tegra->domain = iommu_paging_domain_alloc(dma_dev);
#else
if (host1x_drm_wants_iommu(dev) && iommu_present(&platform_bus_type)) {
tegra->domain = iommu_domain_alloc(&platform_bus_type);
#endif
if (!tegra->domain) {
err = -ENOMEM;
goto free;
@@ -1241,11 +1228,15 @@ static int host1x_drm_probe(struct host1x_device *dev)
drm->mode_config.funcs = &tegra_drm_mode_config_funcs;
drm->mode_config.helper_private = &tegra_drm_mode_config_helpers;
err = tegra_drm_fb_prepare(drm);
if (err < 0)
goto config;
drm_kms_helper_poll_init(drm);
err = host1x_device_init(dev);
if (err < 0)
goto poll;
goto fbdev;
/*
* Now that all display controller have been initialized, the maximum
@@ -1314,9 +1305,7 @@ static int host1x_drm_probe(struct host1x_device *dev)
drm_mode_config_reset(drm);
if (drm->mode_config.num_crtc > 0) {
#if defined(NV_APERTURE_REMOVE_ALL_CONFLICTING_DEVICES_PRESENT) /* Linux v6.0 */
err = aperture_remove_all_conflicting_devices(tegra_drm_driver.name);
#elif defined(NV_DRM_APERTURE_REMOVE_FRAMEBUFFERS_HAS_NO_PRIMARY_ARG) /* Linux v6.5 */
#if defined(NV_DRM_APERTURE_REMOVE_FRAMEBUFFERS_HAS_NO_PRIMARY_ARG) /* Linux v6.5 */
err = drm_aperture_remove_framebuffers(&tegra_drm_driver);
#elif defined(NV_DRM_APERTURE_REMOVE_FRAMEBUFFERS_HAS_DRM_DRIVER_ARG) /* Linux v5.15 */
err = drm_aperture_remove_framebuffers(false, &tegra_drm_driver);
@@ -1327,12 +1316,18 @@ static int host1x_drm_probe(struct host1x_device *dev)
goto hub;
}
err = drm_dev_register(drm, 0);
err = tegra_drm_fb_init(drm);
if (err < 0)
goto hub;
err = drm_dev_register(drm, 0);
if (err < 0)
goto fb;
return 0;
fb:
tegra_drm_fb_exit(drm);
hub:
if (tegra->hub)
tegra_display_hub_cleanup(tegra->hub);
@@ -1345,8 +1340,10 @@ device:
}
host1x_device_exit(dev);
poll:
fbdev:
drm_kms_helper_poll_fini(drm);
tegra_drm_fb_free(drm);
config:
drm_mode_config_cleanup(drm);
domain:
if (tegra->domain)
@@ -1367,6 +1364,7 @@ static int host1x_drm_remove(struct host1x_device *dev)
drm_dev_unregister(drm);
drm_kms_helper_poll_fini(drm);
tegra_drm_fb_exit(drm);
drm_atomic_helper_shutdown(drm);
drm_mode_config_cleanup(drm);

View File

@@ -130,7 +130,7 @@ static inline struct device *
tegra_drm_context_get_memory_device(struct tegra_drm_context *context)
{
if (context->memory_context)
return context->memory_context->context_dev;
return &context->memory_context->dev;
else
return context->client->base.dev;
}

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2013-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (C) 2013 NVIDIA Corporation
*/
#include <nvidia/conftest.h>
@@ -1692,23 +1692,11 @@ static const struct of_device_id tegra_dsi_of_match[] = {
};
MODULE_DEVICE_TABLE(of, tegra_dsi_of_match);
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_dsi_remove_wrapper(struct platform_device *pdev)
{
tegra_dsi_remove(pdev);
}
#else
static int tegra_dsi_remove_wrapper(struct platform_device *pdev)
{
return tegra_dsi_remove(pdev);
}
#endif
struct platform_driver tegra_dsi_driver = {
.driver = {
.name = "tegra-dsi",
.of_match_table = tegra_dsi_of_match,
},
.probe = tegra_dsi_probe,
.remove = tegra_dsi_remove_wrapper,
.remove = tegra_dsi_remove,
};

View File

@@ -12,7 +12,6 @@
#include <linux/console.h>
#include <linux/version.h>
#include <linux/fb.h>
#include <linux/vmalloc.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>

View File

@@ -3,7 +3,7 @@
* NVIDIA Tegra DRM GEM helper functions
*
* Copyright (C) 2012 Sascha Hauer, Pengutronix
* Copyright (C) 2013-2024 NVIDIA CORPORATION, All rights reserved.
* Copyright (C) 2013-2023 NVIDIA CORPORATION, All rights reserved.
*
* Based on the GEM/CMA helpers
*
@@ -15,7 +15,6 @@
#include <linux/dma-buf.h>
#include <linux/iommu.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <drm/drm_drv.h>
#include <drm/drm_prime.h>
@@ -24,11 +23,7 @@
#include "drm.h"
#include "gem.h"
#if defined(NV_MODULE_IMPORT_NS_CALLS_STRINGIFY)
MODULE_IMPORT_NS(DMA_BUF);
#else
MODULE_IMPORT_NS("DMA_BUF");
#endif
static unsigned int sg_dma_count_chunks(struct scatterlist *sgl, unsigned int nents)
{

View File

@@ -1,10 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2012-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (c) 2012-2013, NVIDIA Corporation.
*/
#include <nvidia/conftest.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/iommu.h>
@@ -394,18 +392,6 @@ static const struct dev_pm_ops tegra_gr2d_pm = {
pm_runtime_force_resume)
};
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void gr2d_remove_wrapper(struct platform_device *pdev)
{
gr2d_remove(pdev);
}
#else
static int gr2d_remove_wrapper(struct platform_device *pdev)
{
return gr2d_remove(pdev);
}
#endif
struct platform_driver tegra_gr2d_driver = {
.driver = {
.name = "tegra-gr2d",
@@ -413,5 +399,5 @@ struct platform_driver tegra_gr2d_driver = {
.pm = &tegra_gr2d_pm,
},
.probe = gr2d_probe,
.remove = gr2d_remove_wrapper,
.remove = gr2d_remove,
};

View File

@@ -1,11 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2013 Avionic Design GmbH
* SPDX-FileCopyrightText: Copyright (c) 2013-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (C) 2013 NVIDIA Corporation
*/
#include <nvidia/conftest.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/host1x-next.h>
@@ -49,9 +47,6 @@ struct gr3d {
unsigned int nclocks;
struct reset_control_bulk_data resets[RST_GR3D_MAX];
unsigned int nresets;
#if defined(NV_DEVM_PM_DOMAIN_ATTACH_LIST_PRESENT) /* Linux v6.13 */
struct dev_pm_domain_list *pd_list;
#endif
DECLARE_BITMAP(addr_regs, GR3D_NUM_REGS);
};
@@ -375,21 +370,13 @@ static int gr3d_power_up_legacy_domain(struct device *dev, const char *name,
return 0;
}
#if !defined(NV_DEVM_PM_DOMAIN_ATTACH_LIST_PRESENT) /* Linux v6.13 */
static void gr3d_del_link(void *link)
{
device_link_del(link);
}
#endif
static int gr3d_init_power(struct device *dev, struct gr3d *gr3d)
{
#if defined(NV_DEVM_PM_DOMAIN_ATTACH_LIST_PRESENT) /* Linux v6.13 */
struct dev_pm_domain_attach_data pd_data = {
.pd_names = (const char *[]) { "3d0", "3d1" },
.num_pd_names = 2,
};
#else
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
static const char * const opp_genpd_names[] = { "3d0", "3d1", NULL };
#else
@@ -399,7 +386,6 @@ static int gr3d_init_power(struct device *dev, struct gr3d *gr3d)
struct device **opp_virt_devs, *pd_dev;
struct device_link *link;
unsigned int i;
#endif
int err;
err = of_count_phandle_with_args(dev->of_node, "power-domains",
@@ -433,11 +419,6 @@ static int gr3d_init_power(struct device *dev, struct gr3d *gr3d)
if (dev->pm_domain)
return 0;
#if defined(NV_DEVM_PM_DOMAIN_ATTACH_LIST_PRESENT) /* Linux v6.13 */
err = devm_pm_domain_attach_list(dev, &pd_data, &gr3d->pd_list);
if (err < 0)
return err;
#else
err = devm_pm_opp_attach_genpd(dev, opp_genpd_names, &opp_virt_devs);
if (err)
return err;
@@ -460,7 +441,6 @@ static int gr3d_init_power(struct device *dev, struct gr3d *gr3d)
if (err)
return err;
}
#endif
return 0;
}
@@ -651,18 +631,6 @@ static const struct dev_pm_ops tegra_gr3d_pm = {
pm_runtime_force_resume)
};
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void gr3d_remove_wrapper(struct platform_device *pdev)
{
gr3d_remove(pdev);
}
#else
static int gr3d_remove_wrapper(struct platform_device *pdev)
{
return gr3d_remove(pdev);
}
#endif
struct platform_driver tegra_gr3d_driver = {
.driver = {
.name = "tegra-gr3d",
@@ -670,5 +638,5 @@ struct platform_driver tegra_gr3d_driver = {
.pm = &tegra_gr3d_pm,
},
.probe = gr3d_probe,
.remove = gr3d_remove_wrapper,
.remove = gr3d_remove,
};

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2012 Avionic Design GmbH
* SPDX-FileCopyrightText: Copyright (c) 2012-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
*/
#include <nvidia/conftest.h>
@@ -1909,23 +1909,11 @@ static int tegra_hdmi_remove(struct platform_device *pdev)
return 0;
}
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_hdmi_remove_wrapper(struct platform_device *pdev)
{
tegra_hdmi_remove(pdev);
}
#else
static int tegra_hdmi_remove_wrapper(struct platform_device *pdev)
{
return tegra_hdmi_remove(pdev);
}
#endif
struct platform_driver tegra_hdmi_driver = {
.driver = {
.name = "tegra-hdmi",
.of_match_table = tegra_hdmi_of_match,
},
.probe = tegra_hdmi_probe,
.remove = tegra_hdmi_remove_wrapper,
.remove = tegra_hdmi_remove,
};

View File

@@ -1,10 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2017-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved.
*/
#include <nvidia/conftest.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
@@ -1217,23 +1215,11 @@ static const struct of_device_id tegra_display_hub_of_match[] = {
};
MODULE_DEVICE_TABLE(of, tegra_display_hub_of_match);
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_display_hub_remove_wrapper(struct platform_device *pdev)
{
tegra_display_hub_remove(pdev);
}
#else
static int tegra_display_hub_remove_wrapper(struct platform_device *pdev)
{
return tegra_display_hub_remove(pdev);
}
#endif
struct platform_driver tegra_display_hub_driver = {
.driver = {
.name = "tegra-display-hub",
.of_match_table = tegra_display_hub_of_match,
},
.probe = tegra_display_hub_probe,
.remove = tegra_display_hub_remove_wrapper,
.remove = tegra_display_hub_remove,
};

View File

@@ -1,10 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2015-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2015-2024, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
*/
#include <nvidia/conftest.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
@@ -45,37 +43,11 @@
#define NVDEC_TFBIF_ACTMON_ACTIVE_WEIGHT 0x2c54
#define NVDEC_AXI_RW_BANDWIDTH 512
#define NVDEC_CG_SLCG_CTRL 0x297c
#define NVDEC_CG_SLCG_CTRL_IDLE_SLCG_DIS BIT(9)
#define NVDEC_RISCV_CG 0x4398
#define NVDEC_RISCV_CG_SLCG BIT(0)
#define NVDEC_RISCV_CG_CORE_SLCG BIT(1)
#define NVDEC_PG 0x2314
#define NVDEC_PG_DEEP_ELPG_EN BIT(18)
#define NVDEC_PG1 0x2318
#define NVDEC_CG2 0x2328
#define NVDEC_CG3 0x232c
#define NVDEC_CG4 0x2950
#define NVDEC_CG5 0x2954
#define NVDEC_CG6 0x2958
#define NVDEC_CG7 0x295c
#define NVDEC_CG8 0x2960
#define NVDEC_CG9 0x2964
#define NVDEC_CG10 0x2968
#define NVDEC_CG11 0x296c
#define NVDEC_CG12 0x2970
#define NVDEC_TFBIF_ACTMON_ACTIVE_MASK_STARVED BIT(0)
#define NVDEC_TFBIF_ACTMON_ACTIVE_MASK_STALLED BIT(1)
#define NVDEC_TFBIF_ACTMON_ACTIVE_MASK_DELAYED BIT(2)
#define NVDEC_TFBIF_ACTMON_ACTIVE_BORPS_ACTIVE BIT(7)
struct nvdec_cg_reg {
u32 offset;
u32 value;
};
struct nvdec_config {
const char *firmware;
unsigned int version;
@@ -83,7 +55,6 @@ struct nvdec_config {
bool supports_timestamping;
bool has_riscv;
bool has_extra_clocks;
const struct nvdec_cg_reg *cg_regs;
};
struct nvdec {
@@ -120,11 +91,6 @@ static inline void nvdec_writel(struct nvdec *nvdec, u32 value,
writel(value, nvdec->regs + offset);
}
static inline u32 nvdec_readl(struct nvdec *nvdec, unsigned int offset)
{
return readl(nvdec->regs + offset);
}
static int nvdec_set_rate(struct nvdec *nvdec, unsigned long rate)
{
unsigned long dev_rate;
@@ -591,29 +557,6 @@ static void nvdec_count_weight_init(struct nvdec *nvdec, unsigned long rate)
}
}
static void nvdec_enable_slcg(struct nvdec *nvdec)
{
const struct nvdec_cg_reg *cg;
u32 val;
if (!nvdec->config->cg_regs)
return;
/* Enable power gating */
nvdec_writel(nvdec, 0xff00a725, NVDEC_PG1);
nvdec_writel(nvdec, NVDEC_PG_DEEP_ELPG_EN | (9 << 20) | (2 << 27), NVDEC_PG);
/* Enable clock gating */
for (cg = nvdec->config->cg_regs; cg->offset; cg++)
nvdec_writel(nvdec, cg->value, cg->offset);
val = nvdec_readl(nvdec, NVDEC_CG_SLCG_CTRL);
val &= ~NVDEC_CG_SLCG_CTRL_IDLE_SLCG_DIS;
nvdec_writel(nvdec, val, NVDEC_CG_SLCG_CTRL);
nvdec_writel(nvdec, NVDEC_RISCV_CG_SLCG | NVDEC_RISCV_CG_CORE_SLCG, NVDEC_RISCV_CG);
}
static __maybe_unused int nvdec_runtime_resume(struct device *dev)
{
struct nvdec *nvdec = dev_get_drvdata(dev);
@@ -639,8 +582,6 @@ static __maybe_unused int nvdec_runtime_resume(struct device *dev)
goto disable;
}
nvdec_enable_slcg(nvdec);
/* Forcely set frequency as Fmax when device is resumed back */
nvdec->devfreq->resume_freq = nvdec->devfreq->scaling_max_freq;
err = devfreq_resume_device(nvdec->devfreq);
@@ -757,28 +698,12 @@ static const struct nvdec_config nvdec_t194_config = {
.supports_timestamping = true,
};
static const struct nvdec_cg_reg nvdec_t234_cg_regs[] = {
{ NVDEC_CG2, 0x00000000 },
{ NVDEC_CG3, 0xfc800000 },
{ NVDEC_CG4, 0xffffffc0 },
{ NVDEC_CG5, 0x00000040 },
{ NVDEC_CG6, 0x04004000 },
{ NVDEC_CG7, 0xfc000000 },
{ NVDEC_CG8, 0x00000000 },
{ NVDEC_CG9, 0x80000000 },
{ NVDEC_CG10, 0xfffffb00 },
{ NVDEC_CG11, 0xfff80000 },
{ NVDEC_CG12, 0xffffff80 },
{ },
};
static const struct nvdec_config nvdec_t234_config = {
.version = 0x23,
.supports_sid = true,
.supports_timestamping = true,
.has_riscv = true,
.has_extra_clocks = true,
.cg_regs = nvdec_t234_cg_regs,
};
static const struct of_device_id tegra_nvdec_of_match[] = {
@@ -966,18 +891,6 @@ static const struct dev_pm_ops nvdec_pm_ops = {
pm_runtime_force_resume)
};
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void nvdec_remove_wrapper(struct platform_device *pdev)
{
nvdec_remove(pdev);
}
#else
static int nvdec_remove_wrapper(struct platform_device *pdev)
{
return nvdec_remove(pdev);
}
#endif
struct platform_driver tegra_nvdec_driver = {
.driver = {
.name = "tegra-nvdec",
@@ -985,7 +898,7 @@ struct platform_driver tegra_nvdec_driver = {
.pm = &nvdec_pm_ops
},
.probe = nvdec_probe,
.remove = nvdec_remove_wrapper,
.remove = nvdec_remove,
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)

View File

@@ -1,10 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2021-2024, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
*/
#include <nvidia/conftest.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
@@ -759,18 +757,6 @@ static const struct dev_pm_ops nvenc_pm_ops = {
pm_runtime_force_resume)
};
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void nvenc_remove_wrapper(struct platform_device *pdev)
{
nvenc_remove(pdev);
}
#else
static int nvenc_remove_wrapper(struct platform_device *pdev)
{
return nvenc_remove(pdev);
}
#endif
struct platform_driver tegra_nvenc_driver = {
.driver = {
.name = "tegra-nvenc",
@@ -778,7 +764,7 @@ struct platform_driver tegra_nvenc_driver = {
.pm = &nvenc_pm_ops
},
.probe = nvenc_probe,
.remove = nvenc_remove_wrapper,
.remove = nvenc_remove,
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)

View File

@@ -1,10 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2021-2024, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
*/
#include <nvidia/conftest.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
@@ -736,18 +734,6 @@ static const struct dev_pm_ops nvjpg_pm_ops = {
pm_runtime_force_resume)
};
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void nvjpg_remove_wrapper(struct platform_device *pdev)
{
nvjpg_remove(pdev);
}
#else
static int nvjpg_remove_wrapper(struct platform_device *pdev)
{
return nvjpg_remove(pdev);
}
#endif
struct platform_driver tegra_nvjpg_driver = {
.driver = {
.name = "tegra-nvjpg",
@@ -755,7 +741,7 @@ struct platform_driver tegra_nvjpg_driver = {
.pm = &nvjpg_pm_ops
},
.probe = nvjpg_probe,
.remove = nvjpg_remove_wrapper,
.remove = nvjpg_remove,
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)

View File

@@ -1,10 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2021-2023, NVIDIA Corporation.
*/
#include <nvidia/conftest.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/devfreq.h>
@@ -634,18 +632,6 @@ static const struct dev_pm_ops ofa_pm_ops = {
pm_runtime_force_resume)
};
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void ofa_remove_wrapper(struct platform_device *pdev)
{
ofa_remove(pdev);
}
#else
static int ofa_remove_wrapper(struct platform_device *pdev)
{
return ofa_remove(pdev);
}
#endif
struct platform_driver tegra_ofa_driver = {
.driver = {
.name = "tegra-ofa",
@@ -653,7 +639,7 @@ struct platform_driver tegra_ofa_driver = {
.pm = &ofa_pm_ops
},
.probe = ofa_probe,
.remove = ofa_remove_wrapper,
.remove = ofa_remove,
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)

View File

@@ -1,5 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Copyright (c) 2022, NVIDIA Corporation.
*/
#include <asm/unaligned.h>
#include <linux/dev_printk.h>
#include <linux/device.h>

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2013-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (C) 2013 NVIDIA Corporation
*/
#include <nvidia/conftest.h>
@@ -4082,18 +4082,6 @@ static const struct dev_pm_ops tegra_sor_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(tegra_sor_suspend, tegra_sor_resume)
};
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_sor_remove_wrapper(struct platform_device *pdev)
{
tegra_sor_remove(pdev);
}
#else
static int tegra_sor_remove_wrapper(struct platform_device *pdev)
{
return tegra_sor_remove(pdev);
}
#endif
struct platform_driver tegra_sor_driver = {
.driver = {
.name = "tegra-sor",
@@ -4101,5 +4089,5 @@ struct platform_driver tegra_sor_driver = {
.pm = &tegra_sor_pm_ops,
},
.probe = tegra_sor_probe,
.remove = tegra_sor_remove_wrapper,
.remove = tegra_sor_remove,
};

View File

@@ -240,14 +240,9 @@ static int submit_write_reloc(struct tegra_drm_context *context, struct gather_b
struct drm_tegra_submit_buf *buf, struct tegra_drm_mapping *mapping)
{
/* TODO check that target_offset is within bounds */
dma_addr_t iova = buf->reloc.target_offset;
dma_addr_t iova = mapping->iova + buf->reloc.target_offset;
u32 written_ptr;
if (mapping->bo_map)
iova += mapping->iova;
else
iova += mapping->ctx_map->mapping->phys;
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
if (buf->flags & DRM_TEGRA_SUBMIT_RELOC_SECTOR_LAYOUT)
iova |= BIT_ULL(39);
@@ -531,6 +526,9 @@ static void release_job(struct host1x_job *job)
struct tegra_drm_submit_data *job_data = job->user_data;
u32 i;
if (job->memory_context)
host1x_memory_context_put(job->memory_context);
if (IS_ENABLED(CONFIG_TRACING) && job_data->timestamps.virt) {
u64 *timestamps = job_data->timestamps.virt;
@@ -544,11 +542,6 @@ static void release_job(struct host1x_job *job)
for (i = 0; i < job_data->num_used_mappings; i++)
tegra_drm_mapping_put(job_data->used_mappings[i].mapping);
if (job->memory_context) {
host1x_memory_context_inactive(job->memory_context);
host1x_memory_context_put(job->memory_context);
}
kfree(job_data->used_mappings);
kfree(job_data);
@@ -588,7 +581,6 @@ static int submit_init_profiling(struct tegra_drm_context *context,
int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data,
struct drm_file *file)
{
struct host1x_memory_context *active_memctx = NULL;
struct tegra_drm_file *fpriv = file->driver_priv;
struct drm_tegra_channel_submit *args = data;
static atomic_t next_job_id = ATOMIC_INIT(1);
@@ -612,17 +604,6 @@ int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data,
return -EINVAL;
}
if (context->memory_context) {
err = host1x_memory_context_active(context->memory_context);
if (err) {
mutex_unlock(&fpriv->lock);
SUBMIT_ERR(context, "failed to activate memory context");
return err;
}
active_memctx = context->memory_context;
}
if (args->flags & ~(DRM_TEGRA_SUBMIT_SECONDARY_SYNCPT)) {
SUBMIT_ERR(context, "invalid flags '%#x'", args->flags);
goto unlock;
@@ -723,8 +704,7 @@ int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data,
}
if (supported) {
job->memory_context = active_memctx;
active_memctx = NULL;
job->memory_context = context->memory_context;
host1x_memory_context_get(job->memory_context);
}
} else if (context->client->ops->get_streamid_offset) {
@@ -845,8 +825,6 @@ put_bo:
unlock:
if (syncobj)
drm_syncobj_put(syncobj);
if (active_memctx)
host1x_memory_context_inactive(active_memctx);
mutex_unlock(&fpriv->lock);
return err;

View File

@@ -17,11 +17,7 @@ static void tegra_drm_mapping_release(struct kref *ref)
struct tegra_drm_mapping *mapping =
container_of(ref, struct tegra_drm_mapping, ref);
if (mapping->ctx_map)
host1x_memory_context_unmap(mapping->ctx_map);
else
host1x_bo_unpin(mapping->bo_map);
host1x_bo_unpin(mapping->map);
host1x_bo_put(mapping->bo);
kfree(mapping);
@@ -37,12 +33,12 @@ static void tegra_drm_channel_context_close(struct tegra_drm_context *context)
struct tegra_drm_mapping *mapping;
unsigned long id;
xa_for_each(&context->mappings, id, mapping)
tegra_drm_mapping_put(mapping);
if (context->memory_context)
host1x_memory_context_put(context->memory_context);
xa_for_each(&context->mappings, id, mapping)
tegra_drm_mapping_put(mapping);
xa_destroy(&context->mappings);
host1x_channel_put(context->channel);
@@ -238,27 +234,16 @@ int tegra_drm_ioctl_channel_map(struct drm_device *drm, void *data, struct drm_f
goto put_gem;
}
if (context->memory_context) {
mapping->ctx_map = host1x_memory_context_map(
context->memory_context, mapping->bo, direction);
if (IS_ERR(mapping->ctx_map)) {
err = PTR_ERR(mapping->ctx_map);
goto put_gem;
}
} else {
mapping->bo_map = host1x_bo_pin(context->client->base.dev,
mapping->bo, direction, NULL);
if (IS_ERR(mapping->bo_map)) {
err = PTR_ERR(mapping->bo_map);
goto put_gem;
}
mapping->iova = mapping->bo_map->phys;
mapping->iova_end = mapping->iova + host1x_to_tegra_bo(mapping->bo)->gem.size;
mapping->map = host1x_bo_pin(tegra_drm_context_get_memory_device(context),
mapping->bo, direction, NULL);
if (IS_ERR(mapping->map)) {
err = PTR_ERR(mapping->map);
goto put_gem;
}
mapping->iova = mapping->map->phys;
mapping->iova_end = mapping->iova + host1x_to_tegra_bo(mapping->bo)->gem.size;
err = xa_alloc(&context->mappings, &args->mapping, mapping, XA_LIMIT(1, U32_MAX),
GFP_KERNEL);
if (err < 0)
@@ -269,10 +254,7 @@ int tegra_drm_ioctl_channel_map(struct drm_device *drm, void *data, struct drm_f
return 0;
unpin:
if (mapping->ctx_map)
host1x_memory_context_unmap(mapping->ctx_map);
else
host1x_bo_unpin(mapping->bo_map);
host1x_bo_unpin(mapping->map);
put_gem:
host1x_bo_put(mapping->bo);
free:

View File

@@ -27,8 +27,7 @@ struct tegra_drm_file {
struct tegra_drm_mapping {
struct kref ref;
struct host1x_bo_mapping *bo_map;
struct host1x_context_mapping *ctx_map;
struct host1x_bo_mapping *map;
struct host1x_bo *bo;
dma_addr_t iova;

View File

@@ -1,10 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2015-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (C) 2015-2024 NVIDIA CORPORATION. All rights reserved.
*/
#include <nvidia/conftest.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
@@ -833,18 +831,6 @@ static const struct dev_pm_ops vic_pm_ops = {
#endif
};
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void vic_remove_wrapper(struct platform_device *pdev)
{
vic_remove(pdev);
}
#else
static int vic_remove_wrapper(struct platform_device *pdev)
{
return vic_remove(pdev);
}
#endif
struct platform_driver tegra_vic_driver = {
.driver = {
.name = "tegra-vic",
@@ -852,7 +838,7 @@ struct platform_driver tegra_vic_driver = {
.pm = &vic_pm_ops
},
.probe = vic_probe,
.remove = vic_remove_wrapper,
.remove = vic_remove,
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC)

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
/*
* Copyright (c) 2023, NVIDIA Corporation.
*/
#include <linux/clk.h>
#include <linux/debugfs.h>
@@ -563,18 +563,6 @@ static const struct dev_pm_ops virt_engine_pm_ops = {
#endif
};
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void virt_engine_remove_wrapper(struct platform_device *pdev)
{
virt_engine_remove(pdev);
}
#else
static int virt_engine_remove_wrapper(struct platform_device *pdev)
{
return virt_engine_remove(pdev);
}
#endif
struct platform_driver tegra_virt_engine_driver = {
.driver = {
.name = "tegra-host1x-virtual-engine",
@@ -582,5 +570,5 @@ struct platform_driver tegra_virt_engine_driver = {
.pm = &virt_engine_pm_ops,
},
.probe = virt_engine_probe,
.remove = virt_engine_remove_wrapper,
.remove = virt_engine_remove,
};

View File

@@ -1,5 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Host1x fence UAPI
*
* Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
*/
#include <nvidia/conftest.h>
@@ -172,8 +176,6 @@ static int dev_file_ioctl_fence_extract(struct host1x *host1x, void __user *data
goto put_fence;
}
dma_fence_put(fence);
return 0;
put_fence:
@@ -203,28 +205,20 @@ struct host1x_pollfd {
static int host1x_pollfd_release(struct inode *inode, struct file *file)
{
struct host1x_pollfd *pollfd = file->private_data;
struct host1x_pollfd_fence *pfd_fence, *pfd_fence_temp;
struct host1x_pollfd_fence *pfd_fence;
mutex_lock(&pollfd->lock);
list_for_each_entry_safe(pfd_fence, pfd_fence_temp, &pollfd->fences, list) {
list_for_each_entry(pfd_fence, &pollfd->fences, list) {
if (pfd_fence->callback_set) {
if (dma_fence_remove_callback(pfd_fence->fence, &pfd_fence->callback))
host1x_fence_cancel(pfd_fence->fence);
pfd_fence->callback_set = false;
}
/*The lock/unlock just ensures that the callback execution has finished*/
spin_lock(pfd_fence->fence->lock);
spin_unlock(pfd_fence->fence->lock);
dma_fence_put(pfd_fence->fence);
kfree(pfd_fence);
}
mutex_unlock(&pollfd->lock);
kfree(pollfd);
return 0;
}
@@ -241,20 +235,8 @@ static unsigned int host1x_pollfd_poll(struct file *file, poll_table *wait)
list_for_each_entry_safe(pfd_fence, pfd_fence_temp, &pollfd->fences, list) {
if (dma_fence_is_signaled(pfd_fence->fence)) {
mask = POLLPRI | POLLIN;
if (pfd_fence->callback_set) {
if (dma_fence_remove_callback(pfd_fence->fence,
&pfd_fence->callback))
host1x_fence_cancel(pfd_fence->fence);
pfd_fence->callback_set = false;
}
/*The lock/unlock just ensures that the callback execution has finished*/
spin_lock(pfd_fence->fence->lock);
spin_unlock(pfd_fence->fence->lock);
dma_fence_put(pfd_fence->fence);
list_del(&pfd_fence->list);
kfree(pfd_fence);
}
}

View File

@@ -335,11 +335,7 @@ static int host1x_del_client(struct host1x *host1x,
return -ENODEV;
}
#if defined(NV_BUS_TYPE_STRUCT_MATCH_HAS_CONST_DRV_ARG)
static int host1x_device_match(struct device *dev, const struct device_driver *drv)
#else
static int host1x_device_match(struct device *dev, struct device_driver *drv)
#endif
{
return strcmp(dev_name(dev), drv->name) == 0;
}

View File

@@ -35,14 +35,14 @@
/*
* Typically the commands written into the push buffer are a pair of words. We
* use slots to represent each of these pairs and to simplify things. Note the
* strange number of slots allocated here. 1024 slots will fit exactly within a
* two memory pages. We also need one additional word at the end of the push
* strange number of slots allocated here. 512 slots will fit exactly within a
* single memory page. We also need one additional word at the end of the push
* buffer for the RESTART opcode that will instruct the CDMA to jump back to
* the beginning of the push buffer. With 1024 slots, this means that we'll use
* 3 memory pages and waste 4092 bytes of the third page that will never be
* the beginning of the push buffer. With 512 slots, this means that we'll use
* 2 memory pages and waste 4092 bytes of the second page that will never be
* used.
*/
#define HOST1X_PUSHBUFFER_SLOTS 1023
#define HOST1X_PUSHBUFFER_SLOTS 511
/*
* Clean up push buffer resources

View File

@@ -1,12 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (c) 2021-2024, NVIDIA Corporation.
*/
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/kref.h>
#include <linux/list.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pid.h>
@@ -19,14 +17,13 @@ int host1x_memory_context_list_init(struct host1x *host1x)
{
struct host1x_memory_context_list *cdl = &host1x->context_list;
struct device_node *node = host1x->dev->of_node;
struct host1x_hw_memory_context *ctx;
struct host1x_memory_context *ctx;
unsigned int i;
int err;
cdl->devs = NULL;
cdl->len = 0;
mutex_init(&cdl->lock);
INIT_LIST_HEAD(&cdl->waiters);
err = of_property_count_u32_elems(node, "iommu-map");
if (err < 0)
@@ -57,7 +54,6 @@ int host1x_memory_context_list_init(struct host1x *host1x)
ctx->dev.bus = &host1x_context_device_bus_type;
ctx->dev.parent = host1x->dev;
ctx->dev.dma_parms = &ctx->dma_parms;
dma_set_max_seg_size(&ctx->dev, UINT_MAX);
err = device_add(&ctx->dev);
@@ -107,288 +103,62 @@ void host1x_memory_context_list_free(struct host1x_memory_context_list *cdl)
cdl->len = 0;
}
static bool hw_usable_for_dev(struct host1x_hw_memory_context *hw, struct device *dev)
{
return hw->dev.iommu->iommu_dev == dev->iommu->iommu_dev;
}
static struct host1x_hw_memory_context *host1x_memory_context_alloc_hw_locked(struct host1x *host1x,
struct host1x_memory_context *host1x_memory_context_alloc(struct host1x *host1x,
struct device *dev,
struct pid *pid)
{
struct host1x_memory_context_list *cdl = &host1x->context_list;
struct host1x_hw_memory_context *free = NULL, *can_steal = NULL;
struct host1x_memory_context *ctx;
struct host1x_memory_context *free = NULL;
int i;
if (!cdl->len)
return ERR_PTR(-EOPNOTSUPP);
for (i = 0; i < cdl->len; i++) {
struct host1x_hw_memory_context *cd = &cdl->devs[i];
mutex_lock(&cdl->lock);
if (!hw_usable_for_dev(cd, dev))
for (i = 0; i < cdl->len; i++) {
struct host1x_memory_context *cd = &cdl->devs[i];
if (cd->dev.iommu->iommu_dev != dev->iommu->iommu_dev)
continue;
if (cd->owner == pid) {
refcount_inc(&cd->ref);
mutex_unlock(&cdl->lock);
return cd;
} else if (!cd->owner && !free) {
free = cd;
} else if (!cd->active) {
can_steal = cd;
}
}
if (free)
goto found;
/* Steal */
if (!can_steal)
if (!free) {
mutex_unlock(&cdl->lock);
return ERR_PTR(-EBUSY);
list_for_each_entry(ctx, &can_steal->owners, entry) {
struct host1x_context_mapping *mapping;
ctx->hw = NULL;
ctx->context_dev = NULL;
list_for_each_entry(mapping, &ctx->mappings, entry) {
host1x_bo_unpin(mapping->mapping);
mapping->mapping = NULL;
}
}
put_pid(can_steal->owner);
free = can_steal;
found:
refcount_set(&free->ref, 1);
free->owner = get_pid(pid);
INIT_LIST_HEAD(&free->owners);
mutex_unlock(&cdl->lock);
return free;
}
static void host1x_memory_context_hw_put(struct host1x_hw_memory_context *cd)
{
if (refcount_dec_and_test(&cd->ref)) {
put_pid(cd->owner);
cd->owner = NULL;
}
}
struct host1x_memory_context *host1x_memory_context_alloc(
struct host1x *host1x, struct device *dev, struct pid *pid)
{
struct host1x_memory_context_list *cdl = &host1x->context_list;
struct host1x_memory_context *ctx;
if (!cdl->len)
return ERR_PTR(-EOPNOTSUPP);
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return ERR_PTR(-ENOMEM);
ctx->host = host1x;
ctx->dev = dev;
ctx->pid = get_pid(pid);
refcount_set(&ctx->ref, 1);
INIT_LIST_HEAD(&ctx->mappings);
return ctx;
}
EXPORT_SYMBOL_GPL(host1x_memory_context_alloc);
struct hw_alloc_waiter {
struct completion wait; /* Completion to wait for free hw context */
struct list_head entry;
struct device *dev;
};
int host1x_memory_context_active(struct host1x_memory_context *ctx)
void host1x_memory_context_get(struct host1x_memory_context *cd)
{
struct host1x_memory_context_list *cdl = &ctx->host->context_list;
struct host1x_context_mapping *mapping;
struct host1x_hw_memory_context *hw;
struct hw_alloc_waiter waiter;
bool retrying = false;
int err = 0;
mutex_lock(&cdl->lock);
retry:
if (!ctx->hw) {
hw = host1x_memory_context_alloc_hw_locked(ctx->host, ctx->dev, ctx->pid);
if (PTR_ERR(hw) == -EBUSY) {
/* All contexts busy. Wait for free context. */
if (!retrying)
dev_warn(ctx->dev, "%s: all memory contexts are busy, waiting\n",
current->comm);
init_completion(&waiter.wait);
waiter.dev = ctx->dev;
list_add(&waiter.entry, &cdl->waiters);
mutex_unlock(&cdl->lock);
err = wait_for_completion_interruptible(&waiter.wait);
mutex_lock(&cdl->lock);
list_del(&waiter.entry);
if (err)
goto unlock;
retrying = true;
goto retry;
}
if (IS_ERR(hw)) {
err = PTR_ERR(hw);
goto unlock;
}
ctx->hw = hw;
ctx->context_dev = &hw->dev;
list_add(&ctx->entry, &hw->owners);
list_for_each_entry(mapping, &ctx->mappings, entry) {
mapping->mapping = host1x_bo_pin(
&hw->dev, mapping->bo, mapping->direction, NULL);
if (IS_ERR(mapping->mapping)) {
err = PTR_ERR(mapping->mapping);
mapping->mapping = NULL;
goto unpin;
}
}
}
ctx->hw->active++;
mutex_unlock(&cdl->lock);
return 0;
unpin:
list_for_each_entry(mapping, &ctx->mappings, entry) {
if (mapping->mapping)
host1x_bo_unpin(mapping->mapping);
}
host1x_memory_context_hw_put(ctx->hw);
list_del(&ctx->entry);
ctx->hw = NULL;
unlock:
mutex_unlock(&cdl->lock);
return err;
}
EXPORT_SYMBOL_GPL(host1x_memory_context_active);
struct host1x_context_mapping *host1x_memory_context_map(
struct host1x_memory_context *ctx, struct host1x_bo *bo, enum dma_data_direction direction)
{
struct host1x_memory_context_list *cdl = &ctx->host->context_list;
struct host1x_context_mapping *m;
struct host1x_bo_mapping *bo_m;
m = kzalloc(sizeof(*m), GFP_KERNEL);
if (!m)
return ERR_PTR(-ENOMEM);
m->host = ctx->host;
m->bo = bo;
m->direction = direction;
mutex_lock(&cdl->lock);
if (ctx->hw) {
bo_m = host1x_bo_pin(&ctx->hw->dev, bo, direction, NULL);
if (IS_ERR(bo_m)) {
mutex_unlock(&cdl->lock);
kfree(m);
return ERR_CAST(bo_m);
}
m->mapping = bo_m;
}
list_add(&m->entry, &ctx->mappings);
mutex_unlock(&cdl->lock);
return m;
}
EXPORT_SYMBOL_GPL(host1x_memory_context_map);
void host1x_memory_context_unmap(struct host1x_context_mapping *m)
{
struct host1x_memory_context_list *cdl = &m->host->context_list;
mutex_lock(&cdl->lock);
list_del(&m->entry);
mutex_unlock(&cdl->lock);
if (m->mapping)
host1x_bo_unpin(m->mapping);
kfree(m);
}
EXPORT_SYMBOL_GPL(host1x_memory_context_unmap);
void host1x_memory_context_inactive(struct host1x_memory_context *ctx)
{
struct host1x_memory_context_list *cdl = &ctx->host->context_list;
struct hw_alloc_waiter *waiter;
mutex_lock(&cdl->lock);
if (--ctx->hw->active == 0) {
/* Hardware context becomes eligible for stealing */
list_for_each_entry(waiter, &cdl->waiters, entry) {
if (!hw_usable_for_dev(ctx->hw, waiter->dev))
continue;
complete(&waiter->wait);
/*
* Need to wake up all waiters -- there could be multiple from
* the same process that can use the same freed hardware context.
*/
}
}
mutex_unlock(&cdl->lock);
}
EXPORT_SYMBOL_GPL(host1x_memory_context_inactive);
void host1x_memory_context_get(struct host1x_memory_context *ctx)
{
refcount_inc(&ctx->ref);
refcount_inc(&cd->ref);
}
EXPORT_SYMBOL_GPL(host1x_memory_context_get);
void host1x_memory_context_put(struct host1x_memory_context *ctx)
void host1x_memory_context_put(struct host1x_memory_context *cd)
{
struct host1x_memory_context_list *cdl = &ctx->host->context_list;
struct host1x_memory_context_list *cdl = &cd->host->context_list;
if (refcount_dec_and_mutex_lock(&ctx->ref, &cdl->lock)) {
if (ctx->hw) {
list_del(&ctx->entry);
host1x_memory_context_hw_put(ctx->hw);
ctx->hw = NULL;
WARN_ON(!list_empty(&ctx->mappings));
}
put_pid(ctx->pid);
if (refcount_dec_and_mutex_lock(&cd->ref, &cdl->lock)) {
put_pid(cd->owner);
cd->owner = NULL;
mutex_unlock(&cdl->lock);
kfree(ctx);
}
}
EXPORT_SYMBOL_GPL(host1x_memory_context_put);

View File

@@ -2,7 +2,7 @@
/*
* Host1x context devices
*
* SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation.
*/
#ifndef __HOST1X_CONTEXT_H
@@ -17,24 +17,8 @@ extern struct bus_type host1x_context_device_bus_type;
struct host1x_memory_context_list {
struct mutex lock;
struct host1x_hw_memory_context *devs;
struct host1x_memory_context *devs;
unsigned int len;
struct list_head waiters;
};
struct host1x_hw_memory_context {
struct host1x *host;
refcount_t ref;
struct pid *owner;
struct device_dma_parameters dma_parms;
struct device dev;
u64 dma_mask;
u32 stream_id;
struct list_head owners;
unsigned int active;
};
#ifdef CONFIG_IOMMU_API

View File

@@ -2,7 +2,7 @@
/*
* Tegra host1x driver
*
* SPDX-FileCopyrightText: Copyright (c) 2010-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (c) 2010-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
*/
#include <nvidia/conftest.h>
@@ -620,16 +620,9 @@ static struct iommu_domain *host1x_iommu_attach(struct host1x *host)
if (err < 0)
goto put_group;
#if defined(NV_IOMMU_PAGING_DOMAIN_ALLOC_PRESENT) /* Linux v6.11 */
host->domain = iommu_paging_domain_alloc(host->dev);
if (IS_ERR(host->domain)) {
err = PTR_ERR(host->domain);
host->domain = NULL;
#else
host->domain = iommu_domain_alloc(&platform_bus_type);
if (!host->domain) {
err = -ENOMEM;
#endif
goto put_cache;
}
@@ -1109,18 +1102,6 @@ static const struct dev_pm_ops host1x_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(host1x_runtime_suspend, host1x_runtime_resume)
};
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void host1x_remove_wrapper(struct platform_device *pdev)
{
host1x_remove(pdev);
}
#else
static int host1x_remove_wrapper(struct platform_device *pdev)
{
return host1x_remove(pdev);
}
#endif
static struct platform_driver tegra_host1x_driver = {
.driver = {
.name = "tegra-host1x",
@@ -1128,7 +1109,7 @@ static struct platform_driver tegra_host1x_driver = {
.pm = &host1x_pm_ops,
},
.probe = host1x_probe,
.remove = host1x_remove_wrapper,
.remove = host1x_remove,
};
static struct platform_driver * const drivers[] = {

View File

@@ -12,7 +12,6 @@
#include <trace/events/host1x.h>
#include "../channel.h"
#include "../context.h"
#include "../dev.h"
#include "../intr.h"
#include "../job.h"
@@ -90,7 +89,7 @@ static void submit_setclass(struct host1x_job *job, u32 next_class)
* firmware stream ID.
*/
if (job->memory_context)
stream_id = job->memory_context->hw->stream_id;
stream_id = job->memory_context->stream_id;
else
stream_id = job->engine_fallback_streamid;

View File

@@ -177,14 +177,7 @@ static void show_gather(struct output *o, dma_addr_t phys_addr,
for (i = 0; i < words; i++) {
dma_addr_t addr = phys_addr + i * 4;
u32 voffset = offset + i * 4;
u32 val;
/* If we reach the RESTART opcode, continue at the beginning of pushbuffer */
if (cdma && voffset >= cdma->push_buffer.size)
voffset -= cdma->push_buffer.size;
val = *(map_addr + voffset / 4);
u32 val = *(map_addr + offset / 4 + i);
if (!data_count) {
host1x_debug_output(o, " %pad: %08x: ", &addr, val);
@@ -210,7 +203,7 @@ static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma)
job->num_slots, job->num_unpins);
show_gather(o, pb->dma + job->first_get, job->num_slots * 2, cdma,
pb->dma, pb->mapped);
pb->dma + job->first_get, pb->mapped + job->first_get);
for (i = 0; i < job->num_cmds; i++) {
struct host1x_job_gather *g;
@@ -234,7 +227,7 @@ static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma)
host1x_debug_output(o, " GATHER at %pad+%#x, %d words\n",
&g->base, g->offset, g->words);
show_gather(o, g->base + g->offset, g->words, NULL,
show_gather(o, g->base + g->offset, g->words, cdma,
g->base, mapped);
if (!job->gather_copy_mapped)

View File

@@ -495,26 +495,12 @@ int tegra_mipi_finish_calibration(struct tegra_mipi_device *device);
struct host1x_memory_context {
struct host1x *host;
struct device *dev; /* Owning engine */
struct pid *pid;
refcount_t ref;
struct pid *owner;
struct host1x_hw_memory_context *hw;
struct device *context_dev; /* Context device */
struct list_head entry; /* Entry in hw_memory_context's list */
struct list_head mappings; /* List of mappings */
};
struct host1x_context_mapping {
struct host1x *host;
struct host1x_bo_mapping *mapping;
struct host1x_bo *bo;
enum dma_data_direction direction;
struct list_head entry;
struct device dev;
u64 dma_mask;
u32 stream_id;
};
#ifdef CONFIG_IOMMU_API
@@ -523,11 +509,6 @@ struct host1x_memory_context *host1x_memory_context_alloc(struct host1x *host1x,
struct pid *pid);
void host1x_memory_context_get(struct host1x_memory_context *cd);
void host1x_memory_context_put(struct host1x_memory_context *cd);
int host1x_memory_context_active(struct host1x_memory_context *cd);
void host1x_memory_context_inactive(struct host1x_memory_context *cd);
struct host1x_context_mapping *host1x_memory_context_map(
struct host1x_memory_context *ctx, struct host1x_bo *bo, enum dma_data_direction direction);
void host1x_memory_context_unmap(struct host1x_context_mapping *m);
#else
static inline struct host1x_memory_context *host1x_memory_context_alloc(struct host1x *host1x,
struct pid *pid)
@@ -542,25 +523,6 @@ static inline void host1x_memory_context_get(struct host1x_memory_context *cd)
static inline void host1x_memory_context_put(struct host1x_memory_context *cd)
{
}
static inline int host1x_memory_context_active(struct host1x_memory_context *cd)
{
return -ENODEV;
}
static inline void host1x_memory_context_inactive(struct host1x_memory_context *cd)
{
}
static inline struct host1x_context_mapping *host1x_memory_context_map(
struct host1x_memory_context *ctx, struct host1x_bo *bo, enum dma_data_direction direction)
{
return ERR_PTR(-ENODEV);
}
static inline void host1x_memory_context_unmap(struct host1x_context_mapping *m)
{
}
#endif
int host1x_actmon_read_avg_count(struct host1x_client *client);

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2013-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (C) 2013 NVIDIA Corporation
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@@ -20,8 +20,6 @@
* OF THIS SOFTWARE.
*/
#include <nvidia/conftest.h>
#include <linux/clk.h>
#include <linux/host1x-next.h>
#include <linux/io.h>
@@ -548,23 +546,11 @@ static int tegra_mipi_remove(struct platform_device *pdev)
return 0;
}
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_mipi_remove_wrapper(struct platform_device *pdev)
{
tegra_mipi_remove(pdev);
}
#else
static int tegra_mipi_remove_wrapper(struct platform_device *pdev)
{
return tegra_mipi_remove(pdev);
}
#endif
struct platform_driver tegra_mipi_driver = {
.driver = {
.name = "tegra-mipi",
.of_match_table = tegra_mipi_of_match,
},
.probe = tegra_mipi_probe,
.remove = tegra_mipi_remove_wrapper,
.remove = tegra_mipi_remove,
};

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
@@ -1093,10 +1093,8 @@ static int f75308_probe_child_from_dt(struct device *dev,
u32 reg_idx, seg_idx = 0, seg_val;
u8 seg5[F75308_MAX_FAN_SEG_CNT];
const char *val_str;
#if !defined(NV_OF_PROPERTY_FOR_EACH_REMOVED_INTERNAL_ARGS) /* Linux v6.11 */
struct property *prop;
const __be32 *p;
#endif
status = of_property_read_u32(child, "reg", &reg_idx);
if (status) {
@@ -1127,11 +1125,7 @@ static int f75308_probe_child_from_dt(struct device *dev,
if (status)
return status;
#if defined(NV_OF_PROPERTY_FOR_EACH_REMOVED_INTERNAL_ARGS) /* Linux v6.11 */
of_property_for_each_u32(child, "5seg", seg_val) {
#else
of_property_for_each_u32(child, "5seg", prop, p, seg_val) {
#endif
dev_dbg(dev, "%s: seg5[%u]: %u\n", __func__, seg_idx, seg_val);
if (seg_idx < F75308_MAX_FAN_SEG_CNT)
seg5[seg_idx++] = seg_val;

View File

@@ -1,5 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022-2025, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
obj-m += i2c-nvvrs11.o
obj-m += i2c-tegra-slave-byte.o

View File

@@ -2,7 +2,7 @@
/*
* Voltage Regulator Specification: VRS11 High Current Voltage Regulator
*
* Copyright (C) 2022-2024 NVIDIA CORPORATION. All rights reserved.
* Copyright (C) 2022-2023 NVIDIA CORPORATION. All rights reserved.
*/
#include <nvidia/conftest.h>
@@ -120,8 +120,8 @@ static ssize_t show_loopA_rail_power(struct device *dev,
if (current_A < 0)
return current_A;
power = (voltage_A * current_A);
return sprintf(buf, "%u mW\n", power);
power = (voltage_A * current_A)/1000;
return sprintf(buf, "%u W\n", power);
}
static ssize_t show_loopB_rail_name(struct device *dev,
@@ -180,9 +180,9 @@ static ssize_t show_loopB_rail_power(struct device *dev,
if (current_B < 0)
return current_B;
power = (voltage_B * current_B);
power = (voltage_B * current_B)/1000;
return sprintf(buf, "%u mW\n", power);
return sprintf(buf, "%u W\n", power);
}
static DEVICE_ATTR(loopA_rail_name, S_IRUGO, show_loopA_rail_name, NULL);

View File

@@ -1,475 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/iopoll.h>
#define I2C_SL_CNFG 0x20
#define I2C_SL_CNFG_ENABLE_SL BIT(3)
#define I2C_SL_CNFG_NEW_SL BIT(2)
#define I2C_SL_RCVD 0x24
#define I2C_SL_STATUS 0x28
#define I2C_SL_STATUS_END_TRANS BIT(4)
#define I2C_SL_STATUS_SL_IRQ BIT(3)
#define I2C_SL_STATUS_RCVD BIT(2)
#define I2C_SL_STATUS_RNW BIT(1)
#define I2C_SL_ADDR1 0x2c
#define I2C_SL_ADDR2 0x30
#define I2C_SL_ADDR2_MASK 0x1FFFF
#define I2C_7BIT_ADDR_MASK 0x7F
#define I2C_TLOW_SEXT 0x34
#define I2C_SL_DELAY_COUNT 0x3c
#define I2C_SL_DELAY_COUNT_RESET 0x1e
#define I2C_SL_INT_MASK 0x40
#define I2C_SL_INT_SOURCE 0x44
#define I2C_SL_INT_SET 0x48
#define I2C_FIFO_CONTROL 0x5c
#define I2C_INTERRUPT_MASK_REGISTER 0x64
#define I2C_INTERRUPT_STATUS_REGISTER 0x68
#define I2C_INTERRUPT_SOURCE_REGISTER 0x70
#define I2C_INTERRUPT_SLV_WR2RD BIT(26)
#define I2C_INTERRUPT_SET_REGISTER 0x74
#define I2C_CONFIG_LOAD 0x8c
#define I2C_TIMEOUT_CONFIG_LOAD BIT(2)
#define I2C_CONFIG_LOAD_SLV BIT(1)
#define I2C_CONFIG_LOAD_TIMEOUT 1000000
#define I2C_CLKEN_OVERRIDE 0x90
#define I2C_DEBUG_CONTROL 0xa4
struct tegra_i2cslv_dev {
struct device *dev;
struct i2c_adapter adap;
struct clk *div_clk;
struct reset_control *rstc;
void __iomem *base;
struct i2c_client *slave;
raw_spinlock_t xfer_lock;
};
static inline u32 tegra_i2cslv_readl(struct tegra_i2cslv_dev *i2cslv_dev,
unsigned long reg)
{
return readl(i2cslv_dev->base + reg);
}
static inline void tegra_i2cslv_writel(struct tegra_i2cslv_dev *i2cslv_dev,
unsigned long val, unsigned long reg)
{
writel(val, i2cslv_dev->base + reg);
}
static void tegra_i2cslv_dump_reg(struct tegra_i2cslv_dev *i2cslv_dev)
{
dev_warn(i2cslv_dev->dev, "I2C_I2C_SL_INT_SOURCE_0 0x%x\n",
tegra_i2cslv_readl(i2cslv_dev, I2C_SL_INT_SOURCE));
dev_warn(i2cslv_dev->dev, "I2C_INTERRUPT_STATUS_REGISTER_0 0x%x\n",
tegra_i2cslv_readl(i2cslv_dev, I2C_INTERRUPT_STATUS_REGISTER));
dev_warn(i2cslv_dev->dev, "I2C_I2C_SL_STATUS_0 0x%x\n",
tegra_i2cslv_readl(i2cslv_dev, I2C_SL_STATUS));
dev_warn(i2cslv_dev->dev, "I2C_INTERRUPT_SOURCE_REGISTER 0x%x\n",
tegra_i2cslv_readl(i2cslv_dev, I2C_INTERRUPT_SOURCE_REGISTER));
dev_warn(i2cslv_dev->dev, "I2C_I2C_SL_CNFG_0 0x%x\n",
tegra_i2cslv_readl(i2cslv_dev, I2C_SL_CNFG));
dev_warn(i2cslv_dev->dev, "I2C_SL_ADDR1 0x%x\n",
tegra_i2cslv_readl(i2cslv_dev, I2C_SL_ADDR1));
dev_warn(i2cslv_dev->dev, "I2C_INTERRUPT_MASK_REGISTER_0 0x%x\n",
tegra_i2cslv_readl(i2cslv_dev, I2C_INTERRUPT_MASK_REGISTER));
dev_warn(i2cslv_dev->dev, "I2C_I2C_SL_INT_MASK_0 0x%x\n",
tegra_i2cslv_readl(i2cslv_dev, I2C_SL_INT_MASK));
}
static int tegra_i2cslv_load_config(struct tegra_i2cslv_dev *i2cslv_dev)
{
u32 i2c_load_config_reg, val;
int ret;
i2c_load_config_reg = tegra_i2cslv_readl(i2cslv_dev, I2C_CONFIG_LOAD);
i2c_load_config_reg |= I2C_CONFIG_LOAD_SLV;
tegra_i2cslv_writel(i2cslv_dev, i2c_load_config_reg, I2C_CONFIG_LOAD);
ret = readl_poll_timeout_atomic(i2cslv_dev->base +
I2C_CONFIG_LOAD, val,
!(val & I2C_CONFIG_LOAD_SLV),
1000, I2C_CONFIG_LOAD_TIMEOUT);
if (ret)
dev_err(i2cslv_dev->dev, "ERR unable to load i2cslv config\n");
return ret;
}
/* tegra_i2cslv_handle_rx - To get the data byte from bus and provide the
* data to client driver
*/
static void tegra_i2cslv_handle_rx(struct tegra_i2cslv_dev *i2cslv_dev,
const unsigned long i2c_int_src,
const unsigned long i2c_slv_src)
{
u8 value;
if (i2c_slv_src & I2C_SL_STATUS_END_TRANS) {
/* clear the interrupts to release the SCL line */
tegra_i2cslv_writel(i2cslv_dev, I2C_SL_STATUS_END_TRANS |
I2C_SL_STATUS_SL_IRQ, I2C_SL_STATUS);
i2c_slave_event(i2cslv_dev->slave, I2C_SLAVE_STOP, &value);
} else {
value = (u8)tegra_i2cslv_readl(i2cslv_dev, I2C_SL_RCVD);
/* Send the received data to client driver */
i2c_slave_event(i2cslv_dev->slave, I2C_SLAVE_WRITE_RECEIVED, &value);
/* clear the interrupt to release the SCL line */
tegra_i2cslv_writel(i2cslv_dev, I2C_SL_STATUS_SL_IRQ, I2C_SL_STATUS);
}
}
/* tegra_i2cslv_handle_tx - To get the data byte fron client driver and
* send it to master over bus.
*/
static void tegra_i2cslv_handle_tx(struct tegra_i2cslv_dev *i2cslv_dev,
const unsigned long i2c_int_src,
const unsigned long i2c_slv_src)
{
u8 value;
if (i2c_slv_src & I2C_SL_STATUS_END_TRANS) {
/* clear the interrupt to release the SCL line */
tegra_i2cslv_writel(i2cslv_dev, I2C_SL_STATUS_END_TRANS |
I2C_SL_STATUS_SL_IRQ, I2C_SL_STATUS);
i2c_slave_event(i2cslv_dev->slave, I2C_SLAVE_STOP, &value);
} else {
/* clear the interrupt to release the SCL line */
tegra_i2cslv_writel(i2cslv_dev, I2C_SL_STATUS_SL_IRQ, I2C_SL_STATUS);
/* Get the data byte from client driver*/
i2c_slave_event(i2cslv_dev->slave, I2C_SLAVE_READ_PROCESSED, &value);
tegra_i2cslv_writel(i2cslv_dev, value, I2C_SL_RCVD);
}
}
static int tegra_i2cslv_init(struct tegra_i2cslv_dev *i2cslv_dev)
{
u32 reg;
int ret;
ret = clk_enable(i2cslv_dev->div_clk);
if (ret < 0) {
dev_err(i2cslv_dev->dev, "Enable div-clk failed: %d\n", ret);
return ret;
}
/* Reset the controller */
reset_control_assert(i2cslv_dev->rstc);
udelay(2);
reset_control_deassert(i2cslv_dev->rstc);
/* Program the 7-bit slave address */
tegra_i2cslv_writel(i2cslv_dev, i2cslv_dev->slave->addr &
I2C_7BIT_ADDR_MASK, I2C_SL_ADDR1);
/* Specify its 7-bit address mode */
reg = tegra_i2cslv_readl(i2cslv_dev, I2C_SL_ADDR2);
reg &= ~(I2C_SL_ADDR2_MASK);
tegra_i2cslv_writel(i2cslv_dev, reg, I2C_SL_ADDR2);
/* Unmask WR2RD interrupt, just to clear it */
tegra_i2cslv_writel(i2cslv_dev, (I2C_INTERRUPT_SLV_WR2RD),
I2C_INTERRUPT_MASK_REGISTER);
tegra_i2cslv_writel(i2cslv_dev, (I2C_SL_STATUS_END_TRANS |
I2C_SL_STATUS_SL_IRQ | I2C_SL_STATUS_RCVD),
I2C_SL_INT_MASK);
reg = tegra_i2cslv_readl(i2cslv_dev, I2C_SL_CNFG);
reg |= (I2C_SL_CNFG_NEW_SL | I2C_SL_CNFG_ENABLE_SL);
tegra_i2cslv_writel(i2cslv_dev, reg, I2C_SL_CNFG);
return tegra_i2cslv_load_config(i2cslv_dev);
}
static void tegra_i2cslv_deinit(struct tegra_i2cslv_dev *i2cslv_dev)
{
tegra_i2cslv_writel(i2cslv_dev, 0, I2C_INTERRUPT_MASK_REGISTER);
tegra_i2cslv_writel(i2cslv_dev, 0, I2C_SL_INT_MASK);
clk_disable(i2cslv_dev->div_clk);
}
static irqreturn_t tegra_i2cslv_isr(int irq, void *dev_id)
{
struct tegra_i2cslv_dev *i2cslv_dev = dev_id;
u32 i2c_int_src, i2c_slv_int_src, i2c_slv_sts;
u8 value;
unsigned long flags;
raw_spin_lock_irqsave(&i2cslv_dev->xfer_lock, flags);
i2c_int_src = tegra_i2cslv_readl(i2cslv_dev,
I2C_INTERRUPT_SOURCE_REGISTER);
i2c_slv_int_src = tegra_i2cslv_readl(i2cslv_dev, I2C_SL_INT_SOURCE);
i2c_slv_sts = tegra_i2cslv_readl(i2cslv_dev, I2C_SL_STATUS);
/* Address received */
if ((i2c_slv_int_src & I2C_SL_STATUS_SL_IRQ) &&
(i2c_slv_int_src & I2C_SL_STATUS_RCVD)) {
/* End of transfer of previous transaction, just clear it */
if (i2c_slv_int_src & I2C_SL_STATUS_END_TRANS) {
i2c_slave_event(i2cslv_dev->slave, I2C_SLAVE_STOP,
&value);
tegra_i2cslv_writel(i2cslv_dev, I2C_SL_STATUS_END_TRANS,
I2C_SL_STATUS);
}
/* Clear the interrupt */
tegra_i2cslv_writel(i2cslv_dev, I2C_SL_STATUS_SL_IRQ |
I2C_SL_STATUS_RCVD, I2C_SL_STATUS);
/* if RNW, master issued read. */
if (i2c_slv_sts & I2C_SL_STATUS_RNW) {
i2c_slave_event(i2cslv_dev->slave,
I2C_SLAVE_READ_REQUESTED, &value);
tegra_i2cslv_writel(i2cslv_dev, value,
I2C_SL_RCVD);
} else {
i2c_slave_event(i2cslv_dev->slave,
I2C_SLAVE_WRITE_REQUESTED, &value);
}
goto done;
}
if (unlikely(i2c_int_src & I2C_INTERRUPT_SLV_WR2RD)) {
/* Clear WR2RD interrupt */
tegra_i2cslv_writel(i2cslv_dev, I2C_INTERRUPT_SLV_WR2RD,
I2C_INTERRUPT_STATUS_REGISTER);
goto done;
}
if ((i2c_slv_int_src & I2C_SL_STATUS_SL_IRQ)) {
if (!(i2c_slv_sts & I2C_SL_STATUS_RNW)) {
/* Master write and Slave receive */
tegra_i2cslv_handle_rx(i2cslv_dev, i2c_int_src,
i2c_slv_int_src);
goto done;
} else if (i2c_slv_sts & I2C_SL_STATUS_RNW) {
/* Master read and slave write */
tegra_i2cslv_handle_tx(i2cslv_dev, i2c_int_src,
i2c_slv_int_src);
goto done;
}
} else {
dev_err(i2cslv_dev->dev, "Slave IRQ not set\n");
goto err;
}
err:
tegra_i2cslv_dump_reg(i2cslv_dev);
tegra_i2cslv_init(i2cslv_dev);
done:
raw_spin_unlock_irqrestore(&i2cslv_dev->xfer_lock, flags);
return IRQ_HANDLED;
}
static int tegra_reg_slave(struct i2c_client *slave)
{
struct tegra_i2cslv_dev *i2cslv_dev =
i2c_get_adapdata(slave->adapter);
int ret;
if (i2cslv_dev->slave)
return -EBUSY;
if (slave->flags & I2C_CLIENT_TEN)
return -EAFNOSUPPORT;
i2cslv_dev->slave = slave;
ret = clk_enable(i2cslv_dev->div_clk);
if (ret < 0) {
dev_err(i2cslv_dev->dev, "Enable div-clk failed: %d\n", ret);
return ret;
}
return tegra_i2cslv_init(i2cslv_dev);
}
static int tegra_unreg_slave(struct i2c_client *slave)
{
struct tegra_i2cslv_dev *i2cslv_dev =
i2c_get_adapdata(slave->adapter);
WARN_ON(!i2cslv_dev->slave);
tegra_i2cslv_deinit(i2cslv_dev);
i2cslv_dev->slave = NULL;
return 0;
}
static u32 tegra_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SLAVE;
}
static const struct i2c_algorithm tegra_i2cslv_algo = {
.functionality = tegra_i2c_func,
.reg_slave = tegra_reg_slave,
.unreg_slave = tegra_unreg_slave,
};
static int tegra_i2cslv_probe(struct platform_device *pdev)
{
struct tegra_i2cslv_dev *i2cslv_dev;
struct i2c_adapter *adap;
int irq, ret;
i2cslv_dev = devm_kzalloc(&pdev->dev, sizeof(*i2cslv_dev), GFP_KERNEL);
if (!i2cslv_dev)
return -ENOMEM;
i2cslv_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(i2cslv_dev->base))
return PTR_ERR(i2cslv_dev->base);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "failed to get IRQ %d\n", irq);
return irq;
}
i2cslv_dev->div_clk = devm_clk_get(&pdev->dev, "div-clk");
if (IS_ERR(i2cslv_dev->div_clk)) {
dev_err(&pdev->dev, "missing controller clock");
return PTR_ERR(i2cslv_dev->div_clk);
}
i2cslv_dev->rstc = devm_reset_control_get(&pdev->dev, "i2c");
if (IS_ERR(i2cslv_dev->rstc)) {
dev_err(&pdev->dev, "missing controller reset\n");
return PTR_ERR(i2cslv_dev->rstc);
}
i2cslv_dev->dev = &pdev->dev;
raw_spin_lock_init(&i2cslv_dev->xfer_lock);
adap = &i2cslv_dev->adap;
adap->algo = &tegra_i2cslv_algo;
adap->class = I2C_CLASS_DEPRECATED;
adap->dev.parent = &pdev->dev;
adap->dev.of_node = pdev->dev.of_node;
i2c_set_adapdata(adap, i2cslv_dev);
platform_set_drvdata(pdev, i2cslv_dev);
strscpy(adap->name, pdev->name, sizeof(adap->name));
ret = clk_prepare(i2cslv_dev->div_clk);
if (ret < 0) {
dev_err(&pdev->dev, "clock prepare failed %d\n", ret);
return ret;
}
ret = devm_request_irq(&pdev->dev, irq, tegra_i2cslv_isr,
0, dev_name(&pdev->dev), i2cslv_dev);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n", irq);
clk_unprepare(i2cslv_dev->div_clk);
return ret;
}
ret = i2c_add_adapter(&i2cslv_dev->adap);
if (ret) {
dev_err(&pdev->dev, "Failed to add I2C adapter\n");
clk_unprepare(i2cslv_dev->div_clk);
return ret;
}
return 0;
}
static int tegra_i2cslv_remove(struct platform_device *pdev)
{
struct tegra_i2cslv_dev *i2cslv_dev = platform_get_drvdata(pdev);
i2c_del_adapter(&i2cslv_dev->adap);
clk_unprepare(i2cslv_dev->div_clk);
return 0;
}
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_i2cslv_remove_wrapper(struct platform_device *pdev)
{
tegra_i2cslv_remove(pdev);
}
#else
static int tegra_i2cslv_remove_wrapper(struct platform_device *pdev)
{
return tegra_i2cslv_remove(pdev);
}
#endif
#ifdef CONFIG_PM_SLEEP
static int tegra_i2cslv_suspend(struct device *dev)
{
struct tegra_i2cslv_dev *i2cslv_dev = dev_get_drvdata(dev);
unsigned long flags;
raw_spin_lock_irqsave(&i2cslv_dev->xfer_lock, flags);
tegra_i2cslv_deinit(i2cslv_dev);
raw_spin_unlock_irqrestore(&i2cslv_dev->xfer_lock, flags);
return 0;
}
static int tegra_i2cslv_resume(struct device *dev)
{
struct tegra_i2cslv_dev *i2cslv_dev = dev_get_drvdata(dev);
unsigned long flags;
int ret;
raw_spin_lock_irqsave(&i2cslv_dev->xfer_lock, flags);
ret = tegra_i2cslv_init(i2cslv_dev);
raw_spin_unlock_irqrestore(&i2cslv_dev->xfer_lock, flags);
return ret;
}
#endif
static const struct dev_pm_ops tegra_i2cslv_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(tegra_i2cslv_suspend, tegra_i2cslv_resume)
};
static const struct of_device_id tegra_i2cslv_of_match[] = {
{.compatible = "nvidia,tegra-i2c-slave-byte",},
{}
};
MODULE_DEVICE_TABLE(of, tegra_i2cslv_of_match);
static struct platform_driver tegra_i2cslv_driver = {
.probe = tegra_i2cslv_probe,
.remove = tegra_i2cslv_remove_wrapper,
.driver = {
.name = "tegra-i2cslv",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(tegra_i2cslv_of_match),
.pm = &tegra_i2cslv_pm_ops,
},
};
module_platform_driver(tegra_i2cslv_driver);
MODULE_AUTHOR("Shardar Shariff Md <smohammed@nvidia.com>");
MODULE_DESCRIPTION("NVIDIA Tegra I2C slave driver");
MODULE_LICENSE("GPL v2");

View File

@@ -20,7 +20,6 @@ obj-m += nv_imx477.o
obj-m += nv_ov5693.o
obj-m += nv_ar0234.o
obj-m += nv_hawk_owl.o
obj-m += max929x.o
endif
obj-m += pca9570.o

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-FileCopyrightText: Copyright (c) 2020-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
/*
* imx477_mode_tbls.h - imx477 sensor mode tables
* Copyright (c) 2020-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
*/
#ifndef __IMX477_I2C_TABLES__
@@ -575,9 +575,249 @@ static const imx477_reg imx477_mode_1920x1080_60fps[] = {
{IMX477_TABLE_END, 0x0000}
};
static const imx477_reg imx477_mode_3840x2160_30fps_4lane[] = {
{0x0112, 0x0A},
{0x0113, 0x0A},
{0x0114, 0x03},
{0x0342, 0x16},
{0x0343, 0xC8},
{0x0340, 0x12},
{0x0341, 0xC0},
{0x0344, 0x00},
{0x0345, 0x00},
{0x0346, 0x01},
{0x0347, 0xB8},
{0x0348, 0x0F},
{0x0349, 0xD7},
{0x034A, 0x0A},
{0x034B, 0x27},
{0x00E3, 0x00},
{0x00E4, 0x00},
{0x00FC, 0x0A},
{0x00FD, 0x0A},
{0x00FE, 0x0A},
{0x00FF, 0x0A},
{0x0E13, 0x00},
{0x0220, 0x00},
{0x0221, 0x11},
{0x0381, 0x01},
{0x0383, 0x01},
{0x0385, 0x01},
{0x0387, 0x01},
{0x0900, 0x00},
{0x0901, 0x11},
{0x0902, 0x02},
{0x3140, 0x02},
{0x3C00, 0x00},
{0x3C01, 0x03},
{0x3C02, 0xDC},
{0x3F0D, 0x00},
{0x5748, 0x07},
{0x5749, 0xFF},
{0x574A, 0x00},
{0x574B, 0x00},
{0x7B75, 0x0E},
{0x7B76, 0x09},
{0x7B77, 0x0C},
{0x7B78, 0x06},
{0x7B79, 0x3B},
{0x7B53, 0x01},
{0x9369, 0x5A},
{0x936B, 0x55},
{0x936D, 0x28},
{0x9304, 0x03},
{0x9305, 0x00},
{0x9E9A, 0x2F},
{0x9E9B, 0x2F},
{0x9E9C, 0x2F},
{0x9E9D, 0x00},
{0x9E9E, 0x00},
{0x9E9F, 0x00},
{0xA2A9, 0x60},
{0xA2B7, 0x00},
{0x0401, 0x00},
{0x0404, 0x00},
{0x0405, 0x10},
{0x0408, 0x00},
{0x0409, 0x6C},
{0x040A, 0x00},
{0x040B, 0x00},
{0x040C, 0x0F},
{0x040D, 0x00},
{0x040E, 0x08},
{0x040F, 0x70},
{0x034C, 0x0F},
{0x034D, 0x00},
{0x034E, 0x08},
{0x034F, 0x70},
{0x0301, 0x05},
{0x0303, 0x02},
{0x0305, 0x02},
{0x0306, 0x00},
{0x0307, 0xAF},
{0x0309, 0x0A},
{0x030B, 0x01},
{0x030D, 0x02},
{0x030E, 0x00},
{0x030F, 0x7D},
{0x0310, 0x01},
{0x0820, 0x17},
{0x0821, 0x70},
{0x0822, 0x00},
{0x0823, 0x00},
{0x080A, 0x00},
{0x080B, 0x97},
{0x080C, 0x00},
{0x080D, 0x5F},
{0x080E, 0x00},
{0x080F, 0x9F},
{0x0810, 0x00},
{0x0811, 0x6F},
{0x0812, 0x00},
{0x0813, 0x6F},
{0x0814, 0x00},
{0x0815, 0x57},
{0x0816, 0x01},
{0x0817, 0x87},
{0x0818, 0x00},
{0x0819, 0x4F},
{0xE04C, 0x00},
{0xE04D, 0x9F},
{0xE04E, 0x00},
{0xE04F, 0x1F},
{0x3E20, 0x01},
{0x3E37, 0x00},
{0x3F50, 0x00},
{0x3F56, 0x00},
{0x3F57, 0xA7},
{IMX477_TABLE_WAIT_MS, IMX477_WAIT_MS},
{IMX477_TABLE_END, 0x0000}
};
static const imx477_reg imx477_mode_1920x1080_60fps_4lane[] = {
{0x0112, 0x0A},
{0x0113, 0x0A},
{0x0114, 0x03},
{0x0342, 0x0C},
{0x0343, 0x04},
{0x0340, 0x11},
{0x0341, 0xC6},
{0x0344, 0x00},
{0x0345, 0x00},
{0x0346, 0x01},
{0x0347, 0xB8},
{0x0348, 0x0F},
{0x0349, 0xD7},
{0x034A, 0x0A},
{0x034B, 0x27},
{0x00E3, 0x00},
{0x00E4, 0x00},
{0x00FC, 0x0A},
{0x00FD, 0x0A},
{0x00FE, 0x0A},
{0x00FF, 0x0A},
{0x0220, 0x00},
{0x0221, 0x11},
{0x0381, 0x01},
{0x0383, 0x01},
{0x0385, 0x01},
{0x0387, 0x01},
{0x0900, 0x01},
{0x0901, 0x22},
{0x0902, 0x02},
{0x3140, 0x02},
{0x3C00, 0x00},
{0x3C01, 0x01},
{0x3C02, 0x9C},
{0x3F0D, 0x00},
{0x5748, 0x00},
{0x5749, 0x00},
{0x574A, 0x00},
{0x574B, 0xA4},
{0x7B75, 0x0E},
{0x7B76, 0x09},
{0x7B77, 0x08},
{0x7B78, 0x06},
{0x7B79, 0x34},
{0x7B53, 0x00},
{0x9369, 0x73},
{0x936B, 0x64},
{0x936D, 0x5F},
{0x9304, 0x03},
{0x9305, 0x80},
{0x9E9A, 0x2F},
{0x9E9B, 0x2F},
{0x9E9C, 0x2F},
{0x9E9D, 0x00},
{0x9E9E, 0x00},
{0x9E9F, 0x00},
{0xA2A9, 0x27},
{0xA2B7, 0x03},
{0x0401, 0x00},
{0x0404, 0x00},
{0x0405, 0x10},
{0x0408, 0x00},
{0x0409, 0x36},
{0x040A, 0x00},
{0x040B, 0x00},
{0x040C, 0x07},
{0x040D, 0x80},
{0x040E, 0x04},
{0x040F, 0x38},
{0x034C, 0x07},
{0x034D, 0x80},
{0x034E, 0x04},
{0x034F, 0x38},
{0x0301, 0x05},
{0x0303, 0x02},
{0x0305, 0x02},
{0x0306, 0x00},
{0x0307, 0xAF},
{0x0309, 0x0A},
{0x030B, 0x01},
{0x030D, 0x02},
{0x030E, 0x00},
{0x030F, 0x7D},
{0x0310, 0x01},
{0x0820, 0x17},
{0x0821, 0x70},
{0x0822, 0x00},
{0x0823, 0x00},
{0x080A, 0x00},
{0x080B, 0x97},
{0x080C, 0x00},
{0x080D, 0x5F},
{0x080E, 0x00},
{0x080F, 0x9F},
{0x0810, 0x00},
{0x0811, 0x6F},
{0x0812, 0x00},
{0x0813, 0x6F},
{0x0814, 0x00},
{0x0815, 0x57},
{0x0816, 0x01},
{0x0817, 0x87},
{0x0818, 0x00},
{0x0819, 0x4F},
{0xE04C, 0x00},
{0xE04D, 0x9F},
{0xE04E, 0x00},
{0xE04F, 0x1F},
{0x3E20, 0x01},
{0x3E37, 0x00},
{0x3F50, 0x00},
{0x3F56, 0x00},
{0x3F57, 0x58},
{0X3FF9, 0x01},
{IMX477_TABLE_WAIT_MS, IMX477_WAIT_MS},
{IMX477_TABLE_END, 0x0000}
};
enum {
IMX477_MODE_3840x2160_30FPS,
IMX477_MODE_1920x1080_60FPS,
IMX477_MODE_3840x2160_30FPS_4LANE,
IMX477_MODE_1920x1080_60FPS_4LANE,
IMX477_MODE_COMMON,
IMX477_START_STREAM,
IMX477_STOP_STREAM,
@@ -586,6 +826,8 @@ enum {
static const imx477_reg *mode_table[] = {
[IMX477_MODE_3840x2160_30FPS] = imx477_mode_3840x2160_30fps,
[IMX477_MODE_1920x1080_60FPS] = imx477_mode_1920x1080_60fps,
[IMX477_MODE_3840x2160_30FPS_4LANE] = imx477_mode_3840x2160_30fps_4lane,
[IMX477_MODE_1920x1080_60FPS_4LANE] = imx477_mode_1920x1080_60fps_4lane,
[IMX477_MODE_COMMON] = imx477_mode_common,
[IMX477_START_STREAM] = imx477_start,
[IMX477_STOP_STREAM] = imx477_stop,

View File

@@ -1,194 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* max929x.c - max929x IO Expander driver
*/
#include <nvidia/conftest.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <media/camera_common.h>
#include <linux/module.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include "max929x.h"
struct max929x {
struct i2c_client *i2c_client;
struct regmap *regmap;
unsigned int pwdn_gpio;
unsigned short ser_addr;
};
struct max929x *priv;
static int max929x_write_reg(u8 slave_addr, u16 reg, u8 val)
{
struct i2c_client *i2c_client = priv->i2c_client;
int err;
i2c_client->addr = slave_addr;
err = regmap_write(priv->regmap, reg, val);
if (err)
dev_err(&i2c_client->dev, "%s:i2c write failed, slave_addr 0x%x, 0x%x = 0x%x\n",
__func__, slave_addr, reg, val);
return err;
}
static int max929x_write_reg_list(struct max929x_reg *table, int size)
{
struct device dev = priv->i2c_client->dev;
int err = 0;
int i;
u8 slave_addr;
u16 reg;
u8 val;
for (i = 0; i < size; i++) {
if (table[i].slave_addr == SER_SLAVE2)
slave_addr = priv->ser_addr;
else
slave_addr = table[i].slave_addr;
reg = table[i].reg;
val = table[i].val;
if (slave_addr == 0xf1) {
msleep(val);
msleep(2000);
continue;
}
dev_dbg(&dev, "%s: size %d, slave_addr 0x%x, reg 0x%x, val 0x%x\n",
__func__, size, slave_addr, reg, val);
err = max929x_write_reg(slave_addr, reg, val);
if (err != 0)
break;
mdelay(5);
}
return err;
}
static struct regmap_config max929x_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
};
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
static int max929x_probe(struct i2c_client *client)
#else
static int max929x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
#endif
{
struct device dev = client->dev;
struct device_node *np = (&dev)->of_node;
unsigned short ser_addr = SER_SLAVE2;
int err;
dev_dbg(&dev, "%s: enter\n", __func__);
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
priv->i2c_client = client;
priv->regmap = devm_regmap_init_i2c(priv->i2c_client, &max929x_regmap_config);
if (IS_ERR(priv->regmap)) {
dev_err(&client->dev,
"regmap init failed: %ld\n", PTR_ERR(priv->regmap));
return -ENODEV;
}
priv->pwdn_gpio = of_get_named_gpio(np, "pwdn-gpios", 0);
if (priv->pwdn_gpio < 0) {
dev_err(&dev, "pwdn-gpios not found\n");
return -EINVAL;
}
if (priv->pwdn_gpio) {
gpio_direction_output(priv->pwdn_gpio, 1);
gpio_set_value(priv->pwdn_gpio, 1);
msleep(100);
}
/*
* Try to find the I2C address of serializer by writting to register
* 0x00 at i2c slave address 0x62 and 0x40. When write is successful
* the slave address is saved and used when configuring serializer.
*/
if (max929x_write_reg(SER_SLAVE2, MAX9295_DEV_ADDR, SER_SLAVE2 << 1)) {
if (max929x_write_reg(SER_SLAVE1, MAX9295_DEV_ADDR, SER_SLAVE1 << 1)) {
dev_err(&dev, "%s: failed to find serializer at 0x%x or 0x%x\n",
__func__, SER_SLAVE2, SER_SLAVE1);
return -ENODEV;
}
ser_addr = SER_SLAVE1;
}
msleep(100);
priv->ser_addr = ser_addr;
err = max929x_write_reg_list(max929x_Double_Dser_Ser_init,
sizeof(max929x_Double_Dser_Ser_init)/sizeof(struct max929x_reg));
if (err == 0)
dev_dbg(&dev, "%s: success\n", __func__);
else
dev_err(&dev, "%s: fail\n", __func__);
dev_set_drvdata(&client->dev, priv);
return 0;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
static int max929x_remove(struct i2c_client *client)
#else
static void max929x_remove(struct i2c_client *client)
#endif
{
struct device dev = client->dev;
gpio_set_value(priv->pwdn_gpio, 0);
dev_dbg(&dev, "%s: \n", __func__);
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
return 0;
#endif
}
static const struct i2c_device_id max929x_id[] = {
{ "max929x", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, max929x_id);
const struct of_device_id max929x_of_match[] = {
{ .compatible = "Maxim,max929x", },
{ },
};
MODULE_DEVICE_TABLE(of, max929x_of_match);
static struct i2c_driver max929x_i2c_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "max929x",
.of_match_table = of_match_ptr(max929x_of_match),
},
.probe = max929x_probe,
.remove = max929x_remove,
.id_table = max929x_id,
};
module_i2c_driver(max929x_i2c_driver);
MODULE_DESCRIPTION("IO Expander driver max929x");
MODULE_AUTHOR("NVIDIA Corporation");
MODULE_LICENSE("GPL v2");

View File

@@ -1,152 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-FileCopyrightText: Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
#ifndef __MAX929X_H__
#define __MAX929X_H__
/* TI FPD Link III 954 deser I2C address */
#define TI954_ADDR (0x30)
/* TI FPD Link III 953 ser I2C address */
#define TI953_ADDR (0x18)
/* TI 953 alias address */
#define TI953_CAM1_ADDR (0x29)
#define TI953_CAM2_ADDR (0X2A)
#define MAX9295_DEV_ADDR 0x00
#define SENSOR_ADDR (0x1a)
/* CAM alias address */
#define CAM1_SENSOR_ADDR (0x1b)
#define CAM2_SENSOR_ADDR (0x1c)
#define TI954_RESET_ADDR (0x01)
#define TI954_RESET_VAL (0x02)
#define AFDRV_I2C_ADDR (0x3E)
/*AF ctrl*/
#define AFDRV1_I2C_ADDR (0x21)
#define AFDRV2_I2C_ADDR (0x20)
#define EEPROM_I2C_ADDR (0x50)
/*eeprom ctrl*/
#define EEPROM1_I2C_ADDR (0x51)
#define EEPROM2_I2C_ADDR (0x52)
struct max929x_reg {
u8 slave_addr;
u16 reg;
u8 val;
};
/* Serializer slave addresses */
#define SER_SLAVE1 0x40
#define SER_SLAVE2 0x62
/* Deserializer slave addresses */
#define DESER_SLAVE 0x48
/*
* MAX9296 i2c addr 0x90(8bits) 0x48(7bits)
* (MAX9296 link A) MAX9295 i2c addr 0xc4(8bits) 0x62(7bits)
*/
static struct max929x_reg max929x_Double_Dser_Ser_init[] = {
/* set MFP0 low to reset sensor */
{0x62, 0x02be, 0x80},
/* Set SER to 1x4 mode (phy_config = 0) */
{0x62, 0x0330, 0x00},
{0x62, 0x0332, 0xe4},
/* Additional lane map */
{0x62, 0x0333, 0xe4},
/* Set 4 lanes for serializer (ctrl1_num_lanes = 3) */
{0x62, 0x0331, 0x31},
/* Start video from both port A and port B. */
{0x62, 0x0311, 0x20},
/*
* Enable info lines. Additional start bits for Port A and B.
* Use data from port B for all pipelines
*/
{0x62, 0x0308, 0x62},
/* Route 16bit DCG (DT = 0x30) to VIDEO_X (Bit 6 enable) */
{0x62, 0x0314, 0x22},
/* Route 12bit RAW (DT = 0x2C) to VIDEO_Y (Bit 6 enable) */
{0x62, 0x0316, 0x6c},
/* Route EMBEDDED8 to VIDEO_Z (Bit 6 enable) */
{0x62, 0x0318, 0x22},
/* Unused VIDEO_U */
{0x62, 0x031A, 0x22},
/*
* Make sure all pipelines start transmission
* (VID_TX_EN_X/Y/Z/U = 1)
*/
{0x62, 0x0002, 0x22},
/* Set MIPI Phy Mode: 2x(1x4) mode */
{0x48, 0x0330, 0x04},
/* lane maps - all 4 ports mapped straight */
{0x48, 0x0333, 0x4E},
/* Additional lane map */
{0x48, 0x0334, 0xE4},
/*
* lane count - 0 lanes striping on controller 0
* (Port A slave in 2x1x4 mode).
*/
{0x48, 0x040A, 0x00},
/*
* lane count - 4 lanes striping on controller 1
* (Port A master in 2x1x4 mode).
*/
{0x48, 0x044A, 0xd0},
/*
* lane count - 4 lanes striping on controller 2
* (Port B master in 2x1x4 mode).
*/
{0x48, 0x048A, 0xd0},
/*
* lane count - 0 lanes striping on controller 3
* (Port B slave in 2x1x4 mode).
*/
{0x48, 0x04CA, 0x00},
/*
* MIPI clock rate - 1.5Gbps from controller 0 clock
* (Port A slave in 2x1x4 mode).
*/
{0x48, 0x031D, 0x2f},
/*
* MIPI clock rate - 1.5Gbps from controller 1 clock
* (Port A master in 2x1x4 mode).
*/
{0x48, 0x0320, 0x2f},
/*
* MIPI clock rate - 1.5Gbps from controller 2 clock
* (Port B master in 2x1x4 mode).
*/
{0x48, 0x0323, 0x2f},
/*
* MIPI clock rate - 1.5Gbps from controller 2 clock
* (Port B slave in 2x1x4 mode).
*/
{0x48, 0x0326, 0x2f},
/* Route data from stream 0 to pipe X */
{0x48, 0x0050, 0x00},
/* Route data from stream 0 to pipe Y */
{0x48, 0x0051, 0x01},
/* Route data from stream 0 to pipe Z */
{0x48, 0x0052, 0x02},
/* Route data from stream 0 to pipe U */
{0x48, 0x0053, 0x03},
/* Enable all PHYS. */
{0x48, 0x0332, 0xF0},
/* Enable sensor power down pin. Put imager in,Active mode */
{0x62, 0x02be, 0x90},
/* Output RCLK to sensor. */
{0x62, 0x03F1, 0x89},
/* MFP8 for FSIN */
{0x62, 0x02D8, 0x10},
{0x62, 0x02D6, 0x04},
/* need disable pixel clk out inb order to use MFP1 */
{0x48, 0x0005, 0x00},
/* GPIO TX compensation */
{0x48, 0x02B3, 0x83},
{0x48, 0x02B4, 0x10},
};
#endif

View File

@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2015-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* nv_imx219.c - imx219 sensor driver
*
* Copyright (c) 2015-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
*/
#include <nvidia/conftest.h>
@@ -746,7 +747,6 @@ static int imx219_probe(struct i2c_client *client,
err = tegracam_v4l2subdev_register(tc_dev, true);
if (err) {
tegracam_device_unregister(tc_dev);
dev_err(dev, "tegra camera subdev registration failed\n");
return err;
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,911 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2018-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <media/max9295.h>
#include <media/max9296.h>
#include <media/tegracam_core.h>
#include "imx390_mode_tbls.h"
#define IMX390_MIN_GAIN (0)
#define IMX390_MAX_GAIN (30)
#define IMX390_MAX_GAIN_REG ((IMX390_MAX_GAIN - IMX390_MIN_GAIN) * 10 / 3)
#define IMX390_DEFAULT_FRAME_LENGTH (1125)
#define IMX390_FRAME_LENGTH_ADDR_MSB 0x200A
#define IMX390_FRAME_LENGTH_ADDR_MID 0x2009
#define IMX390_FRAME_LENGTH_ADDR_LSB 0x2008
#define IMX390_COARSE_TIME_SHS1_ADDR_MSB 0x000E
#define IMX390_COARSE_TIME_SHS1_ADDR_MID 0x000D
#define IMX390_COARSE_TIME_SHS1_ADDR_LSB 0x000C
#define IMX390_COARSE_TIME_SHS2_ADDR_MSB 0x0012
#define IMX390_COARSE_TIME_SHS2_ADDR_MID 0x0011
#define IMX390_COARSE_TIME_SHS2_ADDR_LSB 0x0010
#define IMX390_GROUP_HOLD_ADDR 0x0008
#define IMX390_ANALOG_GAIN_SP1H_ADDR 0x0018
#define IMX390_ANALOG_GAIN_SP1L_ADDR 0x001A
static const struct of_device_id imx390_of_match[] = {
{ .compatible = "sony,imx390",},
{ },
};
MODULE_DEVICE_TABLE(of, imx390_of_match);
static const u32 ctrl_cid_list[] = {
TEGRA_CAMERA_CID_GAIN,
TEGRA_CAMERA_CID_EXPOSURE,
TEGRA_CAMERA_CID_EXPOSURE_SHORT,
TEGRA_CAMERA_CID_FRAME_RATE,
TEGRA_CAMERA_CID_HDR_EN,
};
struct imx390 {
struct i2c_client *i2c_client;
const struct i2c_device_id *id;
struct v4l2_subdev *subdev;
struct device *ser_dev;
struct device *dser_dev;
struct gmsl_link_ctx g_ctx;
u32 frame_length;
struct camera_common_data *s_data;
struct tegracam_device *tc_dev;
};
static const struct regmap_config sensor_regmap_config = {
.reg_bits = 16,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
};
static inline void imx390_get_frame_length_regs(imx390_reg *regs,
u32 frame_length)
{
regs->addr = IMX390_FRAME_LENGTH_ADDR_MSB;
regs->val = (frame_length >> 16) & 0x01;
(regs + 1)->addr = IMX390_FRAME_LENGTH_ADDR_MID;
(regs + 1)->val = (frame_length >> 8) & 0xff;
(regs + 2)->addr = IMX390_FRAME_LENGTH_ADDR_LSB;
(regs + 2)->val = (frame_length) & 0xff;
}
static inline void imx390_get_coarse_time_regs_shs1(imx390_reg *regs,
u32 coarse_time)
{
regs->addr = IMX390_COARSE_TIME_SHS1_ADDR_MSB;
regs->val = (coarse_time >> 16) & 0x0f;
(regs + 1)->addr = IMX390_COARSE_TIME_SHS1_ADDR_MID;
(regs + 1)->val = (coarse_time >> 8) & 0xff;
(regs + 2)->addr = IMX390_COARSE_TIME_SHS1_ADDR_LSB;
(regs + 2)->val = (coarse_time) & 0xff;
}
static inline void imx390_get_coarse_time_regs_shs2(imx390_reg *regs,
u32 coarse_time)
{
regs->addr = IMX390_COARSE_TIME_SHS2_ADDR_MSB;
regs->val = (coarse_time >> 16) & 0x0f;
(regs + 1)->addr = IMX390_COARSE_TIME_SHS2_ADDR_MID;
(regs + 1)->val = (coarse_time >> 8) & 0xff;
(regs + 2)->addr = IMX390_COARSE_TIME_SHS2_ADDR_LSB;
(regs + 2)->val = (coarse_time) & 0xff;
}
static inline void imx390_get_gain_reg(imx390_reg *regs,
u16 gain)
{
regs->addr = IMX390_ANALOG_GAIN_SP1H_ADDR;
regs->val = (gain) & 0xff;
(regs + 1)->addr = IMX390_ANALOG_GAIN_SP1H_ADDR + 1;
(regs + 1)->val = (gain >> 8) & 0xff;
(regs + 2)->addr = IMX390_ANALOG_GAIN_SP1L_ADDR;
(regs + 2)->val = (gain) & 0xff;
(regs + 3)->addr = IMX390_ANALOG_GAIN_SP1L_ADDR + 1;
(regs + 3)->val = (gain >> 8) & 0xff;
}
static int test_mode;
module_param(test_mode, int, 0644);
static inline int imx390_read_reg(struct camera_common_data *s_data,
u16 addr, u8 *val)
{
int err = 0;
u32 reg_val = 0;
err = regmap_read(s_data->regmap, addr, &reg_val);
*val = reg_val & 0xFF;
return err;
}
static int imx390_write_reg(struct camera_common_data *s_data,
u16 addr, u8 val)
{
int err;
struct device *dev = s_data->dev;
err = regmap_write(s_data->regmap, addr, val);
if (err)
dev_err(dev, "%s:i2c write failed, 0x%x = %x\n",
__func__, addr, val);
return err;
}
static int imx390_write_table(struct imx390 *priv,
const imx390_reg table[])
{
struct camera_common_data *s_data = priv->s_data;
return regmap_util_write_table_8(s_data->regmap,
table,
NULL, 0,
IMX390_TABLE_WAIT_MS,
IMX390_TABLE_END);
}
static struct mutex serdes_lock__;
static int imx390_gmsl_serdes_setup(struct imx390 *priv)
{
int err = 0;
int des_err = 0;
struct device *dev;
if (!priv || !priv->ser_dev || !priv->dser_dev || !priv->i2c_client)
return -EINVAL;
dev = &priv->i2c_client->dev;
mutex_lock(&serdes_lock__);
/* For now no separate power on required for serializer device */
max9296_power_on(priv->dser_dev);
/* setup serdes addressing and control pipeline */
err = max9296_setup_link(priv->dser_dev, &priv->i2c_client->dev);
if (err) {
dev_err(dev, "gmsl deserializer link config failed\n");
goto error;
}
err = max9295_setup_control(priv->ser_dev);
/* proceed even if ser setup failed, to setup deser correctly */
if (err)
dev_err(dev, "gmsl serializer setup failed\n");
des_err = max9296_setup_control(priv->dser_dev, &priv->i2c_client->dev);
if (des_err) {
dev_err(dev, "gmsl deserializer setup failed\n");
/* overwrite err only if deser setup also failed */
err = des_err;
}
error:
mutex_unlock(&serdes_lock__);
return err;
}
static void imx390_gmsl_serdes_reset(struct imx390 *priv)
{
mutex_lock(&serdes_lock__);
/* reset serdes addressing and control pipeline */
max9295_reset_control(priv->ser_dev);
max9296_reset_control(priv->dser_dev, &priv->i2c_client->dev);
max9296_power_off(priv->dser_dev);
mutex_unlock(&serdes_lock__);
}
static int imx390_power_on(struct camera_common_data *s_data)
{
int err = 0;
struct camera_common_power_rail *pw = s_data->power;
struct camera_common_pdata *pdata = s_data->pdata;
struct device *dev = s_data->dev;
dev_dbg(dev, "%s: power on\n", __func__);
if (pdata && pdata->power_on) {
err = pdata->power_on(pw);
if (err)
dev_err(dev, "%s failed.\n", __func__);
else
pw->state = SWITCH_ON;
return err;
}
pw->state = SWITCH_ON;
return 0;
}
static int imx390_power_off(struct camera_common_data *s_data)
{
int err = 0;
struct camera_common_power_rail *pw = s_data->power;
struct camera_common_pdata *pdata = s_data->pdata;
struct device *dev = s_data->dev;
dev_dbg(dev, "%s:\n", __func__);
if (pdata && pdata->power_off) {
err = pdata->power_off(pw);
if (!err)
goto power_off_done;
else
dev_err(dev, "%s failed.\n", __func__);
return err;
}
power_off_done:
pw->state = SWITCH_OFF;
return 0;
}
static int imx390_power_get(struct tegracam_device *tc_dev)
{
struct device *dev = tc_dev->dev;
struct camera_common_data *s_data = tc_dev->s_data;
struct camera_common_power_rail *pw = s_data->power;
struct camera_common_pdata *pdata = s_data->pdata;
const char *mclk_name;
const char *parentclk_name;
struct clk *parent;
int err = 0;
mclk_name = pdata->mclk_name ?
pdata->mclk_name : "cam_mclk1";
pw->mclk = devm_clk_get(dev, mclk_name);
if (IS_ERR(pw->mclk)) {
dev_err(dev, "unable to get clock %s\n", mclk_name);
return PTR_ERR(pw->mclk);
}
parentclk_name = pdata->parentclk_name;
if (parentclk_name) {
parent = devm_clk_get(dev, parentclk_name);
if (IS_ERR(parent)) {
dev_err(dev, "unable to get parent clcok %s",
parentclk_name);
} else {
err = clk_set_parent(pw->mclk, parent);
if (err < 0)
dev_dbg(dev,
"%s failed to set parent clock %d\n",
__func__, err);
}
}
pw->state = SWITCH_OFF;
return err;
}
static int imx390_power_put(struct tegracam_device *tc_dev)
{
struct camera_common_data *s_data = tc_dev->s_data;
struct camera_common_power_rail *pw = s_data->power;
if (unlikely(!pw))
return -EFAULT;
return 0;
}
static int imx390_set_group_hold(struct tegracam_device *tc_dev, bool val)
{
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = tc_dev->dev;
int err;
err = imx390_write_reg(s_data,
IMX390_GROUP_HOLD_ADDR, val);
if (err) {
dev_dbg(dev,
"%s: Group hold control error\n", __func__);
return err;
}
return 0;
}
static int imx390_set_gain(struct tegracam_device *tc_dev, s64 val)
{
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = tc_dev->dev;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
imx390_reg reg_list[4];
int err, i;
u16 gain;
gain = (u16)(val / mode->control_properties.step_gain_val);
dev_dbg(dev, "%s: db: %d\n", __func__, gain);
if (gain > IMX390_MAX_GAIN_REG)
gain = IMX390_MAX_GAIN_REG;
imx390_get_gain_reg(reg_list, gain);
for (i = 0; i < 4; i++) {
err = imx390_write_reg(s_data, reg_list[i].addr,
reg_list[i].val);
if (err)
goto fail;
}
return 0;
fail:
dev_info(dev, "%s: GAIN control error\n", __func__);
return err;
}
static int imx390_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
{
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
/* fixed 30fps */
priv->frame_length = IMX390_DEFAULT_FRAME_LENGTH;
return 0;
}
static int imx390_set_exposure(struct tegracam_device *tc_dev, s64 val)
{
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
struct camera_common_data *s_data = tc_dev->s_data;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode];
imx390_reg reg_list[3];
int err;
u32 coarse_time;
u32 shs1;
int i = 0;
if (priv->frame_length == 0)
priv->frame_length = IMX390_DEFAULT_FRAME_LENGTH;
/* coarse time in lines */
coarse_time = (u32) (val * s_data->frmfmt[s_data->mode].framerates[0] *
priv->frame_length / mode->control_properties.exposure_factor);
shs1 = priv->frame_length - coarse_time;
/* 0 and 1 are prohibited */
if (shs1 < 2)
shs1 = 2;
imx390_get_coarse_time_regs_shs1(reg_list, shs1);
for (i = 0; i < 3; i++) {
err = imx390_write_reg(priv->s_data, reg_list[i].addr,
reg_list[i].val);
if (err)
goto fail;
}
imx390_get_coarse_time_regs_shs2(reg_list, shs1);
for (i = 0; i < 3; i++) {
err = imx390_write_reg(priv->s_data, reg_list[i].addr,
reg_list[i].val);
if (err)
goto fail;
}
return 0;
fail:
dev_dbg(&priv->i2c_client->dev,
"%s: set coarse time error\n", __func__);
return err;
}
static struct tegracam_ctrl_ops imx390_ctrl_ops = {
.numctrls = ARRAY_SIZE(ctrl_cid_list),
.ctrl_cid_list = ctrl_cid_list,
.set_gain = imx390_set_gain,
.set_exposure = imx390_set_exposure,
.set_exposure_short = imx390_set_exposure,
.set_frame_rate = imx390_set_frame_rate,
.set_group_hold = imx390_set_group_hold,
};
static struct camera_common_pdata
*imx390_parse_dt(struct tegracam_device *tc_dev)
{
struct device *dev = tc_dev->dev;
struct device_node *node = dev->of_node;
struct camera_common_pdata *board_priv_pdata;
const struct of_device_id *match;
int err;
if (!node)
return NULL;
match = of_match_device(imx390_of_match, dev);
if (!match) {
dev_err(dev, "Failed to find matching dt id\n");
return NULL;
}
board_priv_pdata = devm_kzalloc(dev,
sizeof(*board_priv_pdata), GFP_KERNEL);
err = of_property_read_string(node, "mclk",
&board_priv_pdata->mclk_name);
if (err)
dev_err(dev, "mclk not in DT\n");
return board_priv_pdata;
}
static int imx390_set_mode(struct tegracam_device *tc_dev)
{
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = tc_dev->dev;
const struct of_device_id *match;
match = of_match_device(imx390_of_match, dev);
if (!match) {
dev_err(dev, "Failed to find matching dt id\n");
return -EINVAL;
}
if (s_data->mode_prop_idx < 0)
return -EINVAL;
return imx390_write_table(priv, mode_table[s_data->mode_prop_idx]);
}
static int imx390_start_streaming(struct tegracam_device *tc_dev)
{
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
struct device *dev = tc_dev->dev;
int err;
/* enable serdes streaming */
err = max9295_setup_streaming(priv->ser_dev);
if (err)
goto exit;
err = max9296_setup_streaming(priv->dser_dev, dev);
if (err)
goto exit;
err = max9296_start_streaming(priv->dser_dev, dev);
if (err)
goto exit;
err = imx390_write_table(priv,
mode_table[IMX390_MODE_START_STREAM]);
if (err)
return err;
msleep(20);
return 0;
exit:
dev_err(dev, "%s: error setting stream\n", __func__);
return err;
}
static int imx390_stop_streaming(struct tegracam_device *tc_dev)
{
struct device *dev = tc_dev->dev;
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
/* disable serdes streaming */
max9296_stop_streaming(priv->dser_dev, dev);
return imx390_write_table(priv, mode_table[IMX390_MODE_STOP_STREAM]);
}
static struct camera_common_sensor_ops imx390_common_ops = {
.numfrmfmts = ARRAY_SIZE(imx390_frmfmt),
.frmfmt_table = imx390_frmfmt,
.power_on = imx390_power_on,
.power_off = imx390_power_off,
.write_reg = imx390_write_reg,
.read_reg = imx390_read_reg,
.parse_dt = imx390_parse_dt,
.power_get = imx390_power_get,
.power_put = imx390_power_put,
.set_mode = imx390_set_mode,
.start_streaming = imx390_start_streaming,
.stop_streaming = imx390_stop_streaming,
};
static int imx390_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
dev_dbg(&client->dev, "%s:\n", __func__);
return 0;
}
static const struct v4l2_subdev_internal_ops imx390_subdev_internal_ops = {
.open = imx390_open,
};
static int imx390_board_setup(struct imx390 *priv)
{
struct tegracam_device *tc_dev = priv->tc_dev;
struct device *dev = tc_dev->dev;
struct device_node *node = dev->of_node;
struct device_node *ser_node;
struct i2c_client *ser_i2c = NULL;
struct device_node *dser_node;
struct i2c_client *dser_i2c = NULL;
struct device_node *gmsl;
int value = 0xFFFF;
const char *str_value;
const char *str_value1[2];
int i;
int err;
err = of_property_read_u32(node, "reg", &priv->g_ctx.sdev_reg);
if (err < 0) {
dev_err(dev, "reg not found\n");
goto error;
}
err = of_property_read_u32(node, "def-addr",
&priv->g_ctx.sdev_def);
if (err < 0) {
dev_err(dev, "def-addr not found\n");
goto error;
}
ser_node = of_parse_phandle(node, "nvidia,gmsl-ser-device", 0);
if (ser_node == NULL) {
dev_err(dev,
"missing %s handle\n",
"nvidia,gmsl-ser-device");
err = -EINVAL;
goto error;
}
err = of_property_read_u32(ser_node, "reg", &priv->g_ctx.ser_reg);
if (err < 0) {
dev_err(dev, "serializer reg not found\n");
goto error;
}
ser_i2c = of_find_i2c_device_by_node(ser_node);
of_node_put(ser_node);
if (ser_i2c == NULL) {
err = -EPROBE_DEFER;
goto error;
}
if (ser_i2c->dev.driver == NULL) {
dev_err(dev, "missing serializer driver\n");
err = -EINVAL;
goto error;
}
priv->ser_dev = &ser_i2c->dev;
dser_node = of_parse_phandle(node, "nvidia,gmsl-dser-device", 0);
if (dser_node == NULL) {
dev_err(dev,
"missing %s handle\n",
"nvidia,gmsl-dser-device");
err = -EINVAL;
goto error;
}
dser_i2c = of_find_i2c_device_by_node(dser_node);
of_node_put(dser_node);
if (dser_i2c == NULL) {
err = -EPROBE_DEFER;
goto error;
}
if (dser_i2c->dev.driver == NULL) {
dev_err(dev, "missing deserializer driver\n");
err = -EINVAL;
goto error;
}
priv->dser_dev = &dser_i2c->dev;
/* populate g_ctx from DT */
gmsl = of_get_child_by_name(node, "gmsl-link");
if (gmsl == NULL) {
dev_err(dev, "missing gmsl-link device node\n");
err = -EINVAL;
goto error;
}
err = of_property_read_string(gmsl, "dst-csi-port", &str_value);
if (err < 0) {
dev_err(dev, "No dst-csi-port found\n");
goto error;
}
priv->g_ctx.dst_csi_port =
(!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B;
err = of_property_read_string(gmsl, "src-csi-port", &str_value);
if (err < 0) {
dev_err(dev, "No src-csi-port found\n");
goto error;
}
priv->g_ctx.src_csi_port =
(!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B;
err = of_property_read_string(gmsl, "csi-mode", &str_value);
if (err < 0) {
dev_err(dev, "No csi-mode found\n");
goto error;
}
if (!strcmp(str_value, "1x4")) {
priv->g_ctx.csi_mode = GMSL_CSI_1X4_MODE;
} else if (!strcmp(str_value, "2x4")) {
priv->g_ctx.csi_mode = GMSL_CSI_2X4_MODE;
} else if (!strcmp(str_value, "4x2")) {
priv->g_ctx.csi_mode = GMSL_CSI_4X2_MODE;
} else if (!strcmp(str_value, "2x2")) {
priv->g_ctx.csi_mode = GMSL_CSI_2X2_MODE;
} else {
dev_err(dev, "invalid csi mode\n");
err = -EINVAL;
goto error;
}
err = of_property_read_string(gmsl, "serdes-csi-link", &str_value);
if (err < 0) {
dev_err(dev, "No serdes-csi-link found\n");
goto error;
}
priv->g_ctx.serdes_csi_link =
(!strcmp(str_value, "a")) ?
GMSL_SERDES_CSI_LINK_A : GMSL_SERDES_CSI_LINK_B;
err = of_property_read_u32(gmsl, "st-vc", &value);
if (err < 0) {
dev_err(dev, "No st-vc info\n");
goto error;
}
priv->g_ctx.st_vc = value;
err = of_property_read_u32(gmsl, "vc-id", &value);
if (err < 0) {
dev_err(dev, "No vc-id info\n");
goto error;
}
priv->g_ctx.dst_vc = value;
err = of_property_read_u32(gmsl, "num-lanes", &value);
if (err < 0) {
dev_err(dev, "No num-lanes info\n");
goto error;
}
priv->g_ctx.num_csi_lanes = value;
priv->g_ctx.num_streams =
of_property_count_strings(gmsl, "streams");
if (priv->g_ctx.num_streams <= 0) {
dev_err(dev, "No streams found\n");
err = -EINVAL;
goto error;
}
for (i = 0; i < priv->g_ctx.num_streams; i++) {
err = of_property_read_string_index(gmsl, "streams", i,
&str_value1[i]);
if (err < 0) {
dev_err(dev, "Failed to get streams index\n");
goto error;
}
if (!str_value1[i]) {
dev_err(dev, "invalid stream info\n");
err = -EINVAL;
goto error;
}
if (!strcmp(str_value1[i], "raw12")) {
priv->g_ctx.streams[i].st_data_type =
GMSL_CSI_DT_RAW_12;
} else if (!strcmp(str_value1[i], "embed")) {
priv->g_ctx.streams[i].st_data_type =
GMSL_CSI_DT_EMBED;
} else if (!strcmp(str_value1[i], "ued-u1")) {
priv->g_ctx.streams[i].st_data_type =
GMSL_CSI_DT_UED_U1;
} else {
dev_err(dev, "invalid stream data type\n");
err = -EINVAL;
goto error;
}
}
priv->g_ctx.s_dev = dev;
return 0;
error:
return err;
}
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
static int imx390_probe(struct i2c_client *client)
#else
static int imx390_probe(struct i2c_client *client,
const struct i2c_device_id *id)
#endif
{
struct device *dev = &client->dev;
struct device_node *node = dev->of_node;
struct tegracam_device *tc_dev;
struct imx390 *priv;
int err;
dev_info(dev, "probing v4l2 sensor.\n");
if (!IS_ENABLED(CONFIG_OF) || !node)
return -EINVAL;
priv = devm_kzalloc(dev, sizeof(struct imx390), GFP_KERNEL);
if (!priv)
return -ENOMEM;
tc_dev = devm_kzalloc(dev,
sizeof(struct tegracam_device), GFP_KERNEL);
if (!tc_dev)
return -ENOMEM;
priv->i2c_client = tc_dev->client = client;
tc_dev->dev = dev;
strscpy(tc_dev->name, "imx390", sizeof(tc_dev->name));
tc_dev->dev_regmap_config = &sensor_regmap_config;
tc_dev->sensor_ops = &imx390_common_ops;
tc_dev->v4l2sd_internal_ops = &imx390_subdev_internal_ops;
tc_dev->tcctrl_ops = &imx390_ctrl_ops;
err = tegracam_device_register(tc_dev);
if (err) {
dev_err(dev, "tegra camera driver registration failed\n");
return err;
}
priv->tc_dev = tc_dev;
priv->s_data = tc_dev->s_data;
priv->subdev = &tc_dev->s_data->subdev;
tegracam_set_privdata(tc_dev, (void *)priv);
err = imx390_board_setup(priv);
if (err) {
tegracam_device_unregister(tc_dev);
dev_err(dev, "board setup failed\n");
return err;
}
mutex_init(&serdes_lock__);
/* Pair sensor to serializer dev */
err = max9295_sdev_pair(priv->ser_dev, &priv->g_ctx);
if (err) {
dev_err(&client->dev, "gmsl ser pairing failed\n");
return err;
}
/* Register sensor to deserializer dev */
err = max9296_sdev_register(priv->dser_dev, &priv->g_ctx);
if (err) {
dev_err(&client->dev, "gmsl deserializer register failed\n");
return err;
}
/*
* gmsl serdes setup
*
* Sensor power on/off should be the right place for serdes
* setup/reset. But the problem is, the total required delay
* in serdes setup/reset exceeds the frame wait timeout, looks to
* be related to multiple channel open and close sequence
* issue (#BUG 200477330).
* Once this bug is fixed, these may be moved to power on/off.
* The delays in serdes is as per guidelines and can't be reduced,
* so it is placed in probe/remove, though for that, deserializer
* would be powered on always post boot, until 1.2v is supplied
* to deserializer from CVB.
*/
err = imx390_gmsl_serdes_setup(priv);
if (err) {
dev_err(&client->dev,
"%s gmsl serdes setup failed\n", __func__);
return err;
}
err = tegracam_v4l2subdev_register(tc_dev, true);
if (err) {
dev_err(dev, "tegra camera subdev registration failed\n");
return err;
}
dev_info(&client->dev, "Detected IMX390 sensor\n");
return 0;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
static int imx390_remove(struct i2c_client *client)
#else
static void imx390_remove(struct i2c_client *client)
#endif
{
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
struct imx390 *priv;
if (!s_data)
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
return -EINVAL;
#else
return;
#endif
priv = (struct imx390 *)s_data->priv;
imx390_gmsl_serdes_reset(priv);
mutex_destroy(&serdes_lock__);
tegracam_v4l2subdev_unregister(priv->tc_dev);
tegracam_device_unregister(priv->tc_dev);
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
return 0;
#endif
}
static const struct i2c_device_id imx390_id[] = {
{ "imx390", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, imx390_id);
static struct i2c_driver imx390_i2c_driver = {
.driver = {
.name = "imx390",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(imx390_of_match),
},
.probe = imx390_probe,
.remove = imx390_remove,
.id_table = imx390_id,
};
module_i2c_driver(imx390_i2c_driver);
MODULE_DESCRIPTION("Media Controller driver for Sony IMX390");
MODULE_AUTHOR("NVIDIA Corporation");
MODULE_AUTHOR("Sudhir Vyas <svyas@nvidia.com");
MODULE_LICENSE("GPL v2");

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2021-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-FileCopyrightText: Copyright (c) 2021-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Copyright (c) 2020, RidgeRun. All rights reserved.
*
@@ -42,6 +42,11 @@ static const u32 ctrl_cid_list[] = {
TEGRA_CAMERA_CID_SENSOR_MODE_ID,
};
enum imx477_Config {
TWO_LANE_CONFIG,
FOUR_LANE_CONFIG,
};
struct imx477 {
struct i2c_client *i2c_client;
struct v4l2_subdev *subdev;
@@ -49,6 +54,7 @@ struct imx477 {
u32 frame_length;
struct camera_common_data *s_data;
struct tegracam_device *tc_dev;
enum imx477_Config config;
};
static const struct regmap_config sensor_regmap_config = {
@@ -594,14 +600,30 @@ static int imx477_set_mode(struct tegracam_device *tc_dev)
struct camera_common_data *s_data = tc_dev->s_data;
unsigned int mode_index = 0;
int err = 0;
const char *config;
struct device_node *mode;
uint offset = ARRAY_SIZE(imx477_frmfmt);
dev_dbg(tc_dev->dev, "%s:\n", __func__);
mode = of_get_child_by_name(tc_dev->dev->of_node, "mode0");
err = of_property_read_string(mode, "num_lanes", &config);
if (config[0] == '4')
priv->config = FOUR_LANE_CONFIG;
else if (config[0] == '2')
priv->config = TWO_LANE_CONFIG;
else
dev_err(tc_dev->dev, "Unsupported config\n");
err = imx477_write_table(priv, mode_table[IMX477_MODE_COMMON]);
if (err)
return err;
mode_index = s_data->mode;
err = imx477_write_table(priv, mode_table[mode_index]);
if (priv->config == FOUR_LANE_CONFIG)
err = imx477_write_table(priv, mode_table[mode_index + offset]);
else
err = imx477_write_table(priv, mode_table[mode_index]);
if (err)
return err;
@@ -753,7 +775,6 @@ static int imx477_probe(struct i2c_client *client,
err = tegracam_v4l2subdev_register(tc_dev, true);
if (err) {
tegracam_device_unregister(tc_dev);
dev_err(dev, "tegra camera subdev registration failed\n");
return err;
}

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
/*
* virtual_i2c_mux.c - virtual i2c mux driver for P3762 & P3783 GMSL boards.
*/
@@ -15,10 +15,7 @@
#include <linux/version.h>
#define DESER_A (0)
#define ENABLE_CC1 (0xFE)
#define ENABLE_CC2 (0xFB)
#define ENABLE_CC3 (0xEF)
#define ENABLE_CC4 (0xBF)
#define ENABLE_IMU (0xFE)
#define ENABLE_ALL_CC (0xAA)
#define DESER_ADDR (0x52)
#define DESER_CC_REG (0x0003)
@@ -30,31 +27,10 @@ static int virtual_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan)
int ret = 0;
/* Do select 1st channel, to access IMUs from 1st Hawk */
switch (chan) {
case 0:
ret = max96712_write_reg_Dser(DESER_ADDR, DESER_A, DESER_CC_REG, ENABLE_CC1);
if (ret)
pr_err("%s: Failed to do i2c address trans for CC1\n", __func__);
break;
case 1:
ret = max96712_write_reg_Dser(DESER_ADDR, DESER_A, DESER_CC_REG, ENABLE_CC2);
if (ret)
pr_err("%s: Failed to do i2c address trans for CC2\n", __func__);
break;
case 2:
ret = max96712_write_reg_Dser(DESER_ADDR, DESER_A, DESER_CC_REG, ENABLE_CC3);
if (ret)
pr_err("%s: Failed to do i2c address trans for CC3\n", __func__);
break;
case 3:
ret = max96712_write_reg_Dser(DESER_ADDR, DESER_A, DESER_CC_REG, ENABLE_CC4);
if (ret)
pr_err("%s: Failed to do i2c address trans for CC4\n", __func__);
break;
default:
pr_err("%s: No channels matched chan = %d\n", __func__, chan);
ret = -EINVAL;
break;
if (!chan) {
ret = max96712_write_reg_Dser(DESER_ADDR, DESER_A, DESER_CC_REG, ENABLE_IMU);
if (ret)
pr_err("%s: Failed to do i2c address trans for IMUs\n",__func__);
}
return ret;
@@ -65,10 +41,11 @@ static int virtual_i2c_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
int ret = 0;
/* Enable all control channels */
ret = max96712_write_reg_Dser(DESER_ADDR, DESER_A, DESER_CC_REG, ENABLE_ALL_CC);
if (ret)
pr_err("%s: Failed to do i2c address trans for IMUs\n",__func__);
if (!chan) {
ret = max96712_write_reg_Dser(DESER_ADDR, DESER_A, DESER_CC_REG, ENABLE_ALL_CC);
if (ret)
pr_err("%s: Failed to do i2c address trans for IMUs\n",__func__);
}
return ret;
}
@@ -110,11 +87,7 @@ static int virtual_i2c_mux_probe(struct i2c_client *client,
for (chan = 0; chan < children; chan++) {
pr_info("%s: chan = %d\n",__func__, chan);
#if defined(NV_I2C_MUX_ADD_ADAPTER_HAS_NO_CLASS_ARG)
ret = i2c_mux_add_adapter(muxc, 0, chan);
#else
ret = i2c_mux_add_adapter(muxc, 0, chan, 0);
#endif
if (ret)
goto err_children;
}

View File

@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
*/
#include <nvidia/conftest.h>
@@ -1123,18 +1125,6 @@ MODULE_DEVICE_TABLE(of, cam_fsync_of_match);
static SIMPLE_DEV_PM_OPS(cam_fsync_pm, cam_fsync_suspend, cam_fsync_resume);
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void cam_fsync_remove_wrapper(struct platform_device *pdev)
{
cam_fsync_remove(pdev);
}
#else
static int cam_fsync_remove_wrapper(struct platform_device *pdev)
{
return cam_fsync_remove(pdev);
}
#endif
static struct platform_driver cam_fsync_driver = {
.driver = {
.name = "cam_fsync",
@@ -1143,7 +1133,7 @@ static struct platform_driver cam_fsync_driver = {
.pm = &cam_fsync_pm,
},
.probe = cam_fsync_probe,
.remove = cam_fsync_remove_wrapper,
.remove = cam_fsync_remove,
};
module_platform_driver(cam_fsync_driver);

View File

@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2015-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
// SPDX-License-Identifier: GPL-2.0
/*
* camera_common.c - utilities for tegra camera driver
*
* Copyright (c) 2015-2023, NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/types.h>
#include <media/tegra-v4l2-camera.h>
#include <media/camera_common.h>
@@ -28,26 +29,6 @@
#define HDR_ENABLE 0x1
static const struct camera_common_colorfmt camera_common_color_fmts[] = {
{
MEDIA_BUS_FMT_SBGGR14_1X14,
V4L2_COLORSPACE_SRGB,
V4L2_PIX_FMT_SBGGR14,
},
{
MEDIA_BUS_FMT_SRGGB14_1X14,
V4L2_COLORSPACE_SRGB,
V4L2_PIX_FMT_SRGGB14,
},
{
MEDIA_BUS_FMT_SGRBG14_1X14,
V4L2_COLORSPACE_SRGB,
V4L2_PIX_FMT_SGRBG14,
},
{
MEDIA_BUS_FMT_SGBRG14_1X14,
V4L2_COLORSPACE_SRGB,
V4L2_PIX_FMT_SGBRG14
},
{
MEDIA_BUS_FMT_SRGGB12_1X12,
V4L2_COLORSPACE_SRGB,
@@ -63,11 +44,6 @@ static const struct camera_common_colorfmt camera_common_color_fmts[] = {
V4L2_COLORSPACE_SRGB,
V4L2_PIX_FMT_SGBRG12
},
{
MEDIA_BUS_FMT_SBGGR12_1X12,
V4L2_COLORSPACE_SRGB,
V4L2_PIX_FMT_SBGGR12
},
{
MEDIA_BUS_FMT_SRGGB10_1X10,
V4L2_COLORSPACE_SRGB,
@@ -975,12 +951,12 @@ int camera_common_get_mbus_config(struct v4l2_subdev *sd,
* then return an error
*/
cfg->type = V4L2_MBUS_CSI2_DPHY;
#if defined(NV_V4L2_FWNODE_ENDPOINT_STRUCT_HAS_V4L2_MBUS_CONFIG_MIPI_CSI2) /* Linux v5.18 */
cfg->bus.mipi_csi2.num_data_lanes = 4;
#else
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0)
cfg->flags = V4L2_MBUS_CSI2_4_LANE |
V4L2_MBUS_CSI2_CHANNEL_0 |
V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
#else
cfg->bus.mipi_csi2.num_data_lanes = 4;
#endif
return 0;

View File

@@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2015-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
/*
* NVIDIA Tegra CSI Device
*
* Copyright (c) 2015-2024, NVIDIA CORPORATION. All rights reserved.
*/
#include <nvidia/conftest.h>
@@ -686,7 +687,7 @@ static int tegra_csi_set_format(struct v4l2_subdev *subdev,
}
static int tegra_csi_g_frame_interval(struct v4l2_subdev *sd,
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_FRAME_INTERVAL)
struct v4l2_subdev_state *sd_state,
#endif
struct v4l2_subdev_frame_interval *vfi)
@@ -720,13 +721,13 @@ static int tegra_csi_enum_mbus_code(struct v4l2_subdev *sd,
static struct v4l2_subdev_video_ops tegra_csi_video_ops = {
.s_stream = tegra_csi_s_stream,
.g_input_status = tegra_csi_g_input_status,
#if !defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
#if !defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_FRAME_INTERVAL)
.g_frame_interval = tegra_csi_g_frame_interval,
#endif
};
static struct v4l2_subdev_pad_ops tegra_csi_pad_ops = {
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_FRAME_INTERVAL)
.get_frame_interval = tegra_csi_g_frame_interval,
#endif
.get_fmt = tegra_csi_get_format,

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017-2023 NVIDIA Corporation. All rights reserved.
/**
* @file drivers/media/platform/tegra/camera/fusa-capture/capture-isp-channel.c
@@ -523,9 +523,7 @@ static long isp_channel_ioctl(
static const struct file_operations isp_channel_fops = {
.owner = THIS_MODULE,
#if defined(NV_NO_LLSEEK_PRESENT)
.llseek = no_llseek,
#endif
.unlocked_ioctl = isp_channel_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = isp_channel_ioctl,

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// Copyright (c) 2017-2023 NVIDIA Corporation. All rights reserved.
/**
* @file drivers/media/platform/tegra/camera/fusa-capture/capture-isp.c
@@ -14,7 +14,7 @@
#include <linux/nvhost.h>
#include <linux/of_platform.h>
#include <linux/printk.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/tegra-capture-ivc.h>
#include <asm/arch_timer.h>
#include <soc/tegra/fuse.h>

View File

@@ -17,7 +17,7 @@
#include <linux/of_platform.h>
#include <linux/nvhost.h>
#include <linux/sched.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/dma-buf.h>
#include <linux/dma-mapping.h>
@@ -616,9 +616,7 @@ static long vi_channel_ioctl(
static const struct file_operations vi_channel_fops = {
.owner = THIS_MODULE,
#if defined(NV_NO_LLSEEK_PRESENT)
.llseek = no_llseek,
#endif
.unlocked_ioctl = vi_channel_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = vi_channel_ioctl,

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2017-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/**
* @file drivers/media/platform/tegra/camera/fusa-capture/capture-vi.c
@@ -7,14 +7,12 @@
* @brief VI channel operations for the T234 Camera RTCPU platform.
*/
#include <nvidia/conftest.h>
#include <linux/completion.h>
#include <linux/nospec.h>
#include <linux/nvhost.h>
#include <linux/of_platform.h>
#include <linux/printk.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/tegra-capture-ivc.h>
#include <linux/tegra-camera-rtcpu.h>
@@ -1440,12 +1438,7 @@ int vi_capture_status(
/* negative timeout means wait forever */
if (timeout_ms < 0) {
ret = wait_for_completion_interruptible(&capture->capture_resp);
if (ret == -ERESTARTSYS) {
dev_dbg(chan->dev,
"capture status interrupted\n");
return -ETIMEDOUT;
}
wait_for_completion(&capture->capture_resp);
} else {
ret = wait_for_completion_timeout(
&capture->capture_resp,
@@ -1716,21 +1709,9 @@ static const struct of_device_id capture_vi_of_match[] = {
};
MODULE_DEVICE_TABLE(of, capture_vi_of_match);
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void capture_vi_remove_wrapper(struct platform_device *pdev)
{
capture_vi_remove(pdev);
}
#else
static int capture_vi_remove_wrapper(struct platform_device *pdev)
{
return capture_vi_remove(pdev);
}
#endif
static struct platform_driver capture_vi_driver = {
.probe = capture_vi_probe,
.remove = capture_vi_remove_wrapper,
.remove = capture_vi_remove,
.driver = {
.owner = THIS_MODULE,
.name = "tegra-camrtc-capture-vi",
@@ -1762,10 +1743,6 @@ static void __exit capture_vi_exit(void)
module_init(capture_vi_init);
module_exit(capture_vi_exit);
#if defined(NV_MODULE_IMPORT_NS_CALLS_STRINGIFY)
MODULE_IMPORT_NS(DMA_BUF);
#else
MODULE_IMPORT_NS("DMA_BUF");
#endif
MODULE_DESCRIPTION("tegra fusa-capture driver");
MODULE_LICENSE("GPL");

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2016-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (c) 2016-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*
* Tegra CSI5 device common APIs
*/
@@ -213,7 +213,6 @@ static int csi5_stream_set_config(struct tegra_csi_channel *chan, u32 stream_id,
struct CAPTURE_CONTROL_MSG msg;
struct nvcsi_brick_config brick_config;
struct nvcsi_cil_config cil_config;
struct nvcsi_error_config err_config;
u32 phy_mode = read_phy_mode_from_dt(chan);
bool is_cphy = (phy_mode == CSI_PHY_MODE_CPHY);
dev_dbg(csi->dev, "%s: stream_id=%u, csi_port=%u\n",
@@ -286,7 +285,6 @@ static int csi5_stream_set_config(struct tegra_csi_channel *chan, u32 stream_id,
else
cil_config.mipi_clock_rate = csi->clk_freq / 1000;
memset(&err_config, 0, sizeof(err_config));
/* Set NVCSI stream config */
memset(&msg, 0, sizeof(msg));
msg.header.msg_id = CAPTURE_CSI_STREAM_SET_CONFIG_REQ;
@@ -295,9 +293,6 @@ static int csi5_stream_set_config(struct tegra_csi_channel *chan, u32 stream_id,
msg.csi_stream_set_config_req.csi_port = csi_port;
msg.csi_stream_set_config_req.brick_config = brick_config;
msg.csi_stream_set_config_req.cil_config = cil_config;
msg.csi_stream_set_config_req.error_config = err_config;
msg.csi_stream_set_config_req.config_flags = NVCSI_CONFIG_FLAG_BRICK |
NVCSI_CONFIG_FLAG_CIL | NVCSI_CONFIG_FLAG_ERROR;
if (tegra_chan->valid_ports > 1)
vi_port = (stream_id > 0) ? 1 : 0;

View File

@@ -1,19 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES.
* All rights reserved.
* sensor_common.c - utilities for tegra sensor drivers
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* Copyright (c) 2017-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <media/sensor_common.h>
@@ -254,14 +243,6 @@ static int extract_pixel_format(
*format = V4L2_PIX_FMT_SGBRG12;
else if (strncmp(pixel_t, "bayer_grbg12", size) == 0)
*format = V4L2_PIX_FMT_SGRBG12;
else if (strncmp(pixel_t, "bayer_bggr14", size) == 0)
*format = V4L2_PIX_FMT_SBGGR14;
else if (strncmp(pixel_t, "bayer_rggb14", size) == 0)
*format = V4L2_PIX_FMT_SRGGB14;
else if (strncmp(pixel_t, "bayer_gbrg14", size) == 0)
*format = V4L2_PIX_FMT_SGBRG14;
else if (strncmp(pixel_t, "bayer_grbg14", size) == 0)
*format = V4L2_PIX_FMT_SGRBG14;
else if (strncmp(pixel_t, "rgb_rgb88824", size) == 0)
*format = V4L2_PIX_FMT_RGB24;
else if (strncmp(pixel_t, "bayer_wdr_pwl_rggb12", size) == 0)
@@ -272,16 +253,6 @@ static int extract_pixel_format(
*format = V4L2_PIX_FMT_SGRBG12;
else if (strncmp(pixel_t, "bayer_wdr_dol_rggb10", size) == 0)
*format = V4L2_PIX_FMT_SRGGB10;
else if (strncmp(pixel_t, "bayer_wdr_dol_gbrg10", size) == 0)
*format = V4L2_PIX_FMT_SGBRG10;
else if (strncmp(pixel_t, "bayer_wdr_dol_grbg10", size) == 0)
*format = V4L2_PIX_FMT_SGRBG10;
else if (strncmp(pixel_t, "bayer_wdr_dol_rggb12", size) == 0)
*format = V4L2_PIX_FMT_SRGGB12;
else if (strncmp(pixel_t, "bayer_wdr_dol_gbrg12", size) == 0)
*format = V4L2_PIX_FMT_SGBRG12;
else if (strncmp(pixel_t, "bayer_wdr_dol_grbg12", size) == 0)
*format = V4L2_PIX_FMT_SGRBG12;
#if 0 /* disable for Canonical kenrel */
else if (strncmp(pixel_t, "bayer_xbggr10p", size) == 0)
*format = V4L2_PIX_FMT_XBGGR10P;

View File

@@ -1,11 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2018-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
/*
* tegracam_v4l2 - tegra camera framework for v4l2 support
*
* Copyright (c) 2018-2022, NVIDIA CORPORATION. All rights reserved.
*/
#include <nvidia/conftest.h>
#include <linux/types.h>
#include <media/tegra-v4l2-camera.h>
#include <media/tegracam_core.h>
@@ -114,30 +112,9 @@ static int v4l2sd_g_input_status(struct v4l2_subdev *sd, u32 *status)
return 0;
}
static int cam_g_frame_interval(struct v4l2_subdev *sd,
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
struct v4l2_subdev_state *sd_state,
#endif
struct v4l2_subdev_frame_interval *ival)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
if (!s_data)
return -EINVAL;
ival->interval.denominator = s_data->frmfmt[s_data->mode_prop_idx].framerates[0];
ival->interval.numerator = 1;
return 0;
}
static struct v4l2_subdev_video_ops v4l2sd_video_ops = {
.s_stream = v4l2sd_stream,
.g_input_status = v4l2sd_g_input_status,
#if !defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
.g_frame_interval = cam_g_frame_interval,
.s_frame_interval = cam_g_frame_interval,
#endif
};
static struct v4l2_subdev_core_ops v4l2sd_core_ops = {
@@ -184,10 +161,6 @@ static int v4l2sd_set_fmt(struct v4l2_subdev *sd,
}
static struct v4l2_subdev_pad_ops v4l2sd_pad_ops = {
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
.get_frame_interval = cam_g_frame_interval,
.set_frame_interval = cam_g_frame_interval,
#endif
.set_fmt = v4l2sd_set_fmt,
.get_fmt = v4l2sd_get_fmt,
.enum_mbus_code = camera_common_enum_mbus_code,

View File

@@ -1,11 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2015-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-FileCopyrightText: Copyright (c) 2015-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* NVIDIA Tegra Video Input Device
*/
#include <nvidia/conftest.h>
#include <linux/atomic.h>
#include <linux/bitmap.h>
#include <linux/clk.h>
@@ -25,7 +23,6 @@
#include <media/v4l2-dev.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-subdev.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
#include <media/tegra-v4l2-camera.h>
@@ -471,7 +468,6 @@ void tegra_channel_init_ring_buffer(struct tegra_channel *chan)
chan->capture_descr_index = 0;
chan->capture_descr_sequence = 0;
chan->queue_error = false;
chan->capture_reqs_enqueued = 0;
}
EXPORT_SYMBOL(tegra_channel_init_ring_buffer);
@@ -693,34 +689,16 @@ tegra_channel_queue_setup(struct vb2_queue *vq,
{
struct tegra_channel *chan = vb2_get_drv_priv(vq);
struct tegra_mc_vi *vi = chan->vi;
int ret = 0;
/* In some cases, if nplanes is valid
* and the requested image size is less than the
* actual image size, we need to return EINVAL.
* Previously, we were just updating sizes[0] irrespective
* of the requested image size. Although this did not harm the
* flow, according to "v4l2-compliance", we need to check if
* the requested size is invalid.
* Printing this error as info, to avoid kernel error/warning failure.
*/
if (*nplanes) {
if (sizes[0] < chan->format.sizeimage) {
pr_info("%s: sizes[0] = %d, chan->format.sizeimage = %d, for num_planes = %d ...\n"
, __func__, sizes[0], chan->format.sizeimage, *nplanes);
return -EINVAL;
}
} else {
sizes[0] = chan->format.sizeimage;
}
*nplanes = 1;
sizes[0] = chan->format.sizeimage;
alloc_devs[0] = tegra_channel_get_vi_unit(chan);
if (vi->fops && vi->fops->vi_setup_queue)
return vi->fops->vi_setup_queue(chan, nbuffers);
return ret;
else
return -EINVAL;
}
int tegra_channel_alloc_buffer_queue(struct tegra_channel *chan,
@@ -1019,7 +997,6 @@ static void tegra_channel_stop_streaming(struct vb2_queue *vq)
if (vi->fops) {
vi->fops->vi_stop_streaming(vq);
atomic_set(&chan->is_streaming, DISABLE);
vi->fops->vi_power_off(chan);
}
@@ -1180,19 +1157,11 @@ tegra_channel_g_dv_timings(struct file *file, void *fh,
{
struct tegra_channel *chan = video_drvdata(file);
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
if (!v4l2_subdev_has_op(chan->subdev_on_csi, pad, g_dv_timings))
return -ENOTTY;
return v4l2_device_call_until_err(chan->video->v4l2_dev,
chan->grp_id, pad, g_dv_timings, 0, timings);
#else
if (!v4l2_subdev_has_op(chan->subdev_on_csi, video, g_dv_timings))
return -ENOTTY;
return v4l2_device_call_until_err(chan->video->v4l2_dev,
chan->grp_id, video, g_dv_timings, timings);
#endif
}
static int
@@ -1204,11 +1173,7 @@ tegra_channel_s_dv_timings(struct file *file, void *fh,
struct v4l2_dv_timings curr_timings;
int ret;
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
if (!v4l2_subdev_has_op(chan->subdev_on_csi, pad, s_dv_timings))
#else
if (!v4l2_subdev_has_op(chan->subdev_on_csi, video, s_dv_timings))
#endif
return -ENOTTY;
ret = tegra_channel_g_dv_timings(file, fh, &curr_timings);
@@ -1221,13 +1186,9 @@ tegra_channel_s_dv_timings(struct file *file, void *fh,
if (vb2_is_busy(&chan->queue))
return -EBUSY;
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
ret = v4l2_device_call_until_err(chan->video->v4l2_dev,
chan->grp_id, pad, s_dv_timings, 0, timings);
#else
ret = v4l2_device_call_until_err(chan->video->v4l2_dev,
chan->grp_id, video, s_dv_timings, timings);
#endif
if (!ret)
tegra_channel_update_format(chan, bt->width, bt->height,
chan->fmtinfo->fourcc, &chan->fmtinfo->bpp,
@@ -1245,19 +1206,11 @@ tegra_channel_query_dv_timings(struct file *file, void *fh,
{
struct tegra_channel *chan = video_drvdata(file);
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
if (!v4l2_subdev_has_op(chan->subdev_on_csi, pad, query_dv_timings))
return -ENOTTY;
return v4l2_device_call_until_err(chan->video->v4l2_dev,
chan->grp_id, pad, query_dv_timings, 0, timings);
#else
if (!v4l2_subdev_has_op(chan->subdev_on_csi, video, query_dv_timings))
return -ENOTTY;
return v4l2_device_call_until_err(chan->video->v4l2_dev,
chan->grp_id, video, query_dv_timings, timings);
#endif
}
static int
@@ -1304,10 +1257,6 @@ int tegra_channel_s_ctrl(struct v4l2_ctrl *ctrl)
}
break;
case TEGRA_CAMERA_CID_VI_BYPASS_MODE:
/* Prevent changing the bypass mode while the device is still streaming */
if (vb2_is_busy(&chan->queue))
return -EBUSY;
if (switch_ctrl_qmenu[ctrl->val] == SWITCH_ON)
chan->bypass = true;
else if (chan->vi->bypass) {
@@ -1894,13 +1843,8 @@ static void tegra_channel_populate_dev_info(struct tegra_camera_dev_info *cdev,
if (chan->pg_mode) {
/* TPG mode */
cdev->sensor_type = SENSORTYPE_VIRTUAL;
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
} else if (v4l2_subdev_has_op(chan->subdev_on_csi,
pad, g_dv_timings)) {
#else
} else if (v4l2_subdev_has_op(chan->subdev_on_csi,
video, g_dv_timings)) {
#endif
/* HDMI-IN */
cdev->sensor_type = SENSORTYPE_OTHER;
pixelclock = tegra_channel_get_max_source_rate();
@@ -1948,7 +1892,7 @@ int tegra_channel_init_subdevices(struct tegra_channel *chan)
int len = 0;
/* set_stream of CSI */
#if defined(NV_MEDIA_ENTITY_REMOTE_PAD_PRESENT) /* Linux 6.0 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0)
pad = media_entity_remote_pad(&chan->pad);
#else
pad = media_pad_remote_pad_first(&chan->pad);
@@ -1978,7 +1922,7 @@ int tegra_channel_init_subdevices(struct tegra_channel *chan)
if (!(pad->flags & MEDIA_PAD_FL_SINK))
break;
#if defined(NV_MEDIA_ENTITY_REMOTE_PAD_PRESENT) /* Linux 6.0 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 0, 0)
pad = media_entity_remote_pad(pad);
#else
pad = media_pad_remote_pad_first(pad);
@@ -2227,11 +2171,7 @@ tegra_channel_enum_input(struct file *file, void *fh, struct v4l2_input *inp)
return -ENODEV;
inp->type = V4L2_INPUT_TYPE_CAMERA;
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
if (v4l2_subdev_has_op(sd_on_csi, pad, s_dv_timings)) {
#else
if (v4l2_subdev_has_op(sd_on_csi, video, s_dv_timings)) {
#endif
inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
len = snprintf(inp->name,
sizeof(inp->name), "HDMI %u",
@@ -2276,7 +2216,7 @@ static long tegra_channel_default_ioctl(struct file *file, void *fh,
{
struct tegra_channel *chan = video_drvdata(file);
struct tegra_mc_vi *vi = chan->vi;
long ret = -ENOTTY;
long ret = 0;
if (vi->fops && vi->fops->vi_default_ioctl)
ret = vi->fops->vi_default_ioctl(file, fh, use_prio, cmd, arg);
@@ -2284,32 +2224,10 @@ static long tegra_channel_default_ioctl(struct file *file, void *fh,
return ret;
}
/* Implemented vidioc_s_parm and vidioc_g_parm ioctl to support multiple frame
* rates */
static int tegra_channel_s_parm(struct file *file, void *fh,
struct v4l2_streamparm *a)
{
struct tegra_channel *chan = video_drvdata(file);
struct v4l2_subdev *sd = chan->subdev_on_csi;
return v4l2_s_parm_cap(chan->video, sd, a);
}
static int tegra_channel_g_parm(struct file *file, void *fh,
struct v4l2_streamparm *a)
{
struct tegra_channel *chan = video_drvdata(file);
struct v4l2_subdev *sd = chan->subdev_on_csi;
return v4l2_g_parm_cap(chan->video, sd, a);
}
static const struct v4l2_ioctl_ops tegra_channel_ioctl_ops = {
.vidioc_querycap = tegra_channel_querycap,
.vidioc_enum_framesizes = tegra_channel_enum_framesizes,
.vidioc_enum_frameintervals = tegra_channel_enum_frameintervals,
.vidioc_s_parm = tegra_channel_s_parm,
.vidioc_g_parm = tegra_channel_g_parm,
.vidioc_enum_fmt_vid_cap = tegra_channel_enum_format,
.vidioc_g_fmt_vid_cap = tegra_channel_get_format,
.vidioc_s_fmt_vid_cap = tegra_channel_set_format,

View File

@@ -1,14 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/* SPDX-FileCopyrightText: Copyright (c) 2016-2025 NVIDIA CORPORATION & AFFILIATES.
* All rights reserved.
*
/*
* Tegra Video Input 5 device common APIs
*
* Author: Frank Chen <frank@nvidia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* Copyright (c) 2016-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <linux/errno.h>
@@ -140,9 +134,6 @@ static int tegra_vi5_s_ctrl(struct v4l2_ctrl *ctrl)
case TEGRA_CAMERA_CID_WRITE_ISPFORMAT:
chan->write_ispformat = ctrl->val;
break;
case TEGRA_CAMERA_CID_VI_CAPTURE_TIMEOUT:
chan->capture_timeout_ms = ctrl->val;
break;
default:
dev_err(&chan->video->dev, "%s:Not valid ctrl\n", __func__);
return -EINVAL;
@@ -209,16 +200,6 @@ static const struct v4l2_ctrl_config vi5_custom_ctrls[] = {
.step = 1,
.dims = { SENSOR_CTRL_BLOB_SIZE },
},
{
.ops = &vi5_ctrl_ops,
.id = TEGRA_CAMERA_CID_VI_CAPTURE_TIMEOUT,
.name = "Override capture timeout ms",
.type = V4L2_CTRL_TYPE_INTEGER,
.def = CAPTURE_TIMEOUT_MS,
.min = -1,
.max = 0x7FFFFFFF,
.step = 1,
},
};
static int vi5_add_ctrls(struct tegra_channel *chan)
@@ -516,7 +497,6 @@ static void vi5_capture_dequeue(struct tegra_channel *chan,
unsigned long flags;
struct tegra_mc_vi *vi = chan->vi;
struct vb2_v4l2_buffer *vb = &buf->buf;
int timeout_ms = CAPTURE_TIMEOUT_MS;
struct timespec64 ts;
struct capture_descriptor *descr = NULL;
@@ -527,21 +507,12 @@ static void vi5_capture_dequeue(struct tegra_channel *chan,
goto rel_buf;
/* Dequeue a frame and check its capture status */
timeout_ms = chan->capture_timeout_ms;
err = vi_capture_status(chan->tegra_vi_channel[vi_port], timeout_ms);
err = vi_capture_status(chan->tegra_vi_channel[vi_port], CAPTURE_TIMEOUT_MS);
if (err) {
if (err == -ETIMEDOUT) {
if (timeout_ms < 0) {
spin_lock_irqsave(&chan->capture_state_lock, flags);
chan->capture_state = CAPTURE_ERROR_TIMEOUT;
spin_unlock_irqrestore(&chan->capture_state_lock, flags);
buf->vb2_state = VB2_BUF_STATE_ERROR;
goto rel_buf;
} else {
dev_err(vi->dev,
"uncorr_err: request timed out after %d ms\n",
timeout_ms);
}
dev_err(vi->dev,
"uncorr_err: request timed out after %d ms\n",
CAPTURE_TIMEOUT_MS);
} else {
dev_err(vi->dev, "uncorr_err: request err %d\n", err);
}
@@ -594,22 +565,15 @@ static void vi5_capture_dequeue(struct tegra_channel *chan,
uncorr_err:
spin_lock_irqsave(&chan->capture_state_lock, flags);
if (err == -ETIMEDOUT) {
chan->capture_state = CAPTURE_TIMEOUT;
buf->vb2_state = VB2_BUF_STATE_QUEUED;
} else {
chan->capture_state = CAPTURE_ERROR;
buf->vb2_state = VB2_BUF_STATE_ERROR;
}
chan->capture_state = CAPTURE_ERROR;
spin_unlock_irqrestore(&chan->capture_state_lock, flags);
buf->vb2_state = VB2_BUF_STATE_ERROR;
rel_buf:
vi5_release_buffer(chan, buf);
}
static void vi5_unit_get_device_handle(struct platform_device *pdev,
uint32_t csi_stream_id, struct device **dev);
static int vi5_channel_error_recover(struct tegra_channel *chan,
bool queue_error)
{
@@ -627,25 +591,6 @@ static int vi5_channel_error_recover(struct tegra_channel *chan,
dev_err(&chan->video->dev, "vi capture release failed\n");
goto done;
}
/* Release capture requests */
if (chan->request[vi_port] != NULL) {
dma_free_coherent(chan->tegra_vi_channel[vi_port]->rtcpu_dev,
chan->capture_queue_depth * sizeof(struct capture_descriptor),
chan->request[vi_port], chan->request_iova[vi_port]);
}
chan->request[vi_port] = NULL;
/* Release emd data buffers */
if (chan->emb_buf_size > 0) {
struct device *vi_unit_dev;
vi5_unit_get_device_handle(chan->vi->ndev, chan->port[0], &vi_unit_dev);
dma_free_coherent(vi_unit_dev, chan->emb_buf_size,
chan->emb_buf_addr, chan->emb_buf);
chan->emb_buf_size = 0;
}
vi_channel_close_ex(chan->vi_channel_id[vi_port],
chan->tegra_vi_channel[vi_port]);
chan->tegra_vi_channel[vi_port] = NULL;
@@ -663,10 +608,7 @@ static int vi5_channel_error_recover(struct tegra_channel *chan,
buf = dequeue_dequeue_buffer(chan);
if (!buf)
break;
if (chan->capture_state == CAPTURE_TIMEOUT)
buf->vb2_state = VB2_BUF_STATE_QUEUED;
else
buf->vb2_state = VB2_BUF_STATE_ERROR;
buf->vb2_state = VB2_BUF_STATE_ERROR;
vi5_capture_dequeue(chan, buf);
}
@@ -760,7 +702,6 @@ static int tegra_channel_kthread_capture_dequeue(void *data)
struct tegra_channel_buffer *buf;
set_freezable();
allow_signal(SIGINT);
while (1) {
try_to_freeze();
@@ -781,12 +722,6 @@ static int tegra_channel_kthread_capture_dequeue(void *data)
}
spin_lock_irqsave(&chan->capture_state_lock, flags);
if (chan->capture_state == CAPTURE_ERROR_TIMEOUT) {
spin_unlock_irqrestore(&chan->capture_state_lock,
flags);
break;
}
if (chan->capture_state == CAPTURE_ERROR) {
spin_unlock_irqrestore(&chan->capture_state_lock,
flags);
@@ -856,7 +791,6 @@ static void vi5_channel_stop_kthreads(struct tegra_channel *chan)
/* Stop the kthread for capture dequeue */
if (chan->kthread_capture_dequeue) {
send_sig(SIGINT, chan->kthread_capture_dequeue, 1);
kthread_stop(chan->kthread_capture_dequeue);
chan->kthread_capture_dequeue = NULL;
}

View File

@@ -1,14 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-only
* SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES.
* All rights reserved.
*
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* NVIDIA Tegra Video Input Device Driver VI5 formats
*
* Author: Bhanu Murthy V <bmurthyv@nvidia.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
* Copyright (c) 2017-2022, NVIDIA CORPORATION. All rights reserved.
*/
#ifndef __VI5_FORMATS_H_
@@ -97,16 +91,6 @@ static const struct tegra_video_format vi5_video_formats[] = {
TEGRA_VIDEO_FORMAT(RAW8, 8, SBGGR8_1X8, 1, 1, T_R8,
RAW8, SBGGR8, "BGBG.. GRGR.."),
/* RAW 14 */
TEGRA_VIDEO_FORMAT(RAW14, 14, SRGGB14_1X14, 2, 1, T_R16,
RAW14, SRGGB14, "RGRG.. GBGB.."),
TEGRA_VIDEO_FORMAT(RAW14, 14, SGRBG14_1X14, 2, 1, T_R16,
RAW14, SGRBG14, "GRGR.. BGBG.."),
TEGRA_VIDEO_FORMAT(RAW14, 14, SGBRG14_1X14, 2, 1, T_R16,
RAW14, SGBRG14, "GBGB.. RGRG.."),
TEGRA_VIDEO_FORMAT(RAW14, 14, SBGGR14_1X14, 2, 1, T_R16,
RAW14, SBGGR14, "BGBG.. GRGR.."),
/* RAW 10 */
TEGRA_VIDEO_FORMAT(RAW10, 10, SRGGB10_1X10, 2, 1, T_R16,
RAW10, SRGGB10, "RGRG.. GBGB.."),

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
/*
* cam_cdi_tsc.c - tsc driver.
*/
@@ -147,8 +147,6 @@ struct tsc_signal_controller {
} debugfs;
const struct tsc_signal_controller_features *features;
struct list_head generators;
bool opened;
};
static const struct tsc_signal_controller_features tegra234_tsc_features = {
@@ -460,44 +458,22 @@ static void cdi_tsc_debugfs_remove(struct tsc_signal_controller *controller)
static int cdi_tsc_chardev_open(struct inode *inode, struct file *file)
{
struct tsc_signal_controller *controller = dev_get_drvdata(tsc_charDevice);
int err = 0;
pr_info("%s:Device opened\n", __func__);
if (controller->opened)
return -EBUSY;
/* Set External Fsync */
Hawk_Owl_Fsync_program(EXTERNAL_FSYNC);
/* Make sure device opened only once */
controller->opened = true;
/* Set External Fsync */
err = Hawk_Owl_Fsync_program(EXTERNAL_FSYNC);
if (err)
controller->opened = false;
else
dev_dbg(controller->dev, "%s:Device opened successfully!! \n", __func__);
return err;
return 0;
}
static int cdi_tsc_chardev_release(struct inode *inode, struct file *file)
{
struct tsc_signal_controller *controller = dev_get_drvdata(tsc_charDevice);
int err = -EFAULT;
/* To make sure whenever the device is closed, tsc is also stopped
* to avoid inconsistency behaviour at app level i.e to avoid out of sync.
*/
err = cdi_tsc_stop_generators(controller);
if (err)
return err;
pr_info("%s:Device closed\n", __func__);
/* Set back to Internal Fsync */
err = Hawk_Owl_Fsync_program(INTERNAL_FSYNC);
Hawk_Owl_Fsync_program(INTERNAL_FSYNC);
controller->opened = false;
dev_dbg(controller->dev, "%s Device closed ..\n", __func__);
return err;
return 0;
}
static long cdi_tsc_chardev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -544,7 +520,6 @@ static int cdi_tsc_probe(struct platform_device *pdev)
if (!controller)
return -ENOMEM;
controller->opened = false;
controller->dev = &pdev->dev;
controller->features = of_device_get_match_data(&pdev->dev);
if (controller->features == NULL) {
@@ -645,18 +620,6 @@ MODULE_DEVICE_TABLE(of, cdi_tsc_of_match);
static SIMPLE_DEV_PM_OPS(cdi_tsc_pm, cdi_tsc_suspend, cdi_tsc_resume);
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void cdi_tsc_remove_wrapper(struct platform_device *pdev)
{
cdi_tsc_remove(pdev);
}
#else
static int cdi_tsc_remove_wrapper(struct platform_device *pdev)
{
return cdi_tsc_remove(pdev);
}
#endif
static struct platform_driver cdi_tsc_driver = {
.driver = {
.name = "cdi_tsc",
@@ -665,7 +628,7 @@ static struct platform_driver cdi_tsc_driver = {
.pm = &cdi_tsc_pm,
},
.probe = cdi_tsc_probe,
.remove = cdi_tsc_remove_wrapper,
.remove = cdi_tsc_remove,
};
module_platform_driver(cdi_tsc_driver);

View File

@@ -1,13 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-FileCopyrightText: Copyright (c) 2016-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2016-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#ifndef __CDI_PWM_PRIV_H__
#define __CDI_PWM_PRIV_H__
struct cdi_pwm_info {
#if !defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
struct pwm_chip chip;
#endif
struct pwm_device *pwm;
atomic_t in_use;
struct mutex mutex;

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2017-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
@@ -33,11 +33,7 @@ static int of_cdi_gpio_pdata(struct platform_device *pdev,
return err;
}
#if defined(NV_GPIO_DEVICE_FIND_HAS_CONST_DATA_ARG) /* Linux v6.9 */
static int cdi_gpio_chip_match(struct gpio_chip *chip, const void *data)
#else
static int cdi_gpio_chip_match(struct gpio_chip *chip, void *data)
#endif
{
return !strcmp(chip->label, data);
}
@@ -46,8 +42,7 @@ static struct gpio_chip *cdi_gpio_get_chip(struct platform_device *pdev,
struct cdi_gpio_plat_data *pd)
{
struct gpio_chip *gc = NULL;
#if defined(NV_GPIO_DEVICE_FIND_PRESENT) && \
defined(NV_GPIO_DEVICE_GET_CHIP_PRESENT) /* Linux 6.7 */
#if !defined(NV_GPIOCHIP_FIND_PRESENT) /* Linux 6.7 */
struct gpio_device *gdev;
#endif
char name[MAX_STR_SIZE];
@@ -59,15 +54,14 @@ static struct gpio_chip *cdi_gpio_get_chip(struct platform_device *pdev,
}
strcpy(name, pd->gpio_prnt_chip);
#if defined(NV_GPIO_DEVICE_FIND_PRESENT) && \
defined(NV_GPIO_DEVICE_GET_CHIP_PRESENT) /* Linux 6.7 */
#if defined(NV_GPIOCHIP_FIND_PRESENT) /* Linux 6.7 */
gc = gpiochip_find(name, cdi_gpio_chip_match);
#else
gdev = gpio_device_find(name, cdi_gpio_chip_match);
if (gdev) {
gc = gpio_device_get_chip(gdev);
gpio_device_put(gdev);
}
#else
gc = gpiochip_find(name, cdi_gpio_chip_match);
#endif
if (!gc) {
dev_err(&pdev->dev, "%s: unable to find gpio parent chip %s\n",
@@ -330,21 +324,9 @@ static const struct of_device_id cdi_gpio_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, cdi_gpio_dt_ids);
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void cdi_gpio_remove_wrapper(struct platform_device *pdev)
{
cdi_gpio_remove(pdev);
}
#else
static int cdi_gpio_remove_wrapper(struct platform_device *pdev)
{
return cdi_gpio_remove(pdev);
}
#endif
static struct platform_driver cdi_gpio_driver = {
.probe = cdi_gpio_probe,
.remove = cdi_gpio_remove_wrapper,
.remove = cdi_gpio_remove,
.driver = {
.name = "cdi-gpio",
.of_match_table = cdi_gpio_dt_ids,

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2015-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2015-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
@@ -1776,14 +1776,9 @@ static int cdi_mgr_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(cdi_mgr->gpios); i++) {
pin = &cdi_mgr->gpios[i];
pin->mgr = cdi_mgr;
#if defined(NV_HRTIMER_SETUP_PRESENT) /* Linux v6.13 */
hrtimer_setup(&pin->timers.timer, &cdi_mgr_intr_timer,
CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
#else
hrtimer_init(&pin->timers.timer, CLOCK_MONOTONIC,
HRTIMER_MODE_ABS);
pin->timers.timer.function = &cdi_mgr_intr_timer;
#endif
}
if (pdev->dev.of_node) {
@@ -2089,18 +2084,6 @@ static const struct of_device_id cdi_mgr_of_match[] = {
};
MODULE_DEVICE_TABLE(of, cdi_mgr_of_match);
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void cdi_mgr_remove_wrapper(struct platform_device *pdev)
{
cdi_mgr_remove(pdev);
}
#else
static int cdi_mgr_remove_wrapper(struct platform_device *pdev)
{
return cdi_mgr_remove(pdev);
}
#endif
static struct platform_driver cdi_mgr_driver = {
.driver = {
.name = "cdi-mgr",
@@ -2109,7 +2092,7 @@ static struct platform_driver cdi_mgr_driver = {
.pm = &cdi_mgr_pm_ops,
},
.probe = cdi_mgr_probe,
.remove = cdi_mgr_remove_wrapper,
.remove = cdi_mgr_remove,
};
module_platform_driver(cdi_mgr_driver);

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2016-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2016-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
@@ -30,11 +30,7 @@ static const struct of_device_id cdi_pwm_of_match[] = {
static inline struct cdi_pwm_info *to_cdi_pwm_info(struct pwm_chip *chip)
{
#if defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
return pwmchip_get_drvdata(chip);
#else
return container_of(chip, struct cdi_pwm_info, chip);
#endif
}
#if KERNEL_VERSION(6, 0, 0) > LINUX_VERSION_CODE
@@ -99,38 +95,30 @@ static struct pwm_device *of_cdi_pwm_xlate(struct pwm_chip *pc,
{
struct pwm_device *pwm;
struct cdi_pwm_info *info = to_cdi_pwm_info(pc);
#if defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
struct device *dev = &pc->dev;
#else
struct device *dev = pc->dev;
#endif
int err = 0;
pwm = of_pwm_xlate_with_flags(pc, args);
if (IS_ERR(pwm))
return NULL;
if (!pwm->args.period) {
dev_err(dev, "Period should be larger than 0\n");
pwm = pwm_request_from_chip(pc, args->args[0], NULL);
if (!args->args[1]) {
dev_err(pc->dev, "Period should be larger than 0\n");
return NULL;
}
if (info->force_on) {
err = pwm_config(info->pwm, args->args[1]/4, args->args[1]);
if (err) {
dev_err(dev, "can't config PWM: %d\n", err);
dev_err(pc->dev, "can't config PWM: %d\n", err);
return NULL;
}
err = pwm_enable(info->pwm);
if (err) {
dev_err(dev, "can't enable PWM: %d\n", err);
dev_err(pc->dev, "can't enable PWM: %d\n", err);
return NULL;
}
} else {
err = pwm_config(pwm, args->args[1]/4, args->args[1]);
if (err) {
dev_err(dev, "can't config PWM: %d\n", err);
dev_err(pc->dev, "can't config PWM: %d\n", err);
return NULL;
}
}
@@ -152,60 +140,50 @@ static const struct pwm_ops cdi_pwm_ops = {
static int cdi_pwm_probe(struct platform_device *pdev)
{
struct cdi_pwm_info *info = NULL;
struct pwm_chip *chip;
int err = 0, npwm;
bool force_on = false;
dev_info(&pdev->dev, "%sing...\n", __func__);
info = devm_kzalloc(
&pdev->dev, sizeof(struct cdi_pwm_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
atomic_set(&info->in_use, 0);
mutex_init(&info->mutex);
err = of_property_read_u32(pdev->dev.of_node, "npwm", &npwm);
if (err < 0) {
dev_err(&pdev->dev, "npwm is not defined: %d\n", err);
return err;
}
#if defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*info));
if (IS_ERR(chip))
return PTR_ERR(chip);
info = to_cdi_pwm_info(chip);
#else
info = devm_kzalloc(
&pdev->dev, sizeof(struct cdi_pwm_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
chip = &info->chip;
chip->dev = &pdev->dev;
chip->npwm = npwm;
#endif
atomic_set(&info->in_use, 0);
mutex_init(&info->mutex);
force_on = of_property_read_bool(pdev->dev.of_node, "force_on");
chip->ops = &cdi_pwm_ops;
info->chip.dev = &pdev->dev;
info->chip.ops = &cdi_pwm_ops;
#if defined(NV_PWM_CHIP_STRUCT_HAS_BASE_ARG)
chip->base = -1;
info->chip.base = -1;
#endif
chip->of_xlate = of_cdi_pwm_xlate;
info->chip.npwm = npwm;
info->chip.of_xlate = of_cdi_pwm_xlate;
info->force_on = force_on;
err = pwmchip_add(chip);
err = pwmchip_add(&info->chip);
if (err < 0) {
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", err);
return err;
}
platform_set_drvdata(pdev, chip);
platform_set_drvdata(pdev, info);
info->pwm = devm_pwm_get(&pdev->dev, NULL);
if (!IS_ERR(info->pwm)) {
pwm_disable(info->pwm);
dev_info(&pdev->dev, "%s success to get PWM\n", __func__);
} else {
pwmchip_remove(chip);
pwmchip_remove(&info->chip);
err = PTR_ERR(info->pwm);
if (err != -EPROBE_DEFER)
dev_err(&pdev->dev,
@@ -217,24 +195,24 @@ static int cdi_pwm_probe(struct platform_device *pdev)
static int cdi_pwm_remove(struct platform_device *pdev)
{
struct pwm_chip *chip = platform_get_drvdata(pdev);
struct cdi_pwm_info *info = platform_get_drvdata(pdev);
pwmchip_remove(chip);
pwmchip_remove(&info->chip);
return 0;
}
static int cdi_pwm_suspend(struct device *dev)
{
struct pwm_chip *chip = dev_get_drvdata(dev);
struct cdi_pwm_info *info = to_cdi_pwm_info(chip);
int err = 0;
struct cdi_pwm_info *info = dev_get_drvdata(dev);
if (info == NULL) {
dev_err(dev, "%s: fail to get info\n", __func__);
} else {
if (!IS_ERR(info->pwm)) {
pwm_disable(info->pwm);
pwm_config(info->pwm, PWM_SUSPEND_DUTY_RATIO,
err = pwm_config(info->pwm, PWM_SUSPEND_DUTY_RATIO,
PWM_SUSPEND_PERIOD);
}
}
@@ -254,18 +232,6 @@ static const struct dev_pm_ops cdi_pwm_pm_ops = {
.runtime_resume = cdi_pwm_resume,
};
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void cdi_pwm_remove_wrapper(struct platform_device *pdev)
{
cdi_pwm_remove(pdev);
}
#else
static int cdi_pwm_remove_wrapper(struct platform_device *pdev)
{
return cdi_pwm_remove(pdev);
}
#endif
static struct platform_driver cdi_pwm_driver = {
.driver = {
.name = "cdi-pwm",
@@ -274,7 +240,7 @@ static struct platform_driver cdi_pwm_driver = {
.pm = &cdi_pwm_pm_ops,
},
.probe = cdi_pwm_probe,
.remove = cdi_pwm_remove_wrapper,
.remove = cdi_pwm_remove,
};
module_platform_driver(cdi_pwm_driver);

View File

@@ -1,13 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* SPDX-FileCopyrightText: Copyright (c) 2016-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
/*
* Copyright (c) 2016-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#ifndef __ISC_PWM_PRIV_H__
#define __ISC_PWM_PRIV_H__
struct isc_pwm_info {
#if !defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
struct pwm_chip chip;
#endif
struct pwm_device *pwm;
atomic_t in_use;
struct mutex mutex;

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2017-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2017-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
@@ -33,11 +33,7 @@ static int of_isc_gpio_pdata(struct platform_device *pdev,
return err;
}
#if defined(NV_GPIO_DEVICE_FIND_HAS_CONST_DATA_ARG) /* Linux v6.9 */
static int isc_gpio_chip_match(struct gpio_chip *chip, const void *data)
#else
static int isc_gpio_chip_match(struct gpio_chip *chip, void *data)
#endif
{
return !strcmp(chip->label, data);
}
@@ -47,8 +43,7 @@ static struct gpio_chip *isc_gpio_get_chip(struct platform_device *pdev,
{
struct gpio_chip *gc = NULL;
char name[MAX_STR_SIZE];
#if defined(NV_GPIO_DEVICE_FIND_PRESENT) && \
defined(NV_GPIO_DEVICE_GET_CHIP_PRESENT) /* Linux 6.7 */
#if !defined(NV_GPIOCHIP_FIND_PRESENT) /* Linux 6.7 */
struct gpio_device *gdev;
#endif
@@ -59,15 +54,14 @@ static struct gpio_chip *isc_gpio_get_chip(struct platform_device *pdev,
}
strcpy(name, pd->gpio_prnt_chip);
#if defined(NV_GPIO_DEVICE_FIND_PRESENT) && \
defined(NV_GPIO_DEVICE_GET_CHIP_PRESENT) /* Linux 6.7 */
#if defined(NV_GPIOCHIP_FIND_PRESENT) /* Linux 6.7 */
gc = gpiochip_find(name, isc_gpio_chip_match);
#else
gdev = gpio_device_find(name, isc_gpio_chip_match);
if (gdev) {
gc = gpio_device_get_chip(gdev);
gpio_device_put(gdev);
}
#else
gc = gpiochip_find(name, isc_gpio_chip_match);
#endif
if (!gc) {
dev_err(&pdev->dev, "%s: unable to find gpio parent chip %s\n",
@@ -330,21 +324,9 @@ static const struct of_device_id isc_gpio_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, isc_gpio_dt_ids);
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void isc_gpio_remove_wrapper(struct platform_device *pdev)
{
isc_gpio_remove(pdev);
}
#else
static int isc_gpio_remove_wrapper(struct platform_device *pdev)
{
return isc_gpio_remove(pdev);
}
#endif
static struct platform_driver isc_gpio_driver = {
.probe = isc_gpio_probe,
.remove = isc_gpio_remove_wrapper,
.remove = isc_gpio_remove,
.driver = {
.name = "isc-gpio",
.of_match_table = isc_gpio_dt_ids,

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2015-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2015-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
@@ -1204,18 +1204,6 @@ static const struct of_device_id isc_mgr_of_match[] = {
};
MODULE_DEVICE_TABLE(of, isc_mgr_of_match);
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void isc_mgr_remove_wrapper(struct platform_device *pdev)
{
isc_mgr_remove(pdev);
}
#else
static int isc_mgr_remove_wrapper(struct platform_device *pdev)
{
return isc_mgr_remove(pdev);
}
#endif
static struct platform_driver isc_mgr_driver = {
.driver = {
.name = "isc-mgr",
@@ -1224,7 +1212,7 @@ static struct platform_driver isc_mgr_driver = {
.pm = &isc_mgr_pm_ops,
},
.probe = isc_mgr_probe,
.remove = isc_mgr_remove_wrapper,
.remove = isc_mgr_remove,
};
module_platform_driver(isc_mgr_driver);

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2016-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2016-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
@@ -30,11 +30,7 @@ static const struct of_device_id isc_pwm_of_match[] = {
static inline struct isc_pwm_info *to_isc_pwm_info(struct pwm_chip *chip)
{
#if defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
return pwmchip_get_drvdata(chip);
#else
return container_of(chip, struct isc_pwm_info, chip);
#endif
}
#if KERNEL_VERSION(6, 0, 0) > LINUX_VERSION_CODE
@@ -99,38 +95,30 @@ static struct pwm_device *of_isc_pwm_xlate(struct pwm_chip *pc,
{
struct pwm_device *pwm;
struct isc_pwm_info *info = to_isc_pwm_info(pc);
#if defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
struct device *dev = &pc->dev;
#else
struct device *dev = pc->dev;
#endif
int err = 0;
pwm = of_pwm_xlate_with_flags(pc, args);
if (IS_ERR(pwm))
return NULL;
if (!pwm->args.period) {
dev_err(dev, "Period should be larger than 0\n");
pwm = pwm_request_from_chip(pc, args->args[0], NULL);
if (!args->args[1]) {
dev_err(pc->dev, "Period should be larger than 0\n");
return NULL;
}
if (info->force_on) {
err = pwm_config(info->pwm, args->args[1]/4, args->args[1]);
if (err) {
dev_err(dev, "can't config PWM: %d\n", err);
dev_err(pc->dev, "can't config PWM: %d\n", err);
return NULL;
}
err = pwm_enable(info->pwm);
if (err) {
dev_err(dev, "can't enable PWM: %d\n", err);
dev_err(pc->dev, "can't enable PWM: %d\n", err);
return NULL;
}
} else {
err = pwm_config(pwm, args->args[1]/4, args->args[1]);
if (err) {
dev_err(dev, "can't config PWM: %d\n", err);
dev_err(pc->dev, "can't config PWM: %d\n", err);
return NULL;
}
}
@@ -152,60 +140,50 @@ static const struct pwm_ops isc_pwm_ops = {
static int isc_pwm_probe(struct platform_device *pdev)
{
struct isc_pwm_info *info = NULL;
struct pwm_chip *chip;
int err = 0, npwm;
bool force_on = false;
dev_info(&pdev->dev, "%sing...\n", __func__);
info = devm_kzalloc(
&pdev->dev, sizeof(struct isc_pwm_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
atomic_set(&info->in_use, 0);
mutex_init(&info->mutex);
err = of_property_read_u32(pdev->dev.of_node, "npwm", &npwm);
if (err < 0) {
dev_err(&pdev->dev, "npwm is not defined: %d\n", err);
return err;
}
#if defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*info));
if (IS_ERR(chip))
return PTR_ERR(chip);
info = to_isc_pwm_info(chip);
#else
info = devm_kzalloc(
&pdev->dev, sizeof(struct isc_pwm_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
chip = &info->chip;
chip->dev = &pdev->dev;
chip->npwm = npwm;
#endif
atomic_set(&info->in_use, 0);
mutex_init(&info->mutex);
force_on = of_property_read_bool(pdev->dev.of_node, "force_on");
chip->ops = &isc_pwm_ops;
info->chip.dev = &pdev->dev;
info->chip.ops = &isc_pwm_ops;
#if defined(NV_PWM_CHIP_STRUCT_HAS_BASE_ARG)
chip->base = -1;
info->chip.base = -1;
#endif
chip->of_xlate = of_isc_pwm_xlate;
info->chip.npwm = npwm;
info->chip.of_xlate = of_isc_pwm_xlate;
info->force_on = force_on;
err = pwmchip_add(chip);
err = pwmchip_add(&info->chip);
if (err < 0) {
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", err);
return err;
}
platform_set_drvdata(pdev, chip);
platform_set_drvdata(pdev, info);
info->pwm = devm_pwm_get(&pdev->dev, NULL);
if (!IS_ERR(info->pwm)) {
pwm_disable(info->pwm);
dev_info(&pdev->dev, "%s success to get PWM\n", __func__);
} else {
pwmchip_remove(chip);
pwmchip_remove(&info->chip);
err = PTR_ERR(info->pwm);
if (err != -EPROBE_DEFER)
dev_err(&pdev->dev,
@@ -217,24 +195,24 @@ static int isc_pwm_probe(struct platform_device *pdev)
static int isc_pwm_remove(struct platform_device *pdev)
{
struct pwm_chip *chip = platform_get_drvdata(pdev);
struct isc_pwm_info *info = platform_get_drvdata(pdev);
pwmchip_remove(chip);
pwmchip_remove(&info->chip);
return 0;
}
static int isc_pwm_suspend(struct device *dev)
{
struct pwm_chip *chip = dev_get_drvdata(dev);
struct isc_pwm_info *info = to_isc_pwm_info(chip);
int err = 0;
struct isc_pwm_info *info = dev_get_drvdata(dev);
if (info == NULL) {
dev_err(dev, "%s: fail to get info\n", __func__);
} else {
if (!IS_ERR(info->pwm)) {
pwm_disable(info->pwm);
pwm_config(info->pwm, PWM_SUSPEND_DUTY_RATIO,
err = pwm_config(info->pwm, PWM_SUSPEND_DUTY_RATIO,
PWM_SUSPEND_PERIOD);
}
}
@@ -254,18 +232,6 @@ static const struct dev_pm_ops isc_pwm_pm_ops = {
.runtime_resume = isc_pwm_resume,
};
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void isc_pwm_remove_wrapper(struct platform_device *pdev)
{
isc_pwm_remove(pdev);
}
#else
static int isc_pwm_remove_wrapper(struct platform_device *pdev)
{
return isc_pwm_remove(pdev);
}
#endif
static struct platform_driver isc_pwm_driver = {
.driver = {
.name = "isc-pwm",
@@ -274,7 +240,7 @@ static struct platform_driver isc_pwm_driver = {
.pm = &isc_pwm_pm_ops,
},
.probe = isc_pwm_probe,
.remove = isc_pwm_remove_wrapper,
.remove = isc_pwm_remove,
};
module_platform_driver(isc_pwm_driver);

View File

@@ -297,7 +297,7 @@ static int __init tpg_probe_t19x(void)
return -EINVAL;
mc_csi->get_tpg_settings = get_tpg_settings_t23x;
mc_csi->tpg_gain_ctrl = false;
mc_csi->tpg_gain_ctrl = true;
mc_csi->tpg_emb_data_config = emb_data;
dev_info(mc_csi->dev, "%s\n", __func__);
@@ -310,7 +310,7 @@ static int __init tpg_probe_t19x(void)
mc_csi->tpg_frmfmt_table_size = table_size;
memcpy(frmfmt_table, tegra19x_csi_tpg_frmfmt,
table_size * sizeof(struct tpg_frmfmt));
table_size * sizeof(struct tpg_frmfmt));
if (override_frmfmt) {
for (i = 0; i < table_size; i++)

View File

@@ -2,7 +2,7 @@
/*
* Voltage Regulator Specification: Power Sequencer MFD Driver
*
* SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (C) 2020-2023 NVIDIA CORPORATION. All rights reserved.
*/
#include <nvidia/conftest.h>
@@ -228,14 +228,6 @@ static int nvvrs_pseq_probe(struct i2c_client *client,
return ret;
}
/* When battery mounted, the chip may have IRQ asserted. */
/* Clear it before IRQ requested. */
ret = nvvrs_pseq_irq_clear(nvvrs_chip);
if (ret < 0) {
dev_err(nvvrs_chip->dev, "Failed to clear IRQ: %d\n", ret);
return ret;
}
nvvrs_pseq_irq_chip.irq_drv_data = nvvrs_chip;
ret = devm_regmap_add_irq_chip(nvvrs_chip->dev, nvvrs_chip->rmap, client->irq,
IRQF_ONESHOT | IRQF_SHARED, 0,

View File

@@ -1,15 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
LINUX_VERSION := $(shell expr $(VERSION) \* 256 + $(PATCHLEVEL))
LINUX_VERSION_6_11 := $(shell expr 6 \* 256 + 11)
# MODS is currently broken for Linux v6.11 and later
ifeq ($(shell test $(LINUX_VERSION) -lt $(LINUX_VERSION_6_11); echo $$?),0)
ifeq ($(findstring ack_src,$(NV_BUILD_KERNEL_OPTIONS)),)
obj-m += mods/
endif
endif
obj-m += nvsciipc/
ifdef CONFIG_PCI
obj-m += tegra-pcie-dma-test.o
@@ -17,4 +11,3 @@ endif
obj-m += bluedroid_pm.o
obj-m += nvscic2c-pcie/
obj-m += ioctl_example.o
obj-m += tegra-cec/

View File

@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2019-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-FileCopyrightText: Copyright (C) 2019-2023 NVIDIA CORPORATION. All rights reserved.
#include <nvidia/conftest.h>
#include <nvidia/conftest.h>
@@ -265,11 +267,7 @@ static ssize_t lpm_write_proc(struct file *file, const char __user *buffer,
bluedroid_pm_gpio_set_value(
bluedroid_pm->ext_wake, 1);
__pm_stay_awake(&bluedroid_pm->wake_lock);
#if defined(NV_TIMER_DELETE_PRESENT) /* Linux v6.15 */
timer_delete(&bluedroid_pm_timer);
#else
del_timer(&bluedroid_pm_timer);
#endif
set_bit(BT_WAKE, &bluedroid_pm->flags);
} else {
kfree(buf);
@@ -541,11 +539,7 @@ static int bluedroid_pm_remove(struct platform_device *pdev)
wakeup_source_destroy(&bluedroid_pm->wake_lock);
gpio_free(bluedroid_pm->ext_wake);
remove_bt_proc_interface();
#if defined(NV_TIMER_DELETE_PRESENT) /* Linux v6.15 */
timer_delete(&bluedroid_pm_timer);
#else
del_timer(&bluedroid_pm_timer);
#endif
}
if ((gpio_is_valid(bluedroid_pm->gpio_reset)) ||
(gpio_is_valid(bluedroid_pm->gpio_shutdown)) ||
@@ -633,21 +627,9 @@ static struct of_device_id bdroid_of_match[] = {
};
MODULE_DEVICE_TABLE(of, bdroid_of_match);
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void bluedroid_pm_remove_wrapper(struct platform_device *pdev)
{
bluedroid_pm_remove(pdev);
}
#else
static int bluedroid_pm_remove_wrapper(struct platform_device *pdev)
{
return bluedroid_pm_remove(pdev);
}
#endif
static struct platform_driver bluedroid_pm_driver = {
.probe = bluedroid_pm_probe,
.remove = bluedroid_pm_remove_wrapper,
.remove = bluedroid_pm_remove,
.suspend = bluedroid_pm_suspend,
.resume = bluedroid_pm_resume,
.shutdown = bluedroid_pm_shutdown,

View File

@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
/* SPDX-FileCopyrightText: Copyright (c) 2014-2025, NVIDIA CORPORATION. All rights reserved. */
#include <nvidia/conftest.h>
/* SPDX-FileCopyrightText: Copyright (c) 2014-2023, NVIDIA CORPORATION. All rights reserved. */
#include <linux/dma-buf.h>
#include <linux/module.h>
@@ -10,11 +8,7 @@
#include "mods_internal.h"
#if defined(NV_MODULE_IMPORT_NS_CALLS_STRINGIFY)
MODULE_IMPORT_NS(DMA_BUF);
#else
MODULE_IMPORT_NS("DMA_BUF");
#endif
static struct device *dummy_device;

Some files were not shown because too many files have changed in this diff Show More