embox

Форк
0
/
etnaviv_dev.c 
373 строки · 9.7 Кб
1
/**
2
 * @file
3
 * @brief Direct Rendering Manager compatibility module
4
 * @author Denis Deryugin <deryugin.denis@gmail.com>
5
 * @version
6
 * @date 06.12.2017
7
 */
8

9
#include <drm.h>
10
#include <errno.h>
11
#include <etnaviv_drm.h>
12
#include <stddef.h>
13
#include <stdint.h>
14
#include <stdio.h>
15
#include <stdlib.h>
16
#include <string.h>
17
#include <sys/mman.h>
18
#include <sys/stat.h>
19
#include <sys/uio.h>
20

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>
29
#include <fs/dvfs.h>
30
#include <hal/cache.h>
31
#include <kernel/irq.h>
32
#include <mem/vmem.h>
33
#include <util/err.h>
34
#include <util/log.h>
35
#include <util/macro.h>
36

37
#include "etnaviv_drv.h"
38
#include "etnaviv_gem.h"
39
#include "etnaviv_gpu.h"
40

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
47

48
/* Interrupt numbers */
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)
52

53
#define ETNA_UNCACHED_BUFFER_SZ (16 * 1024 * 1024)
54

55
static uint8_t etnaviv_uncached_buffer[ETNA_UNCACHED_BUFFER_SZ]
56
    __attribute__((aligned(0x1000)));
57
/*
58
 * DRM ioctls:
59
 */
60

61
static const char *drm_call_to_string[] = {
62
    [0x00] = "GET_PARAM   ",
63
    [0x01] = "SET_PARAM   ",
64
    [0x02] = "GEM_NEW     ",
65
    [0x03] = "GEM_INFO    ",
66
    [0x04] = "GEM_CPU_PREP",
67
    [0x05] = "GEM_CPU_FINI",
68
    [0x06] = "GEM_SUBMIT  ",
69
    [0x07] = "WAIT_FENCE  ",
70
    [0x08] = "GEM_USERPTR ",
71
    [0x09] = "GEM_WAIT    ",
72
    [0x0a] = "NUM_IOCTLS  ",
73
};
74

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;
78

79
	if (args->flags
80
	    & ~(ETNA_BO_CACHED | ETNA_BO_WC | ETNA_BO_UNCACHED
81
	        | ETNA_BO_FORCE_MMU)) {
82
		log_error("unsupported flags");
83
	}
84

85
	return etnaviv_gem_new_handle(dev, file, args->size, args->flags,
86
	    (void *)&args->handle);
87
}
88

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;
93
	int ret;
94

95
	if (args->pad)
96
		return -EINVAL;
97

98
	obj = drm_gem_object_lookup(file, args->handle);
99
	if (!obj) {
100
		log_error("obj (%p) didn't found", args->handle);
101
		return -ENOENT;
102
	}
103
	log_debug("obj (%p) founded by handle (%i)", obj, args->handle);
104

105
	ret = etnaviv_gem_mmap_offset(obj, &args->offset);
106

107
	return ret;
108
}
109

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;
115

116
	if (args->flags & ~(ETNA_WAIT_NONBLOCK))
117
		return -EINVAL;
118

119
	if (args->pipe >= ETNA_MAX_PIPES)
120
		return -EINVAL;
121

122
	gpu = priv->gpu[args->pipe];
123
	if (!gpu)
124
		return -ENXIO;
125

126
	return 0;
127
}
128

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];
133

134
#define VIVANTE_2D_BASE OPTION_GET(NUMBER, vivante_2d_base)
135
#define VIVANTE_3D_BASE OPTION_GET(NUMBER, vivante_3d_base)
136

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;
140
	int noerr = 1;
141
	uint32_t intr = gpu_read(gpu, VIVS_HI_INTR_ACKNOWLEDGE);
142

143
	if (intr != 0) {
144
		log_debug("intr 0x%08x", intr);
145
		gpu->busy = 0;
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));
156
			}
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));
160
			}
161
			noerr = 0;
162
		}
163

164
		if (intr & VIVS_HI_INTR_ACKNOWLEDGE_MMU_EXCEPTION) {
165
			int i;
166

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)));
172
			}
173

174
			gpu_write(gpu, VIVS_HI_INTR_ACKNOWLEDGE,
175
			    VIVS_HI_INTR_ACKNOWLEDGE_MMU_EXCEPTION);
176

177
			noerr = 0;
178
		}
179

180
		if (noerr) {
181
			log_debug("no error");
182
		}
183

184
		ret = IRQ_HANDLED;
185
	}
186

187
	return ret;
188
}
189

190
static int etnaviv_dev_open(struct char_dev *cdev, struct idesc *idesc) {
191
	int err;
192
	int i;
193

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];
197
	}
198
	etnaviv_gpus[PIPE_ID_PIPE_2D].mmio = (void *)VIVANTE_2D_BASE;
199
	etnaviv_gpus[PIPE_ID_PIPE_3D].mmio = (void *)VIVANTE_3D_BASE;
200

201
	clk_enable("openvg");
202
	clk_enable("gpu3d");
203
	clk_enable("gpu2d");
204
	clk_enable("vpu");
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");
210

211
	if (irq_attach(GPU3D_IRQ, etna_irq_handler, 0,
212
	        &etnaviv_gpus[PIPE_ID_PIPE_3D], "i.MX6 GPU3D")) {
213
		return -1;
214
	}
215

216
	if (irq_attach(R2D_GPU2D_IRQ, etna_irq_handler, 0,
217
	        &etnaviv_gpus[PIPE_ID_PIPE_2D], "i.MX6 GPU2D")) {
218
		return -1;
219
	}
220

221
	if (irq_attach(V2D_GPU2D_IRQ, etna_irq_handler, 0,
222
	        &etnaviv_gpus[PIPE_ID_PIPE_2D], "i.MX6 GPU2D")) {
223
		return -1;
224
	}
225

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);
231

232
		return -1;
233
	}
234

235
	mmu_flush_tlb();
236
	dcache_flush(etnaviv_uncached_buffer, sizeof(etnaviv_uncached_buffer));
237

238
	return 0;
239
}
240

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");
244
	}
245

246
	if (irq_detach(R2D_GPU2D_IRQ, &etnaviv_gpus[PIPE_ID_PIPE_2D])) {
247
		log_error("Failed to detach R2D_GPU2D_IRQ");
248
	}
249

250
	if (irq_detach(V2D_GPU2D_IRQ, &etnaviv_gpus[PIPE_ID_PIPE_2D])) {
251
		log_error("Failed to detach V2D_GPU2D_IRQ");
252
	}
253

254
	imx_gpu_power_set(0);
255
}
256

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");
261
	return 0;
262
}
263

264
static int etnaviv_dev_idesc_ioctl(struct char_dev *cdev, int request,
265
    void *data) {
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;
271
	int res = 0;
272
	int pipe = args->pipe;
273

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])
279
	        : "UNKNOWN");
280
	switch (nr) {
281
	case 0: /* DRM_IOCTL_VERSION */
282
		version = data;
283
		*version = (drm_version_t){
284
		    .version_major = 1,
285
		    .version_minor = 1,
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),
292
		};
293

294
		break;
295
	case DRM_COMMAND_BASE + DRM_ETNAVIV_GET_PARAM:
296
		res = etnaviv_gpu_get_param(&etnaviv_gpus[pipe], args->param,
297
		    &args->value);
298
		break;
299
	case DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_NEW:
300
		res = etnaviv_ioctl_gem_new(dev, data, file);
301
		break;
302
	case DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_INFO:
303
		res = etnaviv_ioctl_gem_info(dev, data, file);
304
		break;
305
	case DRM_COMMAND_BASE + DRM_ETNAVIV_GEM_SUBMIT:
306
		res = etnaviv_ioctl_gem_submit(dev, data, file);
307
		break;
308
	case DRM_COMMAND_BASE + DRM_ETNAVIV_WAIT_FENCE:
309
		res = etnaviv_ioctl_wait_fence(dev, data, file);
310
		break;
311
	default:
312
		log_error("NIY, request=%x", nr);
313
	}
314

315
	return res;
316
}
317

318
#if 0
319
static int etnaviv_dev_idesc_fstat(struct char_dev *cdev, void *buff) {
320
	struct stat *st = buff;
321

322
	st->st_rdev = makedev(226 /* Linux maj */, 0);
323
	st->st_mode = S_IFCHR;
324
	return 0;
325
}
326
#endif
327

328
static int etnaviv_dev_idesc_status(struct char_dev *cdev, int mask) {
329
	return 0;
330
}
331

332
#if 0
333
static int ptr = 0;
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;
339

340
	obj->dma_buf = res;
341

342
	ptr += len;
343

344
	memset(res, 0, len);
345

346
	return NULL;
347
}
348
#endif
349

350
static void *etnaviv_dev_direct_access(struct char_dev *cdev, off_t off,
351
    size_t len) {
352
	if (off + len >= sizeof(etnaviv_uncached_buffer)) {
353
		return NULL;
354
	}
355

356
	return &etnaviv_uncached_buffer[off];
357
}
358

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,
365
};
366

367
static struct char_dev etnaviv_dev = CHAR_DEV_INIT(etnaviv_dev, "card",
368
    &etnaviv_dev_ops);
369

370
CHAR_DEV_REGISTER(&etnaviv_dev);
371

372
PERIPH_MEMORY_DEFINE(vivante2d, VIVANTE_2D_BASE, 0x4000);
373
PERIPH_MEMORY_DEFINE(vivante3d, VIVANTE_3D_BASE, 0x4000);
374

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.