]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-4.10/firmware' into for-4.10/reset
authorThierry Reding <treding@nvidia.com>
Fri, 18 Nov 2016 13:34:46 +0000 (14:34 +0100)
committerThierry Reding <treding@nvidia.com>
Fri, 18 Nov 2016 13:34:46 +0000 (14:34 +0100)
19 files changed:
Documentation/devicetree/bindings/firmware/nvidia,tegra186-bpmp.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt [new file with mode: 0644]
drivers/firmware/Kconfig
drivers/firmware/Makefile
drivers/firmware/tegra/Kconfig [new file with mode: 0644]
drivers/firmware/tegra/Makefile [new file with mode: 0644]
drivers/firmware/tegra/bpmp.c [new file with mode: 0644]
drivers/firmware/tegra/ivc.c [new file with mode: 0644]
drivers/mailbox/Kconfig
drivers/mailbox/Makefile
drivers/mailbox/tegra-hsp.c [new file with mode: 0644]
drivers/soc/tegra/Kconfig
include/dt-bindings/clock/tegra186-clock.h [new file with mode: 0644]
include/dt-bindings/mailbox/tegra186-hsp.h [new file with mode: 0644]
include/dt-bindings/power/tegra186-powergate.h [new file with mode: 0644]
include/dt-bindings/reset/tegra186-reset.h [new file with mode: 0644]
include/soc/tegra/bpmp-abi.h [new file with mode: 0644]
include/soc/tegra/bpmp.h [new file with mode: 0644]
include/soc/tegra/ivc.h [new file with mode: 0644]

diff --git a/Documentation/devicetree/bindings/firmware/nvidia,tegra186-bpmp.txt b/Documentation/devicetree/bindings/firmware/nvidia,tegra186-bpmp.txt
new file mode 100644 (file)
index 0000000..e821e16
--- /dev/null
@@ -0,0 +1,108 @@
+NVIDIA Tegra Boot and Power Management Processor (BPMP)
+
+The BPMP is a specific processor in Tegra chip, which is designed for
+booting process handling and offloading the power management, clock
+management, and reset control tasks from the CPU. The binding document
+defines the resources that would be used by the BPMP firmware driver,
+which can create the interprocessor communication (IPC) between the CPU
+and BPMP.
+
+Required properties:
+- name : Should be bpmp
+- compatible
+    Array of strings
+    One of:
+    - "nvidia,tegra186-bpmp"
+- mboxes : The phandle of mailbox controller and the mailbox specifier.
+- shmem : List of the phandle of the TX and RX shared memory area that
+         the IPC between CPU and BPMP is based on.
+- #clock-cells : Should be 1.
+- #power-domain-cells : Should be 1.
+- #reset-cells : Should be 1.
+
+This node is a mailbox consumer. See the following files for details of
+the mailbox subsystem, and the specifiers implemented by the relevant
+provider(s):
+
+- .../mailbox/mailbox.txt
+- .../mailbox/nvidia,tegra186-hsp.txt
+
+This node is a clock, power domain, and reset provider. See the following
+files for general documentation of those features, and the specifiers
+implemented by this node:
+
+- .../clock/clock-bindings.txt
+- <dt-bindings/clock/tegra186-clock.h>
+- ../power/power_domain.txt
+- <dt-bindings/power/tegra186-powergate.h>
+- .../reset/reset.txt
+- <dt-bindings/reset/tegra186-reset.h>
+
+The BPMP implements some services which must be represented by separate nodes.
+For example, it can provide access to certain I2C controllers, and the I2C
+bindings represent each I2C controller as a device tree node. Such nodes should
+be nested directly inside the main BPMP node.
+
+Software can determine whether a child node of the BPMP node represents a device
+by checking for a compatible property. Any node with a compatible property
+represents a device that can be instantiated. Nodes without a compatible
+property may be used to provide configuration information regarding the BPMP
+itself, although no such configuration nodes are currently defined by this
+binding.
+
+The BPMP firmware defines no single global name-/numbering-space for such
+services. Put another way, the numbering scheme for I2C buses is distinct from
+the numbering scheme for any other service the BPMP may provide (e.g. a future
+hypothetical SPI bus service). As such, child device nodes will have no reg
+property, and the BPMP node will have no #address-cells or #size-cells property.
+
+The shared memory bindings for BPMP
+-----------------------------------
+
+The shared memory area for the IPC TX and RX between CPU and BPMP are
+predefined and work on top of sysram, which is an SRAM inside the chip.
+
+See ".../sram/sram.txt" for the bindings.
+
+Example:
+
+hsp_top0: hsp@03c00000 {
+       ...
+       #mbox-cells = <2>;
+};
+
+sysram@30000000 {
+       compatible = "nvidia,tegra186-sysram", "mmio-sram";
+       reg = <0x0 0x30000000 0x0 0x50000>;
+       #address-cells = <2>;
+       #size-cells = <2>;
+       ranges = <0 0x0 0x0 0x30000000 0x0 0x50000>;
+
+       cpu_bpmp_tx: shmem@4e000 {
+               compatible = "nvidia,tegra186-bpmp-shmem";
+               reg = <0x0 0x4e000 0x0 0x1000>;
+               label = "cpu-bpmp-tx";
+               pool;
+       };
+
+       cpu_bpmp_rx: shmem@4f000 {
+               compatible = "nvidia,tegra186-bpmp-shmem";
+               reg = <0x0 0x4f000 0x0 0x1000>;
+               label = "cpu-bpmp-rx";
+               pool;
+       };
+};
+
+bpmp {
+       compatible = "nvidia,tegra186-bpmp";
+       mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_DB TEGRA_HSP_DB_MASTER_BPMP>;
+       shmem = <&cpu_bpmp_tx &cpu_bpmp_rx>;
+       #clock-cells = <1>;
+       #power-domain-cells = <1>;
+       #reset-cells = <1>;
+
+       i2c {
+               compatible = "...";
+               ...
+       };
+};
diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt
new file mode 100644 (file)
index 0000000..b99d25f
--- /dev/null
@@ -0,0 +1,52 @@
+NVIDIA Tegra Hardware Synchronization Primitives (HSP)
+
+The HSP modules are used for the processors to share resources and communicate
+together. It provides a set of hardware synchronization primitives for
+interprocessor communication. So the interprocessor communication (IPC)
+protocols can use hardware synchronization primitives, when operating between
+two processors not in an SMP relationship.
+
+The features that HSP supported are shared mailboxes, shared semaphores,
+arbitrated semaphores and doorbells.
+
+Required properties:
+- name : Should be hsp
+- compatible
+    Array of strings.
+    one of:
+    - "nvidia,tegra186-hsp"
+- reg : Offset and length of the register set for the device.
+- interrupt-names
+    Array of strings.
+    Contains a list of names for the interrupts described by the interrupt
+    property. May contain the following entries, in any order:
+    - "doorbell"
+    Users of this binding MUST look up entries in the interrupt property
+    by name, using this interrupt-names property to do so.
+- interrupts
+    Array of interrupt specifiers.
+    Must contain one entry per entry in the interrupt-names property,
+    in a matching order.
+- #mbox-cells : Should be 2.
+
+The mbox specifier of the "mboxes" property in the client node should
+contain two data. The first one should be the HSP type and the second
+one should be the ID that the client is going to use. Those information
+can be found in the following file.
+
+- <dt-bindings/mailbox/tegra186-hsp.h>.
+
+Example:
+
+hsp_top0: hsp@3c00000 {
+       compatible = "nvidia,tegra186-hsp";
+       reg = <0x0 0x03c00000 0x0 0xa0000>;
+       interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>;
+       interrupt-names = "doorbell";
+       #mbox-cells = <2>;
+};
+
+client {
+       ...
+       mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_DB TEGRA_HSP_DB_MASTER_XXX>;
+};
index bca172d42c7438f94a870c899f0b27f1421dd7ba..9968de04d1d5690c272f620b42d898a0259a96a4 100644 (file)
@@ -210,5 +210,6 @@ source "drivers/firmware/broadcom/Kconfig"
 source "drivers/firmware/google/Kconfig"
 source "drivers/firmware/efi/Kconfig"
 source "drivers/firmware/meson/Kconfig"
+source "drivers/firmware/tegra/Kconfig"
 
 endmenu
index 898ac41fa8b352ea86886b910796925524e46b77..2afe75c52ac2d95cfdad805216769f2a266e11a0 100644 (file)
@@ -26,3 +26,4 @@ obj-y                         += meson/
 obj-$(CONFIG_GOOGLE_FIRMWARE)  += google/
 obj-$(CONFIG_EFI)              += efi/
 obj-$(CONFIG_UEFI_CPER)                += efi/
+obj-y                          += tegra/
diff --git a/drivers/firmware/tegra/Kconfig b/drivers/firmware/tegra/Kconfig
new file mode 100644 (file)
index 0000000..ff2730d
--- /dev/null
@@ -0,0 +1,25 @@
+menu "Tegra firmware driver"
+
+config TEGRA_IVC
+       bool "Tegra IVC protocol"
+       depends on ARCH_TEGRA
+       help
+         IVC (Inter-VM Communication) protocol is part of the IPC
+         (Inter Processor Communication) framework on Tegra. It maintains the
+         data and the different commuication channels in SysRAM or RAM and
+         keeps the content is synchronization between host CPU and remote
+         processors.
+
+config TEGRA_BPMP
+       bool "Tegra BPMP driver"
+       depends on ARCH_TEGRA && TEGRA_HSP_MBOX && TEGRA_IVC
+       help
+         BPMP (Boot and Power Management Processor) is designed to off-loading
+         the PM functions which include clock/DVFS/thermal/power from the CPU.
+         It needs HSP as the HW synchronization and notification module and
+         IVC module as the message communication protocol.
+
+         This driver manages the IPC interface between host CPU and the
+         firmware running on BPMP.
+
+endmenu
diff --git a/drivers/firmware/tegra/Makefile b/drivers/firmware/tegra/Makefile
new file mode 100644 (file)
index 0000000..e34a2f7
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_TEGRA_BPMP)       += bpmp.o
+obj-$(CONFIG_TEGRA_IVC)                += ivc.o
diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c
new file mode 100644 (file)
index 0000000..4ff02d3
--- /dev/null
@@ -0,0 +1,868 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+#include <linux/clk/tegra.h>
+#include <linux/genalloc.h>
+#include <linux/mailbox_client.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/semaphore.h>
+
+#include <soc/tegra/bpmp.h>
+#include <soc/tegra/bpmp-abi.h>
+#include <soc/tegra/ivc.h>
+
+#define MSG_ACK                BIT(0)
+#define MSG_RING       BIT(1)
+
+static inline struct tegra_bpmp *
+mbox_client_to_bpmp(struct mbox_client *client)
+{
+       return container_of(client, struct tegra_bpmp, mbox.client);
+}
+
+struct tegra_bpmp *tegra_bpmp_get(struct device *dev)
+{
+       struct platform_device *pdev;
+       struct tegra_bpmp *bpmp;
+       struct device_node *np;
+
+       np = of_parse_phandle(dev->of_node, "nvidia,bpmp", 0);
+       if (!np)
+               return ERR_PTR(-ENOENT);
+
+       pdev = of_find_device_by_node(np);
+       if (!pdev) {
+               bpmp = ERR_PTR(-ENODEV);
+               goto put;
+       }
+
+       bpmp = platform_get_drvdata(pdev);
+       if (!bpmp) {
+               bpmp = ERR_PTR(-EPROBE_DEFER);
+               put_device(&pdev->dev);
+               goto put;
+       }
+
+put:
+       of_node_put(np);
+       return bpmp;
+}
+EXPORT_SYMBOL_GPL(tegra_bpmp_get);
+
+void tegra_bpmp_put(struct tegra_bpmp *bpmp)
+{
+       if (bpmp)
+               put_device(bpmp->dev);
+}
+EXPORT_SYMBOL_GPL(tegra_bpmp_put);
+
+static int tegra_bpmp_channel_get_index(struct tegra_bpmp_channel *channel)
+{
+       return channel - channel->bpmp->channels;
+}
+
+static int
+tegra_bpmp_channel_get_thread_index(struct tegra_bpmp_channel *channel)
+{
+       struct tegra_bpmp *bpmp = channel->bpmp;
+       unsigned int offset, count;
+       int index;
+
+       offset = bpmp->soc->channels.thread.offset;
+       count = bpmp->soc->channels.thread.count;
+
+       index = tegra_bpmp_channel_get_index(channel);
+       if (index < 0)
+               return index;
+
+       if (index < offset || index >= offset + count)
+               return -EINVAL;
+
+       return index - offset;
+}
+
+static struct tegra_bpmp_channel *
+tegra_bpmp_channel_get_thread(struct tegra_bpmp *bpmp, unsigned int index)
+{
+       unsigned int offset = bpmp->soc->channels.thread.offset;
+       unsigned int count = bpmp->soc->channels.thread.count;
+
+       if (index >= count)
+               return NULL;
+
+       return &bpmp->channels[offset + index];
+}
+
+static struct tegra_bpmp_channel *
+tegra_bpmp_channel_get_tx(struct tegra_bpmp *bpmp)
+{
+       unsigned int offset = bpmp->soc->channels.cpu_tx.offset;
+
+       return &bpmp->channels[offset + smp_processor_id()];
+}
+
+static struct tegra_bpmp_channel *
+tegra_bpmp_channel_get_rx(struct tegra_bpmp *bpmp)
+{
+       unsigned int offset = bpmp->soc->channels.cpu_rx.offset;
+
+       return &bpmp->channels[offset];
+}
+
+static bool tegra_bpmp_message_valid(const struct tegra_bpmp_message *msg)
+{
+       return (msg->tx.size <= MSG_DATA_MIN_SZ) &&
+              (msg->rx.size <= MSG_DATA_MIN_SZ) &&
+              (msg->tx.size == 0 || msg->tx.data) &&
+              (msg->rx.size == 0 || msg->rx.data);
+}
+
+static bool tegra_bpmp_master_acked(struct tegra_bpmp_channel *channel)
+{
+       void *frame;
+
+       frame = tegra_ivc_read_get_next_frame(channel->ivc);
+       if (IS_ERR(frame)) {
+               channel->ib = NULL;
+               return false;
+       }
+
+       channel->ib = frame;
+
+       return true;
+}
+
+static int tegra_bpmp_wait_ack(struct tegra_bpmp_channel *channel)
+{
+       unsigned long timeout = channel->bpmp->soc->channels.cpu_tx.timeout;
+       ktime_t end;
+
+       end = ktime_add_us(ktime_get(), timeout);
+
+       do {
+               if (tegra_bpmp_master_acked(channel))
+                       return 0;
+       } while (ktime_before(ktime_get(), end));
+
+       return -ETIMEDOUT;
+}
+
+static bool tegra_bpmp_master_free(struct tegra_bpmp_channel *channel)
+{
+       void *frame;
+
+       frame = tegra_ivc_write_get_next_frame(channel->ivc);
+       if (IS_ERR(frame)) {
+               channel->ob = NULL;
+               return false;
+       }
+
+       channel->ob = frame;
+
+       return true;
+}
+
+static int tegra_bpmp_wait_master_free(struct tegra_bpmp_channel *channel)
+{
+       unsigned long timeout = channel->bpmp->soc->channels.cpu_tx.timeout;
+       ktime_t start, now;
+
+       start = ns_to_ktime(local_clock());
+
+       do {
+               if (tegra_bpmp_master_free(channel))
+                       return 0;
+
+               now = ns_to_ktime(local_clock());
+       } while (ktime_us_delta(now, start) < timeout);
+
+       return -ETIMEDOUT;
+}
+
+static ssize_t __tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel,
+                                        void *data, size_t size)
+{
+       if (data && size > 0)
+               memcpy(data, channel->ib->data, size);
+
+       return tegra_ivc_read_advance(channel->ivc);
+}
+
+static ssize_t tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel,
+                                      void *data, size_t size)
+{
+       struct tegra_bpmp *bpmp = channel->bpmp;
+       unsigned long flags;
+       ssize_t err;
+       int index;
+
+       index = tegra_bpmp_channel_get_thread_index(channel);
+       if (index < 0)
+               return index;
+
+       spin_lock_irqsave(&bpmp->lock, flags);
+       err = __tegra_bpmp_channel_read(channel, data, size);
+       clear_bit(index, bpmp->threaded.allocated);
+       spin_unlock_irqrestore(&bpmp->lock, flags);
+
+       up(&bpmp->threaded.lock);
+
+       return err;
+}
+
+static ssize_t __tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel,
+                                         unsigned int mrq, unsigned long flags,
+                                         const void *data, size_t size)
+{
+       channel->ob->code = mrq;
+       channel->ob->flags = flags;
+
+       if (data && size > 0)
+               memcpy(channel->ob->data, data, size);
+
+       return tegra_ivc_write_advance(channel->ivc);
+}
+
+static struct tegra_bpmp_channel *
+tegra_bpmp_write_threaded(struct tegra_bpmp *bpmp, unsigned int mrq,
+                         const void *data, size_t size)
+{
+       unsigned long timeout = bpmp->soc->channels.thread.timeout;
+       unsigned int count = bpmp->soc->channels.thread.count;
+       struct tegra_bpmp_channel *channel;
+       unsigned long flags;
+       unsigned int index;
+       int err;
+
+       err = down_timeout(&bpmp->threaded.lock, usecs_to_jiffies(timeout));
+       if (err < 0)
+               return ERR_PTR(err);
+
+       spin_lock_irqsave(&bpmp->lock, flags);
+
+       index = find_first_zero_bit(bpmp->threaded.allocated, count);
+       if (index == count) {
+               channel = ERR_PTR(-EBUSY);
+               goto unlock;
+       }
+
+       channel = tegra_bpmp_channel_get_thread(bpmp, index);
+       if (!channel) {
+               channel = ERR_PTR(-EINVAL);
+               goto unlock;
+       }
+
+       if (!tegra_bpmp_master_free(channel)) {
+               channel = ERR_PTR(-EBUSY);
+               goto unlock;
+       }
+
+       set_bit(index, bpmp->threaded.allocated);
+
+       err = __tegra_bpmp_channel_write(channel, mrq, MSG_ACK | MSG_RING,
+                                        data, size);
+       if (err < 0) {
+               clear_bit(index, bpmp->threaded.allocated);
+               goto unlock;
+       }
+
+       set_bit(index, bpmp->threaded.busy);
+
+unlock:
+       spin_unlock_irqrestore(&bpmp->lock, flags);
+       return channel;
+}
+
+static ssize_t tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel,
+                                       unsigned int mrq, unsigned long flags,
+                                       const void *data, size_t size)
+{
+       int err;
+
+       err = tegra_bpmp_wait_master_free(channel);
+       if (err < 0)
+               return err;
+
+       return __tegra_bpmp_channel_write(channel, mrq, flags, data, size);
+}
+
+int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp,
+                              struct tegra_bpmp_message *msg)
+{
+       struct tegra_bpmp_channel *channel;
+       int err;
+
+       if (WARN_ON(!irqs_disabled()))
+               return -EPERM;
+
+       if (!tegra_bpmp_message_valid(msg))
+               return -EINVAL;
+
+       channel = tegra_bpmp_channel_get_tx(bpmp);
+
+       err = tegra_bpmp_channel_write(channel, msg->mrq, MSG_ACK,
+                                      msg->tx.data, msg->tx.size);
+       if (err < 0)
+               return err;
+
+       err = mbox_send_message(bpmp->mbox.channel, NULL);
+       if (err < 0)
+               return err;
+
+       mbox_client_txdone(bpmp->mbox.channel, 0);
+
+       err = tegra_bpmp_wait_ack(channel);
+       if (err < 0)
+               return err;
+
+       return __tegra_bpmp_channel_read(channel, msg->rx.data, msg->rx.size);
+}
+EXPORT_SYMBOL_GPL(tegra_bpmp_transfer_atomic);
+
+int tegra_bpmp_transfer(struct tegra_bpmp *bpmp,
+                       struct tegra_bpmp_message *msg)
+{
+       struct tegra_bpmp_channel *channel;
+       unsigned long timeout;
+       int err;
+
+       if (WARN_ON(irqs_disabled()))
+               return -EPERM;
+
+       if (!tegra_bpmp_message_valid(msg))
+               return -EINVAL;
+
+       channel = tegra_bpmp_write_threaded(bpmp, msg->mrq, msg->tx.data,
+                                           msg->tx.size);
+       if (IS_ERR(channel))
+               return PTR_ERR(channel);
+
+       err = mbox_send_message(bpmp->mbox.channel, NULL);
+       if (err < 0)
+               return err;
+
+       mbox_client_txdone(bpmp->mbox.channel, 0);
+
+       timeout = usecs_to_jiffies(bpmp->soc->channels.thread.timeout);
+
+       err = wait_for_completion_timeout(&channel->completion, timeout);
+       if (err == 0)
+               return -ETIMEDOUT;
+
+       return tegra_bpmp_channel_read(channel, msg->rx.data, msg->rx.size);
+}
+EXPORT_SYMBOL_GPL(tegra_bpmp_transfer);
+
+static struct tegra_bpmp_mrq *tegra_bpmp_find_mrq(struct tegra_bpmp *bpmp,
+                                                 unsigned int mrq)
+{
+       struct tegra_bpmp_mrq *entry;
+
+       list_for_each_entry(entry, &bpmp->mrqs, list)
+               if (entry->mrq == mrq)
+                       return entry;
+
+       return NULL;
+}
+
+static void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel,
+                                 int code, const void *data, size_t size)
+{
+       unsigned long flags = channel->ib->flags;
+       struct tegra_bpmp *bpmp = channel->bpmp;
+       struct tegra_bpmp_mb_data *frame;
+       int err;
+
+       if (WARN_ON(size > MSG_DATA_MIN_SZ))
+               return;
+
+       err = tegra_ivc_read_advance(channel->ivc);
+       if (WARN_ON(err < 0))
+               return;
+
+       if ((flags & MSG_ACK) == 0)
+               return;
+
+       frame = tegra_ivc_write_get_next_frame(channel->ivc);
+       if (WARN_ON(IS_ERR(frame)))
+               return;
+
+       frame->code = code;
+
+       if (data && size > 0)
+               memcpy(frame->data, data, size);
+
+       err = tegra_ivc_write_advance(channel->ivc);
+       if (WARN_ON(err < 0))
+               return;
+
+       if (flags & MSG_RING) {
+               err = mbox_send_message(bpmp->mbox.channel, NULL);
+               if (WARN_ON(err < 0))
+                       return;
+
+               mbox_client_txdone(bpmp->mbox.channel, 0);
+       }
+}
+
+static void tegra_bpmp_handle_mrq(struct tegra_bpmp *bpmp,
+                                 unsigned int mrq,
+                                 struct tegra_bpmp_channel *channel)
+{
+       struct tegra_bpmp_mrq *entry;
+       u32 zero = 0;
+
+       spin_lock(&bpmp->lock);
+
+       entry = tegra_bpmp_find_mrq(bpmp, mrq);
+       if (!entry) {
+               spin_unlock(&bpmp->lock);
+               tegra_bpmp_mrq_return(channel, -EINVAL, &zero, sizeof(zero));
+               return;
+       }
+
+       entry->handler(mrq, channel, entry->data);
+
+       spin_unlock(&bpmp->lock);
+}
+
+int tegra_bpmp_request_mrq(struct tegra_bpmp *bpmp, unsigned int mrq,
+                          tegra_bpmp_mrq_handler_t handler, void *data)
+{
+       struct tegra_bpmp_mrq *entry;
+       unsigned long flags;
+
+       if (!handler)
+               return -EINVAL;
+
+       entry = devm_kzalloc(bpmp->dev, sizeof(*entry), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+
+       spin_lock_irqsave(&bpmp->lock, flags);
+
+       entry->mrq = mrq;
+       entry->handler = handler;
+       entry->data = data;
+       list_add(&entry->list, &bpmp->mrqs);
+
+       spin_unlock_irqrestore(&bpmp->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tegra_bpmp_request_mrq);
+
+void tegra_bpmp_free_mrq(struct tegra_bpmp *bpmp, unsigned int mrq, void *data)
+{
+       struct tegra_bpmp_mrq *entry;
+       unsigned long flags;
+
+       spin_lock_irqsave(&bpmp->lock, flags);
+
+       entry = tegra_bpmp_find_mrq(bpmp, mrq);
+       if (!entry)
+               goto unlock;
+
+       list_del(&entry->list);
+       devm_kfree(bpmp->dev, entry);
+
+unlock:
+       spin_unlock_irqrestore(&bpmp->lock, flags);
+}
+EXPORT_SYMBOL_GPL(tegra_bpmp_free_mrq);
+
+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;
+
+       request = (struct mrq_ping_request *)channel->ib->data;
+
+       memset(&response, 0, sizeof(response));
+       response.reply = request->challenge << 1;
+
+       tegra_bpmp_mrq_return(channel, 0, &response, sizeof(response));
+}
+
+static int tegra_bpmp_ping(struct tegra_bpmp *bpmp)
+{
+       struct mrq_ping_response response;
+       struct mrq_ping_request request;
+       struct tegra_bpmp_message msg;
+       unsigned long flags;
+       ktime_t start, end;
+       int err;
+
+       memset(&request, 0, sizeof(request));
+       request.challenge = 1;
+
+       memset(&response, 0, sizeof(response));
+
+       memset(&msg, 0, sizeof(msg));
+       msg.mrq = MRQ_PING;
+       msg.tx.data = &request;
+       msg.tx.size = sizeof(request);
+       msg.rx.data = &response;
+       msg.rx.size = sizeof(response);
+
+       local_irq_save(flags);
+       start = ktime_get();
+       err = tegra_bpmp_transfer_atomic(bpmp, &msg);
+       end = ktime_get();
+       local_irq_restore(flags);
+
+       if (!err)
+               dev_dbg(bpmp->dev,
+                       "ping ok: challenge: %u, response: %u, time: %lld\n",
+                       request.challenge, response.reply,
+                       ktime_to_us(ktime_sub(end, start)));
+
+       return err;
+}
+
+static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag,
+                                      size_t size)
+{
+       struct mrq_query_tag_request request;
+       struct tegra_bpmp_message msg;
+       unsigned long flags;
+       dma_addr_t phys;
+       void *virt;
+       int err;
+
+       virt = dma_alloc_coherent(bpmp->dev, MSG_DATA_MIN_SZ, &phys,
+                                 GFP_KERNEL | GFP_DMA32);
+       if (!virt)
+               return -ENOMEM;
+
+       memset(&request, 0, sizeof(request));
+       request.addr = phys;
+
+       memset(&msg, 0, sizeof(msg));
+       msg.mrq = MRQ_QUERY_TAG;
+       msg.tx.data = &request;
+       msg.tx.size = sizeof(request);
+
+       local_irq_save(flags);
+       err = tegra_bpmp_transfer_atomic(bpmp, &msg);
+       local_irq_restore(flags);
+
+       if (err == 0)
+               strlcpy(tag, virt, size);
+
+       dma_free_coherent(bpmp->dev, MSG_DATA_MIN_SZ, virt, phys);
+
+       return err;
+}
+
+static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel)
+{
+       unsigned long flags = channel->ob->flags;
+
+       if ((flags & MSG_RING) == 0)
+               return;
+
+       complete(&channel->completion);
+}
+
+static void tegra_bpmp_handle_rx(struct mbox_client *client, void *data)
+{
+       struct tegra_bpmp *bpmp = mbox_client_to_bpmp(client);
+       struct tegra_bpmp_channel *channel;
+       unsigned int i, count;
+       unsigned long *busy;
+
+       channel = tegra_bpmp_channel_get_rx(bpmp);
+       count = bpmp->soc->channels.thread.count;
+       busy = bpmp->threaded.busy;
+
+       if (tegra_bpmp_master_acked(channel))
+               tegra_bpmp_handle_mrq(bpmp, channel->ib->code, channel);
+
+       spin_lock(&bpmp->lock);
+
+       for_each_set_bit(i, busy, count) {
+               struct tegra_bpmp_channel *channel;
+
+               channel = tegra_bpmp_channel_get_thread(bpmp, i);
+               if (!channel)
+                       continue;
+
+               if (tegra_bpmp_master_acked(channel)) {
+                       tegra_bpmp_channel_signal(channel);
+                       clear_bit(i, busy);
+               }
+       }
+
+       spin_unlock(&bpmp->lock);
+}
+
+static void tegra_bpmp_ivc_notify(struct tegra_ivc *ivc, void *data)
+{
+       struct tegra_bpmp *bpmp = data;
+       int err;
+
+       if (WARN_ON(bpmp->mbox.channel == NULL))
+               return;
+
+       err = mbox_send_message(bpmp->mbox.channel, NULL);
+       if (err < 0)
+               return;
+
+       mbox_client_txdone(bpmp->mbox.channel, 0);
+}
+
+static int tegra_bpmp_channel_init(struct tegra_bpmp_channel *channel,
+                                  struct tegra_bpmp *bpmp,
+                                  unsigned int index)
+{
+       size_t message_size, queue_size;
+       unsigned int offset;
+       int err;
+
+       channel->ivc = devm_kzalloc(bpmp->dev, sizeof(*channel->ivc),
+                                   GFP_KERNEL);
+       if (!channel->ivc)
+               return -ENOMEM;
+
+       message_size = tegra_ivc_align(MSG_MIN_SZ);
+       queue_size = tegra_ivc_total_queue_size(message_size);
+       offset = queue_size * index;
+
+       err = tegra_ivc_init(channel->ivc, NULL,
+                            bpmp->rx.virt + offset, bpmp->rx.phys + offset,
+                            bpmp->tx.virt + offset, bpmp->tx.phys + offset,
+                            1, message_size, tegra_bpmp_ivc_notify,
+                            bpmp);
+       if (err < 0) {
+               dev_err(bpmp->dev, "failed to setup IVC for channel %u: %d\n",
+                       index, err);
+               return err;
+       }
+
+       init_completion(&channel->completion);
+       channel->bpmp = bpmp;
+
+       return 0;
+}
+
+static void tegra_bpmp_channel_reset(struct tegra_bpmp_channel *channel)
+{
+       /* reset the channel state */
+       tegra_ivc_reset(channel->ivc);
+
+       /* sync the channel state with BPMP */
+       while (tegra_ivc_notified(channel->ivc))
+               ;
+}
+
+static void tegra_bpmp_channel_cleanup(struct tegra_bpmp_channel *channel)
+{
+       tegra_ivc_cleanup(channel->ivc);
+}
+
+static int tegra_bpmp_probe(struct platform_device *pdev)
+{
+       struct tegra_bpmp_channel *channel;
+       struct tegra_bpmp *bpmp;
+       unsigned int i;
+       char tag[32];
+       size_t size;
+       int err;
+
+       bpmp = devm_kzalloc(&pdev->dev, sizeof(*bpmp), GFP_KERNEL);
+       if (!bpmp)
+               return -ENOMEM;
+
+       bpmp->soc = of_device_get_match_data(&pdev->dev);
+       bpmp->dev = &pdev->dev;
+
+       bpmp->tx.pool = of_gen_pool_get(pdev->dev.of_node, "shmem", 0);
+       if (!bpmp->tx.pool) {
+               dev_err(&pdev->dev, "TX shmem pool not found\n");
+               return -ENOMEM;
+       }
+
+       bpmp->tx.virt = gen_pool_dma_alloc(bpmp->tx.pool, 4096, &bpmp->tx.phys);
+       if (!bpmp->tx.virt) {
+               dev_err(&pdev->dev, "failed to allocate from TX pool\n");
+               return -ENOMEM;
+       }
+
+       bpmp->rx.pool = of_gen_pool_get(pdev->dev.of_node, "shmem", 1);
+       if (!bpmp->rx.pool) {
+               dev_err(&pdev->dev, "RX shmem pool not found\n");
+               err = -ENOMEM;
+               goto free_tx;
+       }
+
+       bpmp->rx.virt = gen_pool_dma_alloc(bpmp->rx.pool, 4096, &bpmp->rx.phys);
+       if (!bpmp->rx.pool) {
+               dev_err(&pdev->dev, "failed to allocate from RX pool\n");
+               err = -ENOMEM;
+               goto free_tx;
+       }
+
+       INIT_LIST_HEAD(&bpmp->mrqs);
+       spin_lock_init(&bpmp->lock);
+
+       bpmp->threaded.count = bpmp->soc->channels.thread.count;
+       sema_init(&bpmp->threaded.lock, bpmp->threaded.count);
+
+       size = BITS_TO_LONGS(bpmp->threaded.count) * sizeof(long);
+
+       bpmp->threaded.allocated = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+       if (!bpmp->threaded.allocated) {
+               err = -ENOMEM;
+               goto free_rx;
+       }
+
+       bpmp->threaded.busy = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+       if (!bpmp->threaded.busy) {
+               err = -ENOMEM;
+               goto free_rx;
+       }
+
+       bpmp->num_channels = bpmp->soc->channels.cpu_tx.count +
+                            bpmp->soc->channels.thread.count +
+                            bpmp->soc->channels.cpu_rx.count;
+
+       bpmp->channels = devm_kcalloc(&pdev->dev, bpmp->num_channels,
+                                     sizeof(*channel), GFP_KERNEL);
+       if (!bpmp->channels) {
+               err = -ENOMEM;
+               goto free_rx;
+       }
+
+       /* message channel initialization */
+       for (i = 0; i < bpmp->num_channels; i++) {
+               struct tegra_bpmp_channel *channel = &bpmp->channels[i];
+
+               err = tegra_bpmp_channel_init(channel, bpmp, i);
+               if (err < 0)
+                       goto cleanup_channels;
+       }
+
+       /* mbox registration */
+       bpmp->mbox.client.dev = &pdev->dev;
+       bpmp->mbox.client.rx_callback = tegra_bpmp_handle_rx;
+       bpmp->mbox.client.tx_block = false;
+       bpmp->mbox.client.knows_txdone = false;
+
+       bpmp->mbox.channel = mbox_request_channel(&bpmp->mbox.client, 0);
+       if (IS_ERR(bpmp->mbox.channel)) {
+               err = PTR_ERR(bpmp->mbox.channel);
+               dev_err(&pdev->dev, "failed to get HSP mailbox: %d\n", err);
+               goto cleanup_channels;
+       }
+
+       /* reset message channels */
+       for (i = 0; i < bpmp->num_channels; i++) {
+               struct tegra_bpmp_channel *channel = &bpmp->channels[i];
+
+               tegra_bpmp_channel_reset(channel);
+       }
+
+       err = tegra_bpmp_request_mrq(bpmp, MRQ_PING,
+                                    tegra_bpmp_mrq_handle_ping, bpmp);
+       if (err < 0)
+               goto free_mbox;
+
+       err = tegra_bpmp_ping(bpmp);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to ping BPMP: %d\n", err);
+               goto free_mrq;
+       }
+
+       err = tegra_bpmp_get_firmware_tag(bpmp, tag, sizeof(tag) - 1);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to get firmware tag: %d\n", err);
+               goto free_mrq;
+       }
+
+       dev_info(&pdev->dev, "firmware: %s\n", tag);
+
+       err = of_platform_default_populate(pdev->dev.of_node, NULL, &pdev->dev);
+       if (err < 0)
+               goto free_mrq;
+
+       err = tegra_bpmp_init_clocks(bpmp);
+       if (err < 0)
+               goto free_mrq;
+
+       err = tegra_bpmp_init_resets(bpmp);
+       if (err < 0)
+               goto free_mrq;
+
+       platform_set_drvdata(pdev, bpmp);
+
+       return 0;
+
+free_mrq:
+       tegra_bpmp_free_mrq(bpmp, MRQ_PING, bpmp);
+free_mbox:
+       mbox_free_channel(bpmp->mbox.channel);
+cleanup_channels:
+       while (i--)
+               tegra_bpmp_channel_cleanup(&bpmp->channels[i]);
+free_rx:
+       gen_pool_free(bpmp->rx.pool, (unsigned long)bpmp->rx.virt, 4096);
+free_tx:
+       gen_pool_free(bpmp->tx.pool, (unsigned long)bpmp->tx.virt, 4096);
+       return err;
+}
+
+static const struct tegra_bpmp_soc tegra186_soc = {
+       .channels = {
+               .cpu_tx = {
+                       .offset = 0,
+                       .count = 6,
+                       .timeout = 60 * USEC_PER_SEC,
+               },
+               .thread = {
+                       .offset = 6,
+                       .count = 7,
+                       .timeout = 600 * USEC_PER_SEC,
+               },
+               .cpu_rx = {
+                       .offset = 13,
+                       .count = 1,
+                       .timeout = 0,
+               },
+       },
+       .num_resets = 193,
+};
+
+static const struct of_device_id tegra_bpmp_match[] = {
+       { .compatible = "nvidia,tegra186-bpmp", .data = &tegra186_soc },
+       { }
+};
+
+static struct platform_driver tegra_bpmp_driver = {
+       .driver = {
+               .name = "tegra-bpmp",
+               .of_match_table = tegra_bpmp_match,
+       },
+       .probe = tegra_bpmp_probe,
+};
+
+static int __init tegra_bpmp_init(void)
+{
+       return platform_driver_register(&tegra_bpmp_driver);
+}
+core_initcall(tegra_bpmp_init);
diff --git a/drivers/firmware/tegra/ivc.c b/drivers/firmware/tegra/ivc.c
new file mode 100644 (file)
index 0000000..29ecfd8
--- /dev/null
@@ -0,0 +1,695 @@
+/*
+ * Copyright (c) 2014-2016, 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.
+ */
+
+#include <soc/tegra/ivc.h>
+
+#define TEGRA_IVC_ALIGN 64
+
+/*
+ * IVC channel reset protocol.
+ *
+ * Each end uses its tx_channel.state to indicate its synchronization state.
+ */
+enum tegra_ivc_state {
+       /*
+        * This value is zero for backwards compatibility with services that
+        * assume channels to be initially zeroed. Such channels are in an
+        * initially valid state, but cannot be asynchronously reset, and must
+        * maintain a valid state at all times.
+        *
+        * The transmitting end can enter the established state from the sync or
+        * ack state when it observes the receiving endpoint in the ack or
+        * established state, indicating that has cleared the counters in our
+        * rx_channel.
+        */
+       TEGRA_IVC_STATE_ESTABLISHED = 0,
+
+       /*
+        * If an endpoint is observed in the sync state, the remote endpoint is
+        * allowed to clear the counters it owns asynchronously with respect to
+        * the current endpoint. Therefore, the current endpoint is no longer
+        * allowed to communicate.
+        */
+       TEGRA_IVC_STATE_SYNC,
+
+       /*
+        * When the transmitting end observes the receiving end in the sync
+        * state, it can clear the w_count and r_count and transition to the ack
+        * state. If the remote endpoint observes us in the ack state, it can
+        * return to the established state once it has cleared its counters.
+        */
+       TEGRA_IVC_STATE_ACK
+};
+
+/*
+ * This structure is divided into two-cache aligned parts, the first is only
+ * written through the tx.channel pointer, while the second is only written
+ * through the rx.channel pointer. This delineates ownership of the cache
+ * lines, which is critical to performance and necessary in non-cache coherent
+ * implementations.
+ */
+struct tegra_ivc_header {
+       union {
+               struct {
+                       /* fields owned by the transmitting end */
+                       u32 count;
+                       u32 state;
+               };
+
+               u8 pad[TEGRA_IVC_ALIGN];
+       } tx;
+
+       union {
+               /* fields owned by the receiving end */
+               u32 count;
+               u8 pad[TEGRA_IVC_ALIGN];
+       } rx;
+};
+
+static inline void tegra_ivc_invalidate(struct tegra_ivc *ivc, dma_addr_t phys)
+{
+       if (!ivc->peer)
+               return;
+
+       dma_sync_single_for_cpu(ivc->peer, phys, TEGRA_IVC_ALIGN,
+                               DMA_FROM_DEVICE);
+}
+
+static inline void tegra_ivc_flush(struct tegra_ivc *ivc, dma_addr_t phys)
+{
+       if (!ivc->peer)
+               return;
+
+       dma_sync_single_for_device(ivc->peer, phys, TEGRA_IVC_ALIGN,
+                                  DMA_TO_DEVICE);
+}
+
+static inline bool tegra_ivc_empty(struct tegra_ivc *ivc,
+                                  struct tegra_ivc_header *header)
+{
+       /*
+        * This function performs multiple checks on the same values with
+        * security implications, so create snapshots with ACCESS_ONCE() to
+        * ensure that these checks use the same values.
+        */
+       u32 tx = ACCESS_ONCE(header->tx.count);
+       u32 rx = ACCESS_ONCE(header->rx.count);
+
+       /*
+        * Perform an over-full check to prevent denial of service attacks
+        * where a server could be easily fooled into believing that there's
+        * an extremely large number of frames ready, since receivers are not
+        * expected to check for full or over-full conditions.
+        *
+        * Although the channel isn't empty, this is an invalid case caused by
+        * a potentially malicious peer, so returning empty is safer, because
+        * it gives the impression that the channel has gone silent.
+        */
+       if (tx - rx > ivc->num_frames)
+               return true;
+
+       return tx == rx;
+}
+
+static inline bool tegra_ivc_full(struct tegra_ivc *ivc,
+                                 struct tegra_ivc_header *header)
+{
+       u32 tx = ACCESS_ONCE(header->tx.count);
+       u32 rx = ACCESS_ONCE(header->rx.count);
+
+       /*
+        * Invalid cases where the counters indicate that the queue is over
+        * capacity also appear full.
+        */
+       return tx - rx >= ivc->num_frames;
+}
+
+static inline u32 tegra_ivc_available(struct tegra_ivc *ivc,
+                                     struct tegra_ivc_header *header)
+{
+       u32 tx = ACCESS_ONCE(header->tx.count);
+       u32 rx = ACCESS_ONCE(header->rx.count);
+
+       /*
+        * This function isn't expected to be used in scenarios where an
+        * over-full situation can lead to denial of service attacks. See the
+        * comment in tegra_ivc_empty() for an explanation about special
+        * over-full considerations.
+        */
+       return tx - rx;
+}
+
+static inline void tegra_ivc_advance_tx(struct tegra_ivc *ivc)
+{
+       ACCESS_ONCE(ivc->tx.channel->tx.count) =
+               ACCESS_ONCE(ivc->tx.channel->tx.count) + 1;
+
+       if (ivc->tx.position == ivc->num_frames - 1)
+               ivc->tx.position = 0;
+       else
+               ivc->tx.position++;
+}
+
+static inline void tegra_ivc_advance_rx(struct tegra_ivc *ivc)
+{
+       ACCESS_ONCE(ivc->rx.channel->rx.count) =
+               ACCESS_ONCE(ivc->rx.channel->rx.count) + 1;
+
+       if (ivc->rx.position == ivc->num_frames - 1)
+               ivc->rx.position = 0;
+       else
+               ivc->rx.position++;
+}
+
+static inline int tegra_ivc_check_read(struct tegra_ivc *ivc)
+{
+       unsigned int offset = offsetof(struct tegra_ivc_header, tx.count);
+
+       /*
+        * tx.channel->state is set locally, so it is not synchronized with
+        * state from the remote peer. The remote peer cannot reset its
+        * transmit counters until we've acknowledged its synchronization
+        * request, so no additional synchronization is required because an
+        * asynchronous transition of rx.channel->state to
+        * TEGRA_IVC_STATE_ACK is not allowed.
+        */
+       if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED)
+               return -ECONNRESET;
+
+       /*
+        * Avoid unnecessary invalidations when performing repeated accesses
+        * to an IVC channel by checking the old queue pointers first.
+        *
+        * Synchronization is only necessary when these pointers indicate
+        * empty or full.
+        */
+       if (!tegra_ivc_empty(ivc, ivc->rx.channel))
+               return 0;
+
+       tegra_ivc_invalidate(ivc, ivc->rx.phys + offset);
+
+       if (tegra_ivc_empty(ivc, ivc->rx.channel))
+               return -ENOSPC;
+
+       return 0;
+}
+
+static inline int tegra_ivc_check_write(struct tegra_ivc *ivc)
+{
+       unsigned int offset = offsetof(struct tegra_ivc_header, rx.count);
+
+       if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED)
+               return -ECONNRESET;
+
+       if (!tegra_ivc_full(ivc, ivc->tx.channel))
+               return 0;
+
+       tegra_ivc_invalidate(ivc, ivc->tx.phys + offset);
+
+       if (tegra_ivc_full(ivc, ivc->tx.channel))
+               return -ENOSPC;
+
+       return 0;
+}
+
+static void *tegra_ivc_frame_virt(struct tegra_ivc *ivc,
+                                 struct tegra_ivc_header *header,
+                                 unsigned int frame)
+{
+       if (WARN_ON(frame >= ivc->num_frames))
+               return ERR_PTR(-EINVAL);
+
+       return (void *)(header + 1) + ivc->frame_size * frame;
+}
+
+static inline dma_addr_t tegra_ivc_frame_phys(struct tegra_ivc *ivc,
+                                             dma_addr_t phys,
+                                             unsigned int frame)
+{
+       unsigned long offset;
+
+       offset = sizeof(struct tegra_ivc_header) + ivc->frame_size * frame;
+
+       return phys + offset;
+}
+
+static inline void tegra_ivc_invalidate_frame(struct tegra_ivc *ivc,
+                                             dma_addr_t phys,
+                                             unsigned int frame,
+                                             unsigned int offset,
+                                             size_t size)
+{
+       if (!ivc->peer || WARN_ON(frame >= ivc->num_frames))
+               return;
+
+       phys = tegra_ivc_frame_phys(ivc, phys, frame) + offset;
+
+       dma_sync_single_for_cpu(ivc->peer, phys, size, DMA_FROM_DEVICE);
+}
+
+static inline void tegra_ivc_flush_frame(struct tegra_ivc *ivc,
+                                        dma_addr_t phys,
+                                        unsigned int frame,
+                                        unsigned int offset,
+                                        size_t size)
+{
+       if (!ivc->peer || WARN_ON(frame >= ivc->num_frames))
+               return;
+
+       phys = tegra_ivc_frame_phys(ivc, phys, frame) + offset;
+
+       dma_sync_single_for_device(ivc->peer, phys, size, DMA_TO_DEVICE);
+}
+
+/* directly peek at the next frame rx'ed */
+void *tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc)
+{
+       int err;
+
+       if (WARN_ON(ivc == NULL))
+               return ERR_PTR(-EINVAL);
+
+       err = tegra_ivc_check_read(ivc);
+       if (err < 0)
+               return ERR_PTR(err);
+
+       /*
+        * Order observation of ivc->rx.position potentially indicating new
+        * data before data read.
+        */
+       smp_rmb();
+
+       tegra_ivc_invalidate_frame(ivc, ivc->rx.phys, ivc->rx.position, 0,
+                                  ivc->frame_size);
+
+       return tegra_ivc_frame_virt(ivc, ivc->rx.channel, ivc->rx.position);
+}
+EXPORT_SYMBOL(tegra_ivc_read_get_next_frame);
+
+int tegra_ivc_read_advance(struct tegra_ivc *ivc)
+{
+       unsigned int rx = offsetof(struct tegra_ivc_header, rx.count);
+       unsigned int tx = offsetof(struct tegra_ivc_header, tx.count);
+       int err;
+
+       /*
+        * No read barriers or synchronization here: the caller is expected to
+        * have already observed the channel non-empty. This check is just to
+        * catch programming errors.
+        */
+       err = tegra_ivc_check_read(ivc);
+       if (err < 0)
+               return err;
+
+       tegra_ivc_advance_rx(ivc);
+
+       tegra_ivc_flush(ivc, ivc->rx.phys + rx);
+
+       /*
+        * Ensure our write to ivc->rx.position occurs before our read from
+        * ivc->tx.position.
+        */
+       smp_mb();
+
+       /*
+        * Notify only upon transition from full to non-full. The available
+        * count can only asynchronously increase, so the worst possible
+        * side-effect will be a spurious notification.
+        */
+       tegra_ivc_invalidate(ivc, ivc->rx.phys + tx);
+
+       if (tegra_ivc_available(ivc, ivc->rx.channel) == ivc->num_frames - 1)
+               ivc->notify(ivc, ivc->notify_data);
+
+       return 0;
+}
+EXPORT_SYMBOL(tegra_ivc_read_advance);
+
+/* directly poke at the next frame to be tx'ed */
+void *tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc)
+{
+       int err;
+
+       err = tegra_ivc_check_write(ivc);
+       if (err < 0)
+               return ERR_PTR(err);
+
+       return tegra_ivc_frame_virt(ivc, ivc->tx.channel, ivc->tx.position);
+}
+EXPORT_SYMBOL(tegra_ivc_write_get_next_frame);
+
+/* advance the tx buffer */
+int tegra_ivc_write_advance(struct tegra_ivc *ivc)
+{
+       unsigned int tx = offsetof(struct tegra_ivc_header, tx.count);
+       unsigned int rx = offsetof(struct tegra_ivc_header, rx.count);
+       int err;
+
+       err = tegra_ivc_check_write(ivc);
+       if (err < 0)
+               return err;
+
+       tegra_ivc_flush_frame(ivc, ivc->tx.phys, ivc->tx.position, 0,
+                             ivc->frame_size);
+
+       /*
+        * Order any possible stores to the frame before update of
+        * ivc->tx.position.
+        */
+       smp_wmb();
+
+       tegra_ivc_advance_tx(ivc);
+       tegra_ivc_flush(ivc, ivc->tx.phys + tx);
+
+       /*
+        * Ensure our write to ivc->tx.position occurs before our read from
+        * ivc->rx.position.
+        */
+       smp_mb();
+
+       /*
+        * Notify only upon transition from empty to non-empty. The available
+        * count can only asynchronously decrease, so the worst possible
+        * side-effect will be a spurious notification.
+        */
+       tegra_ivc_invalidate(ivc, ivc->tx.phys + rx);
+
+       if (tegra_ivc_available(ivc, ivc->tx.channel) == 1)
+               ivc->notify(ivc, ivc->notify_data);
+
+       return 0;
+}
+EXPORT_SYMBOL(tegra_ivc_write_advance);
+
+void tegra_ivc_reset(struct tegra_ivc *ivc)
+{
+       unsigned int offset = offsetof(struct tegra_ivc_header, tx.count);
+
+       ivc->tx.channel->tx.state = TEGRA_IVC_STATE_SYNC;
+       tegra_ivc_flush(ivc, ivc->tx.phys + offset);
+       ivc->notify(ivc, ivc->notify_data);
+}
+EXPORT_SYMBOL(tegra_ivc_reset);
+
+/*
+ * =======================================================
+ *  IVC State Transition Table - see tegra_ivc_notified()
+ * =======================================================
+ *
+ *     local   remote  action
+ *     -----   ------  -----------------------------------
+ *     SYNC    EST     <none>
+ *     SYNC    ACK     reset counters; move to EST; notify
+ *     SYNC    SYNC    reset counters; move to ACK; notify
+ *     ACK     EST     move to EST; notify
+ *     ACK     ACK     move to EST; notify
+ *     ACK     SYNC    reset counters; move to ACK; notify
+ *     EST     EST     <none>
+ *     EST     ACK     <none>
+ *     EST     SYNC    reset counters; move to ACK; notify
+ *
+ * ===============================================================
+ */
+
+int tegra_ivc_notified(struct tegra_ivc *ivc)
+{
+       unsigned int offset = offsetof(struct tegra_ivc_header, tx.count);
+       enum tegra_ivc_state state;
+
+       /* Copy the receiver's state out of shared memory. */
+       tegra_ivc_invalidate(ivc, ivc->rx.phys + offset);
+       state = ACCESS_ONCE(ivc->rx.channel->tx.state);
+
+       if (state == TEGRA_IVC_STATE_SYNC) {
+               offset = offsetof(struct tegra_ivc_header, tx.count);
+
+               /*
+                * Order observation of TEGRA_IVC_STATE_SYNC before stores
+                * clearing tx.channel.
+                */
+               smp_rmb();
+
+               /*
+                * Reset tx.channel counters. The remote end is in the SYNC
+                * state and won't make progress until we change our state,
+                * so the counters are not in use at this time.
+                */
+               ivc->tx.channel->tx.count = 0;
+               ivc->rx.channel->rx.count = 0;
+
+               ivc->tx.position = 0;
+               ivc->rx.position = 0;
+
+               /*
+                * Ensure that counters appear cleared before new state can be
+                * observed.
+                */
+               smp_wmb();
+
+               /*
+                * Move to ACK state. We have just cleared our counters, so it
+                * is now safe for the remote end to start using these values.
+                */
+               ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ACK;
+               tegra_ivc_flush(ivc, ivc->tx.phys + offset);
+
+               /*
+                * Notify remote end to observe state transition.
+                */
+               ivc->notify(ivc, ivc->notify_data);
+
+       } else if (ivc->tx.channel->tx.state == TEGRA_IVC_STATE_SYNC &&
+                  state == TEGRA_IVC_STATE_ACK) {
+               offset = offsetof(struct tegra_ivc_header, tx.count);
+
+               /*
+                * Order observation of ivc_state_sync before stores clearing
+                * tx_channel.
+                */
+               smp_rmb();
+
+               /*
+                * Reset tx.channel counters. The remote end is in the ACK
+                * state and won't make progress until we change our state,
+                * so the counters are not in use at this time.
+                */
+               ivc->tx.channel->tx.count = 0;
+               ivc->rx.channel->rx.count = 0;
+
+               ivc->tx.position = 0;
+               ivc->rx.position = 0;
+
+               /*
+                * Ensure that counters appear cleared before new state can be
+                * observed.
+                */
+               smp_wmb();
+
+               /*
+                * Move to ESTABLISHED state. We know that the remote end has
+                * already cleared its counters, so it is safe to start
+                * writing/reading on this channel.
+                */
+               ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ESTABLISHED;
+               tegra_ivc_flush(ivc, ivc->tx.phys + offset);
+
+               /*
+                * Notify remote end to observe state transition.
+                */
+               ivc->notify(ivc, ivc->notify_data);
+
+       } else if (ivc->tx.channel->tx.state == TEGRA_IVC_STATE_ACK) {
+               offset = offsetof(struct tegra_ivc_header, tx.count);
+
+               /*
+                * At this point, we have observed the peer to be in either
+                * the ACK or ESTABLISHED state. Next, order observation of
+                * peer state before storing to tx.channel.
+                */
+               smp_rmb();
+
+               /*
+                * Move to ESTABLISHED state. We know that we have previously
+                * cleared our counters, and we know that the remote end has
+                * cleared its counters, so it is safe to start writing/reading
+                * on this channel.
+                */
+               ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ESTABLISHED;
+               tegra_ivc_flush(ivc, ivc->tx.phys + offset);
+
+               /*
+                * Notify remote end to observe state transition.
+                */
+               ivc->notify(ivc, ivc->notify_data);
+
+       } else {
+               /*
+                * There is no need to handle any further action. Either the
+                * channel is already fully established, or we are waiting for
+                * the remote end to catch up with our current state. Refer
+                * to the diagram in "IVC State Transition Table" above.
+                */
+       }
+
+       if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED)
+               return -EAGAIN;
+
+       return 0;
+}
+EXPORT_SYMBOL(tegra_ivc_notified);
+
+size_t tegra_ivc_align(size_t size)
+{
+       return ALIGN(size, TEGRA_IVC_ALIGN);
+}
+EXPORT_SYMBOL(tegra_ivc_align);
+
+unsigned tegra_ivc_total_queue_size(unsigned queue_size)
+{
+       if (!IS_ALIGNED(queue_size, TEGRA_IVC_ALIGN)) {
+               pr_err("%s: queue_size (%u) must be %u-byte aligned\n",
+                      __func__, queue_size, TEGRA_IVC_ALIGN);
+               return 0;
+       }
+
+       return queue_size + sizeof(struct tegra_ivc_header);
+}
+EXPORT_SYMBOL(tegra_ivc_total_queue_size);
+
+static int tegra_ivc_check_params(unsigned long rx, unsigned long tx,
+                                 unsigned int num_frames, size_t frame_size)
+{
+       BUILD_BUG_ON(!IS_ALIGNED(offsetof(struct tegra_ivc_header, tx.count),
+                                TEGRA_IVC_ALIGN));
+       BUILD_BUG_ON(!IS_ALIGNED(offsetof(struct tegra_ivc_header, rx.count),
+                                TEGRA_IVC_ALIGN));
+       BUILD_BUG_ON(!IS_ALIGNED(sizeof(struct tegra_ivc_header),
+                                TEGRA_IVC_ALIGN));
+
+       if ((uint64_t)num_frames * (uint64_t)frame_size >= 0x100000000UL) {
+               pr_err("num_frames * frame_size overflows\n");
+               return -EINVAL;
+       }
+
+       if (!IS_ALIGNED(frame_size, TEGRA_IVC_ALIGN)) {
+               pr_err("frame size not adequately aligned: %zu\n", frame_size);
+               return -EINVAL;
+       }
+
+       /*
+        * The headers must at least be aligned enough for counters
+        * to be accessed atomically.
+        */
+       if (!IS_ALIGNED(rx, TEGRA_IVC_ALIGN)) {
+               pr_err("IVC channel start not aligned: %#lx\n", rx);
+               return -EINVAL;
+       }
+
+       if (!IS_ALIGNED(tx, TEGRA_IVC_ALIGN)) {
+               pr_err("IVC channel start not aligned: %#lx\n", tx);
+               return -EINVAL;
+       }
+
+       if (rx < tx) {
+               if (rx + frame_size * num_frames > tx) {
+                       pr_err("queue regions overlap: %#lx + %zx > %#lx\n",
+                              rx, frame_size * num_frames, tx);
+                       return -EINVAL;
+               }
+       } else {
+               if (tx + frame_size * num_frames > rx) {
+                       pr_err("queue regions overlap: %#lx + %zx > %#lx\n",
+                              tx, frame_size * num_frames, rx);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx,
+                  dma_addr_t rx_phys, void *tx, dma_addr_t tx_phys,
+                  unsigned int num_frames, size_t frame_size,
+                  void (*notify)(struct tegra_ivc *ivc, void *data),
+                  void *data)
+{
+       size_t queue_size;
+       int err;
+
+       if (WARN_ON(!ivc || !notify))
+               return -EINVAL;
+
+       /*
+        * All sizes that can be returned by communication functions should
+        * fit in an int.
+        */
+       if (frame_size > INT_MAX)
+               return -E2BIG;
+
+       err = tegra_ivc_check_params((unsigned long)rx, (unsigned long)tx,
+                                    num_frames, frame_size);
+       if (err < 0)
+               return err;
+
+       queue_size = tegra_ivc_total_queue_size(num_frames * frame_size);
+
+       if (peer) {
+               ivc->rx.phys = dma_map_single(peer, rx, queue_size,
+                                             DMA_BIDIRECTIONAL);
+               if (ivc->rx.phys == DMA_ERROR_CODE)
+                       return -ENOMEM;
+
+               ivc->tx.phys = dma_map_single(peer, tx, queue_size,
+                                             DMA_BIDIRECTIONAL);
+               if (ivc->tx.phys == DMA_ERROR_CODE) {
+                       dma_unmap_single(peer, ivc->rx.phys, queue_size,
+                                        DMA_BIDIRECTIONAL);
+                       return -ENOMEM;
+               }
+       } else {
+               ivc->rx.phys = rx_phys;
+               ivc->tx.phys = tx_phys;
+       }
+
+       ivc->rx.channel = rx;
+       ivc->tx.channel = tx;
+       ivc->peer = peer;
+       ivc->notify = notify;
+       ivc->notify_data = data;
+       ivc->frame_size = frame_size;
+       ivc->num_frames = num_frames;
+
+       /*
+        * These values aren't necessarily correct until the channel has been
+        * reset.
+        */
+       ivc->tx.position = 0;
+       ivc->rx.position = 0;
+
+       return 0;
+}
+EXPORT_SYMBOL(tegra_ivc_init);
+
+void tegra_ivc_cleanup(struct tegra_ivc *ivc)
+{
+       if (ivc->peer) {
+               size_t size = tegra_ivc_total_queue_size(ivc->num_frames *
+                                                        ivc->frame_size);
+
+               dma_unmap_single(ivc->peer, ivc->rx.phys, size,
+                                DMA_BIDIRECTIONAL);
+               dma_unmap_single(ivc->peer, ivc->tx.phys, size,
+                                DMA_BIDIRECTIONAL);
+       }
+}
+EXPORT_SYMBOL(tegra_ivc_cleanup);
index 11eebfe8a4cbd0d60805cf9279949c9462a92944..ceff415f201c66b5a61a5ce5673b5f1e46c151a6 100644 (file)
@@ -124,6 +124,15 @@ config MAILBOX_TEST
          Test client to help with testing new Controller driver
          implementations.
 
+config TEGRA_HSP_MBOX
+       bool "Tegra HSP (Hardware Synchronization Primitives) Driver"
+       depends on ARCH_TEGRA_186_SOC
+       help
+         The Tegra HSP driver is used for the interprocessor communication
+         between different remote processors and host processors on Tegra186
+         and later SoCs. Say Y here if you want to have this support.
+         If unsure say N.
+
 config XGENE_SLIMPRO_MBOX
        tristate "APM SoC X-Gene SLIMpro Mailbox Controller"
        depends on ARCH_XGENE
index ace6fed8fea99f31de795ead86ccfb6e20b230bf..7dde4f609ae84df8b9f213fd84d922598f223bb4 100644 (file)
@@ -29,3 +29,5 @@ obj-$(CONFIG_XGENE_SLIMPRO_MBOX) += mailbox-xgene-slimpro.o
 obj-$(CONFIG_HI6220_MBOX)      += hi6220-mailbox.o
 
 obj-$(CONFIG_BCM_PDC_MBOX)     += bcm-pdc-mailbox.o
+
+obj-$(CONFIG_TEGRA_HSP_MBOX)   += tegra-hsp.o
diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
new file mode 100644 (file)
index 0000000..0cde356
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mailbox_controller.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/mailbox/tegra186-hsp.h>
+
+#define HSP_INT_DIMENSIONING   0x380
+#define HSP_nSM_SHIFT          0
+#define HSP_nSS_SHIFT          4
+#define HSP_nAS_SHIFT          8
+#define HSP_nDB_SHIFT          12
+#define HSP_nSI_SHIFT          16
+#define HSP_nINT_MASK          0xf
+
+#define HSP_DB_TRIGGER 0x0
+#define HSP_DB_ENABLE  0x4
+#define HSP_DB_RAW     0x8
+#define HSP_DB_PENDING 0xc
+
+#define HSP_DB_CCPLEX          1
+#define HSP_DB_BPMP            3
+#define HSP_DB_MAX             7
+
+struct tegra_hsp_channel;
+struct tegra_hsp;
+
+struct tegra_hsp_channel {
+       struct tegra_hsp *hsp;
+       struct mbox_chan *chan;
+       void __iomem *regs;
+};
+
+struct tegra_hsp_doorbell {
+       struct tegra_hsp_channel channel;
+       struct list_head list;
+       const char *name;
+       unsigned int master;
+       unsigned int index;
+};
+
+struct tegra_hsp_db_map {
+       const char *name;
+       unsigned int master;
+       unsigned int index;
+};
+
+struct tegra_hsp_soc {
+       const struct tegra_hsp_db_map *map;
+};
+
+struct tegra_hsp {
+       const struct tegra_hsp_soc *soc;
+       struct mbox_controller mbox;
+       void __iomem *regs;
+       unsigned int irq;
+       unsigned int num_sm;
+       unsigned int num_as;
+       unsigned int num_ss;
+       unsigned int num_db;
+       unsigned int num_si;
+       spinlock_t lock;
+
+       struct list_head doorbells;
+};
+
+static inline struct tegra_hsp *
+to_tegra_hsp(struct mbox_controller *mbox)
+{
+       return container_of(mbox, struct tegra_hsp, mbox);
+}
+
+static inline u32 tegra_hsp_readl(struct tegra_hsp *hsp, unsigned int offset)
+{
+       return readl(hsp->regs + offset);
+}
+
+static inline void tegra_hsp_writel(struct tegra_hsp *hsp, u32 value,
+                                   unsigned int offset)
+{
+       writel(value, hsp->regs + offset);
+}
+
+static inline u32 tegra_hsp_channel_readl(struct tegra_hsp_channel *channel,
+                                         unsigned int offset)
+{
+       return readl(channel->regs + offset);
+}
+
+static inline void tegra_hsp_channel_writel(struct tegra_hsp_channel *channel,
+                                           u32 value, unsigned int offset)
+{
+       writel(value, channel->regs + offset);
+}
+
+static bool tegra_hsp_doorbell_can_ring(struct tegra_hsp_doorbell *db)
+{
+       u32 value;
+
+       value = tegra_hsp_channel_readl(&db->channel, HSP_DB_ENABLE);
+
+       return (value & BIT(TEGRA_HSP_DB_MASTER_CCPLEX)) != 0;
+}
+
+static struct tegra_hsp_doorbell *
+__tegra_hsp_doorbell_get(struct tegra_hsp *hsp, unsigned int master)
+{
+       struct tegra_hsp_doorbell *entry;
+
+       list_for_each_entry(entry, &hsp->doorbells, list)
+               if (entry->master == master)
+                       return entry;
+
+       return NULL;
+}
+
+static struct tegra_hsp_doorbell *
+tegra_hsp_doorbell_get(struct tegra_hsp *hsp, unsigned int master)
+{
+       struct tegra_hsp_doorbell *db;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hsp->lock, flags);
+       db = __tegra_hsp_doorbell_get(hsp, master);
+       spin_unlock_irqrestore(&hsp->lock, flags);
+
+       return db;
+}
+
+static irqreturn_t tegra_hsp_doorbell_irq(int irq, void *data)
+{
+       struct tegra_hsp *hsp = data;
+       struct tegra_hsp_doorbell *db;
+       unsigned long master, value;
+
+       db = tegra_hsp_doorbell_get(hsp, TEGRA_HSP_DB_MASTER_CCPLEX);
+       if (!db)
+               return IRQ_NONE;
+
+       value = tegra_hsp_channel_readl(&db->channel, HSP_DB_PENDING);
+       tegra_hsp_channel_writel(&db->channel, value, HSP_DB_PENDING);
+
+       spin_lock(&hsp->lock);
+
+       for_each_set_bit(master, &value, hsp->mbox.num_chans) {
+               struct tegra_hsp_doorbell *db;
+
+               db = __tegra_hsp_doorbell_get(hsp, master);
+               /*
+                * Depending on the bootloader chain, the CCPLEX doorbell will
+                * have some doorbells enabled, which means that requesting an
+                * interrupt will immediately fire.
+                *
+                * In that case, db->channel.chan will still be NULL here and
+                * cause a crash if not properly guarded.
+                *
+                * It remains to be seen if ignoring the doorbell in that case
+                * is the correct solution.
+                */
+               if (db && db->channel.chan)
+                       mbox_chan_received_data(db->channel.chan, NULL);
+       }
+
+       spin_unlock(&hsp->lock);
+
+       return IRQ_HANDLED;
+}
+
+static struct tegra_hsp_channel *
+tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name,
+                         unsigned int master, unsigned int index)
+{
+       struct tegra_hsp_doorbell *db;
+       unsigned int offset;
+       unsigned long flags;
+
+       db = kzalloc(sizeof(*db), GFP_KERNEL);
+       if (!db)
+               return ERR_PTR(-ENOMEM);
+
+       offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) << 16;
+       offset += index * 0x100;
+
+       db->channel.regs = hsp->regs + offset;
+       db->channel.hsp = hsp;
+
+       db->name = kstrdup_const(name, GFP_KERNEL);
+       db->master = master;
+       db->index = index;
+
+       spin_lock_irqsave(&hsp->lock, flags);
+       list_add_tail(&db->list, &hsp->doorbells);
+       spin_unlock_irqrestore(&hsp->lock, flags);
+
+       return &db->channel;
+}
+
+static void __tegra_hsp_doorbell_destroy(struct tegra_hsp_doorbell *db)
+{
+       list_del(&db->list);
+       kfree_const(db->name);
+       kfree(db);
+}
+
+static int tegra_hsp_doorbell_send_data(struct mbox_chan *chan, void *data)
+{
+       struct tegra_hsp_doorbell *db = chan->con_priv;
+
+       tegra_hsp_channel_writel(&db->channel, 1, HSP_DB_TRIGGER);
+
+       return 0;
+}
+
+static int tegra_hsp_doorbell_startup(struct mbox_chan *chan)
+{
+       struct tegra_hsp_doorbell *db = chan->con_priv;
+       struct tegra_hsp *hsp = db->channel.hsp;
+       struct tegra_hsp_doorbell *ccplex;
+       unsigned long flags;
+       u32 value;
+
+       if (db->master >= hsp->mbox.num_chans) {
+               dev_err(hsp->mbox.dev,
+                       "invalid master ID %u for HSP channel\n",
+                       db->master);
+               return -EINVAL;
+       }
+
+       ccplex = tegra_hsp_doorbell_get(hsp, TEGRA_HSP_DB_MASTER_CCPLEX);
+       if (!ccplex)
+               return -ENODEV;
+
+       if (!tegra_hsp_doorbell_can_ring(db))
+               return -ENODEV;
+
+       spin_lock_irqsave(&hsp->lock, flags);
+
+       value = tegra_hsp_channel_readl(&ccplex->channel, HSP_DB_ENABLE);
+       value |= BIT(db->master);
+       tegra_hsp_channel_writel(&ccplex->channel, value, HSP_DB_ENABLE);
+
+       spin_unlock_irqrestore(&hsp->lock, flags);
+
+       return 0;
+}
+
+static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan)
+{
+       struct tegra_hsp_doorbell *db = chan->con_priv;
+       struct tegra_hsp *hsp = db->channel.hsp;
+       struct tegra_hsp_doorbell *ccplex;
+       unsigned long flags;
+       u32 value;
+
+       ccplex = tegra_hsp_doorbell_get(hsp, TEGRA_HSP_DB_MASTER_CCPLEX);
+       if (!ccplex)
+               return;
+
+       spin_lock_irqsave(&hsp->lock, flags);
+
+       value = tegra_hsp_channel_readl(&ccplex->channel, HSP_DB_ENABLE);
+       value &= ~BIT(db->master);
+       tegra_hsp_channel_writel(&ccplex->channel, value, HSP_DB_ENABLE);
+
+       spin_unlock_irqrestore(&hsp->lock, flags);
+}
+
+static const struct mbox_chan_ops tegra_hsp_doorbell_ops = {
+       .send_data = tegra_hsp_doorbell_send_data,
+       .startup = tegra_hsp_doorbell_startup,
+       .shutdown = tegra_hsp_doorbell_shutdown,
+};
+
+static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox,
+                                           const struct of_phandle_args *args)
+{
+       struct tegra_hsp_channel *channel = ERR_PTR(-ENODEV);
+       struct tegra_hsp *hsp = to_tegra_hsp(mbox);
+       unsigned int type = args->args[0];
+       unsigned int master = args->args[1];
+       struct tegra_hsp_doorbell *db;
+       struct mbox_chan *chan;
+       unsigned long flags;
+       unsigned int i;
+
+       switch (type) {
+       case TEGRA_HSP_MBOX_TYPE_DB:
+               db = tegra_hsp_doorbell_get(hsp, master);
+               if (db)
+                       channel = &db->channel;
+
+               break;
+
+       default:
+               break;
+       }
+
+       if (IS_ERR(channel))
+               return ERR_CAST(channel);
+
+       spin_lock_irqsave(&hsp->lock, flags);
+
+       for (i = 0; i < hsp->mbox.num_chans; i++) {
+               chan = &hsp->mbox.chans[i];
+               if (!chan->con_priv) {
+                       chan->con_priv = channel;
+                       channel->chan = chan;
+                       break;
+               }
+
+               chan = NULL;
+       }
+
+       spin_unlock_irqrestore(&hsp->lock, flags);
+
+       return chan ?: ERR_PTR(-EBUSY);
+}
+
+static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp)
+{
+       struct tegra_hsp_doorbell *db, *tmp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&hsp->lock, flags);
+
+       list_for_each_entry_safe(db, tmp, &hsp->doorbells, list)
+               __tegra_hsp_doorbell_destroy(db);
+
+       spin_unlock_irqrestore(&hsp->lock, flags);
+}
+
+static int tegra_hsp_add_doorbells(struct tegra_hsp *hsp)
+{
+       const struct tegra_hsp_db_map *map = hsp->soc->map;
+       struct tegra_hsp_channel *channel;
+
+       while (map->name) {
+               channel = tegra_hsp_doorbell_create(hsp, map->name,
+                                                   map->master, map->index);
+               if (IS_ERR(channel)) {
+                       tegra_hsp_remove_doorbells(hsp);
+                       return PTR_ERR(channel);
+               }
+
+               map++;
+       }
+
+       return 0;
+}
+
+static int tegra_hsp_probe(struct platform_device *pdev)
+{
+       struct tegra_hsp *hsp;
+       struct resource *res;
+       u32 value;
+       int err;
+
+       hsp = devm_kzalloc(&pdev->dev, sizeof(*hsp), GFP_KERNEL);
+       if (!hsp)
+               return -ENOMEM;
+
+       hsp->soc = of_device_get_match_data(&pdev->dev);
+       INIT_LIST_HEAD(&hsp->doorbells);
+       spin_lock_init(&hsp->lock);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       hsp->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(hsp->regs))
+               return PTR_ERR(hsp->regs);
+
+       value = tegra_hsp_readl(hsp, HSP_INT_DIMENSIONING);
+       hsp->num_sm = (value >> HSP_nSM_SHIFT) & HSP_nINT_MASK;
+       hsp->num_ss = (value >> HSP_nSS_SHIFT) & HSP_nINT_MASK;
+       hsp->num_as = (value >> HSP_nAS_SHIFT) & HSP_nINT_MASK;
+       hsp->num_db = (value >> HSP_nDB_SHIFT) & HSP_nINT_MASK;
+       hsp->num_si = (value >> HSP_nSI_SHIFT) & HSP_nINT_MASK;
+
+       err = platform_get_irq_byname(pdev, "doorbell");
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to get doorbell IRQ: %d\n", err);
+               return err;
+       }
+
+       hsp->irq = err;
+
+       hsp->mbox.of_xlate = of_tegra_hsp_xlate;
+       hsp->mbox.num_chans = 32;
+       hsp->mbox.dev = &pdev->dev;
+       hsp->mbox.txdone_irq = false;
+       hsp->mbox.txdone_poll = false;
+       hsp->mbox.ops = &tegra_hsp_doorbell_ops;
+
+       hsp->mbox.chans = devm_kcalloc(&pdev->dev, hsp->mbox.num_chans,
+                                       sizeof(*hsp->mbox.chans),
+                                       GFP_KERNEL);
+       if (!hsp->mbox.chans)
+               return -ENOMEM;
+
+       err = tegra_hsp_add_doorbells(hsp);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to add doorbells: %d\n", err);
+               return err;
+       }
+
+       platform_set_drvdata(pdev, hsp);
+
+       err = mbox_controller_register(&hsp->mbox);
+       if (err) {
+               dev_err(&pdev->dev, "failed to register mailbox: %d\n", err);
+               tegra_hsp_remove_doorbells(hsp);
+               return err;
+       }
+
+       err = devm_request_irq(&pdev->dev, hsp->irq, tegra_hsp_doorbell_irq,
+                              IRQF_NO_SUSPEND, dev_name(&pdev->dev), hsp);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n",
+                       hsp->irq, err);
+               return err;
+       }
+
+       return 0;
+}
+
+static int tegra_hsp_remove(struct platform_device *pdev)
+{
+       struct tegra_hsp *hsp = platform_get_drvdata(pdev);
+
+       mbox_controller_unregister(&hsp->mbox);
+       tegra_hsp_remove_doorbells(hsp);
+
+       return 0;
+}
+
+static const struct tegra_hsp_db_map tegra186_hsp_db_map[] = {
+       { "ccplex", TEGRA_HSP_DB_MASTER_CCPLEX, HSP_DB_CCPLEX, },
+       { "bpmp",   TEGRA_HSP_DB_MASTER_BPMP,   HSP_DB_BPMP,   },
+       { /* sentinel */ }
+};
+
+static const struct tegra_hsp_soc tegra186_hsp_soc = {
+       .map = tegra186_hsp_db_map,
+};
+
+static const struct of_device_id tegra_hsp_match[] = {
+       { .compatible = "nvidia,tegra186-hsp", .data = &tegra186_hsp_soc },
+       { }
+};
+
+static struct platform_driver tegra_hsp_driver = {
+       .driver = {
+               .name = "tegra-hsp",
+               .of_match_table = tegra_hsp_match,
+       },
+       .probe = tegra_hsp_probe,
+       .remove = tegra_hsp_remove,
+};
+
+static int __init tegra_hsp_init(void)
+{
+       return platform_driver_register(&tegra_hsp_driver);
+}
+core_initcall(tegra_hsp_init);
index 03089ad2fc6574be9af2b236d7c5c3761c971b7e..e5e124c07066b8a0e202cfe2fd17fb71f979e71e 100644 (file)
@@ -77,5 +77,19 @@ config ARCH_TEGRA_210_SOC
          controllers, such as GPIO, I2C, SPI, SDHCI, PCIe, SATA and XHCI, to
          name only a few.
 
+config ARCH_TEGRA_186_SOC
+       bool "NVIDIA Tegra186 SoC"
+       select MAILBOX
+       select TEGRA_BPMP
+       select TEGRA_HSP_MBOX
+       select TEGRA_IVC
+       help
+         Enable support for the NVIDIA Tegar186 SoC. The Tegra186 features a
+         combination of Denver and Cortex-A57 CPU cores and a GPU based on
+         the Pascal architecture. It contains an ADSP with a Cortex-A9 CPU
+         used for audio processing, hardware video encoders/decoders with
+         multi-format support, ISP for image capture processing and BPMP for
+         power management.
+
 endif
 endif
diff --git a/include/dt-bindings/clock/tegra186-clock.h b/include/dt-bindings/clock/tegra186-clock.h
new file mode 100644 (file)
index 0000000..f73d320
--- /dev/null
@@ -0,0 +1,940 @@
+/** @file */
+
+#ifndef _MACH_T186_CLK_T186_H
+#define _MACH_T186_CLK_T186_H
+
+/**
+ * @defgroup clock_ids Clock Identifiers
+ * @{
+ *   @defgroup extern_input external input clocks
+ *   @{
+ *     @def TEGRA186_CLK_OSC
+ *     @def TEGRA186_CLK_CLK_32K
+ *     @def TEGRA186_CLK_DTV_INPUT
+ *     @def TEGRA186_CLK_SOR0_PAD_CLKOUT
+ *     @def TEGRA186_CLK_SOR1_PAD_CLKOUT
+ *     @def TEGRA186_CLK_I2S1_SYNC_INPUT
+ *     @def TEGRA186_CLK_I2S2_SYNC_INPUT
+ *     @def TEGRA186_CLK_I2S3_SYNC_INPUT
+ *     @def TEGRA186_CLK_I2S4_SYNC_INPUT
+ *     @def TEGRA186_CLK_I2S5_SYNC_INPUT
+ *     @def TEGRA186_CLK_I2S6_SYNC_INPUT
+ *     @def TEGRA186_CLK_SPDIFIN_SYNC_INPUT
+ *   @}
+ *
+ *   @defgroup extern_output external output clocks
+ *   @{
+ *     @def TEGRA186_CLK_EXTPERIPH1
+ *     @def TEGRA186_CLK_EXTPERIPH2
+ *     @def TEGRA186_CLK_EXTPERIPH3
+ *     @def TEGRA186_CLK_EXTPERIPH4
+ *   @}
+ *
+ *   @defgroup display_clks display related clocks
+ *   @{
+ *     @def TEGRA186_CLK_CEC
+ *     @def TEGRA186_CLK_DSIC
+ *     @def TEGRA186_CLK_DSIC_LP
+ *     @def TEGRA186_CLK_DSID
+ *     @def TEGRA186_CLK_DSID_LP
+ *     @def TEGRA186_CLK_DPAUX1
+ *     @def TEGRA186_CLK_DPAUX
+ *     @def TEGRA186_CLK_HDA2HDMICODEC
+ *     @def TEGRA186_CLK_NVDISPLAY_DISP
+ *     @def TEGRA186_CLK_NVDISPLAY_DSC
+ *     @def TEGRA186_CLK_NVDISPLAY_P0
+ *     @def TEGRA186_CLK_NVDISPLAY_P1
+ *     @def TEGRA186_CLK_NVDISPLAY_P2
+ *     @def TEGRA186_CLK_NVDISPLAYHUB
+ *     @def TEGRA186_CLK_SOR_SAFE
+ *     @def TEGRA186_CLK_SOR0
+ *     @def TEGRA186_CLK_SOR0_OUT
+ *     @def TEGRA186_CLK_SOR1
+ *     @def TEGRA186_CLK_SOR1_OUT
+ *     @def TEGRA186_CLK_DSI
+ *     @def TEGRA186_CLK_MIPI_CAL
+ *     @def TEGRA186_CLK_DSIA_LP
+ *     @def TEGRA186_CLK_DSIB
+ *     @def TEGRA186_CLK_DSIB_LP
+ *   @}
+ *
+ *   @defgroup camera_clks camera related clocks
+ *   @{
+ *     @def TEGRA186_CLK_NVCSI
+ *     @def TEGRA186_CLK_NVCSILP
+ *     @def TEGRA186_CLK_VI
+ *   @}
+ *
+ *   @defgroup audio_clks audio related clocks
+ *   @{
+ *     @def TEGRA186_CLK_ACLK
+ *     @def TEGRA186_CLK_ADSP
+ *     @def TEGRA186_CLK_ADSPNEON
+ *     @def TEGRA186_CLK_AHUB
+ *     @def TEGRA186_CLK_APE
+ *     @def TEGRA186_CLK_APB2APE
+ *     @def TEGRA186_CLK_AUD_MCLK
+ *     @def TEGRA186_CLK_DMIC1
+ *     @def TEGRA186_CLK_DMIC2
+ *     @def TEGRA186_CLK_DMIC3
+ *     @def TEGRA186_CLK_DMIC4
+ *     @def TEGRA186_CLK_DSPK1
+ *     @def TEGRA186_CLK_DSPK2
+ *     @def TEGRA186_CLK_HDA
+ *     @def TEGRA186_CLK_HDA2CODEC_2X
+ *     @def TEGRA186_CLK_I2S1
+ *     @def TEGRA186_CLK_I2S2
+ *     @def TEGRA186_CLK_I2S3
+ *     @def TEGRA186_CLK_I2S4
+ *     @def TEGRA186_CLK_I2S5
+ *     @def TEGRA186_CLK_I2S6
+ *     @def TEGRA186_CLK_MAUD
+ *     @def TEGRA186_CLK_PLL_A_OUT0
+ *     @def TEGRA186_CLK_SPDIF_DOUBLER
+ *     @def TEGRA186_CLK_SPDIF_IN
+ *     @def TEGRA186_CLK_SPDIF_OUT
+ *     @def TEGRA186_CLK_SYNC_DMIC1
+ *     @def TEGRA186_CLK_SYNC_DMIC2
+ *     @def TEGRA186_CLK_SYNC_DMIC3
+ *     @def TEGRA186_CLK_SYNC_DMIC4
+ *     @def TEGRA186_CLK_SYNC_DMIC5
+ *     @def TEGRA186_CLK_SYNC_DSPK1
+ *     @def TEGRA186_CLK_SYNC_DSPK2
+ *     @def TEGRA186_CLK_SYNC_I2S1
+ *     @def TEGRA186_CLK_SYNC_I2S2
+ *     @def TEGRA186_CLK_SYNC_I2S3
+ *     @def TEGRA186_CLK_SYNC_I2S4
+ *     @def TEGRA186_CLK_SYNC_I2S5
+ *     @def TEGRA186_CLK_SYNC_I2S6
+ *     @def TEGRA186_CLK_SYNC_SPDIF
+ *   @}
+ *
+ *   @defgroup uart_clks UART clocks
+ *   @{
+ *     @def TEGRA186_CLK_AON_UART_FST_MIPI_CAL
+ *     @def TEGRA186_CLK_UARTA
+ *     @def TEGRA186_CLK_UARTB
+ *     @def TEGRA186_CLK_UARTC
+ *     @def TEGRA186_CLK_UARTD
+ *     @def TEGRA186_CLK_UARTE
+ *     @def TEGRA186_CLK_UARTF
+ *     @def TEGRA186_CLK_UARTG
+ *     @def TEGRA186_CLK_UART_FST_MIPI_CAL
+ *   @}
+ *
+ *   @defgroup i2c_clks I2C clocks
+ *   @{
+ *     @def TEGRA186_CLK_AON_I2C_SLOW
+ *     @def TEGRA186_CLK_I2C1
+ *     @def TEGRA186_CLK_I2C2
+ *     @def TEGRA186_CLK_I2C3
+ *     @def TEGRA186_CLK_I2C4
+ *     @def TEGRA186_CLK_I2C5
+ *     @def TEGRA186_CLK_I2C6
+ *     @def TEGRA186_CLK_I2C8
+ *     @def TEGRA186_CLK_I2C9
+ *     @def TEGRA186_CLK_I2C1
+ *     @def TEGRA186_CLK_I2C12
+ *     @def TEGRA186_CLK_I2C13
+ *     @def TEGRA186_CLK_I2C14
+ *     @def TEGRA186_CLK_I2C_SLOW
+ *     @def TEGRA186_CLK_VI_I2C
+ *   @}
+ *
+ *   @defgroup spi_clks SPI clocks
+ *   @{
+ *     @def TEGRA186_CLK_SPI1
+ *     @def TEGRA186_CLK_SPI2
+ *     @def TEGRA186_CLK_SPI3
+ *     @def TEGRA186_CLK_SPI4
+ *   @}
+ *
+ *   @defgroup storage storage related clocks
+ *   @{
+ *     @def TEGRA186_CLK_SATA
+ *     @def TEGRA186_CLK_SATA_OOB
+ *     @def TEGRA186_CLK_SATA_IOBIST
+ *     @def TEGRA186_CLK_SDMMC_LEGACY_TM
+ *     @def TEGRA186_CLK_SDMMC1
+ *     @def TEGRA186_CLK_SDMMC2
+ *     @def TEGRA186_CLK_SDMMC3
+ *     @def TEGRA186_CLK_SDMMC4
+ *     @def TEGRA186_CLK_QSPI
+ *     @def TEGRA186_CLK_QSPI_OUT
+ *     @def TEGRA186_CLK_UFSDEV_REF
+ *     @def TEGRA186_CLK_UFSHC
+ *   @}
+ *
+ *   @defgroup pwm_clks PWM clocks
+ *   @{
+ *     @def TEGRA186_CLK_PWM1
+ *     @def TEGRA186_CLK_PWM2
+ *     @def TEGRA186_CLK_PWM3
+ *     @def TEGRA186_CLK_PWM4
+ *     @def TEGRA186_CLK_PWM5
+ *     @def TEGRA186_CLK_PWM6
+ *     @def TEGRA186_CLK_PWM7
+ *     @def TEGRA186_CLK_PWM8
+ *   @}
+ *
+ *   @defgroup plls PLLs and related clocks
+ *   @{
+ *     @def TEGRA186_CLK_PLLREFE_OUT_GATED
+ *     @def TEGRA186_CLK_PLLREFE_OUT1
+ *     @def TEGRA186_CLK_PLLD_OUT1
+ *     @def TEGRA186_CLK_PLLP_OUT0
+ *     @def TEGRA186_CLK_PLLP_OUT5
+ *     @def TEGRA186_CLK_PLLA
+ *     @def TEGRA186_CLK_PLLE_PWRSEQ
+ *     @def TEGRA186_CLK_PLLA_OUT1
+ *     @def TEGRA186_CLK_PLLREFE_REF
+ *     @def TEGRA186_CLK_UPHY_PLL0_PWRSEQ
+ *     @def TEGRA186_CLK_UPHY_PLL1_PWRSEQ
+ *     @def TEGRA186_CLK_PLLREFE_PLLE_PASSTHROUGH
+ *     @def TEGRA186_CLK_PLLREFE_PEX
+ *     @def TEGRA186_CLK_PLLREFE_IDDQ
+ *     @def TEGRA186_CLK_PLLC_OUT_AON
+ *     @def TEGRA186_CLK_PLLC_OUT_ISP
+ *     @def TEGRA186_CLK_PLLC_OUT_VE
+ *     @def TEGRA186_CLK_PLLC4_OUT
+ *     @def TEGRA186_CLK_PLLREFE_OUT
+ *     @def TEGRA186_CLK_PLLREFE_PLL_REF
+ *     @def TEGRA186_CLK_PLLE
+ *     @def TEGRA186_CLK_PLLC
+ *     @def TEGRA186_CLK_PLLP
+ *     @def TEGRA186_CLK_PLLD
+ *     @def TEGRA186_CLK_PLLD2
+ *     @def TEGRA186_CLK_PLLREFE_VCO
+ *     @def TEGRA186_CLK_PLLC2
+ *     @def TEGRA186_CLK_PLLC3
+ *     @def TEGRA186_CLK_PLLDP
+ *     @def TEGRA186_CLK_PLLC4_VCO
+ *     @def TEGRA186_CLK_PLLA1
+ *     @def TEGRA186_CLK_PLLNVCSI
+ *     @def TEGRA186_CLK_PLLDISPHUB
+ *     @def TEGRA186_CLK_PLLD3
+ *     @def TEGRA186_CLK_PLLBPMPCAM
+ *     @def TEGRA186_CLK_PLLAON
+ *     @def TEGRA186_CLK_PLLU
+ *     @def TEGRA186_CLK_PLLC4_VCO_DIV2
+ *     @def TEGRA186_CLK_PLL_REF
+ *     @def TEGRA186_CLK_PLLREFE_OUT1_DIV5
+ *     @def TEGRA186_CLK_UTMIP_PLL_PWRSEQ
+ *     @def TEGRA186_CLK_PLL_U_48M
+ *     @def TEGRA186_CLK_PLL_U_480M
+ *     @def TEGRA186_CLK_PLLC4_OUT0
+ *     @def TEGRA186_CLK_PLLC4_OUT1
+ *     @def TEGRA186_CLK_PLLC4_OUT2
+ *     @def TEGRA186_CLK_PLLC4_OUT_MUX
+ *     @def TEGRA186_CLK_DFLLDISP_DIV
+ *     @def TEGRA186_CLK_PLLDISPHUB_DIV
+ *     @def TEGRA186_CLK_PLLP_DIV8
+ *   @}
+ *
+ *   @defgroup nafll_clks NAFLL clock sources
+ *   @{
+ *     @def TEGRA186_CLK_NAFLL_AXI_CBB
+ *     @def TEGRA186_CLK_NAFLL_BCPU
+ *     @def TEGRA186_CLK_NAFLL_BPMP
+ *     @def TEGRA186_CLK_NAFLL_DISP
+ *     @def TEGRA186_CLK_NAFLL_GPU
+ *     @def TEGRA186_CLK_NAFLL_ISP
+ *     @def TEGRA186_CLK_NAFLL_MCPU
+ *     @def TEGRA186_CLK_NAFLL_NVDEC
+ *     @def TEGRA186_CLK_NAFLL_NVENC
+ *     @def TEGRA186_CLK_NAFLL_NVJPG
+ *     @def TEGRA186_CLK_NAFLL_SCE
+ *     @def TEGRA186_CLK_NAFLL_SE
+ *     @def TEGRA186_CLK_NAFLL_TSEC
+ *     @def TEGRA186_CLK_NAFLL_TSECB
+ *     @def TEGRA186_CLK_NAFLL_VI
+ *     @def TEGRA186_CLK_NAFLL_VIC
+ *   @}
+ *
+ *   @defgroup mphy MPHY related clocks
+ *   @{
+ *     @def TEGRA186_CLK_MPHY_L0_RX_SYMB
+ *     @def TEGRA186_CLK_MPHY_L0_RX_LS_BIT
+ *     @def TEGRA186_CLK_MPHY_L0_TX_SYMB
+ *     @def TEGRA186_CLK_MPHY_L0_TX_LS_3XBIT
+ *     @def TEGRA186_CLK_MPHY_L0_RX_ANA
+ *     @def TEGRA186_CLK_MPHY_L1_RX_ANA
+ *     @def TEGRA186_CLK_MPHY_IOBIST
+ *     @def TEGRA186_CLK_MPHY_TX_1MHZ_REF
+ *     @def TEGRA186_CLK_MPHY_CORE_PLL_FIXED
+ *   @}
+ *
+ *   @defgroup eavb EAVB related clocks
+ *   @{
+ *     @def TEGRA186_CLK_EQOS_AXI
+ *     @def TEGRA186_CLK_EQOS_PTP_REF
+ *     @def TEGRA186_CLK_EQOS_RX
+ *     @def TEGRA186_CLK_EQOS_RX_INPUT
+ *     @def TEGRA186_CLK_EQOS_TX
+ *   @}
+ *
+ *   @defgroup usb USB related clocks
+ *   @{
+ *     @def TEGRA186_CLK_PEX_USB_PAD0_MGMT
+ *     @def TEGRA186_CLK_PEX_USB_PAD1_MGMT
+ *     @def TEGRA186_CLK_HSIC_TRK
+ *     @def TEGRA186_CLK_USB2_TRK
+ *     @def TEGRA186_CLK_USB2_HSIC_TRK
+ *     @def TEGRA186_CLK_XUSB_CORE_SS
+ *     @def TEGRA186_CLK_XUSB_CORE_DEV
+ *     @def TEGRA186_CLK_XUSB_FALCON
+ *     @def TEGRA186_CLK_XUSB_FS
+ *     @def TEGRA186_CLK_XUSB
+ *     @def TEGRA186_CLK_XUSB_DEV
+ *     @def TEGRA186_CLK_XUSB_HOST
+ *     @def TEGRA186_CLK_XUSB_SS
+ *   @}
+ *
+ *   @defgroup bigblock compute block related clocks
+ *   @{
+ *     @def TEGRA186_CLK_GPCCLK
+ *     @def TEGRA186_CLK_GPC2CLK
+ *     @def TEGRA186_CLK_GPU
+ *     @def TEGRA186_CLK_HOST1X
+ *     @def TEGRA186_CLK_ISP
+ *     @def TEGRA186_CLK_NVDEC
+ *     @def TEGRA186_CLK_NVENC
+ *     @def TEGRA186_CLK_NVJPG
+ *     @def TEGRA186_CLK_SE
+ *     @def TEGRA186_CLK_TSEC
+ *     @def TEGRA186_CLK_TSECB
+ *     @def TEGRA186_CLK_VIC
+ *   @}
+ *
+ *   @defgroup can CAN bus related clocks
+ *   @{
+ *     @def TEGRA186_CLK_CAN1
+ *     @def TEGRA186_CLK_CAN1_HOST
+ *     @def TEGRA186_CLK_CAN2
+ *     @def TEGRA186_CLK_CAN2_HOST
+ *   @}
+ *
+ *   @defgroup system basic system clocks
+ *   @{
+ *     @def TEGRA186_CLK_ACTMON
+ *     @def TEGRA186_CLK_AON_APB
+ *     @def TEGRA186_CLK_AON_CPU_NIC
+ *     @def TEGRA186_CLK_AON_NIC
+ *     @def TEGRA186_CLK_AXI_CBB
+ *     @def TEGRA186_CLK_BPMP_APB
+ *     @def TEGRA186_CLK_BPMP_CPU_NIC
+ *     @def TEGRA186_CLK_BPMP_NIC_RATE
+ *     @def TEGRA186_CLK_CLK_M
+ *     @def TEGRA186_CLK_EMC
+ *     @def TEGRA186_CLK_MSS_ENCRYPT
+ *     @def TEGRA186_CLK_SCE_APB
+ *     @def TEGRA186_CLK_SCE_CPU_NIC
+ *     @def TEGRA186_CLK_SCE_NIC
+ *     @def TEGRA186_CLK_TSC
+ *   @}
+ *
+ *   @defgroup pcie_clks PCIe related clocks
+ *   @{
+ *     @def TEGRA186_CLK_AFI
+ *     @def TEGRA186_CLK_PCIE
+ *     @def TEGRA186_CLK_PCIE2_IOBIST
+ *     @def TEGRA186_CLK_PCIERX0
+ *     @def TEGRA186_CLK_PCIERX1
+ *     @def TEGRA186_CLK_PCIERX2
+ *     @def TEGRA186_CLK_PCIERX3
+ *     @def TEGRA186_CLK_PCIERX4
+ *   @}
+ */
+
+/** @brief output of gate CLK_ENB_FUSE */
+#define TEGRA186_CLK_FUSE 0
+/**
+ * @brief It's not what you think
+ * @details output of gate CLK_ENB_GPU. This output connects to the GPU
+ * pwrclk. @warning: This is almost certainly not the clock you think
+ * it is. If you're looking for the clock of the graphics engine, see
+ * TEGRA186_GPCCLK
+ */
+#define TEGRA186_CLK_GPU 1
+/** @brief output of gate CLK_ENB_PCIE */
+#define TEGRA186_CLK_PCIE 3
+/** @brief output of the divider IPFS_CLK_DIVISOR */
+#define TEGRA186_CLK_AFI 4
+/** @brief output of gate CLK_ENB_PCIE2_IOBIST */
+#define TEGRA186_CLK_PCIE2_IOBIST 5
+/** @brief output of gate CLK_ENB_PCIERX0*/
+#define TEGRA186_CLK_PCIERX0 6
+/** @brief output of gate CLK_ENB_PCIERX1*/
+#define TEGRA186_CLK_PCIERX1 7
+/** @brief output of gate CLK_ENB_PCIERX2*/
+#define TEGRA186_CLK_PCIERX2 8
+/** @brief output of gate CLK_ENB_PCIERX3*/
+#define TEGRA186_CLK_PCIERX3 9
+/** @brief output of gate CLK_ENB_PCIERX4*/
+#define TEGRA186_CLK_PCIERX4 10
+/** @brief output branch of PLL_C for ISP, controlled by gate CLK_ENB_PLLC_OUT_ISP */
+#define TEGRA186_CLK_PLLC_OUT_ISP 11
+/** @brief output branch of PLL_C for VI, controlled by gate CLK_ENB_PLLC_OUT_VE */
+#define TEGRA186_CLK_PLLC_OUT_VE 12
+/** @brief output branch of PLL_C for AON domain, controlled by gate CLK_ENB_PLLC_OUT_AON */
+#define TEGRA186_CLK_PLLC_OUT_AON 13
+/** @brief output of gate CLK_ENB_SOR_SAFE */
+#define TEGRA186_CLK_SOR_SAFE 39
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2S2 */
+#define TEGRA186_CLK_I2S2 42
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2S3 */
+#define TEGRA186_CLK_I2S3 43
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SPDF_IN */
+#define TEGRA186_CLK_SPDIF_IN 44
+/** @brief output of gate CLK_ENB_SPDIF_DOUBLER */
+#define TEGRA186_CLK_SPDIF_DOUBLER 45
+/**  @clkdesc{spi_clks, out, mux, CLK_RST_CONTROLLER_CLK_SOURCE_SPI3} */
+#define TEGRA186_CLK_SPI3 46
+/** @clkdesc{i2c_clks, out, mux, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1} */
+#define TEGRA186_CLK_I2C1 47
+/** @clkdesc{i2c_clks, out, mux, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5} */
+#define TEGRA186_CLK_I2C5 48
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SPI1 */
+#define TEGRA186_CLK_SPI1 49
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_ISP */
+#define TEGRA186_CLK_ISP 50
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_VI */
+#define TEGRA186_CLK_VI 51
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 */
+#define TEGRA186_CLK_SDMMC1 52
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 */
+#define TEGRA186_CLK_SDMMC2 53
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4 */
+#define TEGRA186_CLK_SDMMC4 54
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTA */
+#define TEGRA186_CLK_UARTA 55
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTB */
+#define TEGRA186_CLK_UARTB 56
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X */
+#define TEGRA186_CLK_HOST1X 57
+/**
+ * @brief controls the EMC clock frequency.
+ * @details Doing a clk_set_rate on this clock will select the
+ * appropriate clock source, program the source rate and execute a
+ * specific sequence to switch to the new clock source for both memory
+ * controllers. This can be used to control the balance between memory
+ * throughput and memory controller power.
+ */
+#define TEGRA186_CLK_EMC 58
+/* @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH4 */
+#define TEGRA186_CLK_EXTPERIPH4 73
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SPI4 */
+#define TEGRA186_CLK_SPI4 74
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 */
+#define TEGRA186_CLK_I2C3 75
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 */
+#define TEGRA186_CLK_SDMMC3 76
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTD */
+#define TEGRA186_CLK_UARTD 77
+/** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2S1 */
+#define TEGRA186_CLK_I2S1 79
+/** output of gate CLK_ENB_DTV */
+#define TEGRA186_CLK_DTV 80
+/** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_TSEC */
+#define TEGRA186_CLK_TSEC 81
+/** @brief output of gate CLK_ENB_DP2 */
+#define TEGRA186_CLK_DP2 82
+/** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2S4 */
+#define TEGRA186_CLK_I2S4 84
+/** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2S5 */
+#define TEGRA186_CLK_I2S5 85
+/** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 */
+#define TEGRA186_CLK_I2C4 86
+/** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AHUB */
+#define TEGRA186_CLK_AHUB 87
+/** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_HDA2CODEC_2X */
+#define TEGRA186_CLK_HDA2CODEC_2X 88
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH1 */
+#define TEGRA186_CLK_EXTPERIPH1 89
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH2 */
+#define TEGRA186_CLK_EXTPERIPH2 90
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH3 */
+#define TEGRA186_CLK_EXTPERIPH3 91
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C_SLOW */
+#define TEGRA186_CLK_I2C_SLOW 92
+/** @brief output of the SOR1_CLK_SRC mux in CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 */
+#define TEGRA186_CLK_SOR1 93
+/** @brief output of gate CLK_ENB_CEC */
+#define TEGRA186_CLK_CEC 94
+/** @brief output of gate CLK_ENB_DPAUX1 */
+#define TEGRA186_CLK_DPAUX1 95
+/** @brief output of gate CLK_ENB_DPAUX */
+#define TEGRA186_CLK_DPAUX 96
+/** @brief output of the SOR0_CLK_SRC mux in CLK_RST_CONTROLLER_CLK_SOURCE_SOR0 */
+#define TEGRA186_CLK_SOR0 97
+/** @brief output of gate CLK_ENB_HDA2HDMICODEC */
+#define TEGRA186_CLK_HDA2HDMICODEC 98
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SATA */
+#define TEGRA186_CLK_SATA 99
+/** @brief output of gate CLK_ENB_SATA_OOB */
+#define TEGRA186_CLK_SATA_OOB 100
+/** @brief output of gate CLK_ENB_SATA_IOBIST */
+#define TEGRA186_CLK_SATA_IOBIST 101
+/** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_HDA */
+#define TEGRA186_CLK_HDA 102
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SE */
+#define TEGRA186_CLK_SE 103
+/** @brief output of gate CLK_ENB_APB2APE */
+#define TEGRA186_CLK_APB2APE 104
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_APE */
+#define TEGRA186_CLK_APE 105
+/** @brief output of gate CLK_ENB_IQC1 */
+#define TEGRA186_CLK_IQC1 106
+/** @brief output of gate CLK_ENB_IQC2 */
+#define TEGRA186_CLK_IQC2 107
+/** divide by 2 version of TEGRA186_CLK_PLLREFE_VCO */
+#define TEGRA186_CLK_PLLREFE_OUT 108
+/** @brief output of gate CLK_ENB_PLLREFE_PLL_REF */
+#define TEGRA186_CLK_PLLREFE_PLL_REF 109
+/** @brief output of gate CLK_ENB_PLLC4_OUT */
+#define TEGRA186_CLK_PLLC4_OUT 110
+/** @brief output of mux xusb_core_clk_switch on page 67 of T186_Clocks_IAS.doc */
+#define TEGRA186_CLK_XUSB 111
+/** controls xusb_dev_ce signal on page 66 and 67 of T186_Clocks_IAS.doc */
+#define TEGRA186_CLK_XUSB_DEV 112
+/** controls xusb_host_ce signal on page 67 of T186_Clocks_IAS.doc */
+#define TEGRA186_CLK_XUSB_HOST 113
+/** controls xusb_ss_ce signal on page 67 of T186_Clocks_IAS.doc */
+#define TEGRA186_CLK_XUSB_SS 114
+/** @brief output of gate CLK_ENB_DSI */
+#define TEGRA186_CLK_DSI 115
+/** @brief output of gate CLK_ENB_MIPI_CAL */
+#define TEGRA186_CLK_MIPI_CAL 116
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP */
+#define TEGRA186_CLK_DSIA_LP 117
+/** @brief output of gate CLK_ENB_DSIB */
+#define TEGRA186_CLK_DSIB 118
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DSIB_LP */
+#define TEGRA186_CLK_DSIB_LP 119
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DMIC1 */
+#define TEGRA186_CLK_DMIC1 122
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DMIC2 */
+#define TEGRA186_CLK_DMIC2 123
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AUD_MCLK */
+#define TEGRA186_CLK_AUD_MCLK 124
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 */
+#define TEGRA186_CLK_I2C6 125
+/**output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL */
+#define TEGRA186_CLK_UART_FST_MIPI_CAL 126
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_VIC */
+#define TEGRA186_CLK_VIC 127
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM */
+#define TEGRA186_CLK_SDMMC_LEGACY_TM 128
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVDEC */
+#define TEGRA186_CLK_NVDEC 129
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVJPG */
+#define TEGRA186_CLK_NVJPG 130
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVENC */
+#define TEGRA186_CLK_NVENC 131
+/** @brief output of the QSPI_CLK_SRC mux in CLK_RST_CONTROLLER_CLK_SOURCE_QSPI */
+#define TEGRA186_CLK_QSPI 132
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_VI_I2C */
+#define TEGRA186_CLK_VI_I2C 133
+/** @brief output of gate CLK_ENB_HSIC_TRK */
+#define TEGRA186_CLK_HSIC_TRK 134
+/** @brief output of gate CLK_ENB_USB2_TRK */
+#define TEGRA186_CLK_USB2_TRK 135
+/** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_MAUD */
+#define TEGRA186_CLK_MAUD 136
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_TSECB */
+#define TEGRA186_CLK_TSECB 137
+/** @brief output of gate CLK_ENB_ADSP */
+#define TEGRA186_CLK_ADSP 138
+/** @brief output of gate CLK_ENB_ADSPNEON */
+#define TEGRA186_CLK_ADSPNEON 139
+/** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_MPHY_L0_RX_LS_SYMB */
+#define TEGRA186_CLK_MPHY_L0_RX_SYMB 140
+/** @brief output of gate CLK_ENB_MPHY_L0_RX_LS_BIT */
+#define TEGRA186_CLK_MPHY_L0_RX_LS_BIT 141
+/** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_MPHY_L0_TX_LS_SYMB */
+#define TEGRA186_CLK_MPHY_L0_TX_SYMB 142
+/** @brief output of gate CLK_ENB_MPHY_L0_TX_LS_3XBIT */
+#define TEGRA186_CLK_MPHY_L0_TX_LS_3XBIT 143
+/** @brief output of gate CLK_ENB_MPHY_L0_RX_ANA */
+#define TEGRA186_CLK_MPHY_L0_RX_ANA 144
+/** @brief output of gate CLK_ENB_MPHY_L1_RX_ANA */
+#define TEGRA186_CLK_MPHY_L1_RX_ANA 145
+/** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_MPHY_IOBIST */
+#define TEGRA186_CLK_MPHY_IOBIST 146
+/** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_MPHY_TX_1MHZ_REF */
+#define TEGRA186_CLK_MPHY_TX_1MHZ_REF 147
+/** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_MPHY_CORE_PLL_FIXED */
+#define TEGRA186_CLK_MPHY_CORE_PLL_FIXED 148
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AXI_CBB */
+#define TEGRA186_CLK_AXI_CBB 149
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DMIC3 */
+#define TEGRA186_CLK_DMIC3 150
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DMIC4 */
+#define TEGRA186_CLK_DMIC4 151
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DSPK1 */
+#define TEGRA186_CLK_DSPK1 152
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DSPK2 */
+#define TEGRA186_CLK_DSPK2 153
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 */
+#define TEGRA186_CLK_I2S6 154
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVDISPLAY_P0 */
+#define TEGRA186_CLK_NVDISPLAY_P0 155
+/** @brief output of the NVDISPLAY_DISP_CLK_SRC mux in CLK_RST_CONTROLLER_CLK_SOURCE_NVDISPLAY_DISP */
+#define TEGRA186_CLK_NVDISPLAY_DISP 156
+/** @brief output of gate CLK_ENB_NVDISPLAY_DSC */
+#define TEGRA186_CLK_NVDISPLAY_DSC 157
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVDISPLAYHUB */
+#define TEGRA186_CLK_NVDISPLAYHUB 158
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVDISPLAY_P1 */
+#define TEGRA186_CLK_NVDISPLAY_P1 159
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVDISPLAY_P2 */
+#define TEGRA186_CLK_NVDISPLAY_P2 160
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_TACH */
+#define TEGRA186_CLK_TACH 166
+/** @brief output of gate CLK_ENB_EQOS */
+#define TEGRA186_CLK_EQOS_AXI 167
+/** @brief output of gate CLK_ENB_EQOS_RX */
+#define TEGRA186_CLK_EQOS_RX 168
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UFSHC_CG_SYS */
+#define TEGRA186_CLK_UFSHC 178
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UFSDEV_REF */
+#define TEGRA186_CLK_UFSDEV_REF 179
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVCSI */
+#define TEGRA186_CLK_NVCSI 180
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVCSILP */
+#define TEGRA186_CLK_NVCSILP 181
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C7 */
+#define TEGRA186_CLK_I2C7 182
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C9 */
+#define TEGRA186_CLK_I2C9 183
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C12 */
+#define TEGRA186_CLK_I2C12 184
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C13 */
+#define TEGRA186_CLK_I2C13 185
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C14 */
+#define TEGRA186_CLK_I2C14 186
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM1 */
+#define TEGRA186_CLK_PWM1 187
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM2 */
+#define TEGRA186_CLK_PWM2 188
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM3 */
+#define TEGRA186_CLK_PWM3 189
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM5 */
+#define TEGRA186_CLK_PWM5 190
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM6 */
+#define TEGRA186_CLK_PWM6 191
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM7 */
+#define TEGRA186_CLK_PWM7 192
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM8 */
+#define TEGRA186_CLK_PWM8 193
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTE */
+#define TEGRA186_CLK_UARTE 194
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTF */
+#define TEGRA186_CLK_UARTF 195
+/** @deprecated */
+#define TEGRA186_CLK_DBGAPB 196
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_BPMP_CPU_NIC */
+#define TEGRA186_CLK_BPMP_CPU_NIC 197
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_BPMP_APB */
+#define TEGRA186_CLK_BPMP_APB 199
+/** @brief output of mux controlled by TEGRA186_CLK_SOC_ACTMON */
+#define TEGRA186_CLK_ACTMON 201
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AON_CPU_NIC */
+#define TEGRA186_CLK_AON_CPU_NIC 208
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_CAN1 */
+#define TEGRA186_CLK_CAN1 210
+/** @brief output of gate CLK_ENB_CAN1_HOST */
+#define TEGRA186_CLK_CAN1_HOST 211
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_CAN2 */
+#define TEGRA186_CLK_CAN2 212
+/** @brief output of gate CLK_ENB_CAN2_HOST */
+#define TEGRA186_CLK_CAN2_HOST 213
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AON_APB */
+#define TEGRA186_CLK_AON_APB 214
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTC */
+#define TEGRA186_CLK_UARTC 215
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTG */
+#define TEGRA186_CLK_UARTG 216
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AON_UART_FST_MIPI_CAL */
+#define TEGRA186_CLK_AON_UART_FST_MIPI_CAL 217
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 */
+#define TEGRA186_CLK_I2C2 218
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C8 */
+#define TEGRA186_CLK_I2C8 219
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C10 */
+#define TEGRA186_CLK_I2C10 220
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AON_I2C_SLOW */
+#define TEGRA186_CLK_AON_I2C_SLOW 221
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SPI2 */
+#define TEGRA186_CLK_SPI2 222
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DMIC5 */
+#define TEGRA186_CLK_DMIC5 223
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AON_TOUCH */
+#define TEGRA186_CLK_AON_TOUCH 224
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM4 */
+#define TEGRA186_CLK_PWM4 225
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_TSC. This clock object is read only and is used for all timers in the system. */
+#define TEGRA186_CLK_TSC 226
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_MSS_ENCRYPT */
+#define TEGRA186_CLK_MSS_ENCRYPT 227
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SCE_CPU_NIC */
+#define TEGRA186_CLK_SCE_CPU_NIC 228
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SCE_APB */
+#define TEGRA186_CLK_SCE_APB 230
+/** @brief output of gate CLK_ENB_DSIC */
+#define TEGRA186_CLK_DSIC 231
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DSIC_LP */
+#define TEGRA186_CLK_DSIC_LP 232
+/** @brief output of gate CLK_ENB_DSID */
+#define TEGRA186_CLK_DSID 233
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DSID_LP */
+#define TEGRA186_CLK_DSID_LP 234
+/** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_PEX_SATA_USB_RX_BYP */
+#define TEGRA186_CLK_PEX_SATA_USB_RX_BYP 236
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SPDIF_OUT */
+#define TEGRA186_CLK_SPDIF_OUT 238
+/** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_EQOS_PTP_REF_CLK_0 */
+#define TEGRA186_CLK_EQOS_PTP_REF 239
+/** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_EQOS_TX_CLK */
+#define TEGRA186_CLK_EQOS_TX 240
+/** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK */
+#define TEGRA186_CLK_USB2_HSIC_TRK 241
+/** @brief output of mux xusb_ss_clk_switch on page 66 of T186_Clocks_IAS.doc */
+#define TEGRA186_CLK_XUSB_CORE_SS 242
+/** @brief output of mux xusb_core_dev_clk_switch on page 67 of T186_Clocks_IAS.doc */
+#define TEGRA186_CLK_XUSB_CORE_DEV 243
+/** @brief output of mux xusb_core_falcon_clk_switch on page 67 of T186_Clocks_IAS.doc */
+#define TEGRA186_CLK_XUSB_FALCON 244
+/** @brief output of mux xusb_fs_clk_switch on page 66 of T186_Clocks_IAS.doc */
+#define TEGRA186_CLK_XUSB_FS 245
+/** @brief output of the divider CLK_RST_CONTROLLER_PLLA_OUT */
+#define TEGRA186_CLK_PLL_A_OUT0 246
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S1 */
+#define TEGRA186_CLK_SYNC_I2S1 247
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S2 */
+#define TEGRA186_CLK_SYNC_I2S2 248
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S3 */
+#define TEGRA186_CLK_SYNC_I2S3 249
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S4 */
+#define TEGRA186_CLK_SYNC_I2S4 250
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S5 */
+#define TEGRA186_CLK_SYNC_I2S5 251
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S6 */
+#define TEGRA186_CLK_SYNC_I2S6 252
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_DSPK1 */
+#define TEGRA186_CLK_SYNC_DSPK1 253
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_DSPK2 */
+#define TEGRA186_CLK_SYNC_DSPK2 254
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_DMIC1 */
+#define TEGRA186_CLK_SYNC_DMIC1 255
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_DMIC2 */
+#define TEGRA186_CLK_SYNC_DMIC2 256
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_DMIC3 */
+#define TEGRA186_CLK_SYNC_DMIC3 257
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_DMIC4 */
+#define TEGRA186_CLK_SYNC_DMIC4 259
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_SPDIF */
+#define TEGRA186_CLK_SYNC_SPDIF 260
+/** @brief output of gate CLK_ENB_PLLREFE_OUT */
+#define TEGRA186_CLK_PLLREFE_OUT_GATED 261
+/** @brief output of the divider PLLREFE_DIVP in CLK_RST_CONTROLLER_PLLREFE_BASE. PLLREFE has 2 outputs:
+  *      * VCO/pdiv defined by this clock object
+  *      * VCO/2 defined by TEGRA186_CLK_PLLREFE_OUT
+  */
+#define TEGRA186_CLK_PLLREFE_OUT1 262
+#define TEGRA186_CLK_PLLD_OUT1 267
+/** @brief output of the divider PLLP_DIVP in CLK_RST_CONTROLLER_PLLP_BASE */
+#define TEGRA186_CLK_PLLP_OUT0 269
+/** @brief output of the divider CLK_RST_CONTROLLER_PLLP_OUTC */
+#define TEGRA186_CLK_PLLP_OUT5 270
+/** PLL controlled by CLK_RST_CONTROLLER_PLLA_BASE for use by audio clocks */
+#define TEGRA186_CLK_PLLA 271
+/** @brief output of mux controlled by CLK_RST_CONTROLLER_ACLK_BURST_POLICY divided by the divider controlled by ACLK_CLK_DIVISOR in CLK_RST_CONTROLLER_SUPER_ACLK_DIVIDER */
+#define TEGRA186_CLK_ACLK 273
+/** fixed 48MHz clock divided down from TEGRA186_CLK_PLL_U */
+#define TEGRA186_CLK_PLL_U_48M 274
+/** fixed 480MHz clock divided down from TEGRA186_CLK_PLL_U */
+#define TEGRA186_CLK_PLL_U_480M 275
+/** @brief output of the divider PLLC4_DIVP in CLK_RST_CONTROLLER_PLLC4_BASE. Output frequency is TEGRA186_CLK_PLLC4_VCO/PLLC4_DIVP */
+#define TEGRA186_CLK_PLLC4_OUT0 276
+/** fixed /3 divider. Output frequency of this clock is TEGRA186_CLK_PLLC4_VCO/3 */
+#define TEGRA186_CLK_PLLC4_OUT1 277
+/** fixed /5 divider. Output frequency of this clock is TEGRA186_CLK_PLLC4_VCO/5 */
+#define TEGRA186_CLK_PLLC4_OUT2 278
+/** @brief output of mux controlled by PLLC4_CLK_SEL in CLK_RST_CONTROLLER_PLLC4_MISC1 */
+#define TEGRA186_CLK_PLLC4_OUT_MUX 279
+/** @brief output of divider NVDISPLAY_DISP_CLK_DIVISOR in CLK_RST_CONTROLLER_CLK_SOURCE_NVDISPLAY_DISP when DFLLDISP_DIV is selected in NVDISPLAY_DISP_CLK_SRC */
+#define TEGRA186_CLK_DFLLDISP_DIV 284
+/** @brief output of divider NVDISPLAY_DISP_CLK_DIVISOR in CLK_RST_CONTROLLER_CLK_SOURCE_NVDISPLAY_DISP when PLLDISPHUB_DIV is selected in NVDISPLAY_DISP_CLK_SRC */
+#define TEGRA186_CLK_PLLDISPHUB_DIV 285
+/** fixed /8 divider which is used as the input for TEGRA186_CLK_SOR_SAFE */
+#define TEGRA186_CLK_PLLP_DIV8 286
+/** @brief output of divider CLK_RST_CONTROLLER_BPMP_NIC_RATE */
+#define TEGRA186_CLK_BPMP_NIC 287
+/** @brief output of the divider CLK_RST_CONTROLLER_PLLA1_OUT1 */
+#define TEGRA186_CLK_PLL_A_OUT1 288
+/** @deprecated */
+#define TEGRA186_CLK_GPC2CLK 289
+/** A fake clock which must be enabled during KFUSE read operations to ensure adequate VDD_CORE voltage. */
+#define TEGRA186_CLK_KFUSE 293
+/**
+ * @brief controls the PLLE hardware sequencer.
+ * @details This clock only has enable and disable methods. When the
+ * PLLE hw sequencer is enabled, PLLE, will be enabled or disabled by
+ * hw based on the control signals from the PCIe, SATA and XUSB
+ * clocks. When the PLLE hw sequencer is disabled, the state of PLLE
+ * is controlled by sw using clk_enable/clk_disable on
+ * TEGRA186_CLK_PLLE.
+ */
+#define TEGRA186_CLK_PLLE_PWRSEQ 294
+/** fixed 60MHz clock divided down from, TEGRA186_CLK_PLL_U */
+#define TEGRA186_CLK_PLLREFE_REF 295
+/** @brief output of mux controlled by SOR0_CLK_SEL0 and SOR0_CLK_SEL1 in CLK_RST_CONTROLLER_CLK_SOURCE_SOR0 */
+#define TEGRA186_CLK_SOR0_OUT 296
+/** @brief output of mux controlled by SOR1_CLK_SEL0 and SOR1_CLK_SEL1 in CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 */
+#define TEGRA186_CLK_SOR1_OUT 297
+/** @brief fixed /5 divider.  Output frequency of this clock is TEGRA186_CLK_PLLREFE_OUT1/5. Used as input for TEGRA186_CLK_EQOS_AXI */
+#define TEGRA186_CLK_PLLREFE_OUT1_DIV5 298
+/** @brief controls the UTMIP_PLL (aka PLLU) hardware sqeuencer */
+#define TEGRA186_CLK_UTMIP_PLL_PWRSEQ 301
+/** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_PEX_USB_PAD_PLL0_MGMT */
+#define TEGRA186_CLK_PEX_USB_PAD0_MGMT 302
+/** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_PEX_USB_PAD_PLL1_MGMT */
+#define TEGRA186_CLK_PEX_USB_PAD1_MGMT 303
+/** @brief controls the UPHY_PLL0 hardware sqeuencer */
+#define TEGRA186_CLK_UPHY_PLL0_PWRSEQ 304
+/** @brief controls the UPHY_PLL1 hardware sqeuencer */
+#define TEGRA186_CLK_UPHY_PLL1_PWRSEQ 305
+/** @brief control for PLLREFE_IDDQ in CLK_RST_CONTROLLER_PLLREFE_MISC so the bypass output even be used when the PLL is disabled */
+#define TEGRA186_CLK_PLLREFE_PLLE_PASSTHROUGH 306
+/** @brief output of the mux controlled by PLLREFE_SEL_CLKIN_PEX in CLK_RST_CONTROLLER_PLLREFE_MISC */
+#define TEGRA186_CLK_PLLREFE_PEX 307
+/** @brief control for PLLREFE_IDDQ in CLK_RST_CONTROLLER_PLLREFE_MISC to turn on the PLL when enabled */
+#define TEGRA186_CLK_PLLREFE_IDDQ 308
+/** @brief output of the divider QSPI_CLK_DIV2_SEL in CLK_RST_CONTROLLER_CLK_SOURCE_QSPI */
+#define TEGRA186_CLK_QSPI_OUT 309
+/**
+ * @brief GPC2CLK-div-2
+ * @details fixed /2 divider. Output frequency is
+ * TEGRA186_CLK_GPC2CLK/2. The frequency of this clock is the
+ * frequency at which the GPU graphics engine runs. */
+#define TEGRA186_CLK_GPCCLK 310
+/** @brief output of divider CLK_RST_CONTROLLER_AON_NIC_RATE */
+#define TEGRA186_CLK_AON_NIC 450
+/** @brief output of divider CLK_RST_CONTROLLER_SCE_NIC_RATE */
+#define TEGRA186_CLK_SCE_NIC 451
+/** Fixed 100MHz PLL for PCIe, SATA and superspeed USB */
+#define TEGRA186_CLK_PLLE 512
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLC_BASE */
+#define TEGRA186_CLK_PLLC 513
+/** Fixed 408MHz PLL for use by peripheral clocks */
+#define TEGRA186_CLK_PLLP 516
+/** @deprecated */
+#define TEGRA186_CLK_PLL_P TEGRA186_CLK_PLLP
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLD_BASE for use by DSI */
+#define TEGRA186_CLK_PLLD 518
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLD2_BASE for use by HDMI or DP */
+#define TEGRA186_CLK_PLLD2 519
+/**
+ * @brief PLL controlled by CLK_RST_CONTROLLER_PLLREFE_BASE.
+ * @details Note that this clock only controls the VCO output, before
+ * the post-divider. See TEGRA186_CLK_PLLREFE_OUT1 for more
+ * information.
+ */
+#define TEGRA186_CLK_PLLREFE_VCO 520
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLC2_BASE */
+#define TEGRA186_CLK_PLLC2 521
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLC3_BASE */
+#define TEGRA186_CLK_PLLC3 522
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLDP_BASE for use as the DP link clock */
+#define TEGRA186_CLK_PLLDP 523
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLC4_BASE */
+#define TEGRA186_CLK_PLLC4_VCO 524
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLA1_BASE for use by audio clocks */
+#define TEGRA186_CLK_PLLA1 525
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLNVCSI_BASE */
+#define TEGRA186_CLK_PLLNVCSI 526
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLDISPHUB_BASE */
+#define TEGRA186_CLK_PLLDISPHUB 527
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLD3_BASE for use by HDMI or DP */
+#define TEGRA186_CLK_PLLD3 528
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLBPMPCAM_BASE */
+#define TEGRA186_CLK_PLLBPMPCAM 531
+/** @brief PLL controlled by CLK_RST_CONTROLLER_PLLAON_BASE for use by IP blocks in the AON domain */
+#define TEGRA186_CLK_PLLAON 532
+/** Fixed frequency 960MHz PLL for USB and EAVB */
+#define TEGRA186_CLK_PLLU 533
+/** fixed /2 divider. Output frequency is TEGRA186_CLK_PLLC4_VCO/2 */
+#define TEGRA186_CLK_PLLC4_VCO_DIV2 535
+/** @brief NAFLL clock source for AXI_CBB */
+#define TEGRA186_CLK_NAFLL_AXI_CBB 564
+/** @brief NAFLL clock source for BPMP */
+#define TEGRA186_CLK_NAFLL_BPMP 565
+/** @brief NAFLL clock source for ISP */
+#define TEGRA186_CLK_NAFLL_ISP 566
+/** @brief NAFLL clock source for NVDEC */
+#define TEGRA186_CLK_NAFLL_NVDEC 567
+/** @brief NAFLL clock source for NVENC */
+#define TEGRA186_CLK_NAFLL_NVENC 568
+/** @brief NAFLL clock source for NVJPG */
+#define TEGRA186_CLK_NAFLL_NVJPG 569
+/** @brief NAFLL clock source for SCE */
+#define TEGRA186_CLK_NAFLL_SCE 570
+/** @brief NAFLL clock source for SE */
+#define TEGRA186_CLK_NAFLL_SE 571
+/** @brief NAFLL clock source for TSEC */
+#define TEGRA186_CLK_NAFLL_TSEC 572
+/** @brief NAFLL clock source for TSECB */
+#define TEGRA186_CLK_NAFLL_TSECB 573
+/** @brief NAFLL clock source for VI */
+#define TEGRA186_CLK_NAFLL_VI 574
+/** @brief NAFLL clock source for VIC */
+#define TEGRA186_CLK_NAFLL_VIC 575
+/** @brief NAFLL clock source for DISP */
+#define TEGRA186_CLK_NAFLL_DISP 576
+/** @brief NAFLL clock source for GPU */
+#define TEGRA186_CLK_NAFLL_GPU 577
+/** @brief NAFLL clock source for M-CPU cluster */
+#define TEGRA186_CLK_NAFLL_MCPU 578
+/** @brief NAFLL clock source for B-CPU cluster */
+#define TEGRA186_CLK_NAFLL_BCPU 579
+/** @brief input from Tegra's CLK_32K_IN pad */
+#define TEGRA186_CLK_CLK_32K 608
+/** @brief output of divider CLK_RST_CONTROLLER_CLK_M_DIVIDE */
+#define TEGRA186_CLK_CLK_M 609
+/** @brief output of divider PLL_REF_DIV in CLK_RST_CONTROLLER_OSC_CTRL */
+#define TEGRA186_CLK_PLL_REF 610
+/** @brief input from Tegra's XTAL_IN */
+#define TEGRA186_CLK_OSC 612
+/** @brief clock recovered from EAVB input */
+#define TEGRA186_CLK_EQOS_RX_INPUT 613
+/** @brief clock recovered from DTV input */
+#define TEGRA186_CLK_DTV_INPUT 614
+/** @brief SOR0 brick output which feeds into SOR0_CLK_SEL mux in CLK_RST_CONTROLLER_CLK_SOURCE_SOR0*/
+#define TEGRA186_CLK_SOR0_PAD_CLKOUT 615
+/** @brief SOR1 brick output which feeds into SOR1_CLK_SEL mux in CLK_RST_CONTROLLER_CLK_SOURCE_SOR1*/
+#define TEGRA186_CLK_SOR1_PAD_CLKOUT 616
+/** @brief clock recovered from I2S1 input */
+#define TEGRA186_CLK_I2S1_SYNC_INPUT 617
+/** @brief clock recovered from I2S2 input */
+#define TEGRA186_CLK_I2S2_SYNC_INPUT 618
+/** @brief clock recovered from I2S3 input */
+#define TEGRA186_CLK_I2S3_SYNC_INPUT 619
+/** @brief clock recovered from I2S4 input */
+#define TEGRA186_CLK_I2S4_SYNC_INPUT 620
+/** @brief clock recovered from I2S5 input */
+#define TEGRA186_CLK_I2S5_SYNC_INPUT 621
+/** @brief clock recovered from I2S6 input */
+#define TEGRA186_CLK_I2S6_SYNC_INPUT 622
+/** @brief clock recovered from SPDIFIN input */
+#define TEGRA186_CLK_SPDIFIN_SYNC_INPUT 623
+
+/**
+ * @brief subject to change
+ * @details maximum clock identifier value plus one.
+ */
+#define TEGRA186_CLK_CLK_MAX 624
+
+/** @} */
+
+#endif
diff --git a/include/dt-bindings/mailbox/tegra186-hsp.h b/include/dt-bindings/mailbox/tegra186-hsp.h
new file mode 100644 (file)
index 0000000..f5d66e5
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * This header provides constants for binding nvidia,tegra186-hsp.
+ */
+
+#ifndef _DT_BINDINGS_MAILBOX_TEGRA186_HSP_H
+#define _DT_BINDINGS_MAILBOX_TEGRA186_HSP_H
+
+/*
+ * These define the type of mailbox that is to be used (doorbell, shared
+ * mailbox, shared semaphore or arbitrated semaphore).
+ */
+#define TEGRA_HSP_MBOX_TYPE_DB 0x0
+#define TEGRA_HSP_MBOX_TYPE_SM 0x1
+#define TEGRA_HSP_MBOX_TYPE_SS 0x2
+#define TEGRA_HSP_MBOX_TYPE_AS 0x3
+
+/*
+ * These defines represent the bit associated with the given master ID in the
+ * doorbell registers.
+ */
+#define TEGRA_HSP_DB_MASTER_CCPLEX 17
+#define TEGRA_HSP_DB_MASTER_BPMP 19
+
+#endif
diff --git a/include/dt-bindings/power/tegra186-powergate.h b/include/dt-bindings/power/tegra186-powergate.h
new file mode 100644 (file)
index 0000000..388d6e2
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2015-2016, 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/>.
+ */
+
+#ifndef _DT_BINDINGS_POWER_TEGRA186_POWERGATE_H
+#define _DT_BINDINGS_POWER_TEGRA186_POWERGATE_H
+
+#define TEGRA186_POWER_DOMAIN_AUD      0
+#define TEGRA186_POWER_DOMAIN_DFD      1
+#define TEGRA186_POWER_DOMAIN_DISP     2
+#define TEGRA186_POWER_DOMAIN_DISPB    3
+#define TEGRA186_POWER_DOMAIN_DISPC    4
+#define TEGRA186_POWER_DOMAIN_ISPA     5
+#define TEGRA186_POWER_DOMAIN_NVDEC    6
+#define TEGRA186_POWER_DOMAIN_NVJPG    7
+#define TEGRA186_POWER_DOMAIN_MPE      8
+#define TEGRA186_POWER_DOMAIN_PCX      9
+#define TEGRA186_POWER_DOMAIN_SAX      10
+#define TEGRA186_POWER_DOMAIN_VE       11
+#define TEGRA186_POWER_DOMAIN_VIC      12
+#define TEGRA186_POWER_DOMAIN_XUSBA    13
+#define TEGRA186_POWER_DOMAIN_XUSBB    14
+#define TEGRA186_POWER_DOMAIN_XUSBC    15
+#define TEGRA186_POWER_DOMAIN_GPU      43
+#define TEGRA186_POWER_DOMAIN_MAX      44
+
+#endif
diff --git a/include/dt-bindings/reset/tegra186-reset.h b/include/dt-bindings/reset/tegra186-reset.h
new file mode 100644 (file)
index 0000000..8a184e3
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2015, 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/>.
+ */
+
+#ifndef _ABI_MACH_T186_RESET_T186_H_
+#define _ABI_MACH_T186_RESET_T186_H_
+
+
+#define TEGRA186_RESET_ACTMON                  0
+#define TEGRA186_RESET_AFI                     1
+#define TEGRA186_RESET_CEC                     2
+#define TEGRA186_RESET_CSITE                   3
+#define TEGRA186_RESET_DP2                     4
+#define TEGRA186_RESET_DPAUX                   5
+#define TEGRA186_RESET_DSI                     6
+#define TEGRA186_RESET_DSIB                    7
+#define TEGRA186_RESET_DTV                     8
+#define TEGRA186_RESET_DVFS                    9
+#define TEGRA186_RESET_ENTROPY                 10
+#define TEGRA186_RESET_EXTPERIPH1              11
+#define TEGRA186_RESET_EXTPERIPH2              12
+#define TEGRA186_RESET_EXTPERIPH3              13
+#define TEGRA186_RESET_GPU                     14
+#define TEGRA186_RESET_HDA                     15
+#define TEGRA186_RESET_HDA2CODEC_2X            16
+#define TEGRA186_RESET_HDA2HDMICODEC           17
+#define TEGRA186_RESET_HOST1X                  18
+#define TEGRA186_RESET_I2C1                    19
+#define TEGRA186_RESET_I2C2                    20
+#define TEGRA186_RESET_I2C3                    21
+#define TEGRA186_RESET_I2C4                    22
+#define TEGRA186_RESET_I2C5                    23
+#define TEGRA186_RESET_I2C6                    24
+#define TEGRA186_RESET_ISP                     25
+#define TEGRA186_RESET_KFUSE                   26
+#define TEGRA186_RESET_LA                      27
+#define TEGRA186_RESET_MIPI_CAL                        28
+#define TEGRA186_RESET_PCIE                    29
+#define TEGRA186_RESET_PCIEXCLK                        30
+#define TEGRA186_RESET_SATA                    31
+#define TEGRA186_RESET_SATACOLD                        32
+#define TEGRA186_RESET_SDMMC1                  33
+#define TEGRA186_RESET_SDMMC2                  34
+#define TEGRA186_RESET_SDMMC3                  35
+#define TEGRA186_RESET_SDMMC4                  36
+#define TEGRA186_RESET_SE                      37
+#define TEGRA186_RESET_SOC_THERM               38
+#define TEGRA186_RESET_SOR0                    39
+#define TEGRA186_RESET_SPI1                    40
+#define TEGRA186_RESET_SPI2                    41
+#define TEGRA186_RESET_SPI3                    42
+#define TEGRA186_RESET_SPI4                    43
+#define TEGRA186_RESET_TMR                     44
+#define TEGRA186_RESET_TRIG_SYS                        45
+#define TEGRA186_RESET_TSEC                    46
+#define TEGRA186_RESET_UARTA                   47
+#define TEGRA186_RESET_UARTB                   48
+#define TEGRA186_RESET_UARTC                   49
+#define TEGRA186_RESET_UARTD                   50
+#define TEGRA186_RESET_VI                      51
+#define TEGRA186_RESET_VIC                     52
+#define TEGRA186_RESET_XUSB_DEV                        53
+#define TEGRA186_RESET_XUSB_HOST               54
+#define TEGRA186_RESET_XUSB_PADCTL             55
+#define TEGRA186_RESET_XUSB_SS                 56
+#define TEGRA186_RESET_AON_APB                 57
+#define TEGRA186_RESET_AXI_CBB                 58
+#define TEGRA186_RESET_BPMP_APB                        59
+#define TEGRA186_RESET_CAN1                    60
+#define TEGRA186_RESET_CAN2                    61
+#define TEGRA186_RESET_DMIC5                   62
+#define TEGRA186_RESET_DSIC                    63
+#define TEGRA186_RESET_DSID                    64
+#define TEGRA186_RESET_EMC_EMC                 65
+#define TEGRA186_RESET_EMC_MEM                 66
+#define TEGRA186_RESET_EMCSB_EMC               67
+#define TEGRA186_RESET_EMCSB_MEM               68
+#define TEGRA186_RESET_EQOS                    69
+#define TEGRA186_RESET_GPCDMA                  70
+#define TEGRA186_RESET_GPIO_CTL0               71
+#define TEGRA186_RESET_GPIO_CTL1               72
+#define TEGRA186_RESET_GPIO_CTL2               73
+#define TEGRA186_RESET_GPIO_CTL3               74
+#define TEGRA186_RESET_GPIO_CTL4               75
+#define TEGRA186_RESET_GPIO_CTL5               76
+#define TEGRA186_RESET_I2C10                   77
+#define TEGRA186_RESET_I2C12                   78
+#define TEGRA186_RESET_I2C13                   79
+#define TEGRA186_RESET_I2C14                   80
+#define TEGRA186_RESET_I2C7                    81
+#define TEGRA186_RESET_I2C8                    82
+#define TEGRA186_RESET_I2C9                    83
+#define TEGRA186_RESET_JTAG2AXI                        84
+#define TEGRA186_RESET_MPHY_IOBIST             85
+#define TEGRA186_RESET_MPHY_L0_RX              86
+#define TEGRA186_RESET_MPHY_L0_TX              87
+#define TEGRA186_RESET_NVCSI                   88
+#define TEGRA186_RESET_NVDISPLAY0_HEAD0                89
+#define TEGRA186_RESET_NVDISPLAY0_HEAD1                90
+#define TEGRA186_RESET_NVDISPLAY0_HEAD2                91
+#define TEGRA186_RESET_NVDISPLAY0_MISC         92
+#define TEGRA186_RESET_NVDISPLAY0_WGRP0                93
+#define TEGRA186_RESET_NVDISPLAY0_WGRP1                94
+#define TEGRA186_RESET_NVDISPLAY0_WGRP2                95
+#define TEGRA186_RESET_NVDISPLAY0_WGRP3                96
+#define TEGRA186_RESET_NVDISPLAY0_WGRP4                97
+#define TEGRA186_RESET_NVDISPLAY0_WGRP5                98
+#define TEGRA186_RESET_PWM1                    99
+#define TEGRA186_RESET_PWM2                    100
+#define TEGRA186_RESET_PWM3                    101
+#define TEGRA186_RESET_PWM4                    102
+#define TEGRA186_RESET_PWM5                    103
+#define TEGRA186_RESET_PWM6                    104
+#define TEGRA186_RESET_PWM7                    105
+#define TEGRA186_RESET_PWM8                    106
+#define TEGRA186_RESET_SCE_APB                 107
+#define TEGRA186_RESET_SOR1                    108
+#define TEGRA186_RESET_TACH                    109
+#define TEGRA186_RESET_TSC                     110
+#define TEGRA186_RESET_UARTF                   111
+#define TEGRA186_RESET_UARTG                   112
+#define TEGRA186_RESET_UFSHC                   113
+#define TEGRA186_RESET_UFSHC_AXI_M             114
+#define TEGRA186_RESET_UPHY                    115
+#define TEGRA186_RESET_ADSP                    116
+#define TEGRA186_RESET_ADSPDBG                 117
+#define TEGRA186_RESET_ADSPINTF                        118
+#define TEGRA186_RESET_ADSPNEON                        119
+#define TEGRA186_RESET_ADSPPERIPH              120
+#define TEGRA186_RESET_ADSPSCU                 121
+#define TEGRA186_RESET_ADSPWDT                 122
+#define TEGRA186_RESET_APE                     123
+#define TEGRA186_RESET_DPAUX1                  124
+#define TEGRA186_RESET_NVDEC                   125
+#define TEGRA186_RESET_NVENC                   126
+#define TEGRA186_RESET_NVJPG                   127
+#define TEGRA186_RESET_PEX_USB_UPHY            128
+#define TEGRA186_RESET_QSPI                    129
+#define TEGRA186_RESET_TSECB                   130
+#define TEGRA186_RESET_VI_I2C                  131
+#define TEGRA186_RESET_UARTE                   132
+#define TEGRA186_RESET_TOP_GTE                 133
+#define TEGRA186_RESET_SHSP                    134
+#define TEGRA186_RESET_PEX_USB_UPHY_L5         135
+#define TEGRA186_RESET_PEX_USB_UPHY_L4         136
+#define TEGRA186_RESET_PEX_USB_UPHY_L3         137
+#define TEGRA186_RESET_PEX_USB_UPHY_L2         138
+#define TEGRA186_RESET_PEX_USB_UPHY_L1         139
+#define TEGRA186_RESET_PEX_USB_UPHY_L0         140
+#define TEGRA186_RESET_PEX_USB_UPHY_PLL1       141
+#define TEGRA186_RESET_PEX_USB_UPHY_PLL0       142
+#define TEGRA186_RESET_TSCTNVI                 143
+#define TEGRA186_RESET_EXTPERIPH4              144
+#define TEGRA186_RESET_DSIPADCTL               145
+#define TEGRA186_RESET_AUD_MCLK                        146
+#define TEGRA186_RESET_MPHY_CLK_CTL            147
+#define TEGRA186_RESET_MPHY_L1_RX              148
+#define TEGRA186_RESET_MPHY_L1_TX              149
+#define TEGRA186_RESET_UFSHC_LP                        150
+#define TEGRA186_RESET_BPMP_NIC                        151
+#define TEGRA186_RESET_BPMP_NSYSPORESET                152
+#define TEGRA186_RESET_BPMP_NRESET             153
+#define TEGRA186_RESET_BPMP_DBGRESETN          154
+#define TEGRA186_RESET_BPMP_PRESETDBGN         155
+#define TEGRA186_RESET_BPMP_PM                 156
+#define TEGRA186_RESET_BPMP_CVC                        157
+#define TEGRA186_RESET_BPMP_DMA                        158
+#define TEGRA186_RESET_BPMP_HSP                        159
+#define TEGRA186_RESET_TSCTNBPMP               160
+#define TEGRA186_RESET_BPMP_TKE                        161
+#define TEGRA186_RESET_BPMP_GTE                        162
+#define TEGRA186_RESET_BPMP_PM_ACTMON          163
+#define TEGRA186_RESET_AON_NIC                 164
+#define TEGRA186_RESET_AON_NSYSPORESET         165
+#define TEGRA186_RESET_AON_NRESET              166
+#define TEGRA186_RESET_AON_DBGRESETN           167
+#define TEGRA186_RESET_AON_PRESETDBGN          168
+#define TEGRA186_RESET_AON_ACTMON              169
+#define TEGRA186_RESET_AOPM                    170
+#define TEGRA186_RESET_AOVC                    171
+#define TEGRA186_RESET_AON_DMA                 172
+#define TEGRA186_RESET_AON_GPIO                        173
+#define TEGRA186_RESET_AON_HSP                 174
+#define TEGRA186_RESET_TSCTNAON                        175
+#define TEGRA186_RESET_AON_TKE                 176
+#define TEGRA186_RESET_AON_GTE                 177
+#define TEGRA186_RESET_SCE_NIC                 178
+#define TEGRA186_RESET_SCE_NSYSPORESET         179
+#define TEGRA186_RESET_SCE_NRESET              180
+#define TEGRA186_RESET_SCE_DBGRESETN           181
+#define TEGRA186_RESET_SCE_PRESETDBGN          182
+#define TEGRA186_RESET_SCE_ACTMON              183
+#define TEGRA186_RESET_SCE_PM                  184
+#define TEGRA186_RESET_SCE_DMA                 185
+#define TEGRA186_RESET_SCE_HSP                 186
+#define TEGRA186_RESET_TSCTNSCE                        187
+#define TEGRA186_RESET_SCE_TKE                 188
+#define TEGRA186_RESET_SCE_GTE                 189
+#define TEGRA186_RESET_SCE_CFG                 190
+#define TEGRA186_RESET_ADSP_ALL                        191
+/** @brief controls the power up/down sequence of UFSHC PSW partition. Controls LP_PWR_READY, LP_ISOL_EN, and LP_RESET_N signals */
+#define TEGRA186_RESET_UFSHC_LP_SEQ            192
+#define TEGRA186_RESET_SIZE                    193
+
+#endif
diff --git a/include/soc/tegra/bpmp-abi.h b/include/soc/tegra/bpmp-abi.h
new file mode 100644 (file)
index 0000000..0aaef59
--- /dev/null
@@ -0,0 +1,1601 @@
+/*
+ * Copyright (c) 2014-2016, 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/>.
+ */
+
+#ifndef _ABI_BPMP_ABI_H_
+#define _ABI_BPMP_ABI_H_
+
+#ifdef LK
+#include <stdint.h>
+#endif
+
+#ifndef __ABI_PACKED
+#define __ABI_PACKED __attribute__((packed))
+#endif
+
+#ifdef NO_GCC_EXTENSIONS
+#define EMPTY char empty;
+#define EMPTY_ARRAY 1
+#else
+#define EMPTY
+#define EMPTY_ARRAY 0
+#endif
+
+#ifndef __UNION_ANON
+#define __UNION_ANON
+#endif
+/**
+ * @file
+ */
+
+
+/**
+ * @defgroup MRQ MRQ Messages
+ * @brief Messages sent to/from BPMP via IPC
+ * @{
+ *   @defgroup MRQ_Format Message Format
+ *   @defgroup MRQ_Codes Message Request (MRQ) Codes
+ *   @defgroup MRQ_Payloads Message Payloads
+ *   @defgroup Error_Codes Error Codes
+ * @}
+ */
+
+/**
+ * @addtogroup MRQ_Format Message Format
+ * @{
+ * The CPU requests the BPMP to perform a particular service by
+ * sending it an IVC frame containing a single MRQ message. An MRQ
+ * message consists of a @ref mrq_request followed by a payload whose
+ * format depends on mrq_request::mrq.
+ *
+ * The BPMP processes the data and replies with an IVC frame (on the
+ * same IVC channel) containing and MRQ response. An MRQ response
+ * consists of a @ref mrq_response followed by a payload whose format
+ * depends on the associated mrq_request::mrq.
+ *
+ * A well-defined subset of the MRQ messages that the CPU sends to the
+ * BPMP can lead to BPMP eventually sending an MRQ message to the
+ * CPU. For example, when the CPU uses an #MRQ_THERMAL message to set
+ * a thermal trip point, the BPMP may eventually send a single
+ * #MRQ_THERMAL message of its own to the CPU indicating that the trip
+ * point has been crossed.
+ * @}
+ */
+
+/**
+ * @ingroup MRQ_Format
+ * @brief header for an MRQ message
+ *
+ * Provides the MRQ number for the MRQ message: #mrq. The remainder of
+ * the MRQ message is a payload (immediately following the
+ * mrq_request) whose format depends on mrq.
+ *
+ * @todo document the flags
+ */
+struct mrq_request {
+       /** @brief MRQ number of the request */
+       uint32_t mrq;
+       /** @brief flags for the request */
+       uint32_t flags;
+} __ABI_PACKED;
+
+/**
+ * @ingroup MRQ_Format
+ * @brief header for an MRQ response
+ *
+ *  Provides an error code for the associated MRQ message. The
+ *  remainder of the MRQ response is a payload (immediately following
+ *  the mrq_response) whose format depends on the associated
+ *  mrq_request::mrq
+ *
+ * @todo document the flags
+ */
+struct mrq_response {
+       /** @brief error code for the MRQ request itself */
+       int32_t err;
+       /** @brief flags for the response */
+       uint32_t flags;
+} __ABI_PACKED;
+
+/**
+ * @ingroup MRQ_Format
+ * Minimum needed size for an IPC message buffer
+ */
+#define MSG_MIN_SZ     128
+/**
+ * @ingroup MRQ_Format
+ *  Minimum size guaranteed for data in an IPC message buffer
+ */
+#define MSG_DATA_MIN_SZ        120
+
+/**
+ * @ingroup MRQ_Codes
+ * @name Legal MRQ codes
+ * These are the legal values for mrq_request::mrq
+ * @{
+ */
+
+#define MRQ_PING               0
+#define MRQ_QUERY_TAG          1
+#define MRQ_MODULE_LOAD                4
+#define MRQ_MODULE_UNLOAD      5
+#define MRQ_TRACE_MODIFY       7
+#define MRQ_WRITE_TRACE                8
+#define MRQ_THREADED_PING      9
+#define MRQ_MODULE_MAIL                11
+#define MRQ_DEBUGFS            19
+#define MRQ_RESET              20
+#define MRQ_I2C                        21
+#define MRQ_CLK                        22
+#define MRQ_QUERY_ABI          23
+#define MRQ_PG_READ_STATE      25
+#define MRQ_PG_UPDATE_STATE    26
+#define MRQ_THERMAL            27
+#define MRQ_CPU_VHINT          28
+#define MRQ_ABI_RATCHET                29
+#define MRQ_EMC_DVFS_LATENCY   31
+#define MRQ_TRACE_ITER         64
+
+/** @} */
+
+/**
+ * @ingroup MRQ_Codes
+ * @brief Maximum MRQ code to be sent by CPU software to
+ * BPMP. Subject to change in future
+ */
+#define MAX_CPU_MRQ_ID         64
+
+/**
+ * @addtogroup MRQ_Payloads Message Payloads
+ * @{
+ *   @defgroup Ping
+ *   @defgroup Query_Tag Query Tag
+ *   @defgroup Module Loadable Modules
+ *   @defgroup Trace
+ *   @defgroup Debugfs
+ *   @defgroup Reset
+ *   @defgroup I2C
+ *   @defgroup Clocks
+ *   @defgroup ABI_info ABI Info
+ *   @defgroup MC_Flush MC Flush
+ *   @defgroup Powergating
+ *   @defgroup Thermal
+ *   @defgroup Vhint CPU Voltage hint
+ *   @defgroup MRQ_Deprecated Deprecated MRQ messages
+ *   @defgroup EMC
+ * @}
+ */
+
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_PING
+ * @brief A simple ping
+ *
+ * * Platforms: All
+ * * Initiators: Any
+ * * Targets: Any
+ * * Request Payload: @ref mrq_ping_request
+ * * Response Payload: @ref mrq_ping_response
+ *
+ * @ingroup MRQ_Codes
+ * @def MRQ_THREADED_PING
+ * @brief A deeper ping
+ *
+ * * Platforms: All
+ * * Initiators: Any
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_ping_request
+ * * Response Payload: @ref mrq_ping_response
+ *
+ * Behavior is equivalent to a simple #MRQ_PING except that BPMP
+ * responds from a thread context (providing a slightly more robust
+ * sign of life).
+ *
+ */
+
+/**
+ * @ingroup Ping
+ * @brief request with #MRQ_PING
+ *
+ * Used by the sender of an #MRQ_PING message to request a pong from
+ * recipient. The response from the recipient is computed based on
+ * #challenge.
+ */
+struct mrq_ping_request {
+/** @brief arbitrarily chosen value */
+       uint32_t challenge;
+} __ABI_PACKED;
+
+/**
+ * @ingroup Ping
+ * @brief response to #MRQ_PING
+ *
+ * Sent in response to an #MRQ_PING message. #reply should be the
+ * mrq_ping_request challenge left shifted by 1 with the carry-bit
+ * dropped.
+ *
+ */
+struct mrq_ping_response {
+       /** @brief response to the MRQ_PING challege */
+       uint32_t reply;
+} __ABI_PACKED;
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_QUERY_TAG
+ * @brief Query BPMP firmware's tag (i.e. version information)
+ *
+ * * Platforms: All
+ * * Initiators: CCPLEX
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_query_tag_request
+ * * Response Payload: N/A
+ *
+ */
+
+/**
+ * @ingroup Query_Tag
+ * @brief request with #MRQ_QUERY_TAG
+ *
+ * Used by #MRQ_QUERY_TAG call to ask BPMP to fill in the memory
+ * pointed by #addr with BPMP firmware header.
+ *
+ * The sender is reponsible for ensuring that #addr is mapped in to
+ * the recipient's address map.
+ */
+struct mrq_query_tag_request {
+  /** @brief base address to store the firmware header */
+       uint32_t addr;
+} __ABI_PACKED;
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_MODULE_LOAD
+ * @brief dynamically load a BPMP code module
+ *
+ * * Platforms: All
+ * * Initiators: CCPLEX
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_module_load_request
+ * * Response Payload: @ref mrq_module_load_response
+ *
+ * @note This MRQ is disabled on production systems
+ *
+ */
+
+/**
+ * @ingroup Module
+ * @brief request with #MRQ_MODULE_LOAD
+ *
+ * Used by #MRQ_MODULE_LOAD calls to ask the recipient to dynamically
+ * load the code located at #phys_addr and having size #size
+ * bytes. #phys_addr is treated as a void pointer.
+ *
+ * The recipient copies the code from #phys_addr to locally allocated
+ * memory prior to responding to this message.
+ *
+ * @todo document the module header format
+ *
+ * The sender is responsible for ensuring that the code is mapped in
+ * the recipient's address map.
+ *
+ */
+struct mrq_module_load_request {
+       /** @brief base address of the code to load. Treated as (void *) */
+       uint32_t phys_addr; /* (void *) */
+       /** @brief size in bytes of code to load */
+       uint32_t size;
+} __ABI_PACKED;
+
+/**
+ * @ingroup Module
+ * @brief response to #MRQ_MODULE_LOAD
+ *
+ * @todo document mrq_response::err
+ */
+struct mrq_module_load_response {
+       /** @brief handle to the loaded module */
+       uint32_t base;
+} __ABI_PACKED;
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_MODULE_UNLOAD
+ * @brief unload a previously loaded code module
+ *
+ * * Platforms: All
+ * * Initiators: CCPLEX
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_module_unload_request
+ * * Response Payload: N/A
+ *
+ * @note This MRQ is disabled on production systems
+ */
+
+/**
+ * @ingroup Module
+ * @brief request with #MRQ_MODULE_UNLOAD
+ *
+ * Used by #MRQ_MODULE_UNLOAD calls to request that a previously loaded
+ * module be unloaded.
+ */
+struct mrq_module_unload_request {
+       /** @brief handle of the module to unload */
+       uint32_t base;
+} __ABI_PACKED;
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_TRACE_MODIFY
+ * @brief modify the set of enabled trace events
+ *
+ * * Platforms: All
+ * * Initiators: CCPLEX
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_trace_modify_request
+ * * Response Payload: @ref mrq_trace_modify_response
+ *
+ * @note This MRQ is disabled on production systems
+ */
+
+/**
+ * @ingroup Trace
+ * @brief request with #MRQ_TRACE_MODIFY
+ *
+ * Used by %MRQ_TRACE_MODIFY calls to enable or disable specify trace
+ * events.  #set takes precedence for any bit set in both #set and
+ * #clr.
+ */
+struct mrq_trace_modify_request {
+       /** @brief bit mask of trace events to disable */
+       uint32_t clr;
+       /** @brief bit mask of trace events to enable */
+       uint32_t set;
+} __ABI_PACKED;
+
+/**
+ * @ingroup Trace
+ * @brief response to #MRQ_TRACE_MODIFY
+ *
+ * Sent in repsonse to an #MRQ_TRACE_MODIFY message. #mask reflects the
+ * state of which events are enabled after the recipient acted on the
+ * message.
+ *
+ */
+struct mrq_trace_modify_response {
+       /** @brief bit mask of trace event enable states */
+       uint32_t mask;
+} __ABI_PACKED;
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_WRITE_TRACE
+ * @brief Write trace data to a buffer
+ *
+ * * Platforms: All
+ * * Initiators: CCPLEX
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_write_trace_request
+ * * Response Payload: @ref mrq_write_trace_response
+ *
+ * mrq_response::err depends on the @ref mrq_write_trace_request field
+ * values. err is -#BPMP_EINVAL if size is zero or area is NULL or
+ * area is in an illegal range. A positive value for err indicates the
+ * number of bytes written to area.
+ *
+ * @note This MRQ is disabled on production systems
+ */
+
+/**
+ * @ingroup Trace
+ * @brief request with #MRQ_WRITE_TRACE
+ *
+ * Used by MRQ_WRITE_TRACE calls to ask the recipient to copy trace
+ * data from the recipient's local buffer to the output buffer. #area
+ * is treated as a byte-aligned pointer in the recipient's address
+ * space.
+ *
+ * The sender is responsible for ensuring that the output
+ * buffer is mapped in the recipient's address map. The recipient is
+ * responsible for protecting its own code and data from accidental
+ * overwrites.
+ */
+struct mrq_write_trace_request {
+       /** @brief base address of output buffer */
+       uint32_t area;
+       /** @brief size in bytes of the output buffer */
+       uint32_t size;
+} __ABI_PACKED;
+
+/**
+ * @ingroup Trace
+ * @brief response to #MRQ_WRITE_TRACE
+ *
+ * Once this response is sent, the respondent will not access the
+ * output buffer further.
+ */
+struct mrq_write_trace_response {
+       /**
+        * @brief flag whether more data remains in local buffer
+        *
+        * Value is 1 if the entire local trace buffer has been
+        * drained to the outputbuffer. Value is 0 otherwise.
+        */
+       uint32_t eof;
+} __ABI_PACKED;
+
+/** @private */
+struct mrq_threaded_ping_request {
+       uint32_t challenge;
+} __ABI_PACKED;
+
+/** @private */
+struct mrq_threaded_ping_response {
+       uint32_t reply;
+} __ABI_PACKED;
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_MODULE_MAIL
+ * @brief send a message to a loadable module
+ *
+ * * Platforms: All
+ * * Initiators: Any
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_module_mail_request
+ * * Response Payload: @ref mrq_module_mail_response
+ *
+ * @note This MRQ is disabled on production systems
+ */
+
+/**
+ * @ingroup Module
+ * @brief request with #MRQ_MODULE_MAIL
+ */
+struct mrq_module_mail_request {
+       /** @brief handle to the previously loaded module */
+       uint32_t base;
+       /** @brief module-specific mail payload
+        *
+        * The length of data[ ] is unknown to the BPMP core firmware
+        * but it is limited to the size of an IPC message.
+        */
+       uint8_t data[EMPTY_ARRAY];
+} __ABI_PACKED;
+
+/**
+ * @ingroup Module
+ * @brief response to #MRQ_MODULE_MAIL
+ */
+struct mrq_module_mail_response {
+       /** @brief module-specific mail payload
+        *
+        * The length of data[ ] is unknown to the BPMP core firmware
+        * but it is limited to the size of an IPC message.
+        */
+       uint8_t data[EMPTY_ARRAY];
+} __ABI_PACKED;
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_DEBUGFS
+ * @brief Interact with BPMP's debugfs file nodes
+ *
+ * * Platforms: T186
+ * * Initiators: Any
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_debugfs_request
+ * * Response Payload: @ref mrq_debugfs_response
+ */
+
+/**
+ * @addtogroup Debugfs
+ * @{
+ *
+ * The BPMP firmware implements a pseudo-filesystem called
+ * debugfs. Any driver within the firmware may register with debugfs
+ * to expose an arbitrary set of "files" in the filesystem. When
+ * software on the CPU writes to a debugfs file, debugfs passes the
+ * written data to a callback provided by the driver. When software on
+ * the CPU reads a debugfs file, debugfs queries the driver for the
+ * data to return to the CPU. The intention of the debugfs filesystem
+ * is to provide information useful for debugging the system at
+ * runtime.
+ *
+ * @note The files exposed via debugfs are not part of the
+ * BPMP firmware's ABI. debugfs files may be added or removed in any
+ * given version of the firmware. Typically the semantics of a debugfs
+ * file are consistent from version to version but even that is not
+ * guaranteed.
+ *
+ * @}
+ */
+/** @ingroup Debugfs */
+enum mrq_debugfs_commands {
+       CMD_DEBUGFS_READ = 1,
+       CMD_DEBUGFS_WRITE = 2,
+       CMD_DEBUGFS_DUMPDIR = 3,
+       CMD_DEBUGFS_MAX
+};
+
+/**
+ * @ingroup Debugfs
+ * @brief parameters for CMD_DEBUGFS_READ/WRITE command
+ */
+struct cmd_debugfs_fileop_request {
+       /** @brief physical address pointing at filename */
+       uint32_t fnameaddr;
+       /** @brief length in bytes of filename buffer */
+       uint32_t fnamelen;
+       /** @brief physical address pointing to data buffer */
+       uint32_t dataaddr;
+       /** @brief length in bytes of data buffer */
+       uint32_t datalen;
+} __ABI_PACKED;
+
+/**
+ * @ingroup Debugfs
+ * @brief parameters for CMD_DEBUGFS_READ/WRITE command
+ */
+struct cmd_debugfs_dumpdir_request {
+       /** @brief physical address pointing to data buffer */
+       uint32_t dataaddr;
+       /** @brief length in bytes of data buffer */
+       uint32_t datalen;
+} __ABI_PACKED;
+
+/**
+ * @ingroup Debugfs
+ * @brief response data for CMD_DEBUGFS_READ/WRITE command
+ */
+struct cmd_debugfs_fileop_response {
+       /** @brief always 0 */
+       uint32_t reserved;
+       /** @brief number of bytes read from or written to data buffer */
+       uint32_t nbytes;
+} __ABI_PACKED;
+
+/**
+ * @ingroup Debugfs
+ * @brief response data for CMD_DEBUGFS_DUMPDIR command
+ */
+struct cmd_debugfs_dumpdir_response {
+       /** @brief always 0 */
+       uint32_t reserved;
+       /** @brief number of bytes read from or written to data buffer */
+       uint32_t nbytes;
+} __ABI_PACKED;
+
+/**
+ * @ingroup Debugfs
+ * @brief request with #MRQ_DEBUGFS.
+ *
+ * The sender of an MRQ_DEBUGFS message uses #cmd to specify a debugfs
+ * command to execute. Legal commands are the values of @ref
+ * mrq_debugfs_commands. Each command requires a specific additional
+ * payload of data.
+ *
+ * |command            |payload|
+ * |-------------------|-------|
+ * |CMD_DEBUGFS_READ   |fop    |
+ * |CMD_DEBUGFS_WRITE  |fop    |
+ * |CMD_DEBUGFS_DUMPDIR|dumpdir|
+ */
+struct mrq_debugfs_request {
+       uint32_t cmd;
+       union {
+               struct cmd_debugfs_fileop_request fop;
+               struct cmd_debugfs_dumpdir_request dumpdir;
+       } __UNION_ANON;
+} __ABI_PACKED;
+
+/**
+ * @ingroup Debugfs
+ */
+struct mrq_debugfs_response {
+       /** @brief always 0 */
+       int32_t reserved;
+       union {
+               /** @brief response data for CMD_DEBUGFS_READ OR
+                * CMD_DEBUGFS_WRITE command
+                */
+               struct cmd_debugfs_fileop_response fop;
+               /** @brief response data for CMD_DEBUGFS_DUMPDIR command */
+               struct cmd_debugfs_dumpdir_response dumpdir;
+       } __UNION_ANON;
+} __ABI_PACKED;
+
+/**
+ * @addtogroup Debugfs
+ * @{
+ */
+#define DEBUGFS_S_ISDIR        (1 << 9)
+#define DEBUGFS_S_IRUSR        (1 << 8)
+#define DEBUGFS_S_IWUSR        (1 << 7)
+/** @} */
+
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_RESET
+ * @brief reset an IP block
+ *
+ * * Platforms: T186
+ * * Initiators: Any
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_reset_request
+ * * Response Payload: N/A
+ */
+
+/**
+ * @ingroup Reset
+ */
+enum mrq_reset_commands {
+       CMD_RESET_ASSERT = 1,
+       CMD_RESET_DEASSERT = 2,
+       CMD_RESET_MODULE = 3,
+       CMD_RESET_MAX, /* not part of ABI and subject to change */
+};
+
+/**
+ * @ingroup Reset
+ * @brief request with MRQ_RESET
+ *
+ * Used by the sender of an #MRQ_RESET message to request BPMP to
+ * assert or or deassert a given reset line.
+ */
+struct mrq_reset_request {
+       /** @brief reset action to perform (@enum mrq_reset_commands) */
+       uint32_t cmd;
+       /** @brief id of the reset to affected */
+       uint32_t reset_id;
+} __ABI_PACKED;
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_I2C
+ * @brief issue an i2c transaction
+ *
+ * * Platforms: T186
+ * * Initiators: Any
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_i2c_request
+ * * Response Payload: @ref mrq_i2c_response
+ */
+
+/**
+ * @addtogroup I2C
+ * @{
+ */
+#define TEGRA_I2C_IPC_MAX_IN_BUF_SIZE  (MSG_DATA_MIN_SZ - 12)
+#define TEGRA_I2C_IPC_MAX_OUT_BUF_SIZE (MSG_DATA_MIN_SZ - 4)
+/** @} */
+
+/**
+ * @ingroup I2C
+ * @name Serial I2C flags
+ * Use these flags with serial_i2c_request::flags
+ * @{
+ */
+#define SERIALI2C_TEN           0x0010
+#define SERIALI2C_RD            0x0001
+#define SERIALI2C_STOP          0x8000
+#define SERIALI2C_NOSTART       0x4000
+#define SERIALI2C_REV_DIR_ADDR  0x2000
+#define SERIALI2C_IGNORE_NAK    0x1000
+#define SERIALI2C_NO_RD_ACK     0x0800
+#define SERIALI2C_RECV_LEN      0x0400
+/** @} */
+/** @ingroup I2C */
+enum {
+       CMD_I2C_XFER = 1
+};
+
+/**
+ * @ingroup I2C
+ * @brief serializable i2c request
+ *
+ * Instances of this structure are packed (little-endian) into
+ * cmd_i2c_xfer_request::data_buf. Each instance represents a single
+ * transaction (or a portion of a transaction with repeated starts) on
+ * an i2c bus.
+ *
+ * Because these structures are packed, some instances are likely to
+ * be misaligned. Additionally because #data is variable length, it is
+ * not possible to iterate through a serialized list of these
+ * structures without inspecting #len in each instance.  It may be
+ * easier to serialize or deserialize cmd_i2c_xfer_request::data_buf
+ * manually rather than using this structure definition.
+*/
+struct serial_i2c_request {
+       /** @brief I2C slave address */
+       uint16_t addr;
+       /** @brief bitmask of SERIALI2C_ flags */
+       uint16_t flags;
+       /** @brief length of I2C transaction in bytes */
+       uint16_t len;
+       /** @brief for write transactions only, #len bytes of data */
+       uint8_t data[];
+} __ABI_PACKED;
+
+/**
+ * @ingroup I2C
+ * @brief trigger one or more i2c transactions
+ */
+struct cmd_i2c_xfer_request {
+       /** @brief valid bus number from mach-t186/i2c-t186.h*/
+       uint32_t bus_id;
+
+       /** @brief count of valid bytes in #data_buf*/
+       uint32_t data_size;
+
+       /** @brief serialized packed instances of @ref serial_i2c_request*/
+       uint8_t data_buf[TEGRA_I2C_IPC_MAX_IN_BUF_SIZE];
+} __ABI_PACKED;
+
+/**
+ * @ingroup I2C
+ * @brief container for data read from the i2c bus
+ *
+ * Processing an cmd_i2c_xfer_request::data_buf causes BPMP to execute
+ * zero or more I2C reads. The data read from the bus is serialized
+ * into #data_buf.
+ */
+struct cmd_i2c_xfer_response {
+       /** @brief count of valid bytes in #data_buf*/
+       uint32_t data_size;
+       /** @brief i2c read data */
+       uint8_t data_buf[TEGRA_I2C_IPC_MAX_OUT_BUF_SIZE];
+} __ABI_PACKED;
+
+/**
+ * @ingroup I2C
+ * @brief request with #MRQ_I2C
+ */
+struct mrq_i2c_request {
+       /** @brief always CMD_I2C_XFER (i.e. 1) */
+       uint32_t cmd;
+       /** @brief parameters of the transfer request */
+       struct cmd_i2c_xfer_request xfer;
+} __ABI_PACKED;
+
+/**
+ * @ingroup I2C
+ * @brief response to #MRQ_I2C
+ */
+struct mrq_i2c_response {
+       struct cmd_i2c_xfer_response xfer;
+} __ABI_PACKED;
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_CLK
+ *
+ * * Platforms: T186
+ * * Initiators: Any
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_clk_request
+ * * Response Payload: @ref mrq_clk_response
+ * @addtogroup Clocks
+ * @{
+ */
+
+/**
+ * @name MRQ_CLK sub-commands
+ * @{
+ */
+enum {
+       CMD_CLK_GET_RATE = 1,
+       CMD_CLK_SET_RATE = 2,
+       CMD_CLK_ROUND_RATE = 3,
+       CMD_CLK_GET_PARENT = 4,
+       CMD_CLK_SET_PARENT = 5,
+       CMD_CLK_IS_ENABLED = 6,
+       CMD_CLK_ENABLE = 7,
+       CMD_CLK_DISABLE = 8,
+       CMD_CLK_GET_ALL_INFO = 14,
+       CMD_CLK_GET_MAX_CLK_ID = 15,
+       CMD_CLK_MAX,
+};
+/** @} */
+
+#define MRQ_CLK_NAME_MAXLEN    40
+#define MRQ_CLK_MAX_PARENTS    16
+
+/** @private */
+struct cmd_clk_get_rate_request {
+       EMPTY
+} __ABI_PACKED;
+
+struct cmd_clk_get_rate_response {
+       int64_t rate;
+} __ABI_PACKED;
+
+struct cmd_clk_set_rate_request {
+       int32_t unused;
+       int64_t rate;
+} __ABI_PACKED;
+
+struct cmd_clk_set_rate_response {
+       int64_t rate;
+} __ABI_PACKED;
+
+struct cmd_clk_round_rate_request {
+       int32_t unused;
+       int64_t rate;
+} __ABI_PACKED;
+
+struct cmd_clk_round_rate_response {
+       int64_t rate;
+} __ABI_PACKED;
+
+/** @private */
+struct cmd_clk_get_parent_request {
+       EMPTY
+} __ABI_PACKED;
+
+struct cmd_clk_get_parent_response {
+       uint32_t parent_id;
+} __ABI_PACKED;
+
+struct cmd_clk_set_parent_request {
+       uint32_t parent_id;
+} __ABI_PACKED;
+
+struct cmd_clk_set_parent_response {
+       uint32_t parent_id;
+} __ABI_PACKED;
+
+/** @private */
+struct cmd_clk_is_enabled_request {
+       EMPTY
+} __ABI_PACKED;
+
+struct cmd_clk_is_enabled_response {
+       int32_t state;
+} __ABI_PACKED;
+
+/** @private */
+struct cmd_clk_enable_request {
+       EMPTY
+} __ABI_PACKED;
+
+/** @private */
+struct cmd_clk_enable_response {
+       EMPTY
+} __ABI_PACKED;
+
+/** @private */
+struct cmd_clk_disable_request {
+       EMPTY
+} __ABI_PACKED;
+
+/** @private */
+struct cmd_clk_disable_response {
+       EMPTY
+} __ABI_PACKED;
+
+/** @private */
+struct cmd_clk_get_all_info_request {
+       EMPTY
+} __ABI_PACKED;
+
+struct cmd_clk_get_all_info_response {
+       uint32_t flags;
+       uint32_t parent;
+       uint32_t parents[MRQ_CLK_MAX_PARENTS];
+       uint8_t num_parents;
+       uint8_t name[MRQ_CLK_NAME_MAXLEN];
+} __ABI_PACKED;
+
+/** @private */
+struct cmd_clk_get_max_clk_id_request {
+       EMPTY
+} __ABI_PACKED;
+
+struct cmd_clk_get_max_clk_id_response {
+       uint32_t max_id;
+} __ABI_PACKED;
+/** @} */
+
+/**
+ * @ingroup Clocks
+ * @brief request with #MRQ_CLK
+ *
+ * Used by the sender of an #MRQ_CLK message to control clocks. The
+ * clk_request is split into several sub-commands. Some sub-commands
+ * require no additional data. Others have a sub-command specific
+ * payload
+ *
+ * |sub-command                 |payload                |
+ * |----------------------------|-----------------------|
+ * |CMD_CLK_GET_RATE            |-                      |
+ * |CMD_CLK_SET_RATE            |clk_set_rate           |
+ * |CMD_CLK_ROUND_RATE          |clk_round_rate         |
+ * |CMD_CLK_GET_PARENT          |-                      |
+ * |CMD_CLK_SET_PARENT          |clk_set_parent         |
+ * |CMD_CLK_IS_ENABLED          |-                      |
+ * |CMD_CLK_ENABLE              |-                      |
+ * |CMD_CLK_DISABLE             |-                      |
+ * |CMD_CLK_GET_ALL_INFO        |-                      |
+ * |CMD_CLK_GET_MAX_CLK_ID      |-                      |
+ *
+ */
+
+struct mrq_clk_request {
+       /** @brief sub-command and clock id concatenated to 32-bit word.
+        * - bits[31..24] is the sub-cmd.
+        * - bits[23..0] is the clock id
+        */
+       uint32_t cmd_and_id;
+
+       union {
+               /** @private */
+               struct cmd_clk_get_rate_request clk_get_rate;
+               struct cmd_clk_set_rate_request clk_set_rate;
+               struct cmd_clk_round_rate_request clk_round_rate;
+               /** @private */
+               struct cmd_clk_get_parent_request clk_get_parent;
+               struct cmd_clk_set_parent_request clk_set_parent;
+               /** @private */
+               struct cmd_clk_enable_request clk_enable;
+               /** @private */
+               struct cmd_clk_disable_request clk_disable;
+               /** @private */
+               struct cmd_clk_is_enabled_request clk_is_enabled;
+               /** @private */
+               struct cmd_clk_get_all_info_request clk_get_all_info;
+               /** @private */
+               struct cmd_clk_get_max_clk_id_request clk_get_max_clk_id;
+       } __UNION_ANON;
+} __ABI_PACKED;
+
+/**
+ * @ingroup Clocks
+ * @brief response to MRQ_CLK
+ *
+ * Each sub-command supported by @ref mrq_clk_request may return
+ * sub-command-specific data. Some do and some do not as indicated in
+ * the following table
+ *
+ * |sub-command                 |payload                 |
+ * |----------------------------|------------------------|
+ * |CMD_CLK_GET_RATE            |clk_get_rate            |
+ * |CMD_CLK_SET_RATE            |clk_set_rate            |
+ * |CMD_CLK_ROUND_RATE          |clk_round_rate          |
+ * |CMD_CLK_GET_PARENT          |clk_get_parent          |
+ * |CMD_CLK_SET_PARENT          |clk_set_parent          |
+ * |CMD_CLK_IS_ENABLED          |clk_is_enabled          |
+ * |CMD_CLK_ENABLE              |-                       |
+ * |CMD_CLK_DISABLE             |-                       |
+ * |CMD_CLK_GET_ALL_INFO        |clk_get_all_info        |
+ * |CMD_CLK_GET_MAX_CLK_ID      |clk_get_max_id          |
+ *
+ */
+
+struct mrq_clk_response {
+       union {
+               struct cmd_clk_get_rate_response clk_get_rate;
+               struct cmd_clk_set_rate_response clk_set_rate;
+               struct cmd_clk_round_rate_response clk_round_rate;
+               struct cmd_clk_get_parent_response clk_get_parent;
+               struct cmd_clk_set_parent_response clk_set_parent;
+               /** @private */
+               struct cmd_clk_enable_response clk_enable;
+               /** @private */
+               struct cmd_clk_disable_response clk_disable;
+               struct cmd_clk_is_enabled_response clk_is_enabled;
+               struct cmd_clk_get_all_info_response clk_get_all_info;
+               struct cmd_clk_get_max_clk_id_response clk_get_max_clk_id;
+       } __UNION_ANON;
+} __ABI_PACKED;
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_QUERY_ABI
+ * @brief check if an MRQ is implemented
+ *
+ * * Platforms: All
+ * * Initiators: Any
+ * * Targets: Any
+ * * Request Payload: @ref mrq_query_abi_request
+ * * Response Payload: @ref mrq_query_abi_response
+ */
+
+/**
+ * @ingroup ABI_info
+ * @brief request with MRQ_QUERY_ABI
+ *
+ * Used by #MRQ_QUERY_ABI call to check if MRQ code #mrq is supported
+ * by the recipient.
+ */
+struct mrq_query_abi_request {
+       /** @brief MRQ code to query */
+       uint32_t mrq;
+} __ABI_PACKED;
+
+/**
+ * @ingroup ABI_info
+ * @brief response to MRQ_QUERY_ABI
+ */
+struct mrq_query_abi_response {
+       /** @brief 0 if queried MRQ is supported. Else, -#BPMP_ENODEV */
+       int32_t status;
+} __ABI_PACKED;
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_PG_READ_STATE
+ * @brief read the power-gating state of a partition
+ *
+ * * Platforms: T186
+ * * Initiators: Any
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_pg_read_state_request
+ * * Response Payload: @ref mrq_pg_read_state_response
+ * @addtogroup Powergating
+ * @{
+ */
+
+/**
+ * @brief request with #MRQ_PG_READ_STATE
+ *
+ * Used by MRQ_PG_READ_STATE call to read the current state of a
+ * partition.
+ */
+struct mrq_pg_read_state_request {
+       /** @brief ID of partition */
+       uint32_t partition_id;
+} __ABI_PACKED;
+
+/**
+ * @brief response to MRQ_PG_READ_STATE
+ * @todo define possible errors.
+ */
+struct mrq_pg_read_state_response {
+       /** @brief read as don't care */
+       uint32_t sram_state;
+       /** @brief state of power partition
+        * * 0 : off
+        * * 1 : on
+        */
+       uint32_t logic_state;
+} __ABI_PACKED;
+
+/** @} */
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_PG_UPDATE_STATE
+ * @brief modify the power-gating state of a partition
+ *
+ * * Platforms: T186
+ * * Initiators: Any
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_pg_update_state_request
+ * * Response Payload: N/A
+ * @addtogroup Powergating
+ * @{
+ */
+
+/**
+ * @brief request with mrq_pg_update_state_request
+ *
+ * Used by #MRQ_PG_UPDATE_STATE call to request BPMP to change the
+ * state of a power partition #partition_id.
+ */
+struct mrq_pg_update_state_request {
+       /** @brief ID of partition */
+       uint32_t partition_id;
+       /** @brief secondary control of power partition
+        *  @details Ignored by many versions of the BPMP
+        *  firmware. For maximum compatibility, set the value
+        *  according to @logic_state
+        * *  0x1: power ON partition (@ref logic_state == 0x3)
+        * *  0x3: power OFF partition (@ref logic_state == 0x1)
+        */
+       uint32_t sram_state;
+       /** @brief controls state of power partition, legal values are
+        * *  0x1 : power OFF partition
+        * *  0x3 : power ON partition
+        */
+       uint32_t logic_state;
+       /** @brief change state of clocks of the power partition, legal values
+        * *  0x0 : do not change clock state
+        * *  0x1 : disable partition clocks (only applicable when
+        *          @ref logic_state == 0x1)
+        * *  0x3 : enable partition clocks (only applicable when
+        *          @ref logic_state == 0x3)
+        */
+       uint32_t clock_state;
+} __ABI_PACKED;
+/** @} */
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_THERMAL
+ * @brief interact with BPMP thermal framework
+ *
+ * * Platforms: T186
+ * * Initiators: Any
+ * * Targets: Any
+ * * Request Payload: TODO
+ * * Response Payload: TODO
+ *
+ * @addtogroup Thermal
+ *
+ * The BPMP firmware includes a thermal framework. Drivers within the
+ * bpmp firmware register with the framework to provide thermal
+ * zones. Each thermal zone corresponds to an entity whose temperature
+ * can be measured. The framework also has a notion of trip points. A
+ * trip point consists of a thermal zone id, a temperature, and a
+ * callback routine. The framework invokes the callback when the zone
+ * hits the indicated temperature. The BPMP firmware uses this thermal
+ * framework interally to implement various temperature-dependent
+ * functions.
+ *
+ * Software on the CPU can use #MRQ_THERMAL (with payload @ref
+ * mrq_thermal_host_to_bpmp_request) to interact with the BPMP thermal
+ * framework. The CPU must It can query the number of supported zones,
+ * query zone temperatures, and set trip points.
+ *
+ * When a trip point set by the CPU gets crossed, BPMP firmware issues
+ * an IPC to the CPU having mrq_request::mrq = #MRQ_THERMAL and a
+ * payload of @ref mrq_thermal_bpmp_to_host_request.
+ * @{
+ */
+enum mrq_thermal_host_to_bpmp_cmd {
+       /**
+        * @brief Check whether the BPMP driver supports the specified
+        * request type.
+        *
+        * Host needs to supply request parameters.
+        *
+        * mrq_response::err is 0 if the specified request is
+        * supported and -#BPMP_ENODEV otherwise.
+        */
+       CMD_THERMAL_QUERY_ABI = 0,
+
+       /**
+        * @brief Get the current temperature of the specified zone.
+        *
+        * Host needs to supply request parameters.
+        *
+        * mrq_response::err is
+        * *  0: Temperature query succeeded.
+        * *  -#BPMP_EINVAL: Invalid request parameters.
+        * *  -#BPMP_ENOENT: No driver registered for thermal zone..
+        * *  -#BPMP_EFAULT: Problem reading temperature measurement.
+        */
+       CMD_THERMAL_GET_TEMP = 1,
+
+       /**
+        * @brief Enable or disable and set the lower and upper
+        *   thermal limits for a thermal trip point. Each zone has
+        *   one trip point.
+        *
+        * Host needs to supply request parameters. Once the
+        * temperature hits a trip point, the BPMP will send a message
+        * to the CPU having MRQ=MRQ_THERMAL and
+        * type=CMD_THERMAL_HOST_TRIP_REACHED
+        *
+        * mrq_response::err is
+        * *  0: Trip successfully set.
+        * *  -#BPMP_EINVAL: Invalid request parameters.
+        * *  -#BPMP_ENOENT: No driver registered for thermal zone.
+        * *  -#BPMP_EFAULT: Problem setting trip point.
+        */
+       CMD_THERMAL_SET_TRIP = 2,
+
+       /**
+        * @brief Get the number of supported thermal zones.
+        *
+        * No request parameters required.
+        *
+        * mrq_response::err is always 0, indicating success.
+        */
+       CMD_THERMAL_GET_NUM_ZONES = 3,
+
+       /** @brief: number of supported host-to-bpmp commands. May
+        * increase in future
+        */
+       CMD_THERMAL_HOST_TO_BPMP_NUM
+};
+
+enum mrq_thermal_bpmp_to_host_cmd {
+       /**
+        * @brief Indication that the temperature for a zone has
+        *   exceeded the range indicated in the thermal trip point
+        *   for the zone.
+        *
+        * BPMP needs to supply request parameters. Host only needs to
+        * acknowledge.
+        */
+       CMD_THERMAL_HOST_TRIP_REACHED = 100,
+
+       /** @brief: number of supported bpmp-to-host commands. May
+        * increase in future
+        */
+       CMD_THERMAL_BPMP_TO_HOST_NUM
+};
+
+/*
+ * Host->BPMP request data for request type CMD_THERMAL_QUERY_ABI
+ *
+ * zone: Request type for which to check existence.
+ */
+struct cmd_thermal_query_abi_request {
+       uint32_t type;
+} __ABI_PACKED;
+
+/*
+ * Host->BPMP request data for request type CMD_THERMAL_GET_TEMP
+ *
+ * zone: Number of thermal zone.
+ */
+struct cmd_thermal_get_temp_request {
+       uint32_t zone;
+} __ABI_PACKED;
+
+/*
+ * BPMP->Host reply data for request CMD_THERMAL_GET_TEMP
+ *
+ * error: 0 if request succeeded.
+ *     -BPMP_EINVAL if request parameters were invalid.
+ *      -BPMP_ENOENT if no driver was registered for the specified thermal zone.
+ *      -BPMP_EFAULT for other thermal zone driver errors.
+ * temp: Current temperature in millicelsius.
+ */
+struct cmd_thermal_get_temp_response {
+       int32_t temp;
+} __ABI_PACKED;
+
+/*
+ * Host->BPMP request data for request type CMD_THERMAL_SET_TRIP
+ *
+ * zone: Number of thermal zone.
+ * low: Temperature of lower trip point in millicelsius
+ * high: Temperature of upper trip point in millicelsius
+ * enabled: 1 to enable trip point, 0 to disable trip point
+ */
+struct cmd_thermal_set_trip_request {
+       uint32_t zone;
+       int32_t low;
+       int32_t high;
+       uint32_t enabled;
+} __ABI_PACKED;
+
+/*
+ * BPMP->Host request data for request type CMD_THERMAL_HOST_TRIP_REACHED
+ *
+ * zone: Number of thermal zone where trip point was reached.
+ */
+struct cmd_thermal_host_trip_reached_request {
+       uint32_t zone;
+} __ABI_PACKED;
+
+/*
+ * BPMP->Host reply data for request type CMD_THERMAL_GET_NUM_ZONES
+ *
+ * num: Number of supported thermal zones. The thermal zones are indexed
+ *      starting from zero.
+ */
+struct cmd_thermal_get_num_zones_response {
+       uint32_t num;
+} __ABI_PACKED;
+
+/*
+ * Host->BPMP request data.
+ *
+ * Reply type is union mrq_thermal_bpmp_to_host_response.
+ *
+ * type: Type of request. Values listed in enum mrq_thermal_type.
+ * data: Request type specific parameters.
+ */
+struct mrq_thermal_host_to_bpmp_request {
+       uint32_t type;
+       union {
+               struct cmd_thermal_query_abi_request query_abi;
+               struct cmd_thermal_get_temp_request get_temp;
+               struct cmd_thermal_set_trip_request set_trip;
+       } __UNION_ANON;
+} __ABI_PACKED;
+
+/*
+ * BPMP->Host request data.
+ *
+ * type: Type of request. Values listed in enum mrq_thermal_type.
+ * data: Request type specific parameters.
+ */
+struct mrq_thermal_bpmp_to_host_request {
+       uint32_t type;
+       union {
+               struct cmd_thermal_host_trip_reached_request host_trip_reached;
+       } __UNION_ANON;
+} __ABI_PACKED;
+
+/*
+ * Data in reply to a Host->BPMP request.
+ */
+union mrq_thermal_bpmp_to_host_response {
+       struct cmd_thermal_get_temp_response get_temp;
+       struct cmd_thermal_get_num_zones_response get_num_zones;
+} __ABI_PACKED;
+/** @} */
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_CPU_VHINT
+ * @brief Query CPU voltage hint data
+ *
+ * * Platforms: T186
+ * * Initiators: CCPLEX
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_cpu_vhint_request
+ * * Response Payload: N/A
+ *
+ * @addtogroup Vhint CPU Voltage hint
+ * @{
+ */
+
+/**
+ * @brief request with #MRQ_CPU_VHINT
+ *
+ * Used by #MRQ_CPU_VHINT call by CCPLEX to retrieve voltage hint data
+ * from BPMP to memory space pointed by #addr. CCPLEX is responsible
+ * to allocate sizeof(cpu_vhint_data) sized block of memory and
+ * appropriately map it for BPMP before sending the request.
+ */
+struct mrq_cpu_vhint_request {
+       /** @brief IOVA address for the #cpu_vhint_data */
+       uint32_t addr; /* struct cpu_vhint_data * */
+       /** @brief ID of the cluster whose data is requested */
+       uint32_t cluster_id; /* enum cluster_id */
+} __ABI_PACKED;
+
+/**
+ * @brief description of the CPU v/f relation
+ *
+ * Used by #MRQ_CPU_VHINT call to carry data pointed by #addr of
+ * struct mrq_cpu_vhint_request
+ */
+struct cpu_vhint_data {
+       uint32_t ref_clk_hz; /**< reference frequency in Hz */
+       uint16_t pdiv; /**< post divider value */
+       uint16_t mdiv; /**< input divider value */
+       uint16_t ndiv_max; /**< fMAX expressed with max NDIV value */
+       /** table of ndiv values as a function of vINDEX (voltage index) */
+       uint16_t ndiv[80];
+       /** minimum allowed NDIV value */
+       uint16_t ndiv_min;
+       /** minimum allowed voltage hint value (as in vINDEX) */
+       uint16_t vfloor;
+       /** maximum allowed voltage hint value (as in vINDEX) */
+       uint16_t vceil;
+       /** post-multiplier for vindex value */
+       uint16_t vindex_mult;
+       /** post-divider for vindex value */
+       uint16_t vindex_div;
+       /** reserved for future use */
+       uint16_t reserved[328];
+} __ABI_PACKED;
+
+/** @} */
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_ABI_RATCHET
+ * @brief ABI ratchet value query
+ *
+ * * Platforms: T186
+ * * Initiators: Any
+ * * Targets: BPMP
+ * * Request Payload: @ref mrq_abi_ratchet_request
+ * * Response Payload: @ref mrq_abi_ratchet_response
+ * @addtogroup ABI_info
+ * @{
+ */
+
+/**
+ * @brief an ABI compatibility mechanism
+ *
+ * BPMP_ABI_RATCHET_VALUE may increase for various reasons in a future
+ * revision of this header file.
+ * 1. That future revision deprecates some MRQ
+ * 2. That future revision introduces a breaking change to an existing
+ *    MRQ or
+ * 3. A bug is discovered in an existing implementation of the BPMP-FW
+ *    (or possibly one of its clients) which warrants deprecating that
+ *    implementation.
+ */
+#define BPMP_ABI_RATCHET_VALUE 3
+
+/**
+ * @brief request with #MRQ_ABI_RATCHET.
+ *
+ * #ratchet should be #BPMP_ABI_RATCHET_VALUE from the ABI header
+ * against which the requester was compiled.
+ *
+ * If ratchet is less than BPMP's #BPMP_ABI_RATCHET_VALUE, BPMP may
+ * reply with mrq_response::err = -#BPMP_ERANGE to indicate that
+ * BPMP-FW cannot interoperate correctly with the requester. Requester
+ * should cease further communication with BPMP.
+ *
+ * Otherwise, err shall be 0.
+ */
+struct mrq_abi_ratchet_request {
+       /** @brief requester's ratchet value */
+       uint16_t ratchet;
+};
+
+/**
+ * @brief response to #MRQ_ABI_RATCHET
+ *
+ * #ratchet shall be #BPMP_ABI_RATCHET_VALUE from the ABI header
+ * against which BPMP firwmare was compiled.
+ *
+ * If #ratchet is less than the requester's #BPMP_ABI_RATCHET_VALUE,
+ * the requster must either interoperate with BPMP according to an ABI
+ * header version with BPMP_ABI_RATCHET_VALUE = ratchet or cease
+ * communication with BPMP.
+ *
+ * If mrq_response::err is 0 and ratchet is greater than or equal to the
+ * requester's BPMP_ABI_RATCHET_VALUE, the requester should continue
+ * normal operation.
+ */
+struct mrq_abi_ratchet_response {
+       /** @brief BPMP's ratchet value */
+       uint16_t ratchet;
+};
+/** @} */
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_EMC_DVFS_LATENCY
+ * @brief query frequency dependent EMC DVFS latency
+ *
+ * * Platforms: T186
+ * * Initiators: CCPLEX
+ * * Targets: BPMP
+ * * Request Payload: N/A
+ * * Response Payload: @ref mrq_emc_dvfs_latency_response
+ * @addtogroup EMC
+ * @{
+ */
+
+/**
+ * @brief used by @ref mrq_emc_dvfs_latency_response
+ */
+struct emc_dvfs_latency {
+       /** @brief EMC frequency in kHz */
+       uint32_t freq;
+       /** @brief EMC DVFS latency in nanoseconds */
+       uint32_t latency;
+} __ABI_PACKED;
+
+#define EMC_DVFS_LATENCY_MAX_SIZE      14
+/**
+ * @brief response to #MRQ_EMC_DVFS_LATENCY
+ */
+struct mrq_emc_dvfs_latency_response {
+       /** @brief the number valid entries in #pairs */
+       uint32_t num_pairs;
+       /** @brief EMC <frequency, latency> information */
+       struct emc_dvfs_latency pairs[EMC_DVFS_LATENCY_MAX_SIZE];
+} __ABI_PACKED;
+
+/** @} */
+
+/**
+ * @ingroup MRQ_Codes
+ * @def MRQ_TRACE_ITER
+ * @brief manage the trace iterator
+ *
+ * * Platforms: All
+ * * Initiators: CCPLEX
+ * * Targets: BPMP
+ * * Request Payload: N/A
+ * * Response Payload: @ref mrq_trace_iter_request
+ * @addtogroup Trace
+ * @{
+ */
+enum {
+       /** @brief (re)start the tracing now. Ignore older events */
+       TRACE_ITER_INIT = 0,
+       /** @brief clobber all events in the trace buffer */
+       TRACE_ITER_CLEAN = 1
+};
+
+/**
+ * @brief request with #MRQ_TRACE_ITER
+ */
+struct mrq_trace_iter_request {
+       /** @brief TRACE_ITER_INIT or TRACE_ITER_CLEAN */
+       uint32_t cmd;
+} __ABI_PACKED;
+
+/** @} */
+
+/*
+ *  4. Enumerations
+ */
+
+/*
+ *   4.1 CPU enumerations
+ *
+ * See <mach-t186/system-t186.h>
+ *
+ *   4.2 CPU Cluster enumerations
+ *
+ * See <mach-t186/system-t186.h>
+ *
+ *   4.3 System low power state enumerations
+ *
+ * See <mach-t186/system-t186.h>
+ */
+
+/*
+ *   4.4 Clock enumerations
+ *
+ * For clock enumerations, see <mach-t186/clk-t186.h>
+ */
+
+/*
+ *   4.5 Reset enumerations
+ *
+ * For reset enumerations, see <mach-t186/reset-t186.h>
+ */
+
+/*
+ *   4.6 Thermal sensor enumerations
+ *
+ * For thermal sensor enumerations, see <mach-t186/thermal-t186.h>
+ */
+
+/**
+ * @defgroup Error_Codes
+ * Negative values for mrq_response::err generally indicate some
+ * error. The ABI defines the following error codes. Negating these
+ * defines is an exercise left to the user.
+ * @{
+ */
+/** @brief No such file or directory */
+#define BPMP_ENOENT    2
+/** @brief No MRQ handler */
+#define BPMP_ENOHANDLER        3
+/** @brief I/O error */
+#define BPMP_EIO       5
+/** @brief Bad sub-MRQ command */
+#define BPMP_EBADCMD   6
+/** @brief Not enough memory */
+#define BPMP_ENOMEM    12
+/** @brief Permission denied */
+#define BPMP_EACCES    13
+/** @brief Bad address */
+#define BPMP_EFAULT    14
+/** @brief No such device */
+#define BPMP_ENODEV    19
+/** @brief Argument is a directory */
+#define BPMP_EISDIR    21
+/** @brief Invalid argument */
+#define BPMP_EINVAL    22
+/** @brief Timeout during operation */
+#define BPMP_ETIMEDOUT  23
+/** @brief Out of range */
+#define BPMP_ERANGE    34
+/** @} */
+/** @} */
+#endif
diff --git a/include/soc/tegra/bpmp.h b/include/soc/tegra/bpmp.h
new file mode 100644 (file)
index 0000000..13dcd44
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+#ifndef __SOC_TEGRA_BPMP_H
+#define __SOC_TEGRA_BPMP_H
+
+#include <linux/mailbox_client.h>
+#include <linux/reset-controller.h>
+#include <linux/semaphore.h>
+#include <linux/types.h>
+
+#include <soc/tegra/bpmp-abi.h>
+
+struct tegra_bpmp_clk;
+
+struct tegra_bpmp_soc {
+       struct {
+               struct {
+                       unsigned int offset;
+                       unsigned int count;
+                       unsigned int timeout;
+               } cpu_tx, thread, cpu_rx;
+       } channels;
+       unsigned int num_resets;
+};
+
+struct tegra_bpmp_mb_data {
+       u32 code;
+       u32 flags;
+       u8 data[MSG_DATA_MIN_SZ];
+} __packed;
+
+struct tegra_bpmp_channel {
+       struct tegra_bpmp *bpmp;
+       struct tegra_bpmp_mb_data *ib;
+       struct tegra_bpmp_mb_data *ob;
+       struct completion completion;
+       struct tegra_ivc *ivc;
+};
+
+typedef void (*tegra_bpmp_mrq_handler_t)(unsigned int mrq,
+                                        struct tegra_bpmp_channel *channel,
+                                        void *data);
+
+struct tegra_bpmp_mrq {
+       struct list_head list;
+       unsigned int mrq;
+       tegra_bpmp_mrq_handler_t handler;
+       void *data;
+};
+
+struct tegra_bpmp {
+       const struct tegra_bpmp_soc *soc;
+       struct device *dev;
+
+       struct {
+               struct gen_pool *pool;
+               dma_addr_t phys;
+               void *virt;
+       } tx, rx;
+
+       struct {
+               struct mbox_client client;
+               struct mbox_chan *channel;
+       } mbox;
+
+       struct tegra_bpmp_channel *channels;
+       unsigned int num_channels;
+
+       struct {
+               unsigned long *allocated;
+               unsigned long *busy;
+               unsigned int count;
+               struct semaphore lock;
+       } threaded;
+
+       struct list_head mrqs;
+       spinlock_t lock;
+
+       struct tegra_bpmp_clk **clocks;
+       unsigned int num_clocks;
+
+       struct reset_controller_dev rstc;
+};
+
+struct tegra_bpmp *tegra_bpmp_get(struct device *dev);
+void tegra_bpmp_put(struct tegra_bpmp *bpmp);
+
+struct tegra_bpmp_message {
+       unsigned int mrq;
+
+       struct {
+               const void *data;
+               size_t size;
+       } tx;
+
+       struct {
+               void *data;
+               size_t size;
+       } rx;
+};
+
+int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp,
+                              struct tegra_bpmp_message *msg);
+int tegra_bpmp_transfer(struct tegra_bpmp *bpmp,
+                       struct tegra_bpmp_message *msg);
+
+int tegra_bpmp_request_mrq(struct tegra_bpmp *bpmp, unsigned int mrq,
+                          tegra_bpmp_mrq_handler_t handler, void *data);
+void tegra_bpmp_free_mrq(struct tegra_bpmp *bpmp, unsigned int mrq,
+                        void *data);
+
+#if IS_ENABLED(CONFIG_CLK_TEGRA_BPMP)
+int tegra_bpmp_init_clocks(struct tegra_bpmp *bpmp);
+#else
+static inline int tegra_bpmp_init_clocks(struct tegra_bpmp *bpmp)
+{
+       return 0;
+}
+#endif
+
+#if IS_ENABLED(CONFIG_RESET_TEGRA_BPMP)
+int tegra_bpmp_init_resets(struct tegra_bpmp *bpmp);
+#else
+static inline int tegra_bpmp_init_resets(struct tegra_bpmp *bpmp)
+{
+       return 0;
+}
+#endif
+
+#endif /* __SOC_TEGRA_BPMP_H */
diff --git a/include/soc/tegra/ivc.h b/include/soc/tegra/ivc.h
new file mode 100644 (file)
index 0000000..b13cc43
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+#ifndef __TEGRA_IVC_H
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/types.h>
+
+struct tegra_ivc_header;
+
+struct tegra_ivc {
+       struct device *peer;
+
+       struct {
+               struct tegra_ivc_header *channel;
+               unsigned int position;
+               dma_addr_t phys;
+       } rx, tx;
+
+       void (*notify)(struct tegra_ivc *ivc, void *data);
+       void *notify_data;
+
+       unsigned int num_frames;
+       size_t frame_size;
+};
+
+/**
+ * tegra_ivc_read_get_next_frame - Peek at the next frame to receive
+ * @ivc                pointer of the IVC channel
+ *
+ * Peek at the next frame to be received, without removing it from
+ * the queue.
+ *
+ * Returns a pointer to the frame, or an error encoded pointer.
+ */
+void *tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc);
+
+/**
+ * tegra_ivc_read_advance - Advance the read queue
+ * @ivc                pointer of the IVC channel
+ *
+ * Advance the read queue
+ *
+ * Returns 0, or a negative error value if failed.
+ */
+int tegra_ivc_read_advance(struct tegra_ivc *ivc);
+
+/**
+ * tegra_ivc_write_get_next_frame - Poke at the next frame to transmit
+ * @ivc                pointer of the IVC channel
+ *
+ * Get access to the next frame.
+ *
+ * Returns a pointer to the frame, or an error encoded pointer.
+ */
+void *tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc);
+
+/**
+ * tegra_ivc_write_advance - Advance the write queue
+ * @ivc                pointer of the IVC channel
+ *
+ * Advance the write queue
+ *
+ * Returns 0, or a negative error value if failed.
+ */
+int tegra_ivc_write_advance(struct tegra_ivc *ivc);
+
+/**
+ * tegra_ivc_notified - handle internal messages
+ * @ivc                pointer of the IVC channel
+ *
+ * This function must be called following every notification.
+ *
+ * Returns 0 if the channel is ready for communication, or -EAGAIN if a channel
+ * reset is in progress.
+ */
+int tegra_ivc_notified(struct tegra_ivc *ivc);
+
+/**
+ * tegra_ivc_reset - initiates a reset of the shared memory state
+ * @ivc                pointer of the IVC channel
+ *
+ * This function must be called after a channel is reserved before it is used
+ * for communication. The channel will be ready for use when a subsequent call
+ * to notify the remote of the channel reset.
+ */
+void tegra_ivc_reset(struct tegra_ivc *ivc);
+
+size_t tegra_ivc_align(size_t size);
+unsigned tegra_ivc_total_queue_size(unsigned queue_size);
+int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx,
+                  dma_addr_t rx_phys, void *tx, dma_addr_t tx_phys,
+                  unsigned int num_frames, size_t frame_size,
+                  void (*notify)(struct tegra_ivc *ivc, void *data),
+                  void *data);
+void tegra_ivc_cleanup(struct tegra_ivc *ivc);
+
+#endif /* __TEGRA_IVC_H */