1 | /* $NetBSD: nouveau_subdev_pwr_memx.c,v 1.1.1.1 2014/08/06 12:36:31 riastradh Exp $ */ |
2 | |
3 | #include <sys/cdefs.h> |
4 | __KERNEL_RCSID(0, "$NetBSD: nouveau_subdev_pwr_memx.c,v 1.1.1.1 2014/08/06 12:36:31 riastradh Exp $" ); |
5 | |
6 | #ifndef __NVKM_PWR_MEMX_H__ |
7 | #define __NVKM_PWR_MEMX_H__ |
8 | |
9 | #include <subdev/pwr.h> |
10 | #include <subdev/pwr/fuc/os.h> |
11 | |
12 | struct nouveau_memx { |
13 | struct nouveau_pwr *ppwr; |
14 | u32 base; |
15 | u32 size; |
16 | struct { |
17 | u32 mthd; |
18 | u32 size; |
19 | u32 data[64]; |
20 | } c; |
21 | }; |
22 | |
23 | static void |
24 | memx_out(struct nouveau_memx *memx) |
25 | { |
26 | struct nouveau_pwr *ppwr = memx->ppwr; |
27 | int i; |
28 | |
29 | if (memx->c.size) { |
30 | nv_wr32(ppwr, 0x10a1c4, (memx->c.size << 16) | memx->c.mthd); |
31 | for (i = 0; i < memx->c.size; i++) |
32 | nv_wr32(ppwr, 0x10a1c4, memx->c.data[i]); |
33 | memx->c.size = 0; |
34 | } |
35 | } |
36 | |
37 | static void |
38 | memx_cmd(struct nouveau_memx *memx, u32 mthd, u32 size, u32 data[]) |
39 | { |
40 | if ((memx->c.size + size >= ARRAY_SIZE(memx->c.data)) || |
41 | (memx->c.size && memx->c.mthd != mthd)) |
42 | memx_out(memx); |
43 | memcpy(&memx->c.data[memx->c.size], data, size * sizeof(data[0])); |
44 | memx->c.size += size; |
45 | memx->c.mthd = mthd; |
46 | } |
47 | |
48 | int |
49 | nouveau_memx_init(struct nouveau_pwr *ppwr, struct nouveau_memx **pmemx) |
50 | { |
51 | struct nouveau_memx *memx; |
52 | u32 reply[2]; |
53 | int ret; |
54 | |
55 | ret = ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_INFO, 0, 0); |
56 | if (ret) |
57 | return ret; |
58 | |
59 | memx = *pmemx = kzalloc(sizeof(*memx), GFP_KERNEL); |
60 | if (!memx) |
61 | return -ENOMEM; |
62 | memx->ppwr = ppwr; |
63 | memx->base = reply[0]; |
64 | memx->size = reply[1]; |
65 | |
66 | /* acquire data segment access */ |
67 | do { |
68 | nv_wr32(ppwr, 0x10a580, 0x00000003); |
69 | } while (nv_rd32(ppwr, 0x10a580) != 0x00000003); |
70 | nv_wr32(ppwr, 0x10a1c0, 0x01000000 | memx->base); |
71 | nv_wr32(ppwr, 0x10a1c4, 0x00010000 | MEMX_ENTER); |
72 | nv_wr32(ppwr, 0x10a1c4, 0x00000000); |
73 | return 0; |
74 | } |
75 | |
76 | int |
77 | nouveau_memx_fini(struct nouveau_memx **pmemx, bool exec) |
78 | { |
79 | struct nouveau_memx *memx = *pmemx; |
80 | struct nouveau_pwr *ppwr = memx->ppwr; |
81 | u32 finish, reply[2]; |
82 | |
83 | /* flush the cache... */ |
84 | memx_out(memx); |
85 | |
86 | /* release data segment access */ |
87 | nv_wr32(ppwr, 0x10a1c4, 0x00000000 | MEMX_LEAVE); |
88 | finish = nv_rd32(ppwr, 0x10a1c0) & 0x00ffffff; |
89 | nv_wr32(ppwr, 0x10a580, 0x00000000); |
90 | |
91 | /* call MEMX process to execute the script, and wait for reply */ |
92 | if (exec) { |
93 | ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_EXEC, |
94 | memx->base, finish); |
95 | } |
96 | |
97 | kfree(memx); |
98 | return 0; |
99 | } |
100 | |
101 | void |
102 | nouveau_memx_wr32(struct nouveau_memx *memx, u32 addr, u32 data) |
103 | { |
104 | nv_debug(memx->ppwr, "R[%06x] = 0x%08x\n" , addr, data); |
105 | memx_cmd(memx, MEMX_WR32, 2, (u32[]){ addr, data }); |
106 | } |
107 | |
108 | void |
109 | nouveau_memx_wait(struct nouveau_memx *memx, |
110 | u32 addr, u32 mask, u32 data, u32 nsec) |
111 | { |
112 | nv_debug(memx->ppwr, "R[%06x] & 0x%08x == 0x%08x, %d us\n" , |
113 | addr, mask, data, nsec); |
114 | memx_cmd(memx, MEMX_WAIT, 4, (u32[]){ addr, ~mask, data, nsec }); |
115 | memx_out(memx); /* fuc can't handle multiple */ |
116 | } |
117 | |
118 | void |
119 | nouveau_memx_nsec(struct nouveau_memx *memx, u32 nsec) |
120 | { |
121 | nv_debug(memx->ppwr, " DELAY = %d ns\n" , nsec); |
122 | memx_cmd(memx, MEMX_DELAY, 1, (u32[]){ nsec }); |
123 | memx_out(memx); /* fuc can't handle multiple */ |
124 | } |
125 | |
126 | #endif |
127 | |