| 1 | // SPDX-License-Identifier: MIT |
| 2 | /* |
| 3 | * Copyright © 2025 Intel Corporation |
| 4 | */ |
| 5 | |
| 6 | #include <linux/debugfs.h> |
| 7 | |
| 8 | #include <drm/drm_print.h> |
| 9 | |
| 10 | #include "intel_cdclk.h" |
| 11 | #include "intel_display_core.h" |
| 12 | #include "intel_display_types.h" |
| 13 | #include "intel_vblank.h" |
| 14 | #include "intel_vdsc.h" |
| 15 | #include "skl_prefill.h" |
| 16 | #include "skl_scaler.h" |
| 17 | #include "skl_watermark.h" |
| 18 | |
| 19 | static unsigned int prefill_usecs_to_lines(const struct intel_crtc_state *crtc_state, |
| 20 | unsigned int usecs) |
| 21 | { |
| 22 | const struct drm_display_mode *pipe_mode = &crtc_state->hw.pipe_mode; |
| 23 | |
| 24 | return DIV_ROUND_UP_ULL(mul_u32_u32(pipe_mode->crtc_clock, usecs << 16), |
| 25 | pipe_mode->crtc_htotal * 1000); |
| 26 | } |
| 27 | |
| 28 | static void prefill_init(struct skl_prefill_ctx *ctx, |
| 29 | const struct intel_crtc_state *crtc_state) |
| 30 | { |
| 31 | memset(ctx, 0, sizeof(*ctx)); |
| 32 | |
| 33 | ctx->prefill.fixed = crtc_state->framestart_delay << 16; |
| 34 | |
| 35 | /* 20 usec for translation walks/etc. */ |
| 36 | ctx->prefill.fixed += prefill_usecs_to_lines(crtc_state, usecs: 20); |
| 37 | |
| 38 | ctx->prefill.dsc = intel_vdsc_prefill_lines(crtc_state); |
| 39 | } |
| 40 | |
| 41 | static void prefill_init_nocdclk_worst(struct skl_prefill_ctx *ctx, |
| 42 | const struct intel_crtc_state *crtc_state) |
| 43 | { |
| 44 | prefill_init(ctx, crtc_state); |
| 45 | |
| 46 | ctx->prefill.wm0 = skl_wm0_prefill_lines_worst(crtc_state); |
| 47 | ctx->prefill.scaler_1st = skl_scaler_1st_prefill_lines_worst(crtc_state); |
| 48 | ctx->prefill.scaler_2nd = skl_scaler_2nd_prefill_lines_worst(crtc_state); |
| 49 | |
| 50 | ctx->adj.scaler_1st = skl_scaler_1st_prefill_adjustment_worst(crtc_state); |
| 51 | ctx->adj.scaler_2nd = skl_scaler_2nd_prefill_adjustment_worst(crtc_state); |
| 52 | } |
| 53 | |
| 54 | static void prefill_init_nocdclk(struct skl_prefill_ctx *ctx, |
| 55 | const struct intel_crtc_state *crtc_state) |
| 56 | { |
| 57 | prefill_init(ctx, crtc_state); |
| 58 | |
| 59 | ctx->prefill.wm0 = skl_wm0_prefill_lines(crtc_state); |
| 60 | ctx->prefill.scaler_1st = skl_scaler_1st_prefill_lines(crtc_state); |
| 61 | ctx->prefill.scaler_2nd = skl_scaler_2nd_prefill_lines(crtc_state); |
| 62 | |
| 63 | ctx->adj.scaler_1st = skl_scaler_1st_prefill_adjustment(crtc_state); |
| 64 | ctx->adj.scaler_2nd = skl_scaler_2nd_prefill_adjustment(crtc_state); |
| 65 | } |
| 66 | |
| 67 | static unsigned int prefill_adjust(unsigned int value, unsigned int factor) |
| 68 | { |
| 69 | return DIV_ROUND_UP_ULL(mul_u32_u32(value, factor), 0x10000); |
| 70 | } |
| 71 | |
| 72 | static unsigned int prefill_lines_nocdclk(const struct skl_prefill_ctx *ctx) |
| 73 | { |
| 74 | unsigned int prefill = 0; |
| 75 | |
| 76 | prefill += ctx->prefill.dsc; |
| 77 | prefill = prefill_adjust(value: prefill, factor: ctx->adj.scaler_2nd); |
| 78 | |
| 79 | prefill += ctx->prefill.scaler_2nd; |
| 80 | prefill = prefill_adjust(value: prefill, factor: ctx->adj.scaler_1st); |
| 81 | |
| 82 | prefill += ctx->prefill.scaler_1st; |
| 83 | prefill += ctx->prefill.wm0; |
| 84 | |
| 85 | return prefill; |
| 86 | } |
| 87 | |
| 88 | static unsigned int prefill_lines_cdclk(const struct skl_prefill_ctx *ctx) |
| 89 | { |
| 90 | return prefill_adjust(value: prefill_lines_nocdclk(ctx), factor: ctx->adj.cdclk); |
| 91 | } |
| 92 | |
| 93 | static unsigned int prefill_lines_full(const struct skl_prefill_ctx *ctx) |
| 94 | { |
| 95 | return ctx->prefill.fixed + prefill_lines_cdclk(ctx); |
| 96 | } |
| 97 | |
| 98 | void skl_prefill_init_worst(struct skl_prefill_ctx *ctx, |
| 99 | const struct intel_crtc_state *crtc_state) |
| 100 | { |
| 101 | prefill_init_nocdclk_worst(ctx, crtc_state); |
| 102 | |
| 103 | ctx->adj.cdclk = intel_cdclk_prefill_adjustment_worst(crtc_state); |
| 104 | |
| 105 | ctx->prefill.full = prefill_lines_full(ctx); |
| 106 | } |
| 107 | |
| 108 | void skl_prefill_init(struct skl_prefill_ctx *ctx, |
| 109 | const struct intel_crtc_state *crtc_state) |
| 110 | { |
| 111 | prefill_init_nocdclk(ctx, crtc_state); |
| 112 | |
| 113 | ctx->adj.cdclk = intel_cdclk_prefill_adjustment(crtc_state); |
| 114 | |
| 115 | ctx->prefill.full = prefill_lines_full(ctx); |
| 116 | } |
| 117 | |
| 118 | static unsigned int prefill_lines_with_latency(const struct skl_prefill_ctx *ctx, |
| 119 | const struct intel_crtc_state *crtc_state, |
| 120 | unsigned int latency_us) |
| 121 | { |
| 122 | return ctx->prefill.full + prefill_usecs_to_lines(crtc_state, usecs: latency_us); |
| 123 | } |
| 124 | |
| 125 | int skl_prefill_min_guardband(const struct skl_prefill_ctx *ctx, |
| 126 | const struct intel_crtc_state *crtc_state, |
| 127 | unsigned int latency_us) |
| 128 | { |
| 129 | unsigned int prefill = prefill_lines_with_latency(ctx, crtc_state, latency_us); |
| 130 | |
| 131 | return DIV_ROUND_UP(prefill, 0x10000); |
| 132 | } |
| 133 | |
| 134 | static unsigned int prefill_guardband(const struct intel_crtc_state *crtc_state) |
| 135 | { |
| 136 | return intel_crtc_vblank_length(crtc_state) << 16; |
| 137 | } |
| 138 | |
| 139 | bool skl_prefill_vblank_too_short(const struct skl_prefill_ctx *ctx, |
| 140 | const struct intel_crtc_state *crtc_state, |
| 141 | unsigned int latency_us) |
| 142 | { |
| 143 | unsigned int guardband = prefill_guardband(crtc_state); |
| 144 | unsigned int prefill = prefill_lines_with_latency(ctx, crtc_state, latency_us); |
| 145 | |
| 146 | return guardband < prefill; |
| 147 | } |
| 148 | |
| 149 | int skl_prefill_min_cdclk(const struct skl_prefill_ctx *ctx, |
| 150 | const struct intel_crtc_state *crtc_state) |
| 151 | { |
| 152 | unsigned int prefill_unadjusted = prefill_lines_nocdclk(ctx); |
| 153 | unsigned int prefill_available = prefill_guardband(crtc_state) - ctx->prefill.fixed; |
| 154 | |
| 155 | return intel_cdclk_min_cdclk_for_prefill(crtc_state, prefill_lines_unadjusted: prefill_unadjusted, |
| 156 | prefill_lines_available: prefill_available); |
| 157 | } |
| 158 | |