Compare commits

..

5 Commits

Author SHA1 Message Date
Mohan Kumar
4212fbd97f ASoC: tegra: avoid enabling aud_mclk during init
Enabling the aud_mclk clock during initialization of drivers
was done for T30 chip due to some external dependencies, now
it is not required for latest version of chips and also due
to this aud_mclk is kept always ON. Add check to avoid enabling
aud_mclk clock other than T30

Bug 4373898

Change-Id: If341b1b73051c5572c5551bf6d4659fab7a116d2
Signed-off-by: Mohan Kumar <mkumard@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3015891
(cherry picked from commit 7ffd0c9cfa)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3019203
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
2023-11-22 13:02:29 -08:00
Praveen AC
4e63d195c6 drivers:media: Fix imx390 & imx185 probe issue.
Due to "mingain - 1" & "minexp - 1" during probe time observing
out of range whenever gain or exp is set "0" as min in DT.
Instead doing "maxgain + 1" & "maxexp + 1" to fix the probe.

Bug 4142996
Bug 4189361
Bug 4386912

Change-Id: I103e87b293079dadcd16b91f8e329ec9f938208c
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3020349
Tested-by: Praveen AC <pac@nvidia.com>
Reviewed-by: Praveen AC <pac@nvidia.com>
Reviewed-by: Narendra Kondapalli <nkondapalli@nvidia.com>
Reviewed-by: Ankur Pawar <ankurp@nvidia.com>
Reviewed-by: Anubhav Rai <arai@nvidia.com>
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
2023-11-22 10:18:55 -08:00
Yi-Wei Wang
4ad0e0c6c8 thermal: add thermal trip event cooling device
This change adds a cooling device driver to notify the user space of the
thermal trip event. To avoid having user space process poll the
cooling state, a sysfs node is exposed that supports blocking reads.
The driver also supports a timeout (in milliseconds) for blocking reads
which can be done by writing the value to thermal_trip_event_block node
before reading. The blocked user space process will be woken up when the
cooling device becomes active or times out.

Bug 4261645
Bug 1688327

Signed-off-by: Yi-Wei Wang <yiweiw@nvidia.com>
Change-Id: Ic89406ba2713e5bc8f3806d6cfeb462601c73a7d
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3015652
(cherry picked from commit 856471d64f)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3019213
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
2023-11-21 12:24:53 -08:00
Anubhav Rai
969619a872 camera: lt6911uxc update with Shadow EDID
Update the Lontium driver to flash shadow EDID
to lt6911uxc chip. This will ensure that the requested
resolution through the application is flashed to the
chip and the source is forced to select the
requested resolution only.

bug 4266018
bug 4301203
bug 4168489
Signed-off-by: Anubhav Rai <arai@nvidia.com>

Change-Id: I945a9658b52c82956535f3710312d317c0098be7
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3007702
(cherry picked from commit c3ddb23392)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3016371
Tested-by: Anubhav Rai <arai@nvidia.com>
Reviewed-by: Anubhav Rai <arai@nvidia.com>
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
2023-11-16 21:15:37 -08:00
Gautham Srinivasan
ad7508c52a drivers: aon: Add AON Echo driver
Add AON echo driver. This driver creates data_channel file in sysfs
which is used to communicate between CCPLEX and AON.

Bug 4296173

Change-Id: Id790fc4076205e16509611f7fa07ffc073491227
Signed-off-by: Gautham Srinivasan <gauthams@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2954202
(cherry picked from commit 66c26d1ac3)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3015993
Reviewed-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
Tested-by: Amulya Yarlagadda <ayarlagadda@nvidia.com>
2023-11-14 20:48:17 -08:00
1813 changed files with 89468 additions and 1443868 deletions

25
.gitignore vendored
View File

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

View File

@@ -5,24 +5,19 @@ correlation feature.
Required properties:
- compatible: This should be nvidia,tegra194-nvpps for Xavier and nvidia,tegra234-nvpps for Orin.
- compatibles: should be "nvpps,tegra194-nvpps"
Optional properties:
- primary-emac: specifies ethernet emac device DT. This is the primary ethernet MAC device utilized
to calculate PTP time. For example, if MGBE0 is used to calculate the PTP time,
then phandle of the device tree node corresponding to MGBE0 needs to be passed.
For Example for Orin:
mgbe0: ethernet@6800000
eqos: ethernet@2310000
For Example for Xavier:
eqos: ethernet@2490000
- sec-emac: specifies secondary ethernet MAC device DT node to be used to calculate PTP time.
- gpios: GPIO number and active level for the PPS input signal
- memmap_phc_regs: boolean flag to indicate MAC PHC regs to be memory mapped
for getting PTP time. If not defined ptp notifer method will
be used with selected interface
- interface: NW interface name to be used for MAC PHC regs. This field can be
set to 'eqos_0', 'mgbe0_0', 'mgbe1_0', 'mgbe2_0' or 'mgbe3_0' for Orin.
For Xavier, it shoud be set to 'eqos_0'. If undef, default to 'eqos_0'
- sec_interface: NW interface name to be used to calculate PTP Time offset.
set to 'eqos_0', 'mgbe0_0', 'mgbe1_0', 'mgbe2_0' or 'mgbe3_0' for Orin.
For Xavier, Leave this undefined. For Orin, If undef default to 'eqos_0'
- ptp_tsc_k_int: Specifies the integer part of the factor used to calculate the delta to
apply to NUM when the fast convergence algorithm is enabled when syncing
or locking TSC time with PTP time domain.
@@ -36,78 +31,42 @@ Optional properties:
If unspecified, NvPPS driver uses 0x26C(corresponding to 20us) by default
- ptp_tsc_sync_dis: boolean flag to indicate if nvpps should disable PTP TSC sync logic.
The default behaviour is to keep PTP TSC sync logic enabled.
- reg: specifies start address and registers count details of TSC module. It is only applicable for Orin.
- nvpps-gpios: specifies GPIO number for PPS input signal.
- timestamps: specifies timestamp for the GPIO provided by HTE.
- timestamp-names: specifies name for GPIO timestamp.
Example: Timer mode on Orin.
mgbe0: ethernet@6800000{
};
Example:
nvpps {
compatible = "nvidia,tegrat194-nvpps";
status = "okay";
compatible = "nvidia,tegra234-nvpps";
primary-emac = <&mgbe0>;
sec-emac = <&mgbe0>;
reg = <0x0 0xc6a0000 0x0 0x1000>;
gpios = <&tegra_aon_gpio TEGRA194_AON_GPIO(BB, 2) GPIO_ACTIVE_HIGH>;
};
Example: Timer mode on Xavier
eqos: ethernet@2490000{
};
Example:
nvpps {
status = "okay";
compatible = "nvidia,tegra194-nvpps";
primary-emac = <&eqos>;
sec-emac = <&eqos>;
};
Example: MAC PHC regs to be memory mapped on Orin
mgbe0: ethernet@6800000{
};
nvpps {
status = "okay";
compatible = "nvidia,tegra234-nvpps";
primary-emac = <&mgbe0>
sec-emac = <&mgbe0>;
gpios = <&tegra_aon_gpio TEGRA234_AON_GPIO(EE, 6) GPIO_ACTIVE_HIGH>;
memmap_phc_regs;
reg = <0x0 0xc6a0000 0x0 0x1000>;
interface = "mgbe2_0";
};
Example: GPIO mode on Orin
mgbe0: ethernet@6800000{
};
Example:
nvpps {
compatible = "nvidia,tegra194-nvpps";
status = "okay";
compatible = "nvidia,tegra234-nvpps";
reg = <0x0 0xc6a0000 0x0 0x1000>;
nvpps-gpios = <&gpio_aon TEGRA234_AON_GPIO(BB, 0) GPIO_ACTIVE_HIGH>;
timestamps = <&hte_aon TEGRA234_AON_GPIO(BB, 0)>;
timestamp-names = "nvpps_gpio";
};
Example: Timer mode on Orin with additional properties.
mgbe0: ethernet@6800000{
};
nvpps {
status = "okay";
compatible = "nvidia,tegra234-nvpps";
primary-emac = <&mgbe0>;
sec-emac = <&mgbe0>;
reg = <0x0 0xc6a0000 0x0 0x1000>;
gpios = <&tegra_aon_gpio TEGRA234_AON_GPIO(EE, 6) GPIO_ACTIVE_HIGH>;
interface = "mgbe2_0";
sec_interface = "eqos_0";
ptp_tsc_k_int = /bits/ 8 <0x70>;
ptp_tsc_lock_threshold = /bits/ 16 <0x26C>;
ptp_tsc_sync_dis;
};
Example: GPIO as optional
nvpps {
compatible = "nvidia,tegra194-nvpps";
status = "okay";
interface = "mgbe2_0";
};

View File

@@ -1,11 +1,67 @@
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
LINUXINCLUDE += -I$(srctree.nvconftest)
LINUXINCLUDE += -I$(srctree.nvidia-oot)/include
subdir-ccflags-y += -Werror
subdir-ccflags-y += -Wmissing-prototypes
LINUX_VERSION := $(shell expr $(VERSION) \* 256 + $(PATCHLEVEL))
LINUX_VERSION_6_2 := $(shell expr 6 \* 256 + 2)
LINUX_VERSION_6_3 := $(shell expr 6 \* 256 + 3)
LINUX_VERSION_6_6 := $(shell expr 6 \* 256 + 6)
# The Tegra IVC driver was updated to support iosys-map in Linux v6.2.
# For Linux v6.2 kernels, don't build any drivers that requires this.
ifeq ($(shell test $(LINUX_VERSION) -ge $(LINUX_VERSION_6_2); echo $$?),0)
export CONFIG_TEGRA_IVC_LEGACY_DISABLE=y
endif
ifeq ($(CONFIG_TEGRA_IVC_LEGACY_DISABLE),y)
subdir-ccflags-y += -DCONFIG_TEGRA_IVC_LEGACY_DISABLE
endif
# Legacy GPIO support is removed in Linux v6.3
ifeq ($(shell test $(LINUX_VERSION) -ge $(LINUX_VERSION_6_3); echo $$?),0)
export CONFIG_TEGRA_GPIO_LEGACY_DISABLE=y
endif
# Changes done in Linux 6.6 onwards
ifeq ($(shell test $(LINUX_VERSION) -ge $(LINUX_VERSION_6_6); echo $$?),0)
# Move probe to DAI Ops.
export CONFIG_SND_SOC_MOVE_DAI_PROBE_TO_OPS=y
subdir-ccflags-y += -DNV_SND_SOC_DAI_OPS_STRUCT_HAS_PROBE_ARG
# probe_new is removed from i2c driver structure
subdir-ccflags-y += -DNV_I2C_LEGACY_PROBE_NEW_REMOVED
# API changes to replace u8 with unsigned char
subdir-ccflags-y += -DNV_TTY_SERIAL_TYPE_U8_CHANGE
# v4l2_async_subdev is renamed to v4l2_async_connection.
subdir-ccflags-y += -DNV_V4L2_ASYNC_SUBDEV_RENAME
# Rename V4L2_ASYNC_MATCH_FWNODE to V4L2_ASYNC_MATCH_TYPE_FWNODE
subdir-ccflags-y += -DNV_V4L2_ASYNC_MATCH_FWNODE_RENAME
# Rename async_nf_init and v4l2_async_subdev_nf_register
subdir-ccflags-y += -DNV_V4L2_ASYNC_NF_SUBDEVICE_INIT_RENAME
# Deprecate PCIED Error reporting pci_enable_pcie_error_reporting
subdir-ccflags-y += -DNV_DROP_PCIE_ERROR_REPORTING
# Split types and declaration of net/page_pool.h
subdir-ccflags-y += -DNV_SPLIT_PAGE_POOL_HEADER
# Unexport helpers for fd/handle conversion
subdir-ccflags-y += -DNV_UNEXPORT_FD_HANDLE_CONVERSION
# FB Deferred IO helpers name alignment
subdir-ccflags-y += -DNV_FB_DEFERRED_IO_OPS_RENAME
# Crypto driver has major change in it ops, skip it
export CONFIG_SKIP_CRYPTO=y
endif
ifeq ($(CONFIG_TEGRA_VIRTUALIZATION),y)
subdir-ccflags-y += -DCONFIG_TEGRA_VIRTUALIZATION

View File

@@ -0,0 +1,41 @@
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
objtree = $(srctree)
# Redefine the fixdep command
cmd_and_fixdep = \
$(cmd); \
$(objtree)/scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).cmd;\
rm -f $(depfile)
include $(oottree)/scripts/Makefile.lib
oot-dtstree = $(oottree)/arch/arm64/boot/dts/nvidia
DTB_LIST := $(dtb-y)
DTBO_LIST := $(dtbo-y)
dtb-y :=
dts_makefile=$(foreach d,$(wildcard $1*), $(call dts_makefile,$(d)/,$(2)) $(if $(findstring Makefile,$(d)),$(d)))
dts_mfiles = $(call dts_makefile, $(oot-dtstree), Makefile)
ifneq ($(dts_mfiles),)
dts-include :=
include $(dts_mfiles)
dtb-y := $(addprefix nvidia/,$(dtb-y))
dtbo-y := $(addprefix nvidia/,$(dtbo-y))
endif
DTC_INCLUDE := $(oottree)/include
DTB_LIST += $(dtb-y)
DTBO_LIST += $(dtbo-y)
DTB_OBJS := $(addprefix $(obj)/,$(DTB_LIST))
DTBO_OBJS := $(addprefix $(obj)/,$(DTBO_LIST))
dtbs: $(DTB_OBJS) $(DTBO_OBJS) FORCE
dtbsclean:
find $(oot-dtstree) -name *.dtb | xargs rm -rf
find $(oot-dtstree) -name *.dtbo | xargs rm -rf
find $(oot-dtstree) -name *.tmp | xargs rm -rf

View File

@@ -0,0 +1,9 @@
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
DTC_FLAGS += -@
# DT overlays
dtbo-y += tegra194-carveouts.dtbo
dtbo-y += tegra194-jetson.dtbo
dtbo-y += tegra194-p3509-0000+p3668-0001-overlay.dtbo

View File

@@ -0,0 +1,29 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
/ {
fragment@0 {
target-path = "/";
__overlay__ {
reserved-memory {
#address-cells = <2>;
#size-cells = <2>;
ranges;
vpr: vpr-carveout {
compatible = "nvidia,vpr-carveout";
status = "okay";
};
};
tegra-carveouts {
compatible = "nvidia,carveouts-t19x";
memory-region = <&vpr>;
status = "okay";
};
};
};
};

View File

@@ -0,0 +1,157 @@
/*
* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES.
*
* SPDX-License-Identifier: GPL-2.0
*/
/dts-v1/;
/plugin/;
#include <dt-bindings/clock/tegra194-clock.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/memory/tegra194-mc.h>
#include <dt-bindings/power/tegra194-powergate.h>
#include <dt-bindings/reset/tegra194-reset.h>
/ {
overlay-name = "Tegra194 Jetson Overlay";
compatible = "nvidia,tegra194";
fragment@0 {
target-path = "/bus@0/host1x@13e00000";
__overlay__ {
#address-cells = <2>;
#size-cells = <2>;
interrupt-parent = <&gic>;
ranges = <0x0 0x14800000 0x0 0x14800000 0x0 0x02800000>,
<0x0 0x24f00000 0x0 0x24f00000 0x0 0x00100000>;
nvdla0@15880000 {
compatible = "nvidia,tegra194-nvdla";
reg = <0x0 0x15880000 0x0 0x00040000>;
interrupts = <GIC_SPI 236 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA194_CLK_DLA0_CORE>,
<&bpmp TEGRA194_CLK_DLA0_FALCON>;
clock-names = "nvdla", "nvdla_flcn";
resets = <&bpmp TEGRA194_RESET_DLA0>;
reset-names = "nvdla";
power-domains = <&bpmp TEGRA194_POWER_DOMAIN_DLAA>;
interconnects = <&mc TEGRA194_MEMORY_CLIENT_DLA0RDA &emc>,
<&mc TEGRA194_MEMORY_CLIENT_DLA0FALRDB &emc>,
<&mc TEGRA194_MEMORY_CLIENT_DLA0WRA &emc>,
<&mc TEGRA194_MEMORY_CLIENT_DLA0FALWRB &emc>;
interconnect-names = "dma-mem", "read-1", "write", "write-1";
iommus = <&smmu TEGRA194_SID_NVDLA0>;
dma-coherent;
};
nvdla1@158c0000 {
compatible = "nvidia,tegra194-nvdla";
reg = <0x0 0x158c0000 0x0 0x00040000>;
interrupts = <GIC_SPI 237 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA194_CLK_DLA1_CORE>,
<&bpmp TEGRA194_CLK_DLA1_FALCON>;
clock-names = "nvdla", "nvdla_flcn";
resets = <&bpmp TEGRA194_RESET_DLA1>;
reset-names = "nvdla";
power-domains = <&bpmp TEGRA194_POWER_DOMAIN_DLAB>;
interconnects = <&mc TEGRA194_MEMORY_CLIENT_DLA1RDA &emc>,
<&mc TEGRA194_MEMORY_CLIENT_DLA1FALRDB &emc>,
<&mc TEGRA194_MEMORY_CLIENT_DLA1WRA &emc>,
<&mc TEGRA194_MEMORY_CLIENT_DLA1FALWRB &emc>;
interconnect-names = "dma-mem", "read-1", "write", "write-1";
iommus = <&smmu TEGRA194_SID_NVDLA1>;
dma-coherent;
};
pva0@16000000 {
compatible = "nvidia,tegra194-pva";
power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PVAA>;
reg = <0x0 0x16000000 0x0 0x00800000>,
<0x0 0x24f00000 0x0 0x00080000>;
interrupts = <GIC_SPI 234 IRQ_TYPE_LEVEL_HIGH>;
resets = <&bpmp TEGRA194_RESET_PVA0_ALL>;
reset-names = "nvpva";
clocks = <&bpmp TEGRA194_CLK_NAFLL_PVA_VPS>,
<&bpmp TEGRA194_CLK_NAFLL_PVA_CORE>,
<&bpmp TEGRA194_CLK_PVA0_AXI>,
<&bpmp TEGRA194_CLK_PVA0_VPS0>,
<&bpmp TEGRA194_CLK_PVA0_VPS1>;
clock-names = "nafll_pva_vps", "nafll_pva_core", "axi", "vps0", "vps1";
interconnects = <&mc TEGRA194_MEMORY_CLIENT_PVA0RDA &emc>,
<&mc TEGRA194_MEMORY_CLIENT_PVA0RDB &emc>,
<&mc TEGRA194_MEMORY_CLIENT_PVA0RDC &emc>,
<&mc TEGRA194_MEMORY_CLIENT_PVA0WRA &emc>,
<&mc TEGRA194_MEMORY_CLIENT_PVA0WRB &emc>,
<&mc TEGRA194_MEMORY_CLIENT_PVA0WRC &emc>;
interconnect-names = "dma-mem", "read-b", "read-c", "write-a", "write-b", "write-c";
iommus = <&smmu TEGRA194_SID_PVA0>;
dma-coherent;
};
pva1@16800000 {
compatible = "nvidia,tegra194-pva";
power-domains = <&bpmp TEGRA194_POWER_DOMAIN_PVAB>;
reg = <0x0 0x16800000 0x0 0x00800000>,
<0x0 0x24f80000 0x0 0x00080000>;
interrupts = <GIC_SPI 235 IRQ_TYPE_LEVEL_HIGH>;
resets = <&bpmp TEGRA194_RESET_PVA1_ALL>;
reset-names = "nvpva";
clocks = <&bpmp TEGRA194_CLK_PVA1_AXI>,
<&bpmp TEGRA194_CLK_PVA1_VPS0>,
<&bpmp TEGRA194_CLK_PVA1_VPS1>;
clock-names = "axi", "vps0", "vps1";
interconnects = <&mc TEGRA194_MEMORY_CLIENT_PVA1RDA &emc>,
<&mc TEGRA194_MEMORY_CLIENT_PVA1RDB &emc>,
<&mc TEGRA194_MEMORY_CLIENT_PVA1RDC &emc>,
<&mc TEGRA194_MEMORY_CLIENT_PVA1WRA &emc>,
<&mc TEGRA194_MEMORY_CLIENT_PVA1WRB &emc>,
<&mc TEGRA194_MEMORY_CLIENT_PVA1WRC &emc>;
interconnect-names = "dma-mem", "read-b", "read-c", "write-a", "write-b", "write-c";
iommus = <&smmu TEGRA194_SID_PVA1>;
dma-coherent;
};
};
};
fragment@1 {
target-path = "/";
__overlay__ {
#address-cells = <2>;
#size-cells = <2>;
cvnas@14000000 {
compatible = "nvidia,tegra194-cvnas";
reg = <0x0 0x14000000 0x0 0x20000>, /* CV0_REG0_BASE */
<0x0 0x14020000 0x0 0x10000>, /* CV0_SRAM_BASE */
<0x0 0x0b240000 0x0 0x10000>; /* HSM_BASE */
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 238 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&bpmp TEGRA194_CLK_CVNAS>;
assigned-clocks = <&bpmp TEGRA194_CLK_CVNAS>;
assigned-clock-rates = <1356800000>;
resets = <&bpmp TEGRA194_RESET_CVNAS>,
<&bpmp TEGRA194_RESET_CVNAS_FCM>;
reset-names = "rst", "rst_fcm";
power-domains = <&bpmp TEGRA194_POWER_DOMAIN_CV>;
cvsramslice = <4 0x1000>;
cvsram-reg = <0x0 0x50000000 0x0 0x400000>;
};
};
};
};

View File

@@ -0,0 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/dts-v1/;
/plugin/;
/ {
overlay-name = "Add p3509-0000+p3668-0001 Overlay Support";
compatible = "nvidia,tegra194";
};

View File

@@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: GPL-2.0-only
objtree ?= $(srctree)
objtree = $(srctree)
# Redefine the fixdep command
cmd_and_fixdep = \

View File

@@ -5,102 +5,102 @@ MAKE[0]="make modules"
BUILT_MODULE_NAME[0]="softdog-platform"
BUILT_MODULE_LOCATION[0]="drivers/watchdog"
DEST_MODULE_LOCATION[0]="/updates"
DEST_MODULE_LOCATION[0]="/extra"
BUILT_MODULE_NAME[1]="watchdog-tegra-t18x"
BUILT_MODULE_LOCATION[1]="drivers/watchdog"
DEST_MODULE_LOCATION[1]="/updates"
DEST_MODULE_LOCATION[1]="/extra"
BUILT_MODULE_NAME[2]="pex9749-thermal"
BUILT_MODULE_LOCATION[2]="drivers/thermal"
DEST_MODULE_LOCATION[2]="/updates"
DEST_MODULE_LOCATION[2]="/extra"
BUILT_MODULE_NAME[3]="spi-aurix-tegra"
BUILT_MODULE_LOCATION[3]="drivers/spi"
DEST_MODULE_LOCATION[3]="/updates"
DEST_MODULE_LOCATION[3]="/extra"
BUILT_MODULE_NAME[4]="tegra186-gpc-dma"
BUILT_MODULE_LOCATION[4]="drivers/dma"
DEST_MODULE_LOCATION[4]="/updates"
DEST_MODULE_LOCATION[4]="/extra"
BUILT_MODULE_NAME[5]="pwm-tegra-tachometer"
BUILT_MODULE_LOCATION[5]="drivers/pwm"
DEST_MODULE_LOCATION[5]="/updates"
DEST_MODULE_LOCATION[5]="/extra"
BUILT_MODULE_NAME[6]="pinctrl-tegra234"
BUILT_MODULE_LOCATION[6]="drivers/pinctrl/tegra"
DEST_MODULE_LOCATION[6]="/updates"
DEST_MODULE_LOCATION[6]="/extra"
BUILT_MODULE_NAME[7]="tegra-cactmon"
BUILT_MODULE_LOCATION[7]="drivers/platform/tegra"
DEST_MODULE_LOCATION[7]="/updates"
DEST_MODULE_LOCATION[7]="/extra"
BUILT_MODULE_NAME[8]="pinctrl-tegra234-dpaux"
BUILT_MODULE_LOCATION[8]="drivers/pinctrl"
DEST_MODULE_LOCATION[8]="/updates"
DEST_MODULE_LOCATION[8]="/extra"
BUILT_MODULE_NAME[9]="tegra-fsicom"
BUILT_MODULE_LOCATION[9]="drivers/platform/tegra"
DEST_MODULE_LOCATION[9]="/updates"
DEST_MODULE_LOCATION[9]="/extra"
BUILT_MODULE_NAME[10]="tegra-bootloader-debug"
BUILT_MODULE_LOCATION[10]="drivers/platform/tegra"
DEST_MODULE_LOCATION[10]="/updates"
DEST_MODULE_LOCATION[10]="/extra"
BUILT_MODULE_NAME[11]="host1x-fence"
BUILT_MODULE_LOCATION[11]="drivers/gpu/host1x-fence"
DEST_MODULE_LOCATION[11]="/updates"
DEST_MODULE_LOCATION[11]="/extra"
BUILT_MODULE_NAME[12]="tegra_vnet"
BUILT_MODULE_LOCATION[12]="drivers/net/ethernet/nvidia/pcie"
DEST_MODULE_LOCATION[12]="/updates"
DEST_MODULE_LOCATION[12]="/extra"
BUILT_MODULE_NAME[13]="arm64-ras"
BUILT_MODULE_LOCATION[13]="drivers/ras"
DEST_MODULE_LOCATION[13]="/updates"
DEST_MODULE_LOCATION[13]="/extra"
BUILT_MODULE_NAME[14]="fuse-burn"
BUILT_MODULE_LOCATION[14]="drivers/soc/tegra/fuse"
DEST_MODULE_LOCATION[14]="/updates"
DEST_MODULE_LOCATION[14]="/extra"
BUILT_MODULE_NAME[15]="kfuse"
BUILT_MODULE_LOCATION[15]="drivers/soc/tegra/fuse"
DEST_MODULE_LOCATION[15]="/updates"
DEST_MODULE_LOCATION[15]="/extra"
BUILT_MODULE_NAME[16]="pci-epf-dma-test"
BUILT_MODULE_LOCATION[16]="drivers/pci/endpoint/functions"
DEST_MODULE_LOCATION[16]="/updates"
DEST_MODULE_LOCATION[16]="/extra"
BUILT_MODULE_NAME[17]="tegra-pcie-edma"
BUILT_MODULE_LOCATION[17]="drivers/pci/controller"
DEST_MODULE_LOCATION[17]="/updates"
DEST_MODULE_LOCATION[17]="/extra"
BUILT_MODULE_NAME[18]="pcie-tegra-vf"
BUILT_MODULE_LOCATION[18]="drivers/pci/controller"
DEST_MODULE_LOCATION[18]="/updates"
DEST_MODULE_LOCATION[18]="/extra"
BUILT_MODULE_NAME[19]="tegra-pcie-dma-test"
BUILT_MODULE_LOCATION[19]="drivers/misc"
DEST_MODULE_LOCATION[19]="/updates"
DEST_MODULE_LOCATION[19]="/extra"
BUILT_MODULE_NAME[20]="tegra-se"
BUILT_MODULE_LOCATION[20]="drivers/crypto/tegra"
DEST_MODULE_LOCATION[20]="/updates"
DEST_MODULE_LOCATION[20]="/extra"
BUILT_MODULE_NAME[21]="tegra-se-nvrng"
BUILT_MODULE_LOCATION[21]="drivers/crypto"
DEST_MODULE_LOCATION[21]="/updates"
DEST_MODULE_LOCATION[21]="/extra"
BUILT_MODULE_NAME[22]="nvidia-vrs-pseq"
BUILT_MODULE_LOCATION[22]="drivers/mfd"
DEST_MODULE_LOCATION[22]="/updates"
DEST_MODULE_LOCATION[22]="/extra"
BUILT_MODULE_NAME[23]="cpuidle-debugfs"
BUILT_MODULE_LOCATION[23]="drivers/cpuidle"
DEST_MODULE_LOCATION[23]="/updates"
DEST_MODULE_LOCATION[23]="/extra"
BUILT_MODULE_NAME[24]="pinctrl-tegra194-pexclk-padctrl"
BUILT_MODULE_LOCATION[24]="drivers/pinctrl"
DEST_MODULE_LOCATION[24]="/updates"
DEST_MODULE_LOCATION[24]="/extra"
AUTO_INSTALL="yes"

View File

@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
# SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
LINUXINCLUDE += -I$(srctree.nvidia-oot)/include
LINUXINCLUDE += -I$(srctree.nvidia-oot)/drivers/gpu/host1x/hw/
@@ -12,14 +12,14 @@ 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/
ifeq ($(CONFIG_SKIP_CRYPTO),)
obj-m += crypto/
endif
ifdef CONFIG_PM_DEVFREQ
obj-m += devfreq/
endif
@@ -34,12 +34,10 @@ endif
ifdef CONFIG_I2C
obj-m += i2c/busses/
obj-m += mfd/
ifdef CONFIG_HTE
ifdef CONFIG_IIO
obj-m += bmi088/
endif
endif
endif
ifdef CONFIG_MEMORY
obj-m += memory/
endif
@@ -83,5 +81,7 @@ obj-m += virt/tegra/
ifdef CONFIG_TEGRA_HOST1X
obj-m += media/
endif
obj-m += staging/platform/tegra/gte/
obj-m += staging/platform/tegra/gte_test/
obj-m += nv-virtio/
obj-m += usb/

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@@ -1,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, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/* Device tree example:
*
@@ -7,15 +7,13 @@
* compatible = "bmi,bmi088";
* reg = <0x69>; // <-- Must be gyroscope I2C address
* accel_i2c_addr = <0x19>; // Must be specified
* accel_irq-gpios = <&tegra_gpio TEGRA_GPIO(BB, 0) GPIO_ACTIVE_HIGH>;
* gyro_irq-gpios = <&tegra_gpio TEGRA_GPIO(BB, 1) GPIO_ACTIVE_HIGH>;
* accel_irq_gpio = <&tegra_gpio TEGRA_GPIO(BB, 0) GPIO_ACTIVE_HIGH>;
* gyro_irq_gpio = <&tegra_gpio TEGRA_GPIO(BB, 1) GPIO_ACTIVE_HIGH>;
* accel_matrix = [01 00 00 00 01 00 00 00 01];
* gyro_matrix = [01 00 00 00 01 00 00 00 01];
* };
*/
#include <nvidia/conftest.h>
#include <linux/device.h>
#include <linux/version.h>
#include <linux/i2c.h>
@@ -27,8 +25,8 @@
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/of.h>
#include <linux/tegra-gte.h>
#include <linux/bitops.h>
#include <linux/hte.h>
#include "bmi_iio.h"
#define BMI_NAME "bmi088"
@@ -109,17 +107,22 @@
#define BMI_PART_BMI088 (0)
#define HTE_TIMEOUT (msecs_to_jiffies(100))
static const struct i2c_device_id bmi_i2c_device_ids[] = {
{ BMI_NAME, BMI_PART_BMI088 },
{},
};
struct bmi_gpio_irq {
struct gpio_desc *gpio_in;
static char *gte_hw_str_t194 = "nvidia,tegra194-gte-aon";
static char *gte_hw_str_t234 = "nvidia,tegra234-gte-aon";
static struct device_node *gte_nd;
struct bmi_gte_irq {
struct tegra_gte_ev_desc *gte;
const char *dev_name;
int gpio;
int irq;
u64 irq_ts;
u64 irq_ts_old;
};
struct bmi_reg_rd {
@@ -408,21 +411,18 @@ struct bmi_snsr {
struct sensor_cfg cfg;
unsigned int usr_cfg;
unsigned int period_us;
u64 irq_ts;
u64 irq_ts_old;
u64 seq;
struct completion hte_ts_cmpl;
struct bmi_gpio_irq gis;
struct bmi_state *st;
};
struct bmi_state {
struct i2c_client *i2c;
struct bmi_snsr snsrs[BMI_HW_N];
struct bmi_gte_irq gis[BMI_HW_N];
bool iio_init_done[BMI_HW_N];
unsigned int part;
unsigned int sts;
unsigned int errs_bus[BMI_HW_N];
unsigned int err_ts_thread[BMI_HW_N];
unsigned int sam_dropped[BMI_HW_N];
unsigned int enabled;
unsigned int suspend_en_st;
unsigned int hw_n;
@@ -537,36 +537,141 @@ static int bmi_i2c_wr(struct bmi_state *st, unsigned int hw, u8 reg, u8 val)
return ret;
}
static void bmi_gte_exit_gpio(struct bmi_gte_irq *ngi, unsigned int n)
{
unsigned int i;
for (i = 0; i < n; i++) {
if (ngi[i].gpio >= 0)
gpio_free(ngi[i].gpio);
}
}
static int bmi_gte_init_gpio2irq(struct device *dev, struct bmi_gte_irq *ngi,
unsigned int n)
{
unsigned int i;
unsigned int prev;
int ret;
for (i = 0; i < n; i++) {
if (!gpio_is_valid(ngi[i].gpio) ||
gpio_request(ngi[i].gpio, ngi[i].dev_name)) {
ret = -EPROBE_DEFER;
if (!i) {
goto out_no_prev;
} else {
prev = i - 1;
goto out;
}
}
ret = gpio_direction_input(ngi[i].gpio);
if (ret < 0) {
dev_err(dev, "%s gpio_dir_input(%d) ERR:%d\n",
ngi[i].dev_name, ngi[i].gpio, ret);
ret = -ENODEV;
if (!i)
prev = i;
else
prev = i - 1;
goto out;
}
ret = gpio_to_irq(ngi[i].gpio);
if (ret <= 0) {
dev_err(dev, "%s gpio_to_irq(%d) ERR:%d\n",
ngi[i].dev_name, ngi[i].gpio, ret);
ret = -ENODEV;
if (!i)
prev = i;
else
prev = i - 1;
goto out;
}
ngi[i].irq = ret;
ret = 0;
}
return ret;
out:
bmi_gte_exit_gpio(ngi, prev);
out_no_prev:
return ret;
}
static int bmi_gte_ts(struct bmi_gte_irq *ngi)
{
struct tegra_gte_ev_desc *desc = (struct tegra_gte_ev_desc *)ngi->gte;
struct tegra_gte_ev_detail dtl;
int ret;
ret = tegra_gte_retrieve_event(desc, &dtl);
if (!ret)
ngi->irq_ts = dtl.ts_ns;
return ret;
}
static inline int bmi_gte_deinit(struct bmi_gte_irq *ngi)
{
int ret = 0;
if (ngi->gte) {
ret = tegra_gte_unregister_event(ngi->gte);
ngi->gte = NULL;
}
return ret;
}
static void bmi_gte_gpio_exit(struct bmi_state *st, unsigned int n)
{
unsigned int i;
struct bmi_gte_irq *ngi = st->gis;
if (gte_nd) {
of_node_put(gte_nd);
gte_nd = NULL;
}
for (i = 0; i < n; i++) {
bmi_gte_deinit(&ngi[i]);
if (ngi[i].gpio >= 0)
gpio_free(ngi[i].gpio);
}
}
static int bmi_gte_init(struct bmi_state *st, unsigned int id)
{
int ret = 0;
struct bmi_gte_irq *ngi = st->gis;
if (!ngi[id].gte) {
ngi[id].gte = tegra_gte_register_event(gte_nd, ngi[id].gpio);
if (!ngi[id].gte)
ret = -ENODEV;
}
return ret;
}
static int bmi_setup_gpio(struct device *dev, struct bmi_state *st,
unsigned int n)
{
unsigned int i;
struct bmi_snsr *snsrs = st->snsrs;
int ret;
struct bmi_gte_irq *ngi = st->gis;
for (i = 0; i < n; i++) {
snsrs[i].gis.irq = -1;
if ((snsrs[i].gis.gpio_in)) {
ret = gpiod_direction_input(snsrs[i].gis.gpio_in);
for (i = 0; i < n; i++)
ngi[i].irq = -1;
if (ret < 0) {
dev_err(dev, "%s gpio_dir_input ERR:%d\n",
snsrs[i].gis.dev_name, ret);
return ret;
}
ret = gpiod_to_irq(snsrs[i].gis.gpio_in);
if (ret < 0) {
dev_err(dev, "%s gpio_to_irq ERR:%d\n",
snsrs[i].gis.dev_name, ret);
return ret;
}
snsrs[i].gis.irq = ret;
}
}
return 0;
return bmi_gte_init_gpio2irq(dev, ngi, n);
}
static int bmi_pm(struct bmi_state *st, int snsr_id, bool en)
@@ -862,32 +967,17 @@ static unsigned long bmi_gyr_irqflags(struct bmi_state *st)
return irqflags;
}
static enum hte_return process_hw_ts(struct hte_ts_data *ts, void *p)
{
struct bmi_snsr *sensor = (struct bmi_snsr *)p;
struct bmi_state *st = sensor->st;
sensor->irq_ts = ts->tsc;
sensor->seq = ts->seq;
complete(&sensor->hte_ts_cmpl);
dev_dbg_ratelimited(&st->i2c->dev, "%s: seq %llu, ts:%llu\n",
__func__, sensor->seq, sensor->irq_ts);
return HTE_CB_HANDLED;
}
static irqreturn_t bmi_irq_thread(int irq, void *dev_id)
{
struct bmi_snsr *sensor = (struct bmi_snsr *)dev_id;
struct bmi_state *st = sensor->st;
struct bmi_state *st = (struct bmi_state *)dev_id;
unsigned int hw;
int ret;
u8 reg;
u8 sample[BMI_IMU_DATA];
int cnt = 0;
u64 ts_old;
if (irq == st->snsrs[BMI_HW_GYR].gis.irq) {
if (irq == st->gis[BMI_HW_GYR].irq) {
hw = BMI_HW_GYR;
reg = BMI_REG_GYR_DATA;
} else {
@@ -895,7 +985,7 @@ static irqreturn_t bmi_irq_thread(int irq, void *dev_id)
reg = BMI_REG_ACC_DATA;
}
/* Disable data ready interrupt before we read out data */
/* Disbale data ready interrupt before we read out data */
ret = bmi_hws[hw].fn_able(st, 0, true);
if (unlikely(ret)) {
dev_err_ratelimited(&st->i2c->dev,
@@ -903,31 +993,71 @@ static irqreturn_t bmi_irq_thread(int irq, void *dev_id)
goto err;
}
/* Wait for HTE IRQ to fetch the latest timestamp */
ret = wait_for_completion_interruptible_timeout(&sensor->hte_ts_cmpl, HTE_TIMEOUT);
if (!ret) {
dev_dbg_ratelimited(&st->i2c->dev,
"sample dropped due to timeout");
goto err;
ts_old = st->gis[hw].irq_ts_old;
/*
* There is a possibility that data ready IRQ may have caused GTE to
* store the timestamps by the time this thread got a chance to run
* and disable IRQ especially for the high data rate, in that case,
* drain the GTE till it returns error and use last timestamp to
* associate the data to be read.
*/
while (bmi_gte_ts(&st->gis[hw]) == 0)
cnt++;
/* Means we failed to get the ts in the first go */
if (!st->gis[hw].irq_ts && !cnt) {
dev_dbg(&st->i2c->dev, "sample dropped, gte get ts failed\n");
st->sam_dropped[hw]++;
goto out;
}
/*
* If ts is same as old or 0, something is seriously wrong,
* re-register with gte
*/
if ((st->gis[hw].irq_ts_old == st->gis[hw].irq_ts) ||
(!st->gis[hw].irq_ts && cnt)) {
dev_dbg(&st->i2c->dev,
"ts issue for: %d, ts old: %llu, new: %llu\n",
hw, st->gis[hw].irq_ts_old, st->gis[hw].irq_ts);
st->err_ts_thread[hw]++;
st->sam_dropped[hw]++;
dev_dbg(&st->i2c->dev, "sample dropped due to ts issues\n");
/* Re-register with GTE */
bmi_gte_deinit(&st->gis[hw]);
ret = bmi_gte_init(st, hw);
if (ret) {
dev_err_ratelimited(&st->i2c->dev,
"GTE re-registration failed: %d\n",
hw);
goto err;
}
goto out;
}
mutex_lock(BMI_MUTEX(st->snsrs[hw].bmi_iio));
ret = bmi_i2c_rd(st, hw, reg, sizeof(sample), sample);
if (!ret) {
bmi_iio_push_buf(st->snsrs[hw].bmi_iio, sample,
sensor->irq_ts);
dev_dbg(&st->i2c->dev, "%d, ts= %lld ts_old= %lld\n",
hw, sensor->irq_ts, sensor->irq_ts_old);
sensor->irq_ts_old = sensor->irq_ts;
}
mutex_unlock(BMI_MUTEX(st->snsrs[hw].bmi_iio));
/* Enable data ready interrupt */
if (!ret) {
bmi_iio_push_buf(st->snsrs[hw].bmi_iio, sample,
st->gis[hw].irq_ts);
st->gis[hw].irq_ts_old = st->gis[hw].irq_ts;
}
dev_dbg(&st->i2c->dev, "%d, ts= %lld, ts_old=%lld\n",
hw, st->gis[hw].irq_ts, ts_old);
out:
st->gis[hw].irq_ts = 0;
bmi_hws[hw].fn_able(st, 1, true);
err:
return IRQ_HANDLED;
}
@@ -942,7 +1072,7 @@ static int bmi_period(struct bmi_state *st, int snsr_id, bool range)
range);
}
static int bmi_enable(void *client, int snsr_id, int enable)
static int bmi_enable(void *client, int snsr_id, int enable, bool is_gte)
{
struct bmi_state *st = (struct bmi_state *)client;
int ret;
@@ -954,10 +1084,20 @@ static int bmi_enable(void *client, int snsr_id, int enable)
return (st->enabled & (1 << snsr_id));
if (enable) {
if (is_gte) {
ret = bmi_gte_init(st, snsr_id);
if (ret)
return ret;
}
enable = st->enabled | (1 << snsr_id);
ret = bmi_pm(st, snsr_id, true);
if (ret < 0)
if (ret < 0) {
if (is_gte)
bmi_gte_deinit(&st->gis[snsr_id]);
return ret;
}
ret = bmi_period(st, snsr_id, true);
ret |= bmi_hws[snsr_id].fn_able(st, 1, false);
@@ -967,6 +1107,9 @@ static int bmi_enable(void *client, int snsr_id, int enable)
}
}
if (is_gte)
bmi_gte_deinit(&st->gis[snsr_id]);
ret = bmi_hws[snsr_id].fn_able(st, 0, false);
ret |= bmi_pm(st, snsr_id, false);
@@ -1159,6 +1302,11 @@ static int bmi_read_err(void *client, int snsr_id, char *buf)
t += snprintf(buf, PAGE_SIZE, "%s:\n", st->snsrs[snsr_id].cfg.name);
t += snprintf(buf + t, PAGE_SIZE - t,
"I2C Bus Errors:%u\n", st->errs_bus[snsr_id]);
t += snprintf(buf + t, PAGE_SIZE - t,
"GTE Timestamp Errors:%u\n", st->err_ts_thread[snsr_id]);
t += snprintf(buf + t, PAGE_SIZE - t,
"Sample dropped:%u\n", st->sam_dropped[snsr_id]);
return t;
}
@@ -1241,9 +1389,11 @@ static int __maybe_unused bmi_suspend(struct device *dev)
for (i = 0; i < st->hw_n; i++) {
mutex_lock(BMI_MUTEX(st->snsrs[i].bmi_iio));
/* check if sensor is enabled to begin with */
old_en_st = bmi_enable(st, st->snsrs[i].cfg.snsr_id, -1);
old_en_st = bmi_enable(st, st->snsrs[i].cfg.snsr_id, -1,
false);
if (old_en_st) {
temp_ret = bmi_enable(st, st->snsrs[i].cfg.snsr_id, 0);
temp_ret = bmi_enable(st, st->snsrs[i].cfg.snsr_id, 0,
false);
if (!temp_ret)
st->suspend_en_st |= old_en_st;
@@ -1265,7 +1415,8 @@ static int __maybe_unused bmi_resume(struct device *dev)
for (i = 0; i < st->hw_n; i++) {
mutex_lock(BMI_MUTEX(st->snsrs[i].bmi_iio));
if (st->suspend_en_st & (1 << st->snsrs[i].cfg.snsr_id))
ret |= bmi_enable(st, st->snsrs[i].cfg.snsr_id, 1);
ret |= bmi_enable(st, st->snsrs[i].cfg.snsr_id, 1,
false);
mutex_unlock(BMI_MUTEX(st->snsrs[i].bmi_iio));
}
@@ -1286,8 +1437,8 @@ static void bmi_shutdown(struct i2c_client *client)
if (st->iio_init_done[i])
mutex_lock(BMI_MUTEX(st->snsrs[i].bmi_iio));
if (bmi_enable(st, st->snsrs[i].cfg.snsr_id, -1))
bmi_enable(st, st->snsrs[i].cfg.snsr_id, 0);
if (bmi_enable(st, st->snsrs[i].cfg.snsr_id, -1, false))
bmi_enable(st, st->snsrs[i].cfg.snsr_id, 0, false);
if (st->iio_init_done[i]) {
mutex_unlock(BMI_MUTEX(st->snsrs[i].bmi_iio));
@@ -1303,6 +1454,7 @@ static void bmi_remove(void *data)
if (st != NULL) {
bmi_shutdown(client);
bmi_gte_gpio_exit(st, BMI_HW_N);
for (i = 0; i < st->hw_n; i++) {
if (st->iio_init_done[i])
bmi_iio_remove(st->snsrs[i].bmi_iio);
@@ -1328,18 +1480,8 @@ static int bmi_of_dt(struct bmi_state *st, struct device_node *dn)
return -ENODEV;
}
st->snsrs[BMI_HW_ACC].gis.gpio_in = devm_gpiod_get(&st->i2c->dev, "accel_irq", 0);
if (IS_ERR(st->snsrs[BMI_HW_ACC].gis.gpio_in)) {
dev_err(&st->i2c->dev, "accel_irq is not set in DT\n");
return PTR_ERR(st->snsrs[BMI_HW_ACC].gis.gpio_in);
}
st->snsrs[BMI_HW_GYR].gis.gpio_in = devm_gpiod_get(&st->i2c->dev, "gyro_irq", 0);
if (IS_ERR(st->snsrs[BMI_HW_GYR].gis.gpio_in)) {
dev_err(&st->i2c->dev, "gyro_irq is not set in DT\n");
return PTR_ERR(st->snsrs[BMI_HW_GYR].gis.gpio_in);
}
st->gis[BMI_HW_ACC].gpio = of_get_named_gpio(dn, "accel_irq_gpio", 0);
st->gis[BMI_HW_GYR].gpio = of_get_named_gpio(dn, "gyro_irq_gpio", 0);
if (!of_property_read_u32(dn, "accel_reg_0x53", &val32))
st->ra_0x53 = (u8)val32;
@@ -1379,11 +1521,14 @@ static int bmi_init(struct bmi_state *st, const struct i2c_device_id *id)
unsigned long irqflags;
unsigned int i;
int ret;
struct hte_ts_desc *desc;
if (id == NULL)
return -EINVAL;
/* driver specific defaults */
for (i = 0; i < BMI_HW_N; i++)
st->gis[i].gpio = -1;
st->ra_0x53 = BMI_INT1_OUT_ACTIVE_HIGH;
st->ra_0x54 = 0x00;
st->ra_0x58 = BMI_INT1_DTRDY;
@@ -1400,6 +1545,13 @@ static int bmi_init(struct bmi_state *st, const struct i2c_device_id *id)
return ret;
}
/*
* Only interrupt mode is supported as we want hardware timestamps
* from GTE.
*/
if (st->gis[BMI_HW_ACC].gpio < 0 || st->gis[BMI_HW_GYR].gpio < 0)
return -EINVAL;
st->part = id->driver_data;
st->i2c_addrs[BMI_HW_GYR] = st->i2c->addr;
ret = bmi_reset_all(st);
@@ -1428,63 +1580,31 @@ static int bmi_init(struct bmi_state *st, const struct i2c_device_id *id)
st->snsrs[i].cfg.part = bmi_i2c_device_ids[st->part].name;
st->snsrs[i].rrs = &bmi_hws[i].rrs[st->part];
bmi_max_range(st, i, st->snsrs[i].cfg.max_range.ival);
st->snsrs[i].gis.dev_name = st->snsrs[i].cfg.name;
st->gis[i].dev_name = st->snsrs[i].cfg.name;
st->gis[i].gte = NULL;
st->iio_init_done[i] = true;
st->snsrs[i].st = st;
init_completion(&st->snsrs[i].hte_ts_cmpl);
}
ret = bmi_setup_gpio(&st->i2c->dev, st, st->hw_n);
if (ret < 0)
return ret;
desc = devm_kzalloc(&st->i2c->dev, sizeof(*desc)*BMI_HW_N, GFP_KERNEL);
if (!desc)
return -ENOMEM;
for (i = 0; i < BMI_HW_N; i++) {
for (i = 0; i < st->hw_n; i++) {
if (bmi_hws[i].fn_irqflags) {
irqflags = bmi_hws[i].fn_irqflags(st);
ret = devm_request_threaded_irq(&st->i2c->dev,
st->snsrs[i].gis.irq,
st->gis[i].irq,
NULL,
bmi_irq_thread,
irqflags,
st->snsrs[i].gis.dev_name,
&st->snsrs[i]);
st->gis[i].dev_name,
st);
if (ret) {
dev_err(&st->i2c->dev,
"req_threaded_irq ERR %d\n", ret);
return ret;
}
}
ret = hte_init_line_attr(&desc[i], 0, 0, NULL,
st->snsrs[i].gis.gpio_in);
if (ret) {
dev_err(&st->i2c->dev,
"hte_init_line_attr ERR %d\n", ret);
return ret;
}
ret = hte_ts_get(&st->i2c->dev, &desc[i], i);
if (ret) {
dev_err(&st->i2c->dev,
"hte_ts_get ERR %d\n", ret);
return ret;
}
ret = devm_hte_request_ts_ns(&st->i2c->dev, &desc[i],
process_hw_ts, NULL,
&st->snsrs[i]);
if (ret) {
dev_err(&st->i2c->dev,
"devm_hte_request_ts_ns ERR %d\n", ret);
return ret;
}
}
/*
@@ -1494,11 +1614,20 @@ static int bmi_init(struct bmi_state *st, const struct i2c_device_id *id)
for (i = 0; i < st->hw_n; i++)
st->snsrs[i].period_us = st->snsrs[i].cfg.delay_us_max;
gte_nd = of_find_compatible_node(NULL, NULL, gte_hw_str_t194);
if (!gte_nd)
gte_nd = of_find_compatible_node(NULL, NULL, gte_hw_str_t234);
if (!gte_nd) {
dev_err(&st->i2c->dev, "Failed to find GTE node\n");
return -ENODEV;
}
return ret;
}
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
static int bmi_probe(struct i2c_client *client)
#else
static int bmi_probe(struct i2c_client *client, const struct i2c_device_id *id)

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <linux/init.h>
#include <linux/module.h>
@@ -164,9 +164,6 @@ int bmi_iio_push_buf(struct iio_dev *indio_dev, unsigned char *data, u64 ts)
if (!indio_dev || !data)
return -EINVAL;
if (!indio_dev->active_scan_mask)
return -EINVAL;
st = iio_priv(indio_dev);
if (!st)
return -EINVAL;
@@ -204,7 +201,8 @@ static int bmi_iio_enable(struct iio_dev *indio_dev, bool en)
int bit;
if (!en)
return st->fn_dev->enable(st->client, st->cfg->snsr_id, 0);
return st->fn_dev->enable(st->client, st->cfg->snsr_id,
0, true);
if (indio_dev->num_channels > 1) {
for_each_set_bit(bit, indio_dev->active_scan_mask,
@@ -215,7 +213,7 @@ static int bmi_iio_enable(struct iio_dev *indio_dev, bool en)
}
return st->fn_dev->enable(st->client, st->cfg->snsr_id, enable);
return st->fn_dev->enable(st->client, st->cfg->snsr_id, enable, true);
}
static ssize_t bmi_iio_attr_store(struct device *dev,
@@ -352,7 +350,7 @@ static inline int bmi_iio_check_enable(struct bmi_iio_state *st)
if (!st->fn_dev->enable)
return -EINVAL;
return st->fn_dev->enable(st->client, st->cfg->snsr_id, -1);
return st->fn_dev->enable(st->client, st->cfg->snsr_id, -1, false);
}
static int bmi_iio_read_raw(struct iio_dev *indio_dev,

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#ifndef _BMI_IIO_H_
@@ -39,7 +39,7 @@ struct sensor_cfg {
struct iio_fn_dev {
unsigned int *sts;
int (*enable)(void *client, int snsr_id, int enable);
int (*enable)(void *client, int snsr_id, int enable, bool is_gte);
int (*freq_read)(void *client, int snsr_id, int *val, int *val2);
int (*freq_write)(void *client, int snsr_id, int val, int val2);
int (*scale_write)(void *client, int snsr_id, int val, int val2);

View File

@@ -1,5 +1,7 @@
// 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, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <linux/clk-provider.h>
#include <linux/device.h>
@@ -364,7 +366,7 @@ static int tegra_bpmp_clk_get_info(struct tegra_bpmp *bpmp, unsigned int id,
if (err < 0)
return err;
strscpy(info->name, response.name, MRQ_CLK_NAME_MAXLEN);
strlcpy(info->name, response.name, MRQ_CLK_NAME_MAXLEN);
info->num_parents = response.num_parents;
for (i = 0; i < info->num_parents; i++)

View File

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

View File

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

View File

@@ -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-2023, NVIDIA Corporation. All Rights Reserved.
*
* Cryptographic API.
*/
#include <nvidia/conftest.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
@@ -16,8 +15,8 @@
#include <linux/dma-mapping.h>
#include <linux/hw_random.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -5210,21 +5209,9 @@ static const struct dev_pm_ops tegra_hv_pm_ops = {
};
#endif /* CONFIG_PM */
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_hv_vse_safety_remove_wrapper(struct platform_device *pdev)
{
tegra_hv_vse_safety_remove(pdev);
}
#else
static int tegra_hv_vse_safety_remove_wrapper(struct platform_device *pdev)
{
return tegra_hv_vse_safety_remove(pdev);
}
#endif
static struct platform_driver tegra_hv_vse_safety_driver = {
.probe = tegra_hv_vse_safety_probe,
.remove = tegra_hv_vse_safety_remove_wrapper,
.remove = tegra_hv_vse_safety_remove,
.shutdown = tegra_hv_vse_safety_shutdown,
.driver = {
.name = "tegra_hv_vse_safety",

View File

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

View File

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

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +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 to handle HASH algorithms using NVIDIA Security Engine.
*/
#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 +23,16 @@
#include "tegra-se.h"
struct tegra_sha_ctx {
#ifndef NV_CRYPTO_ENGINE_OPS_PRESENT
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 +43,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 +213,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 +233,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 +243,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 +260,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 +308,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 +330,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 +344,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 +361,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 +377,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 +391,44 @@ 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
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);
ctx->enginectx.op.prepare_request = NULL;
ctx->enginectx.op.do_one_request = tegra_sha_do_one_req;
ctx->enginectx.op.unprepare_request = NULL;
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 +440,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,43 +449,54 @@ 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;
}
static int tegra_hmac_fallback_setkey(struct tegra_sha_ctx *ctx, const u8 *key,
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 +508,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 +584,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,9 +608,6 @@ 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
.base = {
#endif
.init = tegra_sha_init,
.update = tegra_sha_update,
.final = tegra_sha_final,
@@ -698,6 +617,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,16 +630,9 @@ 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
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
.base = {
#endif
.init = tegra_sha_init,
.update = tegra_sha_update,
.final = tegra_sha_final,
@@ -729,6 +642,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,16 +655,9 @@ 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
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
.base = {
#endif
.init = tegra_sha_init,
.update = tegra_sha_update,
.final = tegra_sha_final,
@@ -760,6 +667,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,16 +680,9 @@ 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
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
.base = {
#endif
.init = tegra_sha_init,
.update = tegra_sha_update,
.final = tegra_sha_final,
@@ -791,6 +692,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,16 +705,9 @@ 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
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
.base = {
#endif
.init = tegra_sha_init,
.update = tegra_sha_update,
.final = tegra_sha_final,
@@ -822,6 +717,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,16 +730,9 @@ 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
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
.base = {
#endif
.init = tegra_sha_init,
.update = tegra_sha_update,
.final = tegra_sha_final,
@@ -853,6 +742,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,16 +755,9 @@ 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
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
.base = {
#endif
.init = tegra_sha_init,
.update = tegra_sha_update,
.final = tegra_sha_final,
@@ -884,6 +767,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,16 +780,9 @@ 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
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
.base = {
#endif
.init = tegra_sha_init,
.update = tegra_sha_update,
.final = tegra_sha_final,
@@ -915,6 +792,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,16 +805,9 @@ 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
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
.base = {
#endif
.init = tegra_sha_init,
.update = tegra_sha_update,
.final = tegra_sha_final,
@@ -946,6 +817,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,17 +830,10 @@ 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
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg_base = "sha224",
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
.base = {
#endif
.init = tegra_sha_init,
.update = tegra_sha_update,
.final = tegra_sha_final,
@@ -979,6 +844,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,17 +857,10 @@ 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
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg_base = "sha256",
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
.base = {
#endif
.init = tegra_sha_init,
.update = tegra_sha_update,
.final = tegra_sha_final,
@@ -1012,6 +871,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,17 +884,10 @@ 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
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg_base = "sha384",
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
.base = {
#endif
.init = tegra_sha_init,
.update = tegra_sha_update,
.final = tegra_sha_final,
@@ -1045,6 +898,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,17 +911,10 @@ 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
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}, {
.alg_base = "sha512",
.alg.ahash = {
#ifdef NV_CRYPTO_ENGINE_OPS_PRESENT
.base = {
#endif
.init = tegra_sha_init,
.update = tegra_sha_update,
.final = tegra_sha_final,
@@ -1078,6 +925,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,10 +938,6 @@ 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
},
.op.do_one_request = tegra_sha_do_one_req,
#endif
}
}
};
@@ -1133,45 +977,37 @@ 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
dev_err(se->dev, "failed to register %s\n",
alg->base.halg.base.cra_name);
#else
dev_err(se->dev, "failed to register %s\n",
alg->halg.base.cra_name);
#endif
tegra_hash_algs[i].alg.ahash.halg.base.cra_name);
goto sha_err;
}
}
dev_info(se->dev, "registered HASH algorithms\n");
return 0;
sha_err:
for (--i; i >= 0; i--)
CRYPTO_UNREGISTER(ahash, &tegra_hash_algs[i].alg.ahash);
crypto_unregister_ahash(&tegra_hash_algs[i].alg.ahash);
return ret;
}
void tegra_deinit_hash(struct tegra_se *se)
void tegra_deinit_hash(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(tegra_hash_algs); i++)
CRYPTO_UNREGISTER(ahash, &tegra_hash_algs[i].alg.ahash);
crypto_unregister_ahash(&tegra_hash_algs[i].alg.ahash);
}

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Header file for NVIDIA Security Engine driver.
*/
@@ -7,18 +7,19 @@
#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>
#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 +64,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 +308,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,35 +352,20 @@
#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
#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)
#define CRYPTO_UNREGISTER(alg, x) \
crypto_unregister_##alg(x)
#endif
/* Security Engine operation modes */
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,15 +398,9 @@ 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;
#else
struct skcipher_alg skcipher;
struct aead_alg aead;
struct ahash_alg ahash;
#endif
struct skcipher_alg skcipher;
struct aead_alg aead;
struct ahash_alg ahash;
} alg;
};
@@ -433,7 +422,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 +431,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 +452,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 +468,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 +512,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 +611,4 @@ static inline bool tegra_dev_iommu_get_stream_id(struct device *dev, u32 *stream
}
#endif
#define se_host1x_opcode_incr_w(x) host1x_opcode_incr_w((x) / 4)
#define se_host1x_opcode_nonincr_w(x) host1x_opcode_nonincr_w((x) / 4)
#define se_host1x_opcode_incr(x, y) host1x_opcode_incr((x) / 4, y)
#define se_host1x_opcode_nonincr(x, y) host1x_opcode_nonincr((x) / 4, y)
#endif /*_TEGRA_SE_H*/

View File

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

View File

@@ -1,14 +1,16 @@
# SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Makefile for Extended IVC Driver and BPMP driver
#
obj-m += ivc_ext.o
ifneq ($(CONFIG_TEGRA_IVC_LEGACY_DISABLE),y)
tegra_bpmp-y += ../../clk/tegra/clk-bpmp.o
tegra_bpmp-y += ../../reset/tegra/reset-bpmp.o
tegra_bpmp-y += ../../soc/tegra/powergate-bpmp.o
tegra_bpmp-$(CONFIG_DEBUG_FS) += bpmp-debugfs.o
tegra_bpmp-y += bpmp-tegra186-hv.o
obj-m += tegra_bpmp.o
obj-m += tegra_bpmp.o
endif

View File

@@ -1,10 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <nvidia/conftest.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -84,11 +82,7 @@ static void tegra_bpmp_handle_mrq(struct tegra_bpmp *bpmp,
static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel)
{
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP)
unsigned long flags = tegra_bpmp_mb_read_field(&channel->ob, flags);
#else
unsigned long flags = channel->ob->flags;
#endif
if ((flags & MSG_RING) == 0)
return;
@@ -122,15 +116,8 @@ void tegra_bpmp_handle_rx(struct tegra_bpmp *bpmp)
/* If supported incoming channel */
if (bpmp->soc->channels.cpu_rx.count == MAX_POSSIBLE_RX_CHANNEL) {
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP)
if (tegra_bpmp_is_request_ready(channel)) {
unsigned int mrq = tegra_bpmp_mb_read_field(&channel->ib, code);
tegra_bpmp_handle_mrq(bpmp, mrq, channel);
}
#else
if (tegra_bpmp_is_request_ready(channel))
tegra_bpmp_handle_mrq(bpmp, channel->ib->code, channel);
#endif
}
spin_lock(&bpmp->lock);
@@ -211,20 +198,12 @@ static bool tegra186_bpmp_hv_is_message_ready(struct tegra_bpmp_channel *channel
void *frame;
frame = tegra_hv_ivc_read_get_next_frame(hv_ivc);
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP)
if (IS_ERR(frame)) {
iosys_map_clear(&channel->ib);
return false;
}
iosys_map_set_vaddr(&channel->ib, frame);
#else
if (IS_ERR(frame)) {
channel->ib = NULL;
return false;
}
channel->ib = frame;
#endif
return true;
}
@@ -242,20 +221,12 @@ static bool tegra186_hv_bpmp_is_channel_free(struct tegra_bpmp_channel *channel)
void *frame;
frame = tegra_hv_ivc_write_get_next_frame(hv_ivc);
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP)
if (IS_ERR(frame)) {
iosys_map_clear(&channel->ob);
return false;
}
iosys_map_set_vaddr(&channel->ob, frame);
#else
if (IS_ERR(frame)) {
channel->ob = NULL;
return false;
}
channel->ob = frame;
#endif
return true;
}
@@ -461,23 +432,13 @@ static void tegra_bpmp_mrq_handle_ping(unsigned int mrq,
struct tegra_bpmp_channel *channel,
void *data)
{
struct mrq_ping_response response;
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP)
struct mrq_ping_request request;
tegra_bpmp_mb_read(&request, &channel->ib, sizeof(request));
memset(&response, 0, sizeof(response));
response.reply = request.challenge << 1;
#else
struct mrq_ping_request *request;
struct mrq_ping_response response;
request = (struct mrq_ping_request *)channel->ib->data;
memset(&response, 0, sizeof(response));
response.reply = request->challenge << 1;
#endif
tegra_bpmp_mrq_return(channel, 0, &response, sizeof(response));
}

View File

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

View File

@@ -1,11 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-only
# Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
ccflags-$(CONFIG_DRM_TEGRA_DEBUG) += -DDEBUG
ccflags-y += -I$(srctree.nvidia-oot)/drivers/gpu/drm/tegra/include
ccflags-y += -I$(srctree.hwpm)/include
tegra-drm-y := \
tegra-drm-next-y := \
drm.o \
uapi.o \
submit.o \
@@ -37,6 +37,6 @@ tegra-drm-y := \
ofa.o \
virt.o
tegra-drm-y += trace.o
tegra-drm-next-y += trace.o
obj-m := tegra-drm.o
obj-m := tegra-drm-next.o

View File

@@ -1,11 +1,9 @@
// 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>
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
@@ -14,7 +12,6 @@
#include <linux/interconnect.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
@@ -1750,19 +1747,7 @@ static void tegra_dc_early_unregister(struct drm_crtc *crtc)
struct drm_minor *minor = crtc->dev->primary;
struct tegra_dc *dc = to_tegra_dc(crtc);
#if defined(NV_DRM_DEBUGFS_REMOVE_FILES_HAS_ROOT_ARG) /* Linux v6.7 */
struct dentry *root;
#ifdef CONFIG_DEBUG_FS
root = crtc->debugfs_entry;
#else
root = NULL;
#endif
drm_debugfs_remove_files(dc->debugfs_files, count, root, minor);
#else
drm_debugfs_remove_files(dc->debugfs_files, count, minor);
#endif
kfree(dc->debugfs_files);
dc->debugfs_files = NULL;
}
@@ -3295,23 +3280,11 @@ static int tegra_dc_remove(struct platform_device *pdev)
return 0;
}
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_dc_remove_wrapper(struct platform_device *pdev)
{
tegra_dc_remove(pdev);
}
#else
static int tegra_dc_remove_wrapper(struct platform_device *pdev)
{
return tegra_dc_remove(pdev);
}
#endif
struct platform_driver tegra_dc_driver = {
.driver = {
.name = "tegra-dc",
.of_match_table = tegra_dc_of_match,
},
.probe = tegra_dc_probe,
.remove = tegra_dc_remove_wrapper,
.remove = tegra_dc_remove,
};

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2013-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (C) 2013 NVIDIA Corporation
*/
#include <nvidia/conftest.h>
@@ -11,7 +11,6 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
@@ -708,18 +707,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 +714,7 @@ struct platform_driver tegra_dpaux_driver = {
.pm = &tegra_dpaux_pm_ops,
},
.probe = tegra_dpaux_probe,
.remove = tegra_dpaux_remove_wrapper,
.remove = tegra_dpaux_remove,
};
struct drm_dp_aux *drm_dp_aux_find_by_of_node(struct device_node *np)

View File

@@ -16,11 +16,7 @@
#include <linux/pm_runtime.h>
#include <linux/version.h>
#if defined(NV_APERTURE_REMOVE_ALL_CONFLICTING_DEVICES_PRESENT) /* Linux v6.0 */
#include <linux/aperture.h>
#else
#include <drm/drm_aperture.h>
#endif
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_debugfs.h>
@@ -30,7 +26,6 @@
#include <drm/drm_ioctl.h>
#include <drm/drm_prime.h>
#include <drm/drm_vblank.h>
#include <drm/tegra_drm-next.h>
#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
#include <asm/dma-iommu.h>
@@ -65,6 +60,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 +804,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,15 +885,14 @@ 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,
#endif
#if NV_IS_EXPORT_SYMBOL_PRESENT_drm_gem_prime_handle_to_fd
#if !defined(NV_UNEXPORT_FD_HANDLE_CONVERSION)
.prime_handle_to_fd = drm_gem_prime_handle_to_fd,
#endif
#if NV_IS_EXPORT_SYMBOL_PRESENT_drm_gem_prime_fd_to_handle
.prime_fd_to_handle = drm_gem_prime_fd_to_handle,
#endif
.gem_prime_import = tegra_gem_prime_import,
@@ -911,9 +905,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 +1180,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 +1194,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 +1225,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 +1302,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 +1313,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 +1337,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 +1361,7 @@ static int host1x_drm_remove(struct host1x_device *dev)
drm_dev_unregister(drm);
drm_kms_helper_poll_fini(drm);
tegra_drm_fb_exit(drm);
drm_atomic_helper_shutdown(drm);
drm_mode_config_cleanup(drm);

View File

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

View File

@@ -1,10 +1,8 @@
// 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>
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
@@ -257,14 +255,8 @@ static void tegra_dsi_early_unregister(struct drm_connector *connector)
unsigned int count = ARRAY_SIZE(debugfs_files);
struct tegra_dsi *dsi = to_dsi(output);
#if defined(NV_DRM_DEBUGFS_REMOVE_FILES_HAS_ROOT_ARG) /* Linux v6.7 */
drm_debugfs_remove_files(dsi->debugfs_files, count,
connector->debugfs_entry,
connector->dev->primary);
#else
drm_debugfs_remove_files(dsi->debugfs_files, count,
connector->dev->primary);
#endif
kfree(dsi->debugfs_files);
dsi->debugfs_files = NULL;
}
@@ -1692,23 +1684,11 @@ static const struct of_device_id tegra_dsi_of_match[] = {
};
MODULE_DEVICE_TABLE(of, tegra_dsi_of_match);
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_dsi_remove_wrapper(struct platform_device *pdev)
{
tegra_dsi_remove(pdev);
}
#else
static int tegra_dsi_remove_wrapper(struct platform_device *pdev)
{
return tegra_dsi_remove(pdev);
}
#endif
struct platform_driver tegra_dsi_driver = {
.driver = {
.name = "tegra-dsi",
.of_match_table = tegra_dsi_of_match,
},
.probe = tegra_dsi_probe,
.remove = tegra_dsi_remove_wrapper,
.remove = tegra_dsi_remove,
};

View File

@@ -11,8 +11,10 @@
#include <linux/console.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)
#include <linux/fb.h>
#include <linux/vmalloc.h>
#endif
#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
@@ -212,21 +214,24 @@ static int tegra_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
return __tegra_gem_mmap(&bo->gem, vma);
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)
#if defined(NV_FB_DEFERRED_IO_OPS_RENAME)
FB_GEN_DEFAULT_DEFERRED_IOMEM_OPS(tegra_fb,
drm_fb_helper_damage_range,
drm_fb_helper_damage_area)
#else
FB_GEN_DEFAULT_DEFERRED_IO_OPS(tegra_fb,
drm_fb_helper_damage_range,
drm_fb_helper_damage_area)
#endif
#endif
static const struct fb_ops tegra_fb_ops = {
.owner = THIS_MODULE,
#if defined(__FB_DEFAULT_DMAMEM_OPS_RDWR) /* Linux v6.6 */
__FB_DEFAULT_DMAMEM_OPS_RDWR,
#elif defined(__FB_DEFAULT_SYS_OPS_RDWR) /* Linux v6.5 */
__FB_DEFAULT_SYS_OPS_RDWR,
#else
.fb_read = drm_fb_helper_sys_read,
.fb_write = drm_fb_helper_sys_write,
#endif
DRM_FB_HELPER_DEFAULT_OPS,
#if defined(__FB_DEFAULT_DMAMEM_OPS_DRAW) /* Linux v6.6 */
__FB_DEFAULT_DMAMEM_OPS_DRAW,
#elif defined(__FB_DEFAULT_SYS_OPS_DRAW) /* Linux v6.5 */
__FB_DEFAULT_SYS_OPS_DRAW,
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)
__FB_DEFAULT_DEFERRED_OPS_RDWR(tegra_fb),
__FB_DEFAULT_DEFERRED_OPS_DRAW(tegra_fb),
#else
.fb_fillrect = drm_fb_helper_sys_fillrect,
.fb_copyarea = drm_fb_helper_sys_copyarea,

View File

@@ -3,7 +3,7 @@
* NVIDIA Tegra DRM GEM helper functions
*
* Copyright (C) 2012 Sascha Hauer, Pengutronix
* Copyright (C) 2013-2024 NVIDIA CORPORATION, All rights reserved.
* Copyright (C) 2013-2023 NVIDIA CORPORATION, All rights reserved.
*
* Based on the GEM/CMA helpers
*
@@ -15,7 +15,7 @@
#include <linux/dma-buf.h>
#include <linux/iommu.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/version.h>
#include <drm/drm_drv.h>
#include <drm/drm_prime.h>
@@ -24,11 +24,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)
{
@@ -588,7 +584,8 @@ int __tegra_gem_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma)
* and set the vm_pgoff (used as a fake buffer offset by DRM)
* to 0 as we want to map the whole buffer.
*/
#if defined(NV_VM_AREA_STRUCT_HAS_CONST_VM_FLAGS) /* Linux v6.3 */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) \
|| (defined(CONFIG_TEGRA_SYSTEM_TYPE_ACK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)))
vm_flags_clear(vma, VM_PFNMAP);
#else
vma->vm_flags &= ~VM_PFNMAP;
@@ -606,7 +603,8 @@ int __tegra_gem_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma)
} else {
pgprot_t prot = vm_get_page_prot(vma->vm_flags);
#if defined(NV_VM_AREA_STRUCT_HAS_CONST_VM_FLAGS) /* Linux v6.3 */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) \
|| (defined(CONFIG_TEGRA_SYSTEM_TYPE_ACK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)))
vm_flags_set(vma, VM_MIXEDMAP);
vm_flags_clear(vma, VM_PFNMAP);
#else
@@ -729,6 +727,7 @@ static int tegra_gem_prime_vmap(struct dma_buf *buf, struct iosys_map *map)
{
struct drm_gem_object *gem = buf->priv;
struct tegra_bo *bo = to_tegra_bo(gem);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
void *vaddr;
vaddr = tegra_bo_mmap(&bo->base);
@@ -736,16 +735,21 @@ static int tegra_gem_prime_vmap(struct dma_buf *buf, struct iosys_map *map)
return PTR_ERR(vaddr);
iosys_map_set_vaddr(map, vaddr);
#else
iosys_map_set_vaddr(map, bo->vaddr);
#endif
return 0;
}
static void tegra_gem_prime_vunmap(struct dma_buf *buf, struct iosys_map *map)
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)
struct drm_gem_object *gem = buf->priv;
struct tegra_bo *bo = to_tegra_bo(gem);
tegra_bo_munmap(&bo->base, map->vaddr);
#endif
}
#else
static int tegra_gem_prime_vmap(struct dma_buf *buf, struct dma_buf_map *map)

View File

@@ -1,18 +1,16 @@
// 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>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/version.h>
#include <soc/tegra/common.h>
@@ -274,7 +272,7 @@ static int gr2d_probe(struct platform_device *pdev)
gr2d->client.version = gr2d->soc->version;
gr2d->client.ops = &gr2d_ops;
#if defined(NV_DEVM_TEGRA_CORE_DEV_INIT_OPP_TABLE_COMMON_PRESENT) /* Linux v5.17 */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
err = devm_tegra_core_dev_init_opp_table_common(dev);
if (err)
return err;
@@ -394,18 +392,6 @@ static const struct dev_pm_ops tegra_gr2d_pm = {
pm_runtime_force_resume)
};
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void gr2d_remove_wrapper(struct platform_device *pdev)
{
gr2d_remove(pdev);
}
#else
static int gr2d_remove_wrapper(struct platform_device *pdev)
{
return gr2d_remove(pdev);
}
#endif
struct platform_driver tegra_gr2d_driver = {
.driver = {
.name = "tegra-gr2d",
@@ -413,5 +399,5 @@ struct platform_driver tegra_gr2d_driver = {
.pm = &tegra_gr2d_pm,
},
.probe = gr2d_probe,
.remove = gr2d_remove_wrapper,
.remove = gr2d_remove,
};

View File

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

View File

@@ -1,11 +1,9 @@
// 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>
#include <linux/clk.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
@@ -25,9 +23,6 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_debugfs.h>
#if defined(NV_DRM_DRM_ELD_H_PRESENT)
#include <drm/drm_eld.h>
#endif
#include <drm/drm_file.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_probe_helper.h>
@@ -1127,12 +1122,7 @@ static void tegra_hdmi_early_unregister(struct drm_connector *connector)
unsigned int count = ARRAY_SIZE(debugfs_files);
struct tegra_hdmi *hdmi = to_hdmi(output);
#if defined(NV_DRM_DEBUGFS_REMOVE_FILES_HAS_ROOT_ARG) /* Linux v6.7 */
drm_debugfs_remove_files(hdmi->debugfs_files, count,
connector->debugfs_entry, minor);
#else
drm_debugfs_remove_files(hdmi->debugfs_files, count, minor);
#endif
kfree(hdmi->debugfs_files);
hdmi->debugfs_files = NULL;
}
@@ -1874,14 +1864,16 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, hdmi);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
err = devm_pm_runtime_enable(&pdev->dev);
if (err)
return err;
#if defined(NV_DEVM_TEGRA_CORE_DEV_INIT_OPP_TABLE_COMMON_PRESENT) /* Linux v5.17 */
err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
if (err)
return err;
#else
pm_runtime_enable(&pdev->dev);
#endif
INIT_LIST_HEAD(&hdmi->client.list);
@@ -1902,6 +1894,10 @@ static int tegra_hdmi_remove(struct platform_device *pdev)
{
struct tegra_hdmi *hdmi = platform_get_drvdata(pdev);
#if !(LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0))
pm_runtime_disable(&pdev->dev);
#endif
host1x_client_unregister(&hdmi->client);
tegra_output_remove(&hdmi->output);
@@ -1909,23 +1905,11 @@ static int tegra_hdmi_remove(struct platform_device *pdev)
return 0;
}
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_hdmi_remove_wrapper(struct platform_device *pdev)
{
tegra_hdmi_remove(pdev);
}
#else
static int tegra_hdmi_remove_wrapper(struct platform_device *pdev)
{
return tegra_hdmi_remove(pdev);
}
#endif
struct platform_driver tegra_hdmi_driver = {
.driver = {
.name = "tegra-hdmi",
.of_match_table = tegra_hdmi_of_match,
},
.probe = tegra_hdmi_probe,
.remove = tegra_hdmi_remove_wrapper,
.remove = tegra_hdmi_remove,
};

View File

@@ -1,18 +1,16 @@
// 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>
#include <linux/host1x-next.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
@@ -1217,23 +1215,11 @@ static const struct of_device_id tegra_display_hub_of_match[] = {
};
MODULE_DEVICE_TABLE(of, tegra_display_hub_of_match);
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
static void tegra_display_hub_remove_wrapper(struct platform_device *pdev)
{
tegra_display_hub_remove(pdev);
}
#else
static int tegra_display_hub_remove_wrapper(struct platform_device *pdev)
{
return tegra_display_hub_remove(pdev);
}
#endif
struct platform_driver tegra_display_hub_driver = {
.driver = {
.name = "tegra-display-hub",
.of_match_table = tegra_display_hub_of_match,
},
.probe = tegra_display_hub_probe,
.remove = tegra_display_hub_remove_wrapper,
.remove = tegra_display_hub_remove,
};

View File

@@ -1,10 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2015-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2015-2023, 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;
@@ -142,7 +108,7 @@ static int nvdec_set_rate(struct nvdec *nvdec, unsigned long rate)
if (nvdec->icc_write) {
emc_kbps = dev_rate * NVDEC_AXI_RW_BANDWIDTH / 1024;
err = icc_set_bw(nvdec->icc_write, 0, kbps_to_icc(emc_kbps));
err = icc_set_bw(nvdec->icc_write, kbps_to_icc(emc_kbps), 0);
if (err)
dev_warn(nvdec->dev, "failed to set icc bw: %d\n", err);
}
@@ -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[] = {
@@ -879,9 +804,10 @@ static int nvdec_probe(struct platform_device *pdev)
}
nvdec->icc_write = devm_of_icc_get(dev, "write");
if (IS_ERR(nvdec->icc_write))
return dev_err_probe(&pdev->dev, PTR_ERR(nvdec->icc_write),
"failed to get icc write handle\n");
if (IS_ERR(nvdec->icc_write)) {
dev_err(&pdev->dev, "failed to get icc write handle\n");
return PTR_ERR(nvdec->icc_write);
}
platform_set_drvdata(pdev, nvdec);
@@ -966,18 +892,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 +899,7 @@ struct platform_driver tegra_nvdec_driver = {
.pm = &nvdec_pm_ops
},
.probe = nvdec_probe,
.remove = nvdec_remove_wrapper,
.remove = nvdec_remove,
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)

View File

@@ -1,10 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
*/
#include <nvidia/conftest.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
@@ -93,7 +91,7 @@ static int nvenc_set_rate(struct nvenc *nvenc, unsigned long rate)
if (nvenc->icc_write) {
emc_kbps = dev_rate * NVENC_AXI_RW_BANDWIDTH / 1024;
err = icc_set_bw(nvenc->icc_write, 0, kbps_to_icc(emc_kbps));
err = icc_set_bw(nvenc->icc_write, kbps_to_icc(emc_kbps), 0);
if (err)
dev_warn(nvenc->dev, "failed to set icc bw: %d\n", err);
}
@@ -672,9 +670,10 @@ static int nvenc_probe(struct platform_device *pdev)
return err;
nvenc->icc_write = devm_of_icc_get(dev, "write");
if (IS_ERR(nvenc->icc_write))
return dev_err_probe(&pdev->dev, PTR_ERR(nvenc->icc_write),
"failed to get icc write handle\n");
if (IS_ERR(nvenc->icc_write)) {
dev_err(&pdev->dev, "failed to get icc write handle\n");
return PTR_ERR(nvenc->icc_write);
}
platform_set_drvdata(pdev, nvenc);
@@ -759,18 +758,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 +765,7 @@ struct platform_driver tegra_nvenc_driver = {
.pm = &nvenc_pm_ops
},
.probe = nvenc_probe,
.remove = nvenc_remove_wrapper,
.remove = nvenc_remove,
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)

View File

@@ -1,10 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
*/
#include <nvidia/conftest.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
@@ -90,7 +88,7 @@ static int nvjpg_set_rate(struct nvjpg *nvjpg, unsigned long rate)
if (nvjpg->icc_write) {
emc_kbps = dev_rate * NVJPG_AXI_RW_BANDWIDTH / 1024;
err = icc_set_bw(nvjpg->icc_write, 0, kbps_to_icc(emc_kbps));
err = icc_set_bw(nvjpg->icc_write, kbps_to_icc(emc_kbps), 0);
if (err)
dev_warn(nvjpg->dev, "failed to set icc bw: %d\n", err);
}
@@ -657,9 +655,10 @@ static int nvjpg_probe(struct platform_device *pdev)
return err;
nvjpg->icc_write = devm_of_icc_get(dev, "write");
if (IS_ERR(nvjpg->icc_write))
return dev_err_probe(&pdev->dev, PTR_ERR(nvjpg->icc_write),
"failed to get icc write handle\n");
if (IS_ERR(nvjpg->icc_write)) {
dev_err(&pdev->dev, "failed to get icc write handle\n");
return PTR_ERR(nvjpg->icc_write);
}
platform_set_drvdata(pdev, nvjpg);
@@ -736,18 +735,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 +742,7 @@ struct platform_driver tegra_nvjpg_driver = {
.pm = &nvjpg_pm_ops
},
.probe = nvjpg_probe,
.remove = nvjpg_remove_wrapper,
.remove = nvjpg_remove,
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC)

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2013-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* Copyright (C) 2013 NVIDIA Corporation
*/
#include <nvidia/conftest.h>
@@ -32,9 +32,6 @@
#endif
#include <drm/drm_atomic_helper.h>
#include <drm/drm_debugfs.h>
#if defined(NV_DRM_DRM_ELD_H_PRESENT)
#include <drm/drm_eld.h>
#endif
#include <drm/drm_file.h>
#include <drm/drm_panel.h>
#include <drm/drm_simple_kms_helper.h>
@@ -1721,15 +1718,8 @@ static void tegra_sor_early_unregister(struct drm_connector *connector)
unsigned int count = ARRAY_SIZE(debugfs_files);
struct tegra_sor *sor = to_sor(output);
#if defined(NV_DRM_DEBUGFS_REMOVE_FILES_HAS_ROOT_ARG) /* Linux v6.7 */
drm_debugfs_remove_files(sor->debugfs_files, count,
connector->debugfs_entry,
connector->dev->primary);
#else
drm_debugfs_remove_files(sor->debugfs_files, count,
connector->dev->primary);
#endif
kfree(sor->debugfs_files);
sor->debugfs_files = NULL;
}
@@ -4082,18 +4072,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 +4079,5 @@ struct platform_driver tegra_sor_driver = {
.pm = &tegra_sor_pm_ops,
},
.probe = tegra_sor_probe,
.remove = tegra_sor_remove_wrapper,
.remove = tegra_sor_remove,
};

View File

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

View File

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

View File

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

View File

@@ -1,10 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* SPDX-FileCopyrightText: Copyright (c) 2015-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
* SPDX-FileCopyrightText: Copyright (C) 2015-2023 NVIDIA CORPORATION. All rights reserved.
*/
#include <nvidia/conftest.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
@@ -131,7 +129,7 @@ static int vic_set_rate(struct vic *vic, unsigned long rate)
if (vic->icc_write) {
emc_kbps = dev_rate * VIC_AXI_RW_BANDWIDTH / 1024;
err = icc_set_bw(vic->icc_write, 0, kbps_to_icc(emc_kbps));
err = icc_set_bw(vic->icc_write, kbps_to_icc(emc_kbps), 0);
if (err)
dev_warn(vic->dev, "failed to set icc bw: %d\n", err);
}
@@ -725,9 +723,10 @@ static int vic_probe(struct platform_device *pdev)
}
vic->icc_write = devm_of_icc_get(dev, "write");
if (IS_ERR(vic->icc_write))
return dev_err_probe(&pdev->dev, PTR_ERR(vic->icc_write),
"failed to get icc write handle\n");
if (IS_ERR(vic->icc_write)) {
dev_err(&pdev->dev, "failed to get icc write handle\n");
return PTR_ERR(vic->icc_write);
}
if (!dev->pm_domain) {
vic->rst = devm_reset_control_get(dev, "vic");
@@ -833,18 +832,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 +839,7 @@ struct platform_driver tegra_vic_driver = {
.pm = &vic_pm_ops
},
.probe = vic_probe,
.remove = vic_remove_wrapper,
.remove = vic_remove,
};
#if IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC)

View File

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

View File

@@ -1,5 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
/*
* Host1x fence UAPI
*
* Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
*/
#include <nvidia/conftest.h>
@@ -10,8 +14,7 @@
#include <linux/host1x-next.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/sync_file.h>
@@ -172,8 +175,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 +204,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 +234,8 @@ static unsigned int host1x_pollfd_poll(struct file *file, poll_table *wait)
list_for_each_entry_safe(pfd_fence, pfd_fence_temp, &pollfd->fences, list) {
if (dma_fence_is_signaled(pfd_fence->fence)) {
mask = POLLPRI | POLLIN;
if (pfd_fence->callback_set) {
if (dma_fence_remove_callback(pfd_fence->fence,
&pfd_fence->callback))
host1x_fence_cancel(pfd_fence->fence);
pfd_fence->callback_set = false;
}
/*The lock/unlock just ensures that the callback execution has finished*/
spin_lock(pfd_fence->fence->lock);
spin_unlock(pfd_fence->fence->lock);
dma_fence_put(pfd_fence->fence);
list_del(&pfd_fence->list);
kfree(pfd_fence);
}
}

View File

@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
/*
* Copyright (c) 2022-2023, NVIDIA Corporation. All rights reserved.
*/
#include <nvidia/conftest.h>
@@ -543,6 +545,7 @@ int flcn_intr_init(struct platform_device *pdev)
return -ENXIO;
}
spin_lock_init(&pdata->mirq_lock);
ret = devm_request_irq(&pdev->dev, pdata->irq, flcn_isr, 0,
dev_name(&pdev->dev), pdev);
if (ret) {

View File

@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
# Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
host1x-y = \
host1x-next-y = \
bus.o \
syncpt.o \
dev.o \
@@ -21,7 +21,7 @@ host1x-y = \
hw/host1x07.o \
hw/host1x08.o
host1x-$(CONFIG_IOMMU_API) += \
host1x-next-$(CONFIG_IOMMU_API) += \
context.o
obj-m := host1x.o
obj-m := host1x-next.o

View File

@@ -4,8 +4,6 @@
* Copyright (C) 2012-2013, NVIDIA Corporation
*/
#include <nvidia/conftest.h>
#include <linux/debugfs.h>
#include <linux/dma-mapping.h>
#include <linux/host1x-next.h>
@@ -13,6 +11,7 @@
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/of_device.h>
#include <linux/version.h>
#include "bus.h"
#include "dev.h"
@@ -335,16 +334,12 @@ 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;
}
#if defined(NV_BUS_TYPE_STRUCT_UEVENT_HAS_CONST_DEV_ARG) /* Linux v6.3 */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)
static int host1x_device_uevent(const struct device *dev,
#else
static int host1x_device_uevent(struct device *dev,

View File

@@ -35,14 +35,14 @@
/*
* Typically the commands written into the push buffer are a pair of words. We
* use slots to represent each of these pairs and to simplify things. Note the
* strange number of slots allocated here. 1024 slots will fit exactly within a
* two memory pages. We also need one additional word at the end of the push
* strange number of slots allocated here. 512 slots will fit exactly within a
* single memory page. We also need one additional word at the end of the push
* buffer for the RESTART opcode that will instruct the CDMA to jump back to
* the beginning of the push buffer. With 1024 slots, this means that we'll use
* 3 memory pages and waste 4092 bytes of the third page that will never be
* the beginning of the push buffer. With 512 slots, this means that we'll use
* 2 memory pages and waste 4092 bytes of the second page that will never be
* used.
*/
#define HOST1X_PUSHBUFFER_SLOTS 1023
#define HOST1X_PUSHBUFFER_SLOTS 511
/*
* Clean up push buffer resources
@@ -496,7 +496,7 @@ resume:
host1x_hw_cdma_resume(host1x, cdma, restart_addr);
}
static void cdma_update_work(struct work_struct *work)
void cdma_update_work(struct work_struct *work)
{
struct host1x_cdma *cdma = container_of(work, struct host1x_cdma, update_work);

View File

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

View File

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

View File

@@ -2,21 +2,20 @@
/*
* 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>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <soc/tegra/common.h>
@@ -620,16 +619,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;
}
@@ -958,7 +950,7 @@ static int host1x_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
#if defined(NV_DEVM_TEGRA_CORE_DEV_INIT_OPP_TABLE_COMMON_PRESENT) /* Linux v5.17 */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
err = devm_tegra_core_dev_init_opp_table_common(&pdev->dev);
if (err)
goto pm_disable;
@@ -1109,18 +1101,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 +1108,7 @@ static struct platform_driver tegra_host1x_driver = {
.pm = &host1x_pm_ops,
},
.probe = host1x_probe,
.remove = host1x_remove_wrapper,
.remove = host1x_remove,
};
static struct platform_driver * const drivers[] = {

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <nvidia/conftest.h>
// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon.h>
@@ -1093,10 +1091,8 @@ static int f75308_probe_child_from_dt(struct device *dev,
u32 reg_idx, seg_idx = 0, seg_val;
u8 seg5[F75308_MAX_FAN_SEG_CNT];
const char *val_str;
#if !defined(NV_OF_PROPERTY_FOR_EACH_REMOVED_INTERNAL_ARGS) /* Linux v6.11 */
struct property *prop;
const __be32 *p;
#endif
status = of_property_read_u32(child, "reg", &reg_idx);
if (status) {
@@ -1127,11 +1123,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;
@@ -1222,7 +1214,7 @@ destroy_lock:
return status;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
static int f75308_remove(struct i2c_client *client)
#else
static void f75308_remove(struct i2c_client *client)
@@ -1231,7 +1223,7 @@ static void f75308_remove(struct i2c_client *client)
struct f75308_priv *priv = dev_get_drvdata(&client->dev);
mutex_destroy(&priv->locker);
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
return 0;
#endif
}
@@ -1264,10 +1256,10 @@ static struct i2c_driver f75308_driver = {
.of_match_table = of_match_ptr(f75308_match_table),
},
.detect = f75308_detect,
#if defined(NV_I2C_DRIVER_STRUCT_HAS_PROBE_NEW) /* Dropped on Linux 6.6 */
.probe_new = f75308_probe,
#else
#if defined(NV_I2C_LEGACY_PROBE_NEW_REMOVED)
.probe = f75308_probe,
#else
.probe_new = f75308_probe,
#endif
.remove = f75308_remove,
.address_list = f75308_addr,

View File

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

View File

@@ -2,11 +2,9 @@
/*
* 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>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -120,8 +118,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 +178,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);
@@ -244,7 +242,7 @@ static int nvvrs11_vendor_info(struct nvvrs11_chip *chip)
return 0;
}
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
static int nvvrs11_probe(struct i2c_client *client)
#else
static int nvvrs11_probe(struct i2c_client *client,
@@ -310,7 +308,7 @@ exit:
return ret;
}
#if !defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
static void nvvrs11_remove(struct i2c_client *client)
{
nvvrs11_delete_sys_files(&client->dev);

View File

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

View File

@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
# Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
subdir-ccflags-y += -Werror
@@ -7,8 +7,6 @@ obj-m += max9295.o
obj-m += max9296.o
ifeq ($(findstring ack_src,$(NV_BUILD_KERNEL_OPTIONS)),)
obj-m += max96712.o
ifdef CONFIG_MEDIA_SUPPORT
obj-m += ar1335_common.o
obj-m += lt6911uxc.o
obj-m += nv_imx185.o
@@ -19,10 +17,7 @@ obj-m += nv_imx390.o
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
obj-m += nv_hawk_owl.o
obj-m += virtual_i2c_mux.o
endif

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2018-2024, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
/* Copyright (c) 2018-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
/*
* ar0234_mode_tbls.h - ar0234 sensor mode tables
*/
@@ -62,6 +62,7 @@ static struct index_reg_8 ar0234_Double_Dser_Ser[] = {
{0x52, 0x0003, 0xAE}, // Disable CC to link B
{0x80, 0x0000, 0x84}, // Link A serializer address is 0x84
{0x52, 0x0003, 0xAB}, // Disable CC to link A
{0x80, 0x0000, 0x88}, // Link B serializer address is 0x88
{0x52, 0x0003, 0xAA}, // Enable CC to links A and B
@@ -69,17 +70,17 @@ static struct index_reg_8 ar0234_Double_Dser_Ser[] = {
{0x84, 0x0308, 0x7E}, // Pipe X pulls clock from port A, pipe Y from port B
{0x84, 0x0311, 0x21}, // Pipe X pulls data from port A, pipe Y from port B
{0x84, 0x0316, 0x6b}, // RAW10 to pipe Y
{0x84, 0x0314, 0x6b}, // RAW10 to pipe X
{0x84, 0x0314, 0x6b}, // RAW10 to pipe Y
{0x88, 0x0002, 0x33}, // Enable pipes X and Y
{0x88, 0x0308, 0x7E}, // Pipe X pulls clock from port A, pipe Y from port B
{0x88, 0x0311, 0x21}, // Pipe X pulls data from port A, pipe Y from port B
{0x88, 0x0316, 0x6b}, // RAW10 to pipe Y
{0x88, 0x0314, 0x6b}, // RAW10 to pipe X
{0x52, 0x00F4, 0x0f}, // Enable pipes 0-3 in deserializer
{0x88, 0x0314, 0x6b}, // RAW10 to pipe Y
{0x52, 0x00F4, 0x0f}, // Enable pipe 0
{0x52, 0x00F0, 0x10}, // Link A ID 0 to pipe 0 // Link A ID 1 to pipe 1
{0x52, 0x00F1, 0x54}, // Link B ID 0 to pipe 2 // Link B ID 1 to pipe 3
{0x52, 0x08A0, 0x01}, // CSI output is 4x2
{0x52, 0x08A0, 0x01}, // CSI output is 2x4
{0x52, 0x08A3, 0x44}, // Default 4x2 lane mapping
{0x52, 0x08A4, 0x44}, // Default 4x2 lane mapping
@@ -91,16 +92,16 @@ static struct index_reg_8 ar0234_Double_Dser_Ser[] = {
{0x52, 0x1D00, 0xF4},
{0x52, 0x1E00, 0xF4},
{0x52, 0x0415, 0x39},
{0x52, 0x0418, 0x39}, // Date rate is 2500Mbps/lane on port D
{0x52, 0x041B, 0x39}, // Data rate is 2500Mbps/lane on port E
{0x52, 0x041E, 0x39},
{0x52, 0x0415, 0x2E},
{0x52, 0x0418, 0x2E}, // 1400Mbps
{0x52, 0x041B, 0x2E},
{0x52, 0x041E, 0x2E},
{0x52, 0x1D00, 0xF5},
{0x52, 0x1E00, 0xF5},
{0x52, 0x090B, 0x07}, // Enable 3 mappings Pipe 0//video2
{0x52, 0x092D, 0x00}, // All mappings to controller 0 (port C)
{0x52, 0x092D, 0x15}, // All mappings to controller 1 (port A)
{0x52, 0x090D, 0x2B}, // Input RAW10, VC0
{0x52, 0x090E, 0x2B}, // Output RAW10, VC0
{0x52, 0x090F, 0x00}, // Input FS, VC0
@@ -109,7 +110,7 @@ static struct index_reg_8 ar0234_Double_Dser_Ser[] = {
{0x52, 0x0912, 0x01}, // Output FE, VC0
{0x52, 0x094B, 0x07}, // Enable 3 mappings Pipe 1 //video3
{0x52, 0x096D, 0x00}, // All mappings to controller 0 (port C)
{0x52, 0x096D, 0x15}, // All mappings to controller 1 (port A)
{0x52, 0x094D, 0x2B}, // Input RAW10, VC0
{0x52, 0x094E, 0x6B}, // Output RAW10, VC1
{0x52, 0x094F, 0x00}, // Input FS, VC0
@@ -118,23 +119,22 @@ static struct index_reg_8 ar0234_Double_Dser_Ser[] = {
{0x52, 0x0952, 0x41}, // Output FE, VC1
{0x52, 0x098B, 0x07}, // Enable 3 mappings Pipe 2 //video1
{0x52, 0x09AD, 0x15}, // All mappings to controller 1 (port D)
{0x52, 0x09AD, 0x15}, // All mappings to controller 1 (port A)
{0x52, 0x098D, 0x2B}, // Input RAW10, VC0
{0x52, 0x098E, 0x2B}, // Output RAW10, VC0
{0x52, 0x098E, 0xaB}, // Output RAW10, VC2
{0x52, 0x098F, 0x00}, // Input FS, VC0
{0x52, 0x0990, 0x00}, // Output FS, VC0
{0x52, 0x0990, 0x80}, // Output FS, VC2
{0x52, 0x0991, 0x01}, // Input FE, VC0
{0x52, 0x0992, 0x01}, // Output FE, VC0
{0x52, 0x0992, 0x81}, // Output FE, VC2
{0x52, 0x09CB, 0x07}, // Enable 3 mappings Pipe 3 //video0
{0x52, 0x09ED, 0x15}, // All mappings to controller 1 (port D)
{0x52, 0x09ED, 0x15}, // All mappings to controller 1 (port A)
{0x52, 0x09CD, 0x2B}, // Input RAW10, VC0
{0x52, 0x09CE, 0x6B}, // Output RAW10, VC1
{0x52, 0x09CE, 0xeB}, // Output RAW10, VC3
{0x52, 0x09CF, 0x00}, // Input FS, VC0
{0x52, 0x09D0, 0x40}, // Output FS, VC1
{0x52, 0x09D0, 0xc0}, // Output FS, VC3
{0x52, 0x09D1, 0x01}, // Input FE, VC0
{0x52, 0x09D2, 0x41}, // Output FE, VC1
{0x52, 0x09D2, 0xc1}, // Output FE, VC3
{0x52, 0x08A2, 0xF0},
{0x84, 0x02be, 0x90}, // Enable sensor power down pin.

View File

@@ -1,12 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2017-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// Copyright (c) 2017-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// Copyright (c) 2022, e-con Systems. All rights reserved.
/*
* ar1335_common.c - AR1335 sensor driver
* ar1335.c - AR1335 sensor driver
*/
#include <nvidia/conftest.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
@@ -52,13 +50,11 @@ static uint32_t u8arr_to_uint32(uint8_t *in_arr)
in_arr[3]);
}
static int mcu_send_ctrl_cmd(struct i2c_client *client,
int cmd,
uint32_t payload_len,
uint16_t index)
static int mcu_send_ctrl_cmd(struct i2c_client *client, int cmd, uint32_t payload_len)
{
int err;
uint8_t orig_crc = 0, calc_crc = 0;
uint16_t index = 0xFFFF;
mc_data[0] = CMD_SIGNATURE;
mc_data[1] = cmd;
@@ -413,7 +409,7 @@ static int cam_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *cfg,
if ((priv->mcu_cam_frmfmt[ret].size.width ==
format->format.width) &&
(priv->mcu_cam_frmfmt[ret].size.height ==
format->format.height))
format->format.height))
{
priv->frmfmt_mode = priv->mcu_cam_frmfmt[ret].mode;
flag = 1;
@@ -988,7 +984,7 @@ static int mcu_get_ctrl(struct i2c_client *client, uint32_t arg_ctrl_id,
/* First Txn Payload length = 2 */
payload_len = 2;
ret = mcu_send_ctrl_cmd(client, CMD_ID_GET_CTRL, payload_len, index);
ret = mcu_send_ctrl_cmd(client, CMD_ID_GET_CTRL, payload_len);
if (ret) {
dev_err(&client->dev, "CMD_ID_GET_CTRL send failed\n");
goto exit;
@@ -1154,8 +1150,7 @@ static int mcu_list_fmts(struct i2c_client *client,ISP_STREAM_INFO *stream_info,
/* First Txn Payload length = 0 */
payload_len = 2;
ret = mcu_send_ctrl_cmd(client, CMD_ID_GET_STREAM_INFO,
payload_len, index);
ret = mcu_send_ctrl_cmd(client, CMD_ID_GET_STREAM_INFO, payload_len);
if (ret) {
dev_err(&client->dev, "CMD_ID_GET_STREAM_INFO send failed\n");
goto exit;
@@ -1277,8 +1272,7 @@ static int mcu_get_ctrl_ui(struct i2c_client *client,
/* First Txn Payload length = 0 */
payload_len = 2;
ret = mcu_send_ctrl_cmd(client, CMD_ID_GET_CTRL_UI_INFO,
payload_len, index);
ret = mcu_send_ctrl_cmd(client, CMD_ID_GET_CTRL_UI_INFO, payload_len);
if (ret) {
dev_err(&client->dev, "CMD_ID_GET_CTRL_UI_INFO send failed\n");
goto exit;
@@ -1408,8 +1402,7 @@ static int mcu_list_ctrls(struct i2c_client *client,
/* First Txn Payload length = 0 */
payload_len = 2;
ret = mcu_send_ctrl_cmd(client, CMD_ID_GET_CTRL_INFO,
payload_len, index);
ret = mcu_send_ctrl_cmd(client, CMD_ID_GET_CTRL_INFO, payload_len);
if (ret) {
dev_err(&client->dev, "CMD_ID_GET_CTRL_INFO send failed\n");
goto exit;
@@ -2368,7 +2361,7 @@ exit:
return ret;
}
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
static int cam_probe(struct i2c_client *client)
#else
static int cam_probe(struct i2c_client *client,
@@ -2790,7 +2783,7 @@ exit:
devm_kfree(dev, ptr); \
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
static int cam_remove(struct i2c_client *client)
#else
static void cam_remove(struct i2c_client *client)
@@ -2804,7 +2797,7 @@ static void cam_remove(struct i2c_client *client)
if (!s_data) {
dev_err(&client->dev, "camera common data is NULL\n");
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
return -EINVAL;
#else
return;
@@ -2816,7 +2809,7 @@ static void cam_remove(struct i2c_client *client)
reset_gpio = of_get_named_gpio(node, "reset-gpios", 0);
if (reset_gpio < 0) {
dev_err(&client->dev, "Unable to get reset GPIO\n");
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
return -EINVAL;
#else
return;

View File

@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
/* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
/*
* hawk_owl_mode_tbls.h - ar0234 sensor mode tables
*/
@@ -179,9 +179,9 @@ static struct index_reg_8 i2c_address_trans_hawk1_eeprom[] = {
};
static struct index_reg_8 i2c_address_trans_hawk2_eeprom[] = {
{0x96, 0x0042, 0x2A},
{0x96, 0x0042, 0x84},
{0x96, 0x0043, 0xA8},
{0x96, 0x0044, 0x2C},
{0x96, 0x0044, 0x86},
{0x96, 0x0045, 0xAA},
{0x00, AR0234_TABLE_END, 0x00}
};
@@ -530,7 +530,6 @@ static struct index_reg_8 ar0234_Hawk_TripleLink_Dser_Ser[] = {
{0x98, 0x0311, 0x21}, // Pipe X pulls data from port A, pipe Y from port B
{0x98, 0x0316, 0x6b}, // RAW10 to pipe Y
{0x98, 0x0314, 0x6b}, // RAW10 to pipe Y
{0x52, 0x00F4, 0x3f}, // Enable video pipe 0,1,2,3,4,5
/*Tuned params to fix streaming issues */
{0x52, 0x00F0, 0x10}, // Link A ID 0 to pipe 0 // Link A ID 1 to pipe 1

View File

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -4,8 +4,6 @@
* Lontium LT6911UXC HDMI-CSI bridge driver
*/
#include <nvidia/conftest.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
@@ -669,7 +667,7 @@ static struct camera_common_sensor_ops lt6911uxc_common_ops = {
};
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
static int lt6911uxc_probe(struct i2c_client *client)
#else
static int lt6911uxc_probe(struct i2c_client *client,
@@ -733,7 +731,7 @@ static int lt6911uxc_probe(struct i2c_client *client,
return 0;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
static int lt6911uxc_remove(struct i2c_client *client)
#else
static void lt6911uxc_remove(struct i2c_client *client)
@@ -743,7 +741,7 @@ static void lt6911uxc_remove(struct i2c_client *client)
struct lt6911uxc *priv;
if (!s_data)
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
return -EINVAL;
#else
return;
@@ -753,7 +751,7 @@ static void lt6911uxc_remove(struct i2c_client *client)
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 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
return 0;
#endif
}

View File

@@ -4,8 +4,6 @@
* max9295.c - max9295 GMSL Serializer driver
*/
#include <nvidia/conftest.h>
#include <media/camera_common.h>
#include <linux/module.h>
#include <media/max9295.h>
@@ -465,7 +463,7 @@ static struct regmap_config max9295_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
static int max9295_probe(struct i2c_client *client)
#else
static int max9295_probe(struct i2c_client *client,
@@ -514,7 +512,7 @@ static int max9295_probe(struct i2c_client *client,
return err;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
static int max9295_remove(struct i2c_client *client)
#else
static void max9295_remove(struct i2c_client *client)
@@ -528,7 +526,7 @@ static void max9295_remove(struct i2c_client *client)
i2c_unregister_device(client);
client = NULL;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
return 0;
#endif
}

View File

@@ -4,8 +4,6 @@
* max9296.c - max9296 GMSL Deserializer driver
*/
#include <nvidia/conftest.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -848,7 +846,7 @@ static struct regmap_config max9296_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
static int max9296_probe(struct i2c_client *client)
#else
static int max9296_probe(struct i2c_client *client,
@@ -894,7 +892,7 @@ static int max9296_probe(struct i2c_client *client,
return 0;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
static int max9296_remove(struct i2c_client *client)
#else
static void max9296_remove(struct i2c_client *client)
@@ -908,7 +906,7 @@ static void max9296_remove(struct i2c_client *client)
i2c_unregister_device(client);
client = NULL;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
return 0;
#endif
}

View File

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

View File

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

View File

@@ -7,8 +7,6 @@
/* #define DEBUG */
#include <nvidia/conftest.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <media/camera_common.h>
@@ -228,7 +226,7 @@ static struct regmap_config max96712_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
static int max96712_probe(struct i2c_client *client)
#else
static int max96712_probe(struct i2c_client *client,
@@ -268,7 +266,7 @@ static int max96712_probe(struct i2c_client *client,
return err;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
static int max96712_remove(struct i2c_client *client)
#else
static void max96712_remove(struct i2c_client *client)
@@ -279,7 +277,7 @@ static void max96712_remove(struct i2c_client *client)
i2c_unregister_device(client);
client = NULL;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
return 0;
#endif
}

View File

@@ -1,11 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
// SPDX-FileCopyrightText: Copyright (c) 2018-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2018-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
/*
* ar0234.c - ar0234 sensor driver
*/
#include <nvidia/conftest.h>
#define DEBUG 1
#include <linux/slab.h>
#include <linux/uaccess.h>
@@ -28,7 +26,6 @@
#define MAX_TANGENTIAL_COEFFICIENTS 2
#define MAX_FISHEYE_COEFFICIENTS 6
#define CAMERA_MAX_SN_LENGTH 32
#define LEOP_CAMERA_MAX_SN_LENGTH 10
#define MAX_RLS_COLOR_CHANNELS 4
#define MAX_RLS_BREAKPOINTS 6
@@ -65,6 +62,7 @@ static const u32 ctrl_cid_list[] = {
TEGRA_CAMERA_CID_ALTERNATING_EXPOSURE,
};
const u16 alternating_exposure_cfg_size = sizeof(struct alternating_exposure_cfg);
// Coefficients as per distortion model (wide FOV) being used
struct fisheye_lens_distortion_coeff {
@@ -127,13 +125,7 @@ struct camera_extrinsics {
float tx, ty, tz;
};
/*
* IMU parameters used by HAWK 1.0. HAWK 1.0 did not have IMU noise model parameters
* in EEPROM. To preserve backward compatibility with HAWK 1.0, the EEPROM data is arranged
* in a certain way which requires tracking the imu noise model parameters in a
* separate structure.
*/
struct imu_params_v1 {
struct imu_params {
// 3D vector to add to accelerometer readings
float linear_acceleration_bias[3];
// 3D vector to add to gyroscope readings
@@ -142,12 +134,7 @@ struct imu_params_v1 {
float gravity_acceleration[3];
// Extrinsic structure for IMU device
struct camera_extrinsics extr;
};
struct imu_params_noise_m {
/*
* Noise model parameters
*/
// Noise model parameters
float update_rate;
float linear_acceleration_noise_density;
float linear_acceleration_random_walk;
@@ -155,14 +142,6 @@ struct imu_params_noise_m {
float angular_velocity_random_walk;
};
/*
* Combined IMU calibration data structure
*/
struct imu_params_v2 {
struct imu_params_v1 imu_data_v1;
struct imu_params_noise_m nm;
};
struct radial_lsc_params {
// Image height
u16 image_height;
@@ -205,7 +184,7 @@ struct NvCamSyncSensorCalibData {
u8 imu_present;
// Intrinsic structure for IMU
struct imu_params_v2 imu;
struct imu_params imu;
// HAWK module serial number
u8 serial_number[CAMERA_MAX_SN_LENGTH];
@@ -240,14 +219,10 @@ struct LiEeprom_Content_Struct {
/**
* Intrinsic structure for IMU
*/
struct imu_params_v1 imu;
u8 tmp[16];
struct imu_params imu;
// HAWK module serial number
u8 serial_number[LEOP_CAMERA_MAX_SN_LENGTH];
struct imu_params_noise_m nm;
u8 serial_number[CAMERA_MAX_SN_LENGTH];
// Radial Lens Shading Correction parameters
struct radial_lsc_params left_rls;
@@ -701,10 +676,9 @@ static int ar0234_fill_eeprom(struct tegracam_device *tc_dev,
priv->EepromCalib.cam_extr = tmp->cam_extr;
priv->EepromCalib.imu_present = tmp->imu_present;
priv->EepromCalib.imu.imu_data_v1 = tmp->imu;
priv->EepromCalib.imu.nm = tmp->nm;
priv->EepromCalib.imu = tmp->imu;
memcpy(priv->EepromCalib.serial_number, tmp->serial_number,
8);
CAMERA_MAX_SN_LENGTH);
if (priv->sync_sensor_index == 1)
priv->EepromCalib.rls = tmp->left_rls;
@@ -818,7 +792,7 @@ static struct tegracam_ctrl_ops ar0234_ctrl_ops = {
.numctrls = ARRAY_SIZE(ctrl_cid_list),
.ctrl_cid_list = ctrl_cid_list,
.string_ctrl_size = {AR0234_EEPROM_STR_SIZE},
.compound_ctrl_size = {sizeof(struct NvCamSyncSensorCalibData), sizeof(struct alternating_exposure_cfg)},
.compound_ctrl_size = {sizeof(struct NvCamSyncSensorCalibData), alternating_exposure_cfg_size},
.set_gain = ar0234_set_gain,
.set_exposure = ar0234_set_exposure,
.set_exposure_short = ar0234_set_exposure,
@@ -1070,7 +1044,7 @@ static int ar0234_board_setup(struct ar0234 *priv)
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
static int ar0234_probe(struct i2c_client *client)
#else
static int ar0234_probe(struct i2c_client *client,
@@ -1175,7 +1149,7 @@ static int ar0234_probe(struct i2c_client *client,
return 0;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
static int ar0234_remove(struct i2c_client *client)
#else
static void ar0234_remove(struct i2c_client *client)
@@ -1185,7 +1159,7 @@ static void ar0234_remove(struct i2c_client *client)
struct ar0234 *priv;
if (!s_data)
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
return -EINVAL;
#else
return;
@@ -1195,7 +1169,7 @@ static void ar0234_remove(struct i2c_client *client)
tegracam_v4l2subdev_unregister(priv->tc_dev);
tegracam_device_unregister(priv->tc_dev);
ar0234_eeprom_device_release(priv);
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
return 0;
#endif
}

View File

@@ -1,11 +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-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
/*
* nv_hawk_owl.c.c - ar0234 sensor driver
*/
#include <nvidia/conftest.h>
#define DEBUG 0
#include <linux/slab.h>
#include <linux/uaccess.h>
@@ -17,7 +15,6 @@
#include <linux/of_gpio.h>
#include <media/max9295.h>
#include <media/max9296.h>
#include <media/nv_hawk_owl.h>
#include <media/tegracam_core.h>
#include "hawk_owl_mode_tbls.h"
#include <linux/ktime.h>
@@ -26,7 +23,6 @@
#define MAX_TANGENTIAL_COEFFICIENTS 2
#define MAX_FISHEYE_COEFFICIENTS 6
#define CAMERA_MAX_SN_LENGTH 32
#define LEOP_CAMERA_MAX_SN_LENGTH 10
#define MAX_RLS_COLOR_CHANNELS 4
#define MAX_RLS_BREAKPOINTS 6
#define OWL_CHANNEL 1
@@ -68,6 +64,8 @@ static const u32 ctrl_cid_list[] = {
TEGRA_CAMERA_CID_ALTERNATING_EXPOSURE,
};
const u16 alternating_exposure_cfg_size = sizeof(struct alternating_exposure_cfg);
// Coefficients as per distortion model (wide FOV) being used
typedef struct
{
@@ -129,13 +127,6 @@ typedef struct
// Translation parameter from one camera to another parameter
float tx, ty, tz;
} camera_extrinsics;
/*
* IMU parameters used by HAWK 1.0. HAWK 1.0 did not have IMU noise model parameters
* in EEPROM. To preserve backward compatibility with HAWK 1.0, the EEPROM data is arranged
* in a certain way which requires tracking the imu noise model parameters in a
* separate structure.
*/
typedef struct
{
// 3D vector to add to accelerometer readings
@@ -146,26 +137,13 @@ typedef struct
float gravity_acceleration[3];
// Extrinsic structure for IMU device
camera_extrinsics extr;
} imu_params_v1;
typedef struct {
/*
* Noise model parameters
*/
// Noise model parameters
float update_rate;
float linear_acceleration_noise_density;
float linear_acceleration_random_walk;
float angular_velocity_noise_density;
float angular_velocity_random_walk;
} imu_params_noise_m;
/*
* Combined IMU calibration data structure
*/
typedef struct {
imu_params_v1 imu_data_v1;
imu_params_noise_m nm;
} imu_params_v2;
} imu_params;
typedef struct {
// Image height
@@ -209,7 +187,7 @@ typedef struct
u8 imu_present;
// Intrinsic structure for IMU
imu_params_v2 imu;
imu_params imu;
// HAWK module serial number
u8 serial_number[CAMERA_MAX_SN_LENGTH];
@@ -217,7 +195,6 @@ typedef struct
// Radial Lens Shading Correction parameters
radial_lsc_params rls;
} NvCamSyncSensorCalibData;
typedef struct
{
/**
@@ -245,20 +222,15 @@ typedef struct
/**
* Intrinsic structure for IMU
*/
imu_params_v1 imu;
u8 tmp[16];
imu_params imu;
// HAWK module serial number
u8 serial_number[LEOP_CAMERA_MAX_SN_LENGTH];
imu_params_noise_m nm;
u8 serial_number[CAMERA_MAX_SN_LENGTH];
// Radial Lens Shading Correction parameters
radial_lsc_params left_rls;
radial_lsc_params right_rls;
} LiEeprom_Content_Struct;
struct ar0234 {
struct camera_common_eeprom_data eeprom[AR0234_EEPROM_NUM_BLOCKS];
u8 eeprom_buf[AR0234_EEPROM_SIZE];
@@ -273,20 +245,17 @@ struct ar0234 {
const char *sensor_name;
NvCamSyncSensorCalibData EepromCalib;
};
static const struct regmap_config sensor_regmap_config = {
.reg_bits = 16,
.val_bits = 16,
.cache_type = REGCACHE_RBTREE,
};
static inline void ar0234_get_coarse_time_regs_shs1(ar0234_reg *regs,
u16 coarse_time)
{
regs->addr = AR0234_COARSE_TIME_SHS1_ADDR;
regs->val = (coarse_time) & 0xffff;
}
static inline void ar0234_get_gain_reg(ar0234_reg *regs,
u16 gain)
{
@@ -374,7 +343,7 @@ retry_sensor:
return -1;
} else {
if (0x301a == table[i].addr || 0x3060 == table[i].addr)
msleep(20);
msleep(100);
}
} else {
retry = 5;
@@ -585,7 +554,7 @@ static int ar0234_power_on(struct camera_common_data *s_data)
struct camera_common_power_rail *pw = s_data->power;
struct camera_common_pdata *pdata = s_data->pdata;
struct device *dev = s_data->dev;
struct ar0234 *priv = (struct ar0234 *) s_data->priv;
if (pdata && pdata->power_on) {
err = pdata->power_on(pw);
if (err)
@@ -598,6 +567,8 @@ static int ar0234_power_on(struct camera_common_data *s_data)
gpio_set_value(pw->reset_gpio, 1);
usleep_range(1000, 2000);
pw->state = SWITCH_ON;
/*i2c address trans for Hawk & Owl*/
err = ar0234_hawk_owl_i2ctrans(priv);
return err;
}
static int ar0234_power_off(struct camera_common_data *s_data)
@@ -792,10 +763,9 @@ static int ar0234_fill_eeprom(struct tegracam_device *tc_dev,
}
priv->EepromCalib.cam_extr = tmp->cam_extr;
priv->EepromCalib.imu_present = tmp->imu_present;
priv->EepromCalib.imu.imu_data_v1 = tmp->imu;
priv->EepromCalib.imu.nm = tmp->nm;
priv->EepromCalib.imu = tmp->imu;
memcpy(priv->EepromCalib.serial_number, tmp->serial_number,
8);
CAMERA_MAX_SN_LENGTH);
if (priv->sync_sensor_index == 1)
priv->EepromCalib.rls = tmp->left_rls;
@@ -907,7 +877,7 @@ static struct tegracam_ctrl_ops ar0234_ctrl_ops = {
.numctrls = ARRAY_SIZE(ctrl_cid_list),
.ctrl_cid_list = ctrl_cid_list,
.string_ctrl_size = {AR0234_EEPROM_STR_SIZE},
.compound_ctrl_size = {sizeof(NvCamSyncSensorCalibData), sizeof(struct alternating_exposure_cfg)},
.compound_ctrl_size = {sizeof(NvCamSyncSensorCalibData), alternating_exposure_cfg_size},
.set_gain = ar0234_set_gain,
.set_exposure = ar0234_set_exposure,
.set_exposure_short = ar0234_set_exposure,
@@ -1464,7 +1434,7 @@ static int ar0234_hawk_owl_deser_ser_program(struct ar0234 *priv)
return err;
}
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
static int ar0234_probe(struct i2c_client *client)
#else
static int ar0234_probe(struct i2c_client *client,
@@ -1533,14 +1503,6 @@ static int ar0234_probe(struct i2c_client *client,
dev_err(&client->dev,"Failed to enable gpio/ to do serializer i2c address trans\n");
goto un_register;
}
/* i2c address trans for Hawk & Owl */
err = ar0234_hawk_owl_i2ctrans(priv);
if (err) {
dev_err(&client->dev, "Failed to do i2c address trans\n");
goto un_register;
}
err = ar0234_power_on(tc_dev->s_data);
if (err) {
dev_err(&client->dev,"Failed to power on\n");
@@ -1610,7 +1572,7 @@ un_register:
return err;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
static int ar0234_remove(struct i2c_client *client)
#else
static void ar0234_remove(struct i2c_client *client)
@@ -1620,7 +1582,7 @@ static void ar0234_remove(struct i2c_client *client)
struct ar0234 *priv = (struct ar0234 *)s_data->priv;
if (!s_data)
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
return -EINVAL;
#else
return;
@@ -1628,7 +1590,7 @@ static void ar0234_remove(struct i2c_client *client)
tegracam_v4l2subdev_unregister(priv->tc_dev);
tegracam_device_unregister(priv->tc_dev);
ar0234_eeprom_device_release(priv);
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
return 0;
#endif
}

View File

@@ -5,8 +5,6 @@
* Copyright (c) 2016-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <nvidia/conftest.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
@@ -777,7 +775,7 @@ static const struct v4l2_subdev_internal_ops imx185_subdev_internal_ops = {
.open = imx185_open,
};
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
static int imx185_probe(struct i2c_client *client)
#else
static int imx185_probe(struct i2c_client *client,
@@ -840,11 +838,11 @@ static int imx185_probe(struct i2c_client *client,
return 0;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
static int
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
static void
imx185_remove(struct i2c_client *client)
#else
static void
static int
imx185_remove(struct i2c_client *client)
#endif
{
@@ -852,17 +850,17 @@ imx185_remove(struct i2c_client *client)
struct imx185 *priv;
if (!s_data)
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
return -EINVAL;
#else
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
return;
#else
return -EINVAL;
#endif
priv = (struct imx185 *)s_data->priv;
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 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)
return 0;
#endif
}

View File

@@ -1,12 +1,11 @@
// 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>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
@@ -692,7 +691,7 @@ static const struct v4l2_subdev_internal_ops imx219_subdev_internal_ops = {
.open = imx219_open,
};
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
static int imx219_probe(struct i2c_client *client)
#else
static int imx219_probe(struct i2c_client *client,
@@ -746,7 +745,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;
}
@@ -756,10 +754,10 @@ static int imx219_probe(struct i2c_client *client,
return 0;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
static int imx219_remove(struct i2c_client *client)
#else
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
static void imx219_remove(struct i2c_client *client)
#else
static int imx219_remove(struct i2c_client *client)
#endif
{
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
@@ -767,7 +765,7 @@ static void imx219_remove(struct i2c_client *client)
if (!s_data) {
dev_err(&client->dev, "camera common data is NULL\n");
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
return -EINVAL;
#else
return;
@@ -778,7 +776,7 @@ static void imx219_remove(struct i2c_client *client)
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 */
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
return 0;
#endif
}

View File

@@ -5,8 +5,6 @@
* Copyright (c) 2015-2023, NVIDIA CORPORATION. All rights reserved.
*/
#include <nvidia/conftest.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
@@ -1262,7 +1260,7 @@ static const struct v4l2_subdev_internal_ops imx274_subdev_internal_ops = {
.open = imx274_open,
};
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
static int imx274_probe(struct i2c_client *client)
#else
static int imx274_probe(struct i2c_client *client,
@@ -1335,20 +1333,20 @@ static int imx274_probe(struct i2c_client *client,
return 0;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
static int imx274_remove(struct i2c_client *client)
#else
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
static void imx274_remove(struct i2c_client *client)
#else
static int imx274_remove(struct i2c_client *client)
#endif
{
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
struct imx274 *priv;
if (!s_data)
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
return -EINVAL;
#else
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
return;
#else
return -EINVAL;
#endif
priv = (struct imx274 *)s_data->priv;
@@ -1360,7 +1358,7 @@ static void imx274_remove(struct i2c_client *client)
imx274_eeprom_device_release(priv);
mutex_destroy(&priv->streaming_lock);
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)
return 0;
#endif
}

View File

@@ -1,11 +1,5 @@
// SPDX-License-Identifier: GPL-2.0
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES.
// All rights reserved.
//
// nv_imx318.c - imx318 sensor driver
//
#include <nvidia/conftest.h>
// Copyright (c) 2017-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#include <linux/slab.h>
#include <linux/uaccess.h>
@@ -135,11 +129,6 @@ static int imx318_set_frame_rate_ex(struct tegracam_device *tc_dev,
u8 fl_arr[2];
int err = 0;
if (val < mode->control_properties.min_framerate)
val = mode->control_properties.min_framerate;
else if (val > mode->control_properties.max_framerate)
val = mode->control_properties.max_framerate;
if (mode->image_properties.line_length == 0 ||
val == 0) {
return -EINVAL;
@@ -706,7 +695,7 @@ static const struct v4l2_subdev_internal_ops imx318_subdev_internal_ops = {
.open = imx318_open,
};
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
static int imx318_probe(struct i2c_client *client)
#else
static int imx318_probe(struct i2c_client *client,
@@ -770,7 +759,7 @@ static int imx318_probe(struct i2c_client *client,
return 0;
}
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
static int imx318_remove(struct i2c_client *client)
#else
static void imx318_remove(struct i2c_client *client)
@@ -780,7 +769,7 @@ static void imx318_remove(struct i2c_client *client)
struct imx318 *priv;
if (!s_data)
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
return -EINVAL;
#else
return;
@@ -791,7 +780,7 @@ static void imx318_remove(struct i2c_client *client)
tegracam_device_unregister(priv->tc_dev);
imx318_eeprom_device_release(priv);
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
return 0;
#endif
}

View File

File diff suppressed because it is too large Load Diff

View File

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

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