| 1 | // SPDX-License-Identifier: MIT | 
|---|
| 2 | /* | 
|---|
| 3 | * Copyright © 2020 Intel Corporation | 
|---|
| 4 | */ | 
|---|
| 5 |  | 
|---|
| 6 | #include <linux/debugfs.h> | 
|---|
| 7 | #include <linux/string_choices.h> | 
|---|
| 8 | #include <linux/string_helpers.h> | 
|---|
| 9 |  | 
|---|
| 10 | #include <drm/drm_debugfs.h> | 
|---|
| 11 | #include <drm/drm_drv.h> | 
|---|
| 12 | #include <drm/drm_edid.h> | 
|---|
| 13 | #include <drm/drm_file.h> | 
|---|
| 14 | #include <drm/drm_fourcc.h> | 
|---|
| 15 |  | 
|---|
| 16 | #include "hsw_ips.h" | 
|---|
| 17 | #include "i915_reg.h" | 
|---|
| 18 | #include "i9xx_wm_regs.h" | 
|---|
| 19 | #include "intel_alpm.h" | 
|---|
| 20 | #include "intel_bo.h" | 
|---|
| 21 | #include "intel_crtc.h" | 
|---|
| 22 | #include "intel_crtc_state_dump.h" | 
|---|
| 23 | #include "intel_de.h" | 
|---|
| 24 | #include "intel_display_debugfs.h" | 
|---|
| 25 | #include "intel_display_debugfs_params.h" | 
|---|
| 26 | #include "intel_display_power.h" | 
|---|
| 27 | #include "intel_display_power_well.h" | 
|---|
| 28 | #include "intel_display_regs.h" | 
|---|
| 29 | #include "intel_display_rpm.h" | 
|---|
| 30 | #include "intel_display_types.h" | 
|---|
| 31 | #include "intel_dmc.h" | 
|---|
| 32 | #include "intel_dp.h" | 
|---|
| 33 | #include "intel_dp_link_training.h" | 
|---|
| 34 | #include "intel_dp_mst.h" | 
|---|
| 35 | #include "intel_dp_test.h" | 
|---|
| 36 | #include "intel_drrs.h" | 
|---|
| 37 | #include "intel_fb.h" | 
|---|
| 38 | #include "intel_fbc.h" | 
|---|
| 39 | #include "intel_fbdev.h" | 
|---|
| 40 | #include "intel_hdcp.h" | 
|---|
| 41 | #include "intel_hdmi.h" | 
|---|
| 42 | #include "intel_hotplug.h" | 
|---|
| 43 | #include "intel_link_bw.h" | 
|---|
| 44 | #include "intel_panel.h" | 
|---|
| 45 | #include "intel_pps.h" | 
|---|
| 46 | #include "intel_psr.h" | 
|---|
| 47 | #include "intel_psr_regs.h" | 
|---|
| 48 | #include "intel_vdsc.h" | 
|---|
| 49 | #include "intel_wm.h" | 
|---|
| 50 |  | 
|---|
| 51 | static struct intel_display *node_to_intel_display(struct drm_info_node *node) | 
|---|
| 52 | { | 
|---|
| 53 | return to_intel_display(node->minor->dev); | 
|---|
| 54 | } | 
|---|
| 55 |  | 
|---|
| 56 | static int intel_display_caps(struct seq_file *m, void *data) | 
|---|
| 57 | { | 
|---|
| 58 | struct intel_display *display = node_to_intel_display(node: m->private); | 
|---|
| 59 | struct drm_printer p = drm_seq_file_printer(f: m); | 
|---|
| 60 |  | 
|---|
| 61 | drm_printf(p: &p, f: "PCH type: %d\n", INTEL_PCH_TYPE(display)); | 
|---|
| 62 |  | 
|---|
| 63 | intel_display_device_info_print(DISPLAY_INFO(display), | 
|---|
| 64 | DISPLAY_RUNTIME_INFO(display), p: &p); | 
|---|
| 65 | intel_display_params_dump(params: &display->params, driver_name: display->drm->driver->name, p: &p); | 
|---|
| 66 |  | 
|---|
| 67 | return 0; | 
|---|
| 68 | } | 
|---|
| 69 |  | 
|---|
| 70 | static int i915_frontbuffer_tracking(struct seq_file *m, void *unused) | 
|---|
| 71 | { | 
|---|
| 72 | struct intel_display *display = node_to_intel_display(node: m->private); | 
|---|
| 73 |  | 
|---|
| 74 | spin_lock(lock: &display->fb_tracking.lock); | 
|---|
| 75 |  | 
|---|
| 76 | seq_printf(m, fmt: "FB tracking busy bits: 0x%08x\n", | 
|---|
| 77 | display->fb_tracking.busy_bits); | 
|---|
| 78 |  | 
|---|
| 79 | seq_printf(m, fmt: "FB tracking flip bits: 0x%08x\n", | 
|---|
| 80 | display->fb_tracking.flip_bits); | 
|---|
| 81 |  | 
|---|
| 82 | spin_unlock(lock: &display->fb_tracking.lock); | 
|---|
| 83 |  | 
|---|
| 84 | return 0; | 
|---|
| 85 | } | 
|---|
| 86 |  | 
|---|
| 87 | static int i915_sr_status(struct seq_file *m, void *unused) | 
|---|
| 88 | { | 
|---|
| 89 | struct intel_display *display = node_to_intel_display(node: m->private); | 
|---|
| 90 | intel_wakeref_t wakeref; | 
|---|
| 91 | bool sr_enabled = false; | 
|---|
| 92 |  | 
|---|
| 93 | wakeref = intel_display_power_get(display, domain: POWER_DOMAIN_INIT); | 
|---|
| 94 |  | 
|---|
| 95 | if (DISPLAY_VER(display) >= 9) | 
|---|
| 96 | /* no global SR status; inspect per-plane WM */; | 
|---|
| 97 | else if (HAS_PCH_SPLIT(display)) | 
|---|
| 98 | sr_enabled = intel_de_read(display, WM1_LP_ILK) & WM_LP_ENABLE; | 
|---|
| 99 | else if (display->platform.i965gm || display->platform.g4x || | 
|---|
| 100 | display->platform.i945g || display->platform.i945gm) | 
|---|
| 101 | sr_enabled = intel_de_read(display, FW_BLC_SELF) & FW_BLC_SELF_EN; | 
|---|
| 102 | else if (display->platform.i915gm) | 
|---|
| 103 | sr_enabled = intel_de_read(display, INSTPM) & INSTPM_SELF_EN; | 
|---|
| 104 | else if (display->platform.pineview) | 
|---|
| 105 | sr_enabled = intel_de_read(display, DSPFW3(display)) & PINEVIEW_SELF_REFRESH_EN; | 
|---|
| 106 | else if (display->platform.valleyview || display->platform.cherryview) | 
|---|
| 107 | sr_enabled = intel_de_read(display, FW_BLC_SELF_VLV) & FW_CSPWRDWNEN; | 
|---|
| 108 |  | 
|---|
| 109 | intel_display_power_put(display, domain: POWER_DOMAIN_INIT, wakeref); | 
|---|
| 110 |  | 
|---|
| 111 | seq_printf(m, fmt: "self-refresh: %s\n", str_enabled_disabled(v: sr_enabled)); | 
|---|
| 112 |  | 
|---|
| 113 | return 0; | 
|---|
| 114 | } | 
|---|
| 115 |  | 
|---|
| 116 | static int i915_gem_framebuffer_info(struct seq_file *m, void *data) | 
|---|
| 117 | { | 
|---|
| 118 | struct intel_display *display = node_to_intel_display(node: m->private); | 
|---|
| 119 | struct intel_framebuffer *fbdev_fb = NULL; | 
|---|
| 120 | struct drm_framebuffer *drm_fb; | 
|---|
| 121 |  | 
|---|
| 122 | fbdev_fb = intel_fbdev_framebuffer(fbdev: display->fbdev.fbdev); | 
|---|
| 123 | if (fbdev_fb) { | 
|---|
| 124 | seq_printf(m, fmt: "fbcon size: %d x %d, depth %d, %d bpp, modifier 0x%llx, refcount %d, obj ", | 
|---|
| 125 | fbdev_fb->base.width, | 
|---|
| 126 | fbdev_fb->base.height, | 
|---|
| 127 | fbdev_fb->base.format->depth, | 
|---|
| 128 | fbdev_fb->base.format->cpp[0] * 8, | 
|---|
| 129 | fbdev_fb->base.modifier, | 
|---|
| 130 | drm_framebuffer_read_refcount(fb: &fbdev_fb->base)); | 
|---|
| 131 | intel_bo_describe(m, obj: intel_fb_bo(fb: &fbdev_fb->base)); | 
|---|
| 132 | seq_putc(m, c: '\n'); | 
|---|
| 133 | } | 
|---|
| 134 |  | 
|---|
| 135 | mutex_lock(lock: &display->drm->mode_config.fb_lock); | 
|---|
| 136 | drm_for_each_fb(drm_fb, display->drm) { | 
|---|
| 137 | struct intel_framebuffer *fb = to_intel_framebuffer(drm_fb); | 
|---|
| 138 | if (fb == fbdev_fb) | 
|---|
| 139 | continue; | 
|---|
| 140 |  | 
|---|
| 141 | seq_printf(m, fmt: "user size: %d x %d, depth %d, %d bpp, modifier 0x%llx, refcount %d, obj ", | 
|---|
| 142 | fb->base.width, | 
|---|
| 143 | fb->base.height, | 
|---|
| 144 | fb->base.format->depth, | 
|---|
| 145 | fb->base.format->cpp[0] * 8, | 
|---|
| 146 | fb->base.modifier, | 
|---|
| 147 | drm_framebuffer_read_refcount(fb: &fb->base)); | 
|---|
| 148 | intel_bo_describe(m, obj: intel_fb_bo(fb: &fb->base)); | 
|---|
| 149 | seq_putc(m, c: '\n'); | 
|---|
| 150 | } | 
|---|
| 151 | mutex_unlock(lock: &display->drm->mode_config.fb_lock); | 
|---|
| 152 |  | 
|---|
| 153 | return 0; | 
|---|
| 154 | } | 
|---|
| 155 |  | 
|---|
| 156 | static int i915_power_domain_info(struct seq_file *m, void *unused) | 
|---|
| 157 | { | 
|---|
| 158 | struct intel_display *display = node_to_intel_display(node: m->private); | 
|---|
| 159 |  | 
|---|
| 160 | intel_display_power_debug(display, m); | 
|---|
| 161 |  | 
|---|
| 162 | return 0; | 
|---|
| 163 | } | 
|---|
| 164 |  | 
|---|
| 165 | static void intel_seq_print_mode(struct seq_file *m, int tabs, | 
|---|
| 166 | const struct drm_display_mode *mode) | 
|---|
| 167 | { | 
|---|
| 168 | int i; | 
|---|
| 169 |  | 
|---|
| 170 | for (i = 0; i < tabs; i++) | 
|---|
| 171 | seq_putc(m, c: '\t'); | 
|---|
| 172 |  | 
|---|
| 173 | seq_printf(m, DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); | 
|---|
| 174 | } | 
|---|
| 175 |  | 
|---|
| 176 | static void intel_encoder_info(struct seq_file *m, | 
|---|
| 177 | struct intel_crtc *crtc, | 
|---|
| 178 | struct intel_encoder *encoder) | 
|---|
| 179 | { | 
|---|
| 180 | struct intel_display *display = node_to_intel_display(node: m->private); | 
|---|
| 181 | struct drm_connector_list_iter conn_iter; | 
|---|
| 182 | struct drm_connector *connector; | 
|---|
| 183 |  | 
|---|
| 184 | seq_printf(m, fmt: "\t[ENCODER:%d:%s]: connectors:\n", | 
|---|
| 185 | encoder->base.base.id, encoder->base.name); | 
|---|
| 186 |  | 
|---|
| 187 | drm_connector_list_iter_begin(dev: display->drm, iter: &conn_iter); | 
|---|
| 188 | drm_for_each_connector_iter(connector, &conn_iter) { | 
|---|
| 189 | const struct drm_connector_state *conn_state = | 
|---|
| 190 | connector->state; | 
|---|
| 191 |  | 
|---|
| 192 | if (conn_state->best_encoder != &encoder->base) | 
|---|
| 193 | continue; | 
|---|
| 194 |  | 
|---|
| 195 | seq_printf(m, fmt: "\t\t[CONNECTOR:%d:%s]\n", | 
|---|
| 196 | connector->base.id, connector->name); | 
|---|
| 197 | } | 
|---|
| 198 | drm_connector_list_iter_end(iter: &conn_iter); | 
|---|
| 199 | } | 
|---|
| 200 |  | 
|---|
| 201 | static void intel_panel_info(struct seq_file *m, | 
|---|
| 202 | struct intel_connector *connector) | 
|---|
| 203 | { | 
|---|
| 204 | const struct drm_display_mode *fixed_mode; | 
|---|
| 205 |  | 
|---|
| 206 | if (list_empty(head: &connector->panel.fixed_modes)) | 
|---|
| 207 | return; | 
|---|
| 208 |  | 
|---|
| 209 | seq_puts(m, s: "\tfixed modes:\n"); | 
|---|
| 210 |  | 
|---|
| 211 | list_for_each_entry(fixed_mode, &connector->panel.fixed_modes, head) | 
|---|
| 212 | intel_seq_print_mode(m, tabs: 2, mode: fixed_mode); | 
|---|
| 213 | } | 
|---|
| 214 |  | 
|---|
| 215 | static void intel_dp_info(struct seq_file *m, struct intel_connector *connector) | 
|---|
| 216 | { | 
|---|
| 217 | struct intel_encoder *intel_encoder = intel_attached_encoder(connector); | 
|---|
| 218 | struct intel_dp *intel_dp = enc_to_intel_dp(encoder: intel_encoder); | 
|---|
| 219 |  | 
|---|
| 220 | seq_printf(m, fmt: "\tDPCD rev: %x\n", intel_dp->dpcd[DP_DPCD_REV]); | 
|---|
| 221 | seq_printf(m, fmt: "\taudio support: %s\n", | 
|---|
| 222 | str_yes_no(v: connector->base.display_info.has_audio)); | 
|---|
| 223 |  | 
|---|
| 224 | drm_dp_downstream_debug(m, dpcd: intel_dp->dpcd, port_cap: intel_dp->downstream_ports, | 
|---|
| 225 | drm_edid: connector->detect_edid, aux: &intel_dp->aux); | 
|---|
| 226 | } | 
|---|
| 227 |  | 
|---|
| 228 | static void intel_dp_mst_info(struct seq_file *m, | 
|---|
| 229 | struct intel_connector *connector) | 
|---|
| 230 | { | 
|---|
| 231 | bool has_audio = connector->base.display_info.has_audio; | 
|---|
| 232 |  | 
|---|
| 233 | seq_printf(m, fmt: "\taudio support: %s\n", str_yes_no(v: has_audio)); | 
|---|
| 234 | } | 
|---|
| 235 |  | 
|---|
| 236 | static void intel_hdmi_info(struct seq_file *m, | 
|---|
| 237 | struct intel_connector *connector) | 
|---|
| 238 | { | 
|---|
| 239 | bool has_audio = connector->base.display_info.has_audio; | 
|---|
| 240 |  | 
|---|
| 241 | seq_printf(m, fmt: "\taudio support: %s\n", str_yes_no(v: has_audio)); | 
|---|
| 242 | } | 
|---|
| 243 |  | 
|---|
| 244 | static void intel_connector_info(struct seq_file *m, | 
|---|
| 245 | struct drm_connector *connector) | 
|---|
| 246 | { | 
|---|
| 247 | struct intel_connector *intel_connector = to_intel_connector(connector); | 
|---|
| 248 | const struct drm_display_mode *mode; | 
|---|
| 249 |  | 
|---|
| 250 | seq_printf(m, fmt: "[CONNECTOR:%d:%s]: status: %s\n", | 
|---|
| 251 | connector->base.id, connector->name, | 
|---|
| 252 | drm_get_connector_status_name(status: connector->status)); | 
|---|
| 253 |  | 
|---|
| 254 | if (connector->status == connector_status_disconnected) | 
|---|
| 255 | return; | 
|---|
| 256 |  | 
|---|
| 257 | seq_printf(m, fmt: "\tphysical dimensions: %dx%dmm\n", | 
|---|
| 258 | connector->display_info.width_mm, | 
|---|
| 259 | connector->display_info.height_mm); | 
|---|
| 260 | seq_printf(m, fmt: "\tsubpixel order: %s\n", | 
|---|
| 261 | drm_get_subpixel_order_name(order: connector->display_info.subpixel_order)); | 
|---|
| 262 | seq_printf(m, fmt: "\tCEA rev: %d\n", connector->display_info.cea_rev); | 
|---|
| 263 |  | 
|---|
| 264 | switch (connector->connector_type) { | 
|---|
| 265 | case DRM_MODE_CONNECTOR_DisplayPort: | 
|---|
| 266 | case DRM_MODE_CONNECTOR_eDP: | 
|---|
| 267 | if (intel_connector->mst.dp) | 
|---|
| 268 | intel_dp_mst_info(m, connector: intel_connector); | 
|---|
| 269 | else | 
|---|
| 270 | intel_dp_info(m, connector: intel_connector); | 
|---|
| 271 | break; | 
|---|
| 272 | case DRM_MODE_CONNECTOR_HDMIA: | 
|---|
| 273 | intel_hdmi_info(m, connector: intel_connector); | 
|---|
| 274 | break; | 
|---|
| 275 | default: | 
|---|
| 276 | break; | 
|---|
| 277 | } | 
|---|
| 278 |  | 
|---|
| 279 | intel_hdcp_info(m, connector: intel_connector); | 
|---|
| 280 |  | 
|---|
| 281 | seq_printf(m, fmt: "\tmax bpc: %u\n", connector->display_info.bpc); | 
|---|
| 282 |  | 
|---|
| 283 | intel_panel_info(m, connector: intel_connector); | 
|---|
| 284 |  | 
|---|
| 285 | seq_printf(m, fmt: "\tmodes:\n"); | 
|---|
| 286 | list_for_each_entry(mode, &connector->modes, head) | 
|---|
| 287 | intel_seq_print_mode(m, tabs: 2, mode); | 
|---|
| 288 | } | 
|---|
| 289 |  | 
|---|
| 290 | static const char *plane_type(enum drm_plane_type type) | 
|---|
| 291 | { | 
|---|
| 292 | switch (type) { | 
|---|
| 293 | case DRM_PLANE_TYPE_OVERLAY: | 
|---|
| 294 | return "OVL"; | 
|---|
| 295 | case DRM_PLANE_TYPE_PRIMARY: | 
|---|
| 296 | return "PRI"; | 
|---|
| 297 | case DRM_PLANE_TYPE_CURSOR: | 
|---|
| 298 | return "CUR"; | 
|---|
| 299 | /* | 
|---|
| 300 | * Deliberately omitting default: to generate compiler warnings | 
|---|
| 301 | * when a new drm_plane_type gets added. | 
|---|
| 302 | */ | 
|---|
| 303 | } | 
|---|
| 304 |  | 
|---|
| 305 | return "unknown"; | 
|---|
| 306 | } | 
|---|
| 307 |  | 
|---|
| 308 | static void plane_rotation(char *buf, size_t bufsize, unsigned int rotation) | 
|---|
| 309 | { | 
|---|
| 310 | /* | 
|---|
| 311 | * According to doc only one DRM_MODE_ROTATE_ is allowed but this | 
|---|
| 312 | * will print them all to visualize if the values are misused | 
|---|
| 313 | */ | 
|---|
| 314 | snprintf(buf, size: bufsize, | 
|---|
| 315 | fmt: "%s%s%s%s%s%s(0x%08x)", | 
|---|
| 316 | (rotation & DRM_MODE_ROTATE_0) ? "0 ": "", | 
|---|
| 317 | (rotation & DRM_MODE_ROTATE_90) ? "90 ": "", | 
|---|
| 318 | (rotation & DRM_MODE_ROTATE_180) ? "180 ": "", | 
|---|
| 319 | (rotation & DRM_MODE_ROTATE_270) ? "270 ": "", | 
|---|
| 320 | (rotation & DRM_MODE_REFLECT_X) ? "FLIPX ": "", | 
|---|
| 321 | (rotation & DRM_MODE_REFLECT_Y) ? "FLIPY ": "", | 
|---|
| 322 | rotation); | 
|---|
| 323 | } | 
|---|
| 324 |  | 
|---|
| 325 | static const char *plane_visibility(const struct intel_plane_state *plane_state) | 
|---|
| 326 | { | 
|---|
| 327 | if (plane_state->uapi.visible) | 
|---|
| 328 | return "visible"; | 
|---|
| 329 |  | 
|---|
| 330 | if (plane_state->is_y_plane) | 
|---|
| 331 | return "Y plane"; | 
|---|
| 332 |  | 
|---|
| 333 | return "hidden"; | 
|---|
| 334 | } | 
|---|
| 335 |  | 
|---|
| 336 | static void intel_plane_uapi_info(struct seq_file *m, struct intel_plane *plane) | 
|---|
| 337 | { | 
|---|
| 338 | const struct intel_plane_state *plane_state = | 
|---|
| 339 | to_intel_plane_state(plane->base.state); | 
|---|
| 340 | const struct drm_framebuffer *fb = plane_state->uapi.fb; | 
|---|
| 341 | struct drm_rect src, dst; | 
|---|
| 342 | char rot_str[48]; | 
|---|
| 343 |  | 
|---|
| 344 | src = drm_plane_state_src(state: &plane_state->uapi); | 
|---|
| 345 | dst = drm_plane_state_dest(state: &plane_state->uapi); | 
|---|
| 346 |  | 
|---|
| 347 | plane_rotation(buf: rot_str, bufsize: sizeof(rot_str), | 
|---|
| 348 | rotation: plane_state->uapi.rotation); | 
|---|
| 349 |  | 
|---|
| 350 | seq_puts(m, s: "\t\tuapi: [FB:"); | 
|---|
| 351 | if (fb) | 
|---|
| 352 | seq_printf(m, fmt: "%d] %p4cc,0x%llx,%dx%d", fb->base.id, | 
|---|
| 353 | &fb->format->format, fb->modifier, fb->width, | 
|---|
| 354 | fb->height); | 
|---|
| 355 | else | 
|---|
| 356 | seq_puts(m, s: "0] n/a,0x0,0x0,"); | 
|---|
| 357 | seq_printf(m, fmt: ", visible=%s, src="DRM_RECT_FP_FMT ", dst="DRM_RECT_FMT | 
|---|
| 358 | ", rotation=%s\n", plane_visibility(plane_state), | 
|---|
| 359 | DRM_RECT_FP_ARG(&src), DRM_RECT_ARG(&dst), rot_str); | 
|---|
| 360 |  | 
|---|
| 361 | if (plane_state->planar_linked_plane) | 
|---|
| 362 | seq_printf(m, fmt: "\t\tplanar: Linked to [PLANE:%d:%s] as a %s\n", | 
|---|
| 363 | plane_state->planar_linked_plane->base.base.id, plane_state->planar_linked_plane->base.name, | 
|---|
| 364 | plane_state->is_y_plane ? "Y plane": "UV plane"); | 
|---|
| 365 | } | 
|---|
| 366 |  | 
|---|
| 367 | static void intel_plane_hw_info(struct seq_file *m, struct intel_plane *plane) | 
|---|
| 368 | { | 
|---|
| 369 | const struct intel_plane_state *plane_state = | 
|---|
| 370 | to_intel_plane_state(plane->base.state); | 
|---|
| 371 | const struct drm_framebuffer *fb = plane_state->hw.fb; | 
|---|
| 372 | char rot_str[48]; | 
|---|
| 373 |  | 
|---|
| 374 | if (!fb) | 
|---|
| 375 | return; | 
|---|
| 376 |  | 
|---|
| 377 | plane_rotation(buf: rot_str, bufsize: sizeof(rot_str), | 
|---|
| 378 | rotation: plane_state->hw.rotation); | 
|---|
| 379 |  | 
|---|
| 380 | seq_printf(m, fmt: "\t\thw: [FB:%d] %p4cc,0x%llx,%dx%d, visible=%s, src=" | 
|---|
| 381 | DRM_RECT_FP_FMT ", dst="DRM_RECT_FMT ", rotation=%s\n", | 
|---|
| 382 | fb->base.id, &fb->format->format, | 
|---|
| 383 | fb->modifier, fb->width, fb->height, | 
|---|
| 384 | str_yes_no(v: plane_state->uapi.visible), | 
|---|
| 385 | DRM_RECT_FP_ARG(&plane_state->uapi.src), | 
|---|
| 386 | DRM_RECT_ARG(&plane_state->uapi.dst), | 
|---|
| 387 | rot_str); | 
|---|
| 388 | } | 
|---|
| 389 |  | 
|---|
| 390 | static void intel_plane_info(struct seq_file *m, struct intel_crtc *crtc) | 
|---|
| 391 | { | 
|---|
| 392 | struct intel_display *display = node_to_intel_display(node: m->private); | 
|---|
| 393 | struct intel_plane *plane; | 
|---|
| 394 |  | 
|---|
| 395 | for_each_intel_plane_on_crtc(display->drm, crtc, plane) { | 
|---|
| 396 | seq_printf(m, fmt: "\t[PLANE:%d:%s]: type=%s\n", | 
|---|
| 397 | plane->base.base.id, plane->base.name, | 
|---|
| 398 | plane_type(type: plane->base.type)); | 
|---|
| 399 | intel_plane_uapi_info(m, plane); | 
|---|
| 400 | intel_plane_hw_info(m, plane); | 
|---|
| 401 | } | 
|---|
| 402 | } | 
|---|
| 403 |  | 
|---|
| 404 | static void intel_scaler_info(struct seq_file *m, struct intel_crtc *crtc) | 
|---|
| 405 | { | 
|---|
| 406 | const struct intel_crtc_state *crtc_state = | 
|---|
| 407 | to_intel_crtc_state(crtc->base.state); | 
|---|
| 408 | int num_scalers = crtc->num_scalers; | 
|---|
| 409 | int i; | 
|---|
| 410 |  | 
|---|
| 411 | /* Not all platforms have a scaler */ | 
|---|
| 412 | if (num_scalers) { | 
|---|
| 413 | seq_printf(m, fmt: "\tnum_scalers=%d, scaler_users=%x scaler_id=%d scaling_filter=%d", | 
|---|
| 414 | num_scalers, | 
|---|
| 415 | crtc_state->scaler_state.scaler_users, | 
|---|
| 416 | crtc_state->scaler_state.scaler_id, | 
|---|
| 417 | crtc_state->hw.scaling_filter); | 
|---|
| 418 |  | 
|---|
| 419 | for (i = 0; i < num_scalers; i++) { | 
|---|
| 420 | const struct intel_scaler *sc = | 
|---|
| 421 | &crtc_state->scaler_state.scalers[i]; | 
|---|
| 422 |  | 
|---|
| 423 | seq_printf(m, fmt: ", scalers[%d]: use=%s, mode=%x", | 
|---|
| 424 | i, str_yes_no(v: sc->in_use), sc->mode); | 
|---|
| 425 | } | 
|---|
| 426 | seq_puts(m, s: "\n"); | 
|---|
| 427 | } else { | 
|---|
| 428 | seq_puts(m, s: "\tNo scalers available on this platform\n"); | 
|---|
| 429 | } | 
|---|
| 430 | } | 
|---|
| 431 |  | 
|---|
| 432 | #if IS_ENABLED(CONFIG_DRM_I915_DEBUG_VBLANK_EVADE) | 
|---|
| 433 | static void crtc_updates_info(struct seq_file *m, | 
|---|
| 434 | struct intel_crtc *crtc, | 
|---|
| 435 | const char *hdr) | 
|---|
| 436 | { | 
|---|
| 437 | u64 count; | 
|---|
| 438 | int row; | 
|---|
| 439 |  | 
|---|
| 440 | count = 0; | 
|---|
| 441 | for (row = 0; row < ARRAY_SIZE(crtc->debug.vbl.times); row++) | 
|---|
| 442 | count += crtc->debug.vbl.times[row]; | 
|---|
| 443 | seq_printf(m, "%sUpdates: %llu\n", hdr, count); | 
|---|
| 444 | if (!count) | 
|---|
| 445 | return; | 
|---|
| 446 |  | 
|---|
| 447 | for (row = 0; row < ARRAY_SIZE(crtc->debug.vbl.times); row++) { | 
|---|
| 448 | char columns[80] = "       |"; | 
|---|
| 449 | unsigned int x; | 
|---|
| 450 |  | 
|---|
| 451 | if (row & 1) { | 
|---|
| 452 | const char *units; | 
|---|
| 453 |  | 
|---|
| 454 | if (row > 10) { | 
|---|
| 455 | x = 1000000; | 
|---|
| 456 | units = "ms"; | 
|---|
| 457 | } else { | 
|---|
| 458 | x = 1000; | 
|---|
| 459 | units = "us"; | 
|---|
| 460 | } | 
|---|
| 461 |  | 
|---|
| 462 | snprintf(columns, sizeof(columns), "%4ld%s |", | 
|---|
| 463 | DIV_ROUND_CLOSEST(BIT(row + 9), x), units); | 
|---|
| 464 | } | 
|---|
| 465 |  | 
|---|
| 466 | if (crtc->debug.vbl.times[row]) { | 
|---|
| 467 | x = ilog2(crtc->debug.vbl.times[row]); | 
|---|
| 468 | memset(columns + 8, '*', x); | 
|---|
| 469 | columns[8 + x] = '\0'; | 
|---|
| 470 | } | 
|---|
| 471 |  | 
|---|
| 472 | seq_printf(m, "%s%s\n", hdr, columns); | 
|---|
| 473 | } | 
|---|
| 474 |  | 
|---|
| 475 | seq_printf(m, "%sMin update: %lluns\n", | 
|---|
| 476 | hdr, crtc->debug.vbl.min); | 
|---|
| 477 | seq_printf(m, "%sMax update: %lluns\n", | 
|---|
| 478 | hdr, crtc->debug.vbl.max); | 
|---|
| 479 | seq_printf(m, "%sAverage update: %lluns\n", | 
|---|
| 480 | hdr, div64_u64(crtc->debug.vbl.sum, count)); | 
|---|
| 481 | seq_printf(m, "%sOverruns > %uus: %u\n", | 
|---|
| 482 | hdr, VBLANK_EVASION_TIME_US, crtc->debug.vbl.over); | 
|---|
| 483 | } | 
|---|
| 484 |  | 
|---|
| 485 | static int crtc_updates_show(struct seq_file *m, void *data) | 
|---|
| 486 | { | 
|---|
| 487 | crtc_updates_info(m, m->private, ""); | 
|---|
| 488 | return 0; | 
|---|
| 489 | } | 
|---|
| 490 |  | 
|---|
| 491 | static int crtc_updates_open(struct inode *inode, struct file *file) | 
|---|
| 492 | { | 
|---|
| 493 | return single_open(file, crtc_updates_show, inode->i_private); | 
|---|
| 494 | } | 
|---|
| 495 |  | 
|---|
| 496 | static ssize_t crtc_updates_write(struct file *file, | 
|---|
| 497 | const char __user *ubuf, | 
|---|
| 498 | size_t len, loff_t *offp) | 
|---|
| 499 | { | 
|---|
| 500 | struct seq_file *m = file->private_data; | 
|---|
| 501 | struct intel_crtc *crtc = m->private; | 
|---|
| 502 |  | 
|---|
| 503 | /* May race with an update. Meh. */ | 
|---|
| 504 | memset(&crtc->debug.vbl, 0, sizeof(crtc->debug.vbl)); | 
|---|
| 505 |  | 
|---|
| 506 | return len; | 
|---|
| 507 | } | 
|---|
| 508 |  | 
|---|
| 509 | static const struct file_operations crtc_updates_fops = { | 
|---|
| 510 | .owner = THIS_MODULE, | 
|---|
| 511 | .open = crtc_updates_open, | 
|---|
| 512 | .read = seq_read, | 
|---|
| 513 | .llseek = seq_lseek, | 
|---|
| 514 | .release = single_release, | 
|---|
| 515 | .write = crtc_updates_write | 
|---|
| 516 | }; | 
|---|
| 517 |  | 
|---|
| 518 | static void crtc_updates_add(struct intel_crtc *crtc) | 
|---|
| 519 | { | 
|---|
| 520 | debugfs_create_file( "i915_update_info", 0644, crtc->base.debugfs_entry, | 
|---|
| 521 | crtc, &crtc_updates_fops); | 
|---|
| 522 | } | 
|---|
| 523 |  | 
|---|
| 524 | #else | 
|---|
| 525 | static void crtc_updates_info(struct seq_file *m, | 
|---|
| 526 | struct intel_crtc *crtc, | 
|---|
| 527 | const char *hdr) | 
|---|
| 528 | { | 
|---|
| 529 | } | 
|---|
| 530 |  | 
|---|
| 531 | static void crtc_updates_add(struct intel_crtc *crtc) | 
|---|
| 532 | { | 
|---|
| 533 | } | 
|---|
| 534 | #endif | 
|---|
| 535 |  | 
|---|
| 536 | static void intel_crtc_info(struct seq_file *m, struct intel_crtc *crtc) | 
|---|
| 537 | { | 
|---|
| 538 | struct intel_display *display = node_to_intel_display(node: m->private); | 
|---|
| 539 | struct drm_printer p = drm_seq_file_printer(f: m); | 
|---|
| 540 | const struct intel_crtc_state *crtc_state = | 
|---|
| 541 | to_intel_crtc_state(crtc->base.state); | 
|---|
| 542 | struct intel_encoder *encoder; | 
|---|
| 543 |  | 
|---|
| 544 | seq_printf(m, fmt: "[CRTC:%d:%s]:\n", | 
|---|
| 545 | crtc->base.base.id, crtc->base.name); | 
|---|
| 546 |  | 
|---|
| 547 | seq_printf(m, fmt: "\tuapi: enable=%s, active=%s, mode="DRM_MODE_FMT "\n", | 
|---|
| 548 | str_yes_no(v: crtc_state->uapi.enable), | 
|---|
| 549 | str_yes_no(v: crtc_state->uapi.active), | 
|---|
| 550 | DRM_MODE_ARG(&crtc_state->uapi.mode)); | 
|---|
| 551 |  | 
|---|
| 552 | seq_printf(m, fmt: "\thw: enable=%s, active=%s\n", | 
|---|
| 553 | str_yes_no(v: crtc_state->hw.enable), str_yes_no(v: crtc_state->hw.active)); | 
|---|
| 554 | seq_printf(m, fmt: "\tadjusted_mode="DRM_MODE_FMT "\n", | 
|---|
| 555 | DRM_MODE_ARG(&crtc_state->hw.adjusted_mode)); | 
|---|
| 556 | seq_printf(m, fmt: "\tpipe__mode="DRM_MODE_FMT "\n", | 
|---|
| 557 | DRM_MODE_ARG(&crtc_state->hw.pipe_mode)); | 
|---|
| 558 |  | 
|---|
| 559 | seq_printf(m, fmt: "\tpipe src="DRM_RECT_FMT ", dither=%s, bpp=%d\n", | 
|---|
| 560 | DRM_RECT_ARG(&crtc_state->pipe_src), | 
|---|
| 561 | str_yes_no(v: crtc_state->dither), crtc_state->pipe_bpp); | 
|---|
| 562 | seq_printf(m, fmt: "\tport_clock=%d, lane_count=%d\n", | 
|---|
| 563 | crtc_state->port_clock, crtc_state->lane_count); | 
|---|
| 564 |  | 
|---|
| 565 | intel_scaler_info(m, crtc); | 
|---|
| 566 |  | 
|---|
| 567 | if (crtc_state->joiner_pipes) | 
|---|
| 568 | seq_printf(m, fmt: "\tLinked to 0x%x pipes as a %s\n", | 
|---|
| 569 | crtc_state->joiner_pipes, | 
|---|
| 570 | intel_crtc_is_joiner_secondary(crtc_state) ? "slave": "master"); | 
|---|
| 571 |  | 
|---|
| 572 | intel_vdsc_state_dump(p: &p, indent: 1, crtc_state); | 
|---|
| 573 |  | 
|---|
| 574 | for_each_intel_encoder_mask(display->drm, encoder, | 
|---|
| 575 | crtc_state->uapi.encoder_mask) | 
|---|
| 576 | intel_encoder_info(m, crtc, encoder); | 
|---|
| 577 |  | 
|---|
| 578 | intel_plane_info(m, crtc); | 
|---|
| 579 |  | 
|---|
| 580 | seq_printf(m, fmt: "\tunderrun reporting: cpu=%s pch=%s\n", | 
|---|
| 581 | str_yes_no(v: !crtc->cpu_fifo_underrun_disabled), | 
|---|
| 582 | str_yes_no(v: !crtc->pch_fifo_underrun_disabled)); | 
|---|
| 583 |  | 
|---|
| 584 | crtc_updates_info(m, crtc, hdr: "\t"); | 
|---|
| 585 | } | 
|---|
| 586 |  | 
|---|
| 587 | static int i915_display_info(struct seq_file *m, void *unused) | 
|---|
| 588 | { | 
|---|
| 589 | struct intel_display *display = node_to_intel_display(node: m->private); | 
|---|
| 590 | struct intel_crtc *crtc; | 
|---|
| 591 | struct drm_connector *connector; | 
|---|
| 592 | struct drm_connector_list_iter conn_iter; | 
|---|
| 593 | struct ref_tracker *wakeref; | 
|---|
| 594 |  | 
|---|
| 595 | wakeref = intel_display_rpm_get(display); | 
|---|
| 596 |  | 
|---|
| 597 | drm_modeset_lock_all(dev: display->drm); | 
|---|
| 598 |  | 
|---|
| 599 | seq_printf(m, fmt: "CRTC info\n"); | 
|---|
| 600 | seq_printf(m, fmt: "---------\n"); | 
|---|
| 601 | for_each_intel_crtc(display->drm, crtc) | 
|---|
| 602 | intel_crtc_info(m, crtc); | 
|---|
| 603 |  | 
|---|
| 604 | seq_printf(m, fmt: "\n"); | 
|---|
| 605 | seq_printf(m, fmt: "Connector info\n"); | 
|---|
| 606 | seq_printf(m, fmt: "--------------\n"); | 
|---|
| 607 | drm_connector_list_iter_begin(dev: display->drm, iter: &conn_iter); | 
|---|
| 608 | drm_for_each_connector_iter(connector, &conn_iter) | 
|---|
| 609 | intel_connector_info(m, connector); | 
|---|
| 610 | drm_connector_list_iter_end(iter: &conn_iter); | 
|---|
| 611 |  | 
|---|
| 612 | drm_modeset_unlock_all(dev: display->drm); | 
|---|
| 613 |  | 
|---|
| 614 | intel_display_rpm_put(display, wakeref); | 
|---|
| 615 |  | 
|---|
| 616 | return 0; | 
|---|
| 617 | } | 
|---|
| 618 |  | 
|---|
| 619 | static int i915_shared_dplls_info(struct seq_file *m, void *unused) | 
|---|
| 620 | { | 
|---|
| 621 | struct intel_display *display = node_to_intel_display(node: m->private); | 
|---|
| 622 | struct drm_printer p = drm_seq_file_printer(f: m); | 
|---|
| 623 | struct intel_dpll *pll; | 
|---|
| 624 | int i; | 
|---|
| 625 |  | 
|---|
| 626 | drm_modeset_lock_all(dev: display->drm); | 
|---|
| 627 |  | 
|---|
| 628 | drm_printf(p: &p, f: "PLL refclks: non-SSC: %d kHz, SSC: %d kHz\n", | 
|---|
| 629 | display->dpll.ref_clks.nssc, | 
|---|
| 630 | display->dpll.ref_clks.ssc); | 
|---|
| 631 |  | 
|---|
| 632 | for_each_dpll(display, pll, i) { | 
|---|
| 633 | drm_printf(p: &p, f: "DPLL%i: %s, id: %i\n", pll->index, | 
|---|
| 634 | pll->info->name, pll->info->id); | 
|---|
| 635 | drm_printf(p: &p, f: " pipe_mask: 0x%x, active: 0x%x, on: %s\n", | 
|---|
| 636 | pll->state.pipe_mask, pll->active_mask, | 
|---|
| 637 | str_yes_no(v: pll->on)); | 
|---|
| 638 | drm_printf(p: &p, f: " tracked hardware state:\n"); | 
|---|
| 639 | intel_dpll_dump_hw_state(display, p: &p, dpll_hw_state: &pll->state.hw_state); | 
|---|
| 640 | } | 
|---|
| 641 | drm_modeset_unlock_all(dev: display->drm); | 
|---|
| 642 |  | 
|---|
| 643 | return 0; | 
|---|
| 644 | } | 
|---|
| 645 |  | 
|---|
| 646 | static int i915_ddb_info(struct seq_file *m, void *unused) | 
|---|
| 647 | { | 
|---|
| 648 | struct intel_display *display = node_to_intel_display(node: m->private); | 
|---|
| 649 | struct skl_ddb_entry *entry; | 
|---|
| 650 | struct intel_crtc *crtc; | 
|---|
| 651 |  | 
|---|
| 652 | if (DISPLAY_VER(display) < 9) | 
|---|
| 653 | return -ENODEV; | 
|---|
| 654 |  | 
|---|
| 655 | drm_modeset_lock_all(dev: display->drm); | 
|---|
| 656 |  | 
|---|
| 657 | seq_printf(m, fmt: "%-15s%8s%8s%8s\n", "", "Start", "End", "Size"); | 
|---|
| 658 |  | 
|---|
| 659 | for_each_intel_crtc(display->drm, crtc) { | 
|---|
| 660 | struct intel_crtc_state *crtc_state = | 
|---|
| 661 | to_intel_crtc_state(crtc->base.state); | 
|---|
| 662 | enum pipe pipe = crtc->pipe; | 
|---|
| 663 | enum plane_id plane_id; | 
|---|
| 664 |  | 
|---|
| 665 | seq_printf(m, fmt: "Pipe %c\n", pipe_name(pipe)); | 
|---|
| 666 |  | 
|---|
| 667 | for_each_plane_id_on_crtc(crtc, plane_id) { | 
|---|
| 668 | entry = &crtc_state->wm.skl.plane_ddb[plane_id]; | 
|---|
| 669 | seq_printf(m, fmt: "  Plane%-8d%8u%8u%8u\n", plane_id + 1, | 
|---|
| 670 | entry->start, entry->end, | 
|---|
| 671 | skl_ddb_entry_size(entry)); | 
|---|
| 672 | } | 
|---|
| 673 |  | 
|---|
| 674 | entry = &crtc_state->wm.skl.plane_ddb[PLANE_CURSOR]; | 
|---|
| 675 | seq_printf(m, fmt: "  %-13s%8u%8u%8u\n", "Cursor", entry->start, | 
|---|
| 676 | entry->end, skl_ddb_entry_size(entry)); | 
|---|
| 677 | } | 
|---|
| 678 |  | 
|---|
| 679 | drm_modeset_unlock_all(dev: display->drm); | 
|---|
| 680 |  | 
|---|
| 681 | return 0; | 
|---|
| 682 | } | 
|---|
| 683 |  | 
|---|
| 684 | static bool | 
|---|
| 685 | intel_lpsp_power_well_enabled(struct intel_display *display, | 
|---|
| 686 | enum i915_power_well_id power_well_id) | 
|---|
| 687 | { | 
|---|
| 688 | bool is_enabled; | 
|---|
| 689 |  | 
|---|
| 690 | with_intel_display_rpm(display) | 
|---|
| 691 | is_enabled = intel_display_power_well_is_enabled(display, | 
|---|
| 692 | power_well_id); | 
|---|
| 693 |  | 
|---|
| 694 | return is_enabled; | 
|---|
| 695 | } | 
|---|
| 696 |  | 
|---|
| 697 | static int i915_lpsp_status(struct seq_file *m, void *unused) | 
|---|
| 698 | { | 
|---|
| 699 | struct intel_display *display = node_to_intel_display(node: m->private); | 
|---|
| 700 | bool lpsp_enabled = false; | 
|---|
| 701 |  | 
|---|
| 702 | if (DISPLAY_VER(display) >= 13 || IS_DISPLAY_VER(display, 9, 10)) { | 
|---|
| 703 | lpsp_enabled = !intel_lpsp_power_well_enabled(display, power_well_id: SKL_DISP_PW_2); | 
|---|
| 704 | } else if (IS_DISPLAY_VER(display, 11, 12)) { | 
|---|
| 705 | lpsp_enabled = !intel_lpsp_power_well_enabled(display, power_well_id: ICL_DISP_PW_3); | 
|---|
| 706 | } else if (display->platform.haswell || display->platform.broadwell) { | 
|---|
| 707 | lpsp_enabled = !intel_lpsp_power_well_enabled(display, power_well_id: HSW_DISP_PW_GLOBAL); | 
|---|
| 708 | } else { | 
|---|
| 709 | seq_puts(m, s: "LPSP: not supported\n"); | 
|---|
| 710 | return 0; | 
|---|
| 711 | } | 
|---|
| 712 |  | 
|---|
| 713 | seq_printf(m, fmt: "LPSP: %s\n", str_enabled_disabled(v: lpsp_enabled)); | 
|---|
| 714 |  | 
|---|
| 715 | return 0; | 
|---|
| 716 | } | 
|---|
| 717 |  | 
|---|
| 718 | static int i915_dp_mst_info(struct seq_file *m, void *unused) | 
|---|
| 719 | { | 
|---|
| 720 | struct intel_display *display = node_to_intel_display(node: m->private); | 
|---|
| 721 | struct intel_encoder *intel_encoder; | 
|---|
| 722 | struct intel_digital_port *dig_port; | 
|---|
| 723 | struct drm_connector *connector; | 
|---|
| 724 | struct drm_connector_list_iter conn_iter; | 
|---|
| 725 |  | 
|---|
| 726 | drm_connector_list_iter_begin(dev: display->drm, iter: &conn_iter); | 
|---|
| 727 | drm_for_each_connector_iter(connector, &conn_iter) { | 
|---|
| 728 | if (connector->connector_type != DRM_MODE_CONNECTOR_DisplayPort) | 
|---|
| 729 | continue; | 
|---|
| 730 |  | 
|---|
| 731 | intel_encoder = intel_attached_encoder(to_intel_connector(connector)); | 
|---|
| 732 | if (!intel_encoder || intel_encoder->type == INTEL_OUTPUT_DP_MST) | 
|---|
| 733 | continue; | 
|---|
| 734 |  | 
|---|
| 735 | dig_port = enc_to_dig_port(encoder: intel_encoder); | 
|---|
| 736 | if (!intel_dp_mst_source_support(intel_dp: &dig_port->dp)) | 
|---|
| 737 | continue; | 
|---|
| 738 |  | 
|---|
| 739 | seq_printf(m, fmt: "MST Source Port [ENCODER:%d:%s]\n", | 
|---|
| 740 | dig_port->base.base.base.id, | 
|---|
| 741 | dig_port->base.base.name); | 
|---|
| 742 | drm_dp_mst_dump_topology(m, mgr: &dig_port->dp.mst.mgr); | 
|---|
| 743 | } | 
|---|
| 744 | drm_connector_list_iter_end(iter: &conn_iter); | 
|---|
| 745 |  | 
|---|
| 746 | return 0; | 
|---|
| 747 | } | 
|---|
| 748 |  | 
|---|
| 749 | static ssize_t | 
|---|
| 750 | i915_fifo_underrun_reset_write(struct file *filp, | 
|---|
| 751 | const char __user *ubuf, | 
|---|
| 752 | size_t cnt, loff_t *ppos) | 
|---|
| 753 | { | 
|---|
| 754 | struct intel_display *display = filp->private_data; | 
|---|
| 755 | struct intel_crtc *crtc; | 
|---|
| 756 | int ret; | 
|---|
| 757 | bool reset; | 
|---|
| 758 |  | 
|---|
| 759 | ret = kstrtobool_from_user(s: ubuf, count: cnt, res: &reset); | 
|---|
| 760 | if (ret) | 
|---|
| 761 | return ret; | 
|---|
| 762 |  | 
|---|
| 763 | if (!reset) | 
|---|
| 764 | return cnt; | 
|---|
| 765 |  | 
|---|
| 766 | for_each_intel_crtc(display->drm, crtc) { | 
|---|
| 767 | struct drm_crtc_commit *commit; | 
|---|
| 768 | struct intel_crtc_state *crtc_state; | 
|---|
| 769 |  | 
|---|
| 770 | ret = drm_modeset_lock_single_interruptible(lock: &crtc->base.mutex); | 
|---|
| 771 | if (ret) | 
|---|
| 772 | return ret; | 
|---|
| 773 |  | 
|---|
| 774 | crtc_state = to_intel_crtc_state(crtc->base.state); | 
|---|
| 775 | commit = crtc_state->uapi.commit; | 
|---|
| 776 | if (commit) { | 
|---|
| 777 | ret = wait_for_completion_interruptible(x: &commit->hw_done); | 
|---|
| 778 | if (!ret) | 
|---|
| 779 | ret = wait_for_completion_interruptible(x: &commit->flip_done); | 
|---|
| 780 | } | 
|---|
| 781 |  | 
|---|
| 782 | if (!ret && crtc_state->hw.active) { | 
|---|
| 783 | drm_dbg_kms(display->drm, | 
|---|
| 784 | "Re-arming FIFO underruns on pipe %c\n", | 
|---|
| 785 | pipe_name(crtc->pipe)); | 
|---|
| 786 |  | 
|---|
| 787 | intel_crtc_arm_fifo_underrun(crtc, crtc_state); | 
|---|
| 788 | } | 
|---|
| 789 |  | 
|---|
| 790 | drm_modeset_unlock(lock: &crtc->base.mutex); | 
|---|
| 791 |  | 
|---|
| 792 | if (ret) | 
|---|
| 793 | return ret; | 
|---|
| 794 | } | 
|---|
| 795 |  | 
|---|
| 796 | intel_fbc_reset_underrun(display); | 
|---|
| 797 |  | 
|---|
| 798 | return cnt; | 
|---|
| 799 | } | 
|---|
| 800 |  | 
|---|
| 801 | static const struct file_operations i915_fifo_underrun_reset_ops = { | 
|---|
| 802 | .owner = THIS_MODULE, | 
|---|
| 803 | .open = simple_open, | 
|---|
| 804 | .write = i915_fifo_underrun_reset_write, | 
|---|
| 805 | .llseek = default_llseek, | 
|---|
| 806 | }; | 
|---|
| 807 |  | 
|---|
| 808 | static const struct drm_info_list intel_display_debugfs_list[] = { | 
|---|
| 809 | { "intel_display_caps", intel_display_caps, 0}, | 
|---|
| 810 | { "i915_frontbuffer_tracking", i915_frontbuffer_tracking, 0}, | 
|---|
| 811 | { "i915_sr_status", i915_sr_status, 0}, | 
|---|
| 812 | { "i915_gem_framebuffer", i915_gem_framebuffer_info, 0}, | 
|---|
| 813 | { "i915_power_domain_info", i915_power_domain_info, 0}, | 
|---|
| 814 | { "i915_display_info", i915_display_info, 0}, | 
|---|
| 815 | { "i915_shared_dplls_info", i915_shared_dplls_info, 0}, | 
|---|
| 816 | { "i915_dp_mst_info", i915_dp_mst_info, 0}, | 
|---|
| 817 | { "i915_ddb_info", i915_ddb_info, 0}, | 
|---|
| 818 | { "i915_lpsp_status", i915_lpsp_status, 0}, | 
|---|
| 819 | }; | 
|---|
| 820 |  | 
|---|
| 821 | void intel_display_debugfs_register(struct intel_display *display) | 
|---|
| 822 | { | 
|---|
| 823 | struct dentry *debugfs_root = display->drm->debugfs_root; | 
|---|
| 824 |  | 
|---|
| 825 | debugfs_create_file( "i915_fifo_underrun_reset", 0644, debugfs_root, | 
|---|
| 826 | display, &i915_fifo_underrun_reset_ops); | 
|---|
| 827 |  | 
|---|
| 828 | drm_debugfs_create_files(files: intel_display_debugfs_list, | 
|---|
| 829 | ARRAY_SIZE(intel_display_debugfs_list), | 
|---|
| 830 | root: debugfs_root, minor: display->drm->primary); | 
|---|
| 831 |  | 
|---|
| 832 | intel_bios_debugfs_register(display); | 
|---|
| 833 | intel_cdclk_debugfs_register(display); | 
|---|
| 834 | intel_dmc_debugfs_register(display); | 
|---|
| 835 | intel_dp_test_debugfs_register(display); | 
|---|
| 836 | intel_fbc_debugfs_register(display); | 
|---|
| 837 | intel_hpd_debugfs_register(display); | 
|---|
| 838 | intel_opregion_debugfs_register(display); | 
|---|
| 839 | intel_psr_debugfs_register(display); | 
|---|
| 840 | intel_wm_debugfs_register(display); | 
|---|
| 841 | intel_display_debugfs_params(display); | 
|---|
| 842 | } | 
|---|
| 843 |  | 
|---|
| 844 | static int i915_lpsp_capability_show(struct seq_file *m, void *data) | 
|---|
| 845 | { | 
|---|
| 846 | struct intel_connector *connector = m->private; | 
|---|
| 847 | struct intel_display *display = to_intel_display(connector); | 
|---|
| 848 | struct intel_encoder *encoder = intel_attached_encoder(connector); | 
|---|
| 849 | int connector_type = connector->base.connector_type; | 
|---|
| 850 | bool lpsp_capable = false; | 
|---|
| 851 |  | 
|---|
| 852 | if (!encoder) | 
|---|
| 853 | return -ENODEV; | 
|---|
| 854 |  | 
|---|
| 855 | if (connector->base.status != connector_status_connected) | 
|---|
| 856 | return -ENODEV; | 
|---|
| 857 |  | 
|---|
| 858 | if (DISPLAY_VER(display) >= 13) | 
|---|
| 859 | lpsp_capable = encoder->port <= PORT_B; | 
|---|
| 860 | else if (DISPLAY_VER(display) >= 12) | 
|---|
| 861 | /* | 
|---|
| 862 | * Actually TGL can drive LPSP on port till DDI_C | 
|---|
| 863 | * but there is no physical connected DDI_C on TGL sku's, | 
|---|
| 864 | * even driver is not initializing DDI_C port for gen12. | 
|---|
| 865 | */ | 
|---|
| 866 | lpsp_capable = encoder->port <= PORT_B; | 
|---|
| 867 | else if (DISPLAY_VER(display) == 11) | 
|---|
| 868 | lpsp_capable = (connector_type == DRM_MODE_CONNECTOR_DSI || | 
|---|
| 869 | connector_type == DRM_MODE_CONNECTOR_eDP); | 
|---|
| 870 | else if (IS_DISPLAY_VER(display, 9, 10)) | 
|---|
| 871 | lpsp_capable = (encoder->port == PORT_A && | 
|---|
| 872 | (connector_type == DRM_MODE_CONNECTOR_DSI || | 
|---|
| 873 | connector_type == DRM_MODE_CONNECTOR_eDP || | 
|---|
| 874 | connector_type == DRM_MODE_CONNECTOR_DisplayPort)); | 
|---|
| 875 | else if (display->platform.haswell || display->platform.broadwell) | 
|---|
| 876 | lpsp_capable = connector_type == DRM_MODE_CONNECTOR_eDP; | 
|---|
| 877 |  | 
|---|
| 878 | seq_printf(m, fmt: "LPSP: %s\n", lpsp_capable ? "capable": "incapable"); | 
|---|
| 879 |  | 
|---|
| 880 | return 0; | 
|---|
| 881 | } | 
|---|
| 882 | DEFINE_SHOW_ATTRIBUTE(i915_lpsp_capability); | 
|---|
| 883 |  | 
|---|
| 884 | static int i915_dsc_fec_support_show(struct seq_file *m, void *data) | 
|---|
| 885 | { | 
|---|
| 886 | struct intel_connector *connector = m->private; | 
|---|
| 887 | struct intel_display *display = to_intel_display(connector); | 
|---|
| 888 | struct drm_crtc *crtc; | 
|---|
| 889 | struct intel_dp *intel_dp; | 
|---|
| 890 | struct drm_modeset_acquire_ctx ctx; | 
|---|
| 891 | struct intel_crtc_state *crtc_state = NULL; | 
|---|
| 892 | int ret = 0; | 
|---|
| 893 | bool try_again = false; | 
|---|
| 894 |  | 
|---|
| 895 | drm_modeset_acquire_init(ctx: &ctx, DRM_MODESET_ACQUIRE_INTERRUPTIBLE); | 
|---|
| 896 |  | 
|---|
| 897 | do { | 
|---|
| 898 | try_again = false; | 
|---|
| 899 | ret = drm_modeset_lock(lock: &display->drm->mode_config.connection_mutex, | 
|---|
| 900 | ctx: &ctx); | 
|---|
| 901 | if (ret) { | 
|---|
| 902 | if (ret == -EDEADLK && !drm_modeset_backoff(ctx: &ctx)) { | 
|---|
| 903 | try_again = true; | 
|---|
| 904 | continue; | 
|---|
| 905 | } | 
|---|
| 906 | break; | 
|---|
| 907 | } | 
|---|
| 908 | crtc = connector->base.state->crtc; | 
|---|
| 909 | if (connector->base.status != connector_status_connected || !crtc) { | 
|---|
| 910 | ret = -ENODEV; | 
|---|
| 911 | break; | 
|---|
| 912 | } | 
|---|
| 913 | ret = drm_modeset_lock(lock: &crtc->mutex, ctx: &ctx); | 
|---|
| 914 | if (ret == -EDEADLK) { | 
|---|
| 915 | ret = drm_modeset_backoff(ctx: &ctx); | 
|---|
| 916 | if (!ret) { | 
|---|
| 917 | try_again = true; | 
|---|
| 918 | continue; | 
|---|
| 919 | } | 
|---|
| 920 | break; | 
|---|
| 921 | } else if (ret) { | 
|---|
| 922 | break; | 
|---|
| 923 | } | 
|---|
| 924 | intel_dp = intel_attached_dp(connector); | 
|---|
| 925 | crtc_state = to_intel_crtc_state(crtc->state); | 
|---|
| 926 | seq_printf(m, fmt: "DSC_Enabled: %s\n", | 
|---|
| 927 | str_yes_no(v: crtc_state->dsc.compression_enable)); | 
|---|
| 928 | seq_printf(m, fmt: "DSC_Sink_Support: %s\n", | 
|---|
| 929 | str_yes_no(v: drm_dp_sink_supports_dsc(dsc_dpcd: connector->dp.dsc_dpcd))); | 
|---|
| 930 | seq_printf(m, fmt: "DSC_Output_Format_Sink_Support: RGB: %s YCBCR420: %s YCBCR444: %s\n", | 
|---|
| 931 | str_yes_no(v: drm_dp_dsc_sink_supports_format(dsc_dpcd: connector->dp.dsc_dpcd, | 
|---|
| 932 | DP_DSC_RGB)), | 
|---|
| 933 | str_yes_no(v: drm_dp_dsc_sink_supports_format(dsc_dpcd: connector->dp.dsc_dpcd, | 
|---|
| 934 | DP_DSC_YCbCr420_Native)), | 
|---|
| 935 | str_yes_no(v: drm_dp_dsc_sink_supports_format(dsc_dpcd: connector->dp.dsc_dpcd, | 
|---|
| 936 | DP_DSC_YCbCr444))); | 
|---|
| 937 | seq_printf(m, fmt: "DSC_Sink_BPP_Precision: %d\n", | 
|---|
| 938 | drm_dp_dsc_sink_bpp_incr(dsc_dpcd: connector->dp.dsc_dpcd)); | 
|---|
| 939 | seq_printf(m, fmt: "DSC_Sink_Max_Slice_Count: %d\n", | 
|---|
| 940 | drm_dp_dsc_sink_max_slice_count(dsc_dpcd: (connector->dp.dsc_dpcd), is_edp: intel_dp_is_edp(intel_dp))); | 
|---|
| 941 | seq_printf(m, fmt: "Force_DSC_Enable: %s\n", | 
|---|
| 942 | str_yes_no(v: intel_dp->force_dsc_en)); | 
|---|
| 943 | if (!intel_dp_is_edp(intel_dp)) | 
|---|
| 944 | seq_printf(m, fmt: "FEC_Sink_Support: %s\n", | 
|---|
| 945 | str_yes_no(v: drm_dp_sink_supports_fec(fec_capable: connector->dp.fec_capability))); | 
|---|
| 946 | } while (try_again); | 
|---|
| 947 |  | 
|---|
| 948 | drm_modeset_drop_locks(ctx: &ctx); | 
|---|
| 949 | drm_modeset_acquire_fini(ctx: &ctx); | 
|---|
| 950 |  | 
|---|
| 951 | return ret; | 
|---|
| 952 | } | 
|---|
| 953 |  | 
|---|
| 954 | static ssize_t i915_dsc_fec_support_write(struct file *file, | 
|---|
| 955 | const char __user *ubuf, | 
|---|
| 956 | size_t len, loff_t *offp) | 
|---|
| 957 | { | 
|---|
| 958 | struct seq_file *m = file->private_data; | 
|---|
| 959 | struct intel_connector *connector = m->private; | 
|---|
| 960 | struct intel_display *display = to_intel_display(connector); | 
|---|
| 961 | struct intel_encoder *encoder = intel_attached_encoder(connector); | 
|---|
| 962 | struct intel_dp *intel_dp = enc_to_intel_dp(encoder); | 
|---|
| 963 | bool dsc_enable = false; | 
|---|
| 964 | int ret; | 
|---|
| 965 |  | 
|---|
| 966 | if (len == 0) | 
|---|
| 967 | return 0; | 
|---|
| 968 |  | 
|---|
| 969 | drm_dbg(display->drm, | 
|---|
| 970 | "Copied %zu bytes from user to force DSC\n", len); | 
|---|
| 971 |  | 
|---|
| 972 | ret = kstrtobool_from_user(s: ubuf, count: len, res: &dsc_enable); | 
|---|
| 973 | if (ret < 0) | 
|---|
| 974 | return ret; | 
|---|
| 975 |  | 
|---|
| 976 | drm_dbg(display->drm, "Got %s for DSC Enable\n", | 
|---|
| 977 | str_true_false(dsc_enable)); | 
|---|
| 978 | intel_dp->force_dsc_en = dsc_enable; | 
|---|
| 979 |  | 
|---|
| 980 | *offp += len; | 
|---|
| 981 | return len; | 
|---|
| 982 | } | 
|---|
| 983 |  | 
|---|
| 984 | static int i915_dsc_fec_support_open(struct inode *inode, | 
|---|
| 985 | struct file *file) | 
|---|
| 986 | { | 
|---|
| 987 | return single_open(file, i915_dsc_fec_support_show, | 
|---|
| 988 | inode->i_private); | 
|---|
| 989 | } | 
|---|
| 990 |  | 
|---|
| 991 | static const struct file_operations i915_dsc_fec_support_fops = { | 
|---|
| 992 | .owner = THIS_MODULE, | 
|---|
| 993 | .open = i915_dsc_fec_support_open, | 
|---|
| 994 | .read = seq_read, | 
|---|
| 995 | .llseek = seq_lseek, | 
|---|
| 996 | .release = single_release, | 
|---|
| 997 | .write = i915_dsc_fec_support_write | 
|---|
| 998 | }; | 
|---|
| 999 |  | 
|---|
| 1000 | static int i915_dsc_bpc_show(struct seq_file *m, void *data) | 
|---|
| 1001 | { | 
|---|
| 1002 | struct intel_connector *connector = m->private; | 
|---|
| 1003 | struct intel_display *display = to_intel_display(connector); | 
|---|
| 1004 | struct intel_encoder *encoder = intel_attached_encoder(connector); | 
|---|
| 1005 | struct drm_crtc *crtc; | 
|---|
| 1006 | struct intel_crtc_state *crtc_state; | 
|---|
| 1007 | int ret; | 
|---|
| 1008 |  | 
|---|
| 1009 | if (!encoder) | 
|---|
| 1010 | return -ENODEV; | 
|---|
| 1011 |  | 
|---|
| 1012 | ret = drm_modeset_lock_single_interruptible(lock: &display->drm->mode_config.connection_mutex); | 
|---|
| 1013 | if (ret) | 
|---|
| 1014 | return ret; | 
|---|
| 1015 |  | 
|---|
| 1016 | crtc = connector->base.state->crtc; | 
|---|
| 1017 | if (connector->base.status != connector_status_connected || !crtc) { | 
|---|
| 1018 | ret = -ENODEV; | 
|---|
| 1019 | goto out; | 
|---|
| 1020 | } | 
|---|
| 1021 |  | 
|---|
| 1022 | crtc_state = to_intel_crtc_state(crtc->state); | 
|---|
| 1023 | seq_printf(m, fmt: "Input_BPC: %d\n", crtc_state->dsc.config.bits_per_component); | 
|---|
| 1024 |  | 
|---|
| 1025 | out:	drm_modeset_unlock(lock: &display->drm->mode_config.connection_mutex); | 
|---|
| 1026 |  | 
|---|
| 1027 | return ret; | 
|---|
| 1028 | } | 
|---|
| 1029 |  | 
|---|
| 1030 | static ssize_t i915_dsc_bpc_write(struct file *file, | 
|---|
| 1031 | const char __user *ubuf, | 
|---|
| 1032 | size_t len, loff_t *offp) | 
|---|
| 1033 | { | 
|---|
| 1034 | struct seq_file *m = file->private_data; | 
|---|
| 1035 | struct intel_connector *connector = m->private; | 
|---|
| 1036 | struct intel_encoder *encoder = intel_attached_encoder(connector); | 
|---|
| 1037 | struct intel_dp *intel_dp = enc_to_intel_dp(encoder); | 
|---|
| 1038 | int dsc_bpc = 0; | 
|---|
| 1039 | int ret; | 
|---|
| 1040 |  | 
|---|
| 1041 | ret = kstrtoint_from_user(s: ubuf, count: len, base: 0, res: &dsc_bpc); | 
|---|
| 1042 | if (ret < 0) | 
|---|
| 1043 | return ret; | 
|---|
| 1044 |  | 
|---|
| 1045 | intel_dp->force_dsc_bpc = dsc_bpc; | 
|---|
| 1046 | *offp += len; | 
|---|
| 1047 |  | 
|---|
| 1048 | return len; | 
|---|
| 1049 | } | 
|---|
| 1050 |  | 
|---|
| 1051 | static int i915_dsc_bpc_open(struct inode *inode, | 
|---|
| 1052 | struct file *file) | 
|---|
| 1053 | { | 
|---|
| 1054 | return single_open(file, i915_dsc_bpc_show, inode->i_private); | 
|---|
| 1055 | } | 
|---|
| 1056 |  | 
|---|
| 1057 | static const struct file_operations i915_dsc_bpc_fops = { | 
|---|
| 1058 | .owner = THIS_MODULE, | 
|---|
| 1059 | .open = i915_dsc_bpc_open, | 
|---|
| 1060 | .read = seq_read, | 
|---|
| 1061 | .llseek = seq_lseek, | 
|---|
| 1062 | .release = single_release, | 
|---|
| 1063 | .write = i915_dsc_bpc_write | 
|---|
| 1064 | }; | 
|---|
| 1065 |  | 
|---|
| 1066 | static int i915_dsc_output_format_show(struct seq_file *m, void *data) | 
|---|
| 1067 | { | 
|---|
| 1068 | struct intel_connector *connector = m->private; | 
|---|
| 1069 | struct intel_display *display = to_intel_display(connector); | 
|---|
| 1070 | struct intel_encoder *encoder = intel_attached_encoder(connector); | 
|---|
| 1071 | struct drm_crtc *crtc; | 
|---|
| 1072 | struct intel_crtc_state *crtc_state; | 
|---|
| 1073 | int ret; | 
|---|
| 1074 |  | 
|---|
| 1075 | if (!encoder) | 
|---|
| 1076 | return -ENODEV; | 
|---|
| 1077 |  | 
|---|
| 1078 | ret = drm_modeset_lock_single_interruptible(lock: &display->drm->mode_config.connection_mutex); | 
|---|
| 1079 | if (ret) | 
|---|
| 1080 | return ret; | 
|---|
| 1081 |  | 
|---|
| 1082 | crtc = connector->base.state->crtc; | 
|---|
| 1083 | if (connector->base.status != connector_status_connected || !crtc) { | 
|---|
| 1084 | ret = -ENODEV; | 
|---|
| 1085 | goto out; | 
|---|
| 1086 | } | 
|---|
| 1087 |  | 
|---|
| 1088 | crtc_state = to_intel_crtc_state(crtc->state); | 
|---|
| 1089 | seq_printf(m, fmt: "DSC_Output_Format: %s\n", | 
|---|
| 1090 | intel_output_format_name(format: crtc_state->output_format)); | 
|---|
| 1091 |  | 
|---|
| 1092 | out:	drm_modeset_unlock(lock: &display->drm->mode_config.connection_mutex); | 
|---|
| 1093 |  | 
|---|
| 1094 | return ret; | 
|---|
| 1095 | } | 
|---|
| 1096 |  | 
|---|
| 1097 | static ssize_t i915_dsc_output_format_write(struct file *file, | 
|---|
| 1098 | const char __user *ubuf, | 
|---|
| 1099 | size_t len, loff_t *offp) | 
|---|
| 1100 | { | 
|---|
| 1101 | struct seq_file *m = file->private_data; | 
|---|
| 1102 | struct intel_connector *connector = m->private; | 
|---|
| 1103 | struct intel_encoder *encoder = intel_attached_encoder(connector); | 
|---|
| 1104 | struct intel_dp *intel_dp = enc_to_intel_dp(encoder); | 
|---|
| 1105 | int dsc_output_format = 0; | 
|---|
| 1106 | int ret; | 
|---|
| 1107 |  | 
|---|
| 1108 | ret = kstrtoint_from_user(s: ubuf, count: len, base: 0, res: &dsc_output_format); | 
|---|
| 1109 | if (ret < 0) | 
|---|
| 1110 | return ret; | 
|---|
| 1111 |  | 
|---|
| 1112 | intel_dp->force_dsc_output_format = dsc_output_format; | 
|---|
| 1113 | *offp += len; | 
|---|
| 1114 |  | 
|---|
| 1115 | return len; | 
|---|
| 1116 | } | 
|---|
| 1117 |  | 
|---|
| 1118 | static int i915_dsc_output_format_open(struct inode *inode, | 
|---|
| 1119 | struct file *file) | 
|---|
| 1120 | { | 
|---|
| 1121 | return single_open(file, i915_dsc_output_format_show, inode->i_private); | 
|---|
| 1122 | } | 
|---|
| 1123 |  | 
|---|
| 1124 | static const struct file_operations i915_dsc_output_format_fops = { | 
|---|
| 1125 | .owner = THIS_MODULE, | 
|---|
| 1126 | .open = i915_dsc_output_format_open, | 
|---|
| 1127 | .read = seq_read, | 
|---|
| 1128 | .llseek = seq_lseek, | 
|---|
| 1129 | .release = single_release, | 
|---|
| 1130 | .write = i915_dsc_output_format_write | 
|---|
| 1131 | }; | 
|---|
| 1132 |  | 
|---|
| 1133 | static int i915_dsc_fractional_bpp_show(struct seq_file *m, void *data) | 
|---|
| 1134 | { | 
|---|
| 1135 | struct intel_connector *connector = m->private; | 
|---|
| 1136 | struct intel_display *display = to_intel_display(connector); | 
|---|
| 1137 | struct intel_encoder *encoder = intel_attached_encoder(connector); | 
|---|
| 1138 | struct drm_crtc *crtc; | 
|---|
| 1139 | struct intel_dp *intel_dp; | 
|---|
| 1140 | int ret; | 
|---|
| 1141 |  | 
|---|
| 1142 | if (!encoder) | 
|---|
| 1143 | return -ENODEV; | 
|---|
| 1144 |  | 
|---|
| 1145 | ret = drm_modeset_lock_single_interruptible(lock: &display->drm->mode_config.connection_mutex); | 
|---|
| 1146 | if (ret) | 
|---|
| 1147 | return ret; | 
|---|
| 1148 |  | 
|---|
| 1149 | crtc = connector->base.state->crtc; | 
|---|
| 1150 | if (connector->base.status != connector_status_connected || !crtc) { | 
|---|
| 1151 | ret = -ENODEV; | 
|---|
| 1152 | goto out; | 
|---|
| 1153 | } | 
|---|
| 1154 |  | 
|---|
| 1155 | intel_dp = intel_attached_dp(connector); | 
|---|
| 1156 | seq_printf(m, fmt: "Force_DSC_Fractional_BPP_Enable: %s\n", | 
|---|
| 1157 | str_yes_no(v: intel_dp->force_dsc_fractional_bpp_en)); | 
|---|
| 1158 |  | 
|---|
| 1159 | out: | 
|---|
| 1160 | drm_modeset_unlock(lock: &display->drm->mode_config.connection_mutex); | 
|---|
| 1161 |  | 
|---|
| 1162 | return ret; | 
|---|
| 1163 | } | 
|---|
| 1164 |  | 
|---|
| 1165 | static ssize_t i915_dsc_fractional_bpp_write(struct file *file, | 
|---|
| 1166 | const char __user *ubuf, | 
|---|
| 1167 | size_t len, loff_t *offp) | 
|---|
| 1168 | { | 
|---|
| 1169 | struct seq_file *m = file->private_data; | 
|---|
| 1170 | struct intel_connector *connector = m->private; | 
|---|
| 1171 | struct intel_display *display = to_intel_display(connector); | 
|---|
| 1172 | struct intel_encoder *encoder = intel_attached_encoder(connector); | 
|---|
| 1173 | struct intel_dp *intel_dp = enc_to_intel_dp(encoder); | 
|---|
| 1174 | bool dsc_fractional_bpp_enable = false; | 
|---|
| 1175 | int ret; | 
|---|
| 1176 |  | 
|---|
| 1177 | if (len == 0) | 
|---|
| 1178 | return 0; | 
|---|
| 1179 |  | 
|---|
| 1180 | drm_dbg(display->drm, | 
|---|
| 1181 | "Copied %zu bytes from user to force fractional bpp for DSC\n", len); | 
|---|
| 1182 |  | 
|---|
| 1183 | ret = kstrtobool_from_user(s: ubuf, count: len, res: &dsc_fractional_bpp_enable); | 
|---|
| 1184 | if (ret < 0) | 
|---|
| 1185 | return ret; | 
|---|
| 1186 |  | 
|---|
| 1187 | drm_dbg(display->drm, "Got %s for DSC Fractional BPP Enable\n", | 
|---|
| 1188 | str_true_false(dsc_fractional_bpp_enable)); | 
|---|
| 1189 | intel_dp->force_dsc_fractional_bpp_en = dsc_fractional_bpp_enable; | 
|---|
| 1190 |  | 
|---|
| 1191 | *offp += len; | 
|---|
| 1192 |  | 
|---|
| 1193 | return len; | 
|---|
| 1194 | } | 
|---|
| 1195 |  | 
|---|
| 1196 | static int i915_dsc_fractional_bpp_open(struct inode *inode, | 
|---|
| 1197 | struct file *file) | 
|---|
| 1198 | { | 
|---|
| 1199 | return single_open(file, i915_dsc_fractional_bpp_show, inode->i_private); | 
|---|
| 1200 | } | 
|---|
| 1201 |  | 
|---|
| 1202 | static const struct file_operations i915_dsc_fractional_bpp_fops = { | 
|---|
| 1203 | .owner = THIS_MODULE, | 
|---|
| 1204 | .open = i915_dsc_fractional_bpp_open, | 
|---|
| 1205 | .read = seq_read, | 
|---|
| 1206 | .llseek = seq_lseek, | 
|---|
| 1207 | .release = single_release, | 
|---|
| 1208 | .write = i915_dsc_fractional_bpp_write | 
|---|
| 1209 | }; | 
|---|
| 1210 |  | 
|---|
| 1211 | /* | 
|---|
| 1212 | * Returns the Current CRTC's bpc. | 
|---|
| 1213 | * Example usage: cat /sys/kernel/debug/dri/0/crtc-0/i915_current_bpc | 
|---|
| 1214 | */ | 
|---|
| 1215 | static int i915_current_bpc_show(struct seq_file *m, void *data) | 
|---|
| 1216 | { | 
|---|
| 1217 | struct intel_crtc *crtc = m->private; | 
|---|
| 1218 | struct intel_crtc_state *crtc_state; | 
|---|
| 1219 | int ret; | 
|---|
| 1220 |  | 
|---|
| 1221 | ret = drm_modeset_lock_single_interruptible(lock: &crtc->base.mutex); | 
|---|
| 1222 | if (ret) | 
|---|
| 1223 | return ret; | 
|---|
| 1224 |  | 
|---|
| 1225 | crtc_state = to_intel_crtc_state(crtc->base.state); | 
|---|
| 1226 | seq_printf(m, fmt: "Current: %u\n", crtc_state->pipe_bpp / 3); | 
|---|
| 1227 |  | 
|---|
| 1228 | drm_modeset_unlock(lock: &crtc->base.mutex); | 
|---|
| 1229 |  | 
|---|
| 1230 | return ret; | 
|---|
| 1231 | } | 
|---|
| 1232 | DEFINE_SHOW_ATTRIBUTE(i915_current_bpc); | 
|---|
| 1233 |  | 
|---|
| 1234 | /* Pipe may differ from crtc index if pipes are fused off */ | 
|---|
| 1235 | static int intel_crtc_pipe_show(struct seq_file *m, void *unused) | 
|---|
| 1236 | { | 
|---|
| 1237 | struct intel_crtc *crtc = m->private; | 
|---|
| 1238 |  | 
|---|
| 1239 | seq_printf(m, fmt: "%c\n", pipe_name(crtc->pipe)); | 
|---|
| 1240 |  | 
|---|
| 1241 | return 0; | 
|---|
| 1242 | } | 
|---|
| 1243 | DEFINE_SHOW_ATTRIBUTE(intel_crtc_pipe); | 
|---|
| 1244 |  | 
|---|
| 1245 | static int i915_joiner_show(struct seq_file *m, void *data) | 
|---|
| 1246 | { | 
|---|
| 1247 | struct intel_connector *connector = m->private; | 
|---|
| 1248 |  | 
|---|
| 1249 | seq_printf(m, fmt: "%d\n", connector->force_joined_pipes); | 
|---|
| 1250 |  | 
|---|
| 1251 | return 0; | 
|---|
| 1252 | } | 
|---|
| 1253 |  | 
|---|
| 1254 | static ssize_t i915_joiner_write(struct file *file, | 
|---|
| 1255 | const char __user *ubuf, | 
|---|
| 1256 | size_t len, loff_t *offp) | 
|---|
| 1257 | { | 
|---|
| 1258 | struct seq_file *m = file->private_data; | 
|---|
| 1259 | struct intel_connector *connector = m->private; | 
|---|
| 1260 | struct intel_display *display = to_intel_display(connector); | 
|---|
| 1261 | int force_joined_pipes = 0; | 
|---|
| 1262 | int ret; | 
|---|
| 1263 |  | 
|---|
| 1264 | if (len == 0) | 
|---|
| 1265 | return 0; | 
|---|
| 1266 |  | 
|---|
| 1267 | ret = kstrtoint_from_user(s: ubuf, count: len, base: 0, res: &force_joined_pipes); | 
|---|
| 1268 | if (ret < 0) | 
|---|
| 1269 | return ret; | 
|---|
| 1270 |  | 
|---|
| 1271 | switch (force_joined_pipes) { | 
|---|
| 1272 | case 0: | 
|---|
| 1273 | case 1: | 
|---|
| 1274 | case 2: | 
|---|
| 1275 | connector->force_joined_pipes = force_joined_pipes; | 
|---|
| 1276 | break; | 
|---|
| 1277 | case 4: | 
|---|
| 1278 | if (HAS_ULTRAJOINER(display)) { | 
|---|
| 1279 | connector->force_joined_pipes = force_joined_pipes; | 
|---|
| 1280 | break; | 
|---|
| 1281 | } | 
|---|
| 1282 |  | 
|---|
| 1283 | fallthrough; | 
|---|
| 1284 | default: | 
|---|
| 1285 | return -EINVAL; | 
|---|
| 1286 | } | 
|---|
| 1287 |  | 
|---|
| 1288 | *offp += len; | 
|---|
| 1289 |  | 
|---|
| 1290 | return len; | 
|---|
| 1291 | } | 
|---|
| 1292 |  | 
|---|
| 1293 | static int i915_joiner_open(struct inode *inode, struct file *file) | 
|---|
| 1294 | { | 
|---|
| 1295 | return single_open(file, i915_joiner_show, inode->i_private); | 
|---|
| 1296 | } | 
|---|
| 1297 |  | 
|---|
| 1298 | static const struct file_operations i915_joiner_fops = { | 
|---|
| 1299 | .owner = THIS_MODULE, | 
|---|
| 1300 | .open = i915_joiner_open, | 
|---|
| 1301 | .read = seq_read, | 
|---|
| 1302 | .llseek = seq_lseek, | 
|---|
| 1303 | .release = single_release, | 
|---|
| 1304 | .write = i915_joiner_write | 
|---|
| 1305 | }; | 
|---|
| 1306 |  | 
|---|
| 1307 | /** | 
|---|
| 1308 | * intel_connector_debugfs_add - add i915 specific connector debugfs files | 
|---|
| 1309 | * @connector: pointer to a registered intel_connector | 
|---|
| 1310 | * | 
|---|
| 1311 | * Cleanup will be done by drm_connector_unregister() through a call to | 
|---|
| 1312 | * drm_debugfs_connector_remove(). | 
|---|
| 1313 | */ | 
|---|
| 1314 | void intel_connector_debugfs_add(struct intel_connector *connector) | 
|---|
| 1315 | { | 
|---|
| 1316 | struct intel_display *display = to_intel_display(connector); | 
|---|
| 1317 | struct dentry *root = connector->base.debugfs_entry; | 
|---|
| 1318 | int connector_type = connector->base.connector_type; | 
|---|
| 1319 |  | 
|---|
| 1320 | /* The connector must have been registered beforehands. */ | 
|---|
| 1321 | if (!root) | 
|---|
| 1322 | return; | 
|---|
| 1323 |  | 
|---|
| 1324 | intel_drrs_connector_debugfs_add(connector); | 
|---|
| 1325 | intel_hdcp_connector_debugfs_add(connector); | 
|---|
| 1326 | intel_pps_connector_debugfs_add(connector); | 
|---|
| 1327 | intel_psr_connector_debugfs_add(connector); | 
|---|
| 1328 | intel_alpm_lobf_debugfs_add(connector); | 
|---|
| 1329 | intel_dp_link_training_debugfs_add(connector); | 
|---|
| 1330 | intel_link_bw_connector_debugfs_add(connector); | 
|---|
| 1331 |  | 
|---|
| 1332 | if (DISPLAY_VER(display) >= 11 && | 
|---|
| 1333 | ((connector_type == DRM_MODE_CONNECTOR_DisplayPort && !connector->mst.dp) || | 
|---|
| 1334 | connector_type == DRM_MODE_CONNECTOR_eDP)) { | 
|---|
| 1335 | debugfs_create_file( "i915_dsc_fec_support", 0644, root, | 
|---|
| 1336 | connector, &i915_dsc_fec_support_fops); | 
|---|
| 1337 |  | 
|---|
| 1338 | debugfs_create_file( "i915_dsc_bpc", 0644, root, | 
|---|
| 1339 | connector, &i915_dsc_bpc_fops); | 
|---|
| 1340 |  | 
|---|
| 1341 | debugfs_create_file( "i915_dsc_output_format", 0644, root, | 
|---|
| 1342 | connector, &i915_dsc_output_format_fops); | 
|---|
| 1343 |  | 
|---|
| 1344 | debugfs_create_file( "i915_dsc_fractional_bpp", 0644, root, | 
|---|
| 1345 | connector, &i915_dsc_fractional_bpp_fops); | 
|---|
| 1346 | } | 
|---|
| 1347 |  | 
|---|
| 1348 | if ((connector_type == DRM_MODE_CONNECTOR_DisplayPort || | 
|---|
| 1349 | connector_type == DRM_MODE_CONNECTOR_eDP) && | 
|---|
| 1350 | intel_dp_has_joiner(intel_dp: intel_attached_dp(connector))) { | 
|---|
| 1351 | debugfs_create_file( "i915_joiner_force_enable", 0644, root, | 
|---|
| 1352 | connector, &i915_joiner_fops); | 
|---|
| 1353 | } | 
|---|
| 1354 |  | 
|---|
| 1355 | if (connector_type == DRM_MODE_CONNECTOR_DSI || | 
|---|
| 1356 | connector_type == DRM_MODE_CONNECTOR_eDP || | 
|---|
| 1357 | connector_type == DRM_MODE_CONNECTOR_DisplayPort || | 
|---|
| 1358 | connector_type == DRM_MODE_CONNECTOR_HDMIA || | 
|---|
| 1359 | connector_type == DRM_MODE_CONNECTOR_HDMIB) | 
|---|
| 1360 | debugfs_create_file( "i915_lpsp_capability", 0444, root, | 
|---|
| 1361 | connector, &i915_lpsp_capability_fops); | 
|---|
| 1362 | } | 
|---|
| 1363 |  | 
|---|
| 1364 | /** | 
|---|
| 1365 | * intel_crtc_debugfs_add - add i915 specific crtc debugfs files | 
|---|
| 1366 | * @crtc: pointer to a drm_crtc | 
|---|
| 1367 | * | 
|---|
| 1368 | * Failure to add debugfs entries should generally be ignored. | 
|---|
| 1369 | */ | 
|---|
| 1370 | void intel_crtc_debugfs_add(struct intel_crtc *crtc) | 
|---|
| 1371 | { | 
|---|
| 1372 | struct dentry *root = crtc->base.debugfs_entry; | 
|---|
| 1373 |  | 
|---|
| 1374 | if (!root) | 
|---|
| 1375 | return; | 
|---|
| 1376 |  | 
|---|
| 1377 | crtc_updates_add(crtc); | 
|---|
| 1378 | intel_drrs_crtc_debugfs_add(crtc); | 
|---|
| 1379 | intel_fbc_crtc_debugfs_add(crtc); | 
|---|
| 1380 | hsw_ips_crtc_debugfs_add(crtc); | 
|---|
| 1381 |  | 
|---|
| 1382 | debugfs_create_file( "i915_current_bpc", 0444, root, crtc, | 
|---|
| 1383 | &i915_current_bpc_fops); | 
|---|
| 1384 | debugfs_create_file( "i915_pipe", 0444, root, crtc, | 
|---|
| 1385 | &intel_crtc_pipe_fops); | 
|---|
| 1386 | } | 
|---|
| 1387 |  | 
|---|