|  | /* | 
|  | * Copyright (c) 2018 - 2019 Antmicro <www.antmicro.com> | 
|  | * | 
|  | * SPDX-License-Identifier: Apache-2.0 | 
|  | */ | 
|  |  | 
|  | #ifndef __RISCV32_LITEX_VEXRISCV_SOC_H_ | 
|  | #define __RISCV32_LITEX_VEXRISCV_SOC_H_ | 
|  |  | 
|  | #include <zephyr/devicetree.h> | 
|  | #include <zephyr/arch/riscv/sys_io.h> | 
|  |  | 
|  | #ifndef _ASMLANGUAGE | 
|  | /* CSR access helpers */ | 
|  |  | 
|  | BUILD_ASSERT(CONFIG_LITEX_CSR_DATA_WIDTH == 8 || CONFIG_LITEX_CSR_DATA_WIDTH == 32, | 
|  | "CONFIG_LITEX_CSR_DATA_WIDTH must be 8 or 32 bits"); | 
|  |  | 
|  | #define LITEX_CSR_DW_BYTES     (CONFIG_LITEX_CSR_DATA_WIDTH/8) | 
|  | #define LITEX_CSR_OFFSET_BYTES 4 | 
|  |  | 
|  | static inline size_t litex_num_subregs(size_t csr_bytes) | 
|  | { | 
|  | return (csr_bytes - 1) / LITEX_CSR_DW_BYTES + 1; | 
|  | } | 
|  |  | 
|  | static inline uint8_t litex_read8(mem_addr_t addr) | 
|  | { | 
|  | return sys_read8(addr); | 
|  | } | 
|  |  | 
|  | static inline uint16_t litex_read16(mem_addr_t addr) | 
|  | { | 
|  | #if CONFIG_LITEX_CSR_DATA_WIDTH == 8 | 
|  | #ifdef CONFIG_LITEX_CSR_ORDERING_BIG | 
|  | return (sys_read8(addr) << 8) | 
|  | | sys_read8(addr + 0x4); | 
|  | #else | 
|  | return sys_read8(addr) | 
|  | | (sys_read8(addr + 0x4) << 8); | 
|  | #endif | 
|  | #else /* CONFIG_LITEX_CSR_DATA_WIDTH == 8 */ | 
|  | return sys_read16(addr); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static inline uint32_t litex_read32(mem_addr_t addr) | 
|  | { | 
|  | #if CONFIG_LITEX_CSR_DATA_WIDTH == 8 | 
|  | #ifdef CONFIG_LITEX_CSR_ORDERING_BIG | 
|  | return (sys_read8(addr) << 24) | 
|  | | (sys_read8(addr + 0x4) << 16) | 
|  | | (sys_read8(addr + 0x8) << 8) | 
|  | | sys_read8(addr + 0xc); | 
|  | #else | 
|  | return sys_read8(addr) | 
|  | | (sys_read8(addr + 0x4) << 8) | 
|  | | (sys_read8(addr + 0x8) << 16) | 
|  | | (sys_read8(addr + 0xc) << 24); | 
|  | #endif | 
|  | #else /* CONFIG_LITEX_CSR_DATA_WIDTH == 8 */ | 
|  | return sys_read32(addr); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static inline uint64_t litex_read64(mem_addr_t addr) | 
|  | { | 
|  | #if CONFIG_LITEX_CSR_DATA_WIDTH == 8 | 
|  | #ifdef CONFIG_LITEX_CSR_ORDERING_BIG | 
|  | return (((uint64_t)sys_read8(addr)) << 56) | 
|  | | ((uint64_t)sys_read8(addr + 0x4) << 48) | 
|  | | ((uint64_t)sys_read8(addr + 0x8) << 40) | 
|  | | ((uint64_t)sys_read8(addr + 0xc) << 32) | 
|  | | ((uint64_t)sys_read8(addr + 0x10) << 24) | 
|  | | ((uint64_t)sys_read8(addr + 0x14) << 16) | 
|  | | ((uint64_t)sys_read8(addr + 0x18) << 8) | 
|  | | (uint64_t)sys_read8(addr + 0x1c); | 
|  | #else | 
|  | return (uint64_t)sys_read8(addr) | 
|  | | ((uint64_t)sys_read8(addr + 0x4) << 8) | 
|  | | ((uint64_t)sys_read8(addr + 0x8) << 16) | 
|  | | ((uint64_t)sys_read8(addr + 0xc) << 24) | 
|  | | ((uint64_t)sys_read8(addr + 0x10) << 32) | 
|  | | ((uint64_t)sys_read8(addr + 0x14) << 40) | 
|  | | ((uint64_t)sys_read8(addr + 0x18) << 48) | 
|  | | ((uint64_t)sys_read8(addr + 0x1c) << 56); | 
|  | #endif | 
|  | #else /* CONFIG_LITEX_CSR_DATA_WIDTH == 8 */ | 
|  | #ifdef CONFIG_LITEX_CSR_ORDERING_BIG | 
|  | return ((uint64_t)sys_read32(addr) << 32) | (uint64_t)sys_read32(addr + 0x4); | 
|  | #else | 
|  | return sys_read64(addr); | 
|  | #endif | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static inline void litex_write8(uint8_t value, mem_addr_t addr) | 
|  | { | 
|  | sys_write8(value, addr); | 
|  | } | 
|  |  | 
|  | static inline void litex_write16(uint16_t value, mem_addr_t addr) | 
|  | { | 
|  | #if CONFIG_LITEX_CSR_DATA_WIDTH == 8 | 
|  | #ifdef CONFIG_LITEX_CSR_ORDERING_BIG | 
|  | sys_write8(value >> 8, addr); | 
|  | sys_write8(value, addr + 0x4); | 
|  | #else | 
|  | sys_write8(value, addr); | 
|  | sys_write8(value >> 8, addr + 0x4); | 
|  | #endif | 
|  | #else /* CONFIG_LITEX_CSR_DATA_WIDTH == 8 */ | 
|  | sys_write16(value, addr); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static inline void litex_write32(uint32_t value, mem_addr_t addr) | 
|  | { | 
|  | #if CONFIG_LITEX_CSR_DATA_WIDTH == 8 | 
|  | #ifdef CONFIG_LITEX_CSR_ORDERING_BIG | 
|  | sys_write8(value >> 24, addr); | 
|  | sys_write8(value >> 16, addr + 0x4); | 
|  | sys_write8(value >> 8, addr + 0x8); | 
|  | sys_write8(value, addr + 0xC); | 
|  | #else | 
|  | sys_write8(value, addr); | 
|  | sys_write8(value >> 8, addr + 0x4); | 
|  | sys_write8(value >> 16, addr + 0x8); | 
|  | sys_write8(value >> 24, addr + 0xC); | 
|  | #endif | 
|  | #else /* CONFIG_LITEX_CSR_DATA_WIDTH == 8 */ | 
|  | sys_write32(value, addr); | 
|  | #endif | 
|  | } | 
|  |  | 
|  | static inline void litex_write64(uint64_t value, mem_addr_t addr) | 
|  | { | 
|  | #if CONFIG_LITEX_CSR_DATA_WIDTH == 8 | 
|  | #ifdef CONFIG_LITEX_CSR_ORDERING_BIG | 
|  | sys_write8(value >> 56, addr); | 
|  | sys_write8(value >> 48, addr + 0x4); | 
|  | sys_write8(value >> 40, addr + 0x8); | 
|  | sys_write8(value >> 32, addr + 0xC); | 
|  | sys_write8(value >> 24, addr + 0x10); | 
|  | sys_write8(value >> 16, addr + 0x14); | 
|  | sys_write8(value >> 8, addr + 0x18); | 
|  | sys_write8(value, addr + 0x1C); | 
|  | #else | 
|  | sys_write8(value, addr); | 
|  | sys_write8(value >> 8, addr + 0x4); | 
|  | sys_write8(value >> 16, addr + 0x8); | 
|  | sys_write8(value >> 24, addr + 0xC); | 
|  | sys_write8(value >> 32, addr + 0x10); | 
|  | sys_write8(value >> 40, addr + 0x14); | 
|  | sys_write8(value >> 48, addr + 0x18); | 
|  | sys_write8(value >> 56, addr + 0x1C); | 
|  | #endif | 
|  | #else /* CONFIG_LITEX_CSR_DATA_WIDTH == 8 */ | 
|  | #ifdef CONFIG_LITEX_CSR_ORDERING_BIG | 
|  | sys_write32(value >> 32, addr); | 
|  | sys_write32(value, addr + 0x4); | 
|  | #else | 
|  | sys_write64(value, addr); | 
|  | #endif | 
|  | #endif /* CONFIG_LITEX_CSR_DATA_WIDTH == 8 */ | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Operates on uint32_t values only | 
|  | * Size is in bytes and meaningful are 1, 2 or 4 | 
|  | * Address must be aligned to 4 bytes | 
|  | */ | 
|  | static inline void litex_write(mem_addr_t addr, uint8_t size, uint32_t value) | 
|  | { | 
|  | switch (size) { | 
|  | case 1: | 
|  | litex_write8(value, addr); | 
|  | break; | 
|  | case 2: | 
|  | litex_write16(value, addr); | 
|  | break; | 
|  | case 4: | 
|  | litex_write32(value, addr); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Operates on uint32_t values only | 
|  | * Size is in bytes and meaningful are 1, 2 or 4 | 
|  | * Address must be aligned to 4 bytes | 
|  | */ | 
|  | static inline uint32_t litex_read(mem_addr_t addr, uint32_t size) | 
|  | { | 
|  | switch (size) { | 
|  | case 1: | 
|  | return litex_read8(addr); | 
|  | case 2: | 
|  | return litex_read16(addr); | 
|  | case 4: | 
|  | return litex_read32(addr); | 
|  | default: | 
|  | return 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | static inline void litex_write32_array(mem_addr_t addr, uint32_t *buf, size_t cnt) | 
|  | { | 
|  | size_t i; | 
|  |  | 
|  | for (i = 0; i < cnt; i++) { | 
|  | #ifdef CONFIG_LITEX_CSR_ORDERING_BIG | 
|  | litex_write32(buf[cnt - 1 - i], addr); | 
|  | #else | 
|  | litex_write32(buf[i], addr); | 
|  | #endif | 
|  | addr += litex_num_subregs(sizeof(uint32_t)) * LITEX_CSR_OFFSET_BYTES; | 
|  | } | 
|  | } | 
|  |  | 
|  | static inline void litex_read32_array(mem_addr_t addr, uint32_t *buf, size_t cnt) | 
|  | { | 
|  | size_t i; | 
|  |  | 
|  | for (i = 0; i < cnt; i++) { | 
|  | #ifdef CONFIG_LITEX_CSR_ORDERING_BIG | 
|  | buf[cnt - 1 - i] = litex_read32(addr); | 
|  | #else | 
|  | buf[i] = litex_read32(addr); | 
|  | #endif | 
|  | addr += litex_num_subregs(sizeof(uint32_t)) * LITEX_CSR_OFFSET_BYTES; | 
|  | } | 
|  | } | 
|  |  | 
|  | #endif /* _ASMLANGUAGE */ | 
|  |  | 
|  | #endif /* __RISCV32_LITEX_VEXRISCV_SOC_H_ */ |