blob: ba5f8ba8fb93f46a07117b20e11587ee0f353cdc [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 {
108 uint16_t start, end; /* in number of blocks */
109};
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
117 return entry->end - entry->start + 1;
118}
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;
174 alloc->end = alloc->start + pipe_size - 1;
175}
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;
227 unsigned int total_data_rate;
228 int plane;
229
230 skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params, &alloc);
231 alloc_size = skl_ddb_entry_size(&alloc);
232 if (alloc_size == 0) {
233 memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
234 memset(&ddb->cursor[pipe], 0, sizeof(ddb->cursor[pipe]));
235 return;
236 }
237
238 cursor_blocks = skl_cursor_allocation(config);
239 ddb->cursor[pipe].start = alloc.end - cursor_blocks + 1;
240 ddb->cursor[pipe].end = alloc.end;
241
242 alloc_size -= cursor_blocks;
243 alloc.end -= cursor_blocks;
244
245 /*
246 * Each active plane get a portion of the remaining space, in
247 * proportion to the amount of data they need to fetch from memory.
248 *
249 * FIXME: we may not allocate every single block here.
250 */
251 total_data_rate = skl_get_total_relative_data_rate(intel_crtc, params);
252
253 start = alloc.start;
254 for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
255 const struct intel_plane_wm_parameters *p;
256 unsigned int data_rate;
257 uint16_t plane_blocks;
258
259 p = &params->plane[plane];
260 if (!p->enabled)
261 continue;
262
263 data_rate = skl_plane_relative_data_rate(p);
264
265 /*
266 * promote the expression to 64 bits to avoid overflowing, the
267 * result is < available as data_rate / total_data_rate < 1
268 */
269 plane_blocks = div_u64((uint64_t)alloc_size * data_rate,
270 total_data_rate);
271
272 ddb->plane[pipe][plane].start = start;
273 ddb->plane[pipe][plane].end = start + plane_blocks - 1;
274
275 start += plane_blocks;
276 }
277
278}
279
Damien Lespiauf9519432014-04-28 07:11:04 +0100280static void skl_ddb_check_entry(struct skl_ddb_entry *entry, int16_t *cursor)
281{
282
283 if (skl_ddb_entry_size(entry) == 0)
284 return;
285
286 /* check that ->start is the next available block */
287 if (entry->start <= *cursor)
288 printf("error: allocation overlaps previous block\n");
289 else if (entry->start > *cursor + 1)
290 printf("warning: allocation leaves a hole\n");
291
292 *cursor = entry->end;
293}
294
295static void skl_ddb_check_last_allocation(int16_t cursor)
296{
297 uint16_t last_offset = SKL_DDB_SIZE - 1 - 4;
298
299 if (cursor < last_offset)
300 printf("warning: %d blocks not allocated\n",
301 last_offset - cursor);
302 else if (cursor > last_offset)
303 printf("error: allocation greater than available space\n");
304}
305
Damien Lespiau69a465d2014-04-28 05:56:31 +0100306static void skl_ddb_print(struct skl_ddb_allocation *ddb)
307{
308 struct skl_ddb_entry *entry;
309 enum pipe pipe;
310 int plane;
Damien Lespiauf9519432014-04-28 07:11:04 +0100311 int16_t cursor = -1;
Damien Lespiau69a465d2014-04-28 05:56:31 +0100312
313 printf("%-15s%8s%8s%8s\n", "", "Start", "End", "Size");
314
315 for_each_pipe(pipe) {
316 printf("Pipe %c\n", pipe_name(pipe));
317
318 for_each_plane(pipe, plane) {
319 entry = &ddb->plane[pipe][plane];
Damien Lespiauf9519432014-04-28 07:11:04 +0100320
Damien Lespiau69a465d2014-04-28 05:56:31 +0100321 printf(" Plane%-8d%8u%8u%8u\n", plane + 1,
322 entry->start, entry->end,
323 skl_ddb_entry_size(entry));
Damien Lespiauf9519432014-04-28 07:11:04 +0100324
325 skl_ddb_check_entry(entry, &cursor);
Damien Lespiau69a465d2014-04-28 05:56:31 +0100326 }
327
328 entry = &ddb->cursor[pipe];
329 printf(" %-13s%8u%8u%8u\n", "Cursor", entry->start,
330 entry->end, skl_ddb_entry_size(entry));
Damien Lespiauf9519432014-04-28 07:11:04 +0100331
332 skl_ddb_check_entry(entry, &cursor);
Damien Lespiau69a465d2014-04-28 05:56:31 +0100333 }
334
Damien Lespiauf9519432014-04-28 07:11:04 +0100335 skl_ddb_check_last_allocation(cursor);
Damien Lespiau69a465d2014-04-28 05:56:31 +0100336}
337
338static struct drm_device drm_device;
339static struct drm_i915_private drm_i915_private;
340
341static void init_stub(void)
342{
343 int i;
344
345 drm_device.dev_private = &drm_i915_private;
346 drm_i915_private.dev = &drm_device;
347
348 for (i = 0; i < I915_MAX_PIPES; i++) {
349 crtcs[i].base.dev = &drm_device;
350 crtcs[i].pipe = i;
351 }
352}
353
354struct wm_input {
355 struct intel_wm_config config;
356 struct skl_pipe_wm_parameters params[I915_MAX_PIPES];
357};
358
359static void wm_input_reset(struct wm_input *in)
360{
361 memset(in, 0, sizeof(*in));
362}
363
364static void wm_enable_plane(struct wm_input *in,
365 enum pipe pipe, enum plane plane,
366 uint32_t width, uint32_t height, int bpp)
367{
368 enum pipe i;
369
370 in->params[pipe].active = 1;
371
372 in->config.num_pipes_active = 0;
373 for_each_pipe(i)
374 if (in->params[i].active)
375 in->config.num_pipes_active++;
376
377 in->params[pipe].plane[plane].horiz_pixels = width;
378 in->params[pipe].plane[plane].vert_pixels = height;
379 in->params[pipe].plane[plane].bytes_per_pixel = bpp;
380 in->params[pipe].plane[plane].enabled = true;
381}
382
383static void skl_ddb_allocate(struct wm_input *in,
384 struct skl_ddb_allocation *out)
385{
386 struct drm_crtc *crtc;
387
388 for_each_crtc(, crtc) {
389 enum pipe pipe = to_intel_crtc(crtc)->pipe;
390
391 skl_allocate_pipe_ddb(crtc,
392 &in->config, &in->params[pipe], out);
393 }
394}
395
396int main(int argc, char **argv)
397{
398 struct wm_input in;
399 static struct skl_ddb_allocation ddb;
400
401 init_stub();
402
403 wm_input_reset(&in);
404 wm_enable_plane(&in, PIPE_A, PLANE_1, 1280, 1024, 4);
405 wm_enable_plane(&in, PIPE_A, PLANE_2, 100, 100, 4);
406 skl_ddb_allocate(&in, &ddb);
407 skl_ddb_print(&ddb);
408
409 return 0;
410}