11bb92983SJerome Forissier /* SPDX-License-Identifier: BSD-2-Clause */ 2b0104773SPascal Brand /* 32d0c93dfSEtienne Carriere * Copyright (c) 2014-2019, Linaro Limited 4b0104773SPascal Brand */ 5d50fee03SEtienne Carriere #ifndef __IO_H 6d50fee03SEtienne Carriere #define __IO_H 7b0104773SPascal Brand 881801f83SVolodymyr Babchuk #include <compiler.h> 9*239dffebSEtienne Carriere #include <kernel/delay.h> 101f70169dSJoakim Bech #include <stdint.h> 11ec219598SPascal Brand #include <types_ext.h> 12685204ebSJens Wiklander #include <utee_defines.h> 131f70169dSJoakim Bech 1481801f83SVolodymyr Babchuk /* 154d3ad62dSEtienne Carriere * Make sure that compiler reads/writes given variable only once. This is needed 1681801f83SVolodymyr Babchuk * in cases when we have normal shared memory, and this memory can be changed 1781801f83SVolodymyr Babchuk * at any moment. Compiler does not knows about this, so it can optimize memory 184d3ad62dSEtienne Carriere * access in any way, including repeated accesses from the same address. 194d3ad62dSEtienne Carriere * These macro enforce compiler to access memory only once. 2081801f83SVolodymyr Babchuk */ 2181801f83SVolodymyr Babchuk #define READ_ONCE(p) __compiler_atomic_load(&(p)) 224d3ad62dSEtienne Carriere #define WRITE_ONCE(p, v) __compiler_atomic_store(&(p), (v)) 2381801f83SVolodymyr Babchuk 242d0c93dfSEtienne Carriere static inline void io_write8(vaddr_t addr, uint8_t val) 25b0104773SPascal Brand { 26b0104773SPascal Brand *(volatile uint8_t *)addr = val; 27b0104773SPascal Brand } 28b0104773SPascal Brand 292d0c93dfSEtienne Carriere static inline void io_write16(vaddr_t addr, uint16_t val) 30b0104773SPascal Brand { 31b0104773SPascal Brand *(volatile uint16_t *)addr = val; 32b0104773SPascal Brand } 33b0104773SPascal Brand 342d0c93dfSEtienne Carriere static inline void io_write32(vaddr_t addr, uint32_t val) 35b0104773SPascal Brand { 36b0104773SPascal Brand *(volatile uint32_t *)addr = val; 37b0104773SPascal Brand } 38b0104773SPascal Brand 396a041defSMarouene Boubakri static inline void io_write64(vaddr_t addr, uint64_t val) 406a041defSMarouene Boubakri { 416a041defSMarouene Boubakri *(volatile uint64_t *)addr = val; 426a041defSMarouene Boubakri } 436a041defSMarouene Boubakri 442d0c93dfSEtienne Carriere static inline uint8_t io_read8(vaddr_t addr) 45b0104773SPascal Brand { 46b0104773SPascal Brand return *(volatile uint8_t *)addr; 47b0104773SPascal Brand } 48b0104773SPascal Brand 492d0c93dfSEtienne Carriere static inline uint16_t io_read16(vaddr_t addr) 50b0104773SPascal Brand { 51b0104773SPascal Brand return *(volatile uint16_t *)addr; 52b0104773SPascal Brand } 53b0104773SPascal Brand 542d0c93dfSEtienne Carriere static inline uint32_t io_read32(vaddr_t addr) 55b0104773SPascal Brand { 56b0104773SPascal Brand return *(volatile uint32_t *)addr; 57b0104773SPascal Brand } 58b0104773SPascal Brand 596a041defSMarouene Boubakri static inline uint64_t io_read64(vaddr_t addr) 606a041defSMarouene Boubakri { 616a041defSMarouene Boubakri return *(volatile uint64_t *)addr; 626a041defSMarouene Boubakri } 636a041defSMarouene Boubakri 6414ed3274SVictor Chong static inline void io_mask8(vaddr_t addr, uint8_t val, uint8_t mask) 6514ed3274SVictor Chong { 662d0c93dfSEtienne Carriere io_write8(addr, (io_read8(addr) & ~mask) | (val & mask)); 6714ed3274SVictor Chong } 6814ed3274SVictor Chong 6914ed3274SVictor Chong static inline void io_mask16(vaddr_t addr, uint16_t val, uint16_t mask) 7014ed3274SVictor Chong { 712d0c93dfSEtienne Carriere io_write16(addr, (io_read16(addr) & ~mask) | (val & mask)); 7214ed3274SVictor Chong } 7314ed3274SVictor Chong 7414ed3274SVictor Chong static inline void io_mask32(vaddr_t addr, uint32_t val, uint32_t mask) 7514ed3274SVictor Chong { 762d0c93dfSEtienne Carriere io_write32(addr, (io_read32(addr) & ~mask) | (val & mask)); 7714ed3274SVictor Chong } 7814ed3274SVictor Chong 79685204ebSJens Wiklander static inline uint64_t get_be64(const void *p) 80685204ebSJens Wiklander { 81685204ebSJens Wiklander return TEE_U64_FROM_BIG_ENDIAN(*(const uint64_t *)p); 82685204ebSJens Wiklander } 83685204ebSJens Wiklander 84685204ebSJens Wiklander static inline void put_be64(void *p, uint64_t val) 85685204ebSJens Wiklander { 86685204ebSJens Wiklander *(uint64_t *)p = TEE_U64_TO_BIG_ENDIAN(val); 87685204ebSJens Wiklander } 88685204ebSJens Wiklander 89685204ebSJens Wiklander static inline uint32_t get_be32(const void *p) 90685204ebSJens Wiklander { 91685204ebSJens Wiklander return TEE_U32_FROM_BIG_ENDIAN(*(const uint32_t *)p); 92685204ebSJens Wiklander } 93685204ebSJens Wiklander 94685204ebSJens Wiklander static inline void put_be32(void *p, uint32_t val) 95685204ebSJens Wiklander { 96685204ebSJens Wiklander *(uint32_t *)p = TEE_U32_TO_BIG_ENDIAN(val); 97685204ebSJens Wiklander } 98685204ebSJens Wiklander 99685204ebSJens Wiklander static inline uint16_t get_be16(const void *p) 100685204ebSJens Wiklander { 101685204ebSJens Wiklander return TEE_U16_FROM_BIG_ENDIAN(*(const uint16_t *)p); 102685204ebSJens Wiklander } 103685204ebSJens Wiklander 104685204ebSJens Wiklander static inline void put_be16(void *p, uint16_t val) 105685204ebSJens Wiklander { 106685204ebSJens Wiklander *(uint16_t *)p = TEE_U16_TO_BIG_ENDIAN(val); 107685204ebSJens Wiklander } 108685204ebSJens Wiklander 109c22e4872SCedric Neveux static inline void put_le32(const void *p, uint32_t val) 110c22e4872SCedric Neveux { 111c22e4872SCedric Neveux *(uint32_t *)p = val; 112c22e4872SCedric Neveux } 113c22e4872SCedric Neveux 114c22e4872SCedric Neveux static inline uint32_t get_le32(const void *p) 115c22e4872SCedric Neveux { 116c22e4872SCedric Neveux return *(const uint32_t *)p; 117c22e4872SCedric Neveux } 118c22e4872SCedric Neveux 119c22e4872SCedric Neveux static inline void put_le64(const void *p, uint64_t val) 120c22e4872SCedric Neveux { 121c22e4872SCedric Neveux *(uint64_t *)p = val; 122c22e4872SCedric Neveux } 123c22e4872SCedric Neveux 124c22e4872SCedric Neveux static inline uint64_t get_le64(const void *p) 125c22e4872SCedric Neveux { 126c22e4872SCedric Neveux return *(const uint64_t *)p; 127c22e4872SCedric Neveux } 128c22e4872SCedric Neveux 1292ba6031aSRuchika Gupta /* Unaligned accesses */ 1302ba6031aSRuchika Gupta 1312ba6031aSRuchika Gupta struct __unaligned_u16_t { uint16_t x; } __packed; 1322ba6031aSRuchika Gupta struct __unaligned_u32_t { uint32_t x; } __packed; 1332ba6031aSRuchika Gupta struct __unaligned_u64_t { uint64_t x; } __packed; 1342ba6031aSRuchika Gupta 1352ba6031aSRuchika Gupta static inline uint64_t get_unaligned_be64(const void *p) 1362ba6031aSRuchika Gupta { 1372ba6031aSRuchika Gupta const struct __unaligned_u64_t *tmp = p; 1382ba6031aSRuchika Gupta 1392ba6031aSRuchika Gupta return TEE_U64_FROM_BIG_ENDIAN(tmp->x); 1402ba6031aSRuchika Gupta } 1412ba6031aSRuchika Gupta 1422ba6031aSRuchika Gupta static inline void put_unaligned_be64(void *p, uint64_t val) 1432ba6031aSRuchika Gupta { 1442ba6031aSRuchika Gupta struct __unaligned_u64_t *tmp = p; 1452ba6031aSRuchika Gupta 1462ba6031aSRuchika Gupta tmp->x = TEE_U64_TO_BIG_ENDIAN(val); 1472ba6031aSRuchika Gupta } 1482ba6031aSRuchika Gupta 1492ba6031aSRuchika Gupta static inline uint32_t get_unaligned_be32(const void *p) 1502ba6031aSRuchika Gupta { 1512ba6031aSRuchika Gupta const struct __unaligned_u32_t *tmp = p; 1522ba6031aSRuchika Gupta 1532ba6031aSRuchika Gupta return TEE_U32_FROM_BIG_ENDIAN(tmp->x); 1542ba6031aSRuchika Gupta } 1552ba6031aSRuchika Gupta 1562ba6031aSRuchika Gupta static inline void put_unaligned_be32(void *p, uint32_t val) 1572ba6031aSRuchika Gupta { 1582ba6031aSRuchika Gupta struct __unaligned_u32_t *tmp = p; 1592ba6031aSRuchika Gupta 1602ba6031aSRuchika Gupta tmp->x = TEE_U32_TO_BIG_ENDIAN(val); 1612ba6031aSRuchika Gupta } 1622ba6031aSRuchika Gupta 1632ba6031aSRuchika Gupta static inline uint16_t get_unaligned_be16(const void *p) 1642ba6031aSRuchika Gupta { 1652ba6031aSRuchika Gupta const struct __unaligned_u16_t *tmp = p; 1662ba6031aSRuchika Gupta 1672ba6031aSRuchika Gupta return TEE_U16_FROM_BIG_ENDIAN(tmp->x); 1682ba6031aSRuchika Gupta } 1692ba6031aSRuchika Gupta 1702ba6031aSRuchika Gupta static inline void put_unaligned_be16(void *p, uint16_t val) 1712ba6031aSRuchika Gupta { 1722ba6031aSRuchika Gupta struct __unaligned_u16_t *tmp = p; 1732ba6031aSRuchika Gupta 1742ba6031aSRuchika Gupta tmp->x = TEE_U16_TO_BIG_ENDIAN(val); 1752ba6031aSRuchika Gupta } 1762ba6031aSRuchika Gupta 177679b0ed6SRuchika Gupta static inline void put_unaligned_le64(void *p, uint64_t val) 178679b0ed6SRuchika Gupta { 179679b0ed6SRuchika Gupta struct __unaligned_u64_t *tmp = p; 180679b0ed6SRuchika Gupta 181679b0ed6SRuchika Gupta tmp->x = val; 182679b0ed6SRuchika Gupta } 183679b0ed6SRuchika Gupta 184679b0ed6SRuchika Gupta static inline uint64_t get_unaligned_le64(const void *p) 185679b0ed6SRuchika Gupta { 186679b0ed6SRuchika Gupta const struct __unaligned_u64_t *tmp = p; 187679b0ed6SRuchika Gupta 188679b0ed6SRuchika Gupta return tmp->x; 189679b0ed6SRuchika Gupta } 190679b0ed6SRuchika Gupta 191679b0ed6SRuchika Gupta static inline void put_unaligned_le32(void *p, uint32_t val) 192679b0ed6SRuchika Gupta { 193679b0ed6SRuchika Gupta struct __unaligned_u32_t *tmp = p; 194679b0ed6SRuchika Gupta 195679b0ed6SRuchika Gupta tmp->x = val; 196679b0ed6SRuchika Gupta } 197679b0ed6SRuchika Gupta 198679b0ed6SRuchika Gupta static inline uint32_t get_unaligned_le32(const void *p) 199679b0ed6SRuchika Gupta { 200679b0ed6SRuchika Gupta const struct __unaligned_u32_t *tmp = p; 201679b0ed6SRuchika Gupta 202679b0ed6SRuchika Gupta return tmp->x; 203679b0ed6SRuchika Gupta } 204679b0ed6SRuchika Gupta 205679b0ed6SRuchika Gupta static inline void put_unaligned_le16(void *p, uint16_t val) 206679b0ed6SRuchika Gupta { 207679b0ed6SRuchika Gupta struct __unaligned_u16_t *tmp = p; 208679b0ed6SRuchika Gupta 209679b0ed6SRuchika Gupta tmp->x = val; 210679b0ed6SRuchika Gupta } 211679b0ed6SRuchika Gupta 212679b0ed6SRuchika Gupta static inline uint16_t get_unaligned_le16(const void *p) 213679b0ed6SRuchika Gupta { 214679b0ed6SRuchika Gupta const struct __unaligned_u16_t *tmp = p; 215679b0ed6SRuchika Gupta 216679b0ed6SRuchika Gupta return tmp->x; 217679b0ed6SRuchika Gupta } 218679b0ed6SRuchika Gupta 21954815590SEtienne Carriere /* 22054815590SEtienne Carriere * Set and clear bits helpers. 22154815590SEtienne Carriere * 22254815590SEtienne Carriere * @addr is the address of the memory cell accessed 22354815590SEtienne Carriere * @set_mask represents the bit mask of the bit(s) to set, aka set to 1 22454815590SEtienne Carriere * @clear_mask represents the bit mask of the bit(s) to clear, aka reset to 0 22554815590SEtienne Carriere * 22654815590SEtienne Carriere * io_clrsetbits32() clears then sets the target bits in this order. If a bit 22754815590SEtienne Carriere * position is defined by both @set_mask and @clear_mask, the bit will be set. 22854815590SEtienne Carriere */ 2294d22155cSEtienne Carriere static inline void io_setbits32(vaddr_t addr, uint32_t set_mask) 23054815590SEtienne Carriere { 2312d0c93dfSEtienne Carriere io_write32(addr, io_read32(addr) | set_mask); 23254815590SEtienne Carriere } 23354815590SEtienne Carriere 2344d22155cSEtienne Carriere static inline void io_clrbits32(vaddr_t addr, uint32_t clear_mask) 23554815590SEtienne Carriere { 2362d0c93dfSEtienne Carriere io_write32(addr, io_read32(addr) & ~clear_mask); 23754815590SEtienne Carriere } 23854815590SEtienne Carriere 2394d22155cSEtienne Carriere static inline void io_clrsetbits32(vaddr_t addr, uint32_t clear_mask, 24054815590SEtienne Carriere uint32_t set_mask) 24154815590SEtienne Carriere { 2422d0c93dfSEtienne Carriere io_write32(addr, (io_read32(addr) & ~clear_mask) | set_mask); 2432d0c93dfSEtienne Carriere } 2442d0c93dfSEtienne Carriere 245b7d2b849SEtienne Carriere static inline void io_setbits16(vaddr_t addr, uint16_t set_mask) 246b7d2b849SEtienne Carriere { 247b7d2b849SEtienne Carriere io_write16(addr, io_read16(addr) | set_mask); 248b7d2b849SEtienne Carriere } 249b7d2b849SEtienne Carriere 250b7d2b849SEtienne Carriere static inline void io_clrbits16(vaddr_t addr, uint16_t clear_mask) 251b7d2b849SEtienne Carriere { 252b7d2b849SEtienne Carriere io_write16(addr, io_read16(addr) & ~clear_mask); 253b7d2b849SEtienne Carriere } 254b7d2b849SEtienne Carriere 255b7d2b849SEtienne Carriere static inline void io_clrsetbits16(vaddr_t addr, uint16_t clear_mask, 256b7d2b849SEtienne Carriere uint16_t set_mask) 257b7d2b849SEtienne Carriere { 258b7d2b849SEtienne Carriere io_write16(addr, (io_read16(addr) & ~clear_mask) | set_mask); 259b7d2b849SEtienne Carriere } 260b7d2b849SEtienne Carriere 261b7d2b849SEtienne Carriere static inline void io_setbits8(vaddr_t addr, uint8_t set_mask) 262b7d2b849SEtienne Carriere { 263b7d2b849SEtienne Carriere io_write8(addr, io_read8(addr) | set_mask); 264b7d2b849SEtienne Carriere } 265b7d2b849SEtienne Carriere 266b7d2b849SEtienne Carriere static inline void io_clrbits8(vaddr_t addr, uint8_t clear_mask) 267b7d2b849SEtienne Carriere { 268b7d2b849SEtienne Carriere io_write8(addr, io_read8(addr) & ~clear_mask); 269b7d2b849SEtienne Carriere } 270b7d2b849SEtienne Carriere 271b7d2b849SEtienne Carriere static inline void io_clrsetbits8(vaddr_t addr, uint8_t clear_mask, 272b7d2b849SEtienne Carriere uint8_t set_mask) 273b7d2b849SEtienne Carriere { 274b7d2b849SEtienne Carriere io_write8(addr, (io_read8(addr) & ~clear_mask) | set_mask); 275b7d2b849SEtienne Carriere } 276b7d2b849SEtienne Carriere 27797ea199aSXiaoxu Zeng /* 27897ea199aSXiaoxu Zeng * Poll on a IO memory content or timeout 27997ea199aSXiaoxu Zeng * 28097ea199aSXiaoxu Zeng * @_addr is the address of the memory cell accessed 28197ea199aSXiaoxu Zeng * @_val represents the val of the memory cell accessed 28297ea199aSXiaoxu Zeng * @_cond represents the condition to get the correct value 28397ea199aSXiaoxu Zeng * @_delay_us represents the read interval in mircorseconds 28497ea199aSXiaoxu Zeng * @_timeout_us represents the timeout period in microseconds 28597ea199aSXiaoxu Zeng * 28697ea199aSXiaoxu Zeng * @return nonzero value means timeout, 0 means got right value 28797ea199aSXiaoxu Zeng */ 28897ea199aSXiaoxu Zeng #define IO_READ32_POLL_TIMEOUT(_addr, _val, _cond, _delay_us, _timeout_us) \ 28997ea199aSXiaoxu Zeng ({ \ 29097ea199aSXiaoxu Zeng uint32_t __timeout = 0; \ 29197ea199aSXiaoxu Zeng uint32_t __delay = (_delay_us); \ 29297ea199aSXiaoxu Zeng \ 29397ea199aSXiaoxu Zeng while (__timeout < (_timeout_us)) { \ 29497ea199aSXiaoxu Zeng (_val) = io_read32(_addr); \ 29597ea199aSXiaoxu Zeng if (_cond) \ 29697ea199aSXiaoxu Zeng break; \ 29797ea199aSXiaoxu Zeng __timeout += (__delay); \ 29897ea199aSXiaoxu Zeng udelay(__delay); \ 29997ea199aSXiaoxu Zeng } \ 30097ea199aSXiaoxu Zeng (_val) = io_read32(_addr); \ 30197ea199aSXiaoxu Zeng !(_cond); \ 30297ea199aSXiaoxu Zeng }) 30397ea199aSXiaoxu Zeng 304d50fee03SEtienne Carriere #endif /*__IO_H*/ 305