linux/drivers/gpu/drm/omapdrm/tcm.h
<<
>>
Prefs
   1/*
   2 * TILER container manager specification and support functions for TI
   3 * TILER driver.
   4 *
   5 * Author: Lajos Molnar <molnar@ti.com>
   6 *
   7 * All rights reserved.
   8 *
   9 * Redistribution and use in source and binary forms, with or without
  10 * modification, are permitted provided that the following conditions
  11 * are met:
  12 *
  13 * * Redistributions of source code must retain the above copyright
  14 *   notice, this list of conditions and the following disclaimer.
  15 *
  16 * * Redistributions in binary form must reproduce the above copyright
  17 *   notice, this list of conditions and the following disclaimer in the
  18 *   documentation and/or other materials provided with the distribution.
  19 *
  20 * * Neither the name of Texas Instruments Incorporated nor the names of
  21 *   its contributors may be used to endorse or promote products derived
  22 *   from this software without specific prior written permission.
  23 *
  24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  26 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  29 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  30 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  31 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  33 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  34 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  35 */
  36
  37#ifndef TCM_H
  38#define TCM_H
  39
  40struct tcm;
  41
  42/* point */
  43struct tcm_pt {
  44        u16 x;
  45        u16 y;
  46};
  47
  48/* 1d or 2d area */
  49struct tcm_area {
  50        bool is2d;              /* whether area is 1d or 2d */
  51        struct tcm    *tcm;     /* parent */
  52        struct tcm_pt  p0;
  53        struct tcm_pt  p1;
  54};
  55
  56struct tcm {
  57        u16 width, height;      /* container dimensions */
  58        int lut_id;             /* Lookup table identifier */
  59
  60        unsigned int y_offset;  /* offset to use for y coordinates */
  61
  62        spinlock_t lock;
  63        unsigned long *bitmap;
  64        size_t map_size;
  65
  66        /* function table */
  67        s32 (*reserve_2d)(struct tcm *tcm, u16 height, u16 width, u16 align,
  68                          s16 offset, u16 slot_bytes,
  69                          struct tcm_area *area);
  70        s32 (*reserve_1d)(struct tcm *tcm, u32 slots, struct tcm_area *area);
  71        s32 (*free)(struct tcm *tcm, struct tcm_area *area);
  72        void (*deinit)(struct tcm *tcm);
  73};
  74
  75/*=============================================================================
  76    BASIC TILER CONTAINER MANAGER INTERFACE
  77=============================================================================*/
  78
  79/*
  80 * NOTE:
  81 *
  82 * Since some basic parameter checking is done outside the TCM algorithms,
  83 * TCM implementation do NOT have to check the following:
  84 *
  85 *   area pointer is NULL
  86 *   width and height fits within container
  87 *   number of pages is more than the size of the container
  88 *
  89 */
  90
  91struct tcm *sita_init(u16 width, u16 height);
  92
  93
  94/**
  95 * Deinitialize tiler container manager.
  96 *
  97 * @param tcm   Pointer to container manager.
  98 *
  99 * @return 0 on success, non-0 error value on error.  The call
 100 *         should free as much memory as possible and meaningful
 101 *         even on failure.  Some error codes: -ENODEV: invalid
 102 *         manager.
 103 */
 104static inline void tcm_deinit(struct tcm *tcm)
 105{
 106        if (tcm)
 107                tcm->deinit(tcm);
 108}
 109
 110/**
 111 * Reserves a 2D area in the container.
 112 *
 113 * @param tcm           Pointer to container manager.
 114 * @param height        Height(in pages) of area to be reserved.
 115 * @param width         Width(in pages) of area to be reserved.
 116 * @param align         Alignment requirement for top-left corner of area. Not
 117 *                      all values may be supported by the container manager,
 118 *                      but it must support 0 (1), 32 and 64.
 119 *                      0 value is equivalent to 1.
 120 * @param offset        Offset requirement, in bytes.  This is the offset
 121 *                      from a 4KiB aligned virtual address.
 122 * @param slot_bytes    Width of slot in bytes
 123 * @param area          Pointer to where the reserved area should be stored.
 124 *
 125 * @return 0 on success.  Non-0 error code on failure.  Also,
 126 *         the tcm field of the area will be set to NULL on
 127 *         failure.  Some error codes: -ENODEV: invalid manager,
 128 *         -EINVAL: invalid area, -ENOMEM: not enough space for
 129 *          allocation.
 130 */
 131static inline s32 tcm_reserve_2d(struct tcm *tcm, u16 width, u16 height,
 132                                u16 align, s16 offset, u16 slot_bytes,
 133                                struct tcm_area *area)
 134{
 135        /* perform rudimentary error checking */
 136        s32 res = tcm  == NULL ? -ENODEV :
 137                (area == NULL || width == 0 || height == 0 ||
 138                 /* align must be a 2 power */
 139                 (align & (align - 1))) ? -EINVAL :
 140                (height > tcm->height || width > tcm->width) ? -ENOMEM : 0;
 141
 142        if (!res) {
 143                area->is2d = true;
 144                res = tcm->reserve_2d(tcm, height, width, align, offset,
 145                                        slot_bytes, area);
 146                area->tcm = res ? NULL : tcm;
 147        }
 148
 149        return res;
 150}
 151
 152/**
 153 * Reserves a 1D area in the container.
 154 *
 155 * @param tcm           Pointer to container manager.
 156 * @param slots         Number of (contiguous) slots to reserve.
 157 * @param area          Pointer to where the reserved area should be stored.
 158 *
 159 * @return 0 on success.  Non-0 error code on failure.  Also,
 160 *         the tcm field of the area will be set to NULL on
 161 *         failure.  Some error codes: -ENODEV: invalid manager,
 162 *         -EINVAL: invalid area, -ENOMEM: not enough space for
 163 *          allocation.
 164 */
 165static inline s32 tcm_reserve_1d(struct tcm *tcm, u32 slots,
 166                                 struct tcm_area *area)
 167{
 168        /* perform rudimentary error checking */
 169        s32 res = tcm  == NULL ? -ENODEV :
 170                (area == NULL || slots == 0) ? -EINVAL :
 171                slots > (tcm->width * (u32) tcm->height) ? -ENOMEM : 0;
 172
 173        if (!res) {
 174                area->is2d = false;
 175                res = tcm->reserve_1d(tcm, slots, area);
 176                area->tcm = res ? NULL : tcm;
 177        }
 178
 179        return res;
 180}
 181
 182/**
 183 * Free a previously reserved area from the container.
 184 *
 185 * @param area  Pointer to area reserved by a prior call to
 186 *              tcm_reserve_1d or tcm_reserve_2d call, whether
 187 *              it was successful or not. (Note: all fields of
 188 *              the structure must match.)
 189 *
 190 * @return 0 on success.  Non-0 error code on failure.  Also, the tcm
 191 *         field of the area is set to NULL on success to avoid subsequent
 192 *         freeing.  This call will succeed even if supplying
 193 *         the area from a failed reserved call.
 194 */
 195static inline s32 tcm_free(struct tcm_area *area)
 196{
 197        s32 res = 0; /* free succeeds by default */
 198
 199        if (area && area->tcm) {
 200                res = area->tcm->free(area->tcm, area);
 201                if (res == 0)
 202                        area->tcm = NULL;
 203        }
 204
 205        return res;
 206}
 207
 208/*=============================================================================
 209    HELPER FUNCTION FOR ANY TILER CONTAINER MANAGER
 210=============================================================================*/
 211
 212/**
 213 * This method slices off the topmost 2D slice from the parent area, and stores
 214 * it in the 'slice' parameter.  The 'parent' parameter will get modified to
 215 * contain the remaining portion of the area.  If the whole parent area can
 216 * fit in a 2D slice, its tcm pointer is set to NULL to mark that it is no
 217 * longer a valid area.
 218 *
 219 * @param parent        Pointer to a VALID parent area that will get modified
 220 * @param slice         Pointer to the slice area that will get modified
 221 */
 222static inline void tcm_slice(struct tcm_area *parent, struct tcm_area *slice)
 223{
 224        *slice = *parent;
 225
 226        /* check if we need to slice */
 227        if (slice->tcm && !slice->is2d &&
 228                slice->p0.y != slice->p1.y &&
 229                (slice->p0.x || (slice->p1.x != slice->tcm->width - 1))) {
 230                /* set end point of slice (start always remains) */
 231                slice->p1.x = slice->tcm->width - 1;
 232                slice->p1.y = (slice->p0.x) ? slice->p0.y : slice->p1.y - 1;
 233                /* adjust remaining area */
 234                parent->p0.x = 0;
 235                parent->p0.y = slice->p1.y + 1;
 236        } else {
 237                /* mark this as the last slice */
 238                parent->tcm = NULL;
 239        }
 240}
 241
 242/* Verify if a tcm area is logically valid */
 243static inline bool tcm_area_is_valid(struct tcm_area *area)
 244{
 245        return area && area->tcm &&
 246                /* coordinate bounds */
 247                area->p1.x < area->tcm->width &&
 248                area->p1.y < area->tcm->height &&
 249                area->p0.y <= area->p1.y &&
 250                /* 1D coordinate relationship + p0.x check */
 251                ((!area->is2d &&
 252                  area->p0.x < area->tcm->width &&
 253                  area->p0.x + area->p0.y * area->tcm->width <=
 254                  area->p1.x + area->p1.y * area->tcm->width) ||
 255                 /* 2D coordinate relationship */
 256                 (area->is2d &&
 257                  area->p0.x <= area->p1.x));
 258}
 259
 260/* see if a coordinate is within an area */
 261static inline bool __tcm_is_in(struct tcm_pt *p, struct tcm_area *a)
 262{
 263        u16 i;
 264
 265        if (a->is2d) {
 266                return p->x >= a->p0.x && p->x <= a->p1.x &&
 267                       p->y >= a->p0.y && p->y <= a->p1.y;
 268        } else {
 269                i = p->x + p->y * a->tcm->width;
 270                return i >= a->p0.x + a->p0.y * a->tcm->width &&
 271                       i <= a->p1.x + a->p1.y * a->tcm->width;
 272        }
 273}
 274
 275/* calculate area width */
 276static inline u16 __tcm_area_width(struct tcm_area *area)
 277{
 278        return area->p1.x - area->p0.x + 1;
 279}
 280
 281/* calculate area height */
 282static inline u16 __tcm_area_height(struct tcm_area *area)
 283{
 284        return area->p1.y - area->p0.y + 1;
 285}
 286
 287/* calculate number of slots in an area */
 288static inline u16 __tcm_sizeof(struct tcm_area *area)
 289{
 290        return area->is2d ?
 291                __tcm_area_width(area) * __tcm_area_height(area) :
 292                (area->p1.x - area->p0.x + 1) + (area->p1.y - area->p0.y) *
 293                                                        area->tcm->width;
 294}
 295#define tcm_sizeof(area) __tcm_sizeof(&(area))
 296#define tcm_awidth(area) __tcm_area_width(&(area))
 297#define tcm_aheight(area) __tcm_area_height(&(area))
 298#define tcm_is_in(pt, area) __tcm_is_in(&(pt), &(area))
 299
 300/* limit a 1D area to the first N pages */
 301static inline s32 tcm_1d_limit(struct tcm_area *a, u32 num_pg)
 302{
 303        if (__tcm_sizeof(a) < num_pg)
 304                return -ENOMEM;
 305        if (!num_pg)
 306                return -EINVAL;
 307
 308        a->p1.x = (a->p0.x + num_pg - 1) % a->tcm->width;
 309        a->p1.y = a->p0.y + ((a->p0.x + num_pg - 1) / a->tcm->width);
 310        return 0;
 311}
 312
 313/**
 314 * Iterate through 2D slices of a valid area. Behaves
 315 * syntactically as a for(;;) statement.
 316 *
 317 * @param var           Name of a local variable of type 'struct
 318 *                      tcm_area *' that will get modified to
 319 *                      contain each slice.
 320 * @param area          Pointer to the VALID parent area. This
 321 *                      structure will not get modified
 322 *                      throughout the loop.
 323 *
 324 */
 325#define tcm_for_each_slice(var, area, safe) \
 326        for (safe = area, \
 327             tcm_slice(&safe, &var); \
 328             var.tcm; tcm_slice(&safe, &var))
 329
 330#endif
 331