110749Smatt.evans@arm.com/*
210749Smatt.evans@arm.com * Copyright (c) 2013 ARM Limited
310749Smatt.evans@arm.com * All rights reserved
410749Smatt.evans@arm.com *
510749Smatt.evans@arm.com * The license below extends only to copyright in the software and shall
610749Smatt.evans@arm.com * not be construed as granting a license to any other intellectual
710749Smatt.evans@arm.com * property including but not limited to intellectual property relating
810749Smatt.evans@arm.com * to a hardware implementation of the functionality of the software
910749Smatt.evans@arm.com * licensed hereunder.  You may use the software subject to the license
1010749Smatt.evans@arm.com * terms below provided that you ensure that this notice is replicated
1110749Smatt.evans@arm.com * unmodified and in its entirety in all distributions of the software,
1210749Smatt.evans@arm.com * modified or unmodified, in source code or in binary form.
1310749Smatt.evans@arm.com *
1410749Smatt.evans@arm.com * Redistribution and use in source and binary forms, with or without
1510749Smatt.evans@arm.com * modification, are permitted provided that the following conditions are
1610749Smatt.evans@arm.com * met: redistributions of source code must retain the above copyright
1710749Smatt.evans@arm.com * notice, this list of conditions and the following disclaimer;
1810749Smatt.evans@arm.com * redistributions in binary form must reproduce the above copyright
1910749Smatt.evans@arm.com * notice, this list of conditions and the following disclaimer in the
2010749Smatt.evans@arm.com * documentation and/or other materials provided with the distribution;
2110749Smatt.evans@arm.com * neither the name of the copyright holders nor the names of its
2210749Smatt.evans@arm.com * contributors may be used to endorse or promote products derived from
2310749Smatt.evans@arm.com * this software without specific prior written permission.
2410749Smatt.evans@arm.com *
2510749Smatt.evans@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2610749Smatt.evans@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2710749Smatt.evans@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2810749Smatt.evans@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2910749Smatt.evans@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3010749Smatt.evans@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3110749Smatt.evans@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3210749Smatt.evans@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3310749Smatt.evans@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3410749Smatt.evans@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3510749Smatt.evans@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3610749Smatt.evans@arm.com *
3710749Smatt.evans@arm.com * Authors: Matt Evans
3810749Smatt.evans@arm.com */
3910749Smatt.evans@arm.com
4010749Smatt.evans@arm.com/** @file
4110749Smatt.evans@arm.com * Implementiation of a GICv2m MSI shim.
4210749Smatt.evans@arm.com *
4310749Smatt.evans@arm.com * This shim adds MSI support to GICv2.
4410749Smatt.evans@arm.com *
4510749Smatt.evans@arm.com * This should be instantiated with the appropriate number of frames,
4610749Smatt.evans@arm.com * and SPI numbers thereof, to the system being modelled.
4710749Smatt.evans@arm.com *
4810749Smatt.evans@arm.com * For example, in RealView.py (or whichever board setup is used), instantiate:
4910749Smatt.evans@arm.com *
5010749Smatt.evans@arm.com * gicv2m = Gicv2m(frames=[
5110749Smatt.evans@arm.com *              Gicv2mFrame(addr=0x12340000, spi_base=320, spi_len=64),
5210749Smatt.evans@arm.com *              Gicv2mFrame(addr=0x12350000, spi_base=100, spi_len=32),
5310749Smatt.evans@arm.com *              Gicv2mFrame(addr=0x12360000, spi_base=150, spi_len=16),
5410749Smatt.evans@arm.com *              Gicv2mFrame(addr=0x12370000, spi_base=190, spi_len=8),
5510749Smatt.evans@arm.com *              ])
5610749Smatt.evans@arm.com *
5710749Smatt.evans@arm.com */
5810749Smatt.evans@arm.com
5910749Smatt.evans@arm.com#include "dev/arm/gic_v2m.hh"
6010749Smatt.evans@arm.com
6110749Smatt.evans@arm.com#include "base/bitunion.hh"
6210749Smatt.evans@arm.com#include "base/intmath.hh"
6310749Smatt.evans@arm.com#include "debug/Checkpoint.hh"
6410749Smatt.evans@arm.com#include "debug/GICV2M.hh"
6510749Smatt.evans@arm.com#include "dev/io_device.hh"
6610749Smatt.evans@arm.com#include "mem/packet.hh"
6710749Smatt.evans@arm.com#include "mem/packet_access.hh"
6810749Smatt.evans@arm.com
6910749Smatt.evans@arm.comGicv2m *
7010749Smatt.evans@arm.comGicv2mParams::create()
7110749Smatt.evans@arm.com{
7210749Smatt.evans@arm.com    return new Gicv2m(this);
7310749Smatt.evans@arm.com}
7410749Smatt.evans@arm.com
7510749Smatt.evans@arm.comGicv2mFrame *
7610749Smatt.evans@arm.comGicv2mFrameParams::create()
7710749Smatt.evans@arm.com{
7810749Smatt.evans@arm.com    return new Gicv2mFrame(this);
7910749Smatt.evans@arm.com}
8010749Smatt.evans@arm.com
8110749Smatt.evans@arm.comGicv2m::Gicv2m(const Params *p)
8210749Smatt.evans@arm.com    : PioDevice(p), pioDelay(p->pio_delay), frames(p->frames), gic(p->gic)
8310749Smatt.evans@arm.com{
8410749Smatt.evans@arm.com    // Assert SPI ranges start at 32
8510749Smatt.evans@arm.com    for (int i = 0; i < frames.size(); i++) {
8610749Smatt.evans@arm.com        if (frames[i]->spi_base < 32)
8710749Smatt.evans@arm.com            fatal("Gicv2m: Frame %d's SPI base (%d) is not in SPI space\n",
8810749Smatt.evans@arm.com                  i, frames[i]->spi_base);
8910749Smatt.evans@arm.com    }
9010749Smatt.evans@arm.com    unsigned int x = frames.size();
9110749Smatt.evans@arm.com    fatal_if(!isPowerOf2(x), "Gicv2m: The v2m shim must be configured with "
9210749Smatt.evans@arm.com              "a power-of-two number of frames\n");
9310749Smatt.evans@arm.com    log2framenum = floorLog2(x);
9410749Smatt.evans@arm.com}
9510749Smatt.evans@arm.com
9610749Smatt.evans@arm.comAddrRangeList
9710749Smatt.evans@arm.comGicv2m::getAddrRanges() const
9810749Smatt.evans@arm.com{
9910749Smatt.evans@arm.com    AddrRangeList ranges;
10010749Smatt.evans@arm.com    for (int i = 0; i < frames.size(); i++) {
10110749Smatt.evans@arm.com        ranges.push_back(RangeSize(frames[i]->addr, FRAME_SIZE));
10210749Smatt.evans@arm.com    }
10310749Smatt.evans@arm.com    return ranges;
10410749Smatt.evans@arm.com}
10510749Smatt.evans@arm.com
10610749Smatt.evans@arm.comTick
10710749Smatt.evans@arm.comGicv2m::read(PacketPtr pkt)
10810749Smatt.evans@arm.com{
10910749Smatt.evans@arm.com    int frame = frameFromAddr(pkt->getAddr());
11010749Smatt.evans@arm.com
11110749Smatt.evans@arm.com    assert(frame >= 0);
11210749Smatt.evans@arm.com
11310749Smatt.evans@arm.com    Addr offset = pkt->getAddr() - frames[frame]->addr;
11410749Smatt.evans@arm.com
11510749Smatt.evans@arm.com    switch (offset) {
11610749Smatt.evans@arm.com      case MSI_TYPER:
11713230Sgabeblack@google.com        pkt->setLE<uint32_t>((frames[frame]->spi_base << 16) |
11810749Smatt.evans@arm.com                           frames[frame]->spi_len);
11910749Smatt.evans@arm.com        break;
12010749Smatt.evans@arm.com
12110749Smatt.evans@arm.com      case PER_ID4:
12213230Sgabeblack@google.com        pkt->setLE<uint32_t>(0x4 | ((4+log2framenum) << 4));
12310749Smatt.evans@arm.com        // Nr of 4KB blocks used by component.  This is messy as frames are 64K
12410749Smatt.evans@arm.com        // (16, ie 2^4) and we should assert we're given a Po2 number of frames.
12510749Smatt.evans@arm.com        break;
12610749Smatt.evans@arm.com      default:
12710749Smatt.evans@arm.com        DPRINTF(GICV2M, "GICv2m: Read of unk reg %#x\n", offset);
12813230Sgabeblack@google.com        pkt->setLE<uint32_t>(0);
12910749Smatt.evans@arm.com    };
13010749Smatt.evans@arm.com
13110749Smatt.evans@arm.com    pkt->makeAtomicResponse();
13210749Smatt.evans@arm.com
13310749Smatt.evans@arm.com    return pioDelay;
13410749Smatt.evans@arm.com}
13510749Smatt.evans@arm.com
13610749Smatt.evans@arm.comTick
13710749Smatt.evans@arm.comGicv2m::write(PacketPtr pkt)
13810749Smatt.evans@arm.com{
13910749Smatt.evans@arm.com    int frame = frameFromAddr(pkt->getAddr());
14010749Smatt.evans@arm.com
14110749Smatt.evans@arm.com    assert(frame >= 0);
14210749Smatt.evans@arm.com
14310749Smatt.evans@arm.com    Addr offset = pkt->getAddr() - frames[frame]->addr;
14410749Smatt.evans@arm.com
14510749Smatt.evans@arm.com    if (offset == MSI_SETSPI_NSR) {
14610749Smatt.evans@arm.com        /* Is payload SPI number within range? */
14713230Sgabeblack@google.com        uint32_t m = pkt->getLE<uint32_t>();
14810749Smatt.evans@arm.com        if (m >= frames[frame]->spi_base &&
14910749Smatt.evans@arm.com            m < (frames[frame]->spi_base + frames[frame]->spi_len)) {
15010749Smatt.evans@arm.com            DPRINTF(GICV2M, "GICv2m: Frame %d raising MSI %d\n", frame, m);
15110749Smatt.evans@arm.com            gic->sendInt(m);
15210749Smatt.evans@arm.com        }
15310749Smatt.evans@arm.com    } else {
15410749Smatt.evans@arm.com        DPRINTF(GICV2M, "GICv2m: Write of unk reg %#x\n", offset);
15510749Smatt.evans@arm.com    }
15610749Smatt.evans@arm.com
15710749Smatt.evans@arm.com    pkt->makeAtomicResponse();
15810749Smatt.evans@arm.com
15910749Smatt.evans@arm.com    return pioDelay;
16010749Smatt.evans@arm.com}
16110749Smatt.evans@arm.com
16210749Smatt.evans@arm.comint
16310749Smatt.evans@arm.comGicv2m::frameFromAddr(Addr a) const
16410749Smatt.evans@arm.com{
16510749Smatt.evans@arm.com    for (int i = 0; i < frames.size(); i++) {
16610749Smatt.evans@arm.com        if (a >= frames[i]->addr && a < (frames[i]->addr + FRAME_SIZE))
16710749Smatt.evans@arm.com            return i;
16810749Smatt.evans@arm.com    }
16910749Smatt.evans@arm.com    return -1;
17010749Smatt.evans@arm.com}
171