Ejemplo n.º 1
0
/*
 * TSC-specific code to read the ID eeprom on the mainboard and extract the
 * unit's EUI-64 which gets translated into a MAC-48 for ethernet.
 */
static void
eeprom_init(void)
{
	const uint32_t twiHz    = 400000;
	const uint32_t twiCkDiv = 1 << 16;
	const uint32_t twiChDiv = ((at91_master_clock / twiHz) - 2) << 8;
	const uint32_t twiClDiv = ((at91_master_clock / twiHz) - 2);

	/*
	 * Set the TWCK and TWD lines for Periph A, no pullup, open-drain.
	 */
	at91_pio_use_periph_a(AT91RM92_PIOA_BASE,
	    AT91C_PIO_PA25 | AT91C_PIO_PA26, 0);
	at91_pio_gpio_high_z(AT91RM92_PIOA_BASE, AT91C_PIO_PA25, 1);

	/*
	 * Enable TWI power (irq numbers are also device IDs for power)
	 */
	WR4HW(AT91RM92_PMC_BASE, PMC_PCER, 1u << AT91RM92_IRQ_TWI);

	/*
	 * Disable TWI interrupts, reset device, enable Master mode,
	 * disable Slave mode, set the clock.
	 */
	WR4HW(AT91RM92_TWI_BASE, TWI_IDR, 0xffffffff);
	WR4HW(AT91RM92_TWI_BASE, TWI_CR, TWI_CR_SWRST);
	WR4HW(AT91RM92_TWI_BASE, TWI_CR, TWI_CR_MSEN | TWI_CR_SVDIS);
	WR4HW(AT91RM92_TWI_BASE, TWI_CWGR, twiCkDiv | twiChDiv | twiClDiv);
}
Ejemplo n.º 2
0
void
at91_ebi_disable(int bank)
{

	WR4HW(AT91SAM9260_MATRIX_BASE, AT91SAM9260_EBICSA, ~(1 << bank) &
	      RD4HW(AT91SAM9260_MATRIX_BASE, AT91SAM9260_EBICSA));
}
Ejemplo n.º 3
0
void
at91_ebi_enable(int bank)
{

	WR4HW(AT91SAM9260_MATRIX_BASE, AT91SAM9260_EBICSA, (1 << bank) |
	      RD4HW(AT91SAM9260_MATRIX_BASE, AT91SAM9260_EBICSA));
}
Ejemplo n.º 4
0
/*
 * 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));
	}
}
Ejemplo n.º 5
0
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;
}
Ejemplo n.º 6
0
void
at91_smc_setup(int id, int cs, const struct at91_smc_init *smc)
{
	// Need a generic way to get this address for all SoCs... Assume 9260 for now...
	uint32_t base = AT91SAM9260_SMC_BASE + SMC_CS_OFF(cs);

	WR4HW(base, SMC_SETUP, SMC_SETUP_NCS_RD_SETUP(smc->ncs_rd_setup) |
	      SMC_SETUP_NRD_SETUP(smc->nrd_setup) |
	      SMC_SETUP_NCS_WR_SETUP(smc->ncs_wr_setup) |
	      SMC_SETUP_NWE_SETUP(smc->nwe_setup));
	WR4HW(base, SMC_PULSE, SMC_PULSE_NCS_RD_PULSE(smc->ncs_rd_pulse) |
	      SMC_PULSE_NRD_PULSE(smc->nrd_pulse) |
	      SMC_PULSE_NCS_WR_PULSE(smc->ncs_wr_pulse) |
	      SMC_PULSE_NWE_PULSE(smc->nwe_pulse));
	WR4HW(base, SMC_CYCLE, SMC_CYCLE_NRD_CYCLE(smc->nrd_cycle) |
	      SMC_CYCLE_NWE_CYCLE(smc->nwe_cycle));
	WR4HW(base, SMC_MODE, smc->mode | SMC_MODE_TDF_CYCLES(smc->tdf_cycles));
}
Ejemplo n.º 7
0
/*
 * 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;
}
Ejemplo n.º 8
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());
}
Ejemplo n.º 9
0
/*
 * Assign SPI chip select pins based on which chip selects are found in hints.
 */
static void
assign_spi_pins(void)
{
	struct {
		uint32_t     num;
		const char * name;
	} chipsel_pins[] = {
		{ AT91C_PIO_PA3, "PA3", },
		{ AT91C_PIO_PA4, "PA4", },
		{ AT91C_PIO_PA5, "PA5", },
		{ AT91C_PIO_PA6, "PA6", },
	};
	int anchor = 0;
	uint32_t chipsel_inuse = 0;

	/*
	 * Search through all device hints looking for any that have
	 * ".at=spibus0".  For each one found, ensure that there is also a
	 * chip select hint ".cs=<num>" and that <num> is 0-3, and assign the
	 * corresponding pin to the SPI peripheral.  Whine if we find a SPI
	 * device with a missing or invalid chipsel hint.
	 */
	for (;;) {
		const char * rName = "";
		int unit = 0;
		int cs = 0;
		int ret;

		ret = resource_find_match(&anchor, &rName, &unit, "at", "spibus0");
		if (ret != 0)
			break;

		ret = resource_int_value(rName, unit, "cs", &cs);
		if (ret != 0) {
			printf( "Error: hint for SPI device %s%d "
				"without a chip select hint; "
				"device will not function.\n",
				rName, unit);
			continue;
		}
		if (cs < 0 || cs > 3) {
			printf( "Error: hint for SPI device %s%d "
				"contains an invalid chip select "
				"value: %d\n",
				rName, unit, cs);
			continue;
		}
		if (chipsel_inuse & (1 << cs)) {
			printf( "Error: hint for SPI device %s%d "
				"specifies chip select %d, which "
				"is already used by another device\n",
				rName, unit, cs);
			continue;
		}
		chipsel_inuse |= 1 << cs;
		at91_pio_use_periph_a(AT91RM92_PIOA_BASE, 
			chipsel_pins[cs].num, 1);
		printf( "Configured pin %s as SPI chip "
			"select %d for %s%d\n",
			chipsel_pins[cs].name, cs, rName, unit);
	}

	/*
	 * If there were hints for any SPI devices, assign the basic SPI IO pins
	 * and enable SPI power (irq numbers are also device IDs for power).
	 */
	if (chipsel_inuse != 0) {
		at91_pio_use_periph_a(AT91RM92_PIOA_BASE, 
			AT91C_PIO_PA1 | AT91C_PIO_PA0 | AT91C_PIO_PA2, 0);
		WR4HW(AT91RM92_PMC_BASE, PMC_PCER, 1u << AT91RM92_IRQ_SPI);
	}
}
Ejemplo n.º 10
0
static int
set_mac_from_idprom(void)
{
#define SIGNATURE_SIZE          4
#define EETYPE_SIZE             2
#define BSLENGTH_SIZE           2
#define RAW_SIZE                52
#define EUI64_SIZE              8
#define BS_SIGNATURE            0x21706d69
#define BSO_SIGNATURE           0x216f7362
#define DEVOFFSET_BSO_SIGNATURE 0x20
#define OFFSET_BS_SIGNATURE     0
#define SIZE_BS_SIGNATURE       SIGNATURE_SIZE
#define OFFSET_EETYPE           (OFFSET_BS_SIGNATURE + SIZE_BS_SIGNATURE)
#define SIZE_EETYPE             EETYPE_SIZE
#define OFFSET_BOOTSECTSIZE     (OFFSET_EETYPE + SIZE_EETYPE)
#define SIZE_BOOTSECTSIZE       BSLENGTH_SIZE
#define OFFSET_RAW              (OFFSET_BOOTSECTSIZE + SIZE_BOOTSECTSIZE)
#define OFFSET_EUI64            (OFFSET_RAW + RAW_SIZE)
#define EE_DEV_ADDR             0xA0    /* eeprom is AT24C256 at address 0xA0 */

	int status;
	uint32_t dev_offset = 0;
	uint32_t sig;
	uint8_t eui64[EUI64_SIZE];
	uint8_t eaddr[ETHER_ADDR_LEN];

	eeprom_init();

	/* Check for the boot section signature at offset 0. */
	status = eeprom_read(EE_DEV_ADDR, OFFSET_BS_SIGNATURE, &sig, sizeof(sig));
	if (status == -1)
		return -1;

	if (sig != BS_SIGNATURE) {
		/* Check for the boot section offset signature. */
		status = eeprom_read(EE_DEV_ADDR, 
		    DEVOFFSET_BSO_SIGNATURE, &sig, sizeof(sig));
		if ((status == -1) || (sig != BSO_SIGNATURE))
				return -1;

		/* Read the device offset of the boot section structure. */
		status = eeprom_read(EE_DEV_ADDR, 
		    DEVOFFSET_BSO_SIGNATURE + sizeof(sig), 
		    &dev_offset, sizeof(dev_offset));
		if (status == -1)
				return -1;;

		/* Check for the boot section signature. */
		status = eeprom_read(EE_DEV_ADDR, 
		    dev_offset + OFFSET_BS_SIGNATURE, &sig, sizeof(sig));
		if ((status == -1) || (sig != BS_SIGNATURE))
				return -1;;
	}
	dev_offset += OFFSET_EUI64;

	/* Read the EUI64 from the device.  */
	if (eeprom_read(EE_DEV_ADDR, dev_offset, eui64, sizeof(eui64)) == -1)
		return -1;;

	/* Transcribe the EUI-64 to a MAC-48.
	 *
	 * Given an EUI-64 of aa:bb:cc:dd:ee:ff:gg:hh
	 *
	 *   if (ff is zero and ee is non-zero)
	 *      mac is aa:bb:cc:ee:gg:hh
	 *   else
	 *      mac is aa:bb:cc:ff:gg:hh
	 *
	 * This logic fixes a glitch in our mfg process in which the ff byte was
	 * always zero and the ee byte contained a non-zero value.  This
	 * resulted in duplicate MAC addresses because we discarded the ee byte.
	 * Now they've fixed the process so that the ff byte is non-zero and
	 * unique addresses are formed from the ff:gg:hh bytes.  If the ff byte
	 * is zero, then we have a unit manufactured during the glitch era, and
	 * we fix the problem by grabbing the ee byte rather than the ff byte.
	 */
	eaddr[0] = eui64[0];
	eaddr[1] = eui64[1];
	eaddr[2] = eui64[2];
	eaddr[3] = eui64[5];
	eaddr[4] = eui64[6];
	eaddr[5] = eui64[7];

	if (eui64[5] == 0 && eui64[4] != 0) {
		eaddr[3] = eui64[4];
	}

	/*
	 * Set the address in the hardware regs where the ate driver
	 * looks for it.
	 */
	WR4HW(AT91RM92_EMAC_BASE, ETH_SA1L, 
	    (eaddr[3] << 24) | (eaddr[2] << 16) | (eaddr[1] << 8) | eaddr[0]);
	WR4HW(AT91RM92_EMAC_BASE, ETH_SA1H, 
	    (eaddr[5] << 8) | (eaddr[4]));

	printf(
	    "ID: EUI-64 %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"
	    "    MAC-48 %02x:%02x:%02x:%02x:%02x:%02x\n"
	    "    read from i2c device 0x%02X offset 0x%x\n",
	    eui64[0], eui64[1], eui64[2], eui64[3], 
	    eui64[4], eui64[5], eui64[6], eui64[7], 
	    eaddr[0], eaddr[1], eaddr[2], 
	    eaddr[3], eaddr[4], eaddr[5], 
	    EE_DEV_ADDR, dev_offset);

	return (0);
}