4
* TILER driver NV12 area reservation functions for TI TILER hardware block.
6
* Author: Lajos Molnar <molnar@ti.com>
8
* Copyright (C) 2009-2010 Texas Instruments, Inc.
10
* This package is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License version 2 as
12
* published by the Free Software Foundation.
14
* THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21
static struct tiler_ops *ops; /* shared methods and variables */
26
* NV12 Reservation Functions
28
* TILER is designed so that a (w * h) * 8bit area is twice as wide as a
29
* (w/2 * h/2) * 16bit area. Since having pairs of such 8-bit and 16-bit
30
* blocks is a common usecase for TILER, we optimize packing these into a
33
* During reservation we want to find the most effective packing (most used area
34
* in the smallest overall area)
36
* We have two algorithms for packing nv12 blocks: either pack 8- and 16-bit
37
* blocks into separate container areas, or pack them together into same area.
41
* Calculate effectiveness of packing. We weight total area much higher than
42
* packing efficiency to get the smallest overall container use.
44
* @param w width of one (8-bit) block
45
* @param n buffers in a packing
46
* @param area width of packing area
47
* @param n_total total number of buffers to be packed
48
* @return effectiveness, the higher the better
50
static inline u32 nv12_eff(u16 w, u16 n, u16 area, u16 n_total)
53
/* weigh against total area needed (for all buffers) */
54
/* 64-slots = -2048 */
55
DIV_ROUND_UP(n_total, n) * area * 32 +
56
/* packing efficiency (0 - 1024) */
57
1024 * n * ((w * 3 + 1) >> 1) / area;
61
* Fallback nv12 packing algorithm: pack 8 and 16 bit block into separate
64
* @author a0194118 (7/16/2010)
66
* @param o desired offset (<a)
67
* @param a desired alignment (>=2)
68
* @param w block width (>0)
69
* @param n number of blocks desired
70
* @param area pointer to store total area needed
72
* @return number of blocks that can be allocated
74
static u16 nv12_separate(u16 o, u16 a, u16 w, u16 n, u16 *area)
76
tiler_best2pack(o, a, band_8, w, &n, area);
77
tiler_best2pack(o >> 1, a >> 1, band_16, (w + 1) >> 1, &n, area);
83
* Specialized NV12 Reservation Algorithms
85
* We use 4 packing methods that pack nv12 blocks into the same area. Together
86
* these 4 methods give the optimal result for most possible input parameters.
88
* For now we pack into a 64-slot area, so that we don't have to worry about
89
* stride issues (all blocks get 4K stride). For some of the algorithms this
90
* could be true even if the area was 128.
94
* Packing types are marked using a letter sequence, capital letters denoting
95
* 8-bit blocks, lower case letters denoting corresponding 16-bit blocks.
97
* All methods have the following parameters. They also define the maximum
98
* number of coordinates that could potentially be packed.
100
* @param o, a, w, n offset, alignment, width, # of blocks as usual
101
* @param area pointer to store area needed for packing
102
* @param p pointer to store packing coordinates
103
* @return number of blocks that can be packed
106
/* Method A: progressive packing: AAAAaaaaBBbbCc into 64-slot area */
108
static int nv12_A(u16 o, u16 a, u16 w, u16 n, u16 *area, u8 *p)
110
u16 x = o, u, l, m = 0;
113
while (x + w < *area && m < n) {
114
/* current 8bit upper bound (a) is next 8bit lower bound (B) */
115
l = u = (*area + x) >> 1;
117
/* pack until upper bound */
118
while (x + w <= u && m < n) {
120
BUG_ON(m + 1 >= MAX_A);
123
l = (*area + x + w + 1) >> 1;
124
x = ALIGN(x + w - o, a) + o;
127
x = ALIGN(l - o, a) + o; /* set new lower bound */
132
/* Method -A: regressive packing: cCbbBBaaaaAAAA into 64-slot area */
133
static int nv12_revA(u16 o, u16 a, u16 w, u16 n, u16 *area, u8 *p)
137
/* this is a mirrored packing of method A */
138
n = nv12_A((a - (o + w) % a) % a, a, w, n, area, p);
140
/* reverse packing */
141
for (m = 0; m < n; m++) {
144
*p = *area - *p - ((w + 1) >> 1);
150
/* Method B: simple layout: aAbcBdeCfgDhEFGH */
152
static int nv12_B(u16 o, u16 a, u16 w, u16 n, u16 *area, u8 *p)
154
u16 e = (o + w) % a; /* end offset */
155
u16 o1 = (o >> 1) % a; /* half offset */
156
u16 e1 = ((o + w + 1) >> 1) % a; /* half end offset */
157
u16 o2 = o1 + (a >> 2); /* 2nd half offset */
158
u16 e2 = e1 + (a >> 2); /* 2nd half end offset */
162
/* ensure 16-bit blocks don't overlap 8-bit blocks */
164
/* width cannot wrap around alignment, half block must be before block,
165
2nd half can be before or after */
166
if (w < a && o < e && e1 <= o && (e2 <= o || o2 >= e))
167
while (o + w <= *area && m < n) {
168
BUG_ON(m + 1 >= MAX_B);
177
/* Method C: butterfly layout: AAbbaaBB */
179
static int nv12_C(u16 o, u16 a, u16 w, u16 n, u16 *area, u8 *p)
182
u16 o2, e = ALIGN(w, a), i = 0, j = 0;
184
o2 = *area - (a - (o + w) % a) % a; /* end of last possible block */
186
m = (min(o2 - 2 * o, 2 * o2 - o - *area) / 3 - w) / e + 1;
187
for (i = j = 0; i < m && j < n; i++, j++) {
188
BUG_ON(j + 1 >= MAX_C);
190
*p++ = (o + i * e + *area) >> 1;
192
*p++ = o2 - i * e - w;
193
*p++ = (o2 - i * e - w) >> 1;
199
/* Method D: for large allocation: aA or Aa */
201
static int nv12_D(u16 o, u16 a, u16 w, u16 n, u16 *area, u8 *p)
203
u16 o1, w1 = (w + 1) >> 1, d;
204
*area = ALIGN(o + w, band_8);
206
for (d = 0; n > 0 && d + o + w <= *area; d += a) {
207
/* try to fit 16-bit before 8-bit */
208
o1 = ((o + d) % band_8) >> 1;
209
if (o1 + w1 <= o + d) {
215
/* try to fit 16-bit after 8-bit */
216
o1 += ALIGN(d + o + w - o1, band_16);
217
if (o1 + w1 <= *area) {
227
* Umbrella nv12 packing method. This selects the best packings from the above
228
* methods. It also contains hardcoded packings for parameter combinations
229
* that have more efficient packings. This method provides is guaranteed to
230
* provide the optimal packing if 2 <= a <= 64 and w <= 64 and n is large.
232
#define MAX_ANY 21 /* must be MAX(method-MAX-s, hardcoded n-s) */
233
static u16 nv12_together(u16 o, u16 a, u16 w, u16 n, u16 *area, u8 *packing)
235
u16 n_best, a_best, n2, a_, o_, w_;
237
/* algo results (packings) */
238
u8 pack_A[MAX_A * 2], pack_rA[MAX_A * 2];
239
u8 pack_B[MAX_B * 2], pack_C[MAX_C * 2];
240
u8 pack_D[MAX_D * 2];
243
* Hardcoded packings. They are sorted by increasing area, and then by
244
* decreasing n. We may not get the best efficiency if less than n
245
* blocks are needed as packings are not necessarily sorted in
246
* increasing order. However, for those n-s one of the other 4 methods
247
* may return the optimal packing.
250
/* n=9, o=2, w=4, a=4, area=64 */
252
/* 8-bit, 16-bit block coordinate pairs */
253
2, 33, 6, 35, 10, 37, 14, 39, 18, 41,
254
46, 23, 50, 25, 54, 27, 58, 29,
255
/* o=0, w=12, a=4, n=3 */
257
0, 32, 12, 38, 48, 24,
260
}, *p = packings, *p_best = NULL, *p_end;
261
p_end = packings + sizeof(packings) - 1;
263
/* see which method gives the best packing */
265
/* start with smallest area algorithms A, B & C, stop if we can
267
n_best = nv12_A(o, a, w, n, area, pack_A);
270
n2 = nv12_revA(o, a, w, n, &a_best, pack_rA);
278
n2 = nv12_B(o, a, w, n, &a_best, pack_B);
286
n2 = nv12_C(o, a, w, n, &a_best, pack_C);
294
/* traverse any special packings */
300
/* stop if we already have a better packing */
304
/* check if this packing is satisfactory */
305
if (a_ >= a && o + w + ALIGN(o_ - o, a) <= o_ + w_) {
312
/* skip to next packing */
317
* If so far unsuccessful, check whether 8 and 16 bit blocks can be
318
* co-packed. This will actually be done in the end by the normal
319
* allocation, but we need to reserve a big-enough area.
322
n_best = nv12_D(o, a, w, n, area, pack_D);
326
/* store best packing */
327
if (p_best && n_best) {
328
BUG_ON(n_best > MAX_ANY);
329
memcpy(packing, p_best, n_best * 2 * sizeof(*pack_A));
335
/* reserve nv12 blocks */
336
static void reserve_nv12(u32 n, u32 width, u32 height, u32 align, u32 offs,
337
u32 gid, struct process_info *pi)
339
u16 w, h, band, a = align, o = offs;
341
int res = 0, res2, i;
342
u16 n_t, n_s, area_t, area_s;
343
u8 packing[2 * MAX_ANY];
344
struct list_head reserved = LIST_HEAD_INIT(reserved);
346
/* adjust alignment to the largest slot width (128 bytes) */
347
a = max_t(u16, PAGE_SIZE / min(band_8, band_16), a);
349
/* Check input parameters for correctness, and support */
350
if (!width || !height || !n ||
351
offs >= align || offs & 1 ||
352
align >= PAGE_SIZE ||
353
n > ops->width * ops->height / 2)
356
/* calculate dimensions, band, offs and alignment in slots */
357
if (ops->analize(TILFMT_8BIT, width, height, &w, &h, &band, &a, &o,
361
/* get group context */
362
gi = ops->get_gi(pi, gid);
366
/* reserve in groups until failed or all is reserved */
367
for (i = 0; i < n && res >= 0; i += res) {
368
/* check packing separately vs together */
369
n_s = nv12_separate(o, a, w, n - i, &area_s);
370
if (ops->nv12_packed)
371
n_t = nv12_together(o, a, w, n - i, &area_t, packing);
375
/* pack based on better efficiency */
377
if (!ops->nv12_packed ||
378
nv12_eff(w, n_s, area_s, n - i) >
379
nv12_eff(w, n_t, area_t, n - i)) {
382
* Reserve blocks separately into a temporary list, so
383
* that we can free them if unsuccessful. We need to be
384
* able to reserve both 8- and 16-bit blocks as the
385
* offsets of them must match.
387
res = ops->lay_2d(TILFMT_8BIT, n_s, w, h, band_8, a, o,
389
res2 = ops->lay_2d(TILFMT_16BIT, n_s, (w + 1) >> 1, h,
390
band_16, a >> 1, o >> 1, gi, &reserved);
392
if (res2 < 0 || res < 0 || res != res2) {
394
ops->release(&reserved);
397
/* add list to reserved */
398
ops->add_reserved(&reserved, gi);
402
/* if separate packing failed, still try to pack together */
403
if (res < 0 && ops->nv12_packed && n_t) {
405
res = ops->lay_nv12(n_t, area_t, w, h, gi, packing);
412
/* initialize shared method pointers and global static variables */
413
void tiler_nv12_init(struct tiler_ops *tiler)
417
ops->reserve_nv12 = reserve_nv12;
419
band_8 = PAGE_SIZE / ops->geom(TILFMT_8BIT)->slot_w
420
/ ops->geom(TILFMT_8BIT)->bpp;
421
band_16 = PAGE_SIZE / ops->geom(TILFMT_16BIT)->slot_w
422
/ ops->geom(TILFMT_16BIT)->bpp;