1/*-
2*******************************************************************************
3Copyright (C) 2015 Annapurna Labs Ltd.
4
5This file may be licensed under the terms of the Annapurna Labs Commercial
6License Agreement.
7
8Alternatively, this file can be distributed under the terms of the GNU General
9Public License V2 as published by the Free Software Foundation and can be
10found at http://www.gnu.org/licenses/gpl-2.0.html
11
12Alternatively, redistribution and use in source and binary forms, with or
13without modification, are permitted provided that the following conditions are
14met:
15
16    *     Redistributions of source code must retain the above copyright notice,
17this list of conditions and the following disclaimer.
18
19    *     Redistributions in binary form must reproduce the above copyright
20notice, this list of conditions and the following disclaimer in
21the documentation and/or other materials provided with the
22distribution.
23
24THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
28ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
35*******************************************************************************/
36
37/**
38 * @defgroup group_services Platform Services API
39 *  @{
40 * The Platform Services API provides miscellaneous system services to HAL
41 * drivers, such as:
42 * - Registers read/write
43 * - Assertions
44 * - Memory barriers
45 * - Endianness conversions
46 *
47 * And more.
48 * @file   plat_api/sample/al_hal_plat_services.h
49 *
50 * @brief  API for Platform services provided for to HAL drivers
51 *
52 *
53 */
54
55#ifndef __PLAT_SERVICES_H__
56#define __PLAT_SERVICES_H__
57
58#include <machine/atomic.h>
59#include <sys/cdefs.h>
60__FBSDID("$FreeBSD$");
61
62#include <sys/param.h>
63#include <sys/systm.h>
64#include <sys/kernel.h>
65#include <sys/endian.h>
66#include <sys/errno.h>
67#include <sys/lock.h>
68#include <sys/mutex.h>
69
70/* Prototypes for all the bus_space structure functions */
71bs_protos(generic);
72bs_protos(generic_armv4);
73
74#define __UNUSED __attribute__((unused))
75
76/* *INDENT-OFF* */
77#ifdef __cplusplus
78extern "C" {
79#endif
80/* *INDENT-ON* */
81
82/*
83 * WMA: This is a hack which allows not modifying the __iomem accessing HAL code.
84 * On ARMv7, bus_handle holds the information about VA of accessed memory. It
85 * is possible to use direct load/store instruction instead of bus_dma machinery.
86 * WARNING: This is not guaranteed to stay that way forever, nor that
87 * on other architectures these variables behave similarly. Keep that
88 * in mind during porting to other systems.
89 */
90/**
91 * Read MMIO 8 bits register
92 * @param  offset	register offset
93 *
94 * @return register value
95 */
96static uint8_t al_reg_read8(uint8_t * offset);
97
98/**
99 * Read MMIO 16 bits register
100 * @param  offset	register offset
101 *
102 * @return register value
103 */
104static uint16_t al_reg_read16(uint16_t * offset);
105
106/**
107 * Read MMIO 32 bits register
108 * @param  offset	register offset
109 *
110 * @return register value
111 */
112static uint32_t al_reg_read32(uint32_t * offset);
113
114/**
115 * Read MMIO 64 bits register
116 * @param  offset	register offset
117 *
118 * @return register value
119 */
120uint64_t al_reg_read64(uint64_t * offset);
121
122/**
123 * Relaxed read MMIO 32 bits register
124 *
125 * Relaxed register read/write functions don't involve cpu instructions that
126 * force syncronization, nor ordering between the register access and memory
127 * data access.
128 * These instructions are used in performance critical code to avoid the
129 * overhead of the synchronization instructions.
130 *
131 * @param  offset	register offset
132 *
133 * @return register value
134 */
135#define al_bus_dma_to_va(bus_tag, bus_handle)	((void*)bus_handle)
136
137/**
138 * Relaxed read MMIO 32 bits register
139 *
140 * Relaxed register read/write functions don't involve cpu instructions that
141 * force syncronization, nor ordering between the register access and memory
142 * data access.
143 * These instructions are used in performance critical code to avoid the
144 * overhead of the synchronization instructions.
145 *
146 * @param  offset	register offset
147 *
148 * @return register value
149 */
150#define al_reg_read32_relaxed(l)	generic_bs_r_4(NULL, (bus_space_handle_t)l, 0)
151
152/**
153 * Relaxed write to MMIO 32 bits register
154 *
155 * Relaxed register read/write functions don't involve cpu instructions that
156 * force syncronization, nor ordering between the register access and memory
157 * data access.
158 * These instructions are used in performance critical code to avoid the
159 * overhead of the synchronization instructions.
160 *
161 * @param  offset	register offset
162 * @param  val		value to write to the register
163 */
164#define al_reg_write32_relaxed(l,v)	generic_bs_w_4(NULL, (bus_space_handle_t)l, 0, v)
165
166/**
167 * Write to MMIO 8 bits register
168 * @param  offset	register offset
169 * @param  val		value to write to the register
170 */
171#define al_reg_write8(l,v)	do { dsb(); generic_bs_w_1(NULL, (bus_space_handle_t)l, 0, v); dmb(); } while (0)
172
173/**
174 * Write to MMIO 16 bits register
175 * @param  offset	register offset
176 * @param  val		value to write to the register
177 */
178#define al_reg_write16(l,v)	do { dsb(); generic_bs_w_2(NULL, (bus_space_handle_t)l, 0, v); dmb(); } while (0)
179
180/**
181 * Write to MMIO 32 bits register
182 * @param  offset	register offset
183 * @param  val		value to write to the register
184 */
185#define al_reg_write32(l,v)	do { dsb(); generic_bs_w_4(NULL, (bus_space_handle_t)l, 0, v); dmb(); } while (0)
186
187/**
188 * Write to MMIO 64 bits register
189 * @param  offset	register offset
190 * @param  val		value to write to the register
191 */
192#define al_reg_write64(l,v)	do { dsb(); generic_bs_w_8(NULL, (bus_space_handle_t)l, 0, v); dmb(); } while (0)
193
194static inline uint8_t
195al_reg_read8(uint8_t *l)
196{
197	dsb();
198
199	return (generic_bs_r_1(NULL, (bus_space_handle_t)l, 0));
200}
201
202static inline uint16_t
203al_reg_read16(uint16_t *l)
204{
205	dsb();
206
207	return (generic_bs_r_2(NULL, (bus_space_handle_t)l, 0));
208}
209
210static inline uint32_t
211al_reg_read32(uint32_t *l)
212{
213	dsb();
214
215	return (generic_bs_r_4(NULL, (bus_space_handle_t)l, 0));
216}
217
218#define AL_DBG_LEVEL_NONE 0
219#define AL_DBG_LEVEL_ERR 1
220#define AL_DBG_LEVEL_WARN 2
221#define AL_DBG_LEVEL_INFO 3
222#define AL_DBG_LEVEL_DBG 4
223
224#define AL_DBG_LEVEL AL_DBG_LEVEL_ERR
225
226extern struct mtx al_dbg_lock;
227
228#define AL_DBG_LOCK()	mtx_lock_spin(&al_dbg_lock)
229#define AL_DBG_UNLOCK()	mtx_unlock_spin(&al_dbg_lock)
230
231/**
232 * print message
233 *
234 * @param format The format string
235 * @param ... Additional arguments
236 */
237#define al_print(type, fmt, ...) 		do { if (AL_DBG_LEVEL >= AL_DBG_LEVEL_NONE) { AL_DBG_LOCK(); printf(fmt, ##__VA_ARGS__); AL_DBG_UNLOCK(); } } while(0)
238
239/**
240 * print error message
241 *
242 * @param format
243 */
244#define al_err(...)			do { if (AL_DBG_LEVEL >= AL_DBG_LEVEL_ERR) { AL_DBG_LOCK(); printf(__VA_ARGS__); AL_DBG_UNLOCK(); } } while(0)
245
246/**
247 * print warning message
248 *
249 * @param format
250 */
251#define al_warn(...)			do { if (AL_DBG_LEVEL >= AL_DBG_LEVEL_WARN) { AL_DBG_LOCK(); printf(__VA_ARGS__); AL_DBG_UNLOCK(); } } while(0)
252
253/**
254 * print info message
255 *
256 * @param format
257 */
258#define al_info(...)			do { if (AL_DBG_LEVEL >= AL_DBG_LEVEL_INFO) { AL_DBG_LOCK(); printf(__VA_ARGS__); AL_DBG_UNLOCK(); } } while(0)
259
260/**
261 * print debug message
262 *
263 * @param format
264 */
265#define al_dbg(...)			do { if (AL_DBG_LEVEL >= AL_DBG_LEVEL_DBG) { AL_DBG_LOCK(); printf(__VA_ARGS__); AL_DBG_UNLOCK(); } } while(0)
266
267/**
268 * Assertion
269 *
270 * @param condition
271 */
272#define al_assert(COND)		\
273	do {			\
274		if (!(COND))	\
275			al_err(	\
276			"%s:%d:%s: Assertion failed! (%s)\n",	\
277			__FILE__, __LINE__, __func__, #COND);	\
278	} while(AL_FALSE)
279
280/**
281  * Make sure data will be visible by other masters (other CPUS and DMA).
282  * usually this is achieved by the ARM DMB instruction.
283  */
284static void al_data_memory_barrier(void);
285
286/**
287  * Make sure data will be visible by DMA masters, no restriction for other cpus
288  */
289static inline void
290al_data_memory_barrier(void)
291{
292	dsb();
293}
294
295/**
296  * Make sure data will be visible in order by other cpus masters.
297  */
298static inline void
299al_smp_data_memory_barrier(void)
300{
301	dsb();
302}
303
304/**
305  * Make sure write data will be visible in order by other cpus masters.
306  */
307static inline void
308al_local_data_memory_barrier(void)
309{
310	dsb();
311}
312
313/**
314 * al_udelay - micro sec delay
315 */
316#define al_udelay(u)		DELAY(u)
317
318/**
319 * al_msleep - mili sec delay
320 */
321#define al_msleep(m)		DELAY((m) * 1000)
322
323/**
324 * swap half word to little endian
325 *
326 * @param x 16 bit value
327 *
328 * @return the value in little endian
329 */
330#define swap16_to_le(x)		htole16(x)
331/**
332 * swap word to little endian
333 *
334 * @param x 32 bit value
335 *
336 * @return the value in little endian
337 */
338#define swap32_to_le(x)		htole32(x)
339
340/**
341 * swap 8 bytes to little endian
342 *
343 * @param x 64 bit value
344 *
345 * @return the value in little endian
346 */
347#define swap64_to_le(x)		htole64(x)
348
349/**
350 * swap half word from little endian
351 *
352 * @param x 16 bit value
353 *
354 * @return the value in the cpu endianess
355 */
356#define swap16_from_le(x)	le16toh(x)
357
358/**
359 * swap word from little endian
360 *
361 * @param x 32 bit value
362 *
363 * @return the value in the cpu endianess
364 */
365#define swap32_from_le(x)	le32toh(x)
366
367/**
368 * swap 8 bytes from little endian
369 *
370 * @param x 64 bit value
371 *
372 * @return the value in the cpu endianess
373 */
374#define swap64_from_le(x)	le64toh(x)
375
376/**
377 * Memory set
378 *
379 * @param p memory pointer
380 * @param val value for setting
381 * @param cnt number of bytes to set
382 */
383#define al_memset(p, val, cnt)	memset(p, val, cnt)
384
385/**
386 * Memory copy
387 *
388 * @param p1 memory pointer
389 * @param p2 memory pointer
390 * @param cnt number of bytes to copy
391 */
392#define al_memcpy(p1, p2, cnt)	memcpy(p1, p2, cnt)
393
394/**
395 * Memory compare
396 *
397 * @param p1 memory pointer
398 * @param p2 memory pointer
399 * @param cnt number of bytes to compare
400 */
401#define al_memcmp(p1, p2, cnt)	memcmp(p1, p2, cnt)
402
403/**
404 * String compare
405 *
406 * @param s1 string pointer
407 * @param s2 string pointer
408 */
409#define al_strcmp(s1, s2)	strcmp(s1, s2)
410
411#define al_get_cpu_id()		0
412
413/* *INDENT-OFF* */
414#ifdef __cplusplus
415}
416#endif
417/* *INDENT-ON* */
418/** @} end of Platform Services API group */
419#endif				/* __PLAT_SERVICES_H__ */
420