gpu_nomali.cc revision 11350
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 "params/NoMaliGpu.hh"
48
49static const std::map<Enums::NoMaliGpuType, nomali_gpu_type_t> gpuTypeMap{
50    { Enums::T60x, NOMALI_GPU_T60X },
51    { Enums::T62x, NOMALI_GPU_T62X },
52    { Enums::T760, NOMALI_GPU_T760 },
53};
54
55NoMaliGpu::NoMaliGpu(const NoMaliGpuParams *p)
56    : PioDevice(p),
57      pioAddr(p->pio_addr),
58      platform(p->platform),
59      interruptMap{
60          { NOMALI_INT_GPU, p->int_gpu },
61          { NOMALI_INT_JOB, p->int_job },
62          { NOMALI_INT_MMU, p->int_mmu },
63      }
64{
65    if (nomali_api_version() != NOMALI_API_VERSION)
66        panic("NoMali library API mismatch!\n");
67
68    /* Setup the GPU configuration based on our param struct */
69    nomali_config_t cfg;
70    memset(&cfg, 0, sizeof(cfg));
71
72    const auto it_gpu(gpuTypeMap.find(p->gpu_type));
73    if (it_gpu == gpuTypeMap.end()) {
74        fatal("Unrecognized GPU type: %s (%i)\n",
75              Enums::NoMaliGpuTypeStrings[p->gpu_type], p->gpu_type);
76    }
77    cfg.type = it_gpu->second;
78
79    cfg.ver_maj = p->ver_maj;
80    cfg.ver_min = p->ver_min;
81    cfg.ver_status = p->ver_status;
82
83    panicOnErr(
84        nomali_create(&nomali, &cfg),
85        "Failed to instantiate NoMali");
86
87
88    /* Setup an interrupt callback */
89    nomali_callback_t cbk_int;
90    cbk_int.type = NOMALI_CALLBACK_INT;
91    cbk_int.usr = (void *)this;
92    cbk_int.func.interrupt = NoMaliGpu::_interrupt;
93    setCallback(cbk_int);
94
95    /* Setup a reset callback */
96    nomali_callback_t cbk_rst;
97    cbk_rst.type = NOMALI_CALLBACK_RESET;
98    cbk_rst.usr = (void *)this;
99    cbk_rst.func.reset = NoMaliGpu::_reset;
100    setCallback(cbk_rst);
101
102    panicOnErr(
103        nomali_get_info(nomali, &nomaliInfo),
104        "Failed to get NoMali information struct");
105}
106
107NoMaliGpu::~NoMaliGpu()
108{
109    nomali_destroy(nomali);
110}
111
112
113void
114NoMaliGpu::init()
115{
116    PioDevice::init();
117
118    /* Reset the GPU here since the reset callback won't have been
119     * installed when the GPU was reset at instantiation time.
120     */
121    reset();
122}
123
124void
125NoMaliGpu::serialize(CheckpointOut &cp) const
126{
127    std::vector<uint32_t> regs(nomaliInfo.reg_size >> 2);
128
129    for (int i = 0; i < nomaliInfo.reg_size; i += 4)
130        regs[i >> 2] = readRegRaw(i);
131
132    SERIALIZE_CONTAINER(regs);
133}
134
135void
136NoMaliGpu::unserialize(CheckpointIn &cp)
137{
138    std::vector<uint32_t> regs(nomaliInfo.reg_size >> 2);
139
140    UNSERIALIZE_CONTAINER(regs);
141
142    for (int i = 0; i < nomaliInfo.reg_size; i += 4)
143        writeRegRaw(i, regs[i >> 2]);
144}
145
146Tick
147NoMaliGpu::read(PacketPtr pkt)
148{
149    assert(pkt->getAddr() >= pioAddr);
150    const Addr addr(pkt->getAddr() - pioAddr);
151    const unsigned size(pkt->getSize());
152
153    if (addr + size >= nomaliInfo.reg_size)
154        panic("GPU register '0x%x' out of range!\n", addr);
155
156    if (size != 4)
157        panic("Unexpected GPU register read size: %i\n", size);
158    else if (addr & 0x3)
159        panic("Unaligned GPU read: %i\n", size);
160
161    pkt->set<uint32_t>(readReg(addr));
162    pkt->makeResponse();
163
164    return 0;
165}
166
167Tick
168NoMaliGpu::write(PacketPtr pkt)
169{
170    assert(pkt->getAddr() >= pioAddr);
171    const Addr addr(pkt->getAddr() - pioAddr);
172    const unsigned size(pkt->getSize());
173
174    if (addr + size >= nomaliInfo.reg_size)
175        panic("GPU register '0x%x' out of range!\n", addr);
176
177    if (size != 4)
178        panic("Unexpected GPU register write size: %i\n", size);
179    else if (addr & 0x3)
180        panic("Unaligned GPU write: %i\n", size);
181
182    writeReg(addr, pkt->get<uint32_t>());
183    pkt->makeAtomicResponse();
184
185    return 0;
186}
187
188AddrRangeList
189NoMaliGpu::getAddrRanges() const
190{
191    return AddrRangeList({ RangeSize(pioAddr, nomaliInfo.reg_size) });
192}
193
194void
195NoMaliGpu::reset()
196{
197    DPRINTF(NoMali, "reset()\n");
198
199    panicOnErr(
200        nomali_reset(nomali),
201        "Failed to reset GPU");
202}
203
204uint32_t
205NoMaliGpu::readReg(nomali_addr_t reg)
206{
207    uint32_t value;
208
209    panicOnErr(
210        nomali_reg_read(nomali, &value, reg),
211        "GPU register read failed");
212
213    DPRINTF(NoMali, "readReg(0x%x): 0x%x\n",
214            reg, value);
215
216    return value;
217}
218
219
220void
221NoMaliGpu::writeReg(nomali_addr_t reg, uint32_t value)
222{
223    DPRINTF(NoMali, "writeReg(0x%x, 0x%x)\n",
224            reg, value);
225
226    panicOnErr(
227        nomali_reg_write(nomali, reg, value),
228        "GPU register write failed");
229}
230
231uint32_t
232NoMaliGpu::readRegRaw(nomali_addr_t reg) const
233{
234    uint32_t value;
235
236    panicOnErr(
237        nomali_reg_read_raw(nomali, &value, reg),
238        "GPU raw register read failed");
239
240    return value;
241}
242
243
244void
245NoMaliGpu::writeRegRaw(nomali_addr_t reg, uint32_t value)
246{
247    panicOnErr(
248        nomali_reg_write_raw(nomali, reg, value),
249        "GPU raw register write failed");
250}
251
252bool
253NoMaliGpu::intState(nomali_int_t intno)
254{
255    int state = 0;
256    panicOnErr(
257        nomali_int_state(nomali, &state, intno),
258        "Failed to get interrupt state");
259
260    return !!state;
261}
262
263void
264NoMaliGpu::gpuPanic(nomali_error_t err, const char *msg)
265{
266    panic("%s: %s\n", msg, nomali_errstr(err));
267}
268
269
270void
271NoMaliGpu::onInterrupt(nomali_int_t intno, bool set)
272{
273    const auto it_int(interruptMap.find(intno));
274    if (it_int == interruptMap.end())
275        panic("Unhandled interrupt from NoMali: %i\n", intno);
276
277    DPRINTF(NoMali, "Interrupt %i->%i: %i\n",
278            intno, it_int->second, set);
279
280    assert(platform);
281    assert(platform->gic);
282
283    if (set)
284        platform->gic->sendInt(it_int->second);
285    else
286        platform->gic->clearInt(it_int->second);
287}
288
289void
290NoMaliGpu::onReset()
291{
292    DPRINTF(NoMali, "Reset\n");
293}
294
295void
296NoMaliGpu::setCallback(const nomali_callback_t &callback)
297{
298    DPRINTF(NoMali, "Registering callback %i\n",
299            callback.type);
300
301    panicOnErr(
302        nomali_set_callback(nomali, &callback),
303        "Failed to register callback");
304}
305
306void
307NoMaliGpu::_interrupt(nomali_handle_t h, void *usr,
308                      nomali_int_t intno, int set)
309{
310    NoMaliGpu *_this(static_cast<NoMaliGpu *>(usr));
311
312    _this->onInterrupt(intno, !!set);
313}
314
315void
316NoMaliGpu::_reset(nomali_handle_t h, void *usr)
317{
318    NoMaliGpu *_this(static_cast<NoMaliGpu *>(usr));
319
320    _this->onReset();
321}
322
323NoMaliGpu *
324NoMaliGpuParams::create()
325{
326    return new NoMaliGpu(this);
327}
328