Commit 7f4b9616 authored by Roy Spliet's avatar Roy Spliet Committed by Ben Skeggs

drm/nouveau/fb/ramnva3: Link training for DDR3

V2: fix whitespace errors in memx.fuc
Signed-off-by: default avatarRoy Spliet <rspliet@eclipso.eu>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent f648cab0
...@@ -48,6 +48,8 @@ void nouveau_memx_wait(struct nouveau_memx *, ...@@ -48,6 +48,8 @@ void nouveau_memx_wait(struct nouveau_memx *,
u32 addr, u32 mask, u32 data, u32 nsec); u32 addr, u32 mask, u32 data, u32 nsec);
void nouveau_memx_nsec(struct nouveau_memx *, u32 nsec); void nouveau_memx_nsec(struct nouveau_memx *, u32 nsec);
void nouveau_memx_wait_vblank(struct nouveau_memx *); void nouveau_memx_wait_vblank(struct nouveau_memx *);
void nouveau_memx_train(struct nouveau_memx *);
int nouveau_memx_train_result(struct nouveau_pwr *, u32 *, int);
void nouveau_memx_block(struct nouveau_memx *); void nouveau_memx_block(struct nouveau_memx *);
void nouveau_memx_unblock(struct nouveau_memx *); void nouveau_memx_unblock(struct nouveau_memx *);
......
...@@ -140,6 +140,20 @@ ramfuc_wait_vblank(struct ramfuc *ram) ...@@ -140,6 +140,20 @@ ramfuc_wait_vblank(struct ramfuc *ram)
nouveau_memx_wait_vblank(ram->memx); nouveau_memx_wait_vblank(ram->memx);
} }
static inline void
ramfuc_train(struct ramfuc *ram)
{
nouveau_memx_train(ram->memx);
}
static inline int
ramfuc_train_result(struct nouveau_fb *pfb, u32 *result, u32 rsize)
{
struct nouveau_pwr *ppwr = nouveau_pwr(pfb);
return nouveau_memx_train_result(ppwr, result, rsize);
}
static inline void static inline void
ramfuc_block(struct ramfuc *ram) ramfuc_block(struct ramfuc *ram)
{ {
...@@ -162,6 +176,8 @@ ramfuc_unblock(struct ramfuc *ram) ...@@ -162,6 +176,8 @@ ramfuc_unblock(struct ramfuc *ram)
#define ram_wait(s,r,m,d,n) ramfuc_wait(&(s)->base, (r), (m), (d), (n)) #define ram_wait(s,r,m,d,n) ramfuc_wait(&(s)->base, (r), (m), (d), (n))
#define ram_nsec(s,n) ramfuc_nsec(&(s)->base, (n)) #define ram_nsec(s,n) ramfuc_nsec(&(s)->base, (n))
#define ram_wait_vblank(s) ramfuc_wait_vblank(&(s)->base) #define ram_wait_vblank(s) ramfuc_wait_vblank(&(s)->base)
#define ram_train(s) ramfuc_train(&(s)->base)
#define ram_train_result(s,r,l) ramfuc_train_result((s), (r), (l))
#define ram_block(s) ramfuc_block(&(s)->base) #define ram_block(s) ramfuc_block(&(s)->base)
#define ram_unblock(s) ramfuc_unblock(&(s)->base) #define ram_unblock(s) ramfuc_unblock(&(s)->base)
......
...@@ -50,6 +50,7 @@ handler(WR32 , 0x0000, 0x0002, #memx_func_wr32) ...@@ -50,6 +50,7 @@ handler(WR32 , 0x0000, 0x0002, #memx_func_wr32)
handler(WAIT , 0x0004, 0x0000, #memx_func_wait) handler(WAIT , 0x0004, 0x0000, #memx_func_wait)
handler(DELAY , 0x0001, 0x0000, #memx_func_delay) handler(DELAY , 0x0001, 0x0000, #memx_func_delay)
handler(VBLANK, 0x0001, 0x0000, #memx_func_wait_vblank) handler(VBLANK, 0x0001, 0x0000, #memx_func_wait_vblank)
handler(TRAIN , 0x0000, 0x0000, #memx_func_train)
memx_func_tail: memx_func_tail:
.equ #memx_func_size #memx_func_next - #memx_func_head .equ #memx_func_size #memx_func_next - #memx_func_head
...@@ -63,6 +64,10 @@ memx_ts_end: ...@@ -63,6 +64,10 @@ memx_ts_end:
memx_data_head: memx_data_head:
.skip 0x0800 .skip 0x0800
memx_data_tail: memx_data_tail:
memx_train_head:
.skip 0x0100
memx_train_tail:
#endif #endif
/****************************************************************************** /******************************************************************************
...@@ -257,6 +262,101 @@ memx_func_delay: ...@@ -257,6 +262,101 @@ memx_func_delay:
call(nsec) call(nsec)
ret 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)
movw $r5 0x3
movw $r7 0x0
// Read random memory to wake up... things
imm32($r9, 0x700000)
nv_rd32($r8,$r9)
movw $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
movw $r6 0x0
memx_func_train_loop_inner:
movw $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
movw $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 // description
// //
// $r15 - current (memx) // $r15 - current (memx)
...@@ -307,8 +407,19 @@ memx_exec: ...@@ -307,8 +407,19 @@ memx_exec:
// $r11 - data1 // $r11 - data1
// $r0 - zero // $r0 - zero
memx_info: memx_info:
cmp b16 $r12 0x1
bra e #memx_info_train
memx_info_data:
mov $r12 #memx_data_head mov $r12 #memx_data_head
mov $r11 #memx_data_tail - #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) call(send)
ret ret
......
...@@ -18,6 +18,10 @@ ...@@ -18,6 +18,10 @@
#define MEMX_MSG_INFO 0 #define MEMX_MSG_INFO 0
#define MEMX_MSG_EXEC 1 #define MEMX_MSG_EXEC 1
/* MEMX: info types */
#define MEMX_INFO_DATA 0
#define MEMX_INFO_TRAIN 1
/* MEMX: script opcode definitions */ /* MEMX: script opcode definitions */
#define MEMX_ENTER 1 #define MEMX_ENTER 1
#define MEMX_LEAVE 2 #define MEMX_LEAVE 2
...@@ -25,6 +29,7 @@ ...@@ -25,6 +29,7 @@
#define MEMX_WAIT 4 #define MEMX_WAIT 4
#define MEMX_DELAY 5 #define MEMX_DELAY 5
#define MEMX_VBLANK 6 #define MEMX_VBLANK 6
#define MEMX_TRAIN 7
/* I2C_: message identifiers */ /* I2C_: message identifiers */
#define I2C__MSG_RD08 0 #define I2C__MSG_RD08 0
......
...@@ -47,7 +47,8 @@ nouveau_memx_init(struct nouveau_pwr *ppwr, struct nouveau_memx **pmemx) ...@@ -47,7 +47,8 @@ nouveau_memx_init(struct nouveau_pwr *ppwr, struct nouveau_memx **pmemx)
u32 reply[2]; u32 reply[2];
int ret; int ret;
ret = ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_INFO, 0, 0); ret = ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_INFO,
MEMX_INFO_DATA, 0);
if (ret) if (ret)
return ret; return ret;
...@@ -151,6 +152,38 @@ nouveau_memx_wait_vblank(struct nouveau_memx *memx) ...@@ -151,6 +152,38 @@ nouveau_memx_wait_vblank(struct nouveau_memx *memx)
memx_out(memx); /* fuc can't handle multiple */ memx_out(memx); /* fuc can't handle multiple */
} }
void
nouveau_memx_train(struct nouveau_memx *memx)
{
nv_debug(memx->ppwr, " MEM TRAIN\n");
memx_cmd(memx, MEMX_TRAIN, 0, NULL);
}
int
nouveau_memx_train_result(struct nouveau_pwr *ppwr, u32 *res, int rsize)
{
u32 reply[2], base, size, i;
int ret;
ret = ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_INFO,
MEMX_INFO_TRAIN, 0);
if (ret)
return ret;
base = reply[0];
size = reply[1] >> 2;
if (size > rsize)
return -ENOMEM;
/* read the packet */
nv_wr32(ppwr, 0x10a1c0, 0x02000000 | base);
for (i = 0; i < size; i++)
res[i] = nv_rd32(ppwr, 0x10a1c4);
return 0;
}
void void
nouveau_memx_block(struct nouveau_memx *memx) nouveau_memx_block(struct nouveau_memx *memx)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment