Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / drivers / gpu / drm / nouveau / core / subdev / pwr / fuc / kernel.fuc
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 /******************************************************************************
26  * kernel data segment
27  *****************************************************************************/
28 #ifdef INCLUDE_PROC
29 proc_kern:
30 process(PROC_KERN, 0, 0)
31 proc_list_head:
32 #endif
33
34 #ifdef INCLUDE_DATA
35 proc_list_tail:
36 time_prev: .b32 0
37 time_next: .b32 0
38 #endif
39
40 /******************************************************************************
41  * kernel code segment
42  *****************************************************************************/
43 #ifdef INCLUDE_CODE
44         bra #init
45
46 // read nv register
47 //
48 // $r15 - current
49 // $r14 - addr
50 // $r13 - data (return)
51 // $r0  - zero
52 rd32:
53         nv_iowr(NV_PPWR_MMIO_ADDR, $r14)
54         mov $r14 NV_PPWR_MMIO_CTRL_OP_RD
55         sethi $r14 NV_PPWR_MMIO_CTRL_TRIGGER
56         nv_iowr(NV_PPWR_MMIO_CTRL, $r14)
57         rd32_wait:
58                 nv_iord($r14, NV_PPWR_MMIO_CTRL)
59                 and $r14 NV_PPWR_MMIO_CTRL_STATUS
60                 bra nz #rd32_wait
61         nv_iord($r13, NV_PPWR_MMIO_DATA)
62         ret
63
64 // write nv register
65 //
66 // $r15 - current
67 // $r14 - addr
68 // $r13 - data
69 // $r0  - zero
70 wr32:
71         nv_iowr(NV_PPWR_MMIO_ADDR, $r14)
72         nv_iowr(NV_PPWR_MMIO_DATA, $r13)
73         mov $r14 NV_PPWR_MMIO_CTRL_OP_WR
74         or $r14 NV_PPWR_MMIO_CTRL_MASK_B32_0
75         sethi $r14 NV_PPWR_MMIO_CTRL_TRIGGER
76
77 #ifdef NVKM_FALCON_MMIO_TRAP
78         mov $r8 NV_PPWR_INTR_TRIGGER_USER1
79         nv_iowr(NV_PPWR_INTR_TRIGGER, $r8)
80         wr32_host:
81                 nv_iord($r8, NV_PPWR_INTR)
82                 and $r8 NV_PPWR_INTR_USER1
83                 bra nz #wr32_host
84 #endif
85
86         nv_iowr(NV_PPWR_MMIO_CTRL, $r14)
87         wr32_wait:
88                 nv_iord($r14, NV_PPWR_MMIO_CTRL)
89                 and $r14 NV_PPWR_MMIO_CTRL_STATUS
90                 bra nz #wr32_wait
91         ret
92
93 // busy-wait for a period of time
94 //
95 // $r15 - current
96 // $r14 - ns
97 // $r0  - zero
98 nsec:
99         nv_iord($r8, NV_PPWR_TIMER_LOW)
100         nsec_loop:
101                 nv_iord($r9, NV_PPWR_TIMER_LOW)
102                 sub b32 $r9 $r8
103                 cmp b32 $r9 $r14
104                 bra l #nsec_loop
105         ret
106
107 // busy-wait for a period of time
108 //
109 // $r15 - current
110 // $r14 - addr
111 // $r13 - mask
112 // $r12 - data
113 // $r11 - timeout (ns)
114 // $r0  - zero
115 wait:
116         nv_iord($r8, NV_PPWR_TIMER_LOW)
117         wait_loop:
118                 nv_rd32($r10, $r14)
119                 and $r10 $r13
120                 cmp b32 $r10 $r12
121                 bra e #wait_done
122                 nv_iord($r9, NV_PPWR_TIMER_LOW)
123                 sub b32 $r9 $r8
124                 cmp b32 $r9 $r11
125                 bra l #wait_loop
126         wait_done:
127         ret
128
129 // $r15 - current (kern)
130 // $r14 - process
131 // $r8  - NV_PPWR_INTR
132 intr_watchdog:
133         // read process' timer status, skip if not enabled
134         ld b32 $r9 D[$r14 + #proc_time]
135         cmp b32 $r9 0
136         bra z #intr_watchdog_next_proc
137
138         // subtract last timer's value from process' timer,
139         // if it's <= 0 then the timer has expired
140         ld b32 $r10 D[$r0 + #time_prev]
141         sub b32 $r9 $r10
142         bra g #intr_watchdog_next_time
143                 mov $r13 KMSG_ALARM
144                 call(send_proc)
145                 clear b32 $r9
146                 bra #intr_watchdog_next_proc
147
148         // otherwise, update the next timer's value if this
149         // process' timer is the soonest
150         intr_watchdog_next_time:
151                 // ... or if there's no next timer yet
152                 ld b32 $r10 D[$r0 + #time_next]
153                 cmp b32 $r10 0
154                 bra z #intr_watchdog_next_time_set
155
156                 cmp b32 $r9 $r10
157                 bra g #intr_watchdog_next_proc
158                 intr_watchdog_next_time_set:
159                 st b32 D[$r0 + #time_next] $r9
160
161         // update process' timer status, and advance
162         intr_watchdog_next_proc:
163         st b32 D[$r14 + #proc_time] $r9
164         add b32 $r14 #proc_size
165         cmp b32 $r14 #proc_list_tail
166         bra ne #intr_watchdog
167         ret
168
169 intr:
170         push $r0
171         clear b32 $r0
172         push $r8
173         push $r9
174         push $r10
175         push $r11
176         push $r12
177         push $r13
178         push $r14
179         push $r15
180         mov $r15 #proc_kern
181         mov $r8 $flags
182         push $r8
183
184         nv_iord($r8, NV_PPWR_DSCRATCH(0))
185         add b32 $r8 1
186         nv_iowr(NV_PPWR_DSCRATCH(0), $r8)
187
188         nv_iord($r8, NV_PPWR_INTR)
189         and $r9 $r8 NV_PPWR_INTR_WATCHDOG
190         bra z #intr_skip_watchdog
191                 st b32 D[$r0 + #time_next] $r0
192                 mov $r14 #proc_list_head
193                 call(intr_watchdog)
194                 ld b32 $r9 D[$r0 + #time_next]
195                 cmp b32 $r9 0
196                 bra z #intr_skip_watchdog
197                         nv_iowr(NV_PPWR_WATCHDOG_TIME, $r9)
198                         st b32 D[$r0 + #time_prev] $r9
199
200         intr_skip_watchdog:
201         and $r9 $r8 NV_PPWR_INTR_SUBINTR
202         bra z #intr_skip_subintr
203                 nv_iord($r9, NV_PPWR_SUBINTR)
204                 and $r10 $r9 NV_PPWR_SUBINTR_FIFO
205                 bra z #intr_subintr_skip_fifo
206                         nv_iord($r12, NV_PPWR_FIFO_INTR)
207                         push $r12
208                         mov $r14 (PROC_HOST & 0x0000ffff)
209                         sethi $r14 (PROC_HOST & 0xffff0000)
210                         mov $r13 KMSG_FIFO
211                         call(send)
212                         pop $r12
213                         nv_iowr(NV_PPWR_FIFO_INTR, $r12)
214                 intr_subintr_skip_fifo:
215                 nv_iowr(NV_PPWR_SUBINTR, $r9)
216
217         intr_skip_subintr:
218         and $r9 $r8 NV_PPWR_INTR_PAUSE
219         bra z #intr_skip_pause
220                 and $r10 0xffbf
221
222         intr_skip_pause:
223         and $r9 $r8 NV_PPWR_INTR_USER0
224         bra z #intr_skip_user0
225                 and $r10 0xffbf
226
227         intr_skip_user0:
228         nv_iowr(NV_PPWR_INTR_ACK, $r8)
229         pop $r8
230         mov $flags $r8
231         pop $r15
232         pop $r14
233         pop $r13
234         pop $r12
235         pop $r11
236         pop $r10
237         pop $r9
238         pop $r8
239         pop $r0
240         bclr $flags $p0
241         iret
242
243 // request the current process be sent a message after a timeout expires
244 //
245 // $r15 - current
246 // $r14 - ticks
247 // $r0  - zero
248 timer:
249         // interrupts off to prevent racing with timer isr
250         bclr $flags ie0
251
252         // if current process already has a timer set, bail
253         ld b32 $r8 D[$r15 + #proc_time]
254         cmp b32 $r8 0
255         bra g #timer_done
256         st b32 D[$r15 + #proc_time] $r14
257
258         // halt watchdog timer temporarily and check for a pending
259         // interrupt.  if there's one already pending, we can just
260         // bail since the timer isr will queue the next soonest
261         // right after it's done
262         nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)
263         nv_iord($r8, NV_PPWR_INTR)
264         and $r8 NV_PPWR_INTR_WATCHDOG
265         bra nz #timer_enable
266
267         // update the watchdog if this timer should expire first,
268         // or if there's no timeout already set
269         nv_iord($r8, NV_PPWR_WATCHDOG_TIME)
270         cmp b32 $r14 $r0
271         bra e #timer_reset
272         cmp b32 $r14 $r8
273         bra l #timer_done
274         timer_reset:
275         nv_iowr(NV_PPWR_WATCHDOG_TIME, $r14)
276         st b32 D[$r0 + #time_prev] $r14
277
278         // re-enable the watchdog timer
279         timer_enable:
280         mov $r8 1
281         nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r8)
282
283         // interrupts back on
284         timer_done:
285         bset $flags ie0
286         ret
287
288 // send message to another process
289 //
290 // $r15 - current
291 // $r14 - process
292 // $r13 - message
293 // $r12 - message data 0
294 // $r11 - message data 1
295 // $r0  - zero
296 send_proc:
297         push $r8
298         push $r9
299         // check for space in queue
300         ld b32 $r8 D[$r14 + #proc_qget]
301         ld b32 $r9 D[$r14 + #proc_qput]
302         xor $r8 #proc_qmaskb
303         cmp b32 $r8 $r9
304         bra e #send_done
305
306         // enqueue message
307         and $r8 $r9 #proc_qmaskp
308         shl b32 $r8 $r8 #proc_qlen
309         add b32 $r8 #proc_queue
310         add b32 $r8 $r14
311
312         ld b32 $r10 D[$r15 + #proc_id]
313         st b32 D[$r8 + #msg_process] $r10
314         st b32 D[$r8 + #msg_message] $r13
315         st b32 D[$r8 + #msg_data0] $r12
316         st b32 D[$r8 + #msg_data1] $r11
317
318         // increment PUT
319         add b32 $r9 1
320         and $r9 #proc_qmaskf
321         st b32 D[$r14 + #proc_qput] $r9
322         bset $flags $p2
323         send_done:
324         pop $r9
325         pop $r8
326         ret
327
328 // lookup process structure by its name
329 //
330 // $r15 - current
331 // $r14 - process name
332 // $r0  - zero
333 //
334 // $r14 - process
335 // $p1  - success
336 find:
337         push $r8
338         mov $r8 #proc_list_head
339         bset $flags $p1
340         find_loop:
341                 ld b32 $r10 D[$r8 + #proc_id]
342                 cmp b32 $r10 $r14
343                 bra e #find_done
344                 add b32 $r8 #proc_size
345                 cmp b32 $r8 #proc_list_tail
346                 bra ne #find_loop
347                 bclr $flags $p1
348         find_done:
349         mov b32 $r14 $r8
350         pop $r8
351         ret
352
353 // send message to another process
354 //
355 // $r15 - current
356 // $r14 - process id
357 // $r13 - message
358 // $r12 - message data 0
359 // $r11 - message data 1
360 // $r0  - zero
361 send:
362         call(find)
363         bra $p1 #send_proc
364         ret
365
366 // process single message for a given process
367 //
368 // $r15 - current
369 // $r14 - process
370 // $r0  - zero
371 recv:
372         ld b32 $r8 D[$r14 + #proc_qget]
373         ld b32 $r9 D[$r14 + #proc_qput]
374         bclr $flags $p1
375         cmp b32 $r8 $r9
376         bra e #recv_done
377                 // dequeue message
378                 and $r9 $r8 #proc_qmaskp
379                 add b32 $r8 1
380                 and $r8 #proc_qmaskf
381                 st b32 D[$r14 + #proc_qget] $r8
382                 ld b32 $r10 D[$r14 + #proc_recv]
383
384                 push $r15
385                 mov $r15 $flags
386                 push $r15
387                 mov b32 $r15 $r14
388
389                 shl b32 $r9 $r9 #proc_qlen
390                 add b32 $r14 $r9
391                 add b32 $r14 #proc_queue
392                 ld b32 $r11 D[$r14 + #msg_data1]
393                 ld b32 $r12 D[$r14 + #msg_data0]
394                 ld b32 $r13 D[$r14 + #msg_message]
395                 ld b32 $r14 D[$r14 + #msg_process]
396
397                 // process it
398                 call $r10
399                 pop $r15
400                 mov $flags $r15
401                 bset $flags $p1
402                 pop $r15
403         recv_done:
404         ret
405
406 init:
407         // setup stack
408         nv_iord($r1, NV_PPWR_CAPS)
409         extr $r1 $r1 9:17
410         shl b32 $r1 8
411         mov $sp $r1
412
413 #ifdef NVKM_FALCON_MMIO_UAS
414         // somehow allows the magic "access mmio via D[]" stuff that's
415         // used by the nv_rd32/nv_wr32 macros to work
416         mov $r1 0x0010
417         sethi $r1 NV_PPWR_UAS_CONFIG_ENABLE
418         nv_iowrs(NV_PPWR_UAS_CONFIG, $r1)
419 #endif
420
421         // route all interrupts except user0/1 and pause to fuc
422         mov $r1 0x00e0
423         sethi $r1 0x00000000
424         nv_iowr(NV_PPWR_INTR_ROUTE, $r1)
425
426         // enable watchdog and subintr intrs
427         mov $r1 NV_PPWR_INTR_EN_CLR_MASK
428         nv_iowr(NV_PPWR_INTR_EN_CLR, $r1)
429         mov $r1 NV_PPWR_INTR_EN_SET_WATCHDOG
430         or $r1 NV_PPWR_INTR_EN_SET_SUBINTR
431         nv_iowr(NV_PPWR_INTR_EN_SET, $r1)
432
433         // enable interrupts globally
434         mov $r1 #intr
435         sethi $r1 0x00000000
436         mov $iv0 $r1
437         bset $flags ie0
438
439         // enable watchdog timer
440         mov $r1 1
441         nv_iowr(NV_PPWR_WATCHDOG_ENABLE, $r1)
442
443         // bootstrap processes, idle process will be last, and not return
444         mov $r15 #proc_list_head
445         init_proc:
446                 ld b32 $r1 D[$r15 + #proc_init]
447                 cmp b32 $r1 0
448                 bra z #init_proc
449                 call $r1
450                 add b32 $r15 #proc_size
451                 bra #init_proc
452 #endif