blob: 4d8e6d185ee709679c094e900c66d445886e692b [file] [log] [blame]
Damien Lespiau69a465d2014-04-28 05:56:31 +01001#include <stdint.h>
2#include <stdio.h>
3#include <stdbool.h>
4#include <stddef.h>
5#include <string.h>
6
7/**
8 * container_of - cast a member of a structure out to the containing structure
9 * @ptr: the pointer to the member.
10 * @type: the type of the container struct this is embedded in.
11 * @member: the name of the member within the struct.
12 *
13 */
14#define container_of(ptr, type, member) ({ \
15 typeof( ((type *)0)->member ) *__mptr = (ptr); \
16 (type *)( (char *)__mptr - offsetof(type,member) );})
17
18#define div_u64(a, b) ((a) / (b))
19
20/*
21 * Stub a few defines/structures
22 */
23
24#define I915_MAX_PIPES 3
25#define I915_MAX_PLANES 3
26#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
27
28#define for_each_pipe(p) for ((p) = 0; (p) < 3; (p)++)
29#define for_each_plane(pipe, p) for ((p) = 0; (p) < 3; (p)++)
30
31#define for_each_crtc(dev, crtc) \
32 for (int i = 0; i < 3 && (crtc = &crtcs[i].base); i++)
33
34#define for_each_intel_crtc(dev, intel_crtc) \
35 for (int i = 0; i < 3, intel_crtc = &crtcs[i]; i++)
36
37enum pipe {
38 PIPE_A,
39 PIPE_B,
40 PIPE_C,
41};
42
43enum plane {
44 PLANE_1,
45 PLANE_2,
46 PLANE_3,
47};
48
49#define pipe_name(p) ((p) + 'A')
50
51struct drm_device {
52 void *dev_private;
53};
54
55struct drm_i915_private {
56 struct drm_device *dev;
57};
58
59struct drm_crtc {
60 struct drm_device *dev;
61 bool active;
62};
63
64static bool intel_crtc_active(struct drm_crtc *crtc)
65{
66 return crtc->active;
67}
68
69struct intel_crtc {
70 struct drm_crtc base;
71 enum pipe pipe;
72};
73
74static int intel_num_planes(struct intel_crtc *crtc)
75{
76 return 3;
77}
78
79struct intel_crtc crtcs[I915_MAX_PIPES];
80
81#define to_intel_crtc(x) container_of(x, struct intel_crtc, base)
82
83/*
84 * DDB code
85 */
86
87struct intel_wm_config {
88 unsigned int num_pipes_active;
89};
90
91struct intel_plane_wm_parameters {
92 uint32_t horiz_pixels;
93 uint32_t vert_pixels;
94 uint8_t bytes_per_pixel;
95 bool enabled;
96 bool scaled;
97};
98
99struct skl_pipe_wm_parameters {
100 bool active;
101 uint32_t pipe_htotal;
102 uint32_t pixel_rate; /* in KHz */
103 struct intel_plane_wm_parameters plane[I915_MAX_PLANES];
104 struct intel_plane_wm_parameters cursor;
105};
106
107struct skl_ddb_entry {
Damien Lespiau303fe742014-10-13 15:14:15 +0100108 uint16_t start, end; /* in number of blocks. 'end' is exclusive */
Damien Lespiau69a465d2014-04-28 05:56:31 +0100109};
110
111static inline uint16_t skl_ddb_entry_size(const struct skl_ddb_entry *entry)
112{
113 /* end not set, clearly no allocation here. start can be 0 though */
114 if (entry->end == 0)
115 return 0;
116
Damien Lespiau303fe742014-10-13 15:14:15 +0100117 return entry->end - entry->start;
Damien Lespiau69a465d2014-04-28 05:56:31 +0100118}
119
120static inline bool skl_ddb_entry_equal(const struct skl_ddb_entry *e1,
121 const struct skl_ddb_entry *e2)
122{
123 if (e1->start == e2->start && e1->end == e2->end)
124 return true;
125
126 return false;
127}
128
129struct skl_ddb_allocation {
130 struct skl_ddb_entry plane[I915_MAX_PIPES][I915_MAX_PLANES];
131 struct skl_ddb_entry cursor[I915_MAX_PIPES];
132};
133
134/*
135 * On gen9, we need to allocate Display Data Buffer (DDB) portions to the
136 * different active planes.
137 */
138
139#define SKL_DDB_SIZE 896 /* in blocks */
140
141static void
142skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
143 struct drm_crtc *for_crtc,
144 const struct intel_wm_config *config,
145 const struct skl_pipe_wm_parameters *params,
146 struct skl_ddb_entry *alloc /* out */)
147{
148 struct drm_crtc *crtc;
149 unsigned int pipe_size, ddb_size;
150 int nth_active_pipe;
151
152 if (!params->active) {
153 alloc->start = 0;
154 alloc->end = 0;
155 return;
156 }
157
158 ddb_size = SKL_DDB_SIZE;
159 ddb_size -= 4; /* 4 blocks for bypass path allocation */
160
161 nth_active_pipe = 0;
162 for_each_crtc(dev, crtc) {
163 if (!intel_crtc_active(crtc))
164 continue;
165
166 if (crtc == for_crtc)
167 break;
168
169 nth_active_pipe++;
170 }
171
172 pipe_size = ddb_size / config->num_pipes_active;
173 alloc->start = nth_active_pipe * ddb_size / config->num_pipes_active;
Damien Lespiau303fe742014-10-13 15:14:15 +0100174 alloc->end = alloc->start + pipe_size;
Damien Lespiau69a465d2014-04-28 05:56:31 +0100175}
176
177static unsigned int skl_cursor_allocation(const struct intel_wm_config *config)
178{
179 if (config->num_pipes_active == 1)
180 return 32;
181
182 return 8;
183}
184
185static unsigned int
186skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p)
187{
188 return p->horiz_pixels * p->vert_pixels * p->bytes_per_pixel;
189}
190
191/*
192 * We don't overflow 32 bits. Worst case is 3 planes enabled, each fetching
193 * a 8192x4096@32bpp framebuffer:
194 * 3 * 4096 * 8192 * 4 < 2^32
195 */
196static unsigned int
197skl_get_total_relative_data_rate(struct intel_crtc *intel_crtc,
198 const struct skl_pipe_wm_parameters *params)
199{
200 unsigned int total_data_rate = 0;
201 int plane;
202
203 for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
204 const struct intel_plane_wm_parameters *p;
205
206 p = &params->plane[plane];
207 if (!p->enabled)
208 continue;
209
210 total_data_rate += skl_plane_relative_data_rate(p);
211 }
212
213 return total_data_rate;
214}
215
216static void
217skl_allocate_pipe_ddb(struct drm_crtc *crtc,
218 const struct intel_wm_config *config,
219 const struct skl_pipe_wm_parameters *params,
220 struct skl_ddb_allocation *ddb /* out */)
221{
222 struct drm_device *dev = crtc->dev;
223 struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
224 enum pipe pipe = intel_crtc->pipe;
225 struct skl_ddb_entry alloc;
226 uint16_t alloc_size, start, cursor_blocks;
Damien Lespiaucba30882014-10-15 23:13:30 +0100227 uint16_t minimum[I915_MAX_PLANES];
Damien Lespiau69a465d2014-04-28 05:56:31 +0100228 unsigned int total_data_rate;
229 int plane;
230
231 skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params, &alloc);
232 alloc_size = skl_ddb_entry_size(&alloc);
233 if (alloc_size == 0) {
234 memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
235 memset(&ddb->cursor[pipe], 0, sizeof(ddb->cursor[pipe]));
236 return;
237 }
238
239 cursor_blocks = skl_cursor_allocation(config);
Damien Lespiau303fe742014-10-13 15:14:15 +0100240 ddb->cursor[pipe].start = alloc.end - cursor_blocks;
Damien Lespiau69a465d2014-04-28 05:56:31 +0100241 ddb->cursor[pipe].end = alloc.end;
242
243 alloc_size -= cursor_blocks;
244 alloc.end -= cursor_blocks;
245
Damien Lespiaucba30882014-10-15 23:13:30 +0100246 /* 1. Allocate the mininum required blocks for each active plane */
247 for_each_plane(pipe, plane) {
248 const struct intel_plane_wm_parameters *p;
249
250 p = &params->plane[plane];
251 if (!p->enabled)
252 continue;
253
254 minimum[plane] = 8;
255 alloc_size -= minimum[plane];
256 }
257
Damien Lespiau69a465d2014-04-28 05:56:31 +0100258 /*
Damien Lespiaucba30882014-10-15 23:13:30 +0100259 * 2. Distribute the remaining space in proportion to the amount of
260 * data each plane needs to fetch from memory.
Damien Lespiau69a465d2014-04-28 05:56:31 +0100261 *
262 * FIXME: we may not allocate every single block here.
263 */
264 total_data_rate = skl_get_total_relative_data_rate(intel_crtc, params);
265
266 start = alloc.start;
267 for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
268 const struct intel_plane_wm_parameters *p;
269 unsigned int data_rate;
270 uint16_t plane_blocks;
271
272 p = &params->plane[plane];
273 if (!p->enabled)
274 continue;
275
276 data_rate = skl_plane_relative_data_rate(p);
277
278 /*
279 * promote the expression to 64 bits to avoid overflowing, the
280 * result is < available as data_rate / total_data_rate < 1
281 */
Damien Lespiaucba30882014-10-15 23:13:30 +0100282 plane_blocks = minimum[plane];
283 plane_blocks += div_u64((uint64_t)alloc_size * data_rate,
284 total_data_rate);
Damien Lespiau69a465d2014-04-28 05:56:31 +0100285
286 ddb->plane[pipe][plane].start = start;
Damien Lespiau303fe742014-10-13 15:14:15 +0100287 ddb->plane[pipe][plane].end = start + plane_blocks;
Damien Lespiau69a465d2014-04-28 05:56:31 +0100288
289 start += plane_blocks;
290 }
291
292}
293
Damien Lespiauf9519432014-04-28 07:11:04 +0100294static void skl_ddb_check_entry(struct skl_ddb_entry *entry, int16_t *cursor)
295{
296
297 if (skl_ddb_entry_size(entry) == 0)
298 return;
299
300 /* check that ->start is the next available block */
Damien Lespiau303fe742014-10-13 15:14:15 +0100301 if (entry->start < *cursor)
Damien Lespiauf9519432014-04-28 07:11:04 +0100302 printf("error: allocation overlaps previous block\n");
Damien Lespiau303fe742014-10-13 15:14:15 +0100303 else if (entry->start >= *cursor + 1)
Damien Lespiauf9519432014-04-28 07:11:04 +0100304 printf("warning: allocation leaves a hole\n");
305
306 *cursor = entry->end;
307}
308
309static void skl_ddb_check_last_allocation(int16_t cursor)
310{
Damien Lespiau303fe742014-10-13 15:14:15 +0100311 uint16_t last_offset = SKL_DDB_SIZE - 4;
Damien Lespiauf9519432014-04-28 07:11:04 +0100312
313 if (cursor < last_offset)
314 printf("warning: %d blocks not allocated\n",
315 last_offset - cursor);
316 else if (cursor > last_offset)
317 printf("error: allocation greater than available space\n");
318}
319
Damien Lespiau69a465d2014-04-28 05:56:31 +0100320static void skl_ddb_print(struct skl_ddb_allocation *ddb)
321{
322 struct skl_ddb_entry *entry;
323 enum pipe pipe;
324 int plane;
Damien Lespiau303fe742014-10-13 15:14:15 +0100325 int16_t cursor = 0;
Damien Lespiau69a465d2014-04-28 05:56:31 +0100326
327 printf("%-15s%8s%8s%8s\n", "", "Start", "End", "Size");
328
329 for_each_pipe(pipe) {
330 printf("Pipe %c\n", pipe_name(pipe));
331
332 for_each_plane(pipe, plane) {
333 entry = &ddb->plane[pipe][plane];
Damien Lespiauf9519432014-04-28 07:11:04 +0100334
Damien Lespiau69a465d2014-04-28 05:56:31 +0100335 printf(" Plane%-8d%8u%8u%8u\n", plane + 1,
336 entry->start, entry->end,
337 skl_ddb_entry_size(entry));
Damien Lespiauf9519432014-04-28 07:11:04 +0100338
339 skl_ddb_check_entry(entry, &cursor);
Damien Lespiau69a465d2014-04-28 05:56:31 +0100340 }
341
342 entry = &ddb->cursor[pipe];
343 printf(" %-13s%8u%8u%8u\n", "Cursor", entry->start,
344 entry->end, skl_ddb_entry_size(entry));
Damien Lespiauf9519432014-04-28 07:11:04 +0100345
346 skl_ddb_check_entry(entry, &cursor);
Damien Lespiau69a465d2014-04-28 05:56:31 +0100347 }
348
Damien Lespiauf9519432014-04-28 07:11:04 +0100349 skl_ddb_check_last_allocation(cursor);
Damien Lespiau69a465d2014-04-28 05:56:31 +0100350}
351
352static struct drm_device drm_device;
353static struct drm_i915_private drm_i915_private;
354
355static void init_stub(void)
356{
357 int i;
358
359 drm_device.dev_private = &drm_i915_private;
360 drm_i915_private.dev = &drm_device;
361
362 for (i = 0; i < I915_MAX_PIPES; i++) {
363 crtcs[i].base.dev = &drm_device;
364 crtcs[i].pipe = i;
365 }
366}
367
368struct wm_input {
369 struct intel_wm_config config;
370 struct skl_pipe_wm_parameters params[I915_MAX_PIPES];
371};
372
373static void wm_input_reset(struct wm_input *in)
374{
375 memset(in, 0, sizeof(*in));
376}
377
378static void wm_enable_plane(struct wm_input *in,
379 enum pipe pipe, enum plane plane,
380 uint32_t width, uint32_t height, int bpp)
381{
382 enum pipe i;
383
384 in->params[pipe].active = 1;
385
386 in->config.num_pipes_active = 0;
387 for_each_pipe(i)
388 if (in->params[i].active)
389 in->config.num_pipes_active++;
390
391 in->params[pipe].plane[plane].horiz_pixels = width;
392 in->params[pipe].plane[plane].vert_pixels = height;
393 in->params[pipe].plane[plane].bytes_per_pixel = bpp;
394 in->params[pipe].plane[plane].enabled = true;
395}
396
397static void skl_ddb_allocate(struct wm_input *in,
398 struct skl_ddb_allocation *out)
399{
400 struct drm_crtc *crtc;
401
402 for_each_crtc(, crtc) {
403 enum pipe pipe = to_intel_crtc(crtc)->pipe;
404
405 skl_allocate_pipe_ddb(crtc,
406 &in->config, &in->params[pipe], out);
407 }
408}
409
410int main(int argc, char **argv)
411{
412 struct wm_input in;
413 static struct skl_ddb_allocation ddb;
414
415 init_stub();
416
417 wm_input_reset(&in);
418 wm_enable_plane(&in, PIPE_A, PLANE_1, 1280, 1024, 4);
419 wm_enable_plane(&in, PIPE_A, PLANE_2, 100, 100, 4);
420 skl_ddb_allocate(&in, &ddb);
421 skl_ddb_print(&ddb);
422
423 return 0;
424}