Loading...
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 | /* 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_ctl.h" #include "dpu_hw_top.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_virt_ops - Interface the containing virtual encoder * provides for the physical encoders to use to callback. * @handle_vblank_virt: Notify virtual encoder of vblank IRQ reception * Note: This is called from IRQ handler context. * @handle_underrun_virt: Notify virtual encoder of underrun IRQ reception * Note: This is called from IRQ handler context. * @handle_frame_done: Notify virtual encoder that this phys encoder * completes last request frame. */ struct dpu_encoder_virt_ops { void (*handle_vblank_virt)(struct drm_encoder *, struct dpu_encoder_phys *phys); void (*handle_underrun_virt)(struct drm_encoder *, struct dpu_encoder_phys *phys); void (*handle_frame_done)(struct drm_encoder *, struct dpu_encoder_phys *phys, u32 event); }; /** * struct dpu_encoder_phys_ops - Interface the physical encoders provide to * the containing virtual encoder. * @late_register: DRM Call. Add Userspace interfaces, debugfs. * @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. * @destroy: DRM Call. Destroy and release resources. * @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_control: Handler to enable/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 { int (*late_register)(struct dpu_encoder_phys *encoder, struct dentry *debugfs_root); 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); void (*destroy)(struct dpu_encoder_phys *encoder); 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); int (*wait_for_vblank)(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_control)(struct dpu_encoder_phys *phys, bool enable); 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 unterrupt for cmd mode panel * @INTR_IDX_UNDERRUN: Underrun unterrupt for video and cmd mode panel * @INTR_IDX_RDPTR: Readpointer done unterrupt for cmd mode panel * @INTR_IDX_WB_DONE: Writeback fone 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 * @dpu_kms: Pointer to the dpu_kms top level * @cached_mode: DRM mode cached at mode_set time, acted on in enable * @enabled: Whether the encoder has enabled and running a mode * @split_role: Role to play in a split-panel configuration * @intf_mode: Interface mode * @intf_idx: Interface index on dpu hardware * @wb_idx: Writeback index on dpu hardware * @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 */ struct dpu_encoder_phys { struct drm_encoder *parent; struct dpu_encoder_phys_ops ops; const struct dpu_encoder_virt_ops *parent_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_kms *dpu_kms; struct drm_display_mode cached_mode; enum dpu_enc_split_role split_role; enum dpu_intf_mode intf_mode; enum dpu_intf intf_idx; enum dpu_wb wb_idx; spinlock_t *enc_spinlock; enum dpu_enc_enable_state enable_state; atomic_t 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; int irq[INTR_IDX_MAX]; }; 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 * @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 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 * @intf_idx: Interface index this phys_enc will control * @wb_idx: Writeback index this phys_enc will control * @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; const struct dpu_encoder_virt_ops *parent_ops; enum dpu_enc_split_role split_role; enum dpu_intf intf_idx; enum dpu_wb wb_idx; 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 dpu_enc_phys_init_params *p); /** * dpu_encoder_phys_cmd_init - Construct a new command mode physical encoder * @p: Pointer to init params structure * Return: Error code or newly allocated encoder */ struct dpu_encoder_phys *dpu_encoder_phys_cmd_init( struct dpu_enc_phys_init_params *p); /** * dpu_encoder_phys_wb_init - initialize writeback encoder * @init: Pointer to init info structure with initialization params */ struct dpu_encoder_phys *dpu_encoder_phys_wb_init( 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, int irq, void (*func)(void *arg, int irq_idx), 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); #endif /* __dpu_encoder_phys_H__ */ |