]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/at91/board_tsc4370.c
MFC r334158:
[FreeBSD/FreeBSD.git] / sys / arm / at91 / board_tsc4370.c
1 /*-
2  * Copyright (c) 2005-2008 Olivier Houchard.  All rights reserved.
3  * Copyright (c) 2005-2012 Warner Losh.  All rights reserved.
4  * Copyright (c) 2007-2014 Ian Lepore.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 /*
29  * Board init code for the TSC4370, and all other current TSC mainboards.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 #include <sys/param.h>
35 #include <sys/systm.h>
36
37 #include <arm/at91/at91_pioreg.h>
38 #include <arm/at91/at91_piovar.h>
39 #include <arm/at91/at91_pmcreg.h>
40 #include <arm/at91/at91_pmcvar.h>
41 #include <arm/at91/at91_twireg.h>
42 #include <arm/at91/at91_usartreg.h>
43 #include <arm/at91/at91board.h>
44 #include <arm/at91/at91var.h>
45 #include <arm/at91/at91rm9200var.h>
46 #include <arm/at91/at91rm92reg.h>
47 #include <arm/at91/if_atereg.h>
48 #include <machine/board.h>
49 #include <machine/cpu.h>
50 #include <machine/machdep.h>
51 #include <net/ethernet.h>
52 #include <sys/reboot.h>
53
54 /*
55  * RD4HW()/WR4HW() read and write at91rm9200 hardware register space directly.
56  * They serve the same purpose as the RD4()/WR4() idiom you see in many drivers,
57  * except that those translate to bus_space calls, but in this code we need to
58  * access the registers directly before the at91 bus_space stuff is set up.
59  */
60
61 static inline uint32_t 
62 RD4HW(uint32_t devbase, uint32_t regoff)
63 {
64         return *(volatile uint32_t *)(AT91_BASE + devbase + regoff);
65 }
66
67 static inline void
68 WR4HW(uint32_t devbase, uint32_t regoff, uint32_t val)
69 {
70         *(volatile uint32_t *)(AT91_BASE + devbase + regoff) = val;
71 }
72
73 /*
74  * This is the same calculation the at91 uart driver does, we use it to update
75  * the console uart baud rate after changing the MCK rate.
76  */
77 #ifndef BAUD2DIVISOR
78 #define BAUD2DIVISOR(b) \
79         ((((at91_master_clock * 10) / ((b) * 16)) + 5) / 10)
80 #endif
81
82 /*
83  * If doing an in-house build, use tsc_bootinfo.h which is shared with our
84  * custom boot2.  Otherwise define some crucial bits of it here, enough to allow
85  * this code to compile.
86  */
87 #ifdef TSC_BUILD
88 #include <machine/tsc_bootinfo.h>
89 #else
90 struct tsc_bootinfo {
91         uint32_t        bi_size;
92         uint32_t        bi_version;
93         uint32_t        bi_flags; /* RB_xxxxx flags from sys/reboot.h */
94         char    bi_rootdevname[64];
95 };
96 #define TSC_BOOTINFO_MAGIC      0x06C30000 
97 #endif
98
99 static struct arm_boot_params   boot_params;
100 static struct tsc_bootinfo      inkernel_bootinfo;
101
102 /*
103  * Change the master clock config and wait for it to stabilize.
104  */
105 static void
106 change_mckr(uint32_t mckr)
107 {
108         int i;
109
110         WR4HW(AT91RM92_PMC_BASE, PMC_MCKR, mckr);
111
112         for (i = 0; i < 1000; ++i)
113                 if ((RD4HW(AT91RM92_PMC_BASE, PMC_SR) & PMC_IER_MCKRDY))
114                         return;
115 }
116
117 /*
118  * Allow the master clock frequency to be changed from whatever the bootloader
119  * set up, because sometimes it's harder to change/update a bootloader than it
120  * is to change/update the kernel once a product is in the field.
121  */
122 static void
123 master_clock_init(void)
124 {
125         uint32_t mckr = RD4HW(AT91RM92_PMC_BASE, PMC_MCKR);
126         int hintvalue = 0;
127         int newmckr = 0;
128
129          /*
130          * If there's a hint that specifies the contents of MCKR, use it
131          * without question (it had better be right).
132          *
133          * If there's a "mckfreq" hint it might be in hertz or mhz (convert the
134          * latter to hz).  Calculate the new MCK divider.  If the CPU frequency
135          * is not a sane multiple of the hinted MCK frequency this is likely to
136          * behave badly.  The moral is: don't hint at impossibilities.
137          */
138
139         if (resource_int_value("at91", 0, "mckr", &hintvalue) == 0) {
140                 newmckr = hintvalue;
141         } else {
142                 hintvalue = 90; /* Default to 90mhz if not specified. */
143                 resource_int_value("at91", 0, "mckfreq", &hintvalue);
144                 if (hintvalue != 0) {
145                         if (hintvalue < 1000)
146                                 hintvalue *= 1000000;
147                         if (hintvalue != at91_master_clock) {
148                                 uint32_t divider;
149                                 struct at91_pmc_clock * cpuclk;
150                                 cpuclk = at91_pmc_clock_ref("cpu");
151                                 divider = (cpuclk->hz / hintvalue) - 1;
152                                 newmckr = (mckr & 0xFFFFFCFF) | ((divider & 0x03) << 8);
153                                 at91_pmc_clock_deref(cpuclk);
154                         }
155                 }
156         }
157
158         /* If the new mckr value is different than what's in the register now,
159          * make the change and wait for the clocks to settle (MCKRDY status).
160          *
161          * MCKRDY will never be asserted unless either the selected clock or the
162          * prescaler value changes (but not both at once) [this is detailed in
163          * the rm9200 errata]. This code assumes the prescaler value is always
164          * zero and that by time we get to here we're running on something other
165          * than the slow clock, so to change the mckr divider we first change
166          * back to the slow clock (keeping prescaler and divider unchanged),
167          * then go back to the original selected clock with the new divider.
168          *
169          * After changing MCK, go re-init everything clock-related, and reset
170          * the baud rate generator for the console (doing this here is kind of a
171          * rude hack, but hey, you do what you have to to run MCK faster).
172          */
173
174         if (newmckr != 0 && newmckr != mckr) {
175                 if (mckr & 0x03)
176                         change_mckr(mckr & ~0x03);
177                 change_mckr(newmckr);
178                 at91_pmc_init_clock();
179                 WR4HW(AT91RM92_DBGU_BASE, USART_BRGR, BAUD2DIVISOR(115200));
180         }
181 }
182
183 /*
184  * TSC-specific code to read the ID eeprom on the mainboard and extract the
185  * unit's EUI-64 which gets translated into a MAC-48 for ethernet.
186  */
187 static void
188 eeprom_init(void)
189 {
190         const uint32_t twiHz    = 400000;
191         const uint32_t twiCkDiv = 1 << 16;
192         const uint32_t twiChDiv = ((at91_master_clock / twiHz) - 2) << 8;
193         const uint32_t twiClDiv = ((at91_master_clock / twiHz) - 2);
194
195         /*
196          * Set the TWCK and TWD lines for Periph A, no pullup, open-drain.
197          */
198         at91_pio_use_periph_a(AT91RM92_PIOA_BASE,
199             AT91C_PIO_PA25 | AT91C_PIO_PA26, 0);
200         at91_pio_gpio_high_z(AT91RM92_PIOA_BASE, AT91C_PIO_PA25, 1);
201
202         /*
203          * Enable TWI power (irq numbers are also device IDs for power)
204          */
205         WR4HW(AT91RM92_PMC_BASE, PMC_PCER, 1u << AT91RM92_IRQ_TWI);
206
207         /*
208          * Disable TWI interrupts, reset device, enable Master mode,
209          * disable Slave mode, set the clock.
210          */
211         WR4HW(AT91RM92_TWI_BASE, TWI_IDR, 0xffffffff);
212         WR4HW(AT91RM92_TWI_BASE, TWI_CR, TWI_CR_SWRST);
213         WR4HW(AT91RM92_TWI_BASE, TWI_CR, TWI_CR_MSEN | TWI_CR_SVDIS);
214         WR4HW(AT91RM92_TWI_BASE, TWI_CWGR, twiCkDiv | twiChDiv | twiClDiv);
215 }
216
217 static int
218 eeprom_read(uint32_t EE_DEV_ADDR, uint32_t ee_off, void * buf, uint32_t size)
219 {
220         uint8_t *bufptr = (uint8_t *)buf;
221         uint32_t status;
222         uint32_t count;
223
224         /* Clean out any old status and received byte. */
225         status = RD4HW(AT91RM92_TWI_BASE, TWI_SR);
226         status = RD4HW(AT91RM92_TWI_BASE, TWI_RHR);
227
228         /* Set the TWI Master Mode Register */
229         WR4HW(AT91RM92_TWI_BASE, TWI_MMR,
230             TWI_MMR_DADR(EE_DEV_ADDR) | TWI_MMR_IADRSZ(2) | TWI_MMR_MREAD);
231
232         /* Set TWI Internal Address Register */
233         WR4HW(AT91RM92_TWI_BASE, TWI_IADR, ee_off);
234
235         /* Start transfer */
236         WR4HW(AT91RM92_TWI_BASE, TWI_CR, TWI_CR_START);
237
238         status = RD4HW(AT91RM92_TWI_BASE, TWI_SR);
239
240         while (size-- > 1){
241                 /* Wait until Receive Holding Register is full */
242                 count = 1000000;
243                 while (!(RD4HW(AT91RM92_TWI_BASE, TWI_SR) & TWI_SR_RXRDY) && 
244                     --count != 0)
245                         continue;
246                 if (count <= 0)
247                         return -1;
248                 /* Read and store byte */
249                 *bufptr++ = (uint8_t)RD4HW(AT91RM92_TWI_BASE, TWI_RHR);
250         }
251         WR4HW(AT91RM92_TWI_BASE, TWI_CR, TWI_CR_STOP);
252
253         status = RD4HW(AT91RM92_TWI_BASE, TWI_SR);
254
255         /* Wait until transfer is finished */
256         while (!(RD4HW(AT91RM92_TWI_BASE, TWI_SR) & TWI_SR_TXCOMP))
257                 continue;
258
259         /* Read last byte */
260         *bufptr = (uint8_t)RD4HW(AT91RM92_TWI_BASE, TWI_RHR);
261
262         return 0;
263 }
264
265 static int
266 set_mac_from_idprom(void)
267 {
268 #define SIGNATURE_SIZE          4
269 #define EETYPE_SIZE             2
270 #define BSLENGTH_SIZE           2
271 #define RAW_SIZE                52
272 #define EUI64_SIZE              8
273 #define BS_SIGNATURE            0x21706d69
274 #define BSO_SIGNATURE           0x216f7362
275 #define DEVOFFSET_BSO_SIGNATURE 0x20
276 #define OFFSET_BS_SIGNATURE     0
277 #define SIZE_BS_SIGNATURE       SIGNATURE_SIZE
278 #define OFFSET_EETYPE           (OFFSET_BS_SIGNATURE + SIZE_BS_SIGNATURE)
279 #define SIZE_EETYPE             EETYPE_SIZE
280 #define OFFSET_BOOTSECTSIZE     (OFFSET_EETYPE + SIZE_EETYPE)
281 #define SIZE_BOOTSECTSIZE       BSLENGTH_SIZE
282 #define OFFSET_RAW              (OFFSET_BOOTSECTSIZE + SIZE_BOOTSECTSIZE)
283 #define OFFSET_EUI64            (OFFSET_RAW + RAW_SIZE)
284 #define EE_DEV_ADDR             0xA0    /* eeprom is AT24C256 at address 0xA0 */
285
286         int status;
287         uint32_t dev_offset = 0;
288         uint32_t sig;
289         uint8_t eui64[EUI64_SIZE];
290         uint8_t eaddr[ETHER_ADDR_LEN];
291
292         eeprom_init();
293
294         /* Check for the boot section signature at offset 0. */
295         status = eeprom_read(EE_DEV_ADDR, OFFSET_BS_SIGNATURE, &sig, sizeof(sig));
296         if (status == -1)
297                 return -1;
298
299         if (sig != BS_SIGNATURE) {
300                 /* Check for the boot section offset signature. */
301                 status = eeprom_read(EE_DEV_ADDR, 
302                     DEVOFFSET_BSO_SIGNATURE, &sig, sizeof(sig));
303                 if ((status == -1) || (sig != BSO_SIGNATURE))
304                                 return -1;
305
306                 /* Read the device offset of the boot section structure. */
307                 status = eeprom_read(EE_DEV_ADDR, 
308                     DEVOFFSET_BSO_SIGNATURE + sizeof(sig), 
309                     &dev_offset, sizeof(dev_offset));
310                 if (status == -1)
311                                 return -1;
312
313                 /* Check for the boot section signature. */
314                 status = eeprom_read(EE_DEV_ADDR, 
315                     dev_offset + OFFSET_BS_SIGNATURE, &sig, sizeof(sig));
316                 if ((status == -1) || (sig != BS_SIGNATURE))
317                                 return -1;
318         }
319         dev_offset += OFFSET_EUI64;
320
321         /* Read the EUI64 from the device.  */
322         if (eeprom_read(EE_DEV_ADDR, dev_offset, eui64, sizeof(eui64)) == -1)
323                 return -1;
324
325         /* Transcribe the EUI-64 to a MAC-48.
326          *
327          * Given an EUI-64 of aa:bb:cc:dd:ee:ff:gg:hh
328          *
329          *   if (ff is zero and ee is non-zero)
330          *      mac is aa:bb:cc:ee:gg:hh
331          *   else
332          *      mac is aa:bb:cc:ff:gg:hh
333          *
334          * This logic fixes a glitch in our mfg process in which the ff byte was
335          * always zero and the ee byte contained a non-zero value.  This
336          * resulted in duplicate MAC addresses because we discarded the ee byte.
337          * Now they've fixed the process so that the ff byte is non-zero and
338          * unique addresses are formed from the ff:gg:hh bytes.  If the ff byte
339          * is zero, then we have a unit manufactured during the glitch era, and
340          * we fix the problem by grabbing the ee byte rather than the ff byte.
341          */
342         eaddr[0] = eui64[0];
343         eaddr[1] = eui64[1];
344         eaddr[2] = eui64[2];
345         eaddr[3] = eui64[5];
346         eaddr[4] = eui64[6];
347         eaddr[5] = eui64[7];
348
349         if (eui64[5] == 0 && eui64[4] != 0) {
350                 eaddr[3] = eui64[4];
351         }
352
353         /*
354          * Set the address in the hardware regs where the ate driver
355          * looks for it.
356          */
357         WR4HW(AT91RM92_EMAC_BASE, ETH_SA1L, 
358             (eaddr[3] << 24) | (eaddr[2] << 16) | (eaddr[1] << 8) | eaddr[0]);
359         WR4HW(AT91RM92_EMAC_BASE, ETH_SA1H, 
360             (eaddr[5] << 8) | (eaddr[4]));
361
362         printf(
363             "ID: EUI-64 %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"
364             "    MAC-48 %02x:%02x:%02x:%02x:%02x:%02x\n"
365             "    read from i2c device 0x%02X offset 0x%x\n",
366             eui64[0], eui64[1], eui64[2], eui64[3], 
367             eui64[4], eui64[5], eui64[6], eui64[7], 
368             eaddr[0], eaddr[1], eaddr[2], 
369             eaddr[3], eaddr[4], eaddr[5], 
370             EE_DEV_ADDR, dev_offset);
371
372         return (0);
373 }
374
375 /*
376  * Assign SPI chip select pins based on which chip selects are found in hints.
377  */
378 static void
379 assign_spi_pins(void)
380 {
381         struct {
382                 uint32_t     num;
383                 const char * name;
384         } chipsel_pins[] = {
385                 { AT91C_PIO_PA3, "PA3", },
386                 { AT91C_PIO_PA4, "PA4", },
387                 { AT91C_PIO_PA5, "PA5", },
388                 { AT91C_PIO_PA6, "PA6", },
389         };
390         int anchor = 0;
391         uint32_t chipsel_inuse = 0;
392
393         /*
394          * Search through all device hints looking for any that have
395          * ".at=spibus0".  For each one found, ensure that there is also a
396          * chip select hint ".cs=<num>" and that <num> is 0-3, and assign the
397          * corresponding pin to the SPI peripheral.  Whine if we find a SPI
398          * device with a missing or invalid chipsel hint.
399          */
400         for (;;) {
401                 const char * rName = "";
402                 int unit = 0;
403                 int cs = 0;
404                 int ret;
405
406                 ret = resource_find_match(&anchor, &rName, &unit, "at", "spibus0");
407                 if (ret != 0)
408                         break;
409
410                 ret = resource_int_value(rName, unit, "cs", &cs);
411                 if (ret != 0) {
412                         printf( "Error: hint for SPI device %s%d "
413                                 "without a chip select hint; "
414                                 "device will not function.\n",
415                                 rName, unit);
416                         continue;
417                 }
418                 if (cs < 0 || cs > 3) {
419                         printf( "Error: hint for SPI device %s%d "
420                                 "contains an invalid chip select "
421                                 "value: %d\n",
422                                 rName, unit, cs);
423                         continue;
424                 }
425                 if (chipsel_inuse & (1 << cs)) {
426                         printf( "Error: hint for SPI device %s%d "
427                                 "specifies chip select %d, which "
428                                 "is already used by another device\n",
429                                 rName, unit, cs);
430                         continue;
431                 }
432                 chipsel_inuse |= 1 << cs;
433                 at91_pio_use_periph_a(AT91RM92_PIOA_BASE, 
434                         chipsel_pins[cs].num, 1);
435                 printf( "Configured pin %s as SPI chip "
436                         "select %d for %s%d\n",
437                         chipsel_pins[cs].name, cs, rName, unit);
438         }
439
440         /*
441          * If there were hints for any SPI devices, assign the basic SPI IO pins
442          * and enable SPI power (irq numbers are also device IDs for power).
443          */
444         if (chipsel_inuse != 0) {
445                 at91_pio_use_periph_a(AT91RM92_PIOA_BASE, 
446                         AT91C_PIO_PA1 | AT91C_PIO_PA0 | AT91C_PIO_PA2, 0);
447                 WR4HW(AT91RM92_PMC_BASE, PMC_PCER, 1u << AT91RM92_IRQ_SPI);
448         }
449 }
450
451 BOARD_INIT long
452 board_init(void)
453 {
454         int is_bga, rev_mii;
455
456         /*
457          * Deal with bootinfo (if any) passed in from the boot2 bootloader and
458          * copied to the static inkernel_bootinfo earlier in the init.  Do this
459          * early so that bootverbose is set from this point on.
460          */
461         if (inkernel_bootinfo.bi_size > 0 && 
462             (inkernel_bootinfo.bi_flags & RB_BOOTINFO)) {
463                 struct tsc_bootinfo *bip = &inkernel_bootinfo;
464                 printf("TSC_BOOTINFO: size %u howtoflags=0x%08x rootdev='%s'\n", 
465                     bip->bi_size, bip->bi_flags, bip->bi_rootdevname);
466                 boothowto = bip->bi_flags;
467                 bootverbose = (boothowto & RB_VERBOSE);
468                 if (bip->bi_rootdevname[0] != 0)
469                         rootdevnames[0] = bip->bi_rootdevname;
470         }
471
472         /*
473          * The only way to know if we're in a BGA package (and thus have PIOD)
474          * is to be told via a hint; there's nothing detectable in the silicon.
475          * This is esentially an rm92-specific extension to getting the chip ID
476          * (which was done by at91_machdep just before calling this routine).
477          * If it is the BGA package, enable the clock for PIOD.
478          */
479         is_bga = 0;
480         resource_int_value("at91", 0, "is_bga_package", &is_bga);
481         
482         if (is_bga)
483                 WR4HW(AT91RM92_PMC_BASE, PMC_PCER, 1u << AT91RM92_IRQ_PIOD);
484         
485 #if __FreeBSD_version >= 1000000
486         at91rm9200_set_subtype(is_bga ? AT91_ST_RM9200_BGA : 
487             AT91_ST_RM9200_PQFP);
488 #endif
489
490         /*
491          * Go reprogram the MCK frequency based on hints.
492          */
493         master_clock_init();
494
495         /* From this point on you can use printf. */
496
497         /*
498          * Configure UARTs.
499          */
500         at91rm9200_config_uart(AT91_ID_DBGU, 0, 0);   /* DBGU just Tx and Rx */
501         at91rm9200_config_uart(AT91RM9200_ID_USART0, 1, 0);   /* Tx and Rx */
502         at91rm9200_config_uart(AT91RM9200_ID_USART1, 2, 0);   /* Tx and Rx */
503         at91rm9200_config_uart(AT91RM9200_ID_USART2, 3, 0);   /* Tx and Rx */
504         at91rm9200_config_uart(AT91RM9200_ID_USART3, 4, 0);   /* Tx and Rx */
505
506         /*
507          * Configure MCI (sdcard)
508          */
509         at91rm9200_config_mci(0);
510
511         /*
512          * Assign the pins needed by the emac device, and power it up. Also,
513          * configure it for RMII operation unless the 'revmii_mode' hint is set,
514          * in which case configure the full set of MII pins.  The revmii_mode
515          * hint is for so-called reverse-MII, used for connections to a Broadcom
516          * 5325E switch on some boards.  Note that order is important here:
517          * configure pins, then power on the device, then access the device's
518          * config registers.
519          */
520         rev_mii = 0;
521         resource_int_value("ate", 0, "phy_revmii_mode", &rev_mii);
522
523         at91_pio_use_periph_a(AT91RM92_PIOA_BASE, 
524                 AT91C_PIO_PA7 | AT91C_PIO_PA8 | AT91C_PIO_PA9 |
525                 AT91C_PIO_PA10 | AT91C_PIO_PA11 | AT91C_PIO_PA12 |
526                 AT91C_PIO_PA13 | AT91C_PIO_PA14 | AT91C_PIO_PA15 |
527                 AT91C_PIO_PA16, 0);
528         if (rev_mii) {
529                 at91_pio_use_periph_b(AT91RM92_PIOB_BASE,
530                     AT91C_PIO_PB12 | AT91C_PIO_PB13  | AT91C_PIO_PB14 |
531                     AT91C_PIO_PB15 | AT91C_PIO_PB16  | AT91C_PIO_PB17 |
532                     AT91C_PIO_PB18 | AT91C_PIO_PB19, 0);
533         }
534         WR4HW(AT91RM92_PMC_BASE, PMC_PCER, 1u << AT91RM92_IRQ_EMAC);
535         if (!rev_mii) {
536                 WR4HW(AT91RM92_EMAC_BASE, ETH_CFG, 
537                     RD4HW(AT91RM92_EMAC_BASE, ETH_CFG) | ETH_CFG_RMII);
538         }
539
540         /*
541          * Get our ethernet MAC address from the ID eeprom.
542          * Configures TWI as a side effect.
543          */
544         set_mac_from_idprom();
545
546         /*
547          * Configure SPI
548          */
549         assign_spi_pins();
550
551         /*
552          * Configure SSC
553          */
554         at91_pio_use_periph_a(
555             AT91RM92_PIOB_BASE,
556             AT91C_PIO_PB6 | AT91C_PIO_PB7 | AT91C_PIO_PB8 |   /* transmit */
557             AT91C_PIO_PB9 | AT91C_PIO_PB10 | AT91C_PIO_PB11,  /* receive */
558             0);                                               /* no pullup */
559
560         /*
561          *  We're using TC1's A1 input for PPS measurements that drive the
562          *  kernel PLL and our NTP refclock.  On some old boards we route a 5mhz
563          *  signal to TC1's A2 input (pin PA21), but we have never used that
564          *  clock (it rolls over too fast for hz=100), and now newer boards are
565          *  using pin PA21 as a CTS0 for USART1, so we no longer assign it to
566          *  the timer block like we used to here.
567          */
568         at91_pio_use_periph_b(AT91RM92_PIOA_BASE, AT91C_PIO_PA19, 0);
569
570         /*
571          * Configure pins used to bitbang-upload the firmware to the main FPGA.
572          */
573         at91_pio_use_gpio(AT91RM92_PIOB_BASE,
574             AT91C_PIO_PB16 | AT91C_PIO_PB17 | AT91C_PIO_PB18 | AT91C_PIO_PB19);
575
576         return (at91_ramsize());
577 }
578
579 /*
580  * Override the default boot param parser (supplied via weak linkage) with one
581  * that knows how to handle our custom tsc_bootinfo passed in from boot2.
582  */
583 vm_offset_t
584 parse_boot_param(struct arm_boot_params *abp)
585 {
586
587         boot_params = *abp;
588
589         /*
590          * If the right magic is in r0 and a non-NULL pointer is in r1, then
591          * it's our bootinfo, copy it.  The pointer in r1 is a physical address
592          * passed from boot2.  This routine is called immediately upon entry to
593          * initarm() and is in very nearly the same environment as boot2.  In
594          * particular, va=pa and we can safely copy the args before we lose easy
595          * access to the memory they're stashed in right now.
596          *
597          * Note that all versions of boot2 that we've ever shipped have put
598          * zeroes into r2 and r3.  Maybe that'll be useful some day.
599          */
600         if (abp->abp_r0 == TSC_BOOTINFO_MAGIC && abp->abp_r1 != 0) {
601                 inkernel_bootinfo = *(struct tsc_bootinfo *)(abp->abp_r1);
602         }
603
604         return fake_preload_metadata(abp, NULL, 0);
605 }
606
607 ARM_BOARD(NONE, "TSC4370 Controller Board");
608