xref: /linux-6.15/include/linux/litex.h (revision ffa4ebc4)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 /*
3  * Common LiteX header providing
4  * helper functions for accessing CSRs.
5  *
6  * Copyright (C) 2019-2020 Antmicro <www.antmicro.com>
7  */
8 
9 #ifndef _LINUX_LITEX_H
10 #define _LINUX_LITEX_H
11 
12 #include <linux/io.h>
13 #include <linux/types.h>
14 #include <linux/compiler_types.h>
15 
16 /*
17  * The parameters below are true for LiteX SoCs configured for 8-bit CSR Bus,
18  * 32-bit aligned.
19  *
20  * Supporting other configurations will require extending the logic in this
21  * header and in the LiteX SoC controller driver.
22  */
23 #define LITEX_SUBREG_SIZE	0x1
24 #define LITEX_SUBREG_SIZE_BIT	 (LITEX_SUBREG_SIZE * 8)
25 
26 /* LiteX subregisters of any width are always aligned on a 4-byte boundary */
27 #define LITEX_SUBREG_ALIGN	  0x4
28 
29 static inline void _write_litex_subregister(u32 val, void __iomem *addr)
30 {
31 	writel((u32 __force)cpu_to_le32(val), addr);
32 }
33 
34 static inline u32 _read_litex_subregister(void __iomem *addr)
35 {
36 	return le32_to_cpu((__le32 __force)readl(addr));
37 }
38 
39 #define WRITE_LITEX_SUBREGISTER(val, base_offset, subreg_id) \
40 	_write_litex_subregister(val, (base_offset) + \
41 					LITEX_SUBREG_ALIGN * (subreg_id))
42 
43 #define READ_LITEX_SUBREGISTER(base_offset, subreg_id) \
44 	_read_litex_subregister((base_offset) + \
45 					LITEX_SUBREG_ALIGN * (subreg_id))
46 
47 /*
48  * LiteX SoC Generator, depending on the configuration, can split a single
49  * logical CSR (Control&Status Register) into a series of consecutive physical
50  * registers.
51  *
52  * For example, in the configuration with 8-bit CSR Bus, 32-bit aligned (the
53  * default one for 32-bit CPUs) a 32-bit logical CSR will be generated as four
54  * 32-bit physical registers, each one containing one byte of meaningful data.
55  *
56  * For details see: https://github.com/enjoy-digital/litex/wiki/CSR-Bus
57  *
58  * The purpose of `litex_set_reg`/`litex_get_reg` is to implement the logic
59  * of writing to/reading from the LiteX CSR in a single place that can be
60  * then reused by all LiteX drivers.
61  */
62 
63 /**
64  * litex_set_reg() - Writes the value to the LiteX CSR (Control&Status Register)
65  * @reg: Address of the CSR
66  * @reg_size: The width of the CSR expressed in the number of bytes
67  * @val: Value to be written to the CSR
68  *
69  * In the currently supported LiteX configuration (8-bit CSR Bus, 32-bit aligned),
70  * a 32-bit LiteX CSR is generated as 4 consecutive 32-bit physical registers,
71  * each one containing one byte of meaningful data.
72  *
73  * This function splits a single possibly multi-byte write into a series of
74  * single-byte writes with a proper offset.
75  */
76 static inline void litex_set_reg(void __iomem *reg, ulong reg_size, ulong val)
77 {
78 	ulong shifted_data, shift, i;
79 
80 	for (i = 0; i < reg_size; ++i) {
81 		shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);
82 		shifted_data = val >> shift;
83 
84 		WRITE_LITEX_SUBREGISTER(shifted_data, reg, i);
85 	}
86 }
87 
88 /**
89  * litex_get_reg() - Reads the value of the LiteX CSR (Control&Status Register)
90  * @reg: Address of the CSR
91  * @reg_size: The width of the CSR expressed in the number of bytes
92  *
93  * Return: Value read from the CSR
94  *
95  * In the currently supported LiteX configuration (8-bit CSR Bus, 32-bit aligned),
96  * a 32-bit LiteX CSR is generated as 4 consecutive 32-bit physical registers,
97  * each one containing one byte of meaningful data.
98  *
99  * This function generates a series of single-byte reads with a proper offset
100  * and joins their results into a single multi-byte value.
101  */
102 static inline ulong litex_get_reg(void __iomem *reg, ulong reg_size)
103 {
104 	ulong shifted_data, shift, i;
105 	ulong result = 0;
106 
107 	for (i = 0; i < reg_size; ++i) {
108 		shifted_data = READ_LITEX_SUBREGISTER(reg, i);
109 
110 		shift = ((reg_size - i - 1) * LITEX_SUBREG_SIZE_BIT);
111 		result |= (shifted_data << shift);
112 	}
113 
114 	return result;
115 }
116 
117 
118 static inline void litex_write8(void __iomem *reg, u8 val)
119 {
120 	WRITE_LITEX_SUBREGISTER(val, reg, 0);
121 }
122 
123 static inline void litex_write16(void __iomem *reg, u16 val)
124 {
125 	WRITE_LITEX_SUBREGISTER(val >> 8, reg, 0);
126 	WRITE_LITEX_SUBREGISTER(val, reg, 1);
127 }
128 
129 static inline void litex_write32(void __iomem *reg, u32 val)
130 {
131 	WRITE_LITEX_SUBREGISTER(val >> 24, reg, 0);
132 	WRITE_LITEX_SUBREGISTER(val >> 16, reg, 1);
133 	WRITE_LITEX_SUBREGISTER(val >> 8, reg, 2);
134 	WRITE_LITEX_SUBREGISTER(val, reg, 3);
135 }
136 
137 static inline void litex_write64(void __iomem *reg, u64 val)
138 {
139 	WRITE_LITEX_SUBREGISTER(val >> 56, reg, 0);
140 	WRITE_LITEX_SUBREGISTER(val >> 48, reg, 1);
141 	WRITE_LITEX_SUBREGISTER(val >> 40, reg, 2);
142 	WRITE_LITEX_SUBREGISTER(val >> 32, reg, 3);
143 	WRITE_LITEX_SUBREGISTER(val >> 24, reg, 4);
144 	WRITE_LITEX_SUBREGISTER(val >> 16, reg, 5);
145 	WRITE_LITEX_SUBREGISTER(val >> 8, reg, 6);
146 	WRITE_LITEX_SUBREGISTER(val, reg, 7);
147 }
148 
149 static inline u8 litex_read8(void __iomem *reg)
150 {
151 	return READ_LITEX_SUBREGISTER(reg, 0);
152 }
153 
154 static inline u16 litex_read16(void __iomem *reg)
155 {
156 	return (READ_LITEX_SUBREGISTER(reg, 0) << 8)
157 		| (READ_LITEX_SUBREGISTER(reg, 1));
158 }
159 
160 static inline u32 litex_read32(void __iomem *reg)
161 {
162 	return (READ_LITEX_SUBREGISTER(reg, 0) << 24)
163 		| (READ_LITEX_SUBREGISTER(reg, 1) << 16)
164 		| (READ_LITEX_SUBREGISTER(reg, 2) << 8)
165 		| (READ_LITEX_SUBREGISTER(reg, 3));
166 }
167 
168 static inline u64 litex_read64(void __iomem *reg)
169 {
170 	return ((u64)READ_LITEX_SUBREGISTER(reg, 0) << 56)
171 		| ((u64)READ_LITEX_SUBREGISTER(reg, 1) << 48)
172 		| ((u64)READ_LITEX_SUBREGISTER(reg, 2) << 40)
173 		| ((u64)READ_LITEX_SUBREGISTER(reg, 3) << 32)
174 		| ((u64)READ_LITEX_SUBREGISTER(reg, 4) << 24)
175 		| ((u64)READ_LITEX_SUBREGISTER(reg, 5) << 16)
176 		| ((u64)READ_LITEX_SUBREGISTER(reg, 6) << 8)
177 		| ((u64)READ_LITEX_SUBREGISTER(reg, 7));
178 }
179 
180 #endif /* _LINUX_LITEX_H */
181