| /* |
| * Copyright 2013 Red Hat Inc. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in |
| * all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| * OTHER DEALINGS IN THE SOFTWARE. |
| * |
| * Authors: Ben Skeggs |
| */ |
| |
| #ifdef INCLUDE_PROC |
| process(PROC_MEMX, #memx_init, #memx_recv) |
| #endif |
| |
| /****************************************************************************** |
| * MEMX data segment |
| *****************************************************************************/ |
| #ifdef INCLUDE_DATA |
| .equ #memx_opcode 0 |
| .equ #memx_header 2 |
| .equ #memx_length 4 |
| .equ #memx_func 8 |
| |
| #define handler(cmd,hdr,len,func) /* |
| */ .b16 MEMX_##cmd /* |
| */ .b16 hdr /* |
| */ .b16 len /* |
| */ .b16 0 /* |
| */ .b32 func |
| |
| memx_func_head: |
| handler(ENTER , 0x0000, 0x0000, #memx_func_enter) |
| memx_func_next: |
| handler(LEAVE , 0x0000, 0x0000, #memx_func_leave) |
| handler(WR32 , 0x0000, 0x0002, #memx_func_wr32) |
| handler(WAIT , 0x0004, 0x0000, #memx_func_wait) |
| handler(DELAY , 0x0001, 0x0000, #memx_func_delay) |
| handler(VBLANK, 0x0001, 0x0000, #memx_func_wait_vblank) |
| handler(TRAIN , 0x0000, 0x0000, #memx_func_train) |
| memx_func_tail: |
| |
| .equ #memx_func_size #memx_func_next - #memx_func_head |
| .equ #memx_func_num (#memx_func_tail - #memx_func_head) / #memx_func_size |
| |
| memx_ts_start: |
| .b32 0 |
| memx_ts_end: |
| .b32 0 |
| |
| memx_data_head: |
| .skip 0x0800 |
| memx_data_tail: |
| |
| memx_train_head: |
| .skip 0x0100 |
| memx_train_tail: |
| #endif |
| |
| /****************************************************************************** |
| * MEMX code segment |
| *****************************************************************************/ |
| #ifdef INCLUDE_CODE |
| // description |
| // |
| // $r15 - current (memx) |
| // $r4 - packet length |
| // $r3 - opcode desciption |
| // $r0 - zero |
| memx_func_enter: |
| #if NVKM_PPWR_CHIPSET == GT215 |
| mov $r8 0x1610 |
| nv_rd32($r7, $r8) |
| imm32($r6, 0xfffffffc) |
| and $r7 $r6 |
| mov $r6 0x2 |
| or $r7 $r6 |
| nv_wr32($r8, $r7) |
| #else |
| mov $r6 0x001620 |
| imm32($r7, ~0x00000aa2); |
| nv_rd32($r8, $r6) |
| and $r8 $r7 |
| nv_wr32($r6, $r8) |
| |
| imm32($r7, ~0x00000001) |
| nv_rd32($r8, $r6) |
| and $r8 $r7 |
| nv_wr32($r6, $r8) |
| |
| mov $r6 0x0026f0 |
| nv_rd32($r8, $r6) |
| and $r8 $r7 |
| nv_wr32($r6, $r8) |
| #endif |
| |
| mov $r6 NV_PPWR_OUTPUT_SET_FB_PAUSE |
| nv_iowr(NV_PPWR_OUTPUT_SET, $r6) |
| memx_func_enter_wait: |
| nv_iord($r6, NV_PPWR_OUTPUT) |
| and $r6 NV_PPWR_OUTPUT_FB_PAUSE |
| bra z #memx_func_enter_wait |
| |
| nv_iord($r6, NV_PPWR_TIMER_LOW) |
| st b32 D[$r0 + #memx_ts_start] $r6 |
| ret |
| |
| // description |
| // |
| // $r15 - current (memx) |
| // $r4 - packet length |
| // $r3 - opcode desciption |
| // $r0 - zero |
| memx_func_leave: |
| nv_iord($r6, NV_PPWR_TIMER_LOW) |
| st b32 D[$r0 + #memx_ts_end] $r6 |
| |
| mov $r6 NV_PPWR_OUTPUT_CLR_FB_PAUSE |
| nv_iowr(NV_PPWR_OUTPUT_CLR, $r6) |
| memx_func_leave_wait: |
| nv_iord($r6, NV_PPWR_OUTPUT) |
| and $r6 NV_PPWR_OUTPUT_FB_PAUSE |
| bra nz #memx_func_leave_wait |
| |
| #if NVKM_PPWR_CHIPSET == GT215 |
| mov $r8 0x1610 |
| nv_rd32($r7, $r8) |
| imm32($r6, 0xffffffcc) |
| and $r7 $r6 |
| nv_wr32($r8, $r7) |
| #else |
| mov $r6 0x0026f0 |
| imm32($r7, 0x00000001) |
| nv_rd32($r8, $r6) |
| or $r8 $r7 |
| nv_wr32($r6, $r8) |
| |
| mov $r6 0x001620 |
| nv_rd32($r8, $r6) |
| or $r8 $r7 |
| nv_wr32($r6, $r8) |
| |
| imm32($r7, 0x00000aa2); |
| nv_rd32($r8, $r6) |
| or $r8 $r7 |
| nv_wr32($r6, $r8) |
| #endif |
| ret |
| |
| #if NVKM_PPWR_CHIPSET < GF119 |
| // description |
| // |
| // $r15 - current (memx) |
| // $r4 - packet length |
| // +00: head to wait for vblank on |
| // $r3 - opcode desciption |
| // $r0 - zero |
| memx_func_wait_vblank: |
| ld b32 $r6 D[$r1 + 0x00] |
| cmp b32 $r6 0x0 |
| bra z #memx_func_wait_vblank_head0 |
| cmp b32 $r6 0x1 |
| bra z #memx_func_wait_vblank_head1 |
| bra #memx_func_wait_vblank_fini |
| |
| memx_func_wait_vblank_head1: |
| mov $r7 0x20 |
| bra #memx_func_wait_vblank_0 |
| |
| memx_func_wait_vblank_head0: |
| mov $r7 0x8 |
| |
| memx_func_wait_vblank_0: |
| nv_iord($r6, NV_PPWR_INPUT) |
| and $r6 $r7 |
| bra nz #memx_func_wait_vblank_0 |
| |
| memx_func_wait_vblank_1: |
| nv_iord($r6, NV_PPWR_INPUT) |
| and $r6 $r7 |
| bra z #memx_func_wait_vblank_1 |
| |
| memx_func_wait_vblank_fini: |
| add b32 $r1 0x4 |
| ret |
| |
| #else |
| |
| // XXX: currently no-op |
| // |
| // $r15 - current (memx) |
| // $r4 - packet length |
| // +00: head to wait for vblank on |
| // $r3 - opcode desciption |
| // $r0 - zero |
| memx_func_wait_vblank: |
| add b32 $r1 0x4 |
| ret |
| |
| #endif |
| |
| // description |
| // |
| // $r15 - current (memx) |
| // $r4 - packet length |
| // +00*n: addr |
| // +04*n: data |
| // $r3 - opcode desciption |
| // $r0 - zero |
| memx_func_wr32: |
| ld b32 $r6 D[$r1 + 0x00] |
| ld b32 $r5 D[$r1 + 0x04] |
| add b32 $r1 0x08 |
| nv_wr32($r6, $r5) |
| sub b32 $r4 0x02 |
| bra nz #memx_func_wr32 |
| ret |
| |
| // description |
| // |
| // $r15 - current (memx) |
| // $r4 - packet length |
| // +00: addr |
| // +04: mask |
| // +08: data |
| // +0c: timeout (ns) |
| // $r3 - opcode desciption |
| // $r0 - zero |
| memx_func_wait: |
| nv_iord($r8, NV_PPWR_TIMER_LOW) |
| ld b32 $r14 D[$r1 + 0x00] |
| ld b32 $r13 D[$r1 + 0x04] |
| ld b32 $r12 D[$r1 + 0x08] |
| ld b32 $r11 D[$r1 + 0x0c] |
| add b32 $r1 0x10 |
| call(wait) |
| ret |
| |
| // description |
| // |
| // $r15 - current (memx) |
| // $r4 - packet length |
| // +00: time (ns) |
| // $r3 - opcode desciption |
| // $r0 - zero |
| memx_func_delay: |
| ld b32 $r14 D[$r1 + 0x00] |
| add b32 $r1 0x04 |
| call(nsec) |
| ret |
| |
| // description |
| // |
| // $r15 - current (memx) |
| // $r4 - packet length |
| // $r3 - opcode desciption |
| // $r0 - zero |
| memx_func_train: |
| #if NVKM_PPWR_CHIPSET == GT215 |
| // $r5 - outer loop counter |
| // $r6 - inner loop counter |
| // $r7 - entry counter (#memx_train_head + $r7) |
| mov $r5 0x3 |
| mov $r7 0x0 |
| |
| // Read random memory to wake up... things |
| imm32($r9, 0x700000) |
| nv_rd32($r8,$r9) |
| mov $r14 0x2710 |
| call(nsec) |
| |
| memx_func_train_loop_outer: |
| mulu $r8 $r5 0x101 |
| sethi $r8 0x02000000 |
| imm32($r9, 0x1111e0) |
| nv_wr32($r9, $r8) |
| push $r5 |
| |
| mov $r6 0x0 |
| memx_func_train_loop_inner: |
| mov $r8 0x1111 |
| mulu $r9 $r6 $r8 |
| shl b32 $r8 $r9 0x10 |
| or $r8 $r9 |
| imm32($r9, 0x100720) |
| nv_wr32($r9, $r8) |
| |
| imm32($r9, 0x100080) |
| nv_rd32($r8, $r9) |
| or $r8 $r8 0x20 |
| nv_wr32($r9, $r8) |
| |
| imm32($r9, 0x10053c) |
| imm32($r8, 0x80003002) |
| nv_wr32($r9, $r8) |
| |
| imm32($r14, 0x100560) |
| imm32($r13, 0x80000000) |
| add b32 $r12 $r13 0 |
| imm32($r11, 0x001e8480) |
| call(wait) |
| |
| // $r5 - inner inner loop counter |
| // $r9 - result |
| mov $r5 0 |
| imm32($r9, 0x8300ffff) |
| memx_func_train_loop_4x: |
| imm32($r10, 0x100080) |
| nv_rd32($r8, $r10) |
| imm32($r11, 0xffffffdf) |
| and $r8 $r11 |
| nv_wr32($r10, $r8) |
| |
| imm32($r10, 0x10053c) |
| imm32($r8, 0x80003002) |
| nv_wr32($r10, $r8) |
| |
| imm32($r14, 0x100560) |
| imm32($r13, 0x80000000) |
| mov b32 $r12 $r13 |
| imm32($r11, 0x00002710) |
| call(wait) |
| |
| nv_rd32($r13, $r14) |
| and $r9 $r9 $r13 |
| |
| add b32 $r5 1 |
| cmp b16 $r5 0x4 |
| bra l #memx_func_train_loop_4x |
| |
| add b32 $r10 $r7 #memx_train_head |
| st b32 D[$r10 + 0] $r9 |
| add b32 $r6 1 |
| add b32 $r7 4 |
| |
| cmp b16 $r6 0x10 |
| bra l #memx_func_train_loop_inner |
| |
| pop $r5 |
| add b32 $r5 1 |
| cmp b16 $r5 7 |
| bra l #memx_func_train_loop_outer |
| |
| #endif |
| ret |
| |
| // description |
| // |
| // $r15 - current (memx) |
| // $r14 - sender process name |
| // $r13 - message (exec) |
| // $r12 - head of script |
| // $r11 - tail of script |
| // $r0 - zero |
| memx_exec: |
| push $r14 |
| push $r13 |
| mov b32 $r1 $r12 |
| mov b32 $r2 $r11 |
| |
| memx_exec_next: |
| // fetch the packet header |
| ld b32 $r3 D[$r1] |
| add b32 $r1 4 |
| extr $r4 $r3 16:31 |
| extr $r3 $r3 0:15 |
| |
| // execute the opcode handler |
| sub b32 $r3 1 |
| mulu $r3 #memx_func_size |
| ld b32 $r5 D[$r3 + #memx_func_head + #memx_func] |
| call $r5 |
| |
| // keep going, if we haven't reached the end |
| cmp b32 $r1 $r2 |
| bra l #memx_exec_next |
| |
| // send completion reply |
| ld b32 $r11 D[$r0 + #memx_ts_start] |
| ld b32 $r12 D[$r0 + #memx_ts_end] |
| sub b32 $r12 $r11 |
| nv_iord($r11, NV_PPWR_INPUT) |
| pop $r13 |
| pop $r14 |
| call(send) |
| ret |
| |
| // description |
| // |
| // $r15 - current (memx) |
| // $r14 - sender process name |
| // $r13 - message |
| // $r12 - data0 |
| // $r11 - data1 |
| // $r0 - zero |
| memx_info: |
| cmp b16 $r12 0x1 |
| bra e #memx_info_train |
| |
| memx_info_data: |
| mov $r12 #memx_data_head |
| mov $r11 #memx_data_tail - #memx_data_head |
| bra #memx_info_send |
| |
| memx_info_train: |
| mov $r12 #memx_train_head |
| mov $r11 #memx_train_tail - #memx_train_head |
| |
| memx_info_send: |
| call(send) |
| ret |
| |
| // description |
| // |
| // $r15 - current (memx) |
| // $r14 - sender process name |
| // $r13 - message |
| // $r12 - data0 |
| // $r11 - data1 |
| // $r0 - zero |
| memx_recv: |
| cmp b32 $r13 MEMX_MSG_EXEC |
| bra e #memx_exec |
| cmp b32 $r13 MEMX_MSG_INFO |
| bra e #memx_info |
| ret |
| |
| // description |
| // |
| // $r15 - current (memx) |
| // $r0 - zero |
| memx_init: |
| ret |
| #endif |