162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * TILER container manager specification and support functions for TI 362306a36Sopenharmony_ci * TILER driver. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Lajos Molnar <molnar@ti.com> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * All rights reserved. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 1062306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 1162306a36Sopenharmony_ci * are met: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * * Redistributions of source code must retain the above copyright 1462306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 1762306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 1862306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * * Neither the name of Texas Instruments Incorporated nor the names of 2162306a36Sopenharmony_ci * its contributors may be used to endorse or promote products derived 2262306a36Sopenharmony_ci * from this software without specific prior written permission. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2562306a36Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 2662306a36Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2762306a36Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 2862306a36Sopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 2962306a36Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 3062306a36Sopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 3162306a36Sopenharmony_ci * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 3262306a36Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 3362306a36Sopenharmony_ci * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 3462306a36Sopenharmony_ci * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#ifndef TCM_H 3862306a36Sopenharmony_ci#define TCM_H 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistruct tcm; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* point */ 4362306a36Sopenharmony_cistruct tcm_pt { 4462306a36Sopenharmony_ci u16 x; 4562306a36Sopenharmony_ci u16 y; 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* 1d or 2d area */ 4962306a36Sopenharmony_cistruct tcm_area { 5062306a36Sopenharmony_ci bool is2d; /* whether area is 1d or 2d */ 5162306a36Sopenharmony_ci struct tcm *tcm; /* parent */ 5262306a36Sopenharmony_ci struct tcm_pt p0; 5362306a36Sopenharmony_ci struct tcm_pt p1; 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistruct tcm { 5762306a36Sopenharmony_ci u16 width, height; /* container dimensions */ 5862306a36Sopenharmony_ci int lut_id; /* Lookup table identifier */ 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci unsigned int y_offset; /* offset to use for y coordinates */ 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci spinlock_t lock; 6362306a36Sopenharmony_ci unsigned long *bitmap; 6462306a36Sopenharmony_ci size_t map_size; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* function table */ 6762306a36Sopenharmony_ci s32 (*reserve_2d)(struct tcm *tcm, u16 height, u16 width, u16 align, 6862306a36Sopenharmony_ci s16 offset, u16 slot_bytes, 6962306a36Sopenharmony_ci struct tcm_area *area); 7062306a36Sopenharmony_ci s32 (*reserve_1d)(struct tcm *tcm, u32 slots, struct tcm_area *area); 7162306a36Sopenharmony_ci s32 (*free)(struct tcm *tcm, struct tcm_area *area); 7262306a36Sopenharmony_ci void (*deinit)(struct tcm *tcm); 7362306a36Sopenharmony_ci}; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/*============================================================================= 7662306a36Sopenharmony_ci BASIC TILER CONTAINER MANAGER INTERFACE 7762306a36Sopenharmony_ci=============================================================================*/ 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* 8062306a36Sopenharmony_ci * NOTE: 8162306a36Sopenharmony_ci * 8262306a36Sopenharmony_ci * Since some basic parameter checking is done outside the TCM algorithms, 8362306a36Sopenharmony_ci * TCM implementation do NOT have to check the following: 8462306a36Sopenharmony_ci * 8562306a36Sopenharmony_ci * area pointer is NULL 8662306a36Sopenharmony_ci * width and height fits within container 8762306a36Sopenharmony_ci * number of pages is more than the size of the container 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistruct tcm *sita_init(u16 width, u16 height); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/** 9562306a36Sopenharmony_ci * Deinitialize tiler container manager. 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * @param tcm Pointer to container manager. 9862306a36Sopenharmony_ci * 9962306a36Sopenharmony_ci * @return 0 on success, non-0 error value on error. The call 10062306a36Sopenharmony_ci * should free as much memory as possible and meaningful 10162306a36Sopenharmony_ci * even on failure. Some error codes: -ENODEV: invalid 10262306a36Sopenharmony_ci * manager. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_cistatic inline void tcm_deinit(struct tcm *tcm) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci if (tcm) 10762306a36Sopenharmony_ci tcm->deinit(tcm); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/** 11162306a36Sopenharmony_ci * Reserves a 2D area in the container. 11262306a36Sopenharmony_ci * 11362306a36Sopenharmony_ci * @param tcm Pointer to container manager. 11462306a36Sopenharmony_ci * @param height Height(in pages) of area to be reserved. 11562306a36Sopenharmony_ci * @param width Width(in pages) of area to be reserved. 11662306a36Sopenharmony_ci * @param align Alignment requirement for top-left corner of area. Not 11762306a36Sopenharmony_ci * all values may be supported by the container manager, 11862306a36Sopenharmony_ci * but it must support 0 (1), 32 and 64. 11962306a36Sopenharmony_ci * 0 value is equivalent to 1. 12062306a36Sopenharmony_ci * @param offset Offset requirement, in bytes. This is the offset 12162306a36Sopenharmony_ci * from a 4KiB aligned virtual address. 12262306a36Sopenharmony_ci * @param slot_bytes Width of slot in bytes 12362306a36Sopenharmony_ci * @param area Pointer to where the reserved area should be stored. 12462306a36Sopenharmony_ci * 12562306a36Sopenharmony_ci * @return 0 on success. Non-0 error code on failure. Also, 12662306a36Sopenharmony_ci * the tcm field of the area will be set to NULL on 12762306a36Sopenharmony_ci * failure. Some error codes: -ENODEV: invalid manager, 12862306a36Sopenharmony_ci * -EINVAL: invalid area, -ENOMEM: not enough space for 12962306a36Sopenharmony_ci * allocation. 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_cistatic inline s32 tcm_reserve_2d(struct tcm *tcm, u16 width, u16 height, 13262306a36Sopenharmony_ci u16 align, s16 offset, u16 slot_bytes, 13362306a36Sopenharmony_ci struct tcm_area *area) 13462306a36Sopenharmony_ci{ 13562306a36Sopenharmony_ci /* perform rudimentary error checking */ 13662306a36Sopenharmony_ci s32 res = tcm == NULL ? -ENODEV : 13762306a36Sopenharmony_ci (area == NULL || width == 0 || height == 0 || 13862306a36Sopenharmony_ci /* align must be a 2 power */ 13962306a36Sopenharmony_ci (align & (align - 1))) ? -EINVAL : 14062306a36Sopenharmony_ci (height > tcm->height || width > tcm->width) ? -ENOMEM : 0; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (!res) { 14362306a36Sopenharmony_ci area->is2d = true; 14462306a36Sopenharmony_ci res = tcm->reserve_2d(tcm, height, width, align, offset, 14562306a36Sopenharmony_ci slot_bytes, area); 14662306a36Sopenharmony_ci area->tcm = res ? NULL : tcm; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return res; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/** 15362306a36Sopenharmony_ci * Reserves a 1D area in the container. 15462306a36Sopenharmony_ci * 15562306a36Sopenharmony_ci * @param tcm Pointer to container manager. 15662306a36Sopenharmony_ci * @param slots Number of (contiguous) slots to reserve. 15762306a36Sopenharmony_ci * @param area Pointer to where the reserved area should be stored. 15862306a36Sopenharmony_ci * 15962306a36Sopenharmony_ci * @return 0 on success. Non-0 error code on failure. Also, 16062306a36Sopenharmony_ci * the tcm field of the area will be set to NULL on 16162306a36Sopenharmony_ci * failure. Some error codes: -ENODEV: invalid manager, 16262306a36Sopenharmony_ci * -EINVAL: invalid area, -ENOMEM: not enough space for 16362306a36Sopenharmony_ci * allocation. 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_cistatic inline s32 tcm_reserve_1d(struct tcm *tcm, u32 slots, 16662306a36Sopenharmony_ci struct tcm_area *area) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci /* perform rudimentary error checking */ 16962306a36Sopenharmony_ci s32 res = tcm == NULL ? -ENODEV : 17062306a36Sopenharmony_ci (area == NULL || slots == 0) ? -EINVAL : 17162306a36Sopenharmony_ci slots > (tcm->width * (u32) tcm->height) ? -ENOMEM : 0; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (!res) { 17462306a36Sopenharmony_ci area->is2d = false; 17562306a36Sopenharmony_ci res = tcm->reserve_1d(tcm, slots, area); 17662306a36Sopenharmony_ci area->tcm = res ? NULL : tcm; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return res; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/** 18362306a36Sopenharmony_ci * Free a previously reserved area from the container. 18462306a36Sopenharmony_ci * 18562306a36Sopenharmony_ci * @param area Pointer to area reserved by a prior call to 18662306a36Sopenharmony_ci * tcm_reserve_1d or tcm_reserve_2d call, whether 18762306a36Sopenharmony_ci * it was successful or not. (Note: all fields of 18862306a36Sopenharmony_ci * the structure must match.) 18962306a36Sopenharmony_ci * 19062306a36Sopenharmony_ci * @return 0 on success. Non-0 error code on failure. Also, the tcm 19162306a36Sopenharmony_ci * field of the area is set to NULL on success to avoid subsequent 19262306a36Sopenharmony_ci * freeing. This call will succeed even if supplying 19362306a36Sopenharmony_ci * the area from a failed reserved call. 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_cistatic inline s32 tcm_free(struct tcm_area *area) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci s32 res = 0; /* free succeeds by default */ 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (area && area->tcm) { 20062306a36Sopenharmony_ci res = area->tcm->free(area->tcm, area); 20162306a36Sopenharmony_ci if (res == 0) 20262306a36Sopenharmony_ci area->tcm = NULL; 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return res; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci/*============================================================================= 20962306a36Sopenharmony_ci HELPER FUNCTION FOR ANY TILER CONTAINER MANAGER 21062306a36Sopenharmony_ci=============================================================================*/ 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/** 21362306a36Sopenharmony_ci * This method slices off the topmost 2D slice from the parent area, and stores 21462306a36Sopenharmony_ci * it in the 'slice' parameter. The 'parent' parameter will get modified to 21562306a36Sopenharmony_ci * contain the remaining portion of the area. If the whole parent area can 21662306a36Sopenharmony_ci * fit in a 2D slice, its tcm pointer is set to NULL to mark that it is no 21762306a36Sopenharmony_ci * longer a valid area. 21862306a36Sopenharmony_ci * 21962306a36Sopenharmony_ci * @param parent Pointer to a VALID parent area that will get modified 22062306a36Sopenharmony_ci * @param slice Pointer to the slice area that will get modified 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_cistatic inline void tcm_slice(struct tcm_area *parent, struct tcm_area *slice) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci *slice = *parent; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* check if we need to slice */ 22762306a36Sopenharmony_ci if (slice->tcm && !slice->is2d && 22862306a36Sopenharmony_ci slice->p0.y != slice->p1.y && 22962306a36Sopenharmony_ci (slice->p0.x || (slice->p1.x != slice->tcm->width - 1))) { 23062306a36Sopenharmony_ci /* set end point of slice (start always remains) */ 23162306a36Sopenharmony_ci slice->p1.x = slice->tcm->width - 1; 23262306a36Sopenharmony_ci slice->p1.y = (slice->p0.x) ? slice->p0.y : slice->p1.y - 1; 23362306a36Sopenharmony_ci /* adjust remaining area */ 23462306a36Sopenharmony_ci parent->p0.x = 0; 23562306a36Sopenharmony_ci parent->p0.y = slice->p1.y + 1; 23662306a36Sopenharmony_ci } else { 23762306a36Sopenharmony_ci /* mark this as the last slice */ 23862306a36Sopenharmony_ci parent->tcm = NULL; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* Verify if a tcm area is logically valid */ 24362306a36Sopenharmony_cistatic inline bool tcm_area_is_valid(struct tcm_area *area) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci return area && area->tcm && 24662306a36Sopenharmony_ci /* coordinate bounds */ 24762306a36Sopenharmony_ci area->p1.x < area->tcm->width && 24862306a36Sopenharmony_ci area->p1.y < area->tcm->height && 24962306a36Sopenharmony_ci area->p0.y <= area->p1.y && 25062306a36Sopenharmony_ci /* 1D coordinate relationship + p0.x check */ 25162306a36Sopenharmony_ci ((!area->is2d && 25262306a36Sopenharmony_ci area->p0.x < area->tcm->width && 25362306a36Sopenharmony_ci area->p0.x + area->p0.y * area->tcm->width <= 25462306a36Sopenharmony_ci area->p1.x + area->p1.y * area->tcm->width) || 25562306a36Sopenharmony_ci /* 2D coordinate relationship */ 25662306a36Sopenharmony_ci (area->is2d && 25762306a36Sopenharmony_ci area->p0.x <= area->p1.x)); 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci/* see if a coordinate is within an area */ 26162306a36Sopenharmony_cistatic inline bool __tcm_is_in(struct tcm_pt *p, struct tcm_area *a) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci u16 i; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (a->is2d) { 26662306a36Sopenharmony_ci return p->x >= a->p0.x && p->x <= a->p1.x && 26762306a36Sopenharmony_ci p->y >= a->p0.y && p->y <= a->p1.y; 26862306a36Sopenharmony_ci } else { 26962306a36Sopenharmony_ci i = p->x + p->y * a->tcm->width; 27062306a36Sopenharmony_ci return i >= a->p0.x + a->p0.y * a->tcm->width && 27162306a36Sopenharmony_ci i <= a->p1.x + a->p1.y * a->tcm->width; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci/* calculate area width */ 27662306a36Sopenharmony_cistatic inline u16 __tcm_area_width(struct tcm_area *area) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci return area->p1.x - area->p0.x + 1; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci/* calculate area height */ 28262306a36Sopenharmony_cistatic inline u16 __tcm_area_height(struct tcm_area *area) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci return area->p1.y - area->p0.y + 1; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci/* calculate number of slots in an area */ 28862306a36Sopenharmony_cistatic inline u16 __tcm_sizeof(struct tcm_area *area) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci return area->is2d ? 29162306a36Sopenharmony_ci __tcm_area_width(area) * __tcm_area_height(area) : 29262306a36Sopenharmony_ci (area->p1.x - area->p0.x + 1) + (area->p1.y - area->p0.y) * 29362306a36Sopenharmony_ci area->tcm->width; 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci#define tcm_sizeof(area) __tcm_sizeof(&(area)) 29662306a36Sopenharmony_ci#define tcm_awidth(area) __tcm_area_width(&(area)) 29762306a36Sopenharmony_ci#define tcm_aheight(area) __tcm_area_height(&(area)) 29862306a36Sopenharmony_ci#define tcm_is_in(pt, area) __tcm_is_in(&(pt), &(area)) 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/* limit a 1D area to the first N pages */ 30162306a36Sopenharmony_cistatic inline s32 tcm_1d_limit(struct tcm_area *a, u32 num_pg) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci if (__tcm_sizeof(a) < num_pg) 30462306a36Sopenharmony_ci return -ENOMEM; 30562306a36Sopenharmony_ci if (!num_pg) 30662306a36Sopenharmony_ci return -EINVAL; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci a->p1.x = (a->p0.x + num_pg - 1) % a->tcm->width; 30962306a36Sopenharmony_ci a->p1.y = a->p0.y + ((a->p0.x + num_pg - 1) / a->tcm->width); 31062306a36Sopenharmony_ci return 0; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci/** 31462306a36Sopenharmony_ci * Iterate through 2D slices of a valid area. Behaves 31562306a36Sopenharmony_ci * syntactically as a for(;;) statement. 31662306a36Sopenharmony_ci * 31762306a36Sopenharmony_ci * @param var Name of a local variable of type 'struct 31862306a36Sopenharmony_ci * tcm_area *' that will get modified to 31962306a36Sopenharmony_ci * contain each slice. 32062306a36Sopenharmony_ci * @param area Pointer to the VALID parent area. This 32162306a36Sopenharmony_ci * structure will not get modified 32262306a36Sopenharmony_ci * throughout the loop. 32362306a36Sopenharmony_ci * 32462306a36Sopenharmony_ci */ 32562306a36Sopenharmony_ci#define tcm_for_each_slice(var, area, safe) \ 32662306a36Sopenharmony_ci for (safe = area, \ 32762306a36Sopenharmony_ci tcm_slice(&safe, &var); \ 32862306a36Sopenharmony_ci var.tcm; tcm_slice(&safe, &var)) 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci#endif 331