0001 /*
0002 * Copyright 2013 Red Hat Inc.
0003 *
0004 * Permission is hereby granted, free of charge, to any person obtaining a
0005 * copy of this software and associated documentation files (the "Software"),
0006 * to deal in the Software without restriction, including without limitation
0007 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008 * and/or sell copies of the Software, and to permit persons to whom the
0009 * Software is furnished to do so, subject to the following conditions:
0010 *
0011 * The above copyright notice and this permission notice shall be included in
0012 * all copies or substantial portions of the Software.
0013 *
0014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
0017 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020 * OTHER DEALINGS IN THE SOFTWARE.
0021 *
0022 * Authors: Ben Skeggs
0023 */
0024
0025 #ifdef INCLUDE_PROC
0026 process(PROC_MEMX, #memx_init, #memx_recv)
0027 #endif
0028
0029 /******************************************************************************
0030 * MEMX data segment
0031 *****************************************************************************/
0032 #ifdef INCLUDE_DATA
0033 .equ #memx_opcode 0
0034 .equ #memx_header 2
0035 .equ #memx_length 4
0036 .equ #memx_func 8
0037
0038 #define handler(cmd,hdr,len,func) /*
0039 */ .b16 MEMX_##cmd /*
0040 */ .b16 hdr /*
0041 */ .b16 len /*
0042 */ .b16 0 /*
0043 */ .b32 func
0044
0045 memx_func_head:
0046 handler(ENTER , 0x0000, 0x0000, #memx_func_enter)
0047 memx_func_next:
0048 handler(LEAVE , 0x0000, 0x0000, #memx_func_leave)
0049 handler(WR32 , 0x0000, 0x0002, #memx_func_wr32)
0050 handler(WAIT , 0x0004, 0x0000, #memx_func_wait)
0051 handler(DELAY , 0x0001, 0x0000, #memx_func_delay)
0052 handler(VBLANK, 0x0001, 0x0000, #memx_func_wait_vblank)
0053 handler(TRAIN , 0x0000, 0x0000, #memx_func_train)
0054 memx_func_tail:
0055
0056 .equ #memx_func_size #memx_func_next - #memx_func_head
0057 .equ #memx_func_num (#memx_func_tail - #memx_func_head) / #memx_func_size
0058
0059 memx_ts_start:
0060 .b32 0
0061 memx_ts_end:
0062 .b32 0
0063
0064 memx_data_head:
0065 .skip 0x0800
0066 memx_data_tail:
0067
0068 memx_train_head:
0069 .skip 0x0100
0070 memx_train_tail:
0071 #endif
0072
0073 /******************************************************************************
0074 * MEMX code segment
0075 *****************************************************************************/
0076 #ifdef INCLUDE_CODE
0077 // description
0078 //
0079 // $r15 - current (memx)
0080 // $r4 - packet length
0081 // $r3 - opcode desciption
0082 // $r0 - zero
0083 memx_func_enter:
0084 #if NVKM_PPWR_CHIPSET == GT215
0085 mov $r8 0x1610
0086 nv_rd32($r7, $r8)
0087 imm32($r6, 0xfffffffc)
0088 and $r7 $r6
0089 mov $r6 0x2
0090 or $r7 $r6
0091 nv_wr32($r8, $r7)
0092 #else
0093 mov $r6 0x001620
0094 imm32($r7, ~0x00000aa2);
0095 nv_rd32($r8, $r6)
0096 and $r8 $r7
0097 nv_wr32($r6, $r8)
0098
0099 imm32($r7, ~0x00000001)
0100 nv_rd32($r8, $r6)
0101 and $r8 $r7
0102 nv_wr32($r6, $r8)
0103
0104 mov $r6 0x0026f0
0105 nv_rd32($r8, $r6)
0106 and $r8 $r7
0107 nv_wr32($r6, $r8)
0108 #endif
0109
0110 mov $r6 NV_PPWR_OUTPUT_SET_FB_PAUSE
0111 nv_iowr(NV_PPWR_OUTPUT_SET, $r6)
0112 memx_func_enter_wait:
0113 nv_iord($r6, NV_PPWR_OUTPUT)
0114 and $r6 NV_PPWR_OUTPUT_FB_PAUSE
0115 bra z #memx_func_enter_wait
0116
0117 nv_iord($r6, NV_PPWR_TIMER_LOW)
0118 st b32 D[$r0 + #memx_ts_start] $r6
0119 ret
0120
0121 // description
0122 //
0123 // $r15 - current (memx)
0124 // $r4 - packet length
0125 // $r3 - opcode desciption
0126 // $r0 - zero
0127 memx_func_leave:
0128 nv_iord($r6, NV_PPWR_TIMER_LOW)
0129 st b32 D[$r0 + #memx_ts_end] $r6
0130
0131 mov $r6 NV_PPWR_OUTPUT_CLR_FB_PAUSE
0132 nv_iowr(NV_PPWR_OUTPUT_CLR, $r6)
0133 memx_func_leave_wait:
0134 nv_iord($r6, NV_PPWR_OUTPUT)
0135 and $r6 NV_PPWR_OUTPUT_FB_PAUSE
0136 bra nz #memx_func_leave_wait
0137
0138 #if NVKM_PPWR_CHIPSET == GT215
0139 mov $r8 0x1610
0140 nv_rd32($r7, $r8)
0141 imm32($r6, 0xffffffcc)
0142 and $r7 $r6
0143 nv_wr32($r8, $r7)
0144 #else
0145 mov $r6 0x0026f0
0146 imm32($r7, 0x00000001)
0147 nv_rd32($r8, $r6)
0148 or $r8 $r7
0149 nv_wr32($r6, $r8)
0150
0151 mov $r6 0x001620
0152 nv_rd32($r8, $r6)
0153 or $r8 $r7
0154 nv_wr32($r6, $r8)
0155
0156 imm32($r7, 0x00000aa2);
0157 nv_rd32($r8, $r6)
0158 or $r8 $r7
0159 nv_wr32($r6, $r8)
0160 #endif
0161 ret
0162
0163 #if NVKM_PPWR_CHIPSET < GF119
0164 // description
0165 //
0166 // $r15 - current (memx)
0167 // $r4 - packet length
0168 // +00: head to wait for vblank on
0169 // $r3 - opcode desciption
0170 // $r0 - zero
0171 memx_func_wait_vblank:
0172 ld b32 $r6 D[$r1 + 0x00]
0173 cmp b32 $r6 0x0
0174 bra z #memx_func_wait_vblank_head0
0175 cmp b32 $r6 0x1
0176 bra z #memx_func_wait_vblank_head1
0177 bra #memx_func_wait_vblank_fini
0178
0179 memx_func_wait_vblank_head1:
0180 mov $r7 0x20
0181 bra #memx_func_wait_vblank_0
0182
0183 memx_func_wait_vblank_head0:
0184 mov $r7 0x8
0185
0186 memx_func_wait_vblank_0:
0187 nv_iord($r6, NV_PPWR_INPUT)
0188 and $r6 $r7
0189 bra nz #memx_func_wait_vblank_0
0190
0191 memx_func_wait_vblank_1:
0192 nv_iord($r6, NV_PPWR_INPUT)
0193 and $r6 $r7
0194 bra z #memx_func_wait_vblank_1
0195
0196 memx_func_wait_vblank_fini:
0197 add b32 $r1 0x4
0198 ret
0199
0200 #else
0201
0202 // XXX: currently no-op
0203 //
0204 // $r15 - current (memx)
0205 // $r4 - packet length
0206 // +00: head to wait for vblank on
0207 // $r3 - opcode desciption
0208 // $r0 - zero
0209 memx_func_wait_vblank:
0210 add b32 $r1 0x4
0211 ret
0212
0213 #endif
0214
0215 // description
0216 //
0217 // $r15 - current (memx)
0218 // $r4 - packet length
0219 // +00*n: addr
0220 // +04*n: data
0221 // $r3 - opcode desciption
0222 // $r0 - zero
0223 memx_func_wr32:
0224 ld b32 $r6 D[$r1 + 0x00]
0225 ld b32 $r5 D[$r1 + 0x04]
0226 add b32 $r1 0x08
0227 nv_wr32($r6, $r5)
0228 sub b32 $r4 0x02
0229 bra nz #memx_func_wr32
0230 ret
0231
0232 // description
0233 //
0234 // $r15 - current (memx)
0235 // $r4 - packet length
0236 // +00: addr
0237 // +04: mask
0238 // +08: data
0239 // +0c: timeout (ns)
0240 // $r3 - opcode desciption
0241 // $r0 - zero
0242 memx_func_wait:
0243 nv_iord($r8, NV_PPWR_TIMER_LOW)
0244 ld b32 $r14 D[$r1 + 0x00]
0245 ld b32 $r13 D[$r1 + 0x04]
0246 ld b32 $r12 D[$r1 + 0x08]
0247 ld b32 $r11 D[$r1 + 0x0c]
0248 add b32 $r1 0x10
0249 call(wait)
0250 ret
0251
0252 // description
0253 //
0254 // $r15 - current (memx)
0255 // $r4 - packet length
0256 // +00: time (ns)
0257 // $r3 - opcode desciption
0258 // $r0 - zero
0259 memx_func_delay:
0260 ld b32 $r14 D[$r1 + 0x00]
0261 add b32 $r1 0x04
0262 call(nsec)
0263 ret
0264
0265 // description
0266 //
0267 // $r15 - current (memx)
0268 // $r4 - packet length
0269 // $r3 - opcode desciption
0270 // $r0 - zero
0271 memx_func_train:
0272 #if NVKM_PPWR_CHIPSET == GT215
0273 // $r5 - outer loop counter
0274 // $r6 - inner loop counter
0275 // $r7 - entry counter (#memx_train_head + $r7)
0276 mov $r5 0x3
0277 mov $r7 0x0
0278
0279 // Read random memory to wake up... things
0280 imm32($r9, 0x700000)
0281 nv_rd32($r8,$r9)
0282 mov $r14 0x2710
0283 call(nsec)
0284
0285 memx_func_train_loop_outer:
0286 mulu $r8 $r5 0x101
0287 sethi $r8 0x02000000
0288 imm32($r9, 0x1111e0)
0289 nv_wr32($r9, $r8)
0290 push $r5
0291
0292 mov $r6 0x0
0293 memx_func_train_loop_inner:
0294 mov $r8 0x1111
0295 mulu $r9 $r6 $r8
0296 shl b32 $r8 $r9 0x10
0297 or $r8 $r9
0298 imm32($r9, 0x100720)
0299 nv_wr32($r9, $r8)
0300
0301 imm32($r9, 0x100080)
0302 nv_rd32($r8, $r9)
0303 or $r8 $r8 0x20
0304 nv_wr32($r9, $r8)
0305
0306 imm32($r9, 0x10053c)
0307 imm32($r8, 0x80003002)
0308 nv_wr32($r9, $r8)
0309
0310 imm32($r14, 0x100560)
0311 imm32($r13, 0x80000000)
0312 add b32 $r12 $r13 0
0313 imm32($r11, 0x001e8480)
0314 call(wait)
0315
0316 // $r5 - inner inner loop counter
0317 // $r9 - result
0318 mov $r5 0
0319 imm32($r9, 0x8300ffff)
0320 memx_func_train_loop_4x:
0321 imm32($r10, 0x100080)
0322 nv_rd32($r8, $r10)
0323 imm32($r11, 0xffffffdf)
0324 and $r8 $r11
0325 nv_wr32($r10, $r8)
0326
0327 imm32($r10, 0x10053c)
0328 imm32($r8, 0x80003002)
0329 nv_wr32($r10, $r8)
0330
0331 imm32($r14, 0x100560)
0332 imm32($r13, 0x80000000)
0333 mov b32 $r12 $r13
0334 imm32($r11, 0x00002710)
0335 call(wait)
0336
0337 nv_rd32($r13, $r14)
0338 and $r9 $r9 $r13
0339
0340 add b32 $r5 1
0341 cmp b16 $r5 0x4
0342 bra l #memx_func_train_loop_4x
0343
0344 add b32 $r10 $r7 #memx_train_head
0345 st b32 D[$r10 + 0] $r9
0346 add b32 $r6 1
0347 add b32 $r7 4
0348
0349 cmp b16 $r6 0x10
0350 bra l #memx_func_train_loop_inner
0351
0352 pop $r5
0353 add b32 $r5 1
0354 cmp b16 $r5 7
0355 bra l #memx_func_train_loop_outer
0356
0357 #endif
0358 ret
0359
0360 // description
0361 //
0362 // $r15 - current (memx)
0363 // $r14 - sender process name
0364 // $r13 - message (exec)
0365 // $r12 - head of script
0366 // $r11 - tail of script
0367 // $r0 - zero
0368 memx_exec:
0369 push $r14
0370 push $r13
0371 mov b32 $r1 $r12
0372 mov b32 $r2 $r11
0373
0374 memx_exec_next:
0375 // fetch the packet header
0376 ld b32 $r3 D[$r1]
0377 add b32 $r1 4
0378 extr $r4 $r3 16:31
0379 extr $r3 $r3 0:15
0380
0381 // execute the opcode handler
0382 sub b32 $r3 1
0383 mulu $r3 #memx_func_size
0384 ld b32 $r5 D[$r3 + #memx_func_head + #memx_func]
0385 call $r5
0386
0387 // keep going, if we haven't reached the end
0388 cmp b32 $r1 $r2
0389 bra l #memx_exec_next
0390
0391 // send completion reply
0392 ld b32 $r11 D[$r0 + #memx_ts_start]
0393 ld b32 $r12 D[$r0 + #memx_ts_end]
0394 sub b32 $r12 $r11
0395 nv_iord($r11, NV_PPWR_INPUT)
0396 pop $r13
0397 pop $r14
0398 call(send)
0399 ret
0400
0401 // description
0402 //
0403 // $r15 - current (memx)
0404 // $r14 - sender process name
0405 // $r13 - message
0406 // $r12 - data0
0407 // $r11 - data1
0408 // $r0 - zero
0409 memx_info:
0410 cmp b16 $r12 0x1
0411 bra e #memx_info_train
0412
0413 memx_info_data:
0414 mov $r12 #memx_data_head
0415 mov $r11 #memx_data_tail - #memx_data_head
0416 bra #memx_info_send
0417
0418 memx_info_train:
0419 mov $r12 #memx_train_head
0420 mov $r11 #memx_train_tail - #memx_train_head
0421
0422 memx_info_send:
0423 call(send)
0424 ret
0425
0426 // description
0427 //
0428 // $r15 - current (memx)
0429 // $r14 - sender process name
0430 // $r13 - message
0431 // $r12 - data0
0432 // $r11 - data1
0433 // $r0 - zero
0434 memx_recv:
0435 cmp b32 $r13 MEMX_MSG_EXEC
0436 bra e #memx_exec
0437 cmp b32 $r13 MEMX_MSG_INFO
0438 bra e #memx_info
0439 ret
0440
0441 // description
0442 //
0443 // $r15 - current (memx)
0444 // $r0 - zero
0445 memx_init:
0446 ret
0447 #endif