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