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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
|
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) 2015-2018 The Linux Foundation. All rights reserved.
*/
#ifndef __DPU_ENCODER_PHYS_H__
#define __DPU_ENCODER_PHYS_H__
#include <drm/drm_writeback.h>
#include <linux/jiffies.h>
#include "dpu_kms.h"
#include "dpu_hw_intf.h"
#include "dpu_hw_wb.h"
#include "dpu_hw_pingpong.h"
#include "dpu_hw_cdm.h"
#include "dpu_hw_ctl.h"
#include "dpu_hw_top.h"
#include "dpu_hw_util.h"
#include "dpu_encoder.h"
#include "dpu_crtc.h"
#define DPU_ENCODER_NAME_MAX 16
/* wait for at most 2 vsync for lowest refresh rate (24hz) */
#define KICKOFF_TIMEOUT_MS 84
#define KICKOFF_TIMEOUT_JIFFIES msecs_to_jiffies(KICKOFF_TIMEOUT_MS)
/**
* enum dpu_enc_split_role - Role this physical encoder will play in a
* split-panel configuration, where one panel is master, and others slaves.
* Masters have extra responsibilities, like managing the VBLANK IRQ.
* @ENC_ROLE_SOLO: This is the one and only panel. This encoder is master.
* @ENC_ROLE_MASTER: This encoder is the master of a split panel config.
* @ENC_ROLE_SLAVE: This encoder is not the master of a split panel config.
*/
enum dpu_enc_split_role {
ENC_ROLE_SOLO,
ENC_ROLE_MASTER,
ENC_ROLE_SLAVE,
};
/**
* enum dpu_enc_enable_state - current enabled state of the physical encoder
* @DPU_ENC_DISABLING: Encoder transitioning to disable state
* Events bounding transition are encoder type specific
* @DPU_ENC_DISABLED: Encoder is disabled
* @DPU_ENC_ENABLING: Encoder transitioning to enabled
* Events bounding transition are encoder type specific
* @DPU_ENC_ENABLED: Encoder is enabled
* @DPU_ENC_ERR_NEEDS_HW_RESET: Encoder is enabled, but requires a hw_reset
* to recover from a previous error
*/
enum dpu_enc_enable_state {
DPU_ENC_DISABLING,
DPU_ENC_DISABLED,
DPU_ENC_ENABLING,
DPU_ENC_ENABLED,
DPU_ENC_ERR_NEEDS_HW_RESET
};
struct dpu_encoder_phys;
/**
* struct dpu_encoder_phys_ops - Interface the physical encoders provide to
* the containing virtual encoder.
* @prepare_commit: MSM Atomic Call, start of atomic commit sequence
* @is_master: Whether this phys_enc is the current master
* encoder. Can be switched at enable time. Based
* on split_role and current mode (CMD/VID).
* @atomic_mode_set: DRM Call. Set a DRM mode.
* This likely caches the mode, for use at enable.
* @enable: DRM Call. Enable a DRM mode.
* @disable: DRM Call. Disable mode.
* @atomic_check: DRM Call. Atomic check new DRM state.
* @control_vblank_irq Register/Deregister for VBLANK IRQ
* @wait_for_commit_done: Wait for hardware to have flushed the
* current pending frames to hardware
* @wait_for_tx_complete: Wait for hardware to transfer the pixels
* to the panel
* @wait_for_vblank: Wait for VBLANK, for sub-driver internal use
* @prepare_for_kickoff: Do any work necessary prior to a kickoff
* For CMD encoder, may wait for previous tx done
* @handle_post_kickoff: Do any work necessary post-kickoff work
* @trigger_start: Process start event on physical encoder
* @needs_single_flush: Whether encoder slaves need to be flushed
* @irq_enable: Handler to enable all the encoder IRQs
* @irq_disable: Handler to disable all the encoder IRQs
* @prepare_idle_pc: phys encoder can update the vsync_enable status
* on idle power collapse prepare
* @restore: Restore all the encoder configs.
* @get_line_count: Obtain current vertical line count
*/
struct dpu_encoder_phys_ops {
void (*prepare_commit)(struct dpu_encoder_phys *encoder);
bool (*is_master)(struct dpu_encoder_phys *encoder);
void (*atomic_mode_set)(struct dpu_encoder_phys *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state);
void (*enable)(struct dpu_encoder_phys *encoder);
void (*disable)(struct dpu_encoder_phys *encoder);
int (*atomic_check)(struct dpu_encoder_phys *encoder,
struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state);
int (*control_vblank_irq)(struct dpu_encoder_phys *enc, bool enable);
int (*wait_for_commit_done)(struct dpu_encoder_phys *phys_enc);
int (*wait_for_tx_complete)(struct dpu_encoder_phys *phys_enc);
void (*prepare_for_kickoff)(struct dpu_encoder_phys *phys_enc);
void (*handle_post_kickoff)(struct dpu_encoder_phys *phys_enc);
void (*trigger_start)(struct dpu_encoder_phys *phys_enc);
bool (*needs_single_flush)(struct dpu_encoder_phys *phys_enc);
void (*irq_enable)(struct dpu_encoder_phys *phys);
void (*irq_disable)(struct dpu_encoder_phys *phys);
void (*prepare_idle_pc)(struct dpu_encoder_phys *phys_enc);
void (*restore)(struct dpu_encoder_phys *phys);
int (*get_line_count)(struct dpu_encoder_phys *phys);
int (*get_frame_count)(struct dpu_encoder_phys *phys);
void (*prepare_wb_job)(struct dpu_encoder_phys *phys_enc,
struct drm_writeback_job *job);
void (*cleanup_wb_job)(struct dpu_encoder_phys *phys_enc,
struct drm_writeback_job *job);
bool (*is_valid_for_commit)(struct dpu_encoder_phys *phys_enc);
};
/**
* enum dpu_intr_idx - dpu encoder interrupt index
* @INTR_IDX_VSYNC: Vsync interrupt for video mode panel
* @INTR_IDX_PINGPONG: Pingpong done interrupt for cmd mode panel
* @INTR_IDX_UNDERRUN: Underrun interrupt for video and cmd mode panel
* @INTR_IDX_RDPTR: Readpointer done interrupt for cmd mode panel
* @INTR_IDX_WB_DONE: Writeback done interrupt for virtual connector
*/
enum dpu_intr_idx {
INTR_IDX_VSYNC,
INTR_IDX_PINGPONG,
INTR_IDX_UNDERRUN,
INTR_IDX_CTL_START,
INTR_IDX_RDPTR,
INTR_IDX_WB_DONE,
INTR_IDX_MAX,
};
/**
* struct dpu_encoder_phys - physical encoder that drives a single INTF block
* tied to a specific panel / sub-panel. Abstract type, sub-classed by
* phys_vid or phys_cmd for video mode or command mode encs respectively.
* @parent: Pointer to the containing virtual encoder
* @ops: Operations exposed to the virtual encoder
* @parent_ops: Callbacks exposed by the parent to the phys_enc
* @hw_mdptop: Hardware interface to the top registers
* @hw_ctl: Hardware interface to the ctl registers
* @hw_pp: Hardware interface to the ping pong registers
* @hw_intf: Hardware interface to the intf registers
* @hw_wb: Hardware interface to the wb registers
* @hw_cdm: Hardware interface to the CDM registers
* @dpu_kms: Pointer to the dpu_kms top level
* @cached_mode: DRM mode cached at mode_set time, acted on in enable
* @vblank_ctl_lock: Vblank ctl mutex lock to protect vblank_refcount
* @enabled: Whether the encoder has enabled and running a mode
* @split_role: Role to play in a split-panel configuration
* @intf_mode: Interface mode
* @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes
* @enable_state: Enable state tracking
* @vblank_refcount: Reference count of vblank request
* @vsync_cnt: Vsync count for the physical encoder
* @underrun_cnt: Underrun count for the physical encoder
* @pending_kickoff_cnt: Atomic counter tracking the number of kickoffs
* vs. the number of done/vblank irqs. Should hover
* between 0-2 Incremented when a new kickoff is
* scheduled. Decremented in irq handler
* @pending_ctlstart_cnt: Atomic counter tracking the number of ctl start
* pending.
* @pending_kickoff_wq: Wait queue for blocking until kickoff completes
* @irq: IRQ indices
* @has_intf_te: Interface TE configuration support
*/
struct dpu_encoder_phys {
struct drm_encoder *parent;
struct dpu_encoder_phys_ops ops;
struct dpu_hw_mdp *hw_mdptop;
struct dpu_hw_ctl *hw_ctl;
struct dpu_hw_pingpong *hw_pp;
struct dpu_hw_intf *hw_intf;
struct dpu_hw_wb *hw_wb;
struct dpu_hw_cdm *hw_cdm;
struct dpu_kms *dpu_kms;
struct drm_display_mode cached_mode;
struct mutex vblank_ctl_lock;
enum dpu_enc_split_role split_role;
enum dpu_intf_mode intf_mode;
spinlock_t *enc_spinlock;
enum dpu_enc_enable_state enable_state;
int vblank_refcount;
atomic_t vsync_cnt;
atomic_t underrun_cnt;
atomic_t pending_ctlstart_cnt;
atomic_t pending_kickoff_cnt;
wait_queue_head_t pending_kickoff_wq;
unsigned int irq[INTR_IDX_MAX];
bool has_intf_te;
};
static inline int dpu_encoder_phys_inc_pending(struct dpu_encoder_phys *phys)
{
atomic_inc_return(&phys->pending_ctlstart_cnt);
return atomic_inc_return(&phys->pending_kickoff_cnt);
}
/**
* struct dpu_encoder_phys_wb - sub-class of dpu_encoder_phys to handle command
* mode specific operations
* @base: Baseclass physical encoder structure
* @wbirq_refcount: Reference count of writeback interrupt
* @wb_done_timeout_cnt: number of wb done irq timeout errors
* @wb_cfg: writeback block config to store fb related details
* @cdm_cfg: cdm block config needed to store writeback block's CDM configuration
* @wb_conn: backpointer to writeback connector
* @wb_job: backpointer to current writeback job
* @dest: dpu buffer layout for current writeback output buffer
*/
struct dpu_encoder_phys_wb {
struct dpu_encoder_phys base;
atomic_t wbirq_refcount;
int wb_done_timeout_cnt;
struct dpu_hw_wb_cfg wb_cfg;
struct dpu_hw_cdm_cfg cdm_cfg;
struct drm_writeback_connector *wb_conn;
struct drm_writeback_job *wb_job;
struct dpu_hw_fmt_layout dest;
};
/**
* struct dpu_encoder_phys_cmd - sub-class of dpu_encoder_phys to handle command
* mode specific operations
* @base: Baseclass physical encoder structure
* @intf_idx: Intf Block index used by this phys encoder
* @stream_sel: Stream selection for multi-stream interfaces
* @serialize_wait4pp: serialize wait4pp feature waits for pp_done interrupt
* after ctl_start instead of before next frame kickoff
* @pp_timeout_report_cnt: number of pingpong done irq timeout errors
* @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK
* @pending_vblank_wq: Wait queue for blocking until VBLANK received
*/
struct dpu_encoder_phys_cmd {
struct dpu_encoder_phys base;
int stream_sel;
bool serialize_wait4pp;
int pp_timeout_report_cnt;
atomic_t pending_vblank_cnt;
wait_queue_head_t pending_vblank_wq;
};
/**
* struct dpu_enc_phys_init_params - initialization parameters for phys encs
* @dpu_kms: Pointer to the dpu_kms top level
* @parent: Pointer to the containing virtual encoder
* @parent_ops: Callbacks exposed by the parent to the phys_enc
* @split_role: Role to play in a split-panel configuration
* @hw_intf: Hardware interface to the intf registers
* @hw_wb: Hardware interface to the wb registers
* @enc_spinlock: Virtual-Encoder-Wide Spin Lock for IRQ purposes
*/
struct dpu_enc_phys_init_params {
struct dpu_kms *dpu_kms;
struct drm_encoder *parent;
enum dpu_enc_split_role split_role;
struct dpu_hw_intf *hw_intf;
struct dpu_hw_wb *hw_wb;
spinlock_t *enc_spinlock;
};
/**
* dpu_encoder_wait_info - container for passing arguments to irq wait functions
* @wq: wait queue structure
* @atomic_cnt: wait until atomic_cnt equals zero
* @timeout_ms: timeout value in milliseconds
*/
struct dpu_encoder_wait_info {
wait_queue_head_t *wq;
atomic_t *atomic_cnt;
s64 timeout_ms;
};
/**
* dpu_encoder_phys_vid_init - Construct a new video mode physical encoder
* @p: Pointer to init params structure
* Return: Error code or newly allocated encoder
*/
struct dpu_encoder_phys *dpu_encoder_phys_vid_init(struct drm_device *dev,
struct dpu_enc_phys_init_params *p);
/**
* dpu_encoder_phys_cmd_init - Construct a new command mode physical encoder
* @dev: Corresponding device for devres management
* @p: Pointer to init params structure
* Return: Error code or newly allocated encoder
*/
struct dpu_encoder_phys *dpu_encoder_phys_cmd_init(struct drm_device *dev,
struct dpu_enc_phys_init_params *p);
/**
* dpu_encoder_phys_wb_init - initialize writeback encoder
* @dev: Corresponding device for devres management
* @init: Pointer to init info structure with initialization params
*/
struct dpu_encoder_phys *dpu_encoder_phys_wb_init(struct drm_device *dev,
struct dpu_enc_phys_init_params *p);
/**
* dpu_encoder_helper_trigger_start - control start helper function
* This helper function may be optionally specified by physical
* encoders if they require ctl_start triggering.
* @phys_enc: Pointer to physical encoder structure
*/
void dpu_encoder_helper_trigger_start(struct dpu_encoder_phys *phys_enc);
static inline enum dpu_3d_blend_mode dpu_encoder_helper_get_3d_blend_mode(
struct dpu_encoder_phys *phys_enc)
{
struct dpu_crtc_state *dpu_cstate;
if (!phys_enc || phys_enc->enable_state == DPU_ENC_DISABLING)
return BLEND_3D_NONE;
dpu_cstate = to_dpu_crtc_state(phys_enc->parent->crtc->state);
/* Use merge_3d unless DSC MERGE topology is used */
if (phys_enc->split_role == ENC_ROLE_SOLO &&
dpu_cstate->num_mixers == CRTC_DUAL_MIXERS &&
!dpu_encoder_use_dsc_merge(phys_enc->parent))
return BLEND_3D_H_ROW_INT;
return BLEND_3D_NONE;
}
/**
* dpu_encoder_helper_get_dsc - get DSC blocks mask for the DPU encoder
* This helper function is used by physical encoder to get DSC blocks mask
* used for this encoder.
* @phys_enc: Pointer to physical encoder structure
*/
unsigned int dpu_encoder_helper_get_dsc(struct dpu_encoder_phys *phys_enc);
/**
* dpu_encoder_helper_split_config - split display configuration helper function
* This helper function may be used by physical encoders to configure
* the split display related registers.
* @phys_enc: Pointer to physical encoder structure
* @interface: enum dpu_intf setting
*/
void dpu_encoder_helper_split_config(
struct dpu_encoder_phys *phys_enc,
enum dpu_intf interface);
/**
* dpu_encoder_helper_report_irq_timeout - utility to report error that irq has
* timed out, including reporting frame error event to crtc and debug dump
* @phys_enc: Pointer to physical encoder structure
* @intr_idx: Failing interrupt index
*/
void dpu_encoder_helper_report_irq_timeout(struct dpu_encoder_phys *phys_enc,
enum dpu_intr_idx intr_idx);
/**
* dpu_encoder_helper_wait_for_irq - utility to wait on an irq.
* note: will call dpu_encoder_helper_wait_for_irq on timeout
* @phys_enc: Pointer to physical encoder structure
* @irq: IRQ index
* @func: IRQ callback to be called in case of timeout
* @wait_info: wait info struct
* @Return: 0 or -ERROR
*/
int dpu_encoder_helper_wait_for_irq(struct dpu_encoder_phys *phys_enc,
unsigned int irq,
void (*func)(void *arg),
struct dpu_encoder_wait_info *wait_info);
/**
* dpu_encoder_helper_phys_cleanup - helper to cleanup dpu pipeline
* @phys_enc: Pointer to physical encoder structure
*/
void dpu_encoder_helper_phys_cleanup(struct dpu_encoder_phys *phys_enc);
/**
* dpu_encoder_vblank_callback - Notify virtual encoder of vblank IRQ reception
* @drm_enc: Pointer to drm encoder structure
* @phys_enc: Pointer to physical encoder
* Note: This is called from IRQ handler context.
*/
void dpu_encoder_vblank_callback(struct drm_encoder *drm_enc,
struct dpu_encoder_phys *phy_enc);
/** dpu_encoder_underrun_callback - Notify virtual encoder of underrun IRQ reception
* @drm_enc: Pointer to drm encoder structure
* @phys_enc: Pointer to physical encoder
* Note: This is called from IRQ handler context.
*/
void dpu_encoder_underrun_callback(struct drm_encoder *drm_enc,
struct dpu_encoder_phys *phy_enc);
/** dpu_encoder_frame_done_callback -- Notify virtual encoder that this phys encoder completes last request frame
* @drm_enc: Pointer to drm encoder structure
* @phys_enc: Pointer to physical encoder
* @event: Event to process
*/
void dpu_encoder_frame_done_callback(
struct drm_encoder *drm_enc,
struct dpu_encoder_phys *ready_phys, u32 event);
void dpu_encoder_phys_init(struct dpu_encoder_phys *phys,
struct dpu_enc_phys_init_params *p);
#endif /* __dpu_encoder_phys_H__ */
|