blob: 7faed0ef424b0d31c665686b4d79a53d6561bef4 [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
280static void skl_ddb_print(struct skl_ddb_allocation *ddb)
281{
282 struct skl_ddb_entry *entry;
283 enum pipe pipe;
284 int plane;
285
286 printf("%-15s%8s%8s%8s\n", "", "Start", "End", "Size");
287
288 for_each_pipe(pipe) {
289 printf("Pipe %c\n", pipe_name(pipe));
290
291 for_each_plane(pipe, plane) {
292 entry = &ddb->plane[pipe][plane];
293 printf(" Plane%-8d%8u%8u%8u\n", plane + 1,
294 entry->start, entry->end,
295 skl_ddb_entry_size(entry));
296 }
297
298 entry = &ddb->cursor[pipe];
299 printf(" %-13s%8u%8u%8u\n", "Cursor", entry->start,
300 entry->end, skl_ddb_entry_size(entry));
301 }
302
303
304}
305
306static struct drm_device drm_device;
307static struct drm_i915_private drm_i915_private;
308
309static void init_stub(void)
310{
311 int i;
312
313 drm_device.dev_private = &drm_i915_private;
314 drm_i915_private.dev = &drm_device;
315
316 for (i = 0; i < I915_MAX_PIPES; i++) {
317 crtcs[i].base.dev = &drm_device;
318 crtcs[i].pipe = i;
319 }
320}
321
322struct wm_input {
323 struct intel_wm_config config;
324 struct skl_pipe_wm_parameters params[I915_MAX_PIPES];
325};
326
327static void wm_input_reset(struct wm_input *in)
328{
329 memset(in, 0, sizeof(*in));
330}
331
332static void wm_enable_plane(struct wm_input *in,
333 enum pipe pipe, enum plane plane,
334 uint32_t width, uint32_t height, int bpp)
335{
336 enum pipe i;
337
338 in->params[pipe].active = 1;
339
340 in->config.num_pipes_active = 0;
341 for_each_pipe(i)
342 if (in->params[i].active)
343 in->config.num_pipes_active++;
344
345 in->params[pipe].plane[plane].horiz_pixels = width;
346 in->params[pipe].plane[plane].vert_pixels = height;
347 in->params[pipe].plane[plane].bytes_per_pixel = bpp;
348 in->params[pipe].plane[plane].enabled = true;
349}
350
351static void skl_ddb_allocate(struct wm_input *in,
352 struct skl_ddb_allocation *out)
353{
354 struct drm_crtc *crtc;
355
356 for_each_crtc(, crtc) {
357 enum pipe pipe = to_intel_crtc(crtc)->pipe;
358
359 skl_allocate_pipe_ddb(crtc,
360 &in->config, &in->params[pipe], out);
361 }
362}
363
364int main(int argc, char **argv)
365{
366 struct wm_input in;
367 static struct skl_ddb_allocation ddb;
368
369 init_stub();
370
371 wm_input_reset(&in);
372 wm_enable_plane(&in, PIPE_A, PLANE_1, 1280, 1024, 4);
373 wm_enable_plane(&in, PIPE_A, PLANE_2, 100, 100, 4);
374 skl_ddb_allocate(&in, &ddb);
375 skl_ddb_print(&ddb);
376
377 return 0;
378}