2 * Copyright 2012 Red Hat Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
22 #include <engine/falcon.h>
24 #include <subdev/timer.h>
27 nvkm_falcon_intr(struct nvkm_subdev
*subdev
)
29 struct nvkm_falcon
*falcon
= (void *)subdev
;
30 struct nvkm_device
*device
= falcon
->engine
.subdev
.device
;
31 const u32 base
= falcon
->addr
;
32 u32 dispatch
= nvkm_rd32(device
, base
+ 0x01c);
33 u32 intr
= nvkm_rd32(device
, base
+ 0x008) & dispatch
& ~(dispatch
>> 16);
35 if (intr
& 0x00000010) {
36 nvkm_debug(subdev
, "ucode halted\n");
37 nvkm_wr32(device
, base
+ 0x004, 0x00000010);
42 nvkm_error(subdev
, "intr %08x\n", intr
);
43 nvkm_wr32(device
, base
+ 0x004, intr
);
48 vmemdup(const void *src
, size_t len
)
50 void *p
= vmalloc(len
);
58 _nvkm_falcon_init(struct nvkm_object
*object
)
60 struct nvkm_falcon
*falcon
= (void *)object
;
61 struct nvkm_subdev
*subdev
= &falcon
->engine
.subdev
;
62 struct nvkm_device
*device
= subdev
->device
;
63 const struct firmware
*fw
;
64 char name
[32] = "internal";
65 const u32 base
= falcon
->addr
;
69 /* enable engine, and determine its capabilities */
70 ret
= nvkm_engine_init(&falcon
->engine
);
74 if (device
->chipset
< 0xa3 ||
75 device
->chipset
== 0xaa || device
->chipset
== 0xac) {
77 falcon
->secret
= (falcon
->addr
== 0x087000) ? 1 : 0;
79 caps
= nvkm_rd32(device
, base
+ 0x12c);
80 falcon
->version
= (caps
& 0x0000000f);
81 falcon
->secret
= (caps
& 0x00000030) >> 4;
84 caps
= nvkm_rd32(device
, base
+ 0x108);
85 falcon
->code
.limit
= (caps
& 0x000001ff) << 8;
86 falcon
->data
.limit
= (caps
& 0x0003fe00) >> 1;
88 nvkm_debug(subdev
, "falcon version: %d\n", falcon
->version
);
89 nvkm_debug(subdev
, "secret level: %d\n", falcon
->secret
);
90 nvkm_debug(subdev
, "code limit: %d\n", falcon
->code
.limit
);
91 nvkm_debug(subdev
, "data limit: %d\n", falcon
->data
.limit
);
93 /* wait for 'uc halted' to be signalled before continuing */
94 if (falcon
->secret
&& falcon
->version
< 4) {
95 if (!falcon
->version
) {
96 nvkm_msec(device
, 2000,
97 if (nvkm_rd32(device
, base
+ 0x008) & 0x00000010)
101 nvkm_msec(device
, 2000,
102 if (!(nvkm_rd32(device
, base
+ 0x180) & 0x80000000))
106 nvkm_wr32(device
, base
+ 0x004, 0x00000010);
109 /* disable all interrupts */
110 nvkm_wr32(device
, base
+ 0x014, 0xffffffff);
112 /* no default ucode provided by the engine implementation, try and
113 * locate a "self-bootstrapping" firmware image for the engine
115 if (!falcon
->code
.data
) {
116 snprintf(name
, sizeof(name
), "nouveau/nv%02x_fuc%03x",
117 device
->chipset
, falcon
->addr
>> 12);
119 ret
= request_firmware(&fw
, name
, nv_device_base(device
));
121 falcon
->code
.data
= vmemdup(fw
->data
, fw
->size
);
122 falcon
->code
.size
= fw
->size
;
123 falcon
->data
.data
= NULL
;
124 falcon
->data
.size
= 0;
125 release_firmware(fw
);
128 falcon
->external
= true;
131 /* next step is to try and load "static code/data segment" firmware
132 * images for the engine
134 if (!falcon
->code
.data
) {
135 snprintf(name
, sizeof(name
), "nouveau/nv%02x_fuc%03xd",
136 device
->chipset
, falcon
->addr
>> 12);
138 ret
= request_firmware(&fw
, name
, nv_device_base(device
));
140 nvkm_error(subdev
, "unable to load firmware data\n");
144 falcon
->data
.data
= vmemdup(fw
->data
, fw
->size
);
145 falcon
->data
.size
= fw
->size
;
146 release_firmware(fw
);
147 if (!falcon
->data
.data
)
150 snprintf(name
, sizeof(name
), "nouveau/nv%02x_fuc%03xc",
151 device
->chipset
, falcon
->addr
>> 12);
153 ret
= request_firmware(&fw
, name
, nv_device_base(device
));
155 nvkm_error(subdev
, "unable to load firmware code\n");
159 falcon
->code
.data
= vmemdup(fw
->data
, fw
->size
);
160 falcon
->code
.size
= fw
->size
;
161 release_firmware(fw
);
162 if (!falcon
->code
.data
)
166 nvkm_debug(subdev
, "firmware: %s (%s)\n", name
, falcon
->data
.data
?
167 "static code/data segments" : "self-bootstrapping");
169 /* ensure any "self-bootstrapping" firmware image is in vram */
170 if (!falcon
->data
.data
&& !falcon
->core
) {
171 ret
= nvkm_gpuobj_new(object
->parent
, NULL
, falcon
->code
.size
,
172 256, 0, &falcon
->core
);
174 nvkm_error(subdev
, "core allocation failed, %d\n", ret
);
178 nvkm_kmap(falcon
->core
);
179 for (i
= 0; i
< falcon
->code
.size
; i
+= 4)
180 nvkm_wo32(falcon
->core
, i
, falcon
->code
.data
[i
/ 4]);
181 nvkm_done(falcon
->core
);
184 /* upload firmware bootloader (or the full code segments) */
186 if (device
->card_type
< NV_C0
)
187 nvkm_wr32(device
, base
+ 0x618, 0x04000000);
189 nvkm_wr32(device
, base
+ 0x618, 0x00000114);
190 nvkm_wr32(device
, base
+ 0x11c, 0);
191 nvkm_wr32(device
, base
+ 0x110, falcon
->core
->addr
>> 8);
192 nvkm_wr32(device
, base
+ 0x114, 0);
193 nvkm_wr32(device
, base
+ 0x118, 0x00006610);
195 if (falcon
->code
.size
> falcon
->code
.limit
||
196 falcon
->data
.size
> falcon
->data
.limit
) {
197 nvkm_error(subdev
, "ucode exceeds falcon limit(s)\n");
201 if (falcon
->version
< 3) {
202 nvkm_wr32(device
, base
+ 0xff8, 0x00100000);
203 for (i
= 0; i
< falcon
->code
.size
/ 4; i
++)
204 nvkm_wr32(device
, base
+ 0xff4, falcon
->code
.data
[i
]);
206 nvkm_wr32(device
, base
+ 0x180, 0x01000000);
207 for (i
= 0; i
< falcon
->code
.size
/ 4; i
++) {
209 nvkm_wr32(device
, base
+ 0x188, i
>> 6);
210 nvkm_wr32(device
, base
+ 0x184, falcon
->code
.data
[i
]);
215 /* upload data segment (if necessary), zeroing the remainder */
216 if (falcon
->version
< 3) {
217 nvkm_wr32(device
, base
+ 0xff8, 0x00000000);
218 for (i
= 0; !falcon
->core
&& i
< falcon
->data
.size
/ 4; i
++)
219 nvkm_wr32(device
, base
+ 0xff4, falcon
->data
.data
[i
]);
220 for (; i
< falcon
->data
.limit
; i
+= 4)
221 nvkm_wr32(device
, base
+ 0xff4, 0x00000000);
223 nvkm_wr32(device
, base
+ 0x1c0, 0x01000000);
224 for (i
= 0; !falcon
->core
&& i
< falcon
->data
.size
/ 4; i
++)
225 nvkm_wr32(device
, base
+ 0x1c4, falcon
->data
.data
[i
]);
226 for (; i
< falcon
->data
.limit
/ 4; i
++)
227 nvkm_wr32(device
, base
+ 0x1c4, 0x00000000);
230 /* start it running */
231 nvkm_wr32(device
, base
+ 0x10c, 0x00000001); /* BLOCK_ON_FIFO */
232 nvkm_wr32(device
, base
+ 0x104, 0x00000000); /* ENTRY */
233 nvkm_wr32(device
, base
+ 0x100, 0x00000002); /* TRIGGER */
234 nvkm_wr32(device
, base
+ 0x048, 0x00000003); /* FIFO | CHSW */
239 _nvkm_falcon_fini(struct nvkm_object
*object
, bool suspend
)
241 struct nvkm_falcon
*falcon
= (void *)object
;
242 struct nvkm_device
*device
= falcon
->engine
.subdev
.device
;
243 const u32 base
= falcon
->addr
;
246 nvkm_gpuobj_ref(NULL
, &falcon
->core
);
247 if (falcon
->external
) {
248 vfree(falcon
->data
.data
);
249 vfree(falcon
->code
.data
);
250 falcon
->code
.data
= NULL
;
254 nvkm_mask(device
, base
+ 0x048, 0x00000003, 0x00000000);
255 nvkm_wr32(device
, base
+ 0x014, 0xffffffff);
257 return nvkm_engine_fini(&falcon
->engine
, suspend
);
261 nvkm_falcon_create_(struct nvkm_object
*parent
, struct nvkm_object
*engine
,
262 struct nvkm_oclass
*oclass
, u32 addr
, bool enable
,
263 const char *iname
, const char *fname
,
264 int length
, void **pobject
)
266 struct nvkm_falcon
*falcon
;
269 ret
= nvkm_engine_create_(parent
, engine
, oclass
, enable
, iname
,
270 fname
, length
, pobject
);
This page took 0.051256 seconds and 5 git commands to generate.