1285431Szbb/*-
2285431Szbb*******************************************************************************
3285431SzbbCopyright (C) 2015 Annapurna Labs Ltd.
4285431Szbb
5285431SzbbThis file may be licensed under the terms of the Annapurna Labs Commercial
6285431SzbbLicense Agreement.
7285431Szbb
8285431SzbbAlternatively, this file can be distributed under the terms of the GNU General
9285431SzbbPublic License V2 as published by the Free Software Foundation and can be
10285431Szbbfound at http://www.gnu.org/licenses/gpl-2.0.html
11285431Szbb
12285431SzbbAlternatively, redistribution and use in source and binary forms, with or
13285431Szbbwithout modification, are permitted provided that the following conditions are
14285431Szbbmet:
15285431Szbb
16285431Szbb    *     Redistributions of source code must retain the above copyright notice,
17285431Szbbthis list of conditions and the following disclaimer.
18285431Szbb
19285431Szbb    *     Redistributions in binary form must reproduce the above copyright
20285431Szbbnotice, this list of conditions and the following disclaimer in
21285431Szbbthe documentation and/or other materials provided with the
22285431Szbbdistribution.
23285431Szbb
24285431SzbbTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25285431SzbbANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26285431SzbbWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27285431SzbbDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
28285431SzbbANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29285431Szbb(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30285431SzbbLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31285431SzbbANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32285431Szbb(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33285431SzbbSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34285431Szbb
35285431Szbb*******************************************************************************/
36285431Szbb
37285431Szbb/**
38285431Szbb * @defgroup group_services Platform Services API
39285431Szbb *  @{
40285431Szbb * The Platform Services API provides miscellaneous system services to HAL
41285431Szbb * drivers, such as:
42285431Szbb * - Registers read/write
43285431Szbb * - Assertions
44285431Szbb * - Memory barriers
45285431Szbb * - Endianness conversions
46285431Szbb *
47285431Szbb * And more.
48285431Szbb * @file   plat_api/sample/al_hal_plat_services.h
49285431Szbb *
50285431Szbb * @brief  API for Platform services provided for to HAL drivers
51285431Szbb *
52285431Szbb *
53285431Szbb */
54285431Szbb
55285431Szbb#ifndef __PLAT_SERVICES_H__
56285431Szbb#define __PLAT_SERVICES_H__
57285431Szbb
58285431Szbb#include <machine/atomic.h>
59285431Szbb#include <sys/cdefs.h>
60285431Szbb__FBSDID("$FreeBSD$");
61285431Szbb
62285431Szbb#include <sys/param.h>
63285431Szbb#include <sys/systm.h>
64285431Szbb#include <sys/kernel.h>
65285431Szbb#include <sys/endian.h>
66285431Szbb#include <sys/errno.h>
67285431Szbb#include <sys/lock.h>
68285431Szbb#include <sys/mutex.h>
69285431Szbb
70285431Szbb/* Prototypes for all the bus_space structure functions */
71285431Szbbbs_protos(generic);
72285431Szbbbs_protos(generic_armv4);
73285431Szbb
74285431Szbb#define __UNUSED __attribute__((unused))
75285431Szbb
76285431Szbb/* *INDENT-OFF* */
77285431Szbb#ifdef __cplusplus
78285431Szbbextern "C" {
79285431Szbb#endif
80285431Szbb/* *INDENT-ON* */
81285431Szbb
82285431Szbb/*
83285431Szbb * WMA: This is a hack which allows not modifying the __iomem accessing HAL code.
84285431Szbb * On ARMv7, bus_handle holds the information about VA of accessed memory. It
85285431Szbb * is possible to use direct load/store instruction instead of bus_dma machinery.
86285431Szbb * WARNING: This is not guaranteed to stay that way forever, nor that
87285431Szbb * on other architectures these variables behave similarly. Keep that
88285431Szbb * in mind during porting to other systems.
89285431Szbb */
90285431Szbb/**
91285431Szbb * Read MMIO 8 bits register
92285431Szbb * @param  offset	register offset
93285431Szbb *
94285431Szbb * @return register value
95285431Szbb */
96285431Szbbstatic uint8_t al_reg_read8(uint8_t * offset);
97285431Szbb
98285431Szbb/**
99285431Szbb * Read MMIO 16 bits register
100285431Szbb * @param  offset	register offset
101285431Szbb *
102285431Szbb * @return register value
103285431Szbb */
104285431Szbbstatic uint16_t al_reg_read16(uint16_t * offset);
105285431Szbb
106285431Szbb/**
107285431Szbb * Read MMIO 32 bits register
108285431Szbb * @param  offset	register offset
109285431Szbb *
110285431Szbb * @return register value
111285431Szbb */
112285431Szbbstatic uint32_t al_reg_read32(uint32_t * offset);
113285431Szbb
114285431Szbb/**
115285431Szbb * Read MMIO 64 bits register
116285431Szbb * @param  offset	register offset
117285431Szbb *
118285431Szbb * @return register value
119285431Szbb */
120285431Szbbuint64_t al_reg_read64(uint64_t * offset);
121285431Szbb
122285431Szbb/**
123285431Szbb * Relaxed read MMIO 32 bits register
124285431Szbb *
125285431Szbb * Relaxed register read/write functions don't involve cpu instructions that
126285431Szbb * force syncronization, nor ordering between the register access and memory
127285431Szbb * data access.
128285431Szbb * These instructions are used in performance critical code to avoid the
129285431Szbb * overhead of the synchronization instructions.
130285431Szbb *
131285431Szbb * @param  offset	register offset
132285431Szbb *
133285431Szbb * @return register value
134285431Szbb */
135285431Szbb#define al_bus_dma_to_va(bus_tag, bus_handle)	((void*)bus_handle)
136285431Szbb
137285431Szbb/**
138285431Szbb * Relaxed read MMIO 32 bits register
139285431Szbb *
140285431Szbb * Relaxed register read/write functions don't involve cpu instructions that
141285431Szbb * force syncronization, nor ordering between the register access and memory
142285431Szbb * data access.
143285431Szbb * These instructions are used in performance critical code to avoid the
144285431Szbb * overhead of the synchronization instructions.
145285431Szbb *
146285431Szbb * @param  offset	register offset
147285431Szbb *
148285431Szbb * @return register value
149285431Szbb */
150285431Szbb#define al_reg_read32_relaxed(l)	generic_bs_r_4(NULL, (bus_space_handle_t)l, 0)
151285431Szbb
152285431Szbb/**
153285431Szbb * Relaxed write to MMIO 32 bits register
154285431Szbb *
155285431Szbb * Relaxed register read/write functions don't involve cpu instructions that
156285431Szbb * force syncronization, nor ordering between the register access and memory
157285431Szbb * data access.
158285431Szbb * These instructions are used in performance critical code to avoid the
159285431Szbb * overhead of the synchronization instructions.
160285431Szbb *
161285431Szbb * @param  offset	register offset
162285431Szbb * @param  val		value to write to the register
163285431Szbb */
164285431Szbb#define al_reg_write32_relaxed(l,v)	generic_bs_w_4(NULL, (bus_space_handle_t)l, 0, v)
165285431Szbb
166285431Szbb/**
167285431Szbb * Write to MMIO 8 bits register
168285431Szbb * @param  offset	register offset
169285431Szbb * @param  val		value to write to the register
170285431Szbb */
171285431Szbb#define al_reg_write8(l,v)	do { dsb(); generic_bs_w_1(NULL, (bus_space_handle_t)l, 0, v); dmb(); } while (0)
172285431Szbb
173285431Szbb/**
174285431Szbb * Write to MMIO 16 bits register
175285431Szbb * @param  offset	register offset
176285431Szbb * @param  val		value to write to the register
177285431Szbb */
178285431Szbb#define al_reg_write16(l,v)	do { dsb(); generic_bs_w_2(NULL, (bus_space_handle_t)l, 0, v); dmb(); } while (0)
179285431Szbb
180285431Szbb/**
181285431Szbb * Write to MMIO 32 bits register
182285431Szbb * @param  offset	register offset
183285431Szbb * @param  val		value to write to the register
184285431Szbb */
185285431Szbb#define al_reg_write32(l,v)	do { dsb(); generic_bs_w_4(NULL, (bus_space_handle_t)l, 0, v); dmb(); } while (0)
186285431Szbb
187285431Szbb/**
188285431Szbb * Write to MMIO 64 bits register
189285431Szbb * @param  offset	register offset
190285431Szbb * @param  val		value to write to the register
191285431Szbb */
192285431Szbb#define al_reg_write64(l,v)	do { dsb(); generic_bs_w_8(NULL, (bus_space_handle_t)l, 0, v); dmb(); } while (0)
193285431Szbb
194285431Szbbstatic inline uint8_t
195285431Szbbal_reg_read8(uint8_t *l)
196285431Szbb{
197285431Szbb	dsb();
198285431Szbb
199285431Szbb	return (generic_bs_r_1(NULL, (bus_space_handle_t)l, 0));
200285431Szbb}
201285431Szbb
202285431Szbbstatic inline uint16_t
203285431Szbbal_reg_read16(uint16_t *l)
204285431Szbb{
205285431Szbb	dsb();
206285431Szbb
207285431Szbb	return (generic_bs_r_2(NULL, (bus_space_handle_t)l, 0));
208285431Szbb}
209285431Szbb
210285431Szbbstatic inline uint32_t
211285431Szbbal_reg_read32(uint32_t *l)
212285431Szbb{
213285431Szbb	dsb();
214285431Szbb
215285431Szbb	return (generic_bs_r_4(NULL, (bus_space_handle_t)l, 0));
216285431Szbb}
217285431Szbb
218285431Szbb#define AL_DBG_LEVEL_NONE 0
219285431Szbb#define AL_DBG_LEVEL_ERR 1
220285431Szbb#define AL_DBG_LEVEL_WARN 2
221285431Szbb#define AL_DBG_LEVEL_INFO 3
222285431Szbb#define AL_DBG_LEVEL_DBG 4
223285431Szbb
224285431Szbb#define AL_DBG_LEVEL AL_DBG_LEVEL_ERR
225285431Szbb
226285431Szbbextern struct mtx al_dbg_lock;
227285431Szbb
228285431Szbb#define AL_DBG_LOCK()	mtx_lock_spin(&al_dbg_lock)
229285431Szbb#define AL_DBG_UNLOCK()	mtx_unlock_spin(&al_dbg_lock)
230285431Szbb
231285431Szbb/**
232285431Szbb * print message
233285431Szbb *
234285431Szbb * @param format The format string
235285431Szbb * @param ... Additional arguments
236285431Szbb */
237285431Szbb#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)
238285431Szbb
239285431Szbb/**
240285431Szbb * print error message
241285431Szbb *
242285431Szbb * @param format
243285431Szbb */
244285431Szbb#define al_err(...)			do { if (AL_DBG_LEVEL >= AL_DBG_LEVEL_ERR) { AL_DBG_LOCK(); printf(__VA_ARGS__); AL_DBG_UNLOCK(); } } while(0)
245285431Szbb
246285431Szbb/**
247285431Szbb * print warning message
248285431Szbb *
249285431Szbb * @param format
250285431Szbb */
251285431Szbb#define al_warn(...)			do { if (AL_DBG_LEVEL >= AL_DBG_LEVEL_WARN) { AL_DBG_LOCK(); printf(__VA_ARGS__); AL_DBG_UNLOCK(); } } while(0)
252285431Szbb
253285431Szbb/**
254285431Szbb * print info message
255285431Szbb *
256285431Szbb * @param format
257285431Szbb */
258285431Szbb#define al_info(...)			do { if (AL_DBG_LEVEL >= AL_DBG_LEVEL_INFO) { AL_DBG_LOCK(); printf(__VA_ARGS__); AL_DBG_UNLOCK(); } } while(0)
259285431Szbb
260285431Szbb/**
261285431Szbb * print debug message
262285431Szbb *
263285431Szbb * @param format
264285431Szbb */
265285431Szbb#define al_dbg(...)			do { if (AL_DBG_LEVEL >= AL_DBG_LEVEL_DBG) { AL_DBG_LOCK(); printf(__VA_ARGS__); AL_DBG_UNLOCK(); } } while(0)
266285431Szbb
267285431Szbb/**
268285431Szbb * Assertion
269285431Szbb *
270285431Szbb * @param condition
271285431Szbb */
272285431Szbb#define al_assert(COND)		\
273285431Szbb	do {			\
274285431Szbb		if (!(COND))	\
275285431Szbb			al_err(	\
276285431Szbb			"%s:%d:%s: Assertion failed! (%s)\n",	\
277285431Szbb			__FILE__, __LINE__, __func__, #COND);	\
278285431Szbb	} while(AL_FALSE)
279285431Szbb
280285431Szbb/**
281285431Szbb  * Make sure data will be visible by other masters (other CPUS and DMA).
282285431Szbb  * usually this is achieved by the ARM DMB instruction.
283285431Szbb  */
284285431Szbbstatic void al_data_memory_barrier(void);
285285431Szbb
286285431Szbb/**
287285431Szbb  * Make sure data will be visible by DMA masters, no restriction for other cpus
288285431Szbb  */
289285431Szbbstatic inline void
290285431Szbbal_data_memory_barrier(void)
291285431Szbb{
292285431Szbb	dsb();
293285431Szbb}
294285431Szbb
295285431Szbb/**
296285431Szbb  * Make sure data will be visible in order by other cpus masters.
297285431Szbb  */
298285431Szbbstatic inline void
299285431Szbbal_smp_data_memory_barrier(void)
300285431Szbb{
301285431Szbb	dsb();
302285431Szbb}
303285431Szbb
304285431Szbb/**
305285431Szbb  * Make sure write data will be visible in order by other cpus masters.
306285431Szbb  */
307285431Szbbstatic inline void
308285431Szbbal_local_data_memory_barrier(void)
309285431Szbb{
310285431Szbb	dsb();
311285431Szbb}
312285431Szbb
313285431Szbb/**
314285431Szbb * al_udelay - micro sec delay
315285431Szbb */
316285431Szbb#define al_udelay(u)		DELAY(u)
317285431Szbb
318285431Szbb/**
319285431Szbb * al_msleep - mili sec delay
320285431Szbb */
321285431Szbb#define al_msleep(m)		DELAY((m) * 1000)
322285431Szbb
323285431Szbb/**
324285431Szbb * swap half word to little endian
325285431Szbb *
326285431Szbb * @param x 16 bit value
327285431Szbb *
328285431Szbb * @return the value in little endian
329285431Szbb */
330285431Szbb#define swap16_to_le(x)		htole16(x)
331285431Szbb/**
332285431Szbb * swap word to little endian
333285431Szbb *
334285431Szbb * @param x 32 bit value
335285431Szbb *
336285431Szbb * @return the value in little endian
337285431Szbb */
338285431Szbb#define swap32_to_le(x)		htole32(x)
339285431Szbb
340285431Szbb/**
341285431Szbb * swap 8 bytes to little endian
342285431Szbb *
343285431Szbb * @param x 64 bit value
344285431Szbb *
345285431Szbb * @return the value in little endian
346285431Szbb */
347285431Szbb#define swap64_to_le(x)		htole64(x)
348285431Szbb
349285431Szbb/**
350285431Szbb * swap half word from little endian
351285431Szbb *
352285431Szbb * @param x 16 bit value
353285431Szbb *
354285431Szbb * @return the value in the cpu endianess
355285431Szbb */
356285431Szbb#define swap16_from_le(x)	le16toh(x)
357285431Szbb
358285431Szbb/**
359285431Szbb * swap word from little endian
360285431Szbb *
361285431Szbb * @param x 32 bit value
362285431Szbb *
363285431Szbb * @return the value in the cpu endianess
364285431Szbb */
365285431Szbb#define swap32_from_le(x)	le32toh(x)
366285431Szbb
367285431Szbb/**
368285431Szbb * swap 8 bytes from little endian
369285431Szbb *
370285431Szbb * @param x 64 bit value
371285431Szbb *
372285431Szbb * @return the value in the cpu endianess
373285431Szbb */
374285431Szbb#define swap64_from_le(x)	le64toh(x)
375285431Szbb
376285431Szbb/**
377285431Szbb * Memory set
378285431Szbb *
379285431Szbb * @param p memory pointer
380285431Szbb * @param val value for setting
381285431Szbb * @param cnt number of bytes to set
382285431Szbb */
383285431Szbb#define al_memset(p, val, cnt)	memset(p, val, cnt)
384285431Szbb
385285431Szbb/**
386285431Szbb * Memory copy
387285431Szbb *
388285431Szbb * @param p1 memory pointer
389285431Szbb * @param p2 memory pointer
390285431Szbb * @param cnt number of bytes to copy
391285431Szbb */
392285431Szbb#define al_memcpy(p1, p2, cnt)	memcpy(p1, p2, cnt)
393285431Szbb
394285431Szbb/**
395285431Szbb * Memory compare
396285431Szbb *
397285431Szbb * @param p1 memory pointer
398285431Szbb * @param p2 memory pointer
399285431Szbb * @param cnt number of bytes to compare
400285431Szbb */
401285431Szbb#define al_memcmp(p1, p2, cnt)	memcmp(p1, p2, cnt)
402285431Szbb
403285431Szbb/**
404285431Szbb * String compare
405285431Szbb *
406285431Szbb * @param s1 string pointer
407285431Szbb * @param s2 string pointer
408285431Szbb */
409285431Szbb#define al_strcmp(s1, s2)	strcmp(s1, s2)
410285431Szbb
411285431Szbb#define al_get_cpu_id()		0
412285431Szbb
413285431Szbb/* *INDENT-OFF* */
414285431Szbb#ifdef __cplusplus
415285431Szbb}
416285431Szbb#endif
417285431Szbb/* *INDENT-ON* */
418285431Szbb/** @} end of Platform Services API group */
419285431Szbb#endif				/* __PLAT_SERVICES_H__ */
420