1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef _HARDWARE_GPIO_COPROC_H
8 #define _HARDWARE_GPIO_COPROC_H
9 
10 #ifdef __riscv
11 #error "GPIO coprocessor port is not available on RISC-V"
12 #endif
13 
14 #if PICO_RP2040
15 #error "GPIO coprocessor is not available on RP2040"
16 #endif
17 
18 #if !HAS_GPIO_COPROCESSOR
19 #error "GPIO coprocessor is not available"
20 #endif
21 
22 #include "pico.h"
23 
24 // ----------------------------------------------------------------------------
25 // OUT mask write instructions
26 
27 // Equivalent to sio_hw->gpio_out = x;
gpioc_lo_out_put(uint32_t x)28 __force_inline static void gpioc_lo_out_put(uint32_t x) {
29     pico_default_asm_volatile ("mcr p0, #0, %0, c0, c0" : : "r" (x));
30 }
31 
32 // Equivalent to sio_hw->gpio_togl = x;
gpioc_lo_out_xor(uint32_t x)33 __force_inline static void gpioc_lo_out_xor(uint32_t x) {
34     pico_default_asm_volatile ("mcr p0, #1, %0, c0, c0" : : "r" (x));
35 }
36 
37 // Equivalent to sio_hw->gpio_set = x;
gpioc_lo_out_set(uint32_t x)38 __force_inline static void gpioc_lo_out_set(uint32_t x) {
39     pico_default_asm_volatile ("mcr p0, #2, %0, c0, c0" : : "r" (x));
40 }
41 
42 // Equivalent to sio_hw->gpio_clr = x;
gpioc_lo_out_clr(uint32_t x)43 __force_inline static void gpioc_lo_out_clr(uint32_t x) {
44     pico_default_asm_volatile ("mcr p0, #3, %0, c0, c0" : : "r" (x));
45 }
46 
47 // Equivalent to sio_hw->gpio_hi_out = x;
gpioc_hi_out_put(uint32_t x)48 __force_inline static void gpioc_hi_out_put(uint32_t x) {
49     pico_default_asm_volatile ("mcr p0, #0, %0, c0, c1" : : "r" (x));
50 }
51 
52 // Equivalent to sio_hw->gpio_hi_togl = x;
gpioc_hi_out_xor(uint32_t x)53 __force_inline static void gpioc_hi_out_xor(uint32_t x) {
54     pico_default_asm_volatile ("mcr p0, #1, %0, c0, c1" : : "r" (x));
55 }
56 
57 // Equivalent to sio_hw->gpio_hi_set = x;
gpioc_hi_out_set(uint32_t x)58 __force_inline static void gpioc_hi_out_set(uint32_t x) {
59     pico_default_asm_volatile ("mcr p0, #2, %0, c0, c1" : : "r" (x));
60 }
61 
62 // Equivalent to sio_hw->gpio_hi_clr = x;
gpioc_hi_out_clr(uint32_t x)63 __force_inline static void gpioc_hi_out_clr(uint32_t x) {
64     pico_default_asm_volatile ("mcr p0, #3, %0, c0, c1" : : "r" (x));
65 }
66 
67 // Equivalent to these two operations performed on the same cycle:
68 // - sio_hw->gpio_out    = x & 0xffffffff;
69 // - sio_hw->gpio_hi_out = x >> 32;
gpioc_hilo_out_put(uint64_t x)70 __force_inline static void gpioc_hilo_out_put(uint64_t x) {
71     pico_default_asm_volatile ("mcrr p0, #0, %0, %1, c0" : : "r" (x & 0xffffffffu), "r" (x >> 32));
72 }
73 
74 // Equivalent to these two operations performed on the same cycle:
75 // - sio_hw->gpio_togl    = x & 0xffffffff;
76 // - sio_hw->gpio_hi_togl = x >> 32;
gpioc_hilo_out_xor(uint64_t x)77 __force_inline static void gpioc_hilo_out_xor(uint64_t x) {
78     pico_default_asm_volatile ("mcrr p0, #1, %0, %1, c0" : : "r" (x & 0xffffffffu), "r" (x >> 32));
79 }
80 
81 // Equivalent to these two operations performed on the same cycle:
82 // - sio_hw->gpio_set    = x & 0xffffffff;
83 // - sio_hw->gpio_hi_set = x >> 32;
gpioc_hilo_out_set(uint64_t x)84 __force_inline static void gpioc_hilo_out_set(uint64_t x) {
85     pico_default_asm_volatile ("mcrr p0, #2, %0, %1, c0" : : "r" (x & 0xffffffffu), "r" (x >> 32));
86 }
87 
88 // Equivalent to these two operations performed on the same cycle:
89 // - sio_hw->gpio_clr    = x & 0xffffffff;
90 // - sio_hw->gpio_hi_clr = x >> 32;
gpioc_hilo_out_clr(uint64_t x)91 __force_inline static void gpioc_hilo_out_clr(uint64_t x) {
92     pico_default_asm_volatile ("mcrr p0, #3, %0, %1, c0" : : "r" (x & 0xffffffffu), "r" (x >> 32));
93 }
94 
95 // ----------------------------------------------------------------------------
96 // OE mask write instructions
97 
98 // Equivalent to sio_hw->gpio_oe = x;
gpioc_lo_oe_put(uint32_t x)99 __force_inline static void gpioc_lo_oe_put(uint32_t x) {
100     pico_default_asm_volatile ("mcr p0, #0, %0, c0, c4" : : "r" (x));
101 }
102 
103 // Equivalent to sio_hw->gpio_oe_togl = x;
gpioc_lo_oe_xor(uint32_t x)104 __force_inline static void gpioc_lo_oe_xor(uint32_t x) {
105     pico_default_asm_volatile ("mcr p0, #1, %0, c0, c4" : : "r" (x));
106 }
107 
108 // Equivalent to sio_hw->gpio_oe_set = x;
gpioc_lo_oe_set(uint32_t x)109 __force_inline static void gpioc_lo_oe_set(uint32_t x) {
110     pico_default_asm_volatile ("mcr p0, #2, %0, c0, c4" : : "r" (x));
111 }
112 
113 // Equivalent to sio_hw->gpio_oe_clr = x;
gpioc_lo_oe_clr(uint32_t x)114 __force_inline static void gpioc_lo_oe_clr(uint32_t x) {
115     pico_default_asm_volatile ("mcr p0, #3, %0, c0, c4" : : "r" (x));
116 }
117 
118 // Equivalent to sio_hw->gpio_hi_oe = x;
gpioc_hi_oe_put(uint32_t x)119 __force_inline static void gpioc_hi_oe_put(uint32_t x) {
120     pico_default_asm_volatile ("mcr p0, #0, %0, c0, c5" : : "r" (x));
121 }
122 
123 // Equivalent to sio_hw->gpio_hi_oe_togl = x;
gpioc_hi_oe_xor(uint32_t x)124 __force_inline static void gpioc_hi_oe_xor(uint32_t x) {
125     pico_default_asm_volatile ("mcr p0, #1, %0, c0, c5" : : "r" (x));
126 }
127 
128 // Equivalent to sio_hw->gpio_hi_oe_set = x;
gpioc_hi_oe_set(uint32_t x)129 __force_inline static void gpioc_hi_oe_set(uint32_t x) {
130     pico_default_asm_volatile ("mcr p0, #2, %0, c0, c5" : : "r" (x));
131 }
132 
133 // Equivalent to sio_hw->gpio_hi_oe_clr = x;
gpioc_hi_oe_clr(uint32_t x)134 __force_inline static void gpioc_hi_oe_clr(uint32_t x) {
135     pico_default_asm_volatile ("mcr p0, #3, %0, c0, c5" : : "r" (x));
136 }
137 
138 // Equivalent to these two operations performed on the same cycle:
139 // - sio_hw->gpio_oe    = x & 0xffffffff;
140 // - sio_hw->gpio_hi_oe = x >> 32;
gpioc_hilo_oe_put(uint64_t x)141 __force_inline static void gpioc_hilo_oe_put(uint64_t x) {
142     pico_default_asm_volatile ("mcrr p0, #0, %0, %1, c4" : : "r" (x & 0xffffffffu), "r" (x >> 32));
143 }
144 
145 // Equivalent to these two operations performed on the same cycle:
146 // - sio_hw->gpio_oe_togl    = x & 0xffffffff;
147 // - sio_hw->gpio_hi_oe_togl = x >> 32;
gpioc_hilo_oe_xor(uint64_t x)148 __force_inline static void gpioc_hilo_oe_xor(uint64_t x) {
149     pico_default_asm_volatile ("mcrr p0, #1, %0, %1, c4" : : "r" (x & 0xffffffffu), "r" (x >> 32));
150 }
151 
152 // Equivalent to these two operations performed on the same cycle:
153 // - sio_hw->gpio_oe_set    = x & 0xffffffff;
154 // - sio_hw->gpio_hi_oe_set = x >> 32;
gpioc_hilo_oe_set(uint64_t x)155 __force_inline static void gpioc_hilo_oe_set(uint64_t x) {
156     pico_default_asm_volatile ("mcrr p0, #2, %0, %1, c4" : : "r" (x & 0xffffffffu), "r" (x >> 32));
157 }
158 
159 // Equivalent to these two operations performed on the same cycle:
160 // - sio_hw->gpio_oe_clr    = x & 0xffffffff;
161 // - sio_hw->gpio_hi_oe_clr = x >> 32;
gpioc_hilo_oe_clr(uint64_t x)162 __force_inline static void gpioc_hilo_oe_clr(uint64_t x) {
163     pico_default_asm_volatile ("mcrr p0, #3, %0, %1, c4" : : "r" (x & 0xffffffffu), "r" (x >> 32));
164 }
165 
166 // ----------------------------------------------------------------------------
167 // Single-bit write instructions
168 
169 // Write a 1-bit value to any output. Equivalent to:
170 //
171 //     if (val)
172 //         gpioc_hilo_out_set(1ull << pin);
173 //     else
174 //         gpioc_hilo_out_clr(1ull << pin);
gpioc_bit_out_put(uint pin,bool val)175 __force_inline static void gpioc_bit_out_put(uint pin, bool val) {
176     pico_default_asm_volatile ("mcrr p0, #4, %0, %1, c0" : : "r" (pin), "r" (val));
177 }
178 
179 // Unconditionally toggle any single output. Equivalent to:
180 //
181 //     gpioc_hilo_out_xor(1ull << pin);
gpioc_bit_out_xor(uint pin)182 __force_inline static void gpioc_bit_out_xor(uint pin) {
183     pico_default_asm_volatile ("mcr p0, #5, %0, c0, c0" : : "r" (pin));
184 }
185 
186 // Unconditionally set any single output. Equivalent to:
187 //
188 //     gpioc_hilo_out_set(1ull << pin);
gpioc_bit_out_set(uint pin)189 __force_inline static void gpioc_bit_out_set(uint pin) {
190     pico_default_asm_volatile ("mcr p0, #6, %0, c0, c0" : : "r" (pin));
191 }
192 
193 // Unconditionally clear any single output. Equivalent to:
194 //
195 //     gpioc_hilo_out_clr(1ull << pin);
gpioc_bit_out_clr(uint pin)196 __force_inline static void gpioc_bit_out_clr(uint pin) {
197     pico_default_asm_volatile ("mcr p0, #7, %0, c0, c0" : : "r" (pin));
198 }
199 
200 // Conditionally toggle any single output. Equivalent to:
201 //
202 //     gpioc_hilo_out_xor((uint64_t)val << pin);
gpioc_bit_out_xor2(uint pin,bool val)203 __force_inline static void gpioc_bit_out_xor2(uint pin, bool val) {
204     pico_default_asm_volatile ("mcrr p0, #5, %0, %1, c0" : : "r" (pin), "r" (val));
205 }
206 
207 // Conditionally set any single output. Equivalent to:
208 //
209 //     gpioc_hilo_out_set((uint64_t)val << pin);
gpioc_bit_out_set2(uint pin,bool val)210 __force_inline static void gpioc_bit_out_set2(uint pin, bool val) {
211     pico_default_asm_volatile ("mcrr p0, #6, %0, %1, c0" : : "r" (pin), "r" (val));
212 }
213 
214 // Conditionally clear any single output. Equivalent to:
215 //
216 //     gpioc_hilo_out_clr((uint64_t)val << pin);
gpioc_bit_out_clr2(uint pin,bool val)217 __force_inline static void gpioc_bit_out_clr2(uint pin, bool val) {
218     pico_default_asm_volatile ("mcrr p0, #7, %0, %1, c0" : : "r" (pin), "r" (val));
219 }
220 
221 // Write a 1-bit value to any output enable. Equivalent to:
222 //
223 //     if (val)
224 //         gpioc_hilo_oe_set(1ull << pin);
225 //     else
226 //         gpioc_hilo_oe_clr(1ull << pin);
gpioc_bit_oe_put(uint pin,bool val)227 __force_inline static void gpioc_bit_oe_put(uint pin, bool val) {
228     pico_default_asm_volatile ("mcrr p0, #4, %0, %1, c4" : : "r" (pin), "r" (val));
229 }
230 
231 // Unconditionally toggle any output enable. Equivalent to:
232 //
233 //     gpioc_hilo_oe_xor(1ull << pin);
gpioc_bit_oe_xor(uint pin)234 __force_inline static void gpioc_bit_oe_xor(uint pin) {
235     pico_default_asm_volatile ("mcr p0, #5, %0, c0, c4" : : "r" (pin));
236 }
237 
238 // Unconditionally set any output enable (set to output). Equivalent to:
239 //
240 //     gpioc_hilo_oe_set(1ull << pin);
gpioc_bit_oe_set(uint pin)241 __force_inline static void gpioc_bit_oe_set(uint pin) {
242     pico_default_asm_volatile ("mcr p0, #6, %0, c0, c4" : : "r" (pin));
243 }
244 
245 // Unconditionally clear any output enable (set to input). Equivalent to:
246 //
247 //     gpioc_hilo_oe_clr(1ull << pin);
gpioc_bit_oe_clr(uint pin)248 __force_inline static void gpioc_bit_oe_clr(uint pin) {
249     pico_default_asm_volatile ("mcr p0, #7, %0, c0, c4" : : "r" (pin));
250 }
251 
252 // Conditionally toggle any output enable. Equivalent to:
253 //
254 //     gpioc_hilo_oe_xor((uint64_t)val << pin);
gpioc_bit_oe_xor2(uint pin,bool val)255 __force_inline static void gpioc_bit_oe_xor2(uint pin, bool val) {
256     pico_default_asm_volatile ("mcrr p0, #5, %0, %1, c4" : : "r" (pin), "r" (val));
257 }
258 
259 // Conditionally set any output enable (set to output). Equivalent to:
260 //
261 //     gpioc_hilo_oe_set((uint64_t)val << pin);
gpioc_bit_oe_set2(uint pin,bool val)262 __force_inline static void gpioc_bit_oe_set2(uint pin, bool val) {
263     pico_default_asm_volatile ("mcrr p0, #6, %0, %1, c4" : : "r" (pin), "r" (val));
264 }
265 
266 // Conditionally clear any output enable (set to input). Equivalent to:
267 //
268 //     gpioc_hilo_oe_clr((uint64_t)val << pin);
gpioc_bit_oe_clr2(uint pin,bool val)269 __force_inline static void gpioc_bit_oe_clr2(uint pin, bool val) {
270     pico_default_asm_volatile ("mcrr p0, #7, %0, %1, c4" : : "r" (pin), "r" (val));
271 }
272 
273 // ----------------------------------------------------------------------------
274 // Indexed mask write instructions -- write to a dynamically selected 32-bit
275 // GPIO register
276 
277 // Write to a selected GPIO output register. Equivalent to:
278 //
279 //     if (reg_index == 0) {
280 //         gpioc_lo_out_put(val);
281 //     } else if (reg_index == 1) {
282 //         gpioc_hi_out_put(val);
283 //     } else {
284 //         // undefined
285 //     }
gpioc_index_out_put(uint reg_index,uint32_t val)286 __force_inline static void gpioc_index_out_put(uint reg_index, uint32_t val) {
287     pico_default_asm_volatile ("mcrr p0, #8, %1, %0, c0" : : "r" (reg_index), "r" (val));
288 }
289 
290 // Toggle bits in a selected GPIO output register. Equivalent to:
291 //
292 //     if (reg_index == 0) {
293 //         gpioc_lo_out_xor(val);
294 //     } else if (reg_index == 1) {
295 //         gpioc_hi_out_xor(val);
296 //     } else {
297 //         // undefined
298 //     }
gpioc_index_out_xor(uint reg_index,uint32_t mask)299 __force_inline static void gpioc_index_out_xor(uint reg_index, uint32_t mask) {
300     pico_default_asm_volatile ("mcrr p0, #9, %1, %0, c0" : : "r" (reg_index), "r" (mask));
301 }
302 
303 // Set bits in a selected GPIO output register. Equivalent to:
304 //
305 //     if (reg_index == 0) {
306 //         gpioc_lo_out_set(val);
307 //     } else if (reg_index == 1) {
308 //         gpioc_hi_out_set(val);
309 //     } else {
310 //         // undefined
311 //     }
gpioc_index_out_set(uint reg_index,uint32_t mask)312 __force_inline static void gpioc_index_out_set(uint reg_index, uint32_t mask) {
313     pico_default_asm_volatile ("mcrr p0, #10, %1, %0, c0" : : "r" (reg_index), "r" (mask));
314 }
315 
316 // Clear bits in a selected GPIO output register. Equivalent to:
317 //
318 //     if (reg_index == 0) {
319 //         gpioc_lo_out_clr(val);
320 //     } else if (reg_index == 1) {
321 //         gpioc_hi_out_clr(val);
322 //     } else {
323 //         // undefined
324 //     }
gpioc_index_out_clr(uint reg_index,uint32_t mask)325 __force_inline static void gpioc_index_out_clr(uint reg_index, uint32_t mask) {
326     pico_default_asm_volatile ("mcrr p0, #11, %1, %0, c0" : : "r" (reg_index), "r" (mask));
327 }
328 
329 // Write to a selected GPIO output enable register. Equivalent to:
330 //
331 //     if (reg_index == 0) {
332 //         gpioc_lo_oe_put(val);
333 //     } else if (reg_index == 1) {
334 //         gpioc_hi_oe_put(val);
335 //     } else {
336 //         // undefined
337 //     }
gpioc_index_oe_put(uint reg_index,uint32_t val)338 __force_inline static void gpioc_index_oe_put(uint reg_index, uint32_t val) {
339     pico_default_asm_volatile ("mcrr p0, #8, %1, %0, c4" : : "r" (reg_index), "r" (val));
340 }
341 
342 // Toggle bits in a selected GPIO output enable register. Equivalent to:
343 //
344 //     if (reg_index == 0) {
345 //         gpioc_lo_oe_xor(val);
346 //     } else if (reg_index == 1) {
347 //         gpioc_hi_oe_xor(val);
348 //     } else {
349 //         // undefined
350 //     }
gpioc_index_oe_xor(uint reg_index,uint32_t mask)351 __force_inline static void gpioc_index_oe_xor(uint reg_index, uint32_t mask) {
352     pico_default_asm_volatile ("mcrr p0, #9, %1, %0, c4" : : "r" (reg_index), "r" (mask));
353 }
354 
355 // Set bits in a selected GPIO output enable register (set to output). Equivalent to:
356 //
357 //     if (reg_index == 0) {
358 //         gpioc_lo_oe_set(val);
359 //     } else if (reg_index == 1) {
360 //         gpioc_hi_oe_set(val);
361 //     } else {
362 //         // undefined
363 //     }
gpioc_index_oe_set(uint reg_index,uint32_t mask)364 __force_inline static void gpioc_index_oe_set(uint reg_index, uint32_t mask) {
365     pico_default_asm_volatile ("mcrr p0, #10, %1, %0, c4" : : "r" (reg_index), "r" (mask));
366 }
367 
368 // Clear bits in a selected GPIO output enable register (set to input). Equivalent to:
369 //
370 //     if (reg_index == 0) {
371 //         gpioc_lo_oe_clr(val);
372 //     } else if (reg_index == 1) {
373 //         gpioc_hi_oe_clr(val);
374 //     } else {
375 //         // undefined
376 //     }
gpioc_index_oe_clr(uint reg_index,uint32_t mask)377 __force_inline static void gpioc_index_oe_clr(uint reg_index, uint32_t mask) {
378     pico_default_asm_volatile ("mcrr p0, #11, %1, %0, c4" : : "r" (reg_index), "r" (mask));
379 }
380 
381 // ----------------------------------------------------------------------------
382 // Read instructions
383 
384 // Read back the lower 32-bit output register. Equivalent to:
385 //
386 //     return sio_hw->gpio_out;
gpioc_lo_out_get(void)387 __force_inline static uint32_t gpioc_lo_out_get(void) {
388     uint32_t lo;
389     pico_default_asm_volatile ("mrc p0, #0, %0, c0, c0" : "=r" (lo));
390     return lo;
391 }
392 
393 // Read back the upper 32-bit output register. Equivalent to:
394 //
395 //     return sio_hw->gpio_hi_out;
gpioc_hi_out_get(void)396 __force_inline static uint32_t gpioc_hi_out_get(void) {
397     uint32_t hi;
398     pico_default_asm_volatile ("mrc p0, #0, %0, c0, c1" : "=r" (hi));
399     return hi;
400 }
401 
402 // Read back two 32-bit output registers in a single operation. Equivalent to:
403 //
404 //     return sio_hw->gpio_out | ((uint64_t)sio_hw->gpio_hi_out << 32);
gpioc_hilo_out_get(void)405 __force_inline static uint64_t gpioc_hilo_out_get(void) {
406     uint32_t hi, lo;
407     pico_default_asm_volatile ("mrrc p0, #0, %0, %1, c0" : "=r" (lo), "=r" (hi));
408     return ((uint64_t)hi << 32) | lo;
409 }
410 
411 // Read back the lower 32-bit output enable register. Equivalent to:
412 //
413 //     return sio_hw->gpio_oe;
gpioc_lo_oe_get(void)414 __force_inline static uint32_t gpioc_lo_oe_get(void) {
415     uint32_t lo;
416     pico_default_asm_volatile ("mrc p0, #0, %0, c0, c4" : "=r" (lo));
417     return lo;
418 }
419 
420 // Read back the upper 32-bit output enable register. Equivalent to:
421 //
422 //     return sio_hw->gpio_hi_oe;
gpioc_hi_oe_get(void)423 __force_inline static uint32_t gpioc_hi_oe_get(void) {
424     uint32_t hi;
425     pico_default_asm_volatile ("mrc p0, #0, %0, c0, c5" : "=r" (hi));
426     return hi;
427 }
428 
429 // Read back two 32-bit output enable registers in a single operation. Equivalent to:
430 //
431 //     return sio_hw->gpio_oe | ((uint64_t)sio_hw->gpio_hi_oe << 32);
gpioc_hilo_oe_get(void)432 __force_inline static uint64_t gpioc_hilo_oe_get(void) {
433     uint32_t hi, lo;
434     pico_default_asm_volatile ("mrrc p0, #0, %0, %1, c4" : "=r" (lo), "=r" (hi));
435     return ((uint64_t)hi << 32) | lo;
436 }
437 
438 // Sample the lower 32 GPIOs. Equivalent to:
439 //
440 //     return sio_hw->gpio_in;
gpioc_lo_in_get(void)441 __force_inline static uint32_t gpioc_lo_in_get(void) {
442     uint32_t lo;
443     pico_default_asm_volatile ("mrc p0, #0, %0, c0, c8" : "=r" (lo));
444     return lo;
445 }
446 
447 // Sample the upper 32 GPIOs. Equivalent to:
448 //
449 //     return sio_hw->gpio_hi_in;
gpioc_hi_in_get(void)450 __force_inline static uint32_t gpioc_hi_in_get(void) {
451     uint32_t hi;
452     pico_default_asm_volatile ("mrc p0, #0, %0, c0, c9" : "=r" (hi));
453     return hi;
454 }
455 
456 // Sample 64 GPIOs on the same cycle. Equivalent to:
457 //
458 //     return sio_hw->gpio_in | ((uint64_t)sio_hw->gpio_hi_in << 32);
gpioc_hilo_in_get(void)459 __force_inline static uint64_t gpioc_hilo_in_get(void) {
460     uint32_t hi, lo;
461     pico_default_asm_volatile ("mrrc p0, #0, %0, %1, c8" : "=r" (lo), "=r" (hi));
462     return ((uint64_t)hi << 32) | lo;
463 }
464 
465 #endif
466