summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm/adreno/adreno_gpu.h
blob: 17c5628de8a8907706db3ec46c041a559e803850 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
/*
 * Copyright (C) 2013 Red Hat
 * Author: Rob Clark <robdclark@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __ADRENO_GPU_H__
#define __ADRENO_GPU_H__

#include <linux/firmware.h>
#include <drm/drm_adreno.h>

#include "msm_gpu.h"
#include "adreno_ringbuffer.h"

#include "adreno_common.xml.h"
#include "adreno_pm4.xml.h"

static int adreno_reglog;

struct adreno_rev {
	uint8_t  core;
	uint8_t  major;
	uint8_t  minor;
	uint8_t  patchid;
};

#define ADRENO_REV(core, major, minor, patchid) \
	((struct adreno_rev){ core, major, minor, patchid })

struct adreno_info;

struct adreno_rbmemptrs {
	volatile uint32_t rptr;
	volatile uint32_t wptr;
	volatile uint32_t fence;
};

struct adreno_gpu {
	struct msm_gpu base;
	struct platform_device *pdev;
	struct drm_device *drm;
	struct adreno_rev rev;
	const struct adreno_info *info;
	uint32_t revn;  /* numeric revision name */
	const struct adreno_gpu_funcs *funcs;
	struct adreno_gem *gem;
	struct workqueue_struct *shared_wq;

	/* firmware: */
	const struct firmware *pm4, *pfp;

	void __iomem *mmio;
	int irq;

	/* ringbuffer rptr/wptr: */
	// TODO should this be in adreno_ringbuffer?  I think it would be
	// different for z180..
	struct adreno_rbmemptrs *memptrs;
	struct drm_gem_object *memptrs_bo;
	uint32_t memptrs_iova;

	uint32_t submitted_fence;

	struct adreno_ringbuffer *rb;
	uint32_t rb_iova;

	struct adreno_context *lastctx;

	/* Hang Detction: */
#define DRM_MSM_HANGCHECK_PERIOD 500 /* in ms */
#define DRM_MSM_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_MSM_HANGCHECK_PERIOD)
	struct timer_list hangcheck_timer;
	uint32_t hangcheck_fence;
	struct work_struct recover_work;
};
#define to_adreno_gpu(x) container_of(x, struct adreno_gpu, base)

/* platform config data (ie. from DT, or pdata) */
struct adreno_platform_config {
	struct adreno_rev rev;
	uint32_t fast_rate, slow_rate, bus_freq;
};

#define ADRENO_IDLE_TIMEOUT (20 * 1000)

static inline bool adreno_is_a3xx(struct adreno_gpu *gpu)
{
	return (gpu->revn >= 300) && (gpu->revn < 400);
}

static inline bool adreno_is_a305(struct adreno_gpu *gpu)
{
	return gpu->revn == 305;
}

static inline bool adreno_is_a320(struct adreno_gpu *gpu)
{
	return gpu->revn == 320;
}

static inline bool adreno_is_a330(struct adreno_gpu *gpu)
{
	return gpu->revn == 330;
}

int adreno_get_param(struct adreno_gpu *gpu, uint32_t param, uint64_t *value);
int adreno_hw_init(struct adreno_gpu *gpu);
uint32_t adreno_last_fence(struct adreno_gpu *gpu);
void adreno_recover(struct adreno_gpu *gpu);
int adreno_submit(struct adreno_gpu *gpu, struct adreno_submit *submit,
		struct adreno_context *ctx);
void adreno_flush(struct adreno_gpu *gpu);
void adreno_idle(struct adreno_gpu *gpu);
#ifdef CONFIG_DEBUG_FS
void adreno_show(struct adreno_gpu *gpu, struct seq_file *m);
#endif
void adreno_wait_ring(struct adreno_gpu *gpu, uint32_t ndwords);

int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
		struct adreno_gpu *gpu, const struct adreno_gpu_funcs *funcs,
		struct adreno_gem *gem, struct workqueue_struct *wq,
		struct adreno_rev rev);
void adreno_gpu_cleanup(struct adreno_gpu *gpu);

static inline void gpu_write(struct adreno_gpu *gpu, u32 reg, u32 data)
{
	void __iomem *addr = gpu->mmio + (reg << 2);

	if (IS_ENABLED(CONFIG_DRM_MSM_REGISTER_LOGGING) &&
	    unlikely(adreno_reglog))
		printk(KERN_DEBUG "IO:W %08x %08x\n", (u32)addr, data);

	writel(data, addr);
}

static inline u32 gpu_read(struct adreno_gpu *gpu, u32 reg)
{
	void __iomem *addr = gpu->mmio + (reg << 2);
	u32 val = readl(addr);

	if (IS_ENABLED(CONFIG_DRM_MSM_REGISTER_LOGGING) &&
		    unlikely(adreno_reglog))
		printk(KERN_ERR "IO:R %08x %08x\n", (u32)addr, val);

	return val;
}

/* ringbuffer helpers (the parts that are adreno specific) */

static inline void
OUT_PKT0(struct adreno_ringbuffer *ring, uint16_t regindx, uint16_t cnt)
{
	adreno_wait_ring(ring->gpu, cnt+1);
	OUT_RING(ring, CP_TYPE0_PKT | ((cnt-1) << 16) | (regindx & 0x7FFF));
}

/* no-op packet: */
static inline void
OUT_PKT2(struct adreno_ringbuffer *ring)
{
	adreno_wait_ring(ring->gpu, 1);
	OUT_RING(ring, CP_TYPE2_PKT);
}

static inline void
OUT_PKT3(struct adreno_ringbuffer *ring, uint8_t opcode, uint16_t cnt)
{
	adreno_wait_ring(ring->gpu, cnt+1);
	OUT_RING(ring, CP_TYPE3_PKT | ((cnt-1) << 16) | ((opcode & 0xFF) << 8));
}


#endif /* __ADRENO_GPU_H__ */