| /* | 
 |  * Board initialization for EP93xx | 
 |  * | 
 |  * Copyright (C) 2013 | 
 |  * Sergey Kostanbaev <sergey.kostanbaev <at> fairwaves.ru> | 
 |  * | 
 |  * Copyright (C) 2009 | 
 |  * Matthias Kaehlcke <matthias <at> kaehlcke.net> | 
 |  * | 
 |  * (C) Copyright 2002 2003 | 
 |  * Network Audio Technologies, Inc. <www.netaudiotech.com> | 
 |  * Adam Bezanson <bezanson <at> netaudiotech.com> | 
 |  * | 
 |  * SPDX-License-Identifier:	GPL-2.0+ | 
 |  */ | 
 |  | 
 | #include <config.h> | 
 | #include <common.h> | 
 | #include <netdev.h> | 
 | #include <asm/io.h> | 
 | #include <asm/arch/ep93xx.h> | 
 |  | 
 | DECLARE_GLOBAL_DATA_PTR; | 
 |  | 
 | /* | 
 |  * usb_div: 4, nbyp2: 1, pll2_en: 1 | 
 |  * pll2_x1: 368640000.000000, pll2_x2ip: 15360000.000000, | 
 |  * pll2_x2: 384000000.000000, pll2_out: 192000000.000000 | 
 |  */ | 
 | #define CLKSET2_VAL	(23 << SYSCON_CLKSET_PLL_X2IPD_SHIFT |	\ | 
 | 			24 << SYSCON_CLKSET_PLL_X2FBD2_SHIFT |	\ | 
 | 			24 << SYSCON_CLKSET_PLL_X1FBD1_SHIFT |	\ | 
 | 			1 << SYSCON_CLKSET_PLL_PS_SHIFT |	\ | 
 | 			SYSCON_CLKSET2_PLL2_EN |		\ | 
 | 			SYSCON_CLKSET2_NBYP2 |			\ | 
 | 			3 << SYSCON_CLKSET2_USB_DIV_SHIFT) | 
 |  | 
 | #define SMC_BCR6_VALUE	(2 << SMC_BCR_IDCY_SHIFT | 5 << SMC_BCR_WST1_SHIFT | \ | 
 | 			SMC_BCR_BLE | 2 << SMC_BCR_WST2_SHIFT | \ | 
 | 			1 << SMC_BCR_MW_SHIFT) | 
 |  | 
 | /* delay execution before timers are initialized */ | 
 | static inline void early_udelay(uint32_t usecs) | 
 | { | 
 | 	/* loop takes 4 cycles at 5.0ns (fastest case, running at 200MHz) */ | 
 | 	register uint32_t loops = (usecs * 1000) / 20; | 
 |  | 
 | 	__asm__ volatile ("1:\n" | 
 | 			"subs %0, %1, #1\n" | 
 | 			"bne 1b" : "=r" (loops) : "0" (loops)); | 
 | } | 
 |  | 
 | #ifndef CONFIG_EP93XX_NO_FLASH_CFG | 
 | static void flash_cfg(void) | 
 | { | 
 | 	struct smc_regs *smc = (struct smc_regs *)SMC_BASE; | 
 |  | 
 | 	writel(SMC_BCR6_VALUE, &smc->bcr6); | 
 | } | 
 | #else | 
 | #define flash_cfg() | 
 | #endif | 
 |  | 
 | int board_init(void) | 
 | { | 
 | 	/* | 
 | 	 * Setup PLL2, PPL1 has been set during lowlevel init | 
 | 	 */ | 
 | 	struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE; | 
 | 	writel(CLKSET2_VAL, &syscon->clkset2); | 
 |  | 
 | 	/* | 
 | 	 * the user's guide recommends to wait at least 1 ms for PLL2 to | 
 | 	 * stabilize | 
 | 	 */ | 
 | 	early_udelay(1000); | 
 |  | 
 | 	/* Go to Async mode */ | 
 | 	__asm__ volatile ("mrc p15, 0, r0, c1, c0, 0"); | 
 | 	__asm__ volatile ("orr r0, r0, #0xc0000000"); | 
 | 	__asm__ volatile ("mcr p15, 0, r0, c1, c0, 0"); | 
 |  | 
 | 	icache_enable(); | 
 |  | 
 | #ifdef USE_920T_MMU | 
 | 	dcache_enable(); | 
 | #endif | 
 |  | 
 | 	/* Machine number, as defined in linux/arch/arm/tools/mach-types */ | 
 | 	gd->bd->bi_arch_number = CONFIG_MACH_TYPE; | 
 |  | 
 | 	/* adress of boot parameters */ | 
 | 	gd->bd->bi_boot_params = LINUX_BOOT_PARAM_ADDR; | 
 |  | 
 | 	/* We have a console */ | 
 | 	gd->have_console = 1; | 
 |  | 
 | 	enable_interrupts(); | 
 |  | 
 | 	flash_cfg(); | 
 |  | 
 | 	green_led_on(); | 
 | 	red_led_off(); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | int board_early_init_f(void) | 
 | { | 
 | 	/* | 
 | 	 * set UARTBAUD bit to drive UARTs with 14.7456MHz instead of | 
 | 	 * 14.7456/2 MHz | 
 | 	 */ | 
 | 	struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE; | 
 | 	writel(SYSCON_PWRCNT_UART_BAUD, &syscon->pwrcnt); | 
 | 	return 0; | 
 | } | 
 |  | 
 | int board_eth_init(bd_t *bd) | 
 | { | 
 | 	return ep93xx_eth_initialize(0, MAC_BASE); | 
 | } | 
 |  | 
 | static void dram_fill_bank_addr(unsigned dram_addr_mask, unsigned dram_bank_cnt, | 
 | 				unsigned dram_bank_base[CONFIG_NR_DRAM_BANKS]) | 
 | { | 
 | 	if (dram_bank_cnt == 1) { | 
 | 		dram_bank_base[0] = PHYS_SDRAM_1; | 
 | 	} else { | 
 | 		/* Table lookup for holes in address space. Maximum memory | 
 | 		 * for the single SDCS may be up to 256Mb. We start scanning | 
 | 		 * banks from 1Mb, so it could be up to 128 banks theoretically. | 
 | 		 * We need at maximum 7 bits for the loockup, 8 slots is | 
 | 		 * enough for the worst case. | 
 | 		 */ | 
 | 		unsigned tbl[8]; | 
 | 		unsigned i = dram_bank_cnt / 2; | 
 | 		unsigned j = 0x00100000; /* 1 Mb */ | 
 | 		unsigned *ptbl = tbl; | 
 | 		do { | 
 | 			while (!(dram_addr_mask & j)) { | 
 | 				j <<= 1; | 
 | 			} | 
 | 			*ptbl++ = j; | 
 | 			j <<= 1; | 
 | 			i >>= 1; | 
 | 		} while (i != 0); | 
 |  | 
 | 		for (i = dram_bank_cnt, j = 0; | 
 | 		     (i != 0) && (j < CONFIG_NR_DRAM_BANKS); --i, ++j) { | 
 | 			unsigned addr = PHYS_SDRAM_1; | 
 | 			unsigned k; | 
 | 			unsigned bit; | 
 |  | 
 | 			for (k = 0, bit = 1; k < 8; k++, bit <<= 1) { | 
 | 				if (bit & j) | 
 | 					addr |= tbl[k]; | 
 | 			} | 
 |  | 
 | 			dram_bank_base[j] = addr; | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | /* called in board_init_f (before relocation) */ | 
 | static unsigned dram_init_banksize_int(int print) | 
 | { | 
 | 	/* | 
 | 	 * Collect information of banks that has been filled during lowlevel | 
 | 	 * initialization | 
 | 	 */ | 
 | 	unsigned i; | 
 | 	unsigned dram_bank_base[CONFIG_NR_DRAM_BANKS]; | 
 | 	unsigned dram_total = 0; | 
 | 	unsigned dram_bank_size = *(unsigned *) | 
 | 				  (PHYS_SDRAM_1 | UBOOT_MEMORYCNF_BANK_SIZE); | 
 | 	unsigned dram_addr_mask = *(unsigned *) | 
 | 				  (PHYS_SDRAM_1 | UBOOT_MEMORYCNF_BANK_MASK); | 
 | 	unsigned dram_bank_cnt = *(unsigned *) | 
 | 				 (PHYS_SDRAM_1 | UBOOT_MEMORYCNF_BANK_COUNT); | 
 |  | 
 | 	dram_fill_bank_addr(dram_addr_mask, dram_bank_cnt, dram_bank_base); | 
 |  | 
 | 	for (i = 0; i < dram_bank_cnt; i++) { | 
 | 		gd->bd->bi_dram[i].start = dram_bank_base[i]; | 
 | 		gd->bd->bi_dram[i].size = dram_bank_size; | 
 | 		dram_total += dram_bank_size; | 
 | 	} | 
 | 	for (; i < CONFIG_NR_DRAM_BANKS; i++) { | 
 | 		gd->bd->bi_dram[i].start = 0; | 
 | 		gd->bd->bi_dram[i].size = 0; | 
 | 	} | 
 |  | 
 | 	if (print) { | 
 | 		printf("DRAM mask: %08x\n", dram_addr_mask); | 
 | 		printf("DRAM total %u banks:\n", dram_bank_cnt); | 
 | 		printf("bank          base-address          size\n"); | 
 |  | 
 | 		if (dram_bank_cnt > CONFIG_NR_DRAM_BANKS) { | 
 | 			printf("WARNING! UBoot was configured for %u banks,\n" | 
 | 				"but %u has been found. " | 
 | 				"Supressing extra memory banks\n", | 
 | 				 CONFIG_NR_DRAM_BANKS, dram_bank_cnt); | 
 | 			dram_bank_cnt = CONFIG_NR_DRAM_BANKS; | 
 | 		} | 
 |  | 
 | 		for (i = 0; i < dram_bank_cnt; i++) { | 
 | 			printf("  %u             %08x            %08x\n", | 
 | 			       i, dram_bank_base[i], dram_bank_size); | 
 | 		} | 
 | 		printf("  ------------------------------------------\n" | 
 | 			"Total                              %9d\n\n", | 
 | 			dram_total); | 
 | 	} | 
 |  | 
 | 	return dram_total; | 
 | } | 
 |  | 
 | void dram_init_banksize(void) | 
 | { | 
 | 	dram_init_banksize_int(0); | 
 | } | 
 |  | 
 | /* called in board_init_f (before relocation) */ | 
 | int dram_init(void) | 
 | { | 
 | 	struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE; | 
 | 	unsigned sec_id = readl(SECURITY_EXTENSIONID); | 
 | 	unsigned chip_id = readl(&syscon->chipid); | 
 |  | 
 | 	printf("CPU: Cirrus Logic "); | 
 | 	switch (sec_id & 0x000001FE) { | 
 | 	case 0x00000008: | 
 | 		printf("EP9301"); | 
 | 		break; | 
 | 	case 0x00000004: | 
 | 		printf("EP9307"); | 
 | 		break; | 
 | 	case 0x00000002: | 
 | 		printf("EP931x"); | 
 | 		break; | 
 | 	case 0x00000000: | 
 | 		printf("EP9315"); | 
 | 		break; | 
 | 	default: | 
 | 		printf("<unknown>"); | 
 | 		break; | 
 | 	} | 
 |  | 
 | 	printf(" - Rev. "); | 
 | 	switch (chip_id & 0xF0000000) { | 
 | 	case 0x00000000: | 
 | 		printf("A"); | 
 | 		break; | 
 | 	case 0x10000000: | 
 | 		printf("B"); | 
 | 		break; | 
 | 	case 0x20000000: | 
 | 		printf("C"); | 
 | 		break; | 
 | 	case 0x30000000: | 
 | 		printf("D0"); | 
 | 		break; | 
 | 	case 0x40000000: | 
 | 		printf("D1"); | 
 | 		break; | 
 | 	case 0x50000000: | 
 | 		printf("E0"); | 
 | 		break; | 
 | 	case 0x60000000: | 
 | 		printf("E1"); | 
 | 		break; | 
 | 	case 0x70000000: | 
 | 		printf("E2"); | 
 | 		break; | 
 | 	default: | 
 | 		printf("?"); | 
 | 		break; | 
 | 	} | 
 | 	printf(" (SecExtID=%.8x/ChipID=%.8x)\n", sec_id, chip_id); | 
 |  | 
 | 	gd->ram_size = dram_init_banksize_int(1); | 
 | 	return 0; | 
 | } | 
 |  | 
 |  | 
 | #ifdef CONFIG_EP93XX_SPI | 
 | #include <spi.h> | 
 |  | 
 | /* | 
 |  * EGIO0-EGIPO7 -> port A | 
 |  * EGIO8-EGIP15 -> port B | 
 |  */ | 
 |  | 
 | static void ep93xx_set_epgio(unsigned num) | 
 | { | 
 | 	struct gpio_regs *regs = (struct gpio_regs *)GPIO_BASE; | 
 | 	if (num < 8) | 
 | 		writel(readl(®s->padr) | (1<<num), ®s->padr); | 
 | 	else | 
 | 		writel(readl(®s->pbdr) | (1<<(num-8)), ®s->pbdr); | 
 | } | 
 |  | 
 | static void ep93xx_clear_epgio(unsigned num) | 
 | { | 
 | 	struct gpio_regs *regs = (struct gpio_regs *)GPIO_BASE; | 
 | 	if (num < 8) | 
 | 		writel(readl(®s->padr) & (~(1<<num)), ®s->padr); | 
 | 	else | 
 | 		writel(readl(®s->pbdr) & (~(1<<(num-8))), ®s->pbdr); | 
 | } | 
 |  | 
 | static void ep93xx_dir_epgio_out(unsigned num) | 
 | { | 
 | 	struct gpio_regs *regs = (struct gpio_regs *)GPIO_BASE; | 
 | 	if (num < 8) | 
 | 		writel(readl(®s->paddr) | (1<<num), ®s->paddr); | 
 | 	else | 
 | 		writel(readl(®s->pbddr) | (1<<(num-8)), ®s->pbddr); | 
 | } | 
 |  | 
 | int spi_cs_is_valid(unsigned int bus, unsigned int cs) | 
 | { | 
 | 	if (bus == 0 && cs < 16) | 
 | 		return 1; | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | void spi_cs_activate(struct spi_slave *slave) | 
 | { | 
 | 	ep93xx_clear_epgio(slave->cs); | 
 | } | 
 |  | 
 | void spi_cs_deactivate(struct spi_slave *slave) | 
 | { | 
 | 	ep93xx_set_epgio(slave->cs); | 
 | } | 
 |  | 
 | #ifdef CONFIG_MMC_SPI | 
 | #include <mmc.h> | 
 |  | 
 | #ifndef CONFIG_MMC_SPI_CS_EPGIO | 
 | # define CONFIG_MMC_SPI_CS_EPGIO	4 | 
 | #endif | 
 |  | 
 | #ifndef CONFIG_MMC_SPI_SPEED | 
 | # define CONFIG_MMC_SPI_SPEED		25000000 | 
 | #endif | 
 |  | 
 | #ifndef CONFIG_MMC_SPI_MODE | 
 | # define CONFIG_MMC_SPI_MODE		SPI_MODE_0 | 
 | #endif | 
 |  | 
 | int board_mmc_init(bd_t *bis) | 
 | { | 
 | 	struct gpio_regs *regs = (struct gpio_regs *)GPIO_BASE; | 
 |  | 
 | 	ep93xx_set_epgio(CONFIG_MMC_SPI_CS_EPGIO); | 
 | 	ep93xx_dir_epgio_out(CONFIG_MMC_SPI_CS_EPGIO); | 
 |  | 
 | #ifdef CONFIG_MMC_SPI_POWER_EGPIO | 
 | 	ep93xx_dir_epgio_out(CONFIG_MMC_SPI_POWER_EGPIO); | 
 | 	ep93xx_set_epgio(CONFIG_MMC_SPI_POWER_EGPIO); | 
 | #elif defined(CONFIG_MMC_SPI_NPOWER_EGPIO) | 
 | 	ep93xx_dir_epgio_out(CONFIG_MMC_SPI_NPOWER_EGPIO); | 
 | 	ep93xx_clear_epgio(CONFIG_MMC_SPI_NPOWER_EGPIO); | 
 | #endif | 
 | 	struct mmc *mmc = mmc_spi_init(0, CONFIG_MMC_SPI_CS_EPGIO, | 
 | 				CONFIG_MMC_SPI_SPEED, CONFIG_MMC_SPI_MODE); | 
 |  | 
 | 	if (!mmc) { | 
 | 		printf("Failed to create MMC Device\n"); | 
 | 		return 1; | 
 | 	} | 
 | 	mmc_init(mmc); | 
 | 	return 0; | 
 | } | 
 |  | 
 |  | 
 | #endif /* CONFIG_MMC_SPI */ | 
 | #endif /* CONFIG_EP93XX_SPI */ |