]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
ebb58dc2 BS |
2 | #ifndef __NVKM_PMU_MEMX_H__ |
3 | #define __NVKM_PMU_MEMX_H__ | |
adec9bc3 | 4 | #include "priv.h" |
ff4b42c7 | 5 | |
21b13791 BS |
6 | struct nvkm_memx { |
7 | struct nvkm_pmu *pmu; | |
ff4b42c7 BS |
8 | u32 base; |
9 | u32 size; | |
10 | struct { | |
11 | u32 mthd; | |
12 | u32 size; | |
13 | u32 data[64]; | |
14 | } c; | |
15 | }; | |
16 | ||
17 | static void | |
21b13791 | 18 | memx_out(struct nvkm_memx *memx) |
ff4b42c7 | 19 | { |
bef002e8 | 20 | struct nvkm_device *device = memx->pmu->subdev.device; |
ff4b42c7 BS |
21 | int i; |
22 | ||
30da0806 | 23 | if (memx->c.mthd) { |
bef002e8 | 24 | nvkm_wr32(device, 0x10a1c4, (memx->c.size << 16) | memx->c.mthd); |
ff4b42c7 | 25 | for (i = 0; i < memx->c.size; i++) |
bef002e8 | 26 | nvkm_wr32(device, 0x10a1c4, memx->c.data[i]); |
30da0806 | 27 | memx->c.mthd = 0; |
ff4b42c7 BS |
28 | memx->c.size = 0; |
29 | } | |
30 | } | |
31 | ||
32 | static void | |
21b13791 | 33 | memx_cmd(struct nvkm_memx *memx, u32 mthd, u32 size, u32 data[]) |
ff4b42c7 BS |
34 | { |
35 | if ((memx->c.size + size >= ARRAY_SIZE(memx->c.data)) || | |
30da0806 | 36 | (memx->c.mthd && memx->c.mthd != mthd)) |
ff4b42c7 BS |
37 | memx_out(memx); |
38 | memcpy(&memx->c.data[memx->c.size], data, size * sizeof(data[0])); | |
39 | memx->c.size += size; | |
40 | memx->c.mthd = mthd; | |
41 | } | |
42 | ||
43 | int | |
21b13791 | 44 | nvkm_memx_init(struct nvkm_pmu *pmu, struct nvkm_memx **pmemx) |
ff4b42c7 | 45 | { |
bef002e8 | 46 | struct nvkm_device *device = pmu->subdev.device; |
21b13791 | 47 | struct nvkm_memx *memx; |
ff4b42c7 BS |
48 | u32 reply[2]; |
49 | int ret; | |
50 | ||
e2ca4e7d BS |
51 | ret = nvkm_pmu_send(pmu, reply, PROC_MEMX, MEMX_MSG_INFO, |
52 | MEMX_INFO_DATA, 0); | |
ff4b42c7 BS |
53 | if (ret) |
54 | return ret; | |
55 | ||
56 | memx = *pmemx = kzalloc(sizeof(*memx), GFP_KERNEL); | |
57 | if (!memx) | |
58 | return -ENOMEM; | |
ebb58dc2 | 59 | memx->pmu = pmu; |
ff4b42c7 BS |
60 | memx->base = reply[0]; |
61 | memx->size = reply[1]; | |
62 | ||
63 | /* acquire data segment access */ | |
64 | do { | |
bef002e8 BS |
65 | nvkm_wr32(device, 0x10a580, 0x00000003); |
66 | } while (nvkm_rd32(device, 0x10a580) != 0x00000003); | |
67 | nvkm_wr32(device, 0x10a1c0, 0x01000000 | memx->base); | |
ff4b42c7 BS |
68 | return 0; |
69 | } | |
70 | ||
71 | int | |
21b13791 | 72 | nvkm_memx_fini(struct nvkm_memx **pmemx, bool exec) |
ff4b42c7 | 73 | { |
21b13791 BS |
74 | struct nvkm_memx *memx = *pmemx; |
75 | struct nvkm_pmu *pmu = memx->pmu; | |
c19e329d BS |
76 | struct nvkm_subdev *subdev = &pmu->subdev; |
77 | struct nvkm_device *device = subdev->device; | |
ff4b42c7 BS |
78 | u32 finish, reply[2]; |
79 | ||
80 | /* flush the cache... */ | |
81 | memx_out(memx); | |
82 | ||
83 | /* release data segment access */ | |
bef002e8 BS |
84 | finish = nvkm_rd32(device, 0x10a1c0) & 0x00ffffff; |
85 | nvkm_wr32(device, 0x10a580, 0x00000000); | |
ff4b42c7 BS |
86 | |
87 | /* call MEMX process to execute the script, and wait for reply */ | |
88 | if (exec) { | |
e2ca4e7d BS |
89 | nvkm_pmu_send(pmu, reply, PROC_MEMX, MEMX_MSG_EXEC, |
90 | memx->base, finish); | |
ff4b42c7 BS |
91 | } |
92 | ||
c19e329d BS |
93 | nvkm_debug(subdev, "Exec took %uns, PMU_IN %08x\n", |
94 | reply[0], reply[1]); | |
ff4b42c7 BS |
95 | kfree(memx); |
96 | return 0; | |
97 | } | |
98 | ||
99 | void | |
21b13791 | 100 | nvkm_memx_wr32(struct nvkm_memx *memx, u32 addr, u32 data) |
ff4b42c7 | 101 | { |
c19e329d | 102 | nvkm_debug(&memx->pmu->subdev, "R[%06x] = %08x\n", addr, data); |
ff4b42c7 BS |
103 | memx_cmd(memx, MEMX_WR32, 2, (u32[]){ addr, data }); |
104 | } | |
105 | ||
106 | void | |
21b13791 | 107 | nvkm_memx_wait(struct nvkm_memx *memx, |
ff4b42c7 BS |
108 | u32 addr, u32 mask, u32 data, u32 nsec) |
109 | { | |
c19e329d BS |
110 | nvkm_debug(&memx->pmu->subdev, "R[%06x] & %08x == %08x, %d us\n", |
111 | addr, mask, data, nsec); | |
f67a8ff5 | 112 | memx_cmd(memx, MEMX_WAIT, 4, (u32[]){ addr, mask, data, nsec }); |
ff4b42c7 BS |
113 | memx_out(memx); /* fuc can't handle multiple */ |
114 | } | |
115 | ||
116 | void | |
21b13791 | 117 | nvkm_memx_nsec(struct nvkm_memx *memx, u32 nsec) |
ff4b42c7 | 118 | { |
c19e329d | 119 | nvkm_debug(&memx->pmu->subdev, " DELAY = %d ns\n", nsec); |
ff4b42c7 BS |
120 | memx_cmd(memx, MEMX_DELAY, 1, (u32[]){ nsec }); |
121 | memx_out(memx); /* fuc can't handle multiple */ | |
122 | } | |
123 | ||
e1a6f7da | 124 | void |
21b13791 | 125 | nvkm_memx_wait_vblank(struct nvkm_memx *memx) |
e1a6f7da | 126 | { |
c19e329d BS |
127 | struct nvkm_subdev *subdev = &memx->pmu->subdev; |
128 | struct nvkm_device *device = subdev->device; | |
e1a6f7da RS |
129 | u32 heads, x, y, px = 0; |
130 | int i, head_sync; | |
131 | ||
bef002e8 BS |
132 | if (device->chipset < 0xd0) { |
133 | heads = nvkm_rd32(device, 0x610050); | |
e1a6f7da RS |
134 | for (i = 0; i < 2; i++) { |
135 | /* Heuristic: sync to head with biggest resolution */ | |
136 | if (heads & (2 << (i << 3))) { | |
bef002e8 | 137 | x = nvkm_rd32(device, 0x610b40 + (0x540 * i)); |
e1a6f7da RS |
138 | y = (x & 0xffff0000) >> 16; |
139 | x &= 0x0000ffff; | |
140 | if ((x * y) > px) { | |
141 | px = (x * y); | |
142 | head_sync = i; | |
143 | } | |
144 | } | |
145 | } | |
146 | } | |
147 | ||
148 | if (px == 0) { | |
c19e329d | 149 | nvkm_debug(subdev, "WAIT VBLANK !NO ACTIVE HEAD\n"); |
e1a6f7da RS |
150 | return; |
151 | } | |
152 | ||
c19e329d | 153 | nvkm_debug(subdev, "WAIT VBLANK HEAD%d\n", head_sync); |
e1a6f7da RS |
154 | memx_cmd(memx, MEMX_VBLANK, 1, (u32[]){ head_sync }); |
155 | memx_out(memx); /* fuc can't handle multiple */ | |
156 | } | |
157 | ||
7f4b9616 | 158 | void |
21b13791 | 159 | nvkm_memx_train(struct nvkm_memx *memx) |
7f4b9616 | 160 | { |
c19e329d | 161 | nvkm_debug(&memx->pmu->subdev, " MEM TRAIN\n"); |
7f4b9616 RS |
162 | memx_cmd(memx, MEMX_TRAIN, 0, NULL); |
163 | } | |
164 | ||
165 | int | |
21b13791 | 166 | nvkm_memx_train_result(struct nvkm_pmu *pmu, u32 *res, int rsize) |
7f4b9616 | 167 | { |
bef002e8 | 168 | struct nvkm_device *device = pmu->subdev.device; |
7f4b9616 RS |
169 | u32 reply[2], base, size, i; |
170 | int ret; | |
171 | ||
e2ca4e7d BS |
172 | ret = nvkm_pmu_send(pmu, reply, PROC_MEMX, MEMX_MSG_INFO, |
173 | MEMX_INFO_TRAIN, 0); | |
7f4b9616 RS |
174 | if (ret) |
175 | return ret; | |
176 | ||
177 | base = reply[0]; | |
178 | size = reply[1] >> 2; | |
179 | if (size > rsize) | |
180 | return -ENOMEM; | |
181 | ||
182 | /* read the packet */ | |
bef002e8 | 183 | nvkm_wr32(device, 0x10a1c0, 0x02000000 | base); |
7f4b9616 RS |
184 | |
185 | for (i = 0; i < size; i++) | |
bef002e8 | 186 | res[i] = nvkm_rd32(device, 0x10a1c4); |
7f4b9616 RS |
187 | |
188 | return 0; | |
189 | } | |
190 | ||
d93e996a | 191 | void |
21b13791 | 192 | nvkm_memx_block(struct nvkm_memx *memx) |
d93e996a | 193 | { |
c19e329d | 194 | nvkm_debug(&memx->pmu->subdev, " HOST BLOCKED\n"); |
30da0806 | 195 | memx_cmd(memx, MEMX_ENTER, 0, NULL); |
d93e996a RS |
196 | } |
197 | ||
198 | void | |
21b13791 | 199 | nvkm_memx_unblock(struct nvkm_memx *memx) |
d93e996a | 200 | { |
c19e329d | 201 | nvkm_debug(&memx->pmu->subdev, " HOST UNBLOCKED\n"); |
30da0806 | 202 | memx_cmd(memx, MEMX_LEAVE, 0, NULL); |
d93e996a | 203 | } |
ff4b42c7 | 204 | #endif |