diff options
| author | Deepak Nibade <dnibade@nvidia.com> | 2016-02-29 05:34:16 -0500 |
|---|---|---|
| committer | Deepak Nibade <dnibade@nvidia.com> | 2016-03-08 03:28:17 -0500 |
| commit | 9a8a533e18d81964df148c225773eea2b76039e1 (patch) | |
| tree | 0ba0950ce1a489d6c62f98bad1ab6b7781ac07e1 /drivers/gpu | |
| parent | 5672f8015e9fecf42a6374cf5990a88abd279d68 (diff) | |
gpu: host1x: add T186 support
Add host1x05 version and fill in the h/w details
in host1x05_info
Add all the hardware accessors for T186
(channel, sync, uclass accessors)
Add hardware support files for host1x channel,
syncpoints, cdma, pushbuffer, interrupt, and debug support
Keep gather filter disabled
Things working with this :
- cdma operations
- basic channel job submit path
- syncpoint support
- syncpoint interrupt mechanism
- debug dump
With this support, below tests pass for VIC client
$nvrm_channel channel_Basic
$nvrm_channel --module=vic
Bug 1704301
Change-Id: I7d97560cb1e3a57733fa0853936b0783c71b7060
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-on: http://git-master/r/1021434
GVS: Gerrit_Virtual_Submit
Reviewed-by: Arto Merilainen <amerilainen@nvidia.com>
Reviewed-by: Shridhar Rasal <srasal@nvidia.com>
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/host1x/Makefile | 8 | ||||
| -rw-r--r-- | drivers/gpu/host1x/dev_t186.c | 40 | ||||
| -rw-r--r-- | drivers/gpu/host1x/dev_t186.h | 34 | ||||
| -rw-r--r-- | drivers/gpu/host1x/hw/cdma_hw_t186.c | 340 | ||||
| -rw-r--r-- | drivers/gpu/host1x/hw/channel_hw_t186.c | 297 | ||||
| -rw-r--r-- | drivers/gpu/host1x/hw/debug_hw_t186.c | 288 | ||||
| -rw-r--r-- | drivers/gpu/host1x/hw/host1x05.c | 40 | ||||
| -rw-r--r-- | drivers/gpu/host1x/hw/host1x05.h | 24 | ||||
| -rw-r--r-- | drivers/gpu/host1x/hw/host1x05_hardware.h | 128 | ||||
| -rw-r--r-- | drivers/gpu/host1x/hw/hw_host1x05_channel.h | 169 | ||||
| -rw-r--r-- | drivers/gpu/host1x/hw/hw_host1x05_sync.h | 321 | ||||
| -rw-r--r-- | drivers/gpu/host1x/hw/hw_host1x05_uclass.h | 157 | ||||
| -rw-r--r-- | drivers/gpu/host1x/hw/intr_hw_t186.c | 247 | ||||
| -rw-r--r-- | drivers/gpu/host1x/hw/syncpt_hw_t186.c | 126 |
14 files changed, 2219 insertions, 0 deletions
diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile new file mode 100644 index 000000000..9c8c6467b --- /dev/null +++ b/drivers/gpu/host1x/Makefile | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | ccflags-y += -Idrivers/gpu/host1x | ||
| 2 | ccflags-y += -I../kernel-t18x/drivers/gpu/host1x | ||
| 3 | |||
| 4 | host1x-t186-y = \ | ||
| 5 | dev_t186.o \ | ||
| 6 | hw/host1x05.o | ||
| 7 | |||
| 8 | obj-$(CONFIG_TEGRA_HOST1X) += host1x-t186.o | ||
diff --git a/drivers/gpu/host1x/dev_t186.c b/drivers/gpu/host1x/dev_t186.c new file mode 100644 index 000000000..e4d148760 --- /dev/null +++ b/drivers/gpu/host1x/dev_t186.c | |||
| @@ -0,0 +1,40 @@ | |||
| 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 | * 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 | #include "dev.h" | ||
| 18 | #include "dev_t186.h" | ||
| 19 | |||
| 20 | #include "hw/host1x05.h" | ||
| 21 | |||
| 22 | struct host1x_info host1x05_info = { | ||
| 23 | .nb_channels = 63, | ||
| 24 | .nb_pts = 576, | ||
| 25 | .nb_mlocks = 24, | ||
| 26 | .nb_bases = 16, | ||
| 27 | .init = host1x05_init, | ||
| 28 | .sync_offset = 0x0, | ||
| 29 | .gather_filter_enabled = false, | ||
| 30 | }; | ||
| 31 | |||
| 32 | void host1x_writel(struct host1x *host1x, u32 v, u32 r) | ||
| 33 | { | ||
| 34 | writel(v, host1x->regs + r); | ||
| 35 | } | ||
| 36 | |||
| 37 | u32 host1x_readl(struct host1x *host1x, u32 r) | ||
| 38 | { | ||
| 39 | return readl(host1x->regs + r); | ||
| 40 | } | ||
diff --git a/drivers/gpu/host1x/dev_t186.h b/drivers/gpu/host1x/dev_t186.h new file mode 100644 index 000000000..be9726e88 --- /dev/null +++ b/drivers/gpu/host1x/dev_t186.h | |||
| @@ -0,0 +1,34 @@ | |||
| 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 | * 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 HOST1X_DEV_T186_H | ||
| 18 | #define HOST1X_DEV_T186_H | ||
| 19 | |||
| 20 | #include "dev.h" | ||
| 21 | |||
| 22 | extern struct host1x_info host1x05_info; | ||
| 23 | |||
| 24 | void host1x_writel(struct host1x *host1x, u32 v, u32 r); | ||
| 25 | u32 host1x_readl(struct host1x *host1x, u32 r); | ||
| 26 | |||
| 27 | static inline void host1x_hw_sync_get_mutex_owner(struct host1x *host, | ||
| 28 | struct host1x_syncpt *sp, | ||
| 29 | unsigned int mutex_id, bool *cpu, bool *ch, | ||
| 30 | unsigned int *chid) | ||
| 31 | { | ||
| 32 | host->syncpt_op->get_mutex_owner(sp, mutex_id, cpu, ch, chid); | ||
| 33 | } | ||
| 34 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/cdma_hw_t186.c b/drivers/gpu/host1x/hw/cdma_hw_t186.c new file mode 100644 index 000000000..e903f3e8b --- /dev/null +++ b/drivers/gpu/host1x/hw/cdma_hw_t186.c | |||
| @@ -0,0 +1,340 @@ | |||
| 1 | /* | ||
| 2 | * Tegra host1x Command DMA | ||
| 3 | * | ||
| 4 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms and conditions of the GNU General Public License, | ||
| 8 | * version 2, as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 13 | * more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/scatterlist.h> | ||
| 21 | #include <linux/dma-mapping.h> | ||
| 22 | |||
| 23 | #include "cdma.h" | ||
| 24 | #include "channel.h" | ||
| 25 | #include "dev.h" | ||
| 26 | #include "debug.h" | ||
| 27 | |||
| 28 | /* | ||
| 29 | * Put the restart at the end of pushbuffer memory | ||
| 30 | */ | ||
| 31 | static void push_buffer_init(struct push_buffer *pb) | ||
| 32 | { | ||
| 33 | *(u32 *)(pb->mapped + pb->size_bytes) = host1x_opcode_restart(0); | ||
| 34 | } | ||
| 35 | |||
| 36 | /* | ||
| 37 | * Increment timedout buffer's syncpt via CPU. | ||
| 38 | */ | ||
| 39 | static void cdma_timeout_handle(struct host1x_cdma *cdma, u32 getptr, | ||
| 40 | u32 nr_slots) | ||
| 41 | { | ||
| 42 | struct host1x *host1x = cdma_to_host1x(cdma); | ||
| 43 | struct push_buffer *pb = &cdma->push_buffer; | ||
| 44 | |||
| 45 | /* NOP all the PB slots */ | ||
| 46 | while (nr_slots--) { | ||
| 47 | u32 *p = (u32 *)(pb->mapped + getptr); | ||
| 48 | *(p++) = HOST1X_OPCODE_NOP; | ||
| 49 | *(p++) = HOST1X_OPCODE_NOP; | ||
| 50 | dev_dbg(host1x->dev, "%s: NOP at %pad+%#x\n", __func__, | ||
| 51 | &pb->phys, getptr); | ||
| 52 | getptr = (getptr + 8) & (pb->size_bytes - 1); | ||
| 53 | } | ||
| 54 | wmb(); | ||
| 55 | } | ||
| 56 | |||
| 57 | /* | ||
| 58 | * Start channel DMA | ||
| 59 | */ | ||
| 60 | static void cdma_start(struct host1x_cdma *cdma) | ||
| 61 | { | ||
| 62 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
| 63 | |||
| 64 | if (cdma->running) | ||
| 65 | return; | ||
| 66 | |||
| 67 | cdma->last_pos = cdma->push_buffer.pos; | ||
| 68 | |||
| 69 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, | ||
| 70 | HOST1X_CHANNEL_DMACTRL); | ||
| 71 | |||
| 72 | /* set base, put and end pointer */ | ||
| 73 | host1x_ch_writel(ch, cdma->push_buffer.phys, HOST1X_CHANNEL_DMASTART); | ||
| 74 | host1x_ch_writel(ch, cdma->push_buffer.pos, HOST1X_CHANNEL_DMAPUT); | ||
| 75 | host1x_ch_writel(ch, cdma->push_buffer.phys + | ||
| 76 | cdma->push_buffer.size_bytes + 4, | ||
| 77 | HOST1X_CHANNEL_DMAEND); | ||
| 78 | |||
| 79 | /* reset GET */ | ||
| 80 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP | | ||
| 81 | HOST1X_CHANNEL_DMACTRL_DMAGETRST | | ||
| 82 | HOST1X_CHANNEL_DMACTRL_DMAINITGET, | ||
| 83 | HOST1X_CHANNEL_DMACTRL); | ||
| 84 | |||
| 85 | host1x_channel_enable_gather_filter(ch); | ||
| 86 | |||
| 87 | /* start the command DMA */ | ||
| 88 | host1x_ch_writel(ch, 0, HOST1X_CHANNEL_DMACTRL); | ||
| 89 | |||
| 90 | cdma->running = true; | ||
| 91 | } | ||
| 92 | |||
| 93 | /* | ||
| 94 | * Similar to cdma_start(), but rather than starting from an idle | ||
| 95 | * state (where DMA GET is set to DMA PUT), on a timeout we restore | ||
| 96 | * DMA GET from an explicit value (so DMA may again be pending). | ||
| 97 | */ | ||
| 98 | static void cdma_timeout_restart(struct host1x_cdma *cdma, u32 getptr) | ||
| 99 | { | ||
| 100 | struct host1x *host1x = cdma_to_host1x(cdma); | ||
| 101 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
| 102 | |||
| 103 | if (cdma->running) | ||
| 104 | return; | ||
| 105 | |||
| 106 | cdma->last_pos = cdma->push_buffer.pos; | ||
| 107 | |||
| 108 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, | ||
| 109 | HOST1X_CHANNEL_DMACTRL); | ||
| 110 | |||
| 111 | /* set base, end pointer (all of memory) */ | ||
| 112 | host1x_ch_writel(ch, cdma->push_buffer.phys, HOST1X_CHANNEL_DMASTART); | ||
| 113 | host1x_ch_writel(ch, cdma->push_buffer.phys + | ||
| 114 | cdma->push_buffer.size_bytes, | ||
| 115 | HOST1X_CHANNEL_DMAEND); | ||
| 116 | |||
| 117 | /* set GET, by loading the value in PUT (then reset GET) */ | ||
| 118 | host1x_ch_writel(ch, getptr, HOST1X_CHANNEL_DMAPUT); | ||
| 119 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP | | ||
| 120 | HOST1X_CHANNEL_DMACTRL_DMAGETRST | | ||
| 121 | HOST1X_CHANNEL_DMACTRL_DMAINITGET, | ||
| 122 | HOST1X_CHANNEL_DMACTRL); | ||
| 123 | |||
| 124 | dev_dbg(host1x->dev, | ||
| 125 | "%s: DMA GET 0x%x, PUT HW 0x%x / shadow 0x%x\n", __func__, | ||
| 126 | host1x_ch_readl(ch, HOST1X_CHANNEL_DMAGET), | ||
| 127 | host1x_ch_readl(ch, HOST1X_CHANNEL_DMAPUT), | ||
| 128 | cdma->last_pos); | ||
| 129 | |||
| 130 | /* deassert GET reset and set PUT */ | ||
| 131 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, | ||
| 132 | HOST1X_CHANNEL_DMACTRL); | ||
| 133 | host1x_ch_writel(ch, cdma->push_buffer.pos, HOST1X_CHANNEL_DMAPUT); | ||
| 134 | |||
| 135 | host1x_channel_enable_gather_filter(ch); | ||
| 136 | |||
| 137 | /* start the command DMA */ | ||
| 138 | host1x_ch_writel(ch, 0, HOST1X_CHANNEL_DMACTRL); | ||
| 139 | |||
| 140 | cdma->running = true; | ||
| 141 | } | ||
| 142 | |||
| 143 | /* | ||
| 144 | * Kick channel DMA into action by writing its PUT offset (if it has changed) | ||
| 145 | */ | ||
| 146 | static void cdma_flush(struct host1x_cdma *cdma) | ||
| 147 | { | ||
| 148 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
| 149 | |||
| 150 | if (cdma->push_buffer.pos != cdma->last_pos) { | ||
| 151 | host1x_ch_writel(ch, cdma->push_buffer.pos, | ||
| 152 | HOST1X_CHANNEL_DMAPUT); | ||
| 153 | cdma->last_pos = cdma->push_buffer.pos; | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | static void cdma_stop(struct host1x_cdma *cdma) | ||
| 158 | { | ||
| 159 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
| 160 | |||
| 161 | mutex_lock(&cdma->lock); | ||
| 162 | if (cdma->running) { | ||
| 163 | host1x_cdma_wait_locked(cdma, CDMA_EVENT_SYNC_QUEUE_EMPTY); | ||
| 164 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, | ||
| 165 | HOST1X_CHANNEL_DMACTRL); | ||
| 166 | cdma->running = false; | ||
| 167 | } | ||
| 168 | mutex_unlock(&cdma->lock); | ||
| 169 | } | ||
| 170 | |||
| 171 | /* | ||
| 172 | * Stops both channel's command processor and CDMA immediately. | ||
| 173 | * Also, tears down the channel and resets corresponding module. | ||
| 174 | */ | ||
| 175 | static void cdma_freeze(struct host1x_cdma *cdma) | ||
| 176 | { | ||
| 177 | struct host1x *host = cdma_to_host1x(cdma); | ||
| 178 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
| 179 | u32 cmdproc_stop; | ||
| 180 | |||
| 181 | if (cdma->torndown && !cdma->running) { | ||
| 182 | dev_warn(host->dev, "Already torn down\n"); | ||
| 183 | return; | ||
| 184 | } | ||
| 185 | |||
| 186 | dev_dbg(host->dev, "freezing channel (id %d)\n", ch->id); | ||
| 187 | |||
| 188 | cmdproc_stop = host1x_ch_readl(ch, HOST1X_SYNC_CMDPROC_STOP); | ||
| 189 | cmdproc_stop |= BIT(0); | ||
| 190 | host1x_ch_writel(ch, cmdproc_stop, HOST1X_SYNC_CMDPROC_STOP); | ||
| 191 | |||
| 192 | dev_dbg(host->dev, "%s: DMA GET 0x%x, PUT HW 0x%x / shadow 0x%x\n", | ||
| 193 | __func__, host1x_ch_readl(ch, HOST1X_CHANNEL_DMAGET), | ||
| 194 | host1x_ch_readl(ch, HOST1X_CHANNEL_DMAPUT), | ||
| 195 | cdma->last_pos); | ||
| 196 | |||
| 197 | host1x_ch_writel(ch, HOST1X_CHANNEL_DMACTRL_DMASTOP, | ||
| 198 | HOST1X_CHANNEL_DMACTRL); | ||
| 199 | |||
| 200 | host1x_ch_writel(ch, BIT(0), HOST1X_SYNC_CH_TEARDOWN); | ||
| 201 | |||
| 202 | cdma->running = false; | ||
| 203 | cdma->torndown = true; | ||
| 204 | } | ||
| 205 | |||
| 206 | static void cdma_resume(struct host1x_cdma *cdma, u32 getptr) | ||
| 207 | { | ||
| 208 | struct host1x *host1x = cdma_to_host1x(cdma); | ||
| 209 | struct host1x_channel *ch = cdma_to_channel(cdma); | ||
| 210 | u32 cmdproc_stop; | ||
| 211 | |||
| 212 | dev_dbg(host1x->dev, | ||
| 213 | "resuming channel (id %d, DMAGET restart = 0x%x)\n", | ||
| 214 | ch->id, getptr); | ||
| 215 | |||
| 216 | cmdproc_stop = host1x_ch_readl(ch, HOST1X_SYNC_CMDPROC_STOP); | ||
| 217 | cmdproc_stop &= ~(BIT(0)); | ||
| 218 | host1x_ch_writel(ch, cmdproc_stop, HOST1X_SYNC_CMDPROC_STOP); | ||
| 219 | |||
| 220 | cdma->torndown = false; | ||
| 221 | cdma_timeout_restart(cdma, getptr); | ||
| 222 | } | ||
| 223 | |||
| 224 | /* | ||
| 225 | * If this timeout fires, it indicates the current sync_queue entry has | ||
| 226 | * exceeded its TTL and the userctx should be timed out and remaining | ||
| 227 | * submits already issued cleaned up (future submits return an error). | ||
| 228 | */ | ||
| 229 | static void cdma_timeout_handler(struct work_struct *work) | ||
| 230 | { | ||
| 231 | struct host1x_cdma *cdma; | ||
| 232 | struct host1x *host1x; | ||
| 233 | struct host1x_channel *ch; | ||
| 234 | bool has_timedout = 0; | ||
| 235 | |||
| 236 | u32 prev_cmdproc, cmdproc_stop; | ||
| 237 | |||
| 238 | unsigned int i; | ||
| 239 | |||
| 240 | cdma = container_of(to_delayed_work(work), struct host1x_cdma, | ||
| 241 | timeout.wq); | ||
| 242 | host1x = cdma_to_host1x(cdma); | ||
| 243 | ch = cdma_to_channel(cdma); | ||
| 244 | |||
| 245 | host1x_debug_dump(cdma_to_host1x(cdma)); | ||
| 246 | |||
| 247 | mutex_lock(&cdma->lock); | ||
| 248 | |||
| 249 | if (!cdma->timeout.client) { | ||
| 250 | dev_dbg(host1x->dev, | ||
| 251 | "cdma_timeout: expired, but has no clientid\n"); | ||
| 252 | mutex_unlock(&cdma->lock); | ||
| 253 | return; | ||
| 254 | } | ||
| 255 | |||
| 256 | /* stop processing to get a clean snapshot */ | ||
| 257 | prev_cmdproc = host1x_ch_readl(ch, HOST1X_SYNC_CMDPROC_STOP); | ||
| 258 | cmdproc_stop = prev_cmdproc | BIT(0); | ||
| 259 | host1x_ch_writel(ch, cmdproc_stop, HOST1X_SYNC_CMDPROC_STOP); | ||
| 260 | |||
| 261 | dev_dbg(host1x->dev, "cdma_timeout: cmdproc was 0x%x is 0x%x\n", | ||
| 262 | prev_cmdproc, cmdproc_stop); | ||
| 263 | |||
| 264 | for (i = 0; i < cdma->timeout.num_syncpts; ++i) { | ||
| 265 | u32 id = cdma->timeout.syncpts[i].id; | ||
| 266 | u32 end = cdma->timeout.syncpts[i].end; | ||
| 267 | struct host1x_syncpt *syncpt = host1x_syncpt_get(host1x, id); | ||
| 268 | |||
| 269 | host1x_syncpt_load(syncpt); | ||
| 270 | |||
| 271 | has_timedout = !host1x_syncpt_is_expired(syncpt, end); | ||
| 272 | if (has_timedout) | ||
| 273 | break; | ||
| 274 | } | ||
| 275 | |||
| 276 | /* has buffer actually completed? */ | ||
| 277 | if (!has_timedout) { | ||
| 278 | dev_dbg(host1x->dev, | ||
| 279 | "cdma_timeout: expired, but buffer had completed\n"); | ||
| 280 | /* restore */ | ||
| 281 | cmdproc_stop = prev_cmdproc & ~(BIT(0)); | ||
| 282 | host1x_ch_writel(ch, cmdproc_stop, | ||
| 283 | HOST1X_SYNC_CMDPROC_STOP); | ||
| 284 | mutex_unlock(&cdma->lock); | ||
| 285 | return; | ||
| 286 | } | ||
| 287 | |||
| 288 | for (i = 0; i < cdma->timeout.num_syncpts; ++i) { | ||
| 289 | u32 id = cdma->timeout.syncpts[i].id; | ||
| 290 | struct host1x_syncpt *syncpt = host1x_syncpt_get(host1x, id); | ||
| 291 | u32 syncpt_val = host1x_syncpt_read_min(syncpt); | ||
| 292 | |||
| 293 | dev_warn(host1x->dev, "%s: timeout: %d (%s), HW thresh %d, done %d\n", | ||
| 294 | __func__, syncpt->id, syncpt->name, | ||
| 295 | syncpt_val, syncpt_val); | ||
| 296 | } | ||
| 297 | |||
| 298 | /* stop HW, resetting channel/module */ | ||
| 299 | host1x_hw_cdma_freeze(host1x, cdma); | ||
| 300 | |||
| 301 | host1x_cdma_update_sync_queue(cdma, ch->dev); | ||
| 302 | mutex_unlock(&cdma->lock); | ||
| 303 | } | ||
| 304 | |||
| 305 | /* | ||
| 306 | * Init timeout resources | ||
| 307 | */ | ||
| 308 | static int cdma_timeout_init(struct host1x_cdma *cdma) | ||
| 309 | { | ||
| 310 | INIT_DELAYED_WORK(&cdma->timeout.wq, cdma_timeout_handler); | ||
| 311 | cdma->timeout.initialized = true; | ||
| 312 | |||
| 313 | return 0; | ||
| 314 | } | ||
| 315 | |||
| 316 | /* | ||
| 317 | * Clean up timeout resources | ||
| 318 | */ | ||
| 319 | static void cdma_timeout_destroy(struct host1x_cdma *cdma) | ||
| 320 | { | ||
| 321 | if (cdma->timeout.initialized) | ||
| 322 | cancel_delayed_work(&cdma->timeout.wq); | ||
| 323 | cdma->timeout.initialized = false; | ||
| 324 | } | ||
| 325 | |||
| 326 | static const struct host1x_cdma_ops host1x_cdma_t186_ops = { | ||
| 327 | .start = cdma_start, | ||
| 328 | .stop = cdma_stop, | ||
| 329 | .flush = cdma_flush, | ||
| 330 | |||
| 331 | .timeout_init = cdma_timeout_init, | ||
| 332 | .timeout_destroy = cdma_timeout_destroy, | ||
| 333 | .freeze = cdma_freeze, | ||
| 334 | .resume = cdma_resume, | ||
| 335 | .timeout_handle = cdma_timeout_handle, | ||
| 336 | }; | ||
| 337 | |||
| 338 | static const struct host1x_pushbuffer_ops host1x_pushbuffer_t186_ops = { | ||
| 339 | .init = push_buffer_init, | ||
| 340 | }; | ||
diff --git a/drivers/gpu/host1x/hw/channel_hw_t186.c b/drivers/gpu/host1x/hw/channel_hw_t186.c new file mode 100644 index 000000000..2b90ba638 --- /dev/null +++ b/drivers/gpu/host1x/hw/channel_hw_t186.c | |||
| @@ -0,0 +1,297 @@ | |||
| 1 | /* | ||
| 2 | * Tegra host1x Channel | ||
| 3 | * | ||
| 4 | * Copyright (C) 2016 NVIDIA CORPORATION. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms and conditions of the GNU General Public License, | ||
| 8 | * version 2, as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 13 | * more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/host1x.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | #include <linux/iommu.h> | ||
| 22 | |||
| 23 | #include <trace/events/host1x.h> | ||
| 24 | |||
| 25 | #include "dev_t186.h" | ||
| 26 | #include "channel.h" | ||
| 27 | #include "intr.h" | ||
| 28 | #include "job.h" | ||
| 29 | |||
| 30 | #define TRACE_MAX_LENGTH 128U | ||
| 31 | |||
| 32 | static void trace_write_gather(struct host1x_cdma *cdma, struct host1x_bo *bo, | ||
| 33 | u32 offset, u32 words) | ||
| 34 | { | ||
| 35 | struct device *dev = cdma_to_channel(cdma)->dev; | ||
| 36 | void *mem = NULL; | ||
| 37 | |||
| 38 | if (host1x_debug_trace_cmdbuf) | ||
| 39 | mem = host1x_bo_mmap(bo); | ||
| 40 | |||
| 41 | if (mem) { | ||
| 42 | u32 i; | ||
| 43 | /* | ||
| 44 | * Write in batches of 128 as there seems to be a limit | ||
| 45 | * of how much you can output to ftrace at once. | ||
| 46 | */ | ||
| 47 | for (i = 0; i < words; i += TRACE_MAX_LENGTH) { | ||
| 48 | u32 num_words = min(words - i, TRACE_MAX_LENGTH); | ||
| 49 | u32 next_offset = offset + i * sizeof(u32); | ||
| 50 | |||
| 51 | trace_host1x_cdma_push_gather(dev_name(dev), bo, | ||
| 52 | num_words, | ||
| 53 | next_offset, | ||
| 54 | mem); | ||
| 55 | } | ||
| 56 | |||
| 57 | host1x_bo_munmap(bo, mem); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | |||
| 61 | static void channel_push_wait(struct host1x_channel *channel, | ||
| 62 | u32 id, u32 thresh) | ||
| 63 | { | ||
| 64 | host1x_cdma_push(&channel->cdma, | ||
| 65 | host1x_opcode_setclass(HOST1X_CLASS_HOST1X, | ||
| 66 | HOST1X_UCLASS_LOAD_SYNCPT_PAYLOAD_32, 1), | ||
| 67 | thresh); | ||
| 68 | host1x_cdma_push(&channel->cdma, | ||
| 69 | host1x_opcode_setclass(HOST1X_CLASS_HOST1X, | ||
| 70 | HOST1X_UCLASS_WAIT_SYNCPT_32, 1), | ||
| 71 | id); | ||
| 72 | } | ||
| 73 | |||
| 74 | static inline void serialize(struct host1x_job *job) | ||
| 75 | { | ||
| 76 | struct host1x_channel *ch = job->channel; | ||
| 77 | struct host1x *host = dev_get_drvdata(ch->dev->parent); | ||
| 78 | unsigned int i; | ||
| 79 | |||
| 80 | for (i = 0; i < job->num_syncpts; ++i) { | ||
| 81 | u32 syncpt_id = job->syncpts[i].id; | ||
| 82 | struct host1x_syncpt *syncpt = | ||
| 83 | host1x_syncpt_get(host, syncpt_id); | ||
| 84 | |||
| 85 | /* | ||
| 86 | * Force serialization by inserting a host wait for the | ||
| 87 | * previous job to finish before this one can commence. | ||
| 88 | */ | ||
| 89 | channel_push_wait(ch, syncpt_id, host1x_syncpt_read_max(syncpt)); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | static void add_sync_waits(struct host1x_job *job) | ||
| 94 | { | ||
| 95 | struct host1x *host = dev_get_drvdata(job->channel->dev->parent); | ||
| 96 | unsigned int i; | ||
| 97 | |||
| 98 | for (i = 0; i < job->num_gathers; i++) { | ||
| 99 | struct host1x_job_gather *g = &job->gathers[i]; | ||
| 100 | |||
| 101 | if (g->pre_fence) | ||
| 102 | host1x_sync_fence_wait(g->pre_fence, host, | ||
| 103 | job->channel); | ||
| 104 | } | ||
| 105 | } | ||
| 106 | |||
| 107 | static void submit_gathers(struct host1x_job *job) | ||
| 108 | { | ||
| 109 | struct host1x_cdma *cdma = &job->channel->cdma; | ||
| 110 | unsigned int i; | ||
| 111 | u32 cur_class = 0; | ||
| 112 | |||
| 113 | cur_class = HOST1X_CLASS_HOST1X; | ||
| 114 | host1x_cdma_push(cdma, | ||
| 115 | host1x_opcode_acquire_mlock(cur_class), | ||
| 116 | host1x_opcode_setclass(cur_class, 0, 0)); | ||
| 117 | |||
| 118 | add_sync_waits(job); | ||
| 119 | |||
| 120 | for (i = 0; i < job->num_gathers; i++) { | ||
| 121 | struct host1x_job_gather *g = &job->gathers[i]; | ||
| 122 | u32 op1 = host1x_opcode_gather(g->words); | ||
| 123 | u32 op2 = g->base + g->offset; | ||
| 124 | |||
| 125 | /* add a setclass for modules that require it */ | ||
| 126 | if (cur_class != g->class_id) { | ||
| 127 | if (cur_class) | ||
| 128 | host1x_cdma_push(cdma, | ||
| 129 | HOST1X_OPCODE_NOP, | ||
| 130 | host1x_opcode_release_mlock(cur_class)); | ||
| 131 | |||
| 132 | host1x_cdma_push(cdma, | ||
| 133 | host1x_opcode_acquire_mlock(g->class_id), | ||
| 134 | host1x_opcode_setclass(g->class_id, 0, 0)); | ||
| 135 | cur_class = g->class_id; | ||
| 136 | } | ||
| 137 | |||
| 138 | trace_write_gather(cdma, g->bo, g->offset, op1 & 0xffff); | ||
| 139 | host1x_cdma_push(cdma, op1, op2); | ||
| 140 | } | ||
| 141 | |||
| 142 | if (job->serialize) | ||
| 143 | serialize(job); | ||
| 144 | |||
| 145 | if (cur_class) | ||
| 146 | host1x_cdma_push(cdma, | ||
| 147 | HOST1X_OPCODE_NOP, | ||
| 148 | host1x_opcode_release_mlock(cur_class)); | ||
| 149 | } | ||
| 150 | |||
| 151 | static inline void synchronize_syncpt_base(struct host1x_job *job) | ||
| 152 | { | ||
| 153 | struct host1x_channel *ch = job->channel; | ||
| 154 | struct host1x *host = dev_get_drvdata(ch->dev->parent); | ||
| 155 | unsigned int i; | ||
| 156 | |||
| 157 | for (i = 0; i < job->num_syncpts; ++i) { | ||
| 158 | u32 syncpt_id = job->syncpts[i].id; | ||
| 159 | struct host1x_syncpt *syncpt = | ||
| 160 | host1x_syncpt_get(host, syncpt_id); | ||
| 161 | u32 base_id, value; | ||
| 162 | |||
| 163 | if (!syncpt->base) | ||
| 164 | continue; | ||
| 165 | |||
| 166 | value = host1x_syncpt_read_max(syncpt); | ||
| 167 | base_id = syncpt->base->id; | ||
| 168 | |||
| 169 | host1x_cdma_push(&job->channel->cdma, | ||
| 170 | host1x_opcode_setclass(HOST1X_CLASS_HOST1X, | ||
| 171 | HOST1X_UCLASS_LOAD_SYNCPT_BASE, 1), | ||
| 172 | HOST1X_UCLASS_LOAD_SYNCPT_BASE_BASE_INDX_F(base_id) | | ||
| 173 | HOST1X_UCLASS_LOAD_SYNCPT_BASE_VALUE_F(value)); | ||
| 174 | } | ||
| 175 | } | ||
| 176 | |||
| 177 | static int channel_submit(struct host1x_job *job) | ||
| 178 | { | ||
| 179 | struct host1x_channel *ch = job->channel; | ||
| 180 | struct host1x_syncpt *syncpt; | ||
| 181 | u32 prev_max = 0; | ||
| 182 | int err; | ||
| 183 | struct host1x_waitlist *completed_waiter[job->num_syncpts]; | ||
| 184 | struct host1x *host = dev_get_drvdata(ch->dev->parent); | ||
| 185 | unsigned int i; | ||
| 186 | int streamid = 0; | ||
| 187 | |||
| 188 | trace_host1x_channel_submit(dev_name(ch->dev), | ||
| 189 | job->num_gathers, job->num_relocs, | ||
| 190 | job->num_waitchk, job->syncpts[0].id, | ||
| 191 | job->syncpts[0].incrs); | ||
| 192 | |||
| 193 | /* before error checks, return current max */ | ||
| 194 | syncpt = host1x_syncpt_get(host, job->syncpts[0].id); | ||
| 195 | prev_max = host1x_syncpt_read_max(syncpt); | ||
| 196 | |||
| 197 | /* get submit lock */ | ||
| 198 | err = mutex_lock_interruptible(&ch->submitlock); | ||
| 199 | if (err) | ||
| 200 | goto error; | ||
| 201 | |||
| 202 | for (i = 0; i < job->num_syncpts; i++) { | ||
| 203 | completed_waiter[i] = kzalloc(sizeof(*completed_waiter[i]), | ||
| 204 | GFP_KERNEL); | ||
| 205 | if (!completed_waiter[i]) { | ||
| 206 | mutex_unlock(&ch->submitlock); | ||
| 207 | err = -ENOMEM; | ||
| 208 | goto error; | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | streamid = iommu_get_hwid(host->dev->archdata.iommu, host->dev, 0); | ||
| 213 | if (streamid >= 0) | ||
| 214 | host1x_ch_writel(ch, streamid, HOST1X_CHANNEL_SMMU_STREAMID); | ||
| 215 | |||
| 216 | /* begin a CDMA submit */ | ||
| 217 | err = host1x_cdma_begin(&ch->cdma, job); | ||
| 218 | if (err) { | ||
| 219 | mutex_unlock(&ch->submitlock); | ||
| 220 | goto error; | ||
| 221 | } | ||
| 222 | |||
| 223 | /* Synchronize base register to allow using it for relative waiting */ | ||
| 224 | synchronize_syncpt_base(job); | ||
| 225 | |||
| 226 | /* Increment syncpoint maximum values */ | ||
| 227 | for (i = 0; i < job->num_syncpts; ++i) { | ||
| 228 | u32 id; | ||
| 229 | u32 incrs; | ||
| 230 | |||
| 231 | id = job->syncpts[i].id; | ||
| 232 | incrs = job->syncpts[i].incrs; | ||
| 233 | syncpt = host1x_syncpt_get(host, id); | ||
| 234 | job->syncpts[i].end = host1x_syncpt_incr_max(syncpt, incrs); | ||
| 235 | } | ||
| 236 | |||
| 237 | submit_gathers(job); | ||
| 238 | |||
| 239 | /* end CDMA submit & stash pinned hMems into sync queue */ | ||
| 240 | host1x_cdma_end(&ch->cdma, job); | ||
| 241 | |||
| 242 | trace_host1x_channel_submitted(dev_name(ch->dev), prev_max, | ||
| 243 | job->syncpts[0].end); | ||
| 244 | |||
| 245 | /* schedule submit complete interrupts */ | ||
| 246 | for (i = 0; i < job->num_syncpts; ++i) { | ||
| 247 | u32 syncpt_id = job->syncpts[i].id; | ||
| 248 | u32 syncpt_end = job->syncpts[i].end; | ||
| 249 | |||
| 250 | err = host1x_intr_add_action(host, syncpt_id, syncpt_end, | ||
| 251 | HOST1X_INTR_ACTION_SUBMIT_COMPLETE, | ||
| 252 | ch, completed_waiter[i], NULL); | ||
| 253 | completed_waiter[i] = NULL; | ||
| 254 | WARN(err, "Failed to set submit complete interrupt"); | ||
| 255 | } | ||
| 256 | |||
| 257 | mutex_unlock(&ch->submitlock); | ||
| 258 | |||
| 259 | return 0; | ||
| 260 | |||
| 261 | error: | ||
| 262 | for (i = 0; i < job->num_syncpts; i++) | ||
| 263 | kfree(completed_waiter[i]); | ||
| 264 | return err; | ||
| 265 | } | ||
| 266 | |||
| 267 | static int host1x_channel_init(struct host1x_channel *ch, struct host1x *dev, | ||
| 268 | unsigned int index) | ||
| 269 | { | ||
| 270 | ch->id = index; | ||
| 271 | mutex_init(&ch->reflock); | ||
| 272 | mutex_init(&ch->submitlock); | ||
| 273 | |||
| 274 | ch->regs = dev->regs + (HOST1X_CHANNEL_CH_APERTURE_START + | ||
| 275 | index * HOST1X_CHANNEL_CH_APERTURE_SIZE); | ||
| 276 | return 0; | ||
| 277 | } | ||
| 278 | |||
| 279 | static void channel_enable_gather_filter(struct host1x_channel *ch) | ||
| 280 | { | ||
| 281 | struct host1x *host = dev_get_drvdata(ch->dev->parent); | ||
| 282 | u32 val; | ||
| 283 | |||
| 284 | val = host1x_readl(host, HOST1X_CHANNEL_FILTER_GBUFFER | ||
| 285 | + BIT_WORD(ch->id) * sizeof(u32)); | ||
| 286 | |||
| 287 | host1x_writel(host, val | BIT_MASK(ch->id), | ||
| 288 | HOST1X_CHANNEL_FILTER_GBUFFER | ||
| 289 | + BIT_WORD(ch->id) * sizeof(u32)); | ||
| 290 | } | ||
| 291 | |||
| 292 | static const struct host1x_channel_ops host1x_channel_t186_ops = { | ||
| 293 | .init = host1x_channel_init, | ||
| 294 | .submit = channel_submit, | ||
| 295 | .push_wait = channel_push_wait, | ||
| 296 | .enable_gather_filter = channel_enable_gather_filter, | ||
| 297 | }; | ||
diff --git a/drivers/gpu/host1x/hw/debug_hw_t186.c b/drivers/gpu/host1x/hw/debug_hw_t186.c new file mode 100644 index 000000000..d6111668e --- /dev/null +++ b/drivers/gpu/host1x/hw/debug_hw_t186.c | |||
| @@ -0,0 +1,288 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010 Google, Inc. | ||
| 3 | * Author: Erik Gilling <konkers@android.com> | ||
| 4 | * | ||
| 5 | * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. | ||
| 6 | * | ||
| 7 | * This software is licensed under the terms of the GNU General Public | ||
| 8 | * License version 2, as published by the Free Software Foundation, and | ||
| 9 | * may be copied, distributed, and modified under those terms. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include "dev.h" | ||
| 19 | #include "debug.h" | ||
| 20 | #include "cdma.h" | ||
| 21 | #include "channel.h" | ||
| 22 | |||
| 23 | #define HOST1X_DEBUG_MAX_PAGE_OFFSET 102400 | ||
| 24 | |||
| 25 | enum { | ||
| 26 | HOST1X_OPCODE_SETCLASS = 0x00, | ||
| 27 | HOST1X_OPCODE_INCR = 0x01, | ||
| 28 | HOST1X_OPCODE_NONINCR = 0x02, | ||
| 29 | HOST1X_OPCODE_MASK = 0x03, | ||
| 30 | HOST1X_OPCODE_IMM = 0x04, | ||
| 31 | HOST1X_OPCODE_RESTART = 0x05, | ||
| 32 | HOST1X_OPCODE_GATHER = 0x06, | ||
| 33 | HOST1X_OPCODE_EXTEND = 0x0e, | ||
| 34 | }; | ||
| 35 | |||
| 36 | enum { | ||
| 37 | HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK = 0x00, | ||
| 38 | HOST1X_OPCODE_EXTEND_RELEASE_MLOCK = 0x01, | ||
| 39 | }; | ||
| 40 | |||
| 41 | static unsigned int show_channel_command(struct output *o, u32 val) | ||
| 42 | { | ||
| 43 | unsigned mask; | ||
| 44 | unsigned subop; | ||
| 45 | |||
| 46 | switch (val >> 28) { | ||
| 47 | case HOST1X_OPCODE_SETCLASS: | ||
| 48 | mask = val & 0x3f; | ||
| 49 | if (mask) { | ||
| 50 | host1x_debug_output(o, "SETCL(class=%03x, offset=%03x, mask=%02x, [", | ||
| 51 | val >> 6 & 0x3ff, | ||
| 52 | val >> 16 & 0xfff, mask); | ||
| 53 | return hweight8(mask); | ||
| 54 | } else { | ||
| 55 | host1x_debug_output(o, "SETCL(class=%03x)\n", | ||
| 56 | val >> 6 & 0x3ff); | ||
| 57 | return 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | case HOST1X_OPCODE_INCR: | ||
| 61 | host1x_debug_output(o, "INCR(offset=%03x, [", | ||
| 62 | val >> 16 & 0xfff); | ||
| 63 | return val & 0xffff; | ||
| 64 | |||
| 65 | case HOST1X_OPCODE_NONINCR: | ||
| 66 | host1x_debug_output(o, "NONINCR(offset=%03x, [", | ||
| 67 | val >> 16 & 0xfff); | ||
| 68 | return val & 0xffff; | ||
| 69 | |||
| 70 | case HOST1X_OPCODE_MASK: | ||
| 71 | mask = val & 0xffff; | ||
| 72 | host1x_debug_output(o, "MASK(offset=%03x, mask=%03x, [", | ||
| 73 | val >> 16 & 0xfff, mask); | ||
| 74 | return hweight16(mask); | ||
| 75 | |||
| 76 | case HOST1X_OPCODE_IMM: | ||
| 77 | host1x_debug_output(o, "IMM(offset=%03x, data=%03x)\n", | ||
| 78 | val >> 16 & 0xfff, val & 0xffff); | ||
| 79 | return 0; | ||
| 80 | |||
| 81 | case HOST1X_OPCODE_RESTART: | ||
| 82 | host1x_debug_output(o, "RESTART(offset=%08x)\n", val << 4); | ||
| 83 | return 0; | ||
| 84 | |||
| 85 | case HOST1X_OPCODE_GATHER: | ||
| 86 | host1x_debug_output(o, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[", | ||
| 87 | val >> 16 & 0xfff, val >> 15 & 0x1, | ||
| 88 | val >> 14 & 0x1, val & 0x3fff); | ||
| 89 | return 1; | ||
| 90 | |||
| 91 | case HOST1X_OPCODE_EXTEND: | ||
| 92 | subop = val >> 24 & 0xf; | ||
| 93 | if (subop == HOST1X_OPCODE_EXTEND_ACQUIRE_MLOCK) | ||
| 94 | host1x_debug_output(o, "ACQUIRE_MLOCK(index=%d)\n", | ||
| 95 | val & 0xff); | ||
| 96 | else if (subop == HOST1X_OPCODE_EXTEND_RELEASE_MLOCK) | ||
| 97 | host1x_debug_output(o, "RELEASE_MLOCK(index=%d)\n", | ||
| 98 | val & 0xff); | ||
| 99 | else | ||
| 100 | host1x_debug_output(o, "EXTEND_UNKNOWN(%08x)\n", val); | ||
| 101 | return 0; | ||
| 102 | |||
| 103 | default: | ||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | static void show_gather(struct output *o, phys_addr_t phys_addr, | ||
| 109 | unsigned int words, struct host1x_cdma *cdma, | ||
| 110 | phys_addr_t pin_addr, u32 *map_addr) | ||
| 111 | { | ||
| 112 | /* Map dmaget cursor to corresponding mem handle */ | ||
| 113 | u32 offset = phys_addr - pin_addr; | ||
| 114 | unsigned int data_count = 0, i; | ||
| 115 | |||
| 116 | /* | ||
| 117 | * Sometimes we're given different hardware address to the same | ||
| 118 | * page - in these cases the offset will get an invalid number and | ||
| 119 | * we just have to bail out. | ||
| 120 | */ | ||
| 121 | if (offset > HOST1X_DEBUG_MAX_PAGE_OFFSET) { | ||
| 122 | host1x_debug_output(o, "[address mismatch]\n"); | ||
| 123 | return; | ||
| 124 | } | ||
| 125 | |||
| 126 | for (i = 0; i < words; i++) { | ||
| 127 | u32 addr = phys_addr + i * 4; | ||
| 128 | u32 val = *(map_addr + offset / 4 + i); | ||
| 129 | |||
| 130 | if (!data_count) { | ||
| 131 | host1x_debug_output(o, "%08x: %08x:", addr, val); | ||
| 132 | data_count = show_channel_command(o, val); | ||
| 133 | } else { | ||
| 134 | host1x_debug_output(o, "%08x%s", val, | ||
| 135 | data_count > 0 ? ", " : "])\n"); | ||
| 136 | data_count--; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | static void show_channel_gathers(struct output *o, struct host1x_cdma *cdma) | ||
| 142 | { | ||
| 143 | struct host1x_job *job; | ||
| 144 | |||
| 145 | list_for_each_entry(job, &cdma->sync_queue, list) { | ||
| 146 | int i; | ||
| 147 | host1x_debug_output(o, "\n%p: JOB, syncpt_id=%d, syncpt_val=%d, first_get=%08x, timeout=%d num_slots=%d, num_handles=%d\n", | ||
| 148 | job, | ||
| 149 | (job->syncpts ? job->syncpts[0].id : 0), | ||
| 150 | (job->syncpts ? job->syncpts[0].end : 0), | ||
| 151 | job->first_get, job->timeout, | ||
| 152 | job->num_slots, job->num_unpins); | ||
| 153 | |||
| 154 | for (i = 0; i < job->num_gathers; i++) { | ||
| 155 | struct host1x_job_gather *g = &job->gathers[i]; | ||
| 156 | u32 *mapped; | ||
| 157 | |||
| 158 | if (job->gather_copy_mapped) | ||
| 159 | mapped = (u32 *)job->gather_copy_mapped; | ||
| 160 | else | ||
| 161 | mapped = host1x_bo_mmap(g->bo); | ||
| 162 | |||
| 163 | if (!mapped) { | ||
| 164 | host1x_debug_output(o, "[could not mmap]\n"); | ||
| 165 | continue; | ||
| 166 | } | ||
| 167 | |||
| 168 | host1x_debug_output(o, " GATHER at %pad+%#x, %d words\n", | ||
| 169 | &g->base, g->offset, g->words); | ||
| 170 | |||
| 171 | show_gather(o, g->base + g->offset, g->words, cdma, | ||
| 172 | g->base, mapped); | ||
| 173 | |||
| 174 | if (!job->gather_copy_mapped) | ||
| 175 | host1x_bo_munmap(g->bo, mapped); | ||
| 176 | } | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | static void host1x_debug_show_channel_cdma(struct host1x *host, | ||
| 181 | struct host1x_channel *ch, | ||
| 182 | struct output *o) | ||
| 183 | { | ||
| 184 | struct host1x_cdma *cdma = &ch->cdma; | ||
| 185 | u32 val; | ||
| 186 | |||
| 187 | host1x_debug_output(o, "Host1x basic channel registers: \n"); | ||
| 188 | |||
| 189 | val = host1x_ch_readl(ch, HOST1X_CHANNEL_FIFOSTAT); | ||
| 190 | host1x_debug_output(o, "CMDFIFO_STAT_0: %08x\n", val); | ||
| 191 | val = host1x_ch_readl(ch, HOST1X_CHANNEL_RDATA); | ||
| 192 | host1x_debug_output(o, "CMDFIFO_RDATA_0: %08x\n", val); | ||
| 193 | val = host1x_ch_readl(ch, HOST1X_CHANNEL_CMDP_OFFSET); | ||
| 194 | host1x_debug_output(o, "CMDP_OFFSET_0: %08x\n", val); | ||
| 195 | val = host1x_ch_readl(ch, HOST1X_CHANNEL_CMDP_CLASS); | ||
| 196 | host1x_debug_output(o, "CMDP_CLASS_0: %08x\n", val); | ||
| 197 | val = host1x_ch_readl(ch, HOST1X_CHANNEL_CMDP_CHANNELSTAT); | ||
| 198 | host1x_debug_output(o, "CHANNELSTAT_0: %08x\n", val); | ||
| 199 | |||
| 200 | show_channel_gathers(o, cdma); | ||
| 201 | host1x_debug_output(o, "\n"); | ||
| 202 | } | ||
| 203 | |||
| 204 | static void host1x_debug_show_channel_fifo(struct host1x *host, | ||
| 205 | struct host1x_channel *ch, | ||
| 206 | struct output *o) | ||
| 207 | { | ||
| 208 | u32 val, rd_ptr, wr_ptr, start, end, temp; | ||
| 209 | unsigned int data_count = 0; | ||
| 210 | |||
| 211 | host1x_debug_output(o, "%d: fifo:\n", ch->id); | ||
| 212 | |||
| 213 | temp = host1x_sync_readl(host, HOST1X_THOST_COMMON_ICG_EN_OVERRIDE_0); | ||
| 214 | host1x_sync_writel(host, 0x1, HOST1X_THOST_COMMON_ICG_EN_OVERRIDE_0); | ||
| 215 | |||
| 216 | val = host1x_ch_readl(ch, HOST1X_CHANNEL_FIFOSTAT); | ||
| 217 | host1x_debug_output(o, "FIFOSTAT %08x\n", val); | ||
| 218 | if (HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(val)) { | ||
| 219 | host1x_debug_output(o, "[empty]\n"); | ||
| 220 | return; | ||
| 221 | } | ||
| 222 | |||
| 223 | host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL); | ||
| 224 | host1x_sync_writel(host, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) | | ||
| 225 | HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch->id), | ||
| 226 | HOST1X_SYNC_CFPEEK_CTRL); | ||
| 227 | |||
| 228 | val = host1x_sync_readl(host, HOST1X_SYNC_CFPEEK_PTRS); | ||
| 229 | rd_ptr = HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(val); | ||
| 230 | wr_ptr = HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(val); | ||
| 231 | |||
| 232 | val = host1x_sync_readl(host, HOST1X_SYNC_CF_SETUP(ch->id)); | ||
| 233 | start = HOST1X_SYNC_CF_SETUP_BASE_V(val); | ||
| 234 | end = HOST1X_SYNC_CF_SETUP_LIMIT_V(val); | ||
| 235 | |||
| 236 | do { | ||
| 237 | host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL); | ||
| 238 | host1x_sync_writel(host, HOST1X_SYNC_CFPEEK_CTRL_ENA_F(1) | | ||
| 239 | HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(ch->id) | | ||
| 240 | HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(rd_ptr), | ||
| 241 | HOST1X_SYNC_CFPEEK_CTRL); | ||
| 242 | val = host1x_sync_readl(host, HOST1X_SYNC_CFPEEK_READ); | ||
| 243 | |||
| 244 | if (!data_count) { | ||
| 245 | host1x_debug_output(o, "%08x:", val); | ||
| 246 | data_count = show_channel_command(o, val); | ||
| 247 | } else { | ||
| 248 | host1x_debug_output(o, "%08x%s", val, | ||
| 249 | data_count > 0 ? ", " : "])\n"); | ||
| 250 | data_count--; | ||
| 251 | } | ||
| 252 | |||
| 253 | if (rd_ptr == end) | ||
| 254 | rd_ptr = start; | ||
| 255 | else | ||
| 256 | rd_ptr++; | ||
| 257 | } while (rd_ptr != wr_ptr); | ||
| 258 | |||
| 259 | if (data_count) | ||
| 260 | host1x_debug_output(o, ", ...])\n"); | ||
| 261 | host1x_debug_output(o, "\n"); | ||
| 262 | |||
| 263 | host1x_sync_writel(host, 0x0, HOST1X_SYNC_CFPEEK_CTRL); | ||
| 264 | |||
| 265 | host1x_sync_writel(host, temp, HOST1X_THOST_COMMON_ICG_EN_OVERRIDE_0); | ||
| 266 | } | ||
| 267 | |||
| 268 | static void host1x_debug_show_mlocks(struct host1x *host, struct output *o) | ||
| 269 | { | ||
| 270 | int i; | ||
| 271 | unsigned int chid; | ||
| 272 | bool cpu, ch; | ||
| 273 | |||
| 274 | host1x_debug_output(o, "---- mlocks ----\n"); | ||
| 275 | for (i = 0; i < host1x_syncpt_nb_mlocks(host); i++) { | ||
| 276 | host1x_hw_sync_get_mutex_owner(host, host->syncpt, | ||
| 277 | i, &cpu, &ch, &chid); | ||
| 278 | if (ch) | ||
| 279 | host1x_debug_output(o, "%d: locked by channel %d\n", i, chid); | ||
| 280 | } | ||
| 281 | host1x_debug_output(o, "\n"); | ||
| 282 | } | ||
| 283 | |||
| 284 | static const struct host1x_debug_ops host1x_debug_t186_ops = { | ||
| 285 | .show_channel_cdma = host1x_debug_show_channel_cdma, | ||
| 286 | .show_channel_fifo = host1x_debug_show_channel_fifo, | ||
| 287 | .show_mlocks = host1x_debug_show_mlocks, | ||
| 288 | }; | ||
diff --git a/drivers/gpu/host1x/hw/host1x05.c b/drivers/gpu/host1x/hw/host1x05.c new file mode 100644 index 000000000..db64e7cfe --- /dev/null +++ b/drivers/gpu/host1x/hw/host1x05.c | |||
| @@ -0,0 +1,40 @@ | |||
| 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 | * 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 | /* include hw specification */ | ||
| 18 | #include "host1x05.h" | ||
| 19 | #include "host1x05_hardware.h" | ||
| 20 | |||
| 21 | /* include code */ | ||
| 22 | #include "cdma_hw_t186.c" | ||
| 23 | #include "channel_hw_t186.c" | ||
| 24 | #include "debug_hw_t186.c" | ||
| 25 | #include "intr_hw_t186.c" | ||
| 26 | #include "syncpt_hw_t186.c" | ||
| 27 | |||
| 28 | #include "dev.h" | ||
| 29 | |||
| 30 | int host1x05_init(struct host1x *host) | ||
| 31 | { | ||
| 32 | host->channel_op = &host1x_channel_t186_ops; | ||
| 33 | host->cdma_op = &host1x_cdma_t186_ops; | ||
| 34 | host->cdma_pb_op = &host1x_pushbuffer_t186_ops; | ||
| 35 | host->syncpt_op = &host1x_syncpt_t186_ops; | ||
| 36 | host->intr_op = &host1x_intr_t186_ops; | ||
| 37 | host->debug_op = &host1x_debug_t186_ops; | ||
| 38 | |||
| 39 | return 0; | ||
| 40 | } | ||
diff --git a/drivers/gpu/host1x/hw/host1x05.h b/drivers/gpu/host1x/hw/host1x05.h new file mode 100644 index 000000000..e1b842146 --- /dev/null +++ b/drivers/gpu/host1x/hw/host1x05.h | |||
| @@ -0,0 +1,24 @@ | |||
| 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 | * 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 HOST1X_HOST1X05_H | ||
| 18 | #define HOST1X_HOST1X05_H | ||
| 19 | |||
| 20 | struct host1x; | ||
| 21 | |||
| 22 | int host1x05_init(struct host1x *host); | ||
| 23 | |||
| 24 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/host1x05_hardware.h b/drivers/gpu/host1x/hw/host1x05_hardware.h new file mode 100644 index 000000000..add00014e --- /dev/null +++ b/drivers/gpu/host1x/hw/host1x05_hardware.h | |||
| @@ -0,0 +1,128 @@ | |||
| 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 | * 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 __HOST1X_HOST1X05_HARDWARE_H | ||
| 18 | #define __HOST1X_HOST1X05_HARDWARE_H | ||
| 19 | |||
| 20 | #include <linux/types.h> | ||
| 21 | #include <linux/bitops.h> | ||
| 22 | |||
| 23 | #include "hw_host1x05_channel.h" | ||
| 24 | #include "hw_host1x05_sync.h" | ||
| 25 | #include "hw_host1x05_uclass.h" | ||
| 26 | |||
| 27 | static inline u32 host1x_class_host_wait_syncpt( | ||
| 28 | unsigned indx, unsigned threshold) | ||
| 29 | { | ||
| 30 | return host1x_uclass_wait_syncpt_indx_f(indx) | ||
| 31 | | host1x_uclass_wait_syncpt_thresh_f(threshold); | ||
| 32 | } | ||
| 33 | |||
| 34 | static inline u32 host1x_class_host_load_syncpt_base( | ||
| 35 | unsigned indx, unsigned threshold) | ||
| 36 | { | ||
| 37 | return host1x_uclass_load_syncpt_base_base_indx_f(indx) | ||
| 38 | | host1x_uclass_load_syncpt_base_value_f(threshold); | ||
| 39 | } | ||
| 40 | |||
| 41 | static inline u32 host1x_class_host_wait_syncpt_base( | ||
| 42 | unsigned indx, unsigned base_indx, unsigned offset) | ||
| 43 | { | ||
| 44 | return host1x_uclass_wait_syncpt_base_indx_f(indx) | ||
| 45 | | host1x_uclass_wait_syncpt_base_base_indx_f(base_indx) | ||
| 46 | | host1x_uclass_wait_syncpt_base_offset_f(offset); | ||
| 47 | } | ||
| 48 | |||
| 49 | static inline u32 host1x_class_host_incr_syncpt_base( | ||
| 50 | unsigned base_indx, unsigned offset) | ||
| 51 | { | ||
| 52 | return host1x_uclass_incr_syncpt_base_base_indx_f(base_indx) | ||
| 53 | | host1x_uclass_incr_syncpt_base_offset_f(offset); | ||
| 54 | } | ||
| 55 | |||
| 56 | static inline u32 host1x_class_host_incr_syncpt( | ||
| 57 | unsigned cond, unsigned indx) | ||
| 58 | { | ||
| 59 | return host1x_uclass_incr_syncpt_cond_f(cond) | ||
| 60 | | host1x_uclass_incr_syncpt_indx_f(indx); | ||
| 61 | } | ||
| 62 | |||
| 63 | /* cdma opcodes */ | ||
| 64 | static inline u32 host1x_opcode_setclass( | ||
| 65 | unsigned class_id, unsigned offset, unsigned mask) | ||
| 66 | { | ||
| 67 | return (0 << 28) | (offset << 16) | (class_id << 6) | mask; | ||
| 68 | } | ||
| 69 | |||
| 70 | static inline u32 host1x_opcode_incr(unsigned offset, unsigned count) | ||
| 71 | { | ||
| 72 | return (1 << 28) | (offset << 16) | count; | ||
| 73 | } | ||
| 74 | |||
| 75 | static inline u32 host1x_opcode_nonincr(unsigned offset, unsigned count) | ||
| 76 | { | ||
| 77 | return (2 << 28) | (offset << 16) | count; | ||
| 78 | } | ||
| 79 | |||
| 80 | static inline u32 host1x_opcode_mask(unsigned offset, unsigned mask) | ||
| 81 | { | ||
| 82 | return (3 << 28) | (offset << 16) | mask; | ||
| 83 | } | ||
| 84 | |||
| 85 | static inline u32 host1x_opcode_imm(unsigned offset, unsigned value) | ||
| 86 | { | ||
| 87 | return (4 << 28) | (offset << 16) | value; | ||
| 88 | } | ||
| 89 | |||
| 90 | static inline u32 host1x_opcode_imm_incr_syncpt(unsigned cond, unsigned indx) | ||
| 91 | { | ||
| 92 | return host1x_opcode_imm(host1x_uclass_incr_syncpt_r(), | ||
| 93 | host1x_class_host_incr_syncpt(cond, indx)); | ||
| 94 | } | ||
| 95 | |||
| 96 | static inline u32 host1x_opcode_restart(unsigned address) | ||
| 97 | { | ||
| 98 | return (5 << 28) | (address >> 4); | ||
| 99 | } | ||
| 100 | |||
| 101 | static inline u32 host1x_opcode_gather(unsigned count) | ||
| 102 | { | ||
| 103 | return (6 << 28) | count; | ||
| 104 | } | ||
| 105 | |||
| 106 | static inline u32 host1x_opcode_gather_nonincr(unsigned offset, unsigned count) | ||
| 107 | { | ||
| 108 | return (6 << 28) | (offset << 16) | BIT(15) | count; | ||
| 109 | } | ||
| 110 | |||
| 111 | static inline u32 host1x_opcode_gather_incr(unsigned offset, unsigned count) | ||
| 112 | { | ||
| 113 | return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count; | ||
| 114 | } | ||
| 115 | |||
| 116 | static inline u32 host1x_opcode_acquire_mlock(unsigned id) | ||
| 117 | { | ||
| 118 | return (14 << 28) | id; | ||
| 119 | } | ||
| 120 | |||
| 121 | static inline u32 host1x_opcode_release_mlock(unsigned id) | ||
| 122 | { | ||
| 123 | return (14 << 28) | (1 << 24) | id; | ||
| 124 | } | ||
| 125 | |||
| 126 | #define HOST1X_OPCODE_NOP host1x_opcode_nonincr(0, 0) | ||
| 127 | |||
| 128 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/hw_host1x05_channel.h b/drivers/gpu/host1x/hw/hw_host1x05_channel.h new file mode 100644 index 000000000..8c3499f91 --- /dev/null +++ b/drivers/gpu/host1x/hw/hw_host1x05_channel.h | |||
| @@ -0,0 +1,169 @@ | |||
| 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 | * 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 | |||
| 18 | /* | ||
| 19 | * Function naming determines intended use: | ||
| 20 | * | ||
| 21 | * <x>_r(void) : Returns the offset for register <x>. | ||
| 22 | * | ||
| 23 | * <x>_w(void) : Returns the word offset for word (4 byte) element <x>. | ||
| 24 | * | ||
| 25 | * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits. | ||
| 26 | * | ||
| 27 | * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted | ||
| 28 | * and masked to place it at field <y> of register <x>. This value | ||
| 29 | * can be |'d with others to produce a full register value for | ||
| 30 | * register <x>. | ||
| 31 | * | ||
| 32 | * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This | ||
| 33 | * value can be ~'d and then &'d to clear the value of field <y> for | ||
| 34 | * register <x>. | ||
| 35 | * | ||
| 36 | * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted | ||
| 37 | * to place it at field <y> of register <x>. This value can be |'d | ||
| 38 | * with others to produce a full register value for <x>. | ||
| 39 | * | ||
| 40 | * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register | ||
| 41 | * <x> value 'r' after being shifted to place its LSB at bit 0. | ||
| 42 | * This value is suitable for direct comparison with other unshifted | ||
| 43 | * values appropriate for use in field <y> of register <x>. | ||
| 44 | * | ||
| 45 | * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for | ||
| 46 | * field <y> of register <x>. This value is suitable for direct | ||
| 47 | * comparison with unshifted values appropriate for use in field <y> | ||
| 48 | * of register <x>. | ||
| 49 | */ | ||
| 50 | |||
| 51 | #ifndef HOST1X_HW_HOST1X05_CHANNEL_H | ||
| 52 | #define HOST1X_HW_HOST1X05_CHANNEL_H | ||
| 53 | |||
| 54 | static inline u32 host1x_channel_ch_aperture_start_r(void) | ||
| 55 | { | ||
| 56 | return 0x10000; | ||
| 57 | } | ||
| 58 | #define HOST1X_CHANNEL_CH_APERTURE_START \ | ||
| 59 | host1x_channel_ch_aperture_start_r() | ||
| 60 | static inline u32 host1x_channel_ch_aperture_size_r(void) | ||
| 61 | { | ||
| 62 | return 0x100; | ||
| 63 | } | ||
| 64 | #define HOST1X_CHANNEL_CH_APERTURE_SIZE \ | ||
| 65 | host1x_channel_ch_aperture_size_r() | ||
| 66 | static inline u32 host1x_channel_fifostat_r(void) | ||
| 67 | { | ||
| 68 | return 0x24; | ||
| 69 | } | ||
| 70 | #define HOST1X_CHANNEL_FIFOSTAT \ | ||
| 71 | host1x_channel_fifostat_r() | ||
| 72 | static inline u32 host1x_channel_fifostat_cfempty_v(u32 r) | ||
| 73 | { | ||
| 74 | return (r >> 13) & 0x1; | ||
| 75 | } | ||
| 76 | #define HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(r) \ | ||
| 77 | host1x_channel_fifostat_cfempty_v(r) | ||
| 78 | static inline u32 host1x_channel_rdata_r(void) | ||
| 79 | { | ||
| 80 | return 0x28; | ||
| 81 | } | ||
| 82 | #define HOST1X_CHANNEL_RDATA \ | ||
| 83 | host1x_channel_rdata_r() | ||
| 84 | static inline u32 host1x_channel_cmdp_offset_r(void) | ||
| 85 | { | ||
| 86 | return 0x30; | ||
| 87 | } | ||
| 88 | #define HOST1X_CHANNEL_CMDP_OFFSET \ | ||
| 89 | host1x_channel_cmdp_offset_r() | ||
| 90 | static inline u32 host1x_channel_cmdp_class_r(void) | ||
| 91 | { | ||
| 92 | return 0x34; | ||
| 93 | } | ||
| 94 | #define HOST1X_CHANNEL_CMDP_CLASS \ | ||
| 95 | host1x_channel_cmdp_class_r() | ||
| 96 | static inline u32 host1x_channel_cmdp_channelstat_r(void) | ||
| 97 | { | ||
| 98 | return 0x38; | ||
| 99 | } | ||
| 100 | #define HOST1X_CHANNEL_CMDP_CHANNELSTAT \ | ||
| 101 | host1x_channel_cmdp_channelstat_r() | ||
| 102 | static inline u32 host1x_channel_dmastart_r(void) | ||
| 103 | { | ||
| 104 | return 0x0; | ||
| 105 | } | ||
| 106 | #define HOST1X_CHANNEL_DMASTART \ | ||
| 107 | host1x_channel_dmastart_r() | ||
| 108 | static inline u32 host1x_channel_dmaput_r(void) | ||
| 109 | { | ||
| 110 | return 0x8; | ||
| 111 | } | ||
| 112 | #define HOST1X_CHANNEL_DMAPUT \ | ||
| 113 | host1x_channel_dmaput_r() | ||
| 114 | static inline u32 host1x_channel_dmaget_r(void) | ||
| 115 | { | ||
| 116 | return 0x10; | ||
| 117 | } | ||
| 118 | #define HOST1X_CHANNEL_DMAGET \ | ||
| 119 | host1x_channel_dmaget_r() | ||
| 120 | static inline u32 host1x_channel_dmaend_r(void) | ||
| 121 | { | ||
| 122 | return 0x18; | ||
| 123 | } | ||
| 124 | #define HOST1X_CHANNEL_DMAEND \ | ||
| 125 | host1x_channel_dmaend_r() | ||
| 126 | static inline u32 host1x_channel_dmactrl_r(void) | ||
| 127 | { | ||
| 128 | return 0x20; | ||
| 129 | } | ||
| 130 | #define HOST1X_CHANNEL_DMACTRL \ | ||
| 131 | host1x_channel_dmactrl_r() | ||
| 132 | static inline u32 host1x_channel_dmactrl_dmastop(void) | ||
| 133 | { | ||
| 134 | return 1 << 0; | ||
| 135 | } | ||
| 136 | #define HOST1X_CHANNEL_DMACTRL_DMASTOP \ | ||
| 137 | host1x_channel_dmactrl_dmastop() | ||
| 138 | static inline u32 host1x_channel_dmactrl_dmastop_v(u32 r) | ||
| 139 | { | ||
| 140 | return (r >> 0) & 0x1; | ||
| 141 | } | ||
| 142 | #define HOST1X_CHANNEL_DMACTRL_DMASTOP_V(r) \ | ||
| 143 | host1x_channel_dmactrl_dmastop_v(r) | ||
| 144 | static inline u32 host1x_channel_dmactrl_dmagetrst(void) | ||
| 145 | { | ||
| 146 | return 1 << 1; | ||
| 147 | } | ||
| 148 | #define HOST1X_CHANNEL_DMACTRL_DMAGETRST \ | ||
| 149 | host1x_channel_dmactrl_dmagetrst() | ||
| 150 | static inline u32 host1x_channel_dmactrl_dmainitget(void) | ||
| 151 | { | ||
| 152 | return 1 << 2; | ||
| 153 | } | ||
| 154 | #define HOST1X_CHANNEL_DMACTRL_DMAINITGET \ | ||
| 155 | host1x_channel_dmactrl_dmainitget() | ||
| 156 | static inline u32 host1x_channel_smmu_streamid_r(void) | ||
| 157 | { | ||
| 158 | return 0x84; | ||
| 159 | } | ||
| 160 | #define HOST1X_CHANNEL_SMMU_STREAMID \ | ||
| 161 | host1x_channel_smmu_streamid_r() | ||
| 162 | static inline u32 host1x_channel_filter_gbuffer_r(void) | ||
| 163 | { | ||
| 164 | return 0x2020; | ||
| 165 | } | ||
| 166 | #define HOST1X_CHANNEL_FILTER_GBUFFER \ | ||
| 167 | host1x_channel_filter_gbuffer_r() | ||
| 168 | |||
| 169 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/hw_host1x05_sync.h b/drivers/gpu/host1x/hw/hw_host1x05_sync.h new file mode 100644 index 000000000..55fe98859 --- /dev/null +++ b/drivers/gpu/host1x/hw/hw_host1x05_sync.h | |||
| @@ -0,0 +1,321 @@ | |||
| 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 | * 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 | |||
| 18 | /* | ||
| 19 | * Function naming determines intended use: | ||
| 20 | * | ||
| 21 | * <x>_r(void) : Returns the offset for register <x>. | ||
| 22 | * | ||
| 23 | * <x>_w(void) : Returns the word offset for word (4 byte) element <x>. | ||
| 24 | * | ||
| 25 | * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits. | ||
| 26 | * | ||
| 27 | * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted | ||
| 28 | * and masked to place it at field <y> of register <x>. This value | ||
| 29 | * can be |'d with others to produce a full register value for | ||
| 30 | * register <x>. | ||
| 31 | * | ||
| 32 | * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This | ||
| 33 | * value can be ~'d and then &'d to clear the value of field <y> for | ||
| 34 | * register <x>. | ||
| 35 | * | ||
| 36 | * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted | ||
| 37 | * to place it at field <y> of register <x>. This value can be |'d | ||
| 38 | * with others to produce a full register value for <x>. | ||
| 39 | * | ||
| 40 | * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register | ||
| 41 | * <x> value 'r' after being shifted to place its LSB at bit 0. | ||
| 42 | * This value is suitable for direct comparison with other unshifted | ||
| 43 | * values appropriate for use in field <y> of register <x>. | ||
| 44 | * | ||
| 45 | * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for | ||
| 46 | * field <y> of register <x>. This value is suitable for direct | ||
| 47 | * comparison with unshifted values appropriate for use in field <y> | ||
| 48 | * of register <x>. | ||
| 49 | */ | ||
| 50 | |||
| 51 | #ifndef HOST1X_HW_HOST1X05_SYNC_H | ||
| 52 | #define HOST1X_HW_HOST1X05_SYNC_H | ||
| 53 | |||
| 54 | #define REGISTER_STRIDE 4 | ||
| 55 | |||
| 56 | static inline u32 host1x_sync_intstatus_r(void) | ||
| 57 | { | ||
| 58 | return 0x1c; | ||
| 59 | } | ||
| 60 | #define HOST1X_SYNC_INTSTATUS \ | ||
| 61 | host1x_sync_intstatus_r() | ||
| 62 | static inline u32 host1x_sync_intmask_r(void) | ||
| 63 | { | ||
| 64 | return 0x30; | ||
| 65 | } | ||
| 66 | #define HOST1X_SYNC_INTMASK \ | ||
| 67 | host1x_sync_intmask_r() | ||
| 68 | static inline u32 host1x_sync_intc0mask_r(void) | ||
| 69 | { | ||
| 70 | return 0x4; | ||
| 71 | } | ||
| 72 | #define HOST1X_SYNC_INTC0MASK \ | ||
| 73 | host1x_sync_intc0mask_r() | ||
| 74 | static inline u32 host1x_sync_intgmask_r(void) | ||
| 75 | { | ||
| 76 | return 0x44; | ||
| 77 | } | ||
| 78 | #define HOST1X_SYNC_INTGMASK \ | ||
| 79 | host1x_sync_intgmask_r() | ||
| 80 | static inline u32 host1x_sync_syncpt_intgmask_r(void) | ||
| 81 | { | ||
| 82 | return 0x50; | ||
| 83 | } | ||
| 84 | #define HOST1X_SYNC_SYNCPT_INTGMASK \ | ||
| 85 | host1x_sync_syncpt_intgmask_r() | ||
| 86 | static inline u32 host1x_sync_intstatus_ip_read_int_v(u32 r) | ||
| 87 | { | ||
| 88 | return (r >> 0) & 0x1; | ||
| 89 | } | ||
| 90 | #define HOST1X_SYNC_INTSTATUS_IP_READ_INT_V(r) \ | ||
| 91 | host1x_sync_intstatus_ip_read_int_v(r) | ||
| 92 | static inline u32 host1x_sync_intstatus_ip_write_int_v(u32 r) | ||
| 93 | { | ||
| 94 | return (r >> 1) & 0x1; | ||
| 95 | } | ||
| 96 | #define HOST1X_SYNC_INTSTATUS_IP_WRITE_INT_V(r) \ | ||
| 97 | host1x_sync_intstatus_ip_write_int_v(r) | ||
| 98 | static inline u32 host1x_sync_intstatus_illegal_pb_access_v(u32 r) | ||
| 99 | { | ||
| 100 | return (r >> 28) & 0x1; | ||
| 101 | } | ||
| 102 | #define HOST1X_SYNC_INTSTATUS_ILLEGAL_PB_ACCESS_V(r) \ | ||
| 103 | host1x_sync_intstatus_illegal_pb_access_v(r) | ||
| 104 | static inline u32 host1x_sync_illegal_syncpt_access_frm_pb_r(void) | ||
| 105 | { | ||
| 106 | return 0x2270; | ||
| 107 | } | ||
| 108 | #define HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_PB \ | ||
| 109 | host1x_sync_illegal_syncpt_access_frm_pb_r() | ||
| 110 | static inline u32 host1x_sync_illegal_syncpt_access_frm_pb_syncpt_v(u32 r) | ||
| 111 | { | ||
| 112 | return (r >> 16) & 0x3ff; | ||
| 113 | } | ||
| 114 | #define HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_PB_SYNCPT_V(r) \ | ||
| 115 | host1x_sync_illegal_syncpt_access_frm_pb_syncpt_v(r) | ||
| 116 | static inline u32 host1x_sync_illegal_syncpt_access_frm_pb_ch_v(u32 r) | ||
| 117 | { | ||
| 118 | return (r >> 10) & 0x3f; | ||
| 119 | } | ||
| 120 | #define HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_PB_CH_V(r) \ | ||
| 121 | host1x_sync_illegal_syncpt_access_frm_pb_ch_v(r) | ||
| 122 | static inline u32 host1x_sync_intstatus_illegal_client_access_v(u32 r) | ||
| 123 | { | ||
| 124 | return (r >> 30) & 0x1; | ||
| 125 | } | ||
| 126 | #define HOST1X_SYNC_INTSTATUS_ILLEGAL_CLIENT_ACCESS_V(r) \ | ||
| 127 | host1x_sync_intstatus_illegal_client_access_v(r) | ||
| 128 | static inline u32 host1x_sync_illegal_syncpt_access_frm_client_r(void) | ||
| 129 | { | ||
| 130 | return 0x2268; | ||
| 131 | } | ||
| 132 | #define HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_CLIENT \ | ||
| 133 | host1x_sync_illegal_syncpt_access_frm_client_r() | ||
| 134 | static inline u32 host1x_sync_illegal_syncpt_access_frm_client_syncpt_v(u32 r) | ||
| 135 | { | ||
| 136 | return (r >> 16) & 0x3ff; | ||
| 137 | } | ||
| 138 | #define HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_CLIENT_SYNCPT_V(r) \ | ||
| 139 | host1x_sync_illegal_syncpt_access_frm_client_syncpt_v(r) | ||
| 140 | static inline u32 host1x_sync_illegal_syncpt_access_frm_client_ch_v(u32 r) | ||
| 141 | { | ||
| 142 | return (r >> 10) & 0x3f; | ||
| 143 | } | ||
| 144 | #define HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_CLIENT_CH_V(r) \ | ||
| 145 | host1x_sync_illegal_syncpt_access_frm_client_ch_v(r) | ||
| 146 | static inline u32 host1x_sync_syncpt_r(unsigned int id) | ||
| 147 | { | ||
| 148 | return 0x18080 + id * REGISTER_STRIDE; | ||
| 149 | } | ||
| 150 | #define HOST1X_SYNC_SYNCPT(id) \ | ||
| 151 | host1x_sync_syncpt_r(id) | ||
| 152 | static inline u32 host1x_sync_syncpt_thresh_cpu0_int_status_r(unsigned int id) | ||
| 153 | { | ||
| 154 | return 0x16464 + id * REGISTER_STRIDE; | ||
| 155 | } | ||
| 156 | #define HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id) \ | ||
| 157 | host1x_sync_syncpt_thresh_cpu0_int_status_r(id) | ||
| 158 | static inline u32 host1x_sync_syncpt_thresh_int_disable_r(unsigned int id) | ||
| 159 | { | ||
| 160 | return 0x16590 + id * REGISTER_STRIDE; | ||
| 161 | } | ||
| 162 | #define HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(id) \ | ||
| 163 | host1x_sync_syncpt_thresh_int_disable_r(id) | ||
| 164 | static inline u32 host1x_sync_syncpt_thresh_int_enable_cpu0_r(unsigned int id) | ||
| 165 | { | ||
| 166 | return 0x1652c + id * REGISTER_STRIDE; | ||
| 167 | } | ||
| 168 | #define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id) \ | ||
| 169 | host1x_sync_syncpt_thresh_int_enable_cpu0_r(id) | ||
| 170 | static inline u32 host1x_sync_cf_setup_r(unsigned int channel) | ||
| 171 | { | ||
| 172 | return 0x2588 + channel * REGISTER_STRIDE; | ||
| 173 | } | ||
| 174 | #define HOST1X_SYNC_CF_SETUP(channel) \ | ||
| 175 | host1x_sync_cf_setup_r(channel) | ||
| 176 | static inline u32 host1x_sync_cf_setup_base_v(u32 r) | ||
| 177 | { | ||
| 178 | return (r >> 0) & 0xfff; | ||
| 179 | } | ||
| 180 | #define HOST1X_SYNC_CF_SETUP_BASE_V(r) \ | ||
| 181 | host1x_sync_cf_setup_base_v(r) | ||
| 182 | static inline u32 host1x_sync_cf_setup_limit_v(u32 r) | ||
| 183 | { | ||
| 184 | return (r >> 16) & 0xfff; | ||
| 185 | } | ||
| 186 | #define HOST1X_SYNC_CF_SETUP_LIMIT_V(r) \ | ||
| 187 | host1x_sync_cf_setup_limit_v(r) | ||
| 188 | static inline u32 host1x_sync_cmdproc_stop_r(void) | ||
| 189 | { | ||
| 190 | return 0x48; | ||
| 191 | } | ||
| 192 | #define HOST1X_SYNC_CMDPROC_STOP \ | ||
| 193 | host1x_sync_cmdproc_stop_r() | ||
| 194 | static inline u32 host1x_sync_ch_teardown_r(void) | ||
| 195 | { | ||
| 196 | return 0x4c; | ||
| 197 | } | ||
| 198 | #define HOST1X_SYNC_CH_TEARDOWN \ | ||
| 199 | host1x_sync_ch_teardown_r() | ||
| 200 | static inline u32 host1x_sync_usec_clk_r(void) | ||
| 201 | { | ||
| 202 | return 0x2244; | ||
| 203 | } | ||
| 204 | #define HOST1X_SYNC_USEC_CLK \ | ||
| 205 | host1x_sync_usec_clk_r() | ||
| 206 | static inline u32 host1x_sync_ctxsw_timeout_cfg_r(void) | ||
| 207 | { | ||
| 208 | return 0x2248; | ||
| 209 | } | ||
| 210 | #define HOST1X_SYNC_CTXSW_TIMEOUT_CFG \ | ||
| 211 | host1x_sync_ctxsw_timeout_cfg_r() | ||
| 212 | static inline u32 host1x_sync_ip_busy_timeout_r(void) | ||
| 213 | { | ||
| 214 | return 0x2250; | ||
| 215 | } | ||
| 216 | #define HOST1X_SYNC_IP_BUSY_TIMEOUT \ | ||
| 217 | host1x_sync_ip_busy_timeout_r() | ||
| 218 | static inline u32 host1x_sync_ip_read_timeout_addr_r(void) | ||
| 219 | { | ||
| 220 | return 0x2254; | ||
| 221 | } | ||
| 222 | #define HOST1X_SYNC_IP_READ_TIMEOUT_ADDR \ | ||
| 223 | host1x_sync_ip_read_timeout_addr_r() | ||
| 224 | static inline u32 host1x_sync_ip_write_timeout_addr_r(void) | ||
| 225 | { | ||
| 226 | return 0x225c; | ||
| 227 | } | ||
| 228 | #define HOST1X_SYNC_IP_WRITE_TIMEOUT_ADDR \ | ||
| 229 | host1x_sync_ip_write_timeout_addr_r() | ||
| 230 | static inline u32 host1x_sync_syncpt_int_thresh_r(unsigned int id) | ||
| 231 | { | ||
| 232 | return 0x18a00 + id * REGISTER_STRIDE; | ||
| 233 | } | ||
| 234 | #define HOST1X_SYNC_SYNCPT_INT_THRESH(id) \ | ||
| 235 | host1x_sync_syncpt_int_thresh_r(id) | ||
| 236 | static inline u32 host1x_sync_syncpt_base_r(unsigned int id) | ||
| 237 | { | ||
| 238 | return 0x18000 + id * REGISTER_STRIDE; | ||
| 239 | } | ||
| 240 | #define HOST1X_SYNC_SYNCPT_BASE(id) \ | ||
| 241 | host1x_sync_syncpt_base_r(id) | ||
| 242 | static inline u32 host1x_sync_syncpt_cpu_incr_r(unsigned int id) | ||
| 243 | { | ||
| 244 | return 0x16400 + id * REGISTER_STRIDE; | ||
| 245 | } | ||
| 246 | #define HOST1X_SYNC_SYNCPT_CPU_INCR(id) \ | ||
| 247 | host1x_sync_syncpt_cpu_incr_r(id) | ||
| 248 | static inline u32 host1x_sync_cfpeek_ctrl_r(void) | ||
| 249 | { | ||
| 250 | return 0x233c; | ||
| 251 | } | ||
| 252 | #define HOST1X_SYNC_CFPEEK_CTRL \ | ||
| 253 | host1x_sync_cfpeek_ctrl_r() | ||
| 254 | static inline u32 host1x_sync_cfpeek_ctrl_addr_f(u32 v) | ||
| 255 | { | ||
| 256 | return (v & 0xfff) << 0; | ||
| 257 | } | ||
| 258 | #define HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(v) \ | ||
| 259 | host1x_sync_cfpeek_ctrl_addr_f(v) | ||
| 260 | static inline u32 host1x_sync_cfpeek_ctrl_channr_f(u32 v) | ||
| 261 | { | ||
| 262 | return (v & 0x3f) << 16; | ||
| 263 | } | ||
| 264 | #define HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(v) \ | ||
| 265 | host1x_sync_cfpeek_ctrl_channr_f(v) | ||
| 266 | static inline u32 host1x_sync_cfpeek_ctrl_ena_f(u32 v) | ||
| 267 | { | ||
| 268 | return (v & 0x1) << 31; | ||
| 269 | } | ||
| 270 | #define HOST1X_SYNC_CFPEEK_CTRL_ENA_F(v) \ | ||
| 271 | host1x_sync_cfpeek_ctrl_ena_f(v) | ||
| 272 | static inline u32 host1x_sync_cfpeek_read_r(void) | ||
| 273 | { | ||
| 274 | return 0x2340; | ||
| 275 | } | ||
| 276 | #define HOST1X_SYNC_CFPEEK_READ \ | ||
| 277 | host1x_sync_cfpeek_read_r() | ||
| 278 | static inline u32 host1x_sync_cfpeek_ptrs_r(void) | ||
| 279 | { | ||
| 280 | return 0x2344; | ||
| 281 | } | ||
| 282 | #define HOST1X_SYNC_CFPEEK_PTRS \ | ||
| 283 | host1x_sync_cfpeek_ptrs_r() | ||
| 284 | static inline u32 host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(u32 r) | ||
| 285 | { | ||
| 286 | return (r >> 0) & 0xfff; | ||
| 287 | } | ||
| 288 | #define HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(r) \ | ||
| 289 | host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(r) | ||
| 290 | static inline u32 host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(u32 r) | ||
| 291 | { | ||
| 292 | return (r >> 16) & 0xfff; | ||
| 293 | } | ||
| 294 | #define HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(r) \ | ||
| 295 | host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(r) | ||
| 296 | static inline u32 host1x_sync_common_mlock_r(unsigned long id) | ||
| 297 | { | ||
| 298 | return 0x2030 + id * REGISTER_STRIDE; | ||
| 299 | } | ||
| 300 | #define HOST1X_SYNC_COMMON_MLOCK \ | ||
| 301 | host1x_sync_common_mlock_r() | ||
| 302 | static inline u32 host1x_sync_common_mlock_ch_v(u32 r) | ||
| 303 | { | ||
| 304 | return (r >> 2) & 0x3f; | ||
| 305 | } | ||
| 306 | #define HOST1X_SYNC_COMMON_MLOCK_CH_V(r) \ | ||
| 307 | host1x_sync_common_mlock_ch_v(r) | ||
| 308 | static inline u32 host1x_sync_common_mlock_locked_v(u32 r) | ||
| 309 | { | ||
| 310 | return (r >> 0) & 0x1; | ||
| 311 | } | ||
| 312 | #define HOST1X_SYNC_COMMON_MLOCK_LOCKED_V(r) \ | ||
| 313 | host1x_sync_common_mlock_locked_v(r) | ||
| 314 | static inline u32 host1x_thost_common_icg_en_override_0_r(void) | ||
| 315 | { | ||
| 316 | return 0x2aa8; | ||
| 317 | } | ||
| 318 | #define HOST1X_THOST_COMMON_ICG_EN_OVERRIDE_0 \ | ||
| 319 | host1x_thost_common_icg_en_override_0_r() | ||
| 320 | |||
| 321 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/hw_host1x05_uclass.h b/drivers/gpu/host1x/hw/hw_host1x05_uclass.h new file mode 100644 index 000000000..01145f610 --- /dev/null +++ b/drivers/gpu/host1x/hw/hw_host1x05_uclass.h | |||
| @@ -0,0 +1,157 @@ | |||
| 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 | * 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 | |||
| 18 | /* | ||
| 19 | * Function naming determines intended use: | ||
| 20 | * | ||
| 21 | * <x>_r(void) : Returns the offset for register <x>. | ||
| 22 | * | ||
| 23 | * <x>_w(void) : Returns the word offset for word (4 byte) element <x>. | ||
| 24 | * | ||
| 25 | * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits. | ||
| 26 | * | ||
| 27 | * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted | ||
| 28 | * and masked to place it at field <y> of register <x>. This value | ||
| 29 | * can be |'d with others to produce a full register value for | ||
| 30 | * register <x>. | ||
| 31 | * | ||
| 32 | * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This | ||
| 33 | * value can be ~'d and then &'d to clear the value of field <y> for | ||
| 34 | * register <x>. | ||
| 35 | * | ||
| 36 | * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted | ||
| 37 | * to place it at field <y> of register <x>. This value can be |'d | ||
| 38 | * with others to produce a full register value for <x>. | ||
| 39 | * | ||
| 40 | * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register | ||
| 41 | * <x> value 'r' after being shifted to place its LSB at bit 0. | ||
| 42 | * This value is suitable for direct comparison with other unshifted | ||
| 43 | * values appropriate for use in field <y> of register <x>. | ||
| 44 | * | ||
| 45 | * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for | ||
| 46 | * field <y> of register <x>. This value is suitable for direct | ||
| 47 | * comparison with unshifted values appropriate for use in field <y> | ||
| 48 | * of register <x>. | ||
| 49 | */ | ||
| 50 | |||
| 51 | #ifndef HOST1X_HW_HOST1X05_UCLASS_H | ||
| 52 | #define HOST1X_HW_HOST1X05_UCLASS_H | ||
| 53 | |||
| 54 | static inline u32 host1x_uclass_incr_syncpt_r(void) | ||
| 55 | { | ||
| 56 | return 0x0; | ||
| 57 | } | ||
| 58 | #define HOST1X_UCLASS_INCR_SYNCPT \ | ||
| 59 | host1x_uclass_incr_syncpt_r() | ||
| 60 | static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v) | ||
| 61 | { | ||
| 62 | return (v & 0xff) << 10; | ||
| 63 | } | ||
| 64 | #define HOST1X_UCLASS_INCR_SYNCPT_COND_F(v) \ | ||
| 65 | host1x_uclass_incr_syncpt_cond_f(v) | ||
| 66 | static inline u32 host1x_uclass_incr_syncpt_indx_f(u32 v) | ||
| 67 | { | ||
| 68 | return (v & 0x3ff) << 0; | ||
| 69 | } | ||
| 70 | #define HOST1X_UCLASS_INCR_SYNCPT_INDX_F(v) \ | ||
| 71 | host1x_uclass_incr_syncpt_indx_f(v) | ||
| 72 | static inline u32 host1x_uclass_load_syncpt_payload_32_r(void) | ||
| 73 | { | ||
| 74 | return 0x4e; | ||
| 75 | } | ||
| 76 | #define HOST1X_UCLASS_LOAD_SYNCPT_PAYLOAD_32 \ | ||
| 77 | host1x_uclass_load_syncpt_payload_32_r() | ||
| 78 | static inline u32 host1x_uclass_wait_syncpt_32_r(void) | ||
| 79 | { | ||
| 80 | return 0x50; | ||
| 81 | } | ||
| 82 | #define HOST1X_UCLASS_WAIT_SYNCPT_32 \ | ||
| 83 | host1x_uclass_wait_syncpt_32_r() | ||
| 84 | static inline u32 host1x_uclass_wait_syncpt_r(void) | ||
| 85 | { | ||
| 86 | return 0x8; | ||
| 87 | } | ||
| 88 | #define HOST1X_UCLASS_WAIT_SYNCPT \ | ||
| 89 | host1x_uclass_wait_syncpt_r() | ||
| 90 | static inline u32 host1x_uclass_wait_syncpt_indx_f(u32 v) | ||
| 91 | { | ||
| 92 | return (v & 0xff) << 24; | ||
| 93 | } | ||
| 94 | #define HOST1X_UCLASS_WAIT_SYNCPT_INDX_F(v) \ | ||
| 95 | host1x_uclass_wait_syncpt_indx_f(v) | ||
| 96 | static inline u32 host1x_uclass_wait_syncpt_thresh_f(u32 v) | ||
| 97 | { | ||
| 98 | return (v & 0xffffff) << 0; | ||
| 99 | } | ||
| 100 | #define HOST1X_UCLASS_WAIT_SYNCPT_THRESH_F(v) \ | ||
| 101 | host1x_uclass_wait_syncpt_thresh_f(v) | ||
| 102 | static inline u32 host1x_uclass_wait_syncpt_base_r(void) | ||
| 103 | { | ||
| 104 | return 0x9; | ||
| 105 | } | ||
| 106 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE \ | ||
| 107 | host1x_uclass_wait_syncpt_base_r() | ||
| 108 | static inline u32 host1x_uclass_wait_syncpt_base_indx_f(u32 v) | ||
| 109 | { | ||
| 110 | return (v & 0x3ff) << 22; | ||
| 111 | } | ||
| 112 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_INDX_F(v) \ | ||
| 113 | host1x_uclass_wait_syncpt_base_indx_f(v) | ||
| 114 | static inline u32 host1x_uclass_wait_syncpt_base_base_indx_f(u32 v) | ||
| 115 | { | ||
| 116 | return (v & 0x3f) << 16; | ||
| 117 | } | ||
| 118 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_BASE_INDX_F(v) \ | ||
| 119 | host1x_uclass_wait_syncpt_base_base_indx_f(v) | ||
| 120 | static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v) | ||
| 121 | { | ||
| 122 | return (v & 0xffff) << 0; | ||
| 123 | } | ||
| 124 | #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \ | ||
| 125 | host1x_uclass_wait_syncpt_base_offset_f(v) | ||
| 126 | static inline u32 host1x_uclass_load_syncpt_base_r(void) | ||
| 127 | { | ||
| 128 | return 0xb; | ||
| 129 | } | ||
| 130 | #define HOST1X_UCLASS_LOAD_SYNCPT_BASE \ | ||
| 131 | host1x_uclass_load_syncpt_base_r() | ||
| 132 | static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v) | ||
| 133 | { | ||
| 134 | return (v & 0xff) << 24; | ||
| 135 | } | ||
| 136 | #define HOST1X_UCLASS_LOAD_SYNCPT_BASE_BASE_INDX_F(v) \ | ||
| 137 | host1x_uclass_load_syncpt_base_base_indx_f(v) | ||
| 138 | static inline u32 host1x_uclass_load_syncpt_base_value_f(u32 v) | ||
| 139 | { | ||
| 140 | return (v & 0xffffff) << 0; | ||
| 141 | } | ||
| 142 | #define HOST1X_UCLASS_LOAD_SYNCPT_BASE_VALUE_F(v) \ | ||
| 143 | host1x_uclass_load_syncpt_base_value_f(v) | ||
| 144 | static inline u32 host1x_uclass_incr_syncpt_base_base_indx_f(u32 v) | ||
| 145 | { | ||
| 146 | return (v & 0xff) << 24; | ||
| 147 | } | ||
| 148 | #define HOST1X_UCLASS_INCR_SYNCPT_BASE_BASE_INDX_F(v) \ | ||
| 149 | host1x_uclass_incr_syncpt_base_base_indx_f(v) | ||
| 150 | static inline u32 host1x_uclass_incr_syncpt_base_offset_f(u32 v) | ||
| 151 | { | ||
| 152 | return (v & 0xffffff) << 0; | ||
| 153 | } | ||
| 154 | #define HOST1X_UCLASS_INCR_SYNCPT_BASE_OFFSET_F(v) \ | ||
| 155 | host1x_uclass_incr_syncpt_base_offset_f(v) | ||
| 156 | |||
| 157 | #endif | ||
diff --git a/drivers/gpu/host1x/hw/intr_hw_t186.c b/drivers/gpu/host1x/hw/intr_hw_t186.c new file mode 100644 index 000000000..48bd1150f --- /dev/null +++ b/drivers/gpu/host1x/hw/intr_hw_t186.c | |||
| @@ -0,0 +1,247 @@ | |||
| 1 | /* | ||
| 2 | * Tegra host1x Interrupt Management | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Google, Inc. | ||
| 5 | * Copyright (C) 2016 NVIDIA Corporation. All rights reserved. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify it | ||
| 8 | * under the terms and conditions of the GNU General Public License, | ||
| 9 | * version 2, as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 14 | * more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/interrupt.h> | ||
| 21 | #include <linux/irq.h> | ||
| 22 | #include <linux/io.h> | ||
| 23 | |||
| 24 | #include "intr.h" | ||
| 25 | #include "dev.h" | ||
| 26 | |||
| 27 | |||
| 28 | static inline u32 bit_mask(u32 nr) | ||
| 29 | { | ||
| 30 | return 1UL << (nr % 32); | ||
| 31 | } | ||
| 32 | static inline u32 bit_word(u32 nr) | ||
| 33 | { | ||
| 34 | return nr / 32; | ||
| 35 | } | ||
| 36 | |||
| 37 | /* | ||
| 38 | * Sync point threshold interrupt service function | ||
| 39 | * Handles sync point threshold triggers, in interrupt context | ||
| 40 | */ | ||
| 41 | static void host1x_intr_syncpt_handle(struct host1x_syncpt *syncpt) | ||
| 42 | { | ||
| 43 | unsigned int id = syncpt->id; | ||
| 44 | struct host1x *host = syncpt->host; | ||
| 45 | |||
| 46 | host1x_sync_writel(host, bit_mask(id), | ||
| 47 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(bit_word(id))); | ||
| 48 | host1x_sync_writel(host, bit_mask(id), | ||
| 49 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(bit_word(id))); | ||
| 50 | |||
| 51 | queue_work(host->intr_wq, &syncpt->intr.work); | ||
| 52 | } | ||
| 53 | |||
| 54 | static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id) | ||
| 55 | { | ||
| 56 | struct host1x *host = dev_id; | ||
| 57 | unsigned long reg; | ||
| 58 | int i, set_bit; | ||
| 59 | |||
| 60 | for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); i++) { | ||
| 61 | reg = host1x_sync_readl(host, | ||
| 62 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i)); | ||
| 63 | for_each_set_bit(set_bit, ®, 32) { | ||
| 64 | struct host1x_syncpt *syncpt; | ||
| 65 | int id = i * 32 + set_bit; | ||
| 66 | |||
| 67 | if (unlikely(id < 0 || id >= host->info->nb_pts)) { | ||
| 68 | dev_err(host->dev, | ||
| 69 | "%s(): unexptected syncpt id %d\n", | ||
| 70 | __func__, id); | ||
| 71 | goto out; | ||
| 72 | } | ||
| 73 | syncpt = host->syncpt + id; | ||
| 74 | host1x_intr_syncpt_handle(syncpt); | ||
| 75 | } | ||
| 76 | } | ||
| 77 | out: | ||
| 78 | return IRQ_HANDLED; | ||
| 79 | } | ||
| 80 | |||
| 81 | static void _host1x_intr_disable_all_syncpt_intrs(struct host1x *host) | ||
| 82 | { | ||
| 83 | u32 i; | ||
| 84 | |||
| 85 | for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); ++i) { | ||
| 86 | host1x_sync_writel(host, 0xffffffffu, | ||
| 87 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(i)); | ||
| 88 | host1x_sync_writel(host, 0xffffffffu, | ||
| 89 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i)); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | static int _host1x_intr_init_host_sync(struct host1x *host, u32 cpm, | ||
| 94 | void (*syncpt_thresh_work)(struct work_struct *)) | ||
| 95 | { | ||
| 96 | int i, err; | ||
| 97 | |||
| 98 | host1x_hw_intr_disable_all_syncpt_intrs(host); | ||
| 99 | |||
| 100 | for (i = 0; i < host->info->nb_pts; i++) | ||
| 101 | INIT_WORK(&host->syncpt[i].intr.work, syncpt_thresh_work); | ||
| 102 | |||
| 103 | err = devm_request_irq(host->dev, host->intr_syncpt_irq, | ||
| 104 | syncpt_thresh_isr, IRQF_SHARED, | ||
| 105 | "host1x_syncpt", host); | ||
| 106 | if (IS_ERR_VALUE(err)) { | ||
| 107 | WARN_ON(1); | ||
| 108 | return err; | ||
| 109 | } | ||
| 110 | |||
| 111 | /* disable the ip_busy_timeout. this prevents write drops */ | ||
| 112 | host1x_sync_writel(host, 0, HOST1X_SYNC_IP_BUSY_TIMEOUT); | ||
| 113 | |||
| 114 | /* | ||
| 115 | * increase the auto-ack timout to the maximum value. 2d will hang | ||
| 116 | * otherwise on Tegra2. | ||
| 117 | */ | ||
| 118 | host1x_sync_writel(host, 0xff, HOST1X_SYNC_CTXSW_TIMEOUT_CFG); | ||
| 119 | |||
| 120 | /* update host clocks per usec */ | ||
| 121 | host1x_sync_writel(host, cpm, HOST1X_SYNC_USEC_CLK); | ||
| 122 | |||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | |||
| 126 | static void _host1x_intr_set_syncpt_threshold(struct host1x *host, | ||
| 127 | u32 id, u32 thresh) | ||
| 128 | { | ||
| 129 | host1x_sync_writel(host, thresh, HOST1X_SYNC_SYNCPT_INT_THRESH(id)); | ||
| 130 | } | ||
| 131 | |||
| 132 | static void _host1x_intr_enable_syncpt_intr(struct host1x *host, u32 id) | ||
| 133 | { | ||
| 134 | host1x_sync_writel(host, bit_mask(id), | ||
| 135 | HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(bit_word(id))); | ||
| 136 | } | ||
| 137 | |||
| 138 | static void _host1x_intr_disable_syncpt_intr(struct host1x *host, u32 id) | ||
| 139 | { | ||
| 140 | host1x_sync_writel(host, bit_mask(id), | ||
| 141 | HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(bit_word(id))); | ||
| 142 | host1x_sync_writel(host, bit_mask(id), | ||
| 143 | HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(bit_word(id))); | ||
| 144 | } | ||
| 145 | |||
| 146 | static int _host1x_free_syncpt_irq(struct host1x *host) | ||
| 147 | { | ||
| 148 | devm_free_irq(host->dev, host->intr_syncpt_irq, host); | ||
| 149 | flush_workqueue(host->intr_wq); | ||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | |||
| 153 | /** | ||
| 154 | * Host general interrupt service function | ||
| 155 | * Handles read / write failures | ||
| 156 | */ | ||
| 157 | static irqreturn_t general_isr(int irq, void *dev_id) | ||
| 158 | { | ||
| 159 | struct host1x *host = dev_id; | ||
| 160 | u32 intstatus, addr; | ||
| 161 | |||
| 162 | /* Handle host1x interrupt in ISR */ | ||
| 163 | intstatus = host1x_sync_readl(host, HOST1X_SYNC_INTSTATUS); | ||
| 164 | |||
| 165 | if (HOST1X_SYNC_INTSTATUS_IP_READ_INT_V(intstatus)) { | ||
| 166 | addr = host1x_sync_readl(host, | ||
| 167 | HOST1X_SYNC_IP_READ_TIMEOUT_ADDR); | ||
| 168 | pr_err("Host read timeout at address %x\n", addr); | ||
| 169 | } | ||
| 170 | |||
| 171 | if (HOST1X_SYNC_INTSTATUS_IP_WRITE_INT_V(intstatus)) { | ||
| 172 | addr = host1x_sync_readl(host, | ||
| 173 | HOST1X_SYNC_IP_WRITE_TIMEOUT_ADDR); | ||
| 174 | pr_err("Host write timeout at address %x\n", addr); | ||
| 175 | } | ||
| 176 | |||
| 177 | if (HOST1X_SYNC_INTSTATUS_ILLEGAL_PB_ACCESS_V(intstatus)) { | ||
| 178 | u32 stat = host1x_sync_readl(host, HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_PB); | ||
| 179 | u32 ch = HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_PB_CH_V(stat); | ||
| 180 | u32 id = HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_PB_SYNCPT_V(stat); | ||
| 181 | pr_err("Host illegal syncpoint pb access (ch=%u, id=%u)\n", ch, id); | ||
| 182 | } | ||
| 183 | |||
| 184 | if (HOST1X_SYNC_INTSTATUS_ILLEGAL_CLIENT_ACCESS_V(intstatus)) { | ||
| 185 | u32 stat = host1x_sync_readl(host, HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_CLIENT); | ||
| 186 | u32 ch = HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_CLIENT_CH_V(stat); | ||
| 187 | u32 id = HOST1X_SYNC_ILLEGAL_SYNCPT_ACCESS_FRM_CLIENT_SYNCPT_V(stat); | ||
| 188 | pr_err("Host illegal syncpoint client access (ch=%u, id=%u)\n", ch, id); | ||
| 189 | } | ||
| 190 | |||
| 191 | host1x_sync_writel(host, intstatus, HOST1X_SYNC_INTSTATUS); | ||
| 192 | |||
| 193 | return IRQ_HANDLED; | ||
| 194 | } | ||
| 195 | |||
| 196 | static int _host1x_intr_request_host_general_irq(struct host1x *host) | ||
| 197 | { | ||
| 198 | int err; | ||
| 199 | |||
| 200 | /* master disable for general (not syncpt) host interrupts */ | ||
| 201 | host1x_sync_writel(host, 0, HOST1X_SYNC_INTC0MASK); | ||
| 202 | host1x_sync_writel(host, 0, HOST1X_SYNC_INTGMASK); | ||
| 203 | host1x_sync_writel(host, 0, HOST1X_SYNC_INTMASK); | ||
| 204 | |||
| 205 | err = devm_request_irq(host->dev, host->intr_general_irq, | ||
| 206 | general_isr, 0, | ||
| 207 | "host1x_general", host); | ||
| 208 | if (IS_ERR_VALUE(err)) { | ||
| 209 | WARN_ON(1); | ||
| 210 | return err; | ||
| 211 | } | ||
| 212 | |||
| 213 | /* enable host module interrupt to CPU0 */ | ||
| 214 | host1x_sync_writel(host, BIT(0), HOST1X_SYNC_INTC0MASK); | ||
| 215 | host1x_sync_writel(host, BIT(0), HOST1X_SYNC_INTGMASK); | ||
| 216 | host1x_sync_writel(host, 0xff << 8, HOST1X_SYNC_SYNCPT_INTGMASK); | ||
| 217 | |||
| 218 | /* master enable for general (not syncpt) host interrupts | ||
| 219 | * (AXIREAD, AXIWRITE, Syncpoint protection */ | ||
| 220 | host1x_sync_writel(host, BIT(0) | BIT(1) | BIT(28) | BIT(30), | ||
| 221 | HOST1X_SYNC_INTMASK); | ||
| 222 | |||
| 223 | return err; | ||
| 224 | } | ||
| 225 | |||
| 226 | static void _host1x_intr_free_host_general_irq(struct host1x *host) | ||
| 227 | { | ||
| 228 | /* master disable for general (not syncpt) host interrupts */ | ||
| 229 | host1x_sync_writel(host, 0, HOST1X_SYNC_INTMASK); | ||
| 230 | host1x_sync_writel(host, 0, HOST1X_SYNC_SYNCPT_INTGMASK); | ||
| 231 | |||
| 232 | devm_free_irq(host->dev, host->intr_general_irq, host); | ||
| 233 | } | ||
| 234 | |||
| 235 | static const struct host1x_intr_ops host1x_intr_t186_ops = { | ||
| 236 | /* Syncpt interrupts */ | ||
| 237 | .init_host_sync = _host1x_intr_init_host_sync, | ||
| 238 | .set_syncpt_threshold = _host1x_intr_set_syncpt_threshold, | ||
| 239 | .enable_syncpt_intr = _host1x_intr_enable_syncpt_intr, | ||
| 240 | .disable_syncpt_intr = _host1x_intr_disable_syncpt_intr, | ||
| 241 | .disable_all_syncpt_intrs = _host1x_intr_disable_all_syncpt_intrs, | ||
| 242 | .free_syncpt_irq = _host1x_free_syncpt_irq, | ||
| 243 | |||
| 244 | /* Host general interrupts */ | ||
| 245 | .request_host_general_irq = _host1x_intr_request_host_general_irq, | ||
| 246 | .free_host_general_irq = _host1x_intr_free_host_general_irq, | ||
| 247 | }; | ||
diff --git a/drivers/gpu/host1x/hw/syncpt_hw_t186.c b/drivers/gpu/host1x/hw/syncpt_hw_t186.c new file mode 100644 index 000000000..9b196854a --- /dev/null +++ b/drivers/gpu/host1x/hw/syncpt_hw_t186.c | |||
| @@ -0,0 +1,126 @@ | |||
| 1 | /* | ||
| 2 | * Tegra host1x Syncpoints | ||
| 3 | * | ||
| 4 | * Copyright (c) 2016, NVIDIA Corporation. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms and conditions of the GNU General Public License, | ||
| 8 | * version 2, as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 13 | * more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/io.h> | ||
| 20 | |||
| 21 | #include "dev.h" | ||
| 22 | #include "syncpt.h" | ||
| 23 | |||
| 24 | /* | ||
| 25 | * Write the current syncpoint value back to hw. | ||
| 26 | */ | ||
| 27 | static void syncpt_restore(struct host1x_syncpt *sp) | ||
| 28 | { | ||
| 29 | struct host1x *host = sp->host; | ||
| 30 | int min = host1x_syncpt_read_min(sp); | ||
| 31 | host1x_sync_writel(host, min, HOST1X_SYNC_SYNCPT(sp->id)); | ||
| 32 | } | ||
| 33 | |||
| 34 | /* | ||
| 35 | * Write the current waitbase value back to hw. | ||
| 36 | */ | ||
| 37 | static void syncpt_restore_wait_base(struct host1x_syncpt *sp) | ||
| 38 | { | ||
| 39 | struct host1x *host = sp->host; | ||
| 40 | host1x_sync_writel(host, sp->base_val, | ||
| 41 | HOST1X_SYNC_SYNCPT_BASE(sp->id)); | ||
| 42 | } | ||
| 43 | |||
| 44 | /* | ||
| 45 | * Read waitbase value from hw. | ||
| 46 | */ | ||
| 47 | static void syncpt_read_wait_base(struct host1x_syncpt *sp) | ||
| 48 | { | ||
| 49 | struct host1x *host = sp->host; | ||
| 50 | sp->base_val = | ||
| 51 | host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_BASE(sp->id)); | ||
| 52 | } | ||
| 53 | |||
| 54 | /* | ||
| 55 | * Updates the last value read from hardware. | ||
| 56 | */ | ||
| 57 | static u32 syncpt_load(struct host1x_syncpt *sp) | ||
| 58 | { | ||
| 59 | struct host1x *host = sp->host; | ||
| 60 | u32 old, live; | ||
| 61 | |||
| 62 | /* Loop in case there's a race writing to min_val */ | ||
| 63 | do { | ||
| 64 | old = host1x_syncpt_read_min(sp); | ||
| 65 | live = host1x_sync_readl(host, HOST1X_SYNC_SYNCPT(sp->id)); | ||
| 66 | } while ((u32)atomic_cmpxchg(&sp->min_val, old, live) != old); | ||
| 67 | |||
| 68 | if (!host1x_syncpt_check_max(sp, live)) | ||
| 69 | dev_err(host->dev, "%s failed: id=%u, min=%d, max=%d\n", | ||
| 70 | __func__, sp->id, host1x_syncpt_read_min(sp), | ||
| 71 | host1x_syncpt_read_max(sp)); | ||
| 72 | |||
| 73 | return live; | ||
| 74 | } | ||
| 75 | |||
| 76 | /* | ||
| 77 | * Write a cpu syncpoint increment to the hardware, without touching | ||
| 78 | * the cache. | ||
| 79 | */ | ||
| 80 | static int syncpt_cpu_incr(struct host1x_syncpt *sp) | ||
| 81 | { | ||
| 82 | struct host1x *host = sp->host; | ||
| 83 | u32 reg_offset = sp->id / 32; | ||
| 84 | |||
| 85 | if (!host1x_syncpt_client_managed(sp) && | ||
| 86 | host1x_syncpt_idle(sp)) | ||
| 87 | return -EINVAL; | ||
| 88 | host1x_sync_writel(host, BIT_MASK(sp->id), | ||
| 89 | HOST1X_SYNC_SYNCPT_CPU_INCR(reg_offset)); | ||
| 90 | wmb(); | ||
| 91 | |||
| 92 | return 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | /* remove a wait pointed to by patch_addr */ | ||
| 96 | static int syncpt_patch_wait(struct host1x_syncpt *sp, void *patch_addr) | ||
| 97 | { | ||
| 98 | u32 override = host1x_class_host_wait_syncpt( | ||
| 99 | HOST1X_SYNCPT_RESERVED, 0); | ||
| 100 | |||
| 101 | *((u32 *)patch_addr) = override; | ||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | static void syncpt_get_mutex_owner(struct host1x_syncpt *sp, | ||
| 106 | unsigned int mutex_id, bool *cpu, bool *ch, | ||
| 107 | unsigned int *chid) | ||
| 108 | { | ||
| 109 | struct host1x *host = sp->host; | ||
| 110 | u32 owner; | ||
| 111 | |||
| 112 | owner = host1x_sync_readl(host, host1x_sync_common_mlock_r(mutex_id)); | ||
| 113 | *chid = HOST1X_SYNC_COMMON_MLOCK_CH_V(owner); | ||
| 114 | *ch = HOST1X_SYNC_COMMON_MLOCK_LOCKED_V(owner); | ||
| 115 | *cpu = false; | ||
| 116 | } | ||
| 117 | |||
| 118 | static const struct host1x_syncpt_ops host1x_syncpt_t186_ops = { | ||
| 119 | .restore = syncpt_restore, | ||
| 120 | .restore_wait_base = syncpt_restore_wait_base, | ||
| 121 | .load_wait_base = syncpt_read_wait_base, | ||
| 122 | .load = syncpt_load, | ||
| 123 | .cpu_incr = syncpt_cpu_incr, | ||
| 124 | .patch_wait = syncpt_patch_wait, | ||
| 125 | .get_mutex_owner = syncpt_get_mutex_owner, | ||
| 126 | }; | ||
