1/*
2 * Copyright (c) 2014-2016 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 "libnomali/nomali.h"
21
22#include <cstring>
23
24#include "mali_t6xx.hh"
25#include "mali_t7xx.hh"
26
27#define EXPORT __attribute__ ((visibility ("default")))
28
29static const char *errstrs[] = {
30    "No error",
31    "Unknown error",
32    "Memory allocation failed",
33    "Invalid model handle",
34    "Invalid parameter",
35};
36
37static_assert(sizeof(errstrs) / sizeof(*errstrs) == NOMALI_E_NUM_ERRORS,
38              "NoMali API error descriptions out of sync!");
39
40class NoMaliApi
41{
42  public:
43    NoMaliApi();
44    ~NoMaliApi();
45
46    void setGpu(NoMali::GPU *gpu) { _gpu = gpu; }
47
48  public:
49    nomali_error_t setCallback(const nomali_callback_t *callback);
50
51    nomali_error_t getInfo(nomali_info_t *info);
52
53    nomali_error_t reset();
54    nomali_error_t regRead(uint32_t *value, nomali_addr_t addr);
55    nomali_error_t regWrite(nomali_addr_t addr, uint32_t value);
56    nomali_error_t regReadRaw(uint32_t *value, nomali_addr_t addr);
57    nomali_error_t regWriteRaw(nomali_addr_t addr, uint32_t value);
58    nomali_error_t intState(int *state, nomali_int_t intno) const;
59
60  public:
61    void callbackInt(nomali_int_t intno, int set);
62    void callbackReset();
63
64  private:
65    nomali_callback_t callbacks[NOMALI_CALLBACK_NUM_CALLBACKS];
66
67    NoMali::GPU *_gpu;
68};
69
70template<class BaseGpu>
71class NoMaliApiGpu
72    : public BaseGpu
73{
74  public:
75    template<typename... Args>
76    NoMaliApiGpu(NoMaliApi &_api, Args &&... args)
77        : BaseGpu(std::forward<Args>(args)...),
78          api(_api)
79    {
80        reset();
81    }
82
83    void reset() override {
84        BaseGpu::reset();
85        api.callbackReset();
86    }
87
88  public:
89    void intJob(int set) override { api.callbackInt(NOMALI_INT_JOB, set); }
90    void intMMU(int set) override { api.callbackInt(NOMALI_INT_MMU, set); }
91    void intGPU(int set) override { api.callbackInt(NOMALI_INT_GPU, set); }
92
93  private:
94    NoMaliApi &api;
95};
96
97
98NoMaliApi::NoMaliApi()
99    : _gpu(nullptr)
100{
101    memset(callbacks, 0, sizeof(callbacks));
102}
103
104
105NoMaliApi::~NoMaliApi()
106{
107}
108
109nomali_error_t
110NoMaliApi::setCallback(const nomali_callback_t *callback)
111{
112    if (!callback ||
113        callback->type >= NOMALI_CALLBACK_NUM_CALLBACKS)
114        return NOMALI_E_INVALID;
115
116    callbacks[callback->type] = *callback;
117
118    return NOMALI_E_OK;
119}
120
121nomali_error_t
122NoMaliApi::getInfo(nomali_info_t *info)
123{
124    if (!info)
125        return NOMALI_E_INVALID;
126
127    info->reg_size = 0x4000;
128
129    return NOMALI_E_OK;
130}
131
132nomali_error_t
133NoMaliApi::reset()
134{
135    _gpu->reset();
136    return NOMALI_E_OK;
137}
138
139nomali_error_t
140NoMaliApi::regRead(uint32_t *value, nomali_addr_t addr)
141{
142    if (!value)
143        return NOMALI_E_INVALID;
144
145    *value = _gpu->readReg(NoMali::RegAddr(addr));
146
147    return NOMALI_E_OK;
148}
149
150nomali_error_t
151NoMaliApi::regWrite(nomali_addr_t addr, uint32_t value)
152{
153    _gpu->writeReg(NoMali::RegAddr(addr), value);
154
155    return NOMALI_E_OK;
156}
157
158
159nomali_error_t
160NoMaliApi::regReadRaw(uint32_t *value, nomali_addr_t addr)
161{
162    if (!value)
163        return NOMALI_E_INVALID;
164
165    *value = _gpu->readRegRaw(NoMali::RegAddr(addr));
166
167    return NOMALI_E_OK;
168}
169
170nomali_error_t
171NoMaliApi::regWriteRaw(nomali_addr_t addr, uint32_t value)
172{
173    _gpu->writeRegRaw(NoMali::RegAddr(addr), value);
174
175    return NOMALI_E_OK;
176}
177
178nomali_error_t
179NoMaliApi::intState(int *state, nomali_int_t intno) const
180{
181    if (!state)
182        return NOMALI_E_INVALID;
183
184    switch (intno) {
185      case NOMALI_INT_GPU:
186        *state = _gpu->intGPUAsserted();
187        break;
188
189      case NOMALI_INT_JOB:
190        *state = _gpu->intJobAsserted();
191        break;
192
193      case NOMALI_INT_MMU:
194        *state = _gpu->intMMUAsserted();
195        break;
196
197      default:
198        return NOMALI_E_INVALID;
199    }
200
201    return NOMALI_E_OK;
202}
203
204
205void
206NoMaliApi::callbackInt(nomali_int_t intno, int set)
207{
208    const nomali_callback_t &c(callbacks[NOMALI_CALLBACK_INT]);
209
210    if (c.func.interrupt)
211        c.func.interrupt(static_cast<nomali_handle_t>(this), c.usr, intno, set);
212}
213
214void
215NoMaliApi::callbackReset()
216{
217    const nomali_callback_t &c(callbacks[NOMALI_CALLBACK_RESET]);
218
219    if (c.func.reset)
220        c.func.reset(static_cast<nomali_handle_t>(this), c.usr);
221}
222
223
224
225static NoMaliApi *
226get_gpu(nomali_handle_t h)
227{
228    return h ? static_cast<NoMaliApi *>(h) : nullptr;
229}
230
231
232extern "C" EXPORT nomali_api_version_t
233nomali_api_version()
234{
235    return NOMALI_API_VERSION;
236}
237
238extern "C" EXPORT nomali_error_t
239nomali_create(nomali_handle_t *h, const nomali_config_t *cfg)
240{
241    if (h && cfg) {
242        NoMaliApi *api(new NoMaliApi());
243        *h = api;
244        if (!h)
245            return NOMALI_E_MEMORY;
246
247        NoMali::GPU *gpu;
248        switch (cfg->type) {
249          case NOMALI_GPU_T60X:
250            gpu = new NoMaliApiGpu<NoMali::MaliT60x>(
251                *api,
252                cfg->ver_maj, cfg->ver_min, cfg->ver_status);
253            break;
254
255          case NOMALI_GPU_T62X:
256            gpu = new NoMaliApiGpu<NoMali::MaliT62x>(
257                *api,
258                cfg->ver_maj, cfg->ver_min, cfg->ver_status);
259            break;
260
261
262          case NOMALI_GPU_T76X:
263            gpu = new NoMaliApiGpu<NoMali::MaliT76x>(
264                *api,
265                cfg->ver_maj, cfg->ver_min, cfg->ver_status);
266            break;
267
268          default:
269            delete api;
270            return NOMALI_E_INVALID;
271        };
272
273        if (!gpu) {
274            delete api;
275            return NOMALI_E_MEMORY;
276        }
277
278        api->setGpu(gpu);
279
280        return NOMALI_E_OK;
281    } else {
282        return NOMALI_E_INVALID;
283    }
284}
285
286extern "C" EXPORT nomali_error_t
287nomali_destroy(nomali_handle_t h)
288{
289    NoMaliApi *gpu(get_gpu(h));
290
291    if (gpu) {
292        delete gpu;
293        return NOMALI_E_OK;
294    } else {
295        return NOMALI_E_HANDLE;
296    }
297}
298
299extern "C" EXPORT const char *
300nomali_errstr(nomali_error_t error)
301{
302    if (error < NOMALI_E_NUM_ERRORS)
303        return errstrs[error];
304    else
305        return "Invalid error number";
306}
307
308extern "C" EXPORT nomali_error_t
309nomali_set_callback(nomali_handle_t h,
310                    const nomali_callback_t *callback)
311{
312    NoMaliApi *gpu(get_gpu(h));
313    return gpu ? gpu->setCallback(callback) : NOMALI_E_HANDLE;
314}
315
316extern "C" EXPORT nomali_error_t
317nomali_get_info(nomali_handle_t h, nomali_info_t *info)
318{
319    NoMaliApi *gpu(get_gpu(h));
320    return gpu ? gpu->getInfo(info) : NOMALI_E_HANDLE;
321}
322
323extern "C" EXPORT nomali_error_t
324nomali_reset(nomali_handle_t h)
325{
326    NoMaliApi *gpu(get_gpu(h));
327    return gpu ? gpu->reset() : NOMALI_E_HANDLE;
328}
329
330extern "C" EXPORT nomali_error_t
331nomali_reg_read(nomali_handle_t h, uint32_t *value,
332                nomali_addr_t addr)
333{
334    NoMaliApi *gpu(get_gpu(h));
335    return gpu ? gpu->regRead(value, addr) : NOMALI_E_HANDLE;
336}
337
338extern "C" EXPORT nomali_error_t
339nomali_reg_write(nomali_handle_t h,
340                 nomali_addr_t addr, uint32_t value)
341{
342    NoMaliApi *gpu(get_gpu(h));
343    return gpu ? gpu->regWrite(addr, value) : NOMALI_E_HANDLE;
344}
345
346
347extern "C" EXPORT nomali_error_t
348nomali_reg_read_raw(nomali_handle_t h, uint32_t *value,
349                    nomali_addr_t addr)
350{
351    NoMaliApi *gpu(get_gpu(h));
352    return gpu ? gpu->regReadRaw(value, addr) : NOMALI_E_HANDLE;
353}
354
355extern "C" EXPORT nomali_error_t
356nomali_reg_write_raw(nomali_handle_t h,
357                     nomali_addr_t addr, uint32_t value)
358{
359    NoMaliApi *gpu(get_gpu(h));
360    return gpu ? gpu->regWriteRaw(addr, value) : NOMALI_E_HANDLE;
361}
362
363extern "C" EXPORT nomali_error_t
364nomali_int_state(nomali_handle_t h, int *state,
365                 nomali_int_t intno)
366{
367    NoMaliApi *gpu(get_gpu(h));
368    return gpu ? gpu->intState(state, intno) : NOMALI_E_HANDLE;
369}
370
371