]> Git Repo - J-linux.git/blob - drivers/gpu/drm/xe/display/xe_plane_initial.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / gpu / drm / xe / display / xe_plane_initial.c
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2021 Intel Corporation
4  */
5
6 /* for ioread64 */
7 #include <linux/io-64-nonatomic-lo-hi.h>
8
9 #include "regs/xe_gtt_defs.h"
10 #include "xe_ggtt.h"
11
12 #include "intel_atomic_plane.h"
13 #include "intel_crtc.h"
14 #include "intel_display.h"
15 #include "intel_display_types.h"
16 #include "intel_fb.h"
17 #include "intel_fb_pin.h"
18 #include "intel_frontbuffer.h"
19 #include "intel_plane_initial.h"
20 #include "xe_bo.h"
21 #include "xe_wa.h"
22
23 #include <generated/xe_wa_oob.h>
24
25 static bool
26 intel_reuse_initial_plane_obj(struct intel_crtc *this,
27                               const struct intel_initial_plane_config plane_configs[],
28                               struct drm_framebuffer **fb)
29 {
30         struct xe_device *xe = to_xe_device(this->base.dev);
31         struct intel_crtc *crtc;
32
33         for_each_intel_crtc(&xe->drm, crtc) {
34                 struct intel_plane *plane =
35                         to_intel_plane(crtc->base.primary);
36                 const struct intel_plane_state *plane_state =
37                         to_intel_plane_state(plane->base.state);
38                 const struct intel_crtc_state *crtc_state =
39                         to_intel_crtc_state(crtc->base.state);
40
41                 if (!crtc_state->uapi.active)
42                         continue;
43
44                 if (!plane_state->ggtt_vma)
45                         continue;
46
47                 if (plane_configs[this->pipe].base == plane_configs[crtc->pipe].base) {
48                         *fb = plane_state->hw.fb;
49                         return true;
50                 }
51         }
52
53         return false;
54 }
55
56 static struct xe_bo *
57 initial_plane_bo(struct xe_device *xe,
58                  struct intel_initial_plane_config *plane_config)
59 {
60         struct xe_tile *tile0 = xe_device_get_root_tile(xe);
61         struct xe_bo *bo;
62         resource_size_t phys_base;
63         u32 base, size, flags;
64         u64 page_size = xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K ? SZ_64K : SZ_4K;
65
66         if (plane_config->size == 0)
67                 return NULL;
68
69         flags = XE_BO_FLAG_PINNED | XE_BO_FLAG_SCANOUT | XE_BO_FLAG_GGTT;
70
71         base = round_down(plane_config->base, page_size);
72         if (IS_DGFX(xe)) {
73                 u64 __iomem *gte = tile0->mem.ggtt->gsm;
74                 u64 pte;
75
76                 gte += base / XE_PAGE_SIZE;
77
78                 pte = ioread64(gte);
79                 if (!(pte & XE_GGTT_PTE_DM)) {
80                         drm_err(&xe->drm,
81                                 "Initial plane programming missing DM bit\n");
82                         return NULL;
83                 }
84
85                 phys_base = pte & ~(page_size - 1);
86                 flags |= XE_BO_FLAG_VRAM0;
87
88                 /*
89                  * We don't currently expect this to ever be placed in the
90                  * stolen portion.
91                  */
92                 if (phys_base >= tile0->mem.vram.usable_size) {
93                         drm_err(&xe->drm,
94                                 "Initial plane programming using invalid range, phys_base=%pa\n",
95                                 &phys_base);
96                         return NULL;
97                 }
98
99                 drm_dbg(&xe->drm,
100                         "Using phys_base=%pa, based on initial plane programming\n",
101                         &phys_base);
102         } else {
103                 struct ttm_resource_manager *stolen = ttm_manager_type(&xe->ttm, XE_PL_STOLEN);
104
105                 if (!stolen)
106                         return NULL;
107                 phys_base = base;
108                 flags |= XE_BO_FLAG_STOLEN;
109
110                 if (XE_WA(xe_root_mmio_gt(xe), 22019338487_display))
111                         return NULL;
112
113                 /*
114                  * If the FB is too big, just don't use it since fbdev is not very
115                  * important and we should probably use that space with FBC or other
116                  * features.
117                  */
118                 if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) &&
119                     plane_config->size * 2 >> PAGE_SHIFT >= stolen->size)
120                         return NULL;
121         }
122
123         size = round_up(plane_config->base + plane_config->size,
124                         page_size);
125         size -= base;
126
127         bo = xe_bo_create_pin_map_at(xe, tile0, NULL, size, phys_base,
128                                      ttm_bo_type_kernel, flags);
129         if (IS_ERR(bo)) {
130                 drm_dbg(&xe->drm,
131                         "Failed to create bo phys_base=%pa size %u with flags %x: %li\n",
132                         &phys_base, size, flags, PTR_ERR(bo));
133                 return NULL;
134         }
135
136         return bo;
137 }
138
139 static bool
140 intel_alloc_initial_plane_obj(struct intel_crtc *crtc,
141                               struct intel_initial_plane_config *plane_config)
142 {
143         struct xe_device *xe = to_xe_device(crtc->base.dev);
144         struct drm_mode_fb_cmd2 mode_cmd = { 0 };
145         struct drm_framebuffer *fb = &plane_config->fb->base;
146         struct xe_bo *bo;
147
148         switch (fb->modifier) {
149         case DRM_FORMAT_MOD_LINEAR:
150         case I915_FORMAT_MOD_X_TILED:
151         case I915_FORMAT_MOD_Y_TILED:
152         case I915_FORMAT_MOD_4_TILED:
153                 break;
154         default:
155                 drm_dbg_kms(&xe->drm,
156                             "Unsupported modifier for initial FB: 0x%llx\n",
157                             fb->modifier);
158                 return false;
159         }
160
161         mode_cmd.pixel_format = fb->format->format;
162         mode_cmd.width = fb->width;
163         mode_cmd.height = fb->height;
164         mode_cmd.pitches[0] = fb->pitches[0];
165         mode_cmd.modifier[0] = fb->modifier;
166         mode_cmd.flags = DRM_MODE_FB_MODIFIERS;
167
168         bo = initial_plane_bo(xe, plane_config);
169         if (!bo)
170                 return false;
171
172         if (intel_framebuffer_init(to_intel_framebuffer(fb),
173                                    &bo->ttm.base, &mode_cmd)) {
174                 drm_dbg_kms(&xe->drm, "intel fb init failed\n");
175                 goto err_bo;
176         }
177         /* Reference handed over to fb */
178         xe_bo_put(bo);
179
180         return true;
181
182 err_bo:
183         xe_bo_unpin_map_no_vm(bo);
184         return false;
185 }
186
187 static void
188 intel_find_initial_plane_obj(struct intel_crtc *crtc,
189                              struct intel_initial_plane_config plane_configs[])
190 {
191         struct intel_initial_plane_config *plane_config =
192                 &plane_configs[crtc->pipe];
193         struct intel_plane *plane =
194                 to_intel_plane(crtc->base.primary);
195         struct intel_plane_state *plane_state =
196                 to_intel_plane_state(plane->base.state);
197         struct intel_crtc_state *crtc_state =
198                 to_intel_crtc_state(crtc->base.state);
199         struct drm_framebuffer *fb;
200         struct i915_vma *vma;
201
202         /*
203          * TODO:
204          *   Disable planes if get_initial_plane_config() failed.
205          *   Make sure things work if the surface base is not page aligned.
206          */
207         if (!plane_config->fb)
208                 return;
209
210         if (intel_alloc_initial_plane_obj(crtc, plane_config))
211                 fb = &plane_config->fb->base;
212         else if (!intel_reuse_initial_plane_obj(crtc, plane_configs, &fb))
213                 goto nofb;
214
215         plane_state->uapi.rotation = plane_config->rotation;
216         intel_fb_fill_view(to_intel_framebuffer(fb),
217                            plane_state->uapi.rotation, &plane_state->view);
218
219         vma = intel_fb_pin_to_ggtt(fb, &plane_state->view.gtt,
220                                    0, 0, false, &plane_state->flags);
221         if (IS_ERR(vma))
222                 goto nofb;
223
224         plane_state->ggtt_vma = vma;
225         plane_state->uapi.src_x = 0;
226         plane_state->uapi.src_y = 0;
227         plane_state->uapi.src_w = fb->width << 16;
228         plane_state->uapi.src_h = fb->height << 16;
229
230         plane_state->uapi.crtc_x = 0;
231         plane_state->uapi.crtc_y = 0;
232         plane_state->uapi.crtc_w = fb->width;
233         plane_state->uapi.crtc_h = fb->height;
234
235         plane_state->uapi.fb = fb;
236         drm_framebuffer_get(fb);
237
238         plane_state->uapi.crtc = &crtc->base;
239         intel_plane_copy_uapi_to_hw_state(plane_state, plane_state, crtc);
240
241         atomic_or(plane->frontbuffer_bit, &to_intel_frontbuffer(fb)->bits);
242
243         plane_config->vma = vma;
244
245         /*
246          * Flip to the newly created mapping ASAP, so we can re-use the
247          * first part of GGTT for WOPCM, prevent flickering, and prevent
248          * the lookup of sysmem scratch pages.
249          */
250         plane->check_plane(crtc_state, plane_state);
251         plane->async_flip(NULL, plane, crtc_state, plane_state, true);
252         return;
253
254 nofb:
255         /*
256          * We've failed to reconstruct the BIOS FB.  Current display state
257          * indicates that the primary plane is visible, but has a NULL FB,
258          * which will lead to problems later if we don't fix it up.  The
259          * simplest solution is to just disable the primary plane now and
260          * pretend the BIOS never had it enabled.
261          */
262         intel_plane_disable_noatomic(crtc, plane);
263 }
264
265 static void plane_config_fini(struct intel_initial_plane_config *plane_config)
266 {
267         if (plane_config->fb) {
268                 struct drm_framebuffer *fb = &plane_config->fb->base;
269
270                 /* We may only have the stub and not a full framebuffer */
271                 if (drm_framebuffer_read_refcount(fb))
272                         drm_framebuffer_put(fb);
273                 else
274                         kfree(fb);
275         }
276 }
277
278 void intel_initial_plane_config(struct drm_i915_private *i915)
279 {
280         struct intel_initial_plane_config plane_configs[I915_MAX_PIPES] = {};
281         struct intel_crtc *crtc;
282
283         for_each_intel_crtc(&i915->drm, crtc) {
284                 struct intel_initial_plane_config *plane_config =
285                         &plane_configs[crtc->pipe];
286
287                 if (!to_intel_crtc_state(crtc->base.state)->uapi.active)
288                         continue;
289
290                 /*
291                  * Note that reserving the BIOS fb up front prevents us
292                  * from stuffing other stolen allocations like the ring
293                  * on top.  This prevents some ugliness at boot time, and
294                  * can even allow for smooth boot transitions if the BIOS
295                  * fb is large enough for the active pipe configuration.
296                  */
297                 i915->display.funcs.display->get_initial_plane_config(crtc, plane_config);
298
299                 /*
300                  * If the fb is shared between multiple heads, we'll
301                  * just get the first one.
302                  */
303                 intel_find_initial_plane_obj(crtc, plane_configs);
304
305                 if (i915->display.funcs.display->fixup_initial_plane_config(crtc, plane_config))
306                         intel_crtc_wait_for_next_vblank(crtc);
307
308                 plane_config_fini(plane_config);
309         }
310 }
This page took 0.044292 seconds and 4 git commands to generate.