2021-01-12 18:22:11 +00:00
|
|
|
/* SPDX-License-Identifier: MIT */
|
|
|
|
|
|
|
|
#ifndef UTILS_H
|
|
|
|
#define UTILS_H
|
|
|
|
|
|
|
|
#include "types.h"
|
|
|
|
|
|
|
|
#define printf debug_printf
|
|
|
|
|
2021-02-18 08:54:44 +00:00
|
|
|
#define BIT(x) (1L << (x))
|
|
|
|
|
2021-03-07 08:11:17 +00:00
|
|
|
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
|
|
|
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
|
|
|
|
2021-01-14 09:18:07 +00:00
|
|
|
static inline u64 read64(u64 addr)
|
|
|
|
{
|
|
|
|
u64 data;
|
2021-01-28 06:16:28 +00:00
|
|
|
__asm__ volatile("ldr\t%0, [%1]" : "=r"(data) : "r"(addr) : "memory");
|
2021-01-14 09:18:07 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void write64(u64 addr, u64 data)
|
|
|
|
{
|
2021-01-28 06:16:28 +00:00
|
|
|
__asm__ volatile("str\t%0, [%1]" : : "r"(data), "r"(addr) : "memory");
|
2021-01-14 09:18:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u64 set64(u64 addr, u64 set)
|
|
|
|
{
|
|
|
|
u64 data;
|
|
|
|
__asm__ volatile("ldr\t%0, [%1]\n"
|
|
|
|
"\torr\t%0, %0, %2\n"
|
|
|
|
"\tstr\t%0, [%1]"
|
|
|
|
: "=&r"(data)
|
2021-01-28 06:16:28 +00:00
|
|
|
: "r"(addr), "r"(set)
|
|
|
|
: "memory");
|
2021-01-14 09:18:07 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u64 clear64(u64 addr, u64 clear)
|
|
|
|
{
|
|
|
|
u64 data;
|
|
|
|
__asm__ volatile("ldr\t%0, [%1]\n"
|
|
|
|
"\tbic\t%0, %0, %2\n"
|
|
|
|
"\tstr\t%0, [%1]"
|
|
|
|
: "=&r"(data)
|
2021-01-28 06:16:28 +00:00
|
|
|
: "r"(addr), "r"(clear)
|
|
|
|
: "memory");
|
2021-01-14 09:18:07 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u64 mask64(u64 addr, u64 clear, u64 set)
|
|
|
|
{
|
|
|
|
u64 data;
|
|
|
|
__asm__ volatile("ldr\t%0, [%1]\n"
|
|
|
|
"\tbic\t%0, %0, %3\n"
|
|
|
|
"\torr\t%0, %0, %2\n"
|
|
|
|
"\tstr\t%0, [%1]"
|
|
|
|
: "=&r"(data)
|
2021-01-28 06:16:28 +00:00
|
|
|
: "r"(addr), "r"(set), "r"(clear)
|
|
|
|
: "memory");
|
2021-01-14 09:18:07 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2021-02-17 20:33:51 +00:00
|
|
|
static inline u64 writeread64(u64 addr, u64 data)
|
|
|
|
{
|
|
|
|
write64(addr, data);
|
|
|
|
return read64(addr);
|
|
|
|
}
|
|
|
|
|
2021-01-12 18:22:11 +00:00
|
|
|
static inline u32 read32(u64 addr)
|
|
|
|
{
|
|
|
|
u32 data;
|
2021-01-28 06:16:28 +00:00
|
|
|
__asm__ volatile("ldr\t%w0, [%1]" : "=r"(data) : "r"(addr) : "memory");
|
2021-01-12 18:22:11 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void write32(u64 addr, u32 data)
|
|
|
|
{
|
2021-01-28 06:16:28 +00:00
|
|
|
__asm__ volatile("str\t%w0, [%1]" : : "r"(data), "r"(addr) : "memory");
|
2021-01-12 18:22:11 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 20:33:51 +00:00
|
|
|
static inline u32 writeread32(u64 addr, u32 data)
|
|
|
|
{
|
|
|
|
write32(addr, data);
|
|
|
|
return read32(addr);
|
|
|
|
}
|
|
|
|
|
2021-01-12 18:22:11 +00:00
|
|
|
static inline u32 set32(u64 addr, u32 set)
|
|
|
|
{
|
|
|
|
u32 data;
|
|
|
|
__asm__ volatile("ldr\t%w0, [%1]\n"
|
|
|
|
"\torr\t%w0, %w0, %w2\n"
|
|
|
|
"\tstr\t%w0, [%1]"
|
|
|
|
: "=&r"(data)
|
2021-01-28 06:16:28 +00:00
|
|
|
: "r"(addr), "r"(set)
|
|
|
|
: "memory");
|
2021-01-12 18:22:11 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 clear32(u64 addr, u32 clear)
|
|
|
|
{
|
|
|
|
u32 data;
|
|
|
|
__asm__ volatile("ldr\t%w0, [%1]\n"
|
|
|
|
"\tbic\t%w0, %w0, %w2\n"
|
|
|
|
"\tstr\t%w0, [%1]"
|
|
|
|
: "=&r"(data)
|
2021-01-28 06:16:28 +00:00
|
|
|
: "r"(addr), "r"(clear)
|
|
|
|
: "memory");
|
2021-01-12 18:22:11 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 mask32(u64 addr, u32 clear, u32 set)
|
|
|
|
{
|
|
|
|
u32 data;
|
|
|
|
__asm__ volatile("ldr\t%w0, [%1]\n"
|
|
|
|
"\tbic\t%w0, %w0, %w3\n"
|
|
|
|
"\torr\t%w0, %w0, %w2\n"
|
|
|
|
"\tstr\t%w0, [%1]"
|
|
|
|
: "=&r"(data)
|
2021-01-28 06:16:28 +00:00
|
|
|
: "r"(addr), "r"(set), "r"(clear)
|
|
|
|
: "memory");
|
2021-01-12 18:22:11 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u16 read16(u64 addr)
|
|
|
|
{
|
|
|
|
u32 data;
|
2021-01-28 06:16:28 +00:00
|
|
|
__asm__ volatile("ldrh\t%w0, [%1]" : "=r"(data) : "r"(addr) : "memory");
|
2021-01-12 18:22:11 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void write16(u64 addr, u16 data)
|
|
|
|
{
|
2021-01-28 06:16:28 +00:00
|
|
|
__asm__ volatile("strh\t%w0, [%1]" : : "r"(data), "r"(addr) : "memory");
|
2021-01-12 18:22:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u16 set16(u64 addr, u16 set)
|
|
|
|
{
|
|
|
|
u16 data;
|
|
|
|
__asm__ volatile("ldrh\t%w0, [%1]\n"
|
|
|
|
"\torr\t%w0, %w0, %w2\n"
|
|
|
|
"\tstrh\t%w0, [%1]"
|
|
|
|
: "=&r"(data)
|
|
|
|
: "r"(addr), "r"(set)
|
2021-01-28 06:16:28 +00:00
|
|
|
: "memory"
|
2021-01-12 18:22:11 +00:00
|
|
|
|
|
|
|
);
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u16 clear16(u64 addr, u16 clear)
|
|
|
|
{
|
|
|
|
u16 data;
|
|
|
|
__asm__ volatile("ldrh\t%w0, [%1]\n"
|
|
|
|
"\tbic\t%w0, %w0, %w2\n"
|
|
|
|
"\tstrh\t%w0, [%1]"
|
|
|
|
: "=&r"(data)
|
2021-01-28 06:16:28 +00:00
|
|
|
: "r"(addr), "r"(clear)
|
|
|
|
: "memory");
|
2021-01-12 18:22:11 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u16 mask16(u64 addr, u16 clear, u16 set)
|
|
|
|
{
|
|
|
|
u16 data;
|
|
|
|
__asm__ volatile("ldrh\t%w0, [%1]\n"
|
2021-01-14 09:18:07 +00:00
|
|
|
"\tbic\t%w0, %w0, %w3\n"
|
2021-01-12 18:22:11 +00:00
|
|
|
"\torr\t%w0, %w0, %w2\n"
|
|
|
|
"\tstrh\t%w0, [%1]"
|
|
|
|
: "=&r"(data)
|
2021-01-28 06:16:28 +00:00
|
|
|
: "r"(addr), "r"(set), "r"(clear)
|
|
|
|
: "memory");
|
2021-01-12 18:22:11 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2021-02-17 20:33:51 +00:00
|
|
|
static inline u16 writeread16(u64 addr, u16 data)
|
|
|
|
{
|
|
|
|
write16(addr, data);
|
|
|
|
return read16(addr);
|
|
|
|
}
|
|
|
|
|
2021-01-12 18:22:11 +00:00
|
|
|
static inline u8 read8(u64 addr)
|
|
|
|
{
|
|
|
|
u32 data;
|
2021-01-28 06:16:28 +00:00
|
|
|
__asm__ volatile("ldrb\t%w0, [%1]" : "=r"(data) : "r"(addr) : "memory");
|
2021-01-12 18:22:11 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void write8(u64 addr, u8 data)
|
|
|
|
{
|
2021-01-28 06:16:28 +00:00
|
|
|
__asm__ volatile("strb\t%w0, [%1]" : : "r"(data), "r"(addr) : "memory");
|
2021-01-12 18:22:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u8 set8(u64 addr, u8 set)
|
|
|
|
{
|
|
|
|
u8 data;
|
|
|
|
__asm__ volatile("ldrb\t%w0, [%1]\n"
|
|
|
|
"\torr\t%w0, %w0, %w2\n"
|
|
|
|
"\tstrb\t%w0, [%1]"
|
|
|
|
: "=&r"(data)
|
2021-01-28 06:16:28 +00:00
|
|
|
: "r"(addr), "r"(set)
|
|
|
|
: "memory");
|
2021-01-12 18:22:11 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u8 clear8(u64 addr, u8 clear)
|
|
|
|
{
|
|
|
|
u8 data;
|
|
|
|
__asm__ volatile("ldrb\t%w0, [%1]\n"
|
|
|
|
"\tbic\t%w0, %w0, %w2\n"
|
|
|
|
"\tstrb\t%w0, [%1]"
|
|
|
|
: "=&r"(data)
|
2021-01-28 06:16:28 +00:00
|
|
|
: "r"(addr), "r"(clear)
|
|
|
|
: "memory");
|
2021-01-12 18:22:11 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u8 mask8(u64 addr, u8 clear, u8 set)
|
|
|
|
{
|
|
|
|
u8 data;
|
|
|
|
__asm__ volatile("ldrb\t%w0, [%1]\n"
|
|
|
|
"\tbic\t%w0, %w0, %w3\n"
|
|
|
|
"\torr\t%w0, %w0, %w2\n"
|
|
|
|
"\tstrb\t%w0, [%1]"
|
|
|
|
: "=&r"(data)
|
2021-01-28 06:16:28 +00:00
|
|
|
: "r"(addr), "r"(set), "r"(clear)
|
|
|
|
: "memory");
|
2021-01-12 18:22:11 +00:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2021-02-17 20:33:51 +00:00
|
|
|
static inline u8 writeread8(u64 addr, u8 data)
|
|
|
|
{
|
|
|
|
write8(addr, data);
|
|
|
|
return read8(addr);
|
|
|
|
}
|
|
|
|
|
2021-01-30 06:12:23 +00:00
|
|
|
#define sys_reg(op0, op1, CRn, CRm, op2) s##op0##_##op1##_c##CRn##_c##CRm##_##op2
|
|
|
|
|
2021-01-29 15:26:55 +00:00
|
|
|
#define _mrs(reg) \
|
2021-01-28 06:27:35 +00:00
|
|
|
({ \
|
|
|
|
u64 val; \
|
|
|
|
__asm__ volatile("mrs\t%0, " #reg : "=r"(val)); \
|
|
|
|
val; \
|
2021-01-16 15:45:10 +00:00
|
|
|
})
|
2021-01-29 15:26:55 +00:00
|
|
|
#define mrs(reg) _mrs(reg)
|
2021-01-16 15:45:10 +00:00
|
|
|
|
2021-01-31 00:46:30 +00:00
|
|
|
#define _msr(reg, val) \
|
|
|
|
({ \
|
|
|
|
u64 __val = (u64)val; \
|
|
|
|
__asm__ volatile("msr\t" #reg ", %0" : : "r"(__val)); \
|
|
|
|
})
|
|
|
|
#define msr(reg, val) _msr(reg, val)
|
2021-01-16 15:45:10 +00:00
|
|
|
|
2021-02-18 08:53:51 +00:00
|
|
|
#define reg_clr(reg, bits) msr(reg, mrs(reg) & ~(bits))
|
|
|
|
#define reg_set(reg, bits) msr(reg, mrs(reg) | bits)
|
|
|
|
#define reg_mask(reg, clr, set) msr(reg, (mrs(reg) & ~(clr)) | set)
|
|
|
|
|
2021-01-28 06:16:28 +00:00
|
|
|
#define sysop(op) __asm__ volatile(op ::: "memory")
|
2021-01-16 15:45:10 +00:00
|
|
|
|
2021-01-28 06:16:28 +00:00
|
|
|
#define cacheop(op, val) ({ __asm__ volatile(op ", %0" : : "r"(val) : "memory"); })
|
2021-01-16 15:45:10 +00:00
|
|
|
|
|
|
|
#define ic_ialluis() sysop("ic ialluis")
|
2021-01-28 06:27:35 +00:00
|
|
|
#define ic_iallu() sysop("ic iallu")
|
|
|
|
#define ic_iavau(p) cacheop("ic ivau", p)
|
|
|
|
#define dc_ivac(p) cacheop("dc ivac", p)
|
|
|
|
#define dc_isw(p) cacheop("dc isw", p)
|
|
|
|
#define dc_csw(p) cacheop("dc csw", p)
|
|
|
|
#define dc_cisw(p) cacheop("dc cisw", p)
|
|
|
|
#define dc_zva(p) cacheop("dc zva", p)
|
|
|
|
#define dc_cvac(p) cacheop("dc cvac", p)
|
|
|
|
#define dc_cvau(p) cacheop("dc cvau", p)
|
|
|
|
#define dc_civac(p) cacheop("dc civac", p)
|
2021-01-16 15:45:10 +00:00
|
|
|
|
2021-03-13 16:23:59 +00:00
|
|
|
#define dma_mb() sysop("dmb osh")
|
|
|
|
#define dma_rmb() sysop("dmb oshld")
|
|
|
|
#define dma_wmb() sysop("dmb oshst")
|
|
|
|
|
2021-01-30 06:12:23 +00:00
|
|
|
static inline int is_ecore(void)
|
|
|
|
{
|
|
|
|
return !(mrs(MPIDR_EL1) & (1 << 16));
|
|
|
|
}
|
|
|
|
|
2021-03-04 12:28:07 +00:00
|
|
|
static inline int in_el2(void)
|
|
|
|
{
|
|
|
|
return (mrs(CurrentEL) >> 2) == 2;
|
|
|
|
}
|
|
|
|
|
2021-03-14 21:40:02 +00:00
|
|
|
static inline int is_primary_core(void)
|
|
|
|
{
|
|
|
|
return mrs(MPIDR_EL1) == 0x80000000;
|
|
|
|
}
|
|
|
|
|
2021-03-14 17:26:13 +00:00
|
|
|
extern char _base[];
|
|
|
|
extern char _end[];
|
2021-01-29 06:19:34 +00:00
|
|
|
extern char _payload_start[];
|
|
|
|
extern char _payload_end[];
|
2021-01-16 15:45:10 +00:00
|
|
|
|
2021-01-12 18:22:11 +00:00
|
|
|
/*
|
|
|
|
* These functions are guaranteed to copy by reading from src and writing to dst
|
|
|
|
* in <n>-bit units If size is not aligned, the remaining bytes are not copied
|
|
|
|
*/
|
2021-01-14 09:18:07 +00:00
|
|
|
void memset64(void *dst, u64 value, size_t size);
|
|
|
|
void memcpy64(void *dst, void *src, size_t size);
|
|
|
|
void memset32(void *dst, u32 value, size_t size);
|
|
|
|
void memcpy32(void *dst, void *src, size_t size);
|
|
|
|
void memset16(void *dst, u16 value, size_t size);
|
|
|
|
void memcpy16(void *dst, void *src, size_t size);
|
|
|
|
void memset8(void *dst, u8 value, size_t size);
|
|
|
|
void memcpy8(void *dst, void *src, size_t size);
|
|
|
|
|
|
|
|
void hexdump(const void *d, size_t len);
|
2021-01-16 20:57:43 +00:00
|
|
|
void regdump(u64 addr, size_t len);
|
2021-01-12 18:22:11 +00:00
|
|
|
int sprintf(char *str, const char *fmt, ...);
|
|
|
|
int debug_printf(const char *fmt, ...);
|
|
|
|
void udelay(u32 d);
|
2021-01-29 10:59:21 +00:00
|
|
|
void reboot(void) __attribute__((noreturn));
|
2021-01-12 18:22:11 +00:00
|
|
|
|
2021-01-23 14:13:33 +00:00
|
|
|
#define panic(fmt, ...) \
|
|
|
|
do { \
|
|
|
|
debug_printf(fmt, ##__VA_ARGS__); \
|
|
|
|
reboot(); \
|
|
|
|
} while (0)
|
|
|
|
|
2021-03-06 09:57:21 +00:00
|
|
|
static inline int poll32(u64 addr, u32 mask, u32 target, u32 timeout)
|
|
|
|
{
|
|
|
|
while (--timeout > 0) {
|
|
|
|
u32 value = read32(addr) & mask;
|
|
|
|
if (value == target)
|
|
|
|
return 0;
|
|
|
|
udelay(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2021-01-12 18:22:11 +00:00
|
|
|
#endif
|