blob: c7bfb27918abc633db4bd1a7569de9394484f625 [file] [log] [blame]
Thomas Woodbdbf78d2014-12-10 14:47:45 +00001/*
2 * Copyright © 2014 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
Damien Lespiau69a465d2014-04-28 05:56:31 +010024#include <stdint.h>
25#include <stdio.h>
26#include <stdbool.h>
27#include <stddef.h>
28#include <string.h>
29
30/**
31 * container_of - cast a member of a structure out to the containing structure
32 * @ptr: the pointer to the member.
33 * @type: the type of the container struct this is embedded in.
34 * @member: the name of the member within the struct.
35 *
36 */
37#define container_of(ptr, type, member) ({ \
38 typeof( ((type *)0)->member ) *__mptr = (ptr); \
39 (type *)( (char *)__mptr - offsetof(type,member) );})
40
41#define div_u64(a, b) ((a) / (b))
42
43/*
44 * Stub a few defines/structures
45 */
46
47#define I915_MAX_PIPES 3
48#define I915_MAX_PLANES 3
49#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
50
51#define for_each_pipe(p) for ((p) = 0; (p) < 3; (p)++)
52#define for_each_plane(pipe, p) for ((p) = 0; (p) < 3; (p)++)
53
54#define for_each_crtc(dev, crtc) \
55 for (int i = 0; i < 3 && (crtc = &crtcs[i].base); i++)
56
57#define for_each_intel_crtc(dev, intel_crtc) \
58 for (int i = 0; i < 3, intel_crtc = &crtcs[i]; i++)
59
60enum pipe {
61 PIPE_A,
62 PIPE_B,
63 PIPE_C,
64};
65
66enum plane {
67 PLANE_1,
68 PLANE_2,
69 PLANE_3,
70};
71
72#define pipe_name(p) ((p) + 'A')
73
74struct drm_device {
75 void *dev_private;
76};
77
78struct drm_i915_private {
79 struct drm_device *dev;
80};
81
82struct drm_crtc {
83 struct drm_device *dev;
84 bool active;
85};
86
87static bool intel_crtc_active(struct drm_crtc *crtc)
88{
89 return crtc->active;
90}
91
92struct intel_crtc {
93 struct drm_crtc base;
94 enum pipe pipe;
95};
96
97static int intel_num_planes(struct intel_crtc *crtc)
98{
99 return 3;
100}
101
102struct intel_crtc crtcs[I915_MAX_PIPES];
103
104#define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
105
106/*
107 * DDB code
108 */
109
110struct intel_wm_config {
111 unsigned int num_pipes_active;
112};
113
114struct intel_plane_wm_parameters {
115 uint32_t horiz_pixels;
116 uint32_t vert_pixels;
117 uint8_t bytes_per_pixel;
118 bool enabled;
119 bool scaled;
120};
121
122struct skl_pipe_wm_parameters {
123 bool active;
124 uint32_t pipe_htotal;
125 uint32_t pixel_rate; /* in KHz */
126 struct intel_plane_wm_parameters plane[I915_MAX_PLANES];
127 struct intel_plane_wm_parameters cursor;
128};
129
130struct skl_ddb_entry {
Damien Lespiau303fe742014-10-13 15:14:15 +0100131 uint16_t start, end; /* in number of blocks. 'end' is exclusive */
Damien Lespiau69a465d2014-04-28 05:56:31 +0100132};
133
134static inline uint16_t skl_ddb_entry_size(const struct skl_ddb_entry *entry)
135{
136 /* end not set, clearly no allocation here. start can be 0 though */
137 if (entry->end == 0)
138 return 0;
139
Damien Lespiau303fe742014-10-13 15:14:15 +0100140 return entry->end - entry->start;
Damien Lespiau69a465d2014-04-28 05:56:31 +0100141}
142
143static inline bool skl_ddb_entry_equal(const struct skl_ddb_entry *e1,
144 const struct skl_ddb_entry *e2)
145{
146 if (e1->start == e2->start && e1->end == e2->end)
147 return true;
148
149 return false;
150}
151
152struct skl_ddb_allocation {
153 struct skl_ddb_entry plane[I915_MAX_PIPES][I915_MAX_PLANES];
154 struct skl_ddb_entry cursor[I915_MAX_PIPES];
155};
156
157/*
158 * On gen9, we need to allocate Display Data Buffer (DDB) portions to the
159 * different active planes.
160 */
161
162#define SKL_DDB_SIZE 896 /* in blocks */
163
164static void
165skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
166 struct drm_crtc *for_crtc,
167 const struct intel_wm_config *config,
168 const struct skl_pipe_wm_parameters *params,
169 struct skl_ddb_entry *alloc /* out */)
170{
171 struct drm_crtc *crtc;
172 unsigned int pipe_size, ddb_size;
173 int nth_active_pipe;
174
175 if (!params->active) {
176 alloc->start = 0;
177 alloc->end = 0;
178 return;
179 }
180
181 ddb_size = SKL_DDB_SIZE;
182 ddb_size -= 4; /* 4 blocks for bypass path allocation */
183
184 nth_active_pipe = 0;
185 for_each_crtc(dev, crtc) {
186 if (!intel_crtc_active(crtc))
187 continue;
188
189 if (crtc == for_crtc)
190 break;
191
192 nth_active_pipe++;
193 }
194
195 pipe_size = ddb_size / config->num_pipes_active;
196 alloc->start = nth_active_pipe * ddb_size / config->num_pipes_active;
Damien Lespiau303fe742014-10-13 15:14:15 +0100197 alloc->end = alloc->start + pipe_size;
Damien Lespiau69a465d2014-04-28 05:56:31 +0100198}
199
200static unsigned int skl_cursor_allocation(const struct intel_wm_config *config)
201{
202 if (config->num_pipes_active == 1)
203 return 32;
204
205 return 8;
206}
207
208static unsigned int
209skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p)
210{
211 return p->horiz_pixels * p->vert_pixels * p->bytes_per_pixel;
212}
213
214/*
215 * We don't overflow 32 bits. Worst case is 3 planes enabled, each fetching
216 * a 8192x4096@32bpp framebuffer:
217 * 3 * 4096 * 8192 * 4 < 2^32
218 */
219static unsigned int
220skl_get_total_relative_data_rate(struct intel_crtc *intel_crtc,
221 const struct skl_pipe_wm_parameters *params)
222{
223 unsigned int total_data_rate = 0;
224 int plane;
225
226 for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
227 const struct intel_plane_wm_parameters *p;
228
229 p = &params->plane[plane];
230 if (!p->enabled)
231 continue;
232
233 total_data_rate += skl_plane_relative_data_rate(p);
234 }
235
236 return total_data_rate;
237}
238
239static void
240skl_allocate_pipe_ddb(struct drm_crtc *crtc,
241 const struct intel_wm_config *config,
242 const struct skl_pipe_wm_parameters *params,
243 struct skl_ddb_allocation *ddb /* out */)
244{
245 struct drm_device *dev = crtc->dev;
246 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
247 enum pipe pipe = intel_crtc->pipe;
248 struct skl_ddb_entry alloc;
249 uint16_t alloc_size, start, cursor_blocks;
Damien Lespiaucba30882014-10-15 23:13:30 +0100250 uint16_t minimum[I915_MAX_PLANES];
Damien Lespiau69a465d2014-04-28 05:56:31 +0100251 unsigned int total_data_rate;
252 int plane;
253
254 skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params, &alloc);
255 alloc_size = skl_ddb_entry_size(&alloc);
256 if (alloc_size == 0) {
257 memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
258 memset(&ddb->cursor[pipe], 0, sizeof(ddb->cursor[pipe]));
259 return;
260 }
261
262 cursor_blocks = skl_cursor_allocation(config);
Damien Lespiau303fe742014-10-13 15:14:15 +0100263 ddb->cursor[pipe].start = alloc.end - cursor_blocks;
Damien Lespiau69a465d2014-04-28 05:56:31 +0100264 ddb->cursor[pipe].end = alloc.end;
265
266 alloc_size -= cursor_blocks;
267 alloc.end -= cursor_blocks;
268
Damien Lespiaucba30882014-10-15 23:13:30 +0100269 /* 1. Allocate the mininum required blocks for each active plane */
270 for_each_plane(pipe, plane) {
271 const struct intel_plane_wm_parameters *p;
272
273 p = &params->plane[plane];
274 if (!p->enabled)
275 continue;
276
277 minimum[plane] = 8;
278 alloc_size -= minimum[plane];
279 }
280
Damien Lespiau69a465d2014-04-28 05:56:31 +0100281 /*
Damien Lespiaucba30882014-10-15 23:13:30 +0100282 * 2. Distribute the remaining space in proportion to the amount of
283 * data each plane needs to fetch from memory.
Damien Lespiau69a465d2014-04-28 05:56:31 +0100284 *
285 * FIXME: we may not allocate every single block here.
286 */
287 total_data_rate = skl_get_total_relative_data_rate(intel_crtc, params);
288
289 start = alloc.start;
290 for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
291 const struct intel_plane_wm_parameters *p;
292 unsigned int data_rate;
293 uint16_t plane_blocks;
294
295 p = &params->plane[plane];
296 if (!p->enabled)
297 continue;
298
299 data_rate = skl_plane_relative_data_rate(p);
300
301 /*
302 * promote the expression to 64 bits to avoid overflowing, the
303 * result is < available as data_rate / total_data_rate < 1
304 */
Damien Lespiaucba30882014-10-15 23:13:30 +0100305 plane_blocks = minimum[plane];
306 plane_blocks += div_u64((uint64_t)alloc_size * data_rate,
307 total_data_rate);
Damien Lespiau69a465d2014-04-28 05:56:31 +0100308
309 ddb->plane[pipe][plane].start = start;
Damien Lespiau303fe742014-10-13 15:14:15 +0100310 ddb->plane[pipe][plane].end = start + plane_blocks;
Damien Lespiau69a465d2014-04-28 05:56:31 +0100311
312 start += plane_blocks;
313 }
314
315}
316
Damien Lespiauf9519432014-04-28 07:11:04 +0100317static void skl_ddb_check_entry(struct skl_ddb_entry *entry, int16_t *cursor)
318{
319
320 if (skl_ddb_entry_size(entry) == 0)
321 return;
322
323 /* check that ->start is the next available block */
Damien Lespiau303fe742014-10-13 15:14:15 +0100324 if (entry->start < *cursor)
Damien Lespiauf9519432014-04-28 07:11:04 +0100325 printf("error: allocation overlaps previous block\n");
Damien Lespiau303fe742014-10-13 15:14:15 +0100326 else if (entry->start >= *cursor + 1)
Damien Lespiauf9519432014-04-28 07:11:04 +0100327 printf("warning: allocation leaves a hole\n");
328
329 *cursor = entry->end;
330}
331
332static void skl_ddb_check_last_allocation(int16_t cursor)
333{
Damien Lespiau303fe742014-10-13 15:14:15 +0100334 uint16_t last_offset = SKL_DDB_SIZE - 4;
Damien Lespiauf9519432014-04-28 07:11:04 +0100335
336 if (cursor < last_offset)
337 printf("warning: %d blocks not allocated\n",
338 last_offset - cursor);
339 else if (cursor > last_offset)
340 printf("error: allocation greater than available space\n");
341}
342
Damien Lespiau69a465d2014-04-28 05:56:31 +0100343static void skl_ddb_print(struct skl_ddb_allocation *ddb)
344{
345 struct skl_ddb_entry *entry;
346 enum pipe pipe;
347 int plane;
Damien Lespiau303fe742014-10-13 15:14:15 +0100348 int16_t cursor = 0;
Damien Lespiau69a465d2014-04-28 05:56:31 +0100349
350 printf("%-15s%8s%8s%8s\n", "", "Start", "End", "Size");
351
352 for_each_pipe(pipe) {
353 printf("Pipe %c\n", pipe_name(pipe));
354
355 for_each_plane(pipe, plane) {
356 entry = &ddb->plane[pipe][plane];
Damien Lespiauf9519432014-04-28 07:11:04 +0100357
Damien Lespiau69a465d2014-04-28 05:56:31 +0100358 printf(" Plane%-8d%8u%8u%8u\n", plane + 1,
359 entry->start, entry->end,
360 skl_ddb_entry_size(entry));
Damien Lespiauf9519432014-04-28 07:11:04 +0100361
362 skl_ddb_check_entry(entry, &cursor);
Damien Lespiau69a465d2014-04-28 05:56:31 +0100363 }
364
365 entry = &ddb->cursor[pipe];
366 printf(" %-13s%8u%8u%8u\n", "Cursor", entry->start,
367 entry->end, skl_ddb_entry_size(entry));
Damien Lespiauf9519432014-04-28 07:11:04 +0100368
369 skl_ddb_check_entry(entry, &cursor);
Damien Lespiau69a465d2014-04-28 05:56:31 +0100370 }
371
Damien Lespiauf9519432014-04-28 07:11:04 +0100372 skl_ddb_check_last_allocation(cursor);
Damien Lespiau69a465d2014-04-28 05:56:31 +0100373}
374
375static struct drm_device drm_device;
376static struct drm_i915_private drm_i915_private;
377
378static void init_stub(void)
379{
380 int i;
381
382 drm_device.dev_private = &drm_i915_private;
383 drm_i915_private.dev = &drm_device;
384
385 for (i = 0; i < I915_MAX_PIPES; i++) {
386 crtcs[i].base.dev = &drm_device;
387 crtcs[i].pipe = i;
388 }
389}
390
391struct wm_input {
392 struct intel_wm_config config;
393 struct skl_pipe_wm_parameters params[I915_MAX_PIPES];
394};
395
396static void wm_input_reset(struct wm_input *in)
397{
398 memset(in, 0, sizeof(*in));
399}
400
401static void wm_enable_plane(struct wm_input *in,
402 enum pipe pipe, enum plane plane,
403 uint32_t width, uint32_t height, int bpp)
404{
405 enum pipe i;
406
407 in->params[pipe].active = 1;
408
409 in->config.num_pipes_active = 0;
410 for_each_pipe(i)
411 if (in->params[i].active)
412 in->config.num_pipes_active++;
413
414 in->params[pipe].plane[plane].horiz_pixels = width;
415 in->params[pipe].plane[plane].vert_pixels = height;
416 in->params[pipe].plane[plane].bytes_per_pixel = bpp;
417 in->params[pipe].plane[plane].enabled = true;
418}
419
420static void skl_ddb_allocate(struct wm_input *in,
421 struct skl_ddb_allocation *out)
422{
423 struct drm_crtc *crtc;
424
425 for_each_crtc(, crtc) {
426 enum pipe pipe = to_intel_crtc(crtc)->pipe;
427
428 skl_allocate_pipe_ddb(crtc,
429 &in->config, &in->params[pipe], out);
430 }
431}
432
433int main(int argc, char **argv)
434{
435 struct wm_input in;
436 static struct skl_ddb_allocation ddb;
437
438 init_stub();
439
440 wm_input_reset(&in);
441 wm_enable_plane(&in, PIPE_A, PLANE_1, 1280, 1024, 4);
442 wm_enable_plane(&in, PIPE_A, PLANE_2, 100, 100, 4);
443 skl_ddb_allocate(&in, &ddb);
444 skl_ddb_print(&ddb);
445
446 return 0;
447}