Commit | Line | Data |
---|---|---|
44b1e3bd IM |
1 | /* |
2 | * Copyright 2013 Ilia Mirkin | |
3 | * | |
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: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
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. | |
21 | */ | |
44b1e3bd | 22 | #include <engine/xtensa.h> |
c79a191b | 23 | #include <engine/fifo.h> |
44b1e3bd | 24 | |
c79a191b BS |
25 | static int |
26 | nvkm_xtensa_oclass_get(struct nvkm_oclass *oclass, int index) | |
44b1e3bd | 27 | { |
c79a191b BS |
28 | struct nvkm_xtensa *xtensa = nvkm_xtensa(oclass->engine); |
29 | int c = 0; | |
30 | ||
31 | while (xtensa->func->sclass[c].oclass) { | |
32 | if (c++ == index) { | |
33 | oclass->base = xtensa->func->sclass[index]; | |
34 | return index; | |
35 | } | |
36 | } | |
44b1e3bd | 37 | |
c79a191b | 38 | return c; |
44b1e3bd IM |
39 | } |
40 | ||
c79a191b BS |
41 | static int |
42 | nvkm_xtensa_cclass_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, | |
43 | int align, struct nvkm_gpuobj **pgpuobj) | |
44 | { | |
45 | return nvkm_gpuobj_new(object->engine->subdev.device, 0x10000, align, | |
46 | true, parent, pgpuobj); | |
47 | } | |
48 | ||
49 | static const struct nvkm_object_func | |
50 | nvkm_xtensa_cclass = { | |
51 | .bind = nvkm_xtensa_cclass_bind, | |
52 | }; | |
53 | ||
98b20c9a BS |
54 | static void |
55 | nvkm_xtensa_intr(struct nvkm_engine *engine) | |
44b1e3bd | 56 | { |
98b20c9a BS |
57 | struct nvkm_xtensa *xtensa = nvkm_xtensa(engine); |
58 | struct nvkm_subdev *subdev = &xtensa->engine.subdev; | |
59 | struct nvkm_device *device = subdev->device; | |
9ccdc760 BS |
60 | const u32 base = xtensa->addr; |
61 | u32 unk104 = nvkm_rd32(device, base + 0xd04); | |
62 | u32 intr = nvkm_rd32(device, base + 0xc20); | |
63 | u32 chan = nvkm_rd32(device, base + 0xc28); | |
64 | u32 unk10c = nvkm_rd32(device, base + 0xd0c); | |
44b1e3bd IM |
65 | |
66 | if (intr & 0x10) | |
7108bfe4 | 67 | nvkm_warn(subdev, "Watchdog interrupt, engine hung.\n"); |
9ccdc760 BS |
68 | nvkm_wr32(device, base + 0xc20, intr); |
69 | intr = nvkm_rd32(device, base + 0xc20); | |
44b1e3bd | 70 | if (unk104 == 0x10001 && unk10c == 0x200 && chan && !intr) { |
7108bfe4 | 71 | nvkm_debug(subdev, "Enabling FIFO_CTRL\n"); |
98b20c9a | 72 | nvkm_mask(device, xtensa->addr + 0xd94, 0, xtensa->func->fifo_val); |
44b1e3bd IM |
73 | } |
74 | } | |
75 | ||
98b20c9a BS |
76 | static int |
77 | nvkm_xtensa_fini(struct nvkm_engine *engine, bool suspend) | |
44b1e3bd | 78 | { |
98b20c9a BS |
79 | struct nvkm_xtensa *xtensa = nvkm_xtensa(engine); |
80 | struct nvkm_device *device = xtensa->engine.subdev.device; | |
81 | const u32 base = xtensa->addr; | |
44b1e3bd | 82 | |
98b20c9a BS |
83 | nvkm_wr32(device, base + 0xd84, 0); /* INTR_EN */ |
84 | nvkm_wr32(device, base + 0xd94, 0); /* FIFO_CTRL */ | |
44b1e3bd | 85 | |
98b20c9a BS |
86 | if (!suspend) |
87 | nvkm_memory_del(&xtensa->gpu_fw); | |
44b1e3bd IM |
88 | return 0; |
89 | } | |
90 | ||
98b20c9a BS |
91 | static int |
92 | nvkm_xtensa_init(struct nvkm_engine *engine) | |
44b1e3bd | 93 | { |
98b20c9a | 94 | struct nvkm_xtensa *xtensa = nvkm_xtensa(engine); |
7108bfe4 BS |
95 | struct nvkm_subdev *subdev = &xtensa->engine.subdev; |
96 | struct nvkm_device *device = subdev->device; | |
9ccdc760 | 97 | const u32 base = xtensa->addr; |
44b1e3bd IM |
98 | const struct firmware *fw; |
99 | char name[32]; | |
100 | int i, ret; | |
faf46898 | 101 | u64 addr, size; |
44b1e3bd IM |
102 | u32 tmp; |
103 | ||
44b1e3bd IM |
104 | if (!xtensa->gpu_fw) { |
105 | snprintf(name, sizeof(name), "nouveau/nv84_xuc%03x", | |
106 | xtensa->addr >> 12); | |
107 | ||
420b9469 | 108 | ret = request_firmware(&fw, name, nv_device_base(device)); |
44b1e3bd | 109 | if (ret) { |
7108bfe4 | 110 | nvkm_warn(subdev, "unable to load firmware %s\n", name); |
44b1e3bd IM |
111 | return ret; |
112 | } | |
113 | ||
bfcd92a0 | 114 | if (fw->size > 0x40000) { |
7108bfe4 | 115 | nvkm_warn(subdev, "firmware %s too large\n", name); |
bfcd92a0 IM |
116 | release_firmware(fw); |
117 | return -EINVAL; | |
118 | } | |
119 | ||
faf46898 BS |
120 | ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, |
121 | 0x40000, 0x1000, false, | |
5025407b | 122 | &xtensa->gpu_fw); |
44b1e3bd IM |
123 | if (ret) { |
124 | release_firmware(fw); | |
125 | return ret; | |
126 | } | |
127 | ||
edb1dc51 | 128 | nvkm_kmap(xtensa->gpu_fw); |
44b1e3bd | 129 | for (i = 0; i < fw->size / 4; i++) |
edb1dc51 BS |
130 | nvkm_wo32(xtensa->gpu_fw, i * 4, *((u32 *)fw->data + i)); |
131 | nvkm_done(xtensa->gpu_fw); | |
44b1e3bd IM |
132 | release_firmware(fw); |
133 | } | |
134 | ||
faf46898 BS |
135 | addr = nvkm_memory_addr(xtensa->gpu_fw); |
136 | size = nvkm_memory_size(xtensa->gpu_fw); | |
137 | ||
9ccdc760 BS |
138 | nvkm_wr32(device, base + 0xd10, 0x1fffffff); /* ?? */ |
139 | nvkm_wr32(device, base + 0xd08, 0x0fffffff); /* ?? */ | |
44b1e3bd | 140 | |
98b20c9a | 141 | nvkm_wr32(device, base + 0xd28, xtensa->func->unkd28); /* ?? */ |
9ccdc760 BS |
142 | nvkm_wr32(device, base + 0xc20, 0x3f); /* INTR */ |
143 | nvkm_wr32(device, base + 0xd84, 0x3f); /* INTR_EN */ | |
44b1e3bd | 144 | |
faf46898 | 145 | nvkm_wr32(device, base + 0xcc0, addr >> 8); /* XT_REGION_BASE */ |
9ccdc760 | 146 | nvkm_wr32(device, base + 0xcc4, 0x1c); /* XT_REGION_SETUP */ |
faf46898 | 147 | nvkm_wr32(device, base + 0xcc8, size >> 8); /* XT_REGION_LIMIT */ |
44b1e3bd | 148 | |
2ef770f7 | 149 | tmp = nvkm_rd32(device, 0x0); |
9ccdc760 | 150 | nvkm_wr32(device, base + 0xde0, tmp); /* SCRATCH_H2X */ |
44b1e3bd | 151 | |
9ccdc760 | 152 | nvkm_wr32(device, base + 0xce8, 0xf); /* XT_REGION_SETUP */ |
44b1e3bd | 153 | |
9ccdc760 BS |
154 | nvkm_wr32(device, base + 0xc20, 0x3f); /* INTR */ |
155 | nvkm_wr32(device, base + 0xd84, 0x3f); /* INTR_EN */ | |
44b1e3bd IM |
156 | return 0; |
157 | } | |
158 | ||
98b20c9a BS |
159 | static void * |
160 | nvkm_xtensa_dtor(struct nvkm_engine *engine) | |
44b1e3bd | 161 | { |
98b20c9a BS |
162 | return nvkm_xtensa(engine); |
163 | } | |
44b1e3bd | 164 | |
98b20c9a BS |
165 | static const struct nvkm_engine_func |
166 | nvkm_xtensa = { | |
167 | .dtor = nvkm_xtensa_dtor, | |
168 | .init = nvkm_xtensa_init, | |
169 | .fini = nvkm_xtensa_fini, | |
170 | .intr = nvkm_xtensa_intr, | |
171 | .fifo.sclass = nvkm_xtensa_oclass_get, | |
172 | .cclass = &nvkm_xtensa_cclass, | |
173 | }; | |
44b1e3bd | 174 | |
98b20c9a BS |
175 | int |
176 | nvkm_xtensa_new_(const struct nvkm_xtensa_func *func, | |
177 | struct nvkm_device *device, int index, bool enable, | |
178 | u32 addr, struct nvkm_engine **pengine) | |
179 | { | |
180 | struct nvkm_xtensa *xtensa; | |
181 | ||
182 | if (!(xtensa = kzalloc(sizeof(*xtensa), GFP_KERNEL))) | |
183 | return -ENOMEM; | |
184 | xtensa->func = func; | |
185 | xtensa->addr = addr; | |
186 | *pengine = &xtensa->engine; | |
44b1e3bd | 187 | |
98b20c9a BS |
188 | return nvkm_engine_ctor(&nvkm_xtensa, device, index, func->pmc_enable, |
189 | enable, &xtensa->engine); | |
44b1e3bd | 190 | } |