Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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