0001
0002
0003
0004
0005 #include "intel_de.h"
0006 #include "intel_display_types.h"
0007 #include "intel_fb.h"
0008 #include "skl_scaler.h"
0009 #include "skl_universal_plane.h"
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051 static u16 skl_scaler_calc_phase(int sub, int scale, bool chroma_cosited)
0052 {
0053 int phase = -0x8000;
0054 u16 trip = 0;
0055
0056 if (chroma_cosited)
0057 phase += (sub - 1) * 0x8000 / sub;
0058
0059 phase += scale / (2 * sub);
0060
0061
0062
0063
0064
0065
0066 WARN_ON(phase < -0x8000 || phase > 0x18000);
0067
0068 if (phase < 0)
0069 phase = 0x10000 + phase;
0070 else
0071 trip = PS_PHASE_TRIP;
0072
0073 return ((phase >> 2) & PS_PHASE_MASK) | trip;
0074 }
0075
0076 #define SKL_MIN_SRC_W 8
0077 #define SKL_MAX_SRC_W 4096
0078 #define SKL_MIN_SRC_H 8
0079 #define SKL_MAX_SRC_H 4096
0080 #define SKL_MIN_DST_W 8
0081 #define SKL_MAX_DST_W 4096
0082 #define SKL_MIN_DST_H 8
0083 #define SKL_MAX_DST_H 4096
0084 #define ICL_MAX_SRC_W 5120
0085 #define ICL_MAX_SRC_H 4096
0086 #define ICL_MAX_DST_W 5120
0087 #define ICL_MAX_DST_H 4096
0088 #define SKL_MIN_YUV_420_SRC_W 16
0089 #define SKL_MIN_YUV_420_SRC_H 16
0090
0091 static int
0092 skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach,
0093 unsigned int scaler_user, int *scaler_id,
0094 int src_w, int src_h, int dst_w, int dst_h,
0095 const struct drm_format_info *format,
0096 u64 modifier, bool need_scaler)
0097 {
0098 struct intel_crtc_scaler_state *scaler_state =
0099 &crtc_state->scaler_state;
0100 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
0101 struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
0102 const struct drm_display_mode *adjusted_mode =
0103 &crtc_state->hw.adjusted_mode;
0104
0105
0106
0107
0108
0109
0110 if (src_w != dst_w || src_h != dst_h)
0111 need_scaler = true;
0112
0113
0114
0115
0116
0117
0118
0119 if (DISPLAY_VER(dev_priv) >= 9 && crtc_state->hw.enable &&
0120 need_scaler && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
0121 drm_dbg_kms(&dev_priv->drm,
0122 "Pipe/Plane scaling not supported with IF-ID mode\n");
0123 return -EINVAL;
0124 }
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136 if (force_detach || !need_scaler) {
0137 if (*scaler_id >= 0) {
0138 scaler_state->scaler_users &= ~(1 << scaler_user);
0139 scaler_state->scalers[*scaler_id].in_use = 0;
0140
0141 drm_dbg_kms(&dev_priv->drm,
0142 "scaler_user index %u.%u: "
0143 "Staged freeing scaler id %d scaler_users = 0x%x\n",
0144 crtc->pipe, scaler_user, *scaler_id,
0145 scaler_state->scaler_users);
0146 *scaler_id = -1;
0147 }
0148 return 0;
0149 }
0150
0151 if (format && intel_format_info_is_yuv_semiplanar(format, modifier) &&
0152 (src_h < SKL_MIN_YUV_420_SRC_H || src_w < SKL_MIN_YUV_420_SRC_W)) {
0153 drm_dbg_kms(&dev_priv->drm,
0154 "Planar YUV: src dimensions not met\n");
0155 return -EINVAL;
0156 }
0157
0158
0159 if (src_w < SKL_MIN_SRC_W || src_h < SKL_MIN_SRC_H ||
0160 dst_w < SKL_MIN_DST_W || dst_h < SKL_MIN_DST_H ||
0161 (DISPLAY_VER(dev_priv) >= 11 &&
0162 (src_w > ICL_MAX_SRC_W || src_h > ICL_MAX_SRC_H ||
0163 dst_w > ICL_MAX_DST_W || dst_h > ICL_MAX_DST_H)) ||
0164 (DISPLAY_VER(dev_priv) < 11 &&
0165 (src_w > SKL_MAX_SRC_W || src_h > SKL_MAX_SRC_H ||
0166 dst_w > SKL_MAX_DST_W || dst_h > SKL_MAX_DST_H))) {
0167 drm_dbg_kms(&dev_priv->drm,
0168 "scaler_user index %u.%u: src %ux%u dst %ux%u "
0169 "size is out of scaler range\n",
0170 crtc->pipe, scaler_user, src_w, src_h,
0171 dst_w, dst_h);
0172 return -EINVAL;
0173 }
0174
0175
0176 scaler_state->scaler_users |= (1 << scaler_user);
0177 drm_dbg_kms(&dev_priv->drm, "scaler_user index %u.%u: "
0178 "staged scaling request for %ux%u->%ux%u scaler_users = 0x%x\n",
0179 crtc->pipe, scaler_user, src_w, src_h, dst_w, dst_h,
0180 scaler_state->scaler_users);
0181
0182 return 0;
0183 }
0184
0185 int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state)
0186 {
0187 const struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode;
0188 int width, height;
0189
0190 if (crtc_state->pch_pfit.enabled) {
0191 width = drm_rect_width(&crtc_state->pch_pfit.dst);
0192 height = drm_rect_height(&crtc_state->pch_pfit.dst);
0193 } else {
0194 width = pipe_mode->crtc_hdisplay;
0195 height = pipe_mode->crtc_vdisplay;
0196 }
0197 return skl_update_scaler(crtc_state, !crtc_state->hw.active,
0198 SKL_CRTC_INDEX,
0199 &crtc_state->scaler_state.scaler_id,
0200 drm_rect_width(&crtc_state->pipe_src),
0201 drm_rect_height(&crtc_state->pipe_src),
0202 width, height, NULL, 0,
0203 crtc_state->pch_pfit.enabled);
0204 }
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215 int skl_update_scaler_plane(struct intel_crtc_state *crtc_state,
0216 struct intel_plane_state *plane_state)
0217 {
0218 struct intel_plane *intel_plane =
0219 to_intel_plane(plane_state->uapi.plane);
0220 struct drm_i915_private *dev_priv = to_i915(intel_plane->base.dev);
0221 struct drm_framebuffer *fb = plane_state->hw.fb;
0222 int ret;
0223 bool force_detach = !fb || !plane_state->uapi.visible;
0224 bool need_scaler = false;
0225
0226
0227 if (!icl_is_hdr_plane(dev_priv, intel_plane->id) &&
0228 fb && intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier))
0229 need_scaler = true;
0230
0231 ret = skl_update_scaler(crtc_state, force_detach,
0232 drm_plane_index(&intel_plane->base),
0233 &plane_state->scaler_id,
0234 drm_rect_width(&plane_state->uapi.src) >> 16,
0235 drm_rect_height(&plane_state->uapi.src) >> 16,
0236 drm_rect_width(&plane_state->uapi.dst),
0237 drm_rect_height(&plane_state->uapi.dst),
0238 fb ? fb->format : NULL,
0239 fb ? fb->modifier : 0,
0240 need_scaler);
0241
0242 if (ret || plane_state->scaler_id < 0)
0243 return ret;
0244
0245
0246 if (plane_state->ckey.flags) {
0247 drm_dbg_kms(&dev_priv->drm,
0248 "[PLANE:%d:%s] scaling with color key not allowed",
0249 intel_plane->base.base.id,
0250 intel_plane->base.name);
0251 return -EINVAL;
0252 }
0253
0254
0255 switch (fb->format->format) {
0256 case DRM_FORMAT_RGB565:
0257 case DRM_FORMAT_XBGR8888:
0258 case DRM_FORMAT_XRGB8888:
0259 case DRM_FORMAT_ABGR8888:
0260 case DRM_FORMAT_ARGB8888:
0261 case DRM_FORMAT_XRGB2101010:
0262 case DRM_FORMAT_XBGR2101010:
0263 case DRM_FORMAT_ARGB2101010:
0264 case DRM_FORMAT_ABGR2101010:
0265 case DRM_FORMAT_YUYV:
0266 case DRM_FORMAT_YVYU:
0267 case DRM_FORMAT_UYVY:
0268 case DRM_FORMAT_VYUY:
0269 case DRM_FORMAT_NV12:
0270 case DRM_FORMAT_XYUV8888:
0271 case DRM_FORMAT_P010:
0272 case DRM_FORMAT_P012:
0273 case DRM_FORMAT_P016:
0274 case DRM_FORMAT_Y210:
0275 case DRM_FORMAT_Y212:
0276 case DRM_FORMAT_Y216:
0277 case DRM_FORMAT_XVYU2101010:
0278 case DRM_FORMAT_XVYU12_16161616:
0279 case DRM_FORMAT_XVYU16161616:
0280 break;
0281 case DRM_FORMAT_XBGR16161616F:
0282 case DRM_FORMAT_ABGR16161616F:
0283 case DRM_FORMAT_XRGB16161616F:
0284 case DRM_FORMAT_ARGB16161616F:
0285 if (DISPLAY_VER(dev_priv) >= 11)
0286 break;
0287 fallthrough;
0288 default:
0289 drm_dbg_kms(&dev_priv->drm,
0290 "[PLANE:%d:%s] FB:%d unsupported scaling format 0x%x\n",
0291 intel_plane->base.base.id, intel_plane->base.name,
0292 fb->base.id, fb->format->format);
0293 return -EINVAL;
0294 }
0295
0296 return 0;
0297 }
0298
0299 static int glk_coef_tap(int i)
0300 {
0301 return i % 7;
0302 }
0303
0304 static u16 glk_nearest_filter_coef(int t)
0305 {
0306 return t == 3 ? 0x0800 : 0x3000;
0307 }
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346 static void glk_program_nearest_filter_coefs(struct drm_i915_private *dev_priv,
0347 enum pipe pipe, int id, int set)
0348 {
0349 int i;
0350
0351 intel_de_write_fw(dev_priv, GLK_PS_COEF_INDEX_SET(pipe, id, set),
0352 PS_COEE_INDEX_AUTO_INC);
0353
0354 for (i = 0; i < 17 * 7; i += 2) {
0355 u32 tmp;
0356 int t;
0357
0358 t = glk_coef_tap(i);
0359 tmp = glk_nearest_filter_coef(t);
0360
0361 t = glk_coef_tap(i + 1);
0362 tmp |= glk_nearest_filter_coef(t) << 16;
0363
0364 intel_de_write_fw(dev_priv, GLK_PS_COEF_DATA_SET(pipe, id, set),
0365 tmp);
0366 }
0367
0368 intel_de_write_fw(dev_priv, GLK_PS_COEF_INDEX_SET(pipe, id, set), 0);
0369 }
0370
0371 static u32 skl_scaler_get_filter_select(enum drm_scaling_filter filter, int set)
0372 {
0373 if (filter == DRM_SCALING_FILTER_NEAREST_NEIGHBOR) {
0374 return (PS_FILTER_PROGRAMMED |
0375 PS_Y_VERT_FILTER_SELECT(set) |
0376 PS_Y_HORZ_FILTER_SELECT(set) |
0377 PS_UV_VERT_FILTER_SELECT(set) |
0378 PS_UV_HORZ_FILTER_SELECT(set));
0379 }
0380
0381 return PS_FILTER_MEDIUM;
0382 }
0383
0384 static void skl_scaler_setup_filter(struct drm_i915_private *dev_priv, enum pipe pipe,
0385 int id, int set, enum drm_scaling_filter filter)
0386 {
0387 switch (filter) {
0388 case DRM_SCALING_FILTER_DEFAULT:
0389 break;
0390 case DRM_SCALING_FILTER_NEAREST_NEIGHBOR:
0391 glk_program_nearest_filter_coefs(dev_priv, pipe, id, set);
0392 break;
0393 default:
0394 MISSING_CASE(filter);
0395 }
0396 }
0397
0398 void skl_pfit_enable(const struct intel_crtc_state *crtc_state)
0399 {
0400 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
0401 struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
0402 const struct intel_crtc_scaler_state *scaler_state =
0403 &crtc_state->scaler_state;
0404 const struct drm_rect *dst = &crtc_state->pch_pfit.dst;
0405 u16 uv_rgb_hphase, uv_rgb_vphase;
0406 enum pipe pipe = crtc->pipe;
0407 int width = drm_rect_width(dst);
0408 int height = drm_rect_height(dst);
0409 int x = dst->x1;
0410 int y = dst->y1;
0411 int hscale, vscale;
0412 struct drm_rect src;
0413 int id;
0414 u32 ps_ctrl;
0415
0416 if (!crtc_state->pch_pfit.enabled)
0417 return;
0418
0419 if (drm_WARN_ON(&dev_priv->drm,
0420 crtc_state->scaler_state.scaler_id < 0))
0421 return;
0422
0423 drm_rect_init(&src, 0, 0,
0424 drm_rect_width(&crtc_state->pipe_src) << 16,
0425 drm_rect_height(&crtc_state->pipe_src) << 16);
0426
0427 hscale = drm_rect_calc_hscale(&src, dst, 0, INT_MAX);
0428 vscale = drm_rect_calc_vscale(&src, dst, 0, INT_MAX);
0429
0430 uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false);
0431 uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false);
0432
0433 id = scaler_state->scaler_id;
0434
0435 ps_ctrl = skl_scaler_get_filter_select(crtc_state->hw.scaling_filter, 0);
0436 ps_ctrl |= PS_SCALER_EN | scaler_state->scalers[id].mode;
0437
0438 skl_scaler_setup_filter(dev_priv, pipe, id, 0,
0439 crtc_state->hw.scaling_filter);
0440
0441 intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, id), ps_ctrl);
0442
0443 intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, id),
0444 PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_vphase));
0445 intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, id),
0446 PS_Y_PHASE(0) | PS_UV_RGB_PHASE(uv_rgb_hphase));
0447 intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(pipe, id),
0448 x << 16 | y);
0449 intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, id),
0450 width << 16 | height);
0451 }
0452
0453 void
0454 skl_program_plane_scaler(struct intel_plane *plane,
0455 const struct intel_crtc_state *crtc_state,
0456 const struct intel_plane_state *plane_state)
0457 {
0458 struct drm_i915_private *dev_priv = to_i915(plane->base.dev);
0459 const struct drm_framebuffer *fb = plane_state->hw.fb;
0460 enum pipe pipe = plane->pipe;
0461 int scaler_id = plane_state->scaler_id;
0462 const struct intel_scaler *scaler =
0463 &crtc_state->scaler_state.scalers[scaler_id];
0464 int crtc_x = plane_state->uapi.dst.x1;
0465 int crtc_y = plane_state->uapi.dst.y1;
0466 u32 crtc_w = drm_rect_width(&plane_state->uapi.dst);
0467 u32 crtc_h = drm_rect_height(&plane_state->uapi.dst);
0468 u16 y_hphase, uv_rgb_hphase;
0469 u16 y_vphase, uv_rgb_vphase;
0470 int hscale, vscale;
0471 u32 ps_ctrl;
0472
0473 hscale = drm_rect_calc_hscale(&plane_state->uapi.src,
0474 &plane_state->uapi.dst,
0475 0, INT_MAX);
0476 vscale = drm_rect_calc_vscale(&plane_state->uapi.src,
0477 &plane_state->uapi.dst,
0478 0, INT_MAX);
0479
0480
0481 if (intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier) &&
0482 !icl_is_hdr_plane(dev_priv, plane->id)) {
0483 y_hphase = skl_scaler_calc_phase(1, hscale, false);
0484 y_vphase = skl_scaler_calc_phase(1, vscale, false);
0485
0486
0487 uv_rgb_hphase = skl_scaler_calc_phase(2, hscale, true);
0488 uv_rgb_vphase = skl_scaler_calc_phase(2, vscale, false);
0489 } else {
0490
0491 y_hphase = 0;
0492 y_vphase = 0;
0493
0494 uv_rgb_hphase = skl_scaler_calc_phase(1, hscale, false);
0495 uv_rgb_vphase = skl_scaler_calc_phase(1, vscale, false);
0496 }
0497
0498 ps_ctrl = skl_scaler_get_filter_select(plane_state->hw.scaling_filter, 0);
0499 ps_ctrl |= PS_SCALER_EN | PS_PLANE_SEL(plane->id) | scaler->mode;
0500
0501 skl_scaler_setup_filter(dev_priv, pipe, scaler_id, 0,
0502 plane_state->hw.scaling_filter);
0503
0504 intel_de_write_fw(dev_priv, SKL_PS_CTRL(pipe, scaler_id), ps_ctrl);
0505 intel_de_write_fw(dev_priv, SKL_PS_VPHASE(pipe, scaler_id),
0506 PS_Y_PHASE(y_vphase) | PS_UV_RGB_PHASE(uv_rgb_vphase));
0507 intel_de_write_fw(dev_priv, SKL_PS_HPHASE(pipe, scaler_id),
0508 PS_Y_PHASE(y_hphase) | PS_UV_RGB_PHASE(uv_rgb_hphase));
0509 intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(pipe, scaler_id),
0510 (crtc_x << 16) | crtc_y);
0511 intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(pipe, scaler_id),
0512 (crtc_w << 16) | crtc_h);
0513 }
0514
0515 static void skl_detach_scaler(struct intel_crtc *crtc, int id)
0516 {
0517 struct drm_device *dev = crtc->base.dev;
0518 struct drm_i915_private *dev_priv = to_i915(dev);
0519
0520 intel_de_write_fw(dev_priv, SKL_PS_CTRL(crtc->pipe, id), 0);
0521 intel_de_write_fw(dev_priv, SKL_PS_WIN_POS(crtc->pipe, id), 0);
0522 intel_de_write_fw(dev_priv, SKL_PS_WIN_SZ(crtc->pipe, id), 0);
0523 }
0524
0525
0526
0527
0528 void skl_detach_scalers(const struct intel_crtc_state *crtc_state)
0529 {
0530 struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
0531 const struct intel_crtc_scaler_state *scaler_state =
0532 &crtc_state->scaler_state;
0533 int i;
0534
0535
0536 for (i = 0; i < crtc->num_scalers; i++) {
0537 if (!scaler_state->scalers[i].in_use)
0538 skl_detach_scaler(crtc, i);
0539 }
0540 }
0541
0542 void skl_scaler_disable(const struct intel_crtc_state *old_crtc_state)
0543 {
0544 struct intel_crtc *crtc = to_intel_crtc(old_crtc_state->uapi.crtc);
0545 int i;
0546
0547 for (i = 0; i < crtc->num_scalers; i++)
0548 skl_detach_scaler(crtc, i);
0549 }