void at91_ebi_disable(int bank) { WR4HW(AT91SAM9260_MATRIX_BASE, AT91SAM9260_EBICSA, ~(1 << bank) & RD4HW(AT91SAM9260_MATRIX_BASE, AT91SAM9260_EBICSA)); }
void at91_ebi_enable(int bank) { WR4HW(AT91SAM9260_MATRIX_BASE, AT91SAM9260_EBICSA, (1 << bank) | RD4HW(AT91SAM9260_MATRIX_BASE, AT91SAM9260_EBICSA)); }
/* * Allow the master clock frequency to be changed from whatever the bootloader * set up, because sometimes it's harder to change/update a bootloader than it * is to change/update the kernel once a product is in the field. */ static void master_clock_init(void) { uint32_t mckr = RD4HW(AT91RM92_PMC_BASE, PMC_MCKR); int hintvalue = 0; int newmckr = 0; /* * If there's a hint that specifies the contents of MCKR, use it * without question (it had better be right). * * If there's a "mckfreq" hint it might be in hertz or mhz (convert the * latter to hz). Calculate the new MCK divider. If the CPU frequency * is not a sane multiple of the hinted MCK frequency this is likely to * behave badly. The moral is: don't hint at impossibilities. */ if (resource_int_value("at91", 0, "mckr", &hintvalue) == 0) { newmckr = hintvalue; } else { hintvalue = 90; /* Default to 90mhz if not specified. */ resource_int_value("at91", 0, "mckfreq", &hintvalue); if (hintvalue != 0) { if (hintvalue < 1000) hintvalue *= 1000000; if (hintvalue != at91_master_clock) { uint32_t divider; struct at91_pmc_clock * cpuclk; cpuclk = at91_pmc_clock_ref("cpu"); divider = (cpuclk->hz / hintvalue) - 1; newmckr = (mckr & 0xFFFFFCFF) | ((divider & 0x03) << 8); at91_pmc_clock_deref(cpuclk); } } } /* If the new mckr value is different than what's in the register now, * make the change and wait for the clocks to settle (MCKRDY status). * * MCKRDY will never be asserted unless either the selected clock or the * prescaler value changes (but not both at once) [this is detailed in * the rm9200 errata]. This code assumes the prescaler value is always * zero and that by time we get to here we're running on something other * than the slow clock, so to change the mckr divider we first change * back to the slow clock (keeping prescaler and divider unchanged), * then go back to the original selected clock with the new divider. * * After changing MCK, go re-init everything clock-related, and reset * the baud rate generator for the console (doing this here is kind of a * rude hack, but hey, you do what you have to to run MCK faster). */ if (newmckr != 0 && newmckr != mckr) { if (mckr & 0x03) change_mckr(mckr & ~0x03); change_mckr(newmckr); at91_pmc_init_clock(); WR4HW(AT91RM92_DBGU_BASE, USART_BRGR, BAUD2DIVISOR(115200)); } }
/* * Change the master clock config and wait for it to stabilize. */ static void change_mckr(uint32_t mckr) { int i; WR4HW(AT91RM92_PMC_BASE, PMC_MCKR, mckr); for (i = 0; i < 1000; ++i) if ((RD4HW(AT91RM92_PMC_BASE, PMC_SR) & PMC_IER_MCKRDY)) return; }
static int eeprom_read(uint32_t EE_DEV_ADDR, uint32_t ee_off, void * buf, uint32_t size) { uint8_t *bufptr = (uint8_t *)buf; uint32_t status; uint32_t count; /* Clean out any old status and received byte. */ status = RD4HW(AT91RM92_TWI_BASE, TWI_SR); status = RD4HW(AT91RM92_TWI_BASE, TWI_RHR); /* Set the TWI Master Mode Register */ WR4HW(AT91RM92_TWI_BASE, TWI_MMR, TWI_MMR_DADR(EE_DEV_ADDR) | TWI_MMR_IADRSZ(2) | TWI_MMR_MREAD); /* Set TWI Internal Address Register */ WR4HW(AT91RM92_TWI_BASE, TWI_IADR, ee_off); /* Start transfer */ WR4HW(AT91RM92_TWI_BASE, TWI_CR, TWI_CR_START); status = RD4HW(AT91RM92_TWI_BASE, TWI_SR); while (size-- > 1){ /* Wait until Receive Holding Register is full */ count = 1000000; while (!(RD4HW(AT91RM92_TWI_BASE, TWI_SR) & TWI_SR_RXRDY) && --count != 0) continue; if (count <= 0) return -1; /* Read and store byte */ *bufptr++ = (uint8_t)RD4HW(AT91RM92_TWI_BASE, TWI_RHR); } WR4HW(AT91RM92_TWI_BASE, TWI_CR, TWI_CR_STOP); status = RD4HW(AT91RM92_TWI_BASE, TWI_SR); /* Wait until transfer is finished */ while (!(RD4HW(AT91RM92_TWI_BASE, TWI_SR) & TWI_SR_TXCOMP)) continue; /* Read last byte */ *bufptr = (uint8_t)RD4HW(AT91RM92_TWI_BASE, TWI_RHR); return 0; }
BOARD_INIT long board_init(void) { int is_bga, rev_mii; /* * Deal with bootinfo (if any) passed in from the boot2 bootloader and * copied to the static inkernel_bootinfo earlier in the init. Do this * early so that bootverbose is set from this point on. */ if (inkernel_bootinfo.bi_size > 0 && (inkernel_bootinfo.bi_flags & RB_BOOTINFO)) { struct tsc_bootinfo *bip = &inkernel_bootinfo; printf("TSC_BOOTINFO: size %u howtoflags=0x%08x rootdev='%s'\n", bip->bi_size, bip->bi_flags, bip->bi_rootdevname); boothowto = bip->bi_flags; bootverbose = (boothowto & RB_VERBOSE); if (bip->bi_rootdevname[0] != 0) rootdevnames[0] = bip->bi_rootdevname; } /* * The only way to know if we're in a BGA package (and thus have PIOD) * is to be told via a hint; there's nothing detectable in the silicon. * This is esentially an rm92-specific extension to getting the chip ID * (which was done by at91_machdep just before calling this routine). * If it is the BGA package, enable the clock for PIOD. */ is_bga = 0; resource_int_value("at91", 0, "is_bga_package", &is_bga); if (is_bga) WR4HW(AT91RM92_PMC_BASE, PMC_PCER, 1u << AT91RM92_IRQ_PIOD); #if __FreeBSD_version >= 1000000 at91rm9200_set_subtype(is_bga ? AT91_ST_RM9200_BGA : AT91_ST_RM9200_PQFP); #endif /* * Go reprogram the MCK frequency based on hints. */ master_clock_init(); /* * Configure UARTs. */ at91rm9200_config_uart(AT91_ID_DBGU, 0, 0); /* DBGU just Tx and Rx */ at91rm9200_config_uart(AT91RM9200_ID_USART0, 1, 0); /* Tx and Rx */ at91rm9200_config_uart(AT91RM9200_ID_USART1, 2, 0); /* Tx and Rx */ at91rm9200_config_uart(AT91RM9200_ID_USART2, 3, 0); /* Tx and Rx */ at91rm9200_config_uart(AT91RM9200_ID_USART3, 4, 0); /* Tx and Rx */ /* * Configure MCI (sdcard) */ at91rm9200_config_mci(0); /* * Assign the pins needed by the emac device, and power it up. Also, * configure it for RMII operation unless the 'revmii_mode' hint is set, * in which case configure the full set of MII pins. The revmii_mode * hint is for so-called reverse-MII, used for connections to a Broadcom * 5325E switch on some boards. Note that order is important here: * configure pins, then power on the device, then access the device's * config registers. */ rev_mii = 0; resource_int_value("ate", 0, "phy_revmii_mode", &rev_mii); at91_pio_use_periph_a(AT91RM92_PIOA_BASE, AT91C_PIO_PA7 | AT91C_PIO_PA8 | AT91C_PIO_PA9 | AT91C_PIO_PA10 | AT91C_PIO_PA11 | AT91C_PIO_PA12 | AT91C_PIO_PA13 | AT91C_PIO_PA14 | AT91C_PIO_PA15 | AT91C_PIO_PA16, 0); if (rev_mii) { at91_pio_use_periph_b(AT91RM92_PIOB_BASE, AT91C_PIO_PB12 | AT91C_PIO_PB13 | AT91C_PIO_PB14 | AT91C_PIO_PB15 | AT91C_PIO_PB16 | AT91C_PIO_PB17 | AT91C_PIO_PB18 | AT91C_PIO_PB19, 0); } WR4HW(AT91RM92_PMC_BASE, PMC_PCER, 1u << AT91RM92_IRQ_EMAC); if (!rev_mii) { WR4HW(AT91RM92_EMAC_BASE, ETH_CFG, RD4HW(AT91RM92_EMAC_BASE, ETH_CFG) | ETH_CFG_RMII); } /* * Get our ethernet MAC address from the ID eeprom. * Configures TWI as a side effect. */ set_mac_from_idprom(); /* * Configure SPI */ assign_spi_pins(); /* * Configure SSC */ at91_pio_use_periph_a( AT91RM92_PIOB_BASE, AT91C_PIO_PB6 | AT91C_PIO_PB7 | AT91C_PIO_PB8 | /* transmit */ AT91C_PIO_PB9 | AT91C_PIO_PB10 | AT91C_PIO_PB11, /* receive */ 0); /* no pullup */ /* * We're using TC1's A1 input for PPS measurements that drive the * kernel PLL and our NTP refclock. On some old boards we route a 5mhz * signal to TC1's A2 input (pin PA21), but we have never used that * clock (it rolls over too fast for hz=100), and now newer boards are * using pin PA21 as a CTS0 for USART1, so we no longer assign it to * the timer block like we used to here. */ at91_pio_use_periph_b(AT91RM92_PIOA_BASE, AT91C_PIO_PA19, 0); /* * Configure pins used to bitbang-upload the firmware to the main FPGA. */ at91_pio_use_gpio(AT91RM92_PIOB_BASE, AT91C_PIO_PB16 | AT91C_PIO_PB17 | AT91C_PIO_PB18 | AT91C_PIO_PB19); return (at91_ramsize()); }