1/*
2 * Copyright 2013 Red Hat Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 * Authors: Ben Skeggs
23 */
24
25#ifdef INCLUDE_PROC
26process(PROC_MEMX, #memx_init, #memx_recv)
27#endif
28
29/******************************************************************************
30 * MEMX data segment
31 *****************************************************************************/
32#ifdef INCLUDE_DATA
33.equ #memx_opcode 0
34.equ #memx_header 2
35.equ #memx_length 4
36.equ #memx_func   8
37
38#define handler(cmd,hdr,len,func) /*
39*/	.b16 MEMX_##cmd /*
40*/	.b16 hdr /*
41*/	.b16 len /*
42*/      .b16 0 /*
43*/	.b32 func
44
45memx_func_head:
46handler(ENTER , 0x0000, 0x0000, #memx_func_enter)
47memx_func_next:
48handler(LEAVE , 0x0000, 0x0000, #memx_func_leave)
49handler(WR32  , 0x0000, 0x0002, #memx_func_wr32)
50handler(WAIT  , 0x0004, 0x0000, #memx_func_wait)
51handler(DELAY , 0x0001, 0x0000, #memx_func_delay)
52handler(VBLANK, 0x0001, 0x0000, #memx_func_wait_vblank)
53handler(TRAIN , 0x0000, 0x0000, #memx_func_train)
54memx_func_tail:
55
56.equ #memx_func_size #memx_func_next - #memx_func_head
57.equ #memx_func_num (#memx_func_tail - #memx_func_head) / #memx_func_size
58
59memx_ts_start:
60.b32 0
61memx_ts_end:
62.b32 0
63
64memx_data_head:
65.skip 0x0800
66memx_data_tail:
67
68memx_train_head:
69.skip 0x0100
70memx_train_tail:
71#endif
72
73/******************************************************************************
74 * MEMX code segment
75 *****************************************************************************/
76#ifdef INCLUDE_CODE
77// description
78//
79// $r15 - current (memx)
80// $r4  - packet length
81// $r3  - opcode desciption
82// $r0  - zero
83memx_func_enter:
84#if NVKM_PPWR_CHIPSET == GT215
85	movw $r8 0x1610
86	nv_rd32($r7, $r8)
87	imm32($r6, 0xfffffffc)
88	and $r7 $r6
89	movw $r6 0x2
90	or $r7 $r6
91	nv_wr32($r8, $r7)
92#else
93	movw $r6 0x001620
94	imm32($r7, ~0x00000aa2);
95	nv_rd32($r8, $r6)
96	and $r8 $r7
97	nv_wr32($r6, $r8)
98
99	imm32($r7, ~0x00000001)
100	nv_rd32($r8, $r6)
101	and $r8 $r7
102	nv_wr32($r6, $r8)
103
104	movw $r6 0x0026f0
105	nv_rd32($r8, $r6)
106	and $r8 $r7
107	nv_wr32($r6, $r8)
108#endif
109
110	mov $r6 NV_PPWR_OUTPUT_SET_FB_PAUSE
111	nv_iowr(NV_PPWR_OUTPUT_SET, $r6)
112	memx_func_enter_wait:
113		nv_iord($r6, NV_PPWR_OUTPUT)
114		and $r6 NV_PPWR_OUTPUT_FB_PAUSE
115		bra z #memx_func_enter_wait
116
117	nv_iord($r6, NV_PPWR_TIMER_LOW)
118	st b32 D[$r0 + #memx_ts_start] $r6
119	ret
120
121// description
122//
123// $r15 - current (memx)
124// $r4  - packet length
125// $r3  - opcode desciption
126// $r0  - zero
127memx_func_leave:
128	nv_iord($r6, NV_PPWR_TIMER_LOW)
129	st b32 D[$r0 + #memx_ts_end] $r6
130
131	mov $r6 NV_PPWR_OUTPUT_CLR_FB_PAUSE
132	nv_iowr(NV_PPWR_OUTPUT_CLR, $r6)
133	memx_func_leave_wait:
134		nv_iord($r6, NV_PPWR_OUTPUT)
135		and $r6 NV_PPWR_OUTPUT_FB_PAUSE
136		bra nz #memx_func_leave_wait
137
138#if NVKM_PPWR_CHIPSET == GT215
139	movw $r8 0x1610
140	nv_rd32($r7, $r8)
141	imm32($r6, 0xffffffcc)
142	and $r7 $r6
143	nv_wr32($r8, $r7)
144#else
145	movw $r6 0x0026f0
146	imm32($r7, 0x00000001)
147	nv_rd32($r8, $r6)
148	or $r8 $r7
149	nv_wr32($r6, $r8)
150
151	movw $r6 0x001620
152	nv_rd32($r8, $r6)
153	or $r8 $r7
154	nv_wr32($r6, $r8)
155
156	imm32($r7, 0x00000aa2);
157	nv_rd32($r8, $r6)
158	or $r8 $r7
159	nv_wr32($r6, $r8)
160#endif
161	ret
162
163#if NVKM_PPWR_CHIPSET < GF119
164// description
165//
166// $r15 - current (memx)
167// $r4  - packet length
168//	+00: head to wait for vblank on
169// $r3  - opcode desciption
170// $r0  - zero
171memx_func_wait_vblank:
172	ld b32 $r6 D[$r1 + 0x00]
173	cmp b32 $r6 0x0
174	bra z #memx_func_wait_vblank_head0
175	cmp b32 $r6 0x1
176	bra z #memx_func_wait_vblank_head1
177	bra #memx_func_wait_vblank_fini
178
179	memx_func_wait_vblank_head1:
180	movw $r7 0x20
181	bra #memx_func_wait_vblank_0
182
183	memx_func_wait_vblank_head0:
184	movw $r7 0x8
185
186	memx_func_wait_vblank_0:
187		nv_iord($r6, NV_PPWR_INPUT)
188		and $r6 $r7
189		bra nz #memx_func_wait_vblank_0
190
191	memx_func_wait_vblank_1:
192		nv_iord($r6, NV_PPWR_INPUT)
193		and $r6 $r7
194		bra z #memx_func_wait_vblank_1
195
196	memx_func_wait_vblank_fini:
197	add b32 $r1 0x4
198	ret
199
200#else
201
202// XXX: currently no-op
203//
204// $r15 - current (memx)
205// $r4  - packet length
206//	+00: head to wait for vblank on
207// $r3  - opcode desciption
208// $r0  - zero
209memx_func_wait_vblank:
210	add b32 $r1 0x4
211	ret
212
213#endif
214
215// description
216//
217// $r15 - current (memx)
218// $r4  - packet length
219//	+00*n: addr
220//	+04*n: data
221// $r3  - opcode desciption
222// $r0  - zero
223memx_func_wr32:
224	ld b32 $r6 D[$r1 + 0x00]
225	ld b32 $r5 D[$r1 + 0x04]
226	add b32 $r1 0x08
227	nv_wr32($r6, $r5)
228	sub b32 $r4 0x02
229	bra nz #memx_func_wr32
230	ret
231
232// description
233//
234// $r15 - current (memx)
235// $r4  - packet length
236//	+00: addr
237//	+04: mask
238//	+08: data
239//	+0c: timeout (ns)
240// $r3  - opcode desciption
241// $r0  - zero
242memx_func_wait:
243	nv_iord($r8, NV_PPWR_TIMER_LOW)
244	ld b32 $r14 D[$r1 + 0x00]
245	ld b32 $r13 D[$r1 + 0x04]
246	ld b32 $r12 D[$r1 + 0x08]
247	ld b32 $r11 D[$r1 + 0x0c]
248	add b32 $r1 0x10
249	call(wait)
250	ret
251
252// description
253//
254// $r15 - current (memx)
255// $r4  - packet length
256//	+00: time (ns)
257// $r3  - opcode desciption
258// $r0  - zero
259memx_func_delay:
260	ld b32 $r14 D[$r1 + 0x00]
261	add b32 $r1 0x04
262	call(nsec)
263	ret
264
265// description
266//
267// $r15 - current (memx)
268// $r4  - packet length
269// $r3  - opcode desciption
270// $r0  - zero
271memx_func_train:
272#if NVKM_PPWR_CHIPSET == GT215
273// $r5 - outer loop counter
274// $r6 - inner loop counter
275// $r7 - entry counter (#memx_train_head + $r7)
276	movw $r5 0x3
277	movw $r7 0x0
278
279// Read random memory to wake up... things
280	imm32($r9, 0x700000)
281	nv_rd32($r8,$r9)
282	movw $r14 0x2710
283	call(nsec)
284
285	memx_func_train_loop_outer:
286		mulu $r8 $r5 0x101
287		sethi $r8 0x02000000
288		imm32($r9, 0x1111e0)
289		nv_wr32($r9, $r8)
290		push $r5
291
292		movw $r6 0x0
293		memx_func_train_loop_inner:
294			movw $r8 0x1111
295			mulu $r9 $r6 $r8
296			shl b32 $r8 $r9 0x10
297			or $r8 $r9
298			imm32($r9, 0x100720)
299			nv_wr32($r9, $r8)
300
301			imm32($r9, 0x100080)
302			nv_rd32($r8, $r9)
303			or $r8 $r8 0x20
304			nv_wr32($r9, $r8)
305
306			imm32($r9, 0x10053c)
307			imm32($r8, 0x80003002)
308			nv_wr32($r9, $r8)
309
310			imm32($r14, 0x100560)
311			imm32($r13, 0x80000000)
312			add b32 $r12 $r13 0
313			imm32($r11, 0x001e8480)
314			call(wait)
315
316			// $r5 - inner inner loop counter
317			// $r9 - result
318			movw $r5 0
319			imm32($r9, 0x8300ffff)
320			memx_func_train_loop_4x:
321				imm32($r10, 0x100080)
322				nv_rd32($r8, $r10)
323				imm32($r11, 0xffffffdf)
324				and $r8 $r11
325				nv_wr32($r10, $r8)
326
327				imm32($r10, 0x10053c)
328				imm32($r8, 0x80003002)
329				nv_wr32($r10, $r8)
330
331				imm32($r14, 0x100560)
332				imm32($r13, 0x80000000)
333				mov b32 $r12 $r13
334				imm32($r11, 0x00002710)
335				call(wait)
336
337				nv_rd32($r13, $r14)
338				and $r9 $r9 $r13
339
340				add b32 $r5 1
341				cmp b16 $r5 0x4
342				bra l #memx_func_train_loop_4x
343
344			add b32 $r10 $r7 #memx_train_head
345			st b32 D[$r10 + 0] $r9
346			add b32 $r6 1
347			add b32 $r7 4
348
349			cmp b16 $r6 0x10
350			bra l #memx_func_train_loop_inner
351
352		pop $r5
353		add b32 $r5 1
354		cmp b16 $r5 7
355		bra l #memx_func_train_loop_outer
356
357#endif
358	ret
359
360// description
361//
362// $r15 - current (memx)
363// $r14 - sender process name
364// $r13 - message (exec)
365// $r12 - head of script
366// $r11 - tail of script
367// $r0  - zero
368memx_exec:
369	push $r14
370	push $r13
371	mov b32 $r1 $r12
372	mov b32 $r2 $r11
373
374	memx_exec_next:
375		// fetch the packet header
376		ld b32 $r3 D[$r1]
377		add b32 $r1 4
378		extr $r4 $r3 16:31
379		extr $r3 $r3 0:15
380
381		// execute the opcode handler
382		sub b32 $r3 1
383		mulu $r3 #memx_func_size
384		ld b32 $r5 D[$r3 + #memx_func_head + #memx_func]
385		call $r5
386
387		// keep going, if we haven't reached the end
388		cmp b32 $r1 $r2
389		bra l #memx_exec_next
390
391	// send completion reply
392	ld b32 $r11 D[$r0 + #memx_ts_start]
393	ld b32 $r12 D[$r0 + #memx_ts_end]
394	sub b32 $r12 $r11
395	nv_iord($r11, NV_PPWR_INPUT)
396	pop $r13
397	pop $r14
398	call(send)
399	ret
400
401// description
402//
403// $r15 - current (memx)
404// $r14 - sender process name
405// $r13 - message
406// $r12 - data0
407// $r11 - data1
408// $r0  - zero
409memx_info:
410	cmp b16 $r12 0x1
411	bra e #memx_info_train
412
413	memx_info_data:
414	mov $r12 #memx_data_head
415	mov $r11 #memx_data_tail - #memx_data_head
416	bra #memx_info_send
417
418	memx_info_train:
419	mov $r12 #memx_train_head
420	mov $r11 #memx_train_tail - #memx_train_head
421
422	memx_info_send:
423	call(send)
424	ret
425
426// description
427//
428// $r15 - current (memx)
429// $r14 - sender process name
430// $r13 - message
431// $r12 - data0
432// $r11 - data1
433// $r0  - zero
434memx_recv:
435	cmp b32 $r13 MEMX_MSG_EXEC
436	bra e #memx_exec
437	cmp b32 $r13 MEMX_MSG_INFO
438	bra e #memx_info
439	ret
440
441// description
442//
443// $r15 - current (memx)
444// $r0  - zero
445memx_init:
446	ret
447#endif
448