gpu_nomali.cc revision 13230
16145Snate@binkert.org/*
26145Snate@binkert.org * Copyright (c) 2014-2016 ARM Limited
36145Snate@binkert.org * All rights reserved
46145Snate@binkert.org *
56145Snate@binkert.org * The license below extends only to copyright in the software and shall
66145Snate@binkert.org * not be construed as granting a license to any other intellectual
76145Snate@binkert.org * property including but not limited to intellectual property relating
86145Snate@binkert.org * to a hardware implementation of the functionality of the software
96145Snate@binkert.org * licensed hereunder.  You may use the software subject to the license
106145Snate@binkert.org * terms below provided that you ensure that this notice is replicated
116145Snate@binkert.org * unmodified and in its entirety in all distributions of the software,
126145Snate@binkert.org * modified or unmodified, in source code or in binary form.
136145Snate@binkert.org *
146145Snate@binkert.org * Redistribution and use in source and binary forms, with or without
156145Snate@binkert.org * modification, are permitted provided that the following conditions are
166145Snate@binkert.org * met: redistributions of source code must retain the above copyright
176145Snate@binkert.org * notice, this list of conditions and the following disclaimer;
186145Snate@binkert.org * redistributions in binary form must reproduce the above copyright
196145Snate@binkert.org * notice, this list of conditions and the following disclaimer in the
206145Snate@binkert.org * documentation and/or other materials provided with the distribution;
216145Snate@binkert.org * neither the name of the copyright holders nor the names of its
226145Snate@binkert.org * contributors may be used to endorse or promote products derived from
236145Snate@binkert.org * this software without specific prior written permission.
246145Snate@binkert.org *
256145Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
266145Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
276145Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
286145Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
297054Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
307054Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
316154Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
326154Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
337054Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
347054Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
356154Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
366145Snate@binkert.org *
377055Snate@binkert.org * Authors: Andreas Sandberg
387055Snate@binkert.org */
396145Snate@binkert.org
406145Snate@binkert.org#include "dev/arm/gpu_nomali.hh"
416145Snate@binkert.org
426145Snate@binkert.org#include "debug/NoMali.hh"
436145Snate@binkert.org#include "dev/arm/base_gic.hh"
446145Snate@binkert.org#include "dev/arm/realview.hh"
456145Snate@binkert.org#include "enums/MemoryMode.hh"
466145Snate@binkert.org#include "mem/packet_access.hh"
476145Snate@binkert.org#include "nomali/lib/mali_midg_regmap.h"
487055Snate@binkert.org#include "params/CustomNoMaliGpu.hh"
496145Snate@binkert.org#include "params/NoMaliGpu.hh"
507054Snate@binkert.org
517054Snate@binkert.orgstatic const std::map<Enums::NoMaliGpuType, nomali_gpu_type_t> gpuTypeMap{
526145Snate@binkert.org    { Enums::T60x, NOMALI_GPU_T60X },
537054Snate@binkert.org    { Enums::T62x, NOMALI_GPU_T62X },
547054Snate@binkert.org    { Enums::T760, NOMALI_GPU_T760 },
556145Snate@binkert.org};
566145Snate@binkert.org
577054Snate@binkert.orgNoMaliGpu::NoMaliGpu(const NoMaliGpuParams *p)
587054Snate@binkert.org    : PioDevice(p),
596145Snate@binkert.org      pioAddr(p->pio_addr),
607054Snate@binkert.org      platform(p->platform),
617054Snate@binkert.org      interruptMap{
626145Snate@binkert.org          { NOMALI_INT_GPU, p->int_gpu },
636145Snate@binkert.org          { NOMALI_INT_JOB, p->int_job },
647054Snate@binkert.org          { NOMALI_INT_MMU, p->int_mmu },
657054Snate@binkert.org      }
666145Snate@binkert.org{
677054Snate@binkert.org    if (nomali_api_version() != NOMALI_API_VERSION)
687054Snate@binkert.org        panic("NoMali library API mismatch!\n");
696145Snate@binkert.org
707054Snate@binkert.org    /* Setup the GPU configuration based on our param struct */
717054Snate@binkert.org    nomali_config_t cfg;
727054Snate@binkert.org    memset(&cfg, 0, sizeof(cfg));
736145Snate@binkert.org
747054Snate@binkert.org    const auto it_gpu(gpuTypeMap.find(p->gpu_type));
757054Snate@binkert.org    if (it_gpu == gpuTypeMap.end()) {
766145Snate@binkert.org        fatal("Unrecognized GPU type: %s (%i)\n",
776145Snate@binkert.org              Enums::NoMaliGpuTypeStrings[p->gpu_type], p->gpu_type);
787054Snate@binkert.org    }
797054Snate@binkert.org    cfg.type = it_gpu->second;
806145Snate@binkert.org
817054Snate@binkert.org    cfg.ver_maj = p->ver_maj;
827054Snate@binkert.org    cfg.ver_min = p->ver_min;
837054Snate@binkert.org    cfg.ver_status = p->ver_status;
847054Snate@binkert.org
856145Snate@binkert.org    panicOnErr(
866145Snate@binkert.org        nomali_create(&nomali, &cfg),
877054Snate@binkert.org        "Failed to instantiate NoMali");
887054Snate@binkert.org
897054Snate@binkert.org
906145Snate@binkert.org    /* Setup an interrupt callback */
917054Snate@binkert.org    nomali_callback_t cbk_int;
927054Snate@binkert.org    cbk_int.type = NOMALI_CALLBACK_INT;
937054Snate@binkert.org    cbk_int.usr = (void *)this;
947054Snate@binkert.org    cbk_int.func.interrupt = NoMaliGpu::_interrupt;
956145Snate@binkert.org    setCallback(cbk_int);
967054Snate@binkert.org
977054Snate@binkert.org    /* Setup a reset callback */
987054Snate@binkert.org    nomali_callback_t cbk_rst;
997054Snate@binkert.org    cbk_rst.type = NOMALI_CALLBACK_RESET;
1007054Snate@binkert.org    cbk_rst.usr = (void *)this;
1017054Snate@binkert.org    cbk_rst.func.reset = NoMaliGpu::_reset;
1026145Snate@binkert.org    setCallback(cbk_rst);
1036145Snate@binkert.org
1046145Snate@binkert.org    panicOnErr(
1057054Snate@binkert.org        nomali_get_info(nomali, &nomaliInfo),
1067054Snate@binkert.org        "Failed to get NoMali information struct");
1076145Snate@binkert.org}
1087054Snate@binkert.org
1097054Snate@binkert.orgNoMaliGpu::~NoMaliGpu()
1107054Snate@binkert.org{
1116145Snate@binkert.org    nomali_destroy(nomali);
1127054Snate@binkert.org}
1137054Snate@binkert.org
1147054Snate@binkert.org
1157054Snate@binkert.orgvoid
1167054Snate@binkert.orgNoMaliGpu::init()
1177054Snate@binkert.org{
1186145Snate@binkert.org    PioDevice::init();
1196145Snate@binkert.org
1207054Snate@binkert.org    /* Reset the GPU here since the reset callback won't have been
1217054Snate@binkert.org     * installed when the GPU was reset at instantiation time.
1226145Snate@binkert.org     */
1237054Snate@binkert.org    reset();
1247054Snate@binkert.org}
1257054Snate@binkert.org
1266145Snate@binkert.orgvoid
1277054Snate@binkert.orgNoMaliGpu::serialize(CheckpointOut &cp) const
1287054Snate@binkert.org{
1297054Snate@binkert.org    std::vector<uint32_t> regs(nomaliInfo.reg_size >> 2);
1307054Snate@binkert.org
1317054Snate@binkert.org    for (int i = 0; i < nomaliInfo.reg_size; i += 4)
1327054Snate@binkert.org        regs[i >> 2] = readRegRaw(i);
1336145Snate@binkert.org
1347054Snate@binkert.org    SERIALIZE_CONTAINER(regs);
1357054Snate@binkert.org}
1367054Snate@binkert.org
1377054Snate@binkert.orgvoid
1387054Snate@binkert.orgNoMaliGpu::unserialize(CheckpointIn &cp)
1397054Snate@binkert.org{
1406145Snate@binkert.org    std::vector<uint32_t> regs(nomaliInfo.reg_size >> 2);
1416145Snate@binkert.org
1427054Snate@binkert.org    UNSERIALIZE_CONTAINER(regs);
1437054Snate@binkert.org
1447054Snate@binkert.org    for (int i = 0; i < nomaliInfo.reg_size; i += 4)
1457054Snate@binkert.org        writeRegRaw(i, regs[i >> 2]);
1467054Snate@binkert.org}
1477054Snate@binkert.org
1487054Snate@binkert.orgTick
1497054Snate@binkert.orgNoMaliGpu::read(PacketPtr pkt)
1507054Snate@binkert.org{
1517054Snate@binkert.org    assert(pkt->getAddr() >= pioAddr);
1527054Snate@binkert.org    const Addr addr(pkt->getAddr() - pioAddr);
1537054Snate@binkert.org    const unsigned size(pkt->getSize());
1547054Snate@binkert.org
1557054Snate@binkert.org    if (addr + size >= nomaliInfo.reg_size)
1567054Snate@binkert.org        panic("GPU register '0x%x' out of range!\n", addr);
1577054Snate@binkert.org
1587054Snate@binkert.org    if (size != 4)
1597054Snate@binkert.org        panic("Unexpected GPU register read size: %i\n", size);
1607453Snate@binkert.org    else if (addr & 0x3)
1617054Snate@binkert.org        panic("Unaligned GPU read: %i\n", size);
1627054Snate@binkert.org
1637054Snate@binkert.org    pkt->setLE<uint32_t>(readReg(addr));
1647054Snate@binkert.org    pkt->makeResponse();
1657054Snate@binkert.org
1667054Snate@binkert.org    return 0;
1677054Snate@binkert.org}
1687054Snate@binkert.org
1697054Snate@binkert.orgTick
1707054Snate@binkert.orgNoMaliGpu::write(PacketPtr pkt)
1717054Snate@binkert.org{
1727054Snate@binkert.org    assert(pkt->getAddr() >= pioAddr);
1737054Snate@binkert.org    const Addr addr(pkt->getAddr() - pioAddr);
1747054Snate@binkert.org    const unsigned size(pkt->getSize());
1757054Snate@binkert.org
1767054Snate@binkert.org    if (addr + size >= nomaliInfo.reg_size)
1777054Snate@binkert.org        panic("GPU register '0x%x' out of range!\n", addr);
1787054Snate@binkert.org
1797054Snate@binkert.org    if (size != 4)
1807054Snate@binkert.org        panic("Unexpected GPU register write size: %i\n", size);
1817054Snate@binkert.org    else if (addr & 0x3)
1827054Snate@binkert.org        panic("Unaligned GPU write: %i\n", size);
1837054Snate@binkert.org
1847054Snate@binkert.org    writeReg(addr, pkt->getLE<uint32_t>());
1857054Snate@binkert.org    pkt->makeAtomicResponse();
1867054Snate@binkert.org
1877054Snate@binkert.org    return 0;
1887054Snate@binkert.org}
1897054Snate@binkert.org
1907054Snate@binkert.orgAddrRangeList
1917054Snate@binkert.orgNoMaliGpu::getAddrRanges() const
1927054Snate@binkert.org{
1937054Snate@binkert.org    return AddrRangeList({ RangeSize(pioAddr, nomaliInfo.reg_size) });
1947054Snate@binkert.org}
1957054Snate@binkert.org
1966145Snate@binkert.orgvoid
1976145Snate@binkert.orgNoMaliGpu::reset()
1987054Snate@binkert.org{
1997054Snate@binkert.org    DPRINTF(NoMali, "reset()\n");
2007054Snate@binkert.org
2016145Snate@binkert.org    panicOnErr(
2027054Snate@binkert.org        nomali_reset(nomali),
2037054Snate@binkert.org        "Failed to reset GPU");
2046145Snate@binkert.org}
2057054Snate@binkert.org
2067054Snate@binkert.orguint32_t
2077054Snate@binkert.orgNoMaliGpu::readReg(nomali_addr_t reg)
2087054Snate@binkert.org{
2097054Snate@binkert.org    uint32_t value;
2107054Snate@binkert.org
2117054Snate@binkert.org    panicOnErr(
2127054Snate@binkert.org        nomali_reg_read(nomali, &value, reg),
2137054Snate@binkert.org        "GPU register read failed");
2147054Snate@binkert.org
2157054Snate@binkert.org    DPRINTF(NoMali, "readReg(0x%x): 0x%x\n",
2167054Snate@binkert.org            reg, value);
2177054Snate@binkert.org
2187054Snate@binkert.org    return value;
2197054Snate@binkert.org}
2207054Snate@binkert.org
2217054Snate@binkert.org
2226145Snate@binkert.orgvoid
2236145Snate@binkert.orgNoMaliGpu::writeReg(nomali_addr_t reg, uint32_t value)
2247054Snate@binkert.org{
2257054Snate@binkert.org    DPRINTF(NoMali, "writeReg(0x%x, 0x%x)\n",
2266145Snate@binkert.org            reg, value);
2277054Snate@binkert.org
2286145Snate@binkert.org    panicOnErr(
2296145Snate@binkert.org        nomali_reg_write(nomali, reg, value),
2307054Snate@binkert.org        "GPU register write failed");
2317054Snate@binkert.org}
2326145Snate@binkert.org
2337054Snate@binkert.orguint32_t
2347054Snate@binkert.orgNoMaliGpu::readRegRaw(nomali_addr_t reg) const
2356145Snate@binkert.org{
2367054Snate@binkert.org    uint32_t value;
2377054Snate@binkert.org
2387054Snate@binkert.org    panicOnErr(
2397054Snate@binkert.org        nomali_reg_read_raw(nomali, &value, reg),
2406145Snate@binkert.org        "GPU raw register read failed");
2416145Snate@binkert.org
2426145Snate@binkert.org    return value;
2437054Snate@binkert.org}
2447054Snate@binkert.org
2456145Snate@binkert.org
2466145Snate@binkert.orgvoid
2476145Snate@binkert.orgNoMaliGpu::writeRegRaw(nomali_addr_t reg, uint32_t value)
2487054Snate@binkert.org{
2497054Snate@binkert.org    panicOnErr(
2506145Snate@binkert.org        nomali_reg_write_raw(nomali, reg, value),
2517054Snate@binkert.org        "GPU raw register write failed");
2527054Snate@binkert.org}
2536145Snate@binkert.org
2546145Snate@binkert.orgbool
2557054Snate@binkert.orgNoMaliGpu::intState(nomali_int_t intno)
2567054Snate@binkert.org{
2576145Snate@binkert.org    int state = 0;
2587054Snate@binkert.org    panicOnErr(
2597054Snate@binkert.org        nomali_int_state(nomali, &state, intno),
2606145Snate@binkert.org        "Failed to get interrupt state");
2616145Snate@binkert.org
2627054Snate@binkert.org    return !!state;
2637054Snate@binkert.org}
2647054Snate@binkert.org
2657054Snate@binkert.orgvoid
2666145Snate@binkert.orgNoMaliGpu::gpuPanic(nomali_error_t err, const char *msg)
2677054Snate@binkert.org{
2687054Snate@binkert.org    panic("%s: %s\n", msg, nomali_errstr(err));
2697054Snate@binkert.org}
2706145Snate@binkert.org
2717054Snate@binkert.org
2727054Snate@binkert.orgvoid
2737054Snate@binkert.orgNoMaliGpu::onInterrupt(nomali_int_t intno, bool set)
2747054Snate@binkert.org{
2757054Snate@binkert.org    const auto it_int(interruptMap.find(intno));
2766145Snate@binkert.org    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
291void
292NoMaliGpu::onReset()
293{
294    DPRINTF(NoMali, "Reset\n");
295}
296
297void
298NoMaliGpu::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
308void
309NoMaliGpu::_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
317void
318NoMaliGpu::_reset(nomali_handle_t h, void *usr)
319{
320    NoMaliGpu *_this(static_cast<NoMaliGpu *>(usr));
321
322    _this->onReset();
323}
324
325
326CustomNoMaliGpu::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
367CustomNoMaliGpu::~CustomNoMaliGpu()
368{
369}
370
371void
372CustomNoMaliGpu::onReset()
373{
374    NoMaliGpu::onReset();
375
376    for (const auto &reg : idRegs)
377        writeRegRaw(reg.first, reg.second);
378}
379
380
381
382NoMaliGpu *
383NoMaliGpuParams::create()
384{
385    return new NoMaliGpu(this);
386}
387
388CustomNoMaliGpu *
389CustomNoMaliGpuParams::create()
390{
391    return new CustomNoMaliGpu(this);
392}
393