Linux Audio

Check our new training course

Loading...
v3.1
  1/* fuc microcode for nvc0 PGRAPH/HUB
  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/* To build:
 27 *    m4 nvc0_grhub.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_grhub.fuc.h
 28 */
 29
 30.section nvc0_grhub_data
 31include(`nvc0_graph.fuc')
 32gpc_count:		.b32 0
 33rop_count:		.b32 0
 34cmd_queue:		queue_init
 35hub_mmio_list_head:	.b32 0
 36hub_mmio_list_tail:	.b32 0
 37
 38ctx_current:		.b32 0
 39
 40chipsets:
 41.b8  0xc0 0 0 0
 42.b16 nvc0_hub_mmio_head
 43.b16 nvc0_hub_mmio_tail
 44.b8  0xc1 0 0 0
 45.b16 nvc0_hub_mmio_head
 46.b16 nvc1_hub_mmio_tail
 47.b8  0xc3 0 0 0
 48.b16 nvc0_hub_mmio_head
 49.b16 nvc0_hub_mmio_tail
 50.b8  0xc4 0 0 0
 51.b16 nvc0_hub_mmio_head
 52.b16 nvc0_hub_mmio_tail
 53.b8  0xc8 0 0 0
 54.b16 nvc0_hub_mmio_head
 55.b16 nvc0_hub_mmio_tail
 56.b8  0xce 0 0 0
 57.b16 nvc0_hub_mmio_head
 58.b16 nvc0_hub_mmio_tail
 
 
 
 
 
 
 59.b8  0 0 0 0
 60
 61nvc0_hub_mmio_head:
 62mmctx_data(0x17e91c, 2)
 63mmctx_data(0x400204, 2)
 64mmctx_data(0x404004, 11)
 65mmctx_data(0x404044, 1)
 66mmctx_data(0x404094, 14)
 67mmctx_data(0x4040d0, 7)
 68mmctx_data(0x4040f8, 1)
 69mmctx_data(0x404130, 3)
 70mmctx_data(0x404150, 3)
 71mmctx_data(0x404164, 2)
 72mmctx_data(0x404174, 3)
 73mmctx_data(0x404200, 8)
 74mmctx_data(0x404404, 14)
 75mmctx_data(0x404460, 4)
 76mmctx_data(0x404480, 1)
 77mmctx_data(0x404498, 1)
 78mmctx_data(0x404604, 4)
 79mmctx_data(0x404618, 32)
 80mmctx_data(0x404698, 21)
 81mmctx_data(0x4046f0, 2)
 82mmctx_data(0x404700, 22)
 83mmctx_data(0x405800, 1)
 84mmctx_data(0x405830, 3)
 85mmctx_data(0x405854, 1)
 86mmctx_data(0x405870, 4)
 87mmctx_data(0x405a00, 2)
 88mmctx_data(0x405a18, 1)
 89mmctx_data(0x406020, 1)
 90mmctx_data(0x406028, 4)
 91mmctx_data(0x4064a8, 2)
 92mmctx_data(0x4064b4, 2)
 93mmctx_data(0x407804, 1)
 94mmctx_data(0x40780c, 6)
 95mmctx_data(0x4078bc, 1)
 96mmctx_data(0x408000, 7)
 97mmctx_data(0x408064, 1)
 98mmctx_data(0x408800, 3)
 99mmctx_data(0x408900, 4)
100mmctx_data(0x408980, 1)
101nvc0_hub_mmio_tail:
102mmctx_data(0x4064c0, 2)
103nvc1_hub_mmio_tail:
104
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105.align 256
106chan_data:
107chan_mmio_count:	.b32 0
108chan_mmio_address:	.b32 0
109
110.align 256
111xfer_data: 		.b32 0
112
113.section nvc0_grhub_code
114bra init
115define(`include_code')
116include(`nvc0_graph.fuc')
117
118// reports an exception to the host
119//
120// In: $r15 error code (see nvc0_graph.fuc)
121//
122error:
123	push $r14
124	mov $r14 0x814
125	shl b32 $r14 6
126	iowr I[$r14 + 0x000] $r15	// CC_SCRATCH[5] = error code
127	mov $r14 0xc1c
128	shl b32 $r14 6
129	mov $r15 1
130	iowr I[$r14 + 0x000] $r15	// INTR_UP_SET
131	pop $r14
132	ret
133
134// HUB fuc initialisation, executed by triggering ucode start, will
135// fall through to main loop after completion.
136//
137// Input:
138//   CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
139//
140// Output:
141//   CC_SCRATCH[0]:
142//	     31:31: set to signal completion
143//   CC_SCRATCH[1]:
144//	      31:0: total PGRAPH context size
145//
146init:
147	clear b32 $r0
148	mov $sp $r0
149	mov $xdbase $r0
150
151	// enable fifo access
152	mov $r1 0x1200
153	mov $r2 2
154	iowr I[$r1 + 0x000] $r2	// FIFO_ENABLE
155
156	// setup i0 handler, and route all interrupts to it
157	mov $r1 ih
158	mov $iv0 $r1
159	mov $r1 0x400
160	iowr I[$r1 + 0x300] $r0	// INTR_DISPATCH
161
162	// route HUB_CHANNEL_SWITCH to fuc interrupt 8
163	mov $r3 0x404
164	shl b32 $r3 6
165	mov $r2 0x2003		// { HUB_CHANNEL_SWITCH, ZERO } -> intr 8
166	iowr I[$r3 + 0x000] $r2
167
168	// not sure what these are, route them because NVIDIA does, and
169	// the IRQ handler will signal the host if we ever get one.. we
170	// may find out if/why we need to handle these if so..
171	//
172	mov $r2 0x2004
173	iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9
174	mov $r2 0x200b
175	iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10
176	mov $r2 0x200c
177	iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15
178
179	// enable all INTR_UP interrupts
180	mov $r2 0xc24
181	shl b32 $r2 6
182	not b32 $r3 $r0
183	iowr I[$r2] $r3
184
185	// enable fifo, ctxsw, 9, 10, 15 interrupts
186	mov $r2 -0x78fc		// 0x8704
187	sethi $r2 0
188	iowr I[$r1 + 0x000] $r2	// INTR_EN_SET
189
190	// fifo level triggered, rest edge
191	sub b32 $r1 0x100
192	mov $r2 4
193	iowr I[$r1] $r2
194
195	// enable interrupts
196	bset $flags ie0
197
198	// fetch enabled GPC/ROP counts
199	mov $r14 -0x69fc	// 0x409604
200	sethi $r14 0x400000
201	call nv_rd32
202	extr $r1 $r15 16:20
203	st b32 D[$r0 + rop_count] $r1
204	and $r15 0x1f
205	st b32 D[$r0 + gpc_count] $r15
206
207	// set BAR_REQMASK to GPC mask
208	mov $r1 1
209	shl b32 $r1 $r15
210	sub b32 $r1 1
211	mov $r2 0x40c
212	shl b32 $r2 6
213	iowr I[$r2 + 0x000] $r1
214	iowr I[$r2 + 0x100] $r1
215
216	// find context data for this chipset
217	mov $r2 0x800
218	shl b32 $r2 6
219	iord $r2 I[$r2 + 0x000]		// CC_SCRATCH[0]
220	mov $r15 chipsets - 8
221	init_find_chipset:
222		add b32 $r15 8
223		ld b32 $r3 D[$r15 + 0x00]
224		cmpu b32 $r3 $r2
225		bra e init_context
226		cmpu b32 $r3 0
227		bra ne init_find_chipset
228		// unknown chipset
229		ret
230
231	// context size calculation, reserve first 256 bytes for use by fuc
232	init_context:
233	mov $r1 256
234
235	// calculate size of mmio context data
236	ld b16 $r14 D[$r15 + 4]
237	ld b16 $r15 D[$r15 + 6]
238	sethi $r14 0
239	st b32 D[$r0 + hub_mmio_list_head] $r14
240	st b32 D[$r0 + hub_mmio_list_tail] $r15
241	call mmctx_size
242
243	// set mmctx base addresses now so we don't have to do it later,
244	// they don't (currently) ever change
245	mov $r3 0x700
246	shl b32 $r3 6
247	shr b32 $r4 $r1 8
248	iowr I[$r3 + 0x000] $r4		// MMCTX_SAVE_SWBASE
249	iowr I[$r3 + 0x100] $r4		// MMCTX_LOAD_SWBASE
250	add b32 $r3 0x1300
251	add b32 $r1 $r15
252	shr b32 $r15 2
253	iowr I[$r3 + 0x000] $r15	// MMCTX_LOAD_COUNT, wtf for?!?
254
255	// strands, base offset needs to be aligned to 256 bytes
256	shr b32 $r1 8
257	add b32 $r1 1
258	shl b32 $r1 8
259	mov b32 $r15 $r1
260	call strand_ctx_init
261	add b32 $r1 $r15
262
263	// initialise each GPC in sequence by passing in the offset of its
264	// context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
265	// has previously been uploaded by the host) running.
266	//
267	// the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
268	// when it has completed, and return the size of its context data
269	// in GPCn_CC_SCRATCH[1]
270	//
271	ld b32 $r3 D[$r0 + gpc_count]
272	mov $r4 0x2000
273	sethi $r4 0x500000
274	init_gpc:
275		// setup, and start GPC ucode running
276		add b32 $r14 $r4 0x804
277		mov b32 $r15 $r1
278		call nv_wr32			// CC_SCRATCH[1] = ctx offset
279		add b32 $r14 $r4 0x800
280		mov b32 $r15 $r2
281		call nv_wr32			// CC_SCRATCH[0] = chipset
282		add b32 $r14 $r4 0x10c
283		clear b32 $r15
284		call nv_wr32
285		add b32 $r14 $r4 0x104
286		call nv_wr32			// ENTRY
287		add b32 $r14 $r4 0x100
288		mov $r15 2			// CTRL_START_TRIGGER
289		call nv_wr32			// CTRL
290
291		// wait for it to complete, and adjust context size
292		add b32 $r14 $r4 0x800
293		init_gpc_wait:
294			call nv_rd32
295			xbit $r15 $r15 31
296			bra e init_gpc_wait
297		add b32 $r14 $r4 0x804
298		call nv_rd32
299		add b32 $r1 $r15
300
301		// next!
302		add b32 $r4 0x8000
303		sub b32 $r3 1
304		bra ne init_gpc
305
306	// save context size, and tell host we're ready
307	mov $r2 0x800
308	shl b32 $r2 6
309	iowr I[$r2 + 0x100] $r1		// CC_SCRATCH[1]  = context size
310	add b32 $r2 0x800
311	clear b32 $r1
312	bset $r1 31
313	iowr I[$r2 + 0x000] $r1		// CC_SCRATCH[0] |= 0x80000000
314
315// Main program loop, very simple, sleeps until woken up by the interrupt
316// handler, pulls a command from the queue and executes its handler
317//
318main:
319	// sleep until we have something to do
320	bset $flags $p0
321	sleep $p0
322	mov $r13 cmd_queue
323	call queue_get
324	bra $p1 main
325
326	// context switch, requested by GPU?
327	cmpu b32 $r14 0x4001
328	bra ne main_not_ctx_switch
329		trace_set(T_AUTO)
330		mov $r1 0xb00
331		shl b32 $r1 6
332		iord $r2 I[$r1 + 0x100]		// CHAN_NEXT
333		iord $r1 I[$r1 + 0x000]		// CHAN_CUR
334
335		xbit $r3 $r1 31
336		bra e chsw_no_prev
337			xbit $r3 $r2 31
338			bra e chsw_prev_no_next
339				push $r2
340				mov b32 $r2 $r1
341				trace_set(T_SAVE)
342				bclr $flags $p1
343				bset $flags $p2
344				call ctx_xfer
345				trace_clr(T_SAVE);
346				pop $r2
347				trace_set(T_LOAD);
348				bset $flags $p1
349				call ctx_xfer
350				trace_clr(T_LOAD);
351				bra chsw_done
352			chsw_prev_no_next:
353				push $r2
354				mov b32 $r2 $r1
355				bclr $flags $p1
356				bclr $flags $p2
357				call ctx_xfer
358				pop $r2
359				mov $r1 0xb00
360				shl b32 $r1 6
361				iowr I[$r1] $r2
362				bra chsw_done
363		chsw_no_prev:
364			xbit $r3 $r2 31
365			bra e chsw_done
366				bset $flags $p1
367				bclr $flags $p2
368				call ctx_xfer
369
370		// ack the context switch request
371		chsw_done:
372		mov $r1 0xb0c
373		shl b32 $r1 6
374		mov $r2 1
375		iowr I[$r1 + 0x000] $r2		// 0x409b0c
376		trace_clr(T_AUTO)
377		bra main
378
379	// request to set current channel? (*not* a context switch)
380	main_not_ctx_switch:
381	cmpu b32 $r14 0x0001
382	bra ne main_not_ctx_chan
383		mov b32 $r2 $r15
384		call ctx_chan
385		bra main_done
386
387	// request to store current channel context?
388	main_not_ctx_chan:
389	cmpu b32 $r14 0x0002
390	bra ne main_not_ctx_save
391		trace_set(T_SAVE)
392		bclr $flags $p1
393		bclr $flags $p2
394		call ctx_xfer
395		trace_clr(T_SAVE)
396		bra main_done
397
398	main_not_ctx_save:
399		shl b32 $r15 $r14 16
400		or $r15 E_BAD_COMMAND
401		call error
402		bra main
403
404	main_done:
405	mov $r1 0x820
406	shl b32 $r1 6
407	clear b32 $r2
408	bset $r2 31
409	iowr I[$r1 + 0x000] $r2		// CC_SCRATCH[0] |= 0x80000000
410	bra main
411
412// interrupt handler
413ih:
414	push $r8
415	mov $r8 $flags
416	push $r8
417	push $r9
418	push $r10
419	push $r11
420	push $r13
421	push $r14
422	push $r15
423
424	// incoming fifo command?
425	iord $r10 I[$r0 + 0x200]	// INTR
426	and $r11 $r10 0x00000004
427	bra e ih_no_fifo
428		// queue incoming fifo command for later processing
429		mov $r11 0x1900
430		mov $r13 cmd_queue
431		iord $r14 I[$r11 + 0x100]	// FIFO_CMD
432		iord $r15 I[$r11 + 0x000]	// FIFO_DATA
433		call queue_put
434		add b32 $r11 0x400
435		mov $r14 1
436		iowr I[$r11 + 0x000] $r14	// FIFO_ACK
437
438	// context switch request?
439	ih_no_fifo:
440	and $r11 $r10 0x00000100
441	bra e ih_no_ctxsw
442		// enqueue a context switch for later processing
443		mov $r13 cmd_queue
444		mov $r14 0x4001
445		call queue_put
446
447	// anything we didn't handle, bring it to the host's attention
448	ih_no_ctxsw:
449	mov $r11 0x104
450	not b32 $r11
451	and $r11 $r10 $r11
452	bra e ih_no_other
453		mov $r10 0xc1c
454		shl b32 $r10 6
455		iowr I[$r10] $r11	// INTR_UP_SET
456
457	// ack, and wake up main()
458	ih_no_other:
459	iowr I[$r0 + 0x100] $r10	// INTR_ACK
460
461	pop $r15
462	pop $r14
463	pop $r13
464	pop $r11
465	pop $r10
466	pop $r9
467	pop $r8
468	mov $flags $r8
469	pop $r8
470	bclr $flags $p0
471	iret
472
473// Not real sure, but, MEM_CMD 7 will hang forever if this isn't done
474ctx_4160s:
475	mov $r14 0x4160
476	sethi $r14 0x400000
477	mov $r15 1
478	call nv_wr32
479	ctx_4160s_wait:
480		call nv_rd32
481		xbit $r15 $r15 4
482		bra e ctx_4160s_wait
483	ret
484
485// Without clearing again at end of xfer, some things cause PGRAPH
486// to hang with STATUS=0x00000007 until it's cleared.. fbcon can
487// still function with it set however...
488ctx_4160c:
489	mov $r14 0x4160
490	sethi $r14 0x400000
491	clear b32 $r15
492	call nv_wr32
493	ret
494
495// Again, not real sure
496//
497// In: $r15 value to set 0x404170 to
498//
499ctx_4170s:
500	mov $r14 0x4170
501	sethi $r14 0x400000
502	or $r15 0x10
503	call nv_wr32
504	ret
505
506// Waits for a ctx_4170s() call to complete
507//
508ctx_4170w:
509	mov $r14 0x4170
510	sethi $r14 0x400000
511	call nv_rd32
512	and $r15 0x10
513	bra ne ctx_4170w
514	ret
515
516// Disables various things, waits a bit, and re-enables them..
517//
518// Not sure how exactly this helps, perhaps "ENABLE" is not such a
519// good description for the bits we turn off?  Anyways, without this,
520// funny things happen.
521//
522ctx_redswitch:
523	mov $r14 0x614
524	shl b32 $r14 6
525	mov $r15 0x270
526	iowr I[$r14] $r15	// HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL
527	mov $r15 8
528	ctx_redswitch_delay:
529		sub b32 $r15 1
530		bra ne ctx_redswitch_delay
531	mov $r15 0x770
532	iowr I[$r14] $r15	// HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL
533	ret
534
535// Not a clue what this is for, except that unless the value is 0x10, the
536// strand context is saved (and presumably restored) incorrectly..
537//
538// In: $r15 value to set to (0x00/0x10 are used)
539//
540ctx_86c:
541	mov $r14 0x86c
542	shl b32 $r14 6
543	iowr I[$r14] $r15	// HUB(0x86c) = val
544	mov $r14 -0x75ec
545	sethi $r14 0x400000
546	call nv_wr32		// ROP(0xa14) = val
547	mov $r14 -0x5794
548	sethi $r14 0x410000
549	call nv_wr32		// GPC(0x86c) = val
550	ret
551
552// ctx_load - load's a channel's ctxctl data, and selects its vm
553//
554// In: $r2 channel address
555//
556ctx_load:
557	trace_set(T_CHAN)
558
559	// switch to channel, somewhat magic in parts..
560	mov $r10 12		// DONE_UNK12
561	call wait_donez
562	mov $r1 0xa24
563	shl b32 $r1 6
564	iowr I[$r1 + 0x000] $r0	// 0x409a24
565	mov $r3 0xb00
566	shl b32 $r3 6
567	iowr I[$r3 + 0x100] $r2	// CHAN_NEXT
568	mov $r1 0xa0c
569	shl b32 $r1 6
570	mov $r4 7
571	iowr I[$r1 + 0x000] $r2 // MEM_CHAN
572	iowr I[$r1 + 0x100] $r4	// MEM_CMD
573	ctx_chan_wait_0:
574		iord $r4 I[$r1 + 0x100]
575		and $r4 0x1f
576		bra ne ctx_chan_wait_0
577	iowr I[$r3 + 0x000] $r2	// CHAN_CUR
578
579	// load channel header, fetch PGRAPH context pointer
580	mov $xtargets $r0
581	bclr $r2 31
582	shl b32 $r2 4
583	add b32 $r2 2
584
585	trace_set(T_LCHAN)
586	mov $r1 0xa04
587	shl b32 $r1 6
588	iowr I[$r1 + 0x000] $r2		// MEM_BASE
589	mov $r1 0xa20
590	shl b32 $r1 6
591	mov $r2 0x0002
592	sethi $r2 0x80000000
593	iowr I[$r1 + 0x000] $r2		// MEM_TARGET = vram
594	mov $r1 0x10			// chan + 0x0210
595	mov $r2 xfer_data
596	sethi $r2 0x00020000		// 16 bytes
597	xdld $r1 $r2
598	xdwait
599	trace_clr(T_LCHAN)
600
601	// update current context
602	ld b32 $r1 D[$r0 + xfer_data + 4]
603	shl b32 $r1 24
604	ld b32 $r2 D[$r0 + xfer_data + 0]
605	shr b32 $r2 8
606	or $r1 $r2
607	st b32 D[$r0 + ctx_current] $r1
608
609	// set transfer base to start of context, and fetch context header
610	trace_set(T_LCTXH)
611	mov $r2 0xa04
612	shl b32 $r2 6
613	iowr I[$r2 + 0x000] $r1		// MEM_BASE
614	mov $r2 1
615	mov $r1 0xa20
616	shl b32 $r1 6
617	iowr I[$r1 + 0x000] $r2		// MEM_TARGET = vm
618	mov $r1 chan_data
619	sethi $r1 0x00060000		// 256 bytes
620	xdld $r0 $r1
621	xdwait
622	trace_clr(T_LCTXH)
623
624	trace_clr(T_CHAN)
625	ret
626
627// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
628//            the active channel for ctxctl, but not actually transfer
629//            any context data.  intended for use only during initial
630//            context construction.
631//
632// In: $r2 channel address
633//
634ctx_chan:
635	call ctx_4160s
636	call ctx_load
637	mov $r10 12			// DONE_UNK12
638	call wait_donez
639	mov $r1 0xa10
640	shl b32 $r1 6
641	mov $r2 5
642	iowr I[$r1 + 0x000] $r2		// MEM_CMD = 5 (???)
643	ctx_chan_wait:
644		iord $r2 I[$r1 + 0x000]
645		or $r2 $r2
646		bra ne ctx_chan_wait
647	call ctx_4160c
648	ret
649
650// Execute per-context state overrides list
651//
652// Only executed on the first load of a channel.  Might want to look into
653// removing this and having the host directly modify the channel's context
654// to change this state...  The nouveau DRM already builds this list as
655// it's definitely needed for NVIDIA's, so we may as well use it for now
656//
657// Input: $r1 mmio list length
658//
659ctx_mmio_exec:
660	// set transfer base to be the mmio list
661	ld b32 $r3 D[$r0 + chan_mmio_address]
662	mov $r2 0xa04
663	shl b32 $r2 6
664	iowr I[$r2 + 0x000] $r3		// MEM_BASE
665
666	clear b32 $r3
667	ctx_mmio_loop:
668		// fetch next 256 bytes of mmio list if necessary
669		and $r4 $r3 0xff
670		bra ne ctx_mmio_pull
671			mov $r5 xfer_data
672			sethi $r5 0x00060000	// 256 bytes
673			xdld $r3 $r5
674			xdwait
675
676		// execute a single list entry
677		ctx_mmio_pull:
678		ld b32 $r14 D[$r4 + xfer_data + 0x00]
679		ld b32 $r15 D[$r4 + xfer_data + 0x04]
680		call nv_wr32
681
682		// next!
683		add b32 $r3 8
684		sub b32 $r1 1
685		bra ne ctx_mmio_loop
686
687	// set transfer base back to the current context
688	ctx_mmio_done:
689	ld b32 $r3 D[$r0 + ctx_current]
690	iowr I[$r2 + 0x000] $r3		// MEM_BASE
691
692	// disable the mmio list now, we don't need/want to execute it again
693	st b32 D[$r0 + chan_mmio_count] $r0
694	mov $r1 chan_data
695	sethi $r1 0x00060000		// 256 bytes
696	xdst $r0 $r1
697	xdwait
698	ret
699
700// Transfer HUB context data between GPU and storage area
701//
702// In: $r2 channel address
703//     $p1 clear on save, set on load
704//     $p2 set if opposite direction done/will be done, so:
705//		on save it means: "a load will follow this save"
706//		on load it means: "a save preceeded this load"
707//
708ctx_xfer:
709	bra not $p1 ctx_xfer_pre
710	bra $p2 ctx_xfer_pre_load
711	ctx_xfer_pre:
712		mov $r15 0x10
713		call ctx_86c
714		call ctx_4160s
715		bra not $p1 ctx_xfer_exec
716
717	ctx_xfer_pre_load:
718		mov $r15 2
719		call ctx_4170s
720		call ctx_4170w
721		call ctx_redswitch
722		clear b32 $r15
723		call ctx_4170s
724		call ctx_load
725
726	// fetch context pointer, and initiate xfer on all GPCs
727	ctx_xfer_exec:
728	ld b32 $r1 D[$r0 + ctx_current]
729	mov $r2 0x414
730	shl b32 $r2 6
731	iowr I[$r2 + 0x000] $r0	// BAR_STATUS = reset
732	mov $r14 -0x5b00
733	sethi $r14 0x410000
734	mov b32 $r15 $r1
735	call nv_wr32		// GPC_BCAST_WRCMD_DATA = ctx pointer
736	add b32 $r14 4
737	xbit $r15 $flags $p1
738	xbit $r2 $flags $p2
739	shl b32 $r2 1
740	or $r15 $r2
741	call nv_wr32		// GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
742
743	// strands
744	mov $r1 0x4afc
745	sethi $r1 0x20000
746	mov $r2 0xc
747	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0c
748	call strand_wait
749	mov $r2 0x47fc
750	sethi $r2 0x20000
751	iowr I[$r2] $r0		// STRAND_FIRST_GENE(0x3f) = 0x00
752	xbit $r2 $flags $p1
753	add b32 $r2 3
754	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
755
756	// mmio context
757	xbit $r10 $flags $p1	// direction
758	or $r10 6		// first, last
759	mov $r11 0		// base = 0
760	ld b32 $r12 D[$r0 + hub_mmio_list_head]
761	ld b32 $r13 D[$r0 + hub_mmio_list_tail]
762	mov $r14 0		// not multi
763	call mmctx_xfer
764
765	// wait for GPCs to all complete
766	mov $r10 8		// DONE_BAR
767	call wait_doneo
768
769	// wait for strand xfer to complete
770	call strand_wait
771
772	// post-op
773	bra $p1 ctx_xfer_post
774		mov $r10 12		// DONE_UNK12
775		call wait_donez
776		mov $r1 0xa10
777		shl b32 $r1 6
778		mov $r2 5
779		iowr I[$r1] $r2		// MEM_CMD
780		ctx_xfer_post_save_wait:
781			iord $r2 I[$r1]
782			or $r2 $r2
783			bra ne ctx_xfer_post_save_wait
784
785	bra $p2 ctx_xfer_done
786	ctx_xfer_post:
787		mov $r15 2
788		call ctx_4170s
789		clear b32 $r15
790		call ctx_86c
791		call strand_post
792		call ctx_4170w
793		clear b32 $r15
794		call ctx_4170s
795
796		bra not $p1 ctx_xfer_no_post_mmio
797		ld b32 $r1 D[$r0 + chan_mmio_count]
798		or $r1 $r1
799		bra e ctx_xfer_no_post_mmio
800			call ctx_mmio_exec
801
802		ctx_xfer_no_post_mmio:
803		call ctx_4160c
804
805	ctx_xfer_done:
806	ret
807
808.align 256
v3.5.6
  1/* fuc microcode for nvc0 PGRAPH/HUB
  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/* To build:
 27 *    m4 nvc0_grhub.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_grhub.fuc.h
 28 */
 29
 30.section #nvc0_grhub_data
 31include(`nvc0_graph.fuc')
 32gpc_count:		.b32 0
 33rop_count:		.b32 0
 34cmd_queue:		queue_init
 35hub_mmio_list_head:	.b32 0
 36hub_mmio_list_tail:	.b32 0
 37
 38ctx_current:		.b32 0
 39
 40chipsets:
 41.b8  0xc0 0 0 0
 42.b16 #nvc0_hub_mmio_head
 43.b16 #nvc0_hub_mmio_tail
 44.b8  0xc1 0 0 0
 45.b16 #nvc0_hub_mmio_head
 46.b16 #nvc1_hub_mmio_tail
 47.b8  0xc3 0 0 0
 48.b16 #nvc0_hub_mmio_head
 49.b16 #nvc0_hub_mmio_tail
 50.b8  0xc4 0 0 0
 51.b16 #nvc0_hub_mmio_head
 52.b16 #nvc0_hub_mmio_tail
 53.b8  0xc8 0 0 0
 54.b16 #nvc0_hub_mmio_head
 55.b16 #nvc0_hub_mmio_tail
 56.b8  0xce 0 0 0
 57.b16 #nvc0_hub_mmio_head
 58.b16 #nvc0_hub_mmio_tail
 59.b8  0xcf 0 0 0
 60.b16 #nvc0_hub_mmio_head
 61.b16 #nvc0_hub_mmio_tail
 62.b8  0xd9 0 0 0
 63.b16 #nvd9_hub_mmio_head
 64.b16 #nvd9_hub_mmio_tail
 65.b8  0 0 0 0
 66
 67nvc0_hub_mmio_head:
 68mmctx_data(0x17e91c, 2)
 69mmctx_data(0x400204, 2)
 70mmctx_data(0x404004, 11)
 71mmctx_data(0x404044, 1)
 72mmctx_data(0x404094, 14)
 73mmctx_data(0x4040d0, 7)
 74mmctx_data(0x4040f8, 1)
 75mmctx_data(0x404130, 3)
 76mmctx_data(0x404150, 3)
 77mmctx_data(0x404164, 2)
 78mmctx_data(0x404174, 3)
 79mmctx_data(0x404200, 8)
 80mmctx_data(0x404404, 14)
 81mmctx_data(0x404460, 4)
 82mmctx_data(0x404480, 1)
 83mmctx_data(0x404498, 1)
 84mmctx_data(0x404604, 4)
 85mmctx_data(0x404618, 32)
 86mmctx_data(0x404698, 21)
 87mmctx_data(0x4046f0, 2)
 88mmctx_data(0x404700, 22)
 89mmctx_data(0x405800, 1)
 90mmctx_data(0x405830, 3)
 91mmctx_data(0x405854, 1)
 92mmctx_data(0x405870, 4)
 93mmctx_data(0x405a00, 2)
 94mmctx_data(0x405a18, 1)
 95mmctx_data(0x406020, 1)
 96mmctx_data(0x406028, 4)
 97mmctx_data(0x4064a8, 2)
 98mmctx_data(0x4064b4, 2)
 99mmctx_data(0x407804, 1)
100mmctx_data(0x40780c, 6)
101mmctx_data(0x4078bc, 1)
102mmctx_data(0x408000, 7)
103mmctx_data(0x408064, 1)
104mmctx_data(0x408800, 3)
105mmctx_data(0x408900, 4)
106mmctx_data(0x408980, 1)
107nvc0_hub_mmio_tail:
108mmctx_data(0x4064c0, 2)
109nvc1_hub_mmio_tail:
110
111nvd9_hub_mmio_head:
112mmctx_data(0x17e91c, 2)
113mmctx_data(0x400204, 2)
114mmctx_data(0x404004, 10)
115mmctx_data(0x404044, 1)
116mmctx_data(0x404094, 14)
117mmctx_data(0x4040d0, 7)
118mmctx_data(0x4040f8, 1)
119mmctx_data(0x404130, 3)
120mmctx_data(0x404150, 3)
121mmctx_data(0x404164, 2)
122mmctx_data(0x404178, 2)
123mmctx_data(0x404200, 8)
124mmctx_data(0x404404, 14)
125mmctx_data(0x404460, 4)
126mmctx_data(0x404480, 1)
127mmctx_data(0x404498, 1)
128mmctx_data(0x404604, 4)
129mmctx_data(0x404618, 32)
130mmctx_data(0x404698, 21)
131mmctx_data(0x4046f0, 2)
132mmctx_data(0x404700, 22)
133mmctx_data(0x405800, 1)
134mmctx_data(0x405830, 3)
135mmctx_data(0x405854, 1)
136mmctx_data(0x405870, 4)
137mmctx_data(0x405a00, 2)
138mmctx_data(0x405a18, 1)
139mmctx_data(0x406020, 1)
140mmctx_data(0x406028, 4)
141mmctx_data(0x4064a8, 2)
142mmctx_data(0x4064b4, 5)
143mmctx_data(0x407804, 1)
144mmctx_data(0x40780c, 6)
145mmctx_data(0x4078bc, 1)
146mmctx_data(0x408000, 7)
147mmctx_data(0x408064, 1)
148mmctx_data(0x408800, 3)
149mmctx_data(0x408900, 4)
150mmctx_data(0x408980, 1)
151nvd9_hub_mmio_tail:
152
153.align 256
154chan_data:
155chan_mmio_count:	.b32 0
156chan_mmio_address:	.b32 0
157
158.align 256
159xfer_data: 		.b32 0
160
161.section #nvc0_grhub_code
162bra #init
163define(`include_code')
164include(`nvc0_graph.fuc')
165
166// reports an exception to the host
167//
168// In: $r15 error code (see nvc0_graph.fuc)
169//
170error:
171	push $r14
172	mov $r14 0x814
173	shl b32 $r14 6
174	iowr I[$r14 + 0x000] $r15	// CC_SCRATCH[5] = error code
175	mov $r14 0xc1c
176	shl b32 $r14 6
177	mov $r15 1
178	iowr I[$r14 + 0x000] $r15	// INTR_UP_SET
179	pop $r14
180	ret
181
182// HUB fuc initialisation, executed by triggering ucode start, will
183// fall through to main loop after completion.
184//
185// Input:
186//   CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh)
187//
188// Output:
189//   CC_SCRATCH[0]:
190//	     31:31: set to signal completion
191//   CC_SCRATCH[1]:
192//	      31:0: total PGRAPH context size
193//
194init:
195	clear b32 $r0
196	mov $sp $r0
197	mov $xdbase $r0
198
199	// enable fifo access
200	mov $r1 0x1200
201	mov $r2 2
202	iowr I[$r1 + 0x000] $r2	// FIFO_ENABLE
203
204	// setup i0 handler, and route all interrupts to it
205	mov $r1 #ih
206	mov $iv0 $r1
207	mov $r1 0x400
208	iowr I[$r1 + 0x300] $r0	// INTR_DISPATCH
209
210	// route HUB_CHANNEL_SWITCH to fuc interrupt 8
211	mov $r3 0x404
212	shl b32 $r3 6
213	mov $r2 0x2003		// { HUB_CHANNEL_SWITCH, ZERO } -> intr 8
214	iowr I[$r3 + 0x000] $r2
215
216	// not sure what these are, route them because NVIDIA does, and
217	// the IRQ handler will signal the host if we ever get one.. we
218	// may find out if/why we need to handle these if so..
219	//
220	mov $r2 0x2004
221	iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9
222	mov $r2 0x200b
223	iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10
224	mov $r2 0x200c
225	iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15
226
227	// enable all INTR_UP interrupts
228	mov $r2 0xc24
229	shl b32 $r2 6
230	not b32 $r3 $r0
231	iowr I[$r2] $r3
232
233	// enable fifo, ctxsw, 9, 10, 15 interrupts
234	mov $r2 -0x78fc		// 0x8704
235	sethi $r2 0
236	iowr I[$r1 + 0x000] $r2	// INTR_EN_SET
237
238	// fifo level triggered, rest edge
239	sub b32 $r1 0x100
240	mov $r2 4
241	iowr I[$r1] $r2
242
243	// enable interrupts
244	bset $flags ie0
245
246	// fetch enabled GPC/ROP counts
247	mov $r14 -0x69fc	// 0x409604
248	sethi $r14 0x400000
249	call #nv_rd32
250	extr $r1 $r15 16:20
251	st b32 D[$r0 + #rop_count] $r1
252	and $r15 0x1f
253	st b32 D[$r0 + #gpc_count] $r15
254
255	// set BAR_REQMASK to GPC mask
256	mov $r1 1
257	shl b32 $r1 $r15
258	sub b32 $r1 1
259	mov $r2 0x40c
260	shl b32 $r2 6
261	iowr I[$r2 + 0x000] $r1
262	iowr I[$r2 + 0x100] $r1
263
264	// find context data for this chipset
265	mov $r2 0x800
266	shl b32 $r2 6
267	iord $r2 I[$r2 + 0x000]		// CC_SCRATCH[0]
268	mov $r15 #chipsets - 8
269	init_find_chipset:
270		add b32 $r15 8
271		ld b32 $r3 D[$r15 + 0x00]
272		cmpu b32 $r3 $r2
273		bra e #init_context
274		cmpu b32 $r3 0
275		bra ne #init_find_chipset
276		// unknown chipset
277		ret
278
279	// context size calculation, reserve first 256 bytes for use by fuc
280	init_context:
281	mov $r1 256
282
283	// calculate size of mmio context data
284	ld b16 $r14 D[$r15 + 4]
285	ld b16 $r15 D[$r15 + 6]
286	sethi $r14 0
287	st b32 D[$r0 + #hub_mmio_list_head] $r14
288	st b32 D[$r0 + #hub_mmio_list_tail] $r15
289	call #mmctx_size
290
291	// set mmctx base addresses now so we don't have to do it later,
292	// they don't (currently) ever change
293	mov $r3 0x700
294	shl b32 $r3 6
295	shr b32 $r4 $r1 8
296	iowr I[$r3 + 0x000] $r4		// MMCTX_SAVE_SWBASE
297	iowr I[$r3 + 0x100] $r4		// MMCTX_LOAD_SWBASE
298	add b32 $r3 0x1300
299	add b32 $r1 $r15
300	shr b32 $r15 2
301	iowr I[$r3 + 0x000] $r15	// MMCTX_LOAD_COUNT, wtf for?!?
302
303	// strands, base offset needs to be aligned to 256 bytes
304	shr b32 $r1 8
305	add b32 $r1 1
306	shl b32 $r1 8
307	mov b32 $r15 $r1
308	call #strand_ctx_init
309	add b32 $r1 $r15
310
311	// initialise each GPC in sequence by passing in the offset of its
312	// context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
313	// has previously been uploaded by the host) running.
314	//
315	// the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
316	// when it has completed, and return the size of its context data
317	// in GPCn_CC_SCRATCH[1]
318	//
319	ld b32 $r3 D[$r0 + #gpc_count]
320	mov $r4 0x2000
321	sethi $r4 0x500000
322	init_gpc:
323		// setup, and start GPC ucode running
324		add b32 $r14 $r4 0x804
325		mov b32 $r15 $r1
326		call #nv_wr32			// CC_SCRATCH[1] = ctx offset
327		add b32 $r14 $r4 0x800
328		mov b32 $r15 $r2
329		call #nv_wr32			// CC_SCRATCH[0] = chipset
330		add b32 $r14 $r4 0x10c
331		clear b32 $r15
332		call #nv_wr32
333		add b32 $r14 $r4 0x104
334		call #nv_wr32			// ENTRY
335		add b32 $r14 $r4 0x100
336		mov $r15 2			// CTRL_START_TRIGGER
337		call #nv_wr32			// CTRL
338
339		// wait for it to complete, and adjust context size
340		add b32 $r14 $r4 0x800
341		init_gpc_wait:
342			call #nv_rd32
343			xbit $r15 $r15 31
344			bra e #init_gpc_wait
345		add b32 $r14 $r4 0x804
346		call #nv_rd32
347		add b32 $r1 $r15
348
349		// next!
350		add b32 $r4 0x8000
351		sub b32 $r3 1
352		bra ne #init_gpc
353
354	// save context size, and tell host we're ready
355	mov $r2 0x800
356	shl b32 $r2 6
357	iowr I[$r2 + 0x100] $r1		// CC_SCRATCH[1]  = context size
358	add b32 $r2 0x800
359	clear b32 $r1
360	bset $r1 31
361	iowr I[$r2 + 0x000] $r1		// CC_SCRATCH[0] |= 0x80000000
362
363// Main program loop, very simple, sleeps until woken up by the interrupt
364// handler, pulls a command from the queue and executes its handler
365//
366main:
367	// sleep until we have something to do
368	bset $flags $p0
369	sleep $p0
370	mov $r13 #cmd_queue
371	call #queue_get
372	bra $p1 #main
373
374	// context switch, requested by GPU?
375	cmpu b32 $r14 0x4001
376	bra ne #main_not_ctx_switch
377		trace_set(T_AUTO)
378		mov $r1 0xb00
379		shl b32 $r1 6
380		iord $r2 I[$r1 + 0x100]		// CHAN_NEXT
381		iord $r1 I[$r1 + 0x000]		// CHAN_CUR
382
383		xbit $r3 $r1 31
384		bra e #chsw_no_prev
385			xbit $r3 $r2 31
386			bra e #chsw_prev_no_next
387				push $r2
388				mov b32 $r2 $r1
389				trace_set(T_SAVE)
390				bclr $flags $p1
391				bset $flags $p2
392				call #ctx_xfer
393				trace_clr(T_SAVE);
394				pop $r2
395				trace_set(T_LOAD);
396				bset $flags $p1
397				call #ctx_xfer
398				trace_clr(T_LOAD);
399				bra #chsw_done
400			chsw_prev_no_next:
401				push $r2
402				mov b32 $r2 $r1
403				bclr $flags $p1
404				bclr $flags $p2
405				call #ctx_xfer
406				pop $r2
407				mov $r1 0xb00
408				shl b32 $r1 6
409				iowr I[$r1] $r2
410				bra #chsw_done
411		chsw_no_prev:
412			xbit $r3 $r2 31
413			bra e #chsw_done
414				bset $flags $p1
415				bclr $flags $p2
416				call #ctx_xfer
417
418		// ack the context switch request
419		chsw_done:
420		mov $r1 0xb0c
421		shl b32 $r1 6
422		mov $r2 1
423		iowr I[$r1 + 0x000] $r2		// 0x409b0c
424		trace_clr(T_AUTO)
425		bra #main
426
427	// request to set current channel? (*not* a context switch)
428	main_not_ctx_switch:
429	cmpu b32 $r14 0x0001
430	bra ne #main_not_ctx_chan
431		mov b32 $r2 $r15
432		call #ctx_chan
433		bra #main_done
434
435	// request to store current channel context?
436	main_not_ctx_chan:
437	cmpu b32 $r14 0x0002
438	bra ne #main_not_ctx_save
439		trace_set(T_SAVE)
440		bclr $flags $p1
441		bclr $flags $p2
442		call #ctx_xfer
443		trace_clr(T_SAVE)
444		bra #main_done
445
446	main_not_ctx_save:
447		shl b32 $r15 $r14 16
448		or $r15 E_BAD_COMMAND
449		call #error
450		bra #main
451
452	main_done:
453	mov $r1 0x820
454	shl b32 $r1 6
455	clear b32 $r2
456	bset $r2 31
457	iowr I[$r1 + 0x000] $r2		// CC_SCRATCH[0] |= 0x80000000
458	bra #main
459
460// interrupt handler
461ih:
462	push $r8
463	mov $r8 $flags
464	push $r8
465	push $r9
466	push $r10
467	push $r11
468	push $r13
469	push $r14
470	push $r15
471
472	// incoming fifo command?
473	iord $r10 I[$r0 + 0x200]	// INTR
474	and $r11 $r10 0x00000004
475	bra e #ih_no_fifo
476		// queue incoming fifo command for later processing
477		mov $r11 0x1900
478		mov $r13 #cmd_queue
479		iord $r14 I[$r11 + 0x100]	// FIFO_CMD
480		iord $r15 I[$r11 + 0x000]	// FIFO_DATA
481		call #queue_put
482		add b32 $r11 0x400
483		mov $r14 1
484		iowr I[$r11 + 0x000] $r14	// FIFO_ACK
485
486	// context switch request?
487	ih_no_fifo:
488	and $r11 $r10 0x00000100
489	bra e #ih_no_ctxsw
490		// enqueue a context switch for later processing
491		mov $r13 #cmd_queue
492		mov $r14 0x4001
493		call #queue_put
494
495	// anything we didn't handle, bring it to the host's attention
496	ih_no_ctxsw:
497	mov $r11 0x104
498	not b32 $r11
499	and $r11 $r10 $r11
500	bra e #ih_no_other
501		mov $r10 0xc1c
502		shl b32 $r10 6
503		iowr I[$r10] $r11	// INTR_UP_SET
504
505	// ack, and wake up main()
506	ih_no_other:
507	iowr I[$r0 + 0x100] $r10	// INTR_ACK
508
509	pop $r15
510	pop $r14
511	pop $r13
512	pop $r11
513	pop $r10
514	pop $r9
515	pop $r8
516	mov $flags $r8
517	pop $r8
518	bclr $flags $p0
519	iret
520
521// Not real sure, but, MEM_CMD 7 will hang forever if this isn't done
522ctx_4160s:
523	mov $r14 0x4160
524	sethi $r14 0x400000
525	mov $r15 1
526	call #nv_wr32
527	ctx_4160s_wait:
528		call #nv_rd32
529		xbit $r15 $r15 4
530		bra e #ctx_4160s_wait
531	ret
532
533// Without clearing again at end of xfer, some things cause PGRAPH
534// to hang with STATUS=0x00000007 until it's cleared.. fbcon can
535// still function with it set however...
536ctx_4160c:
537	mov $r14 0x4160
538	sethi $r14 0x400000
539	clear b32 $r15
540	call #nv_wr32
541	ret
542
543// Again, not real sure
544//
545// In: $r15 value to set 0x404170 to
546//
547ctx_4170s:
548	mov $r14 0x4170
549	sethi $r14 0x400000
550	or $r15 0x10
551	call #nv_wr32
552	ret
553
554// Waits for a ctx_4170s() call to complete
555//
556ctx_4170w:
557	mov $r14 0x4170
558	sethi $r14 0x400000
559	call #nv_rd32
560	and $r15 0x10
561	bra ne #ctx_4170w
562	ret
563
564// Disables various things, waits a bit, and re-enables them..
565//
566// Not sure how exactly this helps, perhaps "ENABLE" is not such a
567// good description for the bits we turn off?  Anyways, without this,
568// funny things happen.
569//
570ctx_redswitch:
571	mov $r14 0x614
572	shl b32 $r14 6
573	mov $r15 0x270
574	iowr I[$r14] $r15	// HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL
575	mov $r15 8
576	ctx_redswitch_delay:
577		sub b32 $r15 1
578		bra ne #ctx_redswitch_delay
579	mov $r15 0x770
580	iowr I[$r14] $r15	// HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL
581	ret
582
583// Not a clue what this is for, except that unless the value is 0x10, the
584// strand context is saved (and presumably restored) incorrectly..
585//
586// In: $r15 value to set to (0x00/0x10 are used)
587//
588ctx_86c:
589	mov $r14 0x86c
590	shl b32 $r14 6
591	iowr I[$r14] $r15	// HUB(0x86c) = val
592	mov $r14 -0x75ec
593	sethi $r14 0x400000
594	call #nv_wr32		// ROP(0xa14) = val
595	mov $r14 -0x5794
596	sethi $r14 0x410000
597	call #nv_wr32		// GPC(0x86c) = val
598	ret
599
600// ctx_load - load's a channel's ctxctl data, and selects its vm
601//
602// In: $r2 channel address
603//
604ctx_load:
605	trace_set(T_CHAN)
606
607	// switch to channel, somewhat magic in parts..
608	mov $r10 12		// DONE_UNK12
609	call #wait_donez
610	mov $r1 0xa24
611	shl b32 $r1 6
612	iowr I[$r1 + 0x000] $r0	// 0x409a24
613	mov $r3 0xb00
614	shl b32 $r3 6
615	iowr I[$r3 + 0x100] $r2	// CHAN_NEXT
616	mov $r1 0xa0c
617	shl b32 $r1 6
618	mov $r4 7
619	iowr I[$r1 + 0x000] $r2 // MEM_CHAN
620	iowr I[$r1 + 0x100] $r4	// MEM_CMD
621	ctx_chan_wait_0:
622		iord $r4 I[$r1 + 0x100]
623		and $r4 0x1f
624		bra ne #ctx_chan_wait_0
625	iowr I[$r3 + 0x000] $r2	// CHAN_CUR
626
627	// load channel header, fetch PGRAPH context pointer
628	mov $xtargets $r0
629	bclr $r2 31
630	shl b32 $r2 4
631	add b32 $r2 2
632
633	trace_set(T_LCHAN)
634	mov $r1 0xa04
635	shl b32 $r1 6
636	iowr I[$r1 + 0x000] $r2		// MEM_BASE
637	mov $r1 0xa20
638	shl b32 $r1 6
639	mov $r2 0x0002
640	sethi $r2 0x80000000
641	iowr I[$r1 + 0x000] $r2		// MEM_TARGET = vram
642	mov $r1 0x10			// chan + 0x0210
643	mov $r2 #xfer_data
644	sethi $r2 0x00020000		// 16 bytes
645	xdld $r1 $r2
646	xdwait
647	trace_clr(T_LCHAN)
648
649	// update current context
650	ld b32 $r1 D[$r0 + #xfer_data + 4]
651	shl b32 $r1 24
652	ld b32 $r2 D[$r0 + #xfer_data + 0]
653	shr b32 $r2 8
654	or $r1 $r2
655	st b32 D[$r0 + #ctx_current] $r1
656
657	// set transfer base to start of context, and fetch context header
658	trace_set(T_LCTXH)
659	mov $r2 0xa04
660	shl b32 $r2 6
661	iowr I[$r2 + 0x000] $r1		// MEM_BASE
662	mov $r2 1
663	mov $r1 0xa20
664	shl b32 $r1 6
665	iowr I[$r1 + 0x000] $r2		// MEM_TARGET = vm
666	mov $r1 #chan_data
667	sethi $r1 0x00060000		// 256 bytes
668	xdld $r0 $r1
669	xdwait
670	trace_clr(T_LCTXH)
671
672	trace_clr(T_CHAN)
673	ret
674
675// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
676//            the active channel for ctxctl, but not actually transfer
677//            any context data.  intended for use only during initial
678//            context construction.
679//
680// In: $r2 channel address
681//
682ctx_chan:
683	call #ctx_4160s
684	call #ctx_load
685	mov $r10 12			// DONE_UNK12
686	call #wait_donez
687	mov $r1 0xa10
688	shl b32 $r1 6
689	mov $r2 5
690	iowr I[$r1 + 0x000] $r2		// MEM_CMD = 5 (???)
691	ctx_chan_wait:
692		iord $r2 I[$r1 + 0x000]
693		or $r2 $r2
694		bra ne #ctx_chan_wait
695	call #ctx_4160c
696	ret
697
698// Execute per-context state overrides list
699//
700// Only executed on the first load of a channel.  Might want to look into
701// removing this and having the host directly modify the channel's context
702// to change this state...  The nouveau DRM already builds this list as
703// it's definitely needed for NVIDIA's, so we may as well use it for now
704//
705// Input: $r1 mmio list length
706//
707ctx_mmio_exec:
708	// set transfer base to be the mmio list
709	ld b32 $r3 D[$r0 + #chan_mmio_address]
710	mov $r2 0xa04
711	shl b32 $r2 6
712	iowr I[$r2 + 0x000] $r3		// MEM_BASE
713
714	clear b32 $r3
715	ctx_mmio_loop:
716		// fetch next 256 bytes of mmio list if necessary
717		and $r4 $r3 0xff
718		bra ne #ctx_mmio_pull
719			mov $r5 #xfer_data
720			sethi $r5 0x00060000	// 256 bytes
721			xdld $r3 $r5
722			xdwait
723
724		// execute a single list entry
725		ctx_mmio_pull:
726		ld b32 $r14 D[$r4 + #xfer_data + 0x00]
727		ld b32 $r15 D[$r4 + #xfer_data + 0x04]
728		call #nv_wr32
729
730		// next!
731		add b32 $r3 8
732		sub b32 $r1 1
733		bra ne #ctx_mmio_loop
734
735	// set transfer base back to the current context
736	ctx_mmio_done:
737	ld b32 $r3 D[$r0 + #ctx_current]
738	iowr I[$r2 + 0x000] $r3		// MEM_BASE
739
740	// disable the mmio list now, we don't need/want to execute it again
741	st b32 D[$r0 + #chan_mmio_count] $r0
742	mov $r1 #chan_data
743	sethi $r1 0x00060000		// 256 bytes
744	xdst $r0 $r1
745	xdwait
746	ret
747
748// Transfer HUB context data between GPU and storage area
749//
750// In: $r2 channel address
751//     $p1 clear on save, set on load
752//     $p2 set if opposite direction done/will be done, so:
753//		on save it means: "a load will follow this save"
754//		on load it means: "a save preceeded this load"
755//
756ctx_xfer:
757	bra not $p1 #ctx_xfer_pre
758	bra $p2 #ctx_xfer_pre_load
759	ctx_xfer_pre:
760		mov $r15 0x10
761		call #ctx_86c
762		call #ctx_4160s
763		bra not $p1 #ctx_xfer_exec
764
765	ctx_xfer_pre_load:
766		mov $r15 2
767		call #ctx_4170s
768		call #ctx_4170w
769		call #ctx_redswitch
770		clear b32 $r15
771		call #ctx_4170s
772		call #ctx_load
773
774	// fetch context pointer, and initiate xfer on all GPCs
775	ctx_xfer_exec:
776	ld b32 $r1 D[$r0 + #ctx_current]
777	mov $r2 0x414
778	shl b32 $r2 6
779	iowr I[$r2 + 0x000] $r0	// BAR_STATUS = reset
780	mov $r14 -0x5b00
781	sethi $r14 0x410000
782	mov b32 $r15 $r1
783	call #nv_wr32		// GPC_BCAST_WRCMD_DATA = ctx pointer
784	add b32 $r14 4
785	xbit $r15 $flags $p1
786	xbit $r2 $flags $p2
787	shl b32 $r2 1
788	or $r15 $r2
789	call #nv_wr32		// GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
790
791	// strands
792	mov $r1 0x4afc
793	sethi $r1 0x20000
794	mov $r2 0xc
795	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x0c
796	call #strand_wait
797	mov $r2 0x47fc
798	sethi $r2 0x20000
799	iowr I[$r2] $r0		// STRAND_FIRST_GENE(0x3f) = 0x00
800	xbit $r2 $flags $p1
801	add b32 $r2 3
802	iowr I[$r1] $r2		// STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
803
804	// mmio context
805	xbit $r10 $flags $p1	// direction
806	or $r10 6		// first, last
807	mov $r11 0		// base = 0
808	ld b32 $r12 D[$r0 + #hub_mmio_list_head]
809	ld b32 $r13 D[$r0 + #hub_mmio_list_tail]
810	mov $r14 0		// not multi
811	call #mmctx_xfer
812
813	// wait for GPCs to all complete
814	mov $r10 8		// DONE_BAR
815	call #wait_doneo
816
817	// wait for strand xfer to complete
818	call #strand_wait
819
820	// post-op
821	bra $p1 #ctx_xfer_post
822		mov $r10 12		// DONE_UNK12
823		call #wait_donez
824		mov $r1 0xa10
825		shl b32 $r1 6
826		mov $r2 5
827		iowr I[$r1] $r2		// MEM_CMD
828		ctx_xfer_post_save_wait:
829			iord $r2 I[$r1]
830			or $r2 $r2
831			bra ne #ctx_xfer_post_save_wait
832
833	bra $p2 #ctx_xfer_done
834	ctx_xfer_post:
835		mov $r15 2
836		call #ctx_4170s
837		clear b32 $r15
838		call #ctx_86c
839		call #strand_post
840		call #ctx_4170w
841		clear b32 $r15
842		call #ctx_4170s
843
844		bra not $p1 #ctx_xfer_no_post_mmio
845		ld b32 $r1 D[$r0 + #chan_mmio_count]
846		or $r1 $r1
847		bra e #ctx_xfer_no_post_mmio
848			call #ctx_mmio_exec
849
850		ctx_xfer_no_post_mmio:
851		call #ctx_4160c
852
853	ctx_xfer_done:
854	ret
855
856.align 256