mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 10:11:26 +03:00
Compare commits
6 Commits
rel-36
...
rel-36-lws
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f703af3e0 | ||
|
|
033c964778 | ||
|
|
3b830eb8a7 | ||
|
|
3ebca7545e | ||
|
|
c79de35fb0 | ||
|
|
c5d97870d1 |
25
.gitignore
vendored
25
.gitignore
vendored
@@ -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*
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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__ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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__ */
|
||||
@@ -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, ¤t_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, ¤t_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;
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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", ®_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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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, ®_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");
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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.."),
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user