diff options
author | Thierry Reding <treding@nvidia.com> | 2016-11-18 08:34:46 -0500 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2016-11-18 08:34:46 -0500 |
commit | 801fc022147974f4754939202efe607294479bc9 (patch) | |
tree | fc7099112e411988758b7145780a45cee6d8951c | |
parent | 1001354ca34179f3db924eb66672442a173147dc (diff) | |
parent | b704ed8095ee91af5f3f7343bb3be23aae1cb26d (diff) |
Merge branch 'for-4.10/firmware' into for-4.10/reset
-rw-r--r-- | Documentation/devicetree/bindings/firmware/nvidia,tegra186-bpmp.txt | 108 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt | 52 | ||||
-rw-r--r-- | drivers/firmware/Kconfig | 1 | ||||
-rw-r--r-- | drivers/firmware/Makefile | 1 | ||||
-rw-r--r-- | drivers/firmware/tegra/Kconfig | 25 | ||||
-rw-r--r-- | drivers/firmware/tegra/Makefile | 2 | ||||
-rw-r--r-- | drivers/firmware/tegra/bpmp.c | 868 | ||||
-rw-r--r-- | drivers/firmware/tegra/ivc.c | 695 | ||||
-rw-r--r-- | drivers/mailbox/Kconfig | 9 | ||||
-rw-r--r-- | drivers/mailbox/Makefile | 2 | ||||
-rw-r--r-- | drivers/mailbox/tegra-hsp.c | 479 | ||||
-rw-r--r-- | drivers/soc/tegra/Kconfig | 14 | ||||
-rw-r--r-- | include/dt-bindings/clock/tegra186-clock.h | 940 | ||||
-rw-r--r-- | include/dt-bindings/mailbox/tegra186-hsp.h | 24 | ||||
-rw-r--r-- | include/dt-bindings/power/tegra186-powergate.h | 39 | ||||
-rw-r--r-- | include/dt-bindings/reset/tegra186-reset.h | 217 | ||||
-rw-r--r-- | include/soc/tegra/bpmp-abi.h | 1601 | ||||
-rw-r--r-- | include/soc/tegra/bpmp.h | 141 | ||||
-rw-r--r-- | include/soc/tegra/ivc.h | 109 |
19 files changed, 5327 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/firmware/nvidia,tegra186-bpmp.txt b/Documentation/devicetree/bindings/firmware/nvidia,tegra186-bpmp.txt new file mode 100644 index 000000000000..e821e16ad65b --- /dev/null +++ b/Documentation/devicetree/bindings/firmware/nvidia,tegra186-bpmp.txt | |||
@@ -0,0 +1,108 @@ | |||
1 | NVIDIA Tegra Boot and Power Management Processor (BPMP) | ||
2 | |||
3 | The BPMP is a specific processor in Tegra chip, which is designed for | ||
4 | booting process handling and offloading the power management, clock | ||
5 | management, and reset control tasks from the CPU. The binding document | ||
6 | defines the resources that would be used by the BPMP firmware driver, | ||
7 | which can create the interprocessor communication (IPC) between the CPU | ||
8 | and BPMP. | ||
9 | |||
10 | Required properties: | ||
11 | - name : Should be bpmp | ||
12 | - compatible | ||
13 | Array of strings | ||
14 | One of: | ||
15 | - "nvidia,tegra186-bpmp" | ||
16 | - mboxes : The phandle of mailbox controller and the mailbox specifier. | ||
17 | - shmem : List of the phandle of the TX and RX shared memory area that | ||
18 | the IPC between CPU and BPMP is based on. | ||
19 | - #clock-cells : Should be 1. | ||
20 | - #power-domain-cells : Should be 1. | ||
21 | - #reset-cells : Should be 1. | ||
22 | |||
23 | This node is a mailbox consumer. See the following files for details of | ||
24 | the mailbox subsystem, and the specifiers implemented by the relevant | ||
25 | provider(s): | ||
26 | |||
27 | - .../mailbox/mailbox.txt | ||
28 | - .../mailbox/nvidia,tegra186-hsp.txt | ||
29 | |||
30 | This node is a clock, power domain, and reset provider. See the following | ||
31 | files for general documentation of those features, and the specifiers | ||
32 | implemented by this node: | ||
33 | |||
34 | - .../clock/clock-bindings.txt | ||
35 | - <dt-bindings/clock/tegra186-clock.h> | ||
36 | - ../power/power_domain.txt | ||
37 | - <dt-bindings/power/tegra186-powergate.h> | ||
38 | - .../reset/reset.txt | ||
39 | - <dt-bindings/reset/tegra186-reset.h> | ||
40 | |||
41 | The BPMP implements some services which must be represented by separate nodes. | ||
42 | For example, it can provide access to certain I2C controllers, and the I2C | ||
43 | bindings represent each I2C controller as a device tree node. Such nodes should | ||
44 | be nested directly inside the main BPMP node. | ||
45 | |||
46 | Software can determine whether a child node of the BPMP node represents a device | ||
47 | by checking for a compatible property. Any node with a compatible property | ||
48 | represents a device that can be instantiated. Nodes without a compatible | ||
49 | property may be used to provide configuration information regarding the BPMP | ||
50 | itself, although no such configuration nodes are currently defined by this | ||
51 | binding. | ||
52 | |||
53 | The BPMP firmware defines no single global name-/numbering-space for such | ||
54 | services. Put another way, the numbering scheme for I2C buses is distinct from | ||
55 | the numbering scheme for any other service the BPMP may provide (e.g. a future | ||
56 | hypothetical SPI bus service). As such, child device nodes will have no reg | ||
57 | property, and the BPMP node will have no #address-cells or #size-cells property. | ||
58 | |||
59 | The shared memory bindings for BPMP | ||
60 | ----------------------------------- | ||
61 | |||
62 | The shared memory area for the IPC TX and RX between CPU and BPMP are | ||
63 | predefined and work on top of sysram, which is an SRAM inside the chip. | ||
64 | |||
65 | See ".../sram/sram.txt" for the bindings. | ||
66 | |||
67 | Example: | ||
68 | |||
69 | hsp_top0: hsp@03c00000 { | ||
70 | ... | ||
71 | #mbox-cells = <2>; | ||
72 | }; | ||
73 | |||
74 | sysram@30000000 { | ||
75 | compatible = "nvidia,tegra186-sysram", "mmio-sram"; | ||
76 | reg = <0x0 0x30000000 0x0 0x50000>; | ||
77 | #address-cells = <2>; | ||
78 | #size-cells = <2>; | ||
79 | ranges = <0 0x0 0x0 0x30000000 0x0 0x50000>; | ||
80 | |||
81 | cpu_bpmp_tx: shmem@4e000 { | ||
82 | compatible = "nvidia,tegra186-bpmp-shmem"; | ||
83 | reg = <0x0 0x4e000 0x0 0x1000>; | ||
84 | label = "cpu-bpmp-tx"; | ||
85 | pool; | ||
86 | }; | ||
87 | |||
88 | cpu_bpmp_rx: shmem@4f000 { | ||
89 | compatible = "nvidia,tegra186-bpmp-shmem"; | ||
90 | reg = <0x0 0x4f000 0x0 0x1000>; | ||
91 | label = "cpu-bpmp-rx"; | ||
92 | pool; | ||
93 | }; | ||
94 | }; | ||
95 | |||
96 | bpmp { | ||
97 | compatible = "nvidia,tegra186-bpmp"; | ||
98 | mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_DB TEGRA_HSP_DB_MASTER_BPMP>; | ||
99 | shmem = <&cpu_bpmp_tx &cpu_bpmp_rx>; | ||
100 | #clock-cells = <1>; | ||
101 | #power-domain-cells = <1>; | ||
102 | #reset-cells = <1>; | ||
103 | |||
104 | i2c { | ||
105 | compatible = "..."; | ||
106 | ... | ||
107 | }; | ||
108 | }; | ||
diff --git a/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt new file mode 100644 index 000000000000..b99d25fc2f26 --- /dev/null +++ b/Documentation/devicetree/bindings/mailbox/nvidia,tegra186-hsp.txt | |||
@@ -0,0 +1,52 @@ | |||
1 | NVIDIA Tegra Hardware Synchronization Primitives (HSP) | ||
2 | |||
3 | The HSP modules are used for the processors to share resources and communicate | ||
4 | together. It provides a set of hardware synchronization primitives for | ||
5 | interprocessor communication. So the interprocessor communication (IPC) | ||
6 | protocols can use hardware synchronization primitives, when operating between | ||
7 | two processors not in an SMP relationship. | ||
8 | |||
9 | The features that HSP supported are shared mailboxes, shared semaphores, | ||
10 | arbitrated semaphores and doorbells. | ||
11 | |||
12 | Required properties: | ||
13 | - name : Should be hsp | ||
14 | - compatible | ||
15 | Array of strings. | ||
16 | one of: | ||
17 | - "nvidia,tegra186-hsp" | ||
18 | - reg : Offset and length of the register set for the device. | ||
19 | - interrupt-names | ||
20 | Array of strings. | ||
21 | Contains a list of names for the interrupts described by the interrupt | ||
22 | property. May contain the following entries, in any order: | ||
23 | - "doorbell" | ||
24 | Users of this binding MUST look up entries in the interrupt property | ||
25 | by name, using this interrupt-names property to do so. | ||
26 | - interrupts | ||
27 | Array of interrupt specifiers. | ||
28 | Must contain one entry per entry in the interrupt-names property, | ||
29 | in a matching order. | ||
30 | - #mbox-cells : Should be 2. | ||
31 | |||
32 | The mbox specifier of the "mboxes" property in the client node should | ||
33 | contain two data. The first one should be the HSP type and the second | ||
34 | one should be the ID that the client is going to use. Those information | ||
35 | can be found in the following file. | ||
36 | |||
37 | - <dt-bindings/mailbox/tegra186-hsp.h>. | ||
38 | |||
39 | Example: | ||
40 | |||
41 | hsp_top0: hsp@3c00000 { | ||
42 | compatible = "nvidia,tegra186-hsp"; | ||
43 | reg = <0x0 0x03c00000 0x0 0xa0000>; | ||
44 | interrupts = <GIC_SPI 176 IRQ_TYPE_LEVEL_HIGH>; | ||
45 | interrupt-names = "doorbell"; | ||
46 | #mbox-cells = <2>; | ||
47 | }; | ||
48 | |||
49 | client { | ||
50 | ... | ||
51 | mboxes = <&hsp_top0 TEGRA_HSP_MBOX_TYPE_DB TEGRA_HSP_DB_MASTER_XXX>; | ||
52 | }; | ||
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index bca172d42c74..9968de04d1d5 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig | |||
@@ -210,5 +210,6 @@ source "drivers/firmware/broadcom/Kconfig" | |||
210 | source "drivers/firmware/google/Kconfig" | 210 | source "drivers/firmware/google/Kconfig" |
211 | source "drivers/firmware/efi/Kconfig" | 211 | source "drivers/firmware/efi/Kconfig" |
212 | source "drivers/firmware/meson/Kconfig" | 212 | source "drivers/firmware/meson/Kconfig" |
213 | source "drivers/firmware/tegra/Kconfig" | ||
213 | 214 | ||
214 | endmenu | 215 | endmenu |
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 898ac41fa8b3..2afe75c52ac2 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile | |||
@@ -26,3 +26,4 @@ obj-y += meson/ | |||
26 | obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ | 26 | obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ |
27 | obj-$(CONFIG_EFI) += efi/ | 27 | obj-$(CONFIG_EFI) += efi/ |
28 | obj-$(CONFIG_UEFI_CPER) += efi/ | 28 | obj-$(CONFIG_UEFI_CPER) += efi/ |
29 | obj-y += tegra/ | ||
diff --git a/drivers/firmware/tegra/Kconfig b/drivers/firmware/tegra/Kconfig new file mode 100644 index 000000000000..ff2730d5c468 --- /dev/null +++ b/drivers/firmware/tegra/Kconfig | |||
@@ -0,0 +1,25 @@ | |||
1 | menu "Tegra firmware driver" | ||
2 | |||
3 | config TEGRA_IVC | ||
4 | bool "Tegra IVC protocol" | ||
5 | depends on ARCH_TEGRA | ||
6 | help | ||
7 | IVC (Inter-VM Communication) protocol is part of the IPC | ||
8 | (Inter Processor Communication) framework on Tegra. It maintains the | ||
9 | data and the different commuication channels in SysRAM or RAM and | ||
10 | keeps the content is synchronization between host CPU and remote | ||
11 | processors. | ||
12 | |||
13 | config TEGRA_BPMP | ||
14 | bool "Tegra BPMP driver" | ||
15 | depends on ARCH_TEGRA && TEGRA_HSP_MBOX && TEGRA_IVC | ||
16 | help | ||
17 | BPMP (Boot and Power Management Processor) is designed to off-loading | ||
18 | the PM functions which include clock/DVFS/thermal/power from the CPU. | ||
19 | It needs HSP as the HW synchronization and notification module and | ||
20 | IVC module as the message communication protocol. | ||
21 | |||
22 | This driver manages the IPC interface between host CPU and the | ||
23 | firmware running on BPMP. | ||
24 | |||
25 | endmenu | ||
diff --git a/drivers/firmware/tegra/Makefile b/drivers/firmware/tegra/Makefile new file mode 100644 index 000000000000..e34a2f79e1ad --- /dev/null +++ b/drivers/firmware/tegra/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | obj-$(CONFIG_TEGRA_BPMP) += bpmp.o | ||
2 | obj-$(CONFIG_TEGRA_IVC) += ivc.o | ||
diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c new file mode 100644 index 000000000000..4ff02d310868 --- /dev/null +++ b/drivers/firmware/tegra/bpmp.c | |||
@@ -0,0 +1,868 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk/tegra.h> | ||
15 | #include <linux/genalloc.h> | ||
16 | #include <linux/mailbox_client.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_address.h> | ||
19 | #include <linux/of_device.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/semaphore.h> | ||
22 | |||
23 | #include <soc/tegra/bpmp.h> | ||
24 | #include <soc/tegra/bpmp-abi.h> | ||
25 | #include <soc/tegra/ivc.h> | ||
26 | |||
27 | #define MSG_ACK BIT(0) | ||
28 | #define MSG_RING BIT(1) | ||
29 | |||
30 | static inline struct tegra_bpmp * | ||
31 | mbox_client_to_bpmp(struct mbox_client *client) | ||
32 | { | ||
33 | return container_of(client, struct tegra_bpmp, mbox.client); | ||
34 | } | ||
35 | |||
36 | struct tegra_bpmp *tegra_bpmp_get(struct device *dev) | ||
37 | { | ||
38 | struct platform_device *pdev; | ||
39 | struct tegra_bpmp *bpmp; | ||
40 | struct device_node *np; | ||
41 | |||
42 | np = of_parse_phandle(dev->of_node, "nvidia,bpmp", 0); | ||
43 | if (!np) | ||
44 | return ERR_PTR(-ENOENT); | ||
45 | |||
46 | pdev = of_find_device_by_node(np); | ||
47 | if (!pdev) { | ||
48 | bpmp = ERR_PTR(-ENODEV); | ||
49 | goto put; | ||
50 | } | ||
51 | |||
52 | bpmp = platform_get_drvdata(pdev); | ||
53 | if (!bpmp) { | ||
54 | bpmp = ERR_PTR(-EPROBE_DEFER); | ||
55 | put_device(&pdev->dev); | ||
56 | goto put; | ||
57 | } | ||
58 | |||
59 | put: | ||
60 | of_node_put(np); | ||
61 | return bpmp; | ||
62 | } | ||
63 | EXPORT_SYMBOL_GPL(tegra_bpmp_get); | ||
64 | |||
65 | void tegra_bpmp_put(struct tegra_bpmp *bpmp) | ||
66 | { | ||
67 | if (bpmp) | ||
68 | put_device(bpmp->dev); | ||
69 | } | ||
70 | EXPORT_SYMBOL_GPL(tegra_bpmp_put); | ||
71 | |||
72 | static int tegra_bpmp_channel_get_index(struct tegra_bpmp_channel *channel) | ||
73 | { | ||
74 | return channel - channel->bpmp->channels; | ||
75 | } | ||
76 | |||
77 | static int | ||
78 | tegra_bpmp_channel_get_thread_index(struct tegra_bpmp_channel *channel) | ||
79 | { | ||
80 | struct tegra_bpmp *bpmp = channel->bpmp; | ||
81 | unsigned int offset, count; | ||
82 | int index; | ||
83 | |||
84 | offset = bpmp->soc->channels.thread.offset; | ||
85 | count = bpmp->soc->channels.thread.count; | ||
86 | |||
87 | index = tegra_bpmp_channel_get_index(channel); | ||
88 | if (index < 0) | ||
89 | return index; | ||
90 | |||
91 | if (index < offset || index >= offset + count) | ||
92 | return -EINVAL; | ||
93 | |||
94 | return index - offset; | ||
95 | } | ||
96 | |||
97 | static struct tegra_bpmp_channel * | ||
98 | tegra_bpmp_channel_get_thread(struct tegra_bpmp *bpmp, unsigned int index) | ||
99 | { | ||
100 | unsigned int offset = bpmp->soc->channels.thread.offset; | ||
101 | unsigned int count = bpmp->soc->channels.thread.count; | ||
102 | |||
103 | if (index >= count) | ||
104 | return NULL; | ||
105 | |||
106 | return &bpmp->channels[offset + index]; | ||
107 | } | ||
108 | |||
109 | static struct tegra_bpmp_channel * | ||
110 | tegra_bpmp_channel_get_tx(struct tegra_bpmp *bpmp) | ||
111 | { | ||
112 | unsigned int offset = bpmp->soc->channels.cpu_tx.offset; | ||
113 | |||
114 | return &bpmp->channels[offset + smp_processor_id()]; | ||
115 | } | ||
116 | |||
117 | static struct tegra_bpmp_channel * | ||
118 | tegra_bpmp_channel_get_rx(struct tegra_bpmp *bpmp) | ||
119 | { | ||
120 | unsigned int offset = bpmp->soc->channels.cpu_rx.offset; | ||
121 | |||
122 | return &bpmp->channels[offset]; | ||
123 | } | ||
124 | |||
125 | static bool tegra_bpmp_message_valid(const struct tegra_bpmp_message *msg) | ||
126 | { | ||
127 | return (msg->tx.size <= MSG_DATA_MIN_SZ) && | ||
128 | (msg->rx.size <= MSG_DATA_MIN_SZ) && | ||
129 | (msg->tx.size == 0 || msg->tx.data) && | ||
130 | (msg->rx.size == 0 || msg->rx.data); | ||
131 | } | ||
132 | |||
133 | static bool tegra_bpmp_master_acked(struct tegra_bpmp_channel *channel) | ||
134 | { | ||
135 | void *frame; | ||
136 | |||
137 | frame = tegra_ivc_read_get_next_frame(channel->ivc); | ||
138 | if (IS_ERR(frame)) { | ||
139 | channel->ib = NULL; | ||
140 | return false; | ||
141 | } | ||
142 | |||
143 | channel->ib = frame; | ||
144 | |||
145 | return true; | ||
146 | } | ||
147 | |||
148 | static int tegra_bpmp_wait_ack(struct tegra_bpmp_channel *channel) | ||
149 | { | ||
150 | unsigned long timeout = channel->bpmp->soc->channels.cpu_tx.timeout; | ||
151 | ktime_t end; | ||
152 | |||
153 | end = ktime_add_us(ktime_get(), timeout); | ||
154 | |||
155 | do { | ||
156 | if (tegra_bpmp_master_acked(channel)) | ||
157 | return 0; | ||
158 | } while (ktime_before(ktime_get(), end)); | ||
159 | |||
160 | return -ETIMEDOUT; | ||
161 | } | ||
162 | |||
163 | static bool tegra_bpmp_master_free(struct tegra_bpmp_channel *channel) | ||
164 | { | ||
165 | void *frame; | ||
166 | |||
167 | frame = tegra_ivc_write_get_next_frame(channel->ivc); | ||
168 | if (IS_ERR(frame)) { | ||
169 | channel->ob = NULL; | ||
170 | return false; | ||
171 | } | ||
172 | |||
173 | channel->ob = frame; | ||
174 | |||
175 | return true; | ||
176 | } | ||
177 | |||
178 | static int tegra_bpmp_wait_master_free(struct tegra_bpmp_channel *channel) | ||
179 | { | ||
180 | unsigned long timeout = channel->bpmp->soc->channels.cpu_tx.timeout; | ||
181 | ktime_t start, now; | ||
182 | |||
183 | start = ns_to_ktime(local_clock()); | ||
184 | |||
185 | do { | ||
186 | if (tegra_bpmp_master_free(channel)) | ||
187 | return 0; | ||
188 | |||
189 | now = ns_to_ktime(local_clock()); | ||
190 | } while (ktime_us_delta(now, start) < timeout); | ||
191 | |||
192 | return -ETIMEDOUT; | ||
193 | } | ||
194 | |||
195 | static ssize_t __tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel, | ||
196 | void *data, size_t size) | ||
197 | { | ||
198 | if (data && size > 0) | ||
199 | memcpy(data, channel->ib->data, size); | ||
200 | |||
201 | return tegra_ivc_read_advance(channel->ivc); | ||
202 | } | ||
203 | |||
204 | static ssize_t tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel, | ||
205 | void *data, size_t size) | ||
206 | { | ||
207 | struct tegra_bpmp *bpmp = channel->bpmp; | ||
208 | unsigned long flags; | ||
209 | ssize_t err; | ||
210 | int index; | ||
211 | |||
212 | index = tegra_bpmp_channel_get_thread_index(channel); | ||
213 | if (index < 0) | ||
214 | return index; | ||
215 | |||
216 | spin_lock_irqsave(&bpmp->lock, flags); | ||
217 | err = __tegra_bpmp_channel_read(channel, data, size); | ||
218 | clear_bit(index, bpmp->threaded.allocated); | ||
219 | spin_unlock_irqrestore(&bpmp->lock, flags); | ||
220 | |||
221 | up(&bpmp->threaded.lock); | ||
222 | |||
223 | return err; | ||
224 | } | ||
225 | |||
226 | static ssize_t __tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel, | ||
227 | unsigned int mrq, unsigned long flags, | ||
228 | const void *data, size_t size) | ||
229 | { | ||
230 | channel->ob->code = mrq; | ||
231 | channel->ob->flags = flags; | ||
232 | |||
233 | if (data && size > 0) | ||
234 | memcpy(channel->ob->data, data, size); | ||
235 | |||
236 | return tegra_ivc_write_advance(channel->ivc); | ||
237 | } | ||
238 | |||
239 | static struct tegra_bpmp_channel * | ||
240 | tegra_bpmp_write_threaded(struct tegra_bpmp *bpmp, unsigned int mrq, | ||
241 | const void *data, size_t size) | ||
242 | { | ||
243 | unsigned long timeout = bpmp->soc->channels.thread.timeout; | ||
244 | unsigned int count = bpmp->soc->channels.thread.count; | ||
245 | struct tegra_bpmp_channel *channel; | ||
246 | unsigned long flags; | ||
247 | unsigned int index; | ||
248 | int err; | ||
249 | |||
250 | err = down_timeout(&bpmp->threaded.lock, usecs_to_jiffies(timeout)); | ||
251 | if (err < 0) | ||
252 | return ERR_PTR(err); | ||
253 | |||
254 | spin_lock_irqsave(&bpmp->lock, flags); | ||
255 | |||
256 | index = find_first_zero_bit(bpmp->threaded.allocated, count); | ||
257 | if (index == count) { | ||
258 | channel = ERR_PTR(-EBUSY); | ||
259 | goto unlock; | ||
260 | } | ||
261 | |||
262 | channel = tegra_bpmp_channel_get_thread(bpmp, index); | ||
263 | if (!channel) { | ||
264 | channel = ERR_PTR(-EINVAL); | ||
265 | goto unlock; | ||
266 | } | ||
267 | |||
268 | if (!tegra_bpmp_master_free(channel)) { | ||
269 | channel = ERR_PTR(-EBUSY); | ||
270 | goto unlock; | ||
271 | } | ||
272 | |||
273 | set_bit(index, bpmp->threaded.allocated); | ||
274 | |||
275 | err = __tegra_bpmp_channel_write(channel, mrq, MSG_ACK | MSG_RING, | ||
276 | data, size); | ||
277 | if (err < 0) { | ||
278 | clear_bit(index, bpmp->threaded.allocated); | ||
279 | goto unlock; | ||
280 | } | ||
281 | |||
282 | set_bit(index, bpmp->threaded.busy); | ||
283 | |||
284 | unlock: | ||
285 | spin_unlock_irqrestore(&bpmp->lock, flags); | ||
286 | return channel; | ||
287 | } | ||
288 | |||
289 | static ssize_t tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel, | ||
290 | unsigned int mrq, unsigned long flags, | ||
291 | const void *data, size_t size) | ||
292 | { | ||
293 | int err; | ||
294 | |||
295 | err = tegra_bpmp_wait_master_free(channel); | ||
296 | if (err < 0) | ||
297 | return err; | ||
298 | |||
299 | return __tegra_bpmp_channel_write(channel, mrq, flags, data, size); | ||
300 | } | ||
301 | |||
302 | int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp, | ||
303 | struct tegra_bpmp_message *msg) | ||
304 | { | ||
305 | struct tegra_bpmp_channel *channel; | ||
306 | int err; | ||
307 | |||
308 | if (WARN_ON(!irqs_disabled())) | ||
309 | return -EPERM; | ||
310 | |||
311 | if (!tegra_bpmp_message_valid(msg)) | ||
312 | return -EINVAL; | ||
313 | |||
314 | channel = tegra_bpmp_channel_get_tx(bpmp); | ||
315 | |||
316 | err = tegra_bpmp_channel_write(channel, msg->mrq, MSG_ACK, | ||
317 | msg->tx.data, msg->tx.size); | ||
318 | if (err < 0) | ||
319 | return err; | ||
320 | |||
321 | err = mbox_send_message(bpmp->mbox.channel, NULL); | ||
322 | if (err < 0) | ||
323 | return err; | ||
324 | |||
325 | mbox_client_txdone(bpmp->mbox.channel, 0); | ||
326 | |||
327 | err = tegra_bpmp_wait_ack(channel); | ||
328 | if (err < 0) | ||
329 | return err; | ||
330 | |||
331 | return __tegra_bpmp_channel_read(channel, msg->rx.data, msg->rx.size); | ||
332 | } | ||
333 | EXPORT_SYMBOL_GPL(tegra_bpmp_transfer_atomic); | ||
334 | |||
335 | int tegra_bpmp_transfer(struct tegra_bpmp *bpmp, | ||
336 | struct tegra_bpmp_message *msg) | ||
337 | { | ||
338 | struct tegra_bpmp_channel *channel; | ||
339 | unsigned long timeout; | ||
340 | int err; | ||
341 | |||
342 | if (WARN_ON(irqs_disabled())) | ||
343 | return -EPERM; | ||
344 | |||
345 | if (!tegra_bpmp_message_valid(msg)) | ||
346 | return -EINVAL; | ||
347 | |||
348 | channel = tegra_bpmp_write_threaded(bpmp, msg->mrq, msg->tx.data, | ||
349 | msg->tx.size); | ||
350 | if (IS_ERR(channel)) | ||
351 | return PTR_ERR(channel); | ||
352 | |||
353 | err = mbox_send_message(bpmp->mbox.channel, NULL); | ||
354 | if (err < 0) | ||
355 | return err; | ||
356 | |||
357 | mbox_client_txdone(bpmp->mbox.channel, 0); | ||
358 | |||
359 | timeout = usecs_to_jiffies(bpmp->soc->channels.thread.timeout); | ||
360 | |||
361 | err = wait_for_completion_timeout(&channel->completion, timeout); | ||
362 | if (err == 0) | ||
363 | return -ETIMEDOUT; | ||
364 | |||
365 | return tegra_bpmp_channel_read(channel, msg->rx.data, msg->rx.size); | ||
366 | } | ||
367 | EXPORT_SYMBOL_GPL(tegra_bpmp_transfer); | ||
368 | |||
369 | static struct tegra_bpmp_mrq *tegra_bpmp_find_mrq(struct tegra_bpmp *bpmp, | ||
370 | unsigned int mrq) | ||
371 | { | ||
372 | struct tegra_bpmp_mrq *entry; | ||
373 | |||
374 | list_for_each_entry(entry, &bpmp->mrqs, list) | ||
375 | if (entry->mrq == mrq) | ||
376 | return entry; | ||
377 | |||
378 | return NULL; | ||
379 | } | ||
380 | |||
381 | static void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, | ||
382 | int code, const void *data, size_t size) | ||
383 | { | ||
384 | unsigned long flags = channel->ib->flags; | ||
385 | struct tegra_bpmp *bpmp = channel->bpmp; | ||
386 | struct tegra_bpmp_mb_data *frame; | ||
387 | int err; | ||
388 | |||
389 | if (WARN_ON(size > MSG_DATA_MIN_SZ)) | ||
390 | return; | ||
391 | |||
392 | err = tegra_ivc_read_advance(channel->ivc); | ||
393 | if (WARN_ON(err < 0)) | ||
394 | return; | ||
395 | |||
396 | if ((flags & MSG_ACK) == 0) | ||
397 | return; | ||
398 | |||
399 | frame = tegra_ivc_write_get_next_frame(channel->ivc); | ||
400 | if (WARN_ON(IS_ERR(frame))) | ||
401 | return; | ||
402 | |||
403 | frame->code = code; | ||
404 | |||
405 | if (data && size > 0) | ||
406 | memcpy(frame->data, data, size); | ||
407 | |||
408 | err = tegra_ivc_write_advance(channel->ivc); | ||
409 | if (WARN_ON(err < 0)) | ||
410 | return; | ||
411 | |||
412 | if (flags & MSG_RING) { | ||
413 | err = mbox_send_message(bpmp->mbox.channel, NULL); | ||
414 | if (WARN_ON(err < 0)) | ||
415 | return; | ||
416 | |||
417 | mbox_client_txdone(bpmp->mbox.channel, 0); | ||
418 | } | ||
419 | } | ||
420 | |||
421 | static void tegra_bpmp_handle_mrq(struct tegra_bpmp *bpmp, | ||
422 | unsigned int mrq, | ||
423 | struct tegra_bpmp_channel *channel) | ||
424 | { | ||
425 | struct tegra_bpmp_mrq *entry; | ||
426 | u32 zero = 0; | ||
427 | |||
428 | spin_lock(&bpmp->lock); | ||
429 | |||
430 | entry = tegra_bpmp_find_mrq(bpmp, mrq); | ||
431 | if (!entry) { | ||
432 | spin_unlock(&bpmp->lock); | ||
433 | tegra_bpmp_mrq_return(channel, -EINVAL, &zero, sizeof(zero)); | ||
434 | return; | ||
435 | } | ||
436 | |||
437 | entry->handler(mrq, channel, entry->data); | ||
438 | |||
439 | spin_unlock(&bpmp->lock); | ||
440 | } | ||
441 | |||
442 | int tegra_bpmp_request_mrq(struct tegra_bpmp *bpmp, unsigned int mrq, | ||
443 | tegra_bpmp_mrq_handler_t handler, void *data) | ||
444 | { | ||
445 | struct tegra_bpmp_mrq *entry; | ||
446 | unsigned long flags; | ||
447 | |||
448 | if (!handler) | ||
449 | return -EINVAL; | ||
450 | |||
451 | entry = devm_kzalloc(bpmp->dev, sizeof(*entry), GFP_KERNEL); | ||
452 | if (!entry) | ||
453 | return -ENOMEM; | ||
454 | |||
455 | spin_lock_irqsave(&bpmp->lock, flags); | ||
456 | |||
457 | entry->mrq = mrq; | ||
458 | entry->handler = handler; | ||
459 | entry->data = data; | ||
460 | list_add(&entry->list, &bpmp->mrqs); | ||
461 | |||
462 | spin_unlock_irqrestore(&bpmp->lock, flags); | ||
463 | |||
464 | return 0; | ||
465 | } | ||
466 | EXPORT_SYMBOL_GPL(tegra_bpmp_request_mrq); | ||
467 | |||
468 | void tegra_bpmp_free_mrq(struct tegra_bpmp *bpmp, unsigned int mrq, void *data) | ||
469 | { | ||
470 | struct tegra_bpmp_mrq *entry; | ||
471 | unsigned long flags; | ||
472 | |||
473 | spin_lock_irqsave(&bpmp->lock, flags); | ||
474 | |||
475 | entry = tegra_bpmp_find_mrq(bpmp, mrq); | ||
476 | if (!entry) | ||
477 | goto unlock; | ||
478 | |||
479 | list_del(&entry->list); | ||
480 | devm_kfree(bpmp->dev, entry); | ||
481 | |||
482 | unlock: | ||
483 | spin_unlock_irqrestore(&bpmp->lock, flags); | ||
484 | } | ||
485 | EXPORT_SYMBOL_GPL(tegra_bpmp_free_mrq); | ||
486 | |||
487 | static void tegra_bpmp_mrq_handle_ping(unsigned int mrq, | ||
488 | struct tegra_bpmp_channel *channel, | ||
489 | void *data) | ||
490 | { | ||
491 | struct mrq_ping_request *request; | ||
492 | struct mrq_ping_response response; | ||
493 | |||
494 | request = (struct mrq_ping_request *)channel->ib->data; | ||
495 | |||
496 | memset(&response, 0, sizeof(response)); | ||
497 | response.reply = request->challenge << 1; | ||
498 | |||
499 | tegra_bpmp_mrq_return(channel, 0, &response, sizeof(response)); | ||
500 | } | ||
501 | |||
502 | static int tegra_bpmp_ping(struct tegra_bpmp *bpmp) | ||
503 | { | ||
504 | struct mrq_ping_response response; | ||
505 | struct mrq_ping_request request; | ||
506 | struct tegra_bpmp_message msg; | ||
507 | unsigned long flags; | ||
508 | ktime_t start, end; | ||
509 | int err; | ||
510 | |||
511 | memset(&request, 0, sizeof(request)); | ||
512 | request.challenge = 1; | ||
513 | |||
514 | memset(&response, 0, sizeof(response)); | ||
515 | |||
516 | memset(&msg, 0, sizeof(msg)); | ||
517 | msg.mrq = MRQ_PING; | ||
518 | msg.tx.data = &request; | ||
519 | msg.tx.size = sizeof(request); | ||
520 | msg.rx.data = &response; | ||
521 | msg.rx.size = sizeof(response); | ||
522 | |||
523 | local_irq_save(flags); | ||
524 | start = ktime_get(); | ||
525 | err = tegra_bpmp_transfer_atomic(bpmp, &msg); | ||
526 | end = ktime_get(); | ||
527 | local_irq_restore(flags); | ||
528 | |||
529 | if (!err) | ||
530 | dev_dbg(bpmp->dev, | ||
531 | "ping ok: challenge: %u, response: %u, time: %lld\n", | ||
532 | request.challenge, response.reply, | ||
533 | ktime_to_us(ktime_sub(end, start))); | ||
534 | |||
535 | return err; | ||
536 | } | ||
537 | |||
538 | static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag, | ||
539 | size_t size) | ||
540 | { | ||
541 | struct mrq_query_tag_request request; | ||
542 | struct tegra_bpmp_message msg; | ||
543 | unsigned long flags; | ||
544 | dma_addr_t phys; | ||
545 | void *virt; | ||
546 | int err; | ||
547 | |||
548 | virt = dma_alloc_coherent(bpmp->dev, MSG_DATA_MIN_SZ, &phys, | ||
549 | GFP_KERNEL | GFP_DMA32); | ||
550 | if (!virt) | ||
551 | return -ENOMEM; | ||
552 | |||
553 | memset(&request, 0, sizeof(request)); | ||
554 | request.addr = phys; | ||
555 | |||
556 | memset(&msg, 0, sizeof(msg)); | ||
557 | msg.mrq = MRQ_QUERY_TAG; | ||
558 | msg.tx.data = &request; | ||
559 | msg.tx.size = sizeof(request); | ||
560 | |||
561 | local_irq_save(flags); | ||
562 | err = tegra_bpmp_transfer_atomic(bpmp, &msg); | ||
563 | local_irq_restore(flags); | ||
564 | |||
565 | if (err == 0) | ||
566 | strlcpy(tag, virt, size); | ||
567 | |||
568 | dma_free_coherent(bpmp->dev, MSG_DATA_MIN_SZ, virt, phys); | ||
569 | |||
570 | return err; | ||
571 | } | ||
572 | |||
573 | static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel) | ||
574 | { | ||
575 | unsigned long flags = channel->ob->flags; | ||
576 | |||
577 | if ((flags & MSG_RING) == 0) | ||
578 | return; | ||
579 | |||
580 | complete(&channel->completion); | ||
581 | } | ||
582 | |||
583 | static void tegra_bpmp_handle_rx(struct mbox_client *client, void *data) | ||
584 | { | ||
585 | struct tegra_bpmp *bpmp = mbox_client_to_bpmp(client); | ||
586 | struct tegra_bpmp_channel *channel; | ||
587 | unsigned int i, count; | ||
588 | unsigned long *busy; | ||
589 | |||
590 | channel = tegra_bpmp_channel_get_rx(bpmp); | ||
591 | count = bpmp->soc->channels.thread.count; | ||
592 | busy = bpmp->threaded.busy; | ||
593 | |||
594 | if (tegra_bpmp_master_acked(channel)) | ||
595 | tegra_bpmp_handle_mrq(bpmp, channel->ib->code, channel); | ||
596 | |||
597 | spin_lock(&bpmp->lock); | ||
598 | |||
599 | for_each_set_bit(i, busy, count) { | ||
600 | struct tegra_bpmp_channel *channel; | ||
601 | |||
602 | channel = tegra_bpmp_channel_get_thread(bpmp, i); | ||
603 | if (!channel) | ||
604 | continue; | ||
605 | |||
606 | if (tegra_bpmp_master_acked(channel)) { | ||
607 | tegra_bpmp_channel_signal(channel); | ||
608 | clear_bit(i, busy); | ||
609 | } | ||
610 | } | ||
611 | |||
612 | spin_unlock(&bpmp->lock); | ||
613 | } | ||
614 | |||
615 | static void tegra_bpmp_ivc_notify(struct tegra_ivc *ivc, void *data) | ||
616 | { | ||
617 | struct tegra_bpmp *bpmp = data; | ||
618 | int err; | ||
619 | |||
620 | if (WARN_ON(bpmp->mbox.channel == NULL)) | ||
621 | return; | ||
622 | |||
623 | err = mbox_send_message(bpmp->mbox.channel, NULL); | ||
624 | if (err < 0) | ||
625 | return; | ||
626 | |||
627 | mbox_client_txdone(bpmp->mbox.channel, 0); | ||
628 | } | ||
629 | |||
630 | static int tegra_bpmp_channel_init(struct tegra_bpmp_channel *channel, | ||
631 | struct tegra_bpmp *bpmp, | ||
632 | unsigned int index) | ||
633 | { | ||
634 | size_t message_size, queue_size; | ||
635 | unsigned int offset; | ||
636 | int err; | ||
637 | |||
638 | channel->ivc = devm_kzalloc(bpmp->dev, sizeof(*channel->ivc), | ||
639 | GFP_KERNEL); | ||
640 | if (!channel->ivc) | ||
641 | return -ENOMEM; | ||
642 | |||
643 | message_size = tegra_ivc_align(MSG_MIN_SZ); | ||
644 | queue_size = tegra_ivc_total_queue_size(message_size); | ||
645 | offset = queue_size * index; | ||
646 | |||
647 | err = tegra_ivc_init(channel->ivc, NULL, | ||
648 | bpmp->rx.virt + offset, bpmp->rx.phys + offset, | ||
649 | bpmp->tx.virt + offset, bpmp->tx.phys + offset, | ||
650 | 1, message_size, tegra_bpmp_ivc_notify, | ||
651 | bpmp); | ||
652 | if (err < 0) { | ||
653 | dev_err(bpmp->dev, "failed to setup IVC for channel %u: %d\n", | ||
654 | index, err); | ||
655 | return err; | ||
656 | } | ||
657 | |||
658 | init_completion(&channel->completion); | ||
659 | channel->bpmp = bpmp; | ||
660 | |||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | static void tegra_bpmp_channel_reset(struct tegra_bpmp_channel *channel) | ||
665 | { | ||
666 | /* reset the channel state */ | ||
667 | tegra_ivc_reset(channel->ivc); | ||
668 | |||
669 | /* sync the channel state with BPMP */ | ||
670 | while (tegra_ivc_notified(channel->ivc)) | ||
671 | ; | ||
672 | } | ||
673 | |||
674 | static void tegra_bpmp_channel_cleanup(struct tegra_bpmp_channel *channel) | ||
675 | { | ||
676 | tegra_ivc_cleanup(channel->ivc); | ||
677 | } | ||
678 | |||
679 | static int tegra_bpmp_probe(struct platform_device *pdev) | ||
680 | { | ||
681 | struct tegra_bpmp_channel *channel; | ||
682 | struct tegra_bpmp *bpmp; | ||
683 | unsigned int i; | ||
684 | char tag[32]; | ||
685 | size_t size; | ||
686 | int err; | ||
687 | |||
688 | bpmp = devm_kzalloc(&pdev->dev, sizeof(*bpmp), GFP_KERNEL); | ||
689 | if (!bpmp) | ||
690 | return -ENOMEM; | ||
691 | |||
692 | bpmp->soc = of_device_get_match_data(&pdev->dev); | ||
693 | bpmp->dev = &pdev->dev; | ||
694 | |||
695 | bpmp->tx.pool = of_gen_pool_get(pdev->dev.of_node, "shmem", 0); | ||
696 | if (!bpmp->tx.pool) { | ||
697 | dev_err(&pdev->dev, "TX shmem pool not found\n"); | ||
698 | return -ENOMEM; | ||
699 | } | ||
700 | |||
701 | bpmp->tx.virt = gen_pool_dma_alloc(bpmp->tx.pool, 4096, &bpmp->tx.phys); | ||
702 | if (!bpmp->tx.virt) { | ||
703 | dev_err(&pdev->dev, "failed to allocate from TX pool\n"); | ||
704 | return -ENOMEM; | ||
705 | } | ||
706 | |||
707 | bpmp->rx.pool = of_gen_pool_get(pdev->dev.of_node, "shmem", 1); | ||
708 | if (!bpmp->rx.pool) { | ||
709 | dev_err(&pdev->dev, "RX shmem pool not found\n"); | ||
710 | err = -ENOMEM; | ||
711 | goto free_tx; | ||
712 | } | ||
713 | |||
714 | bpmp->rx.virt = gen_pool_dma_alloc(bpmp->rx.pool, 4096, &bpmp->rx.phys); | ||
715 | if (!bpmp->rx.pool) { | ||
716 | dev_err(&pdev->dev, "failed to allocate from RX pool\n"); | ||
717 | err = -ENOMEM; | ||
718 | goto free_tx; | ||
719 | } | ||
720 | |||
721 | INIT_LIST_HEAD(&bpmp->mrqs); | ||
722 | spin_lock_init(&bpmp->lock); | ||
723 | |||
724 | bpmp->threaded.count = bpmp->soc->channels.thread.count; | ||
725 | sema_init(&bpmp->threaded.lock, bpmp->threaded.count); | ||
726 | |||
727 | size = BITS_TO_LONGS(bpmp->threaded.count) * sizeof(long); | ||
728 | |||
729 | bpmp->threaded.allocated = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); | ||
730 | if (!bpmp->threaded.allocated) { | ||
731 | err = -ENOMEM; | ||
732 | goto free_rx; | ||
733 | } | ||
734 | |||
735 | bpmp->threaded.busy = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); | ||
736 | if (!bpmp->threaded.busy) { | ||
737 | err = -ENOMEM; | ||
738 | goto free_rx; | ||
739 | } | ||
740 | |||
741 | bpmp->num_channels = bpmp->soc->channels.cpu_tx.count + | ||
742 | bpmp->soc->channels.thread.count + | ||
743 | bpmp->soc->channels.cpu_rx.count; | ||
744 | |||
745 | bpmp->channels = devm_kcalloc(&pdev->dev, bpmp->num_channels, | ||
746 | sizeof(*channel), GFP_KERNEL); | ||
747 | if (!bpmp->channels) { | ||
748 | err = -ENOMEM; | ||
749 | goto free_rx; | ||
750 | } | ||
751 | |||
752 | /* message channel initialization */ | ||
753 | for (i = 0; i < bpmp->num_channels; i++) { | ||
754 | struct tegra_bpmp_channel *channel = &bpmp->channels[i]; | ||
755 | |||
756 | err = tegra_bpmp_channel_init(channel, bpmp, i); | ||
757 | if (err < 0) | ||
758 | goto cleanup_channels; | ||
759 | } | ||
760 | |||
761 | /* mbox registration */ | ||
762 | bpmp->mbox.client.dev = &pdev->dev; | ||
763 | bpmp->mbox.client.rx_callback = tegra_bpmp_handle_rx; | ||
764 | bpmp->mbox.client.tx_block = false; | ||
765 | bpmp->mbox.client.knows_txdone = false; | ||
766 | |||
767 | bpmp->mbox.channel = mbox_request_channel(&bpmp->mbox.client, 0); | ||
768 | if (IS_ERR(bpmp->mbox.channel)) { | ||
769 | err = PTR_ERR(bpmp->mbox.channel); | ||
770 | dev_err(&pdev->dev, "failed to get HSP mailbox: %d\n", err); | ||
771 | goto cleanup_channels; | ||
772 | } | ||
773 | |||
774 | /* reset message channels */ | ||
775 | for (i = 0; i < bpmp->num_channels; i++) { | ||
776 | struct tegra_bpmp_channel *channel = &bpmp->channels[i]; | ||
777 | |||
778 | tegra_bpmp_channel_reset(channel); | ||
779 | } | ||
780 | |||
781 | err = tegra_bpmp_request_mrq(bpmp, MRQ_PING, | ||
782 | tegra_bpmp_mrq_handle_ping, bpmp); | ||
783 | if (err < 0) | ||
784 | goto free_mbox; | ||
785 | |||
786 | err = tegra_bpmp_ping(bpmp); | ||
787 | if (err < 0) { | ||
788 | dev_err(&pdev->dev, "failed to ping BPMP: %d\n", err); | ||
789 | goto free_mrq; | ||
790 | } | ||
791 | |||
792 | err = tegra_bpmp_get_firmware_tag(bpmp, tag, sizeof(tag) - 1); | ||
793 | if (err < 0) { | ||
794 | dev_err(&pdev->dev, "failed to get firmware tag: %d\n", err); | ||
795 | goto free_mrq; | ||
796 | } | ||
797 | |||
798 | dev_info(&pdev->dev, "firmware: %s\n", tag); | ||
799 | |||
800 | err = of_platform_default_populate(pdev->dev.of_node, NULL, &pdev->dev); | ||
801 | if (err < 0) | ||
802 | goto free_mrq; | ||
803 | |||
804 | err = tegra_bpmp_init_clocks(bpmp); | ||
805 | if (err < 0) | ||
806 | goto free_mrq; | ||
807 | |||
808 | err = tegra_bpmp_init_resets(bpmp); | ||
809 | if (err < 0) | ||
810 | goto free_mrq; | ||
811 | |||
812 | platform_set_drvdata(pdev, bpmp); | ||
813 | |||
814 | return 0; | ||
815 | |||
816 | free_mrq: | ||
817 | tegra_bpmp_free_mrq(bpmp, MRQ_PING, bpmp); | ||
818 | free_mbox: | ||
819 | mbox_free_channel(bpmp->mbox.channel); | ||
820 | cleanup_channels: | ||
821 | while (i--) | ||
822 | tegra_bpmp_channel_cleanup(&bpmp->channels[i]); | ||
823 | free_rx: | ||
824 | gen_pool_free(bpmp->rx.pool, (unsigned long)bpmp->rx.virt, 4096); | ||
825 | free_tx: | ||
826 | gen_pool_free(bpmp->tx.pool, (unsigned long)bpmp->tx.virt, 4096); | ||
827 | return err; | ||
828 | } | ||
829 | |||
830 | static const struct tegra_bpmp_soc tegra186_soc = { | ||
831 | .channels = { | ||
832 | .cpu_tx = { | ||
833 | .offset = 0, | ||
834 | .count = 6, | ||
835 | .timeout = 60 * USEC_PER_SEC, | ||
836 | }, | ||
837 | .thread = { | ||
838 | .offset = 6, | ||
839 | .count = 7, | ||
840 | .timeout = 600 * USEC_PER_SEC, | ||
841 | }, | ||
842 | .cpu_rx = { | ||
843 | .offset = 13, | ||
844 | .count = 1, | ||
845 | .timeout = 0, | ||
846 | }, | ||
847 | }, | ||
848 | .num_resets = 193, | ||
849 | }; | ||
850 | |||
851 | static const struct of_device_id tegra_bpmp_match[] = { | ||
852 | { .compatible = "nvidia,tegra186-bpmp", .data = &tegra186_soc }, | ||
853 | { } | ||
854 | }; | ||
855 | |||
856 | static struct platform_driver tegra_bpmp_driver = { | ||
857 | .driver = { | ||
858 | .name = "tegra-bpmp", | ||
859 | .of_match_table = tegra_bpmp_match, | ||
860 | }, | ||
861 | .probe = tegra_bpmp_probe, | ||
862 | }; | ||
863 | |||
864 | static int __init tegra_bpmp_init(void) | ||
865 | { | ||
866 | return platform_driver_register(&tegra_bpmp_driver); | ||
867 | } | ||
868 | core_initcall(tegra_bpmp_init); | ||
diff --git a/drivers/firmware/tegra/ivc.c b/drivers/firmware/tegra/ivc.c new file mode 100644 index 000000000000..29ecfd815320 --- /dev/null +++ b/drivers/firmware/tegra/ivc.c | |||
@@ -0,0 +1,695 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | #include <soc/tegra/ivc.h> | ||
15 | |||
16 | #define TEGRA_IVC_ALIGN 64 | ||
17 | |||
18 | /* | ||
19 | * IVC channel reset protocol. | ||
20 | * | ||
21 | * Each end uses its tx_channel.state to indicate its synchronization state. | ||
22 | */ | ||
23 | enum tegra_ivc_state { | ||
24 | /* | ||
25 | * This value is zero for backwards compatibility with services that | ||
26 | * assume channels to be initially zeroed. Such channels are in an | ||
27 | * initially valid state, but cannot be asynchronously reset, and must | ||
28 | * maintain a valid state at all times. | ||
29 | * | ||
30 | * The transmitting end can enter the established state from the sync or | ||
31 | * ack state when it observes the receiving endpoint in the ack or | ||
32 | * established state, indicating that has cleared the counters in our | ||
33 | * rx_channel. | ||
34 | */ | ||
35 | TEGRA_IVC_STATE_ESTABLISHED = 0, | ||
36 | |||
37 | /* | ||
38 | * If an endpoint is observed in the sync state, the remote endpoint is | ||
39 | * allowed to clear the counters it owns asynchronously with respect to | ||
40 | * the current endpoint. Therefore, the current endpoint is no longer | ||
41 | * allowed to communicate. | ||
42 | */ | ||
43 | TEGRA_IVC_STATE_SYNC, | ||
44 | |||
45 | /* | ||
46 | * When the transmitting end observes the receiving end in the sync | ||
47 | * state, it can clear the w_count and r_count and transition to the ack | ||
48 | * state. If the remote endpoint observes us in the ack state, it can | ||
49 | * return to the established state once it has cleared its counters. | ||
50 | */ | ||
51 | TEGRA_IVC_STATE_ACK | ||
52 | }; | ||
53 | |||
54 | /* | ||
55 | * This structure is divided into two-cache aligned parts, the first is only | ||
56 | * written through the tx.channel pointer, while the second is only written | ||
57 | * through the rx.channel pointer. This delineates ownership of the cache | ||
58 | * lines, which is critical to performance and necessary in non-cache coherent | ||
59 | * implementations. | ||
60 | */ | ||
61 | struct tegra_ivc_header { | ||
62 | union { | ||
63 | struct { | ||
64 | /* fields owned by the transmitting end */ | ||
65 | u32 count; | ||
66 | u32 state; | ||
67 | }; | ||
68 | |||
69 | u8 pad[TEGRA_IVC_ALIGN]; | ||
70 | } tx; | ||
71 | |||
72 | union { | ||
73 | /* fields owned by the receiving end */ | ||
74 | u32 count; | ||
75 | u8 pad[TEGRA_IVC_ALIGN]; | ||
76 | } rx; | ||
77 | }; | ||
78 | |||
79 | static inline void tegra_ivc_invalidate(struct tegra_ivc *ivc, dma_addr_t phys) | ||
80 | { | ||
81 | if (!ivc->peer) | ||
82 | return; | ||
83 | |||
84 | dma_sync_single_for_cpu(ivc->peer, phys, TEGRA_IVC_ALIGN, | ||
85 | DMA_FROM_DEVICE); | ||
86 | } | ||
87 | |||
88 | static inline void tegra_ivc_flush(struct tegra_ivc *ivc, dma_addr_t phys) | ||
89 | { | ||
90 | if (!ivc->peer) | ||
91 | return; | ||
92 | |||
93 | dma_sync_single_for_device(ivc->peer, phys, TEGRA_IVC_ALIGN, | ||
94 | DMA_TO_DEVICE); | ||
95 | } | ||
96 | |||
97 | static inline bool tegra_ivc_empty(struct tegra_ivc *ivc, | ||
98 | struct tegra_ivc_header *header) | ||
99 | { | ||
100 | /* | ||
101 | * This function performs multiple checks on the same values with | ||
102 | * security implications, so create snapshots with ACCESS_ONCE() to | ||
103 | * ensure that these checks use the same values. | ||
104 | */ | ||
105 | u32 tx = ACCESS_ONCE(header->tx.count); | ||
106 | u32 rx = ACCESS_ONCE(header->rx.count); | ||
107 | |||
108 | /* | ||
109 | * Perform an over-full check to prevent denial of service attacks | ||
110 | * where a server could be easily fooled into believing that there's | ||
111 | * an extremely large number of frames ready, since receivers are not | ||
112 | * expected to check for full or over-full conditions. | ||
113 | * | ||
114 | * Although the channel isn't empty, this is an invalid case caused by | ||
115 | * a potentially malicious peer, so returning empty is safer, because | ||
116 | * it gives the impression that the channel has gone silent. | ||
117 | */ | ||
118 | if (tx - rx > ivc->num_frames) | ||
119 | return true; | ||
120 | |||
121 | return tx == rx; | ||
122 | } | ||
123 | |||
124 | static inline bool tegra_ivc_full(struct tegra_ivc *ivc, | ||
125 | struct tegra_ivc_header *header) | ||
126 | { | ||
127 | u32 tx = ACCESS_ONCE(header->tx.count); | ||
128 | u32 rx = ACCESS_ONCE(header->rx.count); | ||
129 | |||
130 | /* | ||
131 | * Invalid cases where the counters indicate that the queue is over | ||
132 | * capacity also appear full. | ||
133 | */ | ||
134 | return tx - rx >= ivc->num_frames; | ||
135 | } | ||
136 | |||
137 | static inline u32 tegra_ivc_available(struct tegra_ivc *ivc, | ||
138 | struct tegra_ivc_header *header) | ||
139 | { | ||
140 | u32 tx = ACCESS_ONCE(header->tx.count); | ||
141 | u32 rx = ACCESS_ONCE(header->rx.count); | ||
142 | |||
143 | /* | ||
144 | * This function isn't expected to be used in scenarios where an | ||
145 | * over-full situation can lead to denial of service attacks. See the | ||
146 | * comment in tegra_ivc_empty() for an explanation about special | ||
147 | * over-full considerations. | ||
148 | */ | ||
149 | return tx - rx; | ||
150 | } | ||
151 | |||
152 | static inline void tegra_ivc_advance_tx(struct tegra_ivc *ivc) | ||
153 | { | ||
154 | ACCESS_ONCE(ivc->tx.channel->tx.count) = | ||
155 | ACCESS_ONCE(ivc->tx.channel->tx.count) + 1; | ||
156 | |||
157 | if (ivc->tx.position == ivc->num_frames - 1) | ||
158 | ivc->tx.position = 0; | ||
159 | else | ||
160 | ivc->tx.position++; | ||
161 | } | ||
162 | |||
163 | static inline void tegra_ivc_advance_rx(struct tegra_ivc *ivc) | ||
164 | { | ||
165 | ACCESS_ONCE(ivc->rx.channel->rx.count) = | ||
166 | ACCESS_ONCE(ivc->rx.channel->rx.count) + 1; | ||
167 | |||
168 | if (ivc->rx.position == ivc->num_frames - 1) | ||
169 | ivc->rx.position = 0; | ||
170 | else | ||
171 | ivc->rx.position++; | ||
172 | } | ||
173 | |||
174 | static inline int tegra_ivc_check_read(struct tegra_ivc *ivc) | ||
175 | { | ||
176 | unsigned int offset = offsetof(struct tegra_ivc_header, tx.count); | ||
177 | |||
178 | /* | ||
179 | * tx.channel->state is set locally, so it is not synchronized with | ||
180 | * state from the remote peer. The remote peer cannot reset its | ||
181 | * transmit counters until we've acknowledged its synchronization | ||
182 | * request, so no additional synchronization is required because an | ||
183 | * asynchronous transition of rx.channel->state to | ||
184 | * TEGRA_IVC_STATE_ACK is not allowed. | ||
185 | */ | ||
186 | if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED) | ||
187 | return -ECONNRESET; | ||
188 | |||
189 | /* | ||
190 | * Avoid unnecessary invalidations when performing repeated accesses | ||
191 | * to an IVC channel by checking the old queue pointers first. | ||
192 | * | ||
193 | * Synchronization is only necessary when these pointers indicate | ||
194 | * empty or full. | ||
195 | */ | ||
196 | if (!tegra_ivc_empty(ivc, ivc->rx.channel)) | ||
197 | return 0; | ||
198 | |||
199 | tegra_ivc_invalidate(ivc, ivc->rx.phys + offset); | ||
200 | |||
201 | if (tegra_ivc_empty(ivc, ivc->rx.channel)) | ||
202 | return -ENOSPC; | ||
203 | |||
204 | return 0; | ||
205 | } | ||
206 | |||
207 | static inline int tegra_ivc_check_write(struct tegra_ivc *ivc) | ||
208 | { | ||
209 | unsigned int offset = offsetof(struct tegra_ivc_header, rx.count); | ||
210 | |||
211 | if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED) | ||
212 | return -ECONNRESET; | ||
213 | |||
214 | if (!tegra_ivc_full(ivc, ivc->tx.channel)) | ||
215 | return 0; | ||
216 | |||
217 | tegra_ivc_invalidate(ivc, ivc->tx.phys + offset); | ||
218 | |||
219 | if (tegra_ivc_full(ivc, ivc->tx.channel)) | ||
220 | return -ENOSPC; | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static void *tegra_ivc_frame_virt(struct tegra_ivc *ivc, | ||
226 | struct tegra_ivc_header *header, | ||
227 | unsigned int frame) | ||
228 | { | ||
229 | if (WARN_ON(frame >= ivc->num_frames)) | ||
230 | return ERR_PTR(-EINVAL); | ||
231 | |||
232 | return (void *)(header + 1) + ivc->frame_size * frame; | ||
233 | } | ||
234 | |||
235 | static inline dma_addr_t tegra_ivc_frame_phys(struct tegra_ivc *ivc, | ||
236 | dma_addr_t phys, | ||
237 | unsigned int frame) | ||
238 | { | ||
239 | unsigned long offset; | ||
240 | |||
241 | offset = sizeof(struct tegra_ivc_header) + ivc->frame_size * frame; | ||
242 | |||
243 | return phys + offset; | ||
244 | } | ||
245 | |||
246 | static inline void tegra_ivc_invalidate_frame(struct tegra_ivc *ivc, | ||
247 | dma_addr_t phys, | ||
248 | unsigned int frame, | ||
249 | unsigned int offset, | ||
250 | size_t size) | ||
251 | { | ||
252 | if (!ivc->peer || WARN_ON(frame >= ivc->num_frames)) | ||
253 | return; | ||
254 | |||
255 | phys = tegra_ivc_frame_phys(ivc, phys, frame) + offset; | ||
256 | |||
257 | dma_sync_single_for_cpu(ivc->peer, phys, size, DMA_FROM_DEVICE); | ||
258 | } | ||
259 | |||
260 | static inline void tegra_ivc_flush_frame(struct tegra_ivc *ivc, | ||
261 | dma_addr_t phys, | ||
262 | unsigned int frame, | ||
263 | unsigned int offset, | ||
264 | size_t size) | ||
265 | { | ||
266 | if (!ivc->peer || WARN_ON(frame >= ivc->num_frames)) | ||
267 | return; | ||
268 | |||
269 | phys = tegra_ivc_frame_phys(ivc, phys, frame) + offset; | ||
270 | |||
271 | dma_sync_single_for_device(ivc->peer, phys, size, DMA_TO_DEVICE); | ||
272 | } | ||
273 | |||
274 | /* directly peek at the next frame rx'ed */ | ||
275 | void *tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc) | ||
276 | { | ||
277 | int err; | ||
278 | |||
279 | if (WARN_ON(ivc == NULL)) | ||
280 | return ERR_PTR(-EINVAL); | ||
281 | |||
282 | err = tegra_ivc_check_read(ivc); | ||
283 | if (err < 0) | ||
284 | return ERR_PTR(err); | ||
285 | |||
286 | /* | ||
287 | * Order observation of ivc->rx.position potentially indicating new | ||
288 | * data before data read. | ||
289 | */ | ||
290 | smp_rmb(); | ||
291 | |||
292 | tegra_ivc_invalidate_frame(ivc, ivc->rx.phys, ivc->rx.position, 0, | ||
293 | ivc->frame_size); | ||
294 | |||
295 | return tegra_ivc_frame_virt(ivc, ivc->rx.channel, ivc->rx.position); | ||
296 | } | ||
297 | EXPORT_SYMBOL(tegra_ivc_read_get_next_frame); | ||
298 | |||
299 | int tegra_ivc_read_advance(struct tegra_ivc *ivc) | ||
300 | { | ||
301 | unsigned int rx = offsetof(struct tegra_ivc_header, rx.count); | ||
302 | unsigned int tx = offsetof(struct tegra_ivc_header, tx.count); | ||
303 | int err; | ||
304 | |||
305 | /* | ||
306 | * No read barriers or synchronization here: the caller is expected to | ||
307 | * have already observed the channel non-empty. This check is just to | ||
308 | * catch programming errors. | ||
309 | */ | ||
310 | err = tegra_ivc_check_read(ivc); | ||
311 | if (err < 0) | ||
312 | return err; | ||
313 | |||
314 | tegra_ivc_advance_rx(ivc); | ||
315 | |||
316 | tegra_ivc_flush(ivc, ivc->rx.phys + rx); | ||
317 | |||
318 | /* | ||
319 | * Ensure our write to ivc->rx.position occurs before our read from | ||
320 | * ivc->tx.position. | ||
321 | */ | ||
322 | smp_mb(); | ||
323 | |||
324 | /* | ||
325 | * Notify only upon transition from full to non-full. The available | ||
326 | * count can only asynchronously increase, so the worst possible | ||
327 | * side-effect will be a spurious notification. | ||
328 | */ | ||
329 | tegra_ivc_invalidate(ivc, ivc->rx.phys + tx); | ||
330 | |||
331 | if (tegra_ivc_available(ivc, ivc->rx.channel) == ivc->num_frames - 1) | ||
332 | ivc->notify(ivc, ivc->notify_data); | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | EXPORT_SYMBOL(tegra_ivc_read_advance); | ||
337 | |||
338 | /* directly poke at the next frame to be tx'ed */ | ||
339 | void *tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc) | ||
340 | { | ||
341 | int err; | ||
342 | |||
343 | err = tegra_ivc_check_write(ivc); | ||
344 | if (err < 0) | ||
345 | return ERR_PTR(err); | ||
346 | |||
347 | return tegra_ivc_frame_virt(ivc, ivc->tx.channel, ivc->tx.position); | ||
348 | } | ||
349 | EXPORT_SYMBOL(tegra_ivc_write_get_next_frame); | ||
350 | |||
351 | /* advance the tx buffer */ | ||
352 | int tegra_ivc_write_advance(struct tegra_ivc *ivc) | ||
353 | { | ||
354 | unsigned int tx = offsetof(struct tegra_ivc_header, tx.count); | ||
355 | unsigned int rx = offsetof(struct tegra_ivc_header, rx.count); | ||
356 | int err; | ||
357 | |||
358 | err = tegra_ivc_check_write(ivc); | ||
359 | if (err < 0) | ||
360 | return err; | ||
361 | |||
362 | tegra_ivc_flush_frame(ivc, ivc->tx.phys, ivc->tx.position, 0, | ||
363 | ivc->frame_size); | ||
364 | |||
365 | /* | ||
366 | * Order any possible stores to the frame before update of | ||
367 | * ivc->tx.position. | ||
368 | */ | ||
369 | smp_wmb(); | ||
370 | |||
371 | tegra_ivc_advance_tx(ivc); | ||
372 | tegra_ivc_flush(ivc, ivc->tx.phys + tx); | ||
373 | |||
374 | /* | ||
375 | * Ensure our write to ivc->tx.position occurs before our read from | ||
376 | * ivc->rx.position. | ||
377 | */ | ||
378 | smp_mb(); | ||
379 | |||
380 | /* | ||
381 | * Notify only upon transition from empty to non-empty. The available | ||
382 | * count can only asynchronously decrease, so the worst possible | ||
383 | * side-effect will be a spurious notification. | ||
384 | */ | ||
385 | tegra_ivc_invalidate(ivc, ivc->tx.phys + rx); | ||
386 | |||
387 | if (tegra_ivc_available(ivc, ivc->tx.channel) == 1) | ||
388 | ivc->notify(ivc, ivc->notify_data); | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | EXPORT_SYMBOL(tegra_ivc_write_advance); | ||
393 | |||
394 | void tegra_ivc_reset(struct tegra_ivc *ivc) | ||
395 | { | ||
396 | unsigned int offset = offsetof(struct tegra_ivc_header, tx.count); | ||
397 | |||
398 | ivc->tx.channel->tx.state = TEGRA_IVC_STATE_SYNC; | ||
399 | tegra_ivc_flush(ivc, ivc->tx.phys + offset); | ||
400 | ivc->notify(ivc, ivc->notify_data); | ||
401 | } | ||
402 | EXPORT_SYMBOL(tegra_ivc_reset); | ||
403 | |||
404 | /* | ||
405 | * ======================================================= | ||
406 | * IVC State Transition Table - see tegra_ivc_notified() | ||
407 | * ======================================================= | ||
408 | * | ||
409 | * local remote action | ||
410 | * ----- ------ ----------------------------------- | ||
411 | * SYNC EST <none> | ||
412 | * SYNC ACK reset counters; move to EST; notify | ||
413 | * SYNC SYNC reset counters; move to ACK; notify | ||
414 | * ACK EST move to EST; notify | ||
415 | * ACK ACK move to EST; notify | ||
416 | * ACK SYNC reset counters; move to ACK; notify | ||
417 | * EST EST <none> | ||
418 | * EST ACK <none> | ||
419 | * EST SYNC reset counters; move to ACK; notify | ||
420 | * | ||
421 | * =============================================================== | ||
422 | */ | ||
423 | |||
424 | int tegra_ivc_notified(struct tegra_ivc *ivc) | ||
425 | { | ||
426 | unsigned int offset = offsetof(struct tegra_ivc_header, tx.count); | ||
427 | enum tegra_ivc_state state; | ||
428 | |||
429 | /* Copy the receiver's state out of shared memory. */ | ||
430 | tegra_ivc_invalidate(ivc, ivc->rx.phys + offset); | ||
431 | state = ACCESS_ONCE(ivc->rx.channel->tx.state); | ||
432 | |||
433 | if (state == TEGRA_IVC_STATE_SYNC) { | ||
434 | offset = offsetof(struct tegra_ivc_header, tx.count); | ||
435 | |||
436 | /* | ||
437 | * Order observation of TEGRA_IVC_STATE_SYNC before stores | ||
438 | * clearing tx.channel. | ||
439 | */ | ||
440 | smp_rmb(); | ||
441 | |||
442 | /* | ||
443 | * Reset tx.channel counters. The remote end is in the SYNC | ||
444 | * state and won't make progress until we change our state, | ||
445 | * so the counters are not in use at this time. | ||
446 | */ | ||
447 | ivc->tx.channel->tx.count = 0; | ||
448 | ivc->rx.channel->rx.count = 0; | ||
449 | |||
450 | ivc->tx.position = 0; | ||
451 | ivc->rx.position = 0; | ||
452 | |||
453 | /* | ||
454 | * Ensure that counters appear cleared before new state can be | ||
455 | * observed. | ||
456 | */ | ||
457 | smp_wmb(); | ||
458 | |||
459 | /* | ||
460 | * Move to ACK state. We have just cleared our counters, so it | ||
461 | * is now safe for the remote end to start using these values. | ||
462 | */ | ||
463 | ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ACK; | ||
464 | tegra_ivc_flush(ivc, ivc->tx.phys + offset); | ||
465 | |||
466 | /* | ||
467 | * Notify remote end to observe state transition. | ||
468 | */ | ||
469 | ivc->notify(ivc, ivc->notify_data); | ||
470 | |||
471 | } else if (ivc->tx.channel->tx.state == TEGRA_IVC_STATE_SYNC && | ||
472 | state == TEGRA_IVC_STATE_ACK) { | ||
473 | offset = offsetof(struct tegra_ivc_header, tx.count); | ||
474 | |||
475 | /* | ||
476 | * Order observation of ivc_state_sync before stores clearing | ||
477 | * tx_channel. | ||
478 | */ | ||
479 | smp_rmb(); | ||
480 | |||
481 | /* | ||
482 | * Reset tx.channel counters. The remote end is in the ACK | ||
483 | * state and won't make progress until we change our state, | ||
484 | * so the counters are not in use at this time. | ||
485 | */ | ||
486 | ivc->tx.channel->tx.count = 0; | ||
487 | ivc->rx.channel->rx.count = 0; | ||
488 | |||
489 | ivc->tx.position = 0; | ||
490 | ivc->rx.position = 0; | ||
491 | |||
492 | /* | ||
493 | * Ensure that counters appear cleared before new state can be | ||
494 | * observed. | ||
495 | */ | ||
496 | smp_wmb(); | ||
497 | |||
498 | /* | ||
499 | * Move to ESTABLISHED state. We know that the remote end has | ||
500 | * already cleared its counters, so it is safe to start | ||
501 | * writing/reading on this channel. | ||
502 | */ | ||
503 | ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ESTABLISHED; | ||
504 | tegra_ivc_flush(ivc, ivc->tx.phys + offset); | ||
505 | |||
506 | /* | ||
507 | * Notify remote end to observe state transition. | ||
508 | */ | ||
509 | ivc->notify(ivc, ivc->notify_data); | ||
510 | |||
511 | } else if (ivc->tx.channel->tx.state == TEGRA_IVC_STATE_ACK) { | ||
512 | offset = offsetof(struct tegra_ivc_header, tx.count); | ||
513 | |||
514 | /* | ||
515 | * At this point, we have observed the peer to be in either | ||
516 | * the ACK or ESTABLISHED state. Next, order observation of | ||
517 | * peer state before storing to tx.channel. | ||
518 | */ | ||
519 | smp_rmb(); | ||
520 | |||
521 | /* | ||
522 | * Move to ESTABLISHED state. We know that we have previously | ||
523 | * cleared our counters, and we know that the remote end has | ||
524 | * cleared its counters, so it is safe to start writing/reading | ||
525 | * on this channel. | ||
526 | */ | ||
527 | ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ESTABLISHED; | ||
528 | tegra_ivc_flush(ivc, ivc->tx.phys + offset); | ||
529 | |||
530 | /* | ||
531 | * Notify remote end to observe state transition. | ||
532 | */ | ||
533 | ivc->notify(ivc, ivc->notify_data); | ||
534 | |||
535 | } else { | ||
536 | /* | ||
537 | * There is no need to handle any further action. Either the | ||
538 | * channel is already fully established, or we are waiting for | ||
539 | * the remote end to catch up with our current state. Refer | ||
540 | * to the diagram in "IVC State Transition Table" above. | ||
541 | */ | ||
542 | } | ||
543 | |||
544 | if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED) | ||
545 | return -EAGAIN; | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | EXPORT_SYMBOL(tegra_ivc_notified); | ||
550 | |||
551 | size_t tegra_ivc_align(size_t size) | ||
552 | { | ||
553 | return ALIGN(size, TEGRA_IVC_ALIGN); | ||
554 | } | ||
555 | EXPORT_SYMBOL(tegra_ivc_align); | ||
556 | |||
557 | unsigned tegra_ivc_total_queue_size(unsigned queue_size) | ||
558 | { | ||
559 | if (!IS_ALIGNED(queue_size, TEGRA_IVC_ALIGN)) { | ||
560 | pr_err("%s: queue_size (%u) must be %u-byte aligned\n", | ||
561 | __func__, queue_size, TEGRA_IVC_ALIGN); | ||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | return queue_size + sizeof(struct tegra_ivc_header); | ||
566 | } | ||
567 | EXPORT_SYMBOL(tegra_ivc_total_queue_size); | ||
568 | |||
569 | static int tegra_ivc_check_params(unsigned long rx, unsigned long tx, | ||
570 | unsigned int num_frames, size_t frame_size) | ||
571 | { | ||
572 | BUILD_BUG_ON(!IS_ALIGNED(offsetof(struct tegra_ivc_header, tx.count), | ||
573 | TEGRA_IVC_ALIGN)); | ||
574 | BUILD_BUG_ON(!IS_ALIGNED(offsetof(struct tegra_ivc_header, rx.count), | ||
575 | TEGRA_IVC_ALIGN)); | ||
576 | BUILD_BUG_ON(!IS_ALIGNED(sizeof(struct tegra_ivc_header), | ||
577 | TEGRA_IVC_ALIGN)); | ||
578 | |||
579 | if ((uint64_t)num_frames * (uint64_t)frame_size >= 0x100000000UL) { | ||
580 | pr_err("num_frames * frame_size overflows\n"); | ||
581 | return -EINVAL; | ||
582 | } | ||
583 | |||
584 | if (!IS_ALIGNED(frame_size, TEGRA_IVC_ALIGN)) { | ||
585 | pr_err("frame size not adequately aligned: %zu\n", frame_size); | ||
586 | return -EINVAL; | ||
587 | } | ||
588 | |||
589 | /* | ||
590 | * The headers must at least be aligned enough for counters | ||
591 | * to be accessed atomically. | ||
592 | */ | ||
593 | if (!IS_ALIGNED(rx, TEGRA_IVC_ALIGN)) { | ||
594 | pr_err("IVC channel start not aligned: %#lx\n", rx); | ||
595 | return -EINVAL; | ||
596 | } | ||
597 | |||
598 | if (!IS_ALIGNED(tx, TEGRA_IVC_ALIGN)) { | ||
599 | pr_err("IVC channel start not aligned: %#lx\n", tx); | ||
600 | return -EINVAL; | ||
601 | } | ||
602 | |||
603 | if (rx < tx) { | ||
604 | if (rx + frame_size * num_frames > tx) { | ||
605 | pr_err("queue regions overlap: %#lx + %zx > %#lx\n", | ||
606 | rx, frame_size * num_frames, tx); | ||
607 | return -EINVAL; | ||
608 | } | ||
609 | } else { | ||
610 | if (tx + frame_size * num_frames > rx) { | ||
611 | pr_err("queue regions overlap: %#lx + %zx > %#lx\n", | ||
612 | tx, frame_size * num_frames, rx); | ||
613 | return -EINVAL; | ||
614 | } | ||
615 | } | ||
616 | |||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx, | ||
621 | dma_addr_t rx_phys, void *tx, dma_addr_t tx_phys, | ||
622 | unsigned int num_frames, size_t frame_size, | ||
623 | void (*notify)(struct tegra_ivc *ivc, void *data), | ||
624 | void *data) | ||
625 | { | ||
626 | size_t queue_size; | ||
627 | int err; | ||
628 | |||
629 | if (WARN_ON(!ivc || !notify)) | ||
630 | return -EINVAL; | ||
631 | |||
632 | /* | ||
633 | * All sizes that can be returned by communication functions should | ||
634 | * fit in an int. | ||
635 | */ | ||
636 | if (frame_size > INT_MAX) | ||
637 | return -E2BIG; | ||
638 | |||
639 | err = tegra_ivc_check_params((unsigned long)rx, (unsigned long)tx, | ||
640 | num_frames, frame_size); | ||
641 | if (err < 0) | ||
642 | return err; | ||
643 | |||
644 | queue_size = tegra_ivc_total_queue_size(num_frames * frame_size); | ||
645 | |||
646 | if (peer) { | ||
647 | ivc->rx.phys = dma_map_single(peer, rx, queue_size, | ||
648 | DMA_BIDIRECTIONAL); | ||
649 | if (ivc->rx.phys == DMA_ERROR_CODE) | ||
650 | return -ENOMEM; | ||
651 | |||
652 | ivc->tx.phys = dma_map_single(peer, tx, queue_size, | ||
653 | DMA_BIDIRECTIONAL); | ||
654 | if (ivc->tx.phys == DMA_ERROR_CODE) { | ||
655 | dma_unmap_single(peer, ivc->rx.phys, queue_size, | ||
656 | DMA_BIDIRECTIONAL); | ||
657 | return -ENOMEM; | ||
658 | } | ||
659 | } else { | ||
660 | ivc->rx.phys = rx_phys; | ||
661 | ivc->tx.phys = tx_phys; | ||
662 | } | ||
663 | |||
664 | ivc->rx.channel = rx; | ||
665 | ivc->tx.channel = tx; | ||
666 | ivc->peer = peer; | ||
667 | ivc->notify = notify; | ||
668 | ivc->notify_data = data; | ||
669 | ivc->frame_size = frame_size; | ||
670 | ivc->num_frames = num_frames; | ||
671 | |||
672 | /* | ||
673 | * These values aren't necessarily correct until the channel has been | ||
674 | * reset. | ||
675 | */ | ||
676 | ivc->tx.position = 0; | ||
677 | ivc->rx.position = 0; | ||
678 | |||
679 | return 0; | ||
680 | } | ||
681 | EXPORT_SYMBOL(tegra_ivc_init); | ||
682 | |||
683 | void tegra_ivc_cleanup(struct tegra_ivc *ivc) | ||
684 | { | ||
685 | if (ivc->peer) { | ||
686 | size_t size = tegra_ivc_total_queue_size(ivc->num_frames * | ||
687 | ivc->frame_size); | ||
688 | |||
689 | dma_unmap_single(ivc->peer, ivc->rx.phys, size, | ||
690 | DMA_BIDIRECTIONAL); | ||
691 | dma_unmap_single(ivc->peer, ivc->tx.phys, size, | ||
692 | DMA_BIDIRECTIONAL); | ||
693 | } | ||
694 | } | ||
695 | EXPORT_SYMBOL(tegra_ivc_cleanup); | ||
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 11eebfe8a4cb..ceff415f201c 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig | |||
@@ -124,6 +124,15 @@ config MAILBOX_TEST | |||
124 | Test client to help with testing new Controller driver | 124 | Test client to help with testing new Controller driver |
125 | implementations. | 125 | implementations. |
126 | 126 | ||
127 | config TEGRA_HSP_MBOX | ||
128 | bool "Tegra HSP (Hardware Synchronization Primitives) Driver" | ||
129 | depends on ARCH_TEGRA_186_SOC | ||
130 | help | ||
131 | The Tegra HSP driver is used for the interprocessor communication | ||
132 | between different remote processors and host processors on Tegra186 | ||
133 | and later SoCs. Say Y here if you want to have this support. | ||
134 | If unsure say N. | ||
135 | |||
127 | config XGENE_SLIMPRO_MBOX | 136 | config XGENE_SLIMPRO_MBOX |
128 | tristate "APM SoC X-Gene SLIMpro Mailbox Controller" | 137 | tristate "APM SoC X-Gene SLIMpro Mailbox Controller" |
129 | depends on ARCH_XGENE | 138 | depends on ARCH_XGENE |
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index ace6fed8fea9..7dde4f609ae8 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile | |||
@@ -29,3 +29,5 @@ obj-$(CONFIG_XGENE_SLIMPRO_MBOX) += mailbox-xgene-slimpro.o | |||
29 | obj-$(CONFIG_HI6220_MBOX) += hi6220-mailbox.o | 29 | obj-$(CONFIG_HI6220_MBOX) += hi6220-mailbox.o |
30 | 30 | ||
31 | obj-$(CONFIG_BCM_PDC_MBOX) += bcm-pdc-mailbox.o | 31 | obj-$(CONFIG_BCM_PDC_MBOX) += bcm-pdc-mailbox.o |
32 | |||
33 | obj-$(CONFIG_TEGRA_HSP_MBOX) += tegra-hsp.o | ||
diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c new file mode 100644 index 000000000000..0cde356c11ab --- /dev/null +++ b/drivers/mailbox/tegra-hsp.c | |||
@@ -0,0 +1,479 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/mailbox_controller.h> | ||
17 | #include <linux/of.h> | ||
18 | #include <linux/of_device.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | #include <dt-bindings/mailbox/tegra186-hsp.h> | ||
23 | |||
24 | #define HSP_INT_DIMENSIONING 0x380 | ||
25 | #define HSP_nSM_SHIFT 0 | ||
26 | #define HSP_nSS_SHIFT 4 | ||
27 | #define HSP_nAS_SHIFT 8 | ||
28 | #define HSP_nDB_SHIFT 12 | ||
29 | #define HSP_nSI_SHIFT 16 | ||
30 | #define HSP_nINT_MASK 0xf | ||
31 | |||
32 | #define HSP_DB_TRIGGER 0x0 | ||
33 | #define HSP_DB_ENABLE 0x4 | ||
34 | #define HSP_DB_RAW 0x8 | ||
35 | #define HSP_DB_PENDING 0xc | ||
36 | |||
37 | #define HSP_DB_CCPLEX 1 | ||
38 | #define HSP_DB_BPMP 3 | ||
39 | #define HSP_DB_MAX 7 | ||
40 | |||
41 | struct tegra_hsp_channel; | ||
42 | struct tegra_hsp; | ||
43 | |||
44 | struct tegra_hsp_channel { | ||
45 | struct tegra_hsp *hsp; | ||
46 | struct mbox_chan *chan; | ||
47 | void __iomem *regs; | ||
48 | }; | ||
49 | |||
50 | struct tegra_hsp_doorbell { | ||
51 | struct tegra_hsp_channel channel; | ||
52 | struct list_head list; | ||
53 | const char *name; | ||
54 | unsigned int master; | ||
55 | unsigned int index; | ||
56 | }; | ||
57 | |||
58 | struct tegra_hsp_db_map { | ||
59 | const char *name; | ||
60 | unsigned int master; | ||
61 | unsigned int index; | ||
62 | }; | ||
63 | |||
64 | struct tegra_hsp_soc { | ||
65 | const struct tegra_hsp_db_map *map; | ||
66 | }; | ||
67 | |||
68 | struct tegra_hsp { | ||
69 | const struct tegra_hsp_soc *soc; | ||
70 | struct mbox_controller mbox; | ||
71 | void __iomem *regs; | ||
72 | unsigned int irq; | ||
73 | unsigned int num_sm; | ||
74 | unsigned int num_as; | ||
75 | unsigned int num_ss; | ||
76 | unsigned int num_db; | ||
77 | unsigned int num_si; | ||
78 | spinlock_t lock; | ||
79 | |||
80 | struct list_head doorbells; | ||
81 | }; | ||
82 | |||
83 | static inline struct tegra_hsp * | ||
84 | to_tegra_hsp(struct mbox_controller *mbox) | ||
85 | { | ||
86 | return container_of(mbox, struct tegra_hsp, mbox); | ||
87 | } | ||
88 | |||
89 | static inline u32 tegra_hsp_readl(struct tegra_hsp *hsp, unsigned int offset) | ||
90 | { | ||
91 | return readl(hsp->regs + offset); | ||
92 | } | ||
93 | |||
94 | static inline void tegra_hsp_writel(struct tegra_hsp *hsp, u32 value, | ||
95 | unsigned int offset) | ||
96 | { | ||
97 | writel(value, hsp->regs + offset); | ||
98 | } | ||
99 | |||
100 | static inline u32 tegra_hsp_channel_readl(struct tegra_hsp_channel *channel, | ||
101 | unsigned int offset) | ||
102 | { | ||
103 | return readl(channel->regs + offset); | ||
104 | } | ||
105 | |||
106 | static inline void tegra_hsp_channel_writel(struct tegra_hsp_channel *channel, | ||
107 | u32 value, unsigned int offset) | ||
108 | { | ||
109 | writel(value, channel->regs + offset); | ||
110 | } | ||
111 | |||
112 | static bool tegra_hsp_doorbell_can_ring(struct tegra_hsp_doorbell *db) | ||
113 | { | ||
114 | u32 value; | ||
115 | |||
116 | value = tegra_hsp_channel_readl(&db->channel, HSP_DB_ENABLE); | ||
117 | |||
118 | return (value & BIT(TEGRA_HSP_DB_MASTER_CCPLEX)) != 0; | ||
119 | } | ||
120 | |||
121 | static struct tegra_hsp_doorbell * | ||
122 | __tegra_hsp_doorbell_get(struct tegra_hsp *hsp, unsigned int master) | ||
123 | { | ||
124 | struct tegra_hsp_doorbell *entry; | ||
125 | |||
126 | list_for_each_entry(entry, &hsp->doorbells, list) | ||
127 | if (entry->master == master) | ||
128 | return entry; | ||
129 | |||
130 | return NULL; | ||
131 | } | ||
132 | |||
133 | static struct tegra_hsp_doorbell * | ||
134 | tegra_hsp_doorbell_get(struct tegra_hsp *hsp, unsigned int master) | ||
135 | { | ||
136 | struct tegra_hsp_doorbell *db; | ||
137 | unsigned long flags; | ||
138 | |||
139 | spin_lock_irqsave(&hsp->lock, flags); | ||
140 | db = __tegra_hsp_doorbell_get(hsp, master); | ||
141 | spin_unlock_irqrestore(&hsp->lock, flags); | ||
142 | |||
143 | return db; | ||
144 | } | ||
145 | |||
146 | static irqreturn_t tegra_hsp_doorbell_irq(int irq, void *data) | ||
147 | { | ||
148 | struct tegra_hsp *hsp = data; | ||
149 | struct tegra_hsp_doorbell *db; | ||
150 | unsigned long master, value; | ||
151 | |||
152 | db = tegra_hsp_doorbell_get(hsp, TEGRA_HSP_DB_MASTER_CCPLEX); | ||
153 | if (!db) | ||
154 | return IRQ_NONE; | ||
155 | |||
156 | value = tegra_hsp_channel_readl(&db->channel, HSP_DB_PENDING); | ||
157 | tegra_hsp_channel_writel(&db->channel, value, HSP_DB_PENDING); | ||
158 | |||
159 | spin_lock(&hsp->lock); | ||
160 | |||
161 | for_each_set_bit(master, &value, hsp->mbox.num_chans) { | ||
162 | struct tegra_hsp_doorbell *db; | ||
163 | |||
164 | db = __tegra_hsp_doorbell_get(hsp, master); | ||
165 | /* | ||
166 | * Depending on the bootloader chain, the CCPLEX doorbell will | ||
167 | * have some doorbells enabled, which means that requesting an | ||
168 | * interrupt will immediately fire. | ||
169 | * | ||
170 | * In that case, db->channel.chan will still be NULL here and | ||
171 | * cause a crash if not properly guarded. | ||
172 | * | ||
173 | * It remains to be seen if ignoring the doorbell in that case | ||
174 | * is the correct solution. | ||
175 | */ | ||
176 | if (db && db->channel.chan) | ||
177 | mbox_chan_received_data(db->channel.chan, NULL); | ||
178 | } | ||
179 | |||
180 | spin_unlock(&hsp->lock); | ||
181 | |||
182 | return IRQ_HANDLED; | ||
183 | } | ||
184 | |||
185 | static struct tegra_hsp_channel * | ||
186 | tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name, | ||
187 | unsigned int master, unsigned int index) | ||
188 | { | ||
189 | struct tegra_hsp_doorbell *db; | ||
190 | unsigned int offset; | ||
191 | unsigned long flags; | ||
192 | |||
193 | db = kzalloc(sizeof(*db), GFP_KERNEL); | ||
194 | if (!db) | ||
195 | return ERR_PTR(-ENOMEM); | ||
196 | |||
197 | offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) << 16; | ||
198 | offset += index * 0x100; | ||
199 | |||
200 | db->channel.regs = hsp->regs + offset; | ||
201 | db->channel.hsp = hsp; | ||
202 | |||
203 | db->name = kstrdup_const(name, GFP_KERNEL); | ||
204 | db->master = master; | ||
205 | db->index = index; | ||
206 | |||
207 | spin_lock_irqsave(&hsp->lock, flags); | ||
208 | list_add_tail(&db->list, &hsp->doorbells); | ||
209 | spin_unlock_irqrestore(&hsp->lock, flags); | ||
210 | |||
211 | return &db->channel; | ||
212 | } | ||
213 | |||
214 | static void __tegra_hsp_doorbell_destroy(struct tegra_hsp_doorbell *db) | ||
215 | { | ||
216 | list_del(&db->list); | ||
217 | kfree_const(db->name); | ||
218 | kfree(db); | ||
219 | } | ||
220 | |||
221 | static int tegra_hsp_doorbell_send_data(struct mbox_chan *chan, void *data) | ||
222 | { | ||
223 | struct tegra_hsp_doorbell *db = chan->con_priv; | ||
224 | |||
225 | tegra_hsp_channel_writel(&db->channel, 1, HSP_DB_TRIGGER); | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static int tegra_hsp_doorbell_startup(struct mbox_chan *chan) | ||
231 | { | ||
232 | struct tegra_hsp_doorbell *db = chan->con_priv; | ||
233 | struct tegra_hsp *hsp = db->channel.hsp; | ||
234 | struct tegra_hsp_doorbell *ccplex; | ||
235 | unsigned long flags; | ||
236 | u32 value; | ||
237 | |||
238 | if (db->master >= hsp->mbox.num_chans) { | ||
239 | dev_err(hsp->mbox.dev, | ||
240 | "invalid master ID %u for HSP channel\n", | ||
241 | db->master); | ||
242 | return -EINVAL; | ||
243 | } | ||
244 | |||
245 | ccplex = tegra_hsp_doorbell_get(hsp, TEGRA_HSP_DB_MASTER_CCPLEX); | ||
246 | if (!ccplex) | ||
247 | return -ENODEV; | ||
248 | |||
249 | if (!tegra_hsp_doorbell_can_ring(db)) | ||
250 | return -ENODEV; | ||
251 | |||
252 | spin_lock_irqsave(&hsp->lock, flags); | ||
253 | |||
254 | value = tegra_hsp_channel_readl(&ccplex->channel, HSP_DB_ENABLE); | ||
255 | value |= BIT(db->master); | ||
256 | tegra_hsp_channel_writel(&ccplex->channel, value, HSP_DB_ENABLE); | ||
257 | |||
258 | spin_unlock_irqrestore(&hsp->lock, flags); | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan) | ||
264 | { | ||
265 | struct tegra_hsp_doorbell *db = chan->con_priv; | ||
266 | struct tegra_hsp *hsp = db->channel.hsp; | ||
267 | struct tegra_hsp_doorbell *ccplex; | ||
268 | unsigned long flags; | ||
269 | u32 value; | ||
270 | |||
271 | ccplex = tegra_hsp_doorbell_get(hsp, TEGRA_HSP_DB_MASTER_CCPLEX); | ||
272 | if (!ccplex) | ||
273 | return; | ||
274 | |||
275 | spin_lock_irqsave(&hsp->lock, flags); | ||
276 | |||
277 | value = tegra_hsp_channel_readl(&ccplex->channel, HSP_DB_ENABLE); | ||
278 | value &= ~BIT(db->master); | ||
279 | tegra_hsp_channel_writel(&ccplex->channel, value, HSP_DB_ENABLE); | ||
280 | |||
281 | spin_unlock_irqrestore(&hsp->lock, flags); | ||
282 | } | ||
283 | |||
284 | static const struct mbox_chan_ops tegra_hsp_doorbell_ops = { | ||
285 | .send_data = tegra_hsp_doorbell_send_data, | ||
286 | .startup = tegra_hsp_doorbell_startup, | ||
287 | .shutdown = tegra_hsp_doorbell_shutdown, | ||
288 | }; | ||
289 | |||
290 | static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox, | ||
291 | const struct of_phandle_args *args) | ||
292 | { | ||
293 | struct tegra_hsp_channel *channel = ERR_PTR(-ENODEV); | ||
294 | struct tegra_hsp *hsp = to_tegra_hsp(mbox); | ||
295 | unsigned int type = args->args[0]; | ||
296 | unsigned int master = args->args[1]; | ||
297 | struct tegra_hsp_doorbell *db; | ||
298 | struct mbox_chan *chan; | ||
299 | unsigned long flags; | ||
300 | unsigned int i; | ||
301 | |||
302 | switch (type) { | ||
303 | case TEGRA_HSP_MBOX_TYPE_DB: | ||
304 | db = tegra_hsp_doorbell_get(hsp, master); | ||
305 | if (db) | ||
306 | channel = &db->channel; | ||
307 | |||
308 | break; | ||
309 | |||
310 | default: | ||
311 | break; | ||
312 | } | ||
313 | |||
314 | if (IS_ERR(channel)) | ||
315 | return ERR_CAST(channel); | ||
316 | |||
317 | spin_lock_irqsave(&hsp->lock, flags); | ||
318 | |||
319 | for (i = 0; i < hsp->mbox.num_chans; i++) { | ||
320 | chan = &hsp->mbox.chans[i]; | ||
321 | if (!chan->con_priv) { | ||
322 | chan->con_priv = channel; | ||
323 | channel->chan = chan; | ||
324 | break; | ||
325 | } | ||
326 | |||
327 | chan = NULL; | ||
328 | } | ||
329 | |||
330 | spin_unlock_irqrestore(&hsp->lock, flags); | ||
331 | |||
332 | return chan ?: ERR_PTR(-EBUSY); | ||
333 | } | ||
334 | |||
335 | static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp) | ||
336 | { | ||
337 | struct tegra_hsp_doorbell *db, *tmp; | ||
338 | unsigned long flags; | ||
339 | |||
340 | spin_lock_irqsave(&hsp->lock, flags); | ||
341 | |||
342 | list_for_each_entry_safe(db, tmp, &hsp->doorbells, list) | ||
343 | __tegra_hsp_doorbell_destroy(db); | ||
344 | |||
345 | spin_unlock_irqrestore(&hsp->lock, flags); | ||
346 | } | ||
347 | |||
348 | static int tegra_hsp_add_doorbells(struct tegra_hsp *hsp) | ||
349 | { | ||
350 | const struct tegra_hsp_db_map *map = hsp->soc->map; | ||
351 | struct tegra_hsp_channel *channel; | ||
352 | |||
353 | while (map->name) { | ||
354 | channel = tegra_hsp_doorbell_create(hsp, map->name, | ||
355 | map->master, map->index); | ||
356 | if (IS_ERR(channel)) { | ||
357 | tegra_hsp_remove_doorbells(hsp); | ||
358 | return PTR_ERR(channel); | ||
359 | } | ||
360 | |||
361 | map++; | ||
362 | } | ||
363 | |||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | static int tegra_hsp_probe(struct platform_device *pdev) | ||
368 | { | ||
369 | struct tegra_hsp *hsp; | ||
370 | struct resource *res; | ||
371 | u32 value; | ||
372 | int err; | ||
373 | |||
374 | hsp = devm_kzalloc(&pdev->dev, sizeof(*hsp), GFP_KERNEL); | ||
375 | if (!hsp) | ||
376 | return -ENOMEM; | ||
377 | |||
378 | hsp->soc = of_device_get_match_data(&pdev->dev); | ||
379 | INIT_LIST_HEAD(&hsp->doorbells); | ||
380 | spin_lock_init(&hsp->lock); | ||
381 | |||
382 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
383 | hsp->regs = devm_ioremap_resource(&pdev->dev, res); | ||
384 | if (IS_ERR(hsp->regs)) | ||
385 | return PTR_ERR(hsp->regs); | ||
386 | |||
387 | value = tegra_hsp_readl(hsp, HSP_INT_DIMENSIONING); | ||
388 | hsp->num_sm = (value >> HSP_nSM_SHIFT) & HSP_nINT_MASK; | ||
389 | hsp->num_ss = (value >> HSP_nSS_SHIFT) & HSP_nINT_MASK; | ||
390 | hsp->num_as = (value >> HSP_nAS_SHIFT) & HSP_nINT_MASK; | ||
391 | hsp->num_db = (value >> HSP_nDB_SHIFT) & HSP_nINT_MASK; | ||
392 | hsp->num_si = (value >> HSP_nSI_SHIFT) & HSP_nINT_MASK; | ||
393 | |||
394 | err = platform_get_irq_byname(pdev, "doorbell"); | ||
395 | if (err < 0) { | ||
396 | dev_err(&pdev->dev, "failed to get doorbell IRQ: %d\n", err); | ||
397 | return err; | ||
398 | } | ||
399 | |||
400 | hsp->irq = err; | ||
401 | |||
402 | hsp->mbox.of_xlate = of_tegra_hsp_xlate; | ||
403 | hsp->mbox.num_chans = 32; | ||
404 | hsp->mbox.dev = &pdev->dev; | ||
405 | hsp->mbox.txdone_irq = false; | ||
406 | hsp->mbox.txdone_poll = false; | ||
407 | hsp->mbox.ops = &tegra_hsp_doorbell_ops; | ||
408 | |||
409 | hsp->mbox.chans = devm_kcalloc(&pdev->dev, hsp->mbox.num_chans, | ||
410 | sizeof(*hsp->mbox.chans), | ||
411 | GFP_KERNEL); | ||
412 | if (!hsp->mbox.chans) | ||
413 | return -ENOMEM; | ||
414 | |||
415 | err = tegra_hsp_add_doorbells(hsp); | ||
416 | if (err < 0) { | ||
417 | dev_err(&pdev->dev, "failed to add doorbells: %d\n", err); | ||
418 | return err; | ||
419 | } | ||
420 | |||
421 | platform_set_drvdata(pdev, hsp); | ||
422 | |||
423 | err = mbox_controller_register(&hsp->mbox); | ||
424 | if (err) { | ||
425 | dev_err(&pdev->dev, "failed to register mailbox: %d\n", err); | ||
426 | tegra_hsp_remove_doorbells(hsp); | ||
427 | return err; | ||
428 | } | ||
429 | |||
430 | err = devm_request_irq(&pdev->dev, hsp->irq, tegra_hsp_doorbell_irq, | ||
431 | IRQF_NO_SUSPEND, dev_name(&pdev->dev), hsp); | ||
432 | if (err < 0) { | ||
433 | dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", | ||
434 | hsp->irq, err); | ||
435 | return err; | ||
436 | } | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static int tegra_hsp_remove(struct platform_device *pdev) | ||
442 | { | ||
443 | struct tegra_hsp *hsp = platform_get_drvdata(pdev); | ||
444 | |||
445 | mbox_controller_unregister(&hsp->mbox); | ||
446 | tegra_hsp_remove_doorbells(hsp); | ||
447 | |||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | static const struct tegra_hsp_db_map tegra186_hsp_db_map[] = { | ||
452 | { "ccplex", TEGRA_HSP_DB_MASTER_CCPLEX, HSP_DB_CCPLEX, }, | ||
453 | { "bpmp", TEGRA_HSP_DB_MASTER_BPMP, HSP_DB_BPMP, }, | ||
454 | { /* sentinel */ } | ||
455 | }; | ||
456 | |||
457 | static const struct tegra_hsp_soc tegra186_hsp_soc = { | ||
458 | .map = tegra186_hsp_db_map, | ||
459 | }; | ||
460 | |||
461 | static const struct of_device_id tegra_hsp_match[] = { | ||
462 | { .compatible = "nvidia,tegra186-hsp", .data = &tegra186_hsp_soc }, | ||
463 | { } | ||
464 | }; | ||
465 | |||
466 | static struct platform_driver tegra_hsp_driver = { | ||
467 | .driver = { | ||
468 | .name = "tegra-hsp", | ||
469 | .of_match_table = tegra_hsp_match, | ||
470 | }, | ||
471 | .probe = tegra_hsp_probe, | ||
472 | .remove = tegra_hsp_remove, | ||
473 | }; | ||
474 | |||
475 | static int __init tegra_hsp_init(void) | ||
476 | { | ||
477 | return platform_driver_register(&tegra_hsp_driver); | ||
478 | } | ||
479 | core_initcall(tegra_hsp_init); | ||
diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig index 03089ad2fc65..e5e124c07066 100644 --- a/drivers/soc/tegra/Kconfig +++ b/drivers/soc/tegra/Kconfig | |||
@@ -77,5 +77,19 @@ config ARCH_TEGRA_210_SOC | |||
77 | controllers, such as GPIO, I2C, SPI, SDHCI, PCIe, SATA and XHCI, to | 77 | controllers, such as GPIO, I2C, SPI, SDHCI, PCIe, SATA and XHCI, to |
78 | name only a few. | 78 | name only a few. |
79 | 79 | ||
80 | config ARCH_TEGRA_186_SOC | ||
81 | bool "NVIDIA Tegra186 SoC" | ||
82 | select MAILBOX | ||
83 | select TEGRA_BPMP | ||
84 | select TEGRA_HSP_MBOX | ||
85 | select TEGRA_IVC | ||
86 | help | ||
87 | Enable support for the NVIDIA Tegar186 SoC. The Tegra186 features a | ||
88 | combination of Denver and Cortex-A57 CPU cores and a GPU based on | ||
89 | the Pascal architecture. It contains an ADSP with a Cortex-A9 CPU | ||
90 | used for audio processing, hardware video encoders/decoders with | ||
91 | multi-format support, ISP for image capture processing and BPMP for | ||
92 | power management. | ||
93 | |||
80 | endif | 94 | endif |
81 | endif | 95 | endif |
diff --git a/include/dt-bindings/clock/tegra186-clock.h b/include/dt-bindings/clock/tegra186-clock.h new file mode 100644 index 000000000000..f73d32098f99 --- /dev/null +++ b/include/dt-bindings/clock/tegra186-clock.h | |||
@@ -0,0 +1,940 @@ | |||
1 | /** @file */ | ||
2 | |||
3 | #ifndef _MACH_T186_CLK_T186_H | ||
4 | #define _MACH_T186_CLK_T186_H | ||
5 | |||
6 | /** | ||
7 | * @defgroup clock_ids Clock Identifiers | ||
8 | * @{ | ||
9 | * @defgroup extern_input external input clocks | ||
10 | * @{ | ||
11 | * @def TEGRA186_CLK_OSC | ||
12 | * @def TEGRA186_CLK_CLK_32K | ||
13 | * @def TEGRA186_CLK_DTV_INPUT | ||
14 | * @def TEGRA186_CLK_SOR0_PAD_CLKOUT | ||
15 | * @def TEGRA186_CLK_SOR1_PAD_CLKOUT | ||
16 | * @def TEGRA186_CLK_I2S1_SYNC_INPUT | ||
17 | * @def TEGRA186_CLK_I2S2_SYNC_INPUT | ||
18 | * @def TEGRA186_CLK_I2S3_SYNC_INPUT | ||
19 | * @def TEGRA186_CLK_I2S4_SYNC_INPUT | ||
20 | * @def TEGRA186_CLK_I2S5_SYNC_INPUT | ||
21 | * @def TEGRA186_CLK_I2S6_SYNC_INPUT | ||
22 | * @def TEGRA186_CLK_SPDIFIN_SYNC_INPUT | ||
23 | * @} | ||
24 | * | ||
25 | * @defgroup extern_output external output clocks | ||
26 | * @{ | ||
27 | * @def TEGRA186_CLK_EXTPERIPH1 | ||
28 | * @def TEGRA186_CLK_EXTPERIPH2 | ||
29 | * @def TEGRA186_CLK_EXTPERIPH3 | ||
30 | * @def TEGRA186_CLK_EXTPERIPH4 | ||
31 | * @} | ||
32 | * | ||
33 | * @defgroup display_clks display related clocks | ||
34 | * @{ | ||
35 | * @def TEGRA186_CLK_CEC | ||
36 | * @def TEGRA186_CLK_DSIC | ||
37 | * @def TEGRA186_CLK_DSIC_LP | ||
38 | * @def TEGRA186_CLK_DSID | ||
39 | * @def TEGRA186_CLK_DSID_LP | ||
40 | * @def TEGRA186_CLK_DPAUX1 | ||
41 | * @def TEGRA186_CLK_DPAUX | ||
42 | * @def TEGRA186_CLK_HDA2HDMICODEC | ||
43 | * @def TEGRA186_CLK_NVDISPLAY_DISP | ||
44 | * @def TEGRA186_CLK_NVDISPLAY_DSC | ||
45 | * @def TEGRA186_CLK_NVDISPLAY_P0 | ||
46 | * @def TEGRA186_CLK_NVDISPLAY_P1 | ||
47 | * @def TEGRA186_CLK_NVDISPLAY_P2 | ||
48 | * @def TEGRA186_CLK_NVDISPLAYHUB | ||
49 | * @def TEGRA186_CLK_SOR_SAFE | ||
50 | * @def TEGRA186_CLK_SOR0 | ||
51 | * @def TEGRA186_CLK_SOR0_OUT | ||
52 | * @def TEGRA186_CLK_SOR1 | ||
53 | * @def TEGRA186_CLK_SOR1_OUT | ||
54 | * @def TEGRA186_CLK_DSI | ||
55 | * @def TEGRA186_CLK_MIPI_CAL | ||
56 | * @def TEGRA186_CLK_DSIA_LP | ||
57 | * @def TEGRA186_CLK_DSIB | ||
58 | * @def TEGRA186_CLK_DSIB_LP | ||
59 | * @} | ||
60 | * | ||
61 | * @defgroup camera_clks camera related clocks | ||
62 | * @{ | ||
63 | * @def TEGRA186_CLK_NVCSI | ||
64 | * @def TEGRA186_CLK_NVCSILP | ||
65 | * @def TEGRA186_CLK_VI | ||
66 | * @} | ||
67 | * | ||
68 | * @defgroup audio_clks audio related clocks | ||
69 | * @{ | ||
70 | * @def TEGRA186_CLK_ACLK | ||
71 | * @def TEGRA186_CLK_ADSP | ||
72 | * @def TEGRA186_CLK_ADSPNEON | ||
73 | * @def TEGRA186_CLK_AHUB | ||
74 | * @def TEGRA186_CLK_APE | ||
75 | * @def TEGRA186_CLK_APB2APE | ||
76 | * @def TEGRA186_CLK_AUD_MCLK | ||
77 | * @def TEGRA186_CLK_DMIC1 | ||
78 | * @def TEGRA186_CLK_DMIC2 | ||
79 | * @def TEGRA186_CLK_DMIC3 | ||
80 | * @def TEGRA186_CLK_DMIC4 | ||
81 | * @def TEGRA186_CLK_DSPK1 | ||
82 | * @def TEGRA186_CLK_DSPK2 | ||
83 | * @def TEGRA186_CLK_HDA | ||
84 | * @def TEGRA186_CLK_HDA2CODEC_2X | ||
85 | * @def TEGRA186_CLK_I2S1 | ||
86 | * @def TEGRA186_CLK_I2S2 | ||
87 | * @def TEGRA186_CLK_I2S3 | ||
88 | * @def TEGRA186_CLK_I2S4 | ||
89 | * @def TEGRA186_CLK_I2S5 | ||
90 | * @def TEGRA186_CLK_I2S6 | ||
91 | * @def TEGRA186_CLK_MAUD | ||
92 | * @def TEGRA186_CLK_PLL_A_OUT0 | ||
93 | * @def TEGRA186_CLK_SPDIF_DOUBLER | ||
94 | * @def TEGRA186_CLK_SPDIF_IN | ||
95 | * @def TEGRA186_CLK_SPDIF_OUT | ||
96 | * @def TEGRA186_CLK_SYNC_DMIC1 | ||
97 | * @def TEGRA186_CLK_SYNC_DMIC2 | ||
98 | * @def TEGRA186_CLK_SYNC_DMIC3 | ||
99 | * @def TEGRA186_CLK_SYNC_DMIC4 | ||
100 | * @def TEGRA186_CLK_SYNC_DMIC5 | ||
101 | * @def TEGRA186_CLK_SYNC_DSPK1 | ||
102 | * @def TEGRA186_CLK_SYNC_DSPK2 | ||
103 | * @def TEGRA186_CLK_SYNC_I2S1 | ||
104 | * @def TEGRA186_CLK_SYNC_I2S2 | ||
105 | * @def TEGRA186_CLK_SYNC_I2S3 | ||
106 | * @def TEGRA186_CLK_SYNC_I2S4 | ||
107 | * @def TEGRA186_CLK_SYNC_I2S5 | ||
108 | * @def TEGRA186_CLK_SYNC_I2S6 | ||
109 | * @def TEGRA186_CLK_SYNC_SPDIF | ||
110 | * @} | ||
111 | * | ||
112 | * @defgroup uart_clks UART clocks | ||
113 | * @{ | ||
114 | * @def TEGRA186_CLK_AON_UART_FST_MIPI_CAL | ||
115 | * @def TEGRA186_CLK_UARTA | ||
116 | * @def TEGRA186_CLK_UARTB | ||
117 | * @def TEGRA186_CLK_UARTC | ||
118 | * @def TEGRA186_CLK_UARTD | ||
119 | * @def TEGRA186_CLK_UARTE | ||
120 | * @def TEGRA186_CLK_UARTF | ||
121 | * @def TEGRA186_CLK_UARTG | ||
122 | * @def TEGRA186_CLK_UART_FST_MIPI_CAL | ||
123 | * @} | ||
124 | * | ||
125 | * @defgroup i2c_clks I2C clocks | ||
126 | * @{ | ||
127 | * @def TEGRA186_CLK_AON_I2C_SLOW | ||
128 | * @def TEGRA186_CLK_I2C1 | ||
129 | * @def TEGRA186_CLK_I2C2 | ||
130 | * @def TEGRA186_CLK_I2C3 | ||
131 | * @def TEGRA186_CLK_I2C4 | ||
132 | * @def TEGRA186_CLK_I2C5 | ||
133 | * @def TEGRA186_CLK_I2C6 | ||
134 | * @def TEGRA186_CLK_I2C8 | ||
135 | * @def TEGRA186_CLK_I2C9 | ||
136 | * @def TEGRA186_CLK_I2C1 | ||
137 | * @def TEGRA186_CLK_I2C12 | ||
138 | * @def TEGRA186_CLK_I2C13 | ||
139 | * @def TEGRA186_CLK_I2C14 | ||
140 | * @def TEGRA186_CLK_I2C_SLOW | ||
141 | * @def TEGRA186_CLK_VI_I2C | ||
142 | * @} | ||
143 | * | ||
144 | * @defgroup spi_clks SPI clocks | ||
145 | * @{ | ||
146 | * @def TEGRA186_CLK_SPI1 | ||
147 | * @def TEGRA186_CLK_SPI2 | ||
148 | * @def TEGRA186_CLK_SPI3 | ||
149 | * @def TEGRA186_CLK_SPI4 | ||
150 | * @} | ||
151 | * | ||
152 | * @defgroup storage storage related clocks | ||
153 | * @{ | ||
154 | * @def TEGRA186_CLK_SATA | ||
155 | * @def TEGRA186_CLK_SATA_OOB | ||
156 | * @def TEGRA186_CLK_SATA_IOBIST | ||
157 | * @def TEGRA186_CLK_SDMMC_LEGACY_TM | ||
158 | * @def TEGRA186_CLK_SDMMC1 | ||
159 | * @def TEGRA186_CLK_SDMMC2 | ||
160 | * @def TEGRA186_CLK_SDMMC3 | ||
161 | * @def TEGRA186_CLK_SDMMC4 | ||
162 | * @def TEGRA186_CLK_QSPI | ||
163 | * @def TEGRA186_CLK_QSPI_OUT | ||
164 | * @def TEGRA186_CLK_UFSDEV_REF | ||
165 | * @def TEGRA186_CLK_UFSHC | ||
166 | * @} | ||
167 | * | ||
168 | * @defgroup pwm_clks PWM clocks | ||
169 | * @{ | ||
170 | * @def TEGRA186_CLK_PWM1 | ||
171 | * @def TEGRA186_CLK_PWM2 | ||
172 | * @def TEGRA186_CLK_PWM3 | ||
173 | * @def TEGRA186_CLK_PWM4 | ||
174 | * @def TEGRA186_CLK_PWM5 | ||
175 | * @def TEGRA186_CLK_PWM6 | ||
176 | * @def TEGRA186_CLK_PWM7 | ||
177 | * @def TEGRA186_CLK_PWM8 | ||
178 | * @} | ||
179 | * | ||
180 | * @defgroup plls PLLs and related clocks | ||
181 | * @{ | ||
182 | * @def TEGRA186_CLK_PLLREFE_OUT_GATED | ||
183 | * @def TEGRA186_CLK_PLLREFE_OUT1 | ||
184 | * @def TEGRA186_CLK_PLLD_OUT1 | ||
185 | * @def TEGRA186_CLK_PLLP_OUT0 | ||
186 | * @def TEGRA186_CLK_PLLP_OUT5 | ||
187 | * @def TEGRA186_CLK_PLLA | ||
188 | * @def TEGRA186_CLK_PLLE_PWRSEQ | ||
189 | * @def TEGRA186_CLK_PLLA_OUT1 | ||
190 | * @def TEGRA186_CLK_PLLREFE_REF | ||
191 | * @def TEGRA186_CLK_UPHY_PLL0_PWRSEQ | ||
192 | * @def TEGRA186_CLK_UPHY_PLL1_PWRSEQ | ||
193 | * @def TEGRA186_CLK_PLLREFE_PLLE_PASSTHROUGH | ||
194 | * @def TEGRA186_CLK_PLLREFE_PEX | ||
195 | * @def TEGRA186_CLK_PLLREFE_IDDQ | ||
196 | * @def TEGRA186_CLK_PLLC_OUT_AON | ||
197 | * @def TEGRA186_CLK_PLLC_OUT_ISP | ||
198 | * @def TEGRA186_CLK_PLLC_OUT_VE | ||
199 | * @def TEGRA186_CLK_PLLC4_OUT | ||
200 | * @def TEGRA186_CLK_PLLREFE_OUT | ||
201 | * @def TEGRA186_CLK_PLLREFE_PLL_REF | ||
202 | * @def TEGRA186_CLK_PLLE | ||
203 | * @def TEGRA186_CLK_PLLC | ||
204 | * @def TEGRA186_CLK_PLLP | ||
205 | * @def TEGRA186_CLK_PLLD | ||
206 | * @def TEGRA186_CLK_PLLD2 | ||
207 | * @def TEGRA186_CLK_PLLREFE_VCO | ||
208 | * @def TEGRA186_CLK_PLLC2 | ||
209 | * @def TEGRA186_CLK_PLLC3 | ||
210 | * @def TEGRA186_CLK_PLLDP | ||
211 | * @def TEGRA186_CLK_PLLC4_VCO | ||
212 | * @def TEGRA186_CLK_PLLA1 | ||
213 | * @def TEGRA186_CLK_PLLNVCSI | ||
214 | * @def TEGRA186_CLK_PLLDISPHUB | ||
215 | * @def TEGRA186_CLK_PLLD3 | ||
216 | * @def TEGRA186_CLK_PLLBPMPCAM | ||
217 | * @def TEGRA186_CLK_PLLAON | ||
218 | * @def TEGRA186_CLK_PLLU | ||
219 | * @def TEGRA186_CLK_PLLC4_VCO_DIV2 | ||
220 | * @def TEGRA186_CLK_PLL_REF | ||
221 | * @def TEGRA186_CLK_PLLREFE_OUT1_DIV5 | ||
222 | * @def TEGRA186_CLK_UTMIP_PLL_PWRSEQ | ||
223 | * @def TEGRA186_CLK_PLL_U_48M | ||
224 | * @def TEGRA186_CLK_PLL_U_480M | ||
225 | * @def TEGRA186_CLK_PLLC4_OUT0 | ||
226 | * @def TEGRA186_CLK_PLLC4_OUT1 | ||
227 | * @def TEGRA186_CLK_PLLC4_OUT2 | ||
228 | * @def TEGRA186_CLK_PLLC4_OUT_MUX | ||
229 | * @def TEGRA186_CLK_DFLLDISP_DIV | ||
230 | * @def TEGRA186_CLK_PLLDISPHUB_DIV | ||
231 | * @def TEGRA186_CLK_PLLP_DIV8 | ||
232 | * @} | ||
233 | * | ||
234 | * @defgroup nafll_clks NAFLL clock sources | ||
235 | * @{ | ||
236 | * @def TEGRA186_CLK_NAFLL_AXI_CBB | ||
237 | * @def TEGRA186_CLK_NAFLL_BCPU | ||
238 | * @def TEGRA186_CLK_NAFLL_BPMP | ||
239 | * @def TEGRA186_CLK_NAFLL_DISP | ||
240 | * @def TEGRA186_CLK_NAFLL_GPU | ||
241 | * @def TEGRA186_CLK_NAFLL_ISP | ||
242 | * @def TEGRA186_CLK_NAFLL_MCPU | ||
243 | * @def TEGRA186_CLK_NAFLL_NVDEC | ||
244 | * @def TEGRA186_CLK_NAFLL_NVENC | ||
245 | * @def TEGRA186_CLK_NAFLL_NVJPG | ||
246 | * @def TEGRA186_CLK_NAFLL_SCE | ||
247 | * @def TEGRA186_CLK_NAFLL_SE | ||
248 | * @def TEGRA186_CLK_NAFLL_TSEC | ||
249 | * @def TEGRA186_CLK_NAFLL_TSECB | ||
250 | * @def TEGRA186_CLK_NAFLL_VI | ||
251 | * @def TEGRA186_CLK_NAFLL_VIC | ||
252 | * @} | ||
253 | * | ||
254 | * @defgroup mphy MPHY related clocks | ||
255 | * @{ | ||
256 | * @def TEGRA186_CLK_MPHY_L0_RX_SYMB | ||
257 | * @def TEGRA186_CLK_MPHY_L0_RX_LS_BIT | ||
258 | * @def TEGRA186_CLK_MPHY_L0_TX_SYMB | ||
259 | * @def TEGRA186_CLK_MPHY_L0_TX_LS_3XBIT | ||
260 | * @def TEGRA186_CLK_MPHY_L0_RX_ANA | ||
261 | * @def TEGRA186_CLK_MPHY_L1_RX_ANA | ||
262 | * @def TEGRA186_CLK_MPHY_IOBIST | ||
263 | * @def TEGRA186_CLK_MPHY_TX_1MHZ_REF | ||
264 | * @def TEGRA186_CLK_MPHY_CORE_PLL_FIXED | ||
265 | * @} | ||
266 | * | ||
267 | * @defgroup eavb EAVB related clocks | ||
268 | * @{ | ||
269 | * @def TEGRA186_CLK_EQOS_AXI | ||
270 | * @def TEGRA186_CLK_EQOS_PTP_REF | ||
271 | * @def TEGRA186_CLK_EQOS_RX | ||
272 | * @def TEGRA186_CLK_EQOS_RX_INPUT | ||
273 | * @def TEGRA186_CLK_EQOS_TX | ||
274 | * @} | ||
275 | * | ||
276 | * @defgroup usb USB related clocks | ||
277 | * @{ | ||
278 | * @def TEGRA186_CLK_PEX_USB_PAD0_MGMT | ||
279 | * @def TEGRA186_CLK_PEX_USB_PAD1_MGMT | ||
280 | * @def TEGRA186_CLK_HSIC_TRK | ||
281 | * @def TEGRA186_CLK_USB2_TRK | ||
282 | * @def TEGRA186_CLK_USB2_HSIC_TRK | ||
283 | * @def TEGRA186_CLK_XUSB_CORE_SS | ||
284 | * @def TEGRA186_CLK_XUSB_CORE_DEV | ||
285 | * @def TEGRA186_CLK_XUSB_FALCON | ||
286 | * @def TEGRA186_CLK_XUSB_FS | ||
287 | * @def TEGRA186_CLK_XUSB | ||
288 | * @def TEGRA186_CLK_XUSB_DEV | ||
289 | * @def TEGRA186_CLK_XUSB_HOST | ||
290 | * @def TEGRA186_CLK_XUSB_SS | ||
291 | * @} | ||
292 | * | ||
293 | * @defgroup bigblock compute block related clocks | ||
294 | * @{ | ||
295 | * @def TEGRA186_CLK_GPCCLK | ||
296 | * @def TEGRA186_CLK_GPC2CLK | ||
297 | * @def TEGRA186_CLK_GPU | ||
298 | * @def TEGRA186_CLK_HOST1X | ||
299 | * @def TEGRA186_CLK_ISP | ||
300 | * @def TEGRA186_CLK_NVDEC | ||
301 | * @def TEGRA186_CLK_NVENC | ||
302 | * @def TEGRA186_CLK_NVJPG | ||
303 | * @def TEGRA186_CLK_SE | ||
304 | * @def TEGRA186_CLK_TSEC | ||
305 | * @def TEGRA186_CLK_TSECB | ||
306 | * @def TEGRA186_CLK_VIC | ||
307 | * @} | ||
308 | * | ||
309 | * @defgroup can CAN bus related clocks | ||
310 | * @{ | ||
311 | * @def TEGRA186_CLK_CAN1 | ||
312 | * @def TEGRA186_CLK_CAN1_HOST | ||
313 | * @def TEGRA186_CLK_CAN2 | ||
314 | * @def TEGRA186_CLK_CAN2_HOST | ||
315 | * @} | ||
316 | * | ||
317 | * @defgroup system basic system clocks | ||
318 | * @{ | ||
319 | * @def TEGRA186_CLK_ACTMON | ||
320 | * @def TEGRA186_CLK_AON_APB | ||
321 | * @def TEGRA186_CLK_AON_CPU_NIC | ||
322 | * @def TEGRA186_CLK_AON_NIC | ||
323 | * @def TEGRA186_CLK_AXI_CBB | ||
324 | * @def TEGRA186_CLK_BPMP_APB | ||
325 | * @def TEGRA186_CLK_BPMP_CPU_NIC | ||
326 | * @def TEGRA186_CLK_BPMP_NIC_RATE | ||
327 | * @def TEGRA186_CLK_CLK_M | ||
328 | * @def TEGRA186_CLK_EMC | ||
329 | * @def TEGRA186_CLK_MSS_ENCRYPT | ||
330 | * @def TEGRA186_CLK_SCE_APB | ||
331 | * @def TEGRA186_CLK_SCE_CPU_NIC | ||
332 | * @def TEGRA186_CLK_SCE_NIC | ||
333 | * @def TEGRA186_CLK_TSC | ||
334 | * @} | ||
335 | * | ||
336 | * @defgroup pcie_clks PCIe related clocks | ||
337 | * @{ | ||
338 | * @def TEGRA186_CLK_AFI | ||
339 | * @def TEGRA186_CLK_PCIE | ||
340 | * @def TEGRA186_CLK_PCIE2_IOBIST | ||
341 | * @def TEGRA186_CLK_PCIERX0 | ||
342 | * @def TEGRA186_CLK_PCIERX1 | ||
343 | * @def TEGRA186_CLK_PCIERX2 | ||
344 | * @def TEGRA186_CLK_PCIERX3 | ||
345 | * @def TEGRA186_CLK_PCIERX4 | ||
346 | * @} | ||
347 | */ | ||
348 | |||
349 | /** @brief output of gate CLK_ENB_FUSE */ | ||
350 | #define TEGRA186_CLK_FUSE 0 | ||
351 | /** | ||
352 | * @brief It's not what you think | ||
353 | * @details output of gate CLK_ENB_GPU. This output connects to the GPU | ||
354 | * pwrclk. @warning: This is almost certainly not the clock you think | ||
355 | * it is. If you're looking for the clock of the graphics engine, see | ||
356 | * TEGRA186_GPCCLK | ||
357 | */ | ||
358 | #define TEGRA186_CLK_GPU 1 | ||
359 | /** @brief output of gate CLK_ENB_PCIE */ | ||
360 | #define TEGRA186_CLK_PCIE 3 | ||
361 | /** @brief output of the divider IPFS_CLK_DIVISOR */ | ||
362 | #define TEGRA186_CLK_AFI 4 | ||
363 | /** @brief output of gate CLK_ENB_PCIE2_IOBIST */ | ||
364 | #define TEGRA186_CLK_PCIE2_IOBIST 5 | ||
365 | /** @brief output of gate CLK_ENB_PCIERX0*/ | ||
366 | #define TEGRA186_CLK_PCIERX0 6 | ||
367 | /** @brief output of gate CLK_ENB_PCIERX1*/ | ||
368 | #define TEGRA186_CLK_PCIERX1 7 | ||
369 | /** @brief output of gate CLK_ENB_PCIERX2*/ | ||
370 | #define TEGRA186_CLK_PCIERX2 8 | ||
371 | /** @brief output of gate CLK_ENB_PCIERX3*/ | ||
372 | #define TEGRA186_CLK_PCIERX3 9 | ||
373 | /** @brief output of gate CLK_ENB_PCIERX4*/ | ||
374 | #define TEGRA186_CLK_PCIERX4 10 | ||
375 | /** @brief output branch of PLL_C for ISP, controlled by gate CLK_ENB_PLLC_OUT_ISP */ | ||
376 | #define TEGRA186_CLK_PLLC_OUT_ISP 11 | ||
377 | /** @brief output branch of PLL_C for VI, controlled by gate CLK_ENB_PLLC_OUT_VE */ | ||
378 | #define TEGRA186_CLK_PLLC_OUT_VE 12 | ||
379 | /** @brief output branch of PLL_C for AON domain, controlled by gate CLK_ENB_PLLC_OUT_AON */ | ||
380 | #define TEGRA186_CLK_PLLC_OUT_AON 13 | ||
381 | /** @brief output of gate CLK_ENB_SOR_SAFE */ | ||
382 | #define TEGRA186_CLK_SOR_SAFE 39 | ||
383 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2S2 */ | ||
384 | #define TEGRA186_CLK_I2S2 42 | ||
385 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2S3 */ | ||
386 | #define TEGRA186_CLK_I2S3 43 | ||
387 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SPDF_IN */ | ||
388 | #define TEGRA186_CLK_SPDIF_IN 44 | ||
389 | /** @brief output of gate CLK_ENB_SPDIF_DOUBLER */ | ||
390 | #define TEGRA186_CLK_SPDIF_DOUBLER 45 | ||
391 | /** @clkdesc{spi_clks, out, mux, CLK_RST_CONTROLLER_CLK_SOURCE_SPI3} */ | ||
392 | #define TEGRA186_CLK_SPI3 46 | ||
393 | /** @clkdesc{i2c_clks, out, mux, CLK_RST_CONTROLLER_CLK_SOURCE_I2C1} */ | ||
394 | #define TEGRA186_CLK_I2C1 47 | ||
395 | /** @clkdesc{i2c_clks, out, mux, CLK_RST_CONTROLLER_CLK_SOURCE_I2C5} */ | ||
396 | #define TEGRA186_CLK_I2C5 48 | ||
397 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SPI1 */ | ||
398 | #define TEGRA186_CLK_SPI1 49 | ||
399 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_ISP */ | ||
400 | #define TEGRA186_CLK_ISP 50 | ||
401 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_VI */ | ||
402 | #define TEGRA186_CLK_VI 51 | ||
403 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC1 */ | ||
404 | #define TEGRA186_CLK_SDMMC1 52 | ||
405 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC2 */ | ||
406 | #define TEGRA186_CLK_SDMMC2 53 | ||
407 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC4 */ | ||
408 | #define TEGRA186_CLK_SDMMC4 54 | ||
409 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTA */ | ||
410 | #define TEGRA186_CLK_UARTA 55 | ||
411 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTB */ | ||
412 | #define TEGRA186_CLK_UARTB 56 | ||
413 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_HOST1X */ | ||
414 | #define TEGRA186_CLK_HOST1X 57 | ||
415 | /** | ||
416 | * @brief controls the EMC clock frequency. | ||
417 | * @details Doing a clk_set_rate on this clock will select the | ||
418 | * appropriate clock source, program the source rate and execute a | ||
419 | * specific sequence to switch to the new clock source for both memory | ||
420 | * controllers. This can be used to control the balance between memory | ||
421 | * throughput and memory controller power. | ||
422 | */ | ||
423 | #define TEGRA186_CLK_EMC 58 | ||
424 | /* @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH4 */ | ||
425 | #define TEGRA186_CLK_EXTPERIPH4 73 | ||
426 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SPI4 */ | ||
427 | #define TEGRA186_CLK_SPI4 74 | ||
428 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C3 */ | ||
429 | #define TEGRA186_CLK_I2C3 75 | ||
430 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC3 */ | ||
431 | #define TEGRA186_CLK_SDMMC3 76 | ||
432 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTD */ | ||
433 | #define TEGRA186_CLK_UARTD 77 | ||
434 | /** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2S1 */ | ||
435 | #define TEGRA186_CLK_I2S1 79 | ||
436 | /** output of gate CLK_ENB_DTV */ | ||
437 | #define TEGRA186_CLK_DTV 80 | ||
438 | /** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_TSEC */ | ||
439 | #define TEGRA186_CLK_TSEC 81 | ||
440 | /** @brief output of gate CLK_ENB_DP2 */ | ||
441 | #define TEGRA186_CLK_DP2 82 | ||
442 | /** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2S4 */ | ||
443 | #define TEGRA186_CLK_I2S4 84 | ||
444 | /** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2S5 */ | ||
445 | #define TEGRA186_CLK_I2S5 85 | ||
446 | /** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C4 */ | ||
447 | #define TEGRA186_CLK_I2C4 86 | ||
448 | /** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AHUB */ | ||
449 | #define TEGRA186_CLK_AHUB 87 | ||
450 | /** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_HDA2CODEC_2X */ | ||
451 | #define TEGRA186_CLK_HDA2CODEC_2X 88 | ||
452 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH1 */ | ||
453 | #define TEGRA186_CLK_EXTPERIPH1 89 | ||
454 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH2 */ | ||
455 | #define TEGRA186_CLK_EXTPERIPH2 90 | ||
456 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_EXTPERIPH3 */ | ||
457 | #define TEGRA186_CLK_EXTPERIPH3 91 | ||
458 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C_SLOW */ | ||
459 | #define TEGRA186_CLK_I2C_SLOW 92 | ||
460 | /** @brief output of the SOR1_CLK_SRC mux in CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 */ | ||
461 | #define TEGRA186_CLK_SOR1 93 | ||
462 | /** @brief output of gate CLK_ENB_CEC */ | ||
463 | #define TEGRA186_CLK_CEC 94 | ||
464 | /** @brief output of gate CLK_ENB_DPAUX1 */ | ||
465 | #define TEGRA186_CLK_DPAUX1 95 | ||
466 | /** @brief output of gate CLK_ENB_DPAUX */ | ||
467 | #define TEGRA186_CLK_DPAUX 96 | ||
468 | /** @brief output of the SOR0_CLK_SRC mux in CLK_RST_CONTROLLER_CLK_SOURCE_SOR0 */ | ||
469 | #define TEGRA186_CLK_SOR0 97 | ||
470 | /** @brief output of gate CLK_ENB_HDA2HDMICODEC */ | ||
471 | #define TEGRA186_CLK_HDA2HDMICODEC 98 | ||
472 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SATA */ | ||
473 | #define TEGRA186_CLK_SATA 99 | ||
474 | /** @brief output of gate CLK_ENB_SATA_OOB */ | ||
475 | #define TEGRA186_CLK_SATA_OOB 100 | ||
476 | /** @brief output of gate CLK_ENB_SATA_IOBIST */ | ||
477 | #define TEGRA186_CLK_SATA_IOBIST 101 | ||
478 | /** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_HDA */ | ||
479 | #define TEGRA186_CLK_HDA 102 | ||
480 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SE */ | ||
481 | #define TEGRA186_CLK_SE 103 | ||
482 | /** @brief output of gate CLK_ENB_APB2APE */ | ||
483 | #define TEGRA186_CLK_APB2APE 104 | ||
484 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_APE */ | ||
485 | #define TEGRA186_CLK_APE 105 | ||
486 | /** @brief output of gate CLK_ENB_IQC1 */ | ||
487 | #define TEGRA186_CLK_IQC1 106 | ||
488 | /** @brief output of gate CLK_ENB_IQC2 */ | ||
489 | #define TEGRA186_CLK_IQC2 107 | ||
490 | /** divide by 2 version of TEGRA186_CLK_PLLREFE_VCO */ | ||
491 | #define TEGRA186_CLK_PLLREFE_OUT 108 | ||
492 | /** @brief output of gate CLK_ENB_PLLREFE_PLL_REF */ | ||
493 | #define TEGRA186_CLK_PLLREFE_PLL_REF 109 | ||
494 | /** @brief output of gate CLK_ENB_PLLC4_OUT */ | ||
495 | #define TEGRA186_CLK_PLLC4_OUT 110 | ||
496 | /** @brief output of mux xusb_core_clk_switch on page 67 of T186_Clocks_IAS.doc */ | ||
497 | #define TEGRA186_CLK_XUSB 111 | ||
498 | /** controls xusb_dev_ce signal on page 66 and 67 of T186_Clocks_IAS.doc */ | ||
499 | #define TEGRA186_CLK_XUSB_DEV 112 | ||
500 | /** controls xusb_host_ce signal on page 67 of T186_Clocks_IAS.doc */ | ||
501 | #define TEGRA186_CLK_XUSB_HOST 113 | ||
502 | /** controls xusb_ss_ce signal on page 67 of T186_Clocks_IAS.doc */ | ||
503 | #define TEGRA186_CLK_XUSB_SS 114 | ||
504 | /** @brief output of gate CLK_ENB_DSI */ | ||
505 | #define TEGRA186_CLK_DSI 115 | ||
506 | /** @brief output of gate CLK_ENB_MIPI_CAL */ | ||
507 | #define TEGRA186_CLK_MIPI_CAL 116 | ||
508 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DSIA_LP */ | ||
509 | #define TEGRA186_CLK_DSIA_LP 117 | ||
510 | /** @brief output of gate CLK_ENB_DSIB */ | ||
511 | #define TEGRA186_CLK_DSIB 118 | ||
512 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DSIB_LP */ | ||
513 | #define TEGRA186_CLK_DSIB_LP 119 | ||
514 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DMIC1 */ | ||
515 | #define TEGRA186_CLK_DMIC1 122 | ||
516 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DMIC2 */ | ||
517 | #define TEGRA186_CLK_DMIC2 123 | ||
518 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AUD_MCLK */ | ||
519 | #define TEGRA186_CLK_AUD_MCLK 124 | ||
520 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 */ | ||
521 | #define TEGRA186_CLK_I2C6 125 | ||
522 | /**output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UART_FST_MIPI_CAL */ | ||
523 | #define TEGRA186_CLK_UART_FST_MIPI_CAL 126 | ||
524 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_VIC */ | ||
525 | #define TEGRA186_CLK_VIC 127 | ||
526 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SDMMC_LEGACY_TM */ | ||
527 | #define TEGRA186_CLK_SDMMC_LEGACY_TM 128 | ||
528 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVDEC */ | ||
529 | #define TEGRA186_CLK_NVDEC 129 | ||
530 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVJPG */ | ||
531 | #define TEGRA186_CLK_NVJPG 130 | ||
532 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVENC */ | ||
533 | #define TEGRA186_CLK_NVENC 131 | ||
534 | /** @brief output of the QSPI_CLK_SRC mux in CLK_RST_CONTROLLER_CLK_SOURCE_QSPI */ | ||
535 | #define TEGRA186_CLK_QSPI 132 | ||
536 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_VI_I2C */ | ||
537 | #define TEGRA186_CLK_VI_I2C 133 | ||
538 | /** @brief output of gate CLK_ENB_HSIC_TRK */ | ||
539 | #define TEGRA186_CLK_HSIC_TRK 134 | ||
540 | /** @brief output of gate CLK_ENB_USB2_TRK */ | ||
541 | #define TEGRA186_CLK_USB2_TRK 135 | ||
542 | /** output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_MAUD */ | ||
543 | #define TEGRA186_CLK_MAUD 136 | ||
544 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_TSECB */ | ||
545 | #define TEGRA186_CLK_TSECB 137 | ||
546 | /** @brief output of gate CLK_ENB_ADSP */ | ||
547 | #define TEGRA186_CLK_ADSP 138 | ||
548 | /** @brief output of gate CLK_ENB_ADSPNEON */ | ||
549 | #define TEGRA186_CLK_ADSPNEON 139 | ||
550 | /** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_MPHY_L0_RX_LS_SYMB */ | ||
551 | #define TEGRA186_CLK_MPHY_L0_RX_SYMB 140 | ||
552 | /** @brief output of gate CLK_ENB_MPHY_L0_RX_LS_BIT */ | ||
553 | #define TEGRA186_CLK_MPHY_L0_RX_LS_BIT 141 | ||
554 | /** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_MPHY_L0_TX_LS_SYMB */ | ||
555 | #define TEGRA186_CLK_MPHY_L0_TX_SYMB 142 | ||
556 | /** @brief output of gate CLK_ENB_MPHY_L0_TX_LS_3XBIT */ | ||
557 | #define TEGRA186_CLK_MPHY_L0_TX_LS_3XBIT 143 | ||
558 | /** @brief output of gate CLK_ENB_MPHY_L0_RX_ANA */ | ||
559 | #define TEGRA186_CLK_MPHY_L0_RX_ANA 144 | ||
560 | /** @brief output of gate CLK_ENB_MPHY_L1_RX_ANA */ | ||
561 | #define TEGRA186_CLK_MPHY_L1_RX_ANA 145 | ||
562 | /** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_MPHY_IOBIST */ | ||
563 | #define TEGRA186_CLK_MPHY_IOBIST 146 | ||
564 | /** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_MPHY_TX_1MHZ_REF */ | ||
565 | #define TEGRA186_CLK_MPHY_TX_1MHZ_REF 147 | ||
566 | /** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_MPHY_CORE_PLL_FIXED */ | ||
567 | #define TEGRA186_CLK_MPHY_CORE_PLL_FIXED 148 | ||
568 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AXI_CBB */ | ||
569 | #define TEGRA186_CLK_AXI_CBB 149 | ||
570 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DMIC3 */ | ||
571 | #define TEGRA186_CLK_DMIC3 150 | ||
572 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DMIC4 */ | ||
573 | #define TEGRA186_CLK_DMIC4 151 | ||
574 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DSPK1 */ | ||
575 | #define TEGRA186_CLK_DSPK1 152 | ||
576 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DSPK2 */ | ||
577 | #define TEGRA186_CLK_DSPK2 153 | ||
578 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C6 */ | ||
579 | #define TEGRA186_CLK_I2S6 154 | ||
580 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVDISPLAY_P0 */ | ||
581 | #define TEGRA186_CLK_NVDISPLAY_P0 155 | ||
582 | /** @brief output of the NVDISPLAY_DISP_CLK_SRC mux in CLK_RST_CONTROLLER_CLK_SOURCE_NVDISPLAY_DISP */ | ||
583 | #define TEGRA186_CLK_NVDISPLAY_DISP 156 | ||
584 | /** @brief output of gate CLK_ENB_NVDISPLAY_DSC */ | ||
585 | #define TEGRA186_CLK_NVDISPLAY_DSC 157 | ||
586 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVDISPLAYHUB */ | ||
587 | #define TEGRA186_CLK_NVDISPLAYHUB 158 | ||
588 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVDISPLAY_P1 */ | ||
589 | #define TEGRA186_CLK_NVDISPLAY_P1 159 | ||
590 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVDISPLAY_P2 */ | ||
591 | #define TEGRA186_CLK_NVDISPLAY_P2 160 | ||
592 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_TACH */ | ||
593 | #define TEGRA186_CLK_TACH 166 | ||
594 | /** @brief output of gate CLK_ENB_EQOS */ | ||
595 | #define TEGRA186_CLK_EQOS_AXI 167 | ||
596 | /** @brief output of gate CLK_ENB_EQOS_RX */ | ||
597 | #define TEGRA186_CLK_EQOS_RX 168 | ||
598 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UFSHC_CG_SYS */ | ||
599 | #define TEGRA186_CLK_UFSHC 178 | ||
600 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UFSDEV_REF */ | ||
601 | #define TEGRA186_CLK_UFSDEV_REF 179 | ||
602 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVCSI */ | ||
603 | #define TEGRA186_CLK_NVCSI 180 | ||
604 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_NVCSILP */ | ||
605 | #define TEGRA186_CLK_NVCSILP 181 | ||
606 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C7 */ | ||
607 | #define TEGRA186_CLK_I2C7 182 | ||
608 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C9 */ | ||
609 | #define TEGRA186_CLK_I2C9 183 | ||
610 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C12 */ | ||
611 | #define TEGRA186_CLK_I2C12 184 | ||
612 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C13 */ | ||
613 | #define TEGRA186_CLK_I2C13 185 | ||
614 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C14 */ | ||
615 | #define TEGRA186_CLK_I2C14 186 | ||
616 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM1 */ | ||
617 | #define TEGRA186_CLK_PWM1 187 | ||
618 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM2 */ | ||
619 | #define TEGRA186_CLK_PWM2 188 | ||
620 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM3 */ | ||
621 | #define TEGRA186_CLK_PWM3 189 | ||
622 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM5 */ | ||
623 | #define TEGRA186_CLK_PWM5 190 | ||
624 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM6 */ | ||
625 | #define TEGRA186_CLK_PWM6 191 | ||
626 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM7 */ | ||
627 | #define TEGRA186_CLK_PWM7 192 | ||
628 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM8 */ | ||
629 | #define TEGRA186_CLK_PWM8 193 | ||
630 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTE */ | ||
631 | #define TEGRA186_CLK_UARTE 194 | ||
632 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTF */ | ||
633 | #define TEGRA186_CLK_UARTF 195 | ||
634 | /** @deprecated */ | ||
635 | #define TEGRA186_CLK_DBGAPB 196 | ||
636 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_BPMP_CPU_NIC */ | ||
637 | #define TEGRA186_CLK_BPMP_CPU_NIC 197 | ||
638 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_BPMP_APB */ | ||
639 | #define TEGRA186_CLK_BPMP_APB 199 | ||
640 | /** @brief output of mux controlled by TEGRA186_CLK_SOC_ACTMON */ | ||
641 | #define TEGRA186_CLK_ACTMON 201 | ||
642 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AON_CPU_NIC */ | ||
643 | #define TEGRA186_CLK_AON_CPU_NIC 208 | ||
644 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_CAN1 */ | ||
645 | #define TEGRA186_CLK_CAN1 210 | ||
646 | /** @brief output of gate CLK_ENB_CAN1_HOST */ | ||
647 | #define TEGRA186_CLK_CAN1_HOST 211 | ||
648 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_CAN2 */ | ||
649 | #define TEGRA186_CLK_CAN2 212 | ||
650 | /** @brief output of gate CLK_ENB_CAN2_HOST */ | ||
651 | #define TEGRA186_CLK_CAN2_HOST 213 | ||
652 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AON_APB */ | ||
653 | #define TEGRA186_CLK_AON_APB 214 | ||
654 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTC */ | ||
655 | #define TEGRA186_CLK_UARTC 215 | ||
656 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_UARTG */ | ||
657 | #define TEGRA186_CLK_UARTG 216 | ||
658 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AON_UART_FST_MIPI_CAL */ | ||
659 | #define TEGRA186_CLK_AON_UART_FST_MIPI_CAL 217 | ||
660 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C2 */ | ||
661 | #define TEGRA186_CLK_I2C2 218 | ||
662 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C8 */ | ||
663 | #define TEGRA186_CLK_I2C8 219 | ||
664 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_I2C10 */ | ||
665 | #define TEGRA186_CLK_I2C10 220 | ||
666 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AON_I2C_SLOW */ | ||
667 | #define TEGRA186_CLK_AON_I2C_SLOW 221 | ||
668 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SPI2 */ | ||
669 | #define TEGRA186_CLK_SPI2 222 | ||
670 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DMIC5 */ | ||
671 | #define TEGRA186_CLK_DMIC5 223 | ||
672 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_AON_TOUCH */ | ||
673 | #define TEGRA186_CLK_AON_TOUCH 224 | ||
674 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_PWM4 */ | ||
675 | #define TEGRA186_CLK_PWM4 225 | ||
676 | /** @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. */ | ||
677 | #define TEGRA186_CLK_TSC 226 | ||
678 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_MSS_ENCRYPT */ | ||
679 | #define TEGRA186_CLK_MSS_ENCRYPT 227 | ||
680 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SCE_CPU_NIC */ | ||
681 | #define TEGRA186_CLK_SCE_CPU_NIC 228 | ||
682 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SCE_APB */ | ||
683 | #define TEGRA186_CLK_SCE_APB 230 | ||
684 | /** @brief output of gate CLK_ENB_DSIC */ | ||
685 | #define TEGRA186_CLK_DSIC 231 | ||
686 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DSIC_LP */ | ||
687 | #define TEGRA186_CLK_DSIC_LP 232 | ||
688 | /** @brief output of gate CLK_ENB_DSID */ | ||
689 | #define TEGRA186_CLK_DSID 233 | ||
690 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_DSID_LP */ | ||
691 | #define TEGRA186_CLK_DSID_LP 234 | ||
692 | /** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_PEX_SATA_USB_RX_BYP */ | ||
693 | #define TEGRA186_CLK_PEX_SATA_USB_RX_BYP 236 | ||
694 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_CLK_SOURCE_SPDIF_OUT */ | ||
695 | #define TEGRA186_CLK_SPDIF_OUT 238 | ||
696 | /** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_EQOS_PTP_REF_CLK_0 */ | ||
697 | #define TEGRA186_CLK_EQOS_PTP_REF 239 | ||
698 | /** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_EQOS_TX_CLK */ | ||
699 | #define TEGRA186_CLK_EQOS_TX 240 | ||
700 | /** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_USB2_HSIC_TRK */ | ||
701 | #define TEGRA186_CLK_USB2_HSIC_TRK 241 | ||
702 | /** @brief output of mux xusb_ss_clk_switch on page 66 of T186_Clocks_IAS.doc */ | ||
703 | #define TEGRA186_CLK_XUSB_CORE_SS 242 | ||
704 | /** @brief output of mux xusb_core_dev_clk_switch on page 67 of T186_Clocks_IAS.doc */ | ||
705 | #define TEGRA186_CLK_XUSB_CORE_DEV 243 | ||
706 | /** @brief output of mux xusb_core_falcon_clk_switch on page 67 of T186_Clocks_IAS.doc */ | ||
707 | #define TEGRA186_CLK_XUSB_FALCON 244 | ||
708 | /** @brief output of mux xusb_fs_clk_switch on page 66 of T186_Clocks_IAS.doc */ | ||
709 | #define TEGRA186_CLK_XUSB_FS 245 | ||
710 | /** @brief output of the divider CLK_RST_CONTROLLER_PLLA_OUT */ | ||
711 | #define TEGRA186_CLK_PLL_A_OUT0 246 | ||
712 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S1 */ | ||
713 | #define TEGRA186_CLK_SYNC_I2S1 247 | ||
714 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S2 */ | ||
715 | #define TEGRA186_CLK_SYNC_I2S2 248 | ||
716 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S3 */ | ||
717 | #define TEGRA186_CLK_SYNC_I2S3 249 | ||
718 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S4 */ | ||
719 | #define TEGRA186_CLK_SYNC_I2S4 250 | ||
720 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S5 */ | ||
721 | #define TEGRA186_CLK_SYNC_I2S5 251 | ||
722 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_I2S6 */ | ||
723 | #define TEGRA186_CLK_SYNC_I2S6 252 | ||
724 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_DSPK1 */ | ||
725 | #define TEGRA186_CLK_SYNC_DSPK1 253 | ||
726 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_DSPK2 */ | ||
727 | #define TEGRA186_CLK_SYNC_DSPK2 254 | ||
728 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_DMIC1 */ | ||
729 | #define TEGRA186_CLK_SYNC_DMIC1 255 | ||
730 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_DMIC2 */ | ||
731 | #define TEGRA186_CLK_SYNC_DMIC2 256 | ||
732 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_DMIC3 */ | ||
733 | #define TEGRA186_CLK_SYNC_DMIC3 257 | ||
734 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_DMIC4 */ | ||
735 | #define TEGRA186_CLK_SYNC_DMIC4 259 | ||
736 | /** @brief output of mux controlled by CLK_RST_CONTROLLER_AUDIO_SYNC_CLK_SPDIF */ | ||
737 | #define TEGRA186_CLK_SYNC_SPDIF 260 | ||
738 | /** @brief output of gate CLK_ENB_PLLREFE_OUT */ | ||
739 | #define TEGRA186_CLK_PLLREFE_OUT_GATED 261 | ||
740 | /** @brief output of the divider PLLREFE_DIVP in CLK_RST_CONTROLLER_PLLREFE_BASE. PLLREFE has 2 outputs: | ||
741 | * * VCO/pdiv defined by this clock object | ||
742 | * * VCO/2 defined by TEGRA186_CLK_PLLREFE_OUT | ||
743 | */ | ||
744 | #define TEGRA186_CLK_PLLREFE_OUT1 262 | ||
745 | #define TEGRA186_CLK_PLLD_OUT1 267 | ||
746 | /** @brief output of the divider PLLP_DIVP in CLK_RST_CONTROLLER_PLLP_BASE */ | ||
747 | #define TEGRA186_CLK_PLLP_OUT0 269 | ||
748 | /** @brief output of the divider CLK_RST_CONTROLLER_PLLP_OUTC */ | ||
749 | #define TEGRA186_CLK_PLLP_OUT5 270 | ||
750 | /** PLL controlled by CLK_RST_CONTROLLER_PLLA_BASE for use by audio clocks */ | ||
751 | #define TEGRA186_CLK_PLLA 271 | ||
752 | /** @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 */ | ||
753 | #define TEGRA186_CLK_ACLK 273 | ||
754 | /** fixed 48MHz clock divided down from TEGRA186_CLK_PLL_U */ | ||
755 | #define TEGRA186_CLK_PLL_U_48M 274 | ||
756 | /** fixed 480MHz clock divided down from TEGRA186_CLK_PLL_U */ | ||
757 | #define TEGRA186_CLK_PLL_U_480M 275 | ||
758 | /** @brief output of the divider PLLC4_DIVP in CLK_RST_CONTROLLER_PLLC4_BASE. Output frequency is TEGRA186_CLK_PLLC4_VCO/PLLC4_DIVP */ | ||
759 | #define TEGRA186_CLK_PLLC4_OUT0 276 | ||
760 | /** fixed /3 divider. Output frequency of this clock is TEGRA186_CLK_PLLC4_VCO/3 */ | ||
761 | #define TEGRA186_CLK_PLLC4_OUT1 277 | ||
762 | /** fixed /5 divider. Output frequency of this clock is TEGRA186_CLK_PLLC4_VCO/5 */ | ||
763 | #define TEGRA186_CLK_PLLC4_OUT2 278 | ||
764 | /** @brief output of mux controlled by PLLC4_CLK_SEL in CLK_RST_CONTROLLER_PLLC4_MISC1 */ | ||
765 | #define TEGRA186_CLK_PLLC4_OUT_MUX 279 | ||
766 | /** @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 */ | ||
767 | #define TEGRA186_CLK_DFLLDISP_DIV 284 | ||
768 | /** @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 */ | ||
769 | #define TEGRA186_CLK_PLLDISPHUB_DIV 285 | ||
770 | /** fixed /8 divider which is used as the input for TEGRA186_CLK_SOR_SAFE */ | ||
771 | #define TEGRA186_CLK_PLLP_DIV8 286 | ||
772 | /** @brief output of divider CLK_RST_CONTROLLER_BPMP_NIC_RATE */ | ||
773 | #define TEGRA186_CLK_BPMP_NIC 287 | ||
774 | /** @brief output of the divider CLK_RST_CONTROLLER_PLLA1_OUT1 */ | ||
775 | #define TEGRA186_CLK_PLL_A_OUT1 288 | ||
776 | /** @deprecated */ | ||
777 | #define TEGRA186_CLK_GPC2CLK 289 | ||
778 | /** A fake clock which must be enabled during KFUSE read operations to ensure adequate VDD_CORE voltage. */ | ||
779 | #define TEGRA186_CLK_KFUSE 293 | ||
780 | /** | ||
781 | * @brief controls the PLLE hardware sequencer. | ||
782 | * @details This clock only has enable and disable methods. When the | ||
783 | * PLLE hw sequencer is enabled, PLLE, will be enabled or disabled by | ||
784 | * hw based on the control signals from the PCIe, SATA and XUSB | ||
785 | * clocks. When the PLLE hw sequencer is disabled, the state of PLLE | ||
786 | * is controlled by sw using clk_enable/clk_disable on | ||
787 | * TEGRA186_CLK_PLLE. | ||
788 | */ | ||
789 | #define TEGRA186_CLK_PLLE_PWRSEQ 294 | ||
790 | /** fixed 60MHz clock divided down from, TEGRA186_CLK_PLL_U */ | ||
791 | #define TEGRA186_CLK_PLLREFE_REF 295 | ||
792 | /** @brief output of mux controlled by SOR0_CLK_SEL0 and SOR0_CLK_SEL1 in CLK_RST_CONTROLLER_CLK_SOURCE_SOR0 */ | ||
793 | #define TEGRA186_CLK_SOR0_OUT 296 | ||
794 | /** @brief output of mux controlled by SOR1_CLK_SEL0 and SOR1_CLK_SEL1 in CLK_RST_CONTROLLER_CLK_SOURCE_SOR1 */ | ||
795 | #define TEGRA186_CLK_SOR1_OUT 297 | ||
796 | /** @brief fixed /5 divider. Output frequency of this clock is TEGRA186_CLK_PLLREFE_OUT1/5. Used as input for TEGRA186_CLK_EQOS_AXI */ | ||
797 | #define TEGRA186_CLK_PLLREFE_OUT1_DIV5 298 | ||
798 | /** @brief controls the UTMIP_PLL (aka PLLU) hardware sqeuencer */ | ||
799 | #define TEGRA186_CLK_UTMIP_PLL_PWRSEQ 301 | ||
800 | /** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_PEX_USB_PAD_PLL0_MGMT */ | ||
801 | #define TEGRA186_CLK_PEX_USB_PAD0_MGMT 302 | ||
802 | /** @brief output of the divider CLK_RST_CONTROLLER_CLK_SOURCE_PEX_USB_PAD_PLL1_MGMT */ | ||
803 | #define TEGRA186_CLK_PEX_USB_PAD1_MGMT 303 | ||
804 | /** @brief controls the UPHY_PLL0 hardware sqeuencer */ | ||
805 | #define TEGRA186_CLK_UPHY_PLL0_PWRSEQ 304 | ||
806 | /** @brief controls the UPHY_PLL1 hardware sqeuencer */ | ||
807 | #define TEGRA186_CLK_UPHY_PLL1_PWRSEQ 305 | ||
808 | /** @brief control for PLLREFE_IDDQ in CLK_RST_CONTROLLER_PLLREFE_MISC so the bypass output even be used when the PLL is disabled */ | ||
809 | #define TEGRA186_CLK_PLLREFE_PLLE_PASSTHROUGH 306 | ||
810 | /** @brief output of the mux controlled by PLLREFE_SEL_CLKIN_PEX in CLK_RST_CONTROLLER_PLLREFE_MISC */ | ||
811 | #define TEGRA186_CLK_PLLREFE_PEX 307 | ||
812 | /** @brief control for PLLREFE_IDDQ in CLK_RST_CONTROLLER_PLLREFE_MISC to turn on the PLL when enabled */ | ||
813 | #define TEGRA186_CLK_PLLREFE_IDDQ 308 | ||
814 | /** @brief output of the divider QSPI_CLK_DIV2_SEL in CLK_RST_CONTROLLER_CLK_SOURCE_QSPI */ | ||
815 | #define TEGRA186_CLK_QSPI_OUT 309 | ||
816 | /** | ||
817 | * @brief GPC2CLK-div-2 | ||
818 | * @details fixed /2 divider. Output frequency is | ||
819 | * TEGRA186_CLK_GPC2CLK/2. The frequency of this clock is the | ||
820 | * frequency at which the GPU graphics engine runs. */ | ||
821 | #define TEGRA186_CLK_GPCCLK 310 | ||
822 | /** @brief output of divider CLK_RST_CONTROLLER_AON_NIC_RATE */ | ||
823 | #define TEGRA186_CLK_AON_NIC 450 | ||
824 | /** @brief output of divider CLK_RST_CONTROLLER_SCE_NIC_RATE */ | ||
825 | #define TEGRA186_CLK_SCE_NIC 451 | ||
826 | /** Fixed 100MHz PLL for PCIe, SATA and superspeed USB */ | ||
827 | #define TEGRA186_CLK_PLLE 512 | ||
828 | /** @brief PLL controlled by CLK_RST_CONTROLLER_PLLC_BASE */ | ||
829 | #define TEGRA186_CLK_PLLC 513 | ||
830 | /** Fixed 408MHz PLL for use by peripheral clocks */ | ||
831 | #define TEGRA186_CLK_PLLP 516 | ||
832 | /** @deprecated */ | ||
833 | #define TEGRA186_CLK_PLL_P TEGRA186_CLK_PLLP | ||
834 | /** @brief PLL controlled by CLK_RST_CONTROLLER_PLLD_BASE for use by DSI */ | ||
835 | #define TEGRA186_CLK_PLLD 518 | ||
836 | /** @brief PLL controlled by CLK_RST_CONTROLLER_PLLD2_BASE for use by HDMI or DP */ | ||
837 | #define TEGRA186_CLK_PLLD2 519 | ||
838 | /** | ||
839 | * @brief PLL controlled by CLK_RST_CONTROLLER_PLLREFE_BASE. | ||
840 | * @details Note that this clock only controls the VCO output, before | ||
841 | * the post-divider. See TEGRA186_CLK_PLLREFE_OUT1 for more | ||
842 | * information. | ||
843 | */ | ||
844 | #define TEGRA186_CLK_PLLREFE_VCO 520 | ||
845 | /** @brief PLL controlled by CLK_RST_CONTROLLER_PLLC2_BASE */ | ||
846 | #define TEGRA186_CLK_PLLC2 521 | ||
847 | /** @brief PLL controlled by CLK_RST_CONTROLLER_PLLC3_BASE */ | ||
848 | #define TEGRA186_CLK_PLLC3 522 | ||
849 | /** @brief PLL controlled by CLK_RST_CONTROLLER_PLLDP_BASE for use as the DP link clock */ | ||
850 | #define TEGRA186_CLK_PLLDP 523 | ||
851 | /** @brief PLL controlled by CLK_RST_CONTROLLER_PLLC4_BASE */ | ||
852 | #define TEGRA186_CLK_PLLC4_VCO 524 | ||
853 | /** @brief PLL controlled by CLK_RST_CONTROLLER_PLLA1_BASE for use by audio clocks */ | ||
854 | #define TEGRA186_CLK_PLLA1 525 | ||
855 | /** @brief PLL controlled by CLK_RST_CONTROLLER_PLLNVCSI_BASE */ | ||
856 | #define TEGRA186_CLK_PLLNVCSI 526 | ||
857 | /** @brief PLL controlled by CLK_RST_CONTROLLER_PLLDISPHUB_BASE */ | ||
858 | #define TEGRA186_CLK_PLLDISPHUB 527 | ||
859 | /** @brief PLL controlled by CLK_RST_CONTROLLER_PLLD3_BASE for use by HDMI or DP */ | ||
860 | #define TEGRA186_CLK_PLLD3 528 | ||
861 | /** @brief PLL controlled by CLK_RST_CONTROLLER_PLLBPMPCAM_BASE */ | ||
862 | #define TEGRA186_CLK_PLLBPMPCAM 531 | ||
863 | /** @brief PLL controlled by CLK_RST_CONTROLLER_PLLAON_BASE for use by IP blocks in the AON domain */ | ||
864 | #define TEGRA186_CLK_PLLAON 532 | ||
865 | /** Fixed frequency 960MHz PLL for USB and EAVB */ | ||
866 | #define TEGRA186_CLK_PLLU 533 | ||
867 | /** fixed /2 divider. Output frequency is TEGRA186_CLK_PLLC4_VCO/2 */ | ||
868 | #define TEGRA186_CLK_PLLC4_VCO_DIV2 535 | ||
869 | /** @brief NAFLL clock source for AXI_CBB */ | ||
870 | #define TEGRA186_CLK_NAFLL_AXI_CBB 564 | ||
871 | /** @brief NAFLL clock source for BPMP */ | ||
872 | #define TEGRA186_CLK_NAFLL_BPMP 565 | ||
873 | /** @brief NAFLL clock source for ISP */ | ||
874 | #define TEGRA186_CLK_NAFLL_ISP 566 | ||
875 | /** @brief NAFLL clock source for NVDEC */ | ||
876 | #define TEGRA186_CLK_NAFLL_NVDEC 567 | ||
877 | /** @brief NAFLL clock source for NVENC */ | ||
878 | #define TEGRA186_CLK_NAFLL_NVENC 568 | ||
879 | /** @brief NAFLL clock source for NVJPG */ | ||
880 | #define TEGRA186_CLK_NAFLL_NVJPG 569 | ||
881 | /** @brief NAFLL clock source for SCE */ | ||
882 | #define TEGRA186_CLK_NAFLL_SCE 570 | ||
883 | /** @brief NAFLL clock source for SE */ | ||
884 | #define TEGRA186_CLK_NAFLL_SE 571 | ||
885 | /** @brief NAFLL clock source for TSEC */ | ||
886 | #define TEGRA186_CLK_NAFLL_TSEC 572 | ||
887 | /** @brief NAFLL clock source for TSECB */ | ||
888 | #define TEGRA186_CLK_NAFLL_TSECB 573 | ||
889 | /** @brief NAFLL clock source for VI */ | ||
890 | #define TEGRA186_CLK_NAFLL_VI 574 | ||
891 | /** @brief NAFLL clock source for VIC */ | ||
892 | #define TEGRA186_CLK_NAFLL_VIC 575 | ||
893 | /** @brief NAFLL clock source for DISP */ | ||
894 | #define TEGRA186_CLK_NAFLL_DISP 576 | ||
895 | /** @brief NAFLL clock source for GPU */ | ||
896 | #define TEGRA186_CLK_NAFLL_GPU 577 | ||
897 | /** @brief NAFLL clock source for M-CPU cluster */ | ||
898 | #define TEGRA186_CLK_NAFLL_MCPU 578 | ||
899 | /** @brief NAFLL clock source for B-CPU cluster */ | ||
900 | #define TEGRA186_CLK_NAFLL_BCPU 579 | ||
901 | /** @brief input from Tegra's CLK_32K_IN pad */ | ||
902 | #define TEGRA186_CLK_CLK_32K 608 | ||
903 | /** @brief output of divider CLK_RST_CONTROLLER_CLK_M_DIVIDE */ | ||
904 | #define TEGRA186_CLK_CLK_M 609 | ||
905 | /** @brief output of divider PLL_REF_DIV in CLK_RST_CONTROLLER_OSC_CTRL */ | ||
906 | #define TEGRA186_CLK_PLL_REF 610 | ||
907 | /** @brief input from Tegra's XTAL_IN */ | ||
908 | #define TEGRA186_CLK_OSC 612 | ||
909 | /** @brief clock recovered from EAVB input */ | ||
910 | #define TEGRA186_CLK_EQOS_RX_INPUT 613 | ||
911 | /** @brief clock recovered from DTV input */ | ||
912 | #define TEGRA186_CLK_DTV_INPUT 614 | ||
913 | /** @brief SOR0 brick output which feeds into SOR0_CLK_SEL mux in CLK_RST_CONTROLLER_CLK_SOURCE_SOR0*/ | ||
914 | #define TEGRA186_CLK_SOR0_PAD_CLKOUT 615 | ||
915 | /** @brief SOR1 brick output which feeds into SOR1_CLK_SEL mux in CLK_RST_CONTROLLER_CLK_SOURCE_SOR1*/ | ||
916 | #define TEGRA186_CLK_SOR1_PAD_CLKOUT 616 | ||
917 | /** @brief clock recovered from I2S1 input */ | ||
918 | #define TEGRA186_CLK_I2S1_SYNC_INPUT 617 | ||
919 | /** @brief clock recovered from I2S2 input */ | ||
920 | #define TEGRA186_CLK_I2S2_SYNC_INPUT 618 | ||
921 | /** @brief clock recovered from I2S3 input */ | ||
922 | #define TEGRA186_CLK_I2S3_SYNC_INPUT 619 | ||
923 | /** @brief clock recovered from I2S4 input */ | ||
924 | #define TEGRA186_CLK_I2S4_SYNC_INPUT 620 | ||
925 | /** @brief clock recovered from I2S5 input */ | ||
926 | #define TEGRA186_CLK_I2S5_SYNC_INPUT 621 | ||
927 | /** @brief clock recovered from I2S6 input */ | ||
928 | #define TEGRA186_CLK_I2S6_SYNC_INPUT 622 | ||
929 | /** @brief clock recovered from SPDIFIN input */ | ||
930 | #define TEGRA186_CLK_SPDIFIN_SYNC_INPUT 623 | ||
931 | |||
932 | /** | ||
933 | * @brief subject to change | ||
934 | * @details maximum clock identifier value plus one. | ||
935 | */ | ||
936 | #define TEGRA186_CLK_CLK_MAX 624 | ||
937 | |||
938 | /** @} */ | ||
939 | |||
940 | #endif | ||
diff --git a/include/dt-bindings/mailbox/tegra186-hsp.h b/include/dt-bindings/mailbox/tegra186-hsp.h new file mode 100644 index 000000000000..f5d66e5f5f10 --- /dev/null +++ b/include/dt-bindings/mailbox/tegra186-hsp.h | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * This header provides constants for binding nvidia,tegra186-hsp. | ||
3 | */ | ||
4 | |||
5 | #ifndef _DT_BINDINGS_MAILBOX_TEGRA186_HSP_H | ||
6 | #define _DT_BINDINGS_MAILBOX_TEGRA186_HSP_H | ||
7 | |||
8 | /* | ||
9 | * These define the type of mailbox that is to be used (doorbell, shared | ||
10 | * mailbox, shared semaphore or arbitrated semaphore). | ||
11 | */ | ||
12 | #define TEGRA_HSP_MBOX_TYPE_DB 0x0 | ||
13 | #define TEGRA_HSP_MBOX_TYPE_SM 0x1 | ||
14 | #define TEGRA_HSP_MBOX_TYPE_SS 0x2 | ||
15 | #define TEGRA_HSP_MBOX_TYPE_AS 0x3 | ||
16 | |||
17 | /* | ||
18 | * These defines represent the bit associated with the given master ID in the | ||
19 | * doorbell registers. | ||
20 | */ | ||
21 | #define TEGRA_HSP_DB_MASTER_CCPLEX 17 | ||
22 | #define TEGRA_HSP_DB_MASTER_BPMP 19 | ||
23 | |||
24 | #endif | ||
diff --git a/include/dt-bindings/power/tegra186-powergate.h b/include/dt-bindings/power/tegra186-powergate.h new file mode 100644 index 000000000000..388d6e228dc8 --- /dev/null +++ b/include/dt-bindings/power/tegra186-powergate.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #ifndef _DT_BINDINGS_POWER_TEGRA186_POWERGATE_H | ||
18 | #define _DT_BINDINGS_POWER_TEGRA186_POWERGATE_H | ||
19 | |||
20 | #define TEGRA186_POWER_DOMAIN_AUD 0 | ||
21 | #define TEGRA186_POWER_DOMAIN_DFD 1 | ||
22 | #define TEGRA186_POWER_DOMAIN_DISP 2 | ||
23 | #define TEGRA186_POWER_DOMAIN_DISPB 3 | ||
24 | #define TEGRA186_POWER_DOMAIN_DISPC 4 | ||
25 | #define TEGRA186_POWER_DOMAIN_ISPA 5 | ||
26 | #define TEGRA186_POWER_DOMAIN_NVDEC 6 | ||
27 | #define TEGRA186_POWER_DOMAIN_NVJPG 7 | ||
28 | #define TEGRA186_POWER_DOMAIN_MPE 8 | ||
29 | #define TEGRA186_POWER_DOMAIN_PCX 9 | ||
30 | #define TEGRA186_POWER_DOMAIN_SAX 10 | ||
31 | #define TEGRA186_POWER_DOMAIN_VE 11 | ||
32 | #define TEGRA186_POWER_DOMAIN_VIC 12 | ||
33 | #define TEGRA186_POWER_DOMAIN_XUSBA 13 | ||
34 | #define TEGRA186_POWER_DOMAIN_XUSBB 14 | ||
35 | #define TEGRA186_POWER_DOMAIN_XUSBC 15 | ||
36 | #define TEGRA186_POWER_DOMAIN_GPU 43 | ||
37 | #define TEGRA186_POWER_DOMAIN_MAX 44 | ||
38 | |||
39 | #endif | ||
diff --git a/include/dt-bindings/reset/tegra186-reset.h b/include/dt-bindings/reset/tegra186-reset.h new file mode 100644 index 000000000000..8a184e357955 --- /dev/null +++ b/include/dt-bindings/reset/tegra186-reset.h | |||
@@ -0,0 +1,217 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #ifndef _ABI_MACH_T186_RESET_T186_H_ | ||
18 | #define _ABI_MACH_T186_RESET_T186_H_ | ||
19 | |||
20 | |||
21 | #define TEGRA186_RESET_ACTMON 0 | ||
22 | #define TEGRA186_RESET_AFI 1 | ||
23 | #define TEGRA186_RESET_CEC 2 | ||
24 | #define TEGRA186_RESET_CSITE 3 | ||
25 | #define TEGRA186_RESET_DP2 4 | ||
26 | #define TEGRA186_RESET_DPAUX 5 | ||
27 | #define TEGRA186_RESET_DSI 6 | ||
28 | #define TEGRA186_RESET_DSIB 7 | ||
29 | #define TEGRA186_RESET_DTV 8 | ||
30 | #define TEGRA186_RESET_DVFS 9 | ||
31 | #define TEGRA186_RESET_ENTROPY 10 | ||
32 | #define TEGRA186_RESET_EXTPERIPH1 11 | ||
33 | #define TEGRA186_RESET_EXTPERIPH2 12 | ||
34 | #define TEGRA186_RESET_EXTPERIPH3 13 | ||
35 | #define TEGRA186_RESET_GPU 14 | ||
36 | #define TEGRA186_RESET_HDA 15 | ||
37 | #define TEGRA186_RESET_HDA2CODEC_2X 16 | ||
38 | #define TEGRA186_RESET_HDA2HDMICODEC 17 | ||
39 | #define TEGRA186_RESET_HOST1X 18 | ||
40 | #define TEGRA186_RESET_I2C1 19 | ||
41 | #define TEGRA186_RESET_I2C2 20 | ||
42 | #define TEGRA186_RESET_I2C3 21 | ||
43 | #define TEGRA186_RESET_I2C4 22 | ||
44 | #define TEGRA186_RESET_I2C5 23 | ||
45 | #define TEGRA186_RESET_I2C6 24 | ||
46 | #define TEGRA186_RESET_ISP 25 | ||
47 | #define TEGRA186_RESET_KFUSE 26 | ||
48 | #define TEGRA186_RESET_LA 27 | ||
49 | #define TEGRA186_RESET_MIPI_CAL 28 | ||
50 | #define TEGRA186_RESET_PCIE 29 | ||
51 | #define TEGRA186_RESET_PCIEXCLK 30 | ||
52 | #define TEGRA186_RESET_SATA 31 | ||
53 | #define TEGRA186_RESET_SATACOLD 32 | ||
54 | #define TEGRA186_RESET_SDMMC1 33 | ||
55 | #define TEGRA186_RESET_SDMMC2 34 | ||
56 | #define TEGRA186_RESET_SDMMC3 35 | ||
57 | #define TEGRA186_RESET_SDMMC4 36 | ||
58 | #define TEGRA186_RESET_SE 37 | ||
59 | #define TEGRA186_RESET_SOC_THERM 38 | ||
60 | #define TEGRA186_RESET_SOR0 39 | ||
61 | #define TEGRA186_RESET_SPI1 40 | ||
62 | #define TEGRA186_RESET_SPI2 41 | ||
63 | #define TEGRA186_RESET_SPI3 42 | ||
64 | #define TEGRA186_RESET_SPI4 43 | ||
65 | #define TEGRA186_RESET_TMR 44 | ||
66 | #define TEGRA186_RESET_TRIG_SYS 45 | ||
67 | #define TEGRA186_RESET_TSEC 46 | ||
68 | #define TEGRA186_RESET_UARTA 47 | ||
69 | #define TEGRA186_RESET_UARTB 48 | ||
70 | #define TEGRA186_RESET_UARTC 49 | ||
71 | #define TEGRA186_RESET_UARTD 50 | ||
72 | #define TEGRA186_RESET_VI 51 | ||
73 | #define TEGRA186_RESET_VIC 52 | ||
74 | #define TEGRA186_RESET_XUSB_DEV 53 | ||
75 | #define TEGRA186_RESET_XUSB_HOST 54 | ||
76 | #define TEGRA186_RESET_XUSB_PADCTL 55 | ||
77 | #define TEGRA186_RESET_XUSB_SS 56 | ||
78 | #define TEGRA186_RESET_AON_APB 57 | ||
79 | #define TEGRA186_RESET_AXI_CBB 58 | ||
80 | #define TEGRA186_RESET_BPMP_APB 59 | ||
81 | #define TEGRA186_RESET_CAN1 60 | ||
82 | #define TEGRA186_RESET_CAN2 61 | ||
83 | #define TEGRA186_RESET_DMIC5 62 | ||
84 | #define TEGRA186_RESET_DSIC 63 | ||
85 | #define TEGRA186_RESET_DSID 64 | ||
86 | #define TEGRA186_RESET_EMC_EMC 65 | ||
87 | #define TEGRA186_RESET_EMC_MEM 66 | ||
88 | #define TEGRA186_RESET_EMCSB_EMC 67 | ||
89 | #define TEGRA186_RESET_EMCSB_MEM 68 | ||
90 | #define TEGRA186_RESET_EQOS 69 | ||
91 | #define TEGRA186_RESET_GPCDMA 70 | ||
92 | #define TEGRA186_RESET_GPIO_CTL0 71 | ||
93 | #define TEGRA186_RESET_GPIO_CTL1 72 | ||
94 | #define TEGRA186_RESET_GPIO_CTL2 73 | ||
95 | #define TEGRA186_RESET_GPIO_CTL3 74 | ||
96 | #define TEGRA186_RESET_GPIO_CTL4 75 | ||
97 | #define TEGRA186_RESET_GPIO_CTL5 76 | ||
98 | #define TEGRA186_RESET_I2C10 77 | ||
99 | #define TEGRA186_RESET_I2C12 78 | ||
100 | #define TEGRA186_RESET_I2C13 79 | ||
101 | #define TEGRA186_RESET_I2C14 80 | ||
102 | #define TEGRA186_RESET_I2C7 81 | ||
103 | #define TEGRA186_RESET_I2C8 82 | ||
104 | #define TEGRA186_RESET_I2C9 83 | ||
105 | #define TEGRA186_RESET_JTAG2AXI 84 | ||
106 | #define TEGRA186_RESET_MPHY_IOBIST 85 | ||
107 | #define TEGRA186_RESET_MPHY_L0_RX 86 | ||
108 | #define TEGRA186_RESET_MPHY_L0_TX 87 | ||
109 | #define TEGRA186_RESET_NVCSI 88 | ||
110 | #define TEGRA186_RESET_NVDISPLAY0_HEAD0 89 | ||
111 | #define TEGRA186_RESET_NVDISPLAY0_HEAD1 90 | ||
112 | #define TEGRA186_RESET_NVDISPLAY0_HEAD2 91 | ||
113 | #define TEGRA186_RESET_NVDISPLAY0_MISC 92 | ||
114 | #define TEGRA186_RESET_NVDISPLAY0_WGRP0 93 | ||
115 | #define TEGRA186_RESET_NVDISPLAY0_WGRP1 94 | ||
116 | #define TEGRA186_RESET_NVDISPLAY0_WGRP2 95 | ||
117 | #define TEGRA186_RESET_NVDISPLAY0_WGRP3 96 | ||
118 | #define TEGRA186_RESET_NVDISPLAY0_WGRP4 97 | ||
119 | #define TEGRA186_RESET_NVDISPLAY0_WGRP5 98 | ||
120 | #define TEGRA186_RESET_PWM1 99 | ||
121 | #define TEGRA186_RESET_PWM2 100 | ||
122 | #define TEGRA186_RESET_PWM3 101 | ||
123 | #define TEGRA186_RESET_PWM4 102 | ||
124 | #define TEGRA186_RESET_PWM5 103 | ||
125 | #define TEGRA186_RESET_PWM6 104 | ||
126 | #define TEGRA186_RESET_PWM7 105 | ||
127 | #define TEGRA186_RESET_PWM8 106 | ||
128 | #define TEGRA186_RESET_SCE_APB 107 | ||
129 | #define TEGRA186_RESET_SOR1 108 | ||
130 | #define TEGRA186_RESET_TACH 109 | ||
131 | #define TEGRA186_RESET_TSC 110 | ||
132 | #define TEGRA186_RESET_UARTF 111 | ||
133 | #define TEGRA186_RESET_UARTG 112 | ||
134 | #define TEGRA186_RESET_UFSHC 113 | ||
135 | #define TEGRA186_RESET_UFSHC_AXI_M 114 | ||
136 | #define TEGRA186_RESET_UPHY 115 | ||
137 | #define TEGRA186_RESET_ADSP 116 | ||
138 | #define TEGRA186_RESET_ADSPDBG 117 | ||
139 | #define TEGRA186_RESET_ADSPINTF 118 | ||
140 | #define TEGRA186_RESET_ADSPNEON 119 | ||
141 | #define TEGRA186_RESET_ADSPPERIPH 120 | ||
142 | #define TEGRA186_RESET_ADSPSCU 121 | ||
143 | #define TEGRA186_RESET_ADSPWDT 122 | ||
144 | #define TEGRA186_RESET_APE 123 | ||
145 | #define TEGRA186_RESET_DPAUX1 124 | ||
146 | #define TEGRA186_RESET_NVDEC 125 | ||
147 | #define TEGRA186_RESET_NVENC 126 | ||
148 | #define TEGRA186_RESET_NVJPG 127 | ||
149 | #define TEGRA186_RESET_PEX_USB_UPHY 128 | ||
150 | #define TEGRA186_RESET_QSPI 129 | ||
151 | #define TEGRA186_RESET_TSECB 130 | ||
152 | #define TEGRA186_RESET_VI_I2C 131 | ||
153 | #define TEGRA186_RESET_UARTE 132 | ||
154 | #define TEGRA186_RESET_TOP_GTE 133 | ||
155 | #define TEGRA186_RESET_SHSP 134 | ||
156 | #define TEGRA186_RESET_PEX_USB_UPHY_L5 135 | ||
157 | #define TEGRA186_RESET_PEX_USB_UPHY_L4 136 | ||
158 | #define TEGRA186_RESET_PEX_USB_UPHY_L3 137 | ||
159 | #define TEGRA186_RESET_PEX_USB_UPHY_L2 138 | ||
160 | #define TEGRA186_RESET_PEX_USB_UPHY_L1 139 | ||
161 | #define TEGRA186_RESET_PEX_USB_UPHY_L0 140 | ||
162 | #define TEGRA186_RESET_PEX_USB_UPHY_PLL1 141 | ||
163 | #define TEGRA186_RESET_PEX_USB_UPHY_PLL0 142 | ||
164 | #define TEGRA186_RESET_TSCTNVI 143 | ||
165 | #define TEGRA186_RESET_EXTPERIPH4 144 | ||
166 | #define TEGRA186_RESET_DSIPADCTL 145 | ||
167 | #define TEGRA186_RESET_AUD_MCLK 146 | ||
168 | #define TEGRA186_RESET_MPHY_CLK_CTL 147 | ||
169 | #define TEGRA186_RESET_MPHY_L1_RX 148 | ||
170 | #define TEGRA186_RESET_MPHY_L1_TX 149 | ||
171 | #define TEGRA186_RESET_UFSHC_LP 150 | ||
172 | #define TEGRA186_RESET_BPMP_NIC 151 | ||
173 | #define TEGRA186_RESET_BPMP_NSYSPORESET 152 | ||
174 | #define TEGRA186_RESET_BPMP_NRESET 153 | ||
175 | #define TEGRA186_RESET_BPMP_DBGRESETN 154 | ||
176 | #define TEGRA186_RESET_BPMP_PRESETDBGN 155 | ||
177 | #define TEGRA186_RESET_BPMP_PM 156 | ||
178 | #define TEGRA186_RESET_BPMP_CVC 157 | ||
179 | #define TEGRA186_RESET_BPMP_DMA 158 | ||
180 | #define TEGRA186_RESET_BPMP_HSP 159 | ||
181 | #define TEGRA186_RESET_TSCTNBPMP 160 | ||
182 | #define TEGRA186_RESET_BPMP_TKE 161 | ||
183 | #define TEGRA186_RESET_BPMP_GTE 162 | ||
184 | #define TEGRA186_RESET_BPMP_PM_ACTMON 163 | ||
185 | #define TEGRA186_RESET_AON_NIC 164 | ||
186 | #define TEGRA186_RESET_AON_NSYSPORESET 165 | ||
187 | #define TEGRA186_RESET_AON_NRESET 166 | ||
188 | #define TEGRA186_RESET_AON_DBGRESETN 167 | ||
189 | #define TEGRA186_RESET_AON_PRESETDBGN 168 | ||
190 | #define TEGRA186_RESET_AON_ACTMON 169 | ||
191 | #define TEGRA186_RESET_AOPM 170 | ||
192 | #define TEGRA186_RESET_AOVC 171 | ||
193 | #define TEGRA186_RESET_AON_DMA 172 | ||
194 | #define TEGRA186_RESET_AON_GPIO 173 | ||
195 | #define TEGRA186_RESET_AON_HSP 174 | ||
196 | #define TEGRA186_RESET_TSCTNAON 175 | ||
197 | #define TEGRA186_RESET_AON_TKE 176 | ||
198 | #define TEGRA186_RESET_AON_GTE 177 | ||
199 | #define TEGRA186_RESET_SCE_NIC 178 | ||
200 | #define TEGRA186_RESET_SCE_NSYSPORESET 179 | ||
201 | #define TEGRA186_RESET_SCE_NRESET 180 | ||
202 | #define TEGRA186_RESET_SCE_DBGRESETN 181 | ||
203 | #define TEGRA186_RESET_SCE_PRESETDBGN 182 | ||
204 | #define TEGRA186_RESET_SCE_ACTMON 183 | ||
205 | #define TEGRA186_RESET_SCE_PM 184 | ||
206 | #define TEGRA186_RESET_SCE_DMA 185 | ||
207 | #define TEGRA186_RESET_SCE_HSP 186 | ||
208 | #define TEGRA186_RESET_TSCTNSCE 187 | ||
209 | #define TEGRA186_RESET_SCE_TKE 188 | ||
210 | #define TEGRA186_RESET_SCE_GTE 189 | ||
211 | #define TEGRA186_RESET_SCE_CFG 190 | ||
212 | #define TEGRA186_RESET_ADSP_ALL 191 | ||
213 | /** @brief controls the power up/down sequence of UFSHC PSW partition. Controls LP_PWR_READY, LP_ISOL_EN, and LP_RESET_N signals */ | ||
214 | #define TEGRA186_RESET_UFSHC_LP_SEQ 192 | ||
215 | #define TEGRA186_RESET_SIZE 193 | ||
216 | |||
217 | #endif | ||
diff --git a/include/soc/tegra/bpmp-abi.h b/include/soc/tegra/bpmp-abi.h new file mode 100644 index 000000000000..0aaef5960e29 --- /dev/null +++ b/include/soc/tegra/bpmp-abi.h | |||
@@ -0,0 +1,1601 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #ifndef _ABI_BPMP_ABI_H_ | ||
18 | #define _ABI_BPMP_ABI_H_ | ||
19 | |||
20 | #ifdef LK | ||
21 | #include <stdint.h> | ||
22 | #endif | ||
23 | |||
24 | #ifndef __ABI_PACKED | ||
25 | #define __ABI_PACKED __attribute__((packed)) | ||
26 | #endif | ||
27 | |||
28 | #ifdef NO_GCC_EXTENSIONS | ||
29 | #define EMPTY char empty; | ||
30 | #define EMPTY_ARRAY 1 | ||
31 | #else | ||
32 | #define EMPTY | ||
33 | #define EMPTY_ARRAY 0 | ||
34 | #endif | ||
35 | |||
36 | #ifndef __UNION_ANON | ||
37 | #define __UNION_ANON | ||
38 | #endif | ||
39 | /** | ||
40 | * @file | ||
41 | */ | ||
42 | |||
43 | |||
44 | /** | ||
45 | * @defgroup MRQ MRQ Messages | ||
46 | * @brief Messages sent to/from BPMP via IPC | ||
47 | * @{ | ||
48 | * @defgroup MRQ_Format Message Format | ||
49 | * @defgroup MRQ_Codes Message Request (MRQ) Codes | ||
50 | * @defgroup MRQ_Payloads Message Payloads | ||
51 | * @defgroup Error_Codes Error Codes | ||
52 | * @} | ||
53 | */ | ||
54 | |||
55 | /** | ||
56 | * @addtogroup MRQ_Format Message Format | ||
57 | * @{ | ||
58 | * The CPU requests the BPMP to perform a particular service by | ||
59 | * sending it an IVC frame containing a single MRQ message. An MRQ | ||
60 | * message consists of a @ref mrq_request followed by a payload whose | ||
61 | * format depends on mrq_request::mrq. | ||
62 | * | ||
63 | * The BPMP processes the data and replies with an IVC frame (on the | ||
64 | * same IVC channel) containing and MRQ response. An MRQ response | ||
65 | * consists of a @ref mrq_response followed by a payload whose format | ||
66 | * depends on the associated mrq_request::mrq. | ||
67 | * | ||
68 | * A well-defined subset of the MRQ messages that the CPU sends to the | ||
69 | * BPMP can lead to BPMP eventually sending an MRQ message to the | ||
70 | * CPU. For example, when the CPU uses an #MRQ_THERMAL message to set | ||
71 | * a thermal trip point, the BPMP may eventually send a single | ||
72 | * #MRQ_THERMAL message of its own to the CPU indicating that the trip | ||
73 | * point has been crossed. | ||
74 | * @} | ||
75 | */ | ||
76 | |||
77 | /** | ||
78 | * @ingroup MRQ_Format | ||
79 | * @brief header for an MRQ message | ||
80 | * | ||
81 | * Provides the MRQ number for the MRQ message: #mrq. The remainder of | ||
82 | * the MRQ message is a payload (immediately following the | ||
83 | * mrq_request) whose format depends on mrq. | ||
84 | * | ||
85 | * @todo document the flags | ||
86 | */ | ||
87 | struct mrq_request { | ||
88 | /** @brief MRQ number of the request */ | ||
89 | uint32_t mrq; | ||
90 | /** @brief flags for the request */ | ||
91 | uint32_t flags; | ||
92 | } __ABI_PACKED; | ||
93 | |||
94 | /** | ||
95 | * @ingroup MRQ_Format | ||
96 | * @brief header for an MRQ response | ||
97 | * | ||
98 | * Provides an error code for the associated MRQ message. The | ||
99 | * remainder of the MRQ response is a payload (immediately following | ||
100 | * the mrq_response) whose format depends on the associated | ||
101 | * mrq_request::mrq | ||
102 | * | ||
103 | * @todo document the flags | ||
104 | */ | ||
105 | struct mrq_response { | ||
106 | /** @brief error code for the MRQ request itself */ | ||
107 | int32_t err; | ||
108 | /** @brief flags for the response */ | ||
109 | uint32_t flags; | ||
110 | } __ABI_PACKED; | ||
111 | |||
112 | /** | ||
113 | * @ingroup MRQ_Format | ||
114 | * Minimum needed size for an IPC message buffer | ||
115 | */ | ||
116 | #define MSG_MIN_SZ 128 | ||
117 | /** | ||
118 | * @ingroup MRQ_Format | ||
119 | * Minimum size guaranteed for data in an IPC message buffer | ||
120 | */ | ||
121 | #define MSG_DATA_MIN_SZ 120 | ||
122 | |||
123 | /** | ||
124 | * @ingroup MRQ_Codes | ||
125 | * @name Legal MRQ codes | ||
126 | * These are the legal values for mrq_request::mrq | ||
127 | * @{ | ||
128 | */ | ||
129 | |||
130 | #define MRQ_PING 0 | ||
131 | #define MRQ_QUERY_TAG 1 | ||
132 | #define MRQ_MODULE_LOAD 4 | ||
133 | #define MRQ_MODULE_UNLOAD 5 | ||
134 | #define MRQ_TRACE_MODIFY 7 | ||
135 | #define MRQ_WRITE_TRACE 8 | ||
136 | #define MRQ_THREADED_PING 9 | ||
137 | #define MRQ_MODULE_MAIL 11 | ||
138 | #define MRQ_DEBUGFS 19 | ||
139 | #define MRQ_RESET 20 | ||
140 | #define MRQ_I2C 21 | ||
141 | #define MRQ_CLK 22 | ||
142 | #define MRQ_QUERY_ABI 23 | ||
143 | #define MRQ_PG_READ_STATE 25 | ||
144 | #define MRQ_PG_UPDATE_STATE 26 | ||
145 | #define MRQ_THERMAL 27 | ||
146 | #define MRQ_CPU_VHINT 28 | ||
147 | #define MRQ_ABI_RATCHET 29 | ||
148 | #define MRQ_EMC_DVFS_LATENCY 31 | ||
149 | #define MRQ_TRACE_ITER 64 | ||
150 | |||
151 | /** @} */ | ||
152 | |||
153 | /** | ||
154 | * @ingroup MRQ_Codes | ||
155 | * @brief Maximum MRQ code to be sent by CPU software to | ||
156 | * BPMP. Subject to change in future | ||
157 | */ | ||
158 | #define MAX_CPU_MRQ_ID 64 | ||
159 | |||
160 | /** | ||
161 | * @addtogroup MRQ_Payloads Message Payloads | ||
162 | * @{ | ||
163 | * @defgroup Ping | ||
164 | * @defgroup Query_Tag Query Tag | ||
165 | * @defgroup Module Loadable Modules | ||
166 | * @defgroup Trace | ||
167 | * @defgroup Debugfs | ||
168 | * @defgroup Reset | ||
169 | * @defgroup I2C | ||
170 | * @defgroup Clocks | ||
171 | * @defgroup ABI_info ABI Info | ||
172 | * @defgroup MC_Flush MC Flush | ||
173 | * @defgroup Powergating | ||
174 | * @defgroup Thermal | ||
175 | * @defgroup Vhint CPU Voltage hint | ||
176 | * @defgroup MRQ_Deprecated Deprecated MRQ messages | ||
177 | * @defgroup EMC | ||
178 | * @} | ||
179 | */ | ||
180 | |||
181 | |||
182 | /** | ||
183 | * @ingroup MRQ_Codes | ||
184 | * @def MRQ_PING | ||
185 | * @brief A simple ping | ||
186 | * | ||
187 | * * Platforms: All | ||
188 | * * Initiators: Any | ||
189 | * * Targets: Any | ||
190 | * * Request Payload: @ref mrq_ping_request | ||
191 | * * Response Payload: @ref mrq_ping_response | ||
192 | * | ||
193 | * @ingroup MRQ_Codes | ||
194 | * @def MRQ_THREADED_PING | ||
195 | * @brief A deeper ping | ||
196 | * | ||
197 | * * Platforms: All | ||
198 | * * Initiators: Any | ||
199 | * * Targets: BPMP | ||
200 | * * Request Payload: @ref mrq_ping_request | ||
201 | * * Response Payload: @ref mrq_ping_response | ||
202 | * | ||
203 | * Behavior is equivalent to a simple #MRQ_PING except that BPMP | ||
204 | * responds from a thread context (providing a slightly more robust | ||
205 | * sign of life). | ||
206 | * | ||
207 | */ | ||
208 | |||
209 | /** | ||
210 | * @ingroup Ping | ||
211 | * @brief request with #MRQ_PING | ||
212 | * | ||
213 | * Used by the sender of an #MRQ_PING message to request a pong from | ||
214 | * recipient. The response from the recipient is computed based on | ||
215 | * #challenge. | ||
216 | */ | ||
217 | struct mrq_ping_request { | ||
218 | /** @brief arbitrarily chosen value */ | ||
219 | uint32_t challenge; | ||
220 | } __ABI_PACKED; | ||
221 | |||
222 | /** | ||
223 | * @ingroup Ping | ||
224 | * @brief response to #MRQ_PING | ||
225 | * | ||
226 | * Sent in response to an #MRQ_PING message. #reply should be the | ||
227 | * mrq_ping_request challenge left shifted by 1 with the carry-bit | ||
228 | * dropped. | ||
229 | * | ||
230 | */ | ||
231 | struct mrq_ping_response { | ||
232 | /** @brief response to the MRQ_PING challege */ | ||
233 | uint32_t reply; | ||
234 | } __ABI_PACKED; | ||
235 | |||
236 | /** | ||
237 | * @ingroup MRQ_Codes | ||
238 | * @def MRQ_QUERY_TAG | ||
239 | * @brief Query BPMP firmware's tag (i.e. version information) | ||
240 | * | ||
241 | * * Platforms: All | ||
242 | * * Initiators: CCPLEX | ||
243 | * * Targets: BPMP | ||
244 | * * Request Payload: @ref mrq_query_tag_request | ||
245 | * * Response Payload: N/A | ||
246 | * | ||
247 | */ | ||
248 | |||
249 | /** | ||
250 | * @ingroup Query_Tag | ||
251 | * @brief request with #MRQ_QUERY_TAG | ||
252 | * | ||
253 | * Used by #MRQ_QUERY_TAG call to ask BPMP to fill in the memory | ||
254 | * pointed by #addr with BPMP firmware header. | ||
255 | * | ||
256 | * The sender is reponsible for ensuring that #addr is mapped in to | ||
257 | * the recipient's address map. | ||
258 | */ | ||
259 | struct mrq_query_tag_request { | ||
260 | /** @brief base address to store the firmware header */ | ||
261 | uint32_t addr; | ||
262 | } __ABI_PACKED; | ||
263 | |||
264 | /** | ||
265 | * @ingroup MRQ_Codes | ||
266 | * @def MRQ_MODULE_LOAD | ||
267 | * @brief dynamically load a BPMP code module | ||
268 | * | ||
269 | * * Platforms: All | ||
270 | * * Initiators: CCPLEX | ||
271 | * * Targets: BPMP | ||
272 | * * Request Payload: @ref mrq_module_load_request | ||
273 | * * Response Payload: @ref mrq_module_load_response | ||
274 | * | ||
275 | * @note This MRQ is disabled on production systems | ||
276 | * | ||
277 | */ | ||
278 | |||
279 | /** | ||
280 | * @ingroup Module | ||
281 | * @brief request with #MRQ_MODULE_LOAD | ||
282 | * | ||
283 | * Used by #MRQ_MODULE_LOAD calls to ask the recipient to dynamically | ||
284 | * load the code located at #phys_addr and having size #size | ||
285 | * bytes. #phys_addr is treated as a void pointer. | ||
286 | * | ||
287 | * The recipient copies the code from #phys_addr to locally allocated | ||
288 | * memory prior to responding to this message. | ||
289 | * | ||
290 | * @todo document the module header format | ||
291 | * | ||
292 | * The sender is responsible for ensuring that the code is mapped in | ||
293 | * the recipient's address map. | ||
294 | * | ||
295 | */ | ||
296 | struct mrq_module_load_request { | ||
297 | /** @brief base address of the code to load. Treated as (void *) */ | ||
298 | uint32_t phys_addr; /* (void *) */ | ||
299 | /** @brief size in bytes of code to load */ | ||
300 | uint32_t size; | ||
301 | } __ABI_PACKED; | ||
302 | |||
303 | /** | ||
304 | * @ingroup Module | ||
305 | * @brief response to #MRQ_MODULE_LOAD | ||
306 | * | ||
307 | * @todo document mrq_response::err | ||
308 | */ | ||
309 | struct mrq_module_load_response { | ||
310 | /** @brief handle to the loaded module */ | ||
311 | uint32_t base; | ||
312 | } __ABI_PACKED; | ||
313 | |||
314 | /** | ||
315 | * @ingroup MRQ_Codes | ||
316 | * @def MRQ_MODULE_UNLOAD | ||
317 | * @brief unload a previously loaded code module | ||
318 | * | ||
319 | * * Platforms: All | ||
320 | * * Initiators: CCPLEX | ||
321 | * * Targets: BPMP | ||
322 | * * Request Payload: @ref mrq_module_unload_request | ||
323 | * * Response Payload: N/A | ||
324 | * | ||
325 | * @note This MRQ is disabled on production systems | ||
326 | */ | ||
327 | |||
328 | /** | ||
329 | * @ingroup Module | ||
330 | * @brief request with #MRQ_MODULE_UNLOAD | ||
331 | * | ||
332 | * Used by #MRQ_MODULE_UNLOAD calls to request that a previously loaded | ||
333 | * module be unloaded. | ||
334 | */ | ||
335 | struct mrq_module_unload_request { | ||
336 | /** @brief handle of the module to unload */ | ||
337 | uint32_t base; | ||
338 | } __ABI_PACKED; | ||
339 | |||
340 | /** | ||
341 | * @ingroup MRQ_Codes | ||
342 | * @def MRQ_TRACE_MODIFY | ||
343 | * @brief modify the set of enabled trace events | ||
344 | * | ||
345 | * * Platforms: All | ||
346 | * * Initiators: CCPLEX | ||
347 | * * Targets: BPMP | ||
348 | * * Request Payload: @ref mrq_trace_modify_request | ||
349 | * * Response Payload: @ref mrq_trace_modify_response | ||
350 | * | ||
351 | * @note This MRQ is disabled on production systems | ||
352 | */ | ||
353 | |||
354 | /** | ||
355 | * @ingroup Trace | ||
356 | * @brief request with #MRQ_TRACE_MODIFY | ||
357 | * | ||
358 | * Used by %MRQ_TRACE_MODIFY calls to enable or disable specify trace | ||
359 | * events. #set takes precedence for any bit set in both #set and | ||
360 | * #clr. | ||
361 | */ | ||
362 | struct mrq_trace_modify_request { | ||
363 | /** @brief bit mask of trace events to disable */ | ||
364 | uint32_t clr; | ||
365 | /** @brief bit mask of trace events to enable */ | ||
366 | uint32_t set; | ||
367 | } __ABI_PACKED; | ||
368 | |||
369 | /** | ||
370 | * @ingroup Trace | ||
371 | * @brief response to #MRQ_TRACE_MODIFY | ||
372 | * | ||
373 | * Sent in repsonse to an #MRQ_TRACE_MODIFY message. #mask reflects the | ||
374 | * state of which events are enabled after the recipient acted on the | ||
375 | * message. | ||
376 | * | ||
377 | */ | ||
378 | struct mrq_trace_modify_response { | ||
379 | /** @brief bit mask of trace event enable states */ | ||
380 | uint32_t mask; | ||
381 | } __ABI_PACKED; | ||
382 | |||
383 | /** | ||
384 | * @ingroup MRQ_Codes | ||
385 | * @def MRQ_WRITE_TRACE | ||
386 | * @brief Write trace data to a buffer | ||
387 | * | ||
388 | * * Platforms: All | ||
389 | * * Initiators: CCPLEX | ||
390 | * * Targets: BPMP | ||
391 | * * Request Payload: @ref mrq_write_trace_request | ||
392 | * * Response Payload: @ref mrq_write_trace_response | ||
393 | * | ||
394 | * mrq_response::err depends on the @ref mrq_write_trace_request field | ||
395 | * values. err is -#BPMP_EINVAL if size is zero or area is NULL or | ||
396 | * area is in an illegal range. A positive value for err indicates the | ||
397 | * number of bytes written to area. | ||
398 | * | ||
399 | * @note This MRQ is disabled on production systems | ||
400 | */ | ||
401 | |||
402 | /** | ||
403 | * @ingroup Trace | ||
404 | * @brief request with #MRQ_WRITE_TRACE | ||
405 | * | ||
406 | * Used by MRQ_WRITE_TRACE calls to ask the recipient to copy trace | ||
407 | * data from the recipient's local buffer to the output buffer. #area | ||
408 | * is treated as a byte-aligned pointer in the recipient's address | ||
409 | * space. | ||
410 | * | ||
411 | * The sender is responsible for ensuring that the output | ||
412 | * buffer is mapped in the recipient's address map. The recipient is | ||
413 | * responsible for protecting its own code and data from accidental | ||
414 | * overwrites. | ||
415 | */ | ||
416 | struct mrq_write_trace_request { | ||
417 | /** @brief base address of output buffer */ | ||
418 | uint32_t area; | ||
419 | /** @brief size in bytes of the output buffer */ | ||
420 | uint32_t size; | ||
421 | } __ABI_PACKED; | ||
422 | |||
423 | /** | ||
424 | * @ingroup Trace | ||
425 | * @brief response to #MRQ_WRITE_TRACE | ||
426 | * | ||
427 | * Once this response is sent, the respondent will not access the | ||
428 | * output buffer further. | ||
429 | */ | ||
430 | struct mrq_write_trace_response { | ||
431 | /** | ||
432 | * @brief flag whether more data remains in local buffer | ||
433 | * | ||
434 | * Value is 1 if the entire local trace buffer has been | ||
435 | * drained to the outputbuffer. Value is 0 otherwise. | ||
436 | */ | ||
437 | uint32_t eof; | ||
438 | } __ABI_PACKED; | ||
439 | |||
440 | /** @private */ | ||
441 | struct mrq_threaded_ping_request { | ||
442 | uint32_t challenge; | ||
443 | } __ABI_PACKED; | ||
444 | |||
445 | /** @private */ | ||
446 | struct mrq_threaded_ping_response { | ||
447 | uint32_t reply; | ||
448 | } __ABI_PACKED; | ||
449 | |||
450 | /** | ||
451 | * @ingroup MRQ_Codes | ||
452 | * @def MRQ_MODULE_MAIL | ||
453 | * @brief send a message to a loadable module | ||
454 | * | ||
455 | * * Platforms: All | ||
456 | * * Initiators: Any | ||
457 | * * Targets: BPMP | ||
458 | * * Request Payload: @ref mrq_module_mail_request | ||
459 | * * Response Payload: @ref mrq_module_mail_response | ||
460 | * | ||
461 | * @note This MRQ is disabled on production systems | ||
462 | */ | ||
463 | |||
464 | /** | ||
465 | * @ingroup Module | ||
466 | * @brief request with #MRQ_MODULE_MAIL | ||
467 | */ | ||
468 | struct mrq_module_mail_request { | ||
469 | /** @brief handle to the previously loaded module */ | ||
470 | uint32_t base; | ||
471 | /** @brief module-specific mail payload | ||
472 | * | ||
473 | * The length of data[ ] is unknown to the BPMP core firmware | ||
474 | * but it is limited to the size of an IPC message. | ||
475 | */ | ||
476 | uint8_t data[EMPTY_ARRAY]; | ||
477 | } __ABI_PACKED; | ||
478 | |||
479 | /** | ||
480 | * @ingroup Module | ||
481 | * @brief response to #MRQ_MODULE_MAIL | ||
482 | */ | ||
483 | struct mrq_module_mail_response { | ||
484 | /** @brief module-specific mail payload | ||
485 | * | ||
486 | * The length of data[ ] is unknown to the BPMP core firmware | ||
487 | * but it is limited to the size of an IPC message. | ||
488 | */ | ||
489 | uint8_t data[EMPTY_ARRAY]; | ||
490 | } __ABI_PACKED; | ||
491 | |||
492 | /** | ||
493 | * @ingroup MRQ_Codes | ||
494 | * @def MRQ_DEBUGFS | ||
495 | * @brief Interact with BPMP's debugfs file nodes | ||
496 | * | ||
497 | * * Platforms: T186 | ||
498 | * * Initiators: Any | ||
499 | * * Targets: BPMP | ||
500 | * * Request Payload: @ref mrq_debugfs_request | ||
501 | * * Response Payload: @ref mrq_debugfs_response | ||
502 | */ | ||
503 | |||
504 | /** | ||
505 | * @addtogroup Debugfs | ||
506 | * @{ | ||
507 | * | ||
508 | * The BPMP firmware implements a pseudo-filesystem called | ||
509 | * debugfs. Any driver within the firmware may register with debugfs | ||
510 | * to expose an arbitrary set of "files" in the filesystem. When | ||
511 | * software on the CPU writes to a debugfs file, debugfs passes the | ||
512 | * written data to a callback provided by the driver. When software on | ||
513 | * the CPU reads a debugfs file, debugfs queries the driver for the | ||
514 | * data to return to the CPU. The intention of the debugfs filesystem | ||
515 | * is to provide information useful for debugging the system at | ||
516 | * runtime. | ||
517 | * | ||
518 | * @note The files exposed via debugfs are not part of the | ||
519 | * BPMP firmware's ABI. debugfs files may be added or removed in any | ||
520 | * given version of the firmware. Typically the semantics of a debugfs | ||
521 | * file are consistent from version to version but even that is not | ||
522 | * guaranteed. | ||
523 | * | ||
524 | * @} | ||
525 | */ | ||
526 | /** @ingroup Debugfs */ | ||
527 | enum mrq_debugfs_commands { | ||
528 | CMD_DEBUGFS_READ = 1, | ||
529 | CMD_DEBUGFS_WRITE = 2, | ||
530 | CMD_DEBUGFS_DUMPDIR = 3, | ||
531 | CMD_DEBUGFS_MAX | ||
532 | }; | ||
533 | |||
534 | /** | ||
535 | * @ingroup Debugfs | ||
536 | * @brief parameters for CMD_DEBUGFS_READ/WRITE command | ||
537 | */ | ||
538 | struct cmd_debugfs_fileop_request { | ||
539 | /** @brief physical address pointing at filename */ | ||
540 | uint32_t fnameaddr; | ||
541 | /** @brief length in bytes of filename buffer */ | ||
542 | uint32_t fnamelen; | ||
543 | /** @brief physical address pointing to data buffer */ | ||
544 | uint32_t dataaddr; | ||
545 | /** @brief length in bytes of data buffer */ | ||
546 | uint32_t datalen; | ||
547 | } __ABI_PACKED; | ||
548 | |||
549 | /** | ||
550 | * @ingroup Debugfs | ||
551 | * @brief parameters for CMD_DEBUGFS_READ/WRITE command | ||
552 | */ | ||
553 | struct cmd_debugfs_dumpdir_request { | ||
554 | /** @brief physical address pointing to data buffer */ | ||
555 | uint32_t dataaddr; | ||
556 | /** @brief length in bytes of data buffer */ | ||
557 | uint32_t datalen; | ||
558 | } __ABI_PACKED; | ||
559 | |||
560 | /** | ||
561 | * @ingroup Debugfs | ||
562 | * @brief response data for CMD_DEBUGFS_READ/WRITE command | ||
563 | */ | ||
564 | struct cmd_debugfs_fileop_response { | ||
565 | /** @brief always 0 */ | ||
566 | uint32_t reserved; | ||
567 | /** @brief number of bytes read from or written to data buffer */ | ||
568 | uint32_t nbytes; | ||
569 | } __ABI_PACKED; | ||
570 | |||
571 | /** | ||
572 | * @ingroup Debugfs | ||
573 | * @brief response data for CMD_DEBUGFS_DUMPDIR command | ||
574 | */ | ||
575 | struct cmd_debugfs_dumpdir_response { | ||
576 | /** @brief always 0 */ | ||
577 | uint32_t reserved; | ||
578 | /** @brief number of bytes read from or written to data buffer */ | ||
579 | uint32_t nbytes; | ||
580 | } __ABI_PACKED; | ||
581 | |||
582 | /** | ||
583 | * @ingroup Debugfs | ||
584 | * @brief request with #MRQ_DEBUGFS. | ||
585 | * | ||
586 | * The sender of an MRQ_DEBUGFS message uses #cmd to specify a debugfs | ||
587 | * command to execute. Legal commands are the values of @ref | ||
588 | * mrq_debugfs_commands. Each command requires a specific additional | ||
589 | * payload of data. | ||
590 | * | ||
591 | * |command |payload| | ||
592 | * |-------------------|-------| | ||
593 | * |CMD_DEBUGFS_READ |fop | | ||
594 | * |CMD_DEBUGFS_WRITE |fop | | ||
595 | * |CMD_DEBUGFS_DUMPDIR|dumpdir| | ||
596 | */ | ||
597 | struct mrq_debugfs_request { | ||
598 | uint32_t cmd; | ||
599 | union { | ||
600 | struct cmd_debugfs_fileop_request fop; | ||
601 | struct cmd_debugfs_dumpdir_request dumpdir; | ||
602 | } __UNION_ANON; | ||
603 | } __ABI_PACKED; | ||
604 | |||
605 | /** | ||
606 | * @ingroup Debugfs | ||
607 | */ | ||
608 | struct mrq_debugfs_response { | ||
609 | /** @brief always 0 */ | ||
610 | int32_t reserved; | ||
611 | union { | ||
612 | /** @brief response data for CMD_DEBUGFS_READ OR | ||
613 | * CMD_DEBUGFS_WRITE command | ||
614 | */ | ||
615 | struct cmd_debugfs_fileop_response fop; | ||
616 | /** @brief response data for CMD_DEBUGFS_DUMPDIR command */ | ||
617 | struct cmd_debugfs_dumpdir_response dumpdir; | ||
618 | } __UNION_ANON; | ||
619 | } __ABI_PACKED; | ||
620 | |||
621 | /** | ||
622 | * @addtogroup Debugfs | ||
623 | * @{ | ||
624 | */ | ||
625 | #define DEBUGFS_S_ISDIR (1 << 9) | ||
626 | #define DEBUGFS_S_IRUSR (1 << 8) | ||
627 | #define DEBUGFS_S_IWUSR (1 << 7) | ||
628 | /** @} */ | ||
629 | |||
630 | |||
631 | /** | ||
632 | * @ingroup MRQ_Codes | ||
633 | * @def MRQ_RESET | ||
634 | * @brief reset an IP block | ||
635 | * | ||
636 | * * Platforms: T186 | ||
637 | * * Initiators: Any | ||
638 | * * Targets: BPMP | ||
639 | * * Request Payload: @ref mrq_reset_request | ||
640 | * * Response Payload: N/A | ||
641 | */ | ||
642 | |||
643 | /** | ||
644 | * @ingroup Reset | ||
645 | */ | ||
646 | enum mrq_reset_commands { | ||
647 | CMD_RESET_ASSERT = 1, | ||
648 | CMD_RESET_DEASSERT = 2, | ||
649 | CMD_RESET_MODULE = 3, | ||
650 | CMD_RESET_MAX, /* not part of ABI and subject to change */ | ||
651 | }; | ||
652 | |||
653 | /** | ||
654 | * @ingroup Reset | ||
655 | * @brief request with MRQ_RESET | ||
656 | * | ||
657 | * Used by the sender of an #MRQ_RESET message to request BPMP to | ||
658 | * assert or or deassert a given reset line. | ||
659 | */ | ||
660 | struct mrq_reset_request { | ||
661 | /** @brief reset action to perform (@enum mrq_reset_commands) */ | ||
662 | uint32_t cmd; | ||
663 | /** @brief id of the reset to affected */ | ||
664 | uint32_t reset_id; | ||
665 | } __ABI_PACKED; | ||
666 | |||
667 | /** | ||
668 | * @ingroup MRQ_Codes | ||
669 | * @def MRQ_I2C | ||
670 | * @brief issue an i2c transaction | ||
671 | * | ||
672 | * * Platforms: T186 | ||
673 | * * Initiators: Any | ||
674 | * * Targets: BPMP | ||
675 | * * Request Payload: @ref mrq_i2c_request | ||
676 | * * Response Payload: @ref mrq_i2c_response | ||
677 | */ | ||
678 | |||
679 | /** | ||
680 | * @addtogroup I2C | ||
681 | * @{ | ||
682 | */ | ||
683 | #define TEGRA_I2C_IPC_MAX_IN_BUF_SIZE (MSG_DATA_MIN_SZ - 12) | ||
684 | #define TEGRA_I2C_IPC_MAX_OUT_BUF_SIZE (MSG_DATA_MIN_SZ - 4) | ||
685 | /** @} */ | ||
686 | |||
687 | /** | ||
688 | * @ingroup I2C | ||
689 | * @name Serial I2C flags | ||
690 | * Use these flags with serial_i2c_request::flags | ||
691 | * @{ | ||
692 | */ | ||
693 | #define SERIALI2C_TEN 0x0010 | ||
694 | #define SERIALI2C_RD 0x0001 | ||
695 | #define SERIALI2C_STOP 0x8000 | ||
696 | #define SERIALI2C_NOSTART 0x4000 | ||
697 | #define SERIALI2C_REV_DIR_ADDR 0x2000 | ||
698 | #define SERIALI2C_IGNORE_NAK 0x1000 | ||
699 | #define SERIALI2C_NO_RD_ACK 0x0800 | ||
700 | #define SERIALI2C_RECV_LEN 0x0400 | ||
701 | /** @} */ | ||
702 | /** @ingroup I2C */ | ||
703 | enum { | ||
704 | CMD_I2C_XFER = 1 | ||
705 | }; | ||
706 | |||
707 | /** | ||
708 | * @ingroup I2C | ||
709 | * @brief serializable i2c request | ||
710 | * | ||
711 | * Instances of this structure are packed (little-endian) into | ||
712 | * cmd_i2c_xfer_request::data_buf. Each instance represents a single | ||
713 | * transaction (or a portion of a transaction with repeated starts) on | ||
714 | * an i2c bus. | ||
715 | * | ||
716 | * Because these structures are packed, some instances are likely to | ||
717 | * be misaligned. Additionally because #data is variable length, it is | ||
718 | * not possible to iterate through a serialized list of these | ||
719 | * structures without inspecting #len in each instance. It may be | ||
720 | * easier to serialize or deserialize cmd_i2c_xfer_request::data_buf | ||
721 | * manually rather than using this structure definition. | ||
722 | */ | ||
723 | struct serial_i2c_request { | ||
724 | /** @brief I2C slave address */ | ||
725 | uint16_t addr; | ||
726 | /** @brief bitmask of SERIALI2C_ flags */ | ||
727 | uint16_t flags; | ||
728 | /** @brief length of I2C transaction in bytes */ | ||
729 | uint16_t len; | ||
730 | /** @brief for write transactions only, #len bytes of data */ | ||
731 | uint8_t data[]; | ||
732 | } __ABI_PACKED; | ||
733 | |||
734 | /** | ||
735 | * @ingroup I2C | ||
736 | * @brief trigger one or more i2c transactions | ||
737 | */ | ||
738 | struct cmd_i2c_xfer_request { | ||
739 | /** @brief valid bus number from mach-t186/i2c-t186.h*/ | ||
740 | uint32_t bus_id; | ||
741 | |||
742 | /** @brief count of valid bytes in #data_buf*/ | ||
743 | uint32_t data_size; | ||
744 | |||
745 | /** @brief serialized packed instances of @ref serial_i2c_request*/ | ||
746 | uint8_t data_buf[TEGRA_I2C_IPC_MAX_IN_BUF_SIZE]; | ||
747 | } __ABI_PACKED; | ||
748 | |||
749 | /** | ||
750 | * @ingroup I2C | ||
751 | * @brief container for data read from the i2c bus | ||
752 | * | ||
753 | * Processing an cmd_i2c_xfer_request::data_buf causes BPMP to execute | ||
754 | * zero or more I2C reads. The data read from the bus is serialized | ||
755 | * into #data_buf. | ||
756 | */ | ||
757 | struct cmd_i2c_xfer_response { | ||
758 | /** @brief count of valid bytes in #data_buf*/ | ||
759 | uint32_t data_size; | ||
760 | /** @brief i2c read data */ | ||
761 | uint8_t data_buf[TEGRA_I2C_IPC_MAX_OUT_BUF_SIZE]; | ||
762 | } __ABI_PACKED; | ||
763 | |||
764 | /** | ||
765 | * @ingroup I2C | ||
766 | * @brief request with #MRQ_I2C | ||
767 | */ | ||
768 | struct mrq_i2c_request { | ||
769 | /** @brief always CMD_I2C_XFER (i.e. 1) */ | ||
770 | uint32_t cmd; | ||
771 | /** @brief parameters of the transfer request */ | ||
772 | struct cmd_i2c_xfer_request xfer; | ||
773 | } __ABI_PACKED; | ||
774 | |||
775 | /** | ||
776 | * @ingroup I2C | ||
777 | * @brief response to #MRQ_I2C | ||
778 | */ | ||
779 | struct mrq_i2c_response { | ||
780 | struct cmd_i2c_xfer_response xfer; | ||
781 | } __ABI_PACKED; | ||
782 | |||
783 | /** | ||
784 | * @ingroup MRQ_Codes | ||
785 | * @def MRQ_CLK | ||
786 | * | ||
787 | * * Platforms: T186 | ||
788 | * * Initiators: Any | ||
789 | * * Targets: BPMP | ||
790 | * * Request Payload: @ref mrq_clk_request | ||
791 | * * Response Payload: @ref mrq_clk_response | ||
792 | * @addtogroup Clocks | ||
793 | * @{ | ||
794 | */ | ||
795 | |||
796 | /** | ||
797 | * @name MRQ_CLK sub-commands | ||
798 | * @{ | ||
799 | */ | ||
800 | enum { | ||
801 | CMD_CLK_GET_RATE = 1, | ||
802 | CMD_CLK_SET_RATE = 2, | ||
803 | CMD_CLK_ROUND_RATE = 3, | ||
804 | CMD_CLK_GET_PARENT = 4, | ||
805 | CMD_CLK_SET_PARENT = 5, | ||
806 | CMD_CLK_IS_ENABLED = 6, | ||
807 | CMD_CLK_ENABLE = 7, | ||
808 | CMD_CLK_DISABLE = 8, | ||
809 | CMD_CLK_GET_ALL_INFO = 14, | ||
810 | CMD_CLK_GET_MAX_CLK_ID = 15, | ||
811 | CMD_CLK_MAX, | ||
812 | }; | ||
813 | /** @} */ | ||
814 | |||
815 | #define MRQ_CLK_NAME_MAXLEN 40 | ||
816 | #define MRQ_CLK_MAX_PARENTS 16 | ||
817 | |||
818 | /** @private */ | ||
819 | struct cmd_clk_get_rate_request { | ||
820 | EMPTY | ||
821 | } __ABI_PACKED; | ||
822 | |||
823 | struct cmd_clk_get_rate_response { | ||
824 | int64_t rate; | ||
825 | } __ABI_PACKED; | ||
826 | |||
827 | struct cmd_clk_set_rate_request { | ||
828 | int32_t unused; | ||
829 | int64_t rate; | ||
830 | } __ABI_PACKED; | ||
831 | |||
832 | struct cmd_clk_set_rate_response { | ||
833 | int64_t rate; | ||
834 | } __ABI_PACKED; | ||
835 | |||
836 | struct cmd_clk_round_rate_request { | ||
837 | int32_t unused; | ||
838 | int64_t rate; | ||
839 | } __ABI_PACKED; | ||
840 | |||
841 | struct cmd_clk_round_rate_response { | ||
842 | int64_t rate; | ||
843 | } __ABI_PACKED; | ||
844 | |||
845 | /** @private */ | ||
846 | struct cmd_clk_get_parent_request { | ||
847 | EMPTY | ||
848 | } __ABI_PACKED; | ||
849 | |||
850 | struct cmd_clk_get_parent_response { | ||
851 | uint32_t parent_id; | ||
852 | } __ABI_PACKED; | ||
853 | |||
854 | struct cmd_clk_set_parent_request { | ||
855 | uint32_t parent_id; | ||
856 | } __ABI_PACKED; | ||
857 | |||
858 | struct cmd_clk_set_parent_response { | ||
859 | uint32_t parent_id; | ||
860 | } __ABI_PACKED; | ||
861 | |||
862 | /** @private */ | ||
863 | struct cmd_clk_is_enabled_request { | ||
864 | EMPTY | ||
865 | } __ABI_PACKED; | ||
866 | |||
867 | struct cmd_clk_is_enabled_response { | ||
868 | int32_t state; | ||
869 | } __ABI_PACKED; | ||
870 | |||
871 | /** @private */ | ||
872 | struct cmd_clk_enable_request { | ||
873 | EMPTY | ||
874 | } __ABI_PACKED; | ||
875 | |||
876 | /** @private */ | ||
877 | struct cmd_clk_enable_response { | ||
878 | EMPTY | ||
879 | } __ABI_PACKED; | ||
880 | |||
881 | /** @private */ | ||
882 | struct cmd_clk_disable_request { | ||
883 | EMPTY | ||
884 | } __ABI_PACKED; | ||
885 | |||
886 | /** @private */ | ||
887 | struct cmd_clk_disable_response { | ||
888 | EMPTY | ||
889 | } __ABI_PACKED; | ||
890 | |||
891 | /** @private */ | ||
892 | struct cmd_clk_get_all_info_request { | ||
893 | EMPTY | ||
894 | } __ABI_PACKED; | ||
895 | |||
896 | struct cmd_clk_get_all_info_response { | ||
897 | uint32_t flags; | ||
898 | uint32_t parent; | ||
899 | uint32_t parents[MRQ_CLK_MAX_PARENTS]; | ||
900 | uint8_t num_parents; | ||
901 | uint8_t name[MRQ_CLK_NAME_MAXLEN]; | ||
902 | } __ABI_PACKED; | ||
903 | |||
904 | /** @private */ | ||
905 | struct cmd_clk_get_max_clk_id_request { | ||
906 | EMPTY | ||
907 | } __ABI_PACKED; | ||
908 | |||
909 | struct cmd_clk_get_max_clk_id_response { | ||
910 | uint32_t max_id; | ||
911 | } __ABI_PACKED; | ||
912 | /** @} */ | ||
913 | |||
914 | /** | ||
915 | * @ingroup Clocks | ||
916 | * @brief request with #MRQ_CLK | ||
917 | * | ||
918 | * Used by the sender of an #MRQ_CLK message to control clocks. The | ||
919 | * clk_request is split into several sub-commands. Some sub-commands | ||
920 | * require no additional data. Others have a sub-command specific | ||
921 | * payload | ||
922 | * | ||
923 | * |sub-command |payload | | ||
924 | * |----------------------------|-----------------------| | ||
925 | * |CMD_CLK_GET_RATE |- | | ||
926 | * |CMD_CLK_SET_RATE |clk_set_rate | | ||
927 | * |CMD_CLK_ROUND_RATE |clk_round_rate | | ||
928 | * |CMD_CLK_GET_PARENT |- | | ||
929 | * |CMD_CLK_SET_PARENT |clk_set_parent | | ||
930 | * |CMD_CLK_IS_ENABLED |- | | ||
931 | * |CMD_CLK_ENABLE |- | | ||
932 | * |CMD_CLK_DISABLE |- | | ||
933 | * |CMD_CLK_GET_ALL_INFO |- | | ||
934 | * |CMD_CLK_GET_MAX_CLK_ID |- | | ||
935 | * | ||
936 | */ | ||
937 | |||
938 | struct mrq_clk_request { | ||
939 | /** @brief sub-command and clock id concatenated to 32-bit word. | ||
940 | * - bits[31..24] is the sub-cmd. | ||
941 | * - bits[23..0] is the clock id | ||
942 | */ | ||
943 | uint32_t cmd_and_id; | ||
944 | |||
945 | union { | ||
946 | /** @private */ | ||
947 | struct cmd_clk_get_rate_request clk_get_rate; | ||
948 | struct cmd_clk_set_rate_request clk_set_rate; | ||
949 | struct cmd_clk_round_rate_request clk_round_rate; | ||
950 | /** @private */ | ||
951 | struct cmd_clk_get_parent_request clk_get_parent; | ||
952 | struct cmd_clk_set_parent_request clk_set_parent; | ||
953 | /** @private */ | ||
954 | struct cmd_clk_enable_request clk_enable; | ||
955 | /** @private */ | ||
956 | struct cmd_clk_disable_request clk_disable; | ||
957 | /** @private */ | ||
958 | struct cmd_clk_is_enabled_request clk_is_enabled; | ||
959 | /** @private */ | ||
960 | struct cmd_clk_get_all_info_request clk_get_all_info; | ||
961 | /** @private */ | ||
962 | struct cmd_clk_get_max_clk_id_request clk_get_max_clk_id; | ||
963 | } __UNION_ANON; | ||
964 | } __ABI_PACKED; | ||
965 | |||
966 | /** | ||
967 | * @ingroup Clocks | ||
968 | * @brief response to MRQ_CLK | ||
969 | * | ||
970 | * Each sub-command supported by @ref mrq_clk_request may return | ||
971 | * sub-command-specific data. Some do and some do not as indicated in | ||
972 | * the following table | ||
973 | * | ||
974 | * |sub-command |payload | | ||
975 | * |----------------------------|------------------------| | ||
976 | * |CMD_CLK_GET_RATE |clk_get_rate | | ||
977 | * |CMD_CLK_SET_RATE |clk_set_rate | | ||
978 | * |CMD_CLK_ROUND_RATE |clk_round_rate | | ||
979 | * |CMD_CLK_GET_PARENT |clk_get_parent | | ||
980 | * |CMD_CLK_SET_PARENT |clk_set_parent | | ||
981 | * |CMD_CLK_IS_ENABLED |clk_is_enabled | | ||
982 | * |CMD_CLK_ENABLE |- | | ||
983 | * |CMD_CLK_DISABLE |- | | ||
984 | * |CMD_CLK_GET_ALL_INFO |clk_get_all_info | | ||
985 | * |CMD_CLK_GET_MAX_CLK_ID |clk_get_max_id | | ||
986 | * | ||
987 | */ | ||
988 | |||
989 | struct mrq_clk_response { | ||
990 | union { | ||
991 | struct cmd_clk_get_rate_response clk_get_rate; | ||
992 | struct cmd_clk_set_rate_response clk_set_rate; | ||
993 | struct cmd_clk_round_rate_response clk_round_rate; | ||
994 | struct cmd_clk_get_parent_response clk_get_parent; | ||
995 | struct cmd_clk_set_parent_response clk_set_parent; | ||
996 | /** @private */ | ||
997 | struct cmd_clk_enable_response clk_enable; | ||
998 | /** @private */ | ||
999 | struct cmd_clk_disable_response clk_disable; | ||
1000 | struct cmd_clk_is_enabled_response clk_is_enabled; | ||
1001 | struct cmd_clk_get_all_info_response clk_get_all_info; | ||
1002 | struct cmd_clk_get_max_clk_id_response clk_get_max_clk_id; | ||
1003 | } __UNION_ANON; | ||
1004 | } __ABI_PACKED; | ||
1005 | |||
1006 | /** | ||
1007 | * @ingroup MRQ_Codes | ||
1008 | * @def MRQ_QUERY_ABI | ||
1009 | * @brief check if an MRQ is implemented | ||
1010 | * | ||
1011 | * * Platforms: All | ||
1012 | * * Initiators: Any | ||
1013 | * * Targets: Any | ||
1014 | * * Request Payload: @ref mrq_query_abi_request | ||
1015 | * * Response Payload: @ref mrq_query_abi_response | ||
1016 | */ | ||
1017 | |||
1018 | /** | ||
1019 | * @ingroup ABI_info | ||
1020 | * @brief request with MRQ_QUERY_ABI | ||
1021 | * | ||
1022 | * Used by #MRQ_QUERY_ABI call to check if MRQ code #mrq is supported | ||
1023 | * by the recipient. | ||
1024 | */ | ||
1025 | struct mrq_query_abi_request { | ||
1026 | /** @brief MRQ code to query */ | ||
1027 | uint32_t mrq; | ||
1028 | } __ABI_PACKED; | ||
1029 | |||
1030 | /** | ||
1031 | * @ingroup ABI_info | ||
1032 | * @brief response to MRQ_QUERY_ABI | ||
1033 | */ | ||
1034 | struct mrq_query_abi_response { | ||
1035 | /** @brief 0 if queried MRQ is supported. Else, -#BPMP_ENODEV */ | ||
1036 | int32_t status; | ||
1037 | } __ABI_PACKED; | ||
1038 | |||
1039 | /** | ||
1040 | * @ingroup MRQ_Codes | ||
1041 | * @def MRQ_PG_READ_STATE | ||
1042 | * @brief read the power-gating state of a partition | ||
1043 | * | ||
1044 | * * Platforms: T186 | ||
1045 | * * Initiators: Any | ||
1046 | * * Targets: BPMP | ||
1047 | * * Request Payload: @ref mrq_pg_read_state_request | ||
1048 | * * Response Payload: @ref mrq_pg_read_state_response | ||
1049 | * @addtogroup Powergating | ||
1050 | * @{ | ||
1051 | */ | ||
1052 | |||
1053 | /** | ||
1054 | * @brief request with #MRQ_PG_READ_STATE | ||
1055 | * | ||
1056 | * Used by MRQ_PG_READ_STATE call to read the current state of a | ||
1057 | * partition. | ||
1058 | */ | ||
1059 | struct mrq_pg_read_state_request { | ||
1060 | /** @brief ID of partition */ | ||
1061 | uint32_t partition_id; | ||
1062 | } __ABI_PACKED; | ||
1063 | |||
1064 | /** | ||
1065 | * @brief response to MRQ_PG_READ_STATE | ||
1066 | * @todo define possible errors. | ||
1067 | */ | ||
1068 | struct mrq_pg_read_state_response { | ||
1069 | /** @brief read as don't care */ | ||
1070 | uint32_t sram_state; | ||
1071 | /** @brief state of power partition | ||
1072 | * * 0 : off | ||
1073 | * * 1 : on | ||
1074 | */ | ||
1075 | uint32_t logic_state; | ||
1076 | } __ABI_PACKED; | ||
1077 | |||
1078 | /** @} */ | ||
1079 | |||
1080 | /** | ||
1081 | * @ingroup MRQ_Codes | ||
1082 | * @def MRQ_PG_UPDATE_STATE | ||
1083 | * @brief modify the power-gating state of a partition | ||
1084 | * | ||
1085 | * * Platforms: T186 | ||
1086 | * * Initiators: Any | ||
1087 | * * Targets: BPMP | ||
1088 | * * Request Payload: @ref mrq_pg_update_state_request | ||
1089 | * * Response Payload: N/A | ||
1090 | * @addtogroup Powergating | ||
1091 | * @{ | ||
1092 | */ | ||
1093 | |||
1094 | /** | ||
1095 | * @brief request with mrq_pg_update_state_request | ||
1096 | * | ||
1097 | * Used by #MRQ_PG_UPDATE_STATE call to request BPMP to change the | ||
1098 | * state of a power partition #partition_id. | ||
1099 | */ | ||
1100 | struct mrq_pg_update_state_request { | ||
1101 | /** @brief ID of partition */ | ||
1102 | uint32_t partition_id; | ||
1103 | /** @brief secondary control of power partition | ||
1104 | * @details Ignored by many versions of the BPMP | ||
1105 | * firmware. For maximum compatibility, set the value | ||
1106 | * according to @logic_state | ||
1107 | * * 0x1: power ON partition (@ref logic_state == 0x3) | ||
1108 | * * 0x3: power OFF partition (@ref logic_state == 0x1) | ||
1109 | */ | ||
1110 | uint32_t sram_state; | ||
1111 | /** @brief controls state of power partition, legal values are | ||
1112 | * * 0x1 : power OFF partition | ||
1113 | * * 0x3 : power ON partition | ||
1114 | */ | ||
1115 | uint32_t logic_state; | ||
1116 | /** @brief change state of clocks of the power partition, legal values | ||
1117 | * * 0x0 : do not change clock state | ||
1118 | * * 0x1 : disable partition clocks (only applicable when | ||
1119 | * @ref logic_state == 0x1) | ||
1120 | * * 0x3 : enable partition clocks (only applicable when | ||
1121 | * @ref logic_state == 0x3) | ||
1122 | */ | ||
1123 | uint32_t clock_state; | ||
1124 | } __ABI_PACKED; | ||
1125 | /** @} */ | ||
1126 | |||
1127 | /** | ||
1128 | * @ingroup MRQ_Codes | ||
1129 | * @def MRQ_THERMAL | ||
1130 | * @brief interact with BPMP thermal framework | ||
1131 | * | ||
1132 | * * Platforms: T186 | ||
1133 | * * Initiators: Any | ||
1134 | * * Targets: Any | ||
1135 | * * Request Payload: TODO | ||
1136 | * * Response Payload: TODO | ||
1137 | * | ||
1138 | * @addtogroup Thermal | ||
1139 | * | ||
1140 | * The BPMP firmware includes a thermal framework. Drivers within the | ||
1141 | * bpmp firmware register with the framework to provide thermal | ||
1142 | * zones. Each thermal zone corresponds to an entity whose temperature | ||
1143 | * can be measured. The framework also has a notion of trip points. A | ||
1144 | * trip point consists of a thermal zone id, a temperature, and a | ||
1145 | * callback routine. The framework invokes the callback when the zone | ||
1146 | * hits the indicated temperature. The BPMP firmware uses this thermal | ||
1147 | * framework interally to implement various temperature-dependent | ||
1148 | * functions. | ||
1149 | * | ||
1150 | * Software on the CPU can use #MRQ_THERMAL (with payload @ref | ||
1151 | * mrq_thermal_host_to_bpmp_request) to interact with the BPMP thermal | ||
1152 | * framework. The CPU must It can query the number of supported zones, | ||
1153 | * query zone temperatures, and set trip points. | ||
1154 | * | ||
1155 | * When a trip point set by the CPU gets crossed, BPMP firmware issues | ||
1156 | * an IPC to the CPU having mrq_request::mrq = #MRQ_THERMAL and a | ||
1157 | * payload of @ref mrq_thermal_bpmp_to_host_request. | ||
1158 | * @{ | ||
1159 | */ | ||
1160 | enum mrq_thermal_host_to_bpmp_cmd { | ||
1161 | /** | ||
1162 | * @brief Check whether the BPMP driver supports the specified | ||
1163 | * request type. | ||
1164 | * | ||
1165 | * Host needs to supply request parameters. | ||
1166 | * | ||
1167 | * mrq_response::err is 0 if the specified request is | ||
1168 | * supported and -#BPMP_ENODEV otherwise. | ||
1169 | */ | ||
1170 | CMD_THERMAL_QUERY_ABI = 0, | ||
1171 | |||
1172 | /** | ||
1173 | * @brief Get the current temperature of the specified zone. | ||
1174 | * | ||
1175 | * Host needs to supply request parameters. | ||
1176 | * | ||
1177 | * mrq_response::err is | ||
1178 | * * 0: Temperature query succeeded. | ||
1179 | * * -#BPMP_EINVAL: Invalid request parameters. | ||
1180 | * * -#BPMP_ENOENT: No driver registered for thermal zone.. | ||
1181 | * * -#BPMP_EFAULT: Problem reading temperature measurement. | ||
1182 | */ | ||
1183 | CMD_THERMAL_GET_TEMP = 1, | ||
1184 | |||
1185 | /** | ||
1186 | * @brief Enable or disable and set the lower and upper | ||
1187 | * thermal limits for a thermal trip point. Each zone has | ||
1188 | * one trip point. | ||
1189 | * | ||
1190 | * Host needs to supply request parameters. Once the | ||
1191 | * temperature hits a trip point, the BPMP will send a message | ||
1192 | * to the CPU having MRQ=MRQ_THERMAL and | ||
1193 | * type=CMD_THERMAL_HOST_TRIP_REACHED | ||
1194 | * | ||
1195 | * mrq_response::err is | ||
1196 | * * 0: Trip successfully set. | ||
1197 | * * -#BPMP_EINVAL: Invalid request parameters. | ||
1198 | * * -#BPMP_ENOENT: No driver registered for thermal zone. | ||
1199 | * * -#BPMP_EFAULT: Problem setting trip point. | ||
1200 | */ | ||
1201 | CMD_THERMAL_SET_TRIP = 2, | ||
1202 | |||
1203 | /** | ||
1204 | * @brief Get the number of supported thermal zones. | ||
1205 | * | ||
1206 | * No request parameters required. | ||
1207 | * | ||
1208 | * mrq_response::err is always 0, indicating success. | ||
1209 | */ | ||
1210 | CMD_THERMAL_GET_NUM_ZONES = 3, | ||
1211 | |||
1212 | /** @brief: number of supported host-to-bpmp commands. May | ||
1213 | * increase in future | ||
1214 | */ | ||
1215 | CMD_THERMAL_HOST_TO_BPMP_NUM | ||
1216 | }; | ||
1217 | |||
1218 | enum mrq_thermal_bpmp_to_host_cmd { | ||
1219 | /** | ||
1220 | * @brief Indication that the temperature for a zone has | ||
1221 | * exceeded the range indicated in the thermal trip point | ||
1222 | * for the zone. | ||
1223 | * | ||
1224 | * BPMP needs to supply request parameters. Host only needs to | ||
1225 | * acknowledge. | ||
1226 | */ | ||
1227 | CMD_THERMAL_HOST_TRIP_REACHED = 100, | ||
1228 | |||
1229 | /** @brief: number of supported bpmp-to-host commands. May | ||
1230 | * increase in future | ||
1231 | */ | ||
1232 | CMD_THERMAL_BPMP_TO_HOST_NUM | ||
1233 | }; | ||
1234 | |||
1235 | /* | ||
1236 | * Host->BPMP request data for request type CMD_THERMAL_QUERY_ABI | ||
1237 | * | ||
1238 | * zone: Request type for which to check existence. | ||
1239 | */ | ||
1240 | struct cmd_thermal_query_abi_request { | ||
1241 | uint32_t type; | ||
1242 | } __ABI_PACKED; | ||
1243 | |||
1244 | /* | ||
1245 | * Host->BPMP request data for request type CMD_THERMAL_GET_TEMP | ||
1246 | * | ||
1247 | * zone: Number of thermal zone. | ||
1248 | */ | ||
1249 | struct cmd_thermal_get_temp_request { | ||
1250 | uint32_t zone; | ||
1251 | } __ABI_PACKED; | ||
1252 | |||
1253 | /* | ||
1254 | * BPMP->Host reply data for request CMD_THERMAL_GET_TEMP | ||
1255 | * | ||
1256 | * error: 0 if request succeeded. | ||
1257 | * -BPMP_EINVAL if request parameters were invalid. | ||
1258 | * -BPMP_ENOENT if no driver was registered for the specified thermal zone. | ||
1259 | * -BPMP_EFAULT for other thermal zone driver errors. | ||
1260 | * temp: Current temperature in millicelsius. | ||
1261 | */ | ||
1262 | struct cmd_thermal_get_temp_response { | ||
1263 | int32_t temp; | ||
1264 | } __ABI_PACKED; | ||
1265 | |||
1266 | /* | ||
1267 | * Host->BPMP request data for request type CMD_THERMAL_SET_TRIP | ||
1268 | * | ||
1269 | * zone: Number of thermal zone. | ||
1270 | * low: Temperature of lower trip point in millicelsius | ||
1271 | * high: Temperature of upper trip point in millicelsius | ||
1272 | * enabled: 1 to enable trip point, 0 to disable trip point | ||
1273 | */ | ||
1274 | struct cmd_thermal_set_trip_request { | ||
1275 | uint32_t zone; | ||
1276 | int32_t low; | ||
1277 | int32_t high; | ||
1278 | uint32_t enabled; | ||
1279 | } __ABI_PACKED; | ||
1280 | |||
1281 | /* | ||
1282 | * BPMP->Host request data for request type CMD_THERMAL_HOST_TRIP_REACHED | ||
1283 | * | ||
1284 | * zone: Number of thermal zone where trip point was reached. | ||
1285 | */ | ||
1286 | struct cmd_thermal_host_trip_reached_request { | ||
1287 | uint32_t zone; | ||
1288 | } __ABI_PACKED; | ||
1289 | |||
1290 | /* | ||
1291 | * BPMP->Host reply data for request type CMD_THERMAL_GET_NUM_ZONES | ||
1292 | * | ||
1293 | * num: Number of supported thermal zones. The thermal zones are indexed | ||
1294 | * starting from zero. | ||
1295 | */ | ||
1296 | struct cmd_thermal_get_num_zones_response { | ||
1297 | uint32_t num; | ||
1298 | } __ABI_PACKED; | ||
1299 | |||
1300 | /* | ||
1301 | * Host->BPMP request data. | ||
1302 | * | ||
1303 | * Reply type is union mrq_thermal_bpmp_to_host_response. | ||
1304 | * | ||
1305 | * type: Type of request. Values listed in enum mrq_thermal_type. | ||
1306 | * data: Request type specific parameters. | ||
1307 | */ | ||
1308 | struct mrq_thermal_host_to_bpmp_request { | ||
1309 | uint32_t type; | ||
1310 | union { | ||
1311 | struct cmd_thermal_query_abi_request query_abi; | ||
1312 | struct cmd_thermal_get_temp_request get_temp; | ||
1313 | struct cmd_thermal_set_trip_request set_trip; | ||
1314 | } __UNION_ANON; | ||
1315 | } __ABI_PACKED; | ||
1316 | |||
1317 | /* | ||
1318 | * BPMP->Host request data. | ||
1319 | * | ||
1320 | * type: Type of request. Values listed in enum mrq_thermal_type. | ||
1321 | * data: Request type specific parameters. | ||
1322 | */ | ||
1323 | struct mrq_thermal_bpmp_to_host_request { | ||
1324 | uint32_t type; | ||
1325 | union { | ||
1326 | struct cmd_thermal_host_trip_reached_request host_trip_reached; | ||
1327 | } __UNION_ANON; | ||
1328 | } __ABI_PACKED; | ||
1329 | |||
1330 | /* | ||
1331 | * Data in reply to a Host->BPMP request. | ||
1332 | */ | ||
1333 | union mrq_thermal_bpmp_to_host_response { | ||
1334 | struct cmd_thermal_get_temp_response get_temp; | ||
1335 | struct cmd_thermal_get_num_zones_response get_num_zones; | ||
1336 | } __ABI_PACKED; | ||
1337 | /** @} */ | ||
1338 | |||
1339 | /** | ||
1340 | * @ingroup MRQ_Codes | ||
1341 | * @def MRQ_CPU_VHINT | ||
1342 | * @brief Query CPU voltage hint data | ||
1343 | * | ||
1344 | * * Platforms: T186 | ||
1345 | * * Initiators: CCPLEX | ||
1346 | * * Targets: BPMP | ||
1347 | * * Request Payload: @ref mrq_cpu_vhint_request | ||
1348 | * * Response Payload: N/A | ||
1349 | * | ||
1350 | * @addtogroup Vhint CPU Voltage hint | ||
1351 | * @{ | ||
1352 | */ | ||
1353 | |||
1354 | /** | ||
1355 | * @brief request with #MRQ_CPU_VHINT | ||
1356 | * | ||
1357 | * Used by #MRQ_CPU_VHINT call by CCPLEX to retrieve voltage hint data | ||
1358 | * from BPMP to memory space pointed by #addr. CCPLEX is responsible | ||
1359 | * to allocate sizeof(cpu_vhint_data) sized block of memory and | ||
1360 | * appropriately map it for BPMP before sending the request. | ||
1361 | */ | ||
1362 | struct mrq_cpu_vhint_request { | ||
1363 | /** @brief IOVA address for the #cpu_vhint_data */ | ||
1364 | uint32_t addr; /* struct cpu_vhint_data * */ | ||
1365 | /** @brief ID of the cluster whose data is requested */ | ||
1366 | uint32_t cluster_id; /* enum cluster_id */ | ||
1367 | } __ABI_PACKED; | ||
1368 | |||
1369 | /** | ||
1370 | * @brief description of the CPU v/f relation | ||
1371 | * | ||
1372 | * Used by #MRQ_CPU_VHINT call to carry data pointed by #addr of | ||
1373 | * struct mrq_cpu_vhint_request | ||
1374 | */ | ||
1375 | struct cpu_vhint_data { | ||
1376 | uint32_t ref_clk_hz; /**< reference frequency in Hz */ | ||
1377 | uint16_t pdiv; /**< post divider value */ | ||
1378 | uint16_t mdiv; /**< input divider value */ | ||
1379 | uint16_t ndiv_max; /**< fMAX expressed with max NDIV value */ | ||
1380 | /** table of ndiv values as a function of vINDEX (voltage index) */ | ||
1381 | uint16_t ndiv[80]; | ||
1382 | /** minimum allowed NDIV value */ | ||
1383 | uint16_t ndiv_min; | ||
1384 | /** minimum allowed voltage hint value (as in vINDEX) */ | ||
1385 | uint16_t vfloor; | ||
1386 | /** maximum allowed voltage hint value (as in vINDEX) */ | ||
1387 | uint16_t vceil; | ||
1388 | /** post-multiplier for vindex value */ | ||
1389 | uint16_t vindex_mult; | ||
1390 | /** post-divider for vindex value */ | ||
1391 | uint16_t vindex_div; | ||
1392 | /** reserved for future use */ | ||
1393 | uint16_t reserved[328]; | ||
1394 | } __ABI_PACKED; | ||
1395 | |||
1396 | /** @} */ | ||
1397 | |||
1398 | /** | ||
1399 | * @ingroup MRQ_Codes | ||
1400 | * @def MRQ_ABI_RATCHET | ||
1401 | * @brief ABI ratchet value query | ||
1402 | * | ||
1403 | * * Platforms: T186 | ||
1404 | * * Initiators: Any | ||
1405 | * * Targets: BPMP | ||
1406 | * * Request Payload: @ref mrq_abi_ratchet_request | ||
1407 | * * Response Payload: @ref mrq_abi_ratchet_response | ||
1408 | * @addtogroup ABI_info | ||
1409 | * @{ | ||
1410 | */ | ||
1411 | |||
1412 | /** | ||
1413 | * @brief an ABI compatibility mechanism | ||
1414 | * | ||
1415 | * BPMP_ABI_RATCHET_VALUE may increase for various reasons in a future | ||
1416 | * revision of this header file. | ||
1417 | * 1. That future revision deprecates some MRQ | ||
1418 | * 2. That future revision introduces a breaking change to an existing | ||
1419 | * MRQ or | ||
1420 | * 3. A bug is discovered in an existing implementation of the BPMP-FW | ||
1421 | * (or possibly one of its clients) which warrants deprecating that | ||
1422 | * implementation. | ||
1423 | */ | ||
1424 | #define BPMP_ABI_RATCHET_VALUE 3 | ||
1425 | |||
1426 | /** | ||
1427 | * @brief request with #MRQ_ABI_RATCHET. | ||
1428 | * | ||
1429 | * #ratchet should be #BPMP_ABI_RATCHET_VALUE from the ABI header | ||
1430 | * against which the requester was compiled. | ||
1431 | * | ||
1432 | * If ratchet is less than BPMP's #BPMP_ABI_RATCHET_VALUE, BPMP may | ||
1433 | * reply with mrq_response::err = -#BPMP_ERANGE to indicate that | ||
1434 | * BPMP-FW cannot interoperate correctly with the requester. Requester | ||
1435 | * should cease further communication with BPMP. | ||
1436 | * | ||
1437 | * Otherwise, err shall be 0. | ||
1438 | */ | ||
1439 | struct mrq_abi_ratchet_request { | ||
1440 | /** @brief requester's ratchet value */ | ||
1441 | uint16_t ratchet; | ||
1442 | }; | ||
1443 | |||
1444 | /** | ||
1445 | * @brief response to #MRQ_ABI_RATCHET | ||
1446 | * | ||
1447 | * #ratchet shall be #BPMP_ABI_RATCHET_VALUE from the ABI header | ||
1448 | * against which BPMP firwmare was compiled. | ||
1449 | * | ||
1450 | * If #ratchet is less than the requester's #BPMP_ABI_RATCHET_VALUE, | ||
1451 | * the requster must either interoperate with BPMP according to an ABI | ||
1452 | * header version with BPMP_ABI_RATCHET_VALUE = ratchet or cease | ||
1453 | * communication with BPMP. | ||
1454 | * | ||
1455 | * If mrq_response::err is 0 and ratchet is greater than or equal to the | ||
1456 | * requester's BPMP_ABI_RATCHET_VALUE, the requester should continue | ||
1457 | * normal operation. | ||
1458 | */ | ||
1459 | struct mrq_abi_ratchet_response { | ||
1460 | /** @brief BPMP's ratchet value */ | ||
1461 | uint16_t ratchet; | ||
1462 | }; | ||
1463 | /** @} */ | ||
1464 | |||
1465 | /** | ||
1466 | * @ingroup MRQ_Codes | ||
1467 | * @def MRQ_EMC_DVFS_LATENCY | ||
1468 | * @brief query frequency dependent EMC DVFS latency | ||
1469 | * | ||
1470 | * * Platforms: T186 | ||
1471 | * * Initiators: CCPLEX | ||
1472 | * * Targets: BPMP | ||
1473 | * * Request Payload: N/A | ||
1474 | * * Response Payload: @ref mrq_emc_dvfs_latency_response | ||
1475 | * @addtogroup EMC | ||
1476 | * @{ | ||
1477 | */ | ||
1478 | |||
1479 | /** | ||
1480 | * @brief used by @ref mrq_emc_dvfs_latency_response | ||
1481 | */ | ||
1482 | struct emc_dvfs_latency { | ||
1483 | /** @brief EMC frequency in kHz */ | ||
1484 | uint32_t freq; | ||
1485 | /** @brief EMC DVFS latency in nanoseconds */ | ||
1486 | uint32_t latency; | ||
1487 | } __ABI_PACKED; | ||
1488 | |||
1489 | #define EMC_DVFS_LATENCY_MAX_SIZE 14 | ||
1490 | /** | ||
1491 | * @brief response to #MRQ_EMC_DVFS_LATENCY | ||
1492 | */ | ||
1493 | struct mrq_emc_dvfs_latency_response { | ||
1494 | /** @brief the number valid entries in #pairs */ | ||
1495 | uint32_t num_pairs; | ||
1496 | /** @brief EMC <frequency, latency> information */ | ||
1497 | struct emc_dvfs_latency pairs[EMC_DVFS_LATENCY_MAX_SIZE]; | ||
1498 | } __ABI_PACKED; | ||
1499 | |||
1500 | /** @} */ | ||
1501 | |||
1502 | /** | ||
1503 | * @ingroup MRQ_Codes | ||
1504 | * @def MRQ_TRACE_ITER | ||
1505 | * @brief manage the trace iterator | ||
1506 | * | ||
1507 | * * Platforms: All | ||
1508 | * * Initiators: CCPLEX | ||
1509 | * * Targets: BPMP | ||
1510 | * * Request Payload: N/A | ||
1511 | * * Response Payload: @ref mrq_trace_iter_request | ||
1512 | * @addtogroup Trace | ||
1513 | * @{ | ||
1514 | */ | ||
1515 | enum { | ||
1516 | /** @brief (re)start the tracing now. Ignore older events */ | ||
1517 | TRACE_ITER_INIT = 0, | ||
1518 | /** @brief clobber all events in the trace buffer */ | ||
1519 | TRACE_ITER_CLEAN = 1 | ||
1520 | }; | ||
1521 | |||
1522 | /** | ||
1523 | * @brief request with #MRQ_TRACE_ITER | ||
1524 | */ | ||
1525 | struct mrq_trace_iter_request { | ||
1526 | /** @brief TRACE_ITER_INIT or TRACE_ITER_CLEAN */ | ||
1527 | uint32_t cmd; | ||
1528 | } __ABI_PACKED; | ||
1529 | |||
1530 | /** @} */ | ||
1531 | |||
1532 | /* | ||
1533 | * 4. Enumerations | ||
1534 | */ | ||
1535 | |||
1536 | /* | ||
1537 | * 4.1 CPU enumerations | ||
1538 | * | ||
1539 | * See <mach-t186/system-t186.h> | ||
1540 | * | ||
1541 | * 4.2 CPU Cluster enumerations | ||
1542 | * | ||
1543 | * See <mach-t186/system-t186.h> | ||
1544 | * | ||
1545 | * 4.3 System low power state enumerations | ||
1546 | * | ||
1547 | * See <mach-t186/system-t186.h> | ||
1548 | */ | ||
1549 | |||
1550 | /* | ||
1551 | * 4.4 Clock enumerations | ||
1552 | * | ||
1553 | * For clock enumerations, see <mach-t186/clk-t186.h> | ||
1554 | */ | ||
1555 | |||
1556 | /* | ||
1557 | * 4.5 Reset enumerations | ||
1558 | * | ||
1559 | * For reset enumerations, see <mach-t186/reset-t186.h> | ||
1560 | */ | ||
1561 | |||
1562 | /* | ||
1563 | * 4.6 Thermal sensor enumerations | ||
1564 | * | ||
1565 | * For thermal sensor enumerations, see <mach-t186/thermal-t186.h> | ||
1566 | */ | ||
1567 | |||
1568 | /** | ||
1569 | * @defgroup Error_Codes | ||
1570 | * Negative values for mrq_response::err generally indicate some | ||
1571 | * error. The ABI defines the following error codes. Negating these | ||
1572 | * defines is an exercise left to the user. | ||
1573 | * @{ | ||
1574 | */ | ||
1575 | /** @brief No such file or directory */ | ||
1576 | #define BPMP_ENOENT 2 | ||
1577 | /** @brief No MRQ handler */ | ||
1578 | #define BPMP_ENOHANDLER 3 | ||
1579 | /** @brief I/O error */ | ||
1580 | #define BPMP_EIO 5 | ||
1581 | /** @brief Bad sub-MRQ command */ | ||
1582 | #define BPMP_EBADCMD 6 | ||
1583 | /** @brief Not enough memory */ | ||
1584 | #define BPMP_ENOMEM 12 | ||
1585 | /** @brief Permission denied */ | ||
1586 | #define BPMP_EACCES 13 | ||
1587 | /** @brief Bad address */ | ||
1588 | #define BPMP_EFAULT 14 | ||
1589 | /** @brief No such device */ | ||
1590 | #define BPMP_ENODEV 19 | ||
1591 | /** @brief Argument is a directory */ | ||
1592 | #define BPMP_EISDIR 21 | ||
1593 | /** @brief Invalid argument */ | ||
1594 | #define BPMP_EINVAL 22 | ||
1595 | /** @brief Timeout during operation */ | ||
1596 | #define BPMP_ETIMEDOUT 23 | ||
1597 | /** @brief Out of range */ | ||
1598 | #define BPMP_ERANGE 34 | ||
1599 | /** @} */ | ||
1600 | /** @} */ | ||
1601 | #endif | ||
diff --git a/include/soc/tegra/bpmp.h b/include/soc/tegra/bpmp.h new file mode 100644 index 000000000000..13dcd44e91bb --- /dev/null +++ b/include/soc/tegra/bpmp.h | |||
@@ -0,0 +1,141 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | #ifndef __SOC_TEGRA_BPMP_H | ||
15 | #define __SOC_TEGRA_BPMP_H | ||
16 | |||
17 | #include <linux/mailbox_client.h> | ||
18 | #include <linux/reset-controller.h> | ||
19 | #include <linux/semaphore.h> | ||
20 | #include <linux/types.h> | ||
21 | |||
22 | #include <soc/tegra/bpmp-abi.h> | ||
23 | |||
24 | struct tegra_bpmp_clk; | ||
25 | |||
26 | struct tegra_bpmp_soc { | ||
27 | struct { | ||
28 | struct { | ||
29 | unsigned int offset; | ||
30 | unsigned int count; | ||
31 | unsigned int timeout; | ||
32 | } cpu_tx, thread, cpu_rx; | ||
33 | } channels; | ||
34 | unsigned int num_resets; | ||
35 | }; | ||
36 | |||
37 | struct tegra_bpmp_mb_data { | ||
38 | u32 code; | ||
39 | u32 flags; | ||
40 | u8 data[MSG_DATA_MIN_SZ]; | ||
41 | } __packed; | ||
42 | |||
43 | struct tegra_bpmp_channel { | ||
44 | struct tegra_bpmp *bpmp; | ||
45 | struct tegra_bpmp_mb_data *ib; | ||
46 | struct tegra_bpmp_mb_data *ob; | ||
47 | struct completion completion; | ||
48 | struct tegra_ivc *ivc; | ||
49 | }; | ||
50 | |||
51 | typedef void (*tegra_bpmp_mrq_handler_t)(unsigned int mrq, | ||
52 | struct tegra_bpmp_channel *channel, | ||
53 | void *data); | ||
54 | |||
55 | struct tegra_bpmp_mrq { | ||
56 | struct list_head list; | ||
57 | unsigned int mrq; | ||
58 | tegra_bpmp_mrq_handler_t handler; | ||
59 | void *data; | ||
60 | }; | ||
61 | |||
62 | struct tegra_bpmp { | ||
63 | const struct tegra_bpmp_soc *soc; | ||
64 | struct device *dev; | ||
65 | |||
66 | struct { | ||
67 | struct gen_pool *pool; | ||
68 | dma_addr_t phys; | ||
69 | void *virt; | ||
70 | } tx, rx; | ||
71 | |||
72 | struct { | ||
73 | struct mbox_client client; | ||
74 | struct mbox_chan *channel; | ||
75 | } mbox; | ||
76 | |||
77 | struct tegra_bpmp_channel *channels; | ||
78 | unsigned int num_channels; | ||
79 | |||
80 | struct { | ||
81 | unsigned long *allocated; | ||
82 | unsigned long *busy; | ||
83 | unsigned int count; | ||
84 | struct semaphore lock; | ||
85 | } threaded; | ||
86 | |||
87 | struct list_head mrqs; | ||
88 | spinlock_t lock; | ||
89 | |||
90 | struct tegra_bpmp_clk **clocks; | ||
91 | unsigned int num_clocks; | ||
92 | |||
93 | struct reset_controller_dev rstc; | ||
94 | }; | ||
95 | |||
96 | struct tegra_bpmp *tegra_bpmp_get(struct device *dev); | ||
97 | void tegra_bpmp_put(struct tegra_bpmp *bpmp); | ||
98 | |||
99 | struct tegra_bpmp_message { | ||
100 | unsigned int mrq; | ||
101 | |||
102 | struct { | ||
103 | const void *data; | ||
104 | size_t size; | ||
105 | } tx; | ||
106 | |||
107 | struct { | ||
108 | void *data; | ||
109 | size_t size; | ||
110 | } rx; | ||
111 | }; | ||
112 | |||
113 | int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp, | ||
114 | struct tegra_bpmp_message *msg); | ||
115 | int tegra_bpmp_transfer(struct tegra_bpmp *bpmp, | ||
116 | struct tegra_bpmp_message *msg); | ||
117 | |||
118 | int tegra_bpmp_request_mrq(struct tegra_bpmp *bpmp, unsigned int mrq, | ||
119 | tegra_bpmp_mrq_handler_t handler, void *data); | ||
120 | void tegra_bpmp_free_mrq(struct tegra_bpmp *bpmp, unsigned int mrq, | ||
121 | void *data); | ||
122 | |||
123 | #if IS_ENABLED(CONFIG_CLK_TEGRA_BPMP) | ||
124 | int tegra_bpmp_init_clocks(struct tegra_bpmp *bpmp); | ||
125 | #else | ||
126 | static inline int tegra_bpmp_init_clocks(struct tegra_bpmp *bpmp) | ||
127 | { | ||
128 | return 0; | ||
129 | } | ||
130 | #endif | ||
131 | |||
132 | #if IS_ENABLED(CONFIG_RESET_TEGRA_BPMP) | ||
133 | int tegra_bpmp_init_resets(struct tegra_bpmp *bpmp); | ||
134 | #else | ||
135 | static inline int tegra_bpmp_init_resets(struct tegra_bpmp *bpmp) | ||
136 | { | ||
137 | return 0; | ||
138 | } | ||
139 | #endif | ||
140 | |||
141 | #endif /* __SOC_TEGRA_BPMP_H */ | ||
diff --git a/include/soc/tegra/ivc.h b/include/soc/tegra/ivc.h new file mode 100644 index 000000000000..b13cc43ad9d8 --- /dev/null +++ b/include/soc/tegra/ivc.h | |||
@@ -0,0 +1,109 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | #ifndef __TEGRA_IVC_H | ||
15 | |||
16 | #include <linux/device.h> | ||
17 | #include <linux/dma-mapping.h> | ||
18 | #include <linux/types.h> | ||
19 | |||
20 | struct tegra_ivc_header; | ||
21 | |||
22 | struct tegra_ivc { | ||
23 | struct device *peer; | ||
24 | |||
25 | struct { | ||
26 | struct tegra_ivc_header *channel; | ||
27 | unsigned int position; | ||
28 | dma_addr_t phys; | ||
29 | } rx, tx; | ||
30 | |||
31 | void (*notify)(struct tegra_ivc *ivc, void *data); | ||
32 | void *notify_data; | ||
33 | |||
34 | unsigned int num_frames; | ||
35 | size_t frame_size; | ||
36 | }; | ||
37 | |||
38 | /** | ||
39 | * tegra_ivc_read_get_next_frame - Peek at the next frame to receive | ||
40 | * @ivc pointer of the IVC channel | ||
41 | * | ||
42 | * Peek at the next frame to be received, without removing it from | ||
43 | * the queue. | ||
44 | * | ||
45 | * Returns a pointer to the frame, or an error encoded pointer. | ||
46 | */ | ||
47 | void *tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc); | ||
48 | |||
49 | /** | ||
50 | * tegra_ivc_read_advance - Advance the read queue | ||
51 | * @ivc pointer of the IVC channel | ||
52 | * | ||
53 | * Advance the read queue | ||
54 | * | ||
55 | * Returns 0, or a negative error value if failed. | ||
56 | */ | ||
57 | int tegra_ivc_read_advance(struct tegra_ivc *ivc); | ||
58 | |||
59 | /** | ||
60 | * tegra_ivc_write_get_next_frame - Poke at the next frame to transmit | ||
61 | * @ivc pointer of the IVC channel | ||
62 | * | ||
63 | * Get access to the next frame. | ||
64 | * | ||
65 | * Returns a pointer to the frame, or an error encoded pointer. | ||
66 | */ | ||
67 | void *tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc); | ||
68 | |||
69 | /** | ||
70 | * tegra_ivc_write_advance - Advance the write queue | ||
71 | * @ivc pointer of the IVC channel | ||
72 | * | ||
73 | * Advance the write queue | ||
74 | * | ||
75 | * Returns 0, or a negative error value if failed. | ||
76 | */ | ||
77 | int tegra_ivc_write_advance(struct tegra_ivc *ivc); | ||
78 | |||
79 | /** | ||
80 | * tegra_ivc_notified - handle internal messages | ||
81 | * @ivc pointer of the IVC channel | ||
82 | * | ||
83 | * This function must be called following every notification. | ||
84 | * | ||
85 | * Returns 0 if the channel is ready for communication, or -EAGAIN if a channel | ||
86 | * reset is in progress. | ||
87 | */ | ||
88 | int tegra_ivc_notified(struct tegra_ivc *ivc); | ||
89 | |||
90 | /** | ||
91 | * tegra_ivc_reset - initiates a reset of the shared memory state | ||
92 | * @ivc pointer of the IVC channel | ||
93 | * | ||
94 | * This function must be called after a channel is reserved before it is used | ||
95 | * for communication. The channel will be ready for use when a subsequent call | ||
96 | * to notify the remote of the channel reset. | ||
97 | */ | ||
98 | void tegra_ivc_reset(struct tegra_ivc *ivc); | ||
99 | |||
100 | size_t tegra_ivc_align(size_t size); | ||
101 | unsigned tegra_ivc_total_queue_size(unsigned queue_size); | ||
102 | int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx, | ||
103 | dma_addr_t rx_phys, void *tx, dma_addr_t tx_phys, | ||
104 | unsigned int num_frames, size_t frame_size, | ||
105 | void (*notify)(struct tegra_ivc *ivc, void *data), | ||
106 | void *data); | ||
107 | void tegra_ivc_cleanup(struct tegra_ivc *ivc); | ||
108 | |||
109 | #endif /* __TEGRA_IVC_H */ | ||