// SPDX-License-Identifier: MIT /* * Copyright © 2020 Intel Corporation */ #include "i915_reg.h" #include "intel_de.h" #include "intel_display_types.h" #include "intel_fb.h" #include "skl_scaler.h" #include "skl_universal_plane.h" /* * The hardware phase 0.0 refers to the center of the pixel. * We want to start from the top/left edge which is phase * -0.5. That matches how the hardware calculates the scaling * factors (from top-left of the first pixel to bottom-right * of the last pixel, as opposed to the pixel centers). * * For 4:2:0 subsampled chroma planes we obviously have to * adjust that so that the chroma sample position lands in * the right spot. * * Note that for packed YCbCr 4:2:2 formats there is no way to * control chroma siting. The hardware simply replicates the * chroma samples for both of the luma samples, and thus we don't * actually get the expected MPEG2 chroma siting convention :( * The same behaviour is observed on pre-SKL platforms as well. * * Theory behind the formula (note that we ignore sub-pixel * source coordinates): * s = source sample position * d = destination sample position * * Downscaling 4:1: * -0.5 * | 0.0 * | | 1.5 (initial phase) * | | | * v v v * | s | s | s | s | * | d | * * Upscaling 1:4: * -0.5 * | -0.375 (initial phase) * | | 0.0 * | | | * v v v * | s | * | d | d | d | d | */ static u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_cosited) { … } #define SKL_MIN_SRC_W … #define SKL_MAX_SRC_W … #define SKL_MIN_SRC_H … #define SKL_MAX_SRC_H … #define SKL_MIN_DST_W … #define SKL_MAX_DST_W … #define SKL_MIN_DST_H … #define SKL_MAX_DST_H … #define ICL_MAX_SRC_W … #define ICL_MAX_SRC_H … #define ICL_MAX_DST_W … #define ICL_MAX_DST_H … #define TGL_MAX_SRC_W … #define TGL_MAX_SRC_H … #define TGL_MAX_DST_W … #define TGL_MAX_DST_H … #define MTL_MAX_SRC_W … #define MTL_MAX_SRC_H … #define MTL_MAX_DST_W … #define MTL_MAX_DST_H … #define SKL_MIN_YUV_420_SRC_W … #define SKL_MIN_YUV_420_SRC_H … static int skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, unsigned int scaler_user, int *scaler_id, int src_w, int src_h, int dst_w, int dst_h, const struct drm_format_info *format, u64 modifier, bool need_scaler) { … } int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state) { … } /** * skl_update_scaler_plane - Stages update to scaler state for a given plane. * @crtc_state: crtc's scaler state * @plane_state: atomic plane state to update * * Return * 0 - scaler_usage updated successfully * error - requested scaling cannot be supported or other error condition */ int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, struct intel_plane_state *plane_state) { … } static int intel_atomic_setup_scaler(struct intel_crtc_scaler_state *scaler_state, int num_scalers_need, struct intel_crtc *intel_crtc, const char *name, int idx, struct intel_plane_state *plane_state, int *scaler_id) { … } /** * intel_atomic_setup_scalers() - setup scalers for crtc per staged requests * @dev_priv: i915 device * @intel_crtc: intel crtc * @crtc_state: incoming crtc_state to validate and setup scalers * * This function sets up scalers based on staged scaling requests for * a @crtc and its planes. It is called from crtc level check path. If request * is a supportable request, it attaches scalers to requested planes and crtc. * * This function takes into account the current scaler(s) in use by any planes * not being part of this atomic state * * Returns: * 0 - scalers were setup successfully * error code - otherwise */ int intel_atomic_setup_scalers(struct drm_i915_private *dev_priv, struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state) { … } static int glk_coef_tap(int i) { … } static u16 glk_nearest_filter_coef(int t) { … } /* * Theory behind setting nearest-neighbor integer scaling: * * 17 phase of 7 taps requires 119 coefficients in 60 dwords per set. * The letter represents the filter tap (D is the center tap) and the number * represents the coefficient set for a phase (0-16). * * +------------+------------------------+------------------------+ * |Index value | Data value coeffient 1 | Data value coeffient 2 | * +------------+------------------------+------------------------+ * | 00h | B0 | A0 | * +------------+------------------------+------------------------+ * | 01h | D0 | C0 | * +------------+------------------------+------------------------+ * | 02h | F0 | E0 | * +------------+------------------------+------------------------+ * | 03h | A1 | G0 | * +------------+------------------------+------------------------+ * | 04h | C1 | B1 | * +------------+------------------------+------------------------+ * | ... | ... | ... | * +------------+------------------------+------------------------+ * | 38h | B16 | A16 | * +------------+------------------------+------------------------+ * | 39h | D16 | C16 | * +------------+------------------------+------------------------+ * | 3Ah | F16 | C16 | * +------------+------------------------+------------------------+ * | 3Bh | Reserved | G16 | * +------------+------------------------+------------------------+ * * To enable nearest-neighbor scaling: program scaler coefficents with * the center tap (Dxx) values set to 1 and all other values set to 0 as per * SCALER_COEFFICIENT_FORMAT * */ static void glk_program_nearest_filter_coefs(struct drm_i915_private *dev_priv, enum pipe pipe, int id, int set) { … } static u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set) { … } static void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe, int id, int set, enum drm_scaling_filter filter) { … } void skl_pfit_enable(const struct intel_crtc_state *crtc_state) { … } void skl_program_plane_scaler(struct intel_plane *plane, const struct intel_crtc_state *crtc_state, const struct intel_plane_state *plane_state) { … } static void skl_detach_scaler(struct intel_crtc *crtc, int id) { … } /* * This function detaches (aka. unbinds) unused scalers in hardware */ void skl_detach_scalers(const struct intel_crtc_state *crtc_state) { … } void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state) { … } void skl_scaler_get_config(struct intel_crtc_state *crtc_state) { … }