Angel Pons | 32859fc | 2020-04-02 23:48:27 +0200 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
Kyösti Mälkki | 13f6650 | 2019-03-03 08:01:05 +0200 | [diff] [blame] | 2 | |
| 3 | #ifndef __DEVICE_MMIO_H__ |
| 4 | #define __DEVICE_MMIO_H__ |
| 5 | |
Elyes Haouas | 35c3ae3b | 2022-10-27 12:25:12 +0200 | [diff] [blame] | 6 | #include <arch/mmio.h> /* IWYU pragma: export */ |
Yu-Ping Wu | 941db0e | 2021-07-23 16:17:11 +0800 | [diff] [blame] | 7 | #include <commonlib/helpers.h> |
Kyösti Mälkki | 3ee8b75 | 2019-03-03 00:35:15 +0200 | [diff] [blame] | 8 | #include <endian.h> |
Julius Werner | db7f6fb | 2019-08-12 16:45:21 -0700 | [diff] [blame] | 9 | #include <types.h> |
Kyösti Mälkki | 13f6650 | 2019-03-03 08:01:05 +0200 | [diff] [blame] | 10 | |
Julius Werner | 1c37157 | 2019-12-02 18:02:51 -0800 | [diff] [blame] | 11 | #define __clrsetbits_impl(bits, addr, clear, set) write##bits(addr, \ |
| 12 | (read##bits(addr) & ~((uint##bits##_t)(clear))) | (set)) |
| 13 | |
| 14 | #define clrsetbits8(addr, clear, set) __clrsetbits_impl(8, addr, clear, set) |
| 15 | #define clrsetbits16(addr, clear, set) __clrsetbits_impl(16, addr, clear, set) |
| 16 | #define clrsetbits32(addr, clear, set) __clrsetbits_impl(32, addr, clear, set) |
| 17 | #define clrsetbits64(addr, clear, set) __clrsetbits_impl(64, addr, clear, set) |
| 18 | |
| 19 | #define setbits8(addr, set) clrsetbits8(addr, 0, set) |
| 20 | #define setbits16(addr, set) clrsetbits16(addr, 0, set) |
| 21 | #define setbits32(addr, set) clrsetbits32(addr, 0, set) |
| 22 | #define setbits64(addr, set) clrsetbits64(addr, 0, set) |
| 23 | |
| 24 | #define clrbits8(addr, clear) clrsetbits8(addr, clear, 0) |
| 25 | #define clrbits16(addr, clear) clrsetbits16(addr, clear, 0) |
| 26 | #define clrbits32(addr, clear) clrsetbits32(addr, clear, 0) |
| 27 | #define clrbits64(addr, clear) clrsetbits64(addr, clear, 0) |
| 28 | |
Michael Niewöhner | df8677c | 2022-06-20 21:32:56 +0200 | [diff] [blame] | 29 | #define clrsetbits8p(addr, clear, set) clrsetbits8((void *)((uintptr_t)addr), clear, set) |
| 30 | #define clrsetbits16p(addr, clear, set) clrsetbits16((void *)((uintptr_t)addr), clear, set) |
| 31 | #define clrsetbits32p(addr, clear, set) clrsetbits32((void *)((uintptr_t)addr), clear, set) |
| 32 | #define clrsetbits64p(addr, clear, set) clrsetbits64((void *)((uintptr_t)addr), clear, set) |
| 33 | |
| 34 | #define setbits8p(addr, set) clrsetbits8((void *)((uintptr_t)addr), 0, set) |
| 35 | #define setbits16p(addr, set) clrsetbits16((void *)((uintptr_t)addr), 0, set) |
| 36 | #define setbits32p(addr, set) clrsetbits32((void *)((uintptr_t)addr), 0, set) |
| 37 | #define setbits64p(addr, set) clrsetbits64((void *)((uintptr_t)addr), 0, set) |
| 38 | |
| 39 | #define clrbits8p(addr, clear) clrsetbits8((void *)((uintptr_t)addr), clear, 0) |
| 40 | #define clrbits16p(addr, clear) clrsetbits16((void *)((uintptr_t)addr), clear, 0) |
| 41 | #define clrbits32p(addr, clear) clrsetbits32((void *)((uintptr_t)addr), clear, 0) |
| 42 | #define clrbits64p(addr, clear) clrsetbits64((void *)((uintptr_t)addr), clear, 0) |
| 43 | |
Julius Werner | db7f6fb | 2019-08-12 16:45:21 -0700 | [diff] [blame] | 44 | /* |
| 45 | * Reads a transfer buffer from 32-bit FIFO registers. fifo_stride is the |
| 46 | * distance in bytes between registers (e.g. pass 4 for a normal array of 32-bit |
| 47 | * registers or 0 to read everything from the same register). fifo_width is |
| 48 | * the amount of bytes read per register (can be 1 through 4). |
| 49 | */ |
| 50 | void buffer_from_fifo32(void *buffer, size_t size, void *fifo, |
| 51 | int fifo_stride, int fifo_width); |
| 52 | |
| 53 | /* |
| 54 | * Version of buffer_to_fifo32() that can prepend a prefix of up to fifo_width |
| 55 | * size to the transfer. This is often useful for protocols where a command word |
| 56 | * precedes the actual payload data. The prefix must be packed in the low-order |
| 57 | * bytes of the 'prefix' u32 parameter and any high-order bytes exceeding prefsz |
| 58 | * must be 0. Note that 'size' counts total bytes written, including 'prefsz'. |
| 59 | */ |
Julius Werner | ea03d00 | 2021-09-16 15:53:32 -0700 | [diff] [blame] | 60 | void buffer_to_fifo32_prefix(const void *buffer, u32 prefix, int prefsz, size_t size, |
Julius Werner | db7f6fb | 2019-08-12 16:45:21 -0700 | [diff] [blame] | 61 | void *fifo, int fifo_stride, int fifo_width); |
| 62 | |
| 63 | /* |
| 64 | * Writes a transfer buffer into 32-bit FIFO registers. fifo_stride is the |
| 65 | * distance in bytes between registers (e.g. pass 4 for a normal array of 32-bit |
| 66 | * registers or 0 to write everything into the same register). fifo_width is |
| 67 | * the amount of bytes written per register (can be 1 through 4). |
| 68 | */ |
Julius Werner | ea03d00 | 2021-09-16 15:53:32 -0700 | [diff] [blame] | 69 | static inline void buffer_to_fifo32(const void *buffer, size_t size, void *fifo, |
Julius Werner | db7f6fb | 2019-08-12 16:45:21 -0700 | [diff] [blame] | 70 | int fifo_stride, int fifo_width) |
| 71 | { |
Julius Werner | 9f19dd9 | 2019-11-18 18:21:27 -0800 | [diff] [blame] | 72 | buffer_to_fifo32_prefix(buffer, 0, 0, size, fifo, |
Julius Werner | db7f6fb | 2019-08-12 16:45:21 -0700 | [diff] [blame] | 73 | fifo_stride, fifo_width); |
| 74 | } |
Hung-Te Lin | 0962b1f | 2019-09-19 11:23:30 +0800 | [diff] [blame] | 75 | |
| 76 | /* |
| 77 | * Utilities to help processing bit fields. |
| 78 | * |
| 79 | * To define a bit field (usually inside a register), do: |
| 80 | * |
| 81 | * DEFINE_BITFIELD(name, high_bit, low_bit) |
| 82 | * |
| 83 | * - name: Name of the field to access. |
| 84 | * - high_bit: highest bit that's part of the bit field. |
| 85 | * - low_bit: lowest bit in the bit field. |
| 86 | * |
Hung-Te Lin | dafb661 | 2019-10-04 14:48:46 +0800 | [diff] [blame] | 87 | * To define a field with a single bit: |
| 88 | * |
| 89 | * DEFINE_BIT(name, bit) |
| 90 | * |
Hung-Te Lin | 0962b1f | 2019-09-19 11:23:30 +0800 | [diff] [blame] | 91 | * To extract one field value from a raw reg value: |
| 92 | * |
| 93 | * EXTRACT_BITFIELD(value, name); |
| 94 | * |
| 95 | * To read from an MMIO register and extract one field from it: |
| 96 | * |
| 97 | * READ32_BITFIELD(®, name); |
| 98 | * |
| 99 | * To write into an MMIO register, set given fields (by names) to specified |
| 100 | * values, and all other bits to zero (usually used for resetting a register): |
| 101 | * |
| 102 | * WRITE32_BITFIELDS(®, name, value, [name, value, ...]) |
| 103 | * |
| 104 | * To write into an MMIO register, set given fields (by names) to specified |
| 105 | * values, and leaving all others "unchanged" (usually used for updating some |
| 106 | * settings): |
| 107 | * |
| 108 | * SET32_BITFIELDS(®, name, value, [name, value, ...]) |
| 109 | * |
| 110 | * Examples: |
| 111 | * |
| 112 | * DEFINE_BITFIELD(DISP_TYPE, 2, 1) |
Hung-Te Lin | dafb661 | 2019-10-04 14:48:46 +0800 | [diff] [blame] | 113 | * DEFINE_BIT(DISP_EN, 0) |
Hung-Te Lin | 0962b1f | 2019-09-19 11:23:30 +0800 | [diff] [blame] | 114 | * |
| 115 | * SET32_BITFIELDS(&disp_regs.ctrl, DISP_TYPE, 2); |
| 116 | * SET32_BITFIELDS(&disp_regs.ctrl, DISP_EN, 0); |
| 117 | * |
| 118 | * SET32_BITFIELDS(&disp_regs.ctrl, DISP_TYPE, 1, DISP_EN, 1); |
| 119 | * WRITE32_BITFIELDS(&disp_regs.ctrl, DISP_TYPE, 1, DISP_EN, 1); |
| 120 | * |
| 121 | * READ32_BITFIELD(®, DISP_TYPE) |
| 122 | * EXTRACT_BITFIELD(value, DISP_TYPE) |
| 123 | * |
| 124 | * These will be translated to: |
| 125 | * |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 126 | * clrsetbits32(&disp_regs.ctrl, 0x6, 0x4); |
| 127 | * clrsetbits32(&disp_regs.ctrl, 0x1, 0x0); |
Hung-Te Lin | 0962b1f | 2019-09-19 11:23:30 +0800 | [diff] [blame] | 128 | * |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 129 | * clrsetbits32(&disp_regs.ctrl, 0x7, 0x3); |
Hung-Te Lin | 0962b1f | 2019-09-19 11:23:30 +0800 | [diff] [blame] | 130 | * write32(&disp_regs.ctrl, 0x3); |
| 131 | * |
| 132 | * (read32(®) & 0x6) >> 1 |
| 133 | * (value & 0x6) >> 1 |
| 134 | * |
| 135 | * The {WRITE,SET}32_BITFIELDS currently only allows setting up to 8 fields at |
| 136 | * one invocation. |
| 137 | */ |
| 138 | |
| 139 | #define DEFINE_BITFIELD(name, high_bit, low_bit) \ |
| 140 | _Static_assert(high_bit >= low_bit, "invalid bit field range"); \ |
| 141 | enum { \ |
| 142 | name##_BITFIELD_SHIFT = (low_bit), \ |
| 143 | name##_BITFIELD_SIZE = (high_bit) - (low_bit) + 1, \ |
| 144 | }; |
| 145 | |
Hung-Te Lin | dafb661 | 2019-10-04 14:48:46 +0800 | [diff] [blame] | 146 | #define DEFINE_BIT(name, bit) DEFINE_BITFIELD(name, bit, bit) |
| 147 | |
Hung-Te Lin | 0962b1f | 2019-09-19 11:23:30 +0800 | [diff] [blame] | 148 | #define _BF_MASK(name, value) \ |
Yu-Ping Wu | 941db0e | 2021-07-23 16:17:11 +0800 | [diff] [blame] | 149 | ((u32)GENMASK(name##_BITFIELD_SHIFT + name##_BITFIELD_SIZE - 1, \ |
| 150 | name##_BITFIELD_SHIFT)) |
Hung-Te Lin | 0962b1f | 2019-09-19 11:23:30 +0800 | [diff] [blame] | 151 | |
| 152 | #define _BF_VALUE(name, value) \ |
Hung-Te Lin | 85ecdb1 | 2020-04-15 20:54:14 +0800 | [diff] [blame] | 153 | (((u32)(value) << name##_BITFIELD_SHIFT) & _BF_MASK(name, 0)) |
Hung-Te Lin | 0962b1f | 2019-09-19 11:23:30 +0800 | [diff] [blame] | 154 | |
| 155 | #define _BF_APPLY1(op, name, value, ...) (op(name, value)) |
| 156 | #define _BF_APPLY2(op, name, value, ...) ((op(name, value)) | \ |
| 157 | _BF_APPLY1(op, __VA_ARGS__)) |
| 158 | #define _BF_APPLY3(op, name, value, ...) ((op(name, value)) | \ |
| 159 | _BF_APPLY2(op, __VA_ARGS__)) |
| 160 | #define _BF_APPLY4(op, name, value, ...) ((op(name, value)) | \ |
| 161 | _BF_APPLY3(op, __VA_ARGS__)) |
| 162 | #define _BF_APPLY5(op, name, value, ...) ((op(name, value)) | \ |
| 163 | _BF_APPLY4(op, __VA_ARGS__)) |
| 164 | #define _BF_APPLY6(op, name, value, ...) ((op(name, value)) | \ |
| 165 | _BF_APPLY5(op, __VA_ARGS__)) |
| 166 | #define _BF_APPLY7(op, name, value, ...) ((op(name, value)) | \ |
| 167 | _BF_APPLY6(op, __VA_ARGS__)) |
| 168 | #define _BF_APPLY8(op, name, value, ...) ((op(name, value)) | \ |
| 169 | _BF_APPLY7(op, __VA_ARGS__)) |
Huayang Duan | 232d8a8 | 2020-06-23 12:25:24 +0800 | [diff] [blame] | 170 | #define _BF_APPLY9(op, name, value, ...) ((op(name, value)) | \ |
| 171 | _BF_APPLY8(op, __VA_ARGS__)) |
| 172 | #define _BF_APPLY10(op, name, value, ...) ((op(name, value)) | \ |
| 173 | _BF_APPLY9(op, __VA_ARGS__)) |
| 174 | #define _BF_APPLY11(op, name, value, ...) ((op(name, value)) | \ |
| 175 | _BF_APPLY10(op, __VA_ARGS__)) |
| 176 | #define _BF_APPLY12(op, name, value, ...) ((op(name, value)) | \ |
| 177 | _BF_APPLY11(op, __VA_ARGS__)) |
| 178 | #define _BF_APPLY13(op, name, value, ...) ((op(name, value)) | \ |
| 179 | _BF_APPLY12(op, __VA_ARGS__)) |
| 180 | #define _BF_APPLY14(op, name, value, ...) ((op(name, value)) | \ |
| 181 | _BF_APPLY13(op, __VA_ARGS__)) |
| 182 | #define _BF_APPLY15(op, name, value, ...) ((op(name, value)) | \ |
| 183 | _BF_APPLY14(op, __VA_ARGS__)) |
| 184 | #define _BF_APPLY16(op, name, value, ...) ((op(name, value)) | \ |
| 185 | _BF_APPLY15(op, __VA_ARGS__)) |
Hung-Te Lin | 0962b1f | 2019-09-19 11:23:30 +0800 | [diff] [blame] | 186 | #define _BF_APPLYINVALID(...) \ |
| 187 | _Static_assert(0, "Invalid arguments for {WRITE,SET}*_BITFIELDS") |
| 188 | |
| 189 | #define _BF_IMPL2(op, addr, \ |
| 190 | n1, v1, n2, v2, n3, v3, n4, v4, n5, v5, n6, v6, n7, v7, n8, v8, \ |
Huayang Duan | 232d8a8 | 2020-06-23 12:25:24 +0800 | [diff] [blame] | 191 | n9, v9, n10, v10, n11, v11, n12, v12, n13, v13, n14, v14, n15, v15, n16, v16, \ |
Hung-Te Lin | 0962b1f | 2019-09-19 11:23:30 +0800 | [diff] [blame] | 192 | NARGS, ...) \ |
| 193 | \ |
| 194 | op(addr, \ |
| 195 | _BF_APPLY##NARGS(_BF_MASK, n1, v1, n2, v2, n3, v3, n4, v4, \ |
Huayang Duan | 232d8a8 | 2020-06-23 12:25:24 +0800 | [diff] [blame] | 196 | n5, v5, n6, v6, n7, v7, n8, v8, \ |
| 197 | n9, v9, n10, v10, n11, v11, n12, v12, \ |
| 198 | n13, v13, n14, v14, n15, v15, n16, v16), \ |
Hung-Te Lin | 0962b1f | 2019-09-19 11:23:30 +0800 | [diff] [blame] | 199 | _BF_APPLY##NARGS(_BF_VALUE, n1, v1, n2, v2, n3, v3, n4, v4, \ |
Huayang Duan | 232d8a8 | 2020-06-23 12:25:24 +0800 | [diff] [blame] | 200 | n5, v5, n6, v6, n7, v7, n8, v8,\ |
| 201 | n9, v9, n10, v10, n11, v11, n12, v12, \ |
| 202 | n13, v13, n14, v14, n15, v15, n16, v16)) |
Hung-Te Lin | 0962b1f | 2019-09-19 11:23:30 +0800 | [diff] [blame] | 203 | |
| 204 | #define _BF_IMPL(op, addr, ...) \ |
| 205 | _BF_IMPL2(op, addr, __VA_ARGS__, \ |
Huayang Duan | 232d8a8 | 2020-06-23 12:25:24 +0800 | [diff] [blame] | 206 | 16, INVALID, 15, INVALID, 14, INVALID, 13, INVALID, \ |
| 207 | 12, INVALID, 11, INVALID, 10, INVALID, 9, INVALID, \ |
Hung-Te Lin | 0962b1f | 2019-09-19 11:23:30 +0800 | [diff] [blame] | 208 | 8, INVALID, 7, INVALID, 6, INVALID, 5, INVALID, \ |
| 209 | 4, INVALID, 3, INVALID, 2, INVALID, 1, INVALID) |
| 210 | |
| 211 | #define _WRITE32_BITFIELDS_IMPL(addr, masks, values) write32(addr, values) |
| 212 | |
| 213 | #define WRITE32_BITFIELDS(addr, ...) \ |
| 214 | _BF_IMPL(_WRITE32_BITFIELDS_IMPL, addr, __VA_ARGS__) |
| 215 | |
| 216 | #define SET32_BITFIELDS(addr, ...) \ |
Julius Werner | 55009af | 2019-12-02 22:03:27 -0800 | [diff] [blame] | 217 | _BF_IMPL(clrsetbits32, addr, __VA_ARGS__) |
Hung-Te Lin | 0962b1f | 2019-09-19 11:23:30 +0800 | [diff] [blame] | 218 | |
| 219 | #define EXTRACT_BITFIELD(value, name) \ |
| 220 | (((value) & _BF_MASK(name, 0)) >> name##_BITFIELD_SHIFT) |
| 221 | |
| 222 | #define READ32_BITFIELD(addr, name) \ |
| 223 | EXTRACT_BITFIELD(read32(addr), name) |
| 224 | |
Jianjun Wang | 8565b94a | 2022-03-02 10:20:26 +0800 | [diff] [blame] | 225 | static __always_inline uint8_t read8p(const uintptr_t addr) |
| 226 | { |
| 227 | return read8((void *)addr); |
| 228 | } |
| 229 | |
| 230 | static __always_inline uint16_t read16p(const uintptr_t addr) |
| 231 | { |
| 232 | return read16((void *)addr); |
| 233 | } |
| 234 | |
| 235 | static __always_inline uint32_t read32p(const uintptr_t addr) |
| 236 | { |
| 237 | return read32((void *)addr); |
| 238 | } |
| 239 | |
| 240 | static __always_inline uint64_t read64p(const uintptr_t addr) |
| 241 | { |
| 242 | return read64((void *)addr); |
| 243 | } |
| 244 | |
| 245 | static __always_inline void write8p(const uintptr_t addr, const uint8_t value) |
| 246 | { |
| 247 | write8((void *)addr, value); |
| 248 | } |
| 249 | |
| 250 | static __always_inline void write16p(const uintptr_t addr, const uint16_t value) |
| 251 | { |
| 252 | write16((void *)addr, value); |
| 253 | } |
| 254 | |
| 255 | static __always_inline void write32p(const uintptr_t addr, const uint32_t value) |
| 256 | { |
| 257 | write32((void *)addr, value); |
| 258 | } |
| 259 | |
| 260 | static __always_inline void write64p(const uintptr_t addr, const uint64_t value) |
| 261 | { |
| 262 | write64((void *)addr, value); |
| 263 | } |
| 264 | |
Julius Werner | db7f6fb | 2019-08-12 16:45:21 -0700 | [diff] [blame] | 265 | #endif /* __DEVICE_MMIO_H__ */ |