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