1/*	$NetBSD: nouveau_nvkm_subdev_bar_nv50.c,v 1.3 2021/12/18 23:45:38 riastradh Exp $	*/
2
3/*
4 * Copyright 2012 Red Hat Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors: Ben Skeggs
25 */
26#include <sys/cdefs.h>
27__KERNEL_RCSID(0, "$NetBSD: nouveau_nvkm_subdev_bar_nv50.c,v 1.3 2021/12/18 23:45:38 riastradh Exp $");
28
29#include "nv50.h"
30
31#include <core/gpuobj.h>
32#include <subdev/fb.h>
33#include <subdev/mmu.h>
34#include <subdev/timer.h>
35
36static void
37nv50_bar_flush(struct nvkm_bar *base)
38{
39	struct nv50_bar *bar = nv50_bar(base);
40	struct nvkm_device *device = bar->base.subdev.device;
41	unsigned long flags;
42	spin_lock_irqsave(&bar->base.lock, flags);
43	nvkm_wr32(device, 0x00330c, 0x00000001);
44	nvkm_msec(device, 2000,
45		if (!(nvkm_rd32(device, 0x00330c) & 0x00000002))
46			break;
47	);
48	spin_unlock_irqrestore(&bar->base.lock, flags);
49}
50
51struct nvkm_vmm *
52nv50_bar_bar1_vmm(struct nvkm_bar *base)
53{
54	return nv50_bar(base)->bar1_vmm;
55}
56
57void
58nv50_bar_bar1_wait(struct nvkm_bar *base)
59{
60	nvkm_bar_flush(base);
61}
62
63void
64nv50_bar_bar1_fini(struct nvkm_bar *bar)
65{
66	nvkm_wr32(bar->subdev.device, 0x001708, 0x00000000);
67}
68
69void
70nv50_bar_bar1_init(struct nvkm_bar *base)
71{
72	struct nvkm_device *device = base->subdev.device;
73	struct nv50_bar *bar = nv50_bar(base);
74	nvkm_wr32(device, 0x001708, 0x80000000 | bar->bar1->node->offset >> 4);
75}
76
77struct nvkm_vmm *
78nv50_bar_bar2_vmm(struct nvkm_bar *base)
79{
80	return nv50_bar(base)->bar2_vmm;
81}
82
83void
84nv50_bar_bar2_fini(struct nvkm_bar *bar)
85{
86	nvkm_wr32(bar->subdev.device, 0x00170c, 0x00000000);
87}
88
89void
90nv50_bar_bar2_init(struct nvkm_bar *base)
91{
92	struct nvkm_device *device = base->subdev.device;
93	struct nv50_bar *bar = nv50_bar(base);
94	nvkm_wr32(device, 0x001704, 0x00000000 | bar->mem->addr >> 12);
95	nvkm_wr32(device, 0x001704, 0x40000000 | bar->mem->addr >> 12);
96	nvkm_wr32(device, 0x00170c, 0x80000000 | bar->bar2->node->offset >> 4);
97}
98
99void
100nv50_bar_init(struct nvkm_bar *base)
101{
102	struct nv50_bar *bar = nv50_bar(base);
103	struct nvkm_device *device = bar->base.subdev.device;
104	int i;
105
106	for (i = 0; i < 8; i++)
107		nvkm_wr32(device, 0x001900 + (i * 4), 0x00000000);
108}
109
110int
111nv50_bar_oneinit(struct nvkm_bar *base)
112{
113	struct nv50_bar *bar = nv50_bar(base);
114	struct nvkm_device *device = bar->base.subdev.device;
115	static struct lock_class_key bar1_lock;
116	static struct lock_class_key bar2_lock;
117	u64 start, limit, size;
118	int ret;
119
120	ret = nvkm_gpuobj_new(device, 0x20000, 0, false, NULL, &bar->mem);
121	if (ret)
122		return ret;
123
124	ret = nvkm_gpuobj_new(device, bar->pgd_addr, 0, false, bar->mem,
125			      &bar->pad);
126	if (ret)
127		return ret;
128
129	ret = nvkm_gpuobj_new(device, 0x4000, 0, false, bar->mem, &bar->pgd);
130	if (ret)
131		return ret;
132
133	/* BAR2 */
134	start = 0x0100000000ULL;
135	size = device->func->resource_size(device, 3);
136	if (!size)
137		return -ENOMEM;
138	limit = start + size;
139
140	ret = nvkm_vmm_new(device, start, limit-- - start, NULL, 0,
141			   &bar2_lock, "bar2", &bar->bar2_vmm);
142	if (ret)
143		return ret;
144
145	atomic_inc(&bar->bar2_vmm->engref[NVKM_SUBDEV_BAR]);
146	bar->bar2_vmm->debug = bar->base.subdev.debug;
147
148	ret = nvkm_vmm_boot(bar->bar2_vmm);
149	if (ret)
150		return ret;
151
152	ret = nvkm_vmm_join(bar->bar2_vmm, bar->mem->memory);
153	if (ret)
154		return ret;
155
156	ret = nvkm_gpuobj_new(device, 24, 16, false, bar->mem, &bar->bar2);
157	if (ret)
158		return ret;
159
160	nvkm_kmap(bar->bar2);
161	nvkm_wo32(bar->bar2, 0x00, 0x7fc00000);
162	nvkm_wo32(bar->bar2, 0x04, lower_32_bits(limit));
163	nvkm_wo32(bar->bar2, 0x08, lower_32_bits(start));
164	nvkm_wo32(bar->bar2, 0x0c, upper_32_bits(limit) << 24 |
165				   upper_32_bits(start));
166	nvkm_wo32(bar->bar2, 0x10, 0x00000000);
167	nvkm_wo32(bar->bar2, 0x14, 0x00000000);
168	nvkm_done(bar->bar2);
169
170	bar->base.subdev.oneinit = true;
171	nvkm_bar_bar2_init(device);
172
173	/* BAR1 */
174	start = 0x0000000000ULL;
175	size = device->func->resource_size(device, 1);
176	if (!size)
177		return -ENOMEM;
178	limit = start + size;
179
180	ret = nvkm_vmm_new(device, start, limit-- - start, NULL, 0,
181			   &bar1_lock, "bar1", &bar->bar1_vmm);
182	if (ret)
183		return ret;
184
185	atomic_inc(&bar->bar1_vmm->engref[NVKM_SUBDEV_BAR]);
186	bar->bar1_vmm->debug = bar->base.subdev.debug;
187
188	ret = nvkm_vmm_join(bar->bar1_vmm, bar->mem->memory);
189	if (ret)
190		return ret;
191
192	ret = nvkm_gpuobj_new(device, 24, 16, false, bar->mem, &bar->bar1);
193	if (ret)
194		return ret;
195
196	nvkm_kmap(bar->bar1);
197	nvkm_wo32(bar->bar1, 0x00, 0x7fc00000);
198	nvkm_wo32(bar->bar1, 0x04, lower_32_bits(limit));
199	nvkm_wo32(bar->bar1, 0x08, lower_32_bits(start));
200	nvkm_wo32(bar->bar1, 0x0c, upper_32_bits(limit) << 24 |
201				   upper_32_bits(start));
202	nvkm_wo32(bar->bar1, 0x10, 0x00000000);
203	nvkm_wo32(bar->bar1, 0x14, 0x00000000);
204	nvkm_done(bar->bar1);
205	return 0;
206}
207
208void *
209nv50_bar_dtor(struct nvkm_bar *base)
210{
211	struct nv50_bar *bar = nv50_bar(base);
212	if (bar->mem) {
213		nvkm_gpuobj_del(&bar->bar1);
214		nvkm_vmm_part(bar->bar1_vmm, bar->mem->memory);
215		nvkm_vmm_unref(&bar->bar1_vmm);
216		nvkm_gpuobj_del(&bar->bar2);
217		nvkm_vmm_part(bar->bar2_vmm, bar->mem->memory);
218		nvkm_vmm_unref(&bar->bar2_vmm);
219		nvkm_gpuobj_del(&bar->pgd);
220		nvkm_gpuobj_del(&bar->pad);
221		nvkm_gpuobj_del(&bar->mem);
222	}
223	return bar;
224}
225
226int
227nv50_bar_new_(const struct nvkm_bar_func *func, struct nvkm_device *device,
228	      int index, u32 pgd_addr, struct nvkm_bar **pbar)
229{
230	struct nv50_bar *bar;
231	if (!(bar = kzalloc(sizeof(*bar), GFP_KERNEL)))
232		return -ENOMEM;
233	nvkm_bar_ctor(func, device, index, &bar->base);
234	bar->pgd_addr = pgd_addr;
235	*pbar = &bar->base;
236	return 0;
237}
238
239static const struct nvkm_bar_func
240nv50_bar_func = {
241	.dtor = nv50_bar_dtor,
242	.oneinit = nv50_bar_oneinit,
243	.init = nv50_bar_init,
244	.bar1.init = nv50_bar_bar1_init,
245	.bar1.fini = nv50_bar_bar1_fini,
246	.bar1.wait = nv50_bar_bar1_wait,
247	.bar1.vmm = nv50_bar_bar1_vmm,
248	.bar2.init = nv50_bar_bar2_init,
249	.bar2.fini = nv50_bar_bar2_fini,
250	.bar2.wait = nv50_bar_bar1_wait,
251	.bar2.vmm = nv50_bar_bar2_vmm,
252	.flush = nv50_bar_flush,
253};
254
255int
256nv50_bar_new(struct nvkm_device *device, int index, struct nvkm_bar **pbar)
257{
258	return nv50_bar_new_(&nv50_bar_func, device, index, 0x1400, pbar);
259}
260