dev-arm: Add a VExpress_GEM5_V2 platform with GICv3 support
[gem5.git] / src / dev / arm / gpu_nomali.cc
1 /*
2 * Copyright (c) 2014-2016 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Andreas Sandberg
38 */
39
40 #include "dev/arm/gpu_nomali.hh"
41
42 #include "debug/NoMali.hh"
43 #include "dev/arm/base_gic.hh"
44 #include "dev/arm/realview.hh"
45 #include "enums/MemoryMode.hh"
46 #include "mem/packet_access.hh"
47 #include "nomali/lib/mali_midg_regmap.h"
48 #include "params/CustomNoMaliGpu.hh"
49 #include "params/NoMaliGpu.hh"
50
51 static const std::map<Enums::NoMaliGpuType, nomali_gpu_type_t> gpuTypeMap{
52 { Enums::T60x, NOMALI_GPU_T60X },
53 { Enums::T62x, NOMALI_GPU_T62X },
54 { Enums::T760, NOMALI_GPU_T760 },
55 };
56
57 NoMaliGpu::NoMaliGpu(const NoMaliGpuParams *p)
58 : PioDevice(p),
59 pioAddr(p->pio_addr),
60 platform(p->platform),
61 interruptMap{
62 { NOMALI_INT_GPU, p->int_gpu },
63 { NOMALI_INT_JOB, p->int_job },
64 { NOMALI_INT_MMU, p->int_mmu },
65 }
66 {
67 if (nomali_api_version() != NOMALI_API_VERSION)
68 panic("NoMali library API mismatch!\n");
69
70 /* Setup the GPU configuration based on our param struct */
71 nomali_config_t cfg;
72 memset(&cfg, 0, sizeof(cfg));
73
74 const auto it_gpu(gpuTypeMap.find(p->gpu_type));
75 if (it_gpu == gpuTypeMap.end()) {
76 fatal("Unrecognized GPU type: %s (%i)\n",
77 Enums::NoMaliGpuTypeStrings[p->gpu_type], p->gpu_type);
78 }
79 cfg.type = it_gpu->second;
80
81 cfg.ver_maj = p->ver_maj;
82 cfg.ver_min = p->ver_min;
83 cfg.ver_status = p->ver_status;
84
85 panicOnErr(
86 nomali_create(&nomali, &cfg),
87 "Failed to instantiate NoMali");
88
89
90 /* Setup an interrupt callback */
91 nomali_callback_t cbk_int;
92 cbk_int.type = NOMALI_CALLBACK_INT;
93 cbk_int.usr = (void *)this;
94 cbk_int.func.interrupt = NoMaliGpu::_interrupt;
95 setCallback(cbk_int);
96
97 /* Setup a reset callback */
98 nomali_callback_t cbk_rst;
99 cbk_rst.type = NOMALI_CALLBACK_RESET;
100 cbk_rst.usr = (void *)this;
101 cbk_rst.func.reset = NoMaliGpu::_reset;
102 setCallback(cbk_rst);
103
104 panicOnErr(
105 nomali_get_info(nomali, &nomaliInfo),
106 "Failed to get NoMali information struct");
107 }
108
109 NoMaliGpu::~NoMaliGpu()
110 {
111 nomali_destroy(nomali);
112 }
113
114
115 void
116 NoMaliGpu::init()
117 {
118 PioDevice::init();
119
120 /* Reset the GPU here since the reset callback won't have been
121 * installed when the GPU was reset at instantiation time.
122 */
123 reset();
124 }
125
126 void
127 NoMaliGpu::serialize(CheckpointOut &cp) const
128 {
129 std::vector<uint32_t> regs(nomaliInfo.reg_size >> 2);
130
131 for (int i = 0; i < nomaliInfo.reg_size; i += 4)
132 regs[i >> 2] = readRegRaw(i);
133
134 SERIALIZE_CONTAINER(regs);
135 }
136
137 void
138 NoMaliGpu::unserialize(CheckpointIn &cp)
139 {
140 std::vector<uint32_t> regs(nomaliInfo.reg_size >> 2);
141
142 UNSERIALIZE_CONTAINER(regs);
143
144 for (int i = 0; i < nomaliInfo.reg_size; i += 4)
145 writeRegRaw(i, regs[i >> 2]);
146 }
147
148 Tick
149 NoMaliGpu::read(PacketPtr pkt)
150 {
151 assert(pkt->getAddr() >= pioAddr);
152 const Addr addr(pkt->getAddr() - pioAddr);
153 const unsigned size(pkt->getSize());
154
155 if (addr + size >= nomaliInfo.reg_size)
156 panic("GPU register '0x%x' out of range!\n", addr);
157
158 if (size != 4)
159 panic("Unexpected GPU register read size: %i\n", size);
160 else if (addr & 0x3)
161 panic("Unaligned GPU read: %i\n", size);
162
163 pkt->setLE<uint32_t>(readReg(addr));
164 pkt->makeResponse();
165
166 return 0;
167 }
168
169 Tick
170 NoMaliGpu::write(PacketPtr pkt)
171 {
172 assert(pkt->getAddr() >= pioAddr);
173 const Addr addr(pkt->getAddr() - pioAddr);
174 const unsigned size(pkt->getSize());
175
176 if (addr + size >= nomaliInfo.reg_size)
177 panic("GPU register '0x%x' out of range!\n", addr);
178
179 if (size != 4)
180 panic("Unexpected GPU register write size: %i\n", size);
181 else if (addr & 0x3)
182 panic("Unaligned GPU write: %i\n", size);
183
184 writeReg(addr, pkt->getLE<uint32_t>());
185 pkt->makeAtomicResponse();
186
187 return 0;
188 }
189
190 AddrRangeList
191 NoMaliGpu::getAddrRanges() const
192 {
193 return AddrRangeList({ RangeSize(pioAddr, nomaliInfo.reg_size) });
194 }
195
196 void
197 NoMaliGpu::reset()
198 {
199 DPRINTF(NoMali, "reset()\n");
200
201 panicOnErr(
202 nomali_reset(nomali),
203 "Failed to reset GPU");
204 }
205
206 uint32_t
207 NoMaliGpu::readReg(nomali_addr_t reg)
208 {
209 uint32_t value;
210
211 panicOnErr(
212 nomali_reg_read(nomali, &value, reg),
213 "GPU register read failed");
214
215 DPRINTF(NoMali, "readReg(0x%x): 0x%x\n",
216 reg, value);
217
218 return value;
219 }
220
221
222 void
223 NoMaliGpu::writeReg(nomali_addr_t reg, uint32_t value)
224 {
225 DPRINTF(NoMali, "writeReg(0x%x, 0x%x)\n",
226 reg, value);
227
228 panicOnErr(
229 nomali_reg_write(nomali, reg, value),
230 "GPU register write failed");
231 }
232
233 uint32_t
234 NoMaliGpu::readRegRaw(nomali_addr_t reg) const
235 {
236 uint32_t value;
237
238 panicOnErr(
239 nomali_reg_read_raw(nomali, &value, reg),
240 "GPU raw register read failed");
241
242 return value;
243 }
244
245
246 void
247 NoMaliGpu::writeRegRaw(nomali_addr_t reg, uint32_t value)
248 {
249 panicOnErr(
250 nomali_reg_write_raw(nomali, reg, value),
251 "GPU raw register write failed");
252 }
253
254 bool
255 NoMaliGpu::intState(nomali_int_t intno)
256 {
257 int state = 0;
258 panicOnErr(
259 nomali_int_state(nomali, &state, intno),
260 "Failed to get interrupt state");
261
262 return !!state;
263 }
264
265 void
266 NoMaliGpu::gpuPanic(nomali_error_t err, const char *msg)
267 {
268 panic("%s: %s\n", msg, nomali_errstr(err));
269 }
270
271
272 void
273 NoMaliGpu::onInterrupt(nomali_int_t intno, bool set)
274 {
275 const auto it_int(interruptMap.find(intno));
276 if (it_int == interruptMap.end())
277 panic("Unhandled interrupt from NoMali: %i\n", intno);
278
279 DPRINTF(NoMali, "Interrupt %i->%i: %i\n",
280 intno, it_int->second, set);
281
282 assert(platform);
283 assert(platform->gic);
284
285 if (set)
286 platform->gic->sendInt(it_int->second);
287 else
288 platform->gic->clearInt(it_int->second);
289 }
290
291 void
292 NoMaliGpu::onReset()
293 {
294 DPRINTF(NoMali, "Reset\n");
295 }
296
297 void
298 NoMaliGpu::setCallback(const nomali_callback_t &callback)
299 {
300 DPRINTF(NoMali, "Registering callback %i\n",
301 callback.type);
302
303 panicOnErr(
304 nomali_set_callback(nomali, &callback),
305 "Failed to register callback");
306 }
307
308 void
309 NoMaliGpu::_interrupt(nomali_handle_t h, void *usr,
310 nomali_int_t intno, int set)
311 {
312 NoMaliGpu *_this(static_cast<NoMaliGpu *>(usr));
313
314 _this->onInterrupt(intno, !!set);
315 }
316
317 void
318 NoMaliGpu::_reset(nomali_handle_t h, void *usr)
319 {
320 NoMaliGpu *_this(static_cast<NoMaliGpu *>(usr));
321
322 _this->onReset();
323 }
324
325
326 CustomNoMaliGpu::CustomNoMaliGpu(const CustomNoMaliGpuParams *p)
327 : NoMaliGpu(p),
328 idRegs{
329 { GPU_CONTROL_REG(GPU_ID), p->gpu_id },
330 { GPU_CONTROL_REG(L2_FEATURES), p->l2_features },
331 { GPU_CONTROL_REG(TILER_FEATURES), p->tiler_features },
332 { GPU_CONTROL_REG(MEM_FEATURES), p->mem_features },
333 { GPU_CONTROL_REG(MMU_FEATURES), p->mmu_features },
334 { GPU_CONTROL_REG(AS_PRESENT), p->as_present },
335 { GPU_CONTROL_REG(JS_PRESENT), p->js_present },
336
337 { GPU_CONTROL_REG(THREAD_MAX_THREADS), p->thread_max_threads },
338 { GPU_CONTROL_REG(THREAD_MAX_WORKGROUP_SIZE),
339 p->thread_max_workgroup_size },
340 { GPU_CONTROL_REG(THREAD_MAX_BARRIER_SIZE),
341 p->thread_max_barrier_size },
342 { GPU_CONTROL_REG(THREAD_FEATURES), p->thread_features },
343
344 { GPU_CONTROL_REG(SHADER_PRESENT_LO), bits(p->shader_present, 31, 0) },
345 { GPU_CONTROL_REG(SHADER_PRESENT_HI), bits(p->shader_present, 63, 32) },
346 { GPU_CONTROL_REG(TILER_PRESENT_LO), bits(p->tiler_present, 31, 0) },
347 { GPU_CONTROL_REG(TILER_PRESENT_HI), bits(p->tiler_present, 63, 32) },
348 { GPU_CONTROL_REG(L2_PRESENT_LO), bits(p->l2_present, 31, 0) },
349 { GPU_CONTROL_REG(L2_PRESENT_HI), bits(p->l2_present, 63, 32) },
350 }
351 {
352 fatal_if(p->texture_features.size() > 3,
353 "Too many texture feature registers specified (%i)\n",
354 p->texture_features.size());
355
356 fatal_if(p->js_features.size() > 16,
357 "Too many job slot feature registers specified (%i)\n",
358 p->js_features.size());
359
360 for (int i = 0; i < p->texture_features.size(); i++)
361 idRegs[TEXTURE_FEATURES_REG(i)] = p->texture_features[i];
362
363 for (int i = 0; i < p->js_features.size(); i++)
364 idRegs[JS_FEATURES_REG(i)] = p->js_features[i];
365 }
366
367 CustomNoMaliGpu::~CustomNoMaliGpu()
368 {
369 }
370
371 void
372 CustomNoMaliGpu::onReset()
373 {
374 NoMaliGpu::onReset();
375
376 for (const auto &reg : idRegs)
377 writeRegRaw(reg.first, reg.second);
378 }
379
380
381
382 NoMaliGpu *
383 NoMaliGpuParams::create()
384 {
385 return new NoMaliGpu(this);
386 }
387
388 CustomNoMaliGpu *
389 CustomNoMaliGpuParams::create()
390 {
391 return new CustomNoMaliGpu(this);
392 }