11
#include <etnaviv_drm.h>
21
#include <drivers/char_dev.h>
22
#include <drivers/clk/ccm_imx6.h>
23
#include <drivers/common/memory.h>
24
#include <drivers/power/imx.h>
25
#include <embox_drm/drm_gem.h>
26
#include <embox_drm/drm_priv.h>
27
#include <etnaviv_xml/common.xml.h>
28
#include <etnaviv_xml/state_hi.xml.h>
31
#include <kernel/irq.h>
35
#include <util/macro.h>
37
#include "etnaviv_drv.h"
38
#include "etnaviv_gem.h"
39
#include "etnaviv_gpu.h"
41
#define VERSION_NAME "etnaviv"
42
#define VERSION_NAME_LEN 9
43
#define VERSION_DATE "7 Dec 2017"
44
#define VERSION_DATE_LEN 10
45
#define VERSION_DESC "DEADBEEF"
46
#define VERSION_DESC_LEN 8
49
#define GPU3D_IRQ OPTION_GET(NUMBER, gpu3d_irq)
50
#define R2D_GPU2D_IRQ OPTION_GET(NUMBER, r2d_gpu2d_irq)
51
#define V2D_GPU2D_IRQ OPTION_GET(NUMBER, v2d_gpu2d_irq)
53
#define ETNA_UNCACHED_BUFFER_SZ (16 * 1024 * 1024)
55
static uint8_t etnaviv_uncached_buffer[ETNA_UNCACHED_BUFFER_SZ]
56
__attribute__((aligned(0x1000)));
61
static const char *drm_call_to_string[] = {
62
[0x00] = "GET_PARAM ",
63
[0x01] = "SET_PARAM ",
66
[0x04] = "GEM_CPU_PREP",
67
[0x05] = "GEM_CPU_FINI",
68
[0x06] = "GEM_SUBMIT ",
69
[0x07] = "WAIT_FENCE ",
70
[0x08] = "GEM_USERPTR ",
72
[0x0a] = "NUM_IOCTLS ",
75
int etnaviv_ioctl_gem_new(struct drm_device *dev, void *data,
76
struct drm_file *file) {
77
struct drm_etnaviv_gem_new *args = data;
80
& ~(ETNA_BO_CACHED | ETNA_BO_WC | ETNA_BO_UNCACHED
81
| ETNA_BO_FORCE_MMU)) {
82
log_error("unsupported flags");
85
return etnaviv_gem_new_handle(dev, file, args->size, args->flags,
86
(void *)&args->handle);
89
int etnaviv_ioctl_gem_info(struct drm_device *dev, void *data,
90
struct drm_file *file) {
91
struct drm_etnaviv_gem_info *args = data;
92
struct drm_gem_object *obj;
98
obj = drm_gem_object_lookup(file, args->handle);
100
log_error("obj (%p) didn't found", args->handle);
103
log_debug("obj (%p) founded by handle (%i)", obj, args->handle);
105
ret = etnaviv_gem_mmap_offset(obj, &args->offset);
110
static int etnaviv_ioctl_wait_fence(struct drm_device *dev, void *data,
111
struct drm_file *file) {
112
struct drm_etnaviv_wait_fence *args = data;
113
struct etnaviv_drm_private *priv = dev->dev_private;
114
struct etnaviv_gpu *gpu;
116
if (args->flags & ~(ETNA_WAIT_NONBLOCK))
119
if (args->pipe >= ETNA_MAX_PIPES)
122
gpu = priv->gpu[args->pipe];
129
static struct drm_device etnaviv_drm_device;
130
static struct drm_file etnaviv_drm_file;
131
static struct etnaviv_drm_private etnaviv_drm_private;
132
static struct etnaviv_gpu etnaviv_gpus[ETNA_MAX_PIPES];
134
#define VIVANTE_2D_BASE OPTION_GET(NUMBER, vivante_2d_base)
135
#define VIVANTE_3D_BASE OPTION_GET(NUMBER, vivante_3d_base)
137
static irq_return_t etna_irq_handler(unsigned int irq, void *data) {
138
struct etnaviv_gpu *gpu = data;
139
irq_return_t ret = IRQ_NONE;
141
uint32_t intr = gpu_read(gpu, VIVS_HI_INTR_ACKNOWLEDGE);
144
log_debug("intr 0x%08x", intr);
146
if (intr & VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR) {
147
uint32_t axi_status = gpu_read(gpu, VIVS_HI_AXI_STATUS);
148
gpu_write(gpu, VIVS_HI_INTR_ACKNOWLEDGE,
149
VIVS_HI_INTR_ACKNOWLEDGE_AXI_BUS_ERROR);
150
log_error("AXI bus error");
151
log_debug("AXI config: %08x", gpu_read(gpu, VIVS_HI_AXI_CONFIG));
152
log_debug("AXI status: %08x", axi_status);
153
if (axi_status & VIVS_HI_AXI_STATUS_DET_WR_ERR) {
154
log_error("AXI bus write error ID =0x%x",
155
VIVS_HI_AXI_STATUS_WR_ERR_ID(axi_status));
157
if (axi_status & VIVS_HI_AXI_STATUS_DET_RD_ERR) {
158
log_error("AXI bus read error ID =0x%x",
159
VIVS_HI_AXI_STATUS_RD_ERR_ID(axi_status));
164
if (intr & VIVS_HI_INTR_ACKNOWLEDGE_MMU_EXCEPTION) {
167
log_error("MMU fault status 0x%08x",
168
gpu_read(gpu, VIVS_MMUv2_STATUS));
169
for (i = 0; i < 4; i++) {
170
log_error("MMU %d fault addr 0x%08x\n", i,
171
gpu_read(gpu, VIVS_MMUv2_EXCEPTION_ADDR(i)));
174
gpu_write(gpu, VIVS_HI_INTR_ACKNOWLEDGE,
175
VIVS_HI_INTR_ACKNOWLEDGE_MMU_EXCEPTION);
181
log_debug("no error");
190
static int etnaviv_dev_open(struct char_dev *cdev, struct idesc *idesc) {
194
etnaviv_drm_device.dev_private = &etnaviv_drm_private;
195
for (i = 0; i < ETNA_MAX_PIPES; i++) {
196
etnaviv_drm_private.gpu[i] = &etnaviv_gpus[i];
198
etnaviv_gpus[PIPE_ID_PIPE_2D].mmio = (void *)VIVANTE_2D_BASE;
199
etnaviv_gpus[PIPE_ID_PIPE_3D].mmio = (void *)VIVANTE_3D_BASE;
201
clk_enable("openvg");
205
imx_gpu_power_set(1);
206
etnaviv_gpu_init(&etnaviv_gpus[PIPE_ID_PIPE_2D]);
207
etnaviv_gpu_debugfs(&etnaviv_gpus[PIPE_ID_PIPE_2D], "GPU2D");
208
etnaviv_gpu_init(&etnaviv_gpus[PIPE_ID_PIPE_3D]);
209
etnaviv_gpu_debugfs(&etnaviv_gpus[PIPE_ID_PIPE_2D], "GPU3D");
211
if (irq_attach(GPU3D_IRQ, etna_irq_handler, 0,
212
&etnaviv_gpus[PIPE_ID_PIPE_3D], "i.MX6 GPU3D")) {
216
if (irq_attach(R2D_GPU2D_IRQ, etna_irq_handler, 0,
217
&etnaviv_gpus[PIPE_ID_PIPE_2D], "i.MX6 GPU2D")) {
221
if (irq_attach(V2D_GPU2D_IRQ, etna_irq_handler, 0,
222
&etnaviv_gpus[PIPE_ID_PIPE_2D], "i.MX6 GPU2D")) {
226
if ((err = vmem_set_flags(vmem_current_context(),
227
(mmu_vaddr_t)etnaviv_uncached_buffer,
228
sizeof(etnaviv_uncached_buffer),
229
PROT_WRITE | PROT_READ | PROT_NOCACHE))) {
230
log_error("Failed to set page attributes! Error %d", err);
236
dcache_flush(etnaviv_uncached_buffer, sizeof(etnaviv_uncached_buffer));
241
static void etnaviv_dev_close(struct char_dev *cdev) {
242
if (irq_detach(GPU3D_IRQ, &etnaviv_gpus[PIPE_ID_PIPE_3D])) {
243
log_error("Failed to detach GPU3D_IRQ");
246
if (irq_detach(R2D_GPU2D_IRQ, &etnaviv_gpus[PIPE_ID_PIPE_2D])) {
247
log_error("Failed to detach R2D_GPU2D_IRQ");
250
if (irq_detach(V2D_GPU2D_IRQ, &etnaviv_gpus[PIPE_ID_PIPE_2D])) {
251
log_error("Failed to detach V2D_GPU2D_IRQ");
254
imx_gpu_power_set(0);
257
int etnaviv_dmp(int id) {
258
assert(id >= 0 && id < ETNA_MAX_PIPES);
259
etnaviv_gpu_debugfs(&etnaviv_gpus[id],
260
id == PIPE_ID_PIPE_2D ? "GPU2D" : "GPU3D");
264
static int etnaviv_dev_idesc_ioctl(struct char_dev *cdev, int request,
266
drm_version_t *version;
267
int nr = _IOC_NR(request);
268
struct drm_device *dev = &etnaviv_drm_device;
269
struct drm_file *file = &etnaviv_drm_file;
270
struct drm_etnaviv_param *args = data;
272
int pipe = args->pipe;
274
log_debug("pipe=%cD, dir=%d, type=%d, nr=%d (%s)",
275
args->pipe == PIPE_ID_PIPE_2D ? '2' : '3', _IOC_DIR(request),
276
_IOC_TYPE(request), _IOC_NR(request),
277
(((nr - 0x40) < DRM_ETNAVIV_CALL_NR_MAX) && ((nr - 0x40) >= 0))
278
? (drm_call_to_string[nr - 0x40])
283
*version = (drm_version_t){
286
.name_len = VERSION_NAME_LEN,
287
.name = strdup(VERSION_NAME),
288
.date_len = VERSION_DATE_LEN,
289
.date = strdup(VERSION_DATE),
290
.desc_len = VERSION_DESC_LEN,
291
.desc = strdup(VERSION_DESC),
295
case DRM_COMMAND_BASE + DRM_ETNAVIV_GET_PARAM:
296
res = etnaviv_gpu_get_param(&etnaviv_gpus[pipe], args->param,
299
case DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_NEW:
300
res = etnaviv_ioctl_gem_new(dev, data, file);
302
case DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_INFO:
303
res = etnaviv_ioctl_gem_info(dev, data, file);
305
case DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_SUBMIT:
306
res = etnaviv_ioctl_gem_submit(dev, data, file);
308
case DRM_COMMAND_BASE + DRM_ETNAVIV_WAIT_FENCE:
309
res = etnaviv_ioctl_wait_fence(dev, data, file);
312
log_error("NIY, request=%x", nr);
319
static int etnaviv_dev_idesc_fstat(struct char_dev *cdev, void *buff) {
320
struct stat *st = buff;
322
st->st_rdev = makedev(226 , 0);
323
st->st_mode = S_IFCHR;
328
static int etnaviv_dev_idesc_status(struct char_dev *cdev, int mask) {
334
static void *etnaviv_dev_idesc_mmap(struct idesc *idesc, void *addr, size_t len,
335
int prot, int flags, int fd, off_t off) {
336
void *res = &etnaviv_uncached_buffer[ptr];
337
struct drm_gem_object *obj;
338
obj = (void *)(uint32_t)off;
350
static void *etnaviv_dev_direct_access(struct char_dev *cdev, off_t off,
352
if (off + len >= sizeof(etnaviv_uncached_buffer)) {
356
return &etnaviv_uncached_buffer[off];
359
static struct char_dev_ops etnaviv_dev_ops = {
360
.open = etnaviv_dev_open,
361
.close = etnaviv_dev_close,
362
.ioctl = etnaviv_dev_idesc_ioctl,
363
.status = etnaviv_dev_idesc_status,
364
.direct_access = etnaviv_dev_direct_access,
367
static struct char_dev etnaviv_dev = CHAR_DEV_INIT(etnaviv_dev, "card",
370
CHAR_DEV_REGISTER(&etnaviv_dev);
372
PERIPH_MEMORY_DEFINE(vivante2d, VIVANTE_2D_BASE, 0x4000);
373
PERIPH_MEMORY_DEFINE(vivante3d, VIVANTE_3D_BASE, 0x4000);