/** * struct drm_crtc - central CRTC control structure * * Each CRTC may have one or more connectors associated with it. This structure * allows the CRTC to be controlled. */ structdrm_crtc { /** @dev: parent DRM device */ structdrm_device *dev; /** @port: OF node used by drm_of_find_possible_crtcs(). */ structdevice_node *port; /** * @head: * * List of all CRTCs on @dev, linked from &drm_mode_config.crtc_list. * Invariant over the lifetime of @dev and therefore does not need * locking. */ structlist_headhead;
/** @name: human readable name, can be overwritten by the driver */ char *name;
/** * @mutex: * * This provides a read lock for the overall CRTC state (mode, dpms * state, ...) and a write lock for everything which can be update * without a full modeset (fb, cursor data, CRTC properties ...). A full * modeset also need to grab &drm_mode_config.connection_mutex. * * For atomic drivers specifically this protects @state. */ structdrm_modeset_lockmutex;
/** @base: base KMS object for ID tracking etc. */ structdrm_mode_objectbase;
/** * @primary: * Primary plane for this CRTC. Note that this is only * relevant for legacy IOCTL, it specifies the plane implicitly used by * the SETCRTC and PAGE_FLIP IOCTLs. It does not have any significance * beyond that. */ structdrm_plane *primary;
/** * @cursor: * Cursor plane for this CRTC. Note that this is only relevant for * legacy IOCTL, it specifies the plane implicitly used by the SETCURSOR * and SETCURSOR2 IOCTLs. It does not have any significance * beyond that. */ structdrm_plane *cursor; /** * @index: Position inside the mode_config.list, can be used as an array * index. It is invariant over the lifetime of the CRTC. */ unsigned index;
/** * @cursor_x: Current x position of the cursor, used for universal * cursor planes because the SETCURSOR IOCTL only can update the * framebuffer without supplying the coordinates. Drivers should not use * this directly, atomic drivers should look at &drm_plane_state.crtc_x * of the cursor plane instead. */ int cursor_x; /** * @cursor_y: Current y position of the cursor, used for universal * cursor planes because the SETCURSOR IOCTL only can update the * framebuffer without supplying the coordinates. Drivers should not use * this directly, atomic drivers should look at &drm_plane_state.crtc_y * of the cursor plane instead. */ int cursor_y;
/** * @enabled: * * Is this CRTC enabled? Should only be used by legacy drivers, atomic * drivers should instead consult &drm_crtc_state.enable and * &drm_crtc_state.active. Atomic drivers can update this by calling * drm_atomic_helper_update_legacy_modeset_state(). */ bool enabled;
/** * @mode: * * Current mode timings. Should only be used by legacy drivers, atomic * drivers should instead consult &drm_crtc_state.mode. Atomic drivers * can update this by calling * drm_atomic_helper_update_legacy_modeset_state(). */ structdrm_display_modemode; /** * @hwmode: * * Programmed mode in hw, after adjustments for encoders, crtc, panel * scaling etc. Should only be used by legacy drivers, for high * precision vblank timestamps in * drm_crtc_vblank_helper_get_vblank_timestamp(). * * Note that atomic drivers should not use this, but instead use * &drm_crtc_state.adjusted_mode. And for high-precision timestamps * drm_crtc_vblank_helper_get_vblank_timestamp() used * &drm_vblank_crtc.hwmode, * which is filled out by calling drm_calc_timestamping_constants(). */ structdrm_display_modehwmode;
/** * @x: * x position on screen. Should only be used by legacy drivers, atomic * drivers should look at &drm_plane_state.crtc_x of the primary plane * instead. Updated by calling * drm_atomic_helper_update_legacy_modeset_state(). */ int x; /** * @y: * y position on screen. Should only be used by legacy drivers, atomic * drivers should look at &drm_plane_state.crtc_y of the primary plane * instead. Updated by calling * drm_atomic_helper_update_legacy_modeset_state(). */ int y;
/** @funcs: CRTC control functions */ conststructdrm_crtc_funcs *funcs;
/** * @gamma_size: Size of legacy gamma ramp reported to userspace. Set up * by calling drm_mode_crtc_set_gamma_size(). * * Note that atomic drivers need to instead use * &drm_crtc_state.gamma_lut. See drm_crtc_enable_color_mgmt(). */ uint32_t gamma_size;
/** * @gamma_store: Gamma ramp values used by the legacy SETGAMMA and * GETGAMMA IOCTls. Set up by calling drm_mode_crtc_set_gamma_size(). * * Note that atomic drivers need to instead use * &drm_crtc_state.gamma_lut. See drm_crtc_enable_color_mgmt(). */ uint16_t *gamma_store; /** @helper_private: mid-layer private data */ conststructdrm_crtc_helper_funcs *helper_private;
/** @properties: property tracking for this CRTC */ structdrm_object_propertiesproperties;
/** * @scaling_filter_property: property to apply a particular filter while * scaling. */ structdrm_property *scaling_filter_property;
/** * @state: * * Current atomic state for this CRTC. * * This is protected by @mutex. Note that nonblocking atomic commits * access the current CRTC state without taking locks. Either by going * through the &struct drm_atomic_state pointers, see * for_each_oldnew_crtc_in_state(), for_each_old_crtc_in_state() and * for_each_new_crtc_in_state(). Or through careful ordering of atomic * commit operations as implemented in the atomic helpers, see * &struct drm_crtc_commit. */ structdrm_crtc_state *state;
/** * @commit_list: * * List of &drm_crtc_commit structures tracking pending commits. * Protected by @commit_lock. This list holds its own full reference, * as does the ongoing commit. * * "Note that the commit for a state change is also tracked in * &drm_crtc_state.commit. For accessing the immediately preceding * commit in an atomic update it is recommended to just use that * pointer in the old CRTC state, since accessing that doesn't need * any locking or list-walking. @commit_list should only be used to * stall for framebuffer cleanup that's signalled through * &drm_crtc_commit.cleanup_done." */ structlist_headcommit_list;
/** * @commit_lock: * * Spinlock to protect @commit_list. */ spinlock_t commit_lock; /** * @debugfs_entry: * * Debugfs directory for this CRTC. */ structdentry *debugfs_entry;
/** * @fence_context: * * timeline context used for fence operations. */ unsignedint fence_context;
/** * @fence_lock: * * spinlock to protect the fences in the fence_context. */ spinlock_t fence_lock; /** * @fence_seqno: * * Seqno variable used as monotonic counter for the fences * created on the CRTC's timeline. */ unsignedlong fence_seqno;
/** * @timeline_name: * * The name of the CRTC's fence timeline. */ char timeline_name[32];
/** * @self_refresh_data: Holds the state for the self refresh helpers * * Initialized via drm_self_refresh_helper_init(). */ structdrm_self_refresh_data *self_refresh_data; };
/** * struct drm_display_mode - DRM kernel-internal display mode structure * @hdisplay: horizontal display size * @hsync_start: horizontal sync start * @hsync_end: horizontal sync end * @htotal: horizontal total size * @hskew: horizontal skew?! * @vdisplay: vertical display size * @vsync_start: vertical sync start * @vsync_end: vertical sync end * @vtotal: vertical total size * @vscan: vertical scan?! * @crtc_hdisplay: hardware mode horizontal display size * @crtc_hblank_start: hardware mode horizontal blank start * @crtc_hblank_end: hardware mode horizontal blank end * @crtc_hsync_start: hardware mode horizontal sync start * @crtc_hsync_end: hardware mode horizontal sync end * @crtc_htotal: hardware mode horizontal total size * @crtc_hskew: hardware mode horizontal skew?! * @crtc_vdisplay: hardware mode vertical display size * @crtc_vblank_start: hardware mode vertical blank start * @crtc_vblank_end: hardware mode vertical blank end * @crtc_vsync_start: hardware mode vertical sync start * @crtc_vsync_end: hardware mode vertical sync end * @crtc_vtotal: hardware mode vertical total size * * This is the kernel API display mode information structure. For the * user-space version see struct drm_mode_modeinfo. * * The horizontal and vertical timings are defined per the following diagram. * * :: * * * Active Front Sync Back * Region Porch Porch * <-----------------------><----------------><-------------><--------------> * //////////////////////| * ////////////////////// | * ////////////////////// |.................. ................ * _______________ * <----- [hv]display -----> * <------------- [hv]sync_start ------------> * <--------------------- [hv]sync_end ---------------------> * <-------------------------------- [hv]total ----------------------------->* * * This structure contains two copies of timings. First are the plain timings, * which specify the logical mode, as it would be for a progressive 1:1 scanout * at the refresh rate userspace can observe through vblank timestamps. Then * there's the hardware timings, which are corrected for interlacing, * double-clocking and similar things. They are provided as a convenience, and * can be appropriately computed using drm_mode_set_crtcinfo(). * * For printing you can use %DRM_MODE_FMT and DRM_MODE_ARG(). */ structdrm_display_mode { /** * @clock: * * Pixel clock in kHz. */ int clock; /* in kHz */ u16 hdisplay; u16 hsync_start; u16 hsync_end; u16 htotal; u16 hskew; u16 vdisplay; u16 vsync_start; u16 vsync_end; u16 vtotal; u16 vscan; /** * @flags: * * Sync and timing flags: * * - DRM_MODE_FLAG_PHSYNC: horizontal sync is active high. * - DRM_MODE_FLAG_NHSYNC: horizontal sync is active low. * - DRM_MODE_FLAG_PVSYNC: vertical sync is active high. * - DRM_MODE_FLAG_NVSYNC: vertical sync is active low. * - DRM_MODE_FLAG_INTERLACE: mode is interlaced. * - DRM_MODE_FLAG_DBLSCAN: mode uses doublescan. * - DRM_MODE_FLAG_CSYNC: mode uses composite sync. * - DRM_MODE_FLAG_PCSYNC: composite sync is active high. * - DRM_MODE_FLAG_NCSYNC: composite sync is active low. * - DRM_MODE_FLAG_HSKEW: hskew provided (not used?). * - DRM_MODE_FLAG_BCAST: <deprecated> * - DRM_MODE_FLAG_PIXMUX: <deprecated> * - DRM_MODE_FLAG_DBLCLK: double-clocked mode. * - DRM_MODE_FLAG_CLKDIV2: half-clocked mode. * * Additionally there's flags to specify how 3D modes are packed: * * - DRM_MODE_FLAG_3D_NONE: normal, non-3D mode. * - DRM_MODE_FLAG_3D_FRAME_PACKING: 2 full frames for left and right. * - DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE: interleaved like fields. * - DRM_MODE_FLAG_3D_LINE_ALTERNATIVE: interleaved lines. * - DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL: side-by-side full frames. * - DRM_MODE_FLAG_3D_L_DEPTH: ? * - DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH: ? * - DRM_MODE_FLAG_3D_TOP_AND_BOTTOM: frame split into top and bottom * parts. * - DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF: frame split into left and * right parts. */ u32 flags; u32 flags;
/** * @crtc_clock: * * Actual pixel or dot clock in the hardware. This differs from the * logical @clock when e.g. using interlacing, double-clocking, stereo * modes or other fancy stuff that changes the timings and signals * actually sent over the wire. * * This is again in kHz. * * Note that with digital outputs like HDMI or DP there's usually a * massive confusion between the dot clock and the signal clock at the * bit encoding level. Especially when a 8b/10b encoding is used and the * difference is exactly a factor of 10. */ int crtc_clock; u16 crtc_hdisplay; u16 crtc_hblank_start; u16 crtc_hblank_end; u16 crtc_hsync_start; u16 crtc_hsync_end; u16 crtc_htotal; u16 crtc_hskew; u16 crtc_vdisplay; u16 crtc_vblank_start; u16 crtc_vblank_end; u16 crtc_vsync_start; u16 crtc_vsync_end; u16 crtc_vtotal;
/** * @width_mm: * * Addressable size of the output in mm, projectors should set this to * 0. */ u16 width_mm;
/** * @height_mm: * * Addressable size of the output in mm, projectors should set this to * 0. */ u16 height_mm; /** * @type: * * A bitmask of flags, mostly about the source of a mode. Possible flags * are: * * - DRM_MODE_TYPE_PREFERRED: Preferred mode, usually the native * resolution of an LCD panel. There should only be one preferred * mode per connector at any given time. * - DRM_MODE_TYPE_DRIVER: Mode created by the driver, which is all of * them really. Drivers must set this bit for all modes they create * and expose to userspace. * - DRM_MODE_TYPE_USERDEF: Mode defined or selected via the kernel * command line. * * Plus a big list of flags which shouldn't be used at all, but are * still around since these flags are also used in the userspace ABI. * We no longer accept modes with these types though: * * - DRM_MODE_TYPE_BUILTIN: Meant for hard-coded modes, unused. * Use DRM_MODE_TYPE_DRIVER instead. * - DRM_MODE_TYPE_DEFAULT: Again a leftover, use * DRM_MODE_TYPE_PREFERRED instead. * - DRM_MODE_TYPE_CLOCK_C and DRM_MODE_TYPE_CRTC_C: Define leftovers * which are stuck around for hysterical raisins only. No one has an * idea what they were meant for. Don't use. */ u8 type;
/** * @expose_to_userspace: * * Indicates whether the mode is to be exposed to the userspace. * This is to maintain a set of exposed modes while preparing * user-mode's list in drm_mode_getconnector ioctl. The purpose of * this only lies in the ioctl function, and is not to be used * outside the function. */ bool expose_to_userspace;
/** * @name: * * Human-readable name of the mode, filled out with drm_mode_set_name(). */ char name[DRM_DISPLAY_MODE_LEN];
/** * @status: * * Status of the mode, used to filter out modes not supported by the * hardware. See enum &drm_mode_status. */ enum drm_mode_status status; /** * @picture_aspect_ratio: * * Field for setting the HDMI picture aspect ratio of a mode. */ enum hdmi_picture_aspect picture_aspect_ratio;
/** * struct drm_crtc_state - mutable CRTC state * * Note that the distinction between @enable and @active is rather subtle: * Flipping @active while @enable is set without changing anything else may * never return in a failure from the &drm_mode_config_funcs.atomic_check * callback. Userspace assumes that a DPMS On will always succeed. In other * words: @enable controls resource assignment, @active controls the actual * hardware state. * * The three booleans active_changed, connectors_changed and mode_changed are * intended to indicate whether a full modeset is needed, rather than strictly * describing what has changed in a commit. See also: * drm_atomic_crtc_needs_modeset() * * WARNING: Transitional helpers (like drm_helper_crtc_mode_set() or * drm_helper_crtc_mode_set_base()) do not maintain many of the derived control * state like @plane_mask so drivers not converted over to atomic helpers should * not rely on these being accurate! */ structdrm_crtc_state { /** @crtc: backpointer to the CRTC */ structdrm_crtc *crtc;
/** * @enable: Whether the CRTC should be enabled, gates all other state. * This controls reservations of shared resources. Actual hardware state * is controlled by @active. */ bool enable;
/** * @active: Whether the CRTC is actively displaying (used for DPMS). * Implies that @enable is set. The driver must not release any shared * resources if @active is set to false but @enable still true, because * userspace expects that a DPMS ON always succeeds. * * Hence drivers must not consult @active in their various * &drm_mode_config_funcs.atomic_check callback to reject an atomic * commit. They can consult it to aid in the computation of derived * hardware state, since even in the DPMS OFF state the display hardware * should be as much powered down as when the CRTC is completely * disabled through setting @enable to false. */ bool active;
/** * @planes_changed: Planes on this crtc are updated. Used by the atomic * helpers and drivers to steer the atomic commit control flow. */ bool planes_changed : 1;
/** * @mode_changed: @mode or @enable has been changed. Used by the atomic * helpers and drivers to steer the atomic commit control flow. See also * drm_atomic_crtc_needs_modeset(). * * Drivers are supposed to set this for any CRTC state changes that * require a full modeset. They can also reset it to false if e.g. a * @mode change can be done without a full modeset by only changing * scaler settings. */ bool mode_changed : 1; /** * @active_changed: @active has been toggled. Used by the atomic * helpers and drivers to steer the atomic commit control flow. See also * drm_atomic_crtc_needs_modeset(). */ bool active_changed : 1;
/** * @connectors_changed: Connectors to this crtc have been updated, * either in their state or routing. Used by the atomic * helpers and drivers to steer the atomic commit control flow. See also * drm_atomic_crtc_needs_modeset(). * * Drivers are supposed to set this as-needed from their own atomic * check code, e.g. from &drm_encoder_helper_funcs.atomic_check */ bool connectors_changed : 1; /** * @zpos_changed: zpos values of planes on this crtc have been updated. * Used by the atomic helpers and drivers to steer the atomic commit * control flow. */ bool zpos_changed : 1; /** * @color_mgmt_changed: Color management properties have changed * (@gamma_lut, @degamma_lut or @ctm). Used by the atomic helpers and * drivers to steer the atomic commit control flow. */ bool color_mgmt_changed : 1;
/** * @no_vblank: * * Reflects the ability of a CRTC to send VBLANK events. This state * usually depends on the pipeline configuration. If set to true, DRM * atomic helpers will send out a fake VBLANK event during display * updates after all hardware changes have been committed. This is * implemented in drm_atomic_helper_fake_vblank(). * * One usage is for drivers and/or hardware without support for VBLANK * interrupts. Such drivers typically do not initialize vblanking * (i.e., call drm_vblank_init() with the number of CRTCs). For CRTCs * without initialized vblanking, this field is set to true in * drm_atomic_helper_check_modeset(), and a fake VBLANK event will be * send out on each update of the display pipeline by * drm_atomic_helper_fake_vblank(). * * Another usage is CRTCs feeding a writeback connector operating in * oneshot mode. In this case the fake VBLANK event is only generated * when a job is queued to the writeback connector, and we want the * core to fake VBLANK events when this part of the pipeline hasn't * changed but others had or when the CRTC and connectors are being * disabled. * * __drm_atomic_helper_crtc_duplicate_state() will not reset the value * from the current state, the CRTC driver is then responsible for * updating this field when needed. * * Note that the combination of &drm_crtc_state.event == NULL and * &drm_crtc_state.no_blank == true is valid and usually used when the * writeback connector attached to the CRTC has a new job queued. In * this case the driver will send the VBLANK event on its own when the * writeback job is complete. bool no_vblank : 1; /** * @plane_mask: Bitmask of drm_plane_mask(plane) of planes attached to * this CRTC. */ u32 plane_mask;
/** * @connector_mask: Bitmask of drm_connector_mask(connector) of * connectors attached to this CRTC. */ u32 connector_mask;
/** * @encoder_mask: Bitmask of drm_encoder_mask(encoder) of encoders * attached to this CRTC. */ u32 encoder_mask;
/** * @adjusted_mode: * * Internal display timings which can be used by the driver to handle * differences between the mode requested by userspace in @mode and what * is actually programmed into the hardware. * * For drivers using &drm_bridge, this stores hardware display timings * used between the CRTC and the first bridge. For other drivers, the * meaning of the adjusted_mode field is purely driver implementation * defined information, and will usually be used to store the hardware * display timings used between the CRTC and encoder blocks. */ structdrm_display_modeadjusted_mode;
/** * @mode: * * Display timings requested by userspace. The driver should try to * match the refresh rate as close as possible (but note that it's * undefined what exactly is close enough, e.g. some of the HDMI modes * only differ in less than 1% of the refresh rate). The active width * and height as observed by userspace for positioning planes must match * exactly. * * For external connectors where the sink isn't fixed (like with a * built-in panel), this mode here should match the physical mode on the * wire to the last details (i.e. including sync polarities and * everything). */ structdrm_display_modemode;
/** * @mode_blob: &drm_property_blob for @mode, for exposing the mode to * atomic userspace. */ structdrm_property_blob *mode_blob;
/** * @degamma_lut: * * Lookup table for converting framebuffer pixel data before apply the * color conversion matrix @ctm. See drm_crtc_enable_color_mgmt(). The * blob (if not NULL) is an array of &struct drm_color_lut. */ structdrm_property_blob *degamma_lut;
/** * @ctm: * * Color transformation matrix. See drm_crtc_enable_color_mgmt(). The * blob (if not NULL) is a &struct drm_color_ctm. */ structdrm_property_blob *ctm;
/** * @gamma_lut: * * Lookup table for converting pixel data after the color conversion * matrix @ctm. See drm_crtc_enable_color_mgmt(). The blob (if not * NULL) is an array of &struct drm_color_lut. * * Note that for mostly historical reasons stemming from Xorg heritage, * this is also used to store the color map (also sometimes color lut, * CLUT or color palette) for indexed formats like DRM_FORMAT_C8. */ structdrm_property_blob *gamma_lut;
/** * @target_vblank: * * Target vertical blank period when a page flip * should take effect. */ u32 target_vblank;
/** * @async_flip: * * This is set when DRM_MODE_PAGE_FLIP_ASYNC is set in the legacy * PAGE_FLIP IOCTL. It's not wired up for the atomic IOCTL itself yet. */ bool async_flip;
/** * @vrr_enabled: * * Indicates if variable refresh rate should be enabled for the CRTC. * Support for the requested vrr state will depend on driver and * hardware capabiltiy - lacking support is not treated as failure. */ bool vrr_enabled;
/** * @self_refresh_active: * * Used by the self refresh helpers to denote when a self refresh * transition is occurring. This will be set on enable/disable callbacks * when self refresh is being enabled or disabled. In some cases, it may * not be desirable to fully shut off the crtc during self refresh. * CRTC's can inspect this flag and determine the best course of action. */ bool self_refresh_active;
/** * @scaling_filter: * * Scaling filter to be applied */ enum drm_scaling_filter scaling_filter;
/** * @event: * * Optional pointer to a DRM event to signal upon completion of the * state update. The driver must send out the event when the atomic * commit operation completes. There are two cases: * * - The event is for a CRTC which is being disabled through this * atomic commit. In that case the event can be send out any time * after the hardware has stopped scanning out the current * framebuffers. It should contain the timestamp and counter for the * last vblank before the display pipeline was shut off. The simplest * way to achieve that is calling drm_crtc_send_vblank_event() * somewhen after drm_crtc_vblank_off() has been called. * * - For a CRTC which is enabled at the end of the commit (even when it * undergoes an full modeset) the vblank timestamp and counter must * be for the vblank right before the first frame that scans out the * new set of buffers. Again the event can only be sent out after the * hardware has stopped scanning out the old buffers. * * - Events for disabled CRTCs are not allowed, and drivers can ignore * that case. * * For very simple hardware without VBLANK interrupt, enabling * &struct drm_crtc_state.no_vblank makes DRM's atomic commit helpers * send a fake VBLANK event at the end of the display update after all * hardware changes have been applied. See * drm_atomic_helper_fake_vblank(). * * For more complex hardware this * can be handled by the drm_crtc_send_vblank_event() function, * which the driver should call on the provided event upon completion of * the atomic commit. Note that if the driver supports vblank signalling * and timestamping the vblank counters and timestamps must agree with * the ones returned from page flip events. With the current vblank * helper infrastructure this can be achieved by holding a vblank * reference while the page flip is pending, acquired through * drm_crtc_vblank_get() and released with drm_crtc_vblank_put(). * Drivers are free to implement their own vblank counter and timestamp * tracking though, e.g. if they have accurate timestamp registers in * hardware. * * For hardware which supports some means to synchronize vblank * interrupt delivery with committing display state there's also * drm_crtc_arm_vblank_event(). See the documentation of that function * for a detailed discussion of the constraints it needs to be used * safely. * * If the device can't notify of flip completion in a race-free way * at all, then the event should be armed just after the page flip is * committed. In the worst case the driver will send the event to * userspace one frame too late. This doesn't allow for a real atomic * update, but it should avoid tearing. */ structdrm_pending_vblank_event *event;
/** * @commit: * * This tracks how the commit for this update proceeds through the * various phases. This is never cleared, except when we destroy the * state, so that subsequent commits can synchronize with previous ones. */ structdrm_crtc_commit *commit;
/** @state: backpointer to global drm_atomic_state */ structdrm_atomic_state *state; };
/** * struct drm_crtc_funcs - control CRTCs for a given device * * The drm_crtc_funcs structure is the central CRTC management structure * in the DRM. Each CRTC controls one or more connectors (note that the name * CRTC is simply historical, a CRTC may control LVDS, VGA, DVI, TV out, etc. * connectors, not just CRTs). * * Each driver is responsible for filling out this structure at startup time, * in addition to providing other modesetting features, like i2c and DDC * bus accessors. */ structdrm_crtc_funcs { /** * @reset: * * Reset CRTC hardware and software state to off. This function isn't * called by the core directly, only through drm_mode_config_reset(). * It's not a helper hook only for historical reasons. * * Atomic drivers can use drm_atomic_helper_crtc_reset() to reset * atomic state using this hook. */ void (*reset)(struct drm_crtc *crtc);
/** * @cursor_set: * * Update the cursor image. The cursor position is relative to the CRTC * and can be partially or fully outside of the visible area. * * Note that contrary to all other KMS functions the legacy cursor entry * points don't take a framebuffer object, but instead take directly a * raw buffer object id from the driver's buffer manager (which is * either GEM or TTM for current drivers). * * This entry point is deprecated, drivers should instead implement * universal plane support and register a proper cursor plane using * drm_crtc_init_with_planes(). * * This callback is optional * * RETURNS: * * 0 on success or a negative error code on failure. */ int (*cursor_set)(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height);
/** * @cursor_set2: * * Update the cursor image, including hotspot information. The hotspot * must not affect the cursor position in CRTC coordinates, but is only * meant as a hint for virtualized display hardware to coordinate the * guests and hosts cursor position. The cursor hotspot is relative to * the cursor image. Otherwise this works exactly like @cursor_set. * * This entry point is deprecated, drivers should instead implement * universal plane support and register a proper cursor plane using * drm_crtc_init_with_planes(). * * This callback is optional. * * RETURNS: * * 0 on success or a negative error code on failure. */ int (*cursor_set2)(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height, int32_t hot_x, int32_t hot_y);
/** * @cursor_move: * * Update the cursor position. The cursor does not need to be visible * when this hook is called. * * This entry point is deprecated, drivers should instead implement * universal plane support and register a proper cursor plane using * drm_crtc_init_with_planes(). * * This callback is optional. * * RETURNS: * * 0 on success or a negative error code on failure. */ int (*cursor_move)(struct drm_crtc *crtc, int x, int y);
/** * @gamma_set: * * Set gamma on the CRTC. * * This callback is optional. * * Atomic drivers who want to support gamma tables should implement the * atomic color management support, enabled by calling * drm_crtc_enable_color_mgmt(), which then supports the legacy gamma * interface through the drm_atomic_helper_legacy_gamma_set() * compatibility implementation. */ int (*gamma_set)(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t size, struct drm_modeset_acquire_ctx *ctx);
/** * @destroy: * * Clean up CRTC resources. This is only called at driver unload time * through drm_mode_config_cleanup() since a CRTC cannot be hotplugged * in DRM. */ void (*destroy)(struct drm_crtc *crtc);
/** * @set_config: * * This is the main legacy entry point to change the modeset state on a * CRTC. All the details of the desired configuration are passed in a * &struct drm_mode_set - see there for details. * * Drivers implementing atomic modeset should use * drm_atomic_helper_set_config() to implement this hook. * * RETURNS: * * 0 on success or a negative error code on failure. */ int (*set_config)(struct drm_mode_set *set, struct drm_modeset_acquire_ctx *ctx); /** * @page_flip: * * Legacy entry point to schedule a flip to the given framebuffer. * * Page flipping is a synchronization mechanism that replaces the frame * buffer being scanned out by the CRTC with a new frame buffer during * vertical blanking, avoiding tearing (except when requested otherwise * through the DRM_MODE_PAGE_FLIP_ASYNC flag). When an application * requests a page flip the DRM core verifies that the new frame buffer * is large enough to be scanned out by the CRTC in the currently * configured mode and then calls this hook with a pointer to the new * frame buffer. * * The driver must wait for any pending rendering to the new framebuffer * to complete before executing the flip. It should also wait for any * pending rendering from other drivers if the underlying buffer is a * shared dma-buf. * * An application can request to be notified when the page flip has * completed. The drm core will supply a &struct drm_event in the event * parameter in this case. This can be handled by the * drm_crtc_send_vblank_event() function, which the driver should call on * the provided event upon completion of the flip. Note that if * the driver supports vblank signalling and timestamping the vblank * counters and timestamps must agree with the ones returned from page * flip events. With the current vblank helper infrastructure this can * be achieved by holding a vblank reference while the page flip is * pending, acquired through drm_crtc_vblank_get() and released with * drm_crtc_vblank_put(). Drivers are free to implement their own vblank * counter and timestamp tracking though, e.g. if they have accurate * timestamp registers in hardware. * * This callback is optional. * * NOTE: * * Very early versions of the KMS ABI mandated that the driver must * block (but not reject) any rendering to the old framebuffer until the * flip operation has completed and the old framebuffer is no longer * visible. This requirement has been lifted, and userspace is instead * expected to request delivery of an event and wait with recycling old * buffers until such has been received. * * RETURNS: * * 0 on success or a negative error code on failure. Note that if a * page flip operation is already pending the callback should return * -EBUSY. Pageflips on a disabled CRTC (either by setting a NULL mode * or just runtime disabled through DPMS respectively the new atomic * "ACTIVE" state) should result in an -EINVAL error code. Note that * drm_atomic_helper_page_flip() checks this already for atomic drivers. */ int (*page_flip)(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t flags, struct drm_modeset_acquire_ctx *ctx);
/** * @page_flip_target: * * Same as @page_flip but with an additional parameter specifying the * absolute target vertical blank period (as reported by * drm_crtc_vblank_count()) when the flip should take effect. * * Note that the core code calls drm_crtc_vblank_get before this entry * point, and will call drm_crtc_vblank_put if this entry point returns * any non-0 error code. It's the driver's responsibility to call * drm_crtc_vblank_put after this entry point returns 0, typically when * the flip completes. */ int (*page_flip_target)(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t flags, uint32_t target, struct drm_modeset_acquire_ctx *ctx);
/** * @set_property: * * This is the legacy entry point to update a property attached to the * CRTC. * * This callback is optional if the driver does not support any legacy * driver-private properties. For atomic drivers it is not used because * property handling is done entirely in the DRM core. * * RETURNS: * * 0 on success or a negative error code on failure. */ int (*set_property)(struct drm_crtc *crtc, struct drm_property *property, uint64_t val);
/** * @atomic_duplicate_state: * * Duplicate the current atomic state for this CRTC and return it. * The core and helpers guarantee that any atomic state duplicated with * this hook and still owned by the caller (i.e. not transferred to the * driver by calling &drm_mode_config_funcs.atomic_commit) will be * cleaned up by calling the @atomic_destroy_state hook in this * structure. * * This callback is mandatory for atomic drivers. * * Atomic drivers which don't subclass &struct drm_crtc_state should use * drm_atomic_helper_crtc_duplicate_state(). Drivers that subclass the * state structure to extend it with driver-private state should use * __drm_atomic_helper_crtc_duplicate_state() to make sure shared state is * duplicated in a consistent fashion across drivers. * * It is an error to call this hook before &drm_crtc.state has been * initialized correctly. * * NOTE: * * If the duplicate state references refcounted resources this hook must * acquire a reference for each of them. The driver must release these * references again in @atomic_destroy_state. * * RETURNS: * * Duplicated atomic state or NULL when the allocation failed. */ structdrm_crtc_state *(*atomic_duplicate_state)(structdrm_crtc *crtc);
/** * @atomic_destroy_state: * * Destroy a state duplicated with @atomic_duplicate_state and release * or unreference all resources it references * * This callback is mandatory for atomic drivers. */ void (*atomic_destroy_state)(struct drm_crtc *crtc, struct drm_crtc_state *state);
/** * @atomic_set_property: * * Decode a driver-private property value and store the decoded value * into the passed-in state structure. Since the atomic core decodes all * standardized properties (even for extensions beyond the core set of * properties which might not be implemented by all drivers) this * requires drivers to subclass the state structure. * * Such driver-private properties should really only be implemented for * truly hardware/vendor specific state. Instead it is preferred to * standardize atomic extension and decode the properties used to expose * such an extension in the core. * * Do not call this function directly, use * drm_atomic_crtc_set_property() instead. * * This callback is optional if the driver does not support any * driver-private atomic properties. * * NOTE: * * This function is called in the state assembly phase of atomic * modesets, which can be aborted for any reason (including on * userspace's request to just check whether a configuration would be * possible). Drivers MUST NOT touch any persistent state (hardware or * software) or data structures except the passed in @state parameter. * * Also since userspace controls in which order properties are set this * function must not do any input validation (since the state update is * incomplete and hence likely inconsistent). Instead any such input * validation must be done in the various atomic_check callbacks. * * RETURNS: * * 0 if the property has been found, -EINVAL if the property isn't * implemented by the driver (which should never happen, the core only * asks for properties attached to this CRTC). No other validation is * allowed by the driver. The core already checks that the property * value is within the range (integer, valid enum value, ...) the driver * set when registering the property. */ int (*atomic_set_property)(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, uint64_t val); /** * @atomic_get_property: * * Reads out the decoded driver-private property. This is used to * implement the GETCRTC IOCTL. * * Do not call this function directly, use * drm_atomic_crtc_get_property() instead. * * This callback is optional if the driver does not support any * driver-private atomic properties. * * RETURNS: * * 0 on success, -EINVAL if the property isn't implemented by the * driver (which should never happen, the core only asks for * properties attached to this CRTC). */ int (*atomic_get_property)(struct drm_crtc *crtc, const struct drm_crtc_state *state, struct drm_property *property, uint64_t *val);
/** * @late_register: * * This optional hook can be used to register additional userspace * interfaces attached to the crtc like debugfs interfaces. * It is called late in the driver load sequence from drm_dev_register(). * Everything added from this callback should be unregistered in * the early_unregister callback. * * Returns: * * 0 on success, or a negative error code on failure. */ int (*late_register)(struct drm_crtc *crtc);
/** * @early_unregister: * * This optional hook should be used to unregister the additional * userspace interfaces attached to the crtc from * @late_register. It is called from drm_dev_unregister(), * early in the driver unload sequence to disable userspace access * before data structures are torndown. */ void (*early_unregister)(struct drm_crtc *crtc);
/** * @set_crc_source: * * Changes the source of CRC checksums of frames at the request of * userspace, typically for testing purposes. The sources available are * specific of each driver and a %NULL value indicates that CRC * generation is to be switched off. * * When CRC generation is enabled, the driver should call * drm_crtc_add_crc_entry() at each frame, providing any information * that characterizes the frame contents in the crcN arguments, as * provided from the configured source. Drivers must accept an "auto" * source name that will select a default source for this CRTC. * * This may trigger an atomic modeset commit if necessary, to enable CRC * generation. * * Note that "auto" can depend upon the current modeset configuration, * e.g. it could pick an encoder or output specific CRC sampling point. * * This callback is optional if the driver does not support any CRC * generation functionality. * * RETURNS: * * 0 on success or a negative error code on failure. */ int (*set_crc_source)(struct drm_crtc *crtc, constchar *source);
/** * @verify_crc_source: * * verifies the source of CRC checksums of frames before setting the * source for CRC and during crc open. Source parameter can be NULL * while disabling crc source. * * This callback is optional if the driver does not support any CRC * generation functionality. * * RETURNS: * * 0 on success or a negative error code on failure. */ int (*verify_crc_source)(struct drm_crtc *crtc, constchar *source, size_t *values_cnt); /** * @get_crc_sources: * * Driver callback for getting a list of all the available sources for * CRC generation. This callback depends upon verify_crc_source, So * verify_crc_source callback should be implemented before implementing * this. Driver can pass full list of available crc sources, this * callback does the verification on each crc-source before passing it * to userspace. * * This callback is optional if the driver does not support exporting of * possible CRC sources list. * * RETURNS: * * a constant character pointer to the list of all the available CRC * sources. On failure driver should return NULL. count should be * updated with number of sources in list. if zero we don't process any * source from the list. */ constchar *const *(*get_crc_sources)(struct drm_crtc *crtc, size_t *count);
/** * @atomic_print_state: * * If driver subclasses &struct drm_crtc_state, it should implement * this optional hook for printing additional driver specific state. * * Do not call this directly, use drm_atomic_crtc_print_state() * instead. */ void (*atomic_print_state)(struct drm_printer *p, const struct drm_crtc_state *state);
/** * @get_vblank_counter: * * Driver callback for fetching a raw hardware vblank counter for the * CRTC. It's meant to be used by new drivers as the replacement of * &drm_driver.get_vblank_counter hook. * * This callback is optional. If a device doesn't have a hardware * counter, the driver can simply leave the hook as NULL. The DRM core * will account for missed vblank events while interrupts where disabled * based on system timestamps. * * Wraparound handling and loss of events due to modesetting is dealt * with in the DRM core code, as long as drivers call * drm_crtc_vblank_off() and drm_crtc_vblank_on() when disabling or * enabling a CRTC. * * See also &drm_device.vblank_disable_immediate and * &drm_device.max_vblank_count. * * Returns: * * Raw vblank counter value. */ u32 (*get_vblank_counter)(struct drm_crtc *crtc);
/** * @enable_vblank: * * Enable vblank interrupts for the CRTC. It's meant to be used by * new drivers as the replacement of &drm_driver.enable_vblank hook. * * Returns: * * Zero on success, appropriate errno if the vblank interrupt cannot * be enabled. */ int (*enable_vblank)(struct drm_crtc *crtc);
/** * @disable_vblank: * * Disable vblank interrupts for the CRTC. It's meant to be used by * new drivers as the replacement of &drm_driver.disable_vblank hook. */ void (*disable_vblank)(struct drm_crtc *crtc);
/** * @get_vblank_timestamp: * * Called by drm_get_last_vbltimestamp(). Should return a precise * timestamp when the most recent vblank interval ended or will end. * * Specifically, the timestamp in @vblank_time should correspond as * closely as possible to the time when the first video scanline of * the video frame after the end of vblank will start scanning out, * the time immediately after end of the vblank interval. If the * @crtc is currently inside vblank, this will be a time in the future. * If the @crtc is currently scanning out a frame, this will be the * past start time of the current scanout. This is meant to adhere * to the OpenML OML_sync_control extension specification. * * Parameters: * * crtc: * CRTC for which timestamp should be returned. * max_error: * Maximum allowable timestamp error in nanoseconds. * Implementation should strive to provide timestamp * with an error of at most max_error nanoseconds. * Returns true upper bound on error for timestamp. * vblank_time: * Target location for returned vblank timestamp. * in_vblank_irq: * True when called from drm_crtc_handle_vblank(). Some drivers * need to apply some workarounds for gpu-specific vblank irq quirks * if flag is set. * * Returns: * * True on success, false on failure, which means the core should * fallback to a simple timestamp taken in drm_crtc_handle_vblank(). */ bool (*get_vblank_timestamp)(struct drm_crtc *crtc, int *max_error, ktime_t *vblank_time, bool in_vblank_irq); };
/** * struct drm_crtc_helper_funcs - helper operations for CRTCs * * These hooks are used by the legacy CRTC helpers, the transitional plane * helpers and the new atomic modesetting helpers. */ structdrm_crtc_helper_funcs { /** * @dpms: * * Callback to control power levels on the CRTC. If the mode passed in * is unsupported, the provider must use the next lowest power level. * This is used by the legacy CRTC helpers to implement DPMS * functionality in drm_helper_connector_dpms(). * * This callback is also used to disable a CRTC by calling it with * DRM_MODE_DPMS_OFF if the @disable hook isn't used. * * This callback is used by the legacy CRTC helpers. Atomic helpers * also support using this hook for enabling and disabling a CRTC to * facilitate transitions to atomic, but it is deprecated. Instead * @atomic_enable and @atomic_disable should be used. */ void (*dpms)(struct drm_crtc *crtc, int mode);
/** * @prepare: * * This callback should prepare the CRTC for a subsequent modeset, which * in practice means the driver should disable the CRTC if it is * running. Most drivers ended up implementing this by calling their * @dpms hook with DRM_MODE_DPMS_OFF. * * This callback is used by the legacy CRTC helpers. Atomic helpers * also support using this hook for disabling a CRTC to facilitate * transitions to atomic, but it is deprecated. Instead @atomic_disable * should be used. */ void (*prepare)(struct drm_crtc *crtc);
/** * @commit: * * This callback should commit the new mode on the CRTC after a modeset, * which in practice means the driver should enable the CRTC. Most * drivers ended up implementing this by calling their @dpms hook with * DRM_MODE_DPMS_ON. * * This callback is used by the legacy CRTC helpers. Atomic helpers * also support using this hook for enabling a CRTC to facilitate * transitions to atomic, but it is deprecated. Instead @atomic_enable * should be used. */ void (*commit)(struct drm_crtc *crtc); /** * @mode_valid: * * This callback is used to check if a specific mode is valid in this * crtc. This should be implemented if the crtc has some sort of * restriction in the modes it can display. For example, a given crtc * may be responsible to set a clock value. If the clock can not * produce all the values for the available modes then this callback * can be used to restrict the number of modes to only the ones that * can be displayed. * * This hook is used by the probe helpers to filter the mode list in * drm_helper_probe_single_connector_modes(), and it is used by the * atomic helpers to validate modes supplied by userspace in * drm_atomic_helper_check_modeset(). * * This function is optional. * * NOTE: * * Since this function is both called from the check phase of an atomic * commit, and the mode validation in the probe paths it is not allowed * to look at anything else but the passed-in mode, and validate it * against configuration-invariant hardward constraints. Any further * limits which depend upon the configuration can only be checked in * @mode_fixup or @atomic_check. * * RETURNS: * * drm_mode_status Enum */ enumdrm_mode_status(*mode_valid)(struct drm_crtc *crtc, const struct drm_display_mode *mode);
/** * @mode_fixup: * * This callback is used to validate a mode. The parameter mode is the * display mode that userspace requested, adjusted_mode is the mode the * encoders need to be fed with. Note that this is the inverse semantics * of the meaning for the &drm_encoder and &drm_bridge_funcs.mode_fixup * vfunc. If the CRTC cannot support the requested conversion from mode * to adjusted_mode it should reject the modeset. See also * &drm_crtc_state.adjusted_mode for more details. * * This function is used by both legacy CRTC helpers and atomic helpers. * With atomic helpers it is optional. * * NOTE: * * This function is called in the check phase of atomic modesets, which * can be aborted for any reason (including on userspace's request to * just check whether a configuration would be possible). Atomic drivers * MUST NOT touch any persistent state (hardware or software) or data * structures except the passed in adjusted_mode parameter. * * This is in contrast to the legacy CRTC helpers where this was * allowed. * * Atomic drivers which need to inspect and adjust more state should * instead use the @atomic_check callback, but note that they're not * perfectly equivalent: @mode_valid is called from * drm_atomic_helper_check_modeset(), but @atomic_check is called from * drm_atomic_helper_check_planes(), because originally it was meant for * plane update checks only. * * Also beware that userspace can request its own custom modes, neither * core nor helpers filter modes to the list of probe modes reported by * the GETCONNECTOR IOCTL and stored in &drm_connector.modes. To ensure * that modes are filtered consistently put any CRTC constraints and * limits checks into @mode_valid. * * RETURNS: * * True if an acceptable configuration is possible, false if the modeset * operation should be rejected. */ bool (*mode_fixup)(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode);
/** * @mode_set: * * This callback is used by the legacy CRTC helpers to set a new mode, * position and framebuffer. Since it ties the primary plane to every * mode change it is incompatible with universal plane support. And * since it can't update other planes it's incompatible with atomic * modeset support. * * This callback is only used by CRTC helpers and deprecated. * * RETURNS: * * 0 on success or a negative error code on failure. */ int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode, int x, int y, struct drm_framebuffer *old_fb); /** * @mode_set_nofb: * * This callback is used to update the display mode of a CRTC without * changing anything of the primary plane configuration. This fits the * requirement of atomic and hence is used by the atomic helpers. It is * also used by the transitional plane helpers to implement a * @mode_set hook in drm_helper_crtc_mode_set(). * * Note that the display pipe is completely off when this function is * called. Atomic drivers which need hardware to be running before they * program the new display mode (e.g. because they implement runtime PM) * should not use this hook. This is because the helper library calls * this hook only once per mode change and not every time the display * pipeline is suspended using either DPMS or the new "ACTIVE" property. * Which means register values set in this callback might get reset when * the CRTC is suspended, but not restored. Such drivers should instead * move all their CRTC setup into the @atomic_enable callback. * * This callback is optional. */ void (*mode_set_nofb)(struct drm_crtc *crtc);
/** * @mode_set_base: * * This callback is used by the legacy CRTC helpers to set a new * framebuffer and scanout position. It is optional and used as an * optimized fast-path instead of a full mode set operation with all the * resulting flickering. If it is not present * drm_crtc_helper_set_config() will fall back to a full modeset, using * the @mode_set callback. Since it can't update other planes it's * incompatible with atomic modeset support. * * This callback is only used by the CRTC helpers and deprecated. * * RETURNS: * * 0 on success or a negative error code on failure. */ int (*mode_set_base)(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb);
/** * @mode_set_base_atomic: * * This callback is used by the fbdev helpers to set a new framebuffer * and scanout without sleeping, i.e. from an atomic calling context. It * is only used to implement kgdb support. * * This callback is optional and only needed for kgdb support in the fbdev * helpers. * * RETURNS: * * 0 on success or a negative error code on failure. */ int (*mode_set_base_atomic)(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y, enum mode_set_atomic);
/** * @disable: * * This callback should be used to disable the CRTC. With the atomic * drivers it is called after all encoders connected to this CRTC have * been shut off already using their own * &drm_encoder_helper_funcs.disable hook. If that sequence is too * simple drivers can just add their own hooks and call it from this * CRTC callback here by looping over all encoders connected to it using * for_each_encoder_on_crtc(). * * This hook is used both by legacy CRTC helpers and atomic helpers. * Atomic drivers don't need to implement it if there's no need to * disable anything at the CRTC level. To ensure that runtime PM * handling (using either DPMS or the new "ACTIVE" property) works * @disable must be the inverse of @atomic_enable for atomic drivers. * Atomic drivers should consider to use @atomic_disable instead of * this one. * * NOTE: * * With legacy CRTC helpers there's a big semantic difference between * @disable and other hooks (like @prepare or @dpms) used to shut down a * CRTC: @disable is only called when also logically disabling the * display pipeline and needs to release any resources acquired in * @mode_set (like shared PLLs, or again release pinned framebuffers). * * Therefore @disable must be the inverse of @mode_set plus @commit for * drivers still using legacy CRTC helpers, which is different from the * rules under atomic. */ void (*disable)(struct drm_crtc *crtc);
/** * @atomic_check: * * Drivers should check plane-update related CRTC constraints in this * hook. They can also check mode related limitations but need to be * aware of the calling order, since this hook is used by * drm_atomic_helper_check_planes() whereas the preparations needed to * check output routing and the display mode is done in * drm_atomic_helper_check_modeset(). Therefore drivers that want to * check output routing and display mode constraints in this callback * must ensure that drm_atomic_helper_check_modeset() has been called * beforehand. This is calling order used by the default helper * implementation in drm_atomic_helper_check(). * * When using drm_atomic_helper_check_planes() this hook is called * after the &drm_plane_helper_funcs.atomic_check hook for planes, which * allows drivers to assign shared resources requested by planes in this * callback here. For more complicated dependencies the driver can call * the provided check helpers multiple times until the computed state * has a final configuration and everything has been checked. * * This function is also allowed to inspect any other object's state and * can add more state objects to the atomic commit if needed. Care must * be taken though to ensure that state check and compute functions for * these added states are all called, and derived state in other objects * all updated. Again the recommendation is to just call check helpers * until a maximal configuration is reached. * * This callback is used by the atomic modeset helpers and by the * transitional plane helpers, but it is optional. * * NOTE: * * This function is called in the check phase of an atomic update. The * driver is not allowed to change anything outside of the free-standing * state object passed-in. * * Also beware that userspace can request its own custom modes, neither * core nor helpers filter modes to the list of probe modes reported by * the GETCONNECTOR IOCTL and stored in &drm_connector.modes. To ensure * that modes are filtered consistently put any CRTC constraints and * limits checks into @mode_valid. * * RETURNS: * * 0 on success, -EINVAL if the state or the transition can't be * supported, -ENOMEM on memory allocation failure and -EDEADLK if an * attempt to obtain another state object ran into a &drm_modeset_lock * deadlock. */ int (*atomic_check)(struct drm_crtc *crtc, struct drm_atomic_state *state); /** * @atomic_begin: * * Drivers should prepare for an atomic update of multiple planes on * a CRTC in this hook. Depending upon hardware this might be vblank * evasion, blocking updates by setting bits or doing preparatory work * for e.g. manual update display. * * This hook is called before any plane commit functions are called. * * Note that the power state of the display pipe when this function is * called depends upon the exact helpers and calling sequence the driver * has picked. See drm_atomic_helper_commit_planes() for a discussion of * the tradeoffs and variants of plane commit helpers. * * This callback is used by the atomic modeset helpers and by the * transitional plane helpers, but it is optional. */ void (*atomic_begin)(struct drm_crtc *crtc, struct drm_atomic_state *state); /** * @atomic_flush: * * Drivers should finalize an atomic update of multiple planes on * a CRTC in this hook. Depending upon hardware this might include * checking that vblank evasion was successful, unblocking updates by * setting bits or setting the GO bit to flush out all updates. * * Simple hardware or hardware with special requirements can commit and * flush out all updates for all planes from this hook and forgo all the * other commit hooks for plane updates. * * This hook is called after any plane commit functions are called. * * Note that the power state of the display pipe when this function is * called depends upon the exact helpers and calling sequence the driver * has picked. See drm_atomic_helper_commit_planes() for a discussion of * the tradeoffs and variants of plane commit helpers. * * This callback is used by the atomic modeset helpers and by the * transitional plane helpers, but it is optional. */ void (*atomic_flush)(struct drm_crtc *crtc, struct drm_atomic_state *state);
/** * @atomic_enable: * * This callback should be used to enable the CRTC. With the atomic * drivers it is called before all encoders connected to this CRTC are * enabled through the encoder's own &drm_encoder_helper_funcs.enable * hook. If that sequence is too simple drivers can just add their own * hooks and call it from this CRTC callback here by looping over all * encoders connected to it using for_each_encoder_on_crtc(). * * This hook is used only by atomic helpers, for symmetry with * @atomic_disable. Atomic drivers don't need to implement it if there's * no need to enable anything at the CRTC level. To ensure that runtime * PM handling (using either DPMS or the new "ACTIVE" property) works * @atomic_enable must be the inverse of @atomic_disable for atomic * drivers. * * This function is optional. */ void (*atomic_enable)(struct drm_crtc *crtc, struct drm_atomic_state *state);
/** * @atomic_disable: * * This callback should be used to disable the CRTC. With the atomic * drivers it is called after all encoders connected to this CRTC have * been shut off already using their own * &drm_encoder_helper_funcs.disable hook. If that sequence is too * simple drivers can just add their own hooks and call it from this * CRTC callback here by looping over all encoders connected to it using * for_each_encoder_on_crtc(). * * This hook is used only by atomic helpers. Atomic drivers don't * need to implement it if there's no need to disable anything at the * CRTC level. * * This function is optional. */ void (*atomic_disable)(struct drm_crtc *crtc, struct drm_atomic_state *state);
/** * @get_scanout_position: * * Called by vblank timestamping code. * * Returns the current display scanout position from a CRTC and an * optional accurate ktime_get() timestamp of when the position was * measured. Note that this is a helper callback which is only used * if a driver uses drm_crtc_vblank_helper_get_vblank_timestamp() * for the @drm_crtc_funcs.get_vblank_timestamp callback. * * Parameters: * * crtc: * The CRTC. * in_vblank_irq: * True when called from drm_crtc_handle_vblank(). Some drivers * need to apply some workarounds for gpu-specific vblank irq * quirks if the flag is set. * vpos: * Target location for current vertical scanout position. * hpos: * Target location for current horizontal scanout position. * stime: * Target location for timestamp taken immediately before * scanout position query. Can be NULL to skip timestamp. * etime: * Target location for timestamp taken immediately after * scanout position query. Can be NULL to skip timestamp. * mode: * Current display timings. * * Returns vpos as a positive number while in active scanout area. * Returns vpos as a negative number inside vblank, counting the number * of scanlines to go until end of vblank, e.g., -1 means "one scanline * until start of active scanout / end of vblank." * * Returns: * * True on success, false if a reliable scanout position counter could * not be read out. */ bool (*get_scanout_position)(struct drm_crtc *crtc, bool in_vblank_irq, int *vpos, int *hpos, ktime_t *stime, ktime_t *etime, const struct drm_display_mode *mode); };
/** * drm_crtc_init_with_planes - Initialise a new CRTC object with * specified primary and cursor planes. * @dev: DRM device * @crtc: CRTC object to init * @primary: Primary plane for CRTC * @cursor: Cursor plane for CRTC * @funcs: callbacks for the new CRTC * @name: printf style format string for the CRTC name, or NULL for default name * * Inits a new object created as base part of a driver crtc object. Drivers * should use this function instead of drm_crtc_init(), which is only provided * for backwards compatibility with drivers which do not yet support universal * planes). For really simple hardware which has only 1 plane look at * drm_simple_display_pipe_init() instead. * The &drm_crtc_funcs.destroy hook should call drm_crtc_cleanup() and kfree() * the crtc structure. The crtc structure should not be allocated with * devm_kzalloc(). * * The @primary and @cursor planes are only relevant for legacy uAPI, see * &drm_crtc.primary and &drm_crtc.cursor. * * Note: consider using drmm_crtc_alloc_with_planes() or * drmm_crtc_init_with_planes() instead of drm_crtc_init_with_planes() * to let the DRM managed resource infrastructure take care of cleanup * and deallocation. * * Returns: * Zero on success, error code on failure. */ intdrm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, struct drm_plane *primary, // primary plane struct drm_plane *cursor, // cursor plane const struct drm_crtc_funcs *funcs, // crtc回调函数,重点关注 constchar *name, ...) { va_list ap; int ret;
/** * DOC: standard CRTC properties * * DRM CRTCs have a few standardized properties: * * ACTIVE: * Atomic property for setting the power state of the CRTC. When set to 1 * the CRTC will actively display content. When set to 0 the CRTC will be * powered off. There is no expectation that user-space will reset CRTC * resources like the mode and planes when setting ACTIVE to 0. * * User-space can rely on an ACTIVE change to 1 to never fail an atomic * test as long as no other property has changed. If a change to ACTIVE * fails an atomic test, this is a driver bug. For this reason setting * ACTIVE to 0 must not release internal resources (like reserved memory * bandwidth or clock generators). * * Note that the legacy DPMS property on connectors is internally routed * to control this property for atomic drivers. * MODE_ID: * Atomic property for setting the CRTC display timings. The value is the * ID of a blob containing the DRM mode info. To disable the CRTC, * user-space must set this property to 0. * * Setting MODE_ID to 0 will release reserved resources for the CRTC. * SCALING_FILTER: * Atomic property for setting the scaling filter for CRTC scaler * * The value of this property can be one of the following: * * Default: * Driver's default scaling filter * Nearest Neighbor: * Nearest Neighbor scaling filter */
/* physical map length of vop register */ uint32_t len;
/* one time only one process allowed to config the register */ spinlock_t reg_lock; /* lock vop irq reg */ spinlock_t irq_lock; /* protects crtc enable/disable */ structmutexvop_lock;
/* * Create drm_plane for primary and cursor planes first, since we need * to pass them to drm_crtc_init_with_planes, which sets the * "possible_crtcs" to the newly initialized crtc. * 1. 遍历每一个vop win,每个vop win内部包含一个drm_plane,对类型为primary和cursor plane * 进行初始化 */ for (i = 0; i < vop_data->win_size; i++) { // 获取第i个vop win structvop_win *vop_win = &vop->win[i]; // 获取第i个vop win data conststructvop_win_data *win_data = vop_win->data;
// 5. 从vopb节点的子节点列表中查找名为port的子节点,也就是vopb_out节点 port = of_get_child_by_name(dev->of_node, "port"); if (!port) { DRM_DEV_ERROR(vop->dev, "no port node found in %pOF\n", dev->of_node); ret = -ENOENT; goto err_cleanup_crtc; }
// 7. 对crtc进行自刷新相关的辅助函数初始化 ret = drm_self_refresh_helper_init(crtc); if (ret) DRM_DEV_DEBUG_KMS(vop->dev, "Failed to init %s with SR helpers %d, ignoring\n", crtc->name, ret);
(2) 调用drm_crtc_init_with_planes使用指定的primary and cursor planes初始化的crtc对象,其中crtc回调函数funcs设置为vop_crtc_funcs,定义在drivers/gpu/drm/rockchip/rockchip_drm_vop.c;
/** * drm_self_refresh_helper_init - Initializes self refresh helpers for a crtc * @crtc: the crtc which supports self refresh supported displays * * Returns zero if successful or -errno on failure */ intdrm_self_refresh_helper_init(struct drm_crtc *crtc) { structdrm_self_refresh_data *sr_data = crtc->self_refresh_data;
/* Helper is already initialized */ if (WARN_ON(sr_data)) return -EINVAL;
sr_data = kzalloc(sizeof(*sr_data), GFP_KERNEL); if (!sr_data) return -ENOMEM;
/* * Seed the averages so they're non-zero (and sufficiently large * for even poorly performing panels). As time goes on, this will be * averaged out and the values will trend to their true value. */ ewma_psr_time_add(&sr_data->entry_avg_ms, SELF_REFRESH_AVG_SEED_MS); ewma_psr_time_add(&sr_data->exit_avg_ms, SELF_REFRESH_AVG_SEED_MS);
static int vop_initial(structvop *vop) { structreset_control *ahb_rst; int i, ret;
// 根据时钟名称hclk_vop获取时钟,设备节点属性clock-names、clocks,指定了名字为hclk_vop对应的时钟为<&cru HCLK_VOP0> vop->hclk = devm_clk_get(vop->dev, "hclk_vop"); if (IS_ERR(vop->hclk)) { DRM_DEV_ERROR(vop->dev, "failed to get hclk source\n"); return PTR_ERR(vop->hclk); } // 根据时钟名称aclk_vop获取时钟,设备节点属性clock-names、clocks,指定了名字为aclk_vop对应的时钟为<&cru ACLK_VOP0> vop->aclk = devm_clk_get(vop->dev, "aclk_vop"); if (IS_ERR(vop->aclk)) { DRM_DEV_ERROR(vop->dev, "failed to get aclk source\n"); return PTR_ERR(vop->aclk); } // 根据时钟名称dclk_vop获取时钟,设备节点属性clock-names、clocks,指定了名字为dclk_vop对应的时钟为<&cru DCLK_VOP0> vop->dclk = devm_clk_get(vop->dev, "dclk_vop"); if (IS_ERR(vop->dclk)) { DRM_DEV_ERROR(vop->dev, "failed to get dclk source\n"); return PTR_ERR(vop->dclk); }
// 电源相关,,使能设备的runtime pm功能 暂且忽略 ret = pm_runtime_resume_and_get(vop->dev); if (ret < 0) { DRM_DEV_ERROR(vop->dev, "failed to get pm runtime: %d\n", ret); return ret; } // dclk时钟准备,使其处于可用状态,但不启用它 ret = clk_prepare(vop->dclk); if (ret < 0) { DRM_DEV_ERROR(vop->dev, "failed to prepare dclk\n"); goto err_put_pm_runtime; }
/* Enable both the hclk and aclk to setup the vop,hclk时钟准备和使能 */ ret = clk_prepare_enable(vop->hclk); if (ret < 0) { DRM_DEV_ERROR(vop->dev, "failed to prepare/enable hclk\n"); goto err_unprepare_dclk; }
// aclk时钟准备和使能 ret = clk_prepare_enable(vop->aclk); if (ret < 0) { DRM_DEV_ERROR(vop->dev, "failed to prepare/enable aclk\n"); goto err_disable_hclk; }
/* * do hclk_reset, reset all vop registers. 获取ahb相应的reset句柄 */ ahb_rst = devm_reset_control_get(vop->dev, "ahb"); if (IS_ERR(ahb_rst)) { DRM_DEV_ERROR(vop->dev, "failed to get ahb reset\n"); ret = PTR_ERR(ahb_rst); goto err_disable_aclk; } // 对传入的reset资源进行复位操作 reset_control_assert(ahb_rst); // 睡眠,单位为微妙 usleep_range(10, 20); // 对传入的reset资源进行解复位操作 reset_control_deassert(ahb_rst);
/* * The irq is shared with the iommu. If the runtime-pm state of the * vop-device is disabled the irq has to be targeted at the iommu. */ if (!pm_runtime_get_if_in_use(vop->dev)) return IRQ_NONE;
if (vop_core_clks_enable(vop)) { DRM_DEV_ERROR_RATELIMITED(vop->dev, "couldn't enable clocks\n"); goto out; }
/* * interrupt register has interrupt status, enable and clear bits, we * must hold irq_lock to avoid a race with enable/disable_vblank(). */ spin_lock(&vop->irq_lock);
active_irqs = VOP_INTR_GET_TYPE(vop, status, INTR_MASK); /* Clear all active interrupt sources */ if (active_irqs) VOP_INTR_SET_TYPE(vop, clear, active_irqs, 1);
spin_unlock(&vop->irq_lock);
/* This is expected for vop iommu irqs, since the irq is shared */ if (!active_irqs) goto out_disable;
if (active_irqs & DSP_HOLD_VALID_INTR) { // 唤醒等待此特定complete事件的单个线程 complete(&vop->dsp_hold_completion); active_irqs &= ~DSP_HOLD_VALID_INTR; ret = IRQ_HANDLED; }
if (active_irqs & LINE_FLAG_INTR) { // 唤醒等待此特定complete事件的单个线程 complete(&vop->line_flag_completion); active_irqs &= ~LINE_FLAG_INTR; ret = IRQ_HANDLED; }
if (active_irqs & FS_INTR) { drm_crtc_handle_vblank(crtc); vop_handle_vblank(vop); active_irqs &= ~FS_INTR; ret = IRQ_HANDLED; }
/* Unhandled irqs are spurious. */ if (active_irqs) DRM_DEV_ERROR(vop->dev, "Unknown VOP IRQs: %#02x\n", active_irqs);