1/* $NetBSD: nouveau_subdev_bar_base.c,v 1.5 2016/04/12 15:12:12 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
27#include <sys/cdefs.h>
28__KERNEL_RCSID(0, "$NetBSD: nouveau_subdev_bar_base.c,v 1.5 2016/04/12 15:12:12 riastradh Exp $");
29
30#include <core/object.h>
31
32#include <subdev/fb.h>
33#include <subdev/vm.h>
34
35#include "priv.h"
36
37struct nouveau_barobj {
38 struct nouveau_object base;
39 struct nouveau_vma vma;
40#ifdef __NetBSD__
41 bus_space_tag_t iomemt;
42 bus_space_handle_t iomemh;
43#else
44 void __iomem *iomem;
45#endif
46};
47
48static int
49nouveau_barobj_ctor(struct nouveau_object *parent,
50 struct nouveau_object *engine,
51 struct nouveau_oclass *oclass, void *mem, u32 size,
52 struct nouveau_object **pobject)
53{
54 struct nouveau_bar *bar = (void *)engine;
55 struct nouveau_barobj *barobj;
56 int ret;
57
58 ret = nouveau_object_create(parent, engine, oclass, 0, &barobj);
59 *pobject = nv_object(barobj);
60 if (ret)
61 return ret;
62
63 ret = bar->kmap(bar, mem, NV_MEM_ACCESS_RW, &barobj->vma);
64 if (ret)
65 return ret;
66
67#ifdef __NetBSD__
68 {
69 /* Yes, truncation is really intended here. */
70 uint32_t offset = barobj->vma.offset & 0xffffffffUL;
71
72 KASSERTMSG(offset < bar->iomemsz,
73 "bar object vma exceeds range: %"PRIx32" > %"PRIxMAX,
74 offset, (uintmax_t)bar->iomemsz);
75
76 barobj->iomemt = bar->iomemt;
77 /* XXX errno NetBSD->Linux */
78 ret = -bus_space_subregion(bar->iomemt, bar->iomemh, offset,
79 bar->iomemsz - offset, &barobj->iomemh);
80 if (ret)
81 return ret;
82 }
83#else
84 barobj->iomem = bar->iomem + (u32)barobj->vma.offset;
85#endif
86 return 0;
87}
88
89static void
90nouveau_barobj_dtor(struct nouveau_object *object)
91{
92 struct nouveau_bar *bar = (void *)object->engine;
93 struct nouveau_barobj *barobj = (void *)object;
94 if (barobj->vma.node)
95 bar->unmap(bar, &barobj->vma);
96 nouveau_object_destroy(&barobj->base);
97}
98
99static u32
100nouveau_barobj_rd32(struct nouveau_object *object, u64 addr)
101{
102 struct nouveau_barobj *barobj = (void *)object;
103#ifdef __NetBSD__
104 return bus_space_read_4(barobj->iomemt, barobj->iomemh, addr);
105#else
106 return ioread32_native(barobj->iomem + addr);
107#endif
108}
109
110static void
111nouveau_barobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
112{
113 struct nouveau_barobj *barobj = (void *)object;
114#ifdef __NetBSD__
115 bus_space_write_4(barobj->iomemt, barobj->iomemh, addr, data);
116#else
117 iowrite32_native(data, barobj->iomem + addr);
118#endif
119}
120
121static struct nouveau_oclass
122nouveau_barobj_oclass = {
123 .ofuncs = &(struct nouveau_ofuncs) {
124 .ctor = nouveau_barobj_ctor,
125 .dtor = nouveau_barobj_dtor,
126 .init = nouveau_object_init,
127 .fini = nouveau_object_fini,
128 .rd32 = nouveau_barobj_rd32,
129 .wr32 = nouveau_barobj_wr32,
130 },
131};
132
133int
134nouveau_bar_alloc(struct nouveau_bar *bar, struct nouveau_object *parent,
135 struct nouveau_mem *mem, struct nouveau_object **pobject)
136{
137 struct nouveau_object *engine = nv_object(bar);
138 return nouveau_object_ctor(parent, engine, &nouveau_barobj_oclass,
139 mem, 0, pobject);
140}
141
142int
143nouveau_bar_create_(struct nouveau_object *parent,
144 struct nouveau_object *engine,
145 struct nouveau_oclass *oclass, int length, void **pobject)
146{
147 struct nouveau_device *device = nv_device(parent);
148 struct nouveau_bar *bar;
149 int ret;
150
151 ret = nouveau_subdev_create_(parent, engine, oclass, 0, "BARCTL",
152 "bar", length, pobject);
153 bar = *pobject;
154 if (ret)
155 return ret;
156
157#ifdef __NetBSD__
158 if (nv_device_resource_len(device, 3) != 0) {
159 bar->iomemt = nv_device_resource_tag(device, 3);
160 bar->iomemsz = nv_device_resource_len(device, 3);
161 if (bus_space_map(bar->iomemt, nv_device_resource_start(device, 3),
162 bar->iomemsz, 0, &bar->iomemh))
163 bar->iomemsz = 0; /* XXX Fail? */
164 }
165#else
166 if (nv_device_resource_len(device, 3) != 0)
167 bar->iomem = ioremap(nv_device_resource_start(device, 3),
168 nv_device_resource_len(device, 3));
169#endif
170 return 0;
171}
172
173void
174nouveau_bar_destroy(struct nouveau_bar *bar)
175{
176#ifdef __NetBSD__
177 if (bar->iomemsz)
178 bus_space_unmap(bar->iomemt, bar->iomemh, bar->iomemsz);
179#else
180 if (bar->iomem)
181 iounmap(bar->iomem);
182#endif
183 nouveau_subdev_destroy(&bar->base);
184}
185
186void
187_nouveau_bar_dtor(struct nouveau_object *object)
188{
189 struct nouveau_bar *bar = (void *)object;
190 nouveau_bar_destroy(bar);
191}
192