1/*
2 * Copyright (c) 2014-2015 ARM Limited
3 * All rights reserved
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * Authors: Andreas Sandberg
18 */
19
20#include "jobcontrol.hh"
21
22#include "gpu.hh"
23#include "regutils.hh"
24
25namespace NoMali {
26
27JobControl::JobControl(GPU &_gpu)
28    : GPUBlockInt(_gpu,
29                  RegAddr(JOB_IRQ_RAWSTAT),
30                  RegAddr(JOB_IRQ_CLEAR),
31                  RegAddr(JOB_IRQ_MASK),
32                  RegAddr(JOB_IRQ_STATUS))
33{
34    slots.reserve(16);
35    for (int i = 0; i < 16; ++i)
36        slots.emplace_back(_gpu, *this, i);
37
38}
39
40JobControl::~JobControl()
41{
42}
43
44void
45JobControl::reset()
46{
47    GPUBlockInt::reset();
48
49    for (auto &js : slots)
50        js.reset();
51}
52
53uint32_t
54JobControl::readReg(RegAddr addr)
55{
56    if (addr >= RegAddr(JOB_SLOT0)) {
57        return slots[getJobSlotNo(addr)].readReg(getJobSlotAddr(addr));
58    } else {
59        return GPUBlockInt::readReg(addr);
60    }
61}
62
63void
64JobControl::writeReg(RegAddr addr, uint32_t value)
65{
66    switch(addr.value) {
67      case JOB_IRQ_CLEAR:
68        // Update JS state for all jobs that were affected by the IRQ
69        // clear
70        updateJsState((value & 0xFFFF) | ((value & 0xFFFF0000) >> 16));
71
72        // FALLTHROUGH - IRQ handling in base class
73      case JOB_IRQ_RAWSTAT:
74      case JOB_IRQ_MASK:
75      case JOB_IRQ_STATUS:
76        GPUBlockInt::writeReg(addr, value);
77        break;
78
79      default:
80        if (addr >= RegAddr(JOB_SLOT0))
81            slots[getJobSlotNo(addr)].writeReg(getJobSlotAddr(addr), value);
82        break;
83    }
84}
85
86uint32_t
87JobControl::readRegRaw(RegAddr addr)
88{
89    if (addr >= RegAddr(JOB_SLOT0)) {
90        return slots[getJobSlotNo(addr)].readRegRaw(getJobSlotAddr(addr));
91    } else {
92        return GPUBlockInt::readRegRaw(addr);
93    }
94}
95
96
97void
98JobControl::writeRegRaw(RegAddr addr, uint32_t value)
99{
100    if (addr >= RegAddr(JOB_SLOT0)) {
101        slots[getJobSlotNo(addr)].writeRegRaw(getJobSlotAddr(addr), value);
102    } else {
103        GPUBlockInt::writeRegRaw(addr, value);
104    }
105}
106
107void
108JobControl::jobDone(uint8_t slot)
109{
110    assert(slot <= 15);
111    raiseInterrupt(1 << slot);
112}
113
114void
115JobControl::jobFailed(uint8_t slot)
116{
117    assert(slot <= 15);
118    raiseInterrupt(0x10000 << slot);
119}
120
121void
122JobControl::updateJsState(uint16_t jobs)
123{
124    // The JS_STATE register contains two bits per job slot; one bit
125    // representing an active job and one bit representing the queued
126    // job. We need to mask out bits of the jobs affected by this update.
127    const uint32_t job_mask(jobs | (jobs << 16));
128    uint16_t js_state(regs[RegAddr(JOB_IRQ_JS_STATE)] & ~job_mask);
129
130    // Find if there is an active or active next job for all jobs in
131    // the job mask.
132    for (int i = 0; i < 16; ++i) {
133        const JobSlot &slot(slots[i]);
134        if (jobs & (1 << i)) {
135            js_state |= slot.active() ? (1 << i) : 0 |
136                slot.activeNext() ? (0x10000 << i) : 0;
137        }
138    }
139    regs[RegAddr(JOB_IRQ_JS_STATE)] = js_state;
140}
141
142void
143JobControl::onInterrupt(int set)
144{
145    gpu.intJob(set);
146}
147
148}
149