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 - 4) 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 }
38 
pio_sm_unclaim(PIO pio,uint sm)39 void pio_sm_unclaim(PIO pio, uint sm) {
40     check_sm_param(sm);
41     uint which = pio_get_index(pio);
42     hw_claim_clear(&claimed, which * NUM_PIO_STATE_MACHINES + sm);
43 }
44 
pio_claim_unused_sm(PIO pio,bool required)45 int pio_claim_unused_sm(PIO pio, bool required) {
46     // PIO index is 0 or 1.
47     uint which = pio_get_index(pio);
48     uint base = which * NUM_PIO_STATE_MACHINES;
49     int index = hw_claim_unused_from_range((uint8_t*)&claimed, required, base,
50                                       base + NUM_PIO_STATE_MACHINES - 1, "No PIO state machines are available");
51     return index >= (int)base ? index - (int)base : -1;
52 }
53 
pio_sm_is_claimed(PIO pio,uint sm)54 bool pio_sm_is_claimed(PIO pio, uint sm) {
55     check_sm_param(sm);
56     uint which = pio_get_index(pio);
57     return hw_is_claimed(&claimed, which * NUM_PIO_STATE_MACHINES + sm);
58 }
59 
60 static_assert(PIO_INSTRUCTION_COUNT <= 32, "");
61 static uint32_t _used_instruction_space[2];
62 
_pio_find_offset_for_program(PIO pio,const pio_program_t * program)63 static int _pio_find_offset_for_program(PIO pio, const pio_program_t *program) {
64     assert(program->length <= PIO_INSTRUCTION_COUNT);
65     uint32_t used_mask = _used_instruction_space[pio_get_index(pio)];
66     uint32_t program_mask = (1u << program->length) - 1;
67     if (program->origin >= 0) {
68         if (program->origin > 32 - program->length) return -1;
69         return used_mask & (program_mask << program->origin) ? -1 : program->origin;
70     } else {
71         // work down from the top always
72         for (int i = 32 - program->length; i >= 0; i--) {
73             if (!(used_mask & (program_mask << (uint) i))) {
74                 return i;
75             }
76         }
77         return -1;
78     }
79 }
80 
pio_can_add_program(PIO pio,const pio_program_t * program)81 bool pio_can_add_program(PIO pio, const pio_program_t *program) {
82     uint32_t save = hw_claim_lock();
83     bool rc =  -1 != _pio_find_offset_for_program(pio, program);
84     hw_claim_unlock(save);
85     return rc;
86 }
87 
_pio_can_add_program_at_offset(PIO pio,const pio_program_t * program,uint offset)88 static bool _pio_can_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset) {
89     valid_params_if(PIO, offset < PIO_INSTRUCTION_COUNT);
90     valid_params_if(PIO, offset + program->length <= PIO_INSTRUCTION_COUNT);
91     if (program->origin >= 0 && (uint)program->origin != offset) return false;
92     uint32_t used_mask = _used_instruction_space[pio_get_index(pio)];
93     uint32_t program_mask = (1u << program->length) - 1;
94     return !(used_mask & (program_mask << offset));
95 }
96 
pio_can_add_program_at_offset(PIO pio,const pio_program_t * program,uint offset)97 bool pio_can_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset) {
98     uint32_t save = hw_claim_lock();
99     bool rc = _pio_can_add_program_at_offset(pio, program, offset);
100     hw_claim_unlock(save);
101     return rc;
102 }
103 
_pio_add_program_at_offset(PIO pio,const pio_program_t * program,uint offset)104 static void _pio_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset) {
105     if (!_pio_can_add_program_at_offset(pio, program, offset)) {
106         panic("No program space");
107     }
108     for (uint i = 0; i < program->length; ++i) {
109         uint16_t instr = program->instructions[i];
110         pio->instr_mem[offset + i] = pio_instr_bits_jmp != _pio_major_instr_bits(instr) ? instr : instr + offset;
111     }
112     uint32_t program_mask = (1u << program->length) - 1;
113     _used_instruction_space[pio_get_index(pio)] |= program_mask << offset;
114 }
115 
116 // these assert if unable
pio_add_program(PIO pio,const pio_program_t * program)117 uint pio_add_program(PIO pio, const pio_program_t *program) {
118     uint32_t save = hw_claim_lock();
119     int offset = _pio_find_offset_for_program(pio, program);
120     if (offset < 0) {
121         panic("No program space");
122     }
123     _pio_add_program_at_offset(pio, program, (uint)offset);
124     hw_claim_unlock(save);
125     return (uint)offset;
126 }
127 
pio_add_program_at_offset(PIO pio,const pio_program_t * program,uint offset)128 void pio_add_program_at_offset(PIO pio, const pio_program_t *program, uint offset) {
129     uint32_t save = hw_claim_lock();
130     _pio_add_program_at_offset(pio, program, offset);
131     hw_claim_unlock(save);
132 }
133 
pio_remove_program(PIO pio,const pio_program_t * program,uint loaded_offset)134 void pio_remove_program(PIO pio, const pio_program_t *program, uint loaded_offset) {
135     uint32_t program_mask = (1u << program->length) - 1;
136     program_mask <<= loaded_offset;
137     uint32_t save = hw_claim_lock();
138     assert(program_mask == (_used_instruction_space[pio_get_index(pio)] & program_mask));
139     _used_instruction_space[pio_get_index(pio)] &= ~program_mask;
140     hw_claim_unlock(save);
141 }
142 
pio_clear_instruction_memory(PIO pio)143 void pio_clear_instruction_memory(PIO pio) {
144     uint32_t save = hw_claim_lock();
145     _used_instruction_space[pio_get_index(pio)] = 0;
146     for(uint i=0;i<PIO_INSTRUCTION_COUNT;i++) {
147         pio->instr_mem[i] = pio_encode_jmp(i);
148     }
149     hw_claim_unlock(save);
150 }
151 
152 // Set the value of all PIO pins. This is done by forcibly executing
153 // instructions on a "victim" state machine, sm. Ideally you should choose one
154 // which is not currently running a program. This is intended for one-time
155 // setup of initial pin states.
pio_sm_set_pins(PIO pio,uint sm,uint32_t pins)156 void pio_sm_set_pins(PIO pio, uint sm, uint32_t pins) {
157     check_pio_param(pio);
158     check_sm_param(sm);
159     uint32_t pinctrl_saved = pio->sm[sm].pinctrl;
160     uint32_t execctrl_saved = pio->sm[sm].execctrl;
161     hw_clear_bits(&pio->sm[sm].execctrl, 1u << PIO_SM0_EXECCTRL_OUT_STICKY_LSB);
162     uint remaining = 32;
163     uint base = 0;
164     while (remaining) {
165         uint decrement = remaining > 5 ? 5 : remaining;
166         pio->sm[sm].pinctrl =
167                 (decrement << PIO_SM0_PINCTRL_SET_COUNT_LSB) |
168                 (base << PIO_SM0_PINCTRL_SET_BASE_LSB);
169         pio_sm_exec(pio, sm, pio_encode_set(pio_pins, pins & 0x1fu));
170         remaining -= decrement;
171         base += decrement;
172         pins >>= 5;
173     }
174     pio->sm[sm].pinctrl = pinctrl_saved;
175     pio->sm[sm].execctrl = execctrl_saved;
176 }
177 
pio_sm_set_pins_with_mask(PIO pio,uint sm,uint32_t pinvals,uint32_t pin_mask)178 void pio_sm_set_pins_with_mask(PIO pio, uint sm, uint32_t pinvals, uint32_t pin_mask) {
179     check_pio_param(pio);
180     check_sm_param(sm);
181     uint32_t pinctrl_saved = pio->sm[sm].pinctrl;
182     uint32_t execctrl_saved = pio->sm[sm].execctrl;
183     hw_clear_bits(&pio->sm[sm].execctrl, 1u << PIO_SM0_EXECCTRL_OUT_STICKY_LSB);
184     while (pin_mask) {
185         uint base = (uint)__builtin_ctz(pin_mask);
186         pio->sm[sm].pinctrl =
187                 (1u << PIO_SM0_PINCTRL_SET_COUNT_LSB) |
188                 (base << PIO_SM0_PINCTRL_SET_BASE_LSB);
189         pio_sm_exec(pio, sm, pio_encode_set(pio_pins, (pinvals >> base) & 0x1u));
190         pin_mask &= pin_mask - 1;
191     }
192     pio->sm[sm].pinctrl = pinctrl_saved;
193     pio->sm[sm].execctrl = execctrl_saved;
194 }
195 
pio_sm_set_pindirs_with_mask(PIO pio,uint sm,uint32_t pindirs,uint32_t pin_mask)196 void pio_sm_set_pindirs_with_mask(PIO pio, uint sm, uint32_t pindirs, uint32_t pin_mask) {
197     check_pio_param(pio);
198     check_sm_param(sm);
199     uint32_t pinctrl_saved = pio->sm[sm].pinctrl;
200     uint32_t execctrl_saved = pio->sm[sm].execctrl;
201     hw_clear_bits(&pio->sm[sm].execctrl, 1u << PIO_SM0_EXECCTRL_OUT_STICKY_LSB);
202     while (pin_mask) {
203         uint base = (uint)__builtin_ctz(pin_mask);
204         pio->sm[sm].pinctrl =
205                 (1u << PIO_SM0_PINCTRL_SET_COUNT_LSB) |
206                 (base << PIO_SM0_PINCTRL_SET_BASE_LSB);
207         pio_sm_exec(pio, sm, pio_encode_set(pio_pindirs, (pindirs >> base) & 0x1u));
208         pin_mask &= pin_mask - 1;
209     }
210     pio->sm[sm].pinctrl = pinctrl_saved;
211     pio->sm[sm].execctrl = execctrl_saved;
212 }
213 
pio_sm_set_consecutive_pindirs(PIO pio,uint sm,uint pin,uint count,bool is_out)214 void pio_sm_set_consecutive_pindirs(PIO pio, uint sm, uint pin, uint count, bool is_out) {
215     check_pio_param(pio);
216     check_sm_param(sm);
217     valid_params_if(PIO, pin < 32u);
218     uint32_t pinctrl_saved = pio->sm[sm].pinctrl;
219     uint32_t execctrl_saved = pio->sm[sm].execctrl;
220     hw_clear_bits(&pio->sm[sm].execctrl, 1u << PIO_SM0_EXECCTRL_OUT_STICKY_LSB);
221     uint pindir_val = is_out ? 0x1f : 0;
222     while (count > 5) {
223         pio->sm[sm].pinctrl = (5u << PIO_SM0_PINCTRL_SET_COUNT_LSB) | (pin << PIO_SM0_PINCTRL_SET_BASE_LSB);
224         pio_sm_exec(pio, sm, pio_encode_set(pio_pindirs, pindir_val));
225         count -= 5;
226         pin = (pin + 5) & 0x1f;
227     }
228     pio->sm[sm].pinctrl = (count << PIO_SM0_PINCTRL_SET_COUNT_LSB) | (pin << PIO_SM0_PINCTRL_SET_BASE_LSB);
229     pio_sm_exec(pio, sm, pio_encode_set(pio_pindirs, pindir_val));
230     pio->sm[sm].pinctrl = pinctrl_saved;
231     pio->sm[sm].execctrl = execctrl_saved;
232 }
233 
pio_sm_init(PIO pio,uint sm,uint initial_pc,const pio_sm_config * config)234 void pio_sm_init(PIO pio, uint sm, uint initial_pc, const pio_sm_config *config) {
235     valid_params_if(PIO, initial_pc < PIO_INSTRUCTION_COUNT);
236     // Halt the machine, set some sensible defaults
237     pio_sm_set_enabled(pio, sm, false);
238 
239     if (config) {
240         pio_sm_set_config(pio, sm, config);
241     } else {
242         pio_sm_config c = pio_get_default_sm_config();
243         pio_sm_set_config(pio, sm, &c);
244     }
245 
246     pio_sm_clear_fifos(pio, sm);
247 
248     // Clear FIFO debug flags
249     const uint32_t fdebug_sm_mask =
250             (1u << PIO_FDEBUG_TXOVER_LSB) |
251             (1u << PIO_FDEBUG_RXUNDER_LSB) |
252             (1u << PIO_FDEBUG_TXSTALL_LSB) |
253             (1u << PIO_FDEBUG_RXSTALL_LSB);
254     pio->fdebug = fdebug_sm_mask << sm;
255 
256     // Finally, clear some internal SM state
257     pio_sm_restart(pio, sm);
258     pio_sm_clkdiv_restart(pio, sm);
259     pio_sm_exec(pio, sm, pio_encode_jmp(initial_pc));
260 }
261 
pio_sm_drain_tx_fifo(PIO pio,uint sm)262 void pio_sm_drain_tx_fifo(PIO pio, uint sm) {
263     uint instr = (pio->sm[sm].shiftctrl & PIO_SM0_SHIFTCTRL_AUTOPULL_BITS) ? pio_encode_out(pio_null, 32) :
264                  pio_encode_pull(false, false);
265     while (!pio_sm_is_tx_fifo_empty(pio, sm)) {
266         pio_sm_exec(pio, sm, instr);
267     }
268 }
269