Merge remote-tracking branch 'asoc/fix/rcar' into asoc-linus
[linux-2.6-block.git] / drivers / gpu / drm / nouveau / core / engine / graph / fuc / gpc.fuc
1 /* fuc microcode for nvc0 PGRAPH/GPC
2  *
3  * Copyright 2011 Red Hat Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21  * OTHER DEALINGS IN THE SOFTWARE.
22  *
23  * Authors: Ben Skeggs
24  */
25
26 /* TODO
27  * - bracket certain functions with scratch writes, useful for debugging
28  * - watchdog timer around ctx operations
29  */
30
31 #ifdef INCLUDE_DATA
32 gpc_mmio_list_head:     .b32 #mmio_list_base
33 gpc_mmio_list_tail:
34 tpc_mmio_list_head:     .b32 #mmio_list_base
35 tpc_mmio_list_tail:
36 unk_mmio_list_head:     .b32 #mmio_list_base
37 unk_mmio_list_tail:     .b32 #mmio_list_base
38
39 gpc_id:                 .b32 0
40
41 tpc_count:              .b32 0
42 tpc_mask:               .b32 0
43
44 #if NV_PGRAPH_GPCX_UNK__SIZE > 0
45 unk_count:              .b32 0
46 unk_mask:               .b32 0
47 #endif
48
49 cmd_queue:              queue_init
50
51 mmio_list_base:
52 #endif
53
54 #ifdef INCLUDE_CODE
55 // reports an exception to the host
56 //
57 // In: $r15 error code (see os.h)
58 //
59 error:
60         push $r14
61         nv_wr32(NV_PGRAPH_FECS_CC_SCRATCH_VAL(5), $r15)
62         mov $r15 1
63         nv_wr32(NV_PGRAPH_FECS_INTR_UP_SET, $r15)
64         pop $r14
65         ret
66
67 // GPC fuc initialisation, executed by triggering ucode start, will
68 // fall through to main loop after completion.
69 //
70 // Input:
71 //   CC_SCRATCH[1]: context base
72 //
73 // Output:
74 //   CC_SCRATCH[0]:
75 //           31:31: set to signal completion
76 //   CC_SCRATCH[1]:
77 //            31:0: GPC context size
78 //
79 init:
80         clear b32 $r0
81
82         // setup stack
83         nv_iord($r1, NV_PGRAPH_GPCX_GPCCS_CAPS, 0)
84         extr $r1 $r1 9:17
85         shl b32 $r1 8
86         mov $sp $r1
87
88         // enable fifo access
89         mov $r2 NV_PGRAPH_GPCX_GPCCS_ACCESS_FIFO
90         nv_iowr(NV_PGRAPH_GPCX_GPCCS_ACCESS, 0, $r2)
91
92         // setup i0 handler, and route all interrupts to it
93         mov $r1 #ih
94         mov $iv0 $r1
95         nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_ROUTE, 0, $r0)
96
97         // enable fifo interrupt
98         mov $r2 NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET_FIFO
99         nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET, 0, $r2)
100
101         // enable interrupts
102         bset $flags ie0
103
104         // figure out which GPC we are, and how many TPCs we have
105         nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_UNITS, 0)
106         mov $r3 1
107         and $r2 0x1f
108         shl b32 $r3 $r2
109         sub b32 $r3 1
110         st b32 D[$r0 + #tpc_count] $r2
111         st b32 D[$r0 + #tpc_mask] $r3
112         nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_MYINDEX, 0)
113         st b32 D[$r0 + #gpc_id] $r2
114
115 #if NV_PGRAPH_GPCX_UNK__SIZE > 0
116         // figure out which, and how many, UNKs are actually present
117         imm32($r14, 0x500c30)
118         clear b32 $r2
119         clear b32 $r3
120         clear b32 $r4
121         init_unk_loop:
122                 call(nv_rd32)
123                 cmp b32 $r15 0
124                 bra z #init_unk_next
125                         mov $r15 1
126                         shl b32 $r15 $r2
127                         or $r4 $r15
128                         add b32 $r3 1
129                 init_unk_next:
130                 add b32 $r2 1
131                 add b32 $r14 4
132                 cmp b32 $r2 NV_PGRAPH_GPCX_UNK__SIZE
133                 bra ne #init_unk_loop
134         init_unk_done:
135         st b32 D[$r0 + #unk_count] $r3
136         st b32 D[$r0 + #unk_mask] $r4
137 #endif
138
139         // initialise context base, and size tracking
140         nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0)
141         clear b32 $r3           // track GPC context size here
142
143         // set mmctx base addresses now so we don't have to do it later,
144         // they don't currently ever change
145         shr b32 $r5 $r2 8
146         nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_SAVE_SWBASE, 0, $r5)
147         nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_SWBASE, 0, $r5)
148
149         // calculate GPC mmio context size
150         ld b32 $r14 D[$r0 + #gpc_mmio_list_head]
151         ld b32 $r15 D[$r0 + #gpc_mmio_list_tail]
152         call(mmctx_size)
153         add b32 $r2 $r15
154         add b32 $r3 $r15
155
156         // calculate per-TPC mmio context size
157         ld b32 $r14 D[$r0 + #tpc_mmio_list_head]
158         ld b32 $r15 D[$r0 + #tpc_mmio_list_tail]
159         call(mmctx_size)
160         ld b32 $r14 D[$r0 + #tpc_count]
161         mulu $r14 $r15
162         add b32 $r2 $r14
163         add b32 $r3 $r14
164
165 #if NV_PGRAPH_GPCX_UNK__SIZE > 0
166         // calculate per-UNK mmio context size
167         ld b32 $r14 D[$r0 + #unk_mmio_list_head]
168         ld b32 $r15 D[$r0 + #unk_mmio_list_tail]
169         call(mmctx_size)
170         ld b32 $r14 D[$r0 + #unk_count]
171         mulu $r14 $r15
172         add b32 $r2 $r14
173         add b32 $r3 $r14
174 #endif
175
176         // round up base/size to 256 byte boundary (for strand SWBASE)
177         shr b32 $r3 2
178         nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_COUNT, 0, $r3) // wtf for?!
179         shr b32 $r2 8
180         shr b32 $r3 6
181         add b32 $r2 1
182         add b32 $r3 1
183         shl b32 $r2 8
184         shl b32 $r3 8
185
186         // calculate size of strand context data
187         mov b32 $r15 $r2
188         call(strand_ctx_init)
189         add b32 $r3 $r15
190
191         // save context size, and tell HUB we're done
192         nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0, $r3)
193         clear b32 $r2
194         bset $r2 31
195         nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_SET(0), 0, $r2)
196
197 // Main program loop, very simple, sleeps until woken up by the interrupt
198 // handler, pulls a command from the queue and executes its handler
199 //
200 main:
201         bset $flags $p0
202         sleep $p0
203         mov $r13 #cmd_queue
204         call(queue_get)
205         bra $p1 #main
206
207         // 0x0000-0x0003 are all context transfers
208         cmpu b32 $r14 0x04
209         bra nc #main_not_ctx_xfer
210                 // fetch $flags and mask off $p1/$p2
211                 mov $r1 $flags
212                 mov $r2 0x0006
213                 not b32 $r2
214                 and $r1 $r2
215                 // set $p1/$p2 according to transfer type
216                 shl b32 $r14 1
217                 or $r1 $r14
218                 mov $flags $r1
219                 // transfer context data
220                 call(ctx_xfer)
221                 bra #main
222
223         main_not_ctx_xfer:
224         shl b32 $r15 $r14 16
225         or $r15 E_BAD_COMMAND
226         call(error)
227         bra #main
228
229 // interrupt handler
230 ih:
231         push $r8
232         mov $r8 $flags
233         push $r8
234         push $r9
235         push $r10
236         push $r11
237         push $r13
238         push $r14
239         push $r15
240         clear b32 $r0
241
242         // incoming fifo command?
243         nv_iord($r10, NV_PGRAPH_GPCX_GPCCS_INTR, 0)
244         and $r11 $r10 NV_PGRAPH_GPCX_GPCCS_INTR_FIFO
245         bra e #ih_no_fifo
246                 // queue incoming fifo command for later processing
247                 mov $r13 #cmd_queue
248                 nv_iord($r14, NV_PGRAPH_GPCX_GPCCS_FIFO_CMD, 0)
249                 nv_iord($r15, NV_PGRAPH_GPCX_GPCCS_FIFO_DATA, 0)
250                 call(queue_put)
251                 mov $r14 1
252                 nv_iowr(NV_PGRAPH_GPCX_GPCCS_FIFO_ACK, 0, $r14)
253
254         // ack, and wake up main()
255         ih_no_fifo:
256         nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_ACK, 0, $r10)
257
258         pop $r15
259         pop $r14
260         pop $r13
261         pop $r11
262         pop $r10
263         pop $r9
264         pop $r8
265         mov $flags $r8
266         pop $r8
267         bclr $flags $p0
268         iret
269
270 // Set this GPC's bit in HUB_BAR, used to signal completion of various
271 // activities to the HUB fuc
272 //
273 hub_barrier_done:
274         mov $r15 1
275         ld b32 $r14 D[$r0 + #gpc_id]
276         shl b32 $r15 $r14
277         nv_wr32(0x409418, $r15) // 0x409418 - HUB_BAR_SET
278         ret
279
280 // Disables various things, waits a bit, and re-enables them..
281 //
282 // Not sure how exactly this helps, perhaps "ENABLE" is not such a
283 // good description for the bits we turn off?  Anyways, without this,
284 // funny things happen.
285 //
286 ctx_redswitch:
287         mov $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_POWER
288         nv_iowr(NV_PGRAPH_GPCX_GPCCS_RED_SWITCH, 0, $r15)
289         mov $r14 8
290         ctx_redswitch_delay:
291                 sub b32 $r14 1
292                 bra ne #ctx_redswitch_delay
293         or $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_UNK11
294         or $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_ENABLE
295         nv_iowr(NV_PGRAPH_GPCX_GPCCS_RED_SWITCH, 0, $r15)
296         ret
297
298 // Transfer GPC context data between GPU and storage area
299 //
300 // In: $r15 context base address
301 //     $p1 clear on save, set on load
302 //     $p2 set if opposite direction done/will be done, so:
303 //              on save it means: "a load will follow this save"
304 //              on load it means: "a save preceeded this load"
305 //
306 ctx_xfer:
307         // set context base address
308         nv_iowr(NV_PGRAPH_GPCX_GPCCS_MEM_BASE, 0, $r15)
309         bra not $p1 #ctx_xfer_not_load
310                 call(ctx_redswitch)
311         ctx_xfer_not_load:
312
313         // strands
314         call(strand_pre)
315         clear b32 $r2
316         nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_SELECT, 0x3f, $r2)
317         xbit $r2 $flags $p1     // SAVE/LOAD
318         add b32 $r2 NV_PGRAPH_GPCX_GPCCS_STRAND_CMD_SAVE
319         nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_CMD, 0x3f, $r2)
320
321         // mmio context
322         xbit $r10 $flags $p1    // direction
323         or $r10 2               // first
324         imm32($r11,0x500000)
325         ld b32 $r12 D[$r0 + #gpc_id]
326         shl b32 $r12 15
327         add b32 $r11 $r12       // base = NV_PGRAPH_GPCn
328         ld b32 $r12 D[$r0 + #gpc_mmio_list_head]
329         ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]
330         mov $r14 0              // not multi
331         call(mmctx_xfer)
332
333         // per-TPC mmio context
334         xbit $r10 $flags $p1    // direction
335 #if !NV_PGRAPH_GPCX_UNK__SIZE
336         or $r10 4               // last
337 #endif
338         imm32($r11, 0x504000)
339         ld b32 $r12 D[$r0 + #gpc_id]
340         shl b32 $r12 15
341         add b32 $r11 $r12       // base = NV_PGRAPH_GPCn_TPC0
342         ld b32 $r12 D[$r0 + #tpc_mmio_list_head]
343         ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]
344         ld b32 $r15 D[$r0 + #tpc_mask]
345         mov $r14 0x800          // stride = 0x800
346         call(mmctx_xfer)
347
348 #if NV_PGRAPH_GPCX_UNK__SIZE > 0
349         // per-UNK mmio context
350         xbit $r10 $flags $p1    // direction
351         or $r10 4               // last
352         imm32($r11, 0x503000)
353         ld b32 $r12 D[$r0 + #gpc_id]
354         shl b32 $r12 15
355         add b32 $r11 $r12       // base = NV_PGRAPH_GPCn_UNK0
356         ld b32 $r12 D[$r0 + #unk_mmio_list_head]
357         ld b32 $r13 D[$r0 + #unk_mmio_list_tail]
358         ld b32 $r15 D[$r0 + #unk_mask]
359         mov $r14 0x200          // stride = 0x200
360         call(mmctx_xfer)
361 #endif
362
363         // wait for strands to finish
364         call(strand_wait)
365
366         // if load, or a save without a load following, do some
367         // unknown stuff that's done after finishing a block of
368         // strand commands
369         bra $p1 #ctx_xfer_post
370         bra not $p2 #ctx_xfer_done
371         ctx_xfer_post:
372                 call(strand_post)
373
374         // mark completion in HUB's barrier
375         ctx_xfer_done:
376         call(hub_barrier_done)
377         ret
378 #endif