contrib: add GPL license tag on files that miss it
[fw/openocd] / contrib / loaders / flash / stmqspi / gpio_conf_stm32.pl
1 #!/usr/bin/perl
2 # SPDX-License-Identifier: GPL-2.0-or-later
3
4 #
5 # Helper for generating GPIO setup for STM32F0, F4, F7, H7, L0, L1, L4, L4+
6 # and F1 (for 'stmqspi' and 'cmspi' drivers).
7 #
8 # Each pin is configured by "PortAndBit:Conf:Speed"
9 #  'PortAndBit' specifies Port and bit number
10 #  'Conf' is one of 'AFx' (alternate), 'P' (output), 'IN' (input),
11 #    (each optionally by 'P' (push-pull) or 'O' (open-drain)),
12 #    (all optionally followed by 'UP' (pull-up), or 'DO' (pull-down))
13 #  'Speed' is one of 'L' (low), 'M' (medium), 'H' (high), 'V' (very high)
14 #
15 # Port configuration can be given on command line as a single string (pins separated by commas)
16 # or via CubeMX generated file. The latter must consist of the quadspi.c / octospi.c and the
17 # corresponding header. The precise spelling in these files doesn't seem to be consistent, though ...
18 #
19 # Pins have to be ordered this way:
20 #  - I2C: SDA, SCL
21 #  - SPI (1 line): NCS, CLK, IO1/MISO, IO0/MOSI
22 #  - DPI (2 lines): NCS, CLK, IO1/MISO, IO0/MOSI
23 #  - QPI (4 lines): NCS, CLK, IO3/NHOLD, IO2/NWP, IO1/MISO, IO0/MOSI
24 # For dual flash: BK_1 first, then BK_2. If single NCS for both, omit NCS in BK_2
25 # For octal flash: NCS, CLK, DQS, IO7 down to IO0
26
27 use strict;
28 use Getopt::Std;
29
30 my $GPIO_BASE;
31 my $Conf;
32 my $STM32F1 = 0;
33
34 # "Blue-Pill stm32f103cbt6 board w/ cmspi
35 #$STM32F1 = 1;
36 #$GPIO_BASE = 0x40010800;
37 #$Conf = "PB12:PP:M, PB13:PP:V, PB14:INUP:V, PB15:INUP:V";
38 #$Conf = "PB12:PP:M, PB13:PP:V, PB14:INUP:V, PB01:INUP:V";
39
40 #$STM32F1 = 1;
41 #$GPIO_BASE = 0x40010800;
42 #$Conf = "PB07:INUP:V, PB06:INUP:V";
43
44 # mini-stm32f030f4p6 board w/ cmspi
45 #$GPIO_BASE = 0x48000000;
46 #$Conf = "PB01:PP:V, PA05:PP:V, PA06:INUP:V, PA07:INUP:V";
47
48 # stm32f407vet6 board w/ cmspi
49 #$GPIO_BASE = 0x40020000;
50 #$Conf = "PB00:PP:M, PB03:PP:V, PB04:INUP:V, PB05:INUP:V";
51
52 # stm32f412g-disco quad
53 #$GPIO_BASE = 0x40020000;
54 #$Conf = "PB02:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V, PG06:AF10:V";
55
56 # stm32f413h-disco
57 #$GPIO_BASE = 0x40020000;
58 #$Conf = "PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PF09:AF10:V, PF08:AF10:V, PG06:AF10:V";
59
60 # stm32f469i-disco quad
61 #$GPIO_BASE = 0x40020000;
62 #$Conf = "PB06:AF10:V, PF10:AF09:V, PF09:AF10:V, PF08:AF10:V, PF07:AF09:V, PF06:AF09:V";
63 # w/ cmspi
64 #$Conf = "PB06:PP:M, PF10:PP:V, PF06:INUP:V, PF07:INUP:V, PF09:INUP:V, PF08:INUP:V";
65
66 # stm32f723e-disco quad
67 #$GPIO_BASE = 0x40020000;
68 #$Conf = "PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V";
69
70 # stm32f746g-disco quad
71 #$GPIO_BASE = 0x40020000;
72 #Conf = "PB06:AF10:V, PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V";
73 # w/ cmspi
74 #$Conf = "PB06:PP:M, PB02:PP:V, PD13:INUP:V, PE02:INUP:V, PD12:INUP:V, PD11:INUP:V";
75
76 # stm32f769i-disco quad
77 #$GPIO_BASE = 0x40020000;
78 #$Conf = "PB06:AF10:V, PB02:AF09:V, PC10:AF09:V, PC09:AF09:V, PD13:AF09:V, PE02:AF09:V";
79 # w/ cmspi
80 #$Conf = "PB06:PP:M, PB02:PP:V, PD13:INUP:V, PE02:INUP:V, PC10:INUP:V, PC09:INUP:V, ";
81
82 # b-l475e-iot01a quad
83 #$GPIO_BASE = 0x48000000;
84 #$Conf = "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V";
85
86 # stm32l476g-disco quad
87 #$GPIO_BASE = 0x48000000;
88 #$Conf = "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V";
89
90 # stm32l496g-disco quad
91 #$GPIO_BASE = 0x48000000;
92 #$Conf = "PA07:AF10:V, PA06:AF10:V, PA03:AF10:V, PB11:AF10:V, PB01:AF10:V, PB00:AF10:V";
93
94 # stm32l4r9i-disco octal
95 #$GPIO_BASE = 0x48000000;
96 #$Conf = "PG15:AF05:V, PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PH10:AF05:V, PH09:AF05:V, "
97 #      . "PH08:AF05:V, PI11:AF05:V, PI10:AF05:V, PI09:AF05:V, PI06:AF05:V";
98
99 # stm32l4p5g-disco octal/octal
100 #$GPIO_BASE = 0x48000000;
101 #$Conf = "PA07:AF10:V, PA06:AF10:V, PC03:AF10:V, PD07:AF10:V, PD05:AF10:V, PD04:AF10:V, "
102 #      . "PE13:AF10:V, PE12:AF10:V, PE11:AF10:V, PE10:AF10:V, PG06:AF03:V";
103 #$Conf = "PF12:AF05:V, PF04:AF05:V, PF03:AF05:V, PF02:AF05:V, PF01:AF05:V, PF00:AF05:V, "
104 #      . "PG12:AF05:V, PG10:AF05:V, PG09:AF05:V, PG01:AF05:V, PG00:AF05:V";
105
106 # nucleo-f767zi dual quad
107 #$GPIO_BASE = 0x40020000;
108 #$Conf = "PB06:AF10:V, PB02:AF09:V, PC11:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, "
109 #      . "PD11:AF09:V, PE10:AF10:V, PE09:AF10:V, PE08:AF10:V, PE07:AF10:V";
110 # w/ cmspi
111 #$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V";
112 #$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PE09:INPUP:V, PE08:INPUP:V, PE07:INPUP:V";
113
114 # nucleo-h743zi dual quad
115 #$GPIO_BASE = 0x58020000;
116 #$Conf = "PB10:AF09:V, PB02:AF09:V, PC11:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, "
117 #      . "PD11:AF09:V, PE10:AF10:V, PE09:AF10:V, PE08:AF10:V, PE07:AF10:V";
118 # w/ cmspi
119 #$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V";
120 #$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PE09:INPUP:V, PE08:INPUP:V, PE07:INPUP:V";
121
122 # nucleo-h7a3zi dual quad
123 #$GPIO_BASE = 0x58020000;
124 #$Conf = "PB10:AF09:V, PB02:AF09:V, PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V, "
125 #      . "PC11:AF09:V, PE10:AF10:V, PD06:AF10:V, PE08:AF10:V, PE07:AF10:V";
126 # w/ cmspi
127 #$Conf = "PB10:PPUP:M, PB02:PPUP:V, PD13:INPUP:V, PE02:INPUP:V, PD12:INPUP:V, PD11:INPUP:V";
128 #$Conf = "PC11:PPUP:M, PB02:PPUP:V, PE10:INPUP:V, PD06:INPUP:V, PE08:INPUP:V, PE07:INPUP:V";
129
130 # nucleo-l4r5zi one dual quad single NCS
131 #$GPIO_BASE = 0x48000000;
132 #$Conf = "PA02:AF10:V, PE10:AF10:V, PD07:AF10:V, PD06:AF10:V, PD05:AF10:V, PD04:AF10:V, "
133 #      . "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V";
134 # w/ cmspi
135 #$Conf = "PA02:PPUP:M,  PE10:PPUP:V, PD07:INPDO:V, PD06:INPDO:V, PD05:INPDO:V, PD04:INPDO:V";
136 #$Conf = "PA02:PPUP:M,  PE10:PPUP:V, PE15:INPDO:V, PE14:INPDO:V, PE13:INPDO:V, PE12:INPDO:V";
137
138 # nucleo-l552ze-q dual quad with single NCS
139 #$GPIO_BASE = 0x42020000;
140 #$Conf = "PA02:AF10:V, PE10:AF10:V, PD07:AF10:V, PD06:AF10:V, PD05:AF10:V, PD04:AF10:V, "
141 #      . "PE15:AF10:V, PE14:AF10:V, PE13:AF10:V, PE12:AF10:V";
142 # w/ cmspi
143 #$Conf = "PA02:PPUP:M,  PE10:PPUP:V, PD07:INPDO:V, PD06:INPDO:V, PD05:INPDO:V, PD04:INPDO:V";
144 #$Conf = "PA02:PPUP:M,  PE10:PPUP:V, PE15:INPDO:V, PE14:INPDO:V, PE13:INPDO:V, PE12:INPDO:V";
145
146 # nucleo-g071rb dual quad
147 #$GPIO_BASE = 0x50000000;
148 #$Conf = "PA00:PPUP:H, PA04:PPUP:V, PB03:INPUP:V, PA10:INPUP:V, PB11:INPUP:H, PB01:INPUP:H";
149 #$Conf = "PA01:PPUP:H, PA04:PPUP:V, PA08:INPUP:V, PB14:INPUP:V, PB04:INPUP:V, PB05:INPUP:V";
150
151 # nucleo-g474re dual quad with single NCS
152 #$GPIO_BASE = 0x48000000;
153 #$Conf = "PB11:AF10:H, PB10:AF10:V, PA06:AF10:V, PA07:AF10:V, PB00:AF10:V, PB01:AF10:V, "
154 #      . "PC04:AF10:V, PC03:AF10:V, PC02:AF10:V, PC01:AF10:V";
155 # w/ cmspi
156 #$Conf = "PB11:PPUP:H, PB10:PPUP:V, PA06:INPUP:V, PA07:INPUP:V, PB00:INPUP:V, PB01:INPUP:V";
157 #$Conf = "PB11:PPUP:H, PB10:PPUP:V, PC04:INPUP:V, PC03:INPUP:V, PC02:INPUP:V, PC01:INPUP:V";
158
159 # stm32h745i-disco dual quad with single NCS
160 #$GPIO_BASE = 0x58020000;
161 #$Conf = "PG06:AF10:H, PF10:AF09:V, PF06:AF09:V, PF07:AF09:V, PF09:AF10:V, PD11:AF09:V, "
162 #      . "PG14:AF09:H, PG09:AF09:V, PH03:AF09:V, PH02:AF09:V";
163
164 # stm32h747i-disco dual quad with single NCS
165 #GPIO_BASE = 0x58020000;
166 #$Conf = "PG06:AF10:H, PB02:AF09:V, PF06:AF09:V, PF07:AF09:V, PF09:AF10:V, PD11:AF09:V, "
167 #      . "PG14:AF09:H, PG09:AF09:V, PH03:AF09:V, PH02:AF09:V";
168
169 # stm32h7b3i-disco octal
170 #$GPIO_BASE = 0x58020000;
171 #$Conf = "PG06:AF10:V, PB02:AF09:V, PC05:AF10:V, PD07:AF10:V, PG09:AF09:V, PH03:AF09:V, PC01:AF10:V, "
172 #      . "PF06:AF10:V, PF07:AF10:V, PF09:AF10:V, PD11:AF09:V";
173
174 # stm32h735g-disco octal
175 #$GPIO_BASE = 0x58020000;
176 #$Conf = "PG06:AF10:V, PF10:AF09:V, PB02:AF10:V, PD07:AF10:V, PG09:AF09:V, PD05:AF10:V, PD04:AF10:V, "
177 #      . "PD13:AF09:V, PE02:AF09:V, PD12:AF09:V, PD11:AF09:V";
178
179 # stm32l562e-disco octal
180 #$GPIO_BASE = 0x42020000;
181 #$Conf = "PA02:AF10:V, PA03:AF10:V, PB02:AF10:V, PC00:AF03:V, PC03:AF10:V, PC02:AF10:V, PC01:AF10:V, "
182 #      . "PA06:AF10:V, PA07:AF10:V, PB00:AF10:V, PB01:AF10:V";
183
184 &getopts('b:c:f:t');
185 if ($Getopt::Std::opt_b eq '')
186 {
187         if ($GPIO_BASE eq '')
188         {
189                 die("usage: $0 [ -1 ] -b io_base [ -c port_configuration ] [ -f conf_file ]");
190         }
191 }
192 else
193 {
194         $GPIO_BASE = eval $Getopt::Std::opt_b;
195 }
196
197 if ($Getopt::Std::opt_c eq '')
198 {
199         if (($Conf eq '') && ($Getopt::Std::opt_f eq ''))
200         {
201                 die("usage: $0 [ -b io_base ] ( -c port_configuration | -f conf_file )");
202         }
203 }#
204 else
205 {
206         $Conf = $Getopt::Std::opt_c . ',';
207 }
208
209 $STM32F1 = $Getopt::Std::opt_t;
210
211 my $Sep = "\t";
212 my $Form = "${Sep}mmw 0x%08X 0x%08X 0x%08X\t;# ";
213
214 my $GPIO_OFFS;
215 my $GPIO_CRL;
216 my $GPIO_CRH;
217 my $GPIO_MODER;
218 my $GPIO_OTYPER;
219 my $GPIO_OSPEEDR;
220 my $GPIO_PUPDR;
221 my $GPIO_IDR;
222 my $GPIO_ODR;
223 my $GPIO_AFRL;
224 my $GPIO_AFRH;
225
226 if ($STM32F1)
227 {
228         # offsets for F1 devices
229         $GPIO_OFFS = 0x400;
230         $GPIO_CRL = 0x00;
231         $GPIO_CRH = 0x04;
232         $GPIO_IDR = 0x08;
233         $GPIO_ODR = 0x0C;
234 }
235 else
236 {
237         # these offsets are identical on all F0, F4, F7, H7, L4, L4+ devices up to now
238         $GPIO_OFFS = 0x400;
239         $GPIO_MODER = 0x00;
240         $GPIO_OTYPER = 0x04;
241         $GPIO_OSPEEDR = 0x08;
242         $GPIO_PUPDR = 0x0C;
243         $GPIO_IDR = 0x10;
244         $GPIO_ODR = 0x14;
245         $GPIO_AFRL = 0x20;
246         $GPIO_AFRH = 0x24;
247 }
248
249 my @Out = ( { }, { }, { }, { }, { }, { }, { }, { }, { }, { }, { } );
250 my @Port = ( );
251 my $Exor;
252 my %Conf;
253 my $Pins = "${Sep}#";
254
255 my $pins;
256 my $altn;
257 my %defs;
258
259 if ($Getopt::Std::opt_f ne '')
260 {
261         open(CONF_FILE, '<', $Getopt::Std::opt_f) || die("can't open $Getopt::Std::opt_f");
262         while (my $line = <CONF_FILE>)
263         {
264                 if ($line =~ /^\s*#define\s+.?(QSPI|QUAD_?SPI|OCTOSPI[^_]*)\w+_(Port|Pin)\s/)
265                 {
266                         if ($line =~ /#define\s+(\w+)\s+(\w+)/)
267                         {
268                                 $defs{$1} = $2;
269                         }
270                         else
271                         {
272                                 die($line);
273                         }
274                 }
275                 elsif ($line =~ /^\s*(P[A-Z])([0-9]+)\s*-+>\s+.?(QSPI|QUAD_?SPI|OCTO_?SPI[^_]*)_(\w+)/)
276                 {
277                         $Conf{$4} = sprintf("%s%02d", $1, $2);
278                 }
279                 elsif ($line =~ /^\s*GPIO_InitStruct.Pin\s*=\s*([^;]+\w)/)
280                 {
281                         $pins = $1;
282                         while ($line !~ /;/)
283                         {
284                                 $line = <CONF_FILE>;
285                                 $line =~ /^\s*([^;]+\w)/;
286                                 $pins .= $1;
287                         }
288                 }
289                 elsif ($line =~ /^\s*GPIO_InitStruct.Alternate\s*=\s*GPIO_AF([0-9]+)/)
290                 {
291                         $altn = $1;
292                 }
293                 elsif ($line =~ /^\s*HAL_GPIO_Init\s*\(\s*(\w+)\s*,/)
294                 {
295                         my $port = $1;
296                         if ($port =~ /GPIO([A-Z])/)
297                         {
298                                 $port = $1;
299                         }
300                         elsif (exists($defs{$port}))
301                         {
302                                 $defs{$port} =~ /GPIO([A-Z])/;
303                                 $port = $1;
304                         }
305                         else
306                         {
307                                 printf("\n");
308                                 next;
309                         }
310                         my @pin = split(/\s*\|\s*/, $pins);
311                         foreach my $pin (@pin)
312                         {
313                                 my $bit;
314                                 if (exists($defs{$pin}))
315                                 {
316                                         $defs{$pin} =~ /GPIO_PIN_([0-9]+)/;
317                                         $bit = $1;
318                                 }
319                                 else
320                                 {
321                                         $pin =~ /GPIO_PIN_([0-9]+)/;
322                                         $bit = $1;
323                                 }
324                                 $Conf .= sprintf("P%s%02d:AF%02d:V, ", $port, $bit, $altn);
325                         }
326                         $pins = '';
327                         $altn = 0;
328                 }
329         }
330         close(CONF_FILE);
331 }
332 else
333 {
334         my @names = ( );
335         my @conf = split(/\s*,\s*/, $Conf);
336
337         if (@conf == 2)
338         {
339                 push(@names, 'SDA', 'SCL');
340         } else {
341                 if (@conf == 3)
342                 {
343                         push(@names, 'NCS', 'CLK', 'IO0/DIO');
344                 }
345                 elsif (@conf == 4)
346                 {
347                         push(@names, 'NCS', 'CLK','IO1/MISO', 'IO0/MOSI');
348                 }
349                 elsif (@conf == 6)
350                 {
351                         push(@names, 'NCS', 'CLK', 'IO3/NHOLD', 'IO2/NWP', 'IO1/MISO', 'IO0/MOSI');
352                 }
353                 elsif (@conf == 10)
354                 {
355                         push(@names, 'NCS', 'CLK', 'BK_1_IO3/NHOLD', 'BK1_IO2/NWP', 'BK1_IO1/MISO', 'BK1_IO0/MOSI');
356                         push(@names, 'BK_2_IO3/NHOLD', 'BK2_IO2/NWP', 'BK2_IO1/MISO', 'BK2_IO0/MOSI');
357                 }
358                 elsif (@conf == 11)
359                 {
360                         push(@names, 'BK_1_NCS', 'CLK', 'BK_1_IO3/NHOLD', 'BK1_IO2/NWP', 'BK1_IO1/MISO', 'BK1_IO0/MOSI');
361                         push(@names, 'BK_2_NCS', 'BK_2_IO3/NHOLD', 'BK2_IO2/NWP', 'BK2_IO1/MISO', 'BK2_IO0/MOSI');
362                 }
363                 else
364                 {
365                         die("invalid config");
366                 }
367         }
368
369         for (my $index = 0; $index < @conf; $index++)
370         {
371                 uc($conf[$index]) =~ /^P([A-K])([0-9]+):\s*([A-Z0-9]+):(L|M|H|V)$/;
372                 $Pins .= sprintf(" %s: P%s%02d,", $names[$index], $1, $2);
373         }
374         chop($Pins);
375 }
376
377 if (exists $Conf{'BK1_IO0'})
378 {
379         # QuadSPI on F4, F7, H7
380         my $line;
381         for my $i ('NCS', 'BK1_NCS', 'CLK', 'BK1_IO3', 'BK1_IO2', 'BK1_IO1', 'BK1_IO0')
382         {
383                 (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i));
384         }
385 }
386
387 if (exists $Conf{'BK2_IO0'})
388 {
389         # QuadSPI on F4, F7, H7
390         my $line;
391         for my $i ('NCS', 'BK2_NCS', 'CLK', 'BK2_IO3', 'BK2_IO2', 'BK2_IO1', 'BK2_IO0')
392         {
393                 (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i));
394         }
395 }
396
397 if (exists $Conf{'P1_IO0'})
398 {
399         # OctoSPI on L4+, L5, H7
400         my $line;
401         for my $i ('P1_NCS', 'P1_CLK', 'P1_DQS', 'P1_IO7', 'P1_IO6', 'P1_IO5', 'P1_IO4',
402                            'P1_IO3', 'P1_IO2', 'P1_IO1', 'P1_IO0')
403         {
404                 (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i));
405         }
406 }
407
408 if (exists $Conf{'P2_IO0'})
409 {
410         # OctoSPI on L4+, H7
411         my $line;
412         for my $i ('P2_NCS', 'P2_CLK', 'P2_DQS', 'P2_IO7', 'P2_IO6', 'P2_IO5', 'P2_IO4',
413                            'P2_IO3', 'P2_IO2', 'P2_IO1', 'P2_IO0')
414         {
415                 (exists $Conf{$i}) && ($Pins .= sprintf(" %s: %s,", $Conf{$i}, $i));
416         }
417 }
418
419 my @Col = ( );
420 my @conf = split(/\s*,\s*/, $Conf);
421
422 if (@conf == 3)
423 {
424         splice(@conf, 2, 0, 'NONE', 'NONE', 'NONE');
425 }
426 elsif (@conf == 4)
427 {
428         splice(@conf, 2, 0, 'NONE', 'NONE');
429 }
430
431 foreach my $line (@conf)
432 {
433         $line = uc($line);
434         $line =~ /^P([A-K])([0-9]+):\s*([A-Z0-9]+):(L|M|H|V)$/;
435         my $port = $1;
436         my $pin = $2;
437         my $conf = $3;
438         my $speed = $4;
439
440         my $MODER = 0x0;
441         my $OTYPER = 0x0;
442         my $OSPEEDR = 0x0;
443         my $PUPDR = 0x0;
444         my $AFR = 0x0;
445         my $num = ord(${port}) - ord('A');
446         my $out = $Out[$num];
447
448         (exists $$out{'DEF'}) || ($$out{'DEF'} = 0);
449
450         if ($conf eq '')
451         {
452                 if ($line ne 'NONE')
453                 {
454                         printf(STDERR "invalid conf %s\n", $line);
455                 }
456                 next;
457         }
458         elsif ($conf =~ /^AF([0-9]+)(|P|O)(|UP|DO)$/)
459         {
460                 if ($STM32F1)
461                 {
462                         printf(STDERR "no alternate %s for F1 family\n", $line);
463                         next;
464                 }
465                 if (($1 < 0) || ($1 > 15))
466                 {
467                         printf(STDERR "invalid alternate %s\n", $line);
468                         next;
469                 }
470                 $MODER = 0x2;
471                 $AFR = $1;
472                 if ($pin <= 7)
473                 {
474                         $$out{'AFRL_H'} |= ($AFR << (${pin} << 2));
475                         $$out{'AFRL_L'} |= (($AFR ^ 0xF) << (${pin} << 2));
476                 }
477                 else
478                 {
479                         $$out{'AFRH_H'} |= ($AFR << ((${pin} - 8) << 2));
480                         $$out{'AFRH_L'} |= (($AFR ^ 0xF) << ((${pin} - 8) << 2));
481                 }
482                 if ($2 ne '') {
483                         $OTYPER = ($1 eq 'O') ? 0x1 : 0x0;
484                         $$out{'OTYPER_H'} |= ($OTYPER << $pin);
485                         $$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin);
486                 }
487                 $PUPDR = ($3 eq 'UP') ? 0x1 : (($3 eq 'DO') ? 0x2 : 0x0);
488                 $$out{'PUPDR_H'} |= ($PUPDR << (${pin} << 1));
489                 $$out{'PUPDR_L'} |= (($PUPDR ^0x3) << (${pin} << 1));
490                 $conf = sprintf("AF%02d%s%s", $AFR, $2, $3);
491         }
492         elsif ($conf =~ /^IN(|P|O)(|UP|DO)$/)
493         {
494                 if ($STM32F1)
495                 {
496                         $MODER = ($1 eq '') ? 0x4 : 0x8;
497                         ($2 eq 'UP') && ($$out{'PUPDR_H'} |= (1 << ${pin}));
498                         ($2 eq 'DO') && ($$out{'PUPDR_L'} |= (1 << ${pin}));
499                 }
500                 else
501                 {
502                         $MODER = 0x0;
503                         if ($1 ne '')
504                         {
505                                 $OTYPER = ($1 eq 'O') ? 0x1 : 0x0;
506                                 $$out{'OTYPER_H'} |= ($OTYPER << $pin);
507                                 $$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin);
508                         }
509                         $PUPDR = ($2 eq 'UP') ? 0x1 : (($2 eq 'DO') ? 0x2 : 0x0);
510                         $$out{'PUPDR_H'} |= ($PUPDR << (${pin} << 1));
511                         $$out{'PUPDR_L'} |= (($PUPDR ^0x3) << (${pin} << 1));
512                 }
513                 ($2 eq 'UP') && ($$out{'ODR_H'} |= (1 << ${pin}));
514                 ($2 eq 'DO') && ($$out{'ODR_L'} |= (1 << ${pin}));
515         }
516         elsif ($conf =~ /^P(P|O)(|UP|DO)$/)
517         {
518                 if ($STM32F1)
519                 {
520                         $MODER = ($1 eq 'O') ? 0x4 : 0x0;
521                         $MODER |= (($speed eq 'V') ? 0x03 : (($speed eq 'L') ? 0x2 : 0x1));
522                         if ($2 ne '')
523                         {
524                                 printf(STDERR "WARNING: no output w/ pull-up/pull-down for F1 family %s\n", $line);
525                         }
526                 }
527                 else
528                 {
529                         $MODER = 0x1;
530                         $OTYPER = ($1 eq 'O') ? 0x1 : 0x0;
531                         $$out{'OTYPER_H'} |= ($OTYPER << $pin);
532                         $$out{'OTYPER_L'} |= (($OTYPER ^ 0x1) << $pin);
533                         $PUPDR = ($2 eq 'UP') ? 0x1 : (($2 eq 'DO') ? 0x2 : 0x0);
534                         $$out{'PUPDR_H'} |= ($PUPDR << ($pin << 1));
535                         $$out{'PUPDR_L'} |= (($PUPDR ^ 0x3) << ($pin << 1));
536                 }
537                 ($2 eq 'UP') && ($$out{'ODR_H'} |= (1 << ${pin}));
538                 ($2 eq 'DO') && ($$out{'ODR_L'} |= (1 << ${pin}));
539         }
540         else
541         {
542                 printf(STDERR "invalid conf %s\n", $line);
543                 next;
544         }
545
546         if ($$out{'DEF'} & (1<< ${pin}))
547         {
548                 printf(STDERR "redefinition: %s\n", $line);
549         }
550
551         if ($STM32F1)
552         {
553                 if ($pin >= 8)
554                 {
555                         $$out{'CRH_H'} |= ($MODER << (($pin & 0x7) << 2));
556                         $$out{'CRH_L'} |= (($MODER ^ 0xF) << (($pin & 0x7) << 2));
557                 }
558                 else
559                 {
560                         $$out{'CRL_H'} |= ($MODER << (($pin & 0x7) << 2));
561                         $$out{'CRL_L'} |= (($MODER ^ 0xF) << (($pin & 0x7) << 2));
562                 }
563
564                 $Exor = sprintf("0x%08X %2d", ${GPIO_BASE} + (ord($port)  - ord('A')) * ${GPIO_OFFS} + ${GPIO_ODR}, $pin);
565                 my $exor = 0xB << (($pin & 0x7) << 2);
566                 (($MODER & 0x3) == 0x0) && ($Exor .= sprintf(" 0x%03X 0x%03X 0x%08X",
567                         ((($pin >= 8) ? ${GPIO_CRH} : ${GPIO_CRL})-${GPIO_ODR}) & 0x3FF,
568                         ((($pin >= 8) ? ${GPIO_CRH} : ${GPIO_CRL})-${GPIO_ODR}) & 0x3FF, $exor));
569         }
570         else
571         {
572                 $$out{'DEF'} |= (1 << ${pin});
573                 $$out{'MODER_H'} |= ($MODER << (${pin} << 1));
574                 $$out{'MODER_L'} |= (($MODER ^ 0x3) << (${pin} << 1));
575
576                 $OSPEEDR = (($speed eq 'V') ? 0x3 : (($speed eq 'H') ? 0x2 : (($speed eq 'M') ? 0x1 : 0x0)));
577                 $$out{'OSPEEDR_H'} |= ($OSPEEDR << (${pin} << 1));
578                 $$out{'OSPEEDR_L'} |= (($OSPEEDR ^ 0x3) << (${pin} << 1));
579
580                 $Exor = sprintf("0x%08X %2d", ${GPIO_BASE} + (ord($port)  - ord('A')) * ${GPIO_OFFS} + ${GPIO_ODR}, $pin);
581                 my $exor = (0x1 << ($pin << 1));
582                 ($MODER == 0x0) && ($Exor .= sprintf(" 0x%03X 0x%03X 0x%08X", (${GPIO_MODER}-${GPIO_ODR}) & 0x3FF,
583                         (${GPIO_MODER}-${GPIO_ODR}) & 0x3FF, $exor));
584         }
585
586         push(@{$Port[$num]}, sprintf("P%s%02d:%s:%s", $port, $pin, $conf, $speed));
587         push(@Col, $Exor);
588 }
589
590 my $Col = sprintf("${Sep}0x%03X ", (${GPIO_IDR}-${GPIO_ODR}) & 0x3FF);
591 for (my $i = 0; $i < @Col; $i++)
592 {
593         if (($i != 0) && (($i % 2) == 0))
594         {
595                 (($i + 1) < @Col) && ($Col .= "\\\n${Sep}");
596         }
597         $Col .= sprintf("%s ", $Col[$i]);
598 }
599 printf("%s\n", $Col);
600
601 my @Col = ( );
602 my $Set;
603 for (my $i = 0; $i < @Out; $i++)
604 {
605         my $out = $Out[$i];
606         my $addr = ${GPIO_BASE} + $i * ${GPIO_OFFS};
607         my $count = 0;
608
609         if ($STM32F1)
610         {
611                 if (($$out{'CRH_H'} | $$out{'CRH_L'} | $$out{'CRL_H'} | $$out{'CRL_L'} |
612                                 $$out{'PUPDR_H'} | $$out{'PUPDR_L'}) != 0)
613                 {
614                         push(@Col, sort({ $b cmp $a } @{$Port[$i]}));
615
616                         $Set .= sprintf("\n%s# Port %s: %s\n", ${Sep}, chr($i + ord('A')),
617                                 join(", ", sort({ $b cmp $a } @{$Port[$i]})));
618
619                         (($$out{'CRL_H'} | $$out{'CRL_L'}) != 0) &&
620                                 ($Set .= sprintf("${Form}CRL\n", $addr + ${GPIO_CRL}, $$out{'CRL_H'}, $$out{'CRL_L'}));
621
622                         (($$out{'CRH_H'} | $$out{'CRH_L'}) != 0) &&
623                                 ($Set .= sprintf("${Form}CRH\n", $addr + ${GPIO_CRH}, $$out{'CRH_H'}, $$out{'CRH_L'}));
624
625                         (($$out{'ODR_H'} | $$out{'ODR_L'}) != 0) &&
626                                 ($Set .= sprintf("${Form}ODR/PUPDR\n", $addr + ${GPIO_ODR}, $$out{'ODR_H'}, $$out{'ODR_L'}));
627                 }
628         }
629         else
630         {
631                 if (($$out{'MODER_H'} | $$out{'MODER_L'} |
632                         $$out{'OTYPER_H'} | $$out{'OTYPER_L'} |
633                         $$out{'OSPEEDR_H'} | $$out{'OSPEEDR_L'} |
634                         $$out{'PUPDR_H'} | $$out{'PUPDR_L'} |
635                         $$out{'ODR_H'} | $$out{'ODR_L'} |
636                         $$out{'AFRL_H'} | $$out{'AFRL_L'} |
637                         $$out{'AFRH_H'} | $$out{'AFRH_L'}) != 0)
638                 {
639                         push(@Col, sort({ $b cmp $a } @{$Port[$i]}));
640
641                         $Set .= sprintf("%s# Port %s: %s\n", ${Sep}, chr($i + ord('A')),
642                                 join(", ", sort({ $b cmp $a } @{$Port[$i]})));
643
644                         (($$out{'MODER_H'} | $$out{'MODER_L'}) != 0) &&
645                                 ($Set .= sprintf("${Form}MODER\n", $addr + ${GPIO_MODER}, $$out{'MODER_H'}, $$out{'MODER_L'}));
646
647                         (($$out{'OTYPER_H'} | $$out{'OTYPER_L'}) != 0) &&
648                                 ($Set .= sprintf("${Form}OTYPER\n", $addr + ${GPIO_OTYPER}, $$out{'OTYPER_H'}, $$out{'OTYPER_L'}));
649
650                         (($$out{'OSPEEDR_H'} | $$out{'OSPEEDR_L'}) != 0) &&
651                                 ($Set .= sprintf("${Form}OSPEEDR\n", $addr + ${GPIO_OSPEEDR}, $$out{'OSPEEDR_H'}, $$out{'OSPEEDR_L'}));
652
653                         (($$out{'PUPDR_H'} | $$out{'PUPDR_L'}) != 0) &&
654                                 ($Set .= sprintf("${Form}PUPDR\n", $addr + ${GPIO_PUPDR}, $$out{'PUPDR_H'}, $$out{'PUPDR_L'}));
655
656                         (($$out{'ODR_H'} | $$out{'ODR_L'}) != 0) &&
657                                 ($Set .= sprintf("${Form}ODR\n", $addr + ${GPIO_ODR}, $$out{'ODR_H'}, $$out{'ODR_L'}));
658
659                         (($$out{'AFRL_H'} | $$out{'AFRL_L'}) != 0) &&
660                                 ($Set .= sprintf("${Form}AFRL\n", $addr + ${GPIO_AFRL}, $$out{'AFRL_H'}, $$out{'AFRL_L'}));
661
662                         (($$out{'AFRH_H'} | $$out{'AFRH_L'}) != 0) &&
663                                 ($Set .= sprintf("${Form}AFRH\n", $addr + ${GPIO_AFRH}, $$out{'AFRH_H'}, $$out{'AFRH_L'}));
664                 }
665         }
666 }
667
668 my $Col = '';
669 for (my $i = 0; $i < @Col; $i++)
670 {
671         if (($i % 6) == 0)
672         {
673                 chop($Col);
674                 (($i + 1) < @Col) && ($Col .= "\n${Sep}#");
675         }
676         $Col .= sprintf(" %s,", $Col[$i]);
677 }
678 chop($Col);
679 #printf("\n%s\n", $Pins);
680 printf("%s\n", $Col);
681 printf("%s\n", $Set);