blob: 04a2f7539712fc83677389a3d2e528ca74d76993 [file] [log] [blame]
Thomas Gleixnercaab2772019-06-03 07:44:50 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Rob Clark7198e6b2013-07-19 12:59:32 -04002/*
3 * Copyright (C) 2013 Red Hat
4 * Author: Rob Clark <robdclark@gmail.com>
Rob Clark7198e6b2013-07-19 12:59:32 -04005 */
6
7#ifndef __MSM_GPU_H__
8#define __MSM_GPU_H__
9
Rob Clark9cba4052020-08-17 15:01:32 -070010#include <linux/adreno-smmu-priv.h>
Rob Clark7198e6b2013-07-19 12:59:32 -040011#include <linux/clk.h>
Jordan Crousefcf9d0b2019-02-12 11:52:38 +020012#include <linux/interconnect.h>
Sharat Masetty1f60d112020-07-13 18:11:42 +053013#include <linux/pm_opp.h>
Rob Clark7198e6b2013-07-19 12:59:32 -040014#include <linux/regulator/consumer.h>
15
16#include "msm_drv.h"
Rob Clarkca762a82016-03-15 17:22:13 -040017#include "msm_fence.h"
Rob Clark7198e6b2013-07-19 12:59:32 -040018#include "msm_ringbuffer.h"
Jordan Crouse604234f2020-09-03 20:03:11 -060019#include "msm_gem.h"
Rob Clark7198e6b2013-07-19 12:59:32 -040020
21struct msm_gem_submit;
Rob Clark70c70f02014-05-30 14:49:43 -040022struct msm_gpu_perfcntr;
Jordan Crousee00e4732018-07-24 10:33:24 -060023struct msm_gpu_state;
Rob Clark7198e6b2013-07-19 12:59:32 -040024
Jordan Crouse5770fc72017-05-08 14:35:03 -060025struct msm_gpu_config {
26 const char *ioname;
Jordan Crousef97deca2017-10-20 11:06:57 -060027 unsigned int nr_rings;
Jordan Crouse5770fc72017-05-08 14:35:03 -060028};
29
Rob Clark7198e6b2013-07-19 12:59:32 -040030/* So far, with hardware that I've seen to date, we can have:
31 * + zero, one, or two z180 2d cores
32 * + a3xx or a2xx 3d core, which share a common CP (the firmware
33 * for the CP seems to implement some different PM4 packet types
34 * but the basics of cmdstream submission are the same)
35 *
36 * Which means that the eventual complete "class" hierarchy, once
37 * support for all past and present hw is in place, becomes:
38 * + msm_gpu
39 * + adreno_gpu
40 * + a3xx_gpu
41 * + a2xx_gpu
42 * + z180_gpu
43 */
44struct msm_gpu_funcs {
45 int (*get_param)(struct msm_gpu *gpu, uint32_t param, uint64_t *value);
46 int (*hw_init)(struct msm_gpu *gpu);
47 int (*pm_suspend)(struct msm_gpu *gpu);
48 int (*pm_resume)(struct msm_gpu *gpu);
Jordan Crouse15eb9ad2020-08-17 15:01:37 -070049 void (*submit)(struct msm_gpu *gpu, struct msm_gem_submit *submit);
Jordan Crousef97deca2017-10-20 11:06:57 -060050 void (*flush)(struct msm_gpu *gpu, struct msm_ringbuffer *ring);
Rob Clark7198e6b2013-07-19 12:59:32 -040051 irqreturn_t (*irq)(struct msm_gpu *irq);
Jordan Crousef97deca2017-10-20 11:06:57 -060052 struct msm_ringbuffer *(*active_ring)(struct msm_gpu *gpu);
Rob Clarkbd6f82d2013-08-24 14:20:38 -040053 void (*recover)(struct msm_gpu *gpu);
Rob Clark7198e6b2013-07-19 12:59:32 -040054 void (*destroy)(struct msm_gpu *gpu);
Arnd Bergmannc878a622018-08-13 23:23:44 +020055#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_DEV_COREDUMP)
Rob Clark7198e6b2013-07-19 12:59:32 -040056 /* show GPU status in debugfs: */
Jordan Crouse4f776f42018-07-24 10:33:25 -060057 void (*show)(struct msm_gpu *gpu, struct msm_gpu_state *state,
Jordan Crousec0fec7f2018-07-24 10:33:27 -060058 struct drm_printer *p);
Rob Clark331dc0b2017-12-13 15:12:56 -050059 /* for generation specific debugfs: */
Wambui Karuga7ce844712020-03-10 16:31:21 +030060 void (*debugfs_init)(struct msm_gpu *gpu, struct drm_minor *minor);
Rob Clark7198e6b2013-07-19 12:59:32 -040061#endif
Sharat Masettyde0a3d092018-10-04 15:11:42 +053062 unsigned long (*gpu_busy)(struct msm_gpu *gpu);
Jordan Crousee00e4732018-07-24 10:33:24 -060063 struct msm_gpu_state *(*gpu_state_get)(struct msm_gpu *gpu);
Jordan Crousec0fec7f2018-07-24 10:33:27 -060064 int (*gpu_state_put)(struct msm_gpu_state *state);
Sharat Masettyde0a3d092018-10-04 15:11:42 +053065 unsigned long (*gpu_get_freq)(struct msm_gpu *gpu);
Sharat Masetty1f60d112020-07-13 18:11:42 +053066 void (*gpu_set_freq)(struct msm_gpu *gpu, struct dev_pm_opp *opp);
Jordan Crouseccac7ce2020-05-22 16:03:15 -060067 struct msm_gem_address_space *(*create_address_space)
68 (struct msm_gpu *gpu, struct platform_device *pdev);
Jordan Crouse933415e2020-08-17 15:01:40 -070069 struct msm_gem_address_space *(*create_private_address_space)
70 (struct msm_gpu *gpu);
Rob Clark7198e6b2013-07-19 12:59:32 -040071};
72
73struct msm_gpu {
74 const char *name;
75 struct drm_device *dev;
Rob Clarkeeb75472017-02-10 15:36:33 -050076 struct platform_device *pdev;
Rob Clark7198e6b2013-07-19 12:59:32 -040077 const struct msm_gpu_funcs *funcs;
78
Rob Clark9cba4052020-08-17 15:01:32 -070079 struct adreno_smmu_priv adreno_smmu;
80
Rob Clark70c70f02014-05-30 14:49:43 -040081 /* performance counters (hw & sw): */
82 spinlock_t perf_lock;
83 bool perfcntr_active;
84 struct {
85 bool active;
86 ktime_t time;
87 } last_sample;
88 uint32_t totaltime, activetime; /* sw counters */
89 uint32_t last_cntrs[5]; /* hw counters */
90 const struct msm_gpu_perfcntr *perfcntrs;
91 uint32_t num_perfcntrs;
92
Jordan Crousef97deca2017-10-20 11:06:57 -060093 struct msm_ringbuffer *rb[MSM_GPU_MAX_RINGS];
94 int nr_rings;
Rob Clark7198e6b2013-07-19 12:59:32 -040095
96 /* list of GEM active objects: */
97 struct list_head active_list;
98
Rob Clarkeeb75472017-02-10 15:36:33 -050099 /* does gpu need hw_init? */
100 bool needs_hw_init;
Rob Clark37d77c32014-01-11 16:25:08 -0500101
Rob Clark48dc4242019-04-16 16:13:28 -0700102 /* number of GPU hangs (for all contexts) */
103 int global_faults;
104
Rob Clark7198e6b2013-07-19 12:59:32 -0400105 /* worker for handling active-list retiring: */
106 struct work_struct retire_work;
107
108 void __iomem *mmio;
109 int irq;
110
Rob Clark667ce332016-09-28 19:58:32 -0400111 struct msm_gem_address_space *aspace;
Rob Clark7198e6b2013-07-19 12:59:32 -0400112
113 /* Power Control: */
114 struct regulator *gpu_reg, *gpu_cx;
Jordan Crouse8e54eea2018-08-06 11:33:21 -0600115 struct clk_bulk_data *grp_clks;
Jordan Crouse98db8032017-03-07 10:02:56 -0700116 int nr_clocks;
117 struct clk *ebi1_clk, *core_clk, *rbbmtimer_clk;
Jordan Crouse1babd702017-11-21 12:40:53 -0700118 uint32_t fast_rate;
Rob Clarkbd6f82d2013-08-24 14:20:38 -0400119
Brian Masney00bb9242019-11-21 20:26:43 -0500120 /* The gfx-mem interconnect path that's used by all GPU types. */
Jordan Crousefcf9d0b2019-02-12 11:52:38 +0200121 struct icc_path *icc_path;
122
Brian Masney00bb9242019-11-21 20:26:43 -0500123 /*
124 * Second interconnect path for some A3xx and all A4xx GPUs to the
125 * On Chip MEMory (OCMEM).
126 */
127 struct icc_path *ocmem_icc_path;
128
Rob Clark37d77c32014-01-11 16:25:08 -0500129 /* Hang and Inactivity Detection:
130 */
131#define DRM_MSM_INACTIVE_PERIOD 66 /* in ms (roughly four frames) */
Rob Clarkeeb75472017-02-10 15:36:33 -0500132
Rob Clarkbd6f82d2013-08-24 14:20:38 -0400133#define DRM_MSM_HANGCHECK_PERIOD 500 /* in ms */
134#define DRM_MSM_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_MSM_HANGCHECK_PERIOD)
135 struct timer_list hangcheck_timer;
Rob Clarkbd6f82d2013-08-24 14:20:38 -0400136 struct work_struct recover_work;
Rob Clark1a370be2015-06-07 13:46:04 -0400137
Jordan Crousecd414f32017-10-20 11:06:56 -0600138 struct drm_gem_object *memptrs_bo;
Jordan Crousef91c14a2018-01-10 10:41:54 -0700139
140 struct {
141 struct devfreq *devfreq;
142 u64 busy_cycles;
143 ktime_t time;
144 } devfreq;
Jordan Crousec0fec7f2018-07-24 10:33:27 -0600145
146 struct msm_gpu_state *crashstate;
Jordan Crouse604234f2020-09-03 20:03:11 -0600147 /* True if the hardware supports expanded apriv (a650 and newer) */
148 bool hw_apriv;
Rob Clark7198e6b2013-07-19 12:59:32 -0400149};
150
Rob Clark69a93132020-08-17 15:01:31 -0700151static inline struct msm_gpu *dev_to_gpu(struct device *dev)
152{
Rob Clark9cba4052020-08-17 15:01:32 -0700153 struct adreno_smmu_priv *adreno_smmu = dev_get_drvdata(dev);
154 return container_of(adreno_smmu, struct msm_gpu, adreno_smmu);
Rob Clark69a93132020-08-17 15:01:31 -0700155}
156
Jordan Crousef97deca2017-10-20 11:06:57 -0600157/* It turns out that all targets use the same ringbuffer size */
158#define MSM_GPU_RINGBUFFER_SZ SZ_32K
Jordan Crouse4d87fc32017-10-20 11:07:00 -0600159#define MSM_GPU_RINGBUFFER_BLKSIZE 32
160
161#define MSM_GPU_RB_CNTL_DEFAULT \
162 (AXXX_CP_RB_CNTL_BUFSZ(ilog2(MSM_GPU_RINGBUFFER_SZ / 8)) | \
163 AXXX_CP_RB_CNTL_BLKSZ(ilog2(MSM_GPU_RINGBUFFER_BLKSIZE / 8)))
Jordan Crousef97deca2017-10-20 11:06:57 -0600164
Rob Clark37d77c32014-01-11 16:25:08 -0500165static inline bool msm_gpu_active(struct msm_gpu *gpu)
166{
Jordan Crousef97deca2017-10-20 11:06:57 -0600167 int i;
168
169 for (i = 0; i < gpu->nr_rings; i++) {
170 struct msm_ringbuffer *ring = gpu->rb[i];
171
172 if (ring->seqno > ring->memptrs->fence)
173 return true;
174 }
175
176 return false;
Rob Clark37d77c32014-01-11 16:25:08 -0500177}
178
Rob Clark70c70f02014-05-30 14:49:43 -0400179/* Perf-Counters:
180 * The select_reg and select_val are just there for the benefit of the child
181 * class that actually enables the perf counter.. but msm_gpu base class
182 * will handle sampling/displaying the counters.
183 */
184
185struct msm_gpu_perfcntr {
186 uint32_t select_reg;
187 uint32_t sample_reg;
188 uint32_t select_val;
189 const char *name;
190};
191
Jordan Crousef7de1542017-10-20 11:06:55 -0600192struct msm_gpu_submitqueue {
193 int id;
194 u32 flags;
195 u32 prio;
196 int faults;
Jordan Crousecf655d62020-08-17 15:01:36 -0700197 struct msm_file_private *ctx;
Jordan Crousef7de1542017-10-20 11:06:55 -0600198 struct list_head node;
199 struct kref ref;
200};
201
Jordan Crousecdb95932018-07-24 10:33:31 -0600202struct msm_gpu_state_bo {
203 u64 iova;
204 size_t size;
205 void *data;
Sharat Masetty1df42892018-11-01 20:16:45 +0530206 bool encoded;
Jordan Crousecdb95932018-07-24 10:33:31 -0600207};
208
Jordan Crousee00e4732018-07-24 10:33:24 -0600209struct msm_gpu_state {
Jordan Crousec0fec7f2018-07-24 10:33:27 -0600210 struct kref ref;
Arnd Bergmann3530a172018-07-26 14:39:25 +0200211 struct timespec64 time;
Jordan Crousee00e4732018-07-24 10:33:24 -0600212
213 struct {
214 u64 iova;
215 u32 fence;
216 u32 seqno;
217 u32 rptr;
218 u32 wptr;
Jordan Crouse43a56682018-07-24 10:33:29 -0600219 void *data;
220 int data_size;
Sharat Masetty1df42892018-11-01 20:16:45 +0530221 bool encoded;
Jordan Crousee00e4732018-07-24 10:33:24 -0600222 } ring[MSM_GPU_MAX_RINGS];
223
224 int nr_registers;
225 u32 *registers;
226
227 u32 rbbm_status;
Jordan Crousec0fec7f2018-07-24 10:33:27 -0600228
229 char *comm;
230 char *cmd;
Jordan Crousecdb95932018-07-24 10:33:31 -0600231
232 int nr_bos;
233 struct msm_gpu_state_bo *bos;
Jordan Crousee00e4732018-07-24 10:33:24 -0600234};
235
Rob Clark7198e6b2013-07-19 12:59:32 -0400236static inline void gpu_write(struct msm_gpu *gpu, u32 reg, u32 data)
237{
238 msm_writel(data, gpu->mmio + (reg << 2));
239}
240
241static inline u32 gpu_read(struct msm_gpu *gpu, u32 reg)
242{
243 return msm_readl(gpu->mmio + (reg << 2));
244}
245
Jordan Crouseae53a822016-11-28 12:28:28 -0700246static inline void gpu_rmw(struct msm_gpu *gpu, u32 reg, u32 mask, u32 or)
247{
248 uint32_t val = gpu_read(gpu, reg);
249
250 val &= ~mask;
251 gpu_write(gpu, reg, val | or);
252}
253
254static inline u64 gpu_read64(struct msm_gpu *gpu, u32 lo, u32 hi)
255{
256 u64 val;
257
258 /*
259 * Why not a readq here? Two reasons: 1) many of the LO registers are
260 * not quad word aligned and 2) the GPU hardware designers have a bit
261 * of a history of putting registers where they fit, especially in
262 * spins. The longer a GPU family goes the higher the chance that
263 * we'll get burned. We could do a series of validity checks if we
264 * wanted to, but really is a readq() that much better? Nah.
265 */
266
267 /*
268 * For some lo/hi registers (like perfcounters), the hi value is latched
269 * when the lo is read, so make sure to read the lo first to trigger
270 * that
271 */
272 val = (u64) msm_readl(gpu->mmio + (lo << 2));
273 val |= ((u64) msm_readl(gpu->mmio + (hi << 2)) << 32);
274
275 return val;
276}
277
278static inline void gpu_write64(struct msm_gpu *gpu, u32 lo, u32 hi, u64 val)
279{
280 /* Why not a writeq here? Read the screed above */
281 msm_writel(lower_32_bits(val), gpu->mmio + (lo << 2));
282 msm_writel(upper_32_bits(val), gpu->mmio + (hi << 2));
283}
284
Rob Clark7198e6b2013-07-19 12:59:32 -0400285int msm_gpu_pm_suspend(struct msm_gpu *gpu);
286int msm_gpu_pm_resume(struct msm_gpu *gpu);
Sharat Masettyde0a3d092018-10-04 15:11:42 +0530287void msm_gpu_resume_devfreq(struct msm_gpu *gpu);
Rob Clark7198e6b2013-07-19 12:59:32 -0400288
Rob Clarkeeb75472017-02-10 15:36:33 -0500289int msm_gpu_hw_init(struct msm_gpu *gpu);
290
Rob Clark70c70f02014-05-30 14:49:43 -0400291void msm_gpu_perfcntr_start(struct msm_gpu *gpu);
292void msm_gpu_perfcntr_stop(struct msm_gpu *gpu);
293int msm_gpu_perfcntr_sample(struct msm_gpu *gpu, uint32_t *activetime,
294 uint32_t *totaltime, uint32_t ncntrs, uint32_t *cntrs);
295
Rob Clark7198e6b2013-07-19 12:59:32 -0400296void msm_gpu_retire(struct msm_gpu *gpu);
Jordan Crouse15eb9ad2020-08-17 15:01:37 -0700297void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit);
Rob Clark7198e6b2013-07-19 12:59:32 -0400298
299int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
300 struct msm_gpu *gpu, const struct msm_gpu_funcs *funcs,
Jordan Crouse5770fc72017-05-08 14:35:03 -0600301 const char *name, struct msm_gpu_config *config);
302
Jordan Crouse933415e2020-08-17 15:01:40 -0700303struct msm_gem_address_space *
304msm_gpu_create_private_address_space(struct msm_gpu *gpu);
305
Rob Clark7198e6b2013-07-19 12:59:32 -0400306void msm_gpu_cleanup(struct msm_gpu *gpu);
307
Rob Clarke2550b72014-09-05 13:30:27 -0400308struct msm_gpu *adreno_load_gpu(struct drm_device *dev);
Rob Clarkbfd28b12014-09-05 13:06:37 -0400309void __init adreno_register(void);
310void __exit adreno_unregister(void);
Rob Clark7198e6b2013-07-19 12:59:32 -0400311
Jordan Crousef7de1542017-10-20 11:06:55 -0600312static inline void msm_submitqueue_put(struct msm_gpu_submitqueue *queue)
313{
314 if (queue)
315 kref_put(&queue->ref, msm_submitqueue_destroy);
316}
317
Jordan Crousec0fec7f2018-07-24 10:33:27 -0600318static inline struct msm_gpu_state *msm_gpu_crashstate_get(struct msm_gpu *gpu)
319{
320 struct msm_gpu_state *state = NULL;
321
322 mutex_lock(&gpu->dev->struct_mutex);
323
324 if (gpu->crashstate) {
325 kref_get(&gpu->crashstate->ref);
326 state = gpu->crashstate;
327 }
328
329 mutex_unlock(&gpu->dev->struct_mutex);
330
331 return state;
332}
333
334static inline void msm_gpu_crashstate_put(struct msm_gpu *gpu)
335{
336 mutex_lock(&gpu->dev->struct_mutex);
337
338 if (gpu->crashstate) {
339 if (gpu->funcs->gpu_state_put(gpu->crashstate))
340 gpu->crashstate = NULL;
341 }
342
343 mutex_unlock(&gpu->dev->struct_mutex);
344}
345
Jordan Crouse604234f2020-09-03 20:03:11 -0600346/*
347 * Simple macro to semi-cleanly add the MAP_PRIV flag for targets that can
348 * support expanded privileges
349 */
350#define check_apriv(gpu, flags) \
351 (((gpu)->hw_apriv ? MSM_BO_MAP_PRIV : 0) | (flags))
352
353
Rob Clark7198e6b2013-07-19 12:59:32 -0400354#endif /* __MSM_GPU_H__ */