| /* |
| * 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 */ |