mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-25 02:32:08 +03:00
Compare commits
5 Commits
rel-36
...
l4t/l4t-r3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4212fbd97f | ||
|
|
4e63d195c6 | ||
|
|
4ad0e0c6c8 | ||
|
|
969619a872 | ||
|
|
ad7508c52a |
25
.gitignore
vendored
25
.gitignore
vendored
@@ -1,25 +0,0 @@
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Use command 'git ls-files -i --exclude-standard' to ensure that no
|
||||
# tracked files are ignored.
|
||||
#
|
||||
*.o
|
||||
*.o.*
|
||||
*.a
|
||||
*.s
|
||||
*.ko
|
||||
*.so
|
||||
*.so.dbg
|
||||
*.mod.c
|
||||
*.i
|
||||
*.symtypes
|
||||
*.order
|
||||
*.patch
|
||||
modules.builtin
|
||||
Module.symvers
|
||||
*.dwo
|
||||
*.mod
|
||||
*.cmd
|
||||
*mods.dtb*
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
60
Makefile
60
Makefile
@@ -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
|
||||
|
||||
41
arch/arm64/boot/dts/Makefile
Normal file
41
arch/arm64/boot/dts/Makefile
Normal 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
|
||||
9
arch/arm64/boot/dts/nvidia/Makefile
Normal file
9
arch/arm64/boot/dts/nvidia/Makefile
Normal 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
|
||||
29
arch/arm64/boot/dts/nvidia/tegra194-carveouts.dts
Normal file
29
arch/arm64/boot/dts/nvidia/tegra194-carveouts.dts
Normal 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";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
157
arch/arm64/boot/dts/nvidia/tegra194-jetson.dts
Normal file
157
arch/arm64/boot/dts/nvidia/tegra194-jetson.dts
Normal 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -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";
|
||||
};
|
||||
@@ -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 = \
|
||||
|
||||
50
dkms.conf
50
dkms.conf
@@ -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"
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2023-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
@@ -804,21 +802,9 @@ static const struct of_device_id tegra_hv_vblk_oops_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, tegra_hv_vblk_oops_match);
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
|
||||
static void tegra_hv_vblk_oops_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
tegra_hv_vblk_oops_remove(pdev);
|
||||
}
|
||||
#else
|
||||
static int tegra_hv_vblk_oops_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
return tegra_hv_vblk_oops_remove(pdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct platform_driver tegra_hv_vblk_oops_driver = {
|
||||
.probe = tegra_hv_vblk_oops_probe,
|
||||
.remove = tegra_hv_vblk_oops_remove_wrapper,
|
||||
.remove = tegra_hv_vblk_oops_remove,
|
||||
.driver = {
|
||||
.name = OOPS_DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#
|
||||
# Makefile for Virtual Storage Driver
|
||||
#
|
||||
|
||||
LINUX_VERSION := $(shell expr $(VERSION) \* 256 + $(PATCHLEVEL))
|
||||
LINUX_VERSION_6_11 := $(shell expr 6 \* 256 + 11)
|
||||
|
||||
ifneq ($(NV_OOT_BLOCK_TEGRA_VIRT_STORAGE_SKIP_BUILD),y)
|
||||
# Use dummy driver for Kernel versions greater than or equal to Linux v6.11
|
||||
ifeq ($(shell test $(LINUX_VERSION) -lt $(LINUX_VERSION_6_11); echo $$?),0)
|
||||
tegra_vblk-y += tegra_hv_vblk.o
|
||||
tegra_vblk-y += tegra_hv_ioctl.o
|
||||
tegra_vblk-y += tegra_hv_mmc.o
|
||||
tegra_vblk-y += tegra_hv_scsi.o
|
||||
tegra_vblk-y += tegra_hv_ufs.o
|
||||
obj-m += tegra_vblk.o
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h> /* printk() */
|
||||
#include <linux/vmalloc.h> /* kmalloc() */
|
||||
#include <linux/slab.h> /* kmalloc() */
|
||||
#include <linux/fs.h> /* everything... */
|
||||
#include <linux/errno.h> /* error codes */
|
||||
#include <linux/fcntl.h> /* O_ACCMODE */
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/vmalloc.h> /* kmalloc() */
|
||||
#include <linux/slab.h> /* kmalloc() */
|
||||
#include <linux/errno.h> /* error codes */
|
||||
#include <linux/delay.h> /* For msleep and usleep_range */
|
||||
#include <uapi/scsi/ufs/ioctl.h>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
@@ -145,11 +147,7 @@ static void vblk_put_req(struct vsc_request *req)
|
||||
(vblkdev->queue_state == VBLK_QUEUE_SUSPENDED)) {
|
||||
complete(&vblkdev->req_queue_empty);
|
||||
}
|
||||
#if defined(NV_TIMER_DELETE_PRESENT) /* Linux v6.15 */
|
||||
timer_delete(&req->timer);
|
||||
#else
|
||||
del_timer(&req->timer);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -538,12 +536,8 @@ static bool submit_bio_req(struct vblk_dev *vblkdev)
|
||||
}
|
||||
sg_init_table(vsc_req->sg_lst,
|
||||
bio_req->nr_phys_segments);
|
||||
#if defined(NV_BLK_RQ_MAP_SG_HAS_NO_QUEUE_ARG) /* Linux v6.15 */
|
||||
sg_cnt = blk_rq_map_sg(bio_req, vsc_req->sg_lst);
|
||||
#else
|
||||
sg_cnt = blk_rq_map_sg(vblkdev->queue, bio_req,
|
||||
vsc_req->sg_lst);
|
||||
#endif
|
||||
vsc_req->sg_num_ents = sg_nents(vsc_req->sg_lst);
|
||||
if (dma_map_sg(vblkdev->device, vsc_req->sg_lst,
|
||||
vsc_req->sg_num_ents, DMA_BIDIRECTIONAL) == 0) {
|
||||
@@ -1003,11 +997,7 @@ static void setup_device(struct vblk_dev *vblkdev)
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
#if defined(NV_BLK_MQ_ALLOC_QUEUE_PRESENT)
|
||||
vblkdev->queue = blk_mq_alloc_queue(&vblkdev->tag_set, NULL, NULL);
|
||||
#else
|
||||
vblkdev->queue = blk_mq_init_queue(&vblkdev->tag_set);
|
||||
#endif
|
||||
if (IS_ERR(vblkdev->queue)) {
|
||||
dev_err(vblkdev->device, "failed to init blk queue\n");
|
||||
blk_mq_free_tag_set(&vblkdev->tag_set);
|
||||
@@ -1172,9 +1162,7 @@ static void setup_device(struct vblk_dev *vblkdev)
|
||||
|
||||
vblkdev->max_requests = max_requests;
|
||||
vblkdev->max_ioctl_requests = max_ioctl_requests;
|
||||
#if defined(NV_BLK_QUEUE_MAX_HW_SECTORS_PRESENT) /* Removed in Linux v6.10 */
|
||||
blk_queue_max_hw_sectors(vblkdev->queue, max_io_bytes / SECTOR_SIZE);
|
||||
#endif
|
||||
blk_queue_flag_set(QUEUE_FLAG_NONROT, vblkdev->queue);
|
||||
|
||||
if ((vblkdev->config.blk_config.req_ops_supported & VS_BLK_SECURE_ERASE_OP_F)
|
||||
@@ -1571,21 +1559,9 @@ static struct of_device_id tegra_hv_vblk_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, tegra_hv_vblk_match);
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
|
||||
static void tegra_hv_vblk_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
tegra_hv_vblk_remove(pdev);
|
||||
}
|
||||
#else
|
||||
static int tegra_hv_vblk_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
return tegra_hv_vblk_remove(pdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct platform_driver tegra_hv_vblk_driver = {
|
||||
.probe = tegra_hv_vblk_probe,
|
||||
.remove = tegra_hv_vblk_remove_wrapper,
|
||||
.remove = tegra_hv_vblk_remove,
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m := rtk_btusb.o
|
||||
rtk_btusb-y = rtk_coex.o rtk_misc.o rtk_bt.o
|
||||
else
|
||||
PWD := $(shell pwd)
|
||||
KVER := $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) modules
|
||||
|
||||
clean:
|
||||
rm -rf *.o *.mod.c *.mod.o *.ko *.symvers *.order *.a
|
||||
|
||||
endif
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
CONFIG_BTUSB_AUTOSUSPEND = n
|
||||
CONFIG_BTUSB_WAKEUP_HOST = n
|
||||
CONFIG_BTCOEX = y
|
||||
|
||||
ifeq ($(CONFIG_BTUSB_AUTOSUSPEND), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_BTUSB_AUTOSUSPEND
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BTUSB_WAKEUP_HOST), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_BTUSB_WAKEUP_HOST
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BTCOEX), y)
|
||||
EXTRA_CFLAGS += -DCONFIG_BTCOEX
|
||||
endif
|
||||
|
||||
obj-m := rtk_btusb.o
|
||||
rtk_btusb-objs := rtk_coex.o \
|
||||
rtk_misc.o \
|
||||
rtk_bt.o
|
||||
|
||||
@@ -1,22 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
*
|
||||
* Realtek Bluetooth USB driver
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@@ -31,11 +17,12 @@
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <net/sock.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "rtk_bt.h"
|
||||
#include "rtk_misc.h"
|
||||
|
||||
#define VERSION "3.1.65ab490.20240531-141726"
|
||||
#define VERSION "3.1.6fd4e69.20220818-105856"
|
||||
|
||||
#ifdef BTCOEX
|
||||
#include "rtk_coex.h"
|
||||
@@ -48,64 +35,95 @@ static DEFINE_SEMAPHORE(switch_sem);
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 7, 1)
|
||||
static bool reset = true;
|
||||
static bool reset = 0;
|
||||
#endif
|
||||
|
||||
static struct usb_driver btusb_driver;
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
static u16 iso_min_conn_handle = 0x1b;
|
||||
#endif
|
||||
|
||||
static const struct usb_device_id btusb_table[] = {
|
||||
/* Generic Bluetooth USB device */
|
||||
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
|
||||
|
||||
/* Generic Bluetooth USB interface */
|
||||
{ USB_INTERFACE_INFO(0xe0, 0x01, 0x01) },
|
||||
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct usb_device_id blacklist_table[] = {
|
||||
static struct usb_device_id btusb_table[] = {
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x0bda,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x13d3,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x0489,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x1358,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x04ca,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x2ff8,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x0b05,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x0930,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x10ec,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x04c5,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x0cb5,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = 0x0cb8,
|
||||
}, {
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR,
|
||||
.idVendor = 0x04b8,
|
||||
.bInterfaceClass = 0xe0,
|
||||
.bInterfaceSubClass = 0x01,
|
||||
.bInterfaceProtocol = 0x01
|
||||
}, { }
|
||||
};
|
||||
|
||||
@@ -130,6 +148,20 @@ static struct btusb_data *rtk_alloc(struct usb_interface *intf)
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, btusb_table);
|
||||
|
||||
static int inc_tx(struct btusb_data *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
int rv;
|
||||
|
||||
spin_lock_irqsave(&data->txlock, flags);
|
||||
rv = test_bit(BTUSB_SUSPENDING, &data->flags);
|
||||
if (!rv)
|
||||
data->tx_in_flight++;
|
||||
spin_unlock_irqrestore(&data->txlock, flags);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
static inline void btusb_free_frags(struct btusb_data *data)
|
||||
{
|
||||
@@ -172,11 +204,7 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
|
||||
}
|
||||
|
||||
len = min_t(uint, bt_cb(skb)->expect, count);
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||
skb_put_data(skb, buffer, len);
|
||||
#else
|
||||
memcpy(skb_put(skb, len), buffer, len);
|
||||
#endif
|
||||
|
||||
count -= len;
|
||||
buffer += len;
|
||||
@@ -231,26 +259,15 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
|
||||
}
|
||||
|
||||
len = min_t(uint, bt_cb(skb)->expect, count);
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||
skb_put_data(skb, buffer, len);
|
||||
#else
|
||||
memcpy(skb_put(skb, len), buffer, len);
|
||||
#endif
|
||||
|
||||
count -= len;
|
||||
buffer += len;
|
||||
bt_cb(skb)->expect -= len;
|
||||
|
||||
if (skb->len == HCI_ACL_HDR_SIZE) {
|
||||
struct hci_acl_hdr *h = hci_acl_hdr(skb);
|
||||
__le16 dlen = h->dlen;
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
__u16 handle = __le16_to_cpu(h->handle) & 0xfff;
|
||||
__le16 dlen = hci_acl_hdr(skb)->dlen;
|
||||
|
||||
if(handle >= iso_min_conn_handle) {
|
||||
bt_cb(skb)->pkt_type = HCI_ISODATA_PKT;
|
||||
}
|
||||
#endif
|
||||
/* Complete ACL header */
|
||||
bt_cb(skb)->expect = __le16_to_cpu(dlen);
|
||||
|
||||
@@ -276,42 +293,10 @@ static int btusb_recv_bulk(struct btusb_data *data, void *buffer, int count)
|
||||
return err;
|
||||
}
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
static int btrtl_usb_recv_isoc(u16 pos, u8 *data, u8 *p, int len,
|
||||
u16 wMaxPacketSize)
|
||||
{
|
||||
u8 *prev;
|
||||
|
||||
if (pos >= HCI_SCO_HDR_SIZE && pos >= wMaxPacketSize &&
|
||||
len == wMaxPacketSize && !(pos % wMaxPacketSize) &&
|
||||
wMaxPacketSize >= 10 && p[0] == data[0] && p[1] == data[1]) {
|
||||
|
||||
prev = data + (pos - wMaxPacketSize);
|
||||
|
||||
/* Detect the sco data of usb isoc pkt duplication. */
|
||||
if (!memcmp(p + 2, prev + 2, 8))
|
||||
return -EILSEQ;
|
||||
|
||||
if (wMaxPacketSize >= 12 &&
|
||||
p[2] == prev[6] && p[3] == prev[7] &&
|
||||
p[4] == prev[4] && p[5] == prev[5] &&
|
||||
p[6] == prev[10] && p[7] == prev[11] &&
|
||||
p[8] == prev[8] && p[9] == prev[9]) {
|
||||
return -EILSEQ;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int err = 0;
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
u16 wMaxPacketSize = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize);
|
||||
#endif
|
||||
|
||||
spin_lock(&data->rxlock);
|
||||
skb = data->sco_skb;
|
||||
@@ -331,24 +316,7 @@ static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
|
||||
}
|
||||
|
||||
len = min_t(uint, bt_cb(skb)->expect, count);
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
/* Gaps in audio could be heard while streaming WBS using USB
|
||||
* alt settings 3 on some platforms.
|
||||
* Add the function to detect it.
|
||||
*/
|
||||
if (test_bit(BTUSB_USE_ALT3_FOR_WBS, &data->flags)) {
|
||||
err = btrtl_usb_recv_isoc(skb->len, skb->data, buffer,
|
||||
len, wMaxPacketSize);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||
skb_put_data(skb, buffer, len);
|
||||
#else
|
||||
memcpy(skb_put(skb, len), buffer, len);
|
||||
#endif
|
||||
|
||||
count -= len;
|
||||
buffer += len;
|
||||
@@ -379,21 +347,6 @@ static int btusb_recv_isoc(struct btusb_data *data, void *buffer, int count)
|
||||
|
||||
return err;
|
||||
}
|
||||
#else
|
||||
static int inc_tx(struct btusb_data *data)
|
||||
{
|
||||
unsigned long flags;
|
||||
int rv;
|
||||
|
||||
spin_lock_irqsave(&data->txlock, flags);
|
||||
rv = test_bit(BTUSB_SUSPENDING, &data->flags);
|
||||
if (!rv)
|
||||
data->tx_in_flight++;
|
||||
spin_unlock_irqrestore(&data->txlock, flags);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void btusb_intr_complete(struct urb *urb)
|
||||
@@ -673,51 +626,6 @@ retry:
|
||||
}
|
||||
}
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
static inline void __fill_isoc_descriptor_msbc(struct urb *urb, int len,
|
||||
int mtu, struct btusb_data *data)
|
||||
{
|
||||
int i = 0, offset = 0;
|
||||
unsigned int interval;
|
||||
|
||||
BT_DBG("len %d mtu %d", len, mtu);
|
||||
|
||||
/* For mSBC ALT 6 settings some Realtek chips need to transmit the data
|
||||
* continuously without the zero length of USB packets.
|
||||
*/
|
||||
if (btrealtek_test_flag(data->hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP))
|
||||
goto ignore_usb_alt6_packet_flow;
|
||||
|
||||
/* For mSBC ALT 6 setting the host will send the packet at continuous
|
||||
* flow. As per core spec 5, vol 4, part B, table 2.1. For ALT setting
|
||||
* 6 the HCI PACKET INTERVAL should be 7.5ms for every usb packets.
|
||||
* To maintain the rate we send 63bytes of usb packets alternatively for
|
||||
* 7ms and 8ms to maintain the rate as 7.5ms.
|
||||
*/
|
||||
if (data->usb_alt6_packet_flow) {
|
||||
interval = 7;
|
||||
data->usb_alt6_packet_flow = false;
|
||||
} else {
|
||||
interval = 6;
|
||||
data->usb_alt6_packet_flow = true;
|
||||
}
|
||||
|
||||
for (i = 0; i < interval; i++) {
|
||||
urb->iso_frame_desc[i].offset = offset;
|
||||
urb->iso_frame_desc[i].length = offset;
|
||||
}
|
||||
|
||||
ignore_usb_alt6_packet_flow:
|
||||
if (len && i < BTUSB_MAX_ISOC_FRAMES) {
|
||||
urb->iso_frame_desc[i].offset = offset;
|
||||
urb->iso_frame_desc[i].length = len;
|
||||
i++;
|
||||
}
|
||||
|
||||
urb->number_of_packets = i;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void __fill_isoc_descriptor(struct urb *urb, int len, int mtu)
|
||||
{
|
||||
int i, offset = 0;
|
||||
@@ -767,12 +675,6 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
|
||||
|
||||
pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress);
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 2, 14)
|
||||
usb_fill_int_urb(urb, data->udev, pipe, buf, size, btusb_isoc_complete,
|
||||
hdev, data->isoc_rx_ep->bInterval);
|
||||
|
||||
urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP;
|
||||
#else
|
||||
urb->dev = data->udev;
|
||||
urb->pipe = pipe;
|
||||
urb->context = hdev;
|
||||
@@ -782,7 +684,6 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
|
||||
urb->transfer_flags = URB_FREE_BUFFER | URB_ISO_ASAP;
|
||||
urb->transfer_buffer = buf;
|
||||
urb->transfer_buffer_length = size;
|
||||
#endif
|
||||
|
||||
__fill_isoc_descriptor(urb, size,
|
||||
le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize));
|
||||
@@ -833,8 +734,8 @@ static void btusb_isoc_tx_complete(struct urb *urb)
|
||||
struct sk_buff *skb = urb->context;
|
||||
struct hci_dev *hdev = (struct hci_dev *)skb->dev;
|
||||
|
||||
RTKBT_DBG("%s: urb %p status %d count %d", __func__,
|
||||
urb, urb->status, urb->actual_length);
|
||||
RTKBT_DBG("%s: urb %p status %d count %d",__func__,
|
||||
urb, urb->status, urb->actual_length);
|
||||
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags))
|
||||
goto done;
|
||||
@@ -850,49 +751,6 @@ done:
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
static int rtl_read_iso_handle_range(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct __rp {
|
||||
u8 status;
|
||||
u8 min_handle[2];
|
||||
} *rp;
|
||||
int ret = -EIO;
|
||||
|
||||
skb = __hci_cmd_sync(hdev, 0xfdab, 0, NULL, HCI_CMD_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
return PTR_ERR(skb);
|
||||
}
|
||||
|
||||
/* FIXME: if the return status is not zero, __hci_cmd_sync() would
|
||||
* return an error and we would not reach here.
|
||||
*/
|
||||
if (skb->data[0]) {
|
||||
RTKBT_ERR("%s: Read failed, status %0x", hdev->name,
|
||||
skb->data[0]);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (skb->len < sizeof(*rp)) {
|
||||
RTKBT_WARN("%s: The len %u of rp is too short", __func__,
|
||||
skb->len);
|
||||
goto err;
|
||||
}
|
||||
|
||||
rp = (void *)skb->data;
|
||||
iso_min_conn_handle = (u16)rp->min_handle[1] << 8 | rp->min_handle[0];
|
||||
RTKBT_DBG("ISO handle range (handle >= %04x)", iso_min_conn_handle);
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
err:
|
||||
kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int btusb_open(struct hci_dev *hdev)
|
||||
{
|
||||
struct btusb_data *data = GET_DRV_DATA(hdev);
|
||||
@@ -917,10 +775,6 @@ static int btusb_open(struct hci_dev *hdev)
|
||||
goto failed;
|
||||
/*******************************/
|
||||
|
||||
err = setup_btrealtek_flag(data->intf, hdev);
|
||||
if (err < 0)
|
||||
RTKBT_WARN("setup_btrealtek_flag incorrect!");
|
||||
|
||||
RTKBT_INFO("%s set HCI UP RUNNING", __func__);
|
||||
if (test_and_set_bit(HCI_UP, &hdev->flags))
|
||||
goto done;
|
||||
@@ -963,32 +817,6 @@ failed:
|
||||
return err;
|
||||
}
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
static int btusb_setup(struct hci_dev *hdev)
|
||||
{
|
||||
rtl_read_iso_handle_range(hdev);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
|
||||
static int btusb_shutdown(struct hci_dev *hdev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int ret;
|
||||
|
||||
skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
|
||||
if (IS_ERR(skb)) {
|
||||
ret = PTR_ERR(skb);
|
||||
bt_dev_err(hdev, "HCI reset during shutdown failed");
|
||||
return ret;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void btusb_stop_traffic(struct btusb_data *data)
|
||||
{
|
||||
mdelay(URB_CANCELING_DELAY_MS); // Added by Realtek
|
||||
@@ -1092,152 +920,8 @@ static const char pkt_ind[][8] = {
|
||||
[HCI_COMMAND_PKT] = "cmd",
|
||||
[HCI_ACLDATA_PKT] = "acl",
|
||||
[HCI_SCODATA_PKT] = "sco",
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
[HCI_ISODATA_PKT] = "iso",
|
||||
#endif
|
||||
};
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
static struct urb *alloc_ctrl_urb(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct usb_ctrlrequest *dr;
|
||||
struct urb *urb;
|
||||
unsigned int pipe;
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
dr = kmalloc(sizeof(*dr), GFP_KERNEL);
|
||||
if (!dr) {
|
||||
usb_free_urb(urb);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
dr->bRequestType = data->cmdreq_type;
|
||||
dr->bRequest = 0;
|
||||
dr->wIndex = 0;
|
||||
dr->wValue = 0;
|
||||
dr->wLength = __cpu_to_le16(skb->len);
|
||||
|
||||
pipe = usb_sndctrlpipe(data->udev, 0x00);
|
||||
|
||||
usb_fill_control_urb(urb, data->udev, pipe, (void *)dr,
|
||||
skb->data, skb->len, btusb_tx_complete, skb);
|
||||
|
||||
skb->dev = (void *)hdev;
|
||||
|
||||
return urb;
|
||||
}
|
||||
|
||||
static struct urb *alloc_bulk_urb(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct urb *urb;
|
||||
unsigned int pipe;
|
||||
|
||||
if (!data->bulk_tx_ep)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!urb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pipe = usb_sndbulkpipe(data->udev, data->bulk_tx_ep->bEndpointAddress);
|
||||
|
||||
usb_fill_bulk_urb(urb, data->udev, pipe,
|
||||
skb->data, skb->len, btusb_tx_complete, skb);
|
||||
|
||||
skb->dev = (void *)hdev;
|
||||
|
||||
return urb;
|
||||
}
|
||||
|
||||
static struct urb *alloc_isoc_urb(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
struct urb *urb;
|
||||
unsigned int pipe;
|
||||
|
||||
if (!data->isoc_tx_ep)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL);
|
||||
if (!urb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pipe = usb_sndisocpipe(data->udev, data->isoc_tx_ep->bEndpointAddress);
|
||||
|
||||
usb_fill_int_urb(urb, data->udev, pipe,
|
||||
skb->data, skb->len, btusb_isoc_tx_complete,
|
||||
skb, data->isoc_tx_ep->bInterval);
|
||||
|
||||
urb->transfer_flags = URB_ISO_ASAP;
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
if (data->isoc_altsetting == 6)
|
||||
__fill_isoc_descriptor_msbc(urb, skb->len,
|
||||
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize),
|
||||
data);
|
||||
else
|
||||
__fill_isoc_descriptor(urb, skb->len,
|
||||
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
|
||||
#else
|
||||
__fill_isoc_descriptor(urb, skb->len,
|
||||
le16_to_cpu(data->isoc_tx_ep->wMaxPacketSize));
|
||||
#endif
|
||||
|
||||
skb->dev = (void *)hdev;
|
||||
|
||||
return urb;
|
||||
}
|
||||
|
||||
static int submit_tx_urb(struct hci_dev *hdev, struct urb *urb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
int err;
|
||||
|
||||
usb_anchor_urb(urb, &data->tx_anchor);
|
||||
|
||||
err = usb_submit_urb(urb, GFP_KERNEL);
|
||||
if (err < 0) {
|
||||
if (err != -EPERM && err != -ENODEV)
|
||||
RTKBT_ERR("%s urb %p submission failed (%d)",
|
||||
hdev->name, urb, -err);
|
||||
kfree(urb->setup_packet);
|
||||
usb_unanchor_urb(urb);
|
||||
} else {
|
||||
usb_mark_last_busy(data->udev);
|
||||
}
|
||||
|
||||
usb_free_urb(urb);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int submit_or_queue_tx_urb(struct hci_dev *hdev, struct urb *urb)
|
||||
{
|
||||
struct btusb_data *data = hci_get_drvdata(hdev);
|
||||
unsigned long flags;
|
||||
bool suspending;
|
||||
|
||||
spin_lock_irqsave(&data->txlock, flags);
|
||||
suspending = test_bit(BTUSB_SUSPENDING, &data->flags);
|
||||
if (!suspending)
|
||||
data->tx_in_flight++;
|
||||
spin_unlock_irqrestore(&data->txlock, flags);
|
||||
|
||||
if (!suspending)
|
||||
return submit_tx_urb(hdev, urb);
|
||||
|
||||
usb_anchor_urb(urb, &data->deferred);
|
||||
schedule_work(&data->waker);
|
||||
|
||||
usb_free_urb(urb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
|
||||
int btusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
@@ -1247,20 +931,14 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
struct hci_dev *hdev = (struct hci_dev *)skb->dev;
|
||||
#endif
|
||||
|
||||
struct urb *urb;
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
|
||||
struct btusb_data *data = GET_DRV_DATA(hdev);
|
||||
struct usb_ctrlrequest *dr;
|
||||
struct urb *urb;
|
||||
unsigned int pipe;
|
||||
int err;
|
||||
#endif
|
||||
|
||||
// RTKBT_DBG("%s", hdev->name);
|
||||
//RTKBT_DBG("%s", hdev->name);
|
||||
|
||||
/* After Kernel version 4.4.0, move the check into the
|
||||
* hci_send_frame function before calling hdev->send
|
||||
*/
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(4, 4, 0)
|
||||
if (!test_bit(HCI_RUNNING, &hdev->flags)) {
|
||||
/* If the parameter is wrong, the hdev isn't the correct
|
||||
* one. Then no HCI commands can be sent.
|
||||
@@ -1268,15 +946,13 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
RTKBT_ERR("HCI is not running");
|
||||
return -EBUSY;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Before kernel/hci version 3.13.0, the skb->dev is set before
|
||||
* entering btusb_send_frame(). So there is no need to set it here.
|
||||
*
|
||||
* The skb->dev will be used in the callbacks when urb transfer
|
||||
* completes. See btusb_tx_complete() and btusb_isoc_tx_complete() */
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) && \
|
||||
HCI_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
|
||||
skb->dev = (void *)hdev;
|
||||
#endif
|
||||
|
||||
@@ -1287,14 +963,6 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
#ifdef BTCOEX
|
||||
rtk_btcoex_parse_cmd(skb->data, skb->len);
|
||||
#endif
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
urb = alloc_ctrl_urb(hdev, skb);
|
||||
if (IS_ERR(urb))
|
||||
return PTR_ERR(urb);
|
||||
|
||||
hdev->stat.cmd_tx++;
|
||||
return submit_or_queue_tx_urb(hdev, urb);
|
||||
#else
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
if (!urb)
|
||||
return -ENOMEM;
|
||||
@@ -1320,24 +988,11 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
hdev->stat.cmd_tx++;
|
||||
break;
|
||||
|
||||
#endif
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
case HCI_ISODATA_PKT:
|
||||
#endif
|
||||
case HCI_ACLDATA_PKT:
|
||||
print_acl(skb, 1);
|
||||
#ifdef BTCOEX
|
||||
if(bt_cb(skb)->pkt_type == HCI_ACLDATA_PKT)
|
||||
rtk_btcoex_parse_l2cap_data_tx(skb->data, skb->len);
|
||||
rtk_btcoex_parse_l2cap_data_tx(skb->data, skb->len);
|
||||
#endif
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
urb = alloc_bulk_urb(hdev, skb);
|
||||
if (IS_ERR(urb))
|
||||
return PTR_ERR(urb);
|
||||
|
||||
hdev->stat.acl_tx++;
|
||||
return submit_or_queue_tx_urb(hdev, urb);
|
||||
#else
|
||||
if (!data->bulk_tx_ep)
|
||||
return -ENODEV;
|
||||
|
||||
@@ -1354,22 +1009,7 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
hdev->stat.acl_tx++;
|
||||
break;
|
||||
|
||||
#endif
|
||||
case HCI_SCODATA_PKT:
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)
|
||||
if (hci_conn_num(hdev, SCO_LINK) < 1)
|
||||
return -ENODEV;
|
||||
|
||||
urb = alloc_isoc_urb(hdev, skb);
|
||||
if (IS_ERR(urb))
|
||||
return PTR_ERR(urb);
|
||||
|
||||
hdev->stat.sco_tx++;
|
||||
return submit_tx_urb(hdev, urb);
|
||||
}
|
||||
|
||||
return -EILSEQ;
|
||||
#else
|
||||
if (!data->isoc_tx_ep || SCO_NUM < 1)
|
||||
return -ENODEV;
|
||||
|
||||
@@ -1395,7 +1035,6 @@ int btusb_send_frame(struct sk_buff *skb)
|
||||
|
||||
default:
|
||||
return -EILSEQ;
|
||||
|
||||
}
|
||||
|
||||
err = inc_tx(data);
|
||||
@@ -1418,14 +1057,12 @@ skip_waking:
|
||||
} else {
|
||||
usb_mark_last_busy(data->udev);
|
||||
}
|
||||
usb_free_urb(urb);
|
||||
|
||||
done:
|
||||
usb_free_urb(urb);
|
||||
return err;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 4, 0)
|
||||
static void btusb_destruct(struct hci_dev *hdev)
|
||||
{
|
||||
@@ -1544,9 +1181,6 @@ static struct usb_host_interface *btusb_find_altsetting(struct btusb_data *data,
|
||||
|
||||
BT_DBG("Looking for Alt no :%d", alt);
|
||||
|
||||
if (!intf)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < intf->num_altsetting; i++) {
|
||||
if (intf->altsetting[i].desc.bAlternateSetting == alt)
|
||||
return &intf->altsetting[i];
|
||||
@@ -1587,14 +1221,7 @@ static void btusb_work(struct work_struct *work)
|
||||
new_alts = data->sco_num;
|
||||
}
|
||||
} else if (data->air_mode == HCI_NOTIFY_ENABLE_SCO_TRANSP) {
|
||||
if (btusb_find_altsetting(data, 6))
|
||||
new_alts = 6;
|
||||
else if (btusb_find_altsetting(data, 3) &&
|
||||
hdev->sco_mtu >= 72 &&
|
||||
test_bit(BTUSB_USE_ALT3_FOR_WBS, &data->flags))
|
||||
new_alts = 3;
|
||||
else
|
||||
new_alts = 1;
|
||||
new_alts = btusb_find_altsetting(data, 6) ? 6 : 1;
|
||||
}
|
||||
|
||||
if (btusb_switch_alt_setting(hdev, new_alts) < 0)
|
||||
@@ -1794,7 +1421,7 @@ static int rtkbt_pm_notify(struct notifier_block *notifier,
|
||||
result = __rtk_send_hci_cmd(udev, cmd, 3);
|
||||
kfree(cmd);
|
||||
msleep(100); /* From FW colleague's recommendation */
|
||||
result = download_special_patch(intf, "lps_");
|
||||
result = download_lps_patch(intf);
|
||||
#endif
|
||||
|
||||
#ifdef RTKBT_TV_POWERON_WHITELIST
|
||||
@@ -1913,23 +1540,13 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
struct usb_device *udev;
|
||||
udev = interface_to_usbdev(intf);
|
||||
|
||||
RTKBT_INFO("btusb_probe intf->cur_altsetting->desc.bInterfaceNumber %d",
|
||||
RTKBT_DBG("btusb_probe intf->cur_altsetting->desc.bInterfaceNumber %d",
|
||||
intf->cur_altsetting->desc.bInterfaceNumber);
|
||||
|
||||
/* interface numbers are hardcoded in the spec */
|
||||
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
|
||||
return -ENODEV;
|
||||
|
||||
if (!id->driver_info) {
|
||||
const struct usb_device_id *match;
|
||||
|
||||
match = usb_match_id(intf, blacklist_table);
|
||||
if (match)
|
||||
id = match;
|
||||
else
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*******************************/
|
||||
flag1 = device_can_wakeup(&udev->dev);
|
||||
flag2 = device_may_wakeup(&udev->dev);
|
||||
@@ -2019,13 +1636,6 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
hdev->flush = btusb_flush;
|
||||
hdev->send = btusb_send_frame;
|
||||
hdev->notify = btusb_notify;
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
hdev->setup = btusb_setup;
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
|
||||
hdev->shutdown = btusb_shutdown;
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
|
||||
hci_set_drvdata(hdev, data);
|
||||
@@ -2035,14 +1645,10 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
hdev->owner = THIS_MODULE;
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
set_bit(BTUSB_USE_ALT3_FOR_WBS, &data->flags);
|
||||
set_bit(HCI_QUIRK_WIDEBAND_SPEECH_SUPPORTED, &hdev->quirks);
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(3, 7, 1)
|
||||
if (!reset)
|
||||
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
|
||||
RTKBT_DBG("set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);");
|
||||
#endif
|
||||
|
||||
/* Interface numbers are hardcoded in the specification */
|
||||
|
||||
@@ -1,23 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
*
|
||||
* Realtek Bluetooth USB driver
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#ifndef __RTK_BT_H__
|
||||
#define __RTK_BT_H__
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -41,17 +30,14 @@
|
||||
/* #define HCI_VERSION_CODE KERNEL_VERSION(3, 14, 41) */
|
||||
#define HCI_VERSION_CODE LINUX_VERSION_CODE
|
||||
|
||||
#define CONFIG_BTCOEX 1
|
||||
#define CONFIG_BTUSB_WAKEUP_HOST 0
|
||||
|
||||
#if CONFIG_BTCOEX
|
||||
#ifdef CONFIG_BTCOEX
|
||||
#define BTCOEX
|
||||
#endif
|
||||
|
||||
/***********************************
|
||||
** Realtek - For rtk_btusb driver **
|
||||
***********************************/
|
||||
#if CONFIG_BTUSB_WAKEUP_HOST
|
||||
#ifdef CONFIG_BTUSB_WAKEUP_HOST
|
||||
#define BTUSB_WAKEUP_HOST
|
||||
#endif
|
||||
|
||||
@@ -98,7 +84,6 @@ int btusb_send_frame(struct sk_buff *skb);
|
||||
#define BTUSB_ISOC_RUNNING 2
|
||||
#define BTUSB_SUSPENDING 3
|
||||
#define BTUSB_DID_ISO_RESUME 4
|
||||
#define BTUSB_USE_ALT3_FOR_WBS 15
|
||||
|
||||
struct btusb_data {
|
||||
struct hci_dev *hdev;
|
||||
@@ -140,7 +125,6 @@ struct btusb_data {
|
||||
|
||||
#if HCI_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
unsigned int air_mode;
|
||||
bool usb_alt6_packet_flow;
|
||||
#endif
|
||||
int isoc_altsetting;
|
||||
int suspend_count;
|
||||
@@ -152,3 +136,6 @@ struct btusb_data {
|
||||
struct notifier_block shutdown_notifier;
|
||||
void *context;
|
||||
};
|
||||
|
||||
|
||||
#endif /* __RTK_BT_H__ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
*
|
||||
* Realtek Bluetooth USB driver
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#ifndef __RTK_COEX_H__
|
||||
#define __RTK_COEX_H__
|
||||
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
@@ -49,13 +38,6 @@
|
||||
#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03
|
||||
#define HCI_EV_LE_ENHANCED_CONN_COMPLETE 0x0a
|
||||
|
||||
#define HCI_EV_LE_CIS_EST 0x19
|
||||
#define HCI_EV_LE_CREATE_BIG_CPL 0x1b
|
||||
#define HCI_EV_LE_TERM_BIG_CPL 0x1c
|
||||
#define HCI_EV_LE_BIG_SYNC_EST 0x1d
|
||||
#define HCI_EV_LE_BIG_SYNC_LOST 0x1e
|
||||
#define HCI_EV_LE_REMOVE_ISO_DATA_PATH 0x23
|
||||
|
||||
//vendor cmd to fw
|
||||
#define HCI_VENDOR_ENABLE_PROFILE_REPORT_COMMAND 0xfc18
|
||||
#define HCI_VENDOR_SET_PROFILE_REPORT_LEGACY_COMMAND 0xfc19
|
||||
@@ -158,11 +140,7 @@ enum {
|
||||
profile_hogp = 5,
|
||||
profile_voice = 6,
|
||||
profile_sink = 7,
|
||||
profile_lea_src = 8,
|
||||
profile_opprx = 9,
|
||||
profile_lea_snk = 10,
|
||||
profile_a2dpsink = 11,
|
||||
profile_max = 12
|
||||
profile_max = 8
|
||||
};
|
||||
|
||||
#define A2DP_SIGNAL 0x01
|
||||
@@ -181,10 +159,7 @@ typedef struct {
|
||||
//profile info for each connection
|
||||
typedef struct rtl_hci_conn {
|
||||
struct list_head list;
|
||||
u16 big_handle;
|
||||
u16 handle;
|
||||
u8 direction;
|
||||
u8 remove_path;
|
||||
uint16_t handle;
|
||||
struct delayed_work a2dp_count_work;
|
||||
struct delayed_work pan_count_work;
|
||||
struct delayed_work hogp_count_work;
|
||||
@@ -195,7 +170,7 @@ typedef struct rtl_hci_conn {
|
||||
uint8_t type; // 0:l2cap, 1:sco/esco, 2:le
|
||||
uint16_t profile_bitmap;
|
||||
uint16_t profile_status;
|
||||
int8_t profile_refcount[profile_max];
|
||||
int8_t profile_refcount[8];
|
||||
} rtk_conn_prof, *prtk_conn_prof;
|
||||
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
@@ -229,40 +204,21 @@ struct rtl_btinfo_ctl {
|
||||
};
|
||||
#endif /* RTB_SOFTWARE_MAILBOX */
|
||||
|
||||
#define HCI_PT_CMD 0x01
|
||||
#define HCI_PT_EVT 0x02
|
||||
#define HCI_PT_L2SIG_RX 0x03
|
||||
#define HCI_PT_L2SIG_TX 0x04
|
||||
#define HCI_PT_L2DATA_RX 0x05
|
||||
#define HCI_PT_L2DATA_TX 0x06
|
||||
|
||||
struct rtl_hci_hdr {
|
||||
struct list_head list;
|
||||
u8 type;
|
||||
u16 len;
|
||||
};
|
||||
|
||||
#define MAX_LEN_OF_HCI_EV 32
|
||||
#define NUM_RTL_HCI_EV 32
|
||||
struct rtl_hci_ev {
|
||||
struct list_head list;
|
||||
u8 type;
|
||||
u16 len;
|
||||
|
||||
/* private */
|
||||
__u8 data[MAX_LEN_OF_HCI_EV];
|
||||
__u16 len;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
#define L2_MAX_SUBSEC_LEN 128
|
||||
#define L2_MAX_PKTS 16
|
||||
struct rtl_l2_buff {
|
||||
struct list_head list;
|
||||
u8 type;
|
||||
u16 len;
|
||||
|
||||
/* private */
|
||||
__u8 data[L2_MAX_SUBSEC_LEN];
|
||||
__u16 len;
|
||||
__u16 out;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct rtl_coex_struct {
|
||||
@@ -280,18 +236,18 @@ struct rtl_coex_struct {
|
||||
struct delayed_work sock_work;
|
||||
#endif
|
||||
struct workqueue_struct *fw_wq;
|
||||
struct workqueue_struct *timer_wq;
|
||||
struct delayed_work fw_work;
|
||||
struct delayed_work cmd_work;
|
||||
struct delayed_work l2_work;
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
struct sock *sk;
|
||||
#endif
|
||||
struct urb *urb;
|
||||
spinlock_t spin_lock_sock;
|
||||
struct mutex profile_mutex;
|
||||
struct mutex conn_mutex;
|
||||
spinlock_t spin_lock_profile;
|
||||
uint16_t profile_bitmap;
|
||||
uint16_t profile_status;
|
||||
int8_t profile_refcount[profile_max];
|
||||
int8_t profile_refcount[8];
|
||||
uint8_t ispairing;
|
||||
uint8_t isinquirying;
|
||||
uint8_t ispaging;
|
||||
@@ -310,9 +266,12 @@ struct rtl_coex_struct {
|
||||
uint8_t wifi_on;
|
||||
uint8_t sock_open;
|
||||
#endif
|
||||
|
||||
unsigned long cmd_last_tx;
|
||||
|
||||
/* hci ev buff */
|
||||
struct list_head ev_used_list;
|
||||
struct list_head ev_free_list;
|
||||
|
||||
spinlock_t rxlock;
|
||||
__u8 pkt_type;
|
||||
__u16 expect;
|
||||
@@ -320,18 +279,16 @@ struct rtl_coex_struct {
|
||||
__u16 elen;
|
||||
__u8 back_buff[HCI_MAX_EVENT_SIZE];
|
||||
|
||||
struct list_head ev_free_list;
|
||||
/* l2cap rx buff */
|
||||
struct list_head l2_used_list;
|
||||
struct list_head l2_free_list;
|
||||
struct list_head hci_pkt_list;
|
||||
|
||||
/* buff addr and size */
|
||||
spinlock_t buff_lock;
|
||||
unsigned long pages_addr;
|
||||
unsigned long buff_size;
|
||||
|
||||
#define RTL_COEX_RUNNING 1
|
||||
#define RTL_COEX_PKT_COUNTING 2
|
||||
#define RTL_COEX_CONN_REMOVING 3
|
||||
#define RTL_COEX_RUNNING (1 << 0)
|
||||
unsigned long flags;
|
||||
|
||||
};
|
||||
@@ -406,3 +363,6 @@ void rtk_btcoex_close(void);
|
||||
void rtk_btcoex_probe(struct hci_dev *hdev);
|
||||
void rtk_btcoex_init(void);
|
||||
void rtk_btcoex_exit(void);
|
||||
|
||||
|
||||
#endif /* __RTK_COEX_H__ */
|
||||
@@ -1,22 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
*
|
||||
* Realtek Bluetooth USB download firmware driver
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@@ -30,14 +16,8 @@
|
||||
#include <linux/usb.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/version.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 12, 0)
|
||||
#include <linux/unaligned.h>
|
||||
#else
|
||||
#include <asm/unaligned.h>
|
||||
#endif
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
@@ -50,7 +30,8 @@
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
|
||||
#include <linux/pm_runtime.h>
|
||||
@@ -73,7 +54,7 @@ struct cfg_list_item {
|
||||
struct list_head list;
|
||||
u16 offset;
|
||||
u8 len;
|
||||
u8 data[];
|
||||
u8 data[0];
|
||||
};
|
||||
|
||||
static struct list_head list_configs;
|
||||
@@ -103,7 +84,6 @@ static struct list_head list_extracfgs;
|
||||
#define HCI_VENDOR_READ_RTK_ROM_VERISION 0xfc6d
|
||||
#define HCI_VENDOR_READ_LMP_VERISION 0x1001
|
||||
#define HCI_VENDOR_READ_CMD 0xfc61
|
||||
#define HCI_VENDOR_WRITE_CMD 0xfc62
|
||||
|
||||
#define ROM_LMP_NONE 0x0000
|
||||
#define ROM_LMP_8723a 0x1200
|
||||
@@ -112,9 +92,6 @@ static struct list_head list_extracfgs;
|
||||
#define ROM_LMP_8761a 0X8761
|
||||
#define ROM_LMP_8822b 0X8822
|
||||
#define ROM_LMP_8852a 0x8852
|
||||
#define ROM_LMP_8851b 0x8851
|
||||
#define ROM_LMP_8922a 0x8922
|
||||
#define ROM_LMP_8723c 0x8703
|
||||
|
||||
#define PATCH_SNIPPETS 0x01
|
||||
#define PATCH_DUMMY_HEADER 0x02
|
||||
@@ -186,30 +163,41 @@ static const uint8_t RTK_EPATCH_SIGNATURE_NEW[8] =
|
||||
//Extension Section IGNATURE:0x77FD0451
|
||||
static const uint8_t Extension_Section_SIGNATURE[4] = { 0x51, 0x04, 0xFD, 0x77 };
|
||||
|
||||
static const struct {
|
||||
__u16 lmp_subver;
|
||||
__u8 id;
|
||||
} project_id_to_lmp_subver[] = {
|
||||
{ ROM_LMP_8723a, 0 },
|
||||
{ ROM_LMP_8723b, 1 },
|
||||
{ ROM_LMP_8821a, 2 },
|
||||
{ ROM_LMP_8761a, 3 },
|
||||
{ ROM_LMP_8723c, 7 },
|
||||
{ ROM_LMP_8822b, 8 }, /* 8822B */
|
||||
{ ROM_LMP_8723b, 9 }, /* 8723D */
|
||||
{ ROM_LMP_8821a, 10 }, /* 8821C */
|
||||
{ ROM_LMP_8822b, 13 }, /* 8822C */
|
||||
{ ROM_LMP_8761a, 14 }, /* 8761B */
|
||||
{ ROM_LMP_8852a, 18 }, /* 8852A */
|
||||
{ ROM_LMP_8723b, 19 }, /* 8733B */
|
||||
{ ROM_LMP_8852a, 20 }, /* 8852B */
|
||||
{ ROM_LMP_8852a, 25 }, /* 8852C */
|
||||
{ ROM_LMP_8822b, 33 }, /* 8822E */
|
||||
{ ROM_LMP_8851b, 36 }, /* 8851B */
|
||||
{ ROM_LMP_8852a, 42 }, /* 8852D */
|
||||
{ ROM_LMP_8922a, 44 }, /* 8922A */
|
||||
{ ROM_LMP_8852a, 47 }, /* 8852BT */
|
||||
{ ROM_LMP_8761a, 51 }, /* 8761C */
|
||||
static uint16_t project_id[] = {
|
||||
ROM_LMP_8723a,
|
||||
ROM_LMP_8723b,
|
||||
ROM_LMP_8821a,
|
||||
ROM_LMP_8761a,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_8822b,
|
||||
ROM_LMP_8723b, /* RTL8723DU */
|
||||
ROM_LMP_8821a, /* RTL8821CU */
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_8822b, /* RTL8822CU */
|
||||
ROM_LMP_8761a, /* index 14 for 8761BU */
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_8852a, /* index 18 for 8852AU */
|
||||
ROM_LMP_8723b, /* index 19 for 8723FU */
|
||||
ROM_LMP_8852a, /* index 20 for 8852BU */
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_8852a, /* index 25 for 8852CU */
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_NONE,
|
||||
ROM_LMP_8822b, /* index 33 for 8822EU */
|
||||
};
|
||||
|
||||
enum rtk_endpoit {
|
||||
@@ -227,16 +215,10 @@ enum rtk_endpoit {
|
||||
#define RTL8822CU 0x73
|
||||
#define RTL8761BU 0x74
|
||||
#define RTL8852AU 0x75
|
||||
#define RTL8733BU 0x76
|
||||
#define RTL8723FU 0x76
|
||||
#define RTL8852BU 0x77
|
||||
#define RTL8852CU 0x78
|
||||
#define RTL8822EU 0x79
|
||||
#define RTL8851BU 0x7A
|
||||
#define RTL8852DU 0x7B
|
||||
#define RTL8922AU 0x7C
|
||||
#define RTL8852BTU 0x7D
|
||||
#define RTL8761CU 0x80
|
||||
#define RTL8723CU 0x81
|
||||
|
||||
typedef struct {
|
||||
uint16_t prod_id;
|
||||
@@ -297,7 +279,7 @@ static uint8_t g_key_id = 0;
|
||||
|
||||
static dev_data *dev_data_find(struct usb_interface *intf);
|
||||
static patch_info *get_patch_entry(struct usb_device *udev);
|
||||
static int load_firmware(dev_data *dev_entry, xchange_data *xdata);
|
||||
static int load_firmware(dev_data * dev_entry, uint8_t ** buff);
|
||||
static void init_xdata(xchange_data * xdata, dev_data * dev_entry);
|
||||
static int check_fw_version(xchange_data * xdata);
|
||||
static int download_data(xchange_data * xdata);
|
||||
@@ -362,8 +344,6 @@ static patch_info fw_patch_table[] = {
|
||||
{0xb009, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", RTL8723DU}, /* RTL8723DU */
|
||||
{0x0231, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", RTL8723DU}, /* RTL8723DU for LiteOn */
|
||||
|
||||
{0xb703, 0x8703, "mp_rtl8723cu_fw", "rtl8723cu_fw", "rtl8723cu_config", RTL8723CU}, /* RTL8723CU */
|
||||
|
||||
{0xb820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CU */
|
||||
{0xc820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CU */
|
||||
{0xc821, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", RTL8821CU}, /* RTL8821CE */
|
||||
@@ -397,7 +377,6 @@ static patch_info fw_patch_table[] = {
|
||||
{0xc82e, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CU */
|
||||
{0xc81d, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CU */
|
||||
{0xd820, 0x8822, "mp_rtl8821du_fw", "rtl8821du_fw", "rtl8821du_config", RTL8822CU}, /* RTL8821DU */
|
||||
{0x053b, 0x8822, "mp_rtl8821du_fw", "rtl8821du_fw", "rtl8821du_config", RTL8822CU}, /* RTL8821DU for Epson*/
|
||||
|
||||
{0xc822, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
|
||||
{0xc82b, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE */
|
||||
@@ -426,7 +405,6 @@ static patch_info fw_patch_table[] = {
|
||||
{0xc03f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", RTL8822CU}, /* RTL8822CE-VS */
|
||||
|
||||
{0x8771, 0x8761, "mp_rtl8761b_fw", "rtl8761bu_fw", "rtl8761bu_config", RTL8761BU}, /* RTL8761BU only */
|
||||
{0x876e, 0x8761, "mp_rtl8761b_fw", "rtl8761bu_fw", "rtl8761bu_config", RTL8761BU}, /* RTL8761BUE */
|
||||
{0xa725, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", RTL8761BU}, /* RTL8725AU */
|
||||
{0xa72A, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", RTL8761BU}, /* RTL8725AU BT only */
|
||||
|
||||
@@ -447,13 +425,14 @@ static patch_info fw_patch_table[] = {
|
||||
{0xc125, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0xe852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0xb852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0xc852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0xc549, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0xc127, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
{0x3565, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", RTL8852AU}, /* RTL8852AE */
|
||||
|
||||
{0xb733, 0x8723, "mp_rtl8733bu_fw", "rtl8733bu_fw", "rtl8733bu_config", RTL8733BU}, /* RTL8733BU */
|
||||
{0xb73a, 0x8723, "mp_rtl8733bu_fw", "rtl8733bu_fw", "rtl8733bu_config", RTL8733BU}, /* RTL8733BU */
|
||||
{0xf72b, 0x8723, "mp_rtl8733bu_fw", "rtl8733bu_fw", "rtl8733bu_config", RTL8733BU}, /* RTL8733BU */
|
||||
{0xb733, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
|
||||
{0xb73a, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
|
||||
{0xf72b, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", RTL8723FU}, /* RTL8723FU */
|
||||
|
||||
{0x8851, 0x8852, "mp_rtl8851au_fw", "rtl8851au_fw", "rtl8851au_config", RTL8852BU}, /* RTL8851AU */
|
||||
{0xa85b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", RTL8852BU}, /* RTL8852BU */
|
||||
@@ -474,7 +453,6 @@ static patch_info fw_patch_table[] = {
|
||||
{0x1670, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", RTL8852BU}, /* RTL8852BE */
|
||||
|
||||
{0xc85a, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CU */
|
||||
{0xc85d, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CU */
|
||||
{0x0852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
{0x5852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
{0xc85c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
@@ -482,29 +460,10 @@ static patch_info fw_patch_table[] = {
|
||||
{0x886c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
{0x887c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
{0x4007, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
{0x1675, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
{0x3586, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", RTL8852CU}, /* RTL8852CE */
|
||||
|
||||
{0xe822, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", RTL8822EU}, /* RTL8822EU */
|
||||
{0xa82a, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", RTL8822EU}, /* RTL8822EU */
|
||||
|
||||
{0xb851, 0x8851, "mp_rtl8851bu_fw", "rtl8851bu_fw", "rtl8851bu_config", RTL8851BU}, /* RTL8851BU */
|
||||
|
||||
{0xd85a, 0x8852, "mp_rtl8852du_fw", "rtl8852du_fw", "rtl8852du_config", RTL8852DU}, /* RTL8852DU */
|
||||
|
||||
{0x892a, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AU */
|
||||
{0x8922, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
{0xa890, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
{0xa891, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
{0xa892, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
{0xd922, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
{0xb85f, 0x8922, "mp_rtl8922au_fw", "rtl8922au_fw", "rtl8922au_config", RTL8922AU}, /* RTL8922AE */
|
||||
|
||||
{0xc852, 0x8852, "mp_rtl8852btu_fw", "rtl8852btu_fw", "rtl8852btu_config", RTL8852BTU}, /* RTL8852BTU */
|
||||
{0x8520, 0x8852, "mp_rtl8852btu_fw", "rtl8852btu_fw", "rtl8852btu_config", RTL8852BTU}, /* RTL8852BTE */
|
||||
|
||||
{0xc761, 0x8761, "mp_rtl8761cu_fw", "rtl8761cu_mx_fw", "rtl8761cu_mx_config", RTL8761CU}, /* RTL8761CU */
|
||||
|
||||
/* NOTE: must append patch entries above the null entry */
|
||||
{0, 0, NULL, NULL, NULL, 0}
|
||||
};
|
||||
@@ -787,7 +746,6 @@ static inline int get_max_patch_size(u8 chip_type)
|
||||
max_patch_size = 25 * 1024;
|
||||
break;
|
||||
case RTL8723DU:
|
||||
case RTL8723CU:
|
||||
case RTL8822CU:
|
||||
case RTL8761BU:
|
||||
case RTL8821CU:
|
||||
@@ -796,11 +754,10 @@ static inline int get_max_patch_size(u8 chip_type)
|
||||
case RTL8852AU:
|
||||
max_patch_size = 0x114D0 + 529; /* 69.2KB */
|
||||
break;
|
||||
case RTL8733BU:
|
||||
case RTL8723FU:
|
||||
max_patch_size = 0xC4Cf + 529; /* 49.2KB */
|
||||
break;
|
||||
case RTL8852BU:
|
||||
case RTL8851BU:
|
||||
max_patch_size = 0x104D0 + 529; /* 65KB */
|
||||
break;
|
||||
case RTL8852CU:
|
||||
@@ -809,18 +766,6 @@ static inline int get_max_patch_size(u8 chip_type)
|
||||
case RTL8822EU:
|
||||
max_patch_size = 0x24620 + 529; /* 145KB */
|
||||
break;
|
||||
case RTL8852DU:
|
||||
max_patch_size = 0x20D90 + 529; /* 131KB */
|
||||
break;
|
||||
case RTL8922AU:
|
||||
max_patch_size = 0x23810 + 529; /* 142KB */
|
||||
break;
|
||||
case RTL8852BTU:
|
||||
max_patch_size = 0x27E00 + 529; /* 159.5KB */
|
||||
break;
|
||||
case RTL8761CU:
|
||||
max_patch_size = 1024 * 1024; /* 1MB */
|
||||
break;
|
||||
default:
|
||||
max_patch_size = 40 * 1024;
|
||||
break;
|
||||
@@ -829,64 +774,11 @@ static inline int get_max_patch_size(u8 chip_type)
|
||||
return max_patch_size;
|
||||
}
|
||||
|
||||
static int rtk_vendor_write(dev_data * dev_entry)
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
xchange_data *xdata = NULL;
|
||||
unsigned char cmd_buf[] = {0x31, 0x90, 0xd0, 0x29, 0x80, 0x00, 0x00,
|
||||
0x00, 0x00};
|
||||
|
||||
xdata = kzalloc(sizeof(xchange_data), GFP_KERNEL);
|
||||
if (NULL == xdata) {
|
||||
ret_val = 0xFE;
|
||||
RTKBT_DBG("NULL == xdata");
|
||||
return -1;
|
||||
}
|
||||
|
||||
init_xdata(xdata, dev_entry);
|
||||
|
||||
xdata->cmd_hdr->opcode = cpu_to_le16(HCI_VENDOR_WRITE_CMD);
|
||||
xdata->cmd_hdr->plen = 9;
|
||||
memcpy(xdata->send_pkt, &(xdata->cmd_hdr->opcode), 2);
|
||||
memcpy(xdata->send_pkt+2, &(xdata->cmd_hdr->plen), 1);
|
||||
|
||||
memcpy(xdata->send_pkt+3, cmd_buf, sizeof(cmd_buf));
|
||||
|
||||
xdata->pkt_len = CMD_HDR_LEN + 9;
|
||||
|
||||
ret_val = send_hci_cmd(xdata);
|
||||
if (ret_val < 0) {
|
||||
RTKBT_ERR("%s: Failed to send HCI command.", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret_val = rcv_hci_evt(xdata);
|
||||
if (ret_val < 0) {
|
||||
RTKBT_ERR("%s: Failed to receive HCI event.", __func__);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret_val = 0;
|
||||
end:
|
||||
if (xdata != NULL) {
|
||||
if (xdata->send_pkt)
|
||||
kfree(xdata->send_pkt);
|
||||
if (xdata->rcv_pkt)
|
||||
kfree(xdata->rcv_pkt);
|
||||
kfree(xdata);
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static int check_fw_chip_ver(dev_data * dev_entry, xchange_data * xdata)
|
||||
{
|
||||
int ret_val;
|
||||
uint16_t chip = 0;
|
||||
uint16_t chip_ver = 0;
|
||||
uint16_t lmp_subver, hci_rev;
|
||||
patch_info *patch_entry;
|
||||
struct hci_rp_read_local_version *read_ver_rsp;
|
||||
|
||||
chip = rtk_vendor_read(dev_entry, READ_CHIP_TYPE);
|
||||
if(chip == 0x8822) {
|
||||
@@ -909,16 +801,9 @@ static int check_fw_chip_ver(dev_data * dev_entry, xchange_data * xdata)
|
||||
gEVersion = rtk_get_eversion(dev_entry);
|
||||
}
|
||||
return ret_val;
|
||||
} else {
|
||||
patch_entry = xdata->dev_entry->patch_entry;
|
||||
read_ver_rsp = (struct hci_rp_read_local_version *)(xdata->rsp_para);
|
||||
lmp_subver = le16_to_cpu(read_ver_rsp->lmp_subver);
|
||||
hci_rev = le16_to_cpu(read_ver_rsp->hci_rev);
|
||||
if (lmp_subver == 0x8852 && hci_rev == 0x000d)
|
||||
ret_val = rtk_vendor_write(dev_entry);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int download_patch(struct usb_interface *intf)
|
||||
@@ -951,7 +836,7 @@ int download_patch(struct usb_interface *intf)
|
||||
if (ret_val != 0 )
|
||||
goto patch_end;
|
||||
|
||||
xdata->fw_len = load_firmware(dev_entry, xdata);
|
||||
xdata->fw_len = load_firmware(dev_entry, &xdata->fw_data);
|
||||
if (xdata->fw_len <= 0) {
|
||||
RTKBT_ERR("load firmware failed!");
|
||||
ret_val = -1;
|
||||
@@ -990,7 +875,7 @@ int download_patch(struct usb_interface *intf)
|
||||
|
||||
ret_val = 0;
|
||||
patch_fail:
|
||||
vfree(fw_buf);
|
||||
kfree(fw_buf);
|
||||
patch_end:
|
||||
if (xdata != NULL) {
|
||||
if (xdata->send_pkt)
|
||||
@@ -1008,7 +893,7 @@ patch_end:
|
||||
* -1: error
|
||||
* 0: download patch successfully
|
||||
* >0: patch already exists */
|
||||
int download_special_patch(struct usb_interface *intf, const char *special_name)
|
||||
int download_lps_patch(struct usb_interface *intf)
|
||||
{
|
||||
dev_data *dev_entry;
|
||||
patch_info *pinfo;
|
||||
@@ -1050,18 +935,15 @@ int download_special_patch(struct usb_interface *intf, const char *special_name)
|
||||
}
|
||||
goto patch_end;
|
||||
}
|
||||
memset(name1, 0, sizeof(name1));
|
||||
memset(name2, 0, sizeof(name2));
|
||||
|
||||
origin_name1 = dev_entry->patch_entry->patch_name;
|
||||
origin_name2 = dev_entry->patch_entry->config_name;
|
||||
memcpy(name1, special_name, strlen(special_name));
|
||||
strncat(name1, origin_name1, sizeof(name1) - 1 - strlen(special_name));
|
||||
memcpy(name2, special_name, strlen(special_name));
|
||||
strncat(name2, origin_name2, sizeof(name2) - 1 - strlen(special_name));
|
||||
snprintf(name1, sizeof(name1), "lps_%s", origin_name1);
|
||||
snprintf(name2, sizeof(name2), "lps_%s", origin_name2);
|
||||
dev_entry->patch_entry->patch_name = name1;
|
||||
dev_entry->patch_entry->config_name = name2;
|
||||
RTKBT_INFO("Loading %s and %s", name1, name2);
|
||||
xdata->fw_len = load_firmware(dev_entry, xdata);
|
||||
xdata->fw_len = load_firmware(dev_entry, &xdata->fw_data);
|
||||
dev_entry->patch_entry->patch_name = origin_name1;
|
||||
dev_entry->patch_entry->config_name = origin_name2;
|
||||
if (xdata->fw_len <= 0) {
|
||||
@@ -1073,13 +955,11 @@ int download_special_patch(struct usb_interface *intf, const char *special_name)
|
||||
fw_buf = xdata->fw_data;
|
||||
|
||||
pinfo = dev_entry->patch_entry;
|
||||
/*
|
||||
if (!pinfo) {
|
||||
RTKBT_ERR("%s: No patch entry", __func__);
|
||||
result = -1;
|
||||
goto patch_fail;
|
||||
}
|
||||
*/
|
||||
max_patch_size = get_max_patch_size(pinfo->chip_type);
|
||||
if (xdata->fw_len > max_patch_size) {
|
||||
result = -1;
|
||||
@@ -1118,39 +998,6 @@ patch_end:
|
||||
}
|
||||
#endif
|
||||
|
||||
int setup_btrealtek_flag(struct usb_interface *intf, struct hci_dev *hdev)
|
||||
{
|
||||
dev_data *dev_entry;
|
||||
patch_info *pinfo;
|
||||
int ret_val = 0;
|
||||
|
||||
dev_entry = dev_data_find(intf);
|
||||
if (NULL == dev_entry) {
|
||||
ret_val = -1;
|
||||
RTKBT_ERR("%s: NULL == dev_entry", __func__);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
pinfo = dev_entry->patch_entry;
|
||||
if (!pinfo) {
|
||||
RTKBT_ERR("%s: No patch entry", __func__);
|
||||
ret_val = -1;
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
switch (pinfo->chip_type){
|
||||
case RTL8852CU:
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
btrealtek_set_flag(hdev, REALTEK_ALT6_CONTINUOUS_TX_CHIP);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
#if defined RTKBT_SUSPEND_WAKEUP || defined RTKBT_SHUTDOWN_WAKEUP || defined RTKBT_SWITCH_PATCH
|
||||
int set_scan(struct usb_interface *intf)
|
||||
{
|
||||
@@ -1198,7 +1045,7 @@ end:
|
||||
|
||||
dev_data *dev_data_find(struct usb_interface * intf)
|
||||
{
|
||||
dev_data *dev_entry = NULL;
|
||||
dev_data *dev_entry;
|
||||
|
||||
list_for_each_entry(dev_entry, &dev_data_list, list_node) {
|
||||
if (dev_entry->intf == intf) {
|
||||
@@ -1241,7 +1088,6 @@ static int is_mac(u8 chip_type, u16 offset)
|
||||
switch (chip_type) {
|
||||
case RTL8822BU:
|
||||
case RTL8723DU:
|
||||
case RTL8723CU:
|
||||
case RTL8821CU:
|
||||
if (offset == 0x0044)
|
||||
return 1;
|
||||
@@ -1249,15 +1095,10 @@ static int is_mac(u8 chip_type, u16 offset)
|
||||
case RTL8822CU:
|
||||
case RTL8761BU:
|
||||
case RTL8852AU:
|
||||
case RTL8733BU:
|
||||
case RTL8723FU:
|
||||
case RTL8852BU:
|
||||
case RTL8852CU:
|
||||
case RTL8822EU:
|
||||
case RTL8851BU:
|
||||
case RTL8852DU:
|
||||
case RTL8922AU:
|
||||
case RTL8852BTU:
|
||||
case RTL8761CU:
|
||||
if (offset == 0x0030)
|
||||
return 1;
|
||||
break;
|
||||
@@ -1275,21 +1116,15 @@ static uint16_t get_mac_offset(u8 chip_type)
|
||||
switch (chip_type) {
|
||||
case RTL8822BU:
|
||||
case RTL8723DU:
|
||||
case RTL8723CU:
|
||||
case RTL8821CU:
|
||||
return 0x0044;
|
||||
case RTL8822CU:
|
||||
case RTL8761BU:
|
||||
case RTL8852AU:
|
||||
case RTL8733BU:
|
||||
case RTL8723FU:
|
||||
case RTL8852BU:
|
||||
case RTL8852CU:
|
||||
case RTL8822EU:
|
||||
case RTL8851BU:
|
||||
case RTL8852DU:
|
||||
case RTL8922AU:
|
||||
case RTL8852BTU:
|
||||
case RTL8761CU:
|
||||
return 0x0030;
|
||||
case RTLPREVIOUS:
|
||||
return 0x003c;
|
||||
@@ -1617,12 +1452,14 @@ static uint8_t *rtb_get_patch_header(int *len,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
RTKBT_INFO("Unknown Opcode. Ignore");
|
||||
RTKBT_ERR("Wrong Opcode");
|
||||
goto wrong_opcode;
|
||||
}
|
||||
section_pos += (SECTION_HEADER_SIZE + section_hdr.section_len);
|
||||
}
|
||||
*len = patch_len;
|
||||
|
||||
wrong_opcode:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1906,7 +1743,7 @@ static int rtk_vendor_read(dev_data * dev_entry, uint8_t class)
|
||||
xchange_data *xdata = NULL;
|
||||
unsigned char cmd_ct_buf[] = {0x10, 0x38, 0x04, 0x28, 0x80};
|
||||
unsigned char cmd_cv_buf[] = {0x10, 0x3A, 0x04, 0x28, 0x80};
|
||||
unsigned char cmd_sec_buf[] = {0x10, 0xA4, 0xAD, 0x00, 0xb0};
|
||||
unsigned char cmd_sec_buf[] = {0x10, 0xA4, 0x0D, 0x00, 0xb0};
|
||||
|
||||
xdata = kzalloc(sizeof(xchange_data), GFP_KERNEL);
|
||||
if (NULL == xdata) {
|
||||
@@ -1974,6 +1811,7 @@ static int rtk_vendor_read(dev_data * dev_entry, uint8_t class)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
read_end:
|
||||
if (xdata != NULL) {
|
||||
if (xdata->send_pkt)
|
||||
@@ -1985,57 +1823,7 @@ read_end:
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static int needs_hci_upgrade(xchange_data *xdata, u8 *buf, u32 buf_len)
|
||||
{
|
||||
struct {
|
||||
u8 status;
|
||||
u8 subopcode;
|
||||
u8 ota;
|
||||
} __attribute__((packed)) *evt_params;
|
||||
#define UPG_DL_BLOCK_SIZE 128
|
||||
#define UPG_SUBCMD_CODE 0x01
|
||||
u8 len = UPG_DL_BLOCK_SIZE;
|
||||
u8 *cmd_params;
|
||||
int ret;
|
||||
|
||||
cmd_params = xdata->req_para;
|
||||
evt_params = (void *)xdata->rsp_para;
|
||||
xdata->cmd_hdr->opcode = cpu_to_le16(0xfdbb);
|
||||
if (buf_len < len)
|
||||
len = buf_len;
|
||||
xdata->cmd_hdr->plen = 1 + len;
|
||||
xdata->pkt_len = sizeof(*xdata->cmd_hdr) + xdata->cmd_hdr->plen;
|
||||
*cmd_params++ = UPG_SUBCMD_CODE;
|
||||
memcpy(cmd_params, buf, len);
|
||||
|
||||
ret = send_hci_cmd(xdata);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = rcv_hci_evt(xdata);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (evt_params->status) {
|
||||
RTKBT_ERR("needs_hci_upgrade: status %02x", evt_params->status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (evt_params->subopcode != UPG_SUBCMD_CODE) {
|
||||
RTKBT_ERR("needs_hci_upgrade: return subopcode %02x",
|
||||
evt_params->subopcode);
|
||||
return -2;
|
||||
}
|
||||
|
||||
RTKBT_INFO("needs_hci_upgrade: state %02x", evt_params->ota);
|
||||
|
||||
return evt_params->ota;
|
||||
}
|
||||
|
||||
/* buff: points to the allocated buffer that stores extracted fw and config
|
||||
* This function returns the total length of extracted fw and config
|
||||
*/
|
||||
int load_firmware(dev_data *dev_entry, xchange_data *xdata)
|
||||
int load_firmware(dev_data * dev_entry, uint8_t ** buff)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
struct usb_device *udev;
|
||||
@@ -2047,13 +1835,12 @@ int load_firmware(dev_data *dev_entry, xchange_data *xdata)
|
||||
uint8_t need_download_fw = 1;
|
||||
uint16_t lmp_version;
|
||||
struct rtk_epatch_entry current_entry = { 0 };
|
||||
|
||||
struct list_head *pos, *next;
|
||||
struct patch_node *tmp;
|
||||
struct patch_node patch_node_hdr;
|
||||
int i;
|
||||
|
||||
RTKBT_DBG("load_firmware start");
|
||||
|
||||
udev = dev_entry->udev;
|
||||
patch_entry = dev_entry->patch_entry;
|
||||
lmp_version = patch_entry->lmp_sub;
|
||||
@@ -2066,13 +1853,16 @@ int load_firmware(dev_data *dev_entry, xchange_data *xdata)
|
||||
ret_val = request_firmware(&fw, fw_name, &udev->dev);
|
||||
if (ret_val < 0) {
|
||||
RTKBT_ERR("request_firmware error");
|
||||
fw_len = 0;
|
||||
kfree(config_file_buf);
|
||||
config_file_buf = NULL;
|
||||
goto fw_fail;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&patch_node_hdr.list);
|
||||
|
||||
epatch_buf = vzalloc(fw->size);
|
||||
if (!epatch_buf)
|
||||
epatch_buf = kzalloc(fw->size, GFP_KERNEL);
|
||||
if (NULL == epatch_buf)
|
||||
goto alloc_fail;
|
||||
|
||||
memcpy(epatch_buf, fw->data, fw->size);
|
||||
@@ -2084,174 +1874,137 @@ int load_firmware(dev_data *dev_entry, xchange_data *xdata)
|
||||
if (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) == 0) {
|
||||
RTKBT_ERR("8723a Check signature error!");
|
||||
need_download_fw = 0;
|
||||
goto sign_err;
|
||||
}
|
||||
buf = vzalloc(buf_len);
|
||||
if (!buf) {
|
||||
RTKBT_ERR("Can't alloc memory for fw&config");
|
||||
buf_len = -1;
|
||||
goto alloc_buf_err;
|
||||
} else {
|
||||
if (!(buf = kzalloc(buf_len, GFP_KERNEL))) {
|
||||
RTKBT_ERR("Can't alloc memory for fw&config");
|
||||
buf_len = -1;
|
||||
} else {
|
||||
RTKBT_DBG("8723a, fw copy direct");
|
||||
memcpy(buf, epatch_buf, fw->size);
|
||||
if (config_len) {
|
||||
memcpy(&buf[buf_len - config_len],
|
||||
config_file_buf, config_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
RTKBT_ERR("This is not 8723a, use new patch style!");
|
||||
|
||||
RTKBT_DBG("8723a, fw copy direct");
|
||||
memcpy(buf, epatch_buf, fw->size);
|
||||
if (config_len)
|
||||
memcpy(&buf[buf_len - config_len], config_file_buf,
|
||||
config_len);
|
||||
|
||||
goto done;
|
||||
}
|
||||
|
||||
RTKBT_ERR("This is not 8723a, use new patch style!");
|
||||
|
||||
/* Get version from ROM */
|
||||
gEVersion = rtk_get_eversion(dev_entry);
|
||||
RTKBT_DBG("%s: New gEVersion %d", __func__, gEVersion);
|
||||
if (gEVersion == 0xFE) {
|
||||
RTKBT_ERR("%s: Read ROM version failure", __func__);
|
||||
need_download_fw = 0;
|
||||
goto alloc_fail;
|
||||
}
|
||||
|
||||
/* check Signature and Extension Section Field */
|
||||
if ((memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) &&
|
||||
memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8)) ||
|
||||
memcmp(epatch_buf + buf_len - config_len - 4,
|
||||
Extension_Section_SIGNATURE, 4) != 0) {
|
||||
RTKBT_ERR("Check SIGNATURE error! do not download fw");
|
||||
need_download_fw = 0;
|
||||
goto sign_err;
|
||||
}
|
||||
|
||||
proj_id = rtk_get_fw_project_id(epatch_buf + buf_len - config_len - 5);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(project_id_to_lmp_subver); i++) {
|
||||
if (proj_id == project_id_to_lmp_subver[i].id &&
|
||||
lmp_version == project_id_to_lmp_subver[i].lmp_subver) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= ARRAY_SIZE(project_id_to_lmp_subver)) {
|
||||
RTKBT_ERR("lmp_version %04x, project_id %u, does not match!!!",
|
||||
lmp_version, proj_id);
|
||||
need_download_fw = 0;
|
||||
goto proj_id_err;
|
||||
}
|
||||
|
||||
RTKBT_DBG("lmp_version is %04x, project_id is %u, match!",
|
||||
lmp_version, proj_id);
|
||||
|
||||
if (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8) == 0) {
|
||||
int key_id = rtk_vendor_read(dev_entry, READ_SEC_PROJ);
|
||||
int tmp_len = 0;
|
||||
|
||||
RTKBT_DBG("%s: key id %d", __func__, key_id);
|
||||
if (key_id < 0) {
|
||||
RTKBT_ERR("%s: Read key id failure", __func__);
|
||||
/* Get version from ROM */
|
||||
gEVersion = rtk_get_eversion(dev_entry);
|
||||
RTKBT_DBG("%s: New gEVersion %d", __func__, gEVersion);
|
||||
if (gEVersion == 0xFE) {
|
||||
RTKBT_ERR("%s: Read ROM version failure", __func__);
|
||||
need_download_fw = 0;
|
||||
fw_len = 0;
|
||||
goto extract_err;
|
||||
}
|
||||
rtb_get_patch_header(&buf_len, &patch_node_hdr, epatch_buf,
|
||||
key_id);
|
||||
if (!buf_len)
|
||||
goto extract_err;
|
||||
RTKBT_DBG("buf_len = 0x%x", buf_len);
|
||||
buf_len += config_len;
|
||||
|
||||
buf = vzalloc(buf_len);
|
||||
if (!buf) {
|
||||
RTKBT_ERR("Can't alloc memory for multi fw&config");
|
||||
buf_len = -1;
|
||||
goto alloc_buf_err;
|
||||
goto alloc_fail;
|
||||
}
|
||||
|
||||
list_for_each_safe(pos, next, &patch_node_hdr.list) {
|
||||
tmp = list_entry(pos, struct patch_node, list);
|
||||
RTKBT_DBG("len = 0x%x", tmp->len);
|
||||
memcpy(buf + tmp_len, tmp->payload, tmp->len);
|
||||
tmp_len += tmp->len;
|
||||
list_del_init(pos);
|
||||
kfree(tmp);
|
||||
}
|
||||
if (config_len)
|
||||
memcpy(&buf[buf_len - config_len], config_file_buf,
|
||||
config_len);
|
||||
} else {
|
||||
rtk_get_patch_entry(epatch_buf, ¤t_entry);
|
||||
|
||||
if (current_entry.patch_length == 0)
|
||||
goto extract_err;
|
||||
|
||||
buf_len = current_entry.patch_length + config_len;
|
||||
RTKBT_DBG("buf_len = 0x%x", buf_len);
|
||||
|
||||
buf = vzalloc(buf_len);
|
||||
if (!buf) {
|
||||
RTKBT_ERR("Can't alloc memory for multi fw&config");
|
||||
buf_len = -1;
|
||||
goto alloc_buf_err;
|
||||
}
|
||||
|
||||
memcpy(buf, epatch_buf + current_entry.start_offset,
|
||||
current_entry.patch_length);
|
||||
/* Copy fw version */
|
||||
memcpy(buf + current_entry.patch_length - 4, epatch_buf + 8, 4);
|
||||
if (config_len)
|
||||
memcpy(&buf[buf_len - config_len], config_file_buf,
|
||||
config_len);
|
||||
}
|
||||
|
||||
if (patch_entry->chip_type == RTL8761CU) {
|
||||
if (needs_hci_upgrade(xdata, buf, buf_len) <= 0) {
|
||||
if (config_len > 0) {
|
||||
memmove(buf, buf + buf_len - config_len,
|
||||
config_len);
|
||||
buf_len = config_len;
|
||||
} else {
|
||||
#define FAKE_SEG_LEN 16
|
||||
if (buf_len > FAKE_SEG_LEN)
|
||||
buf_len = FAKE_SEG_LEN;
|
||||
memset(buf, 0, buf_len);
|
||||
}
|
||||
/* check Signature and Extension Section Field */
|
||||
if (((memcmp(epatch_buf, RTK_EPATCH_SIGNATURE, 8) != 0) && (memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8) != 0))||
|
||||
memcmp(epatch_buf + buf_len - config_len - 4,
|
||||
Extension_Section_SIGNATURE, 4) != 0) {
|
||||
RTKBT_ERR("Check SIGNATURE error! do not download fw");
|
||||
need_download_fw = 0;
|
||||
} else {
|
||||
/* It does not need to download config when upgrading */
|
||||
buf_len -= config_len;
|
||||
proj_id =
|
||||
rtk_get_fw_project_id(epatch_buf + buf_len -
|
||||
config_len - 5);
|
||||
|
||||
if (lmp_version != project_id[proj_id]) {
|
||||
RTKBT_ERR
|
||||
("lmp_version is %x, project_id is %x, does not match!!!",
|
||||
lmp_version, project_id[proj_id]);
|
||||
need_download_fw = 0;
|
||||
} else {
|
||||
RTKBT_DBG
|
||||
("lmp_version is %x, project_id is %x, match!",
|
||||
lmp_version, project_id[proj_id]);
|
||||
|
||||
if(memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8) == 0) {
|
||||
int key_id = rtk_vendor_read(dev_entry, READ_SEC_PROJ);
|
||||
RTKBT_DBG("%s: key id %d", __func__, key_id);
|
||||
if (key_id < 0) {
|
||||
RTKBT_ERR("%s: Read key id failure", __func__);
|
||||
need_download_fw = 0;
|
||||
fw_len = 0;
|
||||
goto alloc_fail;
|
||||
}
|
||||
rtb_get_patch_header(&buf_len, &patch_node_hdr, epatch_buf, key_id);
|
||||
if(buf_len == 0)
|
||||
goto alloc_fail;
|
||||
RTKBT_DBG("buf_len = 0x%x", buf_len);
|
||||
buf_len += config_len;
|
||||
} else {
|
||||
rtk_get_patch_entry(epatch_buf, ¤t_entry);
|
||||
|
||||
if (current_entry.patch_length == 0)
|
||||
goto alloc_fail;
|
||||
|
||||
buf_len = current_entry.patch_length + config_len;
|
||||
RTKBT_DBG("buf_len = 0x%x", buf_len);
|
||||
}
|
||||
|
||||
if (!(buf = kzalloc(buf_len, GFP_KERNEL))) {
|
||||
RTKBT_ERR
|
||||
("Can't alloc memory for multi fw&config");
|
||||
buf_len = -1;
|
||||
} else {
|
||||
if(memcmp(epatch_buf, RTK_EPATCH_SIGNATURE_NEW, 8) == 0) {
|
||||
int tmp_len = 0;
|
||||
list_for_each_safe(pos, next, &patch_node_hdr.list)
|
||||
{
|
||||
tmp = list_entry(pos, struct patch_node, list);
|
||||
RTKBT_DBG("len = 0x%x", tmp->len);
|
||||
memcpy(buf + tmp_len, tmp->payload, tmp->len);
|
||||
tmp_len += tmp->len;
|
||||
list_del_init(pos);
|
||||
kfree(tmp);
|
||||
}
|
||||
if (config_len) {
|
||||
memcpy(&buf
|
||||
[buf_len - config_len],
|
||||
config_file_buf,
|
||||
config_len);
|
||||
}
|
||||
} else {
|
||||
memcpy(buf,
|
||||
epatch_buf +
|
||||
current_entry.start_offset,
|
||||
current_entry.patch_length);
|
||||
memcpy(buf + current_entry.patch_length - 4, epatch_buf + 8, 4); /*fw version */
|
||||
if (config_len) {
|
||||
memcpy(&buf
|
||||
[buf_len - config_len],
|
||||
config_file_buf,
|
||||
config_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
RTKBT_DBG("fw:%s exists, config file:%s exists",
|
||||
buf_len > 0 ? "" : "not", config_len > 0 ? "" : "not");
|
||||
if (buf && buf_len > 0 && need_download_fw) {
|
||||
(buf_len > 0) ? "" : "not", (config_len > 0) ? "" : "not");
|
||||
if (buf && (buf_len > 0) && (need_download_fw)) {
|
||||
fw_len = buf_len;
|
||||
xdata->fw_data = buf;
|
||||
*buff = buf;
|
||||
}
|
||||
|
||||
RTKBT_DBG("load_firmware done");
|
||||
alloc_buf_err:
|
||||
extract_err:
|
||||
/* Make sure all the patch nodes freed */
|
||||
list_for_each_safe(pos, next, &patch_node_hdr.list) {
|
||||
tmp = list_entry(pos, struct patch_node, list);
|
||||
list_del_init(pos);
|
||||
kfree(tmp);
|
||||
}
|
||||
proj_id_err:
|
||||
sign_err:
|
||||
|
||||
alloc_fail:
|
||||
release_firmware(fw);
|
||||
|
||||
if (epatch_buf)
|
||||
vfree(epatch_buf);
|
||||
kfree(epatch_buf);
|
||||
|
||||
fw_fail:
|
||||
if (config_file_buf)
|
||||
kfree(config_file_buf);
|
||||
|
||||
fw_fail:
|
||||
if (fw_len == 0)
|
||||
vfree(buf);
|
||||
kfree(buf);
|
||||
|
||||
return fw_len;
|
||||
}
|
||||
@@ -2396,7 +2149,7 @@ int download_data(xchange_data * xdata)
|
||||
uint8_t *pcur;
|
||||
int pkt_len, frag_num, frag_len;
|
||||
int i, ret_val;
|
||||
int j = 0;
|
||||
int j;
|
||||
|
||||
RTKBT_DBG("download_data start");
|
||||
|
||||
@@ -2408,11 +2161,12 @@ int download_data(xchange_data * xdata)
|
||||
frag_len = PATCH_SEG_MAX;
|
||||
|
||||
for (i = 0; i < frag_num; i++) {
|
||||
cmd_para->index = j++;
|
||||
|
||||
if(cmd_para->index == 0x7f)
|
||||
j = 1;
|
||||
if (i > 0x7f)
|
||||
j = (i & 0x7f) + 1;
|
||||
else
|
||||
j = i;
|
||||
|
||||
cmd_para->index = j;
|
||||
if (i == (frag_num - 1)) {
|
||||
cmd_para->index |= DATA_END;
|
||||
frag_len = xdata->fw_len % PATCH_SEG_MAX;
|
||||
|
||||
@@ -1,23 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
*
|
||||
* Realtek Bluetooth USB download firmware driver
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#ifndef __RTK_MISC_H__
|
||||
#define __RTK_MISC_H__
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
@@ -26,8 +14,6 @@
|
||||
#include <linux/usb.h>
|
||||
#include <linux/suspend.h>
|
||||
|
||||
#define CONFIG_BTUSB_AUTOSUSPEND 0
|
||||
|
||||
/* Download LPS patch when host suspends or power off
|
||||
* LPS patch name: lps_rtl8xxx_fw
|
||||
* LPS config name: lps_rtl8xxx_config
|
||||
@@ -59,9 +45,7 @@
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 33)
|
||||
#define USB_RPM 1
|
||||
#else
|
||||
#define USB_RPM 0
|
||||
#define USB_RPM
|
||||
#endif
|
||||
|
||||
#define CONFIG_NEEDS_BINDING
|
||||
@@ -72,7 +56,7 @@
|
||||
#endif
|
||||
|
||||
/* USB SS */
|
||||
#if (CONFIG_BTUSB_AUTOSUSPEND && USB_RPM)
|
||||
#if (defined CONFIG_BTUSB_AUTOSUSPEND) && (defined USB_RPM)
|
||||
#define BTUSB_RPM
|
||||
#endif
|
||||
|
||||
@@ -98,41 +82,12 @@ struct api_context {
|
||||
int status;
|
||||
};
|
||||
|
||||
int download_special_patch(struct usb_interface *intf, const char *special_name);
|
||||
int download_lps_patch(struct usb_interface *intf);
|
||||
#endif
|
||||
|
||||
int setup_btrealtek_flag(struct usb_interface *intf, struct hci_dev *hdev);
|
||||
|
||||
enum {
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)
|
||||
REALTEK_ALT6_CONTINUOUS_TX_CHIP,
|
||||
#endif
|
||||
|
||||
__REALTEK_NUM_FLAGS,
|
||||
};
|
||||
|
||||
struct btrealtek_data {
|
||||
DECLARE_BITMAP(flags, __REALTEK_NUM_FLAGS);
|
||||
};
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)
|
||||
static inline void *hci_get_priv(struct hci_dev *hdev)
|
||||
{
|
||||
return (char *)hdev + sizeof(*hdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define btrealtek_set_flag(hdev, nr) \
|
||||
do { \
|
||||
struct btrealtek_data *realtek = hci_get_priv((hdev)); \
|
||||
set_bit((nr), realtek->flags); \
|
||||
} while (0)
|
||||
|
||||
#define btrealtek_get_flag(hdev) \
|
||||
(((struct btrealtek_data *)hci_get_priv(hdev))->flags)
|
||||
|
||||
#define btrealtek_test_flag(hdev, nr) test_bit((nr), btrealtek_get_flag(hdev))
|
||||
|
||||
#if defined RTKBT_SUSPEND_WAKEUP || defined RTKBT_SHUTDOWN_WAKEUP || defined RTKBT_SWITCH_PATCH
|
||||
int set_scan(struct usb_interface *intf);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __RTK_MISC_H__ */
|
||||
@@ -1,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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
|
||||
*
|
||||
* Module to force cpuidle states through debugfs files.
|
||||
*
|
||||
*/
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/irqdesc.h>
|
||||
@@ -26,16 +26,9 @@ static void suspend_all_device_irqs(void)
|
||||
{
|
||||
struct irq_data *data;
|
||||
struct irq_desc *desc;
|
||||
unsigned int nirqs;
|
||||
int irq;
|
||||
|
||||
#if defined(NV_IRQ_GET_NR_IRQS_PRESENT) /* Linux v6.13 */
|
||||
nirqs = irq_get_nr_irqs();
|
||||
#else
|
||||
nirqs = nr_irqs;
|
||||
#endif
|
||||
|
||||
for (irq = 0, data = irq_get_irq_data(irq); irq < nirqs;
|
||||
for (irq = 0, data = irq_get_irq_data(irq); irq < nr_irqs;
|
||||
irq++, data = irq_get_irq_data(irq)) {
|
||||
if (!data)
|
||||
continue;
|
||||
@@ -51,16 +44,9 @@ static void resume_all_device_irqs(void)
|
||||
{
|
||||
struct irq_data *data;
|
||||
struct irq_desc *desc;
|
||||
unsigned int nirqs;
|
||||
int irq;
|
||||
|
||||
#if defined(NV_IRQ_GET_NR_IRQS_PRESENT)
|
||||
nirqs = irq_get_nr_irqs();
|
||||
#else
|
||||
nirqs = nr_irqs;
|
||||
#endif
|
||||
|
||||
for (irq = 0, data = irq_get_irq_data(irq); irq < nirqs;
|
||||
for (irq = 0, data = irq_get_irq_data(irq); irq < nr_irqs;
|
||||
irq++, data = irq_get_irq_data(irq)) {
|
||||
if (!data)
|
||||
continue;
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
|
||||
|
||||
#include <linux/cpu_cooling.h>
|
||||
#include <linux/cpuidle.h>
|
||||
@@ -228,21 +226,9 @@ static const struct of_device_id tegra_auto_cpuidle_of[] = {
|
||||
{ },
|
||||
};
|
||||
|
||||
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
|
||||
static void tegra_auto_cpuidle_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
tegra_auto_cpuidle_remove(pdev);
|
||||
}
|
||||
#else
|
||||
static int tegra_auto_cpuidle_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
return tegra_auto_cpuidle_remove(pdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct platform_driver tegra_auto_cpuidle_driver __refdata = {
|
||||
.probe = tegra_auto_cpuidle_probe,
|
||||
.remove = tegra_auto_cpuidle_remove_wrapper,
|
||||
.remove = tegra_auto_cpuidle_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "cpuidle_tegra_auto",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Copyright (c) 2020-2023, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Support for Tegra NVRNG Engine Error Handling.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
@@ -359,21 +357,9 @@ static const struct of_device_id tegra_se_nvrng_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_se_nvrng_of_match);
|
||||
|
||||
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
|
||||
static void tegra_se_nvrng_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
tegra_se_nvrng_remove(pdev);
|
||||
}
|
||||
#else
|
||||
static int tegra_se_nvrng_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
return tegra_se_nvrng_remove(pdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct platform_driver tegra_se_nvrng_driver = {
|
||||
.probe = tegra_se_nvrng_probe,
|
||||
.remove = tegra_se_nvrng_remove_wrapper,
|
||||
.remove = tegra_se_nvrng_remove,
|
||||
.driver = {
|
||||
.name = "tegra-se-nvrng",
|
||||
.owner = THIS_MODULE,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
ccflags-y += -I$(srctree.nvidia)/drivers/gpu/host1x/include
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,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);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* Crypto driver file to manage keys of NVIDIA Security Engine.
|
||||
*/
|
||||
@@ -16,77 +16,66 @@
|
||||
#define SE_KEY_RSVD_MASK (BIT(0) | BIT(14) | BIT(15))
|
||||
#define SE_KEY_VALID_MASK (SE_KEY_FULL_MASK & ~SE_KEY_RSVD_MASK)
|
||||
|
||||
/* Mutex lock to guard keyslots */
|
||||
static DEFINE_MUTEX(kslt_lock);
|
||||
|
||||
/* Keyslot bitmask (0 = available, 1 = in use/not available) */
|
||||
static u16 tegra_se_keyslots = SE_KEY_RSVD_MASK;
|
||||
|
||||
static u16 tegra_keyslot_alloc(void)
|
||||
{
|
||||
u16 keyid;
|
||||
|
||||
mutex_lock(&kslt_lock);
|
||||
/* Check if all key slots are full */
|
||||
if (tegra_se_keyslots == GENMASK(SE_MAX_KEYSLOT, 0)) {
|
||||
mutex_unlock(&kslt_lock);
|
||||
if (tegra_se_keyslots == GENMASK(SE_MAX_KEYSLOT, 0))
|
||||
return 0;
|
||||
}
|
||||
|
||||
keyid = ffz(tegra_se_keyslots);
|
||||
tegra_se_keyslots |= BIT(keyid);
|
||||
|
||||
mutex_unlock(&kslt_lock);
|
||||
|
||||
return keyid;
|
||||
}
|
||||
|
||||
static void tegra_keyslot_free(u16 slot)
|
||||
{
|
||||
mutex_lock(&kslt_lock);
|
||||
tegra_se_keyslots &= ~(BIT(slot));
|
||||
mutex_unlock(&kslt_lock);
|
||||
}
|
||||
|
||||
static unsigned int tegra_key_prep_ins_cmd(struct tegra_se *se, u32 *cpuvaddr,
|
||||
const u32 *key, u32 keylen, u16 slot, u32 alg)
|
||||
const u32 *key, u32 keylen, u16 slot, u32 alg)
|
||||
{
|
||||
int i = 0, j;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->op);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->op);
|
||||
cpuvaddr[i++] = SE_AES_OP_WRSTALL | SE_AES_OP_DUMMY;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->manifest);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->manifest);
|
||||
cpuvaddr[i++] = se->manifest(se->owner, alg, keylen);
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_dst);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->key_dst);
|
||||
|
||||
cpuvaddr[i++] = SE_AES_KEY_DST_INDEX(slot);
|
||||
|
||||
for (j = 0; j < keylen / 4; j++) {
|
||||
/* Set key address */
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_addr);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->key_addr);
|
||||
cpuvaddr[i++] = j;
|
||||
|
||||
/* Set key data */
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_data);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->key_data);
|
||||
cpuvaddr[i++] = key[j];
|
||||
}
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->config);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->config);
|
||||
cpuvaddr[i++] = SE_CFG_INS;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->op);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->op);
|
||||
cpuvaddr[i++] = SE_AES_OP_WRSTALL | SE_AES_OP_START |
|
||||
SE_AES_OP_LASTBUF;
|
||||
|
||||
cpuvaddr[i++] = se_host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
|
||||
cpuvaddr[i++] = host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
|
||||
cpuvaddr[i++] = host1x_uclass_incr_syncpt_cond_f(1) |
|
||||
host1x_uclass_incr_syncpt_indx_f(se->syncpt_id);
|
||||
|
||||
@@ -98,44 +87,29 @@ static unsigned int tegra_key_prep_ins_cmd(struct tegra_se *se, u32 *cpuvaddr,
|
||||
|
||||
static bool tegra_key_in_kslt(u32 keyid)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
if (keyid > SE_MAX_KEYSLOT)
|
||||
return false;
|
||||
|
||||
mutex_lock(&kslt_lock);
|
||||
ret = ((BIT(keyid) & SE_KEY_VALID_MASK) &&
|
||||
return ((BIT(keyid) & SE_KEY_VALID_MASK) &&
|
||||
(BIT(keyid) & tegra_se_keyslots));
|
||||
mutex_unlock(&kslt_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_key_insert(struct tegra_se *se, const u8 *key,
|
||||
u32 keylen, u16 slot, u32 alg)
|
||||
u32 keylen, u16 slot, u32 alg)
|
||||
{
|
||||
const u32 *keyval = (u32 *)key;
|
||||
u32 *addr = se->keybuf->addr, size;
|
||||
int ret;
|
||||
u32 *addr = se->cmdbuf->addr, size;
|
||||
|
||||
mutex_lock(&kslt_lock);
|
||||
size = tegra_key_prep_ins_cmd(se, addr, keyval, keylen, slot, alg);
|
||||
ret = tegra_se_host1x_submit(se, se->keybuf, size);
|
||||
mutex_unlock(&kslt_lock);
|
||||
|
||||
return ret;
|
||||
return tegra_se_host1x_submit(se, size);
|
||||
}
|
||||
|
||||
void tegra_key_invalidate(struct tegra_se *se, u32 keyid, u32 alg)
|
||||
void tegra_key_invalidate(struct tegra_se *se, u32 keyid)
|
||||
{
|
||||
u8 zkey[AES_MAX_KEY_SIZE] = {0};
|
||||
|
||||
if (!keyid)
|
||||
return;
|
||||
|
||||
/* Overwrite the key with 0s */
|
||||
tegra_key_insert(se, zkey, AES_MAX_KEY_SIZE, keyid, alg);
|
||||
|
||||
tegra_keyslot_free(keyid);
|
||||
}
|
||||
|
||||
@@ -146,10 +120,8 @@ int tegra_key_submit(struct tegra_se *se, const u8 *key, u32 keylen, u32 alg, u3
|
||||
/* Use the existing slot if it is already allocated */
|
||||
if (!tegra_key_in_kslt(*keyid)) {
|
||||
*keyid = tegra_keyslot_alloc();
|
||||
if (!(*keyid)) {
|
||||
dev_dbg(se->dev, "failed to allocate key slot\n");
|
||||
if (!(*keyid))
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
ret = tegra_key_insert(se, key, keylen, *keyid, alg);
|
||||
@@ -158,20 +130,3 @@ int tegra_key_submit(struct tegra_se *se, const u8 *key, u32 keylen, u32 alg, u3
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tegra_key_invalidate_reserved(struct tegra_se *se, u32 keyid, u32 alg)
|
||||
{
|
||||
u8 zkey[AES_MAX_KEY_SIZE] = {0};
|
||||
|
||||
if (!keyid)
|
||||
return;
|
||||
|
||||
/* Overwrite the key with 0s */
|
||||
tegra_key_insert(se, zkey, AES_MAX_KEY_SIZE, keyid, alg);
|
||||
}
|
||||
|
||||
inline int tegra_key_submit_reserved(struct tegra_se *se, const u8 *key,
|
||||
u32 keylen, u32 alg, u32 *keyid)
|
||||
{
|
||||
return tegra_key_insert(se, key, keylen, *keyid, alg);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* Crypto driver for NVIDIA Security Engine in Tegra Chips
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/host1x-next.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
@@ -125,7 +124,7 @@ static struct tegra_se_cmdbuf *tegra_se_host1x_bo_alloc(struct tegra_se *se, ssi
|
||||
struct tegra_se_cmdbuf *cmdbuf;
|
||||
struct device *dev = se->dev->parent;
|
||||
|
||||
cmdbuf = kzalloc(sizeof(*cmdbuf), GFP_KERNEL);
|
||||
cmdbuf = kzalloc(sizeof(struct tegra_se_cmdbuf), GFP_KERNEL);
|
||||
if (!cmdbuf)
|
||||
return NULL;
|
||||
|
||||
@@ -143,7 +142,7 @@ static struct tegra_se_cmdbuf *tegra_se_host1x_bo_alloc(struct tegra_se *se, ssi
|
||||
return cmdbuf;
|
||||
}
|
||||
|
||||
int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf, u32 size)
|
||||
int tegra_se_host1x_submit(struct tegra_se *se, u32 size)
|
||||
{
|
||||
struct host1x_job *job;
|
||||
int ret;
|
||||
@@ -154,7 +153,7 @@ int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
job->syncpt = host1x_syncpt_get(se->syncpt);
|
||||
job->syncpt = host1x_syncpt_get(se->syncpt);
|
||||
job->syncpt_incrs = 1;
|
||||
job->client = &se->client;
|
||||
job->class = se->client.class;
|
||||
@@ -162,24 +161,24 @@ int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf,
|
||||
job->engine_fallback_streamid = se->stream_id;
|
||||
job->engine_streamid_offset = SE_STREAM_ID;
|
||||
|
||||
cmdbuf->words = size;
|
||||
se->cmdbuf->words = size;
|
||||
|
||||
host1x_job_add_gather(job, &cmdbuf->bo, size, 0);
|
||||
host1x_job_add_gather(job, &se->cmdbuf->bo, size, 0);
|
||||
|
||||
ret = host1x_job_pin(job, se->dev);
|
||||
if (ret) {
|
||||
dev_err(se->dev, "failed to pin host1x job\n");
|
||||
goto job_put;
|
||||
goto err_job_pin;
|
||||
}
|
||||
|
||||
ret = host1x_job_submit(job);
|
||||
if (ret) {
|
||||
dev_err(se->dev, "failed to submit host1x job\n");
|
||||
goto job_unpin;
|
||||
goto err_job_submit;
|
||||
}
|
||||
|
||||
ret = host1x_syncpt_wait(job->syncpt, job->syncpt_end,
|
||||
MAX_SCHEDULE_TIMEOUT, NULL);
|
||||
MAX_SCHEDULE_TIMEOUT, NULL);
|
||||
if (ret) {
|
||||
dev_err(se->dev, "host1x job timed out\n");
|
||||
return ret;
|
||||
@@ -188,9 +187,9 @@ int tegra_se_host1x_submit(struct tegra_se *se, struct tegra_se_cmdbuf *cmdbuf,
|
||||
host1x_job_put(job);
|
||||
return 0;
|
||||
|
||||
job_unpin:
|
||||
err_job_submit:
|
||||
host1x_job_unpin(job);
|
||||
job_put:
|
||||
err_job_pin:
|
||||
host1x_job_put(job);
|
||||
|
||||
return ret;
|
||||
@@ -211,7 +210,7 @@ static int tegra_se_client_init(struct host1x_client *client)
|
||||
if (!se->syncpt) {
|
||||
dev_err(se->dev, "host1x syncpt allocation failed\n");
|
||||
ret = -EINVAL;
|
||||
goto channel_put;
|
||||
goto err_syncpt;
|
||||
}
|
||||
|
||||
se->syncpt_id = host1x_syncpt_id(se->syncpt);
|
||||
@@ -219,30 +218,22 @@ static int tegra_se_client_init(struct host1x_client *client)
|
||||
se->cmdbuf = tegra_se_host1x_bo_alloc(se, SZ_4K);
|
||||
if (!se->cmdbuf) {
|
||||
ret = -ENOMEM;
|
||||
goto syncpt_put;
|
||||
}
|
||||
|
||||
se->keybuf = tegra_se_host1x_bo_alloc(se, SZ_4K);
|
||||
if (!se->cmdbuf) {
|
||||
ret = -ENOMEM;
|
||||
goto cmdbuf_put;
|
||||
goto err_bo;
|
||||
}
|
||||
|
||||
ret = se->hw->init_alg(se);
|
||||
if (ret) {
|
||||
dev_err(se->dev, "failed to register algorithms\n");
|
||||
goto keybuf_put;
|
||||
goto err_alg_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
keybuf_put:
|
||||
tegra_se_cmdbuf_put(&se->keybuf->bo);
|
||||
cmdbuf_put:
|
||||
err_alg_reg:
|
||||
tegra_se_cmdbuf_put(&se->cmdbuf->bo);
|
||||
syncpt_put:
|
||||
err_bo:
|
||||
host1x_syncpt_put(se->syncpt);
|
||||
channel_put:
|
||||
err_syncpt:
|
||||
host1x_channel_put(se->channel);
|
||||
|
||||
return ret;
|
||||
@@ -252,7 +243,7 @@ static int tegra_se_client_deinit(struct host1x_client *client)
|
||||
{
|
||||
struct tegra_se *se = container_of(client, struct tegra_se, client);
|
||||
|
||||
se->hw->deinit_alg(se);
|
||||
se->hw->deinit_alg();
|
||||
tegra_se_cmdbuf_put(&se->cmdbuf->bo);
|
||||
host1x_syncpt_put(se->syncpt);
|
||||
host1x_channel_put(se->channel);
|
||||
@@ -265,7 +256,7 @@ static const struct host1x_client_ops tegra_se_client_ops = {
|
||||
.exit = tegra_se_client_deinit,
|
||||
};
|
||||
|
||||
static int tegra_se_host1x_register(struct tegra_se *se)
|
||||
int tegra_se_host1x_register(struct tegra_se *se)
|
||||
{
|
||||
INIT_LIST_HEAD(&se->client.list);
|
||||
se->client.dev = se->dev;
|
||||
@@ -278,6 +269,38 @@ static int tegra_se_host1x_register(struct tegra_se *se)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_se_clk_init(struct tegra_se *se)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
se->num_clks = devm_clk_bulk_get_all(se->dev, &se->clks);
|
||||
if (se->num_clks < 0) {
|
||||
dev_err(se->dev, "failed to get clocks\n");
|
||||
return se->num_clks;
|
||||
}
|
||||
|
||||
for (i = 0; i < se->num_clks; i++) {
|
||||
ret = clk_set_rate(se->clks[i].clk, ULONG_MAX);
|
||||
if (ret) {
|
||||
dev_err(se->dev, "failed to set %d clock rate", i);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = clk_bulk_prepare_enable(se->num_clks, se->clks);
|
||||
if (ret) {
|
||||
dev_err(se->dev, "failed to enable clocks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_se_clk_deinit(struct tegra_se *se)
|
||||
{
|
||||
clk_bulk_disable_unprepare(se->num_clks, se->clks);
|
||||
}
|
||||
|
||||
static int tegra_se_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
@@ -289,45 +312,61 @@ static int tegra_se_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
se->dev = dev;
|
||||
se->owner = TEGRA_GPSE_ID;
|
||||
se->hw = device_get_match_data(&pdev->dev);
|
||||
|
||||
se->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(se->base))
|
||||
return PTR_ERR(se->base);
|
||||
|
||||
se->owner = TEGRA_GPSE_ID;
|
||||
|
||||
dma_set_mask_and_coherent(dev, DMA_BIT_MASK(39));
|
||||
platform_set_drvdata(pdev, se);
|
||||
|
||||
se->clk = devm_clk_get_enabled(se->dev, NULL);
|
||||
if (IS_ERR(se->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(se->clk),
|
||||
"failed to enable clocks\n");
|
||||
ret = tegra_se_clk_init(se);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to init clocks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!tegra_dev_iommu_get_stream_id(dev, &se->stream_id))
|
||||
return dev_err_probe(dev, -ENODEV,
|
||||
"failed to get IOMMU stream ID\n");
|
||||
if (!tegra_dev_iommu_get_stream_id(dev, &se->stream_id)) {
|
||||
dev_err(dev, "failed to get IOMMU stream ID\n");
|
||||
goto err_iommu_spec;
|
||||
}
|
||||
|
||||
writel(se->stream_id, se->base + SE_STREAM_ID);
|
||||
se_writel(se, se->stream_id, SE_STREAM_ID);
|
||||
|
||||
se->engine = crypto_engine_alloc_init(dev, 0);
|
||||
if (!se->engine)
|
||||
return dev_err_probe(dev, -ENOMEM, "failed to init crypto engine\n");
|
||||
if (!se->engine) {
|
||||
dev_err(dev, "failed to init crypto engine\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_engine_alloc;
|
||||
}
|
||||
|
||||
ret = crypto_engine_start(se->engine);
|
||||
if (ret) {
|
||||
crypto_engine_exit(se->engine);
|
||||
return dev_err_probe(dev, ret, "failed to start crypto engine\n");
|
||||
dev_err(dev, "failed to start crypto engine\n");
|
||||
goto err_engine_start;
|
||||
}
|
||||
|
||||
ret = tegra_se_host1x_register(se);
|
||||
if (ret) {
|
||||
crypto_engine_stop(se->engine);
|
||||
crypto_engine_exit(se->engine);
|
||||
return dev_err_probe(dev, ret, "failed to init host1x params\n");
|
||||
dev_err(dev, "failed to init host1x params\n");
|
||||
goto err_host1x_init;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_host1x_init:
|
||||
crypto_engine_stop(se->engine);
|
||||
err_engine_start:
|
||||
crypto_engine_exit(se->engine);
|
||||
err_engine_alloc:
|
||||
iommu_fwspec_free(se->dev);
|
||||
err_iommu_spec:
|
||||
tegra_se_clk_deinit(se);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tegra_se_remove(struct platform_device *pdev)
|
||||
@@ -338,6 +377,7 @@ static int tegra_se_remove(struct platform_device *pdev)
|
||||
crypto_engine_exit(se->engine);
|
||||
iommu_fwspec_free(se->dev);
|
||||
host1x_client_unregister(&se->client);
|
||||
tegra_se_clk_deinit(se);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -384,35 +424,23 @@ static const struct tegra_se_hw tegra234_hash_hw = {
|
||||
|
||||
static const struct of_device_id tegra_se_of_match[] = {
|
||||
{
|
||||
.compatible = "nvidia,tegra234-se-aes",
|
||||
.compatible = "nvidia,tegra234-se2-aes",
|
||||
.data = &tegra234_aes_hw
|
||||
}, {
|
||||
.compatible = "nvidia,tegra234-se-hash",
|
||||
.compatible = "nvidia,tegra234-se4-hash",
|
||||
.data = &tegra234_hash_hw,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, tegra_se_of_match);
|
||||
|
||||
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
|
||||
static void tegra_se_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
tegra_se_remove(pdev);
|
||||
}
|
||||
#else
|
||||
static int tegra_se_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
return tegra_se_remove(pdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct platform_driver tegra_se_driver = {
|
||||
.driver = {
|
||||
.name = "tegra-se",
|
||||
.of_match_table = tegra_se_of_match,
|
||||
},
|
||||
.probe = tegra_se_probe,
|
||||
.remove = tegra_se_remove_wrapper,
|
||||
.remove = tegra_se_remove,
|
||||
};
|
||||
|
||||
static int tegra_se_host1x_probe(struct host1x_device *dev)
|
||||
@@ -458,4 +486,4 @@ module_exit(tegra_se_module_exit);
|
||||
|
||||
MODULE_DESCRIPTION("NVIDIA Tegra Security Engine Driver");
|
||||
MODULE_AUTHOR("Akhil R <akhilrajeev@nvidia.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023 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*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ static inline int tegra_ivc_check_read(struct tegra_ivc *ivc)
|
||||
tegra_ivc_invalidate(ivc, ivc->rx.phys + offset);
|
||||
|
||||
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP)
|
||||
if (tegra_ivc_empty(ivc, &ivc->rx.map))
|
||||
if (!tegra_ivc_empty(ivc, &ivc->rx.map))
|
||||
#else
|
||||
if (tegra_ivc_empty(ivc, ivc->rx.channel))
|
||||
#endif
|
||||
@@ -229,7 +229,7 @@ static inline int tegra_ivc_check_write(struct tegra_ivc *ivc)
|
||||
tegra_ivc_invalidate(ivc, ivc->tx.phys + offset);
|
||||
|
||||
#if defined(NV_TEGRA_IVC_STRUCT_HAS_IOSYS_MAP)
|
||||
if (tegra_ivc_full(ivc, &ivc->tx.map))
|
||||
if (!tegra_ivc_full(ivc, &ivc->tx.map))
|
||||
#else
|
||||
if (tegra_ivc_full(ivc, ivc->tx.channel))
|
||||
#endif
|
||||
|
||||
@@ -1,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
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ static inline struct device *
|
||||
tegra_drm_context_get_memory_device(struct tegra_drm_context *context)
|
||||
{
|
||||
if (context->memory_context)
|
||||
return context->memory_context->context_dev;
|
||||
return &context->memory_context->dev;
|
||||
else
|
||||
return context->client->base.dev;
|
||||
}
|
||||
|
||||
@@ -1,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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2021-2023, NVIDIA Corporation.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/devfreq.h>
|
||||
@@ -634,18 +632,6 @@ static const struct dev_pm_ops ofa_pm_ops = {
|
||||
pm_runtime_force_resume)
|
||||
};
|
||||
|
||||
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
|
||||
static void ofa_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
ofa_remove(pdev);
|
||||
}
|
||||
#else
|
||||
static int ofa_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
return ofa_remove(pdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct platform_driver tegra_ofa_driver = {
|
||||
.driver = {
|
||||
.name = "tegra-ofa",
|
||||
@@ -653,7 +639,7 @@ struct platform_driver tegra_ofa_driver = {
|
||||
.pm = &ofa_pm_ops
|
||||
},
|
||||
.probe = ofa_probe,
|
||||
.remove = ofa_remove_wrapper,
|
||||
.remove = ofa_remove,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC)
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* Copyright (c) 2022, NVIDIA Corporation.
|
||||
*/
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <linux/dev_printk.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2013-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Copyright (C) 2013 NVIDIA Corporation
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -240,14 +240,9 @@ static int submit_write_reloc(struct tegra_drm_context *context, struct gather_b
|
||||
struct drm_tegra_submit_buf *buf, struct tegra_drm_mapping *mapping)
|
||||
{
|
||||
/* TODO check that target_offset is within bounds */
|
||||
dma_addr_t iova = buf->reloc.target_offset;
|
||||
dma_addr_t iova = mapping->iova + buf->reloc.target_offset;
|
||||
u32 written_ptr;
|
||||
|
||||
if (mapping->bo_map)
|
||||
iova += mapping->iova;
|
||||
else
|
||||
iova += mapping->ctx_map->mapping->phys;
|
||||
|
||||
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
|
||||
if (buf->flags & DRM_TEGRA_SUBMIT_RELOC_SECTOR_LAYOUT)
|
||||
iova |= BIT_ULL(39);
|
||||
@@ -531,6 +526,9 @@ static void release_job(struct host1x_job *job)
|
||||
struct tegra_drm_submit_data *job_data = job->user_data;
|
||||
u32 i;
|
||||
|
||||
if (job->memory_context)
|
||||
host1x_memory_context_put(job->memory_context);
|
||||
|
||||
if (IS_ENABLED(CONFIG_TRACING) && job_data->timestamps.virt) {
|
||||
u64 *timestamps = job_data->timestamps.virt;
|
||||
|
||||
@@ -544,11 +542,6 @@ static void release_job(struct host1x_job *job)
|
||||
for (i = 0; i < job_data->num_used_mappings; i++)
|
||||
tegra_drm_mapping_put(job_data->used_mappings[i].mapping);
|
||||
|
||||
if (job->memory_context) {
|
||||
host1x_memory_context_inactive(job->memory_context);
|
||||
host1x_memory_context_put(job->memory_context);
|
||||
}
|
||||
|
||||
kfree(job_data->used_mappings);
|
||||
kfree(job_data);
|
||||
|
||||
@@ -588,7 +581,6 @@ static int submit_init_profiling(struct tegra_drm_context *context,
|
||||
int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data,
|
||||
struct drm_file *file)
|
||||
{
|
||||
struct host1x_memory_context *active_memctx = NULL;
|
||||
struct tegra_drm_file *fpriv = file->driver_priv;
|
||||
struct drm_tegra_channel_submit *args = data;
|
||||
static atomic_t next_job_id = ATOMIC_INIT(1);
|
||||
@@ -612,17 +604,6 @@ int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (context->memory_context) {
|
||||
err = host1x_memory_context_active(context->memory_context);
|
||||
if (err) {
|
||||
mutex_unlock(&fpriv->lock);
|
||||
SUBMIT_ERR(context, "failed to activate memory context");
|
||||
return err;
|
||||
}
|
||||
|
||||
active_memctx = context->memory_context;
|
||||
}
|
||||
|
||||
if (args->flags & ~(DRM_TEGRA_SUBMIT_SECONDARY_SYNCPT)) {
|
||||
SUBMIT_ERR(context, "invalid flags '%#x'", args->flags);
|
||||
goto unlock;
|
||||
@@ -723,8 +704,7 @@ int tegra_drm_ioctl_channel_submit(struct drm_device *drm, void *data,
|
||||
}
|
||||
|
||||
if (supported) {
|
||||
job->memory_context = active_memctx;
|
||||
active_memctx = NULL;
|
||||
job->memory_context = context->memory_context;
|
||||
host1x_memory_context_get(job->memory_context);
|
||||
}
|
||||
} else if (context->client->ops->get_streamid_offset) {
|
||||
@@ -845,8 +825,6 @@ put_bo:
|
||||
unlock:
|
||||
if (syncobj)
|
||||
drm_syncobj_put(syncobj);
|
||||
if (active_memctx)
|
||||
host1x_memory_context_inactive(active_memctx);
|
||||
|
||||
mutex_unlock(&fpriv->lock);
|
||||
return err;
|
||||
|
||||
@@ -17,11 +17,7 @@ static void tegra_drm_mapping_release(struct kref *ref)
|
||||
struct tegra_drm_mapping *mapping =
|
||||
container_of(ref, struct tegra_drm_mapping, ref);
|
||||
|
||||
if (mapping->ctx_map)
|
||||
host1x_memory_context_unmap(mapping->ctx_map);
|
||||
else
|
||||
host1x_bo_unpin(mapping->bo_map);
|
||||
|
||||
host1x_bo_unpin(mapping->map);
|
||||
host1x_bo_put(mapping->bo);
|
||||
|
||||
kfree(mapping);
|
||||
@@ -37,12 +33,12 @@ static void tegra_drm_channel_context_close(struct tegra_drm_context *context)
|
||||
struct tegra_drm_mapping *mapping;
|
||||
unsigned long id;
|
||||
|
||||
xa_for_each(&context->mappings, id, mapping)
|
||||
tegra_drm_mapping_put(mapping);
|
||||
|
||||
if (context->memory_context)
|
||||
host1x_memory_context_put(context->memory_context);
|
||||
|
||||
xa_for_each(&context->mappings, id, mapping)
|
||||
tegra_drm_mapping_put(mapping);
|
||||
|
||||
xa_destroy(&context->mappings);
|
||||
|
||||
host1x_channel_put(context->channel);
|
||||
@@ -238,27 +234,16 @@ int tegra_drm_ioctl_channel_map(struct drm_device *drm, void *data, struct drm_f
|
||||
goto put_gem;
|
||||
}
|
||||
|
||||
if (context->memory_context) {
|
||||
mapping->ctx_map = host1x_memory_context_map(
|
||||
context->memory_context, mapping->bo, direction);
|
||||
|
||||
if (IS_ERR(mapping->ctx_map)) {
|
||||
err = PTR_ERR(mapping->ctx_map);
|
||||
goto put_gem;
|
||||
}
|
||||
} else {
|
||||
mapping->bo_map = host1x_bo_pin(context->client->base.dev,
|
||||
mapping->bo, direction, NULL);
|
||||
|
||||
if (IS_ERR(mapping->bo_map)) {
|
||||
err = PTR_ERR(mapping->bo_map);
|
||||
goto put_gem;
|
||||
}
|
||||
|
||||
mapping->iova = mapping->bo_map->phys;
|
||||
mapping->iova_end = mapping->iova + host1x_to_tegra_bo(mapping->bo)->gem.size;
|
||||
mapping->map = host1x_bo_pin(tegra_drm_context_get_memory_device(context),
|
||||
mapping->bo, direction, NULL);
|
||||
if (IS_ERR(mapping->map)) {
|
||||
err = PTR_ERR(mapping->map);
|
||||
goto put_gem;
|
||||
}
|
||||
|
||||
mapping->iova = mapping->map->phys;
|
||||
mapping->iova_end = mapping->iova + host1x_to_tegra_bo(mapping->bo)->gem.size;
|
||||
|
||||
err = xa_alloc(&context->mappings, &args->mapping, mapping, XA_LIMIT(1, U32_MAX),
|
||||
GFP_KERNEL);
|
||||
if (err < 0)
|
||||
@@ -269,10 +254,7 @@ int tegra_drm_ioctl_channel_map(struct drm_device *drm, void *data, struct drm_f
|
||||
return 0;
|
||||
|
||||
unpin:
|
||||
if (mapping->ctx_map)
|
||||
host1x_memory_context_unmap(mapping->ctx_map);
|
||||
else
|
||||
host1x_bo_unpin(mapping->bo_map);
|
||||
host1x_bo_unpin(mapping->map);
|
||||
put_gem:
|
||||
host1x_bo_put(mapping->bo);
|
||||
free:
|
||||
|
||||
@@ -27,8 +27,7 @@ struct tegra_drm_file {
|
||||
struct tegra_drm_mapping {
|
||||
struct kref ref;
|
||||
|
||||
struct host1x_bo_mapping *bo_map;
|
||||
struct host1x_context_mapping *ctx_map;
|
||||
struct host1x_bo_mapping *map;
|
||||
struct host1x_bo *bo;
|
||||
|
||||
dma_addr_t iova;
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2015-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* SPDX-FileCopyrightText: Copyright (C) 2015-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)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
/*
|
||||
* Copyright (c) 2023, NVIDIA Corporation.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/debugfs.h>
|
||||
@@ -563,18 +563,6 @@ static const struct dev_pm_ops virt_engine_pm_ops = {
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
|
||||
static void virt_engine_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
virt_engine_remove(pdev);
|
||||
}
|
||||
#else
|
||||
static int virt_engine_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
return virt_engine_remove(pdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct platform_driver tegra_virt_engine_driver = {
|
||||
.driver = {
|
||||
.name = "tegra-host1x-virtual-engine",
|
||||
@@ -582,5 +570,5 @@ struct platform_driver tegra_virt_engine_driver = {
|
||||
.pm = &virt_engine_pm_ops,
|
||||
},
|
||||
.probe = virt_engine_probe,
|
||||
.remove = virt_engine_remove_wrapper,
|
||||
.remove = virt_engine_remove,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* Host1x fence UAPI
|
||||
*
|
||||
* Copyright (c) 2022-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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/*
|
||||
* Host1x context devices
|
||||
*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Copyright (c) 2020, NVIDIA Corporation.
|
||||
*/
|
||||
|
||||
#ifndef __HOST1X_CONTEXT_H
|
||||
@@ -17,24 +17,8 @@ extern struct bus_type host1x_context_device_bus_type;
|
||||
|
||||
struct host1x_memory_context_list {
|
||||
struct mutex lock;
|
||||
struct host1x_hw_memory_context *devs;
|
||||
struct host1x_memory_context *devs;
|
||||
unsigned int len;
|
||||
struct list_head waiters;
|
||||
};
|
||||
|
||||
struct host1x_hw_memory_context {
|
||||
struct host1x *host;
|
||||
|
||||
refcount_t ref;
|
||||
struct pid *owner;
|
||||
|
||||
struct device_dma_parameters dma_parms;
|
||||
struct device dev;
|
||||
u64 dma_mask;
|
||||
u32 stream_id;
|
||||
|
||||
struct list_head owners;
|
||||
unsigned int active;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IOMMU_API
|
||||
|
||||
@@ -2,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[] = {
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <trace/events/host1x.h>
|
||||
|
||||
#include "../channel.h"
|
||||
#include "../context.h"
|
||||
#include "../dev.h"
|
||||
#include "../intr.h"
|
||||
#include "../job.h"
|
||||
@@ -90,7 +89,7 @@ static void submit_setclass(struct host1x_job *job, u32 next_class)
|
||||
* firmware stream ID.
|
||||
*/
|
||||
if (job->memory_context)
|
||||
stream_id = job->memory_context->hw->stream_id;
|
||||
stream_id = job->memory_context->stream_id;
|
||||
else
|
||||
stream_id = job->engine_fallback_streamid;
|
||||
|
||||
|
||||
@@ -177,14 +177,7 @@ static void show_gather(struct output *o, dma_addr_t phys_addr,
|
||||
|
||||
for (i = 0; i < words; i++) {
|
||||
dma_addr_t addr = phys_addr + i * 4;
|
||||
u32 voffset = offset + i * 4;
|
||||
u32 val;
|
||||
|
||||
/* If we reach the RESTART opcode, continue at the beginning of pushbuffer */
|
||||
if (cdma && voffset >= cdma->push_buffer.size)
|
||||
voffset -= cdma->push_buffer.size;
|
||||
|
||||
val = *(map_addr + voffset / 4);
|
||||
u32 val = *(map_addr + offset / 4 + i);
|
||||
|
||||
if (!data_count) {
|
||||
host1x_debug_output(o, " %pad: %08x: ", &addr, val);
|
||||
@@ -210,7 +203,7 @@ static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma)
|
||||
job->num_slots, job->num_unpins);
|
||||
|
||||
show_gather(o, pb->dma + job->first_get, job->num_slots * 2, cdma,
|
||||
pb->dma, pb->mapped);
|
||||
pb->dma + job->first_get, pb->mapped + job->first_get);
|
||||
|
||||
for (i = 0; i < job->num_cmds; i++) {
|
||||
struct host1x_job_gather *g;
|
||||
@@ -234,7 +227,7 @@ static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma)
|
||||
host1x_debug_output(o, " GATHER at %pad+%#x, %d words\n",
|
||||
&g->base, g->offset, g->words);
|
||||
|
||||
show_gather(o, g->base + g->offset, g->words, NULL,
|
||||
show_gather(o, g->base + g->offset, g->words, cdma,
|
||||
g->base, mapped);
|
||||
|
||||
if (!job->gather_copy_mapped)
|
||||
|
||||
@@ -495,26 +495,12 @@ int tegra_mipi_finish_calibration(struct tegra_mipi_device *device);
|
||||
struct host1x_memory_context {
|
||||
struct host1x *host;
|
||||
|
||||
struct device *dev; /* Owning engine */
|
||||
struct pid *pid;
|
||||
|
||||
refcount_t ref;
|
||||
struct pid *owner;
|
||||
|
||||
struct host1x_hw_memory_context *hw;
|
||||
struct device *context_dev; /* Context device */
|
||||
struct list_head entry; /* Entry in hw_memory_context's list */
|
||||
struct list_head mappings; /* List of mappings */
|
||||
};
|
||||
|
||||
struct host1x_context_mapping {
|
||||
struct host1x *host;
|
||||
|
||||
struct host1x_bo_mapping *mapping;
|
||||
|
||||
struct host1x_bo *bo;
|
||||
enum dma_data_direction direction;
|
||||
|
||||
struct list_head entry;
|
||||
struct device dev;
|
||||
u64 dma_mask;
|
||||
u32 stream_id;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_IOMMU_API
|
||||
@@ -523,11 +509,6 @@ struct host1x_memory_context *host1x_memory_context_alloc(struct host1x *host1x,
|
||||
struct pid *pid);
|
||||
void host1x_memory_context_get(struct host1x_memory_context *cd);
|
||||
void host1x_memory_context_put(struct host1x_memory_context *cd);
|
||||
int host1x_memory_context_active(struct host1x_memory_context *cd);
|
||||
void host1x_memory_context_inactive(struct host1x_memory_context *cd);
|
||||
struct host1x_context_mapping *host1x_memory_context_map(
|
||||
struct host1x_memory_context *ctx, struct host1x_bo *bo, enum dma_data_direction direction);
|
||||
void host1x_memory_context_unmap(struct host1x_context_mapping *m);
|
||||
#else
|
||||
static inline struct host1x_memory_context *host1x_memory_context_alloc(struct host1x *host1x,
|
||||
struct pid *pid)
|
||||
@@ -542,25 +523,6 @@ static inline void host1x_memory_context_get(struct host1x_memory_context *cd)
|
||||
static inline void host1x_memory_context_put(struct host1x_memory_context *cd)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int host1x_memory_context_active(struct host1x_memory_context *cd)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline void host1x_memory_context_inactive(struct host1x_memory_context *cd)
|
||||
{
|
||||
}
|
||||
|
||||
static inline struct host1x_context_mapping *host1x_memory_context_map(
|
||||
struct host1x_memory_context *ctx, struct host1x_bo *bo, enum dma_data_direction direction)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static inline void host1x_memory_context_unmap(struct host1x_context_mapping *m)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
int host1x_actmon_read_avg_count(struct host1x_client *client);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2013-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Copyright (C) 2013 NVIDIA Corporation
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
@@ -20,8 +20,6 @@
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/host1x-next.h>
|
||||
#include <linux/io.h>
|
||||
@@ -548,23 +546,11 @@ static int tegra_mipi_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(NV_PLATFORM_DRIVER_STRUCT_REMOVE_RETURNS_VOID) /* Linux v6.11 */
|
||||
static void tegra_mipi_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
tegra_mipi_remove(pdev);
|
||||
}
|
||||
#else
|
||||
static int tegra_mipi_remove_wrapper(struct platform_device *pdev)
|
||||
{
|
||||
return tegra_mipi_remove(pdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct platform_driver tegra_mipi_driver = {
|
||||
.driver = {
|
||||
.name = "tegra-mipi",
|
||||
.of_match_table = tegra_mipi_of_match,
|
||||
},
|
||||
.probe = tegra_mipi_probe,
|
||||
.remove = tegra_mipi_remove_wrapper,
|
||||
.remove = tegra_mipi_remove,
|
||||
};
|
||||
|
||||
@@ -1,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", ®_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,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (c) 2022-2025, NVIDIA CORPORATION. All rights reserved.
|
||||
# Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
|
||||
|
||||
obj-m += i2c-nvvrs11.o
|
||||
obj-m += i2c-tegra-slave-byte.o
|
||||
|
||||
@@ -2,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);
|
||||
|
||||
@@ -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");
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* SPDX-FileCopyrightText: Copyright (c) 2020-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
|
||||
/*
|
||||
* imx477_mode_tbls.h - imx477 sensor mode tables
|
||||
* Copyright (c) 2020-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __IMX477_I2C_TABLES__
|
||||
@@ -575,9 +575,249 @@ static const imx477_reg imx477_mode_1920x1080_60fps[] = {
|
||||
{IMX477_TABLE_END, 0x0000}
|
||||
};
|
||||
|
||||
static const imx477_reg imx477_mode_3840x2160_30fps_4lane[] = {
|
||||
{0x0112, 0x0A},
|
||||
{0x0113, 0x0A},
|
||||
{0x0114, 0x03},
|
||||
{0x0342, 0x16},
|
||||
{0x0343, 0xC8},
|
||||
{0x0340, 0x12},
|
||||
{0x0341, 0xC0},
|
||||
{0x0344, 0x00},
|
||||
{0x0345, 0x00},
|
||||
{0x0346, 0x01},
|
||||
{0x0347, 0xB8},
|
||||
{0x0348, 0x0F},
|
||||
{0x0349, 0xD7},
|
||||
{0x034A, 0x0A},
|
||||
{0x034B, 0x27},
|
||||
{0x00E3, 0x00},
|
||||
{0x00E4, 0x00},
|
||||
{0x00FC, 0x0A},
|
||||
{0x00FD, 0x0A},
|
||||
{0x00FE, 0x0A},
|
||||
{0x00FF, 0x0A},
|
||||
{0x0E13, 0x00},
|
||||
{0x0220, 0x00},
|
||||
{0x0221, 0x11},
|
||||
{0x0381, 0x01},
|
||||
{0x0383, 0x01},
|
||||
{0x0385, 0x01},
|
||||
{0x0387, 0x01},
|
||||
{0x0900, 0x00},
|
||||
{0x0901, 0x11},
|
||||
{0x0902, 0x02},
|
||||
{0x3140, 0x02},
|
||||
{0x3C00, 0x00},
|
||||
{0x3C01, 0x03},
|
||||
{0x3C02, 0xDC},
|
||||
{0x3F0D, 0x00},
|
||||
{0x5748, 0x07},
|
||||
{0x5749, 0xFF},
|
||||
{0x574A, 0x00},
|
||||
{0x574B, 0x00},
|
||||
{0x7B75, 0x0E},
|
||||
{0x7B76, 0x09},
|
||||
{0x7B77, 0x0C},
|
||||
{0x7B78, 0x06},
|
||||
{0x7B79, 0x3B},
|
||||
{0x7B53, 0x01},
|
||||
{0x9369, 0x5A},
|
||||
{0x936B, 0x55},
|
||||
{0x936D, 0x28},
|
||||
{0x9304, 0x03},
|
||||
{0x9305, 0x00},
|
||||
{0x9E9A, 0x2F},
|
||||
{0x9E9B, 0x2F},
|
||||
{0x9E9C, 0x2F},
|
||||
{0x9E9D, 0x00},
|
||||
{0x9E9E, 0x00},
|
||||
{0x9E9F, 0x00},
|
||||
{0xA2A9, 0x60},
|
||||
{0xA2B7, 0x00},
|
||||
{0x0401, 0x00},
|
||||
{0x0404, 0x00},
|
||||
{0x0405, 0x10},
|
||||
{0x0408, 0x00},
|
||||
{0x0409, 0x6C},
|
||||
{0x040A, 0x00},
|
||||
{0x040B, 0x00},
|
||||
{0x040C, 0x0F},
|
||||
{0x040D, 0x00},
|
||||
{0x040E, 0x08},
|
||||
{0x040F, 0x70},
|
||||
{0x034C, 0x0F},
|
||||
{0x034D, 0x00},
|
||||
{0x034E, 0x08},
|
||||
{0x034F, 0x70},
|
||||
{0x0301, 0x05},
|
||||
{0x0303, 0x02},
|
||||
{0x0305, 0x02},
|
||||
{0x0306, 0x00},
|
||||
{0x0307, 0xAF},
|
||||
{0x0309, 0x0A},
|
||||
{0x030B, 0x01},
|
||||
{0x030D, 0x02},
|
||||
{0x030E, 0x00},
|
||||
{0x030F, 0x7D},
|
||||
{0x0310, 0x01},
|
||||
{0x0820, 0x17},
|
||||
{0x0821, 0x70},
|
||||
{0x0822, 0x00},
|
||||
{0x0823, 0x00},
|
||||
{0x080A, 0x00},
|
||||
{0x080B, 0x97},
|
||||
{0x080C, 0x00},
|
||||
{0x080D, 0x5F},
|
||||
{0x080E, 0x00},
|
||||
{0x080F, 0x9F},
|
||||
{0x0810, 0x00},
|
||||
{0x0811, 0x6F},
|
||||
{0x0812, 0x00},
|
||||
{0x0813, 0x6F},
|
||||
{0x0814, 0x00},
|
||||
{0x0815, 0x57},
|
||||
{0x0816, 0x01},
|
||||
{0x0817, 0x87},
|
||||
{0x0818, 0x00},
|
||||
{0x0819, 0x4F},
|
||||
{0xE04C, 0x00},
|
||||
{0xE04D, 0x9F},
|
||||
{0xE04E, 0x00},
|
||||
{0xE04F, 0x1F},
|
||||
{0x3E20, 0x01},
|
||||
{0x3E37, 0x00},
|
||||
{0x3F50, 0x00},
|
||||
{0x3F56, 0x00},
|
||||
{0x3F57, 0xA7},
|
||||
{IMX477_TABLE_WAIT_MS, IMX477_WAIT_MS},
|
||||
{IMX477_TABLE_END, 0x0000}
|
||||
};
|
||||
|
||||
static const imx477_reg imx477_mode_1920x1080_60fps_4lane[] = {
|
||||
{0x0112, 0x0A},
|
||||
{0x0113, 0x0A},
|
||||
{0x0114, 0x03},
|
||||
{0x0342, 0x0C},
|
||||
{0x0343, 0x04},
|
||||
{0x0340, 0x11},
|
||||
{0x0341, 0xC6},
|
||||
{0x0344, 0x00},
|
||||
{0x0345, 0x00},
|
||||
{0x0346, 0x01},
|
||||
{0x0347, 0xB8},
|
||||
{0x0348, 0x0F},
|
||||
{0x0349, 0xD7},
|
||||
{0x034A, 0x0A},
|
||||
{0x034B, 0x27},
|
||||
{0x00E3, 0x00},
|
||||
{0x00E4, 0x00},
|
||||
{0x00FC, 0x0A},
|
||||
{0x00FD, 0x0A},
|
||||
{0x00FE, 0x0A},
|
||||
{0x00FF, 0x0A},
|
||||
{0x0220, 0x00},
|
||||
{0x0221, 0x11},
|
||||
{0x0381, 0x01},
|
||||
{0x0383, 0x01},
|
||||
{0x0385, 0x01},
|
||||
{0x0387, 0x01},
|
||||
{0x0900, 0x01},
|
||||
{0x0901, 0x22},
|
||||
{0x0902, 0x02},
|
||||
{0x3140, 0x02},
|
||||
{0x3C00, 0x00},
|
||||
{0x3C01, 0x01},
|
||||
{0x3C02, 0x9C},
|
||||
{0x3F0D, 0x00},
|
||||
{0x5748, 0x00},
|
||||
{0x5749, 0x00},
|
||||
{0x574A, 0x00},
|
||||
{0x574B, 0xA4},
|
||||
{0x7B75, 0x0E},
|
||||
{0x7B76, 0x09},
|
||||
{0x7B77, 0x08},
|
||||
{0x7B78, 0x06},
|
||||
{0x7B79, 0x34},
|
||||
{0x7B53, 0x00},
|
||||
{0x9369, 0x73},
|
||||
{0x936B, 0x64},
|
||||
{0x936D, 0x5F},
|
||||
{0x9304, 0x03},
|
||||
{0x9305, 0x80},
|
||||
{0x9E9A, 0x2F},
|
||||
{0x9E9B, 0x2F},
|
||||
{0x9E9C, 0x2F},
|
||||
{0x9E9D, 0x00},
|
||||
{0x9E9E, 0x00},
|
||||
{0x9E9F, 0x00},
|
||||
{0xA2A9, 0x27},
|
||||
{0xA2B7, 0x03},
|
||||
{0x0401, 0x00},
|
||||
{0x0404, 0x00},
|
||||
{0x0405, 0x10},
|
||||
{0x0408, 0x00},
|
||||
{0x0409, 0x36},
|
||||
{0x040A, 0x00},
|
||||
{0x040B, 0x00},
|
||||
{0x040C, 0x07},
|
||||
{0x040D, 0x80},
|
||||
{0x040E, 0x04},
|
||||
{0x040F, 0x38},
|
||||
{0x034C, 0x07},
|
||||
{0x034D, 0x80},
|
||||
{0x034E, 0x04},
|
||||
{0x034F, 0x38},
|
||||
{0x0301, 0x05},
|
||||
{0x0303, 0x02},
|
||||
{0x0305, 0x02},
|
||||
{0x0306, 0x00},
|
||||
{0x0307, 0xAF},
|
||||
{0x0309, 0x0A},
|
||||
{0x030B, 0x01},
|
||||
{0x030D, 0x02},
|
||||
{0x030E, 0x00},
|
||||
{0x030F, 0x7D},
|
||||
{0x0310, 0x01},
|
||||
{0x0820, 0x17},
|
||||
{0x0821, 0x70},
|
||||
{0x0822, 0x00},
|
||||
{0x0823, 0x00},
|
||||
{0x080A, 0x00},
|
||||
{0x080B, 0x97},
|
||||
{0x080C, 0x00},
|
||||
{0x080D, 0x5F},
|
||||
{0x080E, 0x00},
|
||||
{0x080F, 0x9F},
|
||||
{0x0810, 0x00},
|
||||
{0x0811, 0x6F},
|
||||
{0x0812, 0x00},
|
||||
{0x0813, 0x6F},
|
||||
{0x0814, 0x00},
|
||||
{0x0815, 0x57},
|
||||
{0x0816, 0x01},
|
||||
{0x0817, 0x87},
|
||||
{0x0818, 0x00},
|
||||
{0x0819, 0x4F},
|
||||
{0xE04C, 0x00},
|
||||
{0xE04D, 0x9F},
|
||||
{0xE04E, 0x00},
|
||||
{0xE04F, 0x1F},
|
||||
{0x3E20, 0x01},
|
||||
{0x3E37, 0x00},
|
||||
{0x3F50, 0x00},
|
||||
{0x3F56, 0x00},
|
||||
{0x3F57, 0x58},
|
||||
{0X3FF9, 0x01},
|
||||
{IMX477_TABLE_WAIT_MS, IMX477_WAIT_MS},
|
||||
{IMX477_TABLE_END, 0x0000}
|
||||
};
|
||||
|
||||
enum {
|
||||
IMX477_MODE_3840x2160_30FPS,
|
||||
IMX477_MODE_1920x1080_60FPS,
|
||||
IMX477_MODE_3840x2160_30FPS_4LANE,
|
||||
IMX477_MODE_1920x1080_60FPS_4LANE,
|
||||
IMX477_MODE_COMMON,
|
||||
IMX477_START_STREAM,
|
||||
IMX477_STOP_STREAM,
|
||||
@@ -586,6 +826,8 @@ enum {
|
||||
static const imx477_reg *mode_table[] = {
|
||||
[IMX477_MODE_3840x2160_30FPS] = imx477_mode_3840x2160_30fps,
|
||||
[IMX477_MODE_1920x1080_60FPS] = imx477_mode_1920x1080_60fps,
|
||||
[IMX477_MODE_3840x2160_30FPS_4LANE] = imx477_mode_3840x2160_30fps_4lane,
|
||||
[IMX477_MODE_1920x1080_60FPS_4LANE] = imx477_mode_1920x1080_60fps_4lane,
|
||||
[IMX477_MODE_COMMON] = imx477_mode_common,
|
||||
[IMX477_START_STREAM] = imx477_start,
|
||||
[IMX477_STOP_STREAM] = imx477_stop,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* max929x.c - max929x IO Expander driver
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <media/camera_common.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include "max929x.h"
|
||||
|
||||
struct max929x {
|
||||
struct i2c_client *i2c_client;
|
||||
struct regmap *regmap;
|
||||
unsigned int pwdn_gpio;
|
||||
unsigned short ser_addr;
|
||||
};
|
||||
struct max929x *priv;
|
||||
|
||||
static int max929x_write_reg(u8 slave_addr, u16 reg, u8 val)
|
||||
{
|
||||
struct i2c_client *i2c_client = priv->i2c_client;
|
||||
int err;
|
||||
|
||||
i2c_client->addr = slave_addr;
|
||||
err = regmap_write(priv->regmap, reg, val);
|
||||
if (err)
|
||||
dev_err(&i2c_client->dev, "%s:i2c write failed, slave_addr 0x%x, 0x%x = 0x%x\n",
|
||||
__func__, slave_addr, reg, val);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int max929x_write_reg_list(struct max929x_reg *table, int size)
|
||||
{
|
||||
struct device dev = priv->i2c_client->dev;
|
||||
int err = 0;
|
||||
int i;
|
||||
u8 slave_addr;
|
||||
u16 reg;
|
||||
u8 val;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (table[i].slave_addr == SER_SLAVE2)
|
||||
slave_addr = priv->ser_addr;
|
||||
else
|
||||
slave_addr = table[i].slave_addr;
|
||||
|
||||
reg = table[i].reg;
|
||||
val = table[i].val;
|
||||
|
||||
if (slave_addr == 0xf1) {
|
||||
msleep(val);
|
||||
msleep(2000);
|
||||
continue;
|
||||
}
|
||||
|
||||
dev_dbg(&dev, "%s: size %d, slave_addr 0x%x, reg 0x%x, val 0x%x\n",
|
||||
__func__, size, slave_addr, reg, val);
|
||||
|
||||
err = max929x_write_reg(slave_addr, reg, val);
|
||||
if (err != 0)
|
||||
break;
|
||||
mdelay(5);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct regmap_config max929x_regmap_config = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int max929x_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int max929x_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
#endif
|
||||
{
|
||||
struct device dev = client->dev;
|
||||
struct device_node *np = (&dev)->of_node;
|
||||
unsigned short ser_addr = SER_SLAVE2;
|
||||
int err;
|
||||
|
||||
dev_dbg(&dev, "%s: enter\n", __func__);
|
||||
|
||||
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
|
||||
priv->i2c_client = client;
|
||||
priv->regmap = devm_regmap_init_i2c(priv->i2c_client, &max929x_regmap_config);
|
||||
if (IS_ERR(priv->regmap)) {
|
||||
dev_err(&client->dev,
|
||||
"regmap init failed: %ld\n", PTR_ERR(priv->regmap));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
priv->pwdn_gpio = of_get_named_gpio(np, "pwdn-gpios", 0);
|
||||
if (priv->pwdn_gpio < 0) {
|
||||
dev_err(&dev, "pwdn-gpios not found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (priv->pwdn_gpio) {
|
||||
gpio_direction_output(priv->pwdn_gpio, 1);
|
||||
gpio_set_value(priv->pwdn_gpio, 1);
|
||||
msleep(100);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to find the I2C address of serializer by writting to register
|
||||
* 0x00 at i2c slave address 0x62 and 0x40. When write is successful
|
||||
* the slave address is saved and used when configuring serializer.
|
||||
*/
|
||||
if (max929x_write_reg(SER_SLAVE2, MAX9295_DEV_ADDR, SER_SLAVE2 << 1)) {
|
||||
if (max929x_write_reg(SER_SLAVE1, MAX9295_DEV_ADDR, SER_SLAVE1 << 1)) {
|
||||
dev_err(&dev, "%s: failed to find serializer at 0x%x or 0x%x\n",
|
||||
__func__, SER_SLAVE2, SER_SLAVE1);
|
||||
return -ENODEV;
|
||||
}
|
||||
ser_addr = SER_SLAVE1;
|
||||
}
|
||||
|
||||
msleep(100);
|
||||
priv->ser_addr = ser_addr;
|
||||
|
||||
err = max929x_write_reg_list(max929x_Double_Dser_Ser_init,
|
||||
sizeof(max929x_Double_Dser_Ser_init)/sizeof(struct max929x_reg));
|
||||
if (err == 0)
|
||||
dev_dbg(&dev, "%s: success\n", __func__);
|
||||
else
|
||||
dev_err(&dev, "%s: fail\n", __func__);
|
||||
|
||||
dev_set_drvdata(&client->dev, priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int max929x_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void max929x_remove(struct i2c_client *client)
|
||||
#endif
|
||||
{
|
||||
struct device dev = client->dev;
|
||||
|
||||
gpio_set_value(priv->pwdn_gpio, 0);
|
||||
dev_dbg(&dev, "%s: \n", __func__);
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max929x_id[] = {
|
||||
{ "max929x", 0 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max929x_id);
|
||||
|
||||
const struct of_device_id max929x_of_match[] = {
|
||||
{ .compatible = "Maxim,max929x", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, max929x_of_match);
|
||||
|
||||
static struct i2c_driver max929x_i2c_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "max929x",
|
||||
.of_match_table = of_match_ptr(max929x_of_match),
|
||||
},
|
||||
.probe = max929x_probe,
|
||||
.remove = max929x_remove,
|
||||
.id_table = max929x_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(max929x_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("IO Expander driver max929x");
|
||||
MODULE_AUTHOR("NVIDIA Corporation");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -1,152 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* SPDX-FileCopyrightText: Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
|
||||
|
||||
#ifndef __MAX929X_H__
|
||||
#define __MAX929X_H__
|
||||
|
||||
/* TI FPD Link III 954 deser I2C address */
|
||||
#define TI954_ADDR (0x30)
|
||||
/* TI FPD Link III 953 ser I2C address */
|
||||
#define TI953_ADDR (0x18)
|
||||
/* TI 953 alias address */
|
||||
#define TI953_CAM1_ADDR (0x29)
|
||||
#define TI953_CAM2_ADDR (0X2A)
|
||||
|
||||
#define MAX9295_DEV_ADDR 0x00
|
||||
|
||||
#define SENSOR_ADDR (0x1a)
|
||||
/* CAM alias address */
|
||||
#define CAM1_SENSOR_ADDR (0x1b)
|
||||
#define CAM2_SENSOR_ADDR (0x1c)
|
||||
|
||||
#define TI954_RESET_ADDR (0x01)
|
||||
#define TI954_RESET_VAL (0x02)
|
||||
|
||||
#define AFDRV_I2C_ADDR (0x3E)
|
||||
/*AF ctrl*/
|
||||
#define AFDRV1_I2C_ADDR (0x21)
|
||||
#define AFDRV2_I2C_ADDR (0x20)
|
||||
|
||||
#define EEPROM_I2C_ADDR (0x50)
|
||||
/*eeprom ctrl*/
|
||||
#define EEPROM1_I2C_ADDR (0x51)
|
||||
#define EEPROM2_I2C_ADDR (0x52)
|
||||
|
||||
struct max929x_reg {
|
||||
u8 slave_addr;
|
||||
u16 reg;
|
||||
u8 val;
|
||||
};
|
||||
|
||||
/* Serializer slave addresses */
|
||||
#define SER_SLAVE1 0x40
|
||||
#define SER_SLAVE2 0x62
|
||||
|
||||
/* Deserializer slave addresses */
|
||||
#define DESER_SLAVE 0x48
|
||||
|
||||
/*
|
||||
* MAX9296 i2c addr 0x90(8bits) 0x48(7bits)
|
||||
* (MAX9296 link A) MAX9295 i2c addr 0xc4(8bits) 0x62(7bits)
|
||||
*/
|
||||
static struct max929x_reg max929x_Double_Dser_Ser_init[] = {
|
||||
/* set MFP0 low to reset sensor */
|
||||
{0x62, 0x02be, 0x80},
|
||||
/* Set SER to 1x4 mode (phy_config = 0) */
|
||||
{0x62, 0x0330, 0x00},
|
||||
{0x62, 0x0332, 0xe4},
|
||||
/* Additional lane map */
|
||||
{0x62, 0x0333, 0xe4},
|
||||
/* Set 4 lanes for serializer (ctrl1_num_lanes = 3) */
|
||||
{0x62, 0x0331, 0x31},
|
||||
/* Start video from both port A and port B. */
|
||||
{0x62, 0x0311, 0x20},
|
||||
/*
|
||||
* Enable info lines. Additional start bits for Port A and B.
|
||||
* Use data from port B for all pipelines
|
||||
*/
|
||||
{0x62, 0x0308, 0x62},
|
||||
/* Route 16bit DCG (DT = 0x30) to VIDEO_X (Bit 6 enable) */
|
||||
{0x62, 0x0314, 0x22},
|
||||
/* Route 12bit RAW (DT = 0x2C) to VIDEO_Y (Bit 6 enable) */
|
||||
{0x62, 0x0316, 0x6c},
|
||||
/* Route EMBEDDED8 to VIDEO_Z (Bit 6 enable) */
|
||||
{0x62, 0x0318, 0x22},
|
||||
/* Unused VIDEO_U */
|
||||
{0x62, 0x031A, 0x22},
|
||||
/*
|
||||
* Make sure all pipelines start transmission
|
||||
* (VID_TX_EN_X/Y/Z/U = 1)
|
||||
*/
|
||||
{0x62, 0x0002, 0x22},
|
||||
/* Set MIPI Phy Mode: 2x(1x4) mode */
|
||||
{0x48, 0x0330, 0x04},
|
||||
/* lane maps - all 4 ports mapped straight */
|
||||
{0x48, 0x0333, 0x4E},
|
||||
/* Additional lane map */
|
||||
{0x48, 0x0334, 0xE4},
|
||||
/*
|
||||
* lane count - 0 lanes striping on controller 0
|
||||
* (Port A slave in 2x1x4 mode).
|
||||
*/
|
||||
{0x48, 0x040A, 0x00},
|
||||
/*
|
||||
* lane count - 4 lanes striping on controller 1
|
||||
* (Port A master in 2x1x4 mode).
|
||||
*/
|
||||
{0x48, 0x044A, 0xd0},
|
||||
/*
|
||||
* lane count - 4 lanes striping on controller 2
|
||||
* (Port B master in 2x1x4 mode).
|
||||
*/
|
||||
{0x48, 0x048A, 0xd0},
|
||||
/*
|
||||
* lane count - 0 lanes striping on controller 3
|
||||
* (Port B slave in 2x1x4 mode).
|
||||
*/
|
||||
{0x48, 0x04CA, 0x00},
|
||||
/*
|
||||
* MIPI clock rate - 1.5Gbps from controller 0 clock
|
||||
* (Port A slave in 2x1x4 mode).
|
||||
*/
|
||||
{0x48, 0x031D, 0x2f},
|
||||
/*
|
||||
* MIPI clock rate - 1.5Gbps from controller 1 clock
|
||||
* (Port A master in 2x1x4 mode).
|
||||
*/
|
||||
{0x48, 0x0320, 0x2f},
|
||||
/*
|
||||
* MIPI clock rate - 1.5Gbps from controller 2 clock
|
||||
* (Port B master in 2x1x4 mode).
|
||||
*/
|
||||
{0x48, 0x0323, 0x2f},
|
||||
/*
|
||||
* MIPI clock rate - 1.5Gbps from controller 2 clock
|
||||
* (Port B slave in 2x1x4 mode).
|
||||
*/
|
||||
{0x48, 0x0326, 0x2f},
|
||||
/* Route data from stream 0 to pipe X */
|
||||
{0x48, 0x0050, 0x00},
|
||||
/* Route data from stream 0 to pipe Y */
|
||||
{0x48, 0x0051, 0x01},
|
||||
/* Route data from stream 0 to pipe Z */
|
||||
{0x48, 0x0052, 0x02},
|
||||
/* Route data from stream 0 to pipe U */
|
||||
{0x48, 0x0053, 0x03},
|
||||
/* Enable all PHYS. */
|
||||
{0x48, 0x0332, 0xF0},
|
||||
/* Enable sensor power down pin. Put imager in,Active mode */
|
||||
{0x62, 0x02be, 0x90},
|
||||
/* Output RCLK to sensor. */
|
||||
{0x62, 0x03F1, 0x89},
|
||||
/* MFP8 for FSIN */
|
||||
{0x62, 0x02D8, 0x10},
|
||||
{0x62, 0x02D6, 0x04},
|
||||
/* need disable pixel clk out inb order to use MFP1 */
|
||||
{0x48, 0x0005, 0x00},
|
||||
/* GPIO TX compensation */
|
||||
{0x48, 0x02B3, 0x83},
|
||||
{0x48, 0x02B4, 0x10},
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,911 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2018-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include <media/max9295.h>
|
||||
#include <media/max9296.h>
|
||||
|
||||
#include <media/tegracam_core.h>
|
||||
#include "imx390_mode_tbls.h"
|
||||
|
||||
#define IMX390_MIN_GAIN (0)
|
||||
#define IMX390_MAX_GAIN (30)
|
||||
#define IMX390_MAX_GAIN_REG ((IMX390_MAX_GAIN - IMX390_MIN_GAIN) * 10 / 3)
|
||||
#define IMX390_DEFAULT_FRAME_LENGTH (1125)
|
||||
#define IMX390_FRAME_LENGTH_ADDR_MSB 0x200A
|
||||
#define IMX390_FRAME_LENGTH_ADDR_MID 0x2009
|
||||
#define IMX390_FRAME_LENGTH_ADDR_LSB 0x2008
|
||||
#define IMX390_COARSE_TIME_SHS1_ADDR_MSB 0x000E
|
||||
#define IMX390_COARSE_TIME_SHS1_ADDR_MID 0x000D
|
||||
#define IMX390_COARSE_TIME_SHS1_ADDR_LSB 0x000C
|
||||
#define IMX390_COARSE_TIME_SHS2_ADDR_MSB 0x0012
|
||||
#define IMX390_COARSE_TIME_SHS2_ADDR_MID 0x0011
|
||||
#define IMX390_COARSE_TIME_SHS2_ADDR_LSB 0x0010
|
||||
#define IMX390_GROUP_HOLD_ADDR 0x0008
|
||||
#define IMX390_ANALOG_GAIN_SP1H_ADDR 0x0018
|
||||
#define IMX390_ANALOG_GAIN_SP1L_ADDR 0x001A
|
||||
|
||||
static const struct of_device_id imx390_of_match[] = {
|
||||
{ .compatible = "sony,imx390",},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx390_of_match);
|
||||
|
||||
static const u32 ctrl_cid_list[] = {
|
||||
TEGRA_CAMERA_CID_GAIN,
|
||||
TEGRA_CAMERA_CID_EXPOSURE,
|
||||
TEGRA_CAMERA_CID_EXPOSURE_SHORT,
|
||||
TEGRA_CAMERA_CID_FRAME_RATE,
|
||||
TEGRA_CAMERA_CID_HDR_EN,
|
||||
};
|
||||
|
||||
struct imx390 {
|
||||
struct i2c_client *i2c_client;
|
||||
const struct i2c_device_id *id;
|
||||
struct v4l2_subdev *subdev;
|
||||
struct device *ser_dev;
|
||||
struct device *dser_dev;
|
||||
struct gmsl_link_ctx g_ctx;
|
||||
u32 frame_length;
|
||||
struct camera_common_data *s_data;
|
||||
struct tegracam_device *tc_dev;
|
||||
};
|
||||
|
||||
static const struct regmap_config sensor_regmap_config = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static inline void imx390_get_frame_length_regs(imx390_reg *regs,
|
||||
u32 frame_length)
|
||||
{
|
||||
regs->addr = IMX390_FRAME_LENGTH_ADDR_MSB;
|
||||
regs->val = (frame_length >> 16) & 0x01;
|
||||
|
||||
(regs + 1)->addr = IMX390_FRAME_LENGTH_ADDR_MID;
|
||||
(regs + 1)->val = (frame_length >> 8) & 0xff;
|
||||
|
||||
(regs + 2)->addr = IMX390_FRAME_LENGTH_ADDR_LSB;
|
||||
(regs + 2)->val = (frame_length) & 0xff;
|
||||
}
|
||||
|
||||
static inline void imx390_get_coarse_time_regs_shs1(imx390_reg *regs,
|
||||
u32 coarse_time)
|
||||
{
|
||||
regs->addr = IMX390_COARSE_TIME_SHS1_ADDR_MSB;
|
||||
regs->val = (coarse_time >> 16) & 0x0f;
|
||||
|
||||
(regs + 1)->addr = IMX390_COARSE_TIME_SHS1_ADDR_MID;
|
||||
(regs + 1)->val = (coarse_time >> 8) & 0xff;
|
||||
|
||||
(regs + 2)->addr = IMX390_COARSE_TIME_SHS1_ADDR_LSB;
|
||||
(regs + 2)->val = (coarse_time) & 0xff;
|
||||
}
|
||||
|
||||
static inline void imx390_get_coarse_time_regs_shs2(imx390_reg *regs,
|
||||
u32 coarse_time)
|
||||
{
|
||||
regs->addr = IMX390_COARSE_TIME_SHS2_ADDR_MSB;
|
||||
regs->val = (coarse_time >> 16) & 0x0f;
|
||||
|
||||
(regs + 1)->addr = IMX390_COARSE_TIME_SHS2_ADDR_MID;
|
||||
(regs + 1)->val = (coarse_time >> 8) & 0xff;
|
||||
|
||||
(regs + 2)->addr = IMX390_COARSE_TIME_SHS2_ADDR_LSB;
|
||||
(regs + 2)->val = (coarse_time) & 0xff;
|
||||
}
|
||||
|
||||
static inline void imx390_get_gain_reg(imx390_reg *regs,
|
||||
u16 gain)
|
||||
{
|
||||
regs->addr = IMX390_ANALOG_GAIN_SP1H_ADDR;
|
||||
regs->val = (gain) & 0xff;
|
||||
|
||||
(regs + 1)->addr = IMX390_ANALOG_GAIN_SP1H_ADDR + 1;
|
||||
(regs + 1)->val = (gain >> 8) & 0xff;
|
||||
|
||||
(regs + 2)->addr = IMX390_ANALOG_GAIN_SP1L_ADDR;
|
||||
(regs + 2)->val = (gain) & 0xff;
|
||||
|
||||
(regs + 3)->addr = IMX390_ANALOG_GAIN_SP1L_ADDR + 1;
|
||||
(regs + 3)->val = (gain >> 8) & 0xff;
|
||||
}
|
||||
|
||||
|
||||
static int test_mode;
|
||||
module_param(test_mode, int, 0644);
|
||||
|
||||
static inline int imx390_read_reg(struct camera_common_data *s_data,
|
||||
u16 addr, u8 *val)
|
||||
{
|
||||
int err = 0;
|
||||
u32 reg_val = 0;
|
||||
|
||||
err = regmap_read(s_data->regmap, addr, ®_val);
|
||||
*val = reg_val & 0xFF;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_write_reg(struct camera_common_data *s_data,
|
||||
u16 addr, u8 val)
|
||||
{
|
||||
int err;
|
||||
struct device *dev = s_data->dev;
|
||||
|
||||
err = regmap_write(s_data->regmap, addr, val);
|
||||
if (err)
|
||||
dev_err(dev, "%s:i2c write failed, 0x%x = %x\n",
|
||||
__func__, addr, val);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_write_table(struct imx390 *priv,
|
||||
const imx390_reg table[])
|
||||
{
|
||||
struct camera_common_data *s_data = priv->s_data;
|
||||
|
||||
return regmap_util_write_table_8(s_data->regmap,
|
||||
table,
|
||||
NULL, 0,
|
||||
IMX390_TABLE_WAIT_MS,
|
||||
IMX390_TABLE_END);
|
||||
}
|
||||
|
||||
static struct mutex serdes_lock__;
|
||||
|
||||
static int imx390_gmsl_serdes_setup(struct imx390 *priv)
|
||||
{
|
||||
int err = 0;
|
||||
int des_err = 0;
|
||||
struct device *dev;
|
||||
|
||||
if (!priv || !priv->ser_dev || !priv->dser_dev || !priv->i2c_client)
|
||||
return -EINVAL;
|
||||
|
||||
dev = &priv->i2c_client->dev;
|
||||
|
||||
mutex_lock(&serdes_lock__);
|
||||
|
||||
/* For now no separate power on required for serializer device */
|
||||
max9296_power_on(priv->dser_dev);
|
||||
|
||||
/* setup serdes addressing and control pipeline */
|
||||
err = max9296_setup_link(priv->dser_dev, &priv->i2c_client->dev);
|
||||
if (err) {
|
||||
dev_err(dev, "gmsl deserializer link config failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = max9295_setup_control(priv->ser_dev);
|
||||
|
||||
/* proceed even if ser setup failed, to setup deser correctly */
|
||||
if (err)
|
||||
dev_err(dev, "gmsl serializer setup failed\n");
|
||||
|
||||
des_err = max9296_setup_control(priv->dser_dev, &priv->i2c_client->dev);
|
||||
if (des_err) {
|
||||
dev_err(dev, "gmsl deserializer setup failed\n");
|
||||
/* overwrite err only if deser setup also failed */
|
||||
err = des_err;
|
||||
}
|
||||
|
||||
error:
|
||||
mutex_unlock(&serdes_lock__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void imx390_gmsl_serdes_reset(struct imx390 *priv)
|
||||
{
|
||||
mutex_lock(&serdes_lock__);
|
||||
|
||||
/* reset serdes addressing and control pipeline */
|
||||
max9295_reset_control(priv->ser_dev);
|
||||
max9296_reset_control(priv->dser_dev, &priv->i2c_client->dev);
|
||||
|
||||
max9296_power_off(priv->dser_dev);
|
||||
|
||||
mutex_unlock(&serdes_lock__);
|
||||
}
|
||||
|
||||
static int imx390_power_on(struct camera_common_data *s_data)
|
||||
{
|
||||
int err = 0;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
struct camera_common_pdata *pdata = s_data->pdata;
|
||||
struct device *dev = s_data->dev;
|
||||
|
||||
dev_dbg(dev, "%s: power on\n", __func__);
|
||||
if (pdata && pdata->power_on) {
|
||||
err = pdata->power_on(pw);
|
||||
if (err)
|
||||
dev_err(dev, "%s failed.\n", __func__);
|
||||
else
|
||||
pw->state = SWITCH_ON;
|
||||
return err;
|
||||
}
|
||||
|
||||
pw->state = SWITCH_ON;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_power_off(struct camera_common_data *s_data)
|
||||
{
|
||||
int err = 0;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
struct camera_common_pdata *pdata = s_data->pdata;
|
||||
struct device *dev = s_data->dev;
|
||||
|
||||
dev_dbg(dev, "%s:\n", __func__);
|
||||
|
||||
if (pdata && pdata->power_off) {
|
||||
err = pdata->power_off(pw);
|
||||
if (!err)
|
||||
goto power_off_done;
|
||||
else
|
||||
dev_err(dev, "%s failed.\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
power_off_done:
|
||||
pw->state = SWITCH_OFF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_power_get(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct device *dev = tc_dev->dev;
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
struct camera_common_pdata *pdata = s_data->pdata;
|
||||
const char *mclk_name;
|
||||
const char *parentclk_name;
|
||||
struct clk *parent;
|
||||
int err = 0;
|
||||
|
||||
mclk_name = pdata->mclk_name ?
|
||||
pdata->mclk_name : "cam_mclk1";
|
||||
pw->mclk = devm_clk_get(dev, mclk_name);
|
||||
if (IS_ERR(pw->mclk)) {
|
||||
dev_err(dev, "unable to get clock %s\n", mclk_name);
|
||||
return PTR_ERR(pw->mclk);
|
||||
}
|
||||
|
||||
parentclk_name = pdata->parentclk_name;
|
||||
if (parentclk_name) {
|
||||
parent = devm_clk_get(dev, parentclk_name);
|
||||
if (IS_ERR(parent)) {
|
||||
dev_err(dev, "unable to get parent clcok %s",
|
||||
parentclk_name);
|
||||
} else {
|
||||
err = clk_set_parent(pw->mclk, parent);
|
||||
if (err < 0)
|
||||
dev_dbg(dev,
|
||||
"%s failed to set parent clock %d\n",
|
||||
__func__, err);
|
||||
}
|
||||
}
|
||||
|
||||
pw->state = SWITCH_OFF;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_power_put(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
|
||||
if (unlikely(!pw))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_set_group_hold(struct tegracam_device *tc_dev, bool val)
|
||||
{
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct device *dev = tc_dev->dev;
|
||||
int err;
|
||||
|
||||
err = imx390_write_reg(s_data,
|
||||
IMX390_GROUP_HOLD_ADDR, val);
|
||||
if (err) {
|
||||
dev_dbg(dev,
|
||||
"%s: Group hold control error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_set_gain(struct tegracam_device *tc_dev, s64 val)
|
||||
{
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct device *dev = tc_dev->dev;
|
||||
const struct sensor_mode_properties *mode =
|
||||
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
|
||||
imx390_reg reg_list[4];
|
||||
int err, i;
|
||||
u16 gain;
|
||||
|
||||
gain = (u16)(val / mode->control_properties.step_gain_val);
|
||||
|
||||
dev_dbg(dev, "%s: db: %d\n", __func__, gain);
|
||||
|
||||
if (gain > IMX390_MAX_GAIN_REG)
|
||||
gain = IMX390_MAX_GAIN_REG;
|
||||
|
||||
imx390_get_gain_reg(reg_list, gain);
|
||||
for (i = 0; i < 4; i++) {
|
||||
err = imx390_write_reg(s_data, reg_list[i].addr,
|
||||
reg_list[i].val);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
dev_info(dev, "%s: GAIN control error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
|
||||
{
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
|
||||
/* fixed 30fps */
|
||||
priv->frame_length = IMX390_DEFAULT_FRAME_LENGTH;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_set_exposure(struct tegracam_device *tc_dev, s64 val)
|
||||
{
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
const struct sensor_mode_properties *mode =
|
||||
&s_data->sensor_props.sensor_modes[s_data->mode];
|
||||
imx390_reg reg_list[3];
|
||||
int err;
|
||||
u32 coarse_time;
|
||||
u32 shs1;
|
||||
int i = 0;
|
||||
|
||||
if (priv->frame_length == 0)
|
||||
priv->frame_length = IMX390_DEFAULT_FRAME_LENGTH;
|
||||
|
||||
/* coarse time in lines */
|
||||
coarse_time = (u32) (val * s_data->frmfmt[s_data->mode].framerates[0] *
|
||||
priv->frame_length / mode->control_properties.exposure_factor);
|
||||
|
||||
shs1 = priv->frame_length - coarse_time;
|
||||
/* 0 and 1 are prohibited */
|
||||
if (shs1 < 2)
|
||||
shs1 = 2;
|
||||
|
||||
imx390_get_coarse_time_regs_shs1(reg_list, shs1);
|
||||
for (i = 0; i < 3; i++) {
|
||||
err = imx390_write_reg(priv->s_data, reg_list[i].addr,
|
||||
reg_list[i].val);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
imx390_get_coarse_time_regs_shs2(reg_list, shs1);
|
||||
for (i = 0; i < 3; i++) {
|
||||
err = imx390_write_reg(priv->s_data, reg_list[i].addr,
|
||||
reg_list[i].val);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
dev_dbg(&priv->i2c_client->dev,
|
||||
"%s: set coarse time error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct tegracam_ctrl_ops imx390_ctrl_ops = {
|
||||
.numctrls = ARRAY_SIZE(ctrl_cid_list),
|
||||
.ctrl_cid_list = ctrl_cid_list,
|
||||
.set_gain = imx390_set_gain,
|
||||
.set_exposure = imx390_set_exposure,
|
||||
.set_exposure_short = imx390_set_exposure,
|
||||
.set_frame_rate = imx390_set_frame_rate,
|
||||
.set_group_hold = imx390_set_group_hold,
|
||||
};
|
||||
|
||||
static struct camera_common_pdata
|
||||
*imx390_parse_dt(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct device *dev = tc_dev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct camera_common_pdata *board_priv_pdata;
|
||||
const struct of_device_id *match;
|
||||
int err;
|
||||
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
match = of_match_device(imx390_of_match, dev);
|
||||
if (!match) {
|
||||
dev_err(dev, "Failed to find matching dt id\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
board_priv_pdata = devm_kzalloc(dev,
|
||||
sizeof(*board_priv_pdata), GFP_KERNEL);
|
||||
|
||||
err = of_property_read_string(node, "mclk",
|
||||
&board_priv_pdata->mclk_name);
|
||||
if (err)
|
||||
dev_err(dev, "mclk not in DT\n");
|
||||
|
||||
return board_priv_pdata;
|
||||
}
|
||||
|
||||
static int imx390_set_mode(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct device *dev = tc_dev->dev;
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_device(imx390_of_match, dev);
|
||||
if (!match) {
|
||||
dev_err(dev, "Failed to find matching dt id\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (s_data->mode_prop_idx < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return imx390_write_table(priv, mode_table[s_data->mode_prop_idx]);
|
||||
}
|
||||
|
||||
static int imx390_start_streaming(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
struct device *dev = tc_dev->dev;
|
||||
int err;
|
||||
|
||||
/* enable serdes streaming */
|
||||
err = max9295_setup_streaming(priv->ser_dev);
|
||||
if (err)
|
||||
goto exit;
|
||||
err = max9296_setup_streaming(priv->dser_dev, dev);
|
||||
if (err)
|
||||
goto exit;
|
||||
err = max9296_start_streaming(priv->dser_dev, dev);
|
||||
if (err)
|
||||
goto exit;
|
||||
|
||||
err = imx390_write_table(priv,
|
||||
mode_table[IMX390_MODE_START_STREAM]);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
msleep(20);
|
||||
|
||||
return 0;
|
||||
|
||||
exit:
|
||||
dev_err(dev, "%s: error setting stream\n", __func__);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_stop_streaming(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct device *dev = tc_dev->dev;
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
|
||||
/* disable serdes streaming */
|
||||
max9296_stop_streaming(priv->dser_dev, dev);
|
||||
|
||||
return imx390_write_table(priv, mode_table[IMX390_MODE_STOP_STREAM]);
|
||||
}
|
||||
|
||||
static struct camera_common_sensor_ops imx390_common_ops = {
|
||||
.numfrmfmts = ARRAY_SIZE(imx390_frmfmt),
|
||||
.frmfmt_table = imx390_frmfmt,
|
||||
.power_on = imx390_power_on,
|
||||
.power_off = imx390_power_off,
|
||||
.write_reg = imx390_write_reg,
|
||||
.read_reg = imx390_read_reg,
|
||||
.parse_dt = imx390_parse_dt,
|
||||
.power_get = imx390_power_get,
|
||||
.power_put = imx390_power_put,
|
||||
.set_mode = imx390_set_mode,
|
||||
.start_streaming = imx390_start_streaming,
|
||||
.stop_streaming = imx390_stop_streaming,
|
||||
};
|
||||
|
||||
static int imx390_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
dev_dbg(&client->dev, "%s:\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_internal_ops imx390_subdev_internal_ops = {
|
||||
.open = imx390_open,
|
||||
};
|
||||
|
||||
static int imx390_board_setup(struct imx390 *priv)
|
||||
{
|
||||
struct tegracam_device *tc_dev = priv->tc_dev;
|
||||
struct device *dev = tc_dev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct device_node *ser_node;
|
||||
struct i2c_client *ser_i2c = NULL;
|
||||
struct device_node *dser_node;
|
||||
struct i2c_client *dser_i2c = NULL;
|
||||
struct device_node *gmsl;
|
||||
int value = 0xFFFF;
|
||||
const char *str_value;
|
||||
const char *str_value1[2];
|
||||
int i;
|
||||
int err;
|
||||
|
||||
err = of_property_read_u32(node, "reg", &priv->g_ctx.sdev_reg);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "reg not found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = of_property_read_u32(node, "def-addr",
|
||||
&priv->g_ctx.sdev_def);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "def-addr not found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ser_node = of_parse_phandle(node, "nvidia,gmsl-ser-device", 0);
|
||||
if (ser_node == NULL) {
|
||||
dev_err(dev,
|
||||
"missing %s handle\n",
|
||||
"nvidia,gmsl-ser-device");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = of_property_read_u32(ser_node, "reg", &priv->g_ctx.ser_reg);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "serializer reg not found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ser_i2c = of_find_i2c_device_by_node(ser_node);
|
||||
of_node_put(ser_node);
|
||||
|
||||
if (ser_i2c == NULL) {
|
||||
err = -EPROBE_DEFER;
|
||||
goto error;
|
||||
}
|
||||
if (ser_i2c->dev.driver == NULL) {
|
||||
dev_err(dev, "missing serializer driver\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
priv->ser_dev = &ser_i2c->dev;
|
||||
|
||||
dser_node = of_parse_phandle(node, "nvidia,gmsl-dser-device", 0);
|
||||
if (dser_node == NULL) {
|
||||
dev_err(dev,
|
||||
"missing %s handle\n",
|
||||
"nvidia,gmsl-dser-device");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
dser_i2c = of_find_i2c_device_by_node(dser_node);
|
||||
of_node_put(dser_node);
|
||||
|
||||
if (dser_i2c == NULL) {
|
||||
err = -EPROBE_DEFER;
|
||||
goto error;
|
||||
}
|
||||
if (dser_i2c->dev.driver == NULL) {
|
||||
dev_err(dev, "missing deserializer driver\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
priv->dser_dev = &dser_i2c->dev;
|
||||
|
||||
/* populate g_ctx from DT */
|
||||
gmsl = of_get_child_by_name(node, "gmsl-link");
|
||||
if (gmsl == NULL) {
|
||||
dev_err(dev, "missing gmsl-link device node\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = of_property_read_string(gmsl, "dst-csi-port", &str_value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No dst-csi-port found\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.dst_csi_port =
|
||||
(!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B;
|
||||
|
||||
err = of_property_read_string(gmsl, "src-csi-port", &str_value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No src-csi-port found\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.src_csi_port =
|
||||
(!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B;
|
||||
|
||||
err = of_property_read_string(gmsl, "csi-mode", &str_value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No csi-mode found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!strcmp(str_value, "1x4")) {
|
||||
priv->g_ctx.csi_mode = GMSL_CSI_1X4_MODE;
|
||||
} else if (!strcmp(str_value, "2x4")) {
|
||||
priv->g_ctx.csi_mode = GMSL_CSI_2X4_MODE;
|
||||
} else if (!strcmp(str_value, "4x2")) {
|
||||
priv->g_ctx.csi_mode = GMSL_CSI_4X2_MODE;
|
||||
} else if (!strcmp(str_value, "2x2")) {
|
||||
priv->g_ctx.csi_mode = GMSL_CSI_2X2_MODE;
|
||||
} else {
|
||||
dev_err(dev, "invalid csi mode\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = of_property_read_string(gmsl, "serdes-csi-link", &str_value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No serdes-csi-link found\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.serdes_csi_link =
|
||||
(!strcmp(str_value, "a")) ?
|
||||
GMSL_SERDES_CSI_LINK_A : GMSL_SERDES_CSI_LINK_B;
|
||||
|
||||
err = of_property_read_u32(gmsl, "st-vc", &value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No st-vc info\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.st_vc = value;
|
||||
|
||||
err = of_property_read_u32(gmsl, "vc-id", &value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No vc-id info\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.dst_vc = value;
|
||||
|
||||
err = of_property_read_u32(gmsl, "num-lanes", &value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No num-lanes info\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.num_csi_lanes = value;
|
||||
|
||||
priv->g_ctx.num_streams =
|
||||
of_property_count_strings(gmsl, "streams");
|
||||
if (priv->g_ctx.num_streams <= 0) {
|
||||
dev_err(dev, "No streams found\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < priv->g_ctx.num_streams; i++) {
|
||||
err = of_property_read_string_index(gmsl, "streams", i,
|
||||
&str_value1[i]);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Failed to get streams index\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!str_value1[i]) {
|
||||
dev_err(dev, "invalid stream info\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
if (!strcmp(str_value1[i], "raw12")) {
|
||||
priv->g_ctx.streams[i].st_data_type =
|
||||
GMSL_CSI_DT_RAW_12;
|
||||
} else if (!strcmp(str_value1[i], "embed")) {
|
||||
priv->g_ctx.streams[i].st_data_type =
|
||||
GMSL_CSI_DT_EMBED;
|
||||
} else if (!strcmp(str_value1[i], "ued-u1")) {
|
||||
priv->g_ctx.streams[i].st_data_type =
|
||||
GMSL_CSI_DT_UED_U1;
|
||||
} else {
|
||||
dev_err(dev, "invalid stream data type\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
priv->g_ctx.s_dev = dev;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int imx390_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int imx390_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
#endif
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct tegracam_device *tc_dev;
|
||||
struct imx390 *priv;
|
||||
int err;
|
||||
|
||||
dev_info(dev, "probing v4l2 sensor.\n");
|
||||
|
||||
if (!IS_ENABLED(CONFIG_OF) || !node)
|
||||
return -EINVAL;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(struct imx390), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
tc_dev = devm_kzalloc(dev,
|
||||
sizeof(struct tegracam_device), GFP_KERNEL);
|
||||
if (!tc_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->i2c_client = tc_dev->client = client;
|
||||
tc_dev->dev = dev;
|
||||
strscpy(tc_dev->name, "imx390", sizeof(tc_dev->name));
|
||||
tc_dev->dev_regmap_config = &sensor_regmap_config;
|
||||
tc_dev->sensor_ops = &imx390_common_ops;
|
||||
tc_dev->v4l2sd_internal_ops = &imx390_subdev_internal_ops;
|
||||
tc_dev->tcctrl_ops = &imx390_ctrl_ops;
|
||||
|
||||
err = tegracam_device_register(tc_dev);
|
||||
if (err) {
|
||||
dev_err(dev, "tegra camera driver registration failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
priv->tc_dev = tc_dev;
|
||||
priv->s_data = tc_dev->s_data;
|
||||
priv->subdev = &tc_dev->s_data->subdev;
|
||||
|
||||
tegracam_set_privdata(tc_dev, (void *)priv);
|
||||
|
||||
err = imx390_board_setup(priv);
|
||||
if (err) {
|
||||
tegracam_device_unregister(tc_dev);
|
||||
dev_err(dev, "board setup failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
mutex_init(&serdes_lock__);
|
||||
|
||||
/* Pair sensor to serializer dev */
|
||||
err = max9295_sdev_pair(priv->ser_dev, &priv->g_ctx);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "gmsl ser pairing failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Register sensor to deserializer dev */
|
||||
err = max9296_sdev_register(priv->dser_dev, &priv->g_ctx);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "gmsl deserializer register failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* gmsl serdes setup
|
||||
*
|
||||
* Sensor power on/off should be the right place for serdes
|
||||
* setup/reset. But the problem is, the total required delay
|
||||
* in serdes setup/reset exceeds the frame wait timeout, looks to
|
||||
* be related to multiple channel open and close sequence
|
||||
* issue (#BUG 200477330).
|
||||
* Once this bug is fixed, these may be moved to power on/off.
|
||||
* The delays in serdes is as per guidelines and can't be reduced,
|
||||
* so it is placed in probe/remove, though for that, deserializer
|
||||
* would be powered on always post boot, until 1.2v is supplied
|
||||
* to deserializer from CVB.
|
||||
*/
|
||||
err = imx390_gmsl_serdes_setup(priv);
|
||||
if (err) {
|
||||
dev_err(&client->dev,
|
||||
"%s gmsl serdes setup failed\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = tegracam_v4l2subdev_register(tc_dev, true);
|
||||
if (err) {
|
||||
dev_err(dev, "tegra camera subdev registration failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "Detected IMX390 sensor\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int imx390_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void imx390_remove(struct i2c_client *client)
|
||||
#endif
|
||||
{
|
||||
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
|
||||
struct imx390 *priv;
|
||||
|
||||
if (!s_data)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return -EINVAL;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
|
||||
priv = (struct imx390 *)s_data->priv;
|
||||
|
||||
imx390_gmsl_serdes_reset(priv);
|
||||
|
||||
mutex_destroy(&serdes_lock__);
|
||||
tegracam_v4l2subdev_unregister(priv->tc_dev);
|
||||
tegracam_device_unregister(priv->tc_dev);
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const struct i2c_device_id imx390_id[] = {
|
||||
{ "imx390", 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, imx390_id);
|
||||
|
||||
static struct i2c_driver imx390_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "imx390",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(imx390_of_match),
|
||||
},
|
||||
.probe = imx390_probe,
|
||||
.remove = imx390_remove,
|
||||
.id_table = imx390_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(imx390_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Media Controller driver for Sony IMX390");
|
||||
MODULE_AUTHOR("NVIDIA Corporation");
|
||||
MODULE_AUTHOR("Sudhir Vyas <svyas@nvidia.com");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user