1 /*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "hardware/claim.h"
8 #include "hardware/pio.h"
9 #include "hardware/pio_instructions.h"
10
11 // sanity check
12 check_hw_layout(pio_hw_t, sm[0].clkdiv, PIO_SM0_CLKDIV_OFFSET);
13 check_hw_layout(pio_hw_t, sm[1].clkdiv, PIO_SM1_CLKDIV_OFFSET);
14 check_hw_layout(pio_hw_t, instr_mem[0], PIO_INSTR_MEM0_OFFSET);
15 check_hw_layout(pio_hw_t, inte0, PIO_IRQ0_INTE_OFFSET);
16 check_hw_layout(pio_hw_t, txf[1], PIO_TXF1_OFFSET);
17 check_hw_layout(pio_hw_t, rxf[3], PIO_RXF3_OFFSET);
18 check_hw_layout(pio_hw_t, ints1, PIO_IRQ1_INTS_OFFSET);
19
20 static_assert(NUM_PIO_STATE_MACHINES * NUM_PIOS <= 8, "");
21 static uint8_t claimed;
22
pio_sm_claim(PIO pio,uint sm)23 void pio_sm_claim(PIO pio, uint sm) {
24 check_sm_param(sm);
25 uint which = pio_get_index(pio);
26 if (which) {
27 hw_claim_or_assert(&claimed, NUM_PIO_STATE_MACHINES + sm, "PIO 1 SM %d already claimed");
28 } else {
29 hw_claim_or_assert(&claimed, sm, "PIO 0 SM %d already claimed");
30 }
31 }
32
pio_claim_sm_mask(PIO pio,uint sm_mask)33 void pio_claim_sm_mask(PIO pio, uint sm_mask) {
34 for(uint i = 0; sm_mask; i++, sm_mask >>= 1u) {
35 if (sm_mask & 1u) pio_sm_claim(pio, i);
36 }
37 }
pio_sm_unclaim(PIO pio,uint sm)38 void pio_sm_unclaim(PIO pio, uint sm) {
39 check_sm_param(sm);
40 uint which = pio_get_index(pio);
41 hw_claim_clear(&claimed, which * NUM_PIO_STATE_MACHINES + sm);
42 }
43
pio_claim_unused_sm(PIO pio,bool required)44 int pio_claim_unused_sm(PIO pio, bool required) {
45 uint which = pio_get_index(pio);
46 uint base = which * NUM_PIO_STATE_MACHINES;
47 int index = hw_claim_unused_from_range((uint8_t*)&claimed, required, base,
48 base + NUM_PIO_STATE_MACHINES - 1, "No PIO state machines are available");
49 return index >= base ? index - base : -1;
50 }
51
pio_load_program(PIO pio,const uint16_t * prog,uint8_t prog_len,uint8_t load_offset)52 void pio_load_program(PIO pio, const uint16_t *prog, uint8_t prog_len, uint8_t load_offset) {
53 // instructions are only 16 bits, but instruction memory locations are spaced 32 bits apart
54 // Adjust the addresses of any jump instructions to respect load offset
55 assert(load_offset + prog_len <= PIO_INSTRUCTION_COUNT);
56
57 }
58
59 static_assert(PIO_INSTRUCTION_COUNT <= 32, "");
60 static uint32_t _used_instruction_space[2];
61
_pio_find_offset_for_program(PIO pio,const pio_program_t * program)62 static int _pio_find_offset_for_program(PIO pio, const pio_program_t *program) {
63 assert(program->length < PIO_INSTRUCTION_COUNT);
64 uint32_t used_mask = _used_instruction_space[pio_get_index(pio)];
65 uint32_t program_mask = (1u << program->length) - 1;
66 if (program->origin >= 0) {
67 if (program->origin > 32 - program->length) return -1;
68 return used_mask & (program_mask << program->origin) ? -1 : program->origin;
69 } else {
70 // work down from the top always
71 for (int i = 32 - program->length; i >= 0; i--) {
72 if (!(used_mask & (program_mask << (uint) i))) {
73 return i;
74 }
75 }
76 return -1;
77 }
78 }
79
pio_can_add_program(PIO pio,const pio_program_t * program)80 bool pio_can_add_program(PIO pio, const pio_program_t *program) {
81 uint32_t save = hw_claim_lock();
82 bool rc = -1 != _pio_find_offset_for_program(pio, program);
83 hw_claim_unlock(save);
84 return rc;
85 }
86
_pio_can_add_program_at_offset(PIO pio,const pio_program_t * program,uint offset)87 static bool _pio_can_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset) {
88 assert(offset < PIO_INSTRUCTION_COUNT);
89 assert(offset + program->length <= PIO_INSTRUCTION_COUNT);
90 if (program->origin >= 0 && program->origin != offset) return false;
91 uint32_t used_mask = _used_instruction_space[pio_get_index(pio)];
92 uint32_t program_mask = (1u << program->length) - 1;
93 return !(used_mask & (program_mask << offset));
94 }
95
pio_can_add_program_at_offset(PIO pio,const pio_program_t * program,uint offset)96 bool pio_can_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset) {
97 uint32_t save = hw_claim_lock();
98 bool rc = _pio_can_add_program_at_offset(pio, program, offset);
99 hw_claim_unlock(save);
100 return rc;
101 }
102
_pio_add_program_at_offset(PIO pio,const pio_program_t * program,uint offset)103 static void _pio_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset) {
104 if (!_pio_can_add_program_at_offset(pio, program, offset)) {
105 panic("No program space");
106 }
107 for (uint i = 0; i < program->length; ++i) {
108 uint16_t instr = program->instructions[i];
109 pio->instr_mem[offset + i] = pio_instr_bits_jmp != _pio_major_instr_bits(instr) ? instr : instr + offset;
110 }
111 uint32_t program_mask = (1u << program->length) - 1;
112 _used_instruction_space[pio_get_index(pio)] |= program_mask << offset;
113 }
114
115 // these assert if unable
pio_add_program(PIO pio,const pio_program_t * program)116 uint pio_add_program(PIO pio, const pio_program_t *program) {
117 uint32_t save = hw_claim_lock();
118 int offset = _pio_find_offset_for_program(pio, program);
119 if (offset < 0) {
120 panic("No program space");
121 }
122 _pio_add_program_at_offset(pio, program, offset);
123 hw_claim_unlock(save);
124 return offset;
125 }
126
pio_add_program_at_offset(PIO pio,const pio_program_t * program,uint offset)127 void pio_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset) {
128 uint32_t save = hw_claim_lock();
129 _pio_add_program_at_offset(pio, program, offset);
130 hw_claim_unlock(save);
131 }
132
pio_remove_program(PIO pio,const pio_program_t * program,uint loaded_offset)133 void pio_remove_program(PIO pio, const pio_program_t *program, uint loaded_offset) {
134 uint32_t program_mask = (1u << program->length) - 1;
135 program_mask <<= loaded_offset;
136 uint32_t save = hw_claim_lock();
137 assert(program_mask == (_used_instruction_space[pio_get_index(pio)] & program_mask));
138 _used_instruction_space[pio_get_index(pio)] &= ~program_mask;
139 hw_claim_unlock(save);
140 }
141
pio_clear_instruction_memory(PIO pio)142 void pio_clear_instruction_memory(PIO pio) {
143 uint32_t save = hw_claim_lock();
144 _used_instruction_space[pio_get_index(pio)] = 0;
145 for(uint i=0;i<PIO_INSTRUCTION_COUNT;i++) {
146 pio->instr_mem[i] = pio_encode_jmp(i);
147 }
148 hw_claim_unlock(save);
149 }
150
151 // Set the value of all PIO pins. This is done by forcibly executing
152 // instructions on a "victim" state machine, sm. Ideally you should choose one
153 // which is not currently running a program. This is intended for one-time
154 // setup of initial pin states.
pio_sm_set_pins(PIO pio,uint sm,uint32_t pins)155 void pio_sm_set_pins(PIO pio, uint sm, uint32_t pins) {
156 uint32_t pinctrl_saved = pio->sm[sm].pinctrl;
157 uint remaining = 32;
158 uint base = 0;
159 while (remaining) {
160 uint decrement = remaining > 5 ? 5 : remaining;
161 pio->sm[sm].pinctrl =
162 (decrement << PIO_SM0_PINCTRL_SET_COUNT_LSB) |
163 (base << PIO_SM0_PINCTRL_SET_BASE_LSB);
164 pio_sm_exec(pio, sm, pio_encode_set(pio_pins, pins & 0x1fu));
165 remaining -= decrement;
166 base += decrement;
167 pins >>= 5;
168 }
169 pio->sm[sm].pinctrl = pinctrl_saved;
170 }
171
pio_sm_set_pins_with_mask(PIO pio,uint sm,uint32_t pinvals,uint32_t pin_mask)172 void pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pinvals, uint32_t pin_mask) {
173 uint32_t pinctrl_saved = pio->sm[sm].pinctrl;
174 while (pin_mask) {
175 uint base = __builtin_ctz(pin_mask);
176 pio->sm[sm].pinctrl =
177 (1u << PIO_SM0_PINCTRL_SET_COUNT_LSB) |
178 (base << PIO_SM0_PINCTRL_SET_BASE_LSB);
179 pio_sm_exec(pio, sm, pio_encode_set(pio_pins, (pinvals >> base) & 0x1u));
180 pin_mask &= pin_mask - 1;
181 }
182 pio->sm[sm].pinctrl = pinctrl_saved;
183 }
184
pio_sm_set_pindirs_with_mask(PIO pio,uint sm,uint32_t pindirs,uint32_t pin_mask)185 void pio_sm_set_pindirs_with_mask(PIO pio, uint sm, uint32_t pindirs, uint32_t pin_mask) {
186 uint32_t pinctrl_saved = pio->sm[sm].pinctrl;
187 while (pin_mask) {
188 uint base = __builtin_ctz(pin_mask);
189 pio->sm[sm].pinctrl =
190 (1u << PIO_SM0_PINCTRL_SET_COUNT_LSB) |
191 (base << PIO_SM0_PINCTRL_SET_BASE_LSB);
192 pio_sm_exec(pio, sm, pio_encode_set(pio_pindirs, (pindirs >> base) & 0x1u));
193 pin_mask &= pin_mask - 1;
194 }
195 pio->sm[sm].pinctrl = pinctrl_saved;
196 }
197
pio_sm_set_consecutive_pindirs(PIO pio,uint sm,uint pin,uint count,bool is_out)198 void pio_sm_set_consecutive_pindirs(PIO pio, uint sm, uint pin, uint count, bool is_out) {
199 assert(pin < 32u);
200 uint32_t pinctrl_saved = pio->sm[sm].pinctrl;
201 uint pindir_val = is_out ? 0x1f : 0;
202 while (count > 5) {
203 pio->sm[sm].pinctrl = (5u << PIO_SM0_PINCTRL_SET_COUNT_LSB) | (pin << PIO_SM0_PINCTRL_SET_BASE_LSB);
204 pio_sm_exec(pio, sm, pio_encode_set(pio_pindirs, pindir_val));
205 count -= 5;
206 pin = (pin + 5) & 0x1f;
207 }
208 pio->sm[sm].pinctrl = (count << PIO_SM0_PINCTRL_SET_COUNT_LSB) | (pin << PIO_SM0_PINCTRL_SET_BASE_LSB);
209 pio_sm_exec(pio, sm, pio_encode_set(pio_pindirs, pindir_val));
210 pio->sm[sm].pinctrl = pinctrl_saved;
211 }
212
pio_sm_init(PIO pio,uint sm,uint initial_pc,const pio_sm_config * config)213 void pio_sm_init(PIO pio, uint sm, uint initial_pc, const pio_sm_config *config) {
214 // Halt the machine, set some sensible defaults
215 pio_sm_set_enabled(pio, sm, false);
216
217 if (config) {
218 pio_sm_set_config(pio, sm, config);
219 } else {
220 pio_sm_config c = pio_get_default_sm_config();
221 pio_sm_set_config(pio, sm, &c);
222 }
223
224 pio_sm_clear_fifos(pio, sm);
225
226 // Clear FIFO debug flags
227 const uint32_t fdebug_sm_mask =
228 (1u << PIO_FDEBUG_TXOVER_LSB) |
229 (1u << PIO_FDEBUG_RXUNDER_LSB) |
230 (1u << PIO_FDEBUG_TXSTALL_LSB) |
231 (1u << PIO_FDEBUG_RXSTALL_LSB);
232 pio->fdebug = fdebug_sm_mask << sm;
233
234 // Finally, clear some internal SM state
235 pio_sm_restart(pio, sm);
236 pio_sm_clkdiv_restart(pio, sm);
237 pio_sm_exec(pio, sm, pio_encode_jmp(initial_pc));
238 }
239
pio_sm_drain_tx_fifo(PIO pio,uint sm)240 void pio_sm_drain_tx_fifo(PIO pio, uint sm) {
241 uint instr = (pio->sm[sm].shiftctrl & PIO_SM0_SHIFTCTRL_AUTOPULL_BITS) ? pio_encode_out(pio_null, 32) :
242 pio_encode_pull(false, false);
243 while (!pio_sm_is_tx_fifo_empty(pio, sm)) {
244 pio_sm_exec(pio, sm, instr);
245 }
246 }
247