xref: /aosp_15_r20/external/libdrm/tegra/pushbuf.c (revision 7688df22e49036ff52a766b7101da3a49edadb8c)
1*7688df22SAndroid Build Coastguard Worker /*
2*7688df22SAndroid Build Coastguard Worker  * Copyright © 2012, 2013 Thierry Reding
3*7688df22SAndroid Build Coastguard Worker  * Copyright © 2013 Erik Faye-Lund
4*7688df22SAndroid Build Coastguard Worker  * Copyright © 2014 NVIDIA Corporation
5*7688df22SAndroid Build Coastguard Worker  *
6*7688df22SAndroid Build Coastguard Worker  * Permission is hereby granted, free of charge, to any person obtaining a
7*7688df22SAndroid Build Coastguard Worker  * copy of this software and associated documentation files (the "Software"),
8*7688df22SAndroid Build Coastguard Worker  * to deal in the Software without restriction, including without limitation
9*7688df22SAndroid Build Coastguard Worker  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10*7688df22SAndroid Build Coastguard Worker  * and/or sell copies of the Software, and to permit persons to whom the
11*7688df22SAndroid Build Coastguard Worker  * Software is furnished to do so, subject to the following conditions:
12*7688df22SAndroid Build Coastguard Worker  *
13*7688df22SAndroid Build Coastguard Worker  * The above copyright notice and this permission notice shall be included in
14*7688df22SAndroid Build Coastguard Worker  * all copies or substantial portions of the Software.
15*7688df22SAndroid Build Coastguard Worker  *
16*7688df22SAndroid Build Coastguard Worker  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*7688df22SAndroid Build Coastguard Worker  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*7688df22SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19*7688df22SAndroid Build Coastguard Worker  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20*7688df22SAndroid Build Coastguard Worker  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21*7688df22SAndroid Build Coastguard Worker  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22*7688df22SAndroid Build Coastguard Worker  * OTHER DEALINGS IN THE SOFTWARE.
23*7688df22SAndroid Build Coastguard Worker  */
24*7688df22SAndroid Build Coastguard Worker 
25*7688df22SAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
26*7688df22SAndroid Build Coastguard Worker #  include "config.h"
27*7688df22SAndroid Build Coastguard Worker #endif
28*7688df22SAndroid Build Coastguard Worker 
29*7688df22SAndroid Build Coastguard Worker #include <errno.h>
30*7688df22SAndroid Build Coastguard Worker #include <stdlib.h>
31*7688df22SAndroid Build Coastguard Worker #include <string.h>
32*7688df22SAndroid Build Coastguard Worker 
33*7688df22SAndroid Build Coastguard Worker #include "util_math.h"
34*7688df22SAndroid Build Coastguard Worker #include "private.h"
35*7688df22SAndroid Build Coastguard Worker 
36*7688df22SAndroid Build Coastguard Worker #define HOST1X_OPCODE_NONINCR(offset, count) \
37*7688df22SAndroid Build Coastguard Worker     ((0x2 << 28) | (((offset) & 0xfff) << 16) | ((count) & 0xffff))
38*7688df22SAndroid Build Coastguard Worker 
39*7688df22SAndroid Build Coastguard Worker static inline unsigned int
drm_tegra_pushbuf_get_offset(struct drm_tegra_pushbuf * pushbuf,uint32_t * ptr)40*7688df22SAndroid Build Coastguard Worker drm_tegra_pushbuf_get_offset(struct drm_tegra_pushbuf *pushbuf, uint32_t *ptr)
41*7688df22SAndroid Build Coastguard Worker {
42*7688df22SAndroid Build Coastguard Worker     return ptr - pushbuf->start;
43*7688df22SAndroid Build Coastguard Worker }
44*7688df22SAndroid Build Coastguard Worker 
drm_tegra_pushbuf_free(struct drm_tegra_pushbuf * pushbuf)45*7688df22SAndroid Build Coastguard Worker void drm_tegra_pushbuf_free(struct drm_tegra_pushbuf *pushbuf)
46*7688df22SAndroid Build Coastguard Worker {
47*7688df22SAndroid Build Coastguard Worker     if (pushbuf->start)
48*7688df22SAndroid Build Coastguard Worker         free(pushbuf->start);
49*7688df22SAndroid Build Coastguard Worker 
50*7688df22SAndroid Build Coastguard Worker     free(pushbuf);
51*7688df22SAndroid Build Coastguard Worker }
52*7688df22SAndroid Build Coastguard Worker 
53*7688df22SAndroid Build Coastguard Worker /**
54*7688df22SAndroid Build Coastguard Worker  * drm_tegra_pushbuf_begin() - prepare push buffer for a series of pushes
55*7688df22SAndroid Build Coastguard Worker  * @pushbuf: push buffer
56*7688df22SAndroid Build Coastguard Worker  * @words: maximum number of words in series of pushes to follow
57*7688df22SAndroid Build Coastguard Worker  */
58*7688df22SAndroid Build Coastguard Worker drm_public int
drm_tegra_pushbuf_begin(struct drm_tegra_pushbuf * pushbuf,unsigned int words,uint32_t ** ptrp)59*7688df22SAndroid Build Coastguard Worker drm_tegra_pushbuf_begin(struct drm_tegra_pushbuf *pushbuf,
60*7688df22SAndroid Build Coastguard Worker                         unsigned int words, uint32_t **ptrp)
61*7688df22SAndroid Build Coastguard Worker {
62*7688df22SAndroid Build Coastguard Worker     struct drm_tegra_job *job = pushbuf->job;
63*7688df22SAndroid Build Coastguard Worker     unsigned long offset;
64*7688df22SAndroid Build Coastguard Worker     size_t size;
65*7688df22SAndroid Build Coastguard Worker     void *ptr;
66*7688df22SAndroid Build Coastguard Worker 
67*7688df22SAndroid Build Coastguard Worker     if (pushbuf->ptr + words >= pushbuf->end) {
68*7688df22SAndroid Build Coastguard Worker         words = pushbuf->end - pushbuf->start + words;
69*7688df22SAndroid Build Coastguard Worker         size = ALIGN(words * 4, job->page_size);
70*7688df22SAndroid Build Coastguard Worker         offset = pushbuf->ptr - pushbuf->start;
71*7688df22SAndroid Build Coastguard Worker 
72*7688df22SAndroid Build Coastguard Worker         ptr = realloc(pushbuf->start, size);
73*7688df22SAndroid Build Coastguard Worker         if (!ptr)
74*7688df22SAndroid Build Coastguard Worker             return -ENOMEM;
75*7688df22SAndroid Build Coastguard Worker 
76*7688df22SAndroid Build Coastguard Worker         pushbuf->start = ptr;
77*7688df22SAndroid Build Coastguard Worker         pushbuf->end = pushbuf->start + size / 4;
78*7688df22SAndroid Build Coastguard Worker         pushbuf->ptr = pushbuf->start + offset;
79*7688df22SAndroid Build Coastguard Worker     }
80*7688df22SAndroid Build Coastguard Worker 
81*7688df22SAndroid Build Coastguard Worker     if (ptrp)
82*7688df22SAndroid Build Coastguard Worker         *ptrp = pushbuf->ptr;
83*7688df22SAndroid Build Coastguard Worker 
84*7688df22SAndroid Build Coastguard Worker     return 0;
85*7688df22SAndroid Build Coastguard Worker }
86*7688df22SAndroid Build Coastguard Worker 
87*7688df22SAndroid Build Coastguard Worker drm_public int
drm_tegra_pushbuf_end(struct drm_tegra_pushbuf * pushbuf,uint32_t * ptr)88*7688df22SAndroid Build Coastguard Worker drm_tegra_pushbuf_end(struct drm_tegra_pushbuf *pushbuf, uint32_t *ptr)
89*7688df22SAndroid Build Coastguard Worker {
90*7688df22SAndroid Build Coastguard Worker     struct drm_tegra_submit_cmd *command;
91*7688df22SAndroid Build Coastguard Worker 
92*7688df22SAndroid Build Coastguard Worker     command = drm_tegra_job_add_command(pushbuf->job,
93*7688df22SAndroid Build Coastguard Worker                                         DRM_TEGRA_SUBMIT_CMD_GATHER_UPTR,
94*7688df22SAndroid Build Coastguard Worker                                         0);
95*7688df22SAndroid Build Coastguard Worker     if (!command)
96*7688df22SAndroid Build Coastguard Worker         return -ENOMEM;
97*7688df22SAndroid Build Coastguard Worker 
98*7688df22SAndroid Build Coastguard Worker     command->gather_uptr.words = ptr - pushbuf->start;
99*7688df22SAndroid Build Coastguard Worker     pushbuf->ptr = ptr;
100*7688df22SAndroid Build Coastguard Worker 
101*7688df22SAndroid Build Coastguard Worker     return 0;
102*7688df22SAndroid Build Coastguard Worker }
103*7688df22SAndroid Build Coastguard Worker 
104*7688df22SAndroid Build Coastguard Worker drm_public int
drm_tegra_pushbuf_wait(struct drm_tegra_pushbuf * pushbuf,struct drm_tegra_syncpoint * syncpt,uint32_t value)105*7688df22SAndroid Build Coastguard Worker drm_tegra_pushbuf_wait(struct drm_tegra_pushbuf *pushbuf,
106*7688df22SAndroid Build Coastguard Worker                        struct drm_tegra_syncpoint *syncpt,
107*7688df22SAndroid Build Coastguard Worker                        uint32_t value)
108*7688df22SAndroid Build Coastguard Worker {
109*7688df22SAndroid Build Coastguard Worker     struct drm_tegra_submit_cmd *command;
110*7688df22SAndroid Build Coastguard Worker 
111*7688df22SAndroid Build Coastguard Worker     command = drm_tegra_job_add_command(pushbuf->job,
112*7688df22SAndroid Build Coastguard Worker                                         DRM_TEGRA_SUBMIT_CMD_WAIT_SYNCPT,
113*7688df22SAndroid Build Coastguard Worker                                         0);
114*7688df22SAndroid Build Coastguard Worker     if (!command)
115*7688df22SAndroid Build Coastguard Worker         return -ENOMEM;
116*7688df22SAndroid Build Coastguard Worker 
117*7688df22SAndroid Build Coastguard Worker     command->wait_syncpt.id = syncpt->id;
118*7688df22SAndroid Build Coastguard Worker     command->wait_syncpt.value = value;
119*7688df22SAndroid Build Coastguard Worker 
120*7688df22SAndroid Build Coastguard Worker     return 0;
121*7688df22SAndroid Build Coastguard Worker }
122*7688df22SAndroid Build Coastguard Worker 
123*7688df22SAndroid Build Coastguard Worker drm_public int
drm_tegra_pushbuf_relocate(struct drm_tegra_pushbuf * pushbuf,uint32_t ** ptrp,struct drm_tegra_mapping * target,unsigned long offset,unsigned int shift,uint32_t flags)124*7688df22SAndroid Build Coastguard Worker drm_tegra_pushbuf_relocate(struct drm_tegra_pushbuf *pushbuf, uint32_t **ptrp,
125*7688df22SAndroid Build Coastguard Worker                            struct drm_tegra_mapping *target,
126*7688df22SAndroid Build Coastguard Worker                            unsigned long offset, unsigned int shift,
127*7688df22SAndroid Build Coastguard Worker                            uint32_t flags)
128*7688df22SAndroid Build Coastguard Worker {
129*7688df22SAndroid Build Coastguard Worker     struct drm_tegra_submit_buf *buffers, *buffer;
130*7688df22SAndroid Build Coastguard Worker     struct drm_tegra_job *job = pushbuf->job;
131*7688df22SAndroid Build Coastguard Worker     size_t size;
132*7688df22SAndroid Build Coastguard Worker 
133*7688df22SAndroid Build Coastguard Worker     size = (job->num_buffers + 1) * sizeof(*buffer);
134*7688df22SAndroid Build Coastguard Worker 
135*7688df22SAndroid Build Coastguard Worker     buffers = realloc(job->buffers, size);
136*7688df22SAndroid Build Coastguard Worker     if (!buffers)
137*7688df22SAndroid Build Coastguard Worker         return -ENOMEM;
138*7688df22SAndroid Build Coastguard Worker 
139*7688df22SAndroid Build Coastguard Worker     buffer = &buffers[job->num_buffers];
140*7688df22SAndroid Build Coastguard Worker 
141*7688df22SAndroid Build Coastguard Worker     memset(buffer, 0, sizeof(*buffer));
142*7688df22SAndroid Build Coastguard Worker     buffer->mapping = target->id;
143*7688df22SAndroid Build Coastguard Worker     buffer->flags = flags;
144*7688df22SAndroid Build Coastguard Worker     buffer->reloc.target_offset = offset;
145*7688df22SAndroid Build Coastguard Worker     buffer->reloc.gather_offset_words = drm_tegra_pushbuf_get_offset(pushbuf,
146*7688df22SAndroid Build Coastguard Worker                                                                      *ptrp);
147*7688df22SAndroid Build Coastguard Worker     buffer->reloc.shift = shift;
148*7688df22SAndroid Build Coastguard Worker 
149*7688df22SAndroid Build Coastguard Worker     *(*ptrp)++ = 0xdeadbeef;
150*7688df22SAndroid Build Coastguard Worker 
151*7688df22SAndroid Build Coastguard Worker     job->buffers = buffers;
152*7688df22SAndroid Build Coastguard Worker     job->num_buffers++;
153*7688df22SAndroid Build Coastguard Worker 
154*7688df22SAndroid Build Coastguard Worker     return 0;
155*7688df22SAndroid Build Coastguard Worker }
156*7688df22SAndroid Build Coastguard Worker 
157*7688df22SAndroid Build Coastguard Worker drm_public int
drm_tegra_pushbuf_sync(struct drm_tegra_pushbuf * pushbuf,struct drm_tegra_syncpoint * syncpt,unsigned int count)158*7688df22SAndroid Build Coastguard Worker drm_tegra_pushbuf_sync(struct drm_tegra_pushbuf *pushbuf,
159*7688df22SAndroid Build Coastguard Worker                        struct drm_tegra_syncpoint *syncpt,
160*7688df22SAndroid Build Coastguard Worker                        unsigned int count)
161*7688df22SAndroid Build Coastguard Worker {
162*7688df22SAndroid Build Coastguard Worker     struct drm_tegra_job *job = pushbuf->job;
163*7688df22SAndroid Build Coastguard Worker 
164*7688df22SAndroid Build Coastguard Worker     job->syncpt.increments += count;
165*7688df22SAndroid Build Coastguard Worker     job->syncpt.id = syncpt->id;
166*7688df22SAndroid Build Coastguard Worker 
167*7688df22SAndroid Build Coastguard Worker     return 0;
168*7688df22SAndroid Build Coastguard Worker }
169*7688df22SAndroid Build Coastguard Worker 
170*7688df22SAndroid Build Coastguard Worker drm_public int
drm_tegra_pushbuf_sync_cond(struct drm_tegra_pushbuf * pushbuf,uint32_t ** ptrp,struct drm_tegra_syncpoint * syncpt,enum drm_tegra_sync_cond cond)171*7688df22SAndroid Build Coastguard Worker drm_tegra_pushbuf_sync_cond(struct drm_tegra_pushbuf *pushbuf, uint32_t **ptrp,
172*7688df22SAndroid Build Coastguard Worker                             struct drm_tegra_syncpoint *syncpt,
173*7688df22SAndroid Build Coastguard Worker                             enum drm_tegra_sync_cond cond)
174*7688df22SAndroid Build Coastguard Worker {
175*7688df22SAndroid Build Coastguard Worker     struct drm_tegra_channel *channel = pushbuf->job->channel;
176*7688df22SAndroid Build Coastguard Worker 
177*7688df22SAndroid Build Coastguard Worker     if (cond >= DRM_TEGRA_SYNC_COND_MAX)
178*7688df22SAndroid Build Coastguard Worker         return -EINVAL;
179*7688df22SAndroid Build Coastguard Worker 
180*7688df22SAndroid Build Coastguard Worker     *(*ptrp)++ = HOST1X_OPCODE_NONINCR(0x0, 0x1);
181*7688df22SAndroid Build Coastguard Worker     *(*ptrp)++ = cond << channel->cond_shift | syncpt->id;
182*7688df22SAndroid Build Coastguard Worker 
183*7688df22SAndroid Build Coastguard Worker     return drm_tegra_pushbuf_sync(pushbuf, syncpt, 1);
184*7688df22SAndroid Build Coastguard Worker }
185