mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 10:11:26 +03:00
Compare commits
248 Commits
l4t/l4t-r3
...
jetson_36.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
087418781c | ||
|
|
fe0a030fee | ||
|
|
7ad4c09866 | ||
|
|
f41b74b8c3 | ||
|
|
ff0c2e64e9 | ||
|
|
8b2781df07 | ||
|
|
34b2a9887a | ||
|
|
f3b12ead83 | ||
|
|
f73208daa3 | ||
|
|
b4250020cf | ||
|
|
0eb7d29c91 | ||
|
|
a863247bfc | ||
|
|
80c7d7a67b | ||
|
|
0d1196a9f2 | ||
|
|
7373b7bc0b | ||
|
|
06c838e81c | ||
|
|
d4a130e720 | ||
|
|
ae8e0690e8 | ||
|
|
3a4fed381d | ||
|
|
d19626ceee | ||
|
|
42263f1dfe | ||
|
|
1ae45fbaa7 | ||
|
|
97a8781a1b | ||
|
|
8f4ee697f9 | ||
|
|
8fbb56adb6 | ||
|
|
55b09a913f | ||
|
|
386aa2f039 | ||
|
|
3c87c18fcf | ||
|
|
84de937501 | ||
|
|
85be13c709 | ||
|
|
913e17563b | ||
|
|
f2d3ec994c | ||
|
|
20374db85d | ||
|
|
bd0a8befee | ||
|
|
118cd4e0a6 | ||
|
|
87c78ad125 | ||
|
|
408ef72fb9 | ||
|
|
537492a880 | ||
|
|
d99dede530 | ||
|
|
df9e50c808 | ||
|
|
a1658e5ab7 | ||
|
|
523d81ebd5 | ||
|
|
cb5d91e562 | ||
|
|
36b50b7f27 | ||
|
|
98c8d2f1ab | ||
|
|
eb9eb329cb | ||
|
|
f65ba6483d | ||
|
|
e2bb52def5 | ||
|
|
f870a5f9fc | ||
|
|
490c984662 | ||
|
|
928bbd8792 | ||
|
|
954d58f2bc | ||
|
|
91baac051e | ||
|
|
6d4ef6154e | ||
|
|
4643e350da | ||
|
|
b4cc53aa67 | ||
|
|
9cb00122ac | ||
|
|
adc35280cb | ||
|
|
517660e465 | ||
|
|
09b7b63ec4 | ||
|
|
fa9c7418dc | ||
|
|
cb70a7e245 | ||
|
|
716ec492d8 | ||
|
|
5e0562c90d | ||
|
|
1b72d87cce | ||
|
|
0104837e60 | ||
|
|
39e07fb02b | ||
|
|
67b36c62c3 | ||
|
|
57d240e007 | ||
|
|
d259181558 | ||
|
|
70cf7e08f3 | ||
|
|
f902d95962 | ||
|
|
d95c0d0add | ||
|
|
32ed59d81b | ||
|
|
664ca6964c | ||
|
|
e9b64b08d1 | ||
|
|
b0e75c8874 | ||
|
|
28f1253514 | ||
|
|
83238f4563 | ||
|
|
cbac517483 | ||
|
|
4e35e4b067 | ||
|
|
a84ded5d3e | ||
|
|
222eebeb31 | ||
|
|
6ca4e1e64c | ||
|
|
e9cdb435a3 | ||
|
|
ac51641cf1 | ||
|
|
0313251d13 | ||
|
|
8b529ece8f | ||
|
|
315ceb951b | ||
|
|
044cc6adda | ||
|
|
51806fef24 | ||
|
|
6997999d7a | ||
|
|
91ee86eced | ||
|
|
91e87c9346 | ||
|
|
e351ba75c7 | ||
|
|
5ff50fc9ea | ||
|
|
94090ac30e | ||
|
|
f78df7fa59 | ||
|
|
1a5be9188a | ||
|
|
6969153c7c | ||
|
|
4e544f3b3a | ||
|
|
ed30eb40ff | ||
|
|
f107cac72e | ||
|
|
83d8dcc34c | ||
|
|
318fd1fe91 | ||
|
|
fc8c410eb6 | ||
|
|
8e77d444fb | ||
|
|
7e82f57b74 | ||
|
|
e77e6c5aec | ||
|
|
e3f09d3989 | ||
|
|
9efa10a1d7 | ||
|
|
90c8229157 | ||
|
|
755f4a8456 | ||
|
|
888f248ee2 | ||
|
|
d01b6a3a2b | ||
|
|
003bd8ed9b | ||
|
|
4a31d7ed61 | ||
|
|
e3673f6890 | ||
|
|
8317f938ec | ||
|
|
8e5cebeb9e | ||
|
|
cccf65a229 | ||
|
|
17e0946ce0 | ||
|
|
f9ed570c2b | ||
|
|
4d4e685699 | ||
|
|
396db89160 | ||
|
|
d495adaddf | ||
|
|
7096cb09a5 | ||
|
|
f877c7e3da | ||
|
|
c8a0c93fc1 | ||
|
|
bba1f3a464 | ||
|
|
3506076764 | ||
|
|
5a65235c0d | ||
|
|
e70b9e4c10 | ||
|
|
29e88ed17e | ||
|
|
61319aef4d | ||
|
|
518ae94bb4 | ||
|
|
6642085af9 | ||
|
|
e31d73fa20 | ||
|
|
d7f14a85db | ||
|
|
05b82fc2fe | ||
|
|
b2e0445c73 | ||
|
|
34ef06bd12 | ||
|
|
7f293be0be | ||
|
|
246e62b38e | ||
|
|
233a7eb320 | ||
|
|
753583f1e3 | ||
|
|
1ccb6edda2 | ||
|
|
1b6db0ce3c | ||
|
|
26e357d588 | ||
|
|
7635873f3d | ||
|
|
176a1bff8d | ||
|
|
e997e8ae5a | ||
|
|
d1c969184b | ||
|
|
e02b9efcc4 | ||
|
|
2ac404f410 | ||
|
|
e7868529f3 | ||
|
|
3f5ba8f70b | ||
|
|
f1f3771dec | ||
|
|
e30e21ebd1 | ||
|
|
ac6a53078b | ||
|
|
56c05f8e3f | ||
|
|
822abd1943 | ||
|
|
71876127a2 | ||
|
|
abeacc3534 | ||
|
|
902712a236 | ||
|
|
ff6f3c6916 | ||
|
|
11e0abc8a3 | ||
|
|
5d31085674 | ||
|
|
a86b3af506 | ||
|
|
32f23c8ab2 | ||
|
|
259736545b | ||
|
|
34fd7d68dc | ||
|
|
4a32aa94e5 | ||
|
|
e4d4103ebe | ||
|
|
7abc2d8726 | ||
|
|
f8e977a8c9 | ||
|
|
1f0954f43d | ||
|
|
711d4aee8d | ||
|
|
afe9bdc7c0 | ||
|
|
5b4a093e24 | ||
|
|
14abda2794 | ||
|
|
6ad6325734 | ||
|
|
a39a2be24e | ||
|
|
9c2c4a695c | ||
|
|
3a35e1c2b1 | ||
|
|
0d940461d4 | ||
|
|
e3fc979712 | ||
|
|
e3f7ab90e1 | ||
|
|
2fc926c8fe | ||
|
|
f7d42ed1c4 | ||
|
|
560b7c1345 | ||
|
|
e94f3bb6d8 | ||
|
|
82f8d2b998 | ||
|
|
b27e2e49de | ||
|
|
a6fc43ecb8 | ||
|
|
c61a3c670f | ||
|
|
ce24d01296 | ||
|
|
a77844b17d | ||
|
|
cef95180b3 | ||
|
|
c0beaa46b5 | ||
|
|
9bfb2e35b7 | ||
|
|
11670f570d | ||
|
|
f255a170a7 | ||
|
|
020bdeded8 | ||
|
|
e1471516b0 | ||
|
|
0ca520ee30 | ||
|
|
6b290b7f84 | ||
|
|
b5178e70d8 | ||
|
|
efbbf91f79 | ||
|
|
29ab9b19c9 | ||
|
|
1432eb248d | ||
|
|
4ab98ef641 | ||
|
|
7f9beef481 | ||
|
|
069d6bb3eb | ||
|
|
7f3751f642 | ||
|
|
e91b43420c | ||
|
|
5b6fed0199 | ||
|
|
7c4bfe82b2 | ||
|
|
1b537bff19 | ||
|
|
75363cdd58 | ||
|
|
09b54bda42 | ||
|
|
4a1a87890d | ||
|
|
ab8b8a6c84 | ||
|
|
9c77439e40 | ||
|
|
715c34434f | ||
|
|
c196de1377 | ||
|
|
0940779cd6 | ||
|
|
029ade906d | ||
|
|
b5d808a6ff | ||
|
|
6fe3abc899 | ||
|
|
a6701b19b9 | ||
|
|
daec781815 | ||
|
|
60adf47e0f | ||
|
|
7997b6e8b0 | ||
|
|
b02f2cd5ee | ||
|
|
ee4493d7bf | ||
|
|
9c2150982a | ||
|
|
9e94468082 | ||
|
|
4f1d3dbeb3 | ||
|
|
4da134034b | ||
|
|
2527826ca1 | ||
|
|
5fe2e2aacc | ||
|
|
067fbd7bbc | ||
|
|
856471d64f | ||
|
|
a3b3ef5cab | ||
|
|
7ffd0c9cfa | ||
|
|
7ff7dcd36a | ||
|
|
c0bc0aa39c |
@@ -5,19 +5,24 @@ correlation feature.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatibles: should be "nvpps,tegra194-nvpps"
|
||||
- compatible: This should be nvidia,tegra194-nvpps for Xavier and nvidia,tegra234-nvpps for Orin.
|
||||
|
||||
Optional properties:
|
||||
- gpios: GPIO number and active level for the PPS input signal
|
||||
- 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.
|
||||
- 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.
|
||||
@@ -31,42 +36,78 @@ 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:
|
||||
Example: Timer mode on Orin.
|
||||
|
||||
nvpps {
|
||||
compatible = "nvidia,tegrat194-nvpps";
|
||||
status = "okay";
|
||||
gpios = <&tegra_aon_gpio TEGRA194_AON_GPIO(BB, 2) GPIO_ACTIVE_HIGH>;
|
||||
mgbe0: ethernet@6800000{
|
||||
};
|
||||
|
||||
Example:
|
||||
nvpps {
|
||||
status = "okay";
|
||||
compatible = "nvidia,tegra234-nvpps";
|
||||
primary-emac = <&mgbe0>;
|
||||
sec-emac = <&mgbe0>;
|
||||
reg = <0x0 0xc6a0000 0x0 0x1000>;
|
||||
};
|
||||
|
||||
Example: Timer mode on Xavier
|
||||
|
||||
eqos: ethernet@2490000{
|
||||
};
|
||||
|
||||
nvpps {
|
||||
compatible = "nvidia,tegra194-nvpps";
|
||||
status = "okay";
|
||||
gpios = <&tegra_aon_gpio TEGRA234_AON_GPIO(EE, 6) GPIO_ACTIVE_HIGH>;
|
||||
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>;
|
||||
memmap_phc_regs;
|
||||
interface = "mgbe2_0";
|
||||
reg = <0x0 0xc6a0000 0x0 0x1000>;
|
||||
};
|
||||
|
||||
Example:
|
||||
|
||||
Example: GPIO mode on Orin
|
||||
|
||||
mgbe0: ethernet@6800000{
|
||||
};
|
||||
|
||||
nvpps {
|
||||
compatible = "nvidia,tegra194-nvpps";
|
||||
status = "okay";
|
||||
gpios = <&tegra_aon_gpio TEGRA234_AON_GPIO(EE, 6) GPIO_ACTIVE_HIGH>;
|
||||
interface = "mgbe2_0";
|
||||
sec_interface = "eqos_0";
|
||||
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>;
|
||||
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,67 +1,11 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
|
||||
# Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
|
||||
|
||||
LINUXINCLUDE += -I$(srctree.nvconftest)
|
||||
LINUXINCLUDE += -I$(srctree.nvidia-oot)/include
|
||||
|
||||
subdir-ccflags-y += -Werror
|
||||
|
||||
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
|
||||
subdir-ccflags-y += -Wmissing-prototypes
|
||||
|
||||
ifeq ($(CONFIG_TEGRA_VIRTUALIZATION),y)
|
||||
subdir-ccflags-y += -DCONFIG_TEGRA_VIRTUALIZATION
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
# 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
|
||||
@@ -1,9 +0,0 @@
|
||||
# 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
|
||||
@@ -1,29 +0,0 @@
|
||||
// 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";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* 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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -1,9 +0,0 @@
|
||||
// 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]="/extra"
|
||||
DEST_MODULE_LOCATION[0]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[1]="watchdog-tegra-t18x"
|
||||
BUILT_MODULE_LOCATION[1]="drivers/watchdog"
|
||||
DEST_MODULE_LOCATION[1]="/extra"
|
||||
DEST_MODULE_LOCATION[1]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[2]="pex9749-thermal"
|
||||
BUILT_MODULE_LOCATION[2]="drivers/thermal"
|
||||
DEST_MODULE_LOCATION[2]="/extra"
|
||||
DEST_MODULE_LOCATION[2]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[3]="spi-aurix-tegra"
|
||||
BUILT_MODULE_LOCATION[3]="drivers/spi"
|
||||
DEST_MODULE_LOCATION[3]="/extra"
|
||||
DEST_MODULE_LOCATION[3]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[4]="tegra186-gpc-dma"
|
||||
BUILT_MODULE_LOCATION[4]="drivers/dma"
|
||||
DEST_MODULE_LOCATION[4]="/extra"
|
||||
DEST_MODULE_LOCATION[4]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[5]="pwm-tegra-tachometer"
|
||||
BUILT_MODULE_LOCATION[5]="drivers/pwm"
|
||||
DEST_MODULE_LOCATION[5]="/extra"
|
||||
DEST_MODULE_LOCATION[5]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[6]="pinctrl-tegra234"
|
||||
BUILT_MODULE_LOCATION[6]="drivers/pinctrl/tegra"
|
||||
DEST_MODULE_LOCATION[6]="/extra"
|
||||
DEST_MODULE_LOCATION[6]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[7]="tegra-cactmon"
|
||||
BUILT_MODULE_LOCATION[7]="drivers/platform/tegra"
|
||||
DEST_MODULE_LOCATION[7]="/extra"
|
||||
DEST_MODULE_LOCATION[7]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[8]="pinctrl-tegra234-dpaux"
|
||||
BUILT_MODULE_LOCATION[8]="drivers/pinctrl"
|
||||
DEST_MODULE_LOCATION[8]="/extra"
|
||||
DEST_MODULE_LOCATION[8]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[9]="tegra-fsicom"
|
||||
BUILT_MODULE_LOCATION[9]="drivers/platform/tegra"
|
||||
DEST_MODULE_LOCATION[9]="/extra"
|
||||
DEST_MODULE_LOCATION[9]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[10]="tegra-bootloader-debug"
|
||||
BUILT_MODULE_LOCATION[10]="drivers/platform/tegra"
|
||||
DEST_MODULE_LOCATION[10]="/extra"
|
||||
DEST_MODULE_LOCATION[10]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[11]="host1x-fence"
|
||||
BUILT_MODULE_LOCATION[11]="drivers/gpu/host1x-fence"
|
||||
DEST_MODULE_LOCATION[11]="/extra"
|
||||
DEST_MODULE_LOCATION[11]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[12]="tegra_vnet"
|
||||
BUILT_MODULE_LOCATION[12]="drivers/net/ethernet/nvidia/pcie"
|
||||
DEST_MODULE_LOCATION[12]="/extra"
|
||||
DEST_MODULE_LOCATION[12]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[13]="arm64-ras"
|
||||
BUILT_MODULE_LOCATION[13]="drivers/ras"
|
||||
DEST_MODULE_LOCATION[13]="/extra"
|
||||
DEST_MODULE_LOCATION[13]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[14]="fuse-burn"
|
||||
BUILT_MODULE_LOCATION[14]="drivers/soc/tegra/fuse"
|
||||
DEST_MODULE_LOCATION[14]="/extra"
|
||||
DEST_MODULE_LOCATION[14]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[15]="kfuse"
|
||||
BUILT_MODULE_LOCATION[15]="drivers/soc/tegra/fuse"
|
||||
DEST_MODULE_LOCATION[15]="/extra"
|
||||
DEST_MODULE_LOCATION[15]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[16]="pci-epf-dma-test"
|
||||
BUILT_MODULE_LOCATION[16]="drivers/pci/endpoint/functions"
|
||||
DEST_MODULE_LOCATION[16]="/extra"
|
||||
DEST_MODULE_LOCATION[16]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[17]="tegra-pcie-edma"
|
||||
BUILT_MODULE_LOCATION[17]="drivers/pci/controller"
|
||||
DEST_MODULE_LOCATION[17]="/extra"
|
||||
DEST_MODULE_LOCATION[17]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[18]="pcie-tegra-vf"
|
||||
BUILT_MODULE_LOCATION[18]="drivers/pci/controller"
|
||||
DEST_MODULE_LOCATION[18]="/extra"
|
||||
DEST_MODULE_LOCATION[18]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[19]="tegra-pcie-dma-test"
|
||||
BUILT_MODULE_LOCATION[19]="drivers/misc"
|
||||
DEST_MODULE_LOCATION[19]="/extra"
|
||||
DEST_MODULE_LOCATION[19]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[20]="tegra-se"
|
||||
BUILT_MODULE_LOCATION[20]="drivers/crypto/tegra"
|
||||
DEST_MODULE_LOCATION[20]="/extra"
|
||||
DEST_MODULE_LOCATION[20]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[21]="tegra-se-nvrng"
|
||||
BUILT_MODULE_LOCATION[21]="drivers/crypto"
|
||||
DEST_MODULE_LOCATION[21]="/extra"
|
||||
DEST_MODULE_LOCATION[21]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[22]="nvidia-vrs-pseq"
|
||||
BUILT_MODULE_LOCATION[22]="drivers/mfd"
|
||||
DEST_MODULE_LOCATION[22]="/extra"
|
||||
DEST_MODULE_LOCATION[22]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[23]="cpuidle-debugfs"
|
||||
BUILT_MODULE_LOCATION[23]="drivers/cpuidle"
|
||||
DEST_MODULE_LOCATION[23]="/extra"
|
||||
DEST_MODULE_LOCATION[23]="/updates"
|
||||
|
||||
BUILT_MODULE_NAME[24]="pinctrl-tegra194-pexclk-padctrl"
|
||||
BUILT_MODULE_LOCATION[24]="drivers/pinctrl"
|
||||
DEST_MODULE_LOCATION[24]="/extra"
|
||||
DEST_MODULE_LOCATION[24]="/updates"
|
||||
|
||||
AUTO_INSTALL="yes"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
LINUXINCLUDE += -I$(srctree.nvidia-oot)/include
|
||||
LINUXINCLUDE += -I$(srctree.nvidia-oot)/drivers/gpu/host1x/hw/
|
||||
@@ -17,9 +17,7 @@ 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,10 +32,12 @@ 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
|
||||
@@ -81,7 +81,5 @@ 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,13 +1,19 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# SPDX-FileCopyrightText: Copyright (c) 2022-2024 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)
|
||||
|
||||
# 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
|
||||
@@ -1,10 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <linux/kernel.h> /* printk() */
|
||||
#include <linux/slab.h> /* kmalloc() */
|
||||
#include <linux/vmalloc.h> /* kmalloc() */
|
||||
#include <linux/fs.h> /* everything... */
|
||||
#include <linux/errno.h> /* error codes */
|
||||
#include <linux/fcntl.h> /* O_ACCMODE */
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <linux/slab.h> /* kmalloc() */
|
||||
#include <linux/vmalloc.h> /* kmalloc() */
|
||||
#include <linux/errno.h> /* error codes */
|
||||
#include <linux/delay.h> /* For msleep and usleep_range */
|
||||
#include <uapi/scsi/ufs/ioctl.h>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
@@ -997,7 +995,11 @@ 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);
|
||||
@@ -1162,7 +1164,9 @@ 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)
|
||||
|
||||
@@ -54,7 +54,7 @@ struct cfg_list_item {
|
||||
struct list_head list;
|
||||
u16 offset;
|
||||
u8 len;
|
||||
u8 data[0];
|
||||
u8 data[];
|
||||
};
|
||||
|
||||
static struct list_head list_configs;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
/* Device tree example:
|
||||
*
|
||||
@@ -7,13 +7,15 @@
|
||||
* compatible = "bmi,bmi088";
|
||||
* reg = <0x69>; // <-- Must be gyroscope I2C address
|
||||
* accel_i2c_addr = <0x19>; // Must be specified
|
||||
* 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_irq-gpios = <&tegra_gpio TEGRA_GPIO(BB, 0) GPIO_ACTIVE_HIGH>;
|
||||
* gyro_irq-gpios = <&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>
|
||||
@@ -25,8 +27,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"
|
||||
@@ -107,22 +109,17 @@
|
||||
|
||||
#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 },
|
||||
{},
|
||||
};
|
||||
|
||||
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;
|
||||
struct bmi_gpio_irq {
|
||||
struct gpio_desc *gpio_in;
|
||||
const char *dev_name;
|
||||
int gpio;
|
||||
int irq;
|
||||
u64 irq_ts;
|
||||
u64 irq_ts_old;
|
||||
};
|
||||
|
||||
struct bmi_reg_rd {
|
||||
@@ -411,18 +408,21 @@ 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,141 +537,36 @@ 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_gte_irq *ngi = st->gis;
|
||||
struct bmi_snsr *snsrs = st->snsrs;
|
||||
int ret;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
ngi[i].irq = -1;
|
||||
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);
|
||||
|
||||
return bmi_gte_init_gpio2irq(dev, ngi, n);
|
||||
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;
|
||||
}
|
||||
|
||||
static int bmi_pm(struct bmi_state *st, int snsr_id, bool en)
|
||||
@@ -967,17 +862,32 @@ 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_state *st = (struct bmi_state *)dev_id;
|
||||
struct bmi_snsr *sensor = (struct bmi_snsr *)dev_id;
|
||||
struct bmi_state *st = sensor->st;
|
||||
unsigned int hw;
|
||||
int ret;
|
||||
u8 reg;
|
||||
u8 sample[BMI_IMU_DATA];
|
||||
int cnt = 0;
|
||||
u64 ts_old;
|
||||
|
||||
if (irq == st->gis[BMI_HW_GYR].irq) {
|
||||
if (irq == st->snsrs[BMI_HW_GYR].gis.irq) {
|
||||
hw = BMI_HW_GYR;
|
||||
reg = BMI_REG_GYR_DATA;
|
||||
} else {
|
||||
@@ -985,7 +895,7 @@ static irqreturn_t bmi_irq_thread(int irq, void *dev_id)
|
||||
reg = BMI_REG_ACC_DATA;
|
||||
}
|
||||
|
||||
/* Disbale data ready interrupt before we read out data */
|
||||
/* Disable 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,
|
||||
@@ -993,71 +903,31 @@ static irqreturn_t bmi_irq_thread(int irq, void *dev_id)
|
||||
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;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
mutex_lock(BMI_MUTEX(st->snsrs[hw].bmi_iio));
|
||||
|
||||
ret = bmi_i2c_rd(st, hw, reg, sizeof(sample), sample);
|
||||
|
||||
mutex_unlock(BMI_MUTEX(st->snsrs[hw].bmi_iio));
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
dev_dbg(&st->i2c->dev, "%d, ts= %lld, ts_old=%lld\n",
|
||||
hw, st->gis[hw].irq_ts, ts_old);
|
||||
mutex_unlock(BMI_MUTEX(st->snsrs[hw].bmi_iio));
|
||||
|
||||
out:
|
||||
st->gis[hw].irq_ts = 0;
|
||||
/* Enable data ready interrupt */
|
||||
bmi_hws[hw].fn_able(st, 1, true);
|
||||
|
||||
err:
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -1072,7 +942,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, bool is_gte)
|
||||
static int bmi_enable(void *client, int snsr_id, int enable)
|
||||
{
|
||||
struct bmi_state *st = (struct bmi_state *)client;
|
||||
int ret;
|
||||
@@ -1084,20 +954,10 @@ static int bmi_enable(void *client, int snsr_id, int enable, bool is_gte)
|
||||
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 (is_gte)
|
||||
bmi_gte_deinit(&st->gis[snsr_id]);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = bmi_period(st, snsr_id, true);
|
||||
ret |= bmi_hws[snsr_id].fn_able(st, 1, false);
|
||||
@@ -1107,9 +967,6 @@ static int bmi_enable(void *client, int snsr_id, int enable, bool is_gte)
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -1302,11 +1159,6 @@ 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;
|
||||
}
|
||||
|
||||
@@ -1389,11 +1241,9 @@ 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,
|
||||
false);
|
||||
old_en_st = bmi_enable(st, st->snsrs[i].cfg.snsr_id, -1);
|
||||
if (old_en_st) {
|
||||
temp_ret = bmi_enable(st, st->snsrs[i].cfg.snsr_id, 0,
|
||||
false);
|
||||
temp_ret = bmi_enable(st, st->snsrs[i].cfg.snsr_id, 0);
|
||||
if (!temp_ret)
|
||||
st->suspend_en_st |= old_en_st;
|
||||
|
||||
@@ -1415,8 +1265,7 @@ 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,
|
||||
false);
|
||||
ret |= bmi_enable(st, st->snsrs[i].cfg.snsr_id, 1);
|
||||
mutex_unlock(BMI_MUTEX(st->snsrs[i].bmi_iio));
|
||||
}
|
||||
|
||||
@@ -1437,8 +1286,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, false))
|
||||
bmi_enable(st, st->snsrs[i].cfg.snsr_id, 0, false);
|
||||
if (bmi_enable(st, st->snsrs[i].cfg.snsr_id, -1))
|
||||
bmi_enable(st, st->snsrs[i].cfg.snsr_id, 0);
|
||||
|
||||
if (st->iio_init_done[i]) {
|
||||
mutex_unlock(BMI_MUTEX(st->snsrs[i].bmi_iio));
|
||||
@@ -1454,7 +1303,6 @@ 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);
|
||||
@@ -1480,8 +1328,18 @@ static int bmi_of_dt(struct bmi_state *st, struct device_node *dn)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(dn, "accel_reg_0x53", &val32))
|
||||
st->ra_0x53 = (u8)val32;
|
||||
@@ -1521,14 +1379,11 @@ 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;
|
||||
@@ -1545,13 +1400,6 @@ 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);
|
||||
@@ -1580,31 +1428,63 @@ 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->gis[i].dev_name = st->snsrs[i].cfg.name;
|
||||
st->gis[i].gte = NULL;
|
||||
st->snsrs[i].gis.dev_name = st->snsrs[i].cfg.name;
|
||||
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;
|
||||
|
||||
for (i = 0; i < st->hw_n; i++) {
|
||||
|
||||
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++) {
|
||||
if (bmi_hws[i].fn_irqflags) {
|
||||
irqflags = bmi_hws[i].fn_irqflags(st);
|
||||
ret = devm_request_threaded_irq(&st->i2c->dev,
|
||||
st->gis[i].irq,
|
||||
st->snsrs[i].gis.irq,
|
||||
NULL,
|
||||
bmi_irq_thread,
|
||||
irqflags,
|
||||
st->gis[i].dev_name,
|
||||
st);
|
||||
st->snsrs[i].gis.dev_name,
|
||||
&st->snsrs[i]);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1614,20 +1494,11 @@ 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 KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
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
|
||||
// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
@@ -164,6 +164,9 @@ 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;
|
||||
@@ -201,8 +204,7 @@ 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, true);
|
||||
return st->fn_dev->enable(st->client, st->cfg->snsr_id, 0);
|
||||
|
||||
if (indio_dev->num_channels > 1) {
|
||||
for_each_set_bit(bit, indio_dev->active_scan_mask,
|
||||
@@ -213,7 +215,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, true);
|
||||
return st->fn_dev->enable(st->client, st->cfg->snsr_id, enable);
|
||||
}
|
||||
|
||||
static ssize_t bmi_iio_attr_store(struct device *dev,
|
||||
@@ -350,7 +352,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, false);
|
||||
return st->fn_dev->enable(st->client, st->cfg->snsr_id, -1);
|
||||
}
|
||||
|
||||
static int bmi_iio_read_raw(struct iio_dev *indio_dev,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024, 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, bool is_gte);
|
||||
int (*enable)(void *client, int snsr_id, int enable);
|
||||
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,7 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/device.h>
|
||||
@@ -366,7 +364,7 @@ static int tegra_bpmp_clk_get_info(struct tegra_bpmp *bpmp, unsigned int id,
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
strlcpy(info->name, response.name, MRQ_CLK_NAME_MAXLEN);
|
||||
strscpy(info->name, response.name, MRQ_CLK_NAME_MAXLEN);
|
||||
info->num_parents = response.num_parents;
|
||||
|
||||
for (i = 0; i < info->num_parents; i++)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2019-2023, NVIDIA Corporation. All Rights Reserved.
|
||||
* Copyright (c) 2019-2024, NVIDIA Corporation. All Rights Reserved.
|
||||
*
|
||||
* Cryptographic API.
|
||||
*/
|
||||
@@ -15,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>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 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 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* Crypto driver to handle HASH algorithms using NVIDIA Security Engine.
|
||||
*/
|
||||
|
||||
#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,16 +23,17 @@
|
||||
#include "tegra-se.h"
|
||||
|
||||
struct tegra_sha_ctx {
|
||||
#ifndef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
struct crypto_engine_ctx enginectx;
|
||||
struct crypto_ahash *fallback_tfm;
|
||||
#endif
|
||||
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;
|
||||
@@ -43,6 +44,9 @@ struct tegra_sha_reqctx {
|
||||
unsigned int blk_size;
|
||||
unsigned int task;
|
||||
u32 key_id;
|
||||
u32 *cmdbuf;
|
||||
u32 result[HASH_RESULT_REG_COUNT];
|
||||
struct ahash_request fallback_req;
|
||||
};
|
||||
|
||||
static int tegra_sha_get_config(u32 alg)
|
||||
@@ -213,13 +217,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 = (u64)rctx->total_len * 8;
|
||||
msg_left = (u64)rctx->datbuf.size * 8;
|
||||
msg_len = rctx->total_len * 8;
|
||||
msg_left = rctx->datbuf.size * 8;
|
||||
|
||||
/*
|
||||
* If IN_ADDR_HI_0.SZ > SHA_MSG_LEFT_[0-3] to the HASH engine,
|
||||
@@ -233,7 +237,7 @@ static int tegra_sha_prep_cmd(struct tegra_se *se, u32 *cpuvaddr,
|
||||
}
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(8);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(SE_SHA_MSG_LENGTH);
|
||||
cpuvaddr[i++] = se_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;
|
||||
@@ -243,14 +247,15 @@ 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++] = host1x_opcode_incr_w(SE_SHA_CFG);
|
||||
cpuvaddr[i++] = se_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)) |
|
||||
@@ -260,31 +265,48 @@ 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++] = host1x_opcode_nonincr_w(SE_SHA_CRYPTO_CFG);
|
||||
cpuvaddr[i++] = se_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++] = host1x_opcode_nonincr_w(SE_SHA_OPERATION);
|
||||
cpuvaddr[i++] = se_host1x_opcode_nonincr_w(SE_SHA_OPERATION);
|
||||
cpuvaddr[i++] = SE_SHA_OP_WRSTALL |
|
||||
SE_SHA_OP_START |
|
||||
SE_SHA_OP_LASTBUF;
|
||||
cpuvaddr[i++] = host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
|
||||
cpuvaddr[i++] = se_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;
|
||||
u32 *cpuvaddr = ctx->se->cmdbuf->addr;
|
||||
unsigned int nblks, nresidue, size, ret;
|
||||
u32 *cpuvaddr = rctx->cmdbuf;
|
||||
|
||||
nresidue = (req->nbytes + rctx->residue.size) % rctx->blk_size;
|
||||
nblks = (req->nbytes + rctx->residue.size) / rctx->blk_size;
|
||||
@@ -308,21 +330,26 @@ 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;
|
||||
@@ -330,9 +357,30 @@ 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);
|
||||
|
||||
return tegra_se_host1x_submit(ctx->se, size);
|
||||
ret = tegra_se_host1x_submit(ctx->se, rctx->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;
|
||||
}
|
||||
|
||||
static int tegra_sha_do_final(struct ahash_request *req)
|
||||
@@ -341,19 +389,28 @@ static int tegra_sha_do_final(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;
|
||||
u32 *cpuvaddr = se->cmdbuf->addr;
|
||||
u32 *cpuvaddr = rctx->cmdbuf;
|
||||
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;
|
||||
|
||||
size = tegra_sha_prep_cmd(se, cpuvaddr, rctx);
|
||||
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;
|
||||
}
|
||||
|
||||
ret = tegra_se_host1x_submit(se, size);
|
||||
memcpy(rctx->datbuf.buf, rctx->residue.buf, rctx->residue.size);
|
||||
}
|
||||
|
||||
size = tegra_sha_prep_cmd(se, cpuvaddr, rctx);
|
||||
ret = tegra_se_host1x_submit(se, rctx->cmdbuf, size);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@@ -361,12 +418,16 @@ static int tegra_sha_do_final(struct ahash_request *req)
|
||||
memcpy(req->result, rctx->digest.buf, rctx->digest.size);
|
||||
|
||||
out:
|
||||
dma_free_coherent(se->dev, SE_SHA_BUFLEN,
|
||||
rctx->datbuf.buf, rctx->datbuf.addr);
|
||||
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, 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);
|
||||
kfree(rctx->cmdbuf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -377,7 +438,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 = -EINVAL;
|
||||
int ret = 0;
|
||||
|
||||
if (rctx->task & SHA_UPDATE) {
|
||||
ret = tegra_sha_do_update(req);
|
||||
@@ -391,44 +452,73 @@ static int tegra_sha_do_one_req(struct crypto_engine *engine, void *areq)
|
||||
|
||||
crypto_finalize_hash_request(se->engine, req, ret);
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_sha_init_fallback(struct tegra_sha_ctx *ctx, const char *algname)
|
||||
static void tegra_sha_init_fallback(struct crypto_ahash *tfm, 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 %ld\n",
|
||||
algname, PTR_ERR(ctx->fallback_tfm));
|
||||
dev_warn(ctx->se->dev,
|
||||
"failed to allocate fallback for %s\n", algname);
|
||||
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_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
se_alg = container_of(alg, struct tegra_se_alg, alg.ahash.base);
|
||||
#else
|
||||
se_alg = container_of(alg, struct tegra_se_alg, alg.ahash);
|
||||
#endif
|
||||
|
||||
crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
|
||||
sizeof(struct tegra_sha_reqctx));
|
||||
crypto_ahash_set_reqsize(ahash_tfm, sizeof(struct tegra_sha_reqctx));
|
||||
|
||||
ctx->se = se_alg->se_dev;
|
||||
ctx->fallback = false;
|
||||
ctx->key_id = 0;
|
||||
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;
|
||||
|
||||
ret = se_algname_to_algid(algname);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->se->dev, "invalid algorithm\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (se_alg->alg_base)
|
||||
tegra_sha_init_fallback(ctx, algname);
|
||||
tegra_sha_init_fallback(ahash_tfm, ctx, algname);
|
||||
|
||||
ctx->alg = ret;
|
||||
|
||||
#ifndef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
ctx->enginectx.op.prepare_request = NULL;
|
||||
ctx->enginectx.op.unprepare_request = NULL;
|
||||
ctx->enginectx.op.do_one_request = tegra_sha_do_one_req;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -440,7 +530,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);
|
||||
tegra_key_invalidate(ctx->se, ctx->key_id, ctx->alg);
|
||||
}
|
||||
|
||||
static int tegra_sha_init(struct ahash_request *req)
|
||||
@@ -449,54 +539,49 @@ 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 = se_algname_to_algid(algname);
|
||||
rctx->alg = ctx->alg;
|
||||
rctx->blk_size = crypto_ahash_blocksize(tfm);
|
||||
rctx->digest.size = crypto_ahash_digestsize(tfm);
|
||||
|
||||
rctx->cmdbuf = kzalloc(SE_MAX_CMDLEN, GFP_KERNEL);
|
||||
if (!rctx->cmdbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
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, SE_SHA_BUFLEN, rctx->datbuf.buf,
|
||||
rctx->datbuf.addr);
|
||||
dma_free_coherent(se->dev, rctx->digest.size, rctx->digest.buf,
|
||||
rctx->digest.addr);
|
||||
digbuf_fail:
|
||||
kfree(rctx->cmdbuf);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int tegra_hmac_fallback_setkey(struct tegra_sha_ctx *ctx, const u8 *key,
|
||||
static int tegra_hmac_fallback_setkey(struct tegra_sha_ctx *ctx, const u8 *key,
|
||||
unsigned int keylen)
|
||||
{
|
||||
if (!ctx->fallback_tfm) {
|
||||
dev_err(ctx->se->dev, "invalid key length\n");
|
||||
dev_dbg(ctx->se->dev, "invalid key length (%d)\n", keylen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -584,9 +669,6 @@ 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;
|
||||
}
|
||||
@@ -608,6 +690,9 @@ static int tegra_sha_import(struct ahash_request *req, const void *in)
|
||||
static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
{
|
||||
.alg.ahash = {
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
.base = {
|
||||
#endif
|
||||
.init = tegra_sha_init,
|
||||
.update = tegra_sha_update,
|
||||
.final = tegra_sha_final,
|
||||
@@ -617,7 +702,6 @@ 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",
|
||||
@@ -630,9 +714,16 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.cra_init = tegra_sha_cra_init,
|
||||
.cra_exit = tegra_sha_cra_exit,
|
||||
}
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
},
|
||||
.op.do_one_request = tegra_sha_do_one_req,
|
||||
#endif
|
||||
}
|
||||
}, {
|
||||
.alg.ahash = {
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
.base = {
|
||||
#endif
|
||||
.init = tegra_sha_init,
|
||||
.update = tegra_sha_update,
|
||||
.final = tegra_sha_final,
|
||||
@@ -642,7 +733,6 @@ 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",
|
||||
@@ -655,9 +745,16 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.cra_init = tegra_sha_cra_init,
|
||||
.cra_exit = tegra_sha_cra_exit,
|
||||
}
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
},
|
||||
.op.do_one_request = tegra_sha_do_one_req,
|
||||
#endif
|
||||
}
|
||||
}, {
|
||||
.alg.ahash = {
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
.base = {
|
||||
#endif
|
||||
.init = tegra_sha_init,
|
||||
.update = tegra_sha_update,
|
||||
.final = tegra_sha_final,
|
||||
@@ -667,7 +764,6 @@ 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",
|
||||
@@ -680,9 +776,16 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.cra_init = tegra_sha_cra_init,
|
||||
.cra_exit = tegra_sha_cra_exit,
|
||||
}
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
},
|
||||
.op.do_one_request = tegra_sha_do_one_req,
|
||||
#endif
|
||||
}
|
||||
}, {
|
||||
.alg.ahash = {
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
.base = {
|
||||
#endif
|
||||
.init = tegra_sha_init,
|
||||
.update = tegra_sha_update,
|
||||
.final = tegra_sha_final,
|
||||
@@ -692,7 +795,6 @@ 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",
|
||||
@@ -705,9 +807,16 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.cra_init = tegra_sha_cra_init,
|
||||
.cra_exit = tegra_sha_cra_exit,
|
||||
}
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
},
|
||||
.op.do_one_request = tegra_sha_do_one_req,
|
||||
#endif
|
||||
}
|
||||
}, {
|
||||
.alg.ahash = {
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
.base = {
|
||||
#endif
|
||||
.init = tegra_sha_init,
|
||||
.update = tegra_sha_update,
|
||||
.final = tegra_sha_final,
|
||||
@@ -717,7 +826,6 @@ 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",
|
||||
@@ -730,9 +838,16 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.cra_init = tegra_sha_cra_init,
|
||||
.cra_exit = tegra_sha_cra_exit,
|
||||
}
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
},
|
||||
.op.do_one_request = tegra_sha_do_one_req,
|
||||
#endif
|
||||
}
|
||||
}, {
|
||||
.alg.ahash = {
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
.base = {
|
||||
#endif
|
||||
.init = tegra_sha_init,
|
||||
.update = tegra_sha_update,
|
||||
.final = tegra_sha_final,
|
||||
@@ -742,7 +857,6 @@ 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",
|
||||
@@ -755,9 +869,16 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.cra_init = tegra_sha_cra_init,
|
||||
.cra_exit = tegra_sha_cra_exit,
|
||||
}
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
},
|
||||
.op.do_one_request = tegra_sha_do_one_req,
|
||||
#endif
|
||||
}
|
||||
}, {
|
||||
.alg.ahash = {
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
.base = {
|
||||
#endif
|
||||
.init = tegra_sha_init,
|
||||
.update = tegra_sha_update,
|
||||
.final = tegra_sha_final,
|
||||
@@ -767,7 +888,6 @@ 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",
|
||||
@@ -780,9 +900,16 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.cra_init = tegra_sha_cra_init,
|
||||
.cra_exit = tegra_sha_cra_exit,
|
||||
}
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
},
|
||||
.op.do_one_request = tegra_sha_do_one_req,
|
||||
#endif
|
||||
}
|
||||
}, {
|
||||
.alg.ahash = {
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
.base = {
|
||||
#endif
|
||||
.init = tegra_sha_init,
|
||||
.update = tegra_sha_update,
|
||||
.final = tegra_sha_final,
|
||||
@@ -792,7 +919,6 @@ 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",
|
||||
@@ -805,9 +931,16 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.cra_init = tegra_sha_cra_init,
|
||||
.cra_exit = tegra_sha_cra_exit,
|
||||
}
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
},
|
||||
.op.do_one_request = tegra_sha_do_one_req,
|
||||
#endif
|
||||
}
|
||||
}, {
|
||||
.alg.ahash = {
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
.base = {
|
||||
#endif
|
||||
.init = tegra_sha_init,
|
||||
.update = tegra_sha_update,
|
||||
.final = tegra_sha_final,
|
||||
@@ -817,7 +950,6 @@ 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",
|
||||
@@ -830,10 +962,17 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.cra_init = tegra_sha_cra_init,
|
||||
.cra_exit = tegra_sha_cra_exit,
|
||||
}
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
},
|
||||
.op.do_one_request = tegra_sha_do_one_req,
|
||||
#endif
|
||||
}
|
||||
}, {
|
||||
.alg_base = "sha224",
|
||||
.alg.ahash = {
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
.base = {
|
||||
#endif
|
||||
.init = tegra_sha_init,
|
||||
.update = tegra_sha_update,
|
||||
.final = tegra_sha_final,
|
||||
@@ -844,7 +983,6 @@ 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",
|
||||
@@ -857,10 +995,17 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.cra_init = tegra_sha_cra_init,
|
||||
.cra_exit = tegra_sha_cra_exit,
|
||||
}
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
},
|
||||
.op.do_one_request = tegra_sha_do_one_req,
|
||||
#endif
|
||||
}
|
||||
}, {
|
||||
.alg_base = "sha256",
|
||||
.alg.ahash = {
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
.base = {
|
||||
#endif
|
||||
.init = tegra_sha_init,
|
||||
.update = tegra_sha_update,
|
||||
.final = tegra_sha_final,
|
||||
@@ -871,7 +1016,6 @@ 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",
|
||||
@@ -884,10 +1028,17 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.cra_init = tegra_sha_cra_init,
|
||||
.cra_exit = tegra_sha_cra_exit,
|
||||
}
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
},
|
||||
.op.do_one_request = tegra_sha_do_one_req,
|
||||
#endif
|
||||
}
|
||||
}, {
|
||||
.alg_base = "sha384",
|
||||
.alg.ahash = {
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
.base = {
|
||||
#endif
|
||||
.init = tegra_sha_init,
|
||||
.update = tegra_sha_update,
|
||||
.final = tegra_sha_final,
|
||||
@@ -898,7 +1049,6 @@ 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",
|
||||
@@ -911,10 +1061,17 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.cra_init = tegra_sha_cra_init,
|
||||
.cra_exit = tegra_sha_cra_exit,
|
||||
}
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
},
|
||||
.op.do_one_request = tegra_sha_do_one_req,
|
||||
#endif
|
||||
}
|
||||
}, {
|
||||
.alg_base = "sha512",
|
||||
.alg.ahash = {
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
.base = {
|
||||
#endif
|
||||
.init = tegra_sha_init,
|
||||
.update = tegra_sha_update,
|
||||
.final = tegra_sha_final,
|
||||
@@ -925,7 +1082,6 @@ 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",
|
||||
@@ -938,6 +1094,10 @@ static struct tegra_se_alg tegra_hash_algs[] = {
|
||||
.cra_init = tegra_sha_cra_init,
|
||||
.cra_exit = tegra_sha_cra_exit,
|
||||
}
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
},
|
||||
.op.do_one_request = tegra_sha_do_one_req,
|
||||
#endif
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -977,37 +1137,45 @@ static int tegra_hash_kac_manifest(u32 user, u32 alg, u32 keylen)
|
||||
|
||||
int tegra_init_hash(struct tegra_se *se)
|
||||
{
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
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;
|
||||
ret = crypto_register_ahash(&tegra_hash_algs[i].alg.ahash);
|
||||
alg = &tegra_hash_algs[i].alg.ahash;
|
||||
|
||||
ret = CRYPTO_REGISTER(ahash, alg);
|
||||
if (ret) {
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
dev_err(se->dev, "failed to register %s\n",
|
||||
tegra_hash_algs[i].alg.ahash.halg.base.cra_name);
|
||||
alg->base.halg.base.cra_name);
|
||||
#else
|
||||
dev_err(se->dev, "failed to register %s\n",
|
||||
alg->halg.base.cra_name);
|
||||
#endif
|
||||
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(void)
|
||||
void tegra_deinit_hash(struct tegra_se *se)
|
||||
{
|
||||
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 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* Crypto driver file to manage keys of NVIDIA Security Engine.
|
||||
*/
|
||||
@@ -16,66 +16,77 @@
|
||||
#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))
|
||||
if (tegra_se_keyslots == GENMASK(SE_MAX_KEYSLOT, 0)) {
|
||||
mutex_unlock(&kslt_lock);
|
||||
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++] = host1x_opcode_incr_w(se->hw->regs->op);
|
||||
cpuvaddr[i++] = se_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++] = host1x_opcode_incr_w(se->hw->regs->manifest);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->manifest);
|
||||
cpuvaddr[i++] = se->manifest(se->owner, alg, keylen);
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->key_dst);
|
||||
cpuvaddr[i++] = se_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++] = host1x_opcode_incr_w(se->hw->regs->key_addr);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_addr);
|
||||
cpuvaddr[i++] = j;
|
||||
|
||||
/* Set key data */
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->key_data);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->key_data);
|
||||
cpuvaddr[i++] = key[j];
|
||||
}
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->config);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->config);
|
||||
cpuvaddr[i++] = SE_CFG_INS;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_setpayload(1);
|
||||
cpuvaddr[i++] = host1x_opcode_incr_w(se->hw->regs->op);
|
||||
cpuvaddr[i++] = se_host1x_opcode_incr_w(se->hw->regs->op);
|
||||
cpuvaddr[i++] = SE_AES_OP_WRSTALL | SE_AES_OP_START |
|
||||
SE_AES_OP_LASTBUF;
|
||||
|
||||
cpuvaddr[i++] = host1x_opcode_nonincr(host1x_uclass_incr_syncpt_r(), 1);
|
||||
cpuvaddr[i++] = se_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);
|
||||
|
||||
@@ -87,29 +98,40 @@ 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;
|
||||
|
||||
return ((BIT(keyid) & SE_KEY_VALID_MASK) &&
|
||||
mutex_lock(&kslt_lock);
|
||||
ret = ((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->cmdbuf->addr, size;
|
||||
u32 addr[100], size;
|
||||
|
||||
size = tegra_key_prep_ins_cmd(se, addr, keyval, keylen, slot, alg);
|
||||
|
||||
return tegra_se_host1x_submit(se, size);
|
||||
return tegra_se_host1x_submit(se, addr, size);
|
||||
}
|
||||
|
||||
void tegra_key_invalidate(struct tegra_se *se, u32 keyid)
|
||||
void tegra_key_invalidate(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);
|
||||
|
||||
tegra_keyslot_free(keyid);
|
||||
}
|
||||
|
||||
@@ -120,8 +142,10 @@ 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))
|
||||
if (!(*keyid)) {
|
||||
dev_err(se->dev, "failed to allocate key slot\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
ret = tegra_key_insert(se, key, keylen, *keyid, alg);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* Crypto driver for NVIDIA Security Engine in Tegra Chips
|
||||
*/
|
||||
|
||||
#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>
|
||||
@@ -124,7 +123,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(struct tegra_se_cmdbuf), GFP_KERNEL);
|
||||
cmdbuf = kzalloc(sizeof(*cmdbuf), GFP_KERNEL);
|
||||
if (!cmdbuf)
|
||||
return NULL;
|
||||
|
||||
@@ -142,9 +141,10 @@ 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, u32 size)
|
||||
int tegra_se_host1x_submit(struct tegra_se *se, u32 *cpuvaddr, u32 size)
|
||||
{
|
||||
struct host1x_job *job;
|
||||
struct tegra_se_cmdbuf *cmdbuf;
|
||||
int ret;
|
||||
|
||||
job = host1x_job_alloc(se->channel, 1, 0, true);
|
||||
@@ -153,7 +153,13 @@ int tegra_se_host1x_submit(struct tegra_se *se, u32 size)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
job->syncpt = host1x_syncpt_get(se->syncpt);
|
||||
cmdbuf = tegra_se_host1x_bo_alloc(se, SZ_4K);
|
||||
if (!cmdbuf)
|
||||
goto job_put;
|
||||
|
||||
memcpy(cmdbuf->addr, cpuvaddr, size * 4);
|
||||
|
||||
job->syncpt = host1x_syncpt_get(se->syncpt);
|
||||
job->syncpt_incrs = 1;
|
||||
job->client = &se->client;
|
||||
job->class = se->client.class;
|
||||
@@ -161,35 +167,39 @@ int tegra_se_host1x_submit(struct tegra_se *se, u32 size)
|
||||
job->engine_fallback_streamid = se->stream_id;
|
||||
job->engine_streamid_offset = SE_STREAM_ID;
|
||||
|
||||
se->cmdbuf->words = size;
|
||||
cmdbuf->words = size;
|
||||
|
||||
host1x_job_add_gather(job, &se->cmdbuf->bo, size, 0);
|
||||
host1x_job_add_gather(job, &cmdbuf->bo, size, 0);
|
||||
|
||||
ret = host1x_job_pin(job, se->dev);
|
||||
if (ret) {
|
||||
dev_err(se->dev, "failed to pin host1x job\n");
|
||||
goto err_job_pin;
|
||||
goto cmdbuf_put;
|
||||
}
|
||||
|
||||
ret = host1x_job_submit(job);
|
||||
if (ret) {
|
||||
dev_err(se->dev, "failed to submit host1x job\n");
|
||||
goto err_job_submit;
|
||||
goto job_unpin;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
host1x_job_put(job);
|
||||
tegra_se_cmdbuf_put(&cmdbuf->bo);
|
||||
|
||||
return 0;
|
||||
|
||||
err_job_submit:
|
||||
job_unpin:
|
||||
host1x_job_unpin(job);
|
||||
err_job_pin:
|
||||
cmdbuf_put:
|
||||
tegra_se_cmdbuf_put(&cmdbuf->bo);
|
||||
job_put:
|
||||
host1x_job_put(job);
|
||||
|
||||
return ret;
|
||||
@@ -210,30 +220,22 @@ 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 err_syncpt;
|
||||
goto channel_put;
|
||||
}
|
||||
|
||||
se->syncpt_id = host1x_syncpt_id(se->syncpt);
|
||||
|
||||
se->cmdbuf = tegra_se_host1x_bo_alloc(se, SZ_4K);
|
||||
if (!se->cmdbuf) {
|
||||
ret = -ENOMEM;
|
||||
goto err_bo;
|
||||
}
|
||||
|
||||
ret = se->hw->init_alg(se);
|
||||
if (ret) {
|
||||
dev_err(se->dev, "failed to register algorithms\n");
|
||||
goto err_alg_reg;
|
||||
goto syncpt_put;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_alg_reg:
|
||||
tegra_se_cmdbuf_put(&se->cmdbuf->bo);
|
||||
err_bo:
|
||||
syncpt_put:
|
||||
host1x_syncpt_put(se->syncpt);
|
||||
err_syncpt:
|
||||
channel_put:
|
||||
host1x_channel_put(se->channel);
|
||||
|
||||
return ret;
|
||||
@@ -243,8 +245,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();
|
||||
tegra_se_cmdbuf_put(&se->cmdbuf->bo);
|
||||
se->hw->deinit_alg(se);
|
||||
host1x_syncpt_put(se->syncpt);
|
||||
host1x_channel_put(se->channel);
|
||||
|
||||
@@ -256,7 +257,7 @@ static const struct host1x_client_ops tegra_se_client_ops = {
|
||||
.exit = tegra_se_client_deinit,
|
||||
};
|
||||
|
||||
int tegra_se_host1x_register(struct tegra_se *se)
|
||||
static int tegra_se_host1x_register(struct tegra_se *se)
|
||||
{
|
||||
INIT_LIST_HEAD(&se->client.list);
|
||||
se->client.dev = se->dev;
|
||||
@@ -269,38 +270,6 @@ 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;
|
||||
@@ -312,61 +281,45 @@ 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);
|
||||
|
||||
ret = tegra_se_clk_init(se);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to init clocks\n");
|
||||
return ret;
|
||||
}
|
||||
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");
|
||||
|
||||
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;
|
||||
}
|
||||
if (!tegra_dev_iommu_get_stream_id(dev, &se->stream_id))
|
||||
return dev_err_probe(dev, -ENODEV,
|
||||
"failed to get IOMMU stream ID\n");
|
||||
|
||||
se_writel(se, se->stream_id, SE_STREAM_ID);
|
||||
writel(se->stream_id, se->base + SE_STREAM_ID);
|
||||
|
||||
se->engine = crypto_engine_alloc_init(dev, 0);
|
||||
if (!se->engine) {
|
||||
dev_err(dev, "failed to init crypto engine\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_engine_alloc;
|
||||
}
|
||||
if (!se->engine)
|
||||
return dev_err_probe(dev, -ENOMEM, "failed to init crypto engine\n");
|
||||
|
||||
ret = crypto_engine_start(se->engine);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to start crypto engine\n");
|
||||
goto err_engine_start;
|
||||
crypto_engine_exit(se->engine);
|
||||
return dev_err_probe(dev, ret, "failed to start crypto engine\n");
|
||||
}
|
||||
|
||||
ret = tegra_se_host1x_register(se);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to init host1x params\n");
|
||||
goto err_host1x_init;
|
||||
crypto_engine_stop(se->engine);
|
||||
crypto_engine_exit(se->engine);
|
||||
return dev_err_probe(dev, ret, "failed to init host1x params\n");
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -377,7 +330,6 @@ 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;
|
||||
}
|
||||
@@ -424,10 +376,10 @@ static const struct tegra_se_hw tegra234_hash_hw = {
|
||||
|
||||
static const struct of_device_id tegra_se_of_match[] = {
|
||||
{
|
||||
.compatible = "nvidia,tegra234-se2-aes",
|
||||
.compatible = "nvidia,tegra234-se-aes",
|
||||
.data = &tegra234_aes_hw
|
||||
}, {
|
||||
.compatible = "nvidia,tegra234-se4-hash",
|
||||
.compatible = "nvidia,tegra234-se-hash",
|
||||
.data = &tegra234_hash_hw,
|
||||
},
|
||||
{ },
|
||||
@@ -486,4 +438,4 @@ module_exit(tegra_se_module_exit);
|
||||
|
||||
MODULE_DESCRIPTION("NVIDIA Tegra Security Engine Driver");
|
||||
MODULE_AUTHOR("Akhil R <akhilrajeev@nvidia.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* Header file for NVIDIA Security Engine driver.
|
||||
*/
|
||||
@@ -7,23 +7,23 @@
|
||||
#ifndef _TEGRA_SE_H
|
||||
#define _TEGRA_SE_H
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/bitfield.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
|
||||
|
||||
#define SE_MAX_CMDLEN (100 * 4) /* max 100 commands of 4 bytes each */
|
||||
#define SE_STREAM_ID 0x90
|
||||
|
||||
#define SE_SHA_CFG 0x4004
|
||||
@@ -64,11 +64,8 @@
|
||||
#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)
|
||||
@@ -308,12 +305,6 @@
|
||||
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 | \
|
||||
@@ -352,20 +343,32 @@
|
||||
#define SE_CRYPTO_CTR_REG_COUNT 4
|
||||
#define SE_MAX_KEYSLOT 15
|
||||
#define SE_MAX_MEM_ALLOC SZ_4M
|
||||
#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)
|
||||
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
#define CRYPTO_REGISTER(alg, x) \
|
||||
crypto_engine_register_##alg(x)
|
||||
#else
|
||||
#define CRYPTO_REGISTER(alg, x) \
|
||||
crypto_register_##alg(x)
|
||||
#endif
|
||||
|
||||
#ifdef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
#define CRYPTO_UNREGISTER(alg, x) \
|
||||
crypto_engine_unregister_##alg(x)
|
||||
#else
|
||||
#define CRYPTO_UNREGISTER(alg, x) \
|
||||
crypto_unregister_##alg(x)
|
||||
#endif
|
||||
|
||||
/* 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 */
|
||||
@@ -398,9 +401,15 @@ struct tegra_se_alg {
|
||||
const char *alg_base;
|
||||
|
||||
union {
|
||||
struct skcipher_alg skcipher;
|
||||
struct aead_alg aead;
|
||||
struct ahash_alg ahash;
|
||||
#ifndef NV_CONFTEST_REMOVE_STRUCT_CRYPTO_ENGINE_CTX
|
||||
struct skcipher_alg skcipher;
|
||||
struct aead_alg aead;
|
||||
struct ahash_alg ahash;
|
||||
#else
|
||||
struct skcipher_engine_alg skcipher;
|
||||
struct aead_engine_alg aead;
|
||||
struct ahash_engine_alg ahash;
|
||||
#endif
|
||||
} alg;
|
||||
};
|
||||
|
||||
@@ -422,7 +431,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)(void);
|
||||
void (*deinit_alg)(struct tegra_se *se);
|
||||
bool support_sm_alg;
|
||||
u32 host1x_class;
|
||||
u32 kac_ver;
|
||||
@@ -431,18 +440,16 @@ struct tegra_se_hw {
|
||||
struct tegra_se {
|
||||
int (*manifest)(u32 user, u32 alg, u32 keylen);
|
||||
const struct tegra_se_hw *hw;
|
||||
struct crypto_engine *engine;
|
||||
struct host1x_channel *channel;
|
||||
struct host1x_client client;
|
||||
struct host1x_channel *channel;
|
||||
struct crypto_engine *engine;
|
||||
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;
|
||||
};
|
||||
|
||||
@@ -452,8 +459,8 @@ struct tegra_se_cmdbuf {
|
||||
struct device *dev;
|
||||
struct kref ref;
|
||||
struct host1x_bo bo;
|
||||
u32 words;
|
||||
ssize_t size;
|
||||
u32 words;
|
||||
};
|
||||
|
||||
struct tegra_se_datbuf {
|
||||
@@ -468,8 +475,6 @@ 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)"))
|
||||
@@ -512,87 +517,61 @@ 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_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);
|
||||
|
||||
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)
|
||||
{
|
||||
writel_relaxed(val, se->base + offset);
|
||||
}
|
||||
|
||||
static inline u32 se_readl(struct tegra_se *se, unsigned int offset)
|
||||
{
|
||||
return readl_relaxed(se->base + offset);
|
||||
}
|
||||
|
||||
|
||||
/****
|
||||
*
|
||||
* HOST1x OPCODES
|
||||
*
|
||||
****/
|
||||
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_se_host1x_submit(struct tegra_se *se, u32 *cpuvaddr, u32 size);
|
||||
|
||||
/* HOST1x OPCODES */
|
||||
static inline u32 host1x_opcode_setpayload(unsigned int payload)
|
||||
{
|
||||
return (9 << 28) | payload;
|
||||
}
|
||||
|
||||
#define host1x_opcode_incr_w(x) __host1x_opcode_incr_w((x) / 4)
|
||||
static inline u32 __host1x_opcode_incr_w(unsigned int offset)
|
||||
static inline u32 host1x_opcode_incr_w(unsigned int offset)
|
||||
{
|
||||
/* 22-bit offset supported */
|
||||
return (10 << 28) | offset;
|
||||
}
|
||||
|
||||
#define host1x_opcode_nonincr_w(x) __host1x_opcode_nonincr_w((x) / 4)
|
||||
static inline u32 __host1x_opcode_nonincr_w(unsigned int offset)
|
||||
static inline u32 host1x_opcode_nonincr_w(unsigned int offset)
|
||||
{
|
||||
/* 22-bit offset supported */
|
||||
return (11 << 28) | offset;
|
||||
}
|
||||
|
||||
#define host1x_opcode_incr(x, y) __host1x_opcode_incr((x) / 4, y)
|
||||
static inline u32 __host1x_opcode_incr(unsigned int offset, unsigned int count)
|
||||
static inline u32 host1x_opcode_incr(unsigned int offset, unsigned int count)
|
||||
{
|
||||
return (1 << 28) | (offset << 16) | count;
|
||||
return (1 << 28) | (offset << 16) | 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)
|
||||
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)
|
||||
@@ -611,4 +590,9 @@ 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,16 +1,14 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# Copyright (c) 2022-2024, 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
|
||||
endif
|
||||
obj-m += tegra_bpmp.o
|
||||
@@ -1,8 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
@@ -82,7 +84,11 @@ 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;
|
||||
@@ -116,8 +122,15 @@ 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);
|
||||
@@ -198,12 +211,20 @@ 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;
|
||||
}
|
||||
@@ -221,12 +242,20 @@ 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;
|
||||
}
|
||||
@@ -432,13 +461,23 @@ static void tegra_bpmp_mrq_handle_ping(unsigned int mrq,
|
||||
struct tegra_bpmp_channel *channel,
|
||||
void *data)
|
||||
{
|
||||
struct mrq_ping_request *request;
|
||||
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;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
|
||||
# Copyright (c) 2022-2024, 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-next-y := \
|
||||
tegra-drm-y := \
|
||||
drm.o \
|
||||
uapi.o \
|
||||
submit.o \
|
||||
@@ -37,6 +37,6 @@ tegra-drm-next-y := \
|
||||
ofa.o \
|
||||
virt.o
|
||||
|
||||
tegra-drm-next-y += trace.o
|
||||
tegra-drm-y += trace.o
|
||||
|
||||
obj-m := tegra-drm-next.o
|
||||
obj-m := tegra-drm.o
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
@@ -12,6 +14,7 @@
|
||||
#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>
|
||||
@@ -1747,7 +1750,19 @@ 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;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#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>
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#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>
|
||||
@@ -891,8 +892,10 @@ static const struct drm_driver tegra_drm_driver = {
|
||||
.debugfs_init = tegra_debugfs_init,
|
||||
#endif
|
||||
|
||||
#if !defined(NV_UNEXPORT_FD_HANDLE_CONVERSION)
|
||||
#if NV_IS_EXPORT_SYMBOL_PRESENT_drm_gem_prime_handle_to_fd
|
||||
.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,
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
* Copyright (C) 2013 NVIDIA Corporation
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
@@ -255,8 +257,14 @@ 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;
|
||||
}
|
||||
|
||||
@@ -11,10 +11,8 @@
|
||||
|
||||
#include <linux/console.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)
|
||||
#include <linux/fb.h>
|
||||
#endif
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <drm/drm_fourcc.h>
|
||||
#include <drm/drm_framebuffer.h>
|
||||
@@ -214,24 +212,21 @@ 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 LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)
|
||||
__FB_DEFAULT_DEFERRED_OPS_RDWR(tegra_fb),
|
||||
__FB_DEFAULT_DEFERRED_OPS_DRAW(tegra_fb),
|
||||
#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,
|
||||
#else
|
||||
.fb_fillrect = drm_fb_helper_sys_fillrect,
|
||||
.fb_copyarea = drm_fb_helper_sys_copyarea,
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_prime.h>
|
||||
@@ -584,8 +584,7 @@ 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 (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) \
|
||||
|| (defined(CONFIG_TEGRA_SYSTEM_TYPE_ACK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)))
|
||||
#if defined(NV_VM_AREA_STRUCT_HAS_CONST_VM_FLAGS) /* Linux v6.3 */
|
||||
vm_flags_clear(vma, VM_PFNMAP);
|
||||
#else
|
||||
vma->vm_flags &= ~VM_PFNMAP;
|
||||
@@ -603,8 +602,7 @@ 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 (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)) \
|
||||
|| (defined(CONFIG_TEGRA_SYSTEM_TYPE_ACK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)))
|
||||
#if defined(NV_VM_AREA_STRUCT_HAS_CONST_VM_FLAGS) /* Linux v6.3 */
|
||||
vm_flags_set(vma, VM_MIXEDMAP);
|
||||
vm_flags_clear(vma, VM_PFNMAP);
|
||||
#else
|
||||
@@ -727,7 +725,6 @@ 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);
|
||||
@@ -735,21 +732,16 @@ 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)
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
#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>
|
||||
|
||||
@@ -272,7 +272,7 @@ static int gr2d_probe(struct platform_device *pdev)
|
||||
gr2d->client.version = gr2d->soc->version;
|
||||
gr2d->client.ops = &gr2d_ops;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
|
||||
#if defined(NV_DEVM_TEGRA_CORE_DEV_INIT_OPP_TABLE_COMMON_PRESENT) /* Linux v5.17 */
|
||||
err = devm_tegra_core_dev_init_opp_table_common(dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -530,7 +530,7 @@ static int gr3d_probe(struct platform_device *pdev)
|
||||
gr3d->client.version = gr3d->soc->version;
|
||||
gr3d->client.ops = &gr3d_ops;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
|
||||
#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;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
@@ -23,6 +25,9 @@
|
||||
#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>
|
||||
@@ -1122,7 +1127,12 @@ 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;
|
||||
}
|
||||
@@ -1864,16 +1874,14 @@ 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);
|
||||
@@ -1894,10 +1902,6 @@ 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);
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
#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>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2015-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2015-2024, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
@@ -43,11 +43,37 @@
|
||||
#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;
|
||||
@@ -55,6 +81,7 @@ struct nvdec_config {
|
||||
bool supports_timestamping;
|
||||
bool has_riscv;
|
||||
bool has_extra_clocks;
|
||||
const struct nvdec_cg_reg *cg_regs;
|
||||
};
|
||||
|
||||
struct nvdec {
|
||||
@@ -91,6 +118,11 @@ 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;
|
||||
@@ -108,7 +140,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, kbps_to_icc(emc_kbps), 0);
|
||||
err = icc_set_bw(nvdec->icc_write, 0, kbps_to_icc(emc_kbps));
|
||||
if (err)
|
||||
dev_warn(nvdec->dev, "failed to set icc bw: %d\n", err);
|
||||
}
|
||||
@@ -557,6 +589,29 @@ 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);
|
||||
@@ -582,6 +637,8 @@ 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);
|
||||
@@ -698,12 +755,28 @@ 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[] = {
|
||||
@@ -804,10 +877,9 @@ static int nvdec_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
nvdec->icc_write = devm_of_icc_get(dev, "write");
|
||||
if (IS_ERR(nvdec->icc_write)) {
|
||||
dev_err(&pdev->dev, "failed to get icc write handle\n");
|
||||
return PTR_ERR(nvdec->icc_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");
|
||||
|
||||
platform_set_drvdata(pdev, nvdec);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2021-2024, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
@@ -91,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, kbps_to_icc(emc_kbps), 0);
|
||||
err = icc_set_bw(nvenc->icc_write, 0, kbps_to_icc(emc_kbps));
|
||||
if (err)
|
||||
dev_warn(nvenc->dev, "failed to set icc bw: %d\n", err);
|
||||
}
|
||||
@@ -670,10 +670,9 @@ 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)) {
|
||||
dev_err(&pdev->dev, "failed to get icc write handle\n");
|
||||
return PTR_ERR(nvenc->icc_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");
|
||||
|
||||
platform_set_drvdata(pdev, nvenc);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
|
||||
* SPDX-FileCopyrightText: Copyright (c) 2021-2024, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
@@ -88,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, kbps_to_icc(emc_kbps), 0);
|
||||
err = icc_set_bw(nvjpg->icc_write, 0, kbps_to_icc(emc_kbps));
|
||||
if (err)
|
||||
dev_warn(nvjpg->dev, "failed to set icc bw: %d\n", err);
|
||||
}
|
||||
@@ -655,10 +655,9 @@ 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)) {
|
||||
dev_err(&pdev->dev, "failed to get icc write handle\n");
|
||||
return PTR_ERR(nvjpg->icc_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");
|
||||
|
||||
platform_set_drvdata(pdev, nvjpg);
|
||||
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
#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>
|
||||
@@ -1718,8 +1721,15 @@ 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;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* SPDX-FileCopyrightText: Copyright (C) 2015-2023 NVIDIA CORPORATION. All rights reserved.
|
||||
* SPDX-FileCopyrightText: Copyright (C) 2015-2024 NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
@@ -129,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, kbps_to_icc(emc_kbps), 0);
|
||||
err = icc_set_bw(vic->icc_write, 0, kbps_to_icc(emc_kbps));
|
||||
if (err)
|
||||
dev_warn(vic->dev, "failed to set icc bw: %d\n", err);
|
||||
}
|
||||
@@ -723,10 +723,9 @@ static int vic_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
vic->icc_write = devm_of_icc_get(dev, "write");
|
||||
if (IS_ERR(vic->icc_write)) {
|
||||
dev_err(&pdev->dev, "failed to get icc write handle\n");
|
||||
return PTR_ERR(vic->icc_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 (!dev->pm_domain) {
|
||||
vic->rst = devm_reset_control_get(dev, "vic");
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Host1x fence UAPI
|
||||
*
|
||||
* Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
@@ -14,7 +10,8 @@
|
||||
#include <linux/host1x-next.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sync_file.h>
|
||||
@@ -204,20 +201,28 @@ 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;
|
||||
struct host1x_pollfd_fence *pfd_fence, *pfd_fence_temp;
|
||||
|
||||
mutex_lock(&pollfd->lock);
|
||||
|
||||
list_for_each_entry(pfd_fence, &pollfd->fences, list) {
|
||||
list_for_each_entry_safe(pfd_fence, pfd_fence_temp, &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;
|
||||
}
|
||||
|
||||
@@ -234,8 +239,20 @@ 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,7 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2022-2023, NVIDIA Corporation. All rights reserved.
|
||||
*/
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
@@ -545,7 +543,6 @@ 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-2023, NVIDIA CORPORATION. All rights reserved.
|
||||
# Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
|
||||
|
||||
host1x-next-y = \
|
||||
host1x-y = \
|
||||
bus.o \
|
||||
syncpt.o \
|
||||
dev.o \
|
||||
@@ -21,7 +21,7 @@ host1x-next-y = \
|
||||
hw/host1x07.o \
|
||||
hw/host1x08.o
|
||||
|
||||
host1x-next-$(CONFIG_IOMMU_API) += \
|
||||
host1x-$(CONFIG_IOMMU_API) += \
|
||||
context.o
|
||||
|
||||
obj-m := host1x-next.o
|
||||
obj-m := host1x.o
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* Copyright (C) 2012-2013, NVIDIA Corporation
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/host1x-next.h>
|
||||
@@ -11,7 +13,6 @@
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "bus.h"
|
||||
#include "dev.h"
|
||||
@@ -334,12 +335,16 @@ 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 LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)
|
||||
#if defined(NV_BUS_TYPE_STRUCT_UEVENT_HAS_CONST_DEV_ARG) /* Linux v6.3 */
|
||||
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. 512 slots will fit exactly within a
|
||||
* single memory page. We also need one additional word at the end of the push
|
||||
* 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
|
||||
* buffer for the RESTART opcode that will instruct the CDMA to jump back to
|
||||
* 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
|
||||
* 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
|
||||
* used.
|
||||
*/
|
||||
#define HOST1X_PUSHBUFFER_SLOTS 511
|
||||
#define HOST1X_PUSHBUFFER_SLOTS 1023
|
||||
|
||||
/*
|
||||
* Clean up push buffer resources
|
||||
@@ -496,7 +496,7 @@ resume:
|
||||
host1x_hw_cdma_resume(host1x, cdma, restart_addr);
|
||||
}
|
||||
|
||||
void cdma_update_work(struct work_struct *work)
|
||||
static void cdma_update_work(struct work_struct *work)
|
||||
{
|
||||
struct host1x_cdma *cdma = container_of(work, struct host1x_cdma, update_work);
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2021, NVIDIA Corporation.
|
||||
* Copyright (c) 2021-2024, NVIDIA Corporation.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pid.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
||||
@@ -5,17 +5,18 @@
|
||||
* 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>
|
||||
|
||||
@@ -950,7 +951,7 @@ static int host1x_probe(struct platform_device *pdev)
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
|
||||
#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)
|
||||
goto pm_disable;
|
||||
|
||||
@@ -177,7 +177,14 @@ 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 val = *(map_addr + offset / 4 + i);
|
||||
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);
|
||||
|
||||
if (!data_count) {
|
||||
host1x_debug_output(o, " %pad: %08x: ", &addr, val);
|
||||
@@ -203,7 +210,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 + job->first_get, pb->mapped + job->first_get);
|
||||
pb->dma, pb->mapped);
|
||||
|
||||
for (i = 0; i < job->num_cmds; i++) {
|
||||
struct host1x_job_gather *g;
|
||||
@@ -227,7 +234,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, cdma,
|
||||
show_gather(o, g->base + g->offset, g->words, NULL,
|
||||
g->base, mapped);
|
||||
|
||||
if (!job->gather_copy_mapped)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/hwmon.h>
|
||||
@@ -1091,8 +1093,10 @@ 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) {
|
||||
@@ -1123,7 +1127,11 @@ 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;
|
||||
@@ -1214,7 +1222,7 @@ destroy_lock:
|
||||
return status;
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int f75308_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void f75308_remove(struct i2c_client *client)
|
||||
@@ -1223,7 +1231,7 @@ static void f75308_remove(struct i2c_client *client)
|
||||
struct f75308_priv *priv = dev_get_drvdata(&client->dev);
|
||||
|
||||
mutex_destroy(&priv->locker);
|
||||
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
@@ -1256,10 +1264,10 @@ static struct i2c_driver f75308_driver = {
|
||||
.of_match_table = of_match_ptr(f75308_match_table),
|
||||
},
|
||||
.detect = f75308_detect,
|
||||
#if defined(NV_I2C_LEGACY_PROBE_NEW_REMOVED)
|
||||
.probe = f75308_probe,
|
||||
#else
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_HAS_PROBE_NEW) /* Dropped on Linux 6.6 */
|
||||
.probe_new = f75308_probe,
|
||||
#else
|
||||
.probe = f75308_probe,
|
||||
#endif
|
||||
.remove = f75308_remove,
|
||||
.address_list = f75308_addr,
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* 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>
|
||||
@@ -242,7 +244,7 @@ static int nvvrs11_vendor_info(struct nvvrs11_chip *chip)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int nvvrs11_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int nvvrs11_probe(struct i2c_client *client,
|
||||
@@ -308,7 +310,7 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
|
||||
#if !defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static void nvvrs11_remove(struct i2c_client *client)
|
||||
{
|
||||
nvvrs11_delete_sys_files(&client->dev);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
subdir-ccflags-y += -Werror
|
||||
|
||||
@@ -7,6 +7,8 @@ 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
|
||||
@@ -17,7 +19,10 @@ obj-m += nv_imx390.o
|
||||
obj-m += nv_imx477.o
|
||||
obj-m += nv_ov5693.o
|
||||
obj-m += nv_ar0234.o
|
||||
obj-m += pca9570.o
|
||||
obj-m += nv_hawk_owl.o
|
||||
obj-m += max929x.o
|
||||
endif
|
||||
|
||||
obj-m += pca9570.o
|
||||
obj-m += virtual_i2c_mux.o
|
||||
endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2018-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
|
||||
/* Copyright (c) 2018-2024, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
|
||||
/*
|
||||
* ar0234_mode_tbls.h - ar0234 sensor mode tables
|
||||
*/
|
||||
@@ -62,7 +62,6 @@ 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
|
||||
@@ -70,17 +69,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 Y
|
||||
{0x84, 0x0314, 0x6b}, // RAW10 to pipe X
|
||||
{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 Y
|
||||
{0x52, 0x00F4, 0x0f}, // Enable pipe 0
|
||||
{0x88, 0x0314, 0x6b}, // RAW10 to pipe X
|
||||
{0x52, 0x00F4, 0x0f}, // Enable pipes 0-3 in deserializer
|
||||
{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 2x4
|
||||
{0x52, 0x08A0, 0x01}, // CSI output is 4x2
|
||||
{0x52, 0x08A3, 0x44}, // Default 4x2 lane mapping
|
||||
{0x52, 0x08A4, 0x44}, // Default 4x2 lane mapping
|
||||
|
||||
@@ -92,16 +91,16 @@ static struct index_reg_8 ar0234_Double_Dser_Ser[] = {
|
||||
{0x52, 0x1D00, 0xF4},
|
||||
{0x52, 0x1E00, 0xF4},
|
||||
|
||||
{0x52, 0x0415, 0x2E},
|
||||
{0x52, 0x0418, 0x2E}, // 1400Mbps
|
||||
{0x52, 0x041B, 0x2E},
|
||||
{0x52, 0x041E, 0x2E},
|
||||
{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, 0x1D00, 0xF5},
|
||||
{0x52, 0x1E00, 0xF5},
|
||||
|
||||
{0x52, 0x090B, 0x07}, // Enable 3 mappings Pipe 0//video2
|
||||
{0x52, 0x092D, 0x15}, // All mappings to controller 1 (port A)
|
||||
{0x52, 0x092D, 0x00}, // All mappings to controller 0 (port C)
|
||||
{0x52, 0x090D, 0x2B}, // Input RAW10, VC0
|
||||
{0x52, 0x090E, 0x2B}, // Output RAW10, VC0
|
||||
{0x52, 0x090F, 0x00}, // Input FS, VC0
|
||||
@@ -110,7 +109,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, 0x15}, // All mappings to controller 1 (port A)
|
||||
{0x52, 0x096D, 0x00}, // All mappings to controller 0 (port C)
|
||||
{0x52, 0x094D, 0x2B}, // Input RAW10, VC0
|
||||
{0x52, 0x094E, 0x6B}, // Output RAW10, VC1
|
||||
{0x52, 0x094F, 0x00}, // Input FS, VC0
|
||||
@@ -119,22 +118,23 @@ 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 A)
|
||||
{0x52, 0x09AD, 0x15}, // All mappings to controller 1 (port D)
|
||||
{0x52, 0x098D, 0x2B}, // Input RAW10, VC0
|
||||
{0x52, 0x098E, 0xaB}, // Output RAW10, VC2
|
||||
{0x52, 0x098E, 0x2B}, // Output RAW10, VC0
|
||||
{0x52, 0x098F, 0x00}, // Input FS, VC0
|
||||
{0x52, 0x0990, 0x80}, // Output FS, VC2
|
||||
{0x52, 0x0990, 0x00}, // Output FS, VC0
|
||||
{0x52, 0x0991, 0x01}, // Input FE, VC0
|
||||
{0x52, 0x0992, 0x81}, // Output FE, VC2
|
||||
{0x52, 0x0992, 0x01}, // Output FE, VC0
|
||||
|
||||
{0x52, 0x09CB, 0x07}, // Enable 3 mappings Pipe 3 //video0
|
||||
{0x52, 0x09ED, 0x15}, // All mappings to controller 1 (port A)
|
||||
{0x52, 0x09ED, 0x15}, // All mappings to controller 1 (port D)
|
||||
{0x52, 0x09CD, 0x2B}, // Input RAW10, VC0
|
||||
{0x52, 0x09CE, 0xeB}, // Output RAW10, VC3
|
||||
{0x52, 0x09CE, 0x6B}, // Output RAW10, VC1
|
||||
{0x52, 0x09CF, 0x00}, // Input FS, VC0
|
||||
{0x52, 0x09D0, 0xc0}, // Output FS, VC3
|
||||
{0x52, 0x09D0, 0x40}, // Output FS, VC1
|
||||
{0x52, 0x09D1, 0x01}, // Input FE, VC0
|
||||
{0x52, 0x09D2, 0xc1}, // Output FE, VC3
|
||||
{0x52, 0x09D2, 0x41}, // Output FE, VC1
|
||||
|
||||
|
||||
{0x52, 0x08A2, 0xF0},
|
||||
{0x84, 0x02be, 0x90}, // Enable sensor power down pin.
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// Copyright (c) 2017-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2017-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// Copyright (c) 2022, e-con Systems. All rights reserved.
|
||||
/*
|
||||
* ar1335.c - AR1335 sensor driver
|
||||
* ar1335_common.c - AR1335 sensor driver
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/gpio.h>
|
||||
@@ -50,11 +52,13 @@ 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)
|
||||
static int mcu_send_ctrl_cmd(struct i2c_client *client,
|
||||
int cmd,
|
||||
uint32_t payload_len,
|
||||
uint16_t index)
|
||||
{
|
||||
int err;
|
||||
uint8_t orig_crc = 0, calc_crc = 0;
|
||||
uint16_t index = 0xFFFF;
|
||||
|
||||
mc_data[0] = CMD_SIGNATURE;
|
||||
mc_data[1] = cmd;
|
||||
@@ -409,7 +413,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;
|
||||
@@ -984,7 +988,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);
|
||||
ret = mcu_send_ctrl_cmd(client, CMD_ID_GET_CTRL, payload_len, index);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "CMD_ID_GET_CTRL send failed\n");
|
||||
goto exit;
|
||||
@@ -1150,7 +1154,8 @@ 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);
|
||||
ret = mcu_send_ctrl_cmd(client, CMD_ID_GET_STREAM_INFO,
|
||||
payload_len, index);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "CMD_ID_GET_STREAM_INFO send failed\n");
|
||||
goto exit;
|
||||
@@ -1272,7 +1277,8 @@ 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);
|
||||
ret = mcu_send_ctrl_cmd(client, CMD_ID_GET_CTRL_UI_INFO,
|
||||
payload_len, index);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "CMD_ID_GET_CTRL_UI_INFO send failed\n");
|
||||
goto exit;
|
||||
@@ -1402,7 +1408,8 @@ 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);
|
||||
ret = mcu_send_ctrl_cmd(client, CMD_ID_GET_CTRL_INFO,
|
||||
payload_len, index);
|
||||
if (ret) {
|
||||
dev_err(&client->dev, "CMD_ID_GET_CTRL_INFO send failed\n");
|
||||
goto exit;
|
||||
@@ -2361,7 +2368,7 @@ exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int cam_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int cam_probe(struct i2c_client *client,
|
||||
@@ -2783,7 +2790,7 @@ exit:
|
||||
devm_kfree(dev, ptr); \
|
||||
}
|
||||
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int cam_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void cam_remove(struct i2c_client *client)
|
||||
@@ -2797,7 +2804,7 @@ static void cam_remove(struct i2c_client *client)
|
||||
|
||||
if (!s_data) {
|
||||
dev_err(&client->dev, "camera common data is NULL\n");
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return -EINVAL;
|
||||
#else
|
||||
return;
|
||||
@@ -2809,7 +2816,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 (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return -EINVAL;
|
||||
#else
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
|
||||
/* Copyright (c) 2022-2024, 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, 0x84},
|
||||
{0x96, 0x0042, 0x2A},
|
||||
{0x96, 0x0043, 0xA8},
|
||||
{0x96, 0x0044, 0x86},
|
||||
{0x96, 0x0044, 0x2C},
|
||||
{0x96, 0x0045, 0xAA},
|
||||
{0x00, AR0234_TABLE_END, 0x00}
|
||||
};
|
||||
@@ -530,6 +530,7 @@ 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
@@ -4,6 +4,8 @@
|
||||
* Lontium LT6911UXC HDMI-CSI bridge driver
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/gpio.h>
|
||||
@@ -19,6 +21,134 @@
|
||||
|
||||
#include "../platform/tegra/camera/camera_gpio.h"
|
||||
|
||||
#define lt6911uxc_reg struct reg_8
|
||||
#define LT6911_TABLE_WAIT_MS 0
|
||||
#define LT6911_TABLE_END 1
|
||||
|
||||
static lt6911uxc_reg lt_enable_i2c[] = {
|
||||
{0xff, 0x80},
|
||||
{0xee, 0x01},
|
||||
{0x10, 0x00},
|
||||
{LT6911_TABLE_END, 0x00}
|
||||
};
|
||||
|
||||
static lt6911uxc_reg lt_configure_param[] = {
|
||||
{0x5e, 0xdf},
|
||||
{0x58, 0x00},
|
||||
{0x59, 0x50},
|
||||
{0x5a, 0x10},
|
||||
{LT6911_TABLE_WAIT_MS, 1},
|
||||
{0x5a, 0x00},
|
||||
{0x58, 0x21},
|
||||
{LT6911_TABLE_END, 0x00}
|
||||
};
|
||||
|
||||
static lt6911uxc_reg lt_block_erase[] = {
|
||||
{0x5a, 0x04},
|
||||
{LT6911_TABLE_WAIT_MS, 1},
|
||||
{0x5a, 0x00},
|
||||
{0x5b, 0x01},
|
||||
{0x5c, 0x80},
|
||||
{0x5d, 0x00},
|
||||
{0x5a, 0x01},
|
||||
{LT6911_TABLE_WAIT_MS, 1},
|
||||
{0x5a, 0x00},
|
||||
{LT6911_TABLE_END, 0x00}
|
||||
};
|
||||
|
||||
static lt6911uxc_reg lt_fifo_rst[] = {
|
||||
{0xff, 0x81},
|
||||
{0x08, 0xbf},
|
||||
{LT6911_TABLE_WAIT_MS, 1},
|
||||
{0x08, 0xff},
|
||||
{LT6911_TABLE_END, 0x00}
|
||||
};
|
||||
|
||||
static lt6911uxc_reg lt_write_enable[] = {
|
||||
{0xff, 0x80},
|
||||
{0x5a, 0x04},
|
||||
{LT6911_TABLE_WAIT_MS, 1},
|
||||
{0x5a, 0x00},
|
||||
{LT6911_TABLE_END, 0x00}
|
||||
};
|
||||
|
||||
static lt6911uxc_reg lt_data_to_fifo[] = {
|
||||
{0x5e, 0xdf},
|
||||
{0x5a, 0x20},
|
||||
{LT6911_TABLE_WAIT_MS, 1},
|
||||
{0x5a, 0x00},
|
||||
{LT6911_TABLE_END, 0x00}
|
||||
};
|
||||
|
||||
static lt6911uxc_reg lt_write_disable[] = {
|
||||
{0xff, 0x80},
|
||||
{0x5a, 0x08},
|
||||
{LT6911_TABLE_WAIT_MS, 1},
|
||||
{0x5a, 0x00},
|
||||
{0x58, 0x00},
|
||||
{LT6911_TABLE_END, 0x00}
|
||||
};
|
||||
|
||||
static u8 LT6911_EDIDs[][256] = {
|
||||
// EDID with default 1920x1080 60fps
|
||||
{
|
||||
0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x3A,0xC4,0x04,0xED,0x01,0x01,0x01,0x01,
|
||||
0x1E,0x21,0x01,0x03,0x80,0x6F,0x3E,0x78,0x0A,0xEE,0x91,0xA3,0x54,0x4C,0x99,0x26,
|
||||
0x0F,0x50,0x54,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
|
||||
0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x3A,0x80,0x18,0x71,0x38,0x2D,0x40,0x58,0x2C,
|
||||
0x45,0x00,0xBA,0x88,0x21,0x00,0x00,0x1E,0x02,0x3A,0x80,0x18,0x71,0x38,0x2D,0x40,
|
||||
0x58,0x2C,0x45,0x00,0xBA,0x88,0x21,0x00,0x00,0x1E,0x00,0x00,0x00,0xFD,0x00,0x18,
|
||||
0x4B,0x0F,0x87,0x22,0x00,0x0A,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xFC,
|
||||
0x00,0x44,0x75,0x61,0x6C,0x20,0x50,0x6F,0x72,0x74,0x20,0x52,0x47,0x42,0x01,0x50,
|
||||
0x02,0x03,0x18,0x71,0x43,0x04,0x01,0x03,0x23,0x09,0x07,0x01,0x83,0x01,0x00,0x00,
|
||||
0x67,0x03,0x0C,0x00,0x10,0x00,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAD
|
||||
},
|
||||
// EDID with default 3840x2160 60fps
|
||||
{
|
||||
0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x3A,0xC4,0x01,0xED,0x01,0x01,0x01,0x01,
|
||||
0x1E,0x21,0x01,0x03,0x80,0x6F,0x3E,0x78,0x0A,0xEE,0x91,0xA3,0x54,0x4C,0x99,0x26,
|
||||
0x0F,0x50,0x54,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
|
||||
0x01,0x01,0x01,0x01,0x01,0x01,0x08,0xE8,0x00,0x30,0xF2,0x70,0x5A,0x80,0xB0,0x58,
|
||||
0x8A,0x00,0x50,0x1D,0x74,0x00,0x00,0x1E,0x08,0xE8,0x00,0x30,0xF2,0x70,0x5A,0x80,
|
||||
0xB0,0x58,0x8A,0x00,0x50,0x1D,0x74,0x00,0x00,0x1E,0x00,0x00,0x00,0xFD,0x00,0x18,
|
||||
0x4B,0x0F,0x87,0x3C,0x00,0x0A,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xFC,
|
||||
0x00,0x44,0x75,0x61,0x6C,0x20,0x50,0x6F,0x72,0x74,0x20,0x52,0x47,0x42,0x01,0xC7,
|
||||
0x02,0x03,0x20,0x71,0x43,0x61,0x01,0x03,0x23,0x09,0x07,0x01,0x83,0x01,0x00,0x00,
|
||||
0x67,0x03,0x0C,0x00,0x10,0x00,0x00,0x3C,0x67,0xD8,0x5D,0xC4,0x01,0x78,0x80,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xEF
|
||||
},
|
||||
// EDID with default 1280x720 60fps
|
||||
{
|
||||
0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x3A,0xC4,0x05,0xED,0x01,0x01,0x01,0x01,
|
||||
0x1E,0x21,0x01,0x03,0x80,0x6F,0x3E,0x78,0x0A,0xEE,0x91,0xA3,0x54,0x4C,0x99,0x26,
|
||||
0x0F,0x50,0x54,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
|
||||
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x1D,0x00,0x72,0x51,0xD0,0x1E,0x20,0x6E,0x28,
|
||||
0x55,0x00,0xC4,0x8E,0x21,0x00,0x00,0x1E,0x01,0x1D,0x00,0x72,0x51,0xD0,0x1E,0x20,
|
||||
0x6E,0x28,0x55,0x00,0xC4,0x8E,0x21,0x00,0x00,0x1E,0x00,0x00,0x00,0xFD,0x00,0x18,
|
||||
0x4B,0x0F,0x87,0x22,0x00,0x0A,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,0xFC,
|
||||
0x00,0x44,0x75,0x61,0x6C,0x20,0x50,0x6F,0x72,0x74,0x20,0x52,0x47,0x42,0x01,0xE1,
|
||||
0x02,0x03,0x18,0x71,0x43,0x04,0x01,0x03,0x23,0x09,0x07,0x01,0x83,0x01,0x00,0x00,
|
||||
0x67,0x03,0x0C,0x00,0x10,0x00,0x00,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xAD
|
||||
}
|
||||
};
|
||||
|
||||
static const struct of_device_id lt6911uxc_of_match[] = {
|
||||
{ .compatible = "nvidia,lt6911uxc", },
|
||||
{ },
|
||||
@@ -37,13 +167,18 @@ static const int lt6911uxc_30fps[] = {
|
||||
30,
|
||||
};
|
||||
|
||||
static const u8 lt6911uxc_HDMI_Signal = 0xa3;
|
||||
|
||||
static const u8 lt6911uxc_FW_version[] = { 0xa7, 0xa8, 0xa9, 0xaa };
|
||||
|
||||
struct lt6911uxc {
|
||||
struct i2c_client *i2c_client;
|
||||
struct v4l2_subdev *subdev;
|
||||
u16 fine_integ_time;
|
||||
u32 frame_length;
|
||||
u16 fine_integ_time;
|
||||
u32 frame_length;
|
||||
struct camera_common_data *s_data;
|
||||
struct tegracam_device *tc_dev;
|
||||
struct regmap *regmap;
|
||||
};
|
||||
|
||||
static const struct camera_common_frmfmt lt6911uxc_frmfmt[] = {
|
||||
@@ -53,11 +188,50 @@ static const struct camera_common_frmfmt lt6911uxc_frmfmt[] = {
|
||||
};
|
||||
|
||||
static const struct regmap_config sensor_regmap_config = {
|
||||
.reg_bits = 16,
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static inline int lt6911uxc_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);
|
||||
if (err) {
|
||||
dev_err(s_data->dev, "%s: i2c read , 0x%x = %x",
|
||||
__func__, addr, reg_val);
|
||||
return err;
|
||||
}
|
||||
|
||||
*val = reg_val & 0xff;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline int lt6911uxc_write_reg(struct camera_common_data *s_data,
|
||||
u16 addr, u8 val)
|
||||
{
|
||||
int err = 0;
|
||||
err = regmap_write(s_data->regmap, addr, val);
|
||||
if (err)
|
||||
dev_err(s_data->dev, "%s: i2c write failed, 0x%x = %x",
|
||||
__func__, addr, val);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int lt6911uxc_write_table(struct lt6911uxc *priv,
|
||||
const lt6911uxc_reg table[])
|
||||
{
|
||||
return regmap_util_write_table_8(priv->s_data->regmap,
|
||||
table,
|
||||
NULL, 0,
|
||||
LT6911_TABLE_WAIT_MS,
|
||||
LT6911_TABLE_END);
|
||||
}
|
||||
|
||||
static int lt6911uxc_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
@@ -84,6 +258,8 @@ static int lt6911uxc_start_streaming(struct tegracam_device *tc_dev)
|
||||
else
|
||||
gpio_set_value(pw->reset_gpio, 1);
|
||||
}
|
||||
msleep(300);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -101,29 +277,7 @@ static int lt6911uxc_stop_streaming(struct tegracam_device *tc_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lt6911uxc_set_mode(struct tegracam_device *tc_dev)
|
||||
{
|
||||
/* Width and Height taken care of by the firmware */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int lt6911uxc_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 inline int lt6911uxc_write_reg(struct camera_common_data *s_data,
|
||||
u16 addr, u8 val)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lt6911uxc_power_get(struct tegracam_device *tc_dev)
|
||||
{
|
||||
@@ -309,9 +463,9 @@ static int lt6911uxc_power_on(struct camera_common_data *s_data)
|
||||
|
||||
if (pw->reset_gpio) {
|
||||
if (gpiod_cansleep(gpio_to_desc(pw->reset_gpio)))
|
||||
gpio_set_value_cansleep(pw->reset_gpio, 0);
|
||||
gpio_set_value_cansleep(pw->reset_gpio, 1);
|
||||
else
|
||||
gpio_set_value(pw->reset_gpio, 0);
|
||||
gpio_set_value(pw->reset_gpio, 1);
|
||||
}
|
||||
|
||||
usleep_range(10, 20);
|
||||
@@ -335,7 +489,7 @@ static int lt6911uxc_power_on(struct camera_common_data *s_data)
|
||||
goto lt6911uxc_dvdd_fail;
|
||||
}
|
||||
|
||||
usleep_range(10, 20);
|
||||
msleep(300);
|
||||
|
||||
pw->state = SWITCH_ON;
|
||||
|
||||
@@ -389,11 +543,64 @@ static int lt6911uxc_power_off(struct camera_common_data *s_data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lt6911uxc_set_mode(struct tegracam_device *tc_dev)
|
||||
{
|
||||
int err = 0;
|
||||
int i, j;
|
||||
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct lt6911uxc *priv = (struct lt6911uxc *)s_data->priv;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
|
||||
// Write the corresponding Shadow EDID
|
||||
err |= lt6911uxc_write_table(priv, lt_enable_i2c);
|
||||
err |= lt6911uxc_write_table(priv, lt_configure_param);
|
||||
err |= lt6911uxc_write_table(priv, lt_block_erase);
|
||||
msleep(600);
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
err |= lt6911uxc_write_table(priv, lt_fifo_rst);
|
||||
err |= lt6911uxc_write_table(priv, lt_write_enable);
|
||||
err |= lt6911uxc_write_table(priv, lt_data_to_fifo);
|
||||
|
||||
for(j = 0; j < 32; j++)
|
||||
{
|
||||
lt6911uxc_write_reg(priv->s_data, 0x59,
|
||||
LT6911_EDIDs[s_data->mode][(i * 32) + j]);
|
||||
}
|
||||
err |= lt6911uxc_write_reg(priv->s_data, 0x5b, 0x01);
|
||||
err |= lt6911uxc_write_reg(priv->s_data, 0x5c, 0x80);
|
||||
err |= lt6911uxc_write_reg(priv->s_data, 0x5d, (i) * 32);
|
||||
err |= lt6911uxc_write_reg(priv->s_data, 0x5a, 0x10);
|
||||
msleep(1);
|
||||
err |= lt6911uxc_write_reg(priv->s_data, 0x5a, 0x00);
|
||||
msleep(1);
|
||||
}
|
||||
err |= lt6911uxc_write_table(priv, lt_write_disable);
|
||||
if (err)
|
||||
dev_err(tc_dev->dev, "%s Error in writing shadow EDID \n", __func__);
|
||||
|
||||
// Toggle the reset pin to low, stream on will again set it to high
|
||||
if (pw->reset_gpio) {
|
||||
if (gpiod_cansleep(gpio_to_desc(pw->reset_gpio)))
|
||||
gpio_set_value_cansleep(pw->reset_gpio, 0);
|
||||
else
|
||||
gpio_set_value(pw->reset_gpio, 0);
|
||||
}
|
||||
// Keep reset pin low for the changes to take effect
|
||||
msleep(800);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int lt6911uxc_board_setup(struct lt6911uxc *priv)
|
||||
{
|
||||
struct camera_common_data *s_data = priv->s_data;
|
||||
struct camera_common_pdata *pdata = s_data->pdata;
|
||||
struct device *dev = s_data->dev;
|
||||
u8 version;
|
||||
int i = 0, fw_ver;
|
||||
int err = 0;
|
||||
|
||||
if (pdata->mclk_name) {
|
||||
@@ -409,11 +616,31 @@ static int lt6911uxc_board_setup(struct lt6911uxc *priv)
|
||||
dev_err(dev, "error during power on sensor (%d)\n", err);
|
||||
goto err_power_on;
|
||||
}
|
||||
msleep(300);
|
||||
|
||||
err |= lt6911uxc_write_table(priv, lt_enable_i2c);
|
||||
err |= lt6911uxc_write_reg(s_data, 0xff, 0x86);
|
||||
|
||||
for (i = 0; i < sizeof(lt6911uxc_FW_version); i++) {
|
||||
fw_ver = 0;
|
||||
err = lt6911uxc_read_reg(s_data, lt6911uxc_FW_version[i], &version);
|
||||
if (err)
|
||||
dev_err(s_data->dev, "%s: Error in reading FW version \n",
|
||||
__func__);
|
||||
fw_ver = (fw_ver << 1) | version;
|
||||
}
|
||||
dev_info(s_data->dev, "Lontium FW version %d \n",fw_ver);
|
||||
|
||||
err_power_on:
|
||||
if (pdata->mclk_name)
|
||||
camera_common_mclk_disable(s_data);
|
||||
|
||||
err = lt6911uxc_power_off(s_data);
|
||||
if (err) {
|
||||
dev_err(dev, "error during power off sensor (%d)\n", err);
|
||||
goto err_power_on;
|
||||
}
|
||||
|
||||
done:
|
||||
return err;
|
||||
}
|
||||
@@ -442,7 +669,7 @@ static struct camera_common_sensor_ops lt6911uxc_common_ops = {
|
||||
};
|
||||
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int lt6911uxc_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int lt6911uxc_probe(struct i2c_client *client,
|
||||
@@ -506,7 +733,7 @@ static int lt6911uxc_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int lt6911uxc_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void lt6911uxc_remove(struct i2c_client *client)
|
||||
@@ -516,7 +743,7 @@ static void lt6911uxc_remove(struct i2c_client *client)
|
||||
struct lt6911uxc *priv;
|
||||
|
||||
if (!s_data)
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return -EINVAL;
|
||||
#else
|
||||
return;
|
||||
@@ -526,7 +753,7 @@ static void lt6911uxc_remove(struct i2c_client *client)
|
||||
tegracam_v4l2subdev_unregister(priv->tc_dev);
|
||||
tegracam_device_unregister(priv->tc_dev);
|
||||
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* max9295.c - max9295 GMSL Serializer driver
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <media/camera_common.h>
|
||||
#include <linux/module.h>
|
||||
#include <media/max9295.h>
|
||||
@@ -463,7 +465,7 @@ static struct regmap_config max9295_regmap_config = {
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int max9295_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int max9295_probe(struct i2c_client *client,
|
||||
@@ -512,7 +514,7 @@ static int max9295_probe(struct i2c_client *client,
|
||||
return err;
|
||||
}
|
||||
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int max9295_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void max9295_remove(struct i2c_client *client)
|
||||
@@ -526,7 +528,7 @@ static void max9295_remove(struct i2c_client *client)
|
||||
i2c_unregister_device(client);
|
||||
client = NULL;
|
||||
}
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* max9296.c - max9296 GMSL Deserializer driver
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
@@ -846,7 +848,7 @@ static struct regmap_config max9296_regmap_config = {
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int max9296_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int max9296_probe(struct i2c_client *client,
|
||||
@@ -892,7 +894,7 @@ static int max9296_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int max9296_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void max9296_remove(struct i2c_client *client)
|
||||
@@ -906,7 +908,7 @@ static void max9296_remove(struct i2c_client *client)
|
||||
i2c_unregister_device(client);
|
||||
client = NULL;
|
||||
}
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
194
drivers/media/i2c/max929x.c
Normal file
194
drivers/media/i2c/max929x.c
Normal file
@@ -0,0 +1,194 @@
|
||||
// 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");
|
||||
152
drivers/media/i2c/max929x.h
Normal file
152
drivers/media/i2c/max929x.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/* 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,6 +7,8 @@
|
||||
|
||||
/* #define DEBUG */
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <media/camera_common.h>
|
||||
@@ -226,7 +228,7 @@ static struct regmap_config max96712_regmap_config = {
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int max96712_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int max96712_probe(struct i2c_client *client,
|
||||
@@ -266,7 +268,7 @@ static int max96712_probe(struct i2c_client *client,
|
||||
return err;
|
||||
}
|
||||
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int max96712_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void max96712_remove(struct i2c_client *client)
|
||||
@@ -277,7 +279,7 @@ static void max96712_remove(struct i2c_client *client)
|
||||
i2c_unregister_device(client);
|
||||
client = NULL;
|
||||
}
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2018-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2018-2024 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>
|
||||
@@ -26,6 +28,7 @@
|
||||
#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
|
||||
|
||||
@@ -62,7 +65,6 @@ 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 {
|
||||
@@ -125,7 +127,13 @@ struct camera_extrinsics {
|
||||
float tx, ty, tz;
|
||||
};
|
||||
|
||||
struct imu_params {
|
||||
/*
|
||||
* 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 {
|
||||
// 3D vector to add to accelerometer readings
|
||||
float linear_acceleration_bias[3];
|
||||
// 3D vector to add to gyroscope readings
|
||||
@@ -134,7 +142,12 @@ struct imu_params {
|
||||
float gravity_acceleration[3];
|
||||
// Extrinsic structure for IMU device
|
||||
struct camera_extrinsics extr;
|
||||
// Noise model parameters
|
||||
};
|
||||
|
||||
struct imu_params_noise_m {
|
||||
/*
|
||||
* Noise model parameters
|
||||
*/
|
||||
float update_rate;
|
||||
float linear_acceleration_noise_density;
|
||||
float linear_acceleration_random_walk;
|
||||
@@ -142,6 +155,14 @@ struct imu_params {
|
||||
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;
|
||||
@@ -184,7 +205,7 @@ struct NvCamSyncSensorCalibData {
|
||||
u8 imu_present;
|
||||
|
||||
// Intrinsic structure for IMU
|
||||
struct imu_params imu;
|
||||
struct imu_params_v2 imu;
|
||||
|
||||
// HAWK module serial number
|
||||
u8 serial_number[CAMERA_MAX_SN_LENGTH];
|
||||
@@ -219,10 +240,14 @@ struct LiEeprom_Content_Struct {
|
||||
/**
|
||||
* Intrinsic structure for IMU
|
||||
*/
|
||||
struct imu_params imu;
|
||||
struct imu_params_v1 imu;
|
||||
|
||||
u8 tmp[16];
|
||||
|
||||
// HAWK module serial number
|
||||
u8 serial_number[CAMERA_MAX_SN_LENGTH];
|
||||
u8 serial_number[LEOP_CAMERA_MAX_SN_LENGTH];
|
||||
|
||||
struct imu_params_noise_m nm;
|
||||
|
||||
// Radial Lens Shading Correction parameters
|
||||
struct radial_lsc_params left_rls;
|
||||
@@ -676,9 +701,10 @@ 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 = tmp->imu;
|
||||
priv->EepromCalib.imu.imu_data_v1 = tmp->imu;
|
||||
priv->EepromCalib.imu.nm = tmp->nm;
|
||||
memcpy(priv->EepromCalib.serial_number, tmp->serial_number,
|
||||
CAMERA_MAX_SN_LENGTH);
|
||||
8);
|
||||
|
||||
if (priv->sync_sensor_index == 1)
|
||||
priv->EepromCalib.rls = tmp->left_rls;
|
||||
@@ -792,7 +818,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), alternating_exposure_cfg_size},
|
||||
.compound_ctrl_size = {sizeof(struct NvCamSyncSensorCalibData), sizeof(struct alternating_exposure_cfg)},
|
||||
.set_gain = ar0234_set_gain,
|
||||
.set_exposure = ar0234_set_exposure,
|
||||
.set_exposure_short = ar0234_set_exposure,
|
||||
@@ -1044,7 +1070,7 @@ static int ar0234_board_setup(struct ar0234 *priv)
|
||||
|
||||
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int ar0234_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int ar0234_probe(struct i2c_client *client,
|
||||
@@ -1149,7 +1175,7 @@ static int ar0234_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int ar0234_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void ar0234_remove(struct i2c_client *client)
|
||||
@@ -1159,7 +1185,7 @@ static void ar0234_remove(struct i2c_client *client)
|
||||
struct ar0234 *priv;
|
||||
|
||||
if (!s_data)
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return -EINVAL;
|
||||
#else
|
||||
return;
|
||||
@@ -1169,7 +1195,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 (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2022-2024 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>
|
||||
@@ -15,6 +17,7 @@
|
||||
#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>
|
||||
@@ -23,6 +26,7 @@
|
||||
#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
|
||||
@@ -64,8 +68,6 @@ 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
|
||||
{
|
||||
@@ -127,6 +129,13 @@ 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
|
||||
@@ -137,13 +146,26 @@ typedef struct
|
||||
float gravity_acceleration[3];
|
||||
// Extrinsic structure for IMU device
|
||||
camera_extrinsics extr;
|
||||
// Noise model parameters
|
||||
} imu_params_v1;
|
||||
|
||||
typedef struct {
|
||||
/*
|
||||
* 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;
|
||||
} 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;
|
||||
|
||||
typedef struct {
|
||||
// Image height
|
||||
@@ -187,7 +209,7 @@ typedef struct
|
||||
u8 imu_present;
|
||||
|
||||
// Intrinsic structure for IMU
|
||||
imu_params imu;
|
||||
imu_params_v2 imu;
|
||||
|
||||
// HAWK module serial number
|
||||
u8 serial_number[CAMERA_MAX_SN_LENGTH];
|
||||
@@ -195,6 +217,7 @@ typedef struct
|
||||
// Radial Lens Shading Correction parameters
|
||||
radial_lsc_params rls;
|
||||
} NvCamSyncSensorCalibData;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/**
|
||||
@@ -222,15 +245,20 @@ typedef struct
|
||||
/**
|
||||
* Intrinsic structure for IMU
|
||||
*/
|
||||
imu_params imu;
|
||||
imu_params_v1 imu;
|
||||
|
||||
u8 tmp[16];
|
||||
|
||||
// HAWK module serial number
|
||||
u8 serial_number[CAMERA_MAX_SN_LENGTH];
|
||||
u8 serial_number[LEOP_CAMERA_MAX_SN_LENGTH];
|
||||
|
||||
imu_params_noise_m nm;
|
||||
|
||||
// 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];
|
||||
@@ -245,17 +273,20 @@ 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)
|
||||
{
|
||||
@@ -343,7 +374,7 @@ retry_sensor:
|
||||
return -1;
|
||||
} else {
|
||||
if (0x301a == table[i].addr || 0x3060 == table[i].addr)
|
||||
msleep(100);
|
||||
msleep(20);
|
||||
}
|
||||
} else {
|
||||
retry = 5;
|
||||
@@ -554,7 +585,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)
|
||||
@@ -567,8 +598,6 @@ 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)
|
||||
@@ -763,9 +792,10 @@ 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 = tmp->imu;
|
||||
priv->EepromCalib.imu.imu_data_v1 = tmp->imu;
|
||||
priv->EepromCalib.imu.nm = tmp->nm;
|
||||
memcpy(priv->EepromCalib.serial_number, tmp->serial_number,
|
||||
CAMERA_MAX_SN_LENGTH);
|
||||
8);
|
||||
|
||||
if (priv->sync_sensor_index == 1)
|
||||
priv->EepromCalib.rls = tmp->left_rls;
|
||||
@@ -877,7 +907,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), alternating_exposure_cfg_size},
|
||||
.compound_ctrl_size = {sizeof(NvCamSyncSensorCalibData), sizeof(struct alternating_exposure_cfg)},
|
||||
.set_gain = ar0234_set_gain,
|
||||
.set_exposure = ar0234_set_exposure,
|
||||
.set_exposure_short = ar0234_set_exposure,
|
||||
@@ -1434,7 +1464,7 @@ static int ar0234_hawk_owl_deser_ser_program(struct ar0234 *priv)
|
||||
return err;
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int ar0234_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int ar0234_probe(struct i2c_client *client,
|
||||
@@ -1503,6 +1533,14 @@ 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");
|
||||
@@ -1572,7 +1610,7 @@ un_register:
|
||||
return err;
|
||||
}
|
||||
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int ar0234_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void ar0234_remove(struct i2c_client *client)
|
||||
@@ -1582,7 +1620,7 @@ static void ar0234_remove(struct i2c_client *client)
|
||||
struct ar0234 *priv = (struct ar0234 *)s_data->priv;
|
||||
|
||||
if (!s_data)
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return -EINVAL;
|
||||
#else
|
||||
return;
|
||||
@@ -1590,7 +1628,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 (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* 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>
|
||||
@@ -775,7 +777,7 @@ static const struct v4l2_subdev_internal_ops imx185_subdev_internal_ops = {
|
||||
.open = imx185_open,
|
||||
};
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int imx185_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int imx185_probe(struct i2c_client *client,
|
||||
@@ -838,11 +840,11 @@ static int imx185_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
|
||||
static void
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int
|
||||
imx185_remove(struct i2c_client *client)
|
||||
#else
|
||||
static int
|
||||
static void
|
||||
imx185_remove(struct i2c_client *client)
|
||||
#endif
|
||||
{
|
||||
@@ -850,17 +852,17 @@ imx185_remove(struct i2c_client *client)
|
||||
struct imx185 *priv;
|
||||
|
||||
if (!s_data)
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
|
||||
return;
|
||||
#else
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return -EINVAL;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
|
||||
priv = (struct imx185 *)s_data->priv;
|
||||
|
||||
tegracam_v4l2subdev_unregister(priv->tc_dev);
|
||||
tegracam_device_unregister(priv->tc_dev);
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
// 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>
|
||||
@@ -691,7 +692,7 @@ static const struct v4l2_subdev_internal_ops imx219_subdev_internal_ops = {
|
||||
.open = imx219_open,
|
||||
};
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int imx219_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int imx219_probe(struct i2c_client *client,
|
||||
@@ -745,6 +746,7 @@ 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;
|
||||
}
|
||||
@@ -754,10 +756,10 @@ static int imx219_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
|
||||
static void imx219_remove(struct i2c_client *client)
|
||||
#else
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int imx219_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void imx219_remove(struct i2c_client *client)
|
||||
#endif
|
||||
{
|
||||
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
|
||||
@@ -765,7 +767,7 @@ static int imx219_remove(struct i2c_client *client)
|
||||
|
||||
if (!s_data) {
|
||||
dev_err(&client->dev, "camera common data is NULL\n");
|
||||
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return -EINVAL;
|
||||
#else
|
||||
return;
|
||||
@@ -776,7 +778,7 @@ static int imx219_remove(struct i2c_client *client)
|
||||
tegracam_v4l2subdev_unregister(priv->tc_dev);
|
||||
tegracam_device_unregister(priv->tc_dev);
|
||||
|
||||
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* 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>
|
||||
@@ -1260,7 +1262,7 @@ static const struct v4l2_subdev_internal_ops imx274_subdev_internal_ops = {
|
||||
.open = imx274_open,
|
||||
};
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int imx274_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int imx274_probe(struct i2c_client *client,
|
||||
@@ -1333,20 +1335,20 @@ static int imx274_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
|
||||
static void imx274_remove(struct i2c_client *client)
|
||||
#else
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int imx274_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void 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 LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
|
||||
return;
|
||||
#else
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return -EINVAL;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
|
||||
priv = (struct imx274 *)s_data->priv;
|
||||
@@ -1358,7 +1360,7 @@ static int imx274_remove(struct i2c_client *client)
|
||||
imx274_eeprom_device_release(priv);
|
||||
|
||||
mutex_destroy(&priv->streaming_lock);
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES.
|
||||
// All rights reserved.
|
||||
//
|
||||
// nv_imx318.c - imx318 sensor driver
|
||||
//
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
@@ -129,6 +135,11 @@ 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;
|
||||
@@ -695,7 +706,7 @@ static const struct v4l2_subdev_internal_ops imx318_subdev_internal_ops = {
|
||||
.open = imx318_open,
|
||||
};
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int imx318_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int imx318_probe(struct i2c_client *client,
|
||||
@@ -759,7 +770,7 @@ static int imx318_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int imx318_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void imx318_remove(struct i2c_client *client)
|
||||
@@ -769,7 +780,7 @@ static void imx318_remove(struct i2c_client *client)
|
||||
struct imx318 *priv;
|
||||
|
||||
if (!s_data)
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return -EINVAL;
|
||||
#else
|
||||
return;
|
||||
@@ -780,7 +791,7 @@ static void imx318_remove(struct i2c_client *client)
|
||||
tegracam_device_unregister(priv->tc_dev);
|
||||
imx318_eeprom_device_release(priv);
|
||||
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
911
drivers/media/i2c/nv_imx390_archived.c
Normal file
911
drivers/media/i2c/nv_imx390_archived.c
Normal file
@@ -0,0 +1,911 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2018-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
|
||||
#include <media/max9295.h>
|
||||
#include <media/max9296.h>
|
||||
|
||||
#include <media/tegracam_core.h>
|
||||
#include "imx390_mode_tbls.h"
|
||||
|
||||
#define IMX390_MIN_GAIN (0)
|
||||
#define IMX390_MAX_GAIN (30)
|
||||
#define IMX390_MAX_GAIN_REG ((IMX390_MAX_GAIN - IMX390_MIN_GAIN) * 10 / 3)
|
||||
#define IMX390_DEFAULT_FRAME_LENGTH (1125)
|
||||
#define IMX390_FRAME_LENGTH_ADDR_MSB 0x200A
|
||||
#define IMX390_FRAME_LENGTH_ADDR_MID 0x2009
|
||||
#define IMX390_FRAME_LENGTH_ADDR_LSB 0x2008
|
||||
#define IMX390_COARSE_TIME_SHS1_ADDR_MSB 0x000E
|
||||
#define IMX390_COARSE_TIME_SHS1_ADDR_MID 0x000D
|
||||
#define IMX390_COARSE_TIME_SHS1_ADDR_LSB 0x000C
|
||||
#define IMX390_COARSE_TIME_SHS2_ADDR_MSB 0x0012
|
||||
#define IMX390_COARSE_TIME_SHS2_ADDR_MID 0x0011
|
||||
#define IMX390_COARSE_TIME_SHS2_ADDR_LSB 0x0010
|
||||
#define IMX390_GROUP_HOLD_ADDR 0x0008
|
||||
#define IMX390_ANALOG_GAIN_SP1H_ADDR 0x0018
|
||||
#define IMX390_ANALOG_GAIN_SP1L_ADDR 0x001A
|
||||
|
||||
static const struct of_device_id imx390_of_match[] = {
|
||||
{ .compatible = "sony,imx390",},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, imx390_of_match);
|
||||
|
||||
static const u32 ctrl_cid_list[] = {
|
||||
TEGRA_CAMERA_CID_GAIN,
|
||||
TEGRA_CAMERA_CID_EXPOSURE,
|
||||
TEGRA_CAMERA_CID_EXPOSURE_SHORT,
|
||||
TEGRA_CAMERA_CID_FRAME_RATE,
|
||||
TEGRA_CAMERA_CID_HDR_EN,
|
||||
};
|
||||
|
||||
struct imx390 {
|
||||
struct i2c_client *i2c_client;
|
||||
const struct i2c_device_id *id;
|
||||
struct v4l2_subdev *subdev;
|
||||
struct device *ser_dev;
|
||||
struct device *dser_dev;
|
||||
struct gmsl_link_ctx g_ctx;
|
||||
u32 frame_length;
|
||||
struct camera_common_data *s_data;
|
||||
struct tegracam_device *tc_dev;
|
||||
};
|
||||
|
||||
static const struct regmap_config sensor_regmap_config = {
|
||||
.reg_bits = 16,
|
||||
.val_bits = 8,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
static inline void imx390_get_frame_length_regs(imx390_reg *regs,
|
||||
u32 frame_length)
|
||||
{
|
||||
regs->addr = IMX390_FRAME_LENGTH_ADDR_MSB;
|
||||
regs->val = (frame_length >> 16) & 0x01;
|
||||
|
||||
(regs + 1)->addr = IMX390_FRAME_LENGTH_ADDR_MID;
|
||||
(regs + 1)->val = (frame_length >> 8) & 0xff;
|
||||
|
||||
(regs + 2)->addr = IMX390_FRAME_LENGTH_ADDR_LSB;
|
||||
(regs + 2)->val = (frame_length) & 0xff;
|
||||
}
|
||||
|
||||
static inline void imx390_get_coarse_time_regs_shs1(imx390_reg *regs,
|
||||
u32 coarse_time)
|
||||
{
|
||||
regs->addr = IMX390_COARSE_TIME_SHS1_ADDR_MSB;
|
||||
regs->val = (coarse_time >> 16) & 0x0f;
|
||||
|
||||
(regs + 1)->addr = IMX390_COARSE_TIME_SHS1_ADDR_MID;
|
||||
(regs + 1)->val = (coarse_time >> 8) & 0xff;
|
||||
|
||||
(regs + 2)->addr = IMX390_COARSE_TIME_SHS1_ADDR_LSB;
|
||||
(regs + 2)->val = (coarse_time) & 0xff;
|
||||
}
|
||||
|
||||
static inline void imx390_get_coarse_time_regs_shs2(imx390_reg *regs,
|
||||
u32 coarse_time)
|
||||
{
|
||||
regs->addr = IMX390_COARSE_TIME_SHS2_ADDR_MSB;
|
||||
regs->val = (coarse_time >> 16) & 0x0f;
|
||||
|
||||
(regs + 1)->addr = IMX390_COARSE_TIME_SHS2_ADDR_MID;
|
||||
(regs + 1)->val = (coarse_time >> 8) & 0xff;
|
||||
|
||||
(regs + 2)->addr = IMX390_COARSE_TIME_SHS2_ADDR_LSB;
|
||||
(regs + 2)->val = (coarse_time) & 0xff;
|
||||
}
|
||||
|
||||
static inline void imx390_get_gain_reg(imx390_reg *regs,
|
||||
u16 gain)
|
||||
{
|
||||
regs->addr = IMX390_ANALOG_GAIN_SP1H_ADDR;
|
||||
regs->val = (gain) & 0xff;
|
||||
|
||||
(regs + 1)->addr = IMX390_ANALOG_GAIN_SP1H_ADDR + 1;
|
||||
(regs + 1)->val = (gain >> 8) & 0xff;
|
||||
|
||||
(regs + 2)->addr = IMX390_ANALOG_GAIN_SP1L_ADDR;
|
||||
(regs + 2)->val = (gain) & 0xff;
|
||||
|
||||
(regs + 3)->addr = IMX390_ANALOG_GAIN_SP1L_ADDR + 1;
|
||||
(regs + 3)->val = (gain >> 8) & 0xff;
|
||||
}
|
||||
|
||||
|
||||
static int test_mode;
|
||||
module_param(test_mode, int, 0644);
|
||||
|
||||
static inline int imx390_read_reg(struct camera_common_data *s_data,
|
||||
u16 addr, u8 *val)
|
||||
{
|
||||
int err = 0;
|
||||
u32 reg_val = 0;
|
||||
|
||||
err = regmap_read(s_data->regmap, addr, ®_val);
|
||||
*val = reg_val & 0xFF;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_write_reg(struct camera_common_data *s_data,
|
||||
u16 addr, u8 val)
|
||||
{
|
||||
int err;
|
||||
struct device *dev = s_data->dev;
|
||||
|
||||
err = regmap_write(s_data->regmap, addr, val);
|
||||
if (err)
|
||||
dev_err(dev, "%s:i2c write failed, 0x%x = %x\n",
|
||||
__func__, addr, val);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_write_table(struct imx390 *priv,
|
||||
const imx390_reg table[])
|
||||
{
|
||||
struct camera_common_data *s_data = priv->s_data;
|
||||
|
||||
return regmap_util_write_table_8(s_data->regmap,
|
||||
table,
|
||||
NULL, 0,
|
||||
IMX390_TABLE_WAIT_MS,
|
||||
IMX390_TABLE_END);
|
||||
}
|
||||
|
||||
static struct mutex serdes_lock__;
|
||||
|
||||
static int imx390_gmsl_serdes_setup(struct imx390 *priv)
|
||||
{
|
||||
int err = 0;
|
||||
int des_err = 0;
|
||||
struct device *dev;
|
||||
|
||||
if (!priv || !priv->ser_dev || !priv->dser_dev || !priv->i2c_client)
|
||||
return -EINVAL;
|
||||
|
||||
dev = &priv->i2c_client->dev;
|
||||
|
||||
mutex_lock(&serdes_lock__);
|
||||
|
||||
/* For now no separate power on required for serializer device */
|
||||
max9296_power_on(priv->dser_dev);
|
||||
|
||||
/* setup serdes addressing and control pipeline */
|
||||
err = max9296_setup_link(priv->dser_dev, &priv->i2c_client->dev);
|
||||
if (err) {
|
||||
dev_err(dev, "gmsl deserializer link config failed\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = max9295_setup_control(priv->ser_dev);
|
||||
|
||||
/* proceed even if ser setup failed, to setup deser correctly */
|
||||
if (err)
|
||||
dev_err(dev, "gmsl serializer setup failed\n");
|
||||
|
||||
des_err = max9296_setup_control(priv->dser_dev, &priv->i2c_client->dev);
|
||||
if (des_err) {
|
||||
dev_err(dev, "gmsl deserializer setup failed\n");
|
||||
/* overwrite err only if deser setup also failed */
|
||||
err = des_err;
|
||||
}
|
||||
|
||||
error:
|
||||
mutex_unlock(&serdes_lock__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void imx390_gmsl_serdes_reset(struct imx390 *priv)
|
||||
{
|
||||
mutex_lock(&serdes_lock__);
|
||||
|
||||
/* reset serdes addressing and control pipeline */
|
||||
max9295_reset_control(priv->ser_dev);
|
||||
max9296_reset_control(priv->dser_dev, &priv->i2c_client->dev);
|
||||
|
||||
max9296_power_off(priv->dser_dev);
|
||||
|
||||
mutex_unlock(&serdes_lock__);
|
||||
}
|
||||
|
||||
static int imx390_power_on(struct camera_common_data *s_data)
|
||||
{
|
||||
int err = 0;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
struct camera_common_pdata *pdata = s_data->pdata;
|
||||
struct device *dev = s_data->dev;
|
||||
|
||||
dev_dbg(dev, "%s: power on\n", __func__);
|
||||
if (pdata && pdata->power_on) {
|
||||
err = pdata->power_on(pw);
|
||||
if (err)
|
||||
dev_err(dev, "%s failed.\n", __func__);
|
||||
else
|
||||
pw->state = SWITCH_ON;
|
||||
return err;
|
||||
}
|
||||
|
||||
pw->state = SWITCH_ON;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_power_off(struct camera_common_data *s_data)
|
||||
{
|
||||
int err = 0;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
struct camera_common_pdata *pdata = s_data->pdata;
|
||||
struct device *dev = s_data->dev;
|
||||
|
||||
dev_dbg(dev, "%s:\n", __func__);
|
||||
|
||||
if (pdata && pdata->power_off) {
|
||||
err = pdata->power_off(pw);
|
||||
if (!err)
|
||||
goto power_off_done;
|
||||
else
|
||||
dev_err(dev, "%s failed.\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
power_off_done:
|
||||
pw->state = SWITCH_OFF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_power_get(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct device *dev = tc_dev->dev;
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
struct camera_common_pdata *pdata = s_data->pdata;
|
||||
const char *mclk_name;
|
||||
const char *parentclk_name;
|
||||
struct clk *parent;
|
||||
int err = 0;
|
||||
|
||||
mclk_name = pdata->mclk_name ?
|
||||
pdata->mclk_name : "cam_mclk1";
|
||||
pw->mclk = devm_clk_get(dev, mclk_name);
|
||||
if (IS_ERR(pw->mclk)) {
|
||||
dev_err(dev, "unable to get clock %s\n", mclk_name);
|
||||
return PTR_ERR(pw->mclk);
|
||||
}
|
||||
|
||||
parentclk_name = pdata->parentclk_name;
|
||||
if (parentclk_name) {
|
||||
parent = devm_clk_get(dev, parentclk_name);
|
||||
if (IS_ERR(parent)) {
|
||||
dev_err(dev, "unable to get parent clcok %s",
|
||||
parentclk_name);
|
||||
} else {
|
||||
err = clk_set_parent(pw->mclk, parent);
|
||||
if (err < 0)
|
||||
dev_dbg(dev,
|
||||
"%s failed to set parent clock %d\n",
|
||||
__func__, err);
|
||||
}
|
||||
}
|
||||
|
||||
pw->state = SWITCH_OFF;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_power_put(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct camera_common_power_rail *pw = s_data->power;
|
||||
|
||||
if (unlikely(!pw))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_set_group_hold(struct tegracam_device *tc_dev, bool val)
|
||||
{
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct device *dev = tc_dev->dev;
|
||||
int err;
|
||||
|
||||
err = imx390_write_reg(s_data,
|
||||
IMX390_GROUP_HOLD_ADDR, val);
|
||||
if (err) {
|
||||
dev_dbg(dev,
|
||||
"%s: Group hold control error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_set_gain(struct tegracam_device *tc_dev, s64 val)
|
||||
{
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct device *dev = tc_dev->dev;
|
||||
const struct sensor_mode_properties *mode =
|
||||
&s_data->sensor_props.sensor_modes[s_data->mode_prop_idx];
|
||||
imx390_reg reg_list[4];
|
||||
int err, i;
|
||||
u16 gain;
|
||||
|
||||
gain = (u16)(val / mode->control_properties.step_gain_val);
|
||||
|
||||
dev_dbg(dev, "%s: db: %d\n", __func__, gain);
|
||||
|
||||
if (gain > IMX390_MAX_GAIN_REG)
|
||||
gain = IMX390_MAX_GAIN_REG;
|
||||
|
||||
imx390_get_gain_reg(reg_list, gain);
|
||||
for (i = 0; i < 4; i++) {
|
||||
err = imx390_write_reg(s_data, reg_list[i].addr,
|
||||
reg_list[i].val);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
dev_info(dev, "%s: GAIN control error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
|
||||
{
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
|
||||
/* fixed 30fps */
|
||||
priv->frame_length = IMX390_DEFAULT_FRAME_LENGTH;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx390_set_exposure(struct tegracam_device *tc_dev, s64 val)
|
||||
{
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
const struct sensor_mode_properties *mode =
|
||||
&s_data->sensor_props.sensor_modes[s_data->mode];
|
||||
imx390_reg reg_list[3];
|
||||
int err;
|
||||
u32 coarse_time;
|
||||
u32 shs1;
|
||||
int i = 0;
|
||||
|
||||
if (priv->frame_length == 0)
|
||||
priv->frame_length = IMX390_DEFAULT_FRAME_LENGTH;
|
||||
|
||||
/* coarse time in lines */
|
||||
coarse_time = (u32) (val * s_data->frmfmt[s_data->mode].framerates[0] *
|
||||
priv->frame_length / mode->control_properties.exposure_factor);
|
||||
|
||||
shs1 = priv->frame_length - coarse_time;
|
||||
/* 0 and 1 are prohibited */
|
||||
if (shs1 < 2)
|
||||
shs1 = 2;
|
||||
|
||||
imx390_get_coarse_time_regs_shs1(reg_list, shs1);
|
||||
for (i = 0; i < 3; i++) {
|
||||
err = imx390_write_reg(priv->s_data, reg_list[i].addr,
|
||||
reg_list[i].val);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
imx390_get_coarse_time_regs_shs2(reg_list, shs1);
|
||||
for (i = 0; i < 3; i++) {
|
||||
err = imx390_write_reg(priv->s_data, reg_list[i].addr,
|
||||
reg_list[i].val);
|
||||
if (err)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
dev_dbg(&priv->i2c_client->dev,
|
||||
"%s: set coarse time error\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct tegracam_ctrl_ops imx390_ctrl_ops = {
|
||||
.numctrls = ARRAY_SIZE(ctrl_cid_list),
|
||||
.ctrl_cid_list = ctrl_cid_list,
|
||||
.set_gain = imx390_set_gain,
|
||||
.set_exposure = imx390_set_exposure,
|
||||
.set_exposure_short = imx390_set_exposure,
|
||||
.set_frame_rate = imx390_set_frame_rate,
|
||||
.set_group_hold = imx390_set_group_hold,
|
||||
};
|
||||
|
||||
static struct camera_common_pdata
|
||||
*imx390_parse_dt(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct device *dev = tc_dev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct camera_common_pdata *board_priv_pdata;
|
||||
const struct of_device_id *match;
|
||||
int err;
|
||||
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
match = of_match_device(imx390_of_match, dev);
|
||||
if (!match) {
|
||||
dev_err(dev, "Failed to find matching dt id\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
board_priv_pdata = devm_kzalloc(dev,
|
||||
sizeof(*board_priv_pdata), GFP_KERNEL);
|
||||
|
||||
err = of_property_read_string(node, "mclk",
|
||||
&board_priv_pdata->mclk_name);
|
||||
if (err)
|
||||
dev_err(dev, "mclk not in DT\n");
|
||||
|
||||
return board_priv_pdata;
|
||||
}
|
||||
|
||||
static int imx390_set_mode(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
struct camera_common_data *s_data = tc_dev->s_data;
|
||||
struct device *dev = tc_dev->dev;
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_device(imx390_of_match, dev);
|
||||
if (!match) {
|
||||
dev_err(dev, "Failed to find matching dt id\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (s_data->mode_prop_idx < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return imx390_write_table(priv, mode_table[s_data->mode_prop_idx]);
|
||||
}
|
||||
|
||||
static int imx390_start_streaming(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
struct device *dev = tc_dev->dev;
|
||||
int err;
|
||||
|
||||
/* enable serdes streaming */
|
||||
err = max9295_setup_streaming(priv->ser_dev);
|
||||
if (err)
|
||||
goto exit;
|
||||
err = max9296_setup_streaming(priv->dser_dev, dev);
|
||||
if (err)
|
||||
goto exit;
|
||||
err = max9296_start_streaming(priv->dser_dev, dev);
|
||||
if (err)
|
||||
goto exit;
|
||||
|
||||
err = imx390_write_table(priv,
|
||||
mode_table[IMX390_MODE_START_STREAM]);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
msleep(20);
|
||||
|
||||
return 0;
|
||||
|
||||
exit:
|
||||
dev_err(dev, "%s: error setting stream\n", __func__);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int imx390_stop_streaming(struct tegracam_device *tc_dev)
|
||||
{
|
||||
struct device *dev = tc_dev->dev;
|
||||
struct imx390 *priv = (struct imx390 *)tegracam_get_privdata(tc_dev);
|
||||
|
||||
/* disable serdes streaming */
|
||||
max9296_stop_streaming(priv->dser_dev, dev);
|
||||
|
||||
return imx390_write_table(priv, mode_table[IMX390_MODE_STOP_STREAM]);
|
||||
}
|
||||
|
||||
static struct camera_common_sensor_ops imx390_common_ops = {
|
||||
.numfrmfmts = ARRAY_SIZE(imx390_frmfmt),
|
||||
.frmfmt_table = imx390_frmfmt,
|
||||
.power_on = imx390_power_on,
|
||||
.power_off = imx390_power_off,
|
||||
.write_reg = imx390_write_reg,
|
||||
.read_reg = imx390_read_reg,
|
||||
.parse_dt = imx390_parse_dt,
|
||||
.power_get = imx390_power_get,
|
||||
.power_put = imx390_power_put,
|
||||
.set_mode = imx390_set_mode,
|
||||
.start_streaming = imx390_start_streaming,
|
||||
.stop_streaming = imx390_stop_streaming,
|
||||
};
|
||||
|
||||
static int imx390_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
dev_dbg(&client->dev, "%s:\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_internal_ops imx390_subdev_internal_ops = {
|
||||
.open = imx390_open,
|
||||
};
|
||||
|
||||
static int imx390_board_setup(struct imx390 *priv)
|
||||
{
|
||||
struct tegracam_device *tc_dev = priv->tc_dev;
|
||||
struct device *dev = tc_dev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct device_node *ser_node;
|
||||
struct i2c_client *ser_i2c = NULL;
|
||||
struct device_node *dser_node;
|
||||
struct i2c_client *dser_i2c = NULL;
|
||||
struct device_node *gmsl;
|
||||
int value = 0xFFFF;
|
||||
const char *str_value;
|
||||
const char *str_value1[2];
|
||||
int i;
|
||||
int err;
|
||||
|
||||
err = of_property_read_u32(node, "reg", &priv->g_ctx.sdev_reg);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "reg not found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = of_property_read_u32(node, "def-addr",
|
||||
&priv->g_ctx.sdev_def);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "def-addr not found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ser_node = of_parse_phandle(node, "nvidia,gmsl-ser-device", 0);
|
||||
if (ser_node == NULL) {
|
||||
dev_err(dev,
|
||||
"missing %s handle\n",
|
||||
"nvidia,gmsl-ser-device");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = of_property_read_u32(ser_node, "reg", &priv->g_ctx.ser_reg);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "serializer reg not found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
ser_i2c = of_find_i2c_device_by_node(ser_node);
|
||||
of_node_put(ser_node);
|
||||
|
||||
if (ser_i2c == NULL) {
|
||||
err = -EPROBE_DEFER;
|
||||
goto error;
|
||||
}
|
||||
if (ser_i2c->dev.driver == NULL) {
|
||||
dev_err(dev, "missing serializer driver\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
priv->ser_dev = &ser_i2c->dev;
|
||||
|
||||
dser_node = of_parse_phandle(node, "nvidia,gmsl-dser-device", 0);
|
||||
if (dser_node == NULL) {
|
||||
dev_err(dev,
|
||||
"missing %s handle\n",
|
||||
"nvidia,gmsl-dser-device");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
dser_i2c = of_find_i2c_device_by_node(dser_node);
|
||||
of_node_put(dser_node);
|
||||
|
||||
if (dser_i2c == NULL) {
|
||||
err = -EPROBE_DEFER;
|
||||
goto error;
|
||||
}
|
||||
if (dser_i2c->dev.driver == NULL) {
|
||||
dev_err(dev, "missing deserializer driver\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
priv->dser_dev = &dser_i2c->dev;
|
||||
|
||||
/* populate g_ctx from DT */
|
||||
gmsl = of_get_child_by_name(node, "gmsl-link");
|
||||
if (gmsl == NULL) {
|
||||
dev_err(dev, "missing gmsl-link device node\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = of_property_read_string(gmsl, "dst-csi-port", &str_value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No dst-csi-port found\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.dst_csi_port =
|
||||
(!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B;
|
||||
|
||||
err = of_property_read_string(gmsl, "src-csi-port", &str_value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No src-csi-port found\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.src_csi_port =
|
||||
(!strcmp(str_value, "a")) ? GMSL_CSI_PORT_A : GMSL_CSI_PORT_B;
|
||||
|
||||
err = of_property_read_string(gmsl, "csi-mode", &str_value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No csi-mode found\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!strcmp(str_value, "1x4")) {
|
||||
priv->g_ctx.csi_mode = GMSL_CSI_1X4_MODE;
|
||||
} else if (!strcmp(str_value, "2x4")) {
|
||||
priv->g_ctx.csi_mode = GMSL_CSI_2X4_MODE;
|
||||
} else if (!strcmp(str_value, "4x2")) {
|
||||
priv->g_ctx.csi_mode = GMSL_CSI_4X2_MODE;
|
||||
} else if (!strcmp(str_value, "2x2")) {
|
||||
priv->g_ctx.csi_mode = GMSL_CSI_2X2_MODE;
|
||||
} else {
|
||||
dev_err(dev, "invalid csi mode\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = of_property_read_string(gmsl, "serdes-csi-link", &str_value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No serdes-csi-link found\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.serdes_csi_link =
|
||||
(!strcmp(str_value, "a")) ?
|
||||
GMSL_SERDES_CSI_LINK_A : GMSL_SERDES_CSI_LINK_B;
|
||||
|
||||
err = of_property_read_u32(gmsl, "st-vc", &value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No st-vc info\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.st_vc = value;
|
||||
|
||||
err = of_property_read_u32(gmsl, "vc-id", &value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No vc-id info\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.dst_vc = value;
|
||||
|
||||
err = of_property_read_u32(gmsl, "num-lanes", &value);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "No num-lanes info\n");
|
||||
goto error;
|
||||
}
|
||||
priv->g_ctx.num_csi_lanes = value;
|
||||
|
||||
priv->g_ctx.num_streams =
|
||||
of_property_count_strings(gmsl, "streams");
|
||||
if (priv->g_ctx.num_streams <= 0) {
|
||||
dev_err(dev, "No streams found\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < priv->g_ctx.num_streams; i++) {
|
||||
err = of_property_read_string_index(gmsl, "streams", i,
|
||||
&str_value1[i]);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "Failed to get streams index\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!str_value1[i]) {
|
||||
dev_err(dev, "invalid stream info\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
if (!strcmp(str_value1[i], "raw12")) {
|
||||
priv->g_ctx.streams[i].st_data_type =
|
||||
GMSL_CSI_DT_RAW_12;
|
||||
} else if (!strcmp(str_value1[i], "embed")) {
|
||||
priv->g_ctx.streams[i].st_data_type =
|
||||
GMSL_CSI_DT_EMBED;
|
||||
} else if (!strcmp(str_value1[i], "ued-u1")) {
|
||||
priv->g_ctx.streams[i].st_data_type =
|
||||
GMSL_CSI_DT_UED_U1;
|
||||
} else {
|
||||
dev_err(dev, "invalid stream data type\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
priv->g_ctx.s_dev = dev;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int imx390_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int imx390_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
#endif
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
struct tegracam_device *tc_dev;
|
||||
struct imx390 *priv;
|
||||
int err;
|
||||
|
||||
dev_info(dev, "probing v4l2 sensor.\n");
|
||||
|
||||
if (!IS_ENABLED(CONFIG_OF) || !node)
|
||||
return -EINVAL;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(struct imx390), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
tc_dev = devm_kzalloc(dev,
|
||||
sizeof(struct tegracam_device), GFP_KERNEL);
|
||||
if (!tc_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->i2c_client = tc_dev->client = client;
|
||||
tc_dev->dev = dev;
|
||||
strscpy(tc_dev->name, "imx390", sizeof(tc_dev->name));
|
||||
tc_dev->dev_regmap_config = &sensor_regmap_config;
|
||||
tc_dev->sensor_ops = &imx390_common_ops;
|
||||
tc_dev->v4l2sd_internal_ops = &imx390_subdev_internal_ops;
|
||||
tc_dev->tcctrl_ops = &imx390_ctrl_ops;
|
||||
|
||||
err = tegracam_device_register(tc_dev);
|
||||
if (err) {
|
||||
dev_err(dev, "tegra camera driver registration failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
priv->tc_dev = tc_dev;
|
||||
priv->s_data = tc_dev->s_data;
|
||||
priv->subdev = &tc_dev->s_data->subdev;
|
||||
|
||||
tegracam_set_privdata(tc_dev, (void *)priv);
|
||||
|
||||
err = imx390_board_setup(priv);
|
||||
if (err) {
|
||||
tegracam_device_unregister(tc_dev);
|
||||
dev_err(dev, "board setup failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
mutex_init(&serdes_lock__);
|
||||
|
||||
/* Pair sensor to serializer dev */
|
||||
err = max9295_sdev_pair(priv->ser_dev, &priv->g_ctx);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "gmsl ser pairing failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Register sensor to deserializer dev */
|
||||
err = max9296_sdev_register(priv->dser_dev, &priv->g_ctx);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "gmsl deserializer register failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* gmsl serdes setup
|
||||
*
|
||||
* Sensor power on/off should be the right place for serdes
|
||||
* setup/reset. But the problem is, the total required delay
|
||||
* in serdes setup/reset exceeds the frame wait timeout, looks to
|
||||
* be related to multiple channel open and close sequence
|
||||
* issue (#BUG 200477330).
|
||||
* Once this bug is fixed, these may be moved to power on/off.
|
||||
* The delays in serdes is as per guidelines and can't be reduced,
|
||||
* so it is placed in probe/remove, though for that, deserializer
|
||||
* would be powered on always post boot, until 1.2v is supplied
|
||||
* to deserializer from CVB.
|
||||
*/
|
||||
err = imx390_gmsl_serdes_setup(priv);
|
||||
if (err) {
|
||||
dev_err(&client->dev,
|
||||
"%s gmsl serdes setup failed\n", __func__);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = tegracam_v4l2subdev_register(tc_dev, true);
|
||||
if (err) {
|
||||
dev_err(dev, "tegra camera subdev registration failed\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "Detected IMX390 sensor\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int imx390_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void imx390_remove(struct i2c_client *client)
|
||||
#endif
|
||||
{
|
||||
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
|
||||
struct imx390 *priv;
|
||||
|
||||
if (!s_data)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return -EINVAL;
|
||||
#else
|
||||
return;
|
||||
#endif
|
||||
|
||||
priv = (struct imx390 *)s_data->priv;
|
||||
|
||||
imx390_gmsl_serdes_reset(priv);
|
||||
|
||||
mutex_destroy(&serdes_lock__);
|
||||
tegracam_v4l2subdev_unregister(priv->tc_dev);
|
||||
tegracam_device_unregister(priv->tc_dev);
|
||||
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static const struct i2c_device_id imx390_id[] = {
|
||||
{ "imx390", 0 },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, imx390_id);
|
||||
|
||||
static struct i2c_driver imx390_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "imx390",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(imx390_of_match),
|
||||
},
|
||||
.probe = imx390_probe,
|
||||
.remove = imx390_remove,
|
||||
.id_table = imx390_id,
|
||||
};
|
||||
|
||||
module_i2c_driver(imx390_i2c_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Media Controller driver for Sony IMX390");
|
||||
MODULE_AUTHOR("NVIDIA Corporation");
|
||||
MODULE_AUTHOR("Sudhir Vyas <svyas@nvidia.com");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -1,13 +1,15 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2021-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* Copyright (c) 2020, RidgeRun. All rights reserved.
|
||||
* Copyright (c) 2021-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*
|
||||
* Contact us: support@ridgerun.com
|
||||
*
|
||||
* nv_imx477.c - imx477 sensor driver
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/gpio.h>
|
||||
@@ -24,6 +26,8 @@
|
||||
#include "../platform/tegra/camera/camera_gpio.h"
|
||||
#include "imx477_mode_tbls.h"
|
||||
|
||||
#define IMX477_SENSOR_INTERNAL_CLK_FREQ 840000000
|
||||
|
||||
static const struct of_device_id imx477_of_match[] = {
|
||||
{.compatible = "ridgerun,imx477",},
|
||||
{},
|
||||
@@ -226,7 +230,7 @@ static int imx477_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
|
||||
if (val == 0 || mode->image_properties.line_length == 0)
|
||||
return -EINVAL;
|
||||
|
||||
frame_length = (u32) (mode->signal_properties.pixel_clock.val *
|
||||
frame_length = (u32) (IMX477_SENSOR_INTERNAL_CLK_FREQ *
|
||||
(u64) mode->control_properties.framerate_factor /
|
||||
mode->image_properties.line_length / val);
|
||||
|
||||
@@ -277,12 +281,12 @@ static int imx477_set_exposure(struct tegracam_device *tc_dev, s64 val)
|
||||
|
||||
fine_integ_time_factor = priv->fine_integ_time *
|
||||
mode->control_properties.exposure_factor /
|
||||
mode->signal_properties.pixel_clock.val;
|
||||
IMX477_SENSOR_INTERNAL_CLK_FREQ;
|
||||
|
||||
dev_dbg(dev, "%s: Setting exposure control to: %lld\n", __func__, val);
|
||||
|
||||
coarse_time = (val - fine_integ_time_factor)
|
||||
* mode->signal_properties.pixel_clock.val
|
||||
* IMX477_SENSOR_INTERNAL_CLK_FREQ
|
||||
/ mode->control_properties.exposure_factor
|
||||
/ mode->image_properties.line_length;
|
||||
|
||||
@@ -720,7 +724,7 @@ static const struct v4l2_subdev_internal_ops imx477_subdev_internal_ops = {
|
||||
.open = imx477_open,
|
||||
};
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int imx477_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int imx477_probe(struct i2c_client *client,
|
||||
@@ -771,6 +775,7 @@ static int imx477_probe(struct i2c_client *client,
|
||||
|
||||
err = tegracam_v4l2subdev_register(tc_dev, true);
|
||||
if (err) {
|
||||
tegracam_device_unregister(tc_dev);
|
||||
dev_err(dev, "tegra camera subdev registration failed\n");
|
||||
return err;
|
||||
}
|
||||
@@ -780,10 +785,10 @@ static int imx477_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
|
||||
static void imx477_remove(struct i2c_client *client)
|
||||
#else
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int imx477_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void imx477_remove(struct i2c_client *client)
|
||||
#endif
|
||||
{
|
||||
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
|
||||
@@ -791,7 +796,7 @@ static int imx477_remove(struct i2c_client *client)
|
||||
|
||||
if (!s_data) {
|
||||
dev_err(&client->dev, "camera common data is NULL\n");
|
||||
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return -EINVAL;
|
||||
#else
|
||||
return;
|
||||
@@ -801,7 +806,7 @@ static int imx477_remove(struct i2c_client *client)
|
||||
|
||||
tegracam_v4l2subdev_unregister(priv->tc_dev);
|
||||
tegracam_device_unregister(priv->tc_dev);
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/gpio.h>
|
||||
@@ -1146,7 +1148,7 @@ static const struct v4l2_subdev_internal_ops ov5693_subdev_internal_ops = {
|
||||
.open = ov5693_open,
|
||||
};
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int ov5693_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int ov5693_probe(struct i2c_client *client,
|
||||
@@ -1236,7 +1238,7 @@ fail:
|
||||
return err;
|
||||
}
|
||||
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int
|
||||
ov5693_remove(struct i2c_client *client)
|
||||
#else
|
||||
@@ -1248,7 +1250,7 @@ ov5693_remove(struct i2c_client *client)
|
||||
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
|
||||
|
||||
if (!s_data)
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return -EINVAL;
|
||||
#else
|
||||
return;
|
||||
@@ -1264,7 +1266,7 @@ ov5693_remove(struct i2c_client *client)
|
||||
ov5693_eeprom_device_release(priv);
|
||||
|
||||
mutex_destroy(&priv->streaming_lock);
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
* Copyright (c) 2016-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/i2c.h>
|
||||
@@ -258,7 +260,7 @@ static struct regmap_config pca9570_regmap_config = {
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
};
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int pca9570_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int pca9570_probe(struct i2c_client *client,
|
||||
@@ -308,7 +310,7 @@ static int pca9570_probe(struct i2c_client *client,
|
||||
return err;
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int pca9570_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void pca9570_remove(struct i2c_client *client)
|
||||
@@ -319,7 +321,7 @@ static void pca9570_remove(struct i2c_client *client)
|
||||
client = NULL;
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* virtual_i2c_mux.c - virtual i2c mux driver for P3762 & P3783 GMSL boards.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-mux.h>
|
||||
#include <linux/module.h>
|
||||
@@ -47,7 +49,7 @@ static int virtual_i2c_mux_deselect(struct i2c_mux_core *muxc, u32 chan)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int virtual_i2c_mux_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int virtual_i2c_mux_probe(struct i2c_client *client,
|
||||
@@ -85,7 +87,11 @@ static int virtual_i2c_mux_probe(struct i2c_client *client,
|
||||
|
||||
for (chan = 0; chan < children; chan++) {
|
||||
pr_info("%s: chan = %d\n",__func__, chan);
|
||||
#if defined(NV_I2C_MUX_ADD_ADAPTER_HAS_NO_CLASS_ARG)
|
||||
ret = i2c_mux_add_adapter(muxc, 0, chan);
|
||||
#else
|
||||
ret = i2c_mux_add_adapter(muxc, 0, chan, 0);
|
||||
#endif
|
||||
if (ret)
|
||||
goto err_children;
|
||||
}
|
||||
@@ -104,7 +110,7 @@ err_parent:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int virtual_i2c_mux_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void virtual_i2c_mux_remove(struct i2c_client *client)
|
||||
@@ -114,7 +120,7 @@ static void virtual_i2c_mux_remove(struct i2c_client *client)
|
||||
|
||||
i2c_mux_del_adapters(muxc);
|
||||
i2c_put_adapter(muxc->parent);
|
||||
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# Copyright (c) 2022-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
ifdef CONFIG_MEDIA_SUPPORT
|
||||
obj-m += cdi/
|
||||
obj-m += tpg/
|
||||
endif
|
||||
obj-m += isc/
|
||||
obj-m += camera/
|
||||
obj-m += tpg/
|
||||
obj-m += cam_fsync/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved.
|
||||
# Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
|
||||
|
||||
ifdef CONFIG_MEDIA_SUPPORT
|
||||
ifeq ($(findstring ack_src,$(NV_BUILD_KERNEL_OPTIONS)),)
|
||||
LINUXINCLUDE += -I$(srctree.nvidia-oot)/drivers/video/tegra/camera
|
||||
LINUXINCLUDE += -I$(srctree.nvidia-oot)/drivers/media/platform/tegra
|
||||
@@ -32,3 +33,4 @@ tegra-camera-objs += fusa-capture/capture-isp.o
|
||||
obj-m += tegra-camera.o
|
||||
obj-m += tests/
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* camera_common.c - utilities for tegra camera driver
|
||||
// SPDX-License-Identifier: GPL-2.0 only
|
||||
/* SPDX-FileCopyrightText: Copyright (c) 2015-2024 NVIDIA CORPORATION & AFFILIATES.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Copyright (c) 2015-2023, NVIDIA CORPORATION. All rights reserved.
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <linux/types.h>
|
||||
#include <media/tegra-v4l2-camera.h>
|
||||
@@ -44,6 +54,11 @@ static const struct camera_common_colorfmt camera_common_color_fmts[] = {
|
||||
V4L2_COLORSPACE_SRGB,
|
||||
V4L2_PIX_FMT_SGBRG12
|
||||
},
|
||||
{
|
||||
MEDIA_BUS_FMT_SBGGR12_1X12,
|
||||
V4L2_COLORSPACE_SRGB,
|
||||
V4L2_PIX_FMT_SBGGR12
|
||||
},
|
||||
{
|
||||
MEDIA_BUS_FMT_SRGGB10_1X10,
|
||||
V4L2_COLORSPACE_SRGB,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2015-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* NVIDIA Tegra CSI Device
|
||||
*
|
||||
* Copyright (c) 2015-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
@@ -685,6 +686,9 @@ static int tegra_csi_set_format(struct v4l2_subdev *subdev,
|
||||
}
|
||||
|
||||
static int tegra_csi_g_frame_interval(struct v4l2_subdev *sd,
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
#endif
|
||||
struct v4l2_subdev_frame_interval *vfi)
|
||||
{
|
||||
struct tegra_csi_channel *chan = to_csi_chan(sd);
|
||||
@@ -716,10 +720,15 @@ static int tegra_csi_enum_mbus_code(struct v4l2_subdev *sd,
|
||||
static struct v4l2_subdev_video_ops tegra_csi_video_ops = {
|
||||
.s_stream = tegra_csi_s_stream,
|
||||
.g_input_status = tegra_csi_g_input_status,
|
||||
#if !defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
|
||||
.g_frame_interval = tegra_csi_g_frame_interval,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_pad_ops tegra_csi_pad_ops = {
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
|
||||
.get_frame_interval = tegra_csi_g_frame_interval,
|
||||
#endif
|
||||
.get_fmt = tegra_csi_get_format,
|
||||
.set_fmt = tegra_csi_set_format,
|
||||
.enum_mbus_code = tegra_csi_enum_mbus_code,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017-2023 NVIDIA Corporation. All rights reserved.
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
/**
|
||||
* @file drivers/media/platform/tegra/camera/fusa-capture/capture-isp.c
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <linux/nvhost.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/tegra-capture-ivc.h>
|
||||
#include <asm/arch_timer.h>
|
||||
#include <soc/tegra/fuse.h>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017-2023 NVIDIA Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
/**
|
||||
* @file drivers/media/platform/tegra/camera/fusa-capture/capture-vi-channel.c
|
||||
*
|
||||
* @brief VI channel character device driver for the T186/T194 Camera RTCPU
|
||||
* @brief VI channel character device driver for the T234 Camera RTCPU
|
||||
* platform.
|
||||
*/
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/nvhost.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
@@ -204,11 +204,7 @@ struct tegra_vi_channel *vi_channel_open_ex(
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
chan->drv = chan_drv;
|
||||
if (chan_drv->use_legacy_path) {
|
||||
chan->dev = chan_drv->dev;
|
||||
chan->ndev = chan_drv->ndev;
|
||||
} else
|
||||
chan->vi_capture_pdev = chan_drv->vi_capture_pdev;
|
||||
chan->vi_capture_pdev = chan_drv->vi_capture_pdev;
|
||||
|
||||
chan->ops = chan_drv->ops;
|
||||
|
||||
@@ -390,17 +386,14 @@ static long vi_channel_ioctl(
|
||||
if (copy_from_user(&setup, ptr, sizeof(setup)))
|
||||
break;
|
||||
|
||||
if (chan->drv->use_legacy_path == false) {
|
||||
vi_get_nvhost_device(chan, &setup);
|
||||
if (chan->dev == NULL) {
|
||||
dev_err(&chan->vi_capture_pdev->dev,
|
||||
"%s: channel device is NULL",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
vi_get_nvhost_device(chan, &setup);
|
||||
if (chan->dev == NULL) {
|
||||
dev_err(&chan->vi_capture_pdev->dev,
|
||||
"%s: channel device is NULL",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
if (setup.request_size < sizeof(struct capture_descriptor)) {
|
||||
dev_err(chan->dev,
|
||||
"request size is too small to fit capture descriptor\n");
|
||||
@@ -650,16 +643,10 @@ int vi_channel_drv_register(
|
||||
if (unlikely(chan_drv == NULL))
|
||||
return -ENOMEM;
|
||||
|
||||
if (strstr(ndev->name, "tegra-capture-vi") == NULL) {
|
||||
chan_drv->use_legacy_path = true;
|
||||
chan_drv->dev = &ndev->dev;
|
||||
chan_drv->ndev = ndev;
|
||||
} else {
|
||||
chan_drv->use_legacy_path = false;
|
||||
chan_drv->dev = NULL;
|
||||
chan_drv->ndev = NULL;
|
||||
chan_drv->vi_capture_pdev = ndev;
|
||||
}
|
||||
chan_drv->dev = NULL;
|
||||
chan_drv->ndev = NULL;
|
||||
chan_drv->vi_capture_pdev = ndev;
|
||||
|
||||
chan_drv->num_channels = max_vi_channels;
|
||||
mutex_init(&chan_drv->lock);
|
||||
|
||||
@@ -676,9 +663,7 @@ int vi_channel_drv_register(
|
||||
for (i = 0; i < chan_drv->num_channels; i++) {
|
||||
dev_t devt = MKDEV(vi_channel_major, i);
|
||||
|
||||
struct device *dev =
|
||||
(chan_drv->use_legacy_path)?chan_drv->dev :
|
||||
&chan_drv->vi_capture_pdev->dev;
|
||||
struct device *dev = &chan_drv->vi_capture_pdev->dev;
|
||||
device_create(vi_channel_class, dev, devt, NULL,
|
||||
"capture-vi-channel%u", i);
|
||||
}
|
||||
@@ -725,7 +710,8 @@ void vi_channel_drv_unregister(
|
||||
mutex_lock(&chdrv_lock);
|
||||
chan_drv = chdrv_;
|
||||
chdrv_ = NULL;
|
||||
WARN_ON(chan_drv->dev != dev);
|
||||
|
||||
WARN_ON(&chan_drv->vi_capture_pdev->dev != dev);
|
||||
mutex_unlock(&chdrv_lock);
|
||||
|
||||
for (i = 0; i < chan_drv->num_channels; i++) {
|
||||
@@ -734,7 +720,7 @@ void vi_channel_drv_unregister(
|
||||
device_destroy(vi_channel_class, devt);
|
||||
}
|
||||
|
||||
devm_kfree(chan_drv->dev, chan_drv);
|
||||
devm_kfree(&chan_drv->vi_capture_pdev->dev, chan_drv);
|
||||
}
|
||||
EXPORT_SYMBOL(vi_channel_drv_unregister);
|
||||
|
||||
|
||||
@@ -1,10 +1,22 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017-2023 NVIDIA Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES.
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file drivers/media/platform/tegra/camera/fusa-capture/capture-vi.c
|
||||
*
|
||||
* @brief VI channel operations for the T186/T194 Camera RTCPU platform.
|
||||
* @brief VI channel operations for the T234 Camera RTCPU platform.
|
||||
*/
|
||||
|
||||
#include <linux/completion.h>
|
||||
@@ -12,7 +24,7 @@
|
||||
#include <linux/nvhost.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/tegra-capture-ivc.h>
|
||||
#include <linux/tegra-camera-rtcpu.h>
|
||||
|
||||
@@ -448,10 +460,7 @@ int vi_capture_init(
|
||||
struct platform_device *rtc_pdev;
|
||||
struct device *dev;
|
||||
|
||||
if (chan->drv->use_legacy_path)
|
||||
dev = chan->dev;
|
||||
else
|
||||
dev = &chan->vi_capture_pdev->dev;
|
||||
dev = &chan->vi_capture_pdev->dev;
|
||||
|
||||
dev_dbg(dev, "%s++\n", __func__);
|
||||
dn = of_find_node_by_path("tegra-camera-rtcpu");
|
||||
@@ -595,10 +604,7 @@ int vi_capture_setup(
|
||||
uint32_t vi_inst = 0;
|
||||
struct device *dev;
|
||||
|
||||
if (chan->drv->use_legacy_path)
|
||||
dev = chan->dev;
|
||||
else
|
||||
dev = &chan->vi_capture_pdev->dev;
|
||||
dev = &chan->vi_capture_pdev->dev;
|
||||
|
||||
if (setup->csi_stream_id >= MAX_NVCSI_STREAM_IDS ||
|
||||
setup->virtual_channel_id >= MAX_VIRTUAL_CHANNEL_PER_STREAM) {
|
||||
@@ -1444,7 +1450,12 @@ int vi_capture_status(
|
||||
|
||||
/* negative timeout means wait forever */
|
||||
if (timeout_ms < 0) {
|
||||
wait_for_completion(&capture->capture_resp);
|
||||
ret = wait_for_completion_interruptible(&capture->capture_resp);
|
||||
if (ret == -ERESTARTSYS) {
|
||||
dev_dbg(chan->dev,
|
||||
"capture status interrupted\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
} else {
|
||||
ret = wait_for_completion_timeout(
|
||||
&capture->capture_resp,
|
||||
@@ -1664,7 +1675,7 @@ static int capture_vi_probe(struct platform_device *pdev)
|
||||
|
||||
err = vi_channel_drv_register(pdev, info->max_vi_channels);
|
||||
if (err) {
|
||||
vi_channel_drv_exit();
|
||||
vi_channel_drv_exit();
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -1702,7 +1713,10 @@ static int capture_vi_remove(struct platform_device *pdev)
|
||||
for (ii = 0; ii < info->num_vi_devices; ii++)
|
||||
put_device(&info->vi_pdevices[ii]->dev);
|
||||
|
||||
vi_channel_drv_exit();
|
||||
vi_channel_drv_unregister(&pdev->dev);
|
||||
tegra_vi_media_controller_cleanup(&info->vi_common.mc_vi);
|
||||
vi_channel_drv_exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2016-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Copyright (c) 2016-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*
|
||||
* Tegra CSI5 device common APIs
|
||||
*/
|
||||
@@ -213,6 +213,7 @@ static int csi5_stream_set_config(struct tegra_csi_channel *chan, u32 stream_id,
|
||||
struct CAPTURE_CONTROL_MSG msg;
|
||||
struct nvcsi_brick_config brick_config;
|
||||
struct nvcsi_cil_config cil_config;
|
||||
struct nvcsi_error_config err_config;
|
||||
u32 phy_mode = read_phy_mode_from_dt(chan);
|
||||
bool is_cphy = (phy_mode == CSI_PHY_MODE_CPHY);
|
||||
dev_dbg(csi->dev, "%s: stream_id=%u, csi_port=%u\n",
|
||||
@@ -285,6 +286,7 @@ static int csi5_stream_set_config(struct tegra_csi_channel *chan, u32 stream_id,
|
||||
else
|
||||
cil_config.mipi_clock_rate = csi->clk_freq / 1000;
|
||||
|
||||
memset(&err_config, 0, sizeof(err_config));
|
||||
/* Set NVCSI stream config */
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.header.msg_id = CAPTURE_CSI_STREAM_SET_CONFIG_REQ;
|
||||
@@ -293,6 +295,9 @@ static int csi5_stream_set_config(struct tegra_csi_channel *chan, u32 stream_id,
|
||||
msg.csi_stream_set_config_req.csi_port = csi_port;
|
||||
msg.csi_stream_set_config_req.brick_config = brick_config;
|
||||
msg.csi_stream_set_config_req.cil_config = cil_config;
|
||||
msg.csi_stream_set_config_req.error_config = err_config;
|
||||
msg.csi_stream_set_config_req.config_flags = NVCSI_CONFIG_FLAG_BRICK |
|
||||
NVCSI_CONFIG_FLAG_CIL | NVCSI_CONFIG_FLAG_ERROR;
|
||||
|
||||
if (tegra_chan->valid_ports > 1)
|
||||
vi_port = (stream_id > 0) ? 1 : 0;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
/*
|
||||
* tegracam_ctrls - control framework for tegra camera drivers
|
||||
*
|
||||
* Copyright (c) 2017-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2017-2023, NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/nospec.h>
|
||||
@@ -326,7 +326,7 @@ static int tegracam_set_ctrls(struct tegracam_ctrl_handler *handler,
|
||||
/* For controls that require sensor to be on */
|
||||
switch (ctrl->id) {
|
||||
case TEGRA_CAMERA_CID_GAIN:
|
||||
if (*ctrl->p_new.p_s64 == ctrlprops->min_gain_val - 1)
|
||||
if (*ctrl->p_new.p_s64 == ctrlprops->max_gain_val + 1)
|
||||
return 0;
|
||||
err = ops->set_gain(tc_dev, *ctrl->p_new.p_s64);
|
||||
break;
|
||||
@@ -334,7 +334,7 @@ static int tegracam_set_ctrls(struct tegracam_ctrl_handler *handler,
|
||||
err = ops->set_frame_rate(tc_dev, *ctrl->p_new.p_s64);
|
||||
break;
|
||||
case TEGRA_CAMERA_CID_EXPOSURE:
|
||||
if (*ctrl->p_new.p_s64 == ctrlprops->min_exp_time.val - 1)
|
||||
if (*ctrl->p_new.p_s64 == ctrlprops->max_exp_time.val + 1)
|
||||
return 0;
|
||||
err = ops->set_exposure(tc_dev, *ctrl->p_new.p_s64);
|
||||
break;
|
||||
@@ -607,8 +607,8 @@ int tegracam_init_ctrl_ranges_by_mode(
|
||||
switch (ctrl->id) {
|
||||
case TEGRA_CAMERA_CID_GAIN:
|
||||
err = v4l2_ctrl_modify_range(ctrl,
|
||||
ctrlprops->min_gain_val - 1,
|
||||
ctrlprops->max_gain_val,
|
||||
ctrlprops->min_gain_val,
|
||||
ctrlprops->max_gain_val + 1,
|
||||
ctrlprops->step_gain_val,
|
||||
ctrlprops->default_gain);
|
||||
break;
|
||||
@@ -621,8 +621,8 @@ int tegracam_init_ctrl_ranges_by_mode(
|
||||
break;
|
||||
case TEGRA_CAMERA_CID_EXPOSURE:
|
||||
err = v4l2_ctrl_modify_range(ctrl,
|
||||
ctrlprops->min_exp_time.val - 1,
|
||||
ctrlprops->max_exp_time.val,
|
||||
ctrlprops->min_exp_time.val,
|
||||
ctrlprops->max_exp_time.val + 1,
|
||||
ctrlprops->step_exp_time.val,
|
||||
ctrlprops->default_exp_time.val);
|
||||
break;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2018-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* tegracam_v4l2 - tegra camera framework for v4l2 support
|
||||
*
|
||||
* Copyright (c) 2018-2022, NVIDIA CORPORATION. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <media/tegra-v4l2-camera.h>
|
||||
#include <media/tegracam_core.h>
|
||||
@@ -112,9 +114,30 @@ static int v4l2sd_g_input_status(struct v4l2_subdev *sd, u32 *status)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cam_g_frame_interval(struct v4l2_subdev *sd,
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
|
||||
struct v4l2_subdev_state *sd_state,
|
||||
#endif
|
||||
struct v4l2_subdev_frame_interval *ival)
|
||||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
struct camera_common_data *s_data = to_camera_common_data(&client->dev);
|
||||
|
||||
if (!s_data)
|
||||
return -EINVAL;
|
||||
|
||||
ival->interval.denominator = s_data->frmfmt[s_data->mode_prop_idx].framerates[0];
|
||||
ival->interval.numerator = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct v4l2_subdev_video_ops v4l2sd_video_ops = {
|
||||
.s_stream = v4l2sd_stream,
|
||||
.g_input_status = v4l2sd_g_input_status,
|
||||
#if !defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
|
||||
.g_frame_interval = cam_g_frame_interval,
|
||||
.s_frame_interval = cam_g_frame_interval,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct v4l2_subdev_core_ops v4l2sd_core_ops = {
|
||||
@@ -161,6 +184,10 @@ static int v4l2sd_set_fmt(struct v4l2_subdev *sd,
|
||||
}
|
||||
|
||||
static struct v4l2_subdev_pad_ops v4l2sd_pad_ops = {
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_GET_SET_FRAME_INTERVAL)
|
||||
.get_frame_interval = cam_g_frame_interval,
|
||||
.set_frame_interval = cam_g_frame_interval,
|
||||
#endif
|
||||
.set_fmt = v4l2sd_set_fmt,
|
||||
.get_fmt = v4l2sd_get_fmt,
|
||||
.enum_mbus_code = camera_common_enum_mbus_code,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2015-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* NVIDIA Tegra Video Input Device
|
||||
*
|
||||
* Copyright (c) 2015-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/clk.h>
|
||||
@@ -24,6 +25,7 @@
|
||||
#include <media/v4l2-dev.h>
|
||||
#include <media/v4l2-fh.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/v4l2-subdev.h>
|
||||
#include <media/videobuf2-core.h>
|
||||
#include <media/videobuf2-dma-contig.h>
|
||||
#include <media/tegra-v4l2-camera.h>
|
||||
@@ -690,16 +692,33 @@ tegra_channel_queue_setup(struct vb2_queue *vq,
|
||||
{
|
||||
struct tegra_channel *chan = vb2_get_drv_priv(vq);
|
||||
struct tegra_mc_vi *vi = chan->vi;
|
||||
int ret = 0;
|
||||
|
||||
|
||||
/* In some cases, if nplanes is valid
|
||||
* and the requested image size is less than the
|
||||
* actual image size, we need to return EINVAL.
|
||||
* Previously, we were just updating sizes[0] irrespective
|
||||
* of the requested image size. Although this did not harm the
|
||||
* flow, according to "v4l2-compliance", we need to check if
|
||||
* the requested size is invalid.
|
||||
*/
|
||||
if (*nplanes) {
|
||||
if (sizes[0] < chan->format.sizeimage) {
|
||||
pr_err("%s: sizes[0] = %d chan->format.sizeimage = %d ...\n"
|
||||
,__func__,sizes[0],chan->format.sizeimage);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
sizes[0] = chan->format.sizeimage;
|
||||
}
|
||||
|
||||
*nplanes = 1;
|
||||
|
||||
sizes[0] = chan->format.sizeimage;
|
||||
alloc_devs[0] = tegra_channel_get_vi_unit(chan);
|
||||
|
||||
if (vi->fops && vi->fops->vi_setup_queue)
|
||||
return vi->fops->vi_setup_queue(chan, nbuffers);
|
||||
else
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tegra_channel_alloc_buffer_queue(struct tegra_channel *chan,
|
||||
@@ -1023,14 +1042,21 @@ static int
|
||||
tegra_channel_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
|
||||
{
|
||||
struct tegra_channel *chan = video_drvdata(file);
|
||||
ssize_t len;
|
||||
int ret = 0;
|
||||
|
||||
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
|
||||
cap->device_caps |= V4L2_CAP_EXT_PIX_FORMAT;
|
||||
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
|
||||
|
||||
strlcpy(cap->driver, "tegra-video", sizeof(cap->driver));
|
||||
strlcpy(cap->card, chan->video->name, sizeof(cap->card));
|
||||
len = strscpy(cap->driver, "tegra-video", sizeof(cap->driver));
|
||||
if (len < 0)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
len = strscpy(cap->card, chan->video->name, sizeof(cap->card));
|
||||
if (len < 0)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
ret = snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s:%u",
|
||||
dev_name(chan->vi->dev), chan->port[0]);
|
||||
if (ret < 0)
|
||||
@@ -1151,11 +1177,19 @@ tegra_channel_g_dv_timings(struct file *file, void *fh,
|
||||
{
|
||||
struct tegra_channel *chan = video_drvdata(file);
|
||||
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
|
||||
if (!v4l2_subdev_has_op(chan->subdev_on_csi, pad, g_dv_timings))
|
||||
return -ENOTTY;
|
||||
|
||||
return v4l2_device_call_until_err(chan->video->v4l2_dev,
|
||||
chan->grp_id, pad, g_dv_timings, 0, timings);
|
||||
#else
|
||||
if (!v4l2_subdev_has_op(chan->subdev_on_csi, video, g_dv_timings))
|
||||
return -ENOTTY;
|
||||
|
||||
return v4l2_device_call_until_err(chan->video->v4l2_dev,
|
||||
chan->grp_id, video, g_dv_timings, timings);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1167,7 +1201,11 @@ tegra_channel_s_dv_timings(struct file *file, void *fh,
|
||||
struct v4l2_dv_timings curr_timings;
|
||||
int ret;
|
||||
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
|
||||
if (!v4l2_subdev_has_op(chan->subdev_on_csi, pad, s_dv_timings))
|
||||
#else
|
||||
if (!v4l2_subdev_has_op(chan->subdev_on_csi, video, s_dv_timings))
|
||||
#endif
|
||||
return -ENOTTY;
|
||||
|
||||
ret = tegra_channel_g_dv_timings(file, fh, &curr_timings);
|
||||
@@ -1180,9 +1218,13 @@ tegra_channel_s_dv_timings(struct file *file, void *fh,
|
||||
if (vb2_is_busy(&chan->queue))
|
||||
return -EBUSY;
|
||||
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
|
||||
ret = v4l2_device_call_until_err(chan->video->v4l2_dev,
|
||||
chan->grp_id, pad, s_dv_timings, 0, timings);
|
||||
#else
|
||||
ret = v4l2_device_call_until_err(chan->video->v4l2_dev,
|
||||
chan->grp_id, video, s_dv_timings, timings);
|
||||
|
||||
#endif
|
||||
if (!ret)
|
||||
tegra_channel_update_format(chan, bt->width, bt->height,
|
||||
chan->fmtinfo->fourcc, &chan->fmtinfo->bpp,
|
||||
@@ -1200,11 +1242,19 @@ tegra_channel_query_dv_timings(struct file *file, void *fh,
|
||||
{
|
||||
struct tegra_channel *chan = video_drvdata(file);
|
||||
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
|
||||
if (!v4l2_subdev_has_op(chan->subdev_on_csi, pad, query_dv_timings))
|
||||
return -ENOTTY;
|
||||
|
||||
return v4l2_device_call_until_err(chan->video->v4l2_dev,
|
||||
chan->grp_id, pad, query_dv_timings, 0, timings);
|
||||
#else
|
||||
if (!v4l2_subdev_has_op(chan->subdev_on_csi, video, query_dv_timings))
|
||||
return -ENOTTY;
|
||||
|
||||
return v4l2_device_call_until_err(chan->video->v4l2_dev,
|
||||
chan->grp_id, video, query_dv_timings, timings);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -1251,6 +1301,10 @@ int tegra_channel_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
}
|
||||
break;
|
||||
case TEGRA_CAMERA_CID_VI_BYPASS_MODE:
|
||||
/* Prevent changing the bypass mode while the device is still streaming */
|
||||
if (vb2_is_busy(&chan->queue))
|
||||
return -EBUSY;
|
||||
|
||||
if (switch_ctrl_qmenu[ctrl->val] == SWITCH_ON)
|
||||
chan->bypass = true;
|
||||
else if (chan->vi->bypass) {
|
||||
@@ -1837,8 +1891,13 @@ static void tegra_channel_populate_dev_info(struct tegra_camera_dev_info *cdev,
|
||||
if (chan->pg_mode) {
|
||||
/* TPG mode */
|
||||
cdev->sensor_type = SENSORTYPE_VIRTUAL;
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
|
||||
} else if (v4l2_subdev_has_op(chan->subdev_on_csi,
|
||||
pad, g_dv_timings)) {
|
||||
#else
|
||||
} else if (v4l2_subdev_has_op(chan->subdev_on_csi,
|
||||
video, g_dv_timings)) {
|
||||
#endif
|
||||
/* HDMI-IN */
|
||||
cdev->sensor_type = SENSORTYPE_OTHER;
|
||||
pixelclock = tegra_channel_get_max_source_rate();
|
||||
@@ -2165,7 +2224,11 @@ tegra_channel_enum_input(struct file *file, void *fh, struct v4l2_input *inp)
|
||||
return -ENODEV;
|
||||
|
||||
inp->type = V4L2_INPUT_TYPE_CAMERA;
|
||||
#if defined(NV_V4L2_SUBDEV_PAD_OPS_STRUCT_HAS_DV_TIMINGS) /* Linux v6.10 */
|
||||
if (v4l2_subdev_has_op(sd_on_csi, pad, s_dv_timings)) {
|
||||
#else
|
||||
if (v4l2_subdev_has_op(sd_on_csi, video, s_dv_timings)) {
|
||||
#endif
|
||||
inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
|
||||
len = snprintf(inp->name,
|
||||
sizeof(inp->name), "HDMI %u",
|
||||
@@ -2210,7 +2273,7 @@ static long tegra_channel_default_ioctl(struct file *file, void *fh,
|
||||
{
|
||||
struct tegra_channel *chan = video_drvdata(file);
|
||||
struct tegra_mc_vi *vi = chan->vi;
|
||||
long ret = 0;
|
||||
long ret = -ENOTTY;
|
||||
|
||||
if (vi->fops && vi->fops->vi_default_ioctl)
|
||||
ret = vi->fops->vi_default_ioctl(file, fh, use_prio, cmd, arg);
|
||||
@@ -2218,10 +2281,32 @@ static long tegra_channel_default_ioctl(struct file *file, void *fh,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Implemented vidioc_s_parm and vidioc_g_parm ioctl to support multiple frame
|
||||
* rates */
|
||||
static int tegra_channel_s_parm(struct file *file, void *fh,
|
||||
struct v4l2_streamparm *a)
|
||||
{
|
||||
struct tegra_channel *chan = video_drvdata(file);
|
||||
struct v4l2_subdev *sd = chan->subdev_on_csi;
|
||||
|
||||
return v4l2_s_parm_cap(chan->video, sd, a);
|
||||
}
|
||||
|
||||
static int tegra_channel_g_parm(struct file *file, void *fh,
|
||||
struct v4l2_streamparm *a)
|
||||
{
|
||||
struct tegra_channel *chan = video_drvdata(file);
|
||||
struct v4l2_subdev *sd = chan->subdev_on_csi;
|
||||
|
||||
return v4l2_g_parm_cap(chan->video, sd, a);
|
||||
}
|
||||
|
||||
static const struct v4l2_ioctl_ops tegra_channel_ioctl_ops = {
|
||||
.vidioc_querycap = tegra_channel_querycap,
|
||||
.vidioc_enum_framesizes = tegra_channel_enum_framesizes,
|
||||
.vidioc_enum_frameintervals = tegra_channel_enum_frameintervals,
|
||||
.vidioc_s_parm = tegra_channel_s_parm,
|
||||
.vidioc_g_parm = tegra_channel_g_parm,
|
||||
.vidioc_enum_fmt_vid_cap = tegra_channel_enum_format,
|
||||
.vidioc_g_fmt_vid_cap = tegra_channel_get_format,
|
||||
.vidioc_s_fmt_vid_cap = tegra_channel_set_format,
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
/*
|
||||
* NVIDIA Media controller graph management
|
||||
*
|
||||
* Copyright (c) 2015-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Copyright (c) 2015-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/of.h>
|
||||
@@ -13,7 +16,6 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/version.h>
|
||||
#include <soc/tegra/fuse.h>
|
||||
#include <media/media-device.h>
|
||||
#include <media/v4l2-async.h>
|
||||
@@ -341,7 +343,7 @@ register_device_error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(NV_V4L2_ASYNC_SUBDEV_RENAME)
|
||||
#if defined(NV_V4L2_ASYNC_CONNECTION_STRUCT_PRESENT) /* Linux 6.5 */
|
||||
static int tegra_vi_graph_notify_bound(struct v4l2_async_notifier *notifier,
|
||||
struct v4l2_subdev *subdev,
|
||||
struct v4l2_async_connection *asd)
|
||||
@@ -380,7 +382,7 @@ static int tegra_vi_graph_notify_bound(struct v4l2_async_notifier *notifier,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if defined(NV_V4L2_ASYNC_SUBDEV_RENAME)
|
||||
#if defined(NV_V4L2_ASYNC_CONNECTION_STRUCT_PRESENT) /* Linux 6.5 */
|
||||
static void tegra_vi_graph_notify_unbind(struct v4l2_async_notifier *notifier,
|
||||
struct v4l2_subdev *subdev,
|
||||
struct v4l2_async_connection *asd)
|
||||
@@ -423,7 +425,7 @@ void tegra_vi_graph_cleanup(struct tegra_mc_vi *vi)
|
||||
|
||||
list_for_each_entry(chan, &vi->vi_chans, list) {
|
||||
#if defined(CONFIG_V4L2_ASYNC)
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)
|
||||
#if defined(NV_V4L2_ASYNC_NOTIFIER_INIT_PRESENT)
|
||||
v4l2_async_notifier_unregister(&chan->notifier);
|
||||
#else
|
||||
v4l2_async_nf_unregister(&chan->notifier);
|
||||
@@ -477,12 +479,14 @@ static int tegra_vi_graph_parse_one(struct tegra_channel *chan,
|
||||
}
|
||||
|
||||
entity->node = remote;
|
||||
#if defined(NV_V4L2_ASYNC_MATCH_FWNODE_RENAME)
|
||||
#if !defined(NV_V4L2_ASYNC_CONNECTION_STRUCT_PRESENT) /* Linux 6.5 */
|
||||
#if defined(NV_V4L2_ASYNC_MATCH_TYPE_ENUM_PRESENT) /* Linux 6.5 */
|
||||
entity->asd.match.type = V4L2_ASYNC_MATCH_TYPE_FWNODE;
|
||||
#else
|
||||
entity->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
|
||||
#endif
|
||||
entity->asd.match.fwnode = of_fwnode_handle(remote);
|
||||
#endif
|
||||
|
||||
list_add_tail(&entity->list, &chan->entities);
|
||||
chan->num_subdevs++;
|
||||
@@ -638,12 +642,14 @@ int tegra_vi_graph_init(struct tegra_mc_vi *vi)
|
||||
|
||||
/* Add the remote entity of this endpoint */
|
||||
entity->node = remote;
|
||||
#if defined(NV_V4L2_ASYNC_MATCH_FWNODE_RENAME)
|
||||
#if !defined(NV_V4L2_ASYNC_CONNECTION_STRUCT_PRESENT) /* Linux 6.5 */
|
||||
#if defined(NV_V4L2_ASYNC_MATCH_TYPE_ENUM_PRESENT) /* Linux 6.5 */
|
||||
entity->asd.match.type = V4L2_ASYNC_MATCH_TYPE_FWNODE;
|
||||
#else
|
||||
entity->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
|
||||
#endif
|
||||
entity->asd.match.fwnode = of_fwnode_handle(remote);
|
||||
#endif
|
||||
list_add_tail(&entity->list, &chan->entities);
|
||||
chan->num_subdevs++;
|
||||
chan->notifier.ops = chan->notifier.ops ? chan->notifier.ops : &vi_chan_notify_ops;
|
||||
@@ -664,39 +670,44 @@ int tegra_vi_graph_init(struct tegra_mc_vi *vi)
|
||||
|
||||
i = 0;
|
||||
#if defined(CONFIG_V4L2_ASYNC)
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)
|
||||
#if defined(NV_V4L2_ASYNC_NOTIFIER_INIT_PRESENT)
|
||||
v4l2_async_notifier_init(&chan->notifier);
|
||||
list_for_each_entry(entity, &chan->entities, list)
|
||||
__v4l2_async_notifier_add_subdev(&chan->notifier, &entity->asd);
|
||||
#else
|
||||
#if defined (NV_V4L2_ASYNC_NF_SUBDEVICE_INIT_RENAME)
|
||||
v4l2_async_subdev_nf_init(&chan->notifier, tegra_channel_find_linked_csi_subdev(chan));
|
||||
list_for_each_entry(entity, &chan->entities, list) {
|
||||
struct v4l2_async_connection *asd;
|
||||
asd = v4l2_async_nf_add_fwnode_remote(&chan->notifier, of_fwnode_handle(remote),
|
||||
struct v4l2_async_connection);
|
||||
if (IS_ERR(asd)) {
|
||||
ret = PTR_ERR(asd);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
#if defined(NV_V4L2_ASYNC_NF_INIT_HAS_V4L2_DEV_ARG) /* Linux 6.6 */
|
||||
v4l2_async_nf_init(&chan->notifier, &vi->v4l2_dev);
|
||||
#else
|
||||
v4l2_async_nf_init(&chan->notifier);
|
||||
#endif
|
||||
|
||||
#if defined(NV_V4L2_ASYNC_NF_ADD_SUBDEV_PRESENT) /* Linux 6.6 */
|
||||
list_for_each_entry(entity, &chan->entities, list)
|
||||
__v4l2_async_nf_add_subdev(&chan->notifier, &entity->asd);
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
list_for_each_entry(entity, &chan->entities, list) {
|
||||
struct v4l2_async_connection *asc;
|
||||
asc = v4l2_async_nf_add_fwnode(&chan->notifier, of_fwnode_handle(entity->node),
|
||||
struct v4l2_async_connection);
|
||||
if (IS_ERR(asc))
|
||||
asc = NULL;
|
||||
entity->asc = asc;
|
||||
}
|
||||
#endif /* NV_V4L2_ASYNC_NF_ADD_SUBDEV_PRESENT */
|
||||
#endif /* NV_V4L2_ASYNC_NOTIFIER_INIT_PRESENT */
|
||||
|
||||
chan->link_status = 0;
|
||||
chan->subdevs_bound = 0;
|
||||
|
||||
/* Register the async notifier for this channel */
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)
|
||||
#if defined(NV_V4L2_ASYNC_NOTIFIER_INIT_PRESENT)
|
||||
ret = v4l2_async_notifier_register(&vi->v4l2_dev,
|
||||
&chan->notifier);
|
||||
#else
|
||||
#if defined (NV_V4L2_ASYNC_NF_SUBDEVICE_INIT_RENAME)
|
||||
#if defined (NV_V4L2_ASYNC_NF_INIT_HAS_V4L2_DEV_ARG) /* Linux 6.6 */
|
||||
ret = v4l2_async_nf_register(&chan->notifier);
|
||||
if (ret < 0)
|
||||
v4l2_async_nf_cleanup(&chan->notifier);
|
||||
#else
|
||||
ret = v4l2_async_nf_register(&vi->v4l2_dev,
|
||||
&chan->notifier);
|
||||
@@ -705,9 +716,9 @@ int tegra_vi_graph_init(struct tegra_mc_vi *vi)
|
||||
#else
|
||||
dev_err(vi->dev, "CONFIG_V4L2_ASYNC is not enabled!\n");
|
||||
ret = -ENOTSUPP;
|
||||
#endif
|
||||
#endif /* CONFIG_V4L2_ASYNC */
|
||||
if (ret < 0) {
|
||||
dev_err(vi->dev, "notifier registration failed\n");
|
||||
dev_err(vi->dev, "notifier registration failed %d\n", ret);
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2015-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/*
|
||||
* Tegra Video Input device common APIs
|
||||
*
|
||||
* Copyright (c) 2015-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
@@ -116,11 +115,15 @@ static void tegra_vi_notify(struct v4l2_subdev *sd,
|
||||
|
||||
int tegra_vi_v4l2_init(struct tegra_mc_vi *vi)
|
||||
{
|
||||
ssize_t len;
|
||||
int ret;
|
||||
|
||||
vi->media_dev.dev = vi->dev;
|
||||
strlcpy(vi->media_dev.model, "NVIDIA Tegra Video Input Device",
|
||||
len = strscpy(vi->media_dev.model, "NVIDIA Tegra Video Input Device",
|
||||
sizeof(vi->media_dev.model));
|
||||
if (len < 0)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
vi->media_dev.hw_revision = 3;
|
||||
|
||||
media_device_init(&vi->media_dev);
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
/* SPDX-FileCopyrightText: Copyright (c) 2016-2024 NVIDIA CORPORATION & AFFILIATES.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Tegra Video Input 5 device common APIs
|
||||
*
|
||||
* Copyright (c) 2016-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
* Author: Frank Chen <frank@nvidia.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
@@ -134,6 +140,9 @@ static int tegra_vi5_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
case TEGRA_CAMERA_CID_WRITE_ISPFORMAT:
|
||||
chan->write_ispformat = ctrl->val;
|
||||
break;
|
||||
case TEGRA_CAMERA_CID_VI_CAPTURE_TIMEOUT:
|
||||
chan->capture_timeout_ms = ctrl->val;
|
||||
break;
|
||||
default:
|
||||
dev_err(&chan->video->dev, "%s:Not valid ctrl\n", __func__);
|
||||
return -EINVAL;
|
||||
@@ -200,6 +209,16 @@ static const struct v4l2_ctrl_config vi5_custom_ctrls[] = {
|
||||
.step = 1,
|
||||
.dims = { SENSOR_CTRL_BLOB_SIZE },
|
||||
},
|
||||
{
|
||||
.ops = &vi5_ctrl_ops,
|
||||
.id = TEGRA_CAMERA_CID_VI_CAPTURE_TIMEOUT,
|
||||
.name = "Override capture timeout ms",
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.def = CAPTURE_TIMEOUT_MS,
|
||||
.min = -1,
|
||||
.max = 0x7FFFFFFF,
|
||||
.step = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static int vi5_add_ctrls(struct tegra_channel *chan)
|
||||
@@ -319,6 +338,8 @@ static int tegra_channel_capture_setup(struct tegra_channel *chan, unsigned int
|
||||
chan->request[vi_port] = dma_alloc_coherent(chan->tegra_vi_channel[vi_port]->rtcpu_dev,
|
||||
setup.queue_depth * setup.request_size,
|
||||
&setup.iova, GFP_KERNEL);
|
||||
chan->request_iova[vi_port] = setup.iova;
|
||||
|
||||
if (chan->request[vi_port] == NULL) {
|
||||
dev_err(chan->vi->dev, "dma_alloc_coherent failed\n");
|
||||
return -ENOMEM;
|
||||
@@ -495,6 +516,7 @@ static void vi5_capture_dequeue(struct tegra_channel *chan,
|
||||
unsigned long flags;
|
||||
struct tegra_mc_vi *vi = chan->vi;
|
||||
struct vb2_v4l2_buffer *vb = &buf->buf;
|
||||
int timeout_ms = CAPTURE_TIMEOUT_MS;
|
||||
struct timespec64 ts;
|
||||
struct capture_descriptor *descr = NULL;
|
||||
|
||||
@@ -505,12 +527,21 @@ static void vi5_capture_dequeue(struct tegra_channel *chan,
|
||||
goto rel_buf;
|
||||
|
||||
/* Dequeue a frame and check its capture status */
|
||||
err = vi_capture_status(chan->tegra_vi_channel[vi_port], CAPTURE_TIMEOUT_MS);
|
||||
timeout_ms = chan->capture_timeout_ms;
|
||||
err = vi_capture_status(chan->tegra_vi_channel[vi_port], timeout_ms);
|
||||
if (err) {
|
||||
if (err == -ETIMEDOUT) {
|
||||
dev_err(vi->dev,
|
||||
"uncorr_err: request timed out after %d ms\n",
|
||||
CAPTURE_TIMEOUT_MS);
|
||||
if (timeout_ms < 0) {
|
||||
spin_lock_irqsave(&chan->capture_state_lock, flags);
|
||||
chan->capture_state = CAPTURE_ERROR_TIMEOUT;
|
||||
spin_unlock_irqrestore(&chan->capture_state_lock, flags);
|
||||
buf->vb2_state = VB2_BUF_STATE_ERROR;
|
||||
goto rel_buf;
|
||||
} else {
|
||||
dev_err(vi->dev,
|
||||
"uncorr_err: request timed out after %d ms\n",
|
||||
timeout_ms);
|
||||
}
|
||||
} else {
|
||||
dev_err(vi->dev, "uncorr_err: request err %d\n", err);
|
||||
}
|
||||
@@ -700,6 +731,7 @@ static int tegra_channel_kthread_capture_dequeue(void *data)
|
||||
struct tegra_channel_buffer *buf;
|
||||
|
||||
set_freezable();
|
||||
allow_signal(SIGINT);
|
||||
|
||||
while (1) {
|
||||
try_to_freeze();
|
||||
@@ -720,6 +752,12 @@ static int tegra_channel_kthread_capture_dequeue(void *data)
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&chan->capture_state_lock, flags);
|
||||
if (chan->capture_state == CAPTURE_ERROR_TIMEOUT) {
|
||||
spin_unlock_irqrestore(&chan->capture_state_lock,
|
||||
flags);
|
||||
break;
|
||||
}
|
||||
|
||||
if (chan->capture_state == CAPTURE_ERROR) {
|
||||
spin_unlock_irqrestore(&chan->capture_state_lock,
|
||||
flags);
|
||||
@@ -789,6 +827,7 @@ static void vi5_channel_stop_kthreads(struct tegra_channel *chan)
|
||||
|
||||
/* Stop the kthread for capture dequeue */
|
||||
if (chan->kthread_capture_dequeue) {
|
||||
send_sig(SIGINT, chan->kthread_capture_dequeue, 1);
|
||||
kthread_stop(chan->kthread_capture_dequeue);
|
||||
chan->kthread_capture_dequeue = NULL;
|
||||
}
|
||||
@@ -967,6 +1006,24 @@ static int vi5_channel_stop_streaming(struct vb2_queue *vq)
|
||||
dev_err(&chan->video->dev,
|
||||
"vi capture release failed\n");
|
||||
|
||||
/* Release capture requests */
|
||||
if (chan->request[vi_port] != NULL) {
|
||||
dma_free_coherent(chan->tegra_vi_channel[vi_port]->rtcpu_dev,
|
||||
chan->capture_queue_depth * sizeof(struct capture_descriptor),
|
||||
chan->request[vi_port], chan->request_iova[vi_port]);
|
||||
}
|
||||
chan->request[vi_port] = NULL;
|
||||
|
||||
/* Release emd data buffers */
|
||||
if (chan->emb_buf_size > 0) {
|
||||
struct device *vi_unit_dev;
|
||||
vi5_unit_get_device_handle(chan->vi->ndev, chan->port[0],\
|
||||
&vi_unit_dev);
|
||||
dma_free_coherent(vi_unit_dev, chan->emb_buf_size,
|
||||
chan->emb_buf_addr, chan->emb_buf);
|
||||
chan->emb_buf_size = 0;
|
||||
}
|
||||
|
||||
vi_channel_close_ex(chan->vi_channel_id[vi_port],
|
||||
chan->tegra_vi_channel[vi_port]);
|
||||
chan->tegra_vi_channel[vi_port] = NULL;
|
||||
@@ -974,6 +1031,7 @@ static int vi5_channel_stop_streaming(struct vb2_queue *vq)
|
||||
|
||||
/* release all remaining buffers to v4l2 */
|
||||
tegra_channel_queued_buf_done(chan, VB2_BUF_STATE_ERROR, false);
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
# Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
ifneq ($(CONFIG_TEGRA_GPIO_LEGACY_DISABLE),y)
|
||||
obj-m += cdi_gpio.o
|
||||
obj-m += cdi_mgr.o
|
||||
endif
|
||||
obj-m += cdi_dev.o
|
||||
obj-m += cdi_pwm.o
|
||||
ifeq ($(findstring ack_src,$(NV_BUILD_KERNEL_OPTIONS)),)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
|
||||
/* Copyright (c) 2023-2024, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved. */
|
||||
/*
|
||||
* cam_cdi_tsc.c - tsc driver.
|
||||
*/
|
||||
@@ -147,6 +147,8 @@ struct tsc_signal_controller {
|
||||
} debugfs;
|
||||
const struct tsc_signal_controller_features *features;
|
||||
struct list_head generators;
|
||||
bool opened;
|
||||
|
||||
};
|
||||
|
||||
static const struct tsc_signal_controller_features tegra234_tsc_features = {
|
||||
@@ -458,22 +460,44 @@ static void cdi_tsc_debugfs_remove(struct tsc_signal_controller *controller)
|
||||
|
||||
static int cdi_tsc_chardev_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
pr_info("%s:Device opened\n", __func__);
|
||||
struct tsc_signal_controller *controller = dev_get_drvdata(tsc_charDevice);
|
||||
int err = 0;
|
||||
|
||||
/* Set External Fsync */
|
||||
Hawk_Owl_Fsync_program(EXTERNAL_FSYNC);
|
||||
if (controller->opened)
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
/* Make sure device opened only once */
|
||||
controller->opened = true;
|
||||
|
||||
/* Set External Fsync */
|
||||
err = Hawk_Owl_Fsync_program(EXTERNAL_FSYNC);
|
||||
if (err)
|
||||
controller->opened = false;
|
||||
else
|
||||
dev_dbg(controller->dev, "%s:Device opened successfully!! \n", __func__);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cdi_tsc_chardev_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
pr_info("%s:Device closed\n", __func__);
|
||||
struct tsc_signal_controller *controller = dev_get_drvdata(tsc_charDevice);
|
||||
int err = -EFAULT;
|
||||
|
||||
/* To make sure whenever the device is closed, tsc is also stopped
|
||||
* to avoid inconsistency behaviour at app level i.e to avoid out of sync.
|
||||
*/
|
||||
err = cdi_tsc_stop_generators(controller);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Set back to Internal Fsync */
|
||||
Hawk_Owl_Fsync_program(INTERNAL_FSYNC);
|
||||
err = Hawk_Owl_Fsync_program(INTERNAL_FSYNC);
|
||||
|
||||
return 0;
|
||||
controller->opened = false;
|
||||
dev_dbg(controller->dev, "%s Device closed ..\n", __func__);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static long cdi_tsc_chardev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
@@ -520,6 +544,7 @@ static int cdi_tsc_probe(struct platform_device *pdev)
|
||||
if (!controller)
|
||||
return -ENOMEM;
|
||||
|
||||
controller->opened = false;
|
||||
controller->dev = &pdev->dev;
|
||||
controller->features = of_device_get_match_data(&pdev->dev);
|
||||
if (controller->features == NULL) {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2016-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/* SPDX-FileCopyrightText: Copyright (c) 2016-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
|
||||
|
||||
#ifndef __CDI_PWM_PRIV_H__
|
||||
#define __CDI_PWM_PRIV_H__
|
||||
|
||||
struct cdi_pwm_info {
|
||||
#if !defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
|
||||
struct pwm_chip chip;
|
||||
#endif
|
||||
struct pwm_device *pwm;
|
||||
atomic_t in_use;
|
||||
struct mutex mutex;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2015-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
@@ -564,7 +566,7 @@ static void cdi_dev_get_cim_ver(struct device_node *np, struct cdi_dev_info *inf
|
||||
}
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_PROBE_WITHOUT_I2C_DEVICE_ID_ARG) /* Linux 6.3 */
|
||||
static int cdi_dev_probe(struct i2c_client *client)
|
||||
#else
|
||||
static int cdi_dev_probe(struct i2c_client *client,
|
||||
@@ -805,7 +807,7 @@ static int cdi_dev_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
static int cdi_dev_remove(struct i2c_client *client)
|
||||
#else
|
||||
static void cdi_dev_remove(struct i2c_client *client)
|
||||
@@ -826,7 +828,7 @@ static void cdi_dev_remove(struct i2c_client *client)
|
||||
if (info->cdev.dev)
|
||||
cdev_del(&info->cdev);
|
||||
|
||||
#if KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE
|
||||
#if defined(NV_I2C_DRIVER_STRUCT_REMOVE_RETURN_TYPE_INT) /* Linux 6.1 */
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2017-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
@@ -31,7 +33,11 @@ static int of_cdi_gpio_pdata(struct platform_device *pdev,
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(NV_GPIO_DEVICE_FIND_HAS_CONST_DATA_ARG) /* Linux v6.9 */
|
||||
static int cdi_gpio_chip_match(struct gpio_chip *chip, const void *data)
|
||||
#else
|
||||
static int cdi_gpio_chip_match(struct gpio_chip *chip, void *data)
|
||||
#endif
|
||||
{
|
||||
return !strcmp(chip->label, data);
|
||||
}
|
||||
@@ -40,6 +46,10 @@ static struct gpio_chip *cdi_gpio_get_chip(struct platform_device *pdev,
|
||||
struct cdi_gpio_plat_data *pd)
|
||||
{
|
||||
struct gpio_chip *gc = NULL;
|
||||
#if defined(NV_GPIO_DEVICE_FIND_PRESENT) && \
|
||||
defined(NV_GPIO_DEVICE_GET_CHIP_PRESENT) /* Linux 6.7 */
|
||||
struct gpio_device *gdev;
|
||||
#endif
|
||||
char name[MAX_STR_SIZE];
|
||||
|
||||
if (strlen(pd->gpio_prnt_chip) > MAX_STR_SIZE) {
|
||||
@@ -49,7 +59,16 @@ static struct gpio_chip *cdi_gpio_get_chip(struct platform_device *pdev,
|
||||
}
|
||||
strcpy(name, pd->gpio_prnt_chip);
|
||||
|
||||
#if defined(NV_GPIO_DEVICE_FIND_PRESENT) && \
|
||||
defined(NV_GPIO_DEVICE_GET_CHIP_PRESENT) /* Linux 6.7 */
|
||||
gdev = gpio_device_find(name, cdi_gpio_chip_match);
|
||||
if (gdev) {
|
||||
gc = gpio_device_get_chip(gdev);
|
||||
gpio_device_put(gdev);
|
||||
}
|
||||
#else
|
||||
gc = gpiochip_find(name, cdi_gpio_chip_match);
|
||||
#endif
|
||||
if (!gc) {
|
||||
dev_err(&pdev->dev, "%s: unable to find gpio parent chip %s\n",
|
||||
__func__, pd->gpio_prnt_chip);
|
||||
@@ -275,7 +294,10 @@ static int cdi_gpio_probe(struct platform_device *pdev)
|
||||
gc->base = -1;
|
||||
gc->ngpio = pd->max_gpio;
|
||||
gc->label = "cdi-gpio";
|
||||
gc->parent = &pdev->dev;
|
||||
#if defined(NV_GPIO_CHIP_STRUCT_HAS_OF_NODE_PRESENT) /* Linux 6.2 */
|
||||
gc->of_node = pdev->dev.of_node;
|
||||
#endif
|
||||
gc->owner = THIS_MODULE;
|
||||
|
||||
err = gpiochip_add_data(gc, cdi_gpio);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <asm/siginfo.h>
|
||||
#include <linux/rcupdate.h>
|
||||
@@ -30,7 +31,6 @@
|
||||
#include <media/cdi-mgr.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include <asm/barrier.h>
|
||||
|
||||
@@ -1328,15 +1328,23 @@ static int cdi_mgr_of_get_grp_gpio(
|
||||
struct device *dev, struct device_node *np,
|
||||
const char *name, int size, u32 *grp, u32 *flags)
|
||||
{
|
||||
char prop_name[32]; /* 32 is max size of property name */
|
||||
int num, i;
|
||||
|
||||
num = of_gpio_named_count(np, name);
|
||||
dev_dbg(dev, " num gpios of %s: %d\n", name, num);
|
||||
snprintf(prop_name, sizeof(prop_name), "%s-gpios", name);
|
||||
|
||||
num = gpiod_count(dev, name);
|
||||
dev_dbg(dev, " num gpios of %s: %d\n", prop_name, num);
|
||||
if (num < 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; (i < num) && (i < size); i++) {
|
||||
grp[i] = of_get_named_gpio_flags(np, name, i, &flags[i]);
|
||||
#if defined(NV_OF_GET_NAMED_GPIO_FLAGS_PRESENT) /* Linux 6.2 */
|
||||
grp[i] = of_get_named_gpio_flags(np, prop_name, i, &flags[i]);
|
||||
#else
|
||||
grp[i] = of_get_named_gpio(np, prop_name, i);
|
||||
flags[i] = 0;
|
||||
#endif
|
||||
if ((int)grp[i] < 0) {
|
||||
dev_err(dev, "%s: gpio[%d] invalid\n", __func__, i);
|
||||
return -EINVAL;
|
||||
@@ -1446,13 +1454,13 @@ static struct cdi_mgr_platform_data *of_cdi_mgr_pdata(struct platform_device
|
||||
dev_dbg(&pdev->dev, " csiport: %d\n", pd->csi_port);
|
||||
|
||||
pd->num_pwr_gpios = cdi_mgr_of_get_grp_gpio(
|
||||
&pdev->dev, child_np, "pwdn-gpios",
|
||||
&pdev->dev, child_np, "pwdn",
|
||||
ARRAY_SIZE(pd->pwr_gpios), pd->pwr_gpios, pd->pwr_flags);
|
||||
if (pd->num_pwr_gpios < 0)
|
||||
return ERR_PTR(pd->num_pwr_gpios);
|
||||
|
||||
pd->num_mcdi_gpios = cdi_mgr_of_get_grp_gpio(
|
||||
&pdev->dev, child_np, "mcdi-gpios",
|
||||
&pdev->dev, child_np, "mcdi",
|
||||
ARRAY_SIZE(pd->mcdi_gpios), pd->mcdi_gpios, pd->mcdi_flags);
|
||||
if (pd->num_mcdi_gpios < 0)
|
||||
return ERR_PTR(pd->num_mcdi_gpios);
|
||||
@@ -1488,10 +1496,10 @@ static struct cdi_mgr_platform_data *of_cdi_mgr_pdata(struct platform_device
|
||||
return pd;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0)
|
||||
static char *cdi_mgr_devnode(struct device *dev, umode_t *mode)
|
||||
#else
|
||||
#if defined(NV_CLASS_STRUCT_DEVNODE_HAS_CONST_DEV_ARG) /* Linux v6.2 */
|
||||
static char *cdi_mgr_devnode(const struct device *dev, umode_t *mode)
|
||||
#else
|
||||
static char *cdi_mgr_devnode(struct device *dev, umode_t *mode)
|
||||
#endif
|
||||
{
|
||||
if (!mode)
|
||||
@@ -1652,13 +1660,8 @@ static int cdi_mgr_configure_gpios(struct device *dev, struct cdi_mgr_priv *cdi_
|
||||
}
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0)
|
||||
cdi_mgr->gpios[i].desc = devm_fwnode_get_gpiod_from_child(dev,
|
||||
"devblk", &child->fwnode, GPIOD_ASIS, NULL);
|
||||
#else
|
||||
cdi_mgr->gpios[i].desc = devm_fwnode_gpiod_get_index(dev,
|
||||
&child->fwnode, "devblk", 0, GPIOD_ASIS, NULL);
|
||||
#endif
|
||||
if (IS_ERR(cdi_mgr->gpios[i].desc)) {
|
||||
ret = PTR_ERR(cdi_mgr->gpios[i].desc);
|
||||
if (ret < 0)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2016-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (c) 2016-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
|
||||
#include <nvidia/conftest.h>
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
@@ -28,7 +30,11 @@ static const struct of_device_id cdi_pwm_of_match[] = {
|
||||
|
||||
static inline struct cdi_pwm_info *to_cdi_pwm_info(struct pwm_chip *chip)
|
||||
{
|
||||
#if defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
|
||||
return pwmchip_get_drvdata(chip);
|
||||
#else
|
||||
return container_of(chip, struct cdi_pwm_info, chip);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(6, 0, 0) > LINUX_VERSION_CODE
|
||||
@@ -93,30 +99,38 @@ static struct pwm_device *of_cdi_pwm_xlate(struct pwm_chip *pc,
|
||||
{
|
||||
struct pwm_device *pwm;
|
||||
struct cdi_pwm_info *info = to_cdi_pwm_info(pc);
|
||||
#if defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
|
||||
struct device *dev = &pc->dev;
|
||||
#else
|
||||
struct device *dev = pc->dev;
|
||||
#endif
|
||||
int err = 0;
|
||||
|
||||
pwm = pwm_request_from_chip(pc, args->args[0], NULL);
|
||||
if (!args->args[1]) {
|
||||
dev_err(pc->dev, "Period should be larger than 0\n");
|
||||
pwm = of_pwm_xlate_with_flags(pc, args);
|
||||
if (IS_ERR(pwm))
|
||||
return NULL;
|
||||
|
||||
if (!pwm->args.period) {
|
||||
dev_err(dev, "Period should be larger than 0\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (info->force_on) {
|
||||
err = pwm_config(info->pwm, args->args[1]/4, args->args[1]);
|
||||
if (err) {
|
||||
dev_err(pc->dev, "can't config PWM: %d\n", err);
|
||||
dev_err(dev, "can't config PWM: %d\n", err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = pwm_enable(info->pwm);
|
||||
if (err) {
|
||||
dev_err(pc->dev, "can't enable PWM: %d\n", err);
|
||||
dev_err(dev, "can't enable PWM: %d\n", err);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
err = pwm_config(pwm, args->args[1]/4, args->args[1]);
|
||||
if (err) {
|
||||
dev_err(pc->dev, "can't config PWM: %d\n", err);
|
||||
dev_err(dev, "can't config PWM: %d\n", err);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -130,55 +144,68 @@ static const struct pwm_ops cdi_pwm_ops = {
|
||||
.enable = cdi_pwm_enable,
|
||||
.disable = cdi_pwm_disable,
|
||||
#endif
|
||||
#if defined(NV_PWM_OPS_STRUCT_HAS_OWNER) /* Linux 6.7 */
|
||||
.owner = THIS_MODULE,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int cdi_pwm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct cdi_pwm_info *info = NULL;
|
||||
struct pwm_chip *chip;
|
||||
int err = 0, npwm;
|
||||
bool force_on = false;
|
||||
|
||||
dev_info(&pdev->dev, "%sing...\n", __func__);
|
||||
|
||||
info = devm_kzalloc(
|
||||
&pdev->dev, sizeof(struct cdi_pwm_info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
atomic_set(&info->in_use, 0);
|
||||
mutex_init(&info->mutex);
|
||||
|
||||
err = of_property_read_u32(pdev->dev.of_node, "npwm", &npwm);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "npwm is not defined: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#if defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
|
||||
chip = devm_pwmchip_alloc(&pdev->dev, npwm, sizeof(*info));
|
||||
if (IS_ERR(chip))
|
||||
return PTR_ERR(chip);
|
||||
info = to_cdi_pwm_info(chip);
|
||||
#else
|
||||
info = devm_kzalloc(
|
||||
&pdev->dev, sizeof(struct cdi_pwm_info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
chip = &info->chip;
|
||||
chip->dev = &pdev->dev;
|
||||
chip->npwm = npwm;
|
||||
#endif
|
||||
|
||||
atomic_set(&info->in_use, 0);
|
||||
mutex_init(&info->mutex);
|
||||
|
||||
force_on = of_property_read_bool(pdev->dev.of_node, "force_on");
|
||||
|
||||
info->chip.dev = &pdev->dev;
|
||||
info->chip.ops = &cdi_pwm_ops;
|
||||
info->chip.base = -1;
|
||||
info->chip.npwm = npwm;
|
||||
info->chip.of_xlate = of_cdi_pwm_xlate;
|
||||
info->chip.of_pwm_n_cells = 2;
|
||||
chip->ops = &cdi_pwm_ops;
|
||||
#if defined(NV_PWM_CHIP_STRUCT_HAS_BASE_ARG)
|
||||
chip->base = -1;
|
||||
#endif
|
||||
chip->of_xlate = of_cdi_pwm_xlate;
|
||||
info->force_on = force_on;
|
||||
|
||||
err = pwmchip_add(&info->chip);
|
||||
err = pwmchip_add(chip);
|
||||
if (err < 0) {
|
||||
dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, info);
|
||||
platform_set_drvdata(pdev, chip);
|
||||
|
||||
info->pwm = devm_pwm_get(&pdev->dev, NULL);
|
||||
if (!IS_ERR(info->pwm)) {
|
||||
pwm_disable(info->pwm);
|
||||
dev_info(&pdev->dev, "%s success to get PWM\n", __func__);
|
||||
} else {
|
||||
pwmchip_remove(&info->chip);
|
||||
pwmchip_remove(chip);
|
||||
err = PTR_ERR(info->pwm);
|
||||
if (err != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev,
|
||||
@@ -190,24 +217,24 @@ static int cdi_pwm_probe(struct platform_device *pdev)
|
||||
|
||||
static int cdi_pwm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct cdi_pwm_info *info = platform_get_drvdata(pdev);
|
||||
struct pwm_chip *chip = platform_get_drvdata(pdev);
|
||||
|
||||
pwmchip_remove(&info->chip);
|
||||
pwmchip_remove(chip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdi_pwm_suspend(struct device *dev)
|
||||
{
|
||||
int err = 0;
|
||||
struct cdi_pwm_info *info = dev_get_drvdata(dev);
|
||||
struct pwm_chip *chip = dev_get_drvdata(dev);
|
||||
struct cdi_pwm_info *info = to_cdi_pwm_info(chip);
|
||||
|
||||
if (info == NULL) {
|
||||
dev_err(dev, "%s: fail to get info\n", __func__);
|
||||
} else {
|
||||
if (!IS_ERR(info->pwm)) {
|
||||
pwm_disable(info->pwm);
|
||||
err = pwm_config(info->pwm, PWM_SUSPEND_DUTY_RATIO,
|
||||
pwm_config(info->pwm, PWM_SUSPEND_DUTY_RATIO,
|
||||
PWM_SUSPEND_PERIOD);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,7 @@
|
||||
|
||||
GCOV_PROFILE := y
|
||||
|
||||
LINUX_VERSION := $(shell expr $(VERSION) \* 256 + $(PATCHLEVEL))
|
||||
LINUX_VERSION_6_3 := $(shell expr 6 \* 256 + 3)
|
||||
|
||||
ifneq ($(CONFIG_TEGRA_GPIO_LEGACY_DISABLE),y)
|
||||
obj-m += isc_gpio.o
|
||||
obj-m += isc_mgr.o
|
||||
endif
|
||||
obj-m += isc_dev.o
|
||||
obj-m += isc_pwm.o
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2016-2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
*/
|
||||
/* SPDX-FileCopyrightText: Copyright (c) 2016-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. */
|
||||
|
||||
#ifndef __ISC_PWM_PRIV_H__
|
||||
#define __ISC_PWM_PRIV_H__
|
||||
|
||||
struct isc_pwm_info {
|
||||
#if !defined(NV_PWM_CHIP_STRUCT_HAS_STRUCT_DEVICE)
|
||||
struct pwm_chip chip;
|
||||
#endif
|
||||
struct pwm_device *pwm;
|
||||
atomic_t in_use;
|
||||
struct mutex mutex;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user