diff --git a/drivers/misc/mods/Makefile.nvidia b/drivers/misc/mods/Makefile.nvidia
new file mode 100644
index 00000000..95ea2916
--- /dev/null
+++ b/drivers/misc/mods/Makefile.nvidia
@@ -0,0 +1,15 @@
+obj-$(CONFIG_MODS) := mods.o
+mods-y := mods_krnl.o
+mods-y += mods_mem.o
+mods-y += mods_irq.o
+mods-y += mods_clock.o
+mods-$(CONFIG_ARCH_TEGRA) += mods_tegraprod.o
+mods-$(CONFIG_PCI) += mods_pci.o
+mods-$(CONFIG_ACPI) += mods_acpi.o
+mods-$(CONFIG_ARCH_TEGRA) += mods_dmabuf.o
+mods-$(CONFIG_DMA_ENGINE) += mods_dma.o
+mods-$(CONFIG_DEBUG_FS) += mods_debugfs.o
+mods-$(CONFIG_TEGRA_DC) += mods_tegradc.o
+mods-$(CONFIG_TEGRA_NVADSP) += mods_adsp.o
+mods-$(CONFIG_NET) += mods_netdevice.o
+mods-objs := mods.dtb.o
diff --git a/drivers/misc/mods/mods.dts b/drivers/misc/mods/mods.dts
new file mode 100644
index 00000000..818b2b0d
--- /dev/null
+++ b/drivers/misc/mods/mods.dts
@@ -0,0 +1,27 @@
+/*
+ * mods.dts - This file is part of NVIDIA MODS kernel driver.
+ *
+ * Copyright (c) 2015-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA MODS kernel driver 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.
+ *
+ * NVIDIA MODS kernel driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NVIDIA MODS kernel driver.
+ * If not, see .
+ */
+
+/dts-v1/;
+
+/ {
+ mods {
+ compatible = "nvidia,tegra-mods";
+ status = "okay";
+ };
+};
diff --git a/drivers/misc/mods/mods.h b/drivers/misc/mods/mods.h
new file mode 100644
index 00000000..1d59872b
--- /dev/null
+++ b/drivers/misc/mods/mods.h
@@ -0,0 +1,1188 @@
+/*
+ * mods.h - This file is part of NVIDIA MODS kernel driver.
+ *
+ * Copyright (c) 2008-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA MODS kernel driver 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.
+ *
+ * NVIDIA MODS kernel driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NVIDIA MODS kernel driver.
+ * If not, see .
+ */
+
+#ifndef _MODS_H_
+#define _MODS_H_
+
+#include
+
+/* Driver version */
+#define MODS_DRIVER_VERSION_MAJOR 3
+#define MODS_DRIVER_VERSION_MINOR 73
+#define MODS_DRIVER_VERSION ((MODS_DRIVER_VERSION_MAJOR << 8) | \
+ ((MODS_DRIVER_VERSION_MINOR/10) << 4) | \
+ (MODS_DRIVER_VERSION_MINOR%10))
+
+#pragma pack(push, 1)
+
+/* ************************************************************************* */
+/* ** ESCAPE INTERFACE STRUCTURE */
+/* ************************************************************************* */
+
+struct mods_pci_dev_2 {
+ __u16 domain;
+ __u16 bus;
+ __u16 device;
+ __u16 function;
+};
+
+struct mods_pci_dev {
+ __u16 bus;
+ __u8 device;
+ __u8 function;
+};
+
+/* MODS_ESC_ALLOC_PAGES */
+struct MODS_ALLOC_PAGES {
+ /* IN */
+ __u32 num_bytes;
+ __u32 contiguous;
+ __u32 address_bits;
+ __u32 attrib;
+
+ /* OUT */
+ __u64 memory_handle;
+};
+
+/* MODS_ESC_DEVICE_ALLOC_PAGES_2 */
+struct MODS_DEVICE_ALLOC_PAGES_2 {
+ /* IN */
+ __u32 num_bytes;
+ __u32 contiguous;
+ __u32 address_bits;
+ __u32 attrib;
+ struct mods_pci_dev_2 pci_device;
+
+ /* OUT */
+ __u64 memory_handle;
+};
+
+/* MODS_ESC_DEVICE_ALLOC_PAGES */
+struct MODS_DEVICE_ALLOC_PAGES {
+ /* IN */
+ __u32 num_bytes;
+ __u32 contiguous;
+ __u32 address_bits;
+ __u32 attrib;
+ struct mods_pci_dev pci_device;
+
+ /* OUT */
+ __u64 memory_handle;
+};
+
+/* MODS_ESC_FREE_PAGES */
+struct MODS_FREE_PAGES {
+ /* IN */
+ __u64 memory_handle;
+};
+
+/* MODS_ESC_GET_PHYSICAL_ADDRESS */
+struct MODS_GET_PHYSICAL_ADDRESS {
+ /* IN */
+ __u64 memory_handle;
+ __u32 offset;
+
+ /* OUT */
+ __u64 physical_address;
+};
+
+/* MODS_ESC_GET_PHYSICAL_ADDRESS */
+struct MODS_GET_PHYSICAL_ADDRESS_2 {
+ /* IN */
+ __u64 memory_handle;
+ __u32 offset;
+ struct mods_pci_dev_2 pci_device;
+
+ /* OUT */
+ __u64 physical_address;
+};
+
+/* MODS_ESC_VIRTUAL_TO_PHYSICAL */
+struct MODS_VIRTUAL_TO_PHYSICAL {
+ /* IN */
+ __u64 virtual_address;
+
+ /* OUT */
+ __u64 physical_address;
+};
+
+/* MODS_ESC_PHYSICAL_TO_VIRTUAL */
+struct MODS_PHYSICAL_TO_VIRTUAL {
+ /* IN */
+ __u64 physical_address;
+
+ /* OUT */
+ __u64 virtual_address;
+
+};
+
+/* MODS_ESC_FLUSH_CACHE_RANGE */
+#define MODS_FLUSH_CPU_CACHE 1
+#define MODS_INVALIDATE_CPU_CACHE 2
+
+struct MODS_FLUSH_CPU_CACHE_RANGE {
+ /* IN */
+ __u64 virt_addr_start;
+ __u64 virt_addr_end;
+ __u32 flags;
+};
+
+/* MODS_ESC_DMA_MAP_MEMORY */
+struct MODS_DMA_MAP_MEMORY {
+ /* IN */
+ __u64 memory_handle;
+ struct mods_pci_dev_2 pci_device;
+};
+
+/* MODS_ESC_FIND_PCI_DEVICE_2 */
+struct MODS_FIND_PCI_DEVICE_2 {
+ /* IN */
+ __u32 device_id;
+ __u32 vendor_id;
+ __u32 index;
+
+ /* OUT */
+ struct mods_pci_dev_2 pci_device;
+};
+
+/* MODS_ESC_FIND_PCI_DEVICE */
+struct MODS_FIND_PCI_DEVICE {
+ /* IN */
+ __u32 device_id;
+ __u32 vendor_id;
+ __u32 index;
+
+ /* OUT */
+ __u32 bus_number;
+ __u32 device_number;
+ __u32 function_number;
+};
+
+/* MODS_ESC_FIND_PCI_CLASS_CODE_2 */
+struct MODS_FIND_PCI_CLASS_CODE_2 {
+ /* IN */
+ __u32 class_code;
+ __u32 index;
+
+ /* OUT */
+ struct mods_pci_dev_2 pci_device;
+};
+
+/* MODS_ESC_FIND_PCI_CLASS_CODE */
+struct MODS_FIND_PCI_CLASS_CODE {
+ /* IN */
+ __u32 class_code;
+ __u32 index;
+
+ /* OUT */
+ __u32 bus_number;
+ __u32 device_number;
+ __u32 function_number;
+};
+
+/* MODS_ESC_PCI_GET_BAR_INFO_2 */
+struct MODS_PCI_GET_BAR_INFO_2 {
+ /* IN */
+ struct mods_pci_dev_2 pci_device;
+ __u32 bar_index;
+
+ /* OUT */
+ __u64 base_address;
+ __u64 bar_size;
+};
+
+/* MODS_ESC_PCI_GET_BAR_INFO */
+struct MODS_PCI_GET_BAR_INFO {
+ /* IN */
+ struct mods_pci_dev pci_device;
+ __u32 bar_index;
+
+ /* OUT */
+ __u64 base_address;
+ __u64 bar_size;
+};
+
+/* MODS_ESC_PCI_GET_IRQ_2 */
+struct MODS_PCI_GET_IRQ_2 {
+ /* IN */
+ struct mods_pci_dev_2 pci_device;
+
+ /* OUT */
+ __u32 irq;
+};
+
+/* MODS_ESC_PCI_GET_IRQ */
+struct MODS_PCI_GET_IRQ {
+ /* IN */
+ struct mods_pci_dev pci_device;
+
+ /* OUT */
+ __u32 irq;
+};
+
+/* MODS_ESC_PCI_READ_2 */
+struct MODS_PCI_READ_2 {
+ /* IN */
+ struct mods_pci_dev_2 pci_device;
+ __u32 address;
+ __u32 data_size;
+
+ /* OUT */
+ __u32 data;
+};
+
+/* MODS_ESC_PCI_READ */
+struct MODS_PCI_READ {
+ /* IN */
+ __u32 bus_number;
+ __u32 device_number;
+ __u32 function_number;
+ __u32 address;
+ __u32 data_size;
+
+ /* OUT */
+ __u32 data;
+};
+
+/* MODS_ESC_PCI_WRITE_2 */
+struct MODS_PCI_WRITE_2 {
+ /* IN */
+ struct mods_pci_dev_2 pci_device;
+ __u32 address;
+ __u32 data;
+ __u32 data_size;
+};
+
+/* MODS_ESC_PCI_WRITE */
+struct MODS_PCI_WRITE {
+ /* IN */
+ __u32 bus_number;
+ __u32 device_number;
+ __u32 function_number;
+ __u32 address;
+ __u32 data;
+ __u32 data_size;
+};
+
+/* MODS_ESC_PCI_HOT_RESET */
+struct MODS_PCI_HOT_RESET {
+ /* IN */
+ struct mods_pci_dev_2 pci_device;
+};
+
+/* MODS_ESC_SET_PPC_TCE_BYPASS */
+#define MODS_PPC_TCE_BYPASS_DEFAULT 0
+#define MODS_PPC_TCE_BYPASS_ON 1
+#define MODS_PPC_TCE_BYPASS_OFF 2
+struct MODS_SET_PPC_TCE_BYPASS {
+ /* IN */
+ __u8 mode;
+ __u8 _dummy_align[7];
+ struct mods_pci_dev_2 pci_device;
+ __u64 device_dma_mask;
+
+ /* OUT */
+ __u64 dma_base_address;
+};
+
+/* MODS_ESC_PCI_BUS_ADD_DEVICES*/
+struct MODS_PCI_BUS_ADD_DEVICES {
+ /* IN */
+ __u32 bus;
+};
+
+/* MODS_ESC_PCI_MAP_RESOURCE */
+struct MODS_PCI_MAP_RESOURCE {
+ /* IN */
+ struct mods_pci_dev_2 local_pci_device;
+ struct mods_pci_dev_2 remote_pci_device;
+ __u32 resource_index;
+ __u64 page_count;
+
+ /* IN/OUT */
+ __u64 va;
+};
+
+/* MODS_ESC_PCI_UNMAP_RESOURCE */
+struct MODS_PCI_UNMAP_RESOURCE {
+ /* IN */
+ struct mods_pci_dev_2 pci_device;
+ __u64 va;
+};
+
+/* MODS_ESC_PIO_READ */
+struct MODS_PIO_READ {
+ /* IN */
+ __u16 port;
+ __u32 data_size;
+
+ /* OUT */
+ __u32 data;
+};
+
+/* MODS_ESC_PIO_WRITE */
+struct MODS_PIO_WRITE {
+ /* IN */
+ __u16 port;
+ __u32 data;
+ __u32 data_size;
+};
+
+#define INQ_CNT 8
+
+struct mods_irq_data {
+ __u32 irq;
+ __u32 delay;
+};
+
+struct mods_irq_status {
+ struct mods_irq_data data[INQ_CNT];
+ __u32 irqbits:INQ_CNT;
+ __u32 otherirq:1;
+};
+
+/* MODS_ESC_IRQ */
+struct MODS_IRQ {
+ /* IN */
+ __u32 cmd;
+ __u32 size; /* memory size */
+ __u32 irq; /* the irq number to be registered in driver */
+
+ /* IN OUT */
+ __u32 channel; /* application id allocated by driver. */
+
+ /* OUT */
+ struct mods_irq_status stat; /* for querying irq */
+ __u64 phys; /* the memory physical address */
+};
+#define MODS_IRQ_MAX_MASKS 16
+
+/* MODS_ESC_REGISTER_IRQ_3 */
+struct mods_mask_info2 {
+ __u8 mask_type; /*mask type 32/64 bit access*/
+ __u8 reserved[7]; /*force 64bit alignment */
+ __u32 irq_pending_offset; /* register to read IRQ pending status*/
+ __u32 irq_enabled_offset; /* register to read IRQ enabled status */
+ __u32 irq_enable_offset; /* register to write to enable IRQs */
+ __u32 irq_disable_offset; /* register to write to disable IRQs */
+ __u64 and_mask; /*and mask for clearing bits in this register */
+ __u64 or_mask; /*or mask for setting bit in this register */
+};
+
+struct MODS_REGISTER_IRQ_3 {
+ /* IN */
+ struct mods_pci_dev_2 dev; /* device identifying interrupt for */
+ /* which the mask will be applied */
+ __u64 aperture_addr; /* physical address of aperture */
+ __u32 aperture_size; /* size of the mapped region */
+ __u32 mask_info_cnt; /* number of entries in mask_info[]*/
+ struct mods_mask_info2 mask_info[MODS_IRQ_MAX_MASKS];
+ __u8 irq_type; /* MODS_IRQ_TYPE_* */
+ __u8 reserved[7]; /* keep alignment to 64bits */
+};
+
+/* MODS_ESC_REGISTER_IRQ_2 */
+/* MODS_ESC_UNREGISTER_IRQ_2 */
+/* MODS_ESC_IRQ_HANDLED_2 */
+struct MODS_REGISTER_IRQ_2 {
+ /* IN */
+ struct mods_pci_dev_2 dev; /* device which generates the interrupt */
+ __u8 type; /* MODS_IRQ_TYPE_* */
+};
+
+/* MODS_ESC_REGISTER_IRQ */
+/* MODS_ESC_UNREGISTER_IRQ */
+/* MODS_ESC_IRQ_HANDLED */
+struct MODS_REGISTER_IRQ {
+ /* IN */
+ struct mods_pci_dev dev; /* device which generates */
+ /* the interrupt */
+ __u8 type; /* MODS_IRQ_TYPE_* */
+};
+
+struct mods_irq_2 {
+ __u32 delay; /* delay in ns between the irq */
+ /* occurring and MODS querying for it */
+ struct mods_pci_dev_2 dev; /* device which generated the interrupt */
+};
+
+struct mods_irq {
+ __u32 delay; /* delay in ns between the irq */
+ /* occurring and MODS querying */
+ /* for it */
+ struct mods_pci_dev dev; /* device which generated */
+ /* the interrupt */
+};
+
+#define MODS_MAX_IRQS 32
+
+/* MODS_ESC_QUERY_IRQ_2 */
+struct MODS_QUERY_IRQ_2 {
+ /* OUT */
+ struct mods_irq_2 irq_list[MODS_MAX_IRQS];
+ __u8 more; /* indicates that more interrupts */
+ /* are waiting */
+};
+
+/* MODS_ESC_QUERY_IRQ */
+struct MODS_QUERY_IRQ {
+ /* OUT */
+ struct mods_irq irq_list[MODS_MAX_IRQS];
+ __u8 more; /* indicates that more interrupts are waiting */
+};
+
+#define MODS_IRQ_TYPE_INT 0
+#define MODS_IRQ_TYPE_MSI 1
+#define MODS_IRQ_TYPE_CPU 2
+
+/* MODS_ESC_SET_IRQ_MULTIMASK */
+struct mods_mask_info {
+ __u8 mask_type; /*mask type 32/64 bit access*/
+ __u8 reserved[3];
+ __u32 reg_offset; /* offset of register within the bar aperture*/
+ __u64 and_mask; /*and mask for clearing bits in this register */
+ __u64 or_mask; /*or value for setting bit in this register */
+};
+struct MODS_SET_IRQ_MULTIMASK {
+ /* IN */
+ __u64 aperture_addr; /* physical address of aperture */
+ __u32 aperture_size; /* size of the mapped region */
+ struct mods_pci_dev_2 dev; /* device identifying interrupt for */
+ /* which the mask will be applied */
+ __u32 mask_info_cnt; /* number of entries in mask_info[]*/
+ struct mods_mask_info mask_info[MODS_IRQ_MAX_MASKS];
+ __u8 irq_type; /* irq type */
+};
+
+
+/* MODS_ESC_SET_IRQ_MASK_2 */
+struct MODS_SET_IRQ_MASK_2 {
+ /* IN */
+ __u64 aperture_addr;/* physical address of aperture */
+ __u32 aperture_size;/* size of the mapped region */
+ __u32 reg_offset; /* offset of the irq mask */
+ /* register within the aperture */
+ __u64 and_mask; /* and mask for clearing bits */
+ /* in the irq mask register */
+ __u64 or_mask; /* or mask for setting bits in */
+ /* the irq mask register */
+ struct mods_pci_dev_2 dev; /* device identifying interrupt */
+ /* for which the mask will be */
+ /* applied */
+ __u8 irq_type; /* irq type */
+ __u8 mask_type; /* mask type */
+};
+
+/* MODS_ESC_SET_IRQ_MASK */
+struct MODS_SET_IRQ_MASK {
+ /* IN */
+ __u64 aperture_addr; /* physical address of aperture */
+ __u32 aperture_size; /* size of the mapped region */
+ __u32 reg_offset; /* offset of the irq mask register */
+ /* within the aperture */
+ __u32 and_mask; /* and mask for clearing bits in */
+ /* the irq mask register */
+ __u32 or_mask; /* or mask for setting bits in */
+ /* the irq mask register */
+ struct mods_pci_dev dev; /* device identifying interrupt */
+ /* for which the mask will be */
+ /* applied */
+ __u8 irq_type; /* irq type */
+ __u8 mask_type; /* mask type */
+};
+
+#define MAX_DT_SIZE 64
+#define MAX_FULL_SIZE 128
+
+/*MODS_ESC_MAP_INTERRUPT*/
+struct MODS_DT_INFO {
+ /* OUT */
+ /* Logical irq number*/
+ __u32 irq;
+ /* IN */
+ /* DT name for looking up device tree node */
+ char dt_name[MAX_DT_SIZE];
+ /* Full name of node as in device tree */
+ char full_name[MAX_FULL_SIZE];
+ /* Irq index corresponding to physical irq */
+ __u32 index;
+};
+
+#define MODS_MASK_TYPE_IRQ_DISABLE 0
+#define MODS_MASK_TYPE_IRQ_DISABLE64 1
+
+#define ACPI_MODS_TYPE_INTEGER 1
+#define ACPI_MODS_TYPE_BUFFER 2
+#define ACPI_MAX_BUFFER_LENGTH 4096
+#define ACPI_MAX_METHOD_LENGTH 12
+#define ACPI_MAX_ARGUMENT_NUMBER 12
+
+union ACPI_ARGUMENT {
+ __u32 type;
+
+ struct {
+ __u32 type;
+ __u32 value;
+ } integer;
+
+ struct {
+ __u32 type;
+ __u32 length;
+ __u32 offset;
+ } buffer;
+};
+
+/* MODS_ESC_EVAL_ACPI_METHOD */
+struct MODS_EVAL_ACPI_METHOD {
+ /* IN */
+ char method_name[ACPI_MAX_METHOD_LENGTH];
+ __u32 argument_count;
+ union ACPI_ARGUMENT argument[ACPI_MAX_ARGUMENT_NUMBER];
+ __u8 in_buffer[ACPI_MAX_BUFFER_LENGTH];
+
+ /* IN OUT */
+ __u32 out_data_size;
+
+ /* OUT */
+ __u8 out_buffer[ACPI_MAX_BUFFER_LENGTH];
+ __u32 out_status;
+};
+
+/* MODS_ESC_EVAL_DEV_ACPI_METHOD_2 */
+struct MODS_EVAL_DEV_ACPI_METHOD_2 {
+ /* IN OUT */
+ struct MODS_EVAL_ACPI_METHOD method;
+
+ /* IN */
+ struct mods_pci_dev_2 device;
+};
+
+/* MODS_ESC_EVAL_DEV_ACPI_METHOD */
+struct MODS_EVAL_DEV_ACPI_METHOD {
+ /* IN OUT */
+ struct MODS_EVAL_ACPI_METHOD method;
+
+ /* IN */
+ struct mods_pci_dev device;
+};
+
+/* MODS_ESC_ACPI_GET_DDC_2 */
+struct MODS_ACPI_GET_DDC_2 {
+ /* OUT */
+ __u32 out_data_size;
+ __u8 out_buffer[ACPI_MAX_BUFFER_LENGTH];
+
+ /* IN */
+ struct mods_pci_dev_2 device;
+};
+
+/* MODS_ESC_ACPI_GET_DDC */
+struct MODS_ACPI_GET_DDC {
+ /* OUT */
+ __u32 out_data_size;
+ __u8 out_buffer[ACPI_MAX_BUFFER_LENGTH];
+
+ /* IN */
+ struct mods_pci_dev device;
+};
+
+/* MODS_ESC_GET_VERSION */
+struct MODS_GET_VERSION {
+ /* OUT */
+ __u64 version;
+};
+
+/* MODS_ESC_SET_PARA */
+struct MODS_SET_PARA {
+ /* IN */
+ __u64 Highmem4g;
+ __u64 debug;
+};
+
+/* MODS_ESC_SET_MEMORY_TYPE */
+struct MODS_MEMORY_TYPE {
+ /* IN */
+ __u64 physical_address;
+ __u64 size;
+ __u32 type;
+};
+
+#define MAX_CLOCK_HANDLE_NAME 64
+
+/* MODS_ESC_GET_CLOCK_HANDLE */
+struct MODS_GET_CLOCK_HANDLE {
+ /* OUT */
+ __u32 clock_handle;
+
+ /* IN */
+ char device_name[MAX_CLOCK_HANDLE_NAME];
+ char controller_name[MAX_CLOCK_HANDLE_NAME];
+};
+
+/* MODS_ESC_SET_CLOCK_RATE, MODS_ESC_GET_CLOCK_RATE, */
+/* MODS_ESC_GET_CLOCK_MAX_RATE, MODS_ESC_SET_CLOCK_MAX_RATE */
+struct MODS_CLOCK_RATE {
+ /* IN/OUT */
+ __u64 clock_rate_hz;
+
+ /* IN */
+ __u32 clock_handle;
+};
+
+/* MODS_ESC_SET_CLOCK_PARENT, MODS_ESC_GET_CLOCK_PARENT */
+struct MODS_CLOCK_PARENT {
+ /* IN */
+ __u32 clock_handle;
+
+ /* IN/OUT */
+ __u32 clock_parent_handle;
+};
+
+/* MODS_ESC_ENABLE_CLOCK, MODS_ESC_DISABLE_CLOCK, */
+/* MODS_ESC_CLOCK_RESET_ASSERT, MODS_ESC_CLOCK_RESET_DEASSERT */
+struct MODS_CLOCK_HANDLE {
+ /* IN */
+ __u32 clock_handle;
+};
+
+/* MODS_ESC_IS_CLOCK_ENABLED */
+struct MODS_CLOCK_ENABLED {
+ /* IN */
+ __u32 clock_handle;
+
+ /* OUT */
+ __u32 enable_count;
+};
+
+#if defined(CONFIG_PPC64) || defined(PPC64LE)
+#define MAX_CPU_MASKS 64 /* 32 masks of 32bits = 2048 CPUs max */
+#else
+#define MAX_CPU_MASKS 32 /* 32 masks of 32bits = 1024 CPUs max */
+#endif
+/* MODS_ESC_DEVICE_NUMA_INFO_2 */
+struct MODS_DEVICE_NUMA_INFO_2 {
+ /* IN */
+ struct mods_pci_dev_2 pci_device;
+
+ /* OUT */
+ __s32 node;
+ __u32 node_count;
+ __u32 node_cpu_mask[MAX_CPU_MASKS];
+ __u32 cpu_count;
+};
+
+/* MODS_ESC_DEVICE_NUMA_INFO */
+struct MODS_DEVICE_NUMA_INFO {
+ /* IN */
+ struct mods_pci_dev pci_device;
+
+ /* OUT */
+ __s32 node;
+ __u32 node_count;
+ __u32 node_cpu_mask[MAX_CPU_MASKS];
+ __u32 cpu_count;
+};
+
+/* The ids match MODS ids */
+#define MODS_MEMORY_CACHED 5
+#define MODS_MEMORY_UNCACHED 1
+#define MODS_MEMORY_WRITECOMBINE 2
+
+struct MODS_TEGRA_DC_WINDOW {
+ __s32 index;
+ __u32 flags;
+ __u32 x;
+ __u32 y;
+ __u32 w;
+ __u32 h;
+ __u32 out_x;
+ __u32 out_y;
+ __u32 out_w;
+ __u32 out_h;
+ __u32 pixformat; /* NVDC pix format */
+
+ __u32 bandwidth;
+};
+#define MODS_TEGRA_DC_WINDOW_FLAG_ENABLED (1 << 0)
+#define MODS_TEGRA_DC_WINDOW_FLAG_TILED (1 << 1)
+#define MODS_TEGRA_DC_WINDOW_FLAG_SCAN_COL (1 << 2)
+#define MODS_TEGRA_DC_MAX_WINDOWS (6)
+
+/* MODS_ESC_TEGRA_DC_CONFIG_POSSIBLE */
+struct MODS_TEGRA_DC_CONFIG_POSSIBLE {
+ /* IN/OUT */
+ struct MODS_TEGRA_DC_WINDOW windows[MODS_TEGRA_DC_MAX_WINDOWS];
+
+ /* IN */
+ __u8 head;
+ __u8 win_num;
+
+ /* OUT */
+ __u8 possible;
+};
+
+
+#define MODS_TEGRA_DC_SETUP_SD_LUT_SIZE 9
+#define MODS_TEGRA_DC_SETUP_BLTF_SIZE 16
+/* MODS_ESC_TEGRA_DC_SETUP_SD */
+struct MODS_TEGRA_DC_SETUP_SD {
+ /* IN */
+ __u8 head;
+ __u8 enable;
+
+ __u8 use_vid_luma;
+ __u8 csc_r;
+ __u8 csc_g;
+ __u8 csc_b;
+ __u8 aggressiveness;
+ __u8 bin_width_log2;
+
+ __u32 lut[MODS_TEGRA_DC_SETUP_SD_LUT_SIZE];
+ __u32 bltf[MODS_TEGRA_DC_SETUP_BLTF_SIZE];
+
+ __u32 klimit;
+ __u32 soft_clipping_threshold;
+ __u32 smooth_k_inc;
+ __u8 k_init_bias;
+
+
+ __u32 win_x;
+ __u32 win_y;
+ __u32 win_w;
+ __u32 win_h;
+};
+
+/* MODS_ESC_DMABUF_GET_PHYSICAL_ADDRESS */
+struct MODS_DMABUF_GET_PHYSICAL_ADDRESS {
+ /* IN */
+ __s32 buf_fd;
+ __u32 padding;
+ __u64 offset;
+
+ /* OUT */
+ __u64 physical_address;
+ __u64 segment_size;
+};
+
+#define MODS_ADSP_APP_NAME_SIZE 64
+#define MODS_ADSP_APP_MAX_PARAM 128
+struct MODS_ADSP_RUN_APP_INFO {
+ char app_name[MODS_ADSP_APP_NAME_SIZE];
+ char app_file_name[MODS_ADSP_APP_NAME_SIZE];
+ __u32 argc;
+ __u32 argv[MODS_ADSP_APP_MAX_PARAM];
+ __u32 timeout;
+};
+
+/* MODS_ESC_GET_SCREEN_INFO */
+struct MODS_SCREEN_INFO {
+ /* OUT */
+ __u8 orig_video_mode;
+ __u8 orig_video_is_vga;
+ __u16 lfb_width;
+ __u16 lfb_height;
+ __u16 lfb_depth;
+ __u32 lfb_base;
+ __u32 lfb_size;
+ __u16 lfb_linelength;
+};
+
+enum MODS_DMA_TRANSACTION_TYPE {
+ MODS_DMA_MEMCPY,
+ MODS_DMA_XOR,
+ MODS_DMA_PQ,
+ MODS_DMA_XOR_VAL,
+ MODS_DMA_PQ_VAL,
+ MODS_DMA_MEMSET,
+ MODS_DMA_MEMSET_SG,
+ MODS_DMA_INTERRUPT,
+ MODS_DMA_SG,
+ MODS_DMA_PRIVATE,
+ MODS_DMA_ASYNC_TX,
+ MODS_DMA_SLAVE,
+ MODS_DMA_CYCLIC,
+ MODS_DMA_INTERLEAVE,
+/* last transaction type for creation of the capabilities mask */
+ MODS_DMA_TX_TYPE_END
+};
+
+struct MODS_DMA_HANDLE {
+ /* IN */
+ __u32 dma_type; /* Indicate the DMA Type*/
+ /* OUT */
+ __u32 dma_id; /* Inditify for the DMA */
+};
+
+enum MODS_DMA_TRANSFER_DIRECTION {
+ MODS_DMA_MEM_TO_MEM,
+ MODS_DMA_MEM_TO_DEV,
+ MODS_DMA_DEV_TO_MEM,
+ MODS_DMA_DEV_TO_DEV,
+ MODS_DMA_TRANS_NONE
+};
+
+enum MODS_DMA_BUSWIDTH {
+ MODS_DMA_BUSWIDTH_UNDEFINED = 0,
+ MODS_DMA_BUSWIDTH_1_BYTE = 1,
+ MODS_DMA_BUSWIDTH_2_BYTES = 2,
+ MODS_DMA_BUSWIDTH_4_BYTES = 4,
+ MODS_DMA_BUSWIDTH_8_BYTES = 8
+};
+
+struct MODS_DMA_CHANNEL_CONFIG {
+ __u64 src_addr;
+ __u64 dst_addr;
+ struct MODS_DMA_HANDLE handle;
+ __u32 direction;
+ __u32 src_addr_width;
+ __u32 dst_addr_width;
+ __u32 src_maxburst;
+ __u32 dst_maxburst;
+ __u32 slave_id;
+ __u32 device_fc;
+};
+
+/* Node: Only support SINGLE MODS so far*/
+enum MODS_DMA_TX_MODE {
+ MODS_DMA_SINGLE = 0,
+ MODS_DMA_TX_CYCLIC,
+ MODS_DMA_INTERLEAVED /* Common to Slave as well as M2M clients. */
+};
+
+typedef __s32 mods_dma_cookie_t;
+
+struct MODS_DMA_TX_DESC {
+ /* IN */
+ __u64 phys;
+ __u64 phys_2; /* only valid for MEMCPY */
+ struct MODS_DMA_HANDLE handle;
+ __u32 mode;
+ __u32 data_dir;
+ __u32 length;
+ __u32 flags;
+ /* OUT */
+ mods_dma_cookie_t cookie;
+};
+
+enum MODS_DMA_WAIT_TYPE {
+ MODS_DMA_SYNC_WAIT, /* wait until finished */
+ MODS_DMA_ASYNC_WAIT /* just check tx status */
+};
+
+struct MODS_DMA_WAIT_DESC {
+ struct MODS_DMA_HANDLE handle;
+ mods_dma_cookie_t cookie;
+ __u32 type;
+ /* OUT */
+ __u32 tx_complete;
+};
+
+#define MAX_NET_DEVICE_NAME_LENGTH 16
+struct MODS_NET_DEVICE_NAME {
+ /* in */
+ char device_name[MAX_NET_DEVICE_NAME_LENGTH];
+};
+struct MODS_DMA_COHERENT_MEM_HANDLE {
+ __u32 num_bytes;
+ __u32 attrib;
+ __u64 memory_handle_phys;
+ __u64 memory_handle_virt;
+};
+
+/* MODS_ESC_DMA_COPY_TO_USER */
+struct MODS_DMA_COPY_TO_USER {
+ __u32 num_bytes;
+ __u32 attrib;
+ __u64 memory_handle_src;
+ __u64 memory_handle_dst;
+};
+
+struct MODS_TEGRA_PROD_SET_TUPLE {
+ /* IN */
+ __u64 prod_dev_handle;
+ __u64 ctrl_dev_handle;
+ char prod_name[MAX_DT_SIZE];
+ __u32 index;
+ __u32 offset;
+ __u32 mask;
+};
+
+struct MODS_TEGRA_PROD_IS_SUPPORTED {
+ /* IN */
+ __u64 prod_dev_handle;
+ char prod_name[MAX_DT_SIZE];
+ /* OUT */
+ __u32 is_supported;
+};
+
+struct MODS_TEGRA_PROD_ITERATOR {
+ /* IN */
+ __u64 device_handle;
+ char name[MAX_DT_SIZE];
+ char next_name[MAX_DT_SIZE];
+ __u32 index;
+ __u32 is_leaf;
+ /* OUT */
+ __u64 next_device_handle;
+};
+
+/* MODS_ESC_GET_ATS_ADDRESS_RANGE */
+struct MODS_GET_ATS_ADDRESS_RANGE {
+ /* IN */
+ struct mods_pci_dev_2 pci_device;
+ __s32 npu_index;
+ __u8 reserved[4]; /* Alignment */
+
+ /* OUT */
+ struct mods_pci_dev_2 npu_device;
+ __u64 phys_addr;
+ __u64 guest_addr;
+ __u64 aperture_size;
+ __s32 numa_memory_node;
+};
+
+#pragma pack(pop)
+
+/* ************************************************************************* */
+/* ************************************************************************* */
+/* ** */
+/* ** ESCAPE CALLS */
+/* ** */
+/* ************************************************************************* */
+/* ************************************************************************* */
+#define MODS_IOC_MAGIC 'x'
+#define MODS_ESC_ALLOC_PAGES \
+ _IOWR(MODS_IOC_MAGIC, 0, struct MODS_ALLOC_PAGES)
+#define MODS_ESC_FREE_PAGES \
+ _IOWR(MODS_IOC_MAGIC, 1, struct MODS_FREE_PAGES)
+#define MODS_ESC_GET_PHYSICAL_ADDRESS \
+ _IOWR(MODS_IOC_MAGIC, 2, struct MODS_GET_PHYSICAL_ADDRESS)
+#define MODS_ESC_VIRTUAL_TO_PHYSICAL \
+ _IOWR(MODS_IOC_MAGIC, 3, struct MODS_VIRTUAL_TO_PHYSICAL)
+#define MODS_ESC_PHYSICAL_TO_VIRTUAL \
+ _IOWR(MODS_IOC_MAGIC, 4, struct MODS_PHYSICAL_TO_VIRTUAL)
+#define MODS_ESC_FIND_PCI_DEVICE \
+ _IOWR(MODS_IOC_MAGIC, 5, struct MODS_FIND_PCI_DEVICE)
+#define MODS_ESC_FIND_PCI_CLASS_CODE \
+ _IOWR(MODS_IOC_MAGIC, 6, struct MODS_FIND_PCI_CLASS_CODE)
+#define MODS_ESC_PCI_READ \
+ _IOWR(MODS_IOC_MAGIC, 7, struct MODS_PCI_READ)
+#define MODS_ESC_PCI_WRITE \
+ _IOWR(MODS_IOC_MAGIC, 8, struct MODS_PCI_WRITE)
+#define MODS_ESC_PIO_READ \
+ _IOWR(MODS_IOC_MAGIC, 9, struct MODS_PIO_READ)
+#define MODS_ESC_PIO_WRITE \
+ _IOWR(MODS_IOC_MAGIC, 10, struct MODS_PIO_WRITE)
+#define MODS_ESC_IRQ_REGISTER \
+ _IOWR(MODS_IOC_MAGIC, 11, struct MODS_IRQ)
+#define MODS_ESC_IRQ_FREE \
+ _IOWR(MODS_IOC_MAGIC, 12, struct MODS_IRQ)
+#define MODS_ESC_IRQ_INQUIRY \
+ _IOWR(MODS_IOC_MAGIC, 13, struct MODS_IRQ)
+#define MODS_ESC_EVAL_ACPI_METHOD \
+ _IOWR_BAD(MODS_IOC_MAGIC, 16, struct MODS_EVAL_ACPI_METHOD)
+#define MODS_ESC_GET_API_VERSION \
+ _IOWR(MODS_IOC_MAGIC, 17, struct MODS_GET_VERSION)
+#define MODS_ESC_GET_KERNEL_VERSION \
+ _IOWR(MODS_IOC_MAGIC, 18, struct MODS_GET_VERSION)
+#define MODS_ESC_SET_DRIVER_PARA \
+ _IOWR(MODS_IOC_MAGIC, 19, struct MODS_SET_PARA)
+#define MODS_ESC_MSI_REGISTER \
+ _IOWR(MODS_IOC_MAGIC, 20, struct MODS_IRQ)
+#define MODS_ESC_REARM_MSI \
+ _IOWR(MODS_IOC_MAGIC, 21, struct MODS_IRQ)
+#define MODS_ESC_SET_MEMORY_TYPE \
+ _IOW(MODS_IOC_MAGIC, 22, struct MODS_MEMORY_TYPE)
+#define MODS_ESC_PCI_BUS_ADD_DEVICES \
+ _IOW(MODS_IOC_MAGIC, 23, struct MODS_PCI_BUS_ADD_DEVICES)
+#define MODS_ESC_REGISTER_IRQ \
+ _IOW(MODS_IOC_MAGIC, 24, struct MODS_REGISTER_IRQ)
+#define MODS_ESC_UNREGISTER_IRQ \
+ _IOW(MODS_IOC_MAGIC, 25, struct MODS_REGISTER_IRQ)
+#define MODS_ESC_QUERY_IRQ \
+ _IOR(MODS_IOC_MAGIC, 26, struct MODS_QUERY_IRQ)
+#define MODS_ESC_EVAL_DEV_ACPI_METHOD \
+ _IOWR_BAD(MODS_IOC_MAGIC, 27, struct MODS_EVAL_DEV_ACPI_METHOD)
+#define MODS_ESC_ACPI_GET_DDC \
+ _IOWR(MODS_IOC_MAGIC, 28, struct MODS_ACPI_GET_DDC)
+#define MODS_ESC_GET_CLOCK_HANDLE \
+ _IOWR(MODS_IOC_MAGIC, 29, struct MODS_GET_CLOCK_HANDLE)
+#define MODS_ESC_SET_CLOCK_RATE \
+ _IOW(MODS_IOC_MAGIC, 30, struct MODS_CLOCK_RATE)
+#define MODS_ESC_GET_CLOCK_RATE \
+ _IOWR(MODS_IOC_MAGIC, 31, struct MODS_CLOCK_RATE)
+#define MODS_ESC_SET_CLOCK_PARENT \
+ _IOW(MODS_IOC_MAGIC, 32, struct MODS_CLOCK_PARENT)
+#define MODS_ESC_GET_CLOCK_PARENT \
+ _IOWR(MODS_IOC_MAGIC, 33, struct MODS_CLOCK_PARENT)
+#define MODS_ESC_ENABLE_CLOCK \
+ _IOW(MODS_IOC_MAGIC, 34, struct MODS_CLOCK_HANDLE)
+#define MODS_ESC_DISABLE_CLOCK \
+ _IOW(MODS_IOC_MAGIC, 35, struct MODS_CLOCK_HANDLE)
+#define MODS_ESC_IS_CLOCK_ENABLED \
+ _IOWR(MODS_IOC_MAGIC, 36, struct MODS_CLOCK_ENABLED)
+#define MODS_ESC_CLOCK_RESET_ASSERT \
+ _IOW(MODS_IOC_MAGIC, 37, struct MODS_CLOCK_HANDLE)
+#define MODS_ESC_CLOCK_RESET_DEASSERT \
+ _IOW(MODS_IOC_MAGIC, 38, struct MODS_CLOCK_HANDLE)
+#define MODS_ESC_SET_IRQ_MASK \
+ _IOW(MODS_IOC_MAGIC, 39, struct MODS_SET_IRQ_MASK)
+#define MODS_ESC_MEMORY_BARRIER \
+ _IO(MODS_IOC_MAGIC, 40)
+#define MODS_ESC_IRQ_HANDLED \
+ _IOW(MODS_IOC_MAGIC, 41, struct MODS_REGISTER_IRQ)
+#define MODS_ESC_FLUSH_CPU_CACHE_RANGE \
+ _IOW(MODS_IOC_MAGIC, 42, struct MODS_FLUSH_CPU_CACHE_RANGE)
+#define MODS_ESC_GET_CLOCK_MAX_RATE \
+ _IOWR(MODS_IOC_MAGIC, 43, struct MODS_CLOCK_RATE)
+#define MODS_ESC_SET_CLOCK_MAX_RATE \
+ _IOW(MODS_IOC_MAGIC, 44, struct MODS_CLOCK_RATE)
+#define MODS_ESC_DEVICE_ALLOC_PAGES \
+ _IOWR(MODS_IOC_MAGIC, 45, struct MODS_DEVICE_ALLOC_PAGES)
+#define MODS_ESC_DEVICE_NUMA_INFO \
+ _IOWR(MODS_IOC_MAGIC, 46, struct MODS_DEVICE_NUMA_INFO)
+#define MODS_ESC_TEGRA_DC_CONFIG_POSSIBLE \
+ _IOWR(MODS_IOC_MAGIC, 47, \
+ struct MODS_TEGRA_DC_CONFIG_POSSIBLE)
+#define MODS_ESC_TEGRA_DC_SETUP_SD \
+ _IOW(MODS_IOC_MAGIC, 48, struct MODS_TEGRA_DC_SETUP_SD)
+#define MODS_ESC_DMABUF_GET_PHYSICAL_ADDRESS \
+ _IOWR(MODS_IOC_MAGIC, 49, \
+ struct MODS_DMABUF_GET_PHYSICAL_ADDRESS)
+#define MODS_ESC_ADSP_LOAD \
+ _IO(MODS_IOC_MAGIC, 50)
+#define MODS_ESC_ADSP_START \
+ _IO(MODS_IOC_MAGIC, 51)
+#define MODS_ESC_ADSP_STOP \
+ _IO(MODS_IOC_MAGIC, 52)
+#define MODS_ESC_ADSP_RUN_APP \
+ _IOW(MODS_IOC_MAGIC, 53, struct MODS_ADSP_RUN_APP_INFO)
+#define MODS_ESC_PCI_GET_BAR_INFO \
+ _IOWR(MODS_IOC_MAGIC, 54, struct MODS_PCI_GET_BAR_INFO)
+#define MODS_ESC_PCI_GET_IRQ \
+ _IOWR(MODS_IOC_MAGIC, 55, struct MODS_PCI_GET_IRQ)
+#define MODS_ESC_GET_MAPPED_PHYSICAL_ADDRESS \
+ _IOWR(MODS_IOC_MAGIC, 56, \
+ struct MODS_GET_PHYSICAL_ADDRESS)
+#define MODS_ESC_DEVICE_ALLOC_PAGES_2 \
+ _IOWR(MODS_IOC_MAGIC, 57, struct MODS_DEVICE_ALLOC_PAGES_2)
+#define MODS_ESC_FIND_PCI_DEVICE_2 \
+ _IOWR(MODS_IOC_MAGIC, 58, struct MODS_FIND_PCI_DEVICE_2)
+#define MODS_ESC_FIND_PCI_CLASS_CODE_2 \
+ _IOWR(MODS_IOC_MAGIC, 59, \
+ struct MODS_FIND_PCI_CLASS_CODE_2)
+#define MODS_ESC_PCI_GET_BAR_INFO_2 \
+ _IOWR(MODS_IOC_MAGIC, 60, struct MODS_PCI_GET_BAR_INFO_2)
+#define MODS_ESC_PCI_GET_IRQ_2 \
+ _IOWR(MODS_IOC_MAGIC, 61, struct MODS_PCI_GET_IRQ_2)
+#define MODS_ESC_PCI_READ_2 \
+ _IOWR(MODS_IOC_MAGIC, 62, struct MODS_PCI_READ_2)
+#define MODS_ESC_PCI_WRITE_2 \
+ _IOW(MODS_IOC_MAGIC, 63, struct MODS_PCI_WRITE_2)
+#define MODS_ESC_REGISTER_IRQ_2 \
+ _IOW(MODS_IOC_MAGIC, 64, struct MODS_REGISTER_IRQ_2)
+#define MODS_ESC_UNREGISTER_IRQ_2 \
+ _IOW(MODS_IOC_MAGIC, 65, struct MODS_REGISTER_IRQ_2)
+#define MODS_ESC_IRQ_HANDLED_2 \
+ _IOW(MODS_IOC_MAGIC, 66, struct MODS_REGISTER_IRQ_2)
+#define MODS_ESC_QUERY_IRQ_2 \
+ _IOR(MODS_IOC_MAGIC, 67, struct MODS_QUERY_IRQ_2)
+#define MODS_ESC_SET_IRQ_MASK_2 \
+ _IOW(MODS_IOC_MAGIC, 68, struct MODS_SET_IRQ_MASK_2)
+#define MODS_ESC_EVAL_DEV_ACPI_METHOD_2 \
+ _IOWR_BAD(MODS_IOC_MAGIC, 69,\
+ struct MODS_EVAL_DEV_ACPI_METHOD_2)
+#define MODS_ESC_DEVICE_NUMA_INFO_2 \
+ _IOWR(MODS_IOC_MAGIC, 70, struct MODS_DEVICE_NUMA_INFO_2)
+#define MODS_ESC_ACPI_GET_DDC_2 \
+ _IOWR(MODS_IOC_MAGIC, 71, struct MODS_ACPI_GET_DDC_2)
+#define MODS_ESC_GET_SCREEN_INFO \
+ _IOR(MODS_IOC_MAGIC, 72, struct MODS_SCREEN_INFO)
+#define MODS_ESC_PCI_HOT_RESET \
+ _IOW(MODS_IOC_MAGIC, 73, struct MODS_PCI_HOT_RESET)
+#define MODS_ESC_SET_PPC_TCE_BYPASS \
+ _IOWR(MODS_IOC_MAGIC, 74, struct MODS_SET_PPC_TCE_BYPASS)
+#define MODS_ESC_DMA_MAP_MEMORY \
+ _IOW(MODS_IOC_MAGIC, 75, struct MODS_DMA_MAP_MEMORY)
+#define MODS_ESC_DMA_UNMAP_MEMORY \
+ _IOW(MODS_IOC_MAGIC, 76, struct MODS_DMA_MAP_MEMORY)
+#define MODS_ESC_GET_MAPPED_PHYSICAL_ADDRESS_2 \
+ _IOWR(MODS_IOC_MAGIC, 77, \
+ struct MODS_GET_PHYSICAL_ADDRESS_2)
+#define MODS_ESC_PCI_MAP_RESOURCE \
+ _IOWR(MODS_IOC_MAGIC, 78, struct MODS_PCI_MAP_RESOURCE)
+#define MODS_ESC_PCI_UNMAP_RESOURCE \
+ _IOW(MODS_IOC_MAGIC, 79, struct MODS_PCI_UNMAP_RESOURCE)
+#define MODS_ESC_DMA_REQUEST_HANDLE \
+ _IOR(MODS_IOC_MAGIC, 80, struct MODS_DMA_HANDLE)
+#define MODS_ESC_DMA_RELEASE_HANDLE \
+ _IOW(MODS_IOC_MAGIC, 81, struct MODS_DMA_HANDLE)
+#define MODS_ESC_DMA_SET_CONFIG \
+ _IOW(MODS_IOC_MAGIC, 82, struct MODS_DMA_CHANNEL_CONFIG)
+#define MODS_ESC_DMA_TX_SUBMIT \
+ _IOW(MODS_IOC_MAGIC, 83, struct MODS_DMA_TX_DESC)
+#define MODS_ESC_DMA_TX_WAIT \
+ _IOWR(MODS_IOC_MAGIC, 84, struct MODS_DMA_WAIT_DESC)
+#define MODS_ESC_DMA_ISSUE_PENDING \
+ _IOW(MODS_IOC_MAGIC, 85, struct MODS_DMA_HANDLE)
+#define MODS_ESC_SET_IRQ_MULTIMASK \
+ _IOW(MODS_IOC_MAGIC, 86, struct MODS_SET_IRQ_MULTIMASK)
+#define MODS_ESC_NET_FORCE_LINK \
+ _IOW(MODS_IOC_MAGIC, 87, struct MODS_NET_DEVICE_NAME)
+#define MODS_ESC_REGISTER_IRQ_3 \
+ _IOW(MODS_IOC_MAGIC, 88, struct MODS_REGISTER_IRQ_3)
+#define MODS_ESC_DMA_ALLOC_COHERENT \
+ _IOWR(MODS_IOC_MAGIC, 89, \
+ struct MODS_DMA_COHERENT_MEM_HANDLE)
+#define MODS_ESC_DMA_FREE_COHERENT \
+ _IOWR(MODS_IOC_MAGIC, 90, \
+ struct MODS_DMA_COHERENT_MEM_HANDLE)
+#define MODS_ESC_DMA_COPY_TO_USER \
+ _IOWR(MODS_IOC_MAGIC, 91, \
+ struct MODS_DMA_COPY_TO_USER)
+#define MODS_ESC_MAP_INTERRUPT \
+ _IOWR(MODS_IOC_MAGIC, 92, \
+ struct MODS_DT_INFO)
+#define MODS_ESC_LOCK_CONSOLE \
+ _IO(MODS_IOC_MAGIC, 93)
+#define MODS_ESC_UNLOCK_CONSOLE \
+ _IO(MODS_IOC_MAGIC, 94)
+#define MODS_ESC_TEGRA_PROD_IS_SUPPORTED \
+ _IOWR(MODS_IOC_MAGIC, 95, \
+ struct MODS_TEGRA_PROD_IS_SUPPORTED)
+#define MODS_ESC_TEGRA_PROD_SET_PROD_ALL \
+ _IOW(MODS_IOC_MAGIC, 96, \
+ struct MODS_TEGRA_PROD_SET_TUPLE)
+#define MODS_ESC_TEGRA_PROD_SET_PROD_BOOT \
+ _IOW(MODS_IOC_MAGIC, 97, \
+ struct MODS_TEGRA_PROD_SET_TUPLE)
+#define MODS_ESC_TEGRA_PROD_SET_PROD_BY_NAME \
+ _IOW(MODS_IOC_MAGIC, 98, \
+ struct MODS_TEGRA_PROD_SET_TUPLE)
+#define MODS_ESC_TEGRA_PROD_SET_PROD_EXACT \
+ _IOW(MODS_IOC_MAGIC, 99, \
+ struct MODS_TEGRA_PROD_SET_TUPLE)
+#define MODS_ESC_TEGRA_PROD_ITERATE_DT \
+ _IOWR(MODS_IOC_MAGIC, 100, \
+ struct MODS_TEGRA_PROD_ITERATOR)
+#define MODS_ESC_GET_ATS_ADDRESS_RANGE \
+ _IOWR(MODS_IOC_MAGIC, 101, \
+ struct MODS_GET_ATS_ADDRESS_RANGE)
+
+#endif /* _MODS_H_ */
diff --git a/drivers/misc/mods/mods_acpi.c b/drivers/misc/mods/mods_acpi.c
new file mode 100644
index 00000000..90974ec9
--- /dev/null
+++ b/drivers/misc/mods/mods_acpi.c
@@ -0,0 +1,452 @@
+/*
+ * mods_acpi.c - This file is part of NVIDIA MODS kernel driver.
+ *
+ * Copyright (c) 2008-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA MODS kernel driver 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.
+ *
+ * NVIDIA MODS kernel driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NVIDIA MODS kernel driver.
+ * If not, see .
+ */
+
+#include "mods_internal.h"
+
+#include
+#include
+#include
+#include
+
+static acpi_status mods_acpi_find_acpi_handler(acpi_handle,
+ u32,
+ void *,
+ void **);
+
+/*********************
+ * PRIVATE FUNCTIONS *
+ *********************/
+
+/* store handle if found. */
+static void mods_acpi_handle_init(char *method_name, acpi_handle *handler)
+{
+ MODS_ACPI_WALK_NAMESPACE(ACPI_TYPE_ANY,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ mods_acpi_find_acpi_handler,
+ method_name,
+ handler);
+
+ if (!(*handler)) {
+ mods_debug_printk(DEBUG_ACPI, "ACPI method %s not found\n",
+ method_name);
+ return;
+ }
+}
+
+static acpi_status mods_acpi_find_acpi_handler(
+ acpi_handle handle,
+ u32 nest_level,
+ void *dummy1,
+ void **dummy2
+)
+{
+ acpi_handle acpi_method_handler_temp;
+
+ if (!acpi_get_handle(handle, dummy1, &acpi_method_handler_temp))
+ *dummy2 = acpi_method_handler_temp;
+
+ return OK;
+}
+
+static int mods_extract_acpi_object(
+ char *method,
+ union acpi_object *obj,
+ u8 **buf,
+ u8 *buf_end
+)
+{
+ int ret = OK;
+
+ switch (obj->type) {
+
+ case ACPI_TYPE_BUFFER:
+ if (obj->buffer.length == 0) {
+ mods_error_printk(
+ "empty ACPI output buffer from ACPI method %s\n",
+ method);
+ ret = -EINVAL;
+ } else if (obj->buffer.length <= buf_end-*buf) {
+ u32 size = obj->buffer.length;
+
+ memcpy(*buf, obj->buffer.pointer, size);
+ *buf += size;
+ } else {
+ mods_error_printk(
+ "output buffer too small for ACPI method %s\n",
+ method);
+ ret = -EINVAL;
+ }
+ break;
+
+ case ACPI_TYPE_INTEGER:
+ if (buf_end - *buf >= 4) {
+ if (obj->integer.value > 0xFFFFFFFFU) {
+ mods_error_printk(
+ "integer value from ACPI method %s out of range\n",
+ method);
+ ret = -EINVAL;
+ } else {
+ memcpy(*buf, &obj->integer.value, 4);
+ *buf += 4;
+ }
+ } else {
+ mods_error_printk(
+ "output buffer too small for ACPI method %s\n",
+ method);
+ ret = -EINVAL;
+ }
+ break;
+
+ case ACPI_TYPE_PACKAGE:
+ if (obj->package.count == 0) {
+ mods_error_printk(
+ "empty ACPI output package from ACPI method %s\n",
+ method);
+ ret = -EINVAL;
+ } else {
+ union acpi_object *elements = obj->package.elements;
+ u32 size = 0;
+ u32 i;
+
+ for (i = 0; i < obj->package.count; i++) {
+ u8 *old_buf = *buf;
+
+ ret = mods_extract_acpi_object(method,
+ &elements[i],
+ buf,
+ buf_end);
+ if (ret == OK) {
+ u32 new_size = *buf - old_buf;
+
+ if (size == 0) {
+ size = new_size;
+ } else if (size != new_size) {
+ mods_error_printk(
+ "ambiguous package element size from ACPI method %s\n",
+ method);
+ ret = -EINVAL;
+ }
+ } else
+ break;
+ }
+ }
+ break;
+
+ default:
+ mods_error_printk(
+ "unsupported ACPI output type 0x%02x from method %s\n",
+ (unsigned int)obj->type, method);
+ ret = -EINVAL;
+ break;
+
+ }
+ return ret;
+}
+
+static int mods_eval_acpi_method(struct file *pfile,
+ struct MODS_EVAL_ACPI_METHOD *p,
+ struct mods_pci_dev_2 *pdevice)
+{
+ int ret = OK;
+ int i;
+ acpi_status status;
+ struct acpi_object_list input;
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *acpi_method = NULL;
+ union acpi_object acpi_params[ACPI_MAX_ARGUMENT_NUMBER];
+ acpi_handle acpi_method_handler = NULL;
+
+ if (pdevice) {
+ unsigned int devfn;
+ struct pci_dev *dev;
+
+ mods_debug_printk(DEBUG_ACPI,
+ "ACPI %s for device %04x:%x:%02x.%x\n",
+ p->method_name,
+ (unsigned int)pdevice->domain,
+ (unsigned int)pdevice->bus,
+ (unsigned int)pdevice->device,
+ (unsigned int)pdevice->function);
+
+ devfn = PCI_DEVFN(pdevice->device, pdevice->function);
+ dev = MODS_PCI_GET_SLOT(pdevice->domain, pdevice->bus, devfn);
+ if (!dev) {
+ mods_error_printk("ACPI: PCI device not found\n");
+ return -EINVAL;
+ }
+ acpi_method_handler = MODS_ACPI_HANDLE(&dev->dev);
+ } else {
+ mods_debug_printk(DEBUG_ACPI, "ACPI %s\n", p->method_name);
+ mods_acpi_handle_init(p->method_name, &acpi_method_handler);
+ }
+
+ if (!acpi_method_handler) {
+ mods_debug_printk(DEBUG_ACPI, "ACPI: handle for %s not found\n",
+ p->method_name);
+ return -EINVAL;
+ }
+
+ if (p->argument_count >= ACPI_MAX_ARGUMENT_NUMBER) {
+ mods_error_printk("invalid argument count for ACPI call\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < p->argument_count; i++) {
+ switch (p->argument[i].type) {
+ case ACPI_MODS_TYPE_INTEGER: {
+ acpi_params[i].integer.type = ACPI_TYPE_INTEGER;
+ acpi_params[i].integer.value
+ = p->argument[i].integer.value;
+ break;
+ }
+ case ACPI_MODS_TYPE_BUFFER: {
+ acpi_params[i].buffer.type = ACPI_TYPE_BUFFER;
+ acpi_params[i].buffer.length
+ = p->argument[i].buffer.length;
+ acpi_params[i].buffer.pointer
+ = p->in_buffer + p->argument[i].buffer.offset;
+ break;
+ }
+ default: {
+ mods_error_printk("unsupported ACPI argument type\n");
+ return -EINVAL;
+ }
+ }
+ }
+
+ input.count = p->argument_count;
+ input.pointer = acpi_params;
+
+ status = acpi_evaluate_object(acpi_method_handler,
+ pdevice ? p->method_name : NULL,
+ &input,
+ &output);
+
+ if (ACPI_FAILURE(status)) {
+ mods_error_printk("ACPI method %s failed\n", p->method_name);
+ return -EINVAL;
+ }
+
+ acpi_method = output.pointer;
+ if (!acpi_method) {
+ mods_error_printk("missing output from ACPI method %s\n",
+ p->method_name);
+ ret = -EINVAL;
+ } else {
+ u8 *buf = p->out_buffer;
+
+ ret = mods_extract_acpi_object(p->method_name,
+ acpi_method,
+ &buf,
+ buf+sizeof(p->out_buffer));
+ p->out_data_size = (ret == OK) ? (buf - p->out_buffer) : 0;
+ }
+
+ kfree(output.pointer);
+ return ret;
+}
+
+static int mods_acpi_get_ddc(struct file *pfile,
+ struct MODS_ACPI_GET_DDC_2 *p,
+ struct mods_pci_dev_2 *pci_device)
+{
+ acpi_status status;
+ struct acpi_device *device = NULL;
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *ddc;
+ union acpi_object ddc_arg0 = { ACPI_TYPE_INTEGER };
+ struct acpi_object_list input = { 1, &ddc_arg0 };
+ struct list_head *node, *next;
+ u32 i;
+ acpi_handle dev_handle = NULL;
+ acpi_handle lcd_dev_handle = NULL;
+
+ mods_debug_printk(DEBUG_ACPI,
+ "ACPI _DDC (EDID) for device %04x:%x:%02x.%x\n",
+ (unsigned int)pci_device->domain,
+ (unsigned int)pci_device->bus,
+ (unsigned int)pci_device->device,
+ (unsigned int)pci_device->function);
+
+ {
+ unsigned int devfn = PCI_DEVFN(pci_device->device,
+ pci_device->function);
+ struct pci_dev *dev = MODS_PCI_GET_SLOT(pci_device->domain,
+ pci_device->bus, devfn);
+ if (!dev) {
+ mods_error_printk("ACPI: PCI device not found\n");
+ return -EINVAL;
+ }
+ dev_handle = MODS_ACPI_HANDLE(&dev->dev);
+ }
+ if (!dev_handle) {
+ mods_debug_printk(DEBUG_ACPI,
+ "ACPI: handle for _DDC not found\n");
+ return -EINVAL;
+ }
+ status = acpi_bus_get_device(dev_handle, &device);
+
+ if (ACPI_FAILURE(status) || !device) {
+ mods_error_printk("ACPI: device for _DDC not found\n");
+ return -EINVAL;
+ }
+
+ list_for_each_safe(node, next, &device->children) {
+#ifdef MODS_ACPI_DEVID_64
+ unsigned long long
+#else
+ unsigned long
+#endif
+ device_id = 0;
+
+ struct acpi_device *dev =
+ list_entry(node, struct acpi_device, node);
+
+ if (!dev)
+ continue;
+
+ status = acpi_evaluate_integer(dev->handle,
+ "_ADR",
+ NULL,
+ &device_id);
+ if (ACPI_FAILURE(status))
+ /* Couldnt query device_id for this device */
+ continue;
+
+ device_id = (device_id & 0xffff);
+
+ if ((device_id == 0x0110) || /* Only for an LCD*/
+ (device_id == 0x0118) ||
+ (device_id == 0x0400)) {
+
+ lcd_dev_handle = dev->handle;
+ mods_debug_printk(DEBUG_ACPI,
+ "ACPI: Found LCD 0x%x on device %04x:%x:%02x.%x\n",
+ (unsigned int)device_id,
+ (unsigned int)p->device.domain,
+ (unsigned int)p->device.bus,
+ (unsigned int)p->device.device,
+ (unsigned int)p->device.function);
+ break;
+ }
+
+ }
+
+ if (lcd_dev_handle == NULL) {
+ mods_error_printk(
+ "ACPI: LCD not found for device %04x:%x:%02x.%x\n",
+ (unsigned int)p->device.domain,
+ (unsigned int)p->device.bus,
+ (unsigned int)p->device.device,
+ (unsigned int)p->device.function);
+ return -EINVAL;
+ }
+
+ /*
+ * As per ACPI Spec 3.0:
+ * ARG0 = 0x1 for 128 bytes EDID buffer
+ * ARG0 = 0x2 for 256 bytes EDID buffer
+ */
+ for (i = 1; i <= 2; i++) {
+ ddc_arg0.integer.value = i;
+ status = acpi_evaluate_object(lcd_dev_handle,
+ "_DDC",
+ &input,
+ &output);
+ if (ACPI_SUCCESS(status))
+ break;
+ }
+
+ if (ACPI_FAILURE(status)) {
+ mods_error_printk("ACPI method _DDC (EDID) failed\n");
+ return -EINVAL;
+ }
+
+ ddc = output.pointer;
+ if (ddc && (ddc->type == ACPI_TYPE_BUFFER)
+ && (ddc->buffer.length > 0)) {
+
+ if (ddc->buffer.length <= sizeof(p->out_buffer)) {
+ p->out_data_size = ddc->buffer.length;
+ memcpy(p->out_buffer,
+ ddc->buffer.pointer,
+ p->out_data_size);
+ } else {
+ mods_error_printk(
+ "output buffer too small for ACPI method _DDC (EDID)\n");
+ kfree(output.pointer);
+ return -EINVAL;
+ }
+ } else {
+ mods_error_printk("unsupported ACPI output type\n");
+ kfree(output.pointer);
+ return -EINVAL;
+ }
+
+ kfree(output.pointer);
+ return OK;
+}
+
+/*************************
+ * ESCAPE CALL FUNCTIONS *
+ *************************/
+
+int esc_mods_eval_acpi_method(struct file *pfile,
+ struct MODS_EVAL_ACPI_METHOD *p)
+{
+ return mods_eval_acpi_method(pfile, p, 0);
+}
+
+int esc_mods_eval_dev_acpi_method_2(struct file *pfile,
+ struct MODS_EVAL_DEV_ACPI_METHOD_2 *p)
+{
+ return mods_eval_acpi_method(pfile, &p->method, &p->device);
+}
+
+int esc_mods_eval_dev_acpi_method(struct file *pfile,
+ struct MODS_EVAL_DEV_ACPI_METHOD *p)
+{
+ struct mods_pci_dev_2 device = {0};
+
+ device.domain = 0;
+ device.bus = p->device.bus;
+ device.device = p->device.device;
+ device.function = p->device.function;
+ return mods_eval_acpi_method(pfile, &p->method, &device);
+}
+
+int esc_mods_acpi_get_ddc_2(struct file *pfile,
+ struct MODS_ACPI_GET_DDC_2 *p)
+{
+ return mods_acpi_get_ddc(pfile, p, &p->device);
+}
+
+int esc_mods_acpi_get_ddc(struct file *pfile, struct MODS_ACPI_GET_DDC *p)
+{
+ struct MODS_ACPI_GET_DDC_2 *pp = (struct MODS_ACPI_GET_DDC_2 *) p;
+ struct mods_pci_dev_2 device = {0};
+
+ device.domain = 0;
+ device.bus = p->device.bus;
+ device.device = p->device.device;
+ device.function = p->device.function;
+
+ return mods_acpi_get_ddc(pfile, pp, &device);
+}
diff --git a/drivers/misc/mods/mods_adsp.c b/drivers/misc/mods/mods_adsp.c
new file mode 100644
index 00000000..244dcc05
--- /dev/null
+++ b/drivers/misc/mods/mods_adsp.c
@@ -0,0 +1,95 @@
+/*
+ * mods_adsp.c - This file is part of NVIDIA MODS kernel driver.
+ *
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA MODS kernel driver 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.
+ *
+ * NVIDIA MODS kernel driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NVIDIA MODS kernel driver.
+ * If not, see .
+ */
+
+#include
+#include "mods_internal.h"
+#include
+
+int esc_mods_adsp_load(struct file *pfile)
+{
+ return nvadsp_os_load();
+}
+
+int esc_mods_adsp_start(struct file *pfile)
+{
+ return nvadsp_os_start();
+}
+
+int esc_mods_adsp_stop(struct file *pfile)
+{
+ nvadsp_os_stop();
+ return OK;
+}
+
+int esc_mods_adsp_run_app(struct file *pfile, struct MODS_ADSP_RUN_APP_INFO *p)
+{
+ int rc = -1;
+ int max_retry = 3;
+ int rcount = 0;
+ nvadsp_app_handle_t handle;
+ nvadsp_app_info_t *p_app_info;
+ nvadsp_app_args_t app_args;
+
+ handle = nvadsp_app_load(p->app_name, p->app_file_name);
+ if (!handle) {
+ mods_error_printk("load adsp app fail");
+ return -1;
+ }
+
+ if (p->argc > 0 && p->argc <= MODS_ADSP_APP_MAX_PARAM) {
+ app_args.argc = p->argc;
+ memcpy(app_args.argv, p->argv, p->argc * sizeof(__u32));
+ p_app_info = nvadsp_app_init(handle, &app_args);
+ } else
+ p_app_info = nvadsp_app_init(handle, NULL);
+
+ if (!p_app_info) {
+ mods_error_printk("init adsp app fail");
+ nvadsp_app_unload(handle);
+ return -1;
+ }
+
+ rc = nvadsp_app_start(p_app_info);
+ if (rc) {
+ mods_error_printk("start adsp app fail");
+ goto failed;
+ }
+
+ while (rcount++ < max_retry) {
+ rc = wait_for_nvadsp_app_complete_timeout(p_app_info,
+ msecs_to_jiffies(p->timeout));
+ if (rc == -ERESTARTSYS)
+ continue;
+ else if (rc == 0) {
+ mods_error_printk("app timeout(%d)", p->timeout);
+ rc = -1;
+ } else if (rc < 0) {
+ mods_error_printk("run app failed, err=%d\n", rc);
+ rc = -1;
+ } else
+ rc = 0;
+ break;
+ }
+
+failed:
+ nvadsp_app_deinit(p_app_info);
+ nvadsp_app_unload(handle);
+
+ return rc;
+}
diff --git a/drivers/misc/mods/mods_clock.c b/drivers/misc/mods/mods_clock.c
new file mode 100644
index 00000000..09101719
--- /dev/null
+++ b/drivers/misc/mods/mods_clock.c
@@ -0,0 +1,621 @@
+/*
+ * mods_clock.c - This file is part of NVIDIA MODS kernel driver.
+ *
+ * Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA MODS kernel driver 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.
+ *
+ * NVIDIA MODS kernel driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NVIDIA MODS kernel driver.
+ * If not, see .
+ */
+
+#include "mods_internal.h"
+#include
+#include
+#if defined(CONFIG_TEGRA_CLK_FRAMEWORK)
+ #include
+#elif defined(CONFIG_COMMON_CLK) && defined(CONFIG_OF_RESOLVE) && \
+defined(CONFIG_OF_DYNAMIC)
+ #define MODS_COMMON_CLK 1
+#endif
+#if defined(MODS_COMMON_CLK)
+ #include
+ #include
+ #include
+ #include
+ #include
+ #define ARBITRARY_MAX_CLK_FREQ 3500000000
+#endif
+
+static struct list_head mods_clock_handles;
+static spinlock_t mods_clock_lock;
+static u32 last_handle;
+
+struct clock_entry {
+ struct clk *pclk;
+ u32 handle;
+ struct list_head list;
+};
+
+#if defined(MODS_COMMON_CLK)
+static struct device_node *find_clocks_node(const char *name)
+{
+ const char *node_name = "mods-simple-bus";
+ struct device_node *pp = NULL, *np = NULL;
+
+ pp = of_find_node_by_name(NULL, node_name);
+
+ if (!pp) {
+ mods_error_printk("'mods-simple-bus' node not found in device tree\n");
+ return pp;
+ }
+
+ np = of_get_child_by_name(pp, name);
+ return np;
+}
+#endif
+
+void mods_init_clock_api(void)
+{
+#if defined(MODS_COMMON_CLK)
+ const char *okay_value = "okay";
+ struct device_node *mods_np = 0;
+ struct property *pp = 0;
+ int size_value = 0;
+
+ mods_np = find_clocks_node("mods-clocks");
+ if (!mods_np) {
+ mods_error_printk("'mods-clocks' node not found in device tree\n");
+ goto err;
+ }
+
+ pp = of_find_property(mods_np, "status", NULL);
+ if (IS_ERR(pp)) {
+ mods_error_printk("'status' prop not found in 'mods-clocks' node.");
+ goto err;
+ }
+
+ /* if status is 'okay', then skip updating property */
+ if (of_device_is_available(mods_np))
+ goto err;
+
+ size_value = strlen(okay_value) + 1;
+ pp->value = kmalloc(size_value, GFP_KERNEL);
+ strncpy(pp->value, okay_value, size_value);
+ pp->length = size_value;
+
+err:
+ of_node_put(mods_np);
+#endif
+
+ spin_lock_init(&mods_clock_lock);
+ INIT_LIST_HEAD(&mods_clock_handles);
+ last_handle = 0;
+}
+
+void mods_shutdown_clock_api(void)
+{
+ struct list_head *head = &mods_clock_handles;
+ struct list_head *iter;
+ struct list_head *tmp;
+
+ spin_lock(&mods_clock_lock);
+
+ list_for_each_safe(iter, tmp, head) {
+ struct clock_entry *entry
+ = list_entry(iter, struct clock_entry, list);
+ list_del(iter);
+ kfree(entry);
+ }
+
+ spin_unlock(&mods_clock_lock);
+}
+
+static u32 mods_get_clock_handle(struct clk *pclk)
+{
+ struct list_head *head = &mods_clock_handles;
+ struct list_head *iter;
+ struct clock_entry *entry = 0;
+ u32 handle = 0;
+
+ spin_lock(&mods_clock_lock);
+
+ list_for_each(iter, head) {
+ struct clock_entry *cur
+ = list_entry(iter, struct clock_entry, list);
+ if (cur->pclk == pclk) {
+ entry = cur;
+ handle = cur->handle;
+ break;
+ }
+ }
+
+ if (!entry) {
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!unlikely(!entry)) {
+ entry->pclk = pclk;
+ entry->handle = ++last_handle;
+ handle = entry->handle;
+ list_add(&entry->list, &mods_clock_handles);
+ }
+ }
+
+ spin_unlock(&mods_clock_lock);
+
+ return handle;
+}
+
+static struct clk *mods_get_clock(u32 handle)
+{
+ struct list_head *head = &mods_clock_handles;
+ struct list_head *iter;
+ struct clk *pclk = 0;
+
+ spin_lock(&mods_clock_lock);
+
+ list_for_each(iter, head) {
+ struct clock_entry *entry
+ = list_entry(iter, struct clock_entry, list);
+ if (entry->handle == handle) {
+ pclk = entry->pclk;
+ break;
+ }
+ }
+
+ spin_unlock(&mods_clock_lock);
+
+ return pclk;
+}
+
+int esc_mods_get_clock_handle(struct file *pfile,
+ struct MODS_GET_CLOCK_HANDLE *p)
+{
+ struct clk *pclk = 0;
+ int ret = -EINVAL;
+
+#if defined(CONFIG_TEGRA_CLK_FRAMEWORK)
+ LOG_ENT();
+
+ p->device_name[sizeof(p->device_name)-1] = 0;
+ p->controller_name[sizeof(p->controller_name)-1] = 0;
+ pclk = clk_get_sys(p->device_name, p->controller_name);
+
+ if (IS_ERR(pclk)) {
+ mods_error_printk("invalid clock specified: dev=%s, ctx=%s\n",
+ p->device_name, p->controller_name);
+ } else {
+ p->clock_handle = mods_get_clock_handle(pclk);
+ ret = OK;
+ }
+#elif defined(MODS_COMMON_CLK)
+ struct device_node *mods_np = 0;
+ struct property *pp = 0;
+
+ LOG_ENT();
+
+ mods_np = find_clocks_node("mods-clocks");
+ if (!mods_np || !of_device_is_available(mods_np)) {
+ mods_error_printk("'mods-clocks' node not found in device tree\n");
+ goto err;
+ }
+ pp = of_find_property(mods_np, "clock-names", NULL);
+ if (IS_ERR(pp)) {
+ mods_error_printk(
+ "No 'clock-names' prop in 'mods-clocks' node for dev %s\n",
+ p->controller_name);
+ goto err;
+ }
+
+ pclk = of_clk_get_by_name(mods_np, p->controller_name);
+
+ if (IS_ERR(pclk))
+ mods_error_printk("clk (%s) not found\n", p->controller_name);
+ else {
+ p->clock_handle = mods_get_clock_handle(pclk);
+ ret = OK;
+ }
+err:
+ of_node_put(mods_np);
+#endif
+ LOG_EXT();
+ return ret;
+}
+
+int esc_mods_set_clock_rate(struct file *pfile, struct MODS_CLOCK_RATE *p)
+{
+ struct clk *pclk = 0;
+ int ret = -EINVAL;
+
+ LOG_ENT();
+
+ pclk = mods_get_clock(p->clock_handle);
+
+ if (!pclk) {
+ mods_error_printk("unrecognized clock handle: 0x%x\n",
+ p->clock_handle);
+ } else {
+ ret = clk_set_rate(pclk, p->clock_rate_hz);
+ if (ret) {
+ mods_error_printk(
+ "unable to set rate %lluHz on clock 0x%x\n",
+ p->clock_rate_hz, p->clock_handle);
+ } else {
+ mods_debug_printk(DEBUG_CLOCK,
+ "successfuly set rate %lluHz on clock 0x%x\n",
+ p->clock_rate_hz, p->clock_handle);
+ }
+ }
+
+ LOG_EXT();
+ return ret;
+}
+
+int esc_mods_get_clock_rate(struct file *pfile, struct MODS_CLOCK_RATE *p)
+{
+ struct clk *pclk = 0;
+ int ret = -EINVAL;
+
+ LOG_ENT();
+
+ pclk = mods_get_clock(p->clock_handle);
+
+ if (!pclk) {
+ mods_error_printk("unrecognized clock handle: 0x%x\n",
+ p->clock_handle);
+ } else {
+ p->clock_rate_hz = clk_get_rate(pclk);
+ mods_debug_printk(DEBUG_CLOCK, "clock 0x%x has rate %lluHz\n",
+ p->clock_handle, p->clock_rate_hz);
+ ret = OK;
+ }
+
+ LOG_EXT();
+ return ret;
+}
+
+int esc_mods_get_clock_max_rate(struct file *pfile, struct MODS_CLOCK_RATE *p)
+{
+ struct clk *pclk = 0;
+ int ret = -EINVAL;
+
+ LOG_ENT();
+ pclk = mods_get_clock(p->clock_handle);
+
+ if (!pclk) {
+ mods_error_printk("unrecognized clock handle: 0x%x\n",
+ p->clock_handle);
+#if defined(CONFIG_TEGRA_CLK_FRAMEWORK)
+ } else if (!pclk->ops || !pclk->ops->round_rate) {
+ mods_error_printk(
+ "unable to detect max rate for clock handle 0x%x\n",
+ p->clock_handle);
+ } else {
+ long rate = pclk->ops->round_rate(pclk, pclk->max_rate);
+
+ p->clock_rate_hz = rate < 0 ? pclk->max_rate
+ : (unsigned long)rate;
+#elif defined(MODS_COMMON_CLK)
+ } else {
+ long rate = clk_round_rate(pclk, ARBITRARY_MAX_CLK_FREQ);
+
+ p->clock_rate_hz = rate < 0 ? ARBITRARY_MAX_CLK_FREQ
+ : (unsigned long)rate;
+#endif
+ mods_debug_printk(DEBUG_CLOCK,
+ "clock 0x%x has max rate %lluHz\n",
+ p->clock_handle, p->clock_rate_hz);
+ ret = OK;
+ }
+
+ LOG_EXT();
+ return ret;
+}
+
+int esc_mods_set_clock_max_rate(struct file *pfile, struct MODS_CLOCK_RATE *p)
+{
+ struct clk *pclk = 0;
+ int ret = -EINVAL;
+
+ LOG_ENT();
+
+ pclk = mods_get_clock(p->clock_handle);
+
+ if (!pclk) {
+ mods_error_printk("unrecognized clock handle: 0x%x\n",
+ p->clock_handle);
+ } else {
+#if defined(CONFIG_TEGRA_CLOCK_DEBUG_FUNC)
+ ret = tegra_clk_set_max(pclk, p->clock_rate_hz);
+ if (ret) {
+ mods_error_printk(
+ "unable to override max clock rate %lluHz on clock 0x%x\n",
+ p->clock_rate_hz, p->clock_handle);
+ } else {
+ mods_debug_printk(DEBUG_CLOCK,
+ "successfuly set max rate %lluHz on clock 0x%x\n",
+ p->clock_rate_hz, p->clock_handle);
+ }
+#else
+ mods_error_printk("unable to override max clock rate\n");
+ mods_error_printk(
+ "reconfigure kernel with CONFIG_TEGRA_CLOCK_DEBUG_FUNC=y\n");
+ ret = -EINVAL;
+#endif
+ }
+
+ LOG_EXT();
+ return ret;
+}
+
+int esc_mods_set_clock_parent(struct file *pfile, struct MODS_CLOCK_PARENT *p)
+{
+ struct clk *pclk = 0;
+ struct clk *pparent = 0;
+ int ret = -EINVAL;
+
+ LOG_ENT();
+
+ pclk = mods_get_clock(p->clock_handle);
+ pparent = mods_get_clock(p->clock_parent_handle);
+
+ if (!pclk) {
+ mods_error_printk("unrecognized clock handle: 0x%x\n",
+ p->clock_handle);
+ } else if (!pparent) {
+ mods_error_printk("unrecognized parent clock handle: 0x%x\n",
+ p->clock_parent_handle);
+ } else {
+ ret = clk_set_parent(pclk, pparent);
+ if (ret) {
+ mods_error_printk(
+ "unable to make clock 0x%x parent of clock 0x%x\n",
+ p->clock_parent_handle, p->clock_handle);
+ } else {
+ mods_debug_printk(DEBUG_CLOCK,
+ "successfuly made clock 0x%x parent of clock 0x%x\n",
+ p->clock_parent_handle, p->clock_handle);
+ }
+ }
+
+ LOG_EXT();
+ return ret;
+}
+
+int esc_mods_get_clock_parent(struct file *pfile, struct MODS_CLOCK_PARENT *p)
+{
+ struct clk *pclk = 0;
+ int ret = -EINVAL;
+
+ LOG_ENT();
+
+ pclk = mods_get_clock(p->clock_handle);
+
+ if (!pclk) {
+ mods_error_printk("unrecognized clock handle: 0x%x\n",
+ p->clock_handle);
+ } else {
+ struct clk *pparent = clk_get_parent(pclk);
+
+ p->clock_parent_handle = mods_get_clock_handle(pparent);
+ mods_debug_printk(DEBUG_CLOCK,
+ "clock 0x%x is parent of clock 0x%x\n",
+ p->clock_parent_handle, p->clock_handle);
+ ret = OK;
+ }
+
+ LOG_EXT();
+ return ret;
+}
+
+int esc_mods_enable_clock(struct file *pfile, struct MODS_CLOCK_HANDLE *p)
+{
+ struct clk *pclk = 0;
+ int ret = -EINVAL;
+
+ LOG_ENT();
+
+ pclk = mods_get_clock(p->clock_handle);
+
+ if (!pclk) {
+ mods_error_printk("unrecognized clock handle: 0x%x\n",
+ p->clock_handle);
+ } else {
+#if defined(MODS_COMMON_CLK)
+ ret = clk_prepare(pclk);
+ if (ret) {
+ mods_error_printk(
+ "unable to prepare clock 0x%x before enabling\n",
+ p->clock_handle);
+ }
+#endif
+ ret = clk_enable(pclk);
+ if (ret) {
+ mods_error_printk("failed to enable clock 0x%x\n",
+ p->clock_handle);
+ } else {
+ mods_debug_printk(DEBUG_CLOCK, "clock 0x%x enabled\n",
+ p->clock_handle);
+ }
+ }
+
+ LOG_EXT();
+ return ret;
+}
+
+int esc_mods_disable_clock(struct file *pfile, struct MODS_CLOCK_HANDLE *p)
+{
+ struct clk *pclk = 0;
+ int ret = -EINVAL;
+
+ LOG_ENT();
+
+ pclk = mods_get_clock(p->clock_handle);
+
+ if (!pclk) {
+ mods_error_printk("unrecognized clock handle: 0x%x\n",
+ p->clock_handle);
+ } else {
+ clk_disable(pclk);
+#if defined(MODS_COMMON_CLK)
+ clk_unprepare(pclk);
+#endif
+ mods_debug_printk(DEBUG_CLOCK, "clock 0x%x disabled\n",
+ p->clock_handle);
+ ret = OK;
+ }
+
+ LOG_EXT();
+ return ret;
+}
+
+int esc_mods_is_clock_enabled(struct file *pfile, struct MODS_CLOCK_ENABLED *p)
+{
+ struct clk *pclk = 0;
+ int ret = -EINVAL;
+
+ LOG_ENT();
+
+ pclk = mods_get_clock(p->clock_handle);
+
+ if (!pclk) {
+ mods_error_printk("unrecognized clock handle: 0x%x\n",
+ p->clock_handle);
+ } else {
+#if defined(CONFIG_TEGRA_CLK_FRAMEWORK)
+ p->enable_count = pclk->refcnt;
+#elif defined(MODS_COMMON_CLK)
+ p->enable_count = (u32)__clk_is_enabled(pclk);
+#endif
+ mods_debug_printk(DEBUG_CLOCK, "clock 0x%x enable count is %u\n",
+ p->clock_handle, p->enable_count);
+ ret = OK;
+ }
+
+ LOG_EXT();
+ return ret;
+}
+
+int esc_mods_clock_reset_assert(struct file *pfile,
+ struct MODS_CLOCK_HANDLE *p)
+{
+ struct clk *pclk = 0;
+ int ret = -EINVAL;
+
+ LOG_ENT();
+
+ pclk = mods_get_clock(p->clock_handle);
+
+ if (!pclk) {
+ mods_error_printk("unrecognized clock handle: 0x%x\n",
+ p->clock_handle);
+ } else {
+#if defined(MODS_COMMON_CLK)
+ const char *clk_name = 0;
+ struct reset_control *prst = 0;
+ struct device_node *mods_np = 0;
+ struct property *pp = 0;
+
+ mods_np = find_clocks_node("mods-clocks");
+ if (!mods_np || !of_device_is_available(mods_np)) {
+ mods_error_printk("'mods-clocks' node not found in DTB\n");
+ goto err;
+ }
+ pp = of_find_property(mods_np, "reset-names", NULL);
+ if (IS_ERR(pp)) {
+ mods_error_printk(
+ "No 'reset-names' prop in 'mods-clocks' node for dev %s\n",
+ __clk_get_name(pclk));
+ goto err;
+ }
+
+ clk_name = __clk_get_name(pclk);
+
+ prst = of_reset_control_get(mods_np, clk_name);
+ if (IS_ERR(prst)) {
+ mods_error_printk("reset device %s not found\n",
+ clk_name);
+ goto err;
+ }
+ ret = reset_control_assert(prst);
+ if (ret) {
+ mods_error_printk("failed to assert reset on '%s'\n",
+ clk_name);
+ } else {
+ mods_debug_printk(DEBUG_CLOCK, "asserted reset on '%s'",
+ clk_name);
+ }
+
+err:
+ of_node_put(mods_np);
+#endif
+ }
+ LOG_EXT();
+ return ret;
+}
+
+int esc_mods_clock_reset_deassert(struct file *pfile,
+ struct MODS_CLOCK_HANDLE *p)
+{
+ struct clk *pclk = 0;
+ int ret = -EINVAL;
+
+ LOG_ENT();
+
+ pclk = mods_get_clock(p->clock_handle);
+
+ if (!pclk) {
+ mods_error_printk("unrecognized clock handle: 0x%x\n",
+ p->clock_handle);
+ } else {
+#if defined(MODS_COMMON_CLK)
+ const char *clk_name = 0;
+ struct reset_control *prst = 0;
+ struct device_node *mods_np = 0;
+ struct property *pp = 0;
+
+ mods_np = find_clocks_node("mods-clocks");
+ if (!mods_np || !of_device_is_available(mods_np)) {
+ mods_error_printk("'mods-clocks' node not found in DTB\n");
+ goto err;
+ }
+ pp = of_find_property(mods_np, "reset-names", NULL);
+ if (IS_ERR(pp)) {
+ mods_error_printk(
+ "No 'reset-names' prop in 'mods-clocks' node for dev %s\n",
+ __clk_get_name(pclk));
+ goto err;
+ }
+
+ clk_name = __clk_get_name(pclk);
+
+ prst = of_reset_control_get(mods_np, clk_name);
+ if (IS_ERR(prst)) {
+ mods_error_printk(
+ "reset device %s not found\n", clk_name);
+ goto err;
+ }
+ ret = reset_control_deassert(prst);
+ if (ret) {
+ mods_error_printk("failed to assert reset on '%s'\n",
+ clk_name);
+ } else {
+ mods_debug_printk(DEBUG_CLOCK, "deasserted reset on '%s'",
+ clk_name);
+ }
+
+err:
+ of_node_put(mods_np);
+#endif
+ }
+
+ LOG_EXT();
+ return ret;
+}
diff --git a/drivers/misc/mods/mods_config.h b/drivers/misc/mods/mods_config.h
new file mode 100644
index 00000000..3978af12
--- /dev/null
+++ b/drivers/misc/mods/mods_config.h
@@ -0,0 +1,63 @@
+/*
+ * mods_config.h - This file is part of NVIDIA MODS kernel driver.
+ *
+ * Copyright (c) 2008-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA MODS kernel driver 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.
+ *
+ * NVIDIA MODS kernel driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NVIDIA MODS kernel driver.
+ * If not, see .
+ */
+
+#ifndef _MODS_CONFIG_H_
+#define _MODS_CONFIG_H_
+
+#define MODS_KERNEL_VERSION KERNEL_VERSION(3, 18, 0)
+
+#define MODS_IRQ_HANDLE_NO_REGS 1
+#define MODS_HAS_SET_MEMORY 1
+#define MODS_ACPI_DEVID_64 1
+#define MODS_HAS_WC 1
+#define MODS_HAS_DEV_TO_NUMA_NODE 1
+#define MODS_HAS_NEW_ACPI_WALK 1
+#ifdef CONFIG_DEBUG_FS
+#define MODS_HAS_DEBUGFS 1
+#endif
+#if defined(CONFIG_TEGRA_KFUSE)
+#define MODS_HAS_KFUSE 1
+#endif
+#ifdef CONFIG_DMA_SHARED_BUFFER
+#define MODS_HAS_DMABUF 1
+#endif
+#define MODS_MULTI_INSTANCE_DEFAULT_VALUE 1
+#define MODS_HAS_IORESOURCE_MEM_64 1
+#undef MODS_HAS_NEW_ACPI_HANDLE /* new in 3.13 */
+#if defined(CONFIG_ARCH_TEGRA)
+#define MODS_TEGRA 1
+#endif
+#if defined(CONFIG_TEGRA_CLK_FRAMEWORK) || \
+ (defined(CONFIG_COMMON_CLK) && defined(CONFIG_OF_RESOLVE) && \
+ defined(CONFIG_OF_DYNAMIC))
+#define MODS_HAS_CLOCK 1
+#endif
+#ifdef CONFIG_NET
+#define MODS_HAS_NET 1
+#endif
+#ifdef CONFIG_ZONE_DMA32
+#define MODS_HAS_DMA32 1
+#endif
+#ifdef CONFIG_PCI
+#define MODS_CAN_REGISTER_PCI_DEV 1
+#endif
+
+#endif /* _MODS_CONFIG_H_ */
+
+/* vim: set ts=8 sw=8 noet: */
diff --git a/drivers/misc/mods/mods_debugfs.c b/drivers/misc/mods/mods_debugfs.c
new file mode 100644
index 00000000..50f484d7
--- /dev/null
+++ b/drivers/misc/mods/mods_debugfs.c
@@ -0,0 +1,807 @@
+/*
+ * mods_debugfs.c - This file is part of NVIDIA MODS kernel driver.
+ *
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA MODS kernel driver 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.
+ *
+ * NVIDIA MODS kernel driver is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with NVIDIA MODS kernel driver.
+ * If not, see .
+ */
+
+#include "mods_internal.h"
+
+#ifdef MODS_HAS_DEBUGFS
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+static struct dentry *mods_debugfs_dir;
+
+#if defined(MODS_TEGRA) && defined(MODS_HAS_KFUSE)
+#include
+#endif
+
+#ifdef CONFIG_TEGRA_DC
+#include