1
0
Fork 0

Merge branch 'for-4.10/firmware' into for-4.10/reset

zero-colors
Thierry Reding 2016-11-18 14:34:46 +01:00
commit 801fc02214
19 changed files with 5327 additions and 0 deletions

View File

@ -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 = "...";
...
};
};

View File

@ -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>;
};

View 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

View 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/

View File

@ -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

View File

@ -0,0 +1,2 @@
obj-$(CONFIG_TEGRA_BPMP) += bpmp.o
obj-$(CONFIG_TEGRA_IVC) += ivc.o

View File

@ -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);

View File

@ -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);

View 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

View 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

View File

@ -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);

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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 */