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