diff options
Diffstat (limited to 'qemu/roms/u-boot/arch/arm/cpu/arm926ejs')
121 files changed, 15364 insertions, 0 deletions
diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/Makefile b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/Makefile new file mode 100644 index 000000000..125299537 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/Makefile @@ -0,0 +1,15 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +extra-y = start.o +obj-y = cpu.o cache.o + +ifdef CONFIG_SPL_BUILD +ifdef CONFIG_SPL_NO_CPU_SUPPORT_CODE +extra-y := +endif +endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/armada100/Makefile b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/armada100/Makefile new file mode 100644 index 000000000..fca98ef42 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/armada100/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2010 +# Marvell Semiconductor <www.marvell.com> +# Written-by: Prafulla Wadaskar <prafulla@marvell.com> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y = cpu.o timer.o dram.o diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/armada100/cpu.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/armada100/cpu.c new file mode 100644 index 000000000..8b02d0be0 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/armada100/cpu.c @@ -0,0 +1,92 @@ +/* + * (C) Copyright 2010 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * Contributor: Mahavir Jain <mjain@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/armada100.h> + +#define UARTCLK14745KHZ (APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(1)) +#define SET_MRVL_ID (1<<8) +#define L2C_RAM_SEL (1<<4) + +int arch_cpu_init(void) +{ + u32 val; + struct armd1cpu_registers *cpuregs = + (struct armd1cpu_registers *) ARMD1_CPU_BASE; + + struct armd1apb1_registers *apb1clkres = + (struct armd1apb1_registers *) ARMD1_APBC1_BASE; + + struct armd1mpmu_registers *mpmu = + (struct armd1mpmu_registers *) ARMD1_MPMU_BASE; + + /* set SEL_MRVL_ID bit in ARMADA100_CPU_CONF register */ + val = readl(&cpuregs->cpu_conf); + val = val | SET_MRVL_ID; + writel(val, &cpuregs->cpu_conf); + + /* Enable Clocks for all hardware units */ + writel(0xFFFFFFFF, &mpmu->acgr); + + /* Turn on AIB and AIB-APB Functional clock */ + writel(APBC_APBCLK | APBC_FNCLK, &apb1clkres->aib); + + /* ensure L2 cache is not mapped as SRAM */ + val = readl(&cpuregs->cpu_conf); + val = val & ~(L2C_RAM_SEL); + writel(val, &cpuregs->cpu_conf); + + /* Enable GPIO clock */ + writel(APBC_APBCLK, &apb1clkres->gpio); + +#ifdef CONFIG_I2C_MV + /* Enable general I2C clock */ + writel(APBC_RST | APBC_FNCLK | APBC_APBCLK, &apb1clkres->twsi0); + writel(APBC_FNCLK | APBC_APBCLK, &apb1clkres->twsi0); + + /* Enable power I2C clock */ + writel(APBC_RST | APBC_FNCLK | APBC_APBCLK, &apb1clkres->twsi1); + writel(APBC_FNCLK | APBC_APBCLK, &apb1clkres->twsi1); +#endif + + /* + * Enable Functional and APB clock at 14.7456MHz + * for configured UART console + */ +#if (CONFIG_SYS_NS16550_COM1 == ARMD1_UART3_BASE) + writel(UARTCLK14745KHZ, &apb1clkres->uart3); +#elif (CONFIG_SYS_NS16550_COM1 == ARMD1_UART2_BASE) + writel(UARTCLK14745KHZ, &apb1clkres->uart2); +#else + writel(UARTCLK14745KHZ, &apb1clkres->uart1); +#endif + icache_enable(); + + return 0; +} + +#if defined(CONFIG_DISPLAY_CPUINFO) +int print_cpuinfo(void) +{ + u32 id; + struct armd1cpu_registers *cpuregs = + (struct armd1cpu_registers *) ARMD1_CPU_BASE; + + id = readl(&cpuregs->chip_id); + printf("SoC: Armada 88AP%X-%X\n", (id & 0xFFF), (id >> 0x10)); + return 0; +} +#endif + +#ifdef CONFIG_I2C_MV +void i2c_clk_enable(void) +{ +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/armada100/dram.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/armada100/dram.c new file mode 100644 index 000000000..8d7c71ff6 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/armada100/dram.c @@ -0,0 +1,116 @@ +/* + * (C) Copyright 2010 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com>, + * Contributor: Mahavir Jain <mjain@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/armada100.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * ARMADA100 DRAM controller supports upto 8 banks + * for chip select 0 and 1 + */ + +/* + * DDR Memory Control Registers + * Refer Datasheet Appendix A.17 + */ +struct armd1ddr_map_registers { + u32 cs; /* Memory Address Map Register -CS */ + u32 pad[3]; +}; + +struct armd1ddr_registers { + u8 pad[0x100 - 0x000]; + struct armd1ddr_map_registers mmap[2]; +}; + +/* + * armd1_sdram_base - reads SDRAM Base Address Register + */ +u32 armd1_sdram_base(int chip_sel) +{ + struct armd1ddr_registers *ddr_regs = + (struct armd1ddr_registers *)ARMD1_DRAM_BASE; + u32 result = 0; + u32 CS_valid = 0x01 & readl(&ddr_regs->mmap[chip_sel].cs); + + if (!CS_valid) + return 0; + + result = readl(&ddr_regs->mmap[chip_sel].cs) & 0xFF800000; + return result; +} + +/* + * armd1_sdram_size - reads SDRAM size + */ +u32 armd1_sdram_size(int chip_sel) +{ + struct armd1ddr_registers *ddr_regs = + (struct armd1ddr_registers *)ARMD1_DRAM_BASE; + u32 result = 0; + u32 CS_valid = 0x01 & readl(&ddr_regs->mmap[chip_sel].cs); + + if (!CS_valid) + return 0; + + result = readl(&ddr_regs->mmap[chip_sel].cs); + result = (result >> 16) & 0xF; + if (result < 0x7) { + printf("Unknown DRAM Size\n"); + return -1; + } else { + return ((0x8 << (result - 0x7)) * 1024 * 1024); + } +} + +#ifndef CONFIG_SYS_BOARD_DRAM_INIT +int dram_init(void) +{ + int i; + + gd->ram_size = 0; + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + gd->bd->bi_dram[i].start = armd1_sdram_base(i); + gd->bd->bi_dram[i].size = armd1_sdram_size(i); + /* + * It is assumed that all memory banks are consecutive + * and without gaps. + * If the gap is found, ram_size will be reported for + * consecutive memory only + */ + if (gd->bd->bi_dram[i].start != gd->ram_size) + break; + + gd->ram_size += gd->bd->bi_dram[i].size; + + } + + for (; i < CONFIG_NR_DRAM_BANKS; i++) { + /* If above loop terminated prematurely, we need to set + * remaining banks' start address & size as 0. Otherwise other + * u-boot functions and Linux kernel gets wrong values which + * could result in crash */ + gd->bd->bi_dram[i].start = 0; + gd->bd->bi_dram[i].size = 0; + } + return 0; +} + +/* + * If this function is not defined here, + * board.c alters dram bank zero configuration defined above. + */ +void dram_init_banksize(void) +{ + dram_init(); +} +#endif /* CONFIG_SYS_BOARD_DRAM_INIT */ diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/armada100/timer.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/armada100/timer.c new file mode 100644 index 000000000..bbd0505bd --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/armada100/timer.c @@ -0,0 +1,194 @@ +/* + * (C) Copyright 2010 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * Contributor: Mahavir Jain <mjain@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/armada100.h> + +/* + * Timer registers + * Refer Section A.6 in Datasheet + */ +struct armd1tmr_registers { + u32 clk_ctrl; /* Timer clk control reg */ + u32 match[9]; /* Timer match registers */ + u32 count[3]; /* Timer count registers */ + u32 status[3]; + u32 ie[3]; + u32 preload[3]; /* Timer preload value */ + u32 preload_ctrl[3]; + u32 wdt_match_en; + u32 wdt_match_r; + u32 wdt_val; + u32 wdt_sts; + u32 icr[3]; + u32 wdt_icr; + u32 cer; /* Timer count enable reg */ + u32 cmr; + u32 ilr[3]; + u32 wcr; + u32 wfar; + u32 wsar; + u32 cvwr; +}; + +#define TIMER 0 /* Use TIMER 0 */ +/* Each timer has 3 match registers */ +#define MATCH_CMP(x) ((3 * TIMER) + x) +#define TIMER_LOAD_VAL 0xffffffff +#define COUNT_RD_REQ 0x1 + +DECLARE_GLOBAL_DATA_PTR; +/* Using gd->arch.tbu from timestamp and gd->arch.tbl for lastdec */ + +/* For preventing risk of instability in reading counter value, + * first set read request to register cvwr and then read same + * register after it captures counter value. + */ +ulong read_timer(void) +{ + struct armd1tmr_registers *armd1timers = + (struct armd1tmr_registers *) ARMD1_TIMER_BASE; + volatile int loop=100; + + writel(COUNT_RD_REQ, &armd1timers->cvwr); + while (loop--); + return(readl(&armd1timers->cvwr)); +} + +ulong get_timer_masked(void) +{ + ulong now = read_timer(); + + if (now >= gd->arch.tbl) { + /* normal mode */ + gd->arch.tbu += now - gd->arch.tbl; + } else { + /* we have an overflow ... */ + gd->arch.tbu += now + TIMER_LOAD_VAL - gd->arch.tbl; + } + gd->arch.tbl = now; + + return gd->arch.tbu; +} + +ulong get_timer(ulong base) +{ + return ((get_timer_masked() / (CONFIG_SYS_HZ_CLOCK / 1000)) - + base); +} + +void __udelay(unsigned long usec) +{ + ulong delayticks; + ulong endtime; + + delayticks = (usec * (CONFIG_SYS_HZ_CLOCK / 1000000)); + endtime = get_timer_masked() + delayticks; + + while (get_timer_masked() < endtime); +} + +/* + * init the Timer + */ +int timer_init(void) +{ + struct armd1apb1_registers *apb1clkres = + (struct armd1apb1_registers *) ARMD1_APBC1_BASE; + struct armd1tmr_registers *armd1timers = + (struct armd1tmr_registers *) ARMD1_TIMER_BASE; + + /* Enable Timer clock at 3.25 MHZ */ + writel(APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3), &apb1clkres->timers); + + /* load value into timer */ + writel(0x0, &armd1timers->clk_ctrl); + /* Use Timer 0 Match Resiger 0 */ + writel(TIMER_LOAD_VAL, &armd1timers->match[MATCH_CMP(0)]); + /* Preload value is 0 */ + writel(0x0, &armd1timers->preload[TIMER]); + /* Enable match comparator 0 for Timer 0 */ + writel(0x1, &armd1timers->preload_ctrl[TIMER]); + + /* Enable timer 0 */ + writel(0x1, &armd1timers->cer); + /* init the gd->arch.tbu and gd->arch.tbl value */ + gd->arch.tbl = read_timer(); + gd->arch.tbu = 0; + + return 0; +} + +#define MPMU_APRR_WDTR (1<<4) +#define TMR_WFAR 0xbaba /* WDT Register First key */ +#define TMP_WSAR 0xeb10 /* WDT Register Second key */ + +/* + * This function uses internal Watchdog Timer + * based reset mechanism. + * Steps to write watchdog registers (protected access) + * 1. Write key value to TMR_WFAR reg. + * 2. Write key value to TMP_WSAR reg. + * 3. Perform write operation. + */ +void reset_cpu (unsigned long ignored) +{ + struct armd1mpmu_registers *mpmu = + (struct armd1mpmu_registers *) ARMD1_MPMU_BASE; + struct armd1tmr_registers *armd1timers = + (struct armd1tmr_registers *) ARMD1_TIMER_BASE; + u32 val; + + /* negate hardware reset to the WDT after system reset */ + val = readl(&mpmu->aprr); + val = val | MPMU_APRR_WDTR; + writel(val, &mpmu->aprr); + + /* reset/enable WDT clock */ + writel(APBC_APBCLK | APBC_FNCLK | APBC_RST, &mpmu->wdtpcr); + readl(&mpmu->wdtpcr); + writel(APBC_APBCLK | APBC_FNCLK, &mpmu->wdtpcr); + readl(&mpmu->wdtpcr); + + /* clear previous WDT status */ + writel(TMR_WFAR, &armd1timers->wfar); + writel(TMP_WSAR, &armd1timers->wsar); + writel(0, &armd1timers->wdt_sts); + + /* set match counter */ + writel(TMR_WFAR, &armd1timers->wfar); + writel(TMP_WSAR, &armd1timers->wsar); + writel(0xf, &armd1timers->wdt_match_r); + + /* enable WDT reset */ + writel(TMR_WFAR, &armd1timers->wfar); + writel(TMP_WSAR, &armd1timers->wsar); + writel(0x3, &armd1timers->wdt_match_en); + + while(1); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk (void) +{ + return (ulong)CONFIG_SYS_HZ; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/Makefile b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/Makefile new file mode 100644 index 000000000..698a28dc5 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/Makefile @@ -0,0 +1,29 @@ +# +# (C) Copyright 2000-2008 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_AT91CAP9) += at91cap9_devices.o +obj-$(CONFIG_AT91SAM9260) += at91sam9260_devices.o +obj-$(CONFIG_AT91SAM9G20) += at91sam9260_devices.o +obj-$(CONFIG_AT91SAM9XE) += at91sam9260_devices.o +obj-$(CONFIG_AT91SAM9261) += at91sam9261_devices.o +obj-$(CONFIG_AT91SAM9G10) += at91sam9261_devices.o +obj-$(CONFIG_AT91SAM9263) += at91sam9263_devices.o +obj-$(CONFIG_AT91SAM9RL) += at91sam9rl_devices.o +obj-$(CONFIG_AT91SAM9M10G45) += at91sam9m10g45_devices.o +obj-$(CONFIG_AT91SAM9G45) += at91sam9m10g45_devices.o +obj-$(CONFIG_AT91SAM9N12) += at91sam9n12_devices.o +obj-$(CONFIG_AT91SAM9X5) += at91sam9x5_devices.o +obj-$(CONFIG_AT91_EFLASH) += eflash.o +obj-$(CONFIG_AT91_LED) += led.o +obj-y += clock.o +obj-y += cpu.o +obj-y += reset.o +obj-y += timer.o + +ifndef CONFIG_SKIP_LOWLEVEL_INIT +obj-y += lowlevel_init.o +endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91cap9_devices.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91cap9_devices.c new file mode 100644 index 000000000..16eeca737 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91cap9_devices.c @@ -0,0 +1,189 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * (C) Copyright 2009 + * Daniel Gorsulowski <daniel.gorsulowski@esd.eu> + * esd electronic system design gmbh <www.esd.eu> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/gpio.h> +#include <asm/arch/io.h> + +void at91_serial0_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; + + at91_set_a_periph(AT91_PIO_PORTA, 22, 1); /* TXD0 */ + at91_set_a_periph(AT91_PIO_PORTA, 23, 0); /* RXD0 */ + writel(1 << AT91CAP9_ID_US0, &pmc->pcer); +} + +void at91_serial1_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; + + at91_set_a_periph(AT91_PIO_PORTD, 0, 1); /* TXD1 */ + at91_set_a_periph(AT91_PIO_PORTD, 1, 0); /* RXD1 */ + writel(1 << AT91CAP9_ID_US1, &pmc->pcer); +} + +void at91_serial2_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; + + at91_set_a_periph(AT91_PIO_PORTD, 2, 1); /* TXD2 */ + at91_set_a_periph(AT91_PIO_PORTD, 3, 0); /* RXD2 */ + writel(1 << AT91CAP9_ID_US2, &pmc->pcer); +} + +void at91_serial3_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; + + at91_set_a_periph(AT91_PIO_PORTC, 30, 0); /* DRXD */ + at91_set_a_periph(AT91_PIO_PORTC, 31, 1); /* DTXD */ + writel(1 << AT91_ID_SYS, &pmc->pcer); +} + +void at91_serial_hw_init(void) +{ +#ifdef CONFIG_USART0 + at91_serial0_hw_init(); +#endif + +#ifdef CONFIG_USART1 + at91_serial1_hw_init(); +#endif + +#ifdef CONFIG_USART2 + at91_serial2_hw_init(); +#endif + +#ifdef CONFIG_USART3 /* DBGU */ + at91_serial3_hw_init(); +#endif +} + +#ifdef CONFIG_HAS_DATAFLASH +void at91_spi0_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; + + at91_set_b_periph(AT91_PIO_PORTA, 0, 0); /* SPI0_MISO */ + at91_set_b_periph(AT91_PIO_PORTA, 1, 0); /* SPI0_MOSI */ + at91_set_b_periph(AT91_PIO_PORTA, 2, 0); /* SPI0_SPCK */ + + /* Enable clock */ + writel(1 << AT91CAP9_ID_SPI0, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_b_periph(AT91_PIO_PORTA, 5, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_b_periph(AT91_PIO_PORTA, 3, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_b_periph(AT91_PIO_PORTD, 0, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_b_periph(AT91_PIO_PORTD, 1, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTA, 5, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTA, 3, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTD, 0, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTD, 1, 1); + } +} + +void at91_spi1_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; + + at91_set_a_periph(AT91_PIO_PORTB, 12, 0); /* SPI1_MISO */ + at91_set_a_periph(AT91_PIO_PORTB, 13, 0); /* SPI1_MOSI */ + at91_set_a_periph(AT91_PIO_PORTB, 14, 0); /* SPI1_SPCK */ + + /* Enable clock */ + writel(1 << AT91CAP9_ID_SPI1, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTB, 15, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_a_periph(AT91_PIO_PORTB, 16, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_a_periph(AT91_PIO_PORTB, 17, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_a_periph(AT91_PIO_PORTB, 18, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTB, 15, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTB, 16, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTB, 17, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTB, 18, 1); + } + +} +#endif + +#ifdef CONFIG_MACB +void at91_macb_hw_init(void) +{ + at91_set_a_periph(AT91_PIO_PORTB, 21, 0); /* ETXCK_EREFCK */ + at91_set_a_periph(AT91_PIO_PORTB, 22, 0); /* ERXDV */ + at91_set_a_periph(AT91_PIO_PORTB, 25, 0); /* ERX0 */ + at91_set_a_periph(AT91_PIO_PORTB, 26, 0); /* ERX1 */ + at91_set_a_periph(AT91_PIO_PORTB, 27, 0); /* ERXER */ + at91_set_a_periph(AT91_PIO_PORTB, 28, 0); /* ETXEN */ + at91_set_a_periph(AT91_PIO_PORTB, 23, 0); /* ETX0 */ + at91_set_a_periph(AT91_PIO_PORTB, 24, 0); /* ETX1 */ + at91_set_a_periph(AT91_PIO_PORTB, 30, 0); /* EMDIO */ + at91_set_a_periph(AT91_PIO_PORTB, 29, 0); /* EMDC */ + +#ifndef CONFIG_RMII + at91_set_b_periph(AT91_PIO_PORTC, 25, 0); /* ECRS */ + at91_set_b_periph(AT91_PIO_PORTC, 26, 0); /* ECOL */ + at91_set_b_periph(AT91_PIO_PORTC, 22, 0); /* ERX2 */ + at91_set_b_periph(AT91_PIO_PORTC, 23, 0); /* ERX3 */ + at91_set_b_periph(AT91_PIO_PORTC, 27, 0); /* ERXCK */ + at91_set_b_periph(AT91_PIO_PORTC, 20, 0); /* ETX2 */ + at91_set_b_periph(AT91_PIO_PORTC, 21, 0); /* ETX3 */ + at91_set_b_periph(AT91_PIO_PORTC, 24, 0); /* ETXER */ +#endif +} +#endif + +#ifdef CONFIG_AT91_CAN +void at91_can_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; + + at91_set_a_periph(AT91_PIO_PORTA, 12, 0); /* CAN_TX */ + at91_set_a_periph(AT91_PIO_PORTA, 13, 1); /* CAN_RX */ + + /* Enable clock */ + writel(1 << AT91CAP9_ID_CAN, &pmc->pcer); +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c new file mode 100644 index 000000000..cae4abcdf --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c @@ -0,0 +1,209 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/gpio.h> + +/* + * if CONFIG_AT91_GPIO_PULLUP ist set, keep pullups on on all + * peripheral pins. Good to have if hardware is soldered optionally + * or in case of SPI no slave is selected. Avoid lines to float + * needlessly. Use a short local PUP define. + * + * Due to errata "TXD floats when CTS is inactive" pullups are always + * on for TXD pins. + */ +#ifdef CONFIG_AT91_GPIO_PULLUP +# define PUP CONFIG_AT91_GPIO_PULLUP +#else +# define PUP 0 +#endif + +void at91_serial0_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 4, 1); /* TXD0 */ + at91_set_a_periph(AT91_PIO_PORTB, 5, PUP); /* RXD0 */ + writel(1 << ATMEL_ID_USART0, &pmc->pcer); +} + +void at91_serial1_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 6, 1); /* TXD1 */ + at91_set_a_periph(AT91_PIO_PORTB, 7, PUP); /* RXD1 */ + writel(1 << ATMEL_ID_USART1, &pmc->pcer); +} + +void at91_serial2_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 8, 1); /* TXD2 */ + at91_set_a_periph(AT91_PIO_PORTB, 9, PUP); /* RXD2 */ + writel(1 << ATMEL_ID_USART2, &pmc->pcer); +} + +void at91_seriald_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 14, PUP); /* DRXD */ + at91_set_a_periph(AT91_PIO_PORTB, 15, 1); /* DTXD */ + writel(1 << ATMEL_ID_SYS, &pmc->pcer); +} + +#if defined(CONFIG_HAS_DATAFLASH) || defined(CONFIG_ATMEL_SPI) +void at91_spi0_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 0, PUP); /* SPI0_MISO */ + at91_set_a_periph(AT91_PIO_PORTA, 1, PUP); /* SPI0_MOSI */ + at91_set_a_periph(AT91_PIO_PORTA, 2, PUP); /* SPI0_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI0, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTA, 3, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_b_periph(AT91_PIO_PORTC, 11, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_b_periph(AT91_PIO_PORTC, 16, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_b_periph(AT91_PIO_PORTC, 17, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTA, 3, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTC, 11, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTC, 16, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTC, 17, 1); + } +} + +void at91_spi1_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 0, PUP); /* SPI1_MISO */ + at91_set_a_periph(AT91_PIO_PORTB, 1, PUP); /* SPI1_MOSI */ + at91_set_a_periph(AT91_PIO_PORTB, 2, PUP); /* SPI1_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI1, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTB, 3, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_b_periph(AT91_PIO_PORTC, 5, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_b_periph(AT91_PIO_PORTC, 4, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_b_periph(AT91_PIO_PORTC, 3, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTB, 3, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTC, 5, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTC, 4, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTC, 3, 1); + } +} +#endif + +#ifdef CONFIG_MACB +void at91_macb_hw_init(void) +{ + /* Enable EMAC clock */ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + writel(1 << ATMEL_ID_EMAC0, &pmc->pcer); + + at91_set_a_periph(AT91_PIO_PORTA, 19, 0); /* ETXCK_EREFCK */ + at91_set_a_periph(AT91_PIO_PORTA, 17, 0); /* ERXDV */ + at91_set_a_periph(AT91_PIO_PORTA, 14, 0); /* ERX0 */ + at91_set_a_periph(AT91_PIO_PORTA, 15, 0); /* ERX1 */ + at91_set_a_periph(AT91_PIO_PORTA, 18, 0); /* ERXER */ + at91_set_a_periph(AT91_PIO_PORTA, 16, 0); /* ETXEN */ + at91_set_a_periph(AT91_PIO_PORTA, 12, 0); /* ETX0 */ + at91_set_a_periph(AT91_PIO_PORTA, 13, 0); /* ETX1 */ + at91_set_a_periph(AT91_PIO_PORTA, 21, 0); /* EMDIO */ + at91_set_a_periph(AT91_PIO_PORTA, 20, 0); /* EMDC */ + +#ifndef CONFIG_RMII + at91_set_b_periph(AT91_PIO_PORTA, 28, 0); /* ECRS */ + at91_set_b_periph(AT91_PIO_PORTA, 29, 0); /* ECOL */ + at91_set_b_periph(AT91_PIO_PORTA, 25, 0); /* ERX2 */ + at91_set_b_periph(AT91_PIO_PORTA, 26, 0); /* ERX3 */ + at91_set_b_periph(AT91_PIO_PORTA, 27, 0); /* ERXCK */ +#if defined(CONFIG_AT91SAM9260EK) || defined(CONFIG_AFEB9260) + /* + * use PA10, PA11 for ETX2, ETX3. + * PA23 and PA24 are for TWI EEPROM + */ + at91_set_b_periph(AT91_PIO_PORTA, 10, 0); /* ETX2 */ + at91_set_b_periph(AT91_PIO_PORTA, 11, 0); /* ETX3 */ +#else + at91_set_b_periph(AT91_PIO_PORTA, 23, 0); /* ETX2 */ + at91_set_b_periph(AT91_PIO_PORTA, 24, 0); /* ETX3 */ +#if defined(CONFIG_AT91SAM9G20) + /* 9G20 BOOT ROM initializes those pins to multi-drive, undo that */ + at91_set_pio_multi_drive(AT91_PIO_PORTA, 23, 0); + at91_set_pio_multi_drive(AT91_PIO_PORTA, 24, 0); +#endif +#endif + at91_set_b_periph(AT91_PIO_PORTA, 22, 0); /* ETXER */ +#endif +} +#endif + +#if defined(CONFIG_GENERIC_ATMEL_MCI) +void at91_mci_hw_init(void) +{ + /* Enable mci clock */ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + writel(1 << ATMEL_ID_MCI, &pmc->pcer); + + at91_set_a_periph(AT91_PIO_PORTA, 8, 1); /* MCCK */ +#if defined(CONFIG_ATMEL_MCI_PORTB) + at91_set_b_periph(AT91_PIO_PORTA, 1, 1); /* MCCDB */ + at91_set_b_periph(AT91_PIO_PORTA, 0, 1); /* MCDB0 */ + at91_set_b_periph(AT91_PIO_PORTA, 5, 1); /* MCDB1 */ + at91_set_b_periph(AT91_PIO_PORTA, 4, 1); /* MCDB2 */ + at91_set_b_periph(AT91_PIO_PORTA, 3, 1); /* MCDB3 */ +#else + at91_set_a_periph(AT91_PIO_PORTA, 7, 1); /* MCCDA */ + at91_set_a_periph(AT91_PIO_PORTA, 6, 1); /* MCDA0 */ + at91_set_a_periph(AT91_PIO_PORTA, 9, 1); /* MCDA1 */ + at91_set_a_periph(AT91_PIO_PORTA, 10, 1); /* MCDA2 */ + at91_set_a_periph(AT91_PIO_PORTA, 11, 1); /* MCDA3 */ +#endif +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9261_devices.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9261_devices.c new file mode 100644 index 000000000..a445c7507 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9261_devices.c @@ -0,0 +1,140 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/gpio.h> + +/* + * if CONFIG_AT91_GPIO_PULLUP ist set, keep pullups on on all + * peripheral pins. Good to have if hardware is soldered optionally + * or in case of SPI no slave is selected. Avoid lines to float + * needlessly. Use a short local PUP define. + * + * Due to errata "TXD floats when CTS is inactive" pullups are always + * on for TXD pins. + */ +#ifdef CONFIG_AT91_GPIO_PULLUP +# define PUP CONFIG_AT91_GPIO_PULLUP +#else +# define PUP 0 +#endif + +void at91_serial0_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTC, 8, 1); /* TXD0 */ + at91_set_a_periph(AT91_PIO_PORTC, 9, 0); /* RXD0 */ + writel(1 << ATMEL_ID_USART0, &pmc->pcer); +} + +void at91_serial1_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTC, 12, 1); /* TXD1 */ + at91_set_a_periph(AT91_PIO_PORTC, 13, 0); /* RXD1 */ + writel(1 << ATMEL_ID_USART1, &pmc->pcer); +} + +void at91_serial2_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTC, 14, 1); /* TXD2 */ + at91_set_a_periph(AT91_PIO_PORTC, 15, 0); /* RXD2 */ + writel(1 << ATMEL_ID_USART2, &pmc->pcer); +} + +void at91_seriald_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 9, 0); /* DRXD */ + at91_set_a_periph(AT91_PIO_PORTA, 10, 1); /* DTXD */ + writel(1 << ATMEL_ID_SYS, &pmc->pcer); +} + +#if defined(CONFIG_HAS_DATAFLASH) || defined(CONFIG_ATMEL_SPI) +void at91_spi0_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 0, PUP); /* SPI0_MISO */ + at91_set_a_periph(AT91_PIO_PORTA, 1, PUP); /* SPI0_MOSI */ + at91_set_a_periph(AT91_PIO_PORTA, 2, PUP); /* SPI0_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI0, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTA, 3, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_a_periph(AT91_PIO_PORTA, 4, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_a_periph(AT91_PIO_PORTA, 5, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_a_periph(AT91_PIO_PORTA, 6, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTA, 3, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTA, 4, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTA, 5, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTA, 6, 1); + } +} + +void at91_spi1_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 30, PUP); /* SPI1_MISO */ + at91_set_a_periph(AT91_PIO_PORTB, 31, PUP); /* SPI1_MOSI */ + at91_set_a_periph(AT91_PIO_PORTB, 29, PUP); /* SPI1_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI1, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTB, 28, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_b_periph(AT91_PIO_PORTA, 24, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_b_periph(AT91_PIO_PORTA, 25, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_a_periph(AT91_PIO_PORTA, 26, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTB, 28, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTA, 24, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTA, 25, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTA, 26, 1); + } +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9263_devices.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9263_devices.c new file mode 100644 index 000000000..6b51d5f35 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9263_devices.c @@ -0,0 +1,218 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * (C) Copyright 2009-2011 + * Daniel Gorsulowski <daniel.gorsulowski@esd.eu> + * esd electronic system design gmbh <www.esd.eu> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/gpio.h> + +/* + * if CONFIG_AT91_GPIO_PULLUP ist set, keep pullups on on all + * peripheral pins. Good to have if hardware is soldered optionally + * or in case of SPI no slave is selected. Avoid lines to float + * needlessly. Use a short local PUP define. + * + * Due to errata "TXD floats when CTS is inactive" pullups are always + * on for TXD pins. + */ +#ifdef CONFIG_AT91_GPIO_PULLUP +# define PUP CONFIG_AT91_GPIO_PULLUP +#else +# define PUP 0 +#endif + +void at91_serial0_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 26, 1); /* TXD0 */ + at91_set_a_periph(AT91_PIO_PORTA, 27, PUP); /* RXD0 */ + writel(1 << ATMEL_ID_USART0, &pmc->pcer); +} + +void at91_serial1_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTD, 0, 1); /* TXD1 */ + at91_set_a_periph(AT91_PIO_PORTD, 1, PUP); /* RXD1 */ + writel(1 << ATMEL_ID_USART1, &pmc->pcer); +} + +void at91_serial2_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTD, 2, 1); /* TXD2 */ + at91_set_a_periph(AT91_PIO_PORTD, 3, PUP); /* RXD2 */ + writel(1 << ATMEL_ID_USART2, &pmc->pcer); +} + +void at91_seriald_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTC, 30, PUP); /* DRXD */ + at91_set_a_periph(AT91_PIO_PORTC, 31, 1); /* DTXD */ + writel(1 << ATMEL_ID_SYS, &pmc->pcer); +} + +#if defined(CONFIG_HAS_DATAFLASH) || defined(CONFIG_ATMEL_SPI) +void at91_spi0_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_b_periph(AT91_PIO_PORTA, 0, PUP); /* SPI0_MISO */ + at91_set_b_periph(AT91_PIO_PORTA, 1, PUP); /* SPI0_MOSI */ + at91_set_b_periph(AT91_PIO_PORTA, 2, PUP); /* SPI0_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI0, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_b_periph(AT91_PIO_PORTA, 5, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_b_periph(AT91_PIO_PORTA, 3, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_b_periph(AT91_PIO_PORTA, 4, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_b_periph(AT91_PIO_PORTB, 11, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTA, 5, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTA, 3, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTA, 4, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTB, 11, 1); + } +} + +void at91_spi1_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 12, PUP); /* SPI1_MISO */ + at91_set_a_periph(AT91_PIO_PORTB, 13, PUP); /* SPI1_MOSI */ + at91_set_a_periph(AT91_PIO_PORTB, 14, PUP); /* SPI1_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI1, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTB, 15, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_a_periph(AT91_PIO_PORTB, 16, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_a_periph(AT91_PIO_PORTB, 17, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_a_periph(AT91_PIO_PORTB, 18, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTB, 15, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTB, 16, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTB, 17, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTB, 18, 1); + } +} +#endif + +#if defined(CONFIG_GENERIC_ATMEL_MCI) +void at91_mci_hw_init(void) +{ + /* Enable mci clock */ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + writel(1 << ATMEL_ID_MCI1, &pmc->pcer); + + at91_set_a_periph(AT91_PIO_PORTA, 6, PUP); /* MCI1_CK */ + +#if defined(CONFIG_ATMEL_MCI_PORTB) + at91_set_a_periph(AT91_PIO_PORTA, 21, PUP); /* MCI1_CDB */ + at91_set_a_periph(AT91_PIO_PORTA, 22, PUP); /* MCI1_DB0 */ + at91_set_a_periph(AT91_PIO_PORTA, 23, PUP); /* MCI1_DB1 */ + at91_set_a_periph(AT91_PIO_PORTA, 24, PUP); /* MCI1_DB2 */ + at91_set_a_periph(AT91_PIO_PORTA, 25, PUP); /* MCI1_DB3 */ +#else + at91_set_a_periph(AT91_PIO_PORTA, 7, PUP); /* MCI1_CDA */ + at91_set_a_periph(AT91_PIO_PORTA, 8, PUP); /* MCI1_DA0 */ + at91_set_a_periph(AT91_PIO_PORTA, 9, PUP); /* MCI1_DA1 */ + at91_set_a_periph(AT91_PIO_PORTA, 10, PUP); /* MCI1_DA2 */ + at91_set_a_periph(AT91_PIO_PORTA, 11, PUP); /* MCI1_DA3 */ +#endif +} +#endif + +#ifdef CONFIG_MACB +void at91_macb_hw_init(void) +{ + at91_set_a_periph(AT91_PIO_PORTE, 21, 0); /* ETXCK_EREFCK */ + at91_set_b_periph(AT91_PIO_PORTC, 25, 0); /* ERXDV */ + at91_set_a_periph(AT91_PIO_PORTE, 25, 0); /* ERX0 */ + at91_set_a_periph(AT91_PIO_PORTE, 26, 0); /* ERX1 */ + at91_set_a_periph(AT91_PIO_PORTE, 27, 0); /* ERXER */ + at91_set_a_periph(AT91_PIO_PORTE, 28, 0); /* ETXEN */ + at91_set_a_periph(AT91_PIO_PORTE, 23, 0); /* ETX0 */ + at91_set_a_periph(AT91_PIO_PORTE, 24, 0); /* ETX1 */ + at91_set_a_periph(AT91_PIO_PORTE, 30, 0); /* EMDIO */ + at91_set_a_periph(AT91_PIO_PORTE, 29, 0); /* EMDC */ + +#ifndef CONFIG_RMII + at91_set_a_periph(AT91_PIO_PORTE, 22, 0); /* ECRS */ + at91_set_b_periph(AT91_PIO_PORTC, 26, 0); /* ECOL */ + at91_set_b_periph(AT91_PIO_PORTC, 22, 0); /* ERX2 */ + at91_set_b_periph(AT91_PIO_PORTC, 23, 0); /* ERX3 */ + at91_set_b_periph(AT91_PIO_PORTC, 27, 0); /* ERXCK */ + at91_set_b_periph(AT91_PIO_PORTC, 20, 0); /* ETX2 */ + at91_set_b_periph(AT91_PIO_PORTC, 21, 0); /* ETX3 */ + at91_set_b_periph(AT91_PIO_PORTC, 24, 0); /* ETXER */ +#endif +} +#endif + +#ifdef CONFIG_USB_OHCI_NEW +void at91_uhp_hw_init(void) +{ + /* Enable VBus on UHP ports */ + at91_set_pio_output(AT91_PIO_PORTA, 21, 0); + at91_set_pio_output(AT91_PIO_PORTA, 24, 0); +} +#endif + +#ifdef CONFIG_AT91_CAN +void at91_can_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 13, 0); /* CAN_TX */ + at91_set_a_periph(AT91_PIO_PORTA, 14, 1); /* CAN_RX */ + + /* Enable clock */ + writel(1 << ATMEL_ID_CAN, &pmc->pcer); +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9m10g45_devices.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9m10g45_devices.c new file mode 100644 index 000000000..7d7725c4b --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9m10g45_devices.c @@ -0,0 +1,167 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/gpio.h> +#include <asm/io.h> + +/* + * if CONFIG_AT91_GPIO_PULLUP ist set, keep pullups on on all + * peripheral pins. Good to have if hardware is soldered optionally + * or in case of SPI no slave is selected. Avoid lines to float + * needlessly. Use a short local PUP define. + * + * Due to errata "TXD floats when CTS is inactive" pullups are always + * on for TXD pins. + */ +#ifdef CONFIG_AT91_GPIO_PULLUP +# define PUP CONFIG_AT91_GPIO_PULLUP +#else +# define PUP 0 +#endif + +void at91_serial0_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 19, 1); /* TXD0 */ + at91_set_a_periph(AT91_PIO_PORTB, 18, PUP); /* RXD0 */ + writel(1 << ATMEL_ID_USART0, &pmc->pcer); +} + +void at91_serial1_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 4, 1); /* TXD1 */ + at91_set_a_periph(AT91_PIO_PORTB, 5, PUP); /* RXD1 */ + writel(1 << ATMEL_ID_USART1, &pmc->pcer); +} + +void at91_serial2_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTD, 6, 1); /* TXD2 */ + at91_set_a_periph(AT91_PIO_PORTD, 7, PUP); /* RXD2 */ + writel(1 << ATMEL_ID_USART2, &pmc->pcer); +} + +void at91_seriald_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 12, 0); /* DRXD */ + at91_set_a_periph(AT91_PIO_PORTB, 13, 1); /* DTXD */ + writel(1 << ATMEL_ID_SYS, &pmc->pcer); +} + +#if defined(CONFIG_HAS_DATAFLASH) || defined(CONFIG_ATMEL_SPI) +void at91_spi0_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 0, PUP); /* SPI0_MISO */ + at91_set_a_periph(AT91_PIO_PORTB, 1, PUP); /* SPI0_MOSI */ + at91_set_a_periph(AT91_PIO_PORTB, 2, PUP); /* SPI0_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI0, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTB, 3, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_b_periph(AT91_PIO_PORTB, 18, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_b_periph(AT91_PIO_PORTB, 19, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_b_periph(AT91_PIO_PORTD, 27, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTB, 3, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTB, 18, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTB, 19, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTD, 27, 1); + } +} + +void at91_spi1_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 14, PUP); /* SPI1_MISO */ + at91_set_a_periph(AT91_PIO_PORTB, 15, PUP); /* SPI1_MOSI */ + at91_set_a_periph(AT91_PIO_PORTB, 16, PUP); /* SPI1_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI1, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTB, 17, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_b_periph(AT91_PIO_PORTD, 28, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_a_periph(AT91_PIO_PORTD, 18, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_a_periph(AT91_PIO_PORTD, 19, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTB, 17, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTD, 28, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTD, 18, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTD, 19, 1); + } + +} +#endif + +#ifdef CONFIG_MACB +void at91_macb_hw_init(void) +{ + at91_set_a_periph(AT91_PIO_PORTA, 17, 0); /* ETXCK_EREFCK */ + at91_set_a_periph(AT91_PIO_PORTA, 15, 0); /* ERXDV */ + at91_set_a_periph(AT91_PIO_PORTA, 12, 0); /* ERX0 */ + at91_set_a_periph(AT91_PIO_PORTA, 13, 0); /* ERX1 */ + at91_set_a_periph(AT91_PIO_PORTA, 16, 0); /* ERXER */ + at91_set_a_periph(AT91_PIO_PORTA, 14, 0); /* ETXEN */ + at91_set_a_periph(AT91_PIO_PORTA, 10, 0); /* ETX0 */ + at91_set_a_periph(AT91_PIO_PORTA, 11, 0); /* ETX1 */ + at91_set_a_periph(AT91_PIO_PORTA, 19, 0); /* EMDIO */ + at91_set_a_periph(AT91_PIO_PORTA, 18, 0); /* EMDC */ +#ifndef CONFIG_RMII + at91_set_b_periph(AT91_PIO_PORTA, 29, 0); /* ECRS */ + at91_set_b_periph(AT91_PIO_PORTA, 30, 0); /* ECOL */ + at91_set_b_periph(AT91_PIO_PORTA, 8, 0); /* ERX2 */ + at91_set_b_periph(AT91_PIO_PORTA, 9, 0); /* ERX3 */ + at91_set_b_periph(AT91_PIO_PORTA, 28, 0); /* ERXCK */ + at91_set_b_periph(AT91_PIO_PORTA, 6, 0); /* ETX2 */ + at91_set_b_periph(AT91_PIO_PORTA, 7, 0); /* ETX3 */ + at91_set_b_periph(AT91_PIO_PORTA, 27, 0); /* ETXER */ +#endif +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9n12_devices.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9n12_devices.c new file mode 100644 index 000000000..39f17a1e1 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9n12_devices.c @@ -0,0 +1,161 @@ +/* + * (C) Copyright 2013 Atmel Corporation + * Josh Wu <josh.wu@atmel.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/at91_pio.h> + +unsigned int has_lcdc() +{ + return 1; +} + +void at91_serial0_hw_init(void) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 0, 1); /* TXD0 */ + at91_set_a_periph(AT91_PIO_PORTA, 1, 0); /* RXD0 */ + writel(1 << ATMEL_ID_USART0, &pmc->pcer); +} + +void at91_serial1_hw_init(void) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 5, 1); /* TXD1 */ + at91_set_a_periph(AT91_PIO_PORTA, 6, 0); /* RXD1 */ + writel(1 << ATMEL_ID_USART1, &pmc->pcer); +} + +void at91_serial2_hw_init(void) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 7, 1); /* TXD2 */ + at91_set_a_periph(AT91_PIO_PORTA, 8, 0); /* RXD2 */ + writel(1 << ATMEL_ID_USART2, &pmc->pcer); +} + +void at91_serial3_hw_init(void) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_b_periph(AT91_PIO_PORTC, 22, 1); /* TXD3 */ + at91_set_b_periph(AT91_PIO_PORTC, 23, 0); /* RXD3 */ + writel(1 << ATMEL_ID_USART3, &pmc->pcer); +} + +void at91_seriald_hw_init(void) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 10, 1); /* DTXD */ + at91_set_a_periph(AT91_PIO_PORTA, 9, 0); /* DRXD */ + writel(1 << ATMEL_ID_SYS, &pmc->pcer); +} + +#ifdef CONFIG_ATMEL_SPI +void at91_spi0_hw_init(unsigned long cs_mask) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 11, 0); /* SPI0_MISO */ + at91_set_a_periph(AT91_PIO_PORTA, 12, 0); /* SPI0_MOSI */ + at91_set_a_periph(AT91_PIO_PORTA, 13, 0); /* SPI0_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI0, &pmc->pcer); + + if (cs_mask & (1 << 0)) + at91_set_pio_output(AT91_PIO_PORTA, 14, 1); + if (cs_mask & (1 << 1)) + at91_set_pio_output(AT91_PIO_PORTA, 7, 1); + if (cs_mask & (1 << 2)) + at91_set_pio_output(AT91_PIO_PORTA, 1, 1); + if (cs_mask & (1 << 3)) + at91_set_pio_output(AT91_PIO_PORTB, 3, 1); +} + +void at91_spi1_hw_init(unsigned long cs_mask) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_b_periph(AT91_PIO_PORTA, 21, 0); /* SPI1_MISO */ + at91_set_b_periph(AT91_PIO_PORTA, 22, 0); /* SPI1_MOSI */ + at91_set_b_periph(AT91_PIO_PORTA, 23, 0); /* SPI1_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI1, &pmc->pcer); + + if (cs_mask & (1 << 0)) + at91_set_pio_output(AT91_PIO_PORTA, 8, 1); + if (cs_mask & (1 << 1)) + at91_set_pio_output(AT91_PIO_PORTA, 0, 1); + if (cs_mask & (1 << 2)) + at91_set_pio_output(AT91_PIO_PORTA, 31, 1); + if (cs_mask & (1 << 3)) + at91_set_pio_output(AT91_PIO_PORTA, 30, 1); +} +#endif + +void at91_mci_hw_init(void) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 17, 0); /* MCCK */ + at91_set_a_periph(AT91_PIO_PORTA, 16, 0); /* MCCDA */ + at91_set_a_periph(AT91_PIO_PORTA, 15, 0); /* MCDA0 */ + at91_set_a_periph(AT91_PIO_PORTA, 18, 0); /* MCDA1 */ + at91_set_a_periph(AT91_PIO_PORTA, 19, 0); /* MCDA2 */ + at91_set_a_periph(AT91_PIO_PORTA, 20, 0); /* MCDA3 */ + + writel(1 << ATMEL_ID_HSMCI0, &pmc->pcer); +} + +#ifdef CONFIG_LCD +void at91_lcd_hw_init(void) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTC, 24, 0); /* LCDDPWR */ + at91_set_a_periph(AT91_PIO_PORTC, 26, 0); /* LCDVSYNC */ + at91_set_a_periph(AT91_PIO_PORTC, 27, 0); /* LCDHSYNC */ + at91_set_a_periph(AT91_PIO_PORTC, 28, 0); /* LCDDOTCK */ + at91_set_a_periph(AT91_PIO_PORTC, 29, 0); /* LCDDEN */ + at91_set_a_periph(AT91_PIO_PORTC, 30, 0); /* LCDDOTCK */ + + at91_set_a_periph(AT91_PIO_PORTC, 0, 0); /* LCDD0 */ + at91_set_a_periph(AT91_PIO_PORTC, 1, 0); /* LCDD1 */ + at91_set_a_periph(AT91_PIO_PORTC, 2, 0); /* LCDD2 */ + at91_set_a_periph(AT91_PIO_PORTC, 3, 0); /* LCDD3 */ + at91_set_a_periph(AT91_PIO_PORTC, 4, 0); /* LCDD4 */ + at91_set_a_periph(AT91_PIO_PORTC, 5, 0); /* LCDD5 */ + at91_set_a_periph(AT91_PIO_PORTC, 6, 0); /* LCDD6 */ + at91_set_a_periph(AT91_PIO_PORTC, 7, 0); /* LCDD7 */ + at91_set_a_periph(AT91_PIO_PORTC, 8, 0); /* LCDD8 */ + at91_set_a_periph(AT91_PIO_PORTC, 9, 0); /* LCDD9 */ + at91_set_a_periph(AT91_PIO_PORTC, 10, 0); /* LCDD10 */ + at91_set_a_periph(AT91_PIO_PORTC, 11, 0); /* LCDD11 */ + at91_set_a_periph(AT91_PIO_PORTC, 12, 0); /* LCDD12 */ + at91_set_a_periph(AT91_PIO_PORTC, 13, 0); /* LCDD13 */ + at91_set_a_periph(AT91_PIO_PORTC, 14, 0); /* LCDD14 */ + at91_set_a_periph(AT91_PIO_PORTC, 15, 0); /* LCDD15 */ + at91_set_a_periph(AT91_PIO_PORTC, 16, 0); /* LCDD16 */ + at91_set_a_periph(AT91_PIO_PORTC, 17, 0); /* LCDD17 */ + at91_set_a_periph(AT91_PIO_PORTC, 18, 0); /* LCDD18 */ + at91_set_a_periph(AT91_PIO_PORTC, 19, 0); /* LCDD19 */ + at91_set_a_periph(AT91_PIO_PORTC, 20, 0); /* LCDD20 */ + at91_set_a_periph(AT91_PIO_PORTC, 21, 0); /* LCDD21 */ + at91_set_a_periph(AT91_PIO_PORTC, 22, 0); /* LCDD22 */ + at91_set_a_periph(AT91_PIO_PORTC, 23, 0); /* LCDD23 */ + + writel(1 << ATMEL_ID_LCDC, &pmc->pcer); +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9rl_devices.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9rl_devices.c new file mode 100644 index 000000000..0ec32c3ab --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9rl_devices.c @@ -0,0 +1,103 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/gpio.h> + +/* + * if CONFIG_AT91_GPIO_PULLUP ist set, keep pullups on on all + * peripheral pins. Good to have if hardware is soldered optionally + * or in case of SPI no slave is selected. Avoid lines to float + * needlessly. Use a short local PUP define. + * + * Due to errata "TXD floats when CTS is inactive" pullups are always + * on for TXD pins. + */ +#ifdef CONFIG_AT91_GPIO_PULLUP +# define PUP CONFIG_AT91_GPIO_PULLUP +#else +# define PUP 0 +#endif + +void at91_serial0_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 6, 1); /* TXD0 */ + at91_set_a_periph(AT91_PIO_PORTA, 7, PUP); /* RXD0 */ + writel(1 << ATMEL_ID_USART0, &pmc->pcer); +} + +void at91_serial1_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 11, 1); /* TXD1 */ + at91_set_a_periph(AT91_PIO_PORTA, 12, PUP); /* RXD1 */ + writel(1 << ATMEL_ID_USART1, &pmc->pcer); +} + +void at91_serial2_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 13, 1); /* TXD2 */ + at91_set_a_periph(AT91_PIO_PORTA, 14, PUP); /* RXD2 */ + writel(1 << ATMEL_ID_USART2, &pmc->pcer); +} + +void at91_seriald_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 21, PUP); /* DRXD */ + at91_set_a_periph(AT91_PIO_PORTA, 22, 1); /* DTXD */ + writel(1 << ATMEL_ID_SYS, &pmc->pcer); +} + +#if defined(CONFIG_HAS_DATAFLASH) || defined(CONFIG_ATMEL_SPI) +void at91_spi0_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 25, PUP); /* SPI0_MISO */ + at91_set_a_periph(AT91_PIO_PORTA, 26, PUP); /* SPI0_MOSI */ + at91_set_a_periph(AT91_PIO_PORTA, 27, PUP); /* SPI0_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTA, 28, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_b_periph(AT91_PIO_PORTB, 7, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_a_periph(AT91_PIO_PORTD, 8, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_b_periph(AT91_PIO_PORTD, 9, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTA, 28, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTB, 7, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTD, 8, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTD, 9, 1); + } +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9x5_devices.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9x5_devices.c new file mode 100644 index 000000000..6d9457223 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/at91sam9x5_devices.c @@ -0,0 +1,244 @@ +/* + * Copyright (C) 2012 Atmel Corporation + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/gpio.h> +#include <asm/io.h> + +unsigned int get_chip_id(void) +{ + /* The 0x40 is the offset of cidr in DBGU */ + return readl(ATMEL_BASE_DBGU + 0x40) & ~ARCH_ID_VERSION_MASK; +} + +unsigned int get_extension_chip_id(void) +{ + /* The 0x44 is the offset of exid in DBGU */ + return readl(ATMEL_BASE_DBGU + 0x44); +} + +unsigned int has_emac1() +{ + return cpu_is_at91sam9x25(); +} + +unsigned int has_emac0() +{ + return !(cpu_is_at91sam9g15()); +} + +unsigned int has_lcdc() +{ + return cpu_is_at91sam9g15() || cpu_is_at91sam9g35() + || cpu_is_at91sam9x35(); +} + +char *get_cpu_name() +{ + unsigned int extension_id = get_extension_chip_id(); + + if (cpu_is_at91sam9x5()) { + switch (extension_id) { + case ARCH_EXID_AT91SAM9G15: + return "AT91SAM9G15"; + case ARCH_EXID_AT91SAM9G25: + return "AT91SAM9G25"; + case ARCH_EXID_AT91SAM9G35: + return "AT91SAM9G35"; + case ARCH_EXID_AT91SAM9X25: + return "AT91SAM9X25"; + case ARCH_EXID_AT91SAM9X35: + return "AT91SAM9X35"; + default: + return "Unknown CPU type"; + } + } else { + return "Unknown CPU type"; + } +} + +void at91_seriald_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 9, 0); /* DRXD */ + at91_set_a_periph(AT91_PIO_PORTA, 10, 1); /* DTXD */ + + writel(1 << ATMEL_ID_SYS, &pmc->pcer); +} + +void at91_serial0_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 0, 1); /* TXD */ + at91_set_a_periph(AT91_PIO_PORTA, 1, 0); /* RXD */ + + writel(1 << ATMEL_ID_USART0, &pmc->pcer); +} + +void at91_serial1_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 5, 1); /* TXD */ + at91_set_a_periph(AT91_PIO_PORTA, 6, 0); /* RXD */ + + writel(1 << ATMEL_ID_USART1, &pmc->pcer); +} + +void at91_serial2_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 7, 1); /* TXD */ + at91_set_a_periph(AT91_PIO_PORTA, 8, 0); /* RXD */ + + writel(1 << ATMEL_ID_USART2, &pmc->pcer); +} + +void at91_mci_hw_init(void) +{ + /* Initialize the MCI0 */ + at91_set_a_periph(AT91_PIO_PORTA, 17, 1); /* MCCK */ + at91_set_a_periph(AT91_PIO_PORTA, 16, 1); /* MCCDA */ + at91_set_a_periph(AT91_PIO_PORTA, 15, 1); /* MCDA0 */ + at91_set_a_periph(AT91_PIO_PORTA, 18, 1); /* MCDA1 */ + at91_set_a_periph(AT91_PIO_PORTA, 19, 1); /* MCDA2 */ + at91_set_a_periph(AT91_PIO_PORTA, 20, 1); /* MCDA3 */ + + /* Enable clock for MCI0 */ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + writel(1 << ATMEL_ID_HSMCI0, &pmc->pcer); +} + +#ifdef CONFIG_ATMEL_SPI +void at91_spi0_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 11, 0); /* SPI0_MISO */ + at91_set_a_periph(AT91_PIO_PORTA, 12, 0); /* SPI0_MOSI */ + at91_set_a_periph(AT91_PIO_PORTA, 13, 0); /* SPI0_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI0, &pmc->pcer); + + if (cs_mask & (1 << 0)) + at91_set_a_periph(AT91_PIO_PORTA, 14, 0); + if (cs_mask & (1 << 1)) + at91_set_b_periph(AT91_PIO_PORTA, 7, 0); + if (cs_mask & (1 << 2)) + at91_set_b_periph(AT91_PIO_PORTA, 1, 0); + if (cs_mask & (1 << 3)) + at91_set_b_periph(AT91_PIO_PORTB, 3, 0); + if (cs_mask & (1 << 4)) + at91_set_pio_output(AT91_PIO_PORTA, 14, 0); + if (cs_mask & (1 << 5)) + at91_set_pio_output(AT91_PIO_PORTA, 7, 0); + if (cs_mask & (1 << 6)) + at91_set_pio_output(AT91_PIO_PORTA, 1, 0); + if (cs_mask & (1 << 7)) + at91_set_pio_output(AT91_PIO_PORTB, 3, 0); +} + +void at91_spi1_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_b_periph(AT91_PIO_PORTA, 21, 0); /* SPI1_MISO */ + at91_set_b_periph(AT91_PIO_PORTA, 22, 0); /* SPI1_MOSI */ + at91_set_b_periph(AT91_PIO_PORTA, 23, 0); /* SPI1_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI1, &pmc->pcer); + + if (cs_mask & (1 << 0)) + at91_set_b_periph(AT91_PIO_PORTA, 8, 0); + if (cs_mask & (1 << 1)) + at91_set_b_periph(AT91_PIO_PORTA, 0, 0); + if (cs_mask & (1 << 2)) + at91_set_b_periph(AT91_PIO_PORTA, 31, 0); + if (cs_mask & (1 << 3)) + at91_set_b_periph(AT91_PIO_PORTA, 30, 0); + if (cs_mask & (1 << 4)) + at91_set_pio_output(AT91_PIO_PORTA, 8, 0); + if (cs_mask & (1 << 5)) + at91_set_pio_output(AT91_PIO_PORTA, 0, 0); + if (cs_mask & (1 << 6)) + at91_set_pio_output(AT91_PIO_PORTA, 31, 0); + if (cs_mask & (1 << 7)) + at91_set_pio_output(AT91_PIO_PORTA, 30, 0); +} +#endif + +#if defined(CONFIG_USB_OHCI_NEW) || defined(CONFIG_USB_EHCI) +void at91_uhp_hw_init(void) +{ + /* Enable VBus on UHP ports */ + at91_set_pio_output(AT91_PIO_PORTD, 18, 0); /* port A */ + at91_set_pio_output(AT91_PIO_PORTD, 19, 0); /* port B */ +#if defined(CONFIG_USB_OHCI_NEW) + /* port C is OHCI only */ + at91_set_pio_output(AT91_PIO_PORTD, 20, 0); /* port C */ +#endif +} +#endif + +#ifdef CONFIG_MACB +void at91_macb_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + if (has_emac0()) { + /* Enable EMAC0 clock */ + writel(1 << ATMEL_ID_EMAC0, &pmc->pcer); + /* EMAC0 pins setup */ + at91_set_a_periph(AT91_PIO_PORTB, 4, 0); /* ETXCK */ + at91_set_a_periph(AT91_PIO_PORTB, 3, 0); /* ERXDV */ + at91_set_a_periph(AT91_PIO_PORTB, 0, 0); /* ERX0 */ + at91_set_a_periph(AT91_PIO_PORTB, 1, 0); /* ERX1 */ + at91_set_a_periph(AT91_PIO_PORTB, 2, 0); /* ERXER */ + at91_set_a_periph(AT91_PIO_PORTB, 7, 0); /* ETXEN */ + at91_set_a_periph(AT91_PIO_PORTB, 9, 0); /* ETX0 */ + at91_set_a_periph(AT91_PIO_PORTB, 10, 0); /* ETX1 */ + at91_set_a_periph(AT91_PIO_PORTB, 5, 0); /* EMDIO */ + at91_set_a_periph(AT91_PIO_PORTB, 6, 0); /* EMDC */ + } + + if (has_emac1()) { + /* Enable EMAC1 clock */ + writel(1 << ATMEL_ID_EMAC1, &pmc->pcer); + /* EMAC1 pins setup */ + at91_set_b_periph(AT91_PIO_PORTC, 29, 0); /* ETXCK */ + at91_set_b_periph(AT91_PIO_PORTC, 28, 0); /* ECRSDV */ + at91_set_b_periph(AT91_PIO_PORTC, 20, 0); /* ERXO */ + at91_set_b_periph(AT91_PIO_PORTC, 21, 0); /* ERX1 */ + at91_set_b_periph(AT91_PIO_PORTC, 16, 0); /* ERXER */ + at91_set_b_periph(AT91_PIO_PORTC, 27, 0); /* ETXEN */ + at91_set_b_periph(AT91_PIO_PORTC, 18, 0); /* ETX0 */ + at91_set_b_periph(AT91_PIO_PORTC, 19, 0); /* ETX1 */ + at91_set_b_periph(AT91_PIO_PORTC, 31, 0); /* EMDIO */ + at91_set_b_periph(AT91_PIO_PORTC, 30, 0); /* EMDC */ + } + +#ifndef CONFIG_RMII + /* Only emac0 support MII */ + if (has_emac0()) { + at91_set_a_periph(AT91_PIO_PORTB, 16, 0); /* ECRS */ + at91_set_a_periph(AT91_PIO_PORTB, 17, 0); /* ECOL */ + at91_set_a_periph(AT91_PIO_PORTB, 13, 0); /* ERX2 */ + at91_set_a_periph(AT91_PIO_PORTB, 14, 0); /* ERX3 */ + at91_set_a_periph(AT91_PIO_PORTB, 15, 0); /* ERXCK */ + at91_set_a_periph(AT91_PIO_PORTB, 11, 0); /* ETX2 */ + at91_set_a_periph(AT91_PIO_PORTB, 12, 0); /* ETX3 */ + at91_set_a_periph(AT91_PIO_PORTB, 8, 0); /* ETXER */ + } +#endif +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/clock.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/clock.c new file mode 100644 index 000000000..31315b58e --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/clock.c @@ -0,0 +1,189 @@ +/* + * [origin: Linux kernel linux/arch/arm/mach-at91/clock.c] + * + * Copyright (C) 2005 David Brownell + * Copyright (C) 2005 Ivan Kokshaysky + * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/clk.h> + +#if !defined(CONFIG_AT91FAMILY) +# error You need to define CONFIG_AT91FAMILY in your board config! +#endif + +DECLARE_GLOBAL_DATA_PTR; + +static unsigned long at91_css_to_rate(unsigned long css) +{ + switch (css) { + case AT91_PMC_MCKR_CSS_SLOW: + return CONFIG_SYS_AT91_SLOW_CLOCK; + case AT91_PMC_MCKR_CSS_MAIN: + return gd->arch.main_clk_rate_hz; + case AT91_PMC_MCKR_CSS_PLLA: + return gd->arch.plla_rate_hz; + case AT91_PMC_MCKR_CSS_PLLB: + return gd->arch.pllb_rate_hz; + } + + return 0; +} + +#ifdef CONFIG_USB_ATMEL +static unsigned at91_pll_calc(unsigned main_freq, unsigned out_freq) +{ + unsigned i, div = 0, mul = 0, diff = 1 << 30; + unsigned ret = (out_freq > 155000000) ? 0xbe00 : 0x3e00; + + /* PLL output max 240 MHz (or 180 MHz per errata) */ + if (out_freq > 240000000) + goto fail; + + for (i = 1; i < 256; i++) { + int diff1; + unsigned input, mul1; + + /* + * PLL input between 1MHz and 32MHz per spec, but lower + * frequences seem necessary in some cases so allow 100K. + * Warning: some newer products need 2MHz min. + */ + input = main_freq / i; +#if defined(CONFIG_AT91SAM9G20) + if (input < 2000000) + continue; +#endif + if (input < 100000) + continue; + if (input > 32000000) + continue; + + mul1 = out_freq / input; +#if defined(CONFIG_AT91SAM9G20) + if (mul > 63) + continue; +#endif + if (mul1 > 2048) + continue; + if (mul1 < 2) + goto fail; + + diff1 = out_freq - input * mul1; + if (diff1 < 0) + diff1 = -diff1; + if (diff > diff1) { + diff = diff1; + div = i; + mul = mul1; + if (diff == 0) + break; + } + } + if (i == 256 && diff > (out_freq >> 5)) + goto fail; + return ret | ((mul - 1) << 16) | div; +fail: + return 0; +} +#endif + +static u32 at91_pll_rate(u32 freq, u32 reg) +{ + unsigned mul, div; + + div = reg & 0xff; + mul = (reg >> 16) & 0x7ff; + if (div && mul) { + freq /= div; + freq *= mul + 1; + } else + freq = 0; + + return freq; +} + +int at91_clock_init(unsigned long main_clock) +{ + unsigned freq, mckr; + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; +#ifndef CONFIG_SYS_AT91_MAIN_CLOCK + unsigned tmp; + /* + * When the bootloader initialized the main oscillator correctly, + * there's no problem using the cycle counter. But if it didn't, + * or when using oscillator bypass mode, we must be told the speed + * of the main clock. + */ + if (!main_clock) { + do { + tmp = readl(&pmc->mcfr); + } while (!(tmp & AT91_PMC_MCFR_MAINRDY)); + tmp &= AT91_PMC_MCFR_MAINF_MASK; + main_clock = tmp * (CONFIG_SYS_AT91_SLOW_CLOCK / 16); + } +#endif + gd->arch.main_clk_rate_hz = main_clock; + + /* report if PLLA is more than mildly overclocked */ + gd->arch.plla_rate_hz = at91_pll_rate(main_clock, readl(&pmc->pllar)); + +#ifdef CONFIG_USB_ATMEL + /* + * USB clock init: choose 48 MHz PLLB value, + * disable 48MHz clock during usb peripheral suspend. + * + * REVISIT: assumes MCK doesn't derive from PLLB! + */ + gd->arch.at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | + AT91_PMC_PLLBR_USBDIV_2; + gd->arch.pllb_rate_hz = at91_pll_rate(main_clock, + gd->arch.at91_pllb_usb_init); +#endif + + /* + * MCK and CPU derive from one of those primary clocks. + * For now, assume this parentage won't change. + */ + mckr = readl(&pmc->mckr); +#if defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) \ + || defined(CONFIG_AT91SAM9N12) || defined(CONFIG_AT91SAM9X5) + /* plla divisor by 2 */ + gd->arch.plla_rate_hz /= (1 << ((mckr & 1 << 12) >> 12)); +#endif + gd->arch.mck_rate_hz = at91_css_to_rate(mckr & AT91_PMC_MCKR_CSS_MASK); + freq = gd->arch.mck_rate_hz; + + freq /= (1 << ((mckr & AT91_PMC_MCKR_PRES_MASK) >> 2)); /* prescale */ +#if defined(CONFIG_AT91SAM9G20) + /* mdiv ; (x >> 7) = ((x >> 8) * 2) */ + gd->arch.mck_rate_hz = (mckr & AT91_PMC_MCKR_MDIV_MASK) ? + freq / ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 7) : freq; + if (mckr & AT91_PMC_MCKR_MDIV_MASK) + freq /= 2; /* processor clock division */ +#elif defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) \ + || defined(CONFIG_AT91SAM9N12) || defined(CONFIG_AT91SAM9X5) + /* mdiv <==> divisor + * 0 <==> 1 + * 1 <==> 2 + * 2 <==> 4 + * 3 <==> 3 + */ + gd->arch.mck_rate_hz = (mckr & AT91_PMC_MCKR_MDIV_MASK) == + (AT91_PMC_MCKR_MDIV_2 | AT91_PMC_MCKR_MDIV_4) + ? freq / 3 + : freq / (1 << ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8)); +#else + gd->arch.mck_rate_hz = freq / + (1 << ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8)); +#endif + gd->arch.cpu_clk_rate_hz = freq; + + return 0; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/config.mk b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/config.mk new file mode 100644 index 000000000..370630d4d --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/config.mk @@ -0,0 +1,2 @@ +PF_CPPFLAGS_TUNE := $(call cc-option,-mtune=arm926ejs,) +PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_TUNE) diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/cpu.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/cpu.c new file mode 100644 index 000000000..da1d35907 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/cpu.c @@ -0,0 +1,57 @@ +/* + * (C) Copyright 2010 + * Reinhard Meyer, reinhard.meyer@emk-elektronik.de + * (C) Copyright 2009 + * Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/at91_pit.h> +#include <asm/arch/at91_gpbr.h> +#include <asm/arch/clk.h> + +#ifndef CONFIG_SYS_AT91_MAIN_CLOCK +#define CONFIG_SYS_AT91_MAIN_CLOCK 0 +#endif + +int arch_cpu_init(void) +{ + return at91_clock_init(CONFIG_SYS_AT91_MAIN_CLOCK); +} + +void arch_preboot_os(void) +{ + ulong cpiv; + at91_pit_t *pit = (at91_pit_t *) ATMEL_BASE_PIT; + + cpiv = AT91_PIT_MR_PIV_MASK(readl(&pit->piir)); + + /* + * Disable PITC + * Add 0x1000 to current counter to stop it faster + * without waiting for wrapping back to 0 + */ + writel(cpiv + 0x1000, &pit->mr); +} + +#if defined(CONFIG_DISPLAY_CPUINFO) +int print_cpuinfo(void) +{ + char buf[32]; + + printf("CPU: %s\n", ATMEL_CPU_NAME); + printf("Crystal frequency: %8s MHz\n", + strmhz(buf, get_main_clk_rate())); + printf("CPU clock : %8s MHz\n", + strmhz(buf, get_cpu_clk_rate())); + printf("Master clock : %8s MHz\n", + strmhz(buf, get_mck_clk_rate())); + + return 0; +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/eflash.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/eflash.c new file mode 100644 index 000000000..3f3926428 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/eflash.c @@ -0,0 +1,254 @@ +/* + * (C) Copyright 2010 + * Reinhard Meyer, EMK Elektronik, reinhard.meyer@emk-elektronik.de + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * this driver supports the enhanced embedded flash in the Atmel + * AT91SAM9XE devices with the following geometry: + * + * AT91SAM9XE128: 1 plane of 8 regions of 32 pages (total 256 pages) + * AT91SAM9XE256: 1 plane of 16 regions of 32 pages (total 512 pages) + * AT91SAM9XE512: 1 plane of 32 regions of 32 pages (total 1024 pages) + * (the exact geometry is read from the flash at runtime, so any + * future devices should already be covered) + * + * Regions can be write/erase protected. + * Whole (!) pages can be individually written with erase on the fly. + * Writing partial pages will corrupt the rest of the page. + * + * The flash is presented to u-boot with each region being a sector, + * having the following effects: + * Each sector can be hardware protected (protect on/off). + * Each page in a sector can be rewritten anytime. + * Since pages are erased when written, the "erase" does nothing. + * The first "CONFIG_EFLASH_PROTSECTORS" cannot be unprotected + * by u-Boot commands. + * + * Note: Redundant environment will not work in this flash since + * it does use partial page writes. Make sure the environment spans + * whole pages! + */ + +/* + * optional TODOs (nice to have features): + * + * make the driver coexist with other NOR flash drivers + * (use an index into flash_info[], requires work + * in those other drivers, too) + * Make the erase command fill the sectors with 0xff + * (if the flashes grow larger in the future and + * someone puts a jffs2 into them) + * do a read-modify-write for partially programmed pages + */ +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/at91_eefc.h> +#include <asm/arch/at91_dbu.h> + +/* checks to detect configuration errors */ +#if CONFIG_SYS_MAX_FLASH_BANKS!=1 +#error eflash: this driver can only handle 1 bank +#endif + +/* global structure */ +flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; +static u32 pagesize; + +unsigned long flash_init (void) +{ + at91_eefc_t *eefc = (at91_eefc_t *) ATMEL_BASE_EEFC; + at91_dbu_t *dbu = (at91_dbu_t *) ATMEL_BASE_DBGU; + u32 id, size, nplanes, planesize, nlocks; + u32 addr, i, tmp=0; + + debug("eflash: init\n"); + + flash_info[0].flash_id = FLASH_UNKNOWN; + + /* check if its an AT91ARM9XE SoC */ + if ((readl(&dbu->cidr) & AT91_DBU_CID_ARCH_MASK) != AT91_DBU_CID_ARCH_9XExx) { + puts("eflash: not an AT91SAM9XE\n"); + return 0; + } + + /* now query the eflash for its structure */ + writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_GETD, &eefc->fcr); + while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0) + ; + id = readl(&eefc->frr); /* word 0 */ + size = readl(&eefc->frr); /* word 1 */ + pagesize = readl(&eefc->frr); /* word 2 */ + nplanes = readl(&eefc->frr); /* word 3 */ + planesize = readl(&eefc->frr); /* word 4 */ + debug("id=%08x size=%u pagesize=%u planes=%u planesize=%u\n", + id, size, pagesize, nplanes, planesize); + for (i=1; i<nplanes; i++) { + tmp = readl(&eefc->frr); /* words 5..4+nplanes-1 */ + }; + nlocks = readl(&eefc->frr); /* word 4+nplanes */ + debug("nlocks=%u\n", nlocks); + /* since we are going to use the lock regions as sectors, check count */ + if (nlocks > CONFIG_SYS_MAX_FLASH_SECT) { + printf("eflash: number of lock regions(%u) "\ + "> CONFIG_SYS_MAX_FLASH_SECT. reducing...\n", + nlocks); + nlocks = CONFIG_SYS_MAX_FLASH_SECT; + } + flash_info[0].size = size; + flash_info[0].sector_count = nlocks; + flash_info[0].flash_id = id; + + addr = ATMEL_BASE_FLASH; + for (i=0; i<nlocks; i++) { + tmp = readl(&eefc->frr); /* words 4+nplanes+1.. */ + flash_info[0].start[i] = addr; + flash_info[0].protect[i] = 0; + addr += tmp; + }; + + /* now read the protection information for all regions */ + writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_GLB, &eefc->fcr); + while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0) + ; + for (i=0; i<flash_info[0].sector_count; i++) { + if (i%32 == 0) + tmp = readl(&eefc->frr); + flash_info[0].protect[i] = (tmp >> (i%32)) & 1; +#if defined(CONFIG_EFLASH_PROTSECTORS) + if (i < CONFIG_EFLASH_PROTSECTORS) + flash_info[0].protect[i] = 1; +#endif + } + + return size; +} + +void flash_print_info (flash_info_t *info) +{ + int i; + + puts("AT91SAM9XE embedded flash\n Size: "); + print_size(info->size, " in "); + printf("%d Sectors\n", info->sector_count); + + printf(" Sector Start Addresses:"); + for (i=0; i<info->sector_count; ++i) { + if ((i % 5) == 0) + printf("\n "); + printf(" %08lX%s", + info->start[i], + info->protect[i] ? " (RO)" : " " + ); + } + printf ("\n"); + return; +} + +int flash_real_protect (flash_info_t *info, long sector, int prot) +{ + at91_eefc_t *eefc = (at91_eefc_t *) ATMEL_BASE_EEFC; + u32 pagenum = (info->start[sector]-ATMEL_BASE_FLASH)/pagesize; + u32 i, tmp=0; + + debug("protect sector=%ld prot=%d\n", sector, prot); + +#if defined(CONFIG_EFLASH_PROTSECTORS) + if (sector < CONFIG_EFLASH_PROTSECTORS) { + if (!prot) { + printf("eflash: sector %lu cannot be unprotected\n", + sector); + } + return 1; /* return anyway, caller does not care for result */ + } +#endif + if (prot) { + writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_SLB | + (pagenum << AT91_EEFC_FCR_FARG_SHIFT), &eefc->fcr); + } else { + writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_CLB | + (pagenum << AT91_EEFC_FCR_FARG_SHIFT), &eefc->fcr); + } + while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0) + ; + /* now re-read the protection information for all regions */ + writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_GLB, &eefc->fcr); + while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0) + ; + for (i=0; i<info->sector_count; i++) { + if (i%32 == 0) + tmp = readl(&eefc->frr); + info->protect[i] = (tmp >> (i%32)) & 1; + } + return 0; +} + +static u32 erase_write_page (u32 pagenum) +{ + at91_eefc_t *eefc = (at91_eefc_t *) ATMEL_BASE_EEFC; + + debug("erase+write page=%u\n", pagenum); + + /* give erase and write page command */ + writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_EWP | + (pagenum << AT91_EEFC_FCR_FARG_SHIFT), &eefc->fcr); + while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0) + ; + /* return status */ + return readl(&eefc->fsr) + & (AT91_EEFC_FSR_FCMDE | AT91_EEFC_FSR_FLOCKE); +} + +int flash_erase (flash_info_t *info, int s_first, int s_last) +{ + debug("erase first=%d last=%d\n", s_first, s_last); + puts("this flash does not need and support erasing!\n"); + return 0; +} + +/* + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + */ + +int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) +{ + u32 pagenum; + u32 *src32, *dst32; + u32 i; + + debug("write src=%08lx addr=%08lx cnt=%lx\n", + (ulong)src, addr, cnt); + + /* REQUIRE addr to be on a page start, abort if not */ + if (addr % pagesize) { + printf ("eflash: start %08lx is not on page start\n"\ + " write aborted\n", addr); + return 1; + } + + /* now start copying data */ + pagenum = (addr-ATMEL_BASE_FLASH)/pagesize; + src32 = (u32 *) src; + dst32 = (u32 *) addr; + while (cnt > 0) { + i = pagesize / 4; + /* fill page buffer */ + while (i--) + *dst32++ = *src32++; + /* write page */ + if (erase_write_page(pagenum)) + return 1; + pagenum++; + if (cnt > pagesize) + cnt -= pagesize; + else + cnt = 0; + } + return 0; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/led.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/led.c new file mode 100644 index 000000000..46ed05502 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/led.c @@ -0,0 +1,47 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/gpio.h> +#include <asm/arch/gpio.h> + +#ifdef CONFIG_RED_LED +void red_led_on(void) +{ + gpio_set_value(CONFIG_RED_LED, 1); +} + +void red_led_off(void) +{ + gpio_set_value(CONFIG_RED_LED, 0); +} +#endif + +#ifdef CONFIG_GREEN_LED +void green_led_on(void) +{ + gpio_set_value(CONFIG_GREEN_LED, 0); +} + +void green_led_off(void) +{ + gpio_set_value(CONFIG_GREEN_LED, 1); +} +#endif + +#ifdef CONFIG_YELLOW_LED +void yellow_led_on(void) +{ + gpio_set_value(CONFIG_YELLOW_LED, 0); +} + +void yellow_led_off(void) +{ + gpio_set_value(CONFIG_YELLOW_LED, 1); +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/lowlevel_init.S b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/lowlevel_init.S new file mode 100644 index 000000000..a9ec81a75 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/lowlevel_init.S @@ -0,0 +1,246 @@ +/* + * Memory Setup stuff - taken from blob memsetup.S + * + * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) and + * Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl) + * + * Copyright (C) 2008 Ronetix Ilko Iliev (www.ronetix.at) + * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> +#include <asm/arch/hardware.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/at91_wdt.h> +#include <asm/arch/at91_pio.h> +#include <asm/arch/at91_matrix.h> +#include <asm/arch/at91sam9_sdramc.h> +#include <asm/arch/at91sam9_smc.h> +#include <asm/arch/at91_rstc.h> +#ifdef CONFIG_ATMEL_LEGACY +#include <asm/arch/at91sam9_matrix.h> +#endif +#ifndef CONFIG_SYS_MATRIX_EBICSA_VAL +#define CONFIG_SYS_MATRIX_EBICSA_VAL CONFIG_SYS_MATRIX_EBI0CSA_VAL +#endif + +.globl lowlevel_init +.type lowlevel_init,function +lowlevel_init: + +POS1: + adr r5, POS1 /* r5 = POS1 run time */ + ldr r0, =POS1 /* r0 = POS1 compile */ + sub r5, r5, r0 /* r0 = CONFIG_SYS_TEXT_BASE-1 */ + + /* memory control configuration 1 */ + ldr r0, =SMRDATA + ldr r2, =SMRDATA1 + add r0, r0, r5 + add r2, r2, r5 +0: + /* the address */ + ldr r1, [r0], #4 + /* the value */ + ldr r3, [r0], #4 + str r3, [r1] + cmp r2, r0 + bne 0b + +/* ---------------------------------------------------------------------------- + * PMC Init Step 1. + * ---------------------------------------------------------------------------- + * - Check if the PLL is already initialized + * ---------------------------------------------------------------------------- + */ + ldr r1, =(AT91_ASM_PMC_MCKR) + ldr r0, [r1] + and r0, r0, #3 + cmp r0, #0 + bne PLL_setup_end + +/* --------------------------------------------------------------------------- + * - Enable the Main Oscillator + * --------------------------------------------------------------------------- + */ + ldr r1, =(AT91_ASM_PMC_MOR) + ldr r2, =(AT91_ASM_PMC_SR) + /* Main oscillator Enable register PMC_MOR: */ + ldr r0, =CONFIG_SYS_MOR_VAL + str r0, [r1] + + /* Reading the PMC Status to detect when the Main Oscillator is enabled */ + mov r4, #AT91_PMC_IXR_MOSCS +MOSCS_Loop: + ldr r3, [r2] + and r3, r4, r3 + cmp r3, #AT91_PMC_IXR_MOSCS + bne MOSCS_Loop + +/* ---------------------------------------------------------------------------- + * PMC Init Step 2. + * ---------------------------------------------------------------------------- + * Setup PLLA + * ---------------------------------------------------------------------------- + */ + ldr r1, =(AT91_ASM_PMC_PLLAR) + ldr r0, =CONFIG_SYS_PLLAR_VAL + str r0, [r1] + + /* Reading the PMC Status register to detect when the PLLA is locked */ + mov r4, #AT91_PMC_IXR_LOCKA +MOSCS_Loop1: + ldr r3, [r2] + and r3, r4, r3 + cmp r3, #AT91_PMC_IXR_LOCKA + bne MOSCS_Loop1 + +/* ---------------------------------------------------------------------------- + * PMC Init Step 3. + * ---------------------------------------------------------------------------- + * - Switch on the Main Oscillator + * ---------------------------------------------------------------------------- + */ + ldr r1, =(AT91_ASM_PMC_MCKR) + + /* -Master Clock Controller register PMC_MCKR */ + ldr r0, =CONFIG_SYS_MCKR1_VAL + str r0, [r1] + + /* Reading the PMC Status to detect when the Master clock is ready */ + mov r4, #AT91_PMC_IXR_MCKRDY +MCKRDY_Loop: + ldr r3, [r2] + and r3, r4, r3 + cmp r3, #AT91_PMC_IXR_MCKRDY + bne MCKRDY_Loop + + ldr r0, =CONFIG_SYS_MCKR2_VAL + str r0, [r1] + + /* Reading the PMC Status to detect when the Master clock is ready */ + mov r4, #AT91_PMC_IXR_MCKRDY +MCKRDY_Loop1: + ldr r3, [r2] + and r3, r4, r3 + cmp r3, #AT91_PMC_IXR_MCKRDY + bne MCKRDY_Loop1 +PLL_setup_end: + +/* ---------------------------------------------------------------------------- + * - memory control configuration 2 + * ---------------------------------------------------------------------------- + */ + ldr r0, =(AT91_ASM_SDRAMC_TR) + ldr r1, [r0] + cmp r1, #0 + bne SDRAM_setup_end + + ldr r0, =SMRDATA1 + ldr r2, =SMRDATA2 + add r0, r0, r5 + add r2, r2, r5 +2: + /* the address */ + ldr r1, [r0], #4 + /* the value */ + ldr r3, [r0], #4 + str r3, [r1] + cmp r2, r0 + bne 2b + +SDRAM_setup_end: + /* everything is fine now */ + mov pc, lr + + .ltorg + +SMRDATA: + .word AT91_ASM_WDT_MR + .word CONFIG_SYS_WDTC_WDMR_VAL + /* configure PIOx as EBI0 D[16-31] */ +#if defined(CONFIG_AT91SAM9263) + .word AT91_ASM_PIOD_PDR + .word CONFIG_SYS_PIOD_PDR_VAL1 + .word AT91_ASM_PIOD_PUDR + .word CONFIG_SYS_PIOD_PPUDR_VAL + .word AT91_ASM_PIOD_ASR + .word CONFIG_SYS_PIOD_PPUDR_VAL +#elif defined(CONFIG_AT91SAM9260) || defined(CONFIG_AT91SAM9261) \ + || defined(CONFIG_AT91SAM9G20) + .word AT91_ASM_PIOC_PDR + .word CONFIG_SYS_PIOC_PDR_VAL1 + .word AT91_ASM_PIOC_PUDR + .word CONFIG_SYS_PIOC_PPUDR_VAL +#endif + .word AT91_ASM_MATRIX_CSA0 + .word CONFIG_SYS_MATRIX_EBICSA_VAL + + /* flash */ + .word AT91_ASM_SMC_MODE0 + .word CONFIG_SYS_SMC0_MODE0_VAL + + .word AT91_ASM_SMC_CYCLE0 + .word CONFIG_SYS_SMC0_CYCLE0_VAL + + .word AT91_ASM_SMC_PULSE0 + .word CONFIG_SYS_SMC0_PULSE0_VAL + + .word AT91_ASM_SMC_SETUP0 + .word CONFIG_SYS_SMC0_SETUP0_VAL + +SMRDATA1: + .word AT91_ASM_SDRAMC_MR + .word CONFIG_SYS_SDRC_MR_VAL1 + .word AT91_ASM_SDRAMC_TR + .word CONFIG_SYS_SDRC_TR_VAL1 + .word AT91_ASM_SDRAMC_CR + .word CONFIG_SYS_SDRC_CR_VAL + .word AT91_ASM_SDRAMC_MDR + .word CONFIG_SYS_SDRC_MDR_VAL + .word AT91_ASM_SDRAMC_MR + .word CONFIG_SYS_SDRC_MR_VAL2 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL1 + .word AT91_ASM_SDRAMC_MR + .word CONFIG_SYS_SDRC_MR_VAL3 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL2 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL3 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL4 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL5 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL6 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL7 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL8 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL9 + .word AT91_ASM_SDRAMC_MR + .word CONFIG_SYS_SDRC_MR_VAL4 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL10 + .word AT91_ASM_SDRAMC_MR + .word CONFIG_SYS_SDRC_MR_VAL5 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL11 + .word AT91_ASM_SDRAMC_TR + .word CONFIG_SYS_SDRC_TR_VAL2 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL12 + /* User reset enable*/ + .word AT91_ASM_RSTC_MR + .word CONFIG_SYS_RSTC_RMR_VAL +#ifdef CONFIG_SYS_MATRIX_MCFG_REMAP + /* MATRIX_MCFG - REMAP all masters */ + .word AT91_ASM_MATRIX_MCFG + .word 0x1FF +#endif +SMRDATA2: + .word 0 diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/reset.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/reset.c new file mode 100644 index 000000000..e67f47bd0 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/reset.c @@ -0,0 +1,29 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/at91_rstc.h> + +/* Reset the cpu by telling the reset controller to do so */ +void reset_cpu(ulong ignored) +{ + at91_rstc_t *rstc = (at91_rstc_t *) ATMEL_BASE_RSTC; + + writel(AT91_RSTC_KEY + | AT91_RSTC_CR_PROCRST /* Processor Reset */ + | AT91_RSTC_CR_PERRST /* Peripheral Reset */ +#ifdef CONFIG_AT91RESET_EXTRST + | AT91_RSTC_CR_EXTRST /* External Reset (assert nRST pin) */ +#endif + , &rstc->cr); + /* never reached */ + while (1) + ; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/timer.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/timer.c new file mode 100644 index 000000000..b0b7fb93f --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/at91/timer.c @@ -0,0 +1,120 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/at91_pit.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/clk.h> +#include <div64.h> + +#if !defined(CONFIG_AT91FAMILY) +# error You need to define CONFIG_AT91FAMILY in your board config! +#endif + +DECLARE_GLOBAL_DATA_PTR; + +/* + * We're using the AT91CAP9/SAM9 PITC in 32 bit mode, by + * setting the 20 bit counter period to its maximum (0xfffff). + * (See the relevant data sheets to understand that this really works) + * + * We do also mimic the typical powerpc way of incrementing + * two 32 bit registers called tbl and tbu. + * + * Those registers increment at 1/16 the main clock rate. + */ + +#define TIMER_LOAD_VAL 0xfffff + +static inline unsigned long long tick_to_time(unsigned long long tick) +{ + tick *= CONFIG_SYS_HZ; + do_div(tick, gd->arch.timer_rate_hz); + + return tick; +} + +static inline unsigned long long usec_to_tick(unsigned long long usec) +{ + usec *= gd->arch.timer_rate_hz; + do_div(usec, 1000000); + + return usec; +} + +/* + * Use the PITC in full 32 bit incrementing mode + */ +int timer_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + at91_pit_t *pit = (at91_pit_t *) ATMEL_BASE_PIT; + + /* Enable PITC Clock */ + writel(1 << ATMEL_ID_SYS, &pmc->pcer); + + /* Enable PITC */ + writel(TIMER_LOAD_VAL | AT91_PIT_MR_EN , &pit->mr); + + gd->arch.timer_rate_hz = gd->arch.mck_rate_hz / 16; + gd->arch.tbu = gd->arch.tbl = 0; + + return 0; +} + +/* + * Get the current 64 bit timer tick count + */ +unsigned long long get_ticks(void) +{ + at91_pit_t *pit = (at91_pit_t *) ATMEL_BASE_PIT; + + ulong now = readl(&pit->piir); + + /* increment tbu if tbl has rolled over */ + if (now < gd->arch.tbl) + gd->arch.tbu++; + gd->arch.tbl = now; + return (((unsigned long long)gd->arch.tbu) << 32) | gd->arch.tbl; +} + +void __udelay(unsigned long usec) +{ + unsigned long long start; + ulong tmo; + + start = get_ticks(); /* get current timestamp */ + tmo = usec_to_tick(usec); /* convert usecs to ticks */ + while ((get_ticks() - start) < tmo) + ; /* loop till time has passed */ +} + +/* + * get_timer(base) can be used to check for timeouts or + * to measure elasped time relative to an event: + * + * ulong start_time = get_timer(0) sets start_time to the current + * time value. + * get_timer(start_time) returns the time elapsed since then. + * + * The time is used in CONFIG_SYS_HZ units! + */ +ulong get_timer(ulong base) +{ + return tick_to_time(get_ticks()) - base; +} + +/* + * Return the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + return gd->arch.timer_rate_hz; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/cache.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/cache.c new file mode 100644 index 000000000..e86c2edd3 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/cache.c @@ -0,0 +1,105 @@ +/* + * (C) Copyright 2011 + * Ilya Yanok, EmCraft Systems + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <linux/types.h> +#include <common.h> + +#ifndef CONFIG_SYS_DCACHE_OFF + +#ifndef CONFIG_SYS_CACHELINE_SIZE +#define CONFIG_SYS_CACHELINE_SIZE 32 +#endif + +void invalidate_dcache_all(void) +{ + asm volatile("mcr p15, 0, %0, c7, c6, 0\n" : : "r"(0)); +} + +void flush_dcache_all(void) +{ + asm volatile( + "0:" + "mrc p15, 0, r15, c7, c14, 3\n" + "bne 0b\n" + "mcr p15, 0, %0, c7, c10, 4\n" + : : "r"(0) : "memory" + ); +} + +static int check_cache_range(unsigned long start, unsigned long stop) +{ + int ok = 1; + + if (start & (CONFIG_SYS_CACHELINE_SIZE - 1)) + ok = 0; + + if (stop & (CONFIG_SYS_CACHELINE_SIZE - 1)) + ok = 0; + + if (!ok) + debug("CACHE: Misaligned operation at range [%08lx, %08lx]\n", + start, stop); + + return ok; +} + +void invalidate_dcache_range(unsigned long start, unsigned long stop) +{ + if (!check_cache_range(start, stop)) + return; + + while (start < stop) { + asm volatile("mcr p15, 0, %0, c7, c6, 1\n" : : "r"(start)); + start += CONFIG_SYS_CACHELINE_SIZE; + } +} + +void flush_dcache_range(unsigned long start, unsigned long stop) +{ + if (!check_cache_range(start, stop)) + return; + + while (start < stop) { + asm volatile("mcr p15, 0, %0, c7, c14, 1\n" : : "r"(start)); + start += CONFIG_SYS_CACHELINE_SIZE; + } + + asm volatile("mcr p15, 0, %0, c7, c10, 4\n" : : "r"(0)); +} + +void flush_cache(unsigned long start, unsigned long size) +{ + flush_dcache_range(start, start + size); +} +#else /* #ifndef CONFIG_SYS_DCACHE_OFF */ +void invalidate_dcache_all(void) +{ +} + +void flush_dcache_all(void) +{ +} + +void invalidate_dcache_range(unsigned long start, unsigned long stop) +{ +} + +void flush_dcache_range(unsigned long start, unsigned long stop) +{ +} + +void flush_cache(unsigned long start, unsigned long size) +{ +} +#endif /* #ifndef CONFIG_SYS_DCACHE_OFF */ + +/* + * Stub implementations for l2 cache operations + */ +void __l2_cache_disable(void) {} + +void l2_cache_disable(void) + __attribute__((weak, alias("__l2_cache_disable"))); diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/config.mk b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/config.mk new file mode 100644 index 000000000..bdb3da183 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/config.mk @@ -0,0 +1,8 @@ +# +# (C) Copyright 2002 +# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +PLATFORM_CPPFLAGS += -march=armv5te diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/cpu.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/cpu.c new file mode 100644 index 000000000..e37e87b68 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/cpu.c @@ -0,0 +1,51 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * CPU specific code + */ + +#include <common.h> +#include <command.h> +#include <asm/system.h> + +static void cache_flush(void); + +int cleanup_before_linux (void) +{ + /* + * this function is called just before we call linux + * it prepares the processor for linux + * + * we turn off caches etc ... + */ + + disable_interrupts (); + + + /* turn off I/D-cache */ + icache_disable(); + dcache_disable(); + l2_cache_disable(); + + /* flush I/D-cache */ + cache_flush(); + + return 0; +} + +/* flush I/D-cache */ +static void cache_flush (void) +{ + unsigned long i = 0; + + asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i)); +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/Makefile b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/Makefile new file mode 100644 index 000000000..7d67191de --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/Makefile @@ -0,0 +1,28 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y += cpu.o misc.o timer.o psc.o pinmux.o reset.o +obj-$(CONFIG_DA850_LOWLEVEL) += da850_lowlevel.o +obj-$(CONFIG_SOC_DM355) += dm355.o +obj-$(CONFIG_SOC_DM365) += dm365.o +obj-$(CONFIG_SOC_DM644X) += dm644x.o +obj-$(CONFIG_SOC_DM646X) += dm646x.o +obj-$(CONFIG_SOC_DA830) += da830_pinmux.o +obj-$(CONFIG_SOC_DA850) += da850_pinmux.o +obj-$(CONFIG_DRIVER_TI_EMAC) += lxt972.o dp83848.o et1011c.o ksz8873.o + +ifdef CONFIG_SPL_BUILD +obj-$(CONFIG_SPL_FRAMEWORK) += spl.o +obj-$(CONFIG_SOC_DM365) += dm365_lowlevel.o +obj-$(CONFIG_SOC_DA8XX) += da850_lowlevel.o +endif + +ifndef CONFIG_SKIP_LOWLEVEL_INIT +obj-y += lowlevel_init.o +endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/config.mk b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/config.mk new file mode 100644 index 000000000..69e9d5ab2 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/config.mk @@ -0,0 +1,8 @@ +# +# Copyright (C) 2012, Texas Instruments, Incorporated - http://www.ti.com/ +# +# SPDX-License-Identifier: GPL-2.0+ +# +ifndef CONFIG_SPL_BUILD +ALL-$(CONFIG_SPL_FRAMEWORK) += u-boot.ais +endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/cpu.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/cpu.c new file mode 100644 index 000000000..ff6114775 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/cpu.c @@ -0,0 +1,223 @@ +/* + * Copyright (C) 2004 Texas Instruments. + * Copyright (C) 2009 David Brownell + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <netdev.h> +#include <asm/arch/hardware.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* offsets from PLL controller base */ +#define PLLC_PLLCTL 0x100 +#define PLLC_PLLM 0x110 +#define PLLC_PREDIV 0x114 +#define PLLC_PLLDIV1 0x118 +#define PLLC_PLLDIV2 0x11c +#define PLLC_PLLDIV3 0x120 +#define PLLC_POSTDIV 0x128 +#define PLLC_BPDIV 0x12c +#define PLLC_PLLDIV4 0x160 +#define PLLC_PLLDIV5 0x164 +#define PLLC_PLLDIV6 0x168 +#define PLLC_PLLDIV7 0x16c +#define PLLC_PLLDIV8 0x170 +#define PLLC_PLLDIV9 0x174 + +#define BIT(x) (1 << (x)) + +/* SOC-specific pll info */ +#ifdef CONFIG_SOC_DM355 +#define ARM_PLLDIV PLLC_PLLDIV1 +#define DDR_PLLDIV PLLC_PLLDIV1 +#endif + +#ifdef CONFIG_SOC_DM644X +#define ARM_PLLDIV PLLC_PLLDIV2 +#define DSP_PLLDIV PLLC_PLLDIV1 +#define DDR_PLLDIV PLLC_PLLDIV2 +#endif + +#ifdef CONFIG_SOC_DM646X +#define DSP_PLLDIV PLLC_PLLDIV1 +#define ARM_PLLDIV PLLC_PLLDIV2 +#define DDR_PLLDIV PLLC_PLLDIV1 +#endif + +#ifdef CONFIG_SOC_DA8XX +unsigned int sysdiv[9] = { + PLLC_PLLDIV1, PLLC_PLLDIV2, PLLC_PLLDIV3, PLLC_PLLDIV4, PLLC_PLLDIV5, + PLLC_PLLDIV6, PLLC_PLLDIV7, PLLC_PLLDIV8, PLLC_PLLDIV9 +}; + +int clk_get(enum davinci_clk_ids id) +{ + int pre_div; + int pllm; + int post_div; + int pll_out; + unsigned int pll_base; + + pll_out = CONFIG_SYS_OSCIN_FREQ; + + if (id == DAVINCI_AUXCLK_CLKID) + goto out; + + if ((id >> 16) == 1) + pll_base = (unsigned int)davinci_pllc1_regs; + else + pll_base = (unsigned int)davinci_pllc0_regs; + + id &= 0xFFFF; + + /* + * Lets keep this simple. Combining operations can result in + * unexpected approximations + */ + pre_div = (readl(pll_base + PLLC_PREDIV) & + DAVINCI_PLLC_DIV_MASK) + 1; + pllm = readl(pll_base + PLLC_PLLM) + 1; + + pll_out /= pre_div; + pll_out *= pllm; + + if (id == DAVINCI_PLLM_CLKID) + goto out; + + post_div = (readl(pll_base + PLLC_POSTDIV) & + DAVINCI_PLLC_DIV_MASK) + 1; + + pll_out /= post_div; + + if (id == DAVINCI_PLLC_CLKID) + goto out; + + pll_out /= (readl(pll_base + sysdiv[id - 1]) & + DAVINCI_PLLC_DIV_MASK) + 1; + +out: + return pll_out; +} + +int set_cpu_clk_info(void) +{ + gd->bd->bi_arm_freq = clk_get(DAVINCI_ARM_CLKID) / 1000000; + /* DDR PHY uses an x2 input clock */ + gd->bd->bi_ddr_freq = cpu_is_da830() ? 0 : + (clk_get(DAVINCI_DDR_CLKID) / 1000000); + gd->bd->bi_dsp_freq = 0; + return 0; +} + +#else /* CONFIG_SOC_DA8XX */ + +static unsigned pll_div(volatile void *pllbase, unsigned offset) +{ + u32 div; + + div = REG(pllbase + offset); + return (div & BIT(15)) ? (1 + (div & 0x1f)) : 1; +} + +static inline unsigned pll_prediv(volatile void *pllbase) +{ +#ifdef CONFIG_SOC_DM355 + /* this register read seems to fail on pll0 */ + if (pllbase == (volatile void *)DAVINCI_PLL_CNTRL0_BASE) + return 8; + else + return pll_div(pllbase, PLLC_PREDIV); +#elif defined(CONFIG_SOC_DM365) + return pll_div(pllbase, PLLC_PREDIV); +#endif + return 1; +} + +static inline unsigned pll_postdiv(volatile void *pllbase) +{ +#if defined(CONFIG_SOC_DM355) || defined(CONFIG_SOC_DM365) + return pll_div(pllbase, PLLC_POSTDIV); +#elif defined(CONFIG_SOC_DM6446) + if (pllbase == (volatile void *)DAVINCI_PLL_CNTRL0_BASE) + return pll_div(pllbase, PLLC_POSTDIV); +#endif + return 1; +} + +static unsigned pll_sysclk_mhz(unsigned pll_addr, unsigned div) +{ + volatile void *pllbase = (volatile void *) pll_addr; +#ifdef CONFIG_SOC_DM646X + unsigned base = CONFIG_REFCLK_FREQ / 1000; +#else + unsigned base = CONFIG_SYS_HZ_CLOCK / 1000; +#endif + + /* the PLL might be bypassed */ + if (readl(pllbase + PLLC_PLLCTL) & BIT(0)) { + base /= pll_prediv(pllbase); +#if defined(CONFIG_SOC_DM365) + base *= 2 * (readl(pllbase + PLLC_PLLM) & 0x0ff); +#else + base *= 1 + (REG(pllbase + PLLC_PLLM) & 0x0ff); +#endif + base /= pll_postdiv(pllbase); + } + return DIV_ROUND_UP(base, 1000 * pll_div(pllbase, div)); +} + +#ifdef DAVINCI_DM6467EVM +unsigned int davinci_arm_clk_get() +{ + return pll_sysclk_mhz(DAVINCI_PLL_CNTRL0_BASE, ARM_PLLDIV) * 1000000; +} +#endif + +#if defined(CONFIG_SOC_DM365) +unsigned int davinci_clk_get(unsigned int div) +{ + return pll_sysclk_mhz(DAVINCI_PLL_CNTRL0_BASE, div) * 1000000; +} +#endif + +int set_cpu_clk_info(void) +{ + unsigned int pllbase = DAVINCI_PLL_CNTRL0_BASE; +#if defined(CONFIG_SOC_DM365) + pllbase = DAVINCI_PLL_CNTRL1_BASE; +#endif + gd->bd->bi_arm_freq = pll_sysclk_mhz(pllbase, ARM_PLLDIV); + +#ifdef DSP_PLLDIV + gd->bd->bi_dsp_freq = + pll_sysclk_mhz(DAVINCI_PLL_CNTRL0_BASE, DSP_PLLDIV); +#else + gd->bd->bi_dsp_freq = 0; +#endif + + pllbase = DAVINCI_PLL_CNTRL1_BASE; +#if defined(CONFIG_SOC_DM365) + pllbase = DAVINCI_PLL_CNTRL0_BASE; +#endif + gd->bd->bi_ddr_freq = pll_sysclk_mhz(pllbase, DDR_PLLDIV) / 2; + + return 0; +} + +#endif /* !CONFIG_SOC_DA8XX */ + +/* + * Initializes on-chip ethernet controllers. + * to override, implement board_eth_init() + */ +int cpu_eth_init(bd_t *bis) +{ +#if defined(CONFIG_DRIVER_TI_EMAC) + davinci_emac_initialize(); +#endif + return 0; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/da830_pinmux.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/da830_pinmux.c new file mode 100644 index 000000000..edaab4532 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/da830_pinmux.c @@ -0,0 +1,139 @@ +/* + * Pinmux configurations for the DA830 SoCs + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/davinci_misc.h> +#include <asm/arch/hardware.h> +#include <asm/arch/pinmux_defs.h> + +/* SPI0 pin muxer settings */ +const struct pinmux_config spi0_pins_base[] = { + { pinmux(7), 1, 3 }, /* SPI0_SOMI */ + { pinmux(7), 1, 4 }, /* SPI0_SIMO */ + { pinmux(7), 1, 6 } /* SPI0_CLK */ +}; + +const struct pinmux_config spi0_pins_scs0[] = { + { pinmux(7), 1, 7 } /* SPI0_SCS[0] */ +}; + +const struct pinmux_config spi0_pins_ena[] = { + { pinmux(7), 1, 5 } /* SPI0_ENA */ +}; + +/* NAND pin muxer settings */ +const struct pinmux_config emifa_pins_cs0[] = { + { pinmux(18), 1, 2 } /* EMA_CS[0] */ +}; + +const struct pinmux_config emifa_pins_cs2[] = { + { pinmux(18), 1, 3 } /* EMA_CS[2] */ +}; + +const struct pinmux_config emifa_pins_cs3[] = { + { pinmux(18), 1, 4 } /* EMA_CS[3] */ +}; + +#ifdef CONFIG_USE_NAND +const struct pinmux_config emifa_pins[] = { + { pinmux(13), 1, 6 }, /* EMA_D[0] */ + { pinmux(13), 1, 7 }, /* EMA_D[1] */ + { pinmux(14), 1, 0 }, /* EMA_D[2] */ + { pinmux(14), 1, 1 }, /* EMA_D[3] */ + { pinmux(14), 1, 2 }, /* EMA_D[4] */ + { pinmux(14), 1, 3 }, /* EMA_D[5] */ + { pinmux(14), 1, 4 }, /* EMA_D[6] */ + { pinmux(14), 1, 5 }, /* EMA_D[7] */ + { pinmux(14), 1, 6 }, /* EMA_D[8] */ + { pinmux(14), 1, 7 }, /* EMA_D[9] */ + { pinmux(15), 1, 0 }, /* EMA_D[10] */ + { pinmux(15), 1, 1 }, /* EMA_D[11] */ + { pinmux(15), 1, 2 }, /* EMA_D[12] */ + { pinmux(15), 1, 3 }, /* EMA_D[13] */ + { pinmux(15), 1, 4 }, /* EMA_D[14] */ + { pinmux(15), 1, 5 }, /* EMA_D[15] */ + { pinmux(15), 1, 6 }, /* EMA_A[0] */ + { pinmux(15), 1, 7 }, /* EMA_A[1] */ + { pinmux(16), 1, 0 }, /* EMA_A[2] */ + { pinmux(16), 1, 1 }, /* EMA_A[3] */ + { pinmux(16), 1, 2 }, /* EMA_A[4] */ + { pinmux(16), 1, 3 }, /* EMA_A[5] */ + { pinmux(16), 1, 4 }, /* EMA_A[6] */ + { pinmux(16), 1, 5 }, /* EMA_A[7] */ + { pinmux(16), 1, 6 }, /* EMA_A[8] */ + { pinmux(16), 1, 7 }, /* EMA_A[9] */ + { pinmux(17), 1, 0 }, /* EMA_A[10] */ + { pinmux(17), 1, 1 }, /* EMA_A[11] */ + { pinmux(17), 1, 2 }, /* EMA_A[12] */ + { pinmux(17), 1, 3 }, /* EMA_BA[1] */ + { pinmux(17), 1, 4 }, /* EMA_BA[0] */ + { pinmux(17), 1, 5 }, /* EMA_CLK */ + { pinmux(17), 1, 6 }, /* EMA_SDCKE */ + { pinmux(17), 1, 7 }, /* EMA_CAS */ + { pinmux(18), 1, 0 }, /* EMA_CAS */ + { pinmux(18), 1, 1 }, /* EMA_WE */ + { pinmux(18), 1, 5 }, /* EMA_OE */ + { pinmux(18), 1, 6 }, /* EMA_WE_DQM[1] */ + { pinmux(18), 1, 7 }, /* EMA_WE_DQM[0] */ + { pinmux(10), 1, 0 } /* Tristate */ +}; +#endif + +/* EMAC PHY interface pins */ +const struct pinmux_config emac_pins_rmii[] = { + { pinmux(10), 2, 1 }, /* RMII_TXD[0] */ + { pinmux(10), 2, 2 }, /* RMII_TXD[1] */ + { pinmux(10), 2, 3 }, /* RMII_TXEN */ + { pinmux(10), 2, 4 }, /* RMII_CRS_DV */ + { pinmux(10), 2, 5 }, /* RMII_RXD[0] */ + { pinmux(10), 2, 6 }, /* RMII_RXD[1] */ + { pinmux(10), 2, 7 } /* RMII_RXER */ +}; + +const struct pinmux_config emac_pins_mdio[] = { + { pinmux(11), 2, 0 }, /* MDIO_CLK */ + { pinmux(11), 2, 1 } /* MDIO_D */ +}; + +const struct pinmux_config emac_pins_rmii_clk_source[] = { + { pinmux(9), 0, 5 } /* ref.clk from external source */ +}; + +/* UART2 pin muxer settings */ +const struct pinmux_config uart2_pins_txrx[] = { + { pinmux(8), 2, 7 }, /* UART2_RXD */ + { pinmux(9), 2, 0 } /* UART2_TXD */ +}; + +/* I2C0 pin muxer settings */ +const struct pinmux_config i2c0_pins[] = { + { pinmux(8), 2, 3 }, /* I2C0_SDA */ + { pinmux(8), 2, 4 } /* I2C0_SCL */ +}; + +/* USB0_DRVVBUS pin muxer settings */ +const struct pinmux_config usb_pins[] = { + { pinmux(9), 1, 1 } /* USB0_DRVVBUS */ +}; + +#ifdef CONFIG_DAVINCI_MMC +/* MMC0 pin muxer settings */ +const struct pinmux_config mmc0_pins_8bit[] = { + { pinmux(15), 2, 7 }, /* MMCSD0_CLK */ + { pinmux(16), 2, 0 }, /* MMCSD0_CMD */ + { pinmux(13), 2, 6 }, /* MMCSD0_DAT_0 */ + { pinmux(13), 2, 7 }, /* MMCSD0_DAT_1 */ + { pinmux(14), 2, 0 }, /* MMCSD0_DAT_2 */ + { pinmux(14), 2, 1 }, /* MMCSD0_DAT_3 */ + { pinmux(14), 2, 2 }, /* MMCSD0_DAT_4 */ + { pinmux(14), 2, 3 }, /* MMCSD0_DAT_5 */ + { pinmux(14), 2, 4 }, /* MMCSD0_DAT_6 */ + { pinmux(14), 2, 5 } /* MMCSD0_DAT_7 */ + /* DA830 supports 8-bit mode */ +}; +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/da850_lowlevel.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/da850_lowlevel.c new file mode 100644 index 000000000..b91e948ce --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/da850_lowlevel.c @@ -0,0 +1,313 @@ +/* + * SoC-specific lowlevel code for DA850 + * + * Copyright (C) 2011 + * Heiko Schocher, DENX Software Engineering, hs@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <nand.h> +#include <ns16550.h> +#include <post.h> +#include <asm/arch/da850_lowlevel.h> +#include <asm/arch/hardware.h> +#include <asm/arch/davinci_misc.h> +#include <asm/arch/ddr2_defs.h> +#include <asm/arch/emif_defs.h> +#include <asm/arch/pll_defs.h> + +void davinci_enable_uart0(void) +{ + lpsc_on(DAVINCI_LPSC_UART0); + + /* Bringup UART0 out of reset */ + REG(UART0_PWREMU_MGMT) = 0x00006001; +} + +#if defined(CONFIG_SYS_DA850_PLL_INIT) +static void da850_waitloop(unsigned long loopcnt) +{ + unsigned long i; + + for (i = 0; i < loopcnt; i++) + asm(" NOP"); +} + +static int da850_pll_init(struct davinci_pllc_regs *reg, unsigned long pllmult) +{ + if (reg == davinci_pllc0_regs) + /* Unlock PLL registers. */ + clrbits_le32(&davinci_syscfg_regs->cfgchip0, PLL_MASTER_LOCK); + + /* + * Set PLLENSRC '0',bit 5, PLL Enable(PLLEN) selection is controlled + * through MMR + */ + clrbits_le32(®->pllctl, PLLCTL_PLLENSRC); + /* PLLCTL.EXTCLKSRC bit 9 should be left at 0 for Freon */ + clrbits_le32(®->pllctl, PLLCTL_EXTCLKSRC); + + /* Set PLLEN=0 => PLL BYPASS MODE */ + clrbits_le32(®->pllctl, PLLCTL_PLLEN); + + da850_waitloop(150); + + if (reg == davinci_pllc0_regs) { + /* + * Select the Clock Mode bit 8 as External Clock or On Chip + * Oscilator + */ + dv_maskbits(®->pllctl, ~PLLCTL_RES_9); + setbits_le32(®->pllctl, + (CONFIG_SYS_DV_CLKMODE << PLLCTL_CLOCK_MODE_SHIFT)); + } + + /* Clear PLLRST bit to reset the PLL */ + clrbits_le32(®->pllctl, PLLCTL_PLLRST); + + /* Disable the PLL output */ + setbits_le32(®->pllctl, PLLCTL_PLLDIS); + + /* PLL initialization sequence */ + /* + * Power up the PLL- PWRDN bit set to 0 to bring the PLL out of + * power down bit + */ + clrbits_le32(®->pllctl, PLLCTL_PLLPWRDN); + + /* Enable the PLL from Disable Mode PLLDIS bit to 0 */ + clrbits_le32(®->pllctl, PLLCTL_PLLDIS); + +#if defined(CONFIG_SYS_DA850_PLL0_PREDIV) + /* program the prediv */ + if (reg == davinci_pllc0_regs && CONFIG_SYS_DA850_PLL0_PREDIV) + writel((PLL_DIVEN | CONFIG_SYS_DA850_PLL0_PREDIV), + ®->prediv); +#endif + + /* Program the required multiplier value in PLLM */ + writel(pllmult, ®->pllm); + + /* program the postdiv */ + if (reg == davinci_pllc0_regs) + writel((PLL_POSTDEN | CONFIG_SYS_DA850_PLL0_POSTDIV), + ®->postdiv); + else + writel((PLL_POSTDEN | CONFIG_SYS_DA850_PLL1_POSTDIV), + ®->postdiv); + + /* + * Check for the GOSTAT bit in PLLSTAT to clear to 0 to indicate that + * no GO operation is currently in progress + */ + while ((readl(®->pllstat) & PLLCMD_GOSTAT) == PLLCMD_GOSTAT) + ; + + if (reg == davinci_pllc0_regs) { + writel(CONFIG_SYS_DA850_PLL0_PLLDIV1, ®->plldiv1); + writel(CONFIG_SYS_DA850_PLL0_PLLDIV2, ®->plldiv2); + writel(CONFIG_SYS_DA850_PLL0_PLLDIV3, ®->plldiv3); + writel(CONFIG_SYS_DA850_PLL0_PLLDIV4, ®->plldiv4); + writel(CONFIG_SYS_DA850_PLL0_PLLDIV5, ®->plldiv5); + writel(CONFIG_SYS_DA850_PLL0_PLLDIV6, ®->plldiv6); + writel(CONFIG_SYS_DA850_PLL0_PLLDIV7, ®->plldiv7); + } else { + writel(CONFIG_SYS_DA850_PLL1_PLLDIV1, ®->plldiv1); + writel(CONFIG_SYS_DA850_PLL1_PLLDIV2, ®->plldiv2); + writel(CONFIG_SYS_DA850_PLL1_PLLDIV3, ®->plldiv3); + } + + /* + * Set the GOSET bit in PLLCMD to 1 to initiate a new divider + * transition. + */ + setbits_le32(®->pllcmd, PLLCMD_GOSTAT); + + /* + * Wait for the GOSTAT bit in PLLSTAT to clear to 0 + * (completion of phase alignment). + */ + while ((readl(®->pllstat) & PLLCMD_GOSTAT) == PLLCMD_GOSTAT) + ; + + /* Wait for PLL to reset properly. See PLL spec for PLL reset time */ + da850_waitloop(200); + + /* Set the PLLRST bit in PLLCTL to 1 to bring the PLL out of reset */ + setbits_le32(®->pllctl, PLLCTL_PLLRST); + + /* Wait for PLL to lock. See PLL spec for PLL lock time */ + da850_waitloop(2400); + + /* + * Set the PLLEN bit in PLLCTL to 1 to remove the PLL from bypass + * mode + */ + setbits_le32(®->pllctl, PLLCTL_PLLEN); + + + /* + * clear EMIFA and EMIFB clock source settings, let them + * run off SYSCLK + */ + if (reg == davinci_pllc0_regs) + dv_maskbits(&davinci_syscfg_regs->cfgchip3, + ~(PLL_SCSCFG3_DIV45PENA | PLL_SCSCFG3_EMA_CLKSRC)); + + return 0; +} +#endif /* CONFIG_SYS_DA850_PLL_INIT */ + +#if defined(CONFIG_SYS_DA850_DDR_INIT) +static int da850_ddr_setup(void) +{ + unsigned long tmp; + + /* Enable the Clock to DDR2/mDDR */ + lpsc_on(DAVINCI_LPSC_DDR_EMIF); + + tmp = readl(&davinci_syscfg1_regs->vtpio_ctl); + if ((tmp & VTP_POWERDWN) == VTP_POWERDWN) { + /* Begin VTP Calibration */ + clrbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_POWERDWN); + clrbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_LOCK); + setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_CLKRZ); + clrbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_CLKRZ); + setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_CLKRZ); + + /* Polling READY bit to see when VTP calibration is done */ + tmp = readl(&davinci_syscfg1_regs->vtpio_ctl); + while ((tmp & VTP_READY) != VTP_READY) + tmp = readl(&davinci_syscfg1_regs->vtpio_ctl); + + setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_LOCK); + setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_POWERDWN); + } + setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_IOPWRDWN); + writel(CONFIG_SYS_DA850_DDR2_DDRPHYCR, &dv_ddr2_regs_ctrl->ddrphycr); + + if (CONFIG_SYS_DA850_DDR2_SDBCR & (1 << DV_DDR_SDCR_DDR2EN_SHIFT)) { + /* DDR2 */ + clrbits_le32(&davinci_syscfg1_regs->ddr_slew, + (1 << DDR_SLEW_DDR_PDENA_BIT) | + (1 << DDR_SLEW_CMOSEN_BIT)); + } else { + /* MOBILE DDR */ + setbits_le32(&davinci_syscfg1_regs->ddr_slew, + (1 << DDR_SLEW_DDR_PDENA_BIT) | + (1 << DDR_SLEW_CMOSEN_BIT)); + } + + /* + * SDRAM Configuration Register (SDCR): + * First set the BOOTUNLOCK bit to make configuration bits + * writeable. + */ + setbits_le32(&dv_ddr2_regs_ctrl->sdbcr, DV_DDR_BOOTUNLOCK); + + /* + * Write the new value of these bits and clear BOOTUNLOCK. + * At the same time, set the TIMUNLOCK bit to allow changing + * the timing registers + */ + tmp = CONFIG_SYS_DA850_DDR2_SDBCR; + tmp &= ~DV_DDR_BOOTUNLOCK; + tmp |= DV_DDR_TIMUNLOCK; + writel(tmp, &dv_ddr2_regs_ctrl->sdbcr); + + /* write memory configuration and timing */ + if (!(CONFIG_SYS_DA850_DDR2_SDBCR & (1 << DV_DDR_SDCR_DDR2EN_SHIFT))) { + /* MOBILE DDR only*/ + writel(CONFIG_SYS_DA850_DDR2_SDBCR2, + &dv_ddr2_regs_ctrl->sdbcr2); + } + writel(CONFIG_SYS_DA850_DDR2_SDTIMR, &dv_ddr2_regs_ctrl->sdtimr); + writel(CONFIG_SYS_DA850_DDR2_SDTIMR2, &dv_ddr2_regs_ctrl->sdtimr2); + + /* clear the TIMUNLOCK bit and write the value of the CL field */ + tmp &= ~DV_DDR_TIMUNLOCK; + writel(tmp, &dv_ddr2_regs_ctrl->sdbcr); + + /* + * LPMODEN and MCLKSTOPEN must be set! + * Without this bits set, PSC don;t switch states !! + */ + writel(CONFIG_SYS_DA850_DDR2_SDRCR | + (1 << DV_DDR_SRCR_LPMODEN_SHIFT) | + (1 << DV_DDR_SRCR_MCLKSTOPEN_SHIFT), + &dv_ddr2_regs_ctrl->sdrcr); + + /* SyncReset the Clock to EMIF3A SDRAM */ + lpsc_syncreset(DAVINCI_LPSC_DDR_EMIF); + /* Enable the Clock to EMIF3A SDRAM */ + lpsc_on(DAVINCI_LPSC_DDR_EMIF); + + /* disable self refresh */ + clrbits_le32(&dv_ddr2_regs_ctrl->sdrcr, + DV_DDR_SDRCR_LPMODEN | DV_DDR_SDRCR_MCLKSTOPEN); + writel(CONFIG_SYS_DA850_DDR2_PBBPR, &dv_ddr2_regs_ctrl->pbbpr); + + return 0; +} +#endif /* CONFIG_SYS_DA850_DDR_INIT */ + +__attribute__((weak)) +void board_gpio_init(void) +{ + return; +} + +int arch_cpu_init(void) +{ + /* Unlock kick registers */ + writel(DV_SYSCFG_KICK0_UNLOCK, &davinci_syscfg_regs->kick0); + writel(DV_SYSCFG_KICK1_UNLOCK, &davinci_syscfg_regs->kick1); + + dv_maskbits(&davinci_syscfg_regs->suspsrc, + CONFIG_SYS_DA850_SYSCFG_SUSPSRC); + + /* configure pinmux settings */ + if (davinci_configure_pin_mux_items(pinmuxes, pinmuxes_size)) + return 1; + +#if defined(CONFIG_SYS_DA850_PLL_INIT) + /* PLL setup */ + da850_pll_init(davinci_pllc0_regs, CONFIG_SYS_DA850_PLL0_PLLM); + da850_pll_init(davinci_pllc1_regs, CONFIG_SYS_DA850_PLL1_PLLM); +#endif + /* setup CSn config */ +#if defined(CONFIG_SYS_DA850_CS2CFG) + writel(CONFIG_SYS_DA850_CS2CFG, &davinci_emif_regs->ab1cr); +#endif +#if defined(CONFIG_SYS_DA850_CS3CFG) + writel(CONFIG_SYS_DA850_CS3CFG, &davinci_emif_regs->ab2cr); +#endif + + da8xx_configure_lpsc_items(lpsc, lpsc_size); + + /* GPIO setup */ + board_gpio_init(); + + + NS16550_init((NS16550_t)(CONFIG_SYS_NS16550_COM1), + CONFIG_SYS_NS16550_CLK / 16 / CONFIG_BAUDRATE); + + /* + * Fix Power and Emulation Management Register + * see sprufw3a.pdf page 37 Table 24 + */ + writel((DAVINCI_UART_PWREMU_MGMT_FREE | DAVINCI_UART_PWREMU_MGMT_URRST | + DAVINCI_UART_PWREMU_MGMT_UTRST), +#if (CONFIG_SYS_NS16550_COM1 == DAVINCI_UART0_BASE) + &davinci_uart0_ctrl_regs->pwremu_mgmt); +#else + &davinci_uart2_ctrl_regs->pwremu_mgmt); +#endif + +#if defined(CONFIG_SYS_DA850_DDR_INIT) + da850_ddr_setup(); +#endif + + return 0; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/da850_pinmux.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/da850_pinmux.c new file mode 100644 index 000000000..6105f6390 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/da850_pinmux.c @@ -0,0 +1,181 @@ +/* + * Pinmux configurations for the DA850 SoCs + * + * Copyright (C) 2011 OMICRON electronics GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/davinci_misc.h> +#include <asm/arch/hardware.h> +#include <asm/arch/pinmux_defs.h> + +/* SPI pin muxer settings */ +const struct pinmux_config spi1_pins_base[] = { + { pinmux(5), 1, 2 }, /* SPI1_CLK */ + { pinmux(5), 1, 4 }, /* SPI1_SOMI */ + { pinmux(5), 1, 5 }, /* SPI1_SIMO */ +}; + +const struct pinmux_config spi1_pins_scs0[] = { + { pinmux(5), 1, 1 }, /* SPI1_SCS[0] */ +}; + +/* UART pin muxer settings */ +const struct pinmux_config uart0_pins_txrx[] = { + { pinmux(3), 2, 4 }, /* UART0_RXD */ + { pinmux(3), 2, 5 }, /* UART0_TXD */ +}; + +const struct pinmux_config uart0_pins_rtscts[] = { + { pinmux(3), 2, 6 }, + { pinmux(3), 2, 7 }, +}; + +const struct pinmux_config uart1_pins_txrx[] = { + { pinmux(4), 2, 6 }, /* UART1_RXD */ + { pinmux(4), 2, 7 }, /* UART1_TXD */ +}; + +const struct pinmux_config uart2_pins_txrx[] = { + { pinmux(4), 2, 4 }, /* UART2_RXD */ + { pinmux(4), 2, 5 }, /* UART2_TXD */ +}; + +const struct pinmux_config uart2_pins_rtscts[] = { + { pinmux(0), 4, 6 }, /* UART2_RTS */ + { pinmux(0), 4, 7 }, /* UART2_CTS */ +}; + +/* EMAC pin muxer settings*/ +const struct pinmux_config emac_pins_rmii[] = { + { pinmux(14), 8, 2 }, /* RMII_TXD[1] */ + { pinmux(14), 8, 3 }, /* RMII_TXD[0] */ + { pinmux(14), 8, 4 }, /* RMII_TXEN */ + { pinmux(14), 8, 5 }, /* RMII_RXD[1] */ + { pinmux(14), 8, 6 }, /* RMII_RXD[0] */ + { pinmux(14), 8, 7 }, /* RMII_RXER */ + { pinmux(15), 0, 0 }, /* RMII_MHz_50_CLK */ + { pinmux(15), 8, 1 }, /* RMII_CRS_DV */ +}; + +const struct pinmux_config emac_pins_mii[] = { + { pinmux(2), 8, 1 }, /* MII_TXEN */ + { pinmux(2), 8, 2 }, /* MII_TXCLK */ + { pinmux(2), 8, 3 }, /* MII_COL */ + { pinmux(2), 8, 4 }, /* MII_TXD[3] */ + { pinmux(2), 8, 5 }, /* MII_TXD[2] */ + { pinmux(2), 8, 6 }, /* MII_TXD[1] */ + { pinmux(2), 8, 7 }, /* MII_TXD[0] */ + { pinmux(3), 8, 0 }, /* MII_RXCLK */ + { pinmux(3), 8, 1 }, /* MII_RXDV */ + { pinmux(3), 8, 2 }, /* MII_RXER */ + { pinmux(3), 8, 3 }, /* MII_CRS */ + { pinmux(3), 8, 4 }, /* MII_RXD[3] */ + { pinmux(3), 8, 5 }, /* MII_RXD[2] */ + { pinmux(3), 8, 6 }, /* MII_RXD[1] */ + { pinmux(3), 8, 7 }, /* MII_RXD[0] */ +}; + +const struct pinmux_config emac_pins_mdio[] = { + { pinmux(4), 8, 0 }, /* MDIO_CLK */ + { pinmux(4), 8, 1 }, /* MDIO_D */ +}; + +/* I2C pin muxer settings */ +const struct pinmux_config i2c0_pins[] = { + { pinmux(4), 2, 2 }, /* I2C0_SCL */ + { pinmux(4), 2, 3 }, /* I2C0_SDA */ +}; + +const struct pinmux_config i2c1_pins[] = { + { pinmux(4), 4, 4 }, /* I2C1_SCL */ + { pinmux(4), 4, 5 }, /* I2C1_SDA */ +}; + +/* EMIFA pin muxer settings */ +const struct pinmux_config emifa_pins_cs2[] = { + { pinmux(7), 1, 0 }, /* EMA_CS2 */ +}; + +const struct pinmux_config emifa_pins_cs3[] = { + { pinmux(7), 1, 1 }, /* EMA_CS[3] */ +}; + +const struct pinmux_config emifa_pins_cs4[] = { + { pinmux(7), 1, 2 }, /* EMA_CS[4] */ +}; + +const struct pinmux_config emifa_pins_nand[] = { + { pinmux(7), 1, 4 }, /* EMA_WE */ + { pinmux(7), 1, 5 }, /* EMA_OE */ + { pinmux(9), 1, 0 }, /* EMA_D[7] */ + { pinmux(9), 1, 1 }, /* EMA_D[6] */ + { pinmux(9), 1, 2 }, /* EMA_D[5] */ + { pinmux(9), 1, 3 }, /* EMA_D[4] */ + { pinmux(9), 1, 4 }, /* EMA_D[3] */ + { pinmux(9), 1, 5 }, /* EMA_D[2] */ + { pinmux(9), 1, 6 }, /* EMA_D[1] */ + { pinmux(9), 1, 7 }, /* EMA_D[0] */ + { pinmux(12), 1, 5 }, /* EMA_A[2] */ + { pinmux(12), 1, 6 }, /* EMA_A[1] */ +}; + +/* NOR pin muxer settings */ +const struct pinmux_config emifa_pins_nor[] = { + { pinmux(5), 1, 6 }, /* EMA_BA[1] */ + { pinmux(6), 1, 6 }, /* EMA_WAIT[1] */ + { pinmux(7), 1, 4 }, /* EMA_WE */ + { pinmux(7), 1, 5 }, /* EMA_OE */ + { pinmux(8), 1, 0 }, /* EMA_D[15] */ + { pinmux(8), 1, 1 }, /* EMA_D[14] */ + { pinmux(8), 1, 2 }, /* EMA_D[13] */ + { pinmux(8), 1, 3 }, /* EMA_D[12] */ + { pinmux(8), 1, 4 }, /* EMA_D[11] */ + { pinmux(8), 1, 5 }, /* EMA_D[10] */ + { pinmux(8), 1, 6 }, /* EMA_D[9] */ + { pinmux(8), 1, 7 }, /* EMA_D[8] */ + { pinmux(9), 1, 0 }, /* EMA_D[7] */ + { pinmux(9), 1, 1 }, /* EMA_D[6] */ + { pinmux(9), 1, 2 }, /* EMA_D[5] */ + { pinmux(9), 1, 3 }, /* EMA_D[4] */ + { pinmux(9), 1, 4 }, /* EMA_D[3] */ + { pinmux(9), 1, 5 }, /* EMA_D[2] */ + { pinmux(9), 1, 6 }, /* EMA_D[1] */ + { pinmux(9), 1, 7 }, /* EMA_D[0] */ + { pinmux(10), 1, 1 }, /* EMA_A[22] */ + { pinmux(10), 1, 2 }, /* EMA_A[21] */ + { pinmux(10), 1, 3 }, /* EMA_A[20] */ + { pinmux(10), 1, 4 }, /* EMA_A[19] */ + { pinmux(10), 1, 5 }, /* EMA_A[18] */ + { pinmux(10), 1, 6 }, /* EMA_A[17] */ + { pinmux(10), 1, 7 }, /* EMA_A[16] */ + { pinmux(11), 1, 0 }, /* EMA_A[15] */ + { pinmux(11), 1, 1 }, /* EMA_A[14] */ + { pinmux(11), 1, 2 }, /* EMA_A[13] */ + { pinmux(11), 1, 3 }, /* EMA_A[12] */ + { pinmux(11), 1, 4 }, /* EMA_A[11] */ + { pinmux(11), 1, 5 }, /* EMA_A[10] */ + { pinmux(11), 1, 6 }, /* EMA_A[9] */ + { pinmux(11), 1, 7 }, /* EMA_A[8] */ + { pinmux(12), 1, 0 }, /* EMA_A[7] */ + { pinmux(12), 1, 1 }, /* EMA_A[6] */ + { pinmux(12), 1, 2 }, /* EMA_A[5] */ + { pinmux(12), 1, 3 }, /* EMA_A[4] */ + { pinmux(12), 1, 4 }, /* EMA_A[3] */ + { pinmux(12), 1, 5 }, /* EMA_A[2] */ + { pinmux(12), 1, 6 }, /* EMA_A[1] */ + { pinmux(12), 1, 7 }, /* EMA_A[0] */ +}; + +/* MMC0 pin muxer settings */ +const struct pinmux_config mmc0_pins[] = { + { pinmux(10), 2, 0 }, /* MMCSD0_CLK */ + { pinmux(10), 2, 1 }, /* MMCSD0_CMD */ + { pinmux(10), 2, 2 }, /* MMCSD0_DAT_0 */ + { pinmux(10), 2, 3 }, /* MMCSD0_DAT_1 */ + { pinmux(10), 2, 4 }, /* MMCSD0_DAT_2 */ + { pinmux(10), 2, 5 }, /* MMCSD0_DAT_3 */ + /* DA850 supports only 4-bit mode, remaining pins are not configured */ +}; diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dm355.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dm355.c new file mode 100644 index 000000000..f9550a16d --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dm355.c @@ -0,0 +1,30 @@ +/* + * SoC-specific code for tms320dm355 and similar chips + * + * Copyright (C) 2009 David Brownell + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/hardware.h> + + +void davinci_enable_uart0(void) +{ + lpsc_on(DAVINCI_LPSC_UART0); + + /* Bringup UART0 out of reset */ + REG(UART0_PWREMU_MGMT) = 0x00006001; +} + + +#ifdef CONFIG_SYS_I2C_DAVINCI +void davinci_enable_i2c(void) +{ + lpsc_on(DAVINCI_LPSC_I2C); + + /* Enable I2C pin Mux */ + REG(PINMUX3) |= (1 << 20) | (1 << 19); +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dm365.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dm365.c new file mode 100644 index 000000000..f6ca527e7 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dm365.c @@ -0,0 +1,20 @@ +/* + * SoC-specific code for tms320dm365 and similar chips + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/hardware.h> + +void davinci_enable_uart0(void) +{ + lpsc_on(DAVINCI_LPSC_UART0); +} + +#ifdef CONFIG_SYS_I2C_DAVINCI +void davinci_enable_i2c(void) +{ + lpsc_on(DAVINCI_LPSC_I2C); +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dm365_lowlevel.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dm365_lowlevel.c new file mode 100644 index 000000000..ee096fe72 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dm365_lowlevel.c @@ -0,0 +1,459 @@ +/* + * SoC-specific lowlevel code for tms320dm365 and similar chips + * Actually used for booting from NAND with nand_spl. + * + * Copyright (C) 2011 + * Heiko Schocher, DENX Software Engineering, hs@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <nand.h> +#include <ns16550.h> +#include <post.h> +#include <asm/arch/dm365_lowlevel.h> +#include <asm/arch/hardware.h> + +void dm365_waitloop(unsigned long loopcnt) +{ + unsigned long i; + + for (i = 0; i < loopcnt; i++) + asm(" NOP"); +} + +int dm365_pll1_init(unsigned long pllmult, unsigned long prediv) +{ + unsigned int clksrc = 0x0; + + /* Power up the PLL */ + clrbits_le32(&dv_pll0_regs->pllctl, PLLCTL_PLLPWRDN); + + clrbits_le32(&dv_pll0_regs->pllctl, PLLCTL_RES_9); + setbits_le32(&dv_pll0_regs->pllctl, + clksrc << PLLCTL_CLOCK_MODE_SHIFT); + + /* + * Set PLLENSRC '0', PLL Enable(PLLEN) selection is controlled + * through MMR + */ + clrbits_le32(&dv_pll0_regs->pllctl, PLLCTL_PLLENSRC); + + /* Set PLLEN=0 => PLL BYPASS MODE */ + clrbits_le32(&dv_pll0_regs->pllctl, PLLCTL_PLLEN); + + dm365_waitloop(150); + + /* PLLRST=1(reset assert) */ + setbits_le32(&dv_pll0_regs->pllctl, PLLCTL_PLLRST); + + dm365_waitloop(300); + + /*Bring PLL out of Reset*/ + clrbits_le32(&dv_pll0_regs->pllctl, PLLCTL_PLLRST); + + /* Program the Multiper and Pre-Divider for PLL1 */ + writel(pllmult, &dv_pll0_regs->pllm); + writel(prediv, &dv_pll0_regs->prediv); + + /* Assert TENABLE = 1, TENABLEDIV = 1, TINITZ = 1 */ + writel(PLLSECCTL_STOPMODE | PLLSECCTL_TENABLEDIV | PLLSECCTL_TENABLE | + PLLSECCTL_TINITZ, &dv_pll0_regs->secctl); + /* Assert TENABLE = 1, TENABLEDIV = 1, TINITZ = 0 */ + writel(PLLSECCTL_STOPMODE | PLLSECCTL_TENABLEDIV | PLLSECCTL_TENABLE, + &dv_pll0_regs->secctl); + /* Assert TENABLE = 0, TENABLEDIV = 0, TINITZ = 0 */ + writel(PLLSECCTL_STOPMODE, &dv_pll0_regs->secctl); + /* Assert TENABLE = 0, TENABLEDIV = 0, TINITZ = 1 */ + writel(PLLSECCTL_STOPMODE | PLLSECCTL_TINITZ, &dv_pll0_regs->secctl); + + /* Program the PostDiv for PLL1 */ + writel(PLL_POSTDEN, &dv_pll0_regs->postdiv); + + /* Post divider setting for PLL1 */ + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV1, &dv_pll0_regs->plldiv1); + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV2, &dv_pll0_regs->plldiv2); + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV3, &dv_pll0_regs->plldiv3); + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV4, &dv_pll0_regs->plldiv4); + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV5, &dv_pll0_regs->plldiv5); + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV6, &dv_pll0_regs->plldiv6); + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV7, &dv_pll0_regs->plldiv7); + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV8, &dv_pll0_regs->plldiv8); + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV9, &dv_pll0_regs->plldiv9); + + dm365_waitloop(300); + + /* Set the GOSET bit */ + writel(PLLCMD_GOSET, &dv_pll0_regs->pllcmd); /* Go */ + + dm365_waitloop(300); + + /* Wait for PLL to LOCK */ + while (!((readl(&dv_sys_module_regs->pll0_config) & PLL0_LOCK) + == PLL0_LOCK)) + ; + + /* Enable the PLL Bit of PLLCTL*/ + setbits_le32(&dv_pll0_regs->pllctl, PLLCTL_PLLEN); + + return 0; +} + +int dm365_pll2_init(unsigned long pllm, unsigned long prediv) +{ + unsigned int clksrc = 0x0; + + /* Power up the PLL*/ + clrbits_le32(&dv_pll1_regs->pllctl, PLLCTL_PLLPWRDN); + + /* + * Select the Clock Mode as Onchip Oscilator or External Clock on + * MXI pin + * VDB has input on MXI pin + */ + clrbits_le32(&dv_pll1_regs->pllctl, PLLCTL_RES_9); + setbits_le32(&dv_pll1_regs->pllctl, + clksrc << PLLCTL_CLOCK_MODE_SHIFT); + + /* + * Set PLLENSRC '0', PLL Enable(PLLEN) selection is controlled + * through MMR + */ + clrbits_le32(&dv_pll1_regs->pllctl, PLLCTL_PLLENSRC); + + /* Set PLLEN=0 => PLL BYPASS MODE */ + clrbits_le32(&dv_pll1_regs->pllctl, PLLCTL_PLLEN); + + dm365_waitloop(50); + + /* PLLRST=1(reset assert) */ + setbits_le32(&dv_pll1_regs->pllctl, PLLCTL_PLLRST); + + dm365_waitloop(300); + + /* Bring PLL out of Reset */ + clrbits_le32(&dv_pll1_regs->pllctl, PLLCTL_PLLRST); + + /* Program the Multiper and Pre-Divider for PLL2 */ + writel(pllm, &dv_pll1_regs->pllm); + writel(prediv, &dv_pll1_regs->prediv); + + writel(PLL_POSTDEN, &dv_pll1_regs->postdiv); + + /* Assert TENABLE = 1, TENABLEDIV = 1, TINITZ = 1 */ + writel(PLLSECCTL_STOPMODE | PLLSECCTL_TENABLEDIV | PLLSECCTL_TENABLE | + PLLSECCTL_TINITZ, &dv_pll1_regs->secctl); + /* Assert TENABLE = 1, TENABLEDIV = 1, TINITZ = 0 */ + writel(PLLSECCTL_STOPMODE | PLLSECCTL_TENABLEDIV | PLLSECCTL_TENABLE, + &dv_pll1_regs->secctl); + /* Assert TENABLE = 0, TENABLEDIV = 0, TINITZ = 0 */ + writel(PLLSECCTL_STOPMODE, &dv_pll1_regs->secctl); + /* Assert TENABLE = 0, TENABLEDIV = 0, TINITZ = 1 */ + writel(PLLSECCTL_STOPMODE | PLLSECCTL_TINITZ, &dv_pll1_regs->secctl); + + /* Post divider setting for PLL2 */ + writel(CONFIG_SYS_DM36x_PLL2_PLLDIV1, &dv_pll1_regs->plldiv1); + writel(CONFIG_SYS_DM36x_PLL2_PLLDIV2, &dv_pll1_regs->plldiv2); + writel(CONFIG_SYS_DM36x_PLL2_PLLDIV3, &dv_pll1_regs->plldiv3); + writel(CONFIG_SYS_DM36x_PLL2_PLLDIV4, &dv_pll1_regs->plldiv4); + writel(CONFIG_SYS_DM36x_PLL2_PLLDIV5, &dv_pll1_regs->plldiv5); + + /* GoCmd for PostDivider to take effect */ + writel(PLLCMD_GOSET, &dv_pll1_regs->pllcmd); + + dm365_waitloop(150); + + /* Wait for PLL to LOCK */ + while (!((readl(&dv_sys_module_regs->pll1_config) & PLL1_LOCK) + == PLL1_LOCK)) + ; + + dm365_waitloop(4100); + + /* Enable the PLL2 */ + setbits_le32(&dv_pll1_regs->pllctl, PLLCTL_PLLEN); + + /* do this after PLL's have been set up */ + writel(CONFIG_SYS_DM36x_PERI_CLK_CTRL, + &dv_sys_module_regs->peri_clkctl); + + return 0; +} + +int dm365_ddr_setup(void) +{ + lpsc_on(DAVINCI_LPSC_DDR_EMIF); + clrbits_le32(&dv_sys_module_regs->vtpiocr, + VPTIO_IOPWRDN | VPTIO_CLRZ | VPTIO_LOCK | VPTIO_PWRDN); + + /* Set bit CLRZ (bit 13) */ + setbits_le32(&dv_sys_module_regs->vtpiocr, VPTIO_CLRZ); + + /* Check VTP READY Status */ + while (!(readl(&dv_sys_module_regs->vtpiocr) & VPTIO_RDY)) + ; + + /* Set bit VTP_IOPWRDWN bit 14 for DDR input buffers) */ + setbits_le32(&dv_sys_module_regs->vtpiocr, VPTIO_IOPWRDN); + + /* Set bit LOCK(bit7) */ + setbits_le32(&dv_sys_module_regs->vtpiocr, VPTIO_LOCK); + + /* + * Powerdown VTP as it is locked (bit 6) + * Set bit VTP_IOPWRDWN bit 14 for DDR input buffers) + */ + setbits_le32(&dv_sys_module_regs->vtpiocr, + VPTIO_IOPWRDN | VPTIO_PWRDN); + + /* Wait for calibration to complete */ + dm365_waitloop(150); + + /* Set the DDR2 to synreset, then enable it again */ + lpsc_syncreset(DAVINCI_LPSC_DDR_EMIF); + lpsc_on(DAVINCI_LPSC_DDR_EMIF); + + writel(CONFIG_SYS_DM36x_DDR2_DDRPHYCR, &dv_ddr2_regs_ctrl->ddrphycr); + + /* Program SDRAM Bank Config Register */ + writel((CONFIG_SYS_DM36x_DDR2_SDBCR | DV_DDR_BOOTUNLOCK), + &dv_ddr2_regs_ctrl->sdbcr); + writel((CONFIG_SYS_DM36x_DDR2_SDBCR | DV_DDR_TIMUNLOCK), + &dv_ddr2_regs_ctrl->sdbcr); + + /* Program SDRAM Timing Control Register1 */ + writel(CONFIG_SYS_DM36x_DDR2_SDTIMR, &dv_ddr2_regs_ctrl->sdtimr); + /* Program SDRAM Timing Control Register2 */ + writel(CONFIG_SYS_DM36x_DDR2_SDTIMR2, &dv_ddr2_regs_ctrl->sdtimr2); + + writel(CONFIG_SYS_DM36x_DDR2_PBBPR, &dv_ddr2_regs_ctrl->pbbpr); + + writel(CONFIG_SYS_DM36x_DDR2_SDBCR, &dv_ddr2_regs_ctrl->sdbcr); + + /* Program SDRAM Refresh Control Register */ + writel(CONFIG_SYS_DM36x_DDR2_SDRCR, &dv_ddr2_regs_ctrl->sdrcr); + + lpsc_syncreset(DAVINCI_LPSC_DDR_EMIF); + lpsc_on(DAVINCI_LPSC_DDR_EMIF); + + return 0; +} + +static void dm365_vpss_sync_reset(void) +{ + unsigned int PdNum = 0; + + /* VPSS_CLKMD 1:1 */ + setbits_le32(&dv_sys_module_regs->vpss_clkctl, + VPSS_CLK_CTL_VPSS_CLKMD); + + /* LPSC SyncReset DDR Clock Enable */ + writel(((readl(&dv_psc_regs->mdctl[DAVINCI_LPSC_VPSSMASTER]) & + ~PSC_MD_STATE_MSK) | PSC_SYNCRESET), + &dv_psc_regs->mdctl[DAVINCI_LPSC_VPSSMASTER]); + + writel((1 << PdNum), &dv_psc_regs->ptcmd); + + while (!(((readl(&dv_psc_regs->ptstat) >> PdNum) & PSC_GOSTAT) == 0)) + ; + while (!((readl(&dv_psc_regs->mdstat[DAVINCI_LPSC_VPSSMASTER]) & + PSC_MD_STATE_MSK) == PSC_SYNCRESET)) + ; +} + +static void dm365_por_reset(void) +{ + struct davinci_timer *wdog = + (struct davinci_timer *)DAVINCI_WDOG_BASE; + + if (readl(&dv_pll0_regs->rstype) & + (PLL_RSTYPE_POR | PLL_RSTYPE_XWRST)) { + dm365_vpss_sync_reset(); + + writel(DV_TMPBUF_VAL, TMPBUF); + setbits_le32(TMPSTATUS, FLAG_PORRST); + writel(DV_WDT_ENABLE_SYS_RESET, &wdog->na1); + writel(DV_WDT_TRIGGER_SYS_RESET, &wdog->na2); + + while (1); + } +} + +static void dm365_wdt_reset(void) +{ + struct davinci_timer *wdog = + (struct davinci_timer *)DAVINCI_WDOG_BASE; + + if (readl(TMPBUF) != DV_TMPBUF_VAL) { + writel(DV_TMPBUF_VAL, TMPBUF); + setbits_le32(TMPSTATUS, FLAG_PORRST); + setbits_le32(TMPSTATUS, FLAG_FLGOFF); + + dm365_waitloop(100); + + dm365_vpss_sync_reset(); + + writel(DV_WDT_ENABLE_SYS_RESET, &wdog->na1); + writel(DV_WDT_TRIGGER_SYS_RESET, &wdog->na2); + + while (1); + } +} + +static void dm365_wdt_flag_on(void) +{ + /* VPSS_CLKMD 1:2 */ + clrbits_le32(&dv_sys_module_regs->vpss_clkctl, + VPSS_CLK_CTL_VPSS_CLKMD); + writel(0, TMPBUF); + setbits_le32(TMPSTATUS, FLAG_FLGON); +} + +void dm365_psc_init(void) +{ + unsigned char i = 0; + unsigned char lpsc_start; + unsigned char lpsc_end, lpscgroup, lpscmin, lpscmax; + unsigned int PdNum = 0; + + lpscmin = 0; + lpscmax = 2; + + for (lpscgroup = lpscmin; lpscgroup <= lpscmax; lpscgroup++) { + if (lpscgroup == 0) { + /* Enabling LPSC 3 to 28 SCR first */ + lpsc_start = DAVINCI_LPSC_VPSSMSTR; + lpsc_end = DAVINCI_LPSC_TIMER1; + } else if (lpscgroup == 1) { /* Skip locked LPSCs [29-37] */ + lpsc_start = DAVINCI_LPSC_CFG5; + lpsc_end = DAVINCI_LPSC_VPSSMASTER; + } else { + lpsc_start = DAVINCI_LPSC_MJCP; + lpsc_end = DAVINCI_LPSC_HDVICP; + } + + /* NEXT=0x3, Enable LPSC's */ + for (i = lpsc_start; i <= lpsc_end; i++) + setbits_le32(&dv_psc_regs->mdctl[i], PSC_ENABLE); + + /* + * Program goctl to start transition sequence for LPSCs + * CSL_PSC_0_REGS->PTCMD = (1<<PdNum); Kick off Power + * Domain 0 Modules + */ + writel((1 << PdNum), &dv_psc_regs->ptcmd); + + /* + * Wait for GOSTAT = NO TRANSITION from PSC for Powerdomain 0 + */ + while (!(((readl(&dv_psc_regs->ptstat) >> PdNum) & PSC_GOSTAT) + == 0)) + ; + + /* Wait for MODSTAT = ENABLE from LPSC's */ + for (i = lpsc_start; i <= lpsc_end; i++) + while (!((readl(&dv_psc_regs->mdstat[i]) & + PSC_MD_STATE_MSK) == PSC_ENABLE)) + ; + } +} + +static void dm365_emif_init(void) +{ + writel(CONFIG_SYS_DM36x_AWCCR, &davinci_emif_regs->awccr); + writel(CONFIG_SYS_DM36x_AB1CR, &davinci_emif_regs->ab1cr); + + setbits_le32(&davinci_emif_regs->nandfcr, DAVINCI_NANDFCR_CS2NAND); + + writel(CONFIG_SYS_DM36x_AB2CR, &davinci_emif_regs->ab2cr); + + return; +} + +void dm365_pinmux_ctl(unsigned long offset, unsigned long mask, + unsigned long value) +{ + clrbits_le32(&dv_sys_module_regs->pinmux[offset], mask); + setbits_le32(&dv_sys_module_regs->pinmux[offset], (mask & value)); +} + +__attribute__((weak)) +void board_gpio_init(void) +{ + return; +} + +#if defined(CONFIG_POST) +int post_log(char *format, ...) +{ + return 0; +} +#endif + +void dm36x_lowlevel_init(ulong bootflag) +{ + struct davinci_uart_ctrl_regs *davinci_uart_ctrl_regs = + (struct davinci_uart_ctrl_regs *)(CONFIG_SYS_NS16550_COM1 + + DAVINCI_UART_CTRL_BASE); + + /* Mask all interrupts */ + writel(DV_AINTC_INTCTL_IDMODE, &dv_aintc_regs->intctl); + writel(0x0, &dv_aintc_regs->eabase); + writel(0x0, &dv_aintc_regs->eint0); + writel(0x0, &dv_aintc_regs->eint1); + + /* Clear all interrupts */ + writel(0xffffffff, &dv_aintc_regs->fiq0); + writel(0xffffffff, &dv_aintc_regs->fiq1); + writel(0xffffffff, &dv_aintc_regs->irq0); + writel(0xffffffff, &dv_aintc_regs->irq1); + + dm365_por_reset(); + dm365_wdt_reset(); + + /* System PSC setup - enable all */ + dm365_psc_init(); + + /* Setup Pinmux */ + dm365_pinmux_ctl(0, 0xFFFFFFFF, CONFIG_SYS_DM36x_PINMUX0); + dm365_pinmux_ctl(1, 0xFFFFFFFF, CONFIG_SYS_DM36x_PINMUX1); + dm365_pinmux_ctl(2, 0xFFFFFFFF, CONFIG_SYS_DM36x_PINMUX2); + dm365_pinmux_ctl(3, 0xFFFFFFFF, CONFIG_SYS_DM36x_PINMUX3); + dm365_pinmux_ctl(4, 0xFFFFFFFF, CONFIG_SYS_DM36x_PINMUX4); + + /* PLL setup */ + dm365_pll1_init(CONFIG_SYS_DM36x_PLL1_PLLM, + CONFIG_SYS_DM36x_PLL1_PREDIV); + dm365_pll2_init(CONFIG_SYS_DM36x_PLL2_PLLM, + CONFIG_SYS_DM36x_PLL2_PREDIV); + + /* GPIO setup */ + board_gpio_init(); + + NS16550_init((NS16550_t)(CONFIG_SYS_NS16550_COM1), + CONFIG_SYS_NS16550_CLK / 16 / CONFIG_BAUDRATE); + + /* + * Fix Power and Emulation Management Register + * see sprufh2.pdf page 38 Table 22 + */ + writel((DAVINCI_UART_PWREMU_MGMT_FREE | DAVINCI_UART_PWREMU_MGMT_URRST | + DAVINCI_UART_PWREMU_MGMT_UTRST), + &davinci_uart_ctrl_regs->pwremu_mgmt); + + puts("ddr init\n"); + dm365_ddr_setup(); + + puts("emif init\n"); + dm365_emif_init(); + + dm365_wdt_flag_on(); + +#if defined(CONFIG_POST) + /* + * Do memory tests, calls arch_memory_failure_handle() + * if error detected. + */ + memory_post_test(0); +#endif +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dm644x.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dm644x.c new file mode 100644 index 000000000..c58e271e2 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dm644x.c @@ -0,0 +1,81 @@ +/* + * SoC-specific code for tms320dm644x chips + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * Copyright (C) 2008 Lyrtech <www.lyrtech.com> + * Copyright (C) 2004 Texas Instruments. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/hardware.h> + + +#define PINMUX0_EMACEN (1 << 31) +#define PINMUX0_AECS5 (1 << 11) +#define PINMUX0_AECS4 (1 << 10) + +#define PINMUX1_I2C (1 << 7) +#define PINMUX1_UART1 (1 << 1) +#define PINMUX1_UART0 (1 << 0) + + +void davinci_enable_uart0(void) +{ + lpsc_on(DAVINCI_LPSC_UART0); + + /* Bringup UART0 out of reset */ + REG(UART0_PWREMU_MGMT) = 0x00006001; + + /* Enable UART0 MUX lines */ + REG(PINMUX1) |= PINMUX1_UART0; +} + +#ifdef CONFIG_DRIVER_TI_EMAC +void davinci_enable_emac(void) +{ + lpsc_on(DAVINCI_LPSC_EMAC); + lpsc_on(DAVINCI_LPSC_EMAC_WRAPPER); + lpsc_on(DAVINCI_LPSC_MDIO); + + /* Enable GIO3.3V cells used for EMAC */ + REG(VDD3P3V_PWDN) = 0; + + /* Enable EMAC. */ + REG(PINMUX0) |= PINMUX0_EMACEN; +} +#endif + +#ifdef CONFIG_SYS_I2C_DAVINCI +void davinci_enable_i2c(void) +{ + lpsc_on(DAVINCI_LPSC_I2C); + + /* Enable I2C pin Mux */ + REG(PINMUX1) |= PINMUX1_I2C; +} +#endif + +void davinci_errata_workarounds(void) +{ + /* + * Workaround for TMS320DM6446 errata 1.3.22: + * PSC: PTSTAT Register Does Not Clear After Warm/Maximum Reset + * Revision(s) Affected: 1.3 and earlier + */ + REG(PSC_SILVER_BULLET) = 0; + + /* + * Set the PR_OLD_COUNT bits in the Bus Burst Priority Register (PBBPR) + * as suggested in TMS320DM6446 errata 2.1.2: + * + * On DM6446 Silicon Revision 2.1 and earlier, under certain conditions + * low priority modules can occupy the bus and prevent high priority + * modules like the VPSS from getting the required DDR2 throughput. + * A hex value of 0x20 should provide a good ARM (cache enabled) + * performance and still allow good utilization by the VPSS or other + * modules. + */ + REG(VBPR) = 0x20; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dm646x.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dm646x.c new file mode 100644 index 000000000..cfea8300d --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dm646x.c @@ -0,0 +1,26 @@ +/* + * SoC-specific code for TMS320DM646x chips + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <asm/arch/hardware.h> + +void davinci_enable_uart0(void) +{ + lpsc_on(DAVINCI_DM646X_LPSC_UART0); +} + +#ifdef CONFIG_DRIVER_TI_EMAC +void davinci_enable_emac(void) +{ + lpsc_on(DAVINCI_DM646X_LPSC_EMAC); +} +#endif + +#ifdef CONFIG_SYS_I2C_DAVINCI +void davinci_enable_i2c(void) +{ + lpsc_on(DAVINCI_DM646X_LPSC_I2C); +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dp83848.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dp83848.c new file mode 100644 index 000000000..603d507c7 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/dp83848.c @@ -0,0 +1,128 @@ +/* + * National Semiconductor DP83848 PHY Driver for TI DaVinci + * (TMS320DM644x) based boards. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * -------------------------------------------------------- + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <net.h> +#include <dp83848.h> +#include <asm/arch/emac_defs.h> +#include "../../../../../drivers/net/davinci_emac.h" + +#ifdef CONFIG_DRIVER_TI_EMAC + +#ifdef CONFIG_CMD_NET + +int dp83848_is_phy_connected(int phy_addr) +{ + u_int16_t id1, id2; + + if (!davinci_eth_phy_read(phy_addr, DP83848_PHYID1_REG, &id1)) + return(0); + if (!davinci_eth_phy_read(phy_addr, DP83848_PHYID2_REG, &id2)) + return(0); + + if ((id1 == DP83848_PHYID1_OUI) && (id2 == DP83848_PHYID2_OUI)) + return(1); + + return(0); +} + +int dp83848_get_link_speed(int phy_addr) +{ + u_int16_t tmp; + volatile emac_regs* emac = (emac_regs *)EMAC_BASE_ADDR; + + if (!davinci_eth_phy_read(phy_addr, DP83848_STAT_REG, &tmp)) + return(0); + + if (!(tmp & DP83848_LINK_STATUS)) /* link up? */ + return(0); + + if (!davinci_eth_phy_read(phy_addr, DP83848_PHY_STAT_REG, &tmp)) + return(0); + + /* Speed doesn't matter, there is no setting for it in EMAC... */ + if (tmp & DP83848_DUPLEX) { + /* set DM644x EMAC for Full Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | + EMAC_MACCONTROL_FULLDUPLEX_ENABLE; + } else { + /*set DM644x EMAC for Half Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE; + } + + return(1); +} + + +int dp83848_init_phy(int phy_addr) +{ + int ret = 1; + + if (!dp83848_get_link_speed(phy_addr)) { + /* Try another time */ + udelay(100000); + ret = dp83848_get_link_speed(phy_addr); + } + + /* Disable PHY Interrupts */ + davinci_eth_phy_write(phy_addr, DP83848_PHY_INTR_CTRL_REG, 0); + + return(ret); +} + + +int dp83848_auto_negotiate(int phy_addr) +{ + u_int16_t tmp; + + + if (!davinci_eth_phy_read(phy_addr, DP83848_CTL_REG, &tmp)) + return(0); + + /* Restart Auto_negotiation */ + tmp &= ~DP83848_AUTONEG; /* remove autonegotiation enable */ + tmp |= DP83848_ISOLATE; /* Electrically isolate PHY */ + davinci_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp); + + /* Set the Auto_negotiation Advertisement Register + * MII advertising for Next page, 100BaseTxFD and HD, + * 10BaseTFD and HD, IEEE 802.3 + */ + tmp = DP83848_NP | DP83848_TX_FDX | DP83848_TX_HDX | + DP83848_10_FDX | DP83848_10_HDX | DP83848_AN_IEEE_802_3; + davinci_eth_phy_write(phy_addr, DP83848_ANA_REG, tmp); + + + /* Read Control Register */ + if (!davinci_eth_phy_read(phy_addr, DP83848_CTL_REG, &tmp)) + return(0); + + tmp |= DP83848_SPEED_SELECT | DP83848_AUTONEG | DP83848_DUPLEX_MODE; + davinci_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp); + + /* Restart Auto_negotiation */ + tmp |= DP83848_RESTART_AUTONEG; + davinci_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp); + + /*check AutoNegotiate complete */ + udelay(10000); + if (!davinci_eth_phy_read(phy_addr, DP83848_STAT_REG, &tmp)) + return(0); + + if (!(tmp & DP83848_AUTONEG_COMP)) + return(0); + + return (dp83848_get_link_speed(phy_addr)); +} + +#endif /* CONFIG_CMD_NET */ + +#endif /* CONFIG_DRIVER_ETHER */ diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/et1011c.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/et1011c.c new file mode 100644 index 000000000..9d53875b9 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/et1011c.c @@ -0,0 +1,42 @@ +/* + * LSI ET1011C PHY Driver for TI DaVinci(TMS320DM6467) board. + * + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <net.h> +#include <miiphy.h> +#include <asm/arch/emac_defs.h> +#include "../../../../../drivers/net/davinci_emac.h" + +#ifdef CONFIG_DRIVER_TI_EMAC + +#ifdef CONFIG_CMD_NET + +/* LSI PHYSICAL LAYER TRANSCEIVER ET1011C */ + +#define MII_PHY_CONFIG_REG 22 + +/* PHY Config bits */ +#define PHY_SYS_CLK_EN (1 << 4) + +int et1011c_get_link_speed(int phy_addr) +{ + u_int16_t data; + + if (davinci_eth_phy_read(phy_addr, MII_STATUS_REG, &data) && (data & 0x04)) { + davinci_eth_phy_read(phy_addr, MII_PHY_CONFIG_REG, &data); + /* Enable 125MHz clock sourced from PHY */ + davinci_eth_phy_write(phy_addr, MII_PHY_CONFIG_REG, + data | PHY_SYS_CLK_EN); + return (1); + } + return (0); +} + +#endif /* CONFIG_CMD_NET */ + +#endif /* CONFIG_DRIVER_ETHER */ diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/ksz8873.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/ksz8873.c new file mode 100644 index 000000000..4af5dd213 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/ksz8873.c @@ -0,0 +1,53 @@ +/* + * Micrel KSZ8873 PHY Driver for TI DaVinci + * (TMS320DM644x) based boards. + * + * Copyright (C) 2011 Heiko Schocher <hsdenx.de> + * + * based on: + * National Semiconductor DP83848 PHY Driver for TI DaVinci + * (TMS320DM644x) based boards. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * -------------------------------------------------------- + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <miiphy.h> +#include <net.h> +#include <asm/arch/emac_defs.h> +#include <asm/io.h> +#include "../../../../../drivers/net/davinci_emac.h" + +int ksz8873_is_phy_connected(int phy_addr) +{ + u_int16_t dummy; + + return davinci_eth_phy_read(phy_addr, MII_PHYSID1, &dummy); +} + +int ksz8873_get_link_speed(int phy_addr) +{ + emac_regs *emac = (emac_regs *)EMAC_BASE_ADDR; + + /* we always have a link to the switch, 100 FD */ + writel((EMAC_MACCONTROL_MIIEN_ENABLE | + EMAC_MACCONTROL_FULLDUPLEX_ENABLE), + &emac->MACCONTROL); + return 1; +} + + +int ksz8873_init_phy(int phy_addr) +{ + return 1; +} + + +int ksz8873_auto_negotiate(int phy_addr) +{ + return dp83848_get_link_speed(phy_addr); +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/lowlevel_init.S b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/lowlevel_init.S new file mode 100644 index 000000000..e91623497 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/lowlevel_init.S @@ -0,0 +1,693 @@ +/* + * Low-level board setup code for TI DaVinci SoC based boards. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * Partially based on TI sources, original copyrights follow: + */ + +/* + * Board specific setup info + * + * (C) Copyright 2003 + * Texas Instruments, <www.ti.com> + * Kshitij Gupta <Kshitij@ti.com> + * + * Modified for OMAP 1610 H2 board by Nishant Kamat, Jan 2004 + * + * Modified for OMAP 5912 OSK board by Rishi Bhattacharya, Apr 2004 + * + * Modified for DV-EVM board by Rishi Bhattacharya, Apr 2005 + * + * Modified for DV-EVM board by Swaminathan S, Nov 2005 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> + +#define MDSTAT_STATE 0x3f + +.globl lowlevel_init +lowlevel_init: +#ifdef CONFIG_SOC_DM644X + + /*-------------------------------------------------------* + * Mask all IRQs by setting all bits in the EINT default * + *-------------------------------------------------------*/ + mov r1, $0 + ldr r0, =EINT_ENABLE0 + str r1, [r0] + ldr r0, =EINT_ENABLE1 + str r1, [r0] + + /*------------------------------------------------------* + * Put the GEM in reset * + *------------------------------------------------------*/ + + /* Put the GEM in reset */ + ldr r8, PSC_GEM_FLAG_CLEAR + ldr r6, MDCTL_GEM + ldr r7, [r6] + and r7, r7, r8 + str r7, [r6] + + /* Enable the Power Domain Transition Command */ + ldr r6, PTCMD + ldr r7, [r6] + orr r7, r7, $0x02 + str r7, [r6] + + /* Check for Transition Complete(PTSTAT) */ +checkStatClkStopGem: + ldr r6, PTSTAT + ldr r7, [r6] + ands r7, r7, $0x02 + bne checkStatClkStopGem + + /* Check for GEM Reset Completion */ +checkGemStatClkStop: + ldr r6, MDSTAT_GEM + ldr r7, [r6] + ands r7, r7, $0x100 + bne checkGemStatClkStop + + /* Do this for enabling a WDT initiated reset this is a workaround + for a chip bug. Not required under normal situations */ + ldr r6, P1394 + mov r10, $0 + str r10, [r6] + + /*------------------------------------------------------* + * Enable L1 & L2 Memories in Fast mode * + *------------------------------------------------------*/ + ldr r6, DFT_ENABLE + mov r10, $0x01 + str r10, [r6] + + ldr r6, MMARG_BRF0 + ldr r10, MMARG_BRF0_VAL + str r10, [r6] + + ldr r6, DFT_ENABLE + mov r10, $0 + str r10, [r6] + + /*------------------------------------------------------* + * DDR2 PLL Initialization * + *------------------------------------------------------*/ + + /* Select the Clock Mode Depending on the Value written in the Boot Table by the run script */ + mov r10, $0 + ldr r6, PLL2_CTL + ldr r7, PLL_CLKSRC_MASK + ldr r8, [r6] + and r8, r8, r7 + mov r9, r10, lsl $8 + orr r8, r8, r9 + str r8, [r6] + + /* Select the PLLEN source */ + ldr r7, PLL_ENSRC_MASK + and r8, r8, r7 + str r8, [r6] + + /* Bypass the PLL */ + ldr r7, PLL_BYPASS_MASK + and r8, r8, r7 + str r8, [r6] + + /* Wait for few cycles to allow PLLEN Mux switch properly to bypass Clock */ + mov r10, $0x20 +WaitPPL2Loop: + subs r10, r10, $1 + bne WaitPPL2Loop + + /* Reset the PLL */ + ldr r7, PLL_RESET_MASK + and r8, r8, r7 + str r8, [r6] + + /* Power up the PLL */ + ldr r7, PLL_PWRUP_MASK + and r8, r8, r7 + str r8, [r6] + + /* Enable the PLL from Disable Mode */ + ldr r7, PLL_DISABLE_ENABLE_MASK + and r8, r8, r7 + str r8, [r6] + + /* Program the PLL Multiplier */ + ldr r6, PLL2_PLLM + mov r2, $0x17 /* 162 MHz */ + str r2, [r6] + + /* Program the PLL2 Divisor Value */ + ldr r6, PLL2_DIV2 + mov r3, $0x01 + str r3, [r6] + + /* Program the PLL2 Divisor Value */ + ldr r6, PLL2_DIV1 + mov r4, $0x0b /* 54 MHz */ + str r4, [r6] + + /* PLL2 DIV2 MMR */ + ldr r8, PLL2_DIV_MASK + ldr r6, PLL2_DIV2 + ldr r9, [r6] + and r8, r8, r9 + mov r9, $0x01 + mov r9, r9, lsl $15 + orr r8, r8, r9 + str r8, [r6] + + /* Program the GOSET bit to take new divider values */ + ldr r6, PLL2_PLLCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Wait for Done */ + ldr r6, PLL2_PLLSTAT +doneLoop_0: + ldr r7, [r6] + ands r7, r7, $0x01 + bne doneLoop_0 + + /* PLL2 DIV1 MMR */ + ldr r8, PLL2_DIV_MASK + ldr r6, PLL2_DIV1 + ldr r9, [r6] + and r8, r8, r9 + mov r9, $0x01 + mov r9, r9, lsl $15 + orr r8, r8, r9 + str r8, [r6] + + /* Program the GOSET bit to take new divider values */ + ldr r6, PLL2_PLLCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Wait for Done */ + ldr r6, PLL2_PLLSTAT +doneLoop: + ldr r7, [r6] + ands r7, r7, $0x01 + bne doneLoop + + /* Wait for PLL to Reset Properly */ + mov r10, $0x218 +ResetPPL2Loop: + subs r10, r10, $1 + bne ResetPPL2Loop + + /* Bring PLL out of Reset */ + ldr r6, PLL2_CTL + ldr r8, [r6] + orr r8, r8, $0x08 + str r8, [r6] + + /* Wait for PLL to Lock */ + ldr r10, PLL_LOCK_COUNT +PLL2Lock: + subs r10, r10, $1 + bne PLL2Lock + + /* Enable the PLL */ + ldr r6, PLL2_CTL + ldr r8, [r6] + orr r8, r8, $0x01 + str r8, [r6] + + /*------------------------------------------------------* + * Issue Soft Reset to DDR Module * + *------------------------------------------------------*/ + + /* Shut down the DDR2 LPSC Module */ + ldr r8, PSC_FLAG_CLEAR + ldr r6, MDCTL_DDR2 + ldr r7, [r6] + and r7, r7, r8 + orr r7, r7, $0x03 + str r7, [r6] + + /* Enable the Power Domain Transition Command */ + ldr r6, PTCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Check for Transition Complete(PTSTAT) */ +checkStatClkStop: + ldr r6, PTSTAT + ldr r7, [r6] + ands r7, r7, $0x01 + bne checkStatClkStop + + /* Check for DDR2 Controller Enable Completion */ +checkDDRStatClkStop: + ldr r6, MDSTAT_DDR2 + ldr r7, [r6] + and r7, r7, $MDSTAT_STATE + cmp r7, $0x03 + bne checkDDRStatClkStop + + /*------------------------------------------------------* + * Program DDR2 MMRs for 162MHz Setting * + *------------------------------------------------------*/ + + /* Program PHY Control Register */ + ldr r6, DDRCTL + ldr r7, DDRCTL_VAL + str r7, [r6] + + /* Program SDRAM Bank Config Register */ + ldr r6, SDCFG + ldr r7, SDCFG_VAL + str r7, [r6] + + /* Program SDRAM TIM-0 Config Register */ + ldr r6, SDTIM0 + ldr r7, SDTIM0_VAL_162MHz + str r7, [r6] + + /* Program SDRAM TIM-1 Config Register */ + ldr r6, SDTIM1 + ldr r7, SDTIM1_VAL_162MHz + str r7, [r6] + + /* Program the SDRAM Bank Config Control Register */ + ldr r10, MASK_VAL + ldr r8, SDCFG + ldr r9, SDCFG_VAL + and r9, r9, r10 + str r9, [r8] + + /* Program SDRAM SDREF Config Register */ + ldr r6, SDREF + ldr r7, SDREF_VAL + str r7, [r6] + + /*------------------------------------------------------* + * Issue Soft Reset to DDR Module * + *------------------------------------------------------*/ + + /* Issue a Dummy DDR2 read/write */ + ldr r8, DDR2_START_ADDR + ldr r7, DUMMY_VAL + str r7, [r8] + ldr r7, [r8] + + /* Shut down the DDR2 LPSC Module */ + ldr r8, PSC_FLAG_CLEAR + ldr r6, MDCTL_DDR2 + ldr r7, [r6] + and r7, r7, r8 + orr r7, r7, $0x01 + str r7, [r6] + + /* Enable the Power Domain Transition Command */ + ldr r6, PTCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Check for Transition Complete(PTSTAT) */ +checkStatClkStop2: + ldr r6, PTSTAT + ldr r7, [r6] + ands r7, r7, $0x01 + bne checkStatClkStop2 + + /* Check for DDR2 Controller Enable Completion */ +checkDDRStatClkStop2: + ldr r6, MDSTAT_DDR2 + ldr r7, [r6] + and r7, r7, $MDSTAT_STATE + cmp r7, $0x01 + bne checkDDRStatClkStop2 + + /*------------------------------------------------------* + * Turn DDR2 Controller Clocks On * + *------------------------------------------------------*/ + + /* Enable the DDR2 LPSC Module */ + ldr r6, MDCTL_DDR2 + ldr r7, [r6] + orr r7, r7, $0x03 + str r7, [r6] + + /* Enable the Power Domain Transition Command */ + ldr r6, PTCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Check for Transition Complete(PTSTAT) */ +checkStatClkEn2: + ldr r6, PTSTAT + ldr r7, [r6] + ands r7, r7, $0x01 + bne checkStatClkEn2 + + /* Check for DDR2 Controller Enable Completion */ +checkDDRStatClkEn2: + ldr r6, MDSTAT_DDR2 + ldr r7, [r6] + and r7, r7, $MDSTAT_STATE + cmp r7, $0x03 + bne checkDDRStatClkEn2 + + /* DDR Writes and Reads */ + ldr r6, CFGTEST + mov r3, $0x01 + str r3, [r6] + + /*------------------------------------------------------* + * System PLL Initialization * + *------------------------------------------------------*/ + + /* Select the Clock Mode Depending on the Value written in the Boot Table by the run script */ + mov r2, $0 + ldr r6, PLL1_CTL + ldr r7, PLL_CLKSRC_MASK + ldr r8, [r6] + and r8, r8, r7 + mov r9, r2, lsl $8 + orr r8, r8, r9 + str r8, [r6] + + /* Select the PLLEN source */ + ldr r7, PLL_ENSRC_MASK + and r8, r8, r7 + str r8, [r6] + + /* Bypass the PLL */ + ldr r7, PLL_BYPASS_MASK + and r8, r8, r7 + str r8, [r6] + + /* Wait for few cycles to allow PLLEN Mux switch properly to bypass Clock */ + mov r10, $0x20 + +WaitLoop: + subs r10, r10, $1 + bne WaitLoop + + /* Reset the PLL */ + ldr r7, PLL_RESET_MASK + and r8, r8, r7 + str r8, [r6] + + /* Disable the PLL */ + orr r8, r8, $0x10 + str r8, [r6] + + /* Power up the PLL */ + ldr r7, PLL_PWRUP_MASK + and r8, r8, r7 + str r8, [r6] + + /* Enable the PLL from Disable Mode */ + ldr r7, PLL_DISABLE_ENABLE_MASK + and r8, r8, r7 + str r8, [r6] + + /* Program the PLL Multiplier */ + ldr r6, PLL1_PLLM + mov r3, $0x15 /* For 594MHz */ + str r3, [r6] + + /* Wait for PLL to Reset Properly */ + mov r10, $0xff + +ResetLoop: + subs r10, r10, $1 + bne ResetLoop + + /* Bring PLL out of Reset */ + ldr r6, PLL1_CTL + orr r8, r8, $0x08 + str r8, [r6] + + /* Wait for PLL to Lock */ + ldr r10, PLL_LOCK_COUNT + +PLL1Lock: + subs r10, r10, $1 + bne PLL1Lock + + /* Enable the PLL */ + orr r8, r8, $0x01 + str r8, [r6] + + nop + nop + nop + nop + + /*------------------------------------------------------* + * AEMIF configuration for NOR Flash (double check) * + *------------------------------------------------------*/ + ldr r0, _PINMUX0 + ldr r1, _DEV_SETTING + str r1, [r0] + + ldr r0, WAITCFG + ldr r1, WAITCFG_VAL + ldr r2, [r0] + orr r2, r2, r1 + str r2, [r0] + + ldr r0, ACFG3 + ldr r1, ACFG3_VAL + ldr r2, [r0] + and r1, r2, r1 + str r1, [r0] + + ldr r0, ACFG4 + ldr r1, ACFG4_VAL + ldr r2, [r0] + and r1, r2, r1 + str r1, [r0] + + ldr r0, ACFG5 + ldr r1, ACFG5_VAL + ldr r2, [r0] + and r1, r2, r1 + str r1, [r0] + + /*--------------------------------------* + * VTP manual Calibration * + *--------------------------------------*/ + ldr r0, VTPIOCR + ldr r1, VTP_MMR0 + str r1, [r0] + + ldr r0, VTPIOCR + ldr r1, VTP_MMR1 + str r1, [r0] + + /* Wait for 33 VTP CLK cycles. VRP operates at 27 MHz */ + ldr r10, VTP_LOCK_COUNT +VTPLock: + subs r10, r10, $1 + bne VTPLock + + ldr r6, DFT_ENABLE + mov r10, $0x01 + str r10, [r6] + + ldr r6, DDRVTPR + ldr r7, [r6] + mov r8, r7, LSL #32-10 + mov r8, r8, LSR #32-10 /* grab low 10 bits */ + ldr r7, VTP_RECAL + orr r8, r7, r8 + ldr r7, VTP_EN + orr r8, r7, r8 + str r8, [r0] + + + /* Wait for 33 VTP CLK cycles. VRP operates at 27 MHz */ + ldr r10, VTP_LOCK_COUNT +VTP1Lock: + subs r10, r10, $1 + bne VTP1Lock + + ldr r1, [r0] + ldr r2, VTP_MASK + and r2, r1, r2 + str r2, [r0] + + ldr r6, DFT_ENABLE + mov r10, $0 + str r10, [r6] + + /* + * Call board-specific lowlevel init. + * That MUST be present and THAT returns + * back to arch calling code with "mov pc, lr." + */ + b dv_board_init + +.ltorg + +_PINMUX0: + .word 0x01c40000 /* Device Configuration Registers */ +_PINMUX1: + .word 0x01c40004 /* Device Configuration Registers */ + +_DEV_SETTING: + .word 0x00000c1f + +WAITCFG: + .word 0x01e00004 +WAITCFG_VAL: + .word 0 +ACFG3: + .word 0x01e00014 +ACFG3_VAL: + .word 0x3ffffffd +ACFG4: + .word 0x01e00018 +ACFG4_VAL: + .word 0x3ffffffd +ACFG5: + .word 0x01e0001c +ACFG5_VAL: + .word 0x3ffffffd + +MDCTL_DDR2: + .word 0x01c41a34 +MDSTAT_DDR2: + .word 0x01c41834 + +PTCMD: + .word 0x01c41120 +PTSTAT: + .word 0x01c41128 + +EINT_ENABLE0: + .word 0x01c48018 +EINT_ENABLE1: + .word 0x01c4801c + +PSC_FLAG_CLEAR: + .word 0xffffffe0 +PSC_GEM_FLAG_CLEAR: + .word 0xfffffeff + +/* DDR2 MMR & CONFIGURATION VALUES, 162 MHZ clock */ +DDRCTL: + .word 0x200000e4 +DDRCTL_VAL: + .word 0x50006405 +SDREF: + .word 0x2000000c +SDREF_VAL: + .word 0x000005c3 +SDCFG: + .word 0x20000008 +SDCFG_VAL: +#ifdef DDR_4BANKS + .word 0x00178622 +#elif defined DDR_8BANKS + .word 0x00178632 +#else +#error "Unknown DDR configuration!!!" +#endif +SDTIM0: + .word 0x20000010 +SDTIM0_VAL_162MHz: + .word 0x28923211 +SDTIM1: + .word 0x20000014 +SDTIM1_VAL_162MHz: + .word 0x0016c722 +VTPIOCR: + .word 0x200000f0 /* VTP IO Control register */ +DDRVTPR: + .word 0x01c42030 /* DDR VPTR MMR */ +VTP_MMR0: + .word 0x201f +VTP_MMR1: + .word 0xa01f +DFT_ENABLE: + .word 0x01c4004c +VTP_LOCK_COUNT: + .word 0x5b0 +VTP_MASK: + .word 0xffffdfff +VTP_RECAL: + .word 0x08000 +VTP_EN: + .word 0x02000 +CFGTEST: + .word 0x80010000 +MASK_VAL: + .word 0x00000fff + +/* GEM Power Up & LPSC Control Register */ +MDCTL_GEM: + .word 0x01c41a9c +MDSTAT_GEM: + .word 0x01c4189c + +/* For WDT reset chip bug */ +P1394: + .word 0x01c41a20 + +PLL_CLKSRC_MASK: + .word 0xfffffeff /* Mask the Clock Mode bit */ +PLL_ENSRC_MASK: + .word 0xffffffdf /* Select the PLLEN source */ +PLL_BYPASS_MASK: + .word 0xfffffffe /* Put the PLL in BYPASS */ +PLL_RESET_MASK: + .word 0xfffffff7 /* Put the PLL in Reset Mode */ +PLL_PWRUP_MASK: + .word 0xfffffffd /* PLL Power up Mask Bit */ +PLL_DISABLE_ENABLE_MASK: + .word 0xffffffef /* Enable the PLL from Disable */ +PLL_LOCK_COUNT: + .word 0x2000 + +/* PLL1-SYSTEM PLL MMRs */ +PLL1_CTL: + .word 0x01c40900 +PLL1_PLLM: + .word 0x01c40910 + +/* PLL2-SYSTEM PLL MMRs */ +PLL2_CTL: + .word 0x01c40d00 +PLL2_PLLM: + .word 0x01c40d10 +PLL2_DIV1: + .word 0x01c40d18 +PLL2_DIV2: + .word 0x01c40d1c +PLL2_PLLCMD: + .word 0x01c40d38 +PLL2_PLLSTAT: + .word 0x01c40d3c +PLL2_DIV_MASK: + .word 0xffff7fff + +MMARG_BRF0: + .word 0x01c42010 /* BRF margin mode 0 (R/W)*/ +MMARG_BRF0_VAL: + .word 0x00444400 + +DDR2_START_ADDR: + .word 0x80000000 +DUMMY_VAL: + .word 0xa55aa55a +#else /* CONFIG_SOC_DM644X */ + mov pc, lr +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/lxt972.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/lxt972.c new file mode 100644 index 000000000..c482fd937 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/lxt972.c @@ -0,0 +1,113 @@ +/* + * Intel LXT971/LXT972 PHY Driver for TI DaVinci + * (TMS320DM644x) based boards. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * -------------------------------------------------------- + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <net.h> +#include <miiphy.h> +#include <lxt971a.h> +#include <asm/arch/emac_defs.h> +#include "../../../../../drivers/net/davinci_emac.h" + +#ifdef CONFIG_DRIVER_TI_EMAC + +#ifdef CONFIG_CMD_NET + +int lxt972_is_phy_connected(int phy_addr) +{ + u_int16_t id1, id2; + + if (!davinci_eth_phy_read(phy_addr, MII_PHYSID1, &id1)) + return(0); + if (!davinci_eth_phy_read(phy_addr, MII_PHYSID2, &id2)) + return(0); + + if ((id1 == (0x0013)) && ((id2 & 0xfff0) == 0x78e0)) + return(1); + + return(0); +} + +int lxt972_get_link_speed(int phy_addr) +{ + u_int16_t stat1, tmp; + volatile emac_regs *emac = (emac_regs *)EMAC_BASE_ADDR; + + if (!davinci_eth_phy_read(phy_addr, PHY_LXT971_STAT2, &stat1)) + return(0); + + if (!(stat1 & PHY_LXT971_STAT2_LINK)) /* link up? */ + return(0); + + if (!davinci_eth_phy_read(phy_addr, PHY_LXT971_DIG_CFG, &tmp)) + return(0); + + tmp |= PHY_LXT971_DIG_CFG_MII_DRIVE; + + davinci_eth_phy_write(phy_addr, PHY_LXT971_DIG_CFG, tmp); + /* Read back */ + if (!davinci_eth_phy_read(phy_addr, PHY_LXT971_DIG_CFG, &tmp)) + return(0); + + /* Speed doesn't matter, there is no setting for it in EMAC... */ + if (stat1 & PHY_LXT971_STAT2_DUPLEX_MODE) { + /* set DM644x EMAC for Full Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | + EMAC_MACCONTROL_FULLDUPLEX_ENABLE; + } else { + /*set DM644x EMAC for Half Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE; + } + + return(1); +} + + +int lxt972_init_phy(int phy_addr) +{ + int ret = 1; + + if (!lxt972_get_link_speed(phy_addr)) { + /* Try another time */ + ret = lxt972_get_link_speed(phy_addr); + } + + /* Disable PHY Interrupts */ + davinci_eth_phy_write(phy_addr, PHY_LXT971_INT_ENABLE, 0); + + return(ret); +} + + +int lxt972_auto_negotiate(int phy_addr) +{ + u_int16_t tmp; + + if (!davinci_eth_phy_read(phy_addr, MII_BMCR, &tmp)) + return(0); + + /* Restart Auto_negotiation */ + tmp |= BMCR_ANRESTART; + davinci_eth_phy_write(phy_addr, MII_BMCR, tmp); + + /*check AutoNegotiate complete */ + udelay (10000); + if (!davinci_eth_phy_read(phy_addr, MII_BMSR, &tmp)) + return(0); + + if (!(tmp & BMSR_ANEGCOMPLETE)) + return(0); + + return (lxt972_get_link_speed(phy_addr)); +} + +#endif /* CONFIG_CMD_NET */ + +#endif /* CONFIG_DRIVER_ETHER */ diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/misc.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/misc.c new file mode 100644 index 000000000..e18bdfc72 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/misc.c @@ -0,0 +1,138 @@ +/* + * Miscelaneous DaVinci functions. + * + * Copyright (C) 2009 Nick Thompson, GE Fanuc Ltd, <nick.thompson@gefanuc.com> + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * Copyright (C) 2008 Lyrtech <www.lyrtech.com> + * Copyright (C) 2004 Texas Instruments. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <i2c.h> +#include <net.h> +#include <asm/arch/hardware.h> +#include <asm/io.h> +#include <asm/arch/davinci_misc.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifndef CONFIG_SPL_BUILD +int dram_init(void) +{ + /* dram_init must store complete ramsize in gd->ram_size */ + gd->ram_size = get_ram_size( + (void *)CONFIG_SYS_SDRAM_BASE, + CONFIG_MAX_RAM_BANK_SIZE); + return 0; +} + +void dram_init_banksize(void) +{ + gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE; + gd->bd->bi_dram[0].size = gd->ram_size; +} +#endif + +#ifdef CONFIG_DRIVER_TI_EMAC +/* + * Read ethernet MAC address from EEPROM for DVEVM compatible boards. + * Returns 1 if found, 0 otherwise. + */ +int dvevm_read_mac_address(uint8_t *buf) +{ +#ifdef CONFIG_SYS_I2C_EEPROM_ADDR + /* Read MAC address. */ + if (i2c_read(CONFIG_SYS_I2C_EEPROM_ADDR, 0x7F00, + CONFIG_SYS_I2C_EEPROM_ADDR_LEN, (uint8_t *) &buf[0], 6)) + goto i2cerr; + + /* Check that MAC address is valid. */ + if (!is_valid_ether_addr(buf)) + goto err; + + return 1; /* Found */ + +i2cerr: + printf("Read from EEPROM @ 0x%02x failed\n", + CONFIG_SYS_I2C_EEPROM_ADDR); +err: +#endif /* CONFIG_SYS_I2C_EEPROM_ADDR */ + + return 0; +} + +/* + * Set the mii mode as MII or RMII + */ +#if defined(CONFIG_SOC_DA8XX) +void davinci_emac_mii_mode_sel(int mode_sel) +{ + int val; + + val = readl(&davinci_syscfg_regs->cfgchip3); + if (mode_sel == 0) + val &= ~(1 << 8); + else + val |= (1 << 8); + writel(val, &davinci_syscfg_regs->cfgchip3); +} +#endif +/* + * If there is no MAC address in the environment, then it will be initialized + * (silently) from the value in the EEPROM. + */ +void davinci_sync_env_enetaddr(uint8_t *rom_enetaddr) +{ + uint8_t env_enetaddr[6]; + int ret; + + ret = eth_getenv_enetaddr_by_index("eth", 0, env_enetaddr); + if (!ret) { + /* + * There is no MAC address in the environment, so we + * initialize it from the value in the EEPROM. + */ + debug("### Setting environment from EEPROM MAC address = " + "\"%pM\"\n", + env_enetaddr); + ret = !eth_setenv_enetaddr("ethaddr", rom_enetaddr); + } + if (!ret) + printf("Failed to set mac address from EEPROM: %d\n", ret); +} +#endif /* CONFIG_DRIVER_TI_EMAC */ + +#if defined(CONFIG_SOC_DA8XX) +#ifndef CONFIG_USE_IRQ +void irq_init(void) +{ + /* + * Mask all IRQs by clearing the global enable and setting + * the enable clear for all the 90 interrupts. + */ + writel(0, &davinci_aintc_regs->ger); + + writel(0, &davinci_aintc_regs->hier); + + writel(0xffffffff, &davinci_aintc_regs->ecr1); + writel(0xffffffff, &davinci_aintc_regs->ecr2); + writel(0xffffffff, &davinci_aintc_regs->ecr3); +} +#endif + +/* + * Enable PSC for various peripherals. + */ +int da8xx_configure_lpsc_items(const struct lpsc_resource *item, + const int n_items) +{ + int i; + + for (i = 0; i < n_items; i++) + lpsc_on(item[i].lpsc_no); + + return 0; +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/pinmux.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/pinmux.c new file mode 100644 index 000000000..e9d8c87cc --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/pinmux.c @@ -0,0 +1,90 @@ +/* + * DaVinci pinmux functions. + * + * Copyright (C) 2009 Nick Thompson, GE Fanuc Ltd, <nick.thompson@gefanuc.com> + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * Copyright (C) 2008 Lyrtech <www.lyrtech.com> + * Copyright (C) 2004 Texas Instruments. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/hardware.h> +#include <asm/io.h> +#include <asm/arch/davinci_misc.h> + +/* + * Change the setting of a pin multiplexer field. + * + * Takes an array of pinmux settings similar to: + * + * struct pinmux_config uart_pins[] = { + * { &davinci_syscfg_regs->pinmux[8], 2, 7 }, + * { &davinci_syscfg_regs->pinmux[9], 2, 0 } + * }; + * + * Stepping through the array, each pinmux[n] register has the given value + * set in the pin mux field specified. + * + * The number of pins in the array must be passed (ARRAY_SIZE can provide + * this value conveniently). + * + * Returns 0 if all field numbers and values are in the correct range, + * else returns -1. + */ +int davinci_configure_pin_mux(const struct pinmux_config *pins, + const int n_pins) +{ + int i; + + /* check for invalid pinmux values */ + for (i = 0; i < n_pins; i++) { + if (pins[i].field >= PIN_MUX_NUM_FIELDS || + (pins[i].value & ~PIN_MUX_FIELD_MASK) != 0) + return -1; + } + + /* configure the pinmuxes */ + for (i = 0; i < n_pins; i++) { + const int offset = pins[i].field * PIN_MUX_FIELD_SIZE; + const unsigned int value = pins[i].value << offset; + const unsigned int mask = PIN_MUX_FIELD_MASK << offset; + const dv_reg *mux = pins[i].mux; + + writel(value | (readl(mux) & (~mask)), mux); + } + + return 0; +} + +/* + * Configure multiple pinmux resources. + * + * Takes an pinmux_resource array of pinmux_config and pin counts: + * + * const struct pinmux_resource pinmuxes[] = { + * PINMUX_ITEM(uart_pins), + * PINMUX_ITEM(i2c_pins), + * }; + * + * The number of items in the array must be passed (ARRAY_SIZE can provide + * this value conveniently). + * + * Each item entry is configured in the defined order. If configuration + * of any item fails, -1 is returned and none of the following items are + * configured. On success, 0 is returned. + */ +int davinci_configure_pin_mux_items(const struct pinmux_resource *item, + const int n_items) +{ + int i; + + for (i = 0; i < n_items; i++) { + if (davinci_configure_pin_mux(item[i].pins, + item[i].n_pins) != 0) + return -1; + } + + return 0; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/psc.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/psc.c new file mode 100644 index 000000000..8d99e2e99 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/psc.c @@ -0,0 +1,160 @@ +/* + * Power and Sleep Controller (PSC) functions. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * Copyright (C) 2008 Lyrtech <www.lyrtech.com> + * Copyright (C) 2004 Texas Instruments. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/hardware.h> +#include <asm/io.h> + +/* + * The PSC manages three inputs to a "module" which may be a peripheral or + * CPU. Those inputs are the module's: clock; reset signal; and sometimes + * its power domain. For our purposes, we only care whether clock and power + * are active, and the module is out of reset. + * + * DaVinci chips may include two separate power domains: "Always On" and "DSP". + * Chips without a DSP generally have only one domain. + * + * The "Always On" power domain is always on when the chip is on, and is + * powered by the VDD pins (on DM644X). The majority of DaVinci modules + * lie within the "Always On" power domain. + * + * A separate domain called the "DSP" domain houses the C64x+ and other video + * hardware such as VICP. In some chips, the "DSP" domain is not always on. + * The "DSP" power domain is powered by the CVDDDSP pins (on DM644X). + */ + +/* Works on Always On power domain only (no PD argument) */ +static void lpsc_transition(unsigned int id, unsigned int state) +{ + dv_reg_p mdstat, mdctl, ptstat, ptcmd; +#ifdef CONFIG_SOC_DA8XX + struct davinci_psc_regs *psc_regs; +#endif + +#ifndef CONFIG_SOC_DA8XX + if (id >= DAVINCI_LPSC_GEM) + return; /* Don't work on DSP Power Domain */ + + mdstat = REG_P(PSC_MDSTAT_BASE + (id * 4)); + mdctl = REG_P(PSC_MDCTL_BASE + (id * 4)); + ptstat = REG_P(PSC_PTSTAT); + ptcmd = REG_P(PSC_PTCMD); +#else + if (id < DAVINCI_LPSC_PSC1_BASE) { + if (id >= PSC_PSC0_MODULE_ID_CNT) + return; + psc_regs = davinci_psc0_regs; + mdstat = &psc_regs->psc0.mdstat[id]; + mdctl = &psc_regs->psc0.mdctl[id]; + } else { + id -= DAVINCI_LPSC_PSC1_BASE; + if (id >= PSC_PSC1_MODULE_ID_CNT) + return; + psc_regs = davinci_psc1_regs; + mdstat = &psc_regs->psc1.mdstat[id]; + mdctl = &psc_regs->psc1.mdctl[id]; + } + ptstat = &psc_regs->ptstat; + ptcmd = &psc_regs->ptcmd; +#endif + + while (readl(ptstat) & 0x01) + continue; + + if ((readl(mdstat) & PSC_MDSTAT_STATE) == state) + return; /* Already in that state */ + + writel((readl(mdctl) & ~PSC_MDCTL_NEXT) | state, mdctl); + + switch (id) { +#ifdef CONFIG_SOC_DM644X + /* Special treatment for some modules as for sprue14 p.7.4.2 */ + case DAVINCI_LPSC_VPSSSLV: + case DAVINCI_LPSC_EMAC: + case DAVINCI_LPSC_EMAC_WRAPPER: + case DAVINCI_LPSC_MDIO: + case DAVINCI_LPSC_USB: + case DAVINCI_LPSC_ATA: + case DAVINCI_LPSC_VLYNQ: + case DAVINCI_LPSC_UHPI: + case DAVINCI_LPSC_DDR_EMIF: + case DAVINCI_LPSC_AEMIF: + case DAVINCI_LPSC_MMC_SD: + case DAVINCI_LPSC_MEMSTICK: + case DAVINCI_LPSC_McBSP: + case DAVINCI_LPSC_GPIO: + writel(readl(mdctl) | 0x200, mdctl); + break; +#endif + } + + writel(0x01, ptcmd); + + while (readl(ptstat) & 0x01) + continue; + while ((readl(mdstat) & PSC_MDSTAT_STATE) != state) + continue; +} + +void lpsc_on(unsigned int id) +{ + lpsc_transition(id, 0x03); +} + +void lpsc_syncreset(unsigned int id) +{ + lpsc_transition(id, 0x01); +} + +void lpsc_disable(unsigned int id) +{ + lpsc_transition(id, 0x0); +} + +/* Not all DaVinci chips have a DSP power domain. */ +#ifdef CONFIG_SOC_DM644X + +/* If DSPLINK is used, we don't want U-Boot to power on the DSP. */ +#if !defined(CONFIG_SYS_USE_DSPLINK) +void dsp_on(void) +{ + int i; + + if (REG(PSC_PDSTAT1) & 0x1f) + return; /* Already on */ + + REG(PSC_GBLCTL) |= 0x01; + REG(PSC_PDCTL1) |= 0x01; + REG(PSC_PDCTL1) &= ~0x100; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_GEM * 4)) |= 0x03; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_GEM * 4)) &= 0xfffffeff; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_IMCOP * 4)) |= 0x03; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_IMCOP * 4)) &= 0xfffffeff; + REG(PSC_PTCMD) = 0x02; + + for (i = 0; i < 100; i++) { + if (REG(PSC_EPCPR) & 0x02) + break; + } + + REG(PSC_CHP_SHRTSW) = 0x01; + REG(PSC_PDCTL1) |= 0x100; + REG(PSC_EPCCR) = 0x02; + + for (i = 0; i < 100; i++) { + if (!(REG(PSC_PTSTAT) & 0x02)) + break; + } + + REG(PSC_GBLCTL) &= ~0x1f; +} +#endif /* CONFIG_SYS_USE_DSPLINK */ + +#endif /* have a DSP */ diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/reset.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/reset.c new file mode 100644 index 000000000..6b0f15428 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/reset.c @@ -0,0 +1,32 @@ +/* + * Processor reset using WDT. + * + * Copyright (C) 2012 Dmitry Bondar <bond@inmys.ru> + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/timer_defs.h> +#include <asm/arch/hardware.h> + +void reset_cpu(unsigned long a) +{ + struct davinci_timer *const wdttimer = + (struct davinci_timer *)DAVINCI_WDOG_BASE; + writel(0x08, &wdttimer->tgcr); + writel(readl(&wdttimer->tgcr) | 0x03, &wdttimer->tgcr); + writel(0, &wdttimer->tim12); + writel(0, &wdttimer->tim34); + writel(0, &wdttimer->prd12); + writel(0, &wdttimer->prd34); + writel(readl(&wdttimer->tcr) | 0x40, &wdttimer->tcr); + writel(readl(&wdttimer->wdtcr) | 0x4000, &wdttimer->wdtcr); + writel(0xa5c64000, &wdttimer->wdtcr); + writel(0xda7e4000, &wdttimer->wdtcr); + writel(0x4000, &wdttimer->wdtcr); + while (1) + /*nothing*/; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/spl.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/spl.c new file mode 100644 index 000000000..59b304efc --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/spl.c @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2011 + * Heiko Schocher, DENX Software Engineering, hs@denx.de. + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <config.h> +#include <spl.h> +#include <asm/u-boot.h> +#include <asm/utils.h> +#include <nand.h> +#include <asm/arch/dm365_lowlevel.h> +#include <ns16550.h> +#include <malloc.h> +#include <spi_flash.h> +#include <mmc.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifndef CONFIG_SPL_LIBCOMMON_SUPPORT +void puts(const char *str) +{ + while (*str) + putc(*str++); +} + +void putc(char c) +{ + if (c == '\n') + NS16550_putc((NS16550_t)(CONFIG_SYS_NS16550_COM1), '\r'); + + NS16550_putc((NS16550_t)(CONFIG_SYS_NS16550_COM1), c); +} +#endif /* CONFIG_SPL_LIBCOMMON_SUPPORT */ + +void board_init_f(ulong dummy) +{ + /* First, setup our stack pointer. */ + asm volatile("mov sp, %0\n" : : "r"(CONFIG_SPL_STACK)); + + /* Second, perform our low-level init. */ +#ifdef CONFIG_SOC_DM365 + dm36x_lowlevel_init(0); +#endif +#ifdef CONFIG_SOC_DA8XX + arch_cpu_init(); +#endif + + /* Third, we clear the BSS. */ + memset(__bss_start, 0, __bss_end - __bss_start); + + /* Finally, setup gd and move to the next step. */ + gd = &gdata; + board_init_r(NULL, 0); +} + +void spl_board_init(void) +{ + preloader_console_init(); +} + +u32 spl_boot_mode(void) +{ + return MMCSD_MODE_RAW; +} + +u32 spl_boot_device(void) +{ +#ifdef CONFIG_SPL_NAND_SIMPLE + return BOOT_DEVICE_NAND; +#elif defined(CONFIG_SPL_SPI_LOAD) + return BOOT_DEVICE_SPI; +#elif defined(CONFIG_SPL_MMC_LOAD) + return BOOT_DEVICE_MMC1; +#else + puts("Unknown boot device\n"); + hang(); +#endif +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/timer.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/timer.c new file mode 100644 index 000000000..c7d0652e8 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/davinci/timer.c @@ -0,0 +1,128 @@ +/* + * (C) Copyright 2003 + * Texas Instruments <www.ti.com> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002-2004 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * (C) Copyright 2004 + * Philippe Robin, ARM Ltd. <philippe.robin@arm.com> + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/timer_defs.h> +#include <div64.h> + +DECLARE_GLOBAL_DATA_PTR; + +static struct davinci_timer * const timer = + (struct davinci_timer *)CONFIG_SYS_TIMERBASE; + +#define TIMER_LOAD_VAL 0xffffffff + +#define TIM_CLK_DIV 16 + +int timer_init(void) +{ + /* We are using timer34 in unchained 32-bit mode, full speed */ + writel(0x0, &timer->tcr); + writel(0x0, &timer->tgcr); + writel(0x06 | ((TIM_CLK_DIV - 1) << 8), &timer->tgcr); + writel(0x0, &timer->tim34); + writel(TIMER_LOAD_VAL, &timer->prd34); + writel(2 << 22, &timer->tcr); + gd->arch.timer_rate_hz = CONFIG_SYS_HZ_CLOCK / TIM_CLK_DIV; + gd->arch.timer_reset_value = 0; + + return(0); +} + +/* + * Get the current 64 bit timer tick count + */ +unsigned long long get_ticks(void) +{ + unsigned long now = readl(&timer->tim34); + + /* increment tbu if tbl has rolled over */ + if (now < gd->arch.tbl) + gd->arch.tbu++; + gd->arch.tbl = now; + + return (((unsigned long long)gd->arch.tbu) << 32) | gd->arch.tbl; +} + +ulong get_timer(ulong base) +{ + unsigned long long timer_diff; + + timer_diff = get_ticks() - gd->arch.timer_reset_value; + + return lldiv(timer_diff, + (gd->arch.timer_rate_hz / CONFIG_SYS_HZ)) - base; +} + +void __udelay(unsigned long usec) +{ + unsigned long long endtime; + + endtime = lldiv((unsigned long long)usec * gd->arch.timer_rate_hz, + 1000000UL); + endtime += get_ticks(); + + while (get_ticks() < endtime) + ; +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + return gd->arch.timer_rate_hz; +} + +#ifdef CONFIG_HW_WATCHDOG +static struct davinci_timer * const wdttimer = + (struct davinci_timer *)CONFIG_SYS_WDTTIMERBASE; + +/* + * See prufw2.pdf for using Timer as a WDT + */ +void davinci_hw_watchdog_enable(void) +{ + writel(0x0, &wdttimer->tcr); + writel(0x0, &wdttimer->tgcr); + /* TIMMODE = 2h */ + writel(0x08 | 0x03 | ((TIM_CLK_DIV - 1) << 8), &wdttimer->tgcr); + writel(CONFIG_SYS_WDT_PERIOD_LOW, &wdttimer->prd12); + writel(CONFIG_SYS_WDT_PERIOD_HIGH, &wdttimer->prd34); + writel(2 << 22, &wdttimer->tcr); + writel(0x0, &wdttimer->tim12); + writel(0x0, &wdttimer->tim34); + /* set WDEN bit, WDKEY 0xa5c6 */ + writel(0xa5c64000, &wdttimer->wdtcr); + /* clear counter register */ + writel(0xda7e4000, &wdttimer->wdtcr); +} + +void davinci_hw_watchdog_reset(void) +{ + writel(0xa5c64000, &wdttimer->wdtcr); + writel(0xda7e4000, &wdttimer->wdtcr); +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/Makefile b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/Makefile new file mode 100644 index 000000000..c230ce899 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/Makefile @@ -0,0 +1,13 @@ +# +# (C) Copyright 2009 +# Marvell Semiconductor <www.marvell.com> +# Written-by: Prafulla Wadaskar <prafulla@marvell.com> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y = cpu.o +obj-y += dram.o +obj-y += mpp.o +obj-y += timer.o +obj-y += cache.o diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/cache.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/cache.c new file mode 100644 index 000000000..e18a3097d --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/cache.c @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2012 Michael Walle + * Michael Walle <michael@walle.cc> + * + * SPDX-License-Identifier: GPL-2.0+ + */ +#include <common.h> +#include <asm/arch/cpu.h> + +#define FEROCEON_EXTRA_FEATURE_L2C_EN (1<<22) + +void l2_cache_disable() +{ + u32 ctrl; + + ctrl = readfr_extra_feature_reg(); + ctrl &= ~FEROCEON_EXTRA_FEATURE_L2C_EN; + writefr_extra_feature_reg(ctrl); +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/cpu.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/cpu.c new file mode 100644 index 000000000..d4711c070 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/cpu.c @@ -0,0 +1,380 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <netdev.h> +#include <asm/cache.h> +#include <u-boot/md5.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/kirkwood.h> +#include <hush.h> + +#define BUFLEN 16 + +void reset_cpu(unsigned long ignored) +{ + struct kwcpu_registers *cpureg = + (struct kwcpu_registers *)KW_CPU_REG_BASE; + + writel(readl(&cpureg->rstoutn_mask) | (1 << 2), + &cpureg->rstoutn_mask); + writel(readl(&cpureg->sys_soft_rst) | 1, + &cpureg->sys_soft_rst); + while (1) ; +} + +/* + * Generates Ramdom hex number reading some time varient system registers + * and using md5 algorithm + */ +unsigned char get_random_hex(void) +{ + int i; + u32 inbuf[BUFLEN]; + u8 outbuf[BUFLEN]; + + /* + * in case of 88F6281/88F6282/88F6192 A0, + * Bit7 need to reset to generate random values in KW_REG_UNDOC_0x1470 + * Soc reg offsets KW_REG_UNDOC_0x1470 and KW_REG_UNDOC_0x1478 are + * reserved regs and does not have names at this moment + * (no errata available) + */ + writel(readl(KW_REG_UNDOC_0x1478) & ~(1 << 7), KW_REG_UNDOC_0x1478); + for (i = 0; i < BUFLEN; i++) { + inbuf[i] = readl(KW_REG_UNDOC_0x1470); + } + md5((u8 *) inbuf, (BUFLEN * sizeof(u32)), outbuf); + return outbuf[outbuf[7] % 0x0f]; +} + +/* + * Window Size + * Used with the Base register to set the address window size and location. + * Must be programmed from LSB to MSB as sequence of ones followed by + * sequence of zeros. The number of ones specifies the size of the window in + * 64 KByte granularity (e.g., a value of 0x00FF specifies 256 = 16 MByte). + * NOTE: A value of 0x0 specifies 64-KByte size. + */ +unsigned int kw_winctrl_calcsize(unsigned int sizeval) +{ + int i; + unsigned int j = 0; + u32 val = sizeval >> 1; + + for (i = 0; val >= 0x10000; i++) { + j |= (1 << i); + val = val >> 1; + } + return (0x0000ffff & j); +} + +/* + * kw_config_adr_windows - Configure address Windows + * + * There are 8 address windows supported by Kirkwood Soc to addess different + * devices. Each window can be configured for size, BAR and remap addr + * Below configuration is standard for most of the cases + * + * If remap function not used, remap_lo must be set as base + * + * Reference Documentation: + * Mbus-L to Mbus Bridge Registers Configuration. + * (Sec 25.1 and 25.3 of Datasheet) + */ +int kw_config_adr_windows(void) +{ + struct kwwin_registers *winregs = + (struct kwwin_registers *)KW_CPU_WIN_BASE; + + /* Window 0: PCIE MEM address space */ + writel(KWCPU_WIN_CTRL_DATA(1024 * 1024 * 256, KWCPU_TARGET_PCIE, + KWCPU_ATTR_PCIE_MEM, KWCPU_WIN_ENABLE), &winregs[0].ctrl); + + writel(KW_DEFADR_PCI_MEM, &winregs[0].base); + writel(KW_DEFADR_PCI_MEM, &winregs[0].remap_lo); + writel(0x0, &winregs[0].remap_hi); + + /* Window 1: PCIE IO address space */ + writel(KWCPU_WIN_CTRL_DATA(1024 * 64, KWCPU_TARGET_PCIE, + KWCPU_ATTR_PCIE_IO, KWCPU_WIN_ENABLE), &winregs[1].ctrl); + writel(KW_DEFADR_PCI_IO, &winregs[1].base); + writel(KW_DEFADR_PCI_IO_REMAP, &winregs[1].remap_lo); + writel(0x0, &winregs[1].remap_hi); + + /* Window 2: NAND Flash address space */ + writel(KWCPU_WIN_CTRL_DATA(1024 * 1024 * 128, KWCPU_TARGET_MEMORY, + KWCPU_ATTR_NANDFLASH, KWCPU_WIN_ENABLE), &winregs[2].ctrl); + writel(KW_DEFADR_NANDF, &winregs[2].base); + writel(KW_DEFADR_NANDF, &winregs[2].remap_lo); + writel(0x0, &winregs[2].remap_hi); + + /* Window 3: SPI Flash address space */ + writel(KWCPU_WIN_CTRL_DATA(1024 * 1024 * 128, KWCPU_TARGET_MEMORY, + KWCPU_ATTR_SPIFLASH, KWCPU_WIN_ENABLE), &winregs[3].ctrl); + writel(KW_DEFADR_SPIF, &winregs[3].base); + writel(KW_DEFADR_SPIF, &winregs[3].remap_lo); + writel(0x0, &winregs[3].remap_hi); + + /* Window 4: BOOT Memory address space */ + writel(KWCPU_WIN_CTRL_DATA(1024 * 1024 * 128, KWCPU_TARGET_MEMORY, + KWCPU_ATTR_BOOTROM, KWCPU_WIN_ENABLE), &winregs[4].ctrl); + writel(KW_DEFADR_BOOTROM, &winregs[4].base); + + /* Window 5: Security SRAM address space */ + writel(KWCPU_WIN_CTRL_DATA(1024 * 64, KWCPU_TARGET_SASRAM, + KWCPU_ATTR_SASRAM, KWCPU_WIN_ENABLE), &winregs[5].ctrl); + writel(KW_DEFADR_SASRAM, &winregs[5].base); + + /* Window 6-7: Disabled */ + writel(KWCPU_WIN_DISABLE, &winregs[6].ctrl); + writel(KWCPU_WIN_DISABLE, &winregs[7].ctrl); + + return 0; +} + +/* + * kw_config_gpio - GPIO configuration + */ +void kw_config_gpio(u32 gpp0_oe_val, u32 gpp1_oe_val, u32 gpp0_oe, u32 gpp1_oe) +{ + struct kwgpio_registers *gpio0reg = + (struct kwgpio_registers *)KW_GPIO0_BASE; + struct kwgpio_registers *gpio1reg = + (struct kwgpio_registers *)KW_GPIO1_BASE; + + /* Init GPIOS to default values as per board requirement */ + writel(gpp0_oe_val, &gpio0reg->dout); + writel(gpp1_oe_val, &gpio1reg->dout); + writel(gpp0_oe, &gpio0reg->oe); + writel(gpp1_oe, &gpio1reg->oe); +} + +/* + * kw_config_mpp - Multi-Purpose Pins Functionality configuration + * + * Each MPP can be configured to different functionality through + * MPP control register, ref (sec 6.1 of kirkwood h/w specification) + * + * There are maximum 64 Multi-Pourpose Pins on Kirkwood + * Each MPP functionality can be configuration by a 4bit value + * of MPP control reg, the value and associated functionality depends + * upon used SoC varient + */ +int kw_config_mpp(u32 mpp0_7, u32 mpp8_15, u32 mpp16_23, u32 mpp24_31, + u32 mpp32_39, u32 mpp40_47, u32 mpp48_55) +{ + u32 *mppreg = (u32 *) KW_MPP_BASE; + + /* program mpp registers */ + writel(mpp0_7, &mppreg[0]); + writel(mpp8_15, &mppreg[1]); + writel(mpp16_23, &mppreg[2]); + writel(mpp24_31, &mppreg[3]); + writel(mpp32_39, &mppreg[4]); + writel(mpp40_47, &mppreg[5]); + writel(mpp48_55, &mppreg[6]); + return 0; +} + +/* + * SYSRSTn Duration Counter Support + * + * Kirkwood SoC implements a hardware-based SYSRSTn duration counter. + * When SYSRSTn is asserted low, a SYSRSTn duration counter is running. + * The SYSRSTn duration counter is useful for implementing a manufacturer + * or factory reset. Upon a long reset assertion that is greater than a + * pre-configured environment variable value for sysrstdelay, + * The counter value is stored in the SYSRSTn Length Counter Register + * The counter is based on the 25-MHz reference clock (40ns) + * It is a 29-bit counter, yielding a maximum counting duration of + * 2^29/25 MHz (21.4 seconds). When the counter reach its maximum value, + * it remains at this value until counter reset is triggered by setting + * bit 31 of KW_REG_SYSRST_CNT + */ +static void kw_sysrst_action(void) +{ + int ret; + char *s = getenv("sysrstcmd"); + + if (!s) { + debug("Error.. %s failed, check sysrstcmd\n", + __FUNCTION__); + return; + } + + debug("Starting %s process...\n", __FUNCTION__); + ret = run_command(s, 0); + if (ret < 0) + debug("Error.. %s failed\n", __FUNCTION__); + else + debug("%s process finished\n", __FUNCTION__); +} + +static void kw_sysrst_check(void) +{ + u32 sysrst_cnt, sysrst_dly; + char *s; + + /* + * no action if sysrstdelay environment variable is not defined + */ + s = getenv("sysrstdelay"); + if (s == NULL) + return; + + /* read sysrstdelay value */ + sysrst_dly = (u32) simple_strtoul(s, NULL, 10); + + /* read SysRst Length counter register (bits 28:0) */ + sysrst_cnt = (0x1fffffff & readl(KW_REG_SYSRST_CNT)); + debug("H/w Rst hold time: %d.%d secs\n", + sysrst_cnt / SYSRST_CNT_1SEC_VAL, + sysrst_cnt % SYSRST_CNT_1SEC_VAL); + + /* clear the counter for next valid read*/ + writel(1 << 31, KW_REG_SYSRST_CNT); + + /* + * sysrst_action: + * if H/w Reset key is pressed and hold for time + * more than sysrst_dly in seconds + */ + if (sysrst_cnt >= SYSRST_CNT_1SEC_VAL * sysrst_dly) + kw_sysrst_action(); +} + +#if defined(CONFIG_DISPLAY_CPUINFO) +int print_cpuinfo(void) +{ + char *rev; + u16 devid = (readl(KW_REG_PCIE_DEVID) >> 16) & 0xffff; + u8 revid = readl(KW_REG_PCIE_REVID) & 0xff; + + if ((readl(KW_REG_DEVICE_ID) & 0x03) > 2) { + printf("Error.. %s:Unsupported Kirkwood SoC 88F%04x\n", __FUNCTION__, devid); + return -1; + } + + switch (revid) { + case 0: + rev = "Z0"; + break; + case 2: + rev = "A0"; + break; + case 3: + rev = "A1"; + break; + default: + rev = "??"; + break; + } + + printf("SoC: Kirkwood 88F%04x_%s\n", devid, rev); + return 0; +} +#endif /* CONFIG_DISPLAY_CPUINFO */ + +#ifdef CONFIG_ARCH_CPU_INIT +int arch_cpu_init(void) +{ + u32 reg; + struct kwcpu_registers *cpureg = + (struct kwcpu_registers *)KW_CPU_REG_BASE; + + /* Linux expects` the internal registers to be at 0xf1000000 */ + writel(KW_REGS_PHY_BASE, KW_OFFSET_REG); + + /* Enable and invalidate L2 cache in write through mode */ + writel(readl(&cpureg->l2_cfg) | 0x18, &cpureg->l2_cfg); + invalidate_l2_cache(); + + kw_config_adr_windows(); + +#ifdef CONFIG_KIRKWOOD_RGMII_PAD_1V8 + /* + * Configures the I/O voltage of the pads connected to Egigabit + * Ethernet interface to 1.8V + * By default it is set to 3.3V + */ + reg = readl(KW_REG_MPP_OUT_DRV_REG); + reg |= (1 << 7); + writel(reg, KW_REG_MPP_OUT_DRV_REG); +#endif +#ifdef CONFIG_KIRKWOOD_EGIGA_INIT + /* + * Set egiga port0/1 in normal functional mode + * This is required becasue on kirkwood by default ports are in reset mode + * OS egiga driver may not have provision to set them in normal mode + * and if u-boot is build without network support, network may fail at OS level + */ + reg = readl(KWGBE_PORT_SERIAL_CONTROL1_REG(0)); + reg &= ~(1 << 4); /* Clear PortReset Bit */ + writel(reg, (KWGBE_PORT_SERIAL_CONTROL1_REG(0))); + reg = readl(KWGBE_PORT_SERIAL_CONTROL1_REG(1)); + reg &= ~(1 << 4); /* Clear PortReset Bit */ + writel(reg, (KWGBE_PORT_SERIAL_CONTROL1_REG(1))); +#endif +#ifdef CONFIG_KIRKWOOD_PCIE_INIT + /* + * Enable PCI Express Port0 + */ + reg = readl(&cpureg->ctrl_stat); + reg |= (1 << 0); /* Set PEX0En Bit */ + writel(reg, &cpureg->ctrl_stat); +#endif + return 0; +} +#endif /* CONFIG_ARCH_CPU_INIT */ + +/* + * SOC specific misc init + */ +#if defined(CONFIG_ARCH_MISC_INIT) +int arch_misc_init(void) +{ + volatile u32 temp; + + /*CPU streaming & write allocate */ + temp = readfr_extra_feature_reg(); + temp &= ~(1 << 28); /* disable wr alloc */ + writefr_extra_feature_reg(temp); + + temp = readfr_extra_feature_reg(); + temp &= ~(1 << 29); /* streaming disabled */ + writefr_extra_feature_reg(temp); + + /* L2Cache settings */ + temp = readfr_extra_feature_reg(); + /* Disable L2C pre fetch - Set bit 24 */ + temp |= (1 << 24); + /* enable L2C - Set bit 22 */ + temp |= (1 << 22); + writefr_extra_feature_reg(temp); + + icache_enable(); + /* Change reset vector to address 0x0 */ + temp = get_cr(); + set_cr(temp & ~CR_V); + + /* checks and execute resset to factory event */ + kw_sysrst_check(); + + return 0; +} +#endif /* CONFIG_ARCH_MISC_INIT */ + +#ifdef CONFIG_MVGBE +int cpu_eth_init(bd_t *bis) +{ + mvgbe_initialize(bis); + return 0; +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/dram.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/dram.c new file mode 100644 index 000000000..d73ae47c3 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/dram.c @@ -0,0 +1,137 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> +#include <common.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/kirkwood.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct kw_sdram_bank { + u32 win_bar; + u32 win_sz; +}; + +struct kw_sdram_addr_dec { + struct kw_sdram_bank sdram_bank[4]; +}; + +#define KW_REG_CPUCS_WIN_ENABLE (1 << 0) +#define KW_REG_CPUCS_WIN_WR_PROTECT (1 << 1) +#define KW_REG_CPUCS_WIN_WIN0_CS(x) (((x) & 0x3) << 2) +#define KW_REG_CPUCS_WIN_SIZE(x) (((x) & 0xff) << 24) + +/* + * kw_sdram_bar - reads SDRAM Base Address Register + */ +u32 kw_sdram_bar(enum memory_bank bank) +{ + struct kw_sdram_addr_dec *base = + (struct kw_sdram_addr_dec *)KW_REGISTER(0x1500); + u32 result = 0; + u32 enable = 0x01 & readl(&base->sdram_bank[bank].win_sz); + + if ((!enable) || (bank > BANK3)) + return 0; + + result = readl(&base->sdram_bank[bank].win_bar); + return result; +} + +/* + * kw_sdram_bs_set - writes SDRAM Bank size + */ +static void kw_sdram_bs_set(enum memory_bank bank, u32 size) +{ + struct kw_sdram_addr_dec *base = + (struct kw_sdram_addr_dec *)KW_REGISTER(0x1500); + /* Read current register value */ + u32 reg = readl(&base->sdram_bank[bank].win_sz); + + /* Clear window size */ + reg &= ~KW_REG_CPUCS_WIN_SIZE(0xFF); + + /* Set new window size */ + reg |= KW_REG_CPUCS_WIN_SIZE((size - 1) >> 24); + + writel(reg, &base->sdram_bank[bank].win_sz); +} + +/* + * kw_sdram_bs - reads SDRAM Bank size + */ +u32 kw_sdram_bs(enum memory_bank bank) +{ + struct kw_sdram_addr_dec *base = + (struct kw_sdram_addr_dec *)KW_REGISTER(0x1500); + u32 result = 0; + u32 enable = 0x01 & readl(&base->sdram_bank[bank].win_sz); + + if ((!enable) || (bank > BANK3)) + return 0; + result = 0xff000000 & readl(&base->sdram_bank[bank].win_sz); + result += 0x01000000; + return result; +} + +void kw_sdram_size_adjust(enum memory_bank bank) +{ + u32 size; + + /* probe currently equipped RAM size */ + size = get_ram_size((void *)kw_sdram_bar(bank), kw_sdram_bs(bank)); + + /* adjust SDRAM window size accordingly */ + kw_sdram_bs_set(bank, size); +} + +#ifndef CONFIG_SYS_BOARD_DRAM_INIT +int dram_init(void) +{ + int i; + + gd->ram_size = 0; + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + gd->bd->bi_dram[i].start = kw_sdram_bar(i); + gd->bd->bi_dram[i].size = kw_sdram_bs(i); + /* + * It is assumed that all memory banks are consecutive + * and without gaps. + * If the gap is found, ram_size will be reported for + * consecutive memory only + */ + if (gd->bd->bi_dram[i].start != gd->ram_size) + break; + + gd->ram_size += gd->bd->bi_dram[i].size; + + } + + for (; i < CONFIG_NR_DRAM_BANKS; i++) { + /* If above loop terminated prematurely, we need to set + * remaining banks' start address & size as 0. Otherwise other + * u-boot functions and Linux kernel gets wrong values which + * could result in crash */ + gd->bd->bi_dram[i].start = 0; + gd->bd->bi_dram[i].size = 0; + } + + return 0; +} + +/* + * If this function is not defined here, + * board.c alters dram bank zero configuration defined above. + */ +void dram_init_banksize(void) +{ + dram_init(); +} +#endif /* CONFIG_SYS_BOARD_DRAM_INIT */ diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/mpp.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/mpp.c new file mode 100644 index 000000000..0ba6f098c --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/mpp.c @@ -0,0 +1,90 @@ +/* + * arch/arm/mach-kirkwood/mpp.c + * + * MPP functions for Marvell Kirkwood SoCs + * Referenced from Linux kernel source + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/kirkwood.h> +#include <asm/arch/mpp.h> + +static u32 kirkwood_variant(void) +{ + switch (readl(KW_REG_DEVICE_ID) & 0x03) { + case 1: + return MPP_F6192_MASK; + case 2: + return MPP_F6281_MASK; + default: + debug("MPP setup: unknown kirkwood variant\n"); + return 0; + } +} + +#define MPP_CTRL(i) (KW_MPP_BASE + (i* 4)) +#define MPP_NR_REGS (1 + MPP_MAX/8) + +void kirkwood_mpp_conf(const u32 *mpp_list, u32 *mpp_save) +{ + u32 mpp_ctrl[MPP_NR_REGS]; + unsigned int variant_mask; + int i; + + variant_mask = kirkwood_variant(); + if (!variant_mask) + return; + + debug( "initial MPP regs:"); + for (i = 0; i < MPP_NR_REGS; i++) { + mpp_ctrl[i] = readl(MPP_CTRL(i)); + debug(" %08x", mpp_ctrl[i]); + } + debug("\n"); + + + while (*mpp_list) { + unsigned int num = MPP_NUM(*mpp_list); + unsigned int sel = MPP_SEL(*mpp_list); + unsigned int sel_save; + int shift; + + if (num > MPP_MAX) { + debug("kirkwood_mpp_conf: invalid MPP " + "number (%u)\n", num); + continue; + } + if (!(*mpp_list & variant_mask)) { + debug("kirkwood_mpp_conf: requested MPP%u config " + "unavailable on this hardware\n", num); + continue; + } + + shift = (num & 7) << 2; + + if (mpp_save) { + sel_save = (mpp_ctrl[num / 8] >> shift) & 0xf; + *mpp_save = num | (sel_save << 8) | variant_mask; + mpp_save++; + } + + mpp_ctrl[num / 8] &= ~(0xf << shift); + mpp_ctrl[num / 8] |= sel << shift; + + mpp_list++; + } + + debug(" final MPP regs:"); + for (i = 0; i < MPP_NR_REGS; i++) { + writel(mpp_ctrl[i], MPP_CTRL(i)); + debug(" %08x", mpp_ctrl[i]); + } + debug("\n"); + +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/timer.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/timer.c new file mode 100644 index 000000000..a08f4a145 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/kirkwood/timer.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/kirkwood.h> + +#define UBOOT_CNTR 0 /* counter to use for uboot timer */ + +/* Timer reload and current value registers */ +struct kwtmr_val { + u32 reload; /* Timer reload reg */ + u32 val; /* Timer value reg */ +}; + +/* Timer registers */ +struct kwtmr_registers { + u32 ctrl; /* Timer control reg */ + u32 pad[3]; + struct kwtmr_val tmr[2]; + u32 wdt_reload; + u32 wdt_val; +}; + +struct kwtmr_registers *kwtmr_regs = (struct kwtmr_registers *)KW_TIMER_BASE; + +/* + * ARM Timers Registers Map + */ +#define CNTMR_CTRL_REG &kwtmr_regs->ctrl +#define CNTMR_RELOAD_REG(tmrnum) &kwtmr_regs->tmr[tmrnum].reload +#define CNTMR_VAL_REG(tmrnum) &kwtmr_regs->tmr[tmrnum].val + +/* + * ARM Timers Control Register + * CPU_TIMERS_CTRL_REG (CTCR) + */ +#define CTCR_ARM_TIMER_EN_OFFS(cntr) (cntr * 2) +#define CTCR_ARM_TIMER_EN_MASK(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS) +#define CTCR_ARM_TIMER_EN(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS(cntr)) +#define CTCR_ARM_TIMER_DIS(cntr) (0 << CTCR_ARM_TIMER_EN_OFFS(cntr)) + +#define CTCR_ARM_TIMER_AUTO_OFFS(cntr) ((cntr * 2) + 1) +#define CTCR_ARM_TIMER_AUTO_MASK(cntr) (1 << 1) +#define CTCR_ARM_TIMER_AUTO_EN(cntr) (1 << CTCR_ARM_TIMER_AUTO_OFFS(cntr)) +#define CTCR_ARM_TIMER_AUTO_DIS(cntr) (0 << CTCR_ARM_TIMER_AUTO_OFFS(cntr)) + +/* + * ARM Timer\Watchdog Reload Register + * CNTMR_RELOAD_REG (TRR) + */ +#define TRG_ARM_TIMER_REL_OFFS 0 +#define TRG_ARM_TIMER_REL_MASK 0xffffffff + +/* + * ARM Timer\Watchdog Register + * CNTMR_VAL_REG (TVRG) + */ +#define TVR_ARM_TIMER_OFFS 0 +#define TVR_ARM_TIMER_MASK 0xffffffff +#define TVR_ARM_TIMER_MAX 0xffffffff +#define TIMER_LOAD_VAL 0xffffffff + +#define READ_TIMER (readl(CNTMR_VAL_REG(UBOOT_CNTR)) / \ + (CONFIG_SYS_TCLK / 1000)) + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp gd->arch.tbl +#define lastdec gd->arch.lastinc + +ulong get_timer_masked(void) +{ + ulong now = READ_TIMER; + + if (lastdec >= now) { + /* normal mode */ + timestamp += lastdec - now; + } else { + /* we have an overflow ... */ + timestamp += lastdec + + (TIMER_LOAD_VAL / (CONFIG_SYS_TCLK / 1000)) - now; + } + lastdec = now; + + return timestamp; +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +void __udelay(unsigned long usec) +{ + uint current; + ulong delayticks; + + current = readl(CNTMR_VAL_REG(UBOOT_CNTR)); + delayticks = (usec * (CONFIG_SYS_TCLK / 1000000)); + + if (current < delayticks) { + delayticks -= current; + while (readl(CNTMR_VAL_REG(UBOOT_CNTR)) < current) ; + while ((TIMER_LOAD_VAL - delayticks) < + readl(CNTMR_VAL_REG(UBOOT_CNTR))) ; + } else { + while (readl(CNTMR_VAL_REG(UBOOT_CNTR)) > + (current - delayticks)) ; + } +} + +/* + * init the counter + */ +int timer_init(void) +{ + unsigned int cntmrctrl; + + /* load value into timer */ + writel(TIMER_LOAD_VAL, CNTMR_RELOAD_REG(UBOOT_CNTR)); + writel(TIMER_LOAD_VAL, CNTMR_VAL_REG(UBOOT_CNTR)); + + /* enable timer in auto reload mode */ + cntmrctrl = readl(CNTMR_CTRL_REG); + cntmrctrl |= CTCR_ARM_TIMER_EN(UBOOT_CNTR); + cntmrctrl |= CTCR_ARM_TIMER_AUTO_EN(UBOOT_CNTR); + writel(cntmrctrl, CNTMR_CTRL_REG); + + /* init the timestamp and lastdec value */ + lastdec = READ_TIMER; + timestamp = 0; + + return 0; +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk (void) +{ + return (ulong)CONFIG_SYS_HZ; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/lpc32xx/Makefile b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/lpc32xx/Makefile new file mode 100644 index 000000000..314f004eb --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/lpc32xx/Makefile @@ -0,0 +1,8 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y = cpu.o clk.o devices.o timer.o diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/lpc32xx/clk.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/lpc32xx/clk.c new file mode 100644 index 000000000..b7a44d59d --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/lpc32xx/clk.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <div64.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clk.h> +#include <asm/io.h> + +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; + +unsigned int get_sys_clk_rate(void) +{ + if (readl(&clk->sysclk_ctrl) & CLK_SYSCLK_PLL397) + return RTC_CLK_FREQUENCY * 397; + else + return OSC_CLK_FREQUENCY; +} + +unsigned int get_hclk_pll_rate(void) +{ + unsigned long long fin, fref, fcco, fout; + u32 val, m_div, n_div, p_div; + + /* + * Valid frequency ranges: + * 1 * 10^6 <= Fin <= 20 * 10^6 + * 1 * 10^6 <= Fref <= 27 * 10^6 + * 156 * 10^6 <= Fcco <= 320 * 10^6 + */ + + fref = fin = get_sys_clk_rate(); + if (fin > 20000000ULL || fin < 1000000ULL) + return 0; + + val = readl(&clk->hclkpll_ctrl); + m_div = ((val & CLK_HCLK_PLL_FEEDBACK_DIV_MASK) >> 1) + 1; + n_div = ((val & CLK_HCLK_PLL_PREDIV_MASK) >> 9) + 1; + if (val & CLK_HCLK_PLL_DIRECT) + p_div = 0; + else + p_div = ((val & CLK_HCLK_PLL_POSTDIV_MASK) >> 11) + 1; + p_div = 1 << p_div; + + if (val & CLK_HCLK_PLL_BYPASS) { + do_div(fin, p_div); + return fin; + } + + do_div(fref, n_div); + if (fref > 27000000ULL || fref < 1000000ULL) + return 0; + + fout = fref * m_div; + if (val & CLK_HCLK_PLL_FEEDBACK) { + fcco = fout; + do_div(fout, p_div); + } else + fcco = fout * p_div; + + if (fcco > 320000000ULL || fcco < 156000000ULL) + return 0; + + return fout; +} + +unsigned int get_hclk_clk_div(void) +{ + u32 val; + + val = readl(&clk->hclkdiv_ctrl) & CLK_HCLK_ARM_PLL_DIV_MASK; + + return 1 << val; +} + +unsigned int get_hclk_clk_rate(void) +{ + return get_hclk_pll_rate() / get_hclk_clk_div(); +} + +unsigned int get_periph_clk_div(void) +{ + u32 val; + + val = readl(&clk->hclkdiv_ctrl) & CLK_HCLK_PERIPH_DIV_MASK; + + return (val >> 2) + 1; +} + +unsigned int get_periph_clk_rate(void) +{ + if (!(readl(&clk->pwr_ctrl) & CLK_PWR_NORMAL_RUN)) + return get_sys_clk_rate(); + + return get_hclk_pll_rate() / get_periph_clk_div(); +} + +int get_serial_clock(void) +{ + return get_periph_clk_rate(); +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c new file mode 100644 index 000000000..35095a958 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clk.h> +#include <asm/arch/wdt.h> +#include <asm/io.h> + +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; +static struct wdt_regs *wdt = (struct wdt_regs *)WDT_BASE; + +void reset_cpu(ulong addr) +{ + /* Enable watchdog clock */ + setbits_le32(&clk->timclk_ctrl, CLK_TIMCLK_WATCHDOG); + + /* Reset pulse length is 13005 peripheral clock frames */ + writel(13000, &wdt->pulse); + + /* Force WDOG_RESET2 and RESOUT_N signal active */ + writel(WDTIM_MCTRL_RESFRC2 | WDTIM_MCTRL_RESFRC1 | WDTIM_MCTRL_M_RES2, + &wdt->mctrl); + + while (1) + /* NOP */; +} + +#if defined(CONFIG_ARCH_CPU_INIT) +int arch_cpu_init(void) +{ + /* + * It might be necessary to flush data cache, if U-boot is loaded + * from kickstart bootloader, e.g. from S1L loader + */ + flush_dcache_all(); + + return 0; +} +#else +#error "You have to select CONFIG_ARCH_CPU_INIT" +#endif + +#if defined(CONFIG_DISPLAY_CPUINFO) +int print_cpuinfo(void) +{ + printf("CPU: NXP LPC32XX\n"); + printf("CPU clock: %uMHz\n", get_hclk_pll_rate() / 1000000); + printf("AHB bus clock: %uMHz\n", get_hclk_clk_rate() / 1000000); + printf("Peripheral clock: %uMHz\n", get_periph_clk_rate() / 1000000); + + return 0; +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/lpc32xx/devices.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/lpc32xx/devices.c new file mode 100644 index 000000000..b5676578f --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/lpc32xx/devices.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clk.h> +#include <asm/arch/uart.h> +#include <asm/io.h> + +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; +static struct uart_ctrl_regs *ctrl = (struct uart_ctrl_regs *)UART_CTRL_BASE; + +void lpc32xx_uart_init(unsigned int uart_id) +{ + if (uart_id < 1 || uart_id > 7) + return; + + /* Disable loopback mode, if it is set by S1L bootloader */ + clrbits_le32(&ctrl->loop, + UART_LOOPBACK(CONFIG_SYS_LPC32XX_UART)); + + if (uart_id < 3 || uart_id > 6) + return; + + /* Enable UART system clock */ + setbits_le32(&clk->uartclk_ctrl, CLK_UART(uart_id)); + + /* Set UART into autoclock mode */ + clrsetbits_le32(&ctrl->clkmode, + UART_CLKMODE_MASK(uart_id), + UART_CLKMODE_AUTO(uart_id)); + + /* Bypass pre-divider of UART clock */ + writel(CLK_UART_X_DIV(1) | CLK_UART_Y_DIV(1), + &clk->u3clk + (uart_id - 3)); +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/lpc32xx/timer.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/lpc32xx/timer.c new file mode 100644 index 000000000..dc1217e69 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/lpc32xx/timer.c @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2011 Vladimir Zapolskiy <vz@mleia.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clk.h> +#include <asm/arch/timer.h> +#include <asm/io.h> + +static struct timer_regs *timer0 = (struct timer_regs *)TIMER0_BASE; +static struct timer_regs *timer1 = (struct timer_regs *)TIMER1_BASE; +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; + +static void lpc32xx_timer_clock(u32 bit, int enable) +{ + if (enable) + setbits_le32(&clk->timclk_ctrl1, bit); + else + clrbits_le32(&clk->timclk_ctrl1, bit); +} + +static void lpc32xx_timer_reset(struct timer_regs *timer, u32 freq) +{ + writel(TIMER_TCR_COUNTER_RESET, &timer->tcr); + writel(TIMER_TCR_COUNTER_DISABLE, &timer->tcr); + writel(0, &timer->tc); + writel(0, &timer->pr); + + /* Count mode is every rising PCLK edge */ + writel(TIMER_CTCR_MODE_TIMER, &timer->ctcr); + + /* Set prescale counter value */ + writel((get_periph_clk_rate() / freq) - 1, &timer->pr); +} + +static void lpc32xx_timer_count(struct timer_regs *timer, int enable) +{ + if (enable) + writel(TIMER_TCR_COUNTER_ENABLE, &timer->tcr); + else + writel(TIMER_TCR_COUNTER_DISABLE, &timer->tcr); +} + +int timer_init(void) +{ + lpc32xx_timer_clock(CLK_TIMCLK_TIMER0, 1); + lpc32xx_timer_reset(timer0, CONFIG_SYS_HZ); + lpc32xx_timer_count(timer0, 1); + + return 0; +} + +ulong get_timer(ulong base) +{ + return readl(&timer0->tc) - base; +} + +void __udelay(unsigned long usec) +{ + lpc32xx_timer_clock(CLK_TIMCLK_TIMER1, 1); + lpc32xx_timer_reset(timer1, CONFIG_SYS_HZ * 1000); + lpc32xx_timer_count(timer1, 1); + + while (readl(&timer1->tc) < usec) + /* NOP */; + + lpc32xx_timer_count(timer1, 0); + lpc32xx_timer_clock(CLK_TIMCLK_TIMER1, 0); +} + +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +ulong get_tbclk(void) +{ + return CONFIG_SYS_HZ; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mb86r0x/Makefile b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mb86r0x/Makefile new file mode 100644 index 000000000..365892c41 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mb86r0x/Makefile @@ -0,0 +1,8 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y = clock.o reset.o timer.o diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mb86r0x/clock.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mb86r0x/clock.c new file mode 100644 index 000000000..1f6f66eba --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mb86r0x/clock.c @@ -0,0 +1,27 @@ +/* + * (C) Copyright 2010 + * Matthias Weisser <weisserm@arcor.de> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> + +/* + * Get the peripheral bus frequency depending on pll pin settings + */ +ulong get_bus_freq(ulong dummy) +{ + struct mb86r0x_crg * crg = (struct mb86r0x_crg *) + MB86R0x_CRG_BASE; + uint32_t pllmode; + + pllmode = readl(&crg->crpr) & MB86R0x_CRG_CRPR_PLLMODE; + + if (pllmode == MB86R0x_CRG_CRPR_PLLMODE_X20) + return 40000000; + + return 41164767; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mb86r0x/reset.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mb86r0x/reset.c new file mode 100644 index 000000000..7bd77ff20 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mb86r0x/reset.c @@ -0,0 +1,24 @@ +/* + * (C) Copyright 2010 + * Matthias Weisser <weisserm@arcor.de> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> + +/* + * Reset the cpu by setting software reset request bit + */ +void reset_cpu(ulong ignored) +{ + struct mb86r0x_crg * crg = (struct mb86r0x_crg *) + MB86R0x_CRG_BASE; + + writel(MB86R0x_CRSR_SWRSTREQ, &crg->crsr); + while (1) + /* NOP */; + /* Never reached */ +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mb86r0x/timer.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mb86r0x/timer.c new file mode 100644 index 000000000..bb078196d --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mb86r0x/timer.c @@ -0,0 +1,115 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * (C) Copyright 2010 + * Matthias Weisser, Graf-Syteco <weisserm@arcor.de> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <div64.h> +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> + +#define TIMER_LOAD_VAL 0xffffffff +#define TIMER_FREQ (CONFIG_MB86R0x_IOCLK / 256) + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp gd->arch.tbl +#define lastdec gd->arch.lastinc + +static inline unsigned long long tick_to_time(unsigned long long tick) +{ + tick *= CONFIG_SYS_HZ; + do_div(tick, TIMER_FREQ); + + return tick; +} + +static inline unsigned long long usec_to_tick(unsigned long long usec) +{ + usec *= TIMER_FREQ; + do_div(usec, 1000000); + + return usec; +} + +/* nothing really to do with interrupts, just starts up a counter. */ +int timer_init(void) +{ + struct mb86r0x_timer * timer = (struct mb86r0x_timer *) + MB86R0x_TIMER_BASE; + ulong ctrl = readl(&timer->control); + + writel(TIMER_LOAD_VAL, &timer->load); + + ctrl |= MB86R0x_TIMER_ENABLE | MB86R0x_TIMER_PRS_8S | + MB86R0x_TIMER_SIZE_32; + + writel(ctrl, &timer->control); + + /* capture current value time */ + lastdec = readl(&timer->value); + timestamp = 0; /* start "advancing" time stamp from 0 */ + + return 0; +} + +/* + * timer without interrupts + */ +unsigned long long get_ticks(void) +{ + struct mb86r0x_timer * timer = (struct mb86r0x_timer *) + MB86R0x_TIMER_BASE; + ulong now = readl(&timer->value); + + if (now <= lastdec) { + /* normal mode (non roll) */ + /* move stamp forward with absolut diff ticks */ + timestamp += lastdec - now; + } else { + /* we have rollover of incrementer */ + timestamp += lastdec + TIMER_LOAD_VAL - now; + } + lastdec = now; + return timestamp; +} + +ulong get_timer_masked(void) +{ + return tick_to_time(get_ticks()); +} + +void __udelay(unsigned long usec) +{ + unsigned long long tmp; + ulong tmo; + + tmo = usec_to_tick(usec); + tmp = get_ticks(); /* get current timestamp */ + + while ((get_ticks() - tmp) < tmo) /* loop till event */ + /*NOP*/; +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + ulong tbclk; + + tbclk = TIMER_FREQ; + return tbclk; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx25/Makefile b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx25/Makefile new file mode 100644 index 000000000..134c69d42 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx25/Makefile @@ -0,0 +1,7 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ + +obj-y = generic.o timer.o reset.o diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx25/generic.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx25/generic.c new file mode 100644 index 000000000..4e9c0b548 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx25/generic.c @@ -0,0 +1,249 @@ +/* + * (C) Copyright 2009 DENX Software Engineering + * Author: John Rigby <jrigby@gmail.com> + * + * Based on mx27/generic.c: + * Copyright (c) 2008 Eric Jarrige <eric.jarrige@armadeus.org> + * Copyright (c) 2009 Ilya Yanok <yanok@emcraft.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <div64.h> +#include <netdev.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/clock.h> + +#ifdef CONFIG_FSL_ESDHC +#include <fsl_esdhc.h> + +DECLARE_GLOBAL_DATA_PTR; +#endif + +/* + * get the system pll clock in Hz + * + * mfi + mfn / (mfd +1) + * f = 2 * f_ref * -------------------- + * pd + 1 + */ +static unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref) +{ + unsigned int mfi = (pll >> CCM_PLL_MFI_SHIFT) + & CCM_PLL_MFI_MASK; + int mfn = (pll >> CCM_PLL_MFN_SHIFT) + & CCM_PLL_MFN_MASK; + unsigned int mfd = (pll >> CCM_PLL_MFD_SHIFT) + & CCM_PLL_MFD_MASK; + unsigned int pd = (pll >> CCM_PLL_PD_SHIFT) + & CCM_PLL_PD_MASK; + + mfi = mfi <= 5 ? 5 : mfi; + mfn = mfn >= 512 ? mfn - 1024 : mfn; + mfd += 1; + pd += 1; + + return lldiv(2 * (u64) f_ref * (mfi * mfd + mfn), + mfd * pd); +} + +static ulong imx_get_mpllclk(void) +{ + struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; + ulong fref = MXC_HCLK; + + return imx_decode_pll(readl(&ccm->mpctl), fref); +} + +static ulong imx_get_armclk(void) +{ + struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; + ulong cctl = readl(&ccm->cctl); + ulong fref = imx_get_mpllclk(); + ulong div; + + if (cctl & CCM_CCTL_ARM_SRC) + fref = lldiv((u64) fref * 3, 4); + + div = ((cctl >> CCM_CCTL_ARM_DIV_SHIFT) + & CCM_CCTL_ARM_DIV_MASK) + 1; + + return fref / div; +} + +static ulong imx_get_ahbclk(void) +{ + struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; + ulong cctl = readl(&ccm->cctl); + ulong fref = imx_get_armclk(); + ulong div; + + div = ((cctl >> CCM_CCTL_AHB_DIV_SHIFT) + & CCM_CCTL_AHB_DIV_MASK) + 1; + + return fref / div; +} + +static ulong imx_get_ipgclk(void) +{ + return imx_get_ahbclk() / 2; +} + +static ulong imx_get_perclk(int clk) +{ + struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; + ulong fref = imx_get_ahbclk(); + ulong div; + + div = readl(&ccm->pcdr[CCM_PERCLK_REG(clk)]); + div = ((div >> CCM_PERCLK_SHIFT(clk)) & CCM_PERCLK_MASK) + 1; + + return fref / div; +} + +unsigned int mxc_get_clock(enum mxc_clock clk) +{ + if (clk >= MXC_CLK_NUM) + return -1; + switch (clk) { + case MXC_ARM_CLK: + return imx_get_armclk(); + case MXC_AHB_CLK: + return imx_get_ahbclk(); + case MXC_IPG_CLK: + case MXC_CSPI_CLK: + case MXC_FEC_CLK: + return imx_get_ipgclk(); + default: + return imx_get_perclk(clk); + } +} + +u32 get_cpu_rev(void) +{ + u32 srev; + u32 system_rev = 0x25000; + + /* read SREV register from IIM module */ + struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; + srev = readl(&iim->iim_srev); + + switch (srev) { + case 0x00: + system_rev |= CHIP_REV_1_0; + break; + case 0x01: + system_rev |= CHIP_REV_1_1; + break; + case 0x02: + system_rev |= CHIP_REV_1_2; + break; + default: + system_rev |= 0x8000; + break; + } + + return system_rev; +} + +#if defined(CONFIG_DISPLAY_CPUINFO) +static char *get_reset_cause(void) +{ + /* read RCSR register from CCM module */ + struct ccm_regs *ccm = + (struct ccm_regs *)IMX_CCM_BASE; + + u32 cause = readl(&ccm->rcsr) & 0x0f; + + if (cause == 0) + return "POR"; + else if (cause == 1) + return "RST"; + else if ((cause & 2) == 2) + return "WDOG"; + else if ((cause & 4) == 4) + return "SW RESET"; + else if ((cause & 8) == 8) + return "JTAG"; + else + return "unknown reset"; + +} + +int print_cpuinfo(void) +{ + char buf[32]; + u32 cpurev = get_cpu_rev(); + + printf("CPU: Freescale i.MX25 rev%d.%d%s at %s MHz\n", + (cpurev & 0xF0) >> 4, (cpurev & 0x0F), + ((cpurev & 0x8000) ? " unknown" : ""), + strmhz(buf, imx_get_armclk())); + printf("Reset cause: %s\n\n", get_reset_cause()); + return 0; +} +#endif + +void enable_caches(void) +{ +#ifndef CONFIG_SYS_DCACHE_OFF + /* Enable D-cache. I-cache is already enabled in start.S */ + dcache_enable(); +#endif +} + +#if defined(CONFIG_FEC_MXC) +/* + * Initializes on-chip ethernet controllers. + * to override, implement board_eth_init() + */ +int cpu_eth_init(bd_t *bis) +{ + struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; + ulong val; + + val = readl(&ccm->cgr0); + val |= (1 << 23); + writel(val, &ccm->cgr0); + return fecmxc_initialize(bis); +} +#endif + +int get_clocks(void) +{ +#ifdef CONFIG_FSL_ESDHC +#if CONFIG_SYS_FSL_ESDHC_ADDR == IMX_MMC_SDHC2_BASE + gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); +#else + gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC1_CLK); +#endif +#endif + return 0; +} + +#ifdef CONFIG_FSL_ESDHC +/* + * Initializes on-chip MMC controllers. + * to override, implement board_mmc_init() + */ +int cpu_mmc_init(bd_t *bis) +{ + return fsl_esdhc_mmc_init(bis); +} +#endif + +#ifdef CONFIG_FEC_MXC +void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) +{ + int i; + struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; + struct fuse_bank *bank = &iim->bank[0]; + struct fuse_bank0_regs *fuse = + (struct fuse_bank0_regs *)bank->fuse_regs; + + for (i = 0; i < 6; i++) + mac[i] = readl(&fuse->mac_addr[i]) & 0xff; +} +#endif /* CONFIG_FEC_MXC */ diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx25/reset.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx25/reset.c new file mode 100644 index 000000000..5db689dbb --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx25/reset.c @@ -0,0 +1,40 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * (C) Copyright 2009 + * Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> + +/* + * Reset the cpu by setting up the watchdog timer and let it time out + */ +void reset_cpu(ulong ignored) +{ + struct wdog_regs *regs = (struct wdog_regs *)IMX_WDT_BASE; + /* Disable watchdog and set Time-Out field to 0 */ + writew(0, ®s->wcr); + + /* Write Service Sequence */ + writew(WSR_UNLOCK1, ®s->wsr); + writew(WSR_UNLOCK2, ®s->wsr); + + /* Enable watchdog */ + writew(WCR_WDE, ®s->wcr); + + while (1) ; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx25/timer.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx25/timer.c new file mode 100644 index 000000000..7f1979173 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx25/timer.c @@ -0,0 +1,49 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * (C) Copyright 2009 + * Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com> + * + * (C) Copyright 2009 DENX Software Engineering + * Author: John Rigby <jrigby@gmail.com> + * Add support for MX25 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> + +/* nothing really to do with interrupts, just starts up a counter. */ +/* The 32KHz 32-bit timer overruns in 134217 seconds */ +int timer_init(void) +{ + int i; + struct gpt_regs *gpt = (struct gpt_regs *)IMX_GPT1_BASE; + struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; + + /* setup GP Timer 1 */ + writel(GPT_CTRL_SWR, &gpt->ctrl); + + writel(readl(&ccm->cgr1) | CCM_CGR1_GPT1, &ccm->cgr1); + + for (i = 0; i < 100; i++) + writel(0, &gpt->ctrl); /* We have no udelay by now */ + writel(0, &gpt->pre); /* prescaler = 1 */ + /* Freerun Mode, 32KHz input */ + writel(readl(&gpt->ctrl) | GPT_CTRL_CLKSOURCE_32 | GPT_CTRL_FRR, + &gpt->ctrl); + writel(readl(&gpt->ctrl) | GPT_CTRL_TEN, &gpt->ctrl); + + return 0; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx27/Makefile b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx27/Makefile new file mode 100644 index 000000000..4976bbb89 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx27/Makefile @@ -0,0 +1,7 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ + +obj-y = generic.o reset.o timer.o diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx27/generic.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx27/generic.c new file mode 100644 index 000000000..5ee9f07d8 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx27/generic.c @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2008 Eric Jarrige <eric.jarrige@armadeus.org> + * Copyright (c) 2009 Ilya Yanok <yanok@emcraft.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <div64.h> +#include <netdev.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/clock.h> +#include <asm/arch/gpio.h> +#ifdef CONFIG_MXC_MMC +#include <asm/arch/mxcmmc.h> +#endif + +/* + * get the system pll clock in Hz + * + * mfi + mfn / (mfd +1) + * f = 2 * f_ref * -------------------- + * pd + 1 + */ +static unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref) +{ + unsigned int mfi = (pll >> 10) & 0xf; + unsigned int mfn = pll & 0x3ff; + unsigned int mfd = (pll >> 16) & 0x3ff; + unsigned int pd = (pll >> 26) & 0xf; + + mfi = mfi <= 5 ? 5 : mfi; + + return lldiv(2 * (u64)f_ref * (mfi * (mfd + 1) + mfn), + (mfd + 1) * (pd + 1)); +} + +static ulong clk_in_32k(void) +{ + return 1024 * CONFIG_MX27_CLK32; +} + +static ulong clk_in_26m(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + + if (readl(&pll->cscr) & CSCR_OSC26M_DIV1P5) { + /* divide by 1.5 */ + return 26000000 * 2 / 3; + } else { + return 26000000; + } +} + +static ulong imx_get_mpllclk(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + ulong cscr = readl(&pll->cscr); + ulong fref; + + if (cscr & CSCR_MCU_SEL) + fref = clk_in_26m(); + else + fref = clk_in_32k(); + + return imx_decode_pll(readl(&pll->mpctl0), fref); +} + +static ulong imx_get_armclk(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + ulong cscr = readl(&pll->cscr); + ulong fref = imx_get_mpllclk(); + ulong div; + + if (!(cscr & CSCR_ARM_SRC_MPLL)) + fref = lldiv((fref * 2), 3); + + div = ((cscr >> 12) & 0x3) + 1; + + return lldiv(fref, div); +} + +static ulong imx_get_ahbclk(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + ulong cscr = readl(&pll->cscr); + ulong fref = imx_get_mpllclk(); + ulong div; + + div = ((cscr >> 8) & 0x3) + 1; + + return lldiv(fref * 2, 3 * div); +} + +static __attribute__((unused)) ulong imx_get_spllclk(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + ulong cscr = readl(&pll->cscr); + ulong fref; + + if (cscr & CSCR_SP_SEL) + fref = clk_in_26m(); + else + fref = clk_in_32k(); + + return imx_decode_pll(readl(&pll->spctl0), fref); +} + +static ulong imx_decode_perclk(ulong div) +{ + return lldiv((imx_get_mpllclk() * 2), (div * 3)); +} + +static ulong imx_get_perclk1(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + + return imx_decode_perclk((readl(&pll->pcdr1) & 0x3f) + 1); +} + +static ulong imx_get_perclk2(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + + return imx_decode_perclk(((readl(&pll->pcdr1) >> 8) & 0x3f) + 1); +} + +static __attribute__((unused)) ulong imx_get_perclk3(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + + return imx_decode_perclk(((readl(&pll->pcdr1) >> 16) & 0x3f) + 1); +} + +static __attribute__((unused)) ulong imx_get_perclk4(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + + return imx_decode_perclk(((readl(&pll->pcdr1) >> 24) & 0x3f) + 1); +} + +unsigned int mxc_get_clock(enum mxc_clock clk) +{ + switch (clk) { + case MXC_ARM_CLK: + return imx_get_armclk(); + case MXC_I2C_CLK: + return imx_get_ahbclk()/2; + case MXC_UART_CLK: + return imx_get_perclk1(); + case MXC_FEC_CLK: + return imx_get_ahbclk(); + case MXC_ESDHC_CLK: + return imx_get_perclk2(); + } + return -1; +} + + +#if defined(CONFIG_DISPLAY_CPUINFO) +int print_cpuinfo (void) +{ + char buf[32]; + + printf("CPU: Freescale i.MX27 at %s MHz\n\n", + strmhz(buf, imx_get_mpllclk())); + return 0; +} +#endif + +int cpu_eth_init(bd_t *bis) +{ +#if defined(CONFIG_FEC_MXC) + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + + /* enable FEC clock */ + writel(readl(&pll->pccr1) | PCCR1_HCLK_FEC, &pll->pccr1); + writel(readl(&pll->pccr0) | PCCR0_FEC_EN, &pll->pccr0); + return fecmxc_initialize(bis); +#else + return 0; +#endif +} + +/* + * Initializes on-chip MMC controllers. + * to override, implement board_mmc_init() + */ +int cpu_mmc_init(bd_t *bis) +{ +#ifdef CONFIG_MXC_MMC + return mxc_mmc_init(bis); +#else + return 0; +#endif +} + +void imx_gpio_mode(int gpio_mode) +{ + struct gpio_port_regs *regs = (struct gpio_port_regs *)IMX_GPIO_BASE; + unsigned int pin = gpio_mode & GPIO_PIN_MASK; + unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> GPIO_OCR_SHIFT; + unsigned int aout = (gpio_mode & GPIO_AOUT_MASK) >> GPIO_AOUT_SHIFT; + unsigned int bout = (gpio_mode & GPIO_BOUT_MASK) >> GPIO_BOUT_SHIFT; + unsigned int tmp; + + /* Pullup enable */ + if (gpio_mode & GPIO_PUEN) { + writel(readl(®s->port[port].puen) | (1 << pin), + ®s->port[port].puen); + } else { + writel(readl(®s->port[port].puen) & ~(1 << pin), + ®s->port[port].puen); + } + + /* Data direction */ + if (gpio_mode & GPIO_OUT) { + writel(readl(®s->port[port].gpio_dir) | 1 << pin, + ®s->port[port].gpio_dir); + } else { + writel(readl(®s->port[port].gpio_dir) & ~(1 << pin), + ®s->port[port].gpio_dir); + } + + /* Primary / alternate function */ + if (gpio_mode & GPIO_AF) { + writel(readl(®s->port[port].gpr) | (1 << pin), + ®s->port[port].gpr); + } else { + writel(readl(®s->port[port].gpr) & ~(1 << pin), + ®s->port[port].gpr); + } + + /* use as gpio? */ + if (!(gpio_mode & (GPIO_PF | GPIO_AF))) { + writel(readl(®s->port[port].gius) | (1 << pin), + ®s->port[port].gius); + } else { + writel(readl(®s->port[port].gius) & ~(1 << pin), + ®s->port[port].gius); + } + + /* Output / input configuration */ + if (pin < 16) { + tmp = readl(®s->port[port].ocr1); + tmp &= ~(3 << (pin * 2)); + tmp |= (ocr << (pin * 2)); + writel(tmp, ®s->port[port].ocr1); + + writel(readl(®s->port[port].iconfa1) & ~(3 << (pin * 2)), + ®s->port[port].iconfa1); + writel(readl(®s->port[port].iconfa1) | aout << (pin * 2), + ®s->port[port].iconfa1); + writel(readl(®s->port[port].iconfb1) & ~(3 << (pin * 2)), + ®s->port[port].iconfb1); + writel(readl(®s->port[port].iconfb1) | bout << (pin * 2), + ®s->port[port].iconfb1); + } else { + pin -= 16; + + tmp = readl(®s->port[port].ocr2); + tmp &= ~(3 << (pin * 2)); + tmp |= (ocr << (pin * 2)); + writel(tmp, ®s->port[port].ocr2); + + writel(readl(®s->port[port].iconfa2) & ~(3 << (pin * 2)), + ®s->port[port].iconfa2); + writel(readl(®s->port[port].iconfa2) | aout << (pin * 2), + ®s->port[port].iconfa2); + writel(readl(®s->port[port].iconfb2) & ~(3 << (pin * 2)), + ®s->port[port].iconfb2); + writel(readl(®s->port[port].iconfb2) | bout << (pin * 2), + ®s->port[port].iconfb2); + } +} + +#ifdef CONFIG_MXC_UART +void mx27_uart1_init_pins(void) +{ + int i; + unsigned int mode[] = { + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + }; + + for (i = 0; i < ARRAY_SIZE(mode); i++) + imx_gpio_mode(mode[i]); + +} +#endif /* CONFIG_MXC_UART */ + +#ifdef CONFIG_FEC_MXC +void mx27_fec_init_pins(void) +{ + int i; + unsigned int mode[] = { + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC | GPIO_PUEN, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_CLR, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, + }; + + for (i = 0; i < ARRAY_SIZE(mode); i++) + imx_gpio_mode(mode[i]); +} + +void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) +{ + int i; + struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; + struct fuse_bank *bank = &iim->bank[0]; + struct fuse_bank0_regs *fuse = + (struct fuse_bank0_regs *)bank->fuse_regs; + + for (i = 0; i < 6; i++) + mac[6 - 1 - i] = readl(&fuse->mac_addr[i]) & 0xff; +} +#endif /* CONFIG_FEC_MXC */ + +#ifdef CONFIG_MXC_MMC +void mx27_sd1_init_pins(void) +{ + int i; + unsigned int mode[] = { + PE18_PF_SD1_D0, + PE19_PF_SD1_D1, + PE20_PF_SD1_D2, + PE21_PF_SD1_D3, + PE22_PF_SD1_CMD, + PE23_PF_SD1_CLK, + }; + + for (i = 0; i < ARRAY_SIZE(mode); i++) + imx_gpio_mode(mode[i]); + +} + +void mx27_sd2_init_pins(void) +{ + int i; + unsigned int mode[] = { + PB4_PF_SD2_D0, + PB5_PF_SD2_D1, + PB6_PF_SD2_D2, + PB7_PF_SD2_D3, + PB8_PF_SD2_CMD, + PB9_PF_SD2_CLK, + }; + + for (i = 0; i < ARRAY_SIZE(mode); i++) + imx_gpio_mode(mode[i]); + +} +#endif /* CONFIG_MXC_MMC */ + +#ifndef CONFIG_SYS_DCACHE_OFF +void enable_caches(void) +{ + /* Enable D-cache. I-cache is already enabled in start.S */ + dcache_enable(); +} +#endif /* CONFIG_SYS_DCACHE_OFF */ diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx27/reset.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx27/reset.c new file mode 100644 index 000000000..f7b4a1c83 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx27/reset.c @@ -0,0 +1,41 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * (C) Copyright 2009 + * Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> + +/* + * Reset the cpu by setting up the watchdog timer and let it time out + */ +void reset_cpu(ulong ignored) +{ + struct wdog_regs *regs = (struct wdog_regs *)IMX_WDT_BASE; + /* Disable watchdog and set Time-Out field to 0 */ + writel(0x00000000, ®s->wcr); + + /* Write Service Sequence */ + writel(0x00005555, ®s->wsr); + writel(0x0000AAAA, ®s->wsr); + + /* Enable watchdog */ + writel(WCR_WDE, ®s->wcr); + + while (1); + /*NOTREACHED*/ +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx27/timer.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx27/timer.c new file mode 100644 index 000000000..40fe2aafc --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mx27/timer.c @@ -0,0 +1,162 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * (C) Copyright 2009 + * Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <div64.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> + +/* General purpose timers bitfields */ +#define GPTCR_SWR (1 << 15) /* Software reset */ +#define GPTCR_FRR (1 << 8) /* Freerun / restart */ +#define GPTCR_CLKSOURCE_32 (4 << 1) /* Clock source */ +#define GPTCR_TEN 1 /* Timer enable */ + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp (gd->arch.tbl) +#define lastinc (gd->arch.lastinc) + +/* + * "time" is measured in 1 / CONFIG_SYS_HZ seconds, + * "tick" is internal timer period + */ +#ifdef CONFIG_MX27_TIMER_HIGH_PRECISION +/* ~0.4% error - measured with stop-watch on 100s boot-delay */ +static inline unsigned long long tick_to_time(unsigned long long tick) +{ + tick *= CONFIG_SYS_HZ; + do_div(tick, CONFIG_MX27_CLK32); + return tick; +} + +static inline unsigned long long time_to_tick(unsigned long long time) +{ + time *= CONFIG_MX27_CLK32; + do_div(time, CONFIG_SYS_HZ); + return time; +} + +static inline unsigned long long us_to_tick(unsigned long long us) +{ + us = us * CONFIG_MX27_CLK32 + 999999; + do_div(us, 1000000); + return us; +} +#else +/* ~2% error */ +#define TICK_PER_TIME ((CONFIG_MX27_CLK32 + CONFIG_SYS_HZ / 2) / \ + CONFIG_SYS_HZ) +#define US_PER_TICK (1000000 / CONFIG_MX27_CLK32) + +static inline unsigned long long tick_to_time(unsigned long long tick) +{ + do_div(tick, TICK_PER_TIME); + return tick; +} + +static inline unsigned long long time_to_tick(unsigned long long time) +{ + return time * TICK_PER_TIME; +} + +static inline unsigned long long us_to_tick(unsigned long long us) +{ + us += US_PER_TICK - 1; + do_div(us, US_PER_TICK); + return us; +} +#endif + +/* nothing really to do with interrupts, just starts up a counter. */ +/* The 32768Hz 32-bit timer overruns in 131072 seconds */ +int timer_init(void) +{ + int i; + struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE; + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + + /* setup GP Timer 1 */ + writel(GPTCR_SWR, ®s->gpt_tctl); + + writel(readl(&pll->pccr0) | PCCR0_GPT1_EN, &pll->pccr0); + writel(readl(&pll->pccr1) | PCCR1_PERCLK1_EN, &pll->pccr1); + + for (i = 0; i < 100; i++) + writel(0, ®s->gpt_tctl); /* We have no udelay by now */ + writel(0, ®s->gpt_tprer); /* 32Khz */ + /* Freerun Mode, PERCLK1 input */ + writel(readl(®s->gpt_tctl) | GPTCR_CLKSOURCE_32 | GPTCR_FRR, + ®s->gpt_tctl); + writel(readl(®s->gpt_tctl) | GPTCR_TEN, ®s->gpt_tctl); + + return 0; +} + +unsigned long long get_ticks(void) +{ + struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE; + ulong now = readl(®s->gpt_tcn); /* current tick value */ + + if (now >= lastinc) { + /* + * normal mode (non roll) + * move stamp forward with absolut diff ticks + */ + timestamp += (now - lastinc); + } else { + /* we have rollover of incrementer */ + timestamp += (0xFFFFFFFF - lastinc) + now; + } + lastinc = now; + return timestamp; +} + +ulong get_timer_masked(void) +{ + /* + * get_ticks() returns a long long (64 bit), it wraps in + * 2^64 / CONFIG_MX27_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~ + * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in + * 5 * 10^6 days - long enough. + */ + return tick_to_time(get_ticks()); +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +/* delay x useconds AND preserve advance timstamp value */ +void __udelay(unsigned long usec) +{ + unsigned long long tmp; + ulong tmo; + + tmo = us_to_tick(usec); + tmp = get_ticks() + tmo; /* get current timestamp */ + + while (get_ticks() < tmp) /* loop till event */ + /*NOP*/; +} + +ulong get_tbclk(void) +{ + return CONFIG_MX27_CLK32; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/Makefile b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/Makefile new file mode 100644 index 000000000..6c5949455 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/Makefile @@ -0,0 +1,85 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +extra-$(CONFIG_SPL_BUILD) := start.o + +obj-y = clock.o mxs.o iomux.o timer.o + +ifdef CONFIG_SPL_BUILD +obj-y += spl_boot.o spl_lradc_init.o spl_mem_init.o spl_power_init.o +endif + +# Specify the target for use in elftosb call +MKIMAGE_TARGET-$(CONFIG_MX23) = mxsimage.mx23.cfg +MKIMAGE_TARGET-$(CONFIG_MX28) = mxsimage.mx28.cfg + +# Generate HAB-capable IVT +# +# Note on computing the post-IVT size field value for the U-Boot binary. +# The value is the result of adding the following: +# -> The size of U-Boot binary aligned to 64B (u-boot.bin) +# -> The size of IVT block aligned to 64B (u-boot.ivt) +# -> The size of U-Boot signature (u-boot.sig), 3904 B +# -> The 64B hole in front of U-Boot binary for 'struct mxs_spl_data' passing +# +quiet_cmd_mkivt_mxs = MXSIVT $@ +cmd_mkivt_mxs = \ + sz=`expr \`stat -c "%s" $^\` + 64 + 3904 + 128` ; \ + echo -n "0x402000d1 $2 0 0 0 $3 $4 0 $$sz 0 0 0 0 0 0 0" | \ + tr -s " " | xargs -d " " -i printf "%08x\n" "{}" | rev | \ + sed "s/\(.\)\(.\)/\\\\\\\\x\2\1\n/g" | xargs -i printf "{}" >$@ + +# Align binary to 64B +quiet_cmd_mkalign_mxs = MXSALGN $@ +cmd_mkalign_mxs = \ + dd if=$^ of=$@ ibs=64 conv=sync 2>/dev/null && \ + mv $@ $^ + +# Assemble the CSF file +quiet_cmd_mkcsfreq_mxs = MXSCSFR $@ +cmd_mkcsfreq_mxs = \ + ivt=$(word 1,$^) ; \ + bin=$(word 2,$^) ; \ + csf=$(word 3,$^) ; \ + sed "s@VENDOR@$(VENDOR)@g;s@BOARD@$(BOARD)@g" "$$csf" | \ + sed '/^\#\#Blocks/ d' > $@ ; \ + echo " Blocks = $2 0x0 `stat -c '%s' $$bin` \"$$bin\" , \\" >> $@ ; \ + echo " $3 0x0 0x40 \"$$ivt\"" >> $@ + +# Sign files +quiet_cmd_mkcst_mxs = MXSCST $@ +cmd_mkcst_mxs = cst -o $@ < $^ \ + $(if $(KBUILD_VERBOSE:1=), >/dev/null) + +spl/u-boot-spl.ivt: spl/u-boot-spl.bin + $(call if_changed,mkalign_mxs) + $(call if_changed,mkivt_mxs,$(CONFIG_SPL_TEXT_BASE),\ + 0x00008000,0x00008040) + +u-boot.ivt: u-boot.bin + $(call if_changed,mkalign_mxs) + $(call if_changed,mkivt_mxs,$(CONFIG_SYS_TEXT_BASE),\ + 0x40001000,0x40001040) + +spl/u-boot-spl.csf: spl/u-boot-spl.ivt spl/u-boot-spl.bin board/$(VENDOR)/$(BOARD)/sign/u-boot-spl.csf + $(call if_changed,mkcsfreq_mxs,$(CONFIG_SPL_TEXT_BASE),0x8000) + +u-boot.csf: u-boot.ivt u-boot.bin board/$(VENDOR)/$(BOARD)/sign/u-boot.csf + $(call if_changed,mkcsfreq_mxs,$(CONFIG_SYS_TEXT_BASE),0x40001000) + +%.sig: %.csf + $(call if_changed,mkcst_mxs) + +quiet_cmd_mkimage_mxs = MKIMAGE $@ +cmd_mkimage_mxs = $(objtree)/tools/mkimage -n $< -T mxsimage $@ \ + $(if $(KBUILD_VERBOSE:1=), >/dev/null) + +u-boot.sb: $(src)/$(MKIMAGE_TARGET-y) u-boot.bin spl/u-boot-spl.bin FORCE + $(call if_changed,mkimage_mxs) + +u-boot-signed.sb: $(src)/mxsimage-signed.cfg u-boot.ivt u-boot.sig spl/u-boot-spl.ivt spl/u-boot-spl.sig FORCE + $(call if_changed,mkimage_mxs) diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/clock.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/clock.c new file mode 100644 index 000000000..e9d8800f8 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/clock.c @@ -0,0 +1,436 @@ +/* + * Freescale i.MX23/i.MX28 clock setup code + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * Based on code from LTIB: + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/imx-regs.h> + +/* + * The PLL frequency is 480MHz and XTAL frequency is 24MHz + * iMX23: datasheet section 4.2 + * iMX28: datasheet section 10.2 + */ +#define PLL_FREQ_KHZ 480000 +#define PLL_FREQ_COEF 18 +#define XTAL_FREQ_KHZ 24000 + +#define PLL_FREQ_MHZ (PLL_FREQ_KHZ / 1000) +#define XTAL_FREQ_MHZ (XTAL_FREQ_KHZ / 1000) + +#if defined(CONFIG_MX23) +#define MXC_SSPCLK_MAX MXC_SSPCLK0 +#elif defined(CONFIG_MX28) +#define MXC_SSPCLK_MAX MXC_SSPCLK3 +#endif + +static uint32_t mxs_get_pclk(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + + uint32_t clkctrl, clkseq, div; + uint8_t clkfrac, frac; + + clkctrl = readl(&clkctrl_regs->hw_clkctrl_cpu); + + /* No support of fractional divider calculation */ + if (clkctrl & + (CLKCTRL_CPU_DIV_XTAL_FRAC_EN | CLKCTRL_CPU_DIV_CPU_FRAC_EN)) { + return 0; + } + + clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq); + + /* XTAL Path */ + if (clkseq & CLKCTRL_CLKSEQ_BYPASS_CPU) { + div = (clkctrl & CLKCTRL_CPU_DIV_XTAL_MASK) >> + CLKCTRL_CPU_DIV_XTAL_OFFSET; + return XTAL_FREQ_MHZ / div; + } + + /* REF Path */ + clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]); + frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK; + div = clkctrl & CLKCTRL_CPU_DIV_CPU_MASK; + return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div; +} + +static uint32_t mxs_get_hclk(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + + uint32_t div; + uint32_t clkctrl; + + clkctrl = readl(&clkctrl_regs->hw_clkctrl_hbus); + + /* No support of fractional divider calculation */ + if (clkctrl & CLKCTRL_HBUS_DIV_FRAC_EN) + return 0; + + div = clkctrl & CLKCTRL_HBUS_DIV_MASK; + return mxs_get_pclk() / div; +} + +static uint32_t mxs_get_emiclk(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + + uint32_t clkctrl, clkseq, div; + uint8_t clkfrac, frac; + + clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq); + clkctrl = readl(&clkctrl_regs->hw_clkctrl_emi); + + /* XTAL Path */ + if (clkseq & CLKCTRL_CLKSEQ_BYPASS_EMI) { + div = (clkctrl & CLKCTRL_EMI_DIV_XTAL_MASK) >> + CLKCTRL_EMI_DIV_XTAL_OFFSET; + return XTAL_FREQ_MHZ / div; + } + + /* REF Path */ + clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]); + frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK; + div = clkctrl & CLKCTRL_EMI_DIV_EMI_MASK; + return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div; +} + +static uint32_t mxs_get_gpmiclk(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; +#if defined(CONFIG_MX23) + uint8_t *reg = + &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]; +#elif defined(CONFIG_MX28) + uint8_t *reg = + &clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_GPMI]; +#endif + uint32_t clkctrl, clkseq, div; + uint8_t clkfrac, frac; + + clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq); + clkctrl = readl(&clkctrl_regs->hw_clkctrl_gpmi); + + /* XTAL Path */ + if (clkseq & CLKCTRL_CLKSEQ_BYPASS_GPMI) { + div = clkctrl & CLKCTRL_GPMI_DIV_MASK; + return XTAL_FREQ_MHZ / div; + } + + /* REF Path */ + clkfrac = readb(reg); + frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK; + div = clkctrl & CLKCTRL_GPMI_DIV_MASK; + return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div; +} + +/* + * Set IO clock frequency, in kHz + */ +void mxs_set_ioclk(enum mxs_ioclock io, uint32_t freq) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + uint32_t div; + int io_reg; + + if (freq == 0) + return; + + if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1)) + return; + + div = (PLL_FREQ_KHZ * PLL_FREQ_COEF) / freq; + + if (div < 18) + div = 18; + + if (div > 35) + div = 35; + + io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */ + writeb(CLKCTRL_FRAC_CLKGATE, + &clkctrl_regs->hw_clkctrl_frac0_set[io_reg]); + writeb(CLKCTRL_FRAC_CLKGATE | (div & CLKCTRL_FRAC_FRAC_MASK), + &clkctrl_regs->hw_clkctrl_frac0[io_reg]); + writeb(CLKCTRL_FRAC_CLKGATE, + &clkctrl_regs->hw_clkctrl_frac0_clr[io_reg]); +} + +/* + * Get IO clock, returns IO clock in kHz + */ +static uint32_t mxs_get_ioclk(enum mxs_ioclock io) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + uint8_t ret; + int io_reg; + + if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1)) + return 0; + + io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */ + + ret = readb(&clkctrl_regs->hw_clkctrl_frac0[io_reg]) & + CLKCTRL_FRAC_FRAC_MASK; + + return (PLL_FREQ_KHZ * PLL_FREQ_COEF) / ret; +} + +/* + * Configure SSP clock frequency, in kHz + */ +void mxs_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + uint32_t clk, clkreg; + + if (ssp > MXC_SSPCLK_MAX) + return; + + clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) + + (ssp * sizeof(struct mxs_register_32)); + + clrbits_le32(clkreg, CLKCTRL_SSP_CLKGATE); + while (readl(clkreg) & CLKCTRL_SSP_CLKGATE) + ; + + if (xtal) + clk = XTAL_FREQ_KHZ; + else + clk = mxs_get_ioclk(ssp >> 1); + + if (freq > clk) + return; + + /* Calculate the divider and cap it if necessary */ + clk /= freq; + if (clk > CLKCTRL_SSP_DIV_MASK) + clk = CLKCTRL_SSP_DIV_MASK; + + clrsetbits_le32(clkreg, CLKCTRL_SSP_DIV_MASK, clk); + while (readl(clkreg) & CLKCTRL_SSP_BUSY) + ; + + if (xtal) + writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp, + &clkctrl_regs->hw_clkctrl_clkseq_set); + else + writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp, + &clkctrl_regs->hw_clkctrl_clkseq_clr); +} + +/* + * Return SSP frequency, in kHz + */ +static uint32_t mxs_get_sspclk(enum mxs_sspclock ssp) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + uint32_t clkreg; + uint32_t clk, tmp; + + if (ssp > MXC_SSPCLK_MAX) + return 0; + + tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq); + if (tmp & (CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp)) + return XTAL_FREQ_KHZ; + + clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) + + (ssp * sizeof(struct mxs_register_32)); + + tmp = readl(clkreg) & CLKCTRL_SSP_DIV_MASK; + + if (tmp == 0) + return 0; + + clk = mxs_get_ioclk(ssp >> 1); + + return clk / tmp; +} + +/* + * Set SSP/MMC bus frequency, in kHz) + */ +void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq) +{ + struct mxs_ssp_regs *ssp_regs; + const enum mxs_sspclock clk = mxs_ssp_clock_by_bus(bus); + const uint32_t sspclk = mxs_get_sspclk(clk); + uint32_t reg; + uint32_t divide, rate, tgtclk; + + ssp_regs = mxs_ssp_regs_by_bus(bus); + + /* + * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)), + * CLOCK_DIVIDE has to be an even value from 2 to 254, and + * CLOCK_RATE could be any integer from 0 to 255. + */ + for (divide = 2; divide < 254; divide += 2) { + rate = sspclk / freq / divide; + if (rate <= 256) + break; + } + + tgtclk = sspclk / divide / rate; + while (tgtclk > freq) { + rate++; + tgtclk = sspclk / divide / rate; + } + if (rate > 256) + rate = 256; + + /* Always set timeout the maximum */ + reg = SSP_TIMING_TIMEOUT_MASK | + (divide << SSP_TIMING_CLOCK_DIVIDE_OFFSET) | + ((rate - 1) << SSP_TIMING_CLOCK_RATE_OFFSET); + writel(reg, &ssp_regs->hw_ssp_timing); + + debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n", + bus, tgtclk, freq); +} + +void mxs_set_lcdclk(uint32_t freq) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + uint32_t fp, x, k_rest, k_best, x_best, tk; + int32_t k_best_l = 999, k_best_t = 0, x_best_l = 0xff, x_best_t = 0xff; + + if (freq == 0) + return; + +#if defined(CONFIG_MX23) + writel(CLKCTRL_CLKSEQ_BYPASS_PIX, &clkctrl_regs->hw_clkctrl_clkseq_clr); +#elif defined(CONFIG_MX28) + writel(CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF, &clkctrl_regs->hw_clkctrl_clkseq_clr); +#endif + + /* + * / 18 \ 1 1 + * freq kHz = | 480000000 Hz * -- | * --- * ------ + * \ x / k 1000 + * + * 480000000 Hz 18 + * ------------ * -- + * freq kHz x + * k = ------------------- + * 1000 + */ + + fp = ((PLL_FREQ_KHZ * 1000) / freq) * 18; + + for (x = 18; x <= 35; x++) { + tk = fp / x; + if ((tk / 1000 == 0) || (tk / 1000 > 255)) + continue; + + k_rest = tk % 1000; + + if (k_rest < (k_best_l % 1000)) { + k_best_l = tk; + x_best_l = x; + } + + if (k_rest > (k_best_t % 1000)) { + k_best_t = tk; + x_best_t = x; + } + } + + if (1000 - (k_best_t % 1000) > (k_best_l % 1000)) { + k_best = k_best_l; + x_best = x_best_l; + } else { + k_best = k_best_t; + x_best = x_best_t; + } + + k_best /= 1000; + +#if defined(CONFIG_MX23) + writeb(CLKCTRL_FRAC_CLKGATE, + &clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_PIX]); + writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK), + &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_PIX]); + writeb(CLKCTRL_FRAC_CLKGATE, + &clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_PIX]); + + writel(CLKCTRL_PIX_CLKGATE, + &clkctrl_regs->hw_clkctrl_pix_set); + clrsetbits_le32(&clkctrl_regs->hw_clkctrl_pix, + CLKCTRL_PIX_DIV_MASK | CLKCTRL_PIX_CLKGATE, + k_best << CLKCTRL_PIX_DIV_OFFSET); + + while (readl(&clkctrl_regs->hw_clkctrl_pix) & CLKCTRL_PIX_BUSY) + ; +#elif defined(CONFIG_MX28) + writeb(CLKCTRL_FRAC_CLKGATE, + &clkctrl_regs->hw_clkctrl_frac1_set[CLKCTRL_FRAC1_PIX]); + writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK), + &clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_PIX]); + writeb(CLKCTRL_FRAC_CLKGATE, + &clkctrl_regs->hw_clkctrl_frac1_clr[CLKCTRL_FRAC1_PIX]); + + writel(CLKCTRL_DIS_LCDIF_CLKGATE, + &clkctrl_regs->hw_clkctrl_lcdif_set); + clrsetbits_le32(&clkctrl_regs->hw_clkctrl_lcdif, + CLKCTRL_DIS_LCDIF_DIV_MASK | CLKCTRL_DIS_LCDIF_CLKGATE, + k_best << CLKCTRL_DIS_LCDIF_DIV_OFFSET); + + while (readl(&clkctrl_regs->hw_clkctrl_lcdif) & CLKCTRL_DIS_LCDIF_BUSY) + ; +#endif +} + +uint32_t mxc_get_clock(enum mxc_clock clk) +{ + switch (clk) { + case MXC_ARM_CLK: + return mxs_get_pclk() * 1000000; + case MXC_GPMI_CLK: + return mxs_get_gpmiclk() * 1000000; + case MXC_AHB_CLK: + case MXC_IPG_CLK: + return mxs_get_hclk() * 1000000; + case MXC_EMI_CLK: + return mxs_get_emiclk(); + case MXC_IO0_CLK: + return mxs_get_ioclk(MXC_IOCLK0); + case MXC_IO1_CLK: + return mxs_get_ioclk(MXC_IOCLK1); + case MXC_XTAL_CLK: + return XTAL_FREQ_KHZ * 1000; + case MXC_SSP0_CLK: + return mxs_get_sspclk(MXC_SSPCLK0); +#ifdef CONFIG_MX28 + case MXC_SSP1_CLK: + return mxs_get_sspclk(MXC_SSPCLK1); + case MXC_SSP2_CLK: + return mxs_get_sspclk(MXC_SSPCLK2); + case MXC_SSP3_CLK: + return mxs_get_sspclk(MXC_SSPCLK3); +#endif + } + + return 0; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/iomux.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/iomux.c new file mode 100644 index 000000000..2e6be06fd --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/iomux.c @@ -0,0 +1,97 @@ +/* + * Copyright 2004-2006,2010 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de> + * Copyright (C) 2009 by Jan Weitzel Phytec Messtechnik GmbH, + * <armlinux@phytec.de> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/iomux.h> +#include <asm/arch/imx-regs.h> + +#if defined(CONFIG_MX23) +#define DRIVE_OFFSET 0x200 +#define PULL_OFFSET 0x400 +#elif defined(CONFIG_MX28) +#define DRIVE_OFFSET 0x300 +#define PULL_OFFSET 0x600 +#else +#error "Please select CONFIG_MX23 or CONFIG_MX28" +#endif + +/* + * configures a single pad in the iomuxer + */ +int mxs_iomux_setup_pad(iomux_cfg_t pad) +{ + u32 reg, ofs, bp, bm; + void *iomux_base = (void *)MXS_PINCTRL_BASE; + struct mxs_register_32 *mxs_reg; + + /* muxsel */ + ofs = 0x100; + ofs += PAD_BANK(pad) * 0x20 + PAD_PIN(pad) / 16 * 0x10; + bp = PAD_PIN(pad) % 16 * 2; + bm = 0x3 << bp; + reg = readl(iomux_base + ofs); + reg &= ~bm; + reg |= PAD_MUXSEL(pad) << bp; + writel(reg, iomux_base + ofs); + + /* drive */ + ofs = DRIVE_OFFSET; + ofs += PAD_BANK(pad) * 0x40 + PAD_PIN(pad) / 8 * 0x10; + /* mA */ + if (PAD_MA_VALID(pad)) { + bp = PAD_PIN(pad) % 8 * 4; + bm = 0x3 << bp; + reg = readl(iomux_base + ofs); + reg &= ~bm; + reg |= PAD_MA(pad) << bp; + writel(reg, iomux_base + ofs); + } + /* vol */ + if (PAD_VOL_VALID(pad)) { + bp = PAD_PIN(pad) % 8 * 4 + 2; + mxs_reg = (struct mxs_register_32 *)(iomux_base + ofs); + if (PAD_VOL(pad)) + writel(1 << bp, &mxs_reg->reg_set); + else + writel(1 << bp, &mxs_reg->reg_clr); + } + + /* pull */ + if (PAD_PULL_VALID(pad)) { + ofs = PULL_OFFSET; + ofs += PAD_BANK(pad) * 0x10; + bp = PAD_PIN(pad); + mxs_reg = (struct mxs_register_32 *)(iomux_base + ofs); + if (PAD_PULL(pad)) + writel(1 << bp, &mxs_reg->reg_set); + else + writel(1 << bp, &mxs_reg->reg_clr); + } + + return 0; +} + +int mxs_iomux_setup_multiple_pads(const iomux_cfg_t *pad_list, unsigned count) +{ + const iomux_cfg_t *p = pad_list; + int i; + int ret; + + for (i = 0; i < count; i++) { + ret = mxs_iomux_setup_pad(*p); + if (ret) + return ret; + p++; + } + + return 0; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/mxs.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/mxs.c new file mode 100644 index 000000000..365542fe0 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/mxs.c @@ -0,0 +1,299 @@ +/* + * Freescale i.MX23/i.MX28 common code + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * Based on code from LTIB: + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/imx-common/dma.h> +#include <asm/arch/gpio.h> +#include <asm/arch/iomux.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/sys_proto.h> +#include <linux/compiler.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Lowlevel init isn't used on i.MX28, so just have a dummy here */ +inline void lowlevel_init(void) {} + +void reset_cpu(ulong ignored) __attribute__((noreturn)); + +void reset_cpu(ulong ignored) +{ + struct mxs_rtc_regs *rtc_regs = + (struct mxs_rtc_regs *)MXS_RTC_BASE; + struct mxs_lcdif_regs *lcdif_regs = + (struct mxs_lcdif_regs *)MXS_LCDIF_BASE; + + /* + * Shut down the LCD controller as it interferes with BootROM boot mode + * pads sampling. + */ + writel(LCDIF_CTRL_RUN, &lcdif_regs->hw_lcdif_ctrl_clr); + + /* Wait 1 uS before doing the actual watchdog reset */ + writel(1, &rtc_regs->hw_rtc_watchdog); + writel(RTC_CTRL_WATCHDOGEN, &rtc_regs->hw_rtc_ctrl_set); + + /* Endless loop, reset will exit from here */ + for (;;) + ; +} + +void enable_caches(void) +{ +#ifndef CONFIG_SYS_ICACHE_OFF + icache_enable(); +#endif +#ifndef CONFIG_SYS_DCACHE_OFF + dcache_enable(); +#endif +} + +/* + * This function will craft a jumptable at 0x0 which will redirect interrupt + * vectoring to proper location of U-Boot in RAM. + * + * The structure of the jumptable will be as follows: + * ldr pc, [pc, #0x18] ..... for each vector, thus repeated 8 times + * <destination address> ... for each previous ldr, thus also repeated 8 times + * + * The "ldr pc, [pc, #0x18]" instruction above loads address from memory at + * offset 0x18 from current value of PC register. Note that PC is already + * incremented by 4 when computing the offset, so the effective offset is + * actually 0x20, this the associated <destination address>. Loading the PC + * register with an address performs a jump to that address. + */ +void mx28_fixup_vt(uint32_t start_addr) +{ + /* ldr pc, [pc, #0x18] */ + const uint32_t ldr_pc = 0xe59ff018; + /* Jumptable location is 0x0 */ + uint32_t *vt = (uint32_t *)0x0; + int i; + + for (i = 0; i < 8; i++) { + vt[i] = ldr_pc; + vt[i + 8] = start_addr + (4 * i); + } +} + +#ifdef CONFIG_ARCH_MISC_INIT +int arch_misc_init(void) +{ + mx28_fixup_vt(gd->relocaddr); + return 0; +} +#endif + +int arch_cpu_init(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + extern uint32_t _start; + + mx28_fixup_vt((uint32_t)&_start); + + /* + * Enable NAND clock + */ + /* Clear bypass bit */ + writel(CLKCTRL_CLKSEQ_BYPASS_GPMI, + &clkctrl_regs->hw_clkctrl_clkseq_set); + + /* Set GPMI clock to ref_gpmi / 12 */ + clrsetbits_le32(&clkctrl_regs->hw_clkctrl_gpmi, + CLKCTRL_GPMI_CLKGATE | CLKCTRL_GPMI_DIV_MASK, 1); + + udelay(1000); + + /* + * Configure GPIO unit + */ + mxs_gpio_init(); + +#ifdef CONFIG_APBH_DMA + /* Start APBH DMA */ + mxs_dma_init(); +#endif + + return 0; +} + +#if defined(CONFIG_DISPLAY_CPUINFO) +static const char *get_cpu_type(void) +{ + struct mxs_digctl_regs *digctl_regs = + (struct mxs_digctl_regs *)MXS_DIGCTL_BASE; + + switch (readl(&digctl_regs->hw_digctl_chipid) & HW_DIGCTL_CHIPID_MASK) { + case HW_DIGCTL_CHIPID_MX23: + return "23"; + case HW_DIGCTL_CHIPID_MX28: + return "28"; + default: + return "??"; + } +} + +static const char *get_cpu_rev(void) +{ + struct mxs_digctl_regs *digctl_regs = + (struct mxs_digctl_regs *)MXS_DIGCTL_BASE; + uint8_t rev = readl(&digctl_regs->hw_digctl_chipid) & 0x000000FF; + + switch (readl(&digctl_regs->hw_digctl_chipid) & HW_DIGCTL_CHIPID_MASK) { + case HW_DIGCTL_CHIPID_MX23: + switch (rev) { + case 0x0: + return "1.0"; + case 0x1: + return "1.1"; + case 0x2: + return "1.2"; + case 0x3: + return "1.3"; + case 0x4: + return "1.4"; + default: + return "??"; + } + case HW_DIGCTL_CHIPID_MX28: + switch (rev) { + case 0x1: + return "1.2"; + default: + return "??"; + } + default: + return "??"; + } +} + +int print_cpuinfo(void) +{ + struct mxs_spl_data *data = (struct mxs_spl_data *) + ((CONFIG_SYS_TEXT_BASE - sizeof(struct mxs_spl_data)) & ~0xf); + + printf("CPU: Freescale i.MX%s rev%s at %d MHz\n", + get_cpu_type(), + get_cpu_rev(), + mxc_get_clock(MXC_ARM_CLK) / 1000000); + printf("BOOT: %s\n", mxs_boot_modes[data->boot_mode_idx].mode); + return 0; +} +#endif + +int do_mx28_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + printf("CPU: %3d MHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000); + printf("BUS: %3d MHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000000); + printf("EMI: %3d MHz\n", mxc_get_clock(MXC_EMI_CLK)); + printf("GPMI: %3d MHz\n", mxc_get_clock(MXC_GPMI_CLK) / 1000000); + return 0; +} + +/* + * Initializes on-chip ethernet controllers. + */ +#if defined(CONFIG_MX28) && defined(CONFIG_CMD_NET) +int cpu_eth_init(bd_t *bis) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + + /* Turn on ENET clocks */ + clrbits_le32(&clkctrl_regs->hw_clkctrl_enet, + CLKCTRL_ENET_SLEEP | CLKCTRL_ENET_DISABLE); + + /* Set up ENET PLL for 50 MHz */ + /* Power on ENET PLL */ + writel(CLKCTRL_PLL2CTRL0_POWER, + &clkctrl_regs->hw_clkctrl_pll2ctrl0_set); + + udelay(10); + + /* Gate on ENET PLL */ + writel(CLKCTRL_PLL2CTRL0_CLKGATE, + &clkctrl_regs->hw_clkctrl_pll2ctrl0_clr); + + /* Enable pad output */ + setbits_le32(&clkctrl_regs->hw_clkctrl_enet, CLKCTRL_ENET_CLK_OUT_EN); + + return 0; +} +#endif + +__weak void mx28_adjust_mac(int dev_id, unsigned char *mac) +{ + mac[0] = 0x00; + mac[1] = 0x04; /* Use FSL vendor MAC address by default */ + + if (dev_id == 1) /* Let MAC1 be MAC0 + 1 by default */ + mac[5] += 1; +} + +#ifdef CONFIG_MX28_FEC_MAC_IN_OCOTP + +#define MXS_OCOTP_MAX_TIMEOUT 1000000 +void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) +{ + struct mxs_ocotp_regs *ocotp_regs = + (struct mxs_ocotp_regs *)MXS_OCOTP_BASE; + uint32_t data; + + memset(mac, 0, 6); + + writel(OCOTP_CTRL_RD_BANK_OPEN, &ocotp_regs->hw_ocotp_ctrl_set); + + if (mxs_wait_mask_clr(&ocotp_regs->hw_ocotp_ctrl_reg, OCOTP_CTRL_BUSY, + MXS_OCOTP_MAX_TIMEOUT)) { + printf("MXS FEC: Can't get MAC from OCOTP\n"); + return; + } + + data = readl(&ocotp_regs->hw_ocotp_cust0); + + mac[2] = (data >> 24) & 0xff; + mac[3] = (data >> 16) & 0xff; + mac[4] = (data >> 8) & 0xff; + mac[5] = data & 0xff; + mx28_adjust_mac(dev_id, mac); +} +#else +void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) +{ + memset(mac, 0, 6); +} +#endif + +int mxs_dram_init(void) +{ + struct mxs_spl_data *data = (struct mxs_spl_data *) + ((CONFIG_SYS_TEXT_BASE - sizeof(struct mxs_spl_data)) & ~0xf); + + if (data->mem_dram_size == 0) { + printf("MXS:\n" + "Error, the RAM size passed up from SPL is 0!\n"); + hang(); + } + + gd->ram_size = data->mem_dram_size; + return 0; +} + +U_BOOT_CMD( + clocks, CONFIG_SYS_MAXARGS, 1, do_mx28_showclocks, + "display clocks", + "" +); diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/mxs_init.h b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/mxs_init.h new file mode 100644 index 000000000..1200ae1ad --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/mxs_init.h @@ -0,0 +1,29 @@ +/* + * Freescale i.MX28 SPL functions + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __M28_INIT_H__ +#define __M28_INIT_H__ + +void early_delay(int delay); + +void mxs_power_init(void); + +#ifdef CONFIG_SPL_MXS_PSWITCH_WAIT +void mxs_power_wait_pswitch(void); +#else +static inline void mxs_power_wait_pswitch(void) { } +#endif + +void mxs_mem_init(void); +uint32_t mxs_mem_get_size(void); + +void mxs_lradc_init(void); +void mxs_lradc_enable_batt_measurement(void); + +#endif /* __M28_INIT_H__ */ diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/mxsimage-signed.cfg b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/mxsimage-signed.cfg new file mode 100644 index 000000000..1520bba3f --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/mxsimage-signed.cfg @@ -0,0 +1,10 @@ +SECTION 0x0 BOOTABLE + TAG LAST + LOAD 0x1000 spl/u-boot-spl.bin + LOAD 0x8000 spl/u-boot-spl.ivt + LOAD 0x8040 spl/u-boot-spl.sig + CALL HAB 0x8000 0x0 + LOAD 0x40002000 u-boot.bin + LOAD 0x40001000 u-boot.ivt + LOAD 0x40001040 u-boot.sig + CALL HAB 0x40001000 0x0 diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/mxsimage.mx23.cfg b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/mxsimage.mx23.cfg new file mode 100644 index 000000000..55510e9cd --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/mxsimage.mx23.cfg @@ -0,0 +1,6 @@ +SECTION 0x0 BOOTABLE + TAG LAST + LOAD 0x1000 spl/u-boot-spl.bin + CALL 0x1000 0x0 + LOAD 0x40002000 u-boot.bin + CALL 0x40002000 0x0 diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/mxsimage.mx28.cfg b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/mxsimage.mx28.cfg new file mode 100644 index 000000000..bb78cb0c8 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/mxsimage.mx28.cfg @@ -0,0 +1,8 @@ +SECTION 0x0 BOOTABLE + TAG LAST + LOAD 0x1000 spl/u-boot-spl.bin + LOAD IVT 0x8000 0x1000 + CALL HAB 0x8000 0x0 + LOAD 0x40002000 u-boot.bin + LOAD IVT 0x8000 0x40002000 + CALL HAB 0x8000 0x0 diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/spl_boot.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/spl_boot.c new file mode 100644 index 000000000..d3e136991 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/spl_boot.c @@ -0,0 +1,170 @@ +/* + * Freescale i.MX28 Boot setup + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <config.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/sys_proto.h> +#include <asm/gpio.h> +#include <linux/compiler.h> + +#include "mxs_init.h" + +DECLARE_GLOBAL_DATA_PTR; +static gd_t gdata __section(".data"); +#ifdef CONFIG_SPL_SERIAL_SUPPORT +static bd_t bdata __section(".data"); +#endif + +/* + * This delay function is intended to be used only in early stage of boot, where + * clock are not set up yet. The timer used here is reset on every boot and + * takes a few seconds to roll. The boot doesn't take that long, so to keep the + * code simple, it doesn't take rolling into consideration. + */ +void early_delay(int delay) +{ + struct mxs_digctl_regs *digctl_regs = + (struct mxs_digctl_regs *)MXS_DIGCTL_BASE; + + uint32_t st = readl(&digctl_regs->hw_digctl_microseconds); + st += delay; + while (st > readl(&digctl_regs->hw_digctl_microseconds)) + ; +} + +#define MUX_CONFIG_BOOTMODE_PAD (MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_NOPULL) +static const iomux_cfg_t iomux_boot[] = { +#if defined(CONFIG_MX23) + MX23_PAD_LCD_D00__GPIO_1_0 | MUX_CONFIG_BOOTMODE_PAD, + MX23_PAD_LCD_D01__GPIO_1_1 | MUX_CONFIG_BOOTMODE_PAD, + MX23_PAD_LCD_D02__GPIO_1_2 | MUX_CONFIG_BOOTMODE_PAD, + MX23_PAD_LCD_D03__GPIO_1_3 | MUX_CONFIG_BOOTMODE_PAD, + MX23_PAD_LCD_D04__GPIO_1_4 | MUX_CONFIG_BOOTMODE_PAD, + MX23_PAD_LCD_D05__GPIO_1_5 | MUX_CONFIG_BOOTMODE_PAD, +#elif defined(CONFIG_MX28) + MX28_PAD_LCD_D00__GPIO_1_0 | MUX_CONFIG_BOOTMODE_PAD, + MX28_PAD_LCD_D01__GPIO_1_1 | MUX_CONFIG_BOOTMODE_PAD, + MX28_PAD_LCD_D02__GPIO_1_2 | MUX_CONFIG_BOOTMODE_PAD, + MX28_PAD_LCD_D03__GPIO_1_3 | MUX_CONFIG_BOOTMODE_PAD, + MX28_PAD_LCD_D04__GPIO_1_4 | MUX_CONFIG_BOOTMODE_PAD, + MX28_PAD_LCD_D05__GPIO_1_5 | MUX_CONFIG_BOOTMODE_PAD, +#endif +}; + +static uint8_t mxs_get_bootmode_index(void) +{ + uint8_t bootmode = 0; + int i; + uint8_t masked; + + /* Setup IOMUX of bootmode pads to GPIO */ + mxs_iomux_setup_multiple_pads(iomux_boot, ARRAY_SIZE(iomux_boot)); + +#if defined(CONFIG_MX23) + /* Setup bootmode pins as GPIO input */ + gpio_direction_input(MX23_PAD_LCD_D00__GPIO_1_0); + gpio_direction_input(MX23_PAD_LCD_D01__GPIO_1_1); + gpio_direction_input(MX23_PAD_LCD_D02__GPIO_1_2); + gpio_direction_input(MX23_PAD_LCD_D03__GPIO_1_3); + gpio_direction_input(MX23_PAD_LCD_D05__GPIO_1_5); + + /* Read bootmode pads */ + bootmode |= (gpio_get_value(MX23_PAD_LCD_D00__GPIO_1_0) ? 1 : 0) << 0; + bootmode |= (gpio_get_value(MX23_PAD_LCD_D01__GPIO_1_1) ? 1 : 0) << 1; + bootmode |= (gpio_get_value(MX23_PAD_LCD_D02__GPIO_1_2) ? 1 : 0) << 2; + bootmode |= (gpio_get_value(MX23_PAD_LCD_D03__GPIO_1_3) ? 1 : 0) << 3; + bootmode |= (gpio_get_value(MX23_PAD_LCD_D05__GPIO_1_5) ? 1 : 0) << 5; +#elif defined(CONFIG_MX28) + /* Setup bootmode pins as GPIO input */ + gpio_direction_input(MX28_PAD_LCD_D00__GPIO_1_0); + gpio_direction_input(MX28_PAD_LCD_D01__GPIO_1_1); + gpio_direction_input(MX28_PAD_LCD_D02__GPIO_1_2); + gpio_direction_input(MX28_PAD_LCD_D03__GPIO_1_3); + gpio_direction_input(MX28_PAD_LCD_D04__GPIO_1_4); + gpio_direction_input(MX28_PAD_LCD_D05__GPIO_1_5); + + /* Read bootmode pads */ + bootmode |= (gpio_get_value(MX28_PAD_LCD_D00__GPIO_1_0) ? 1 : 0) << 0; + bootmode |= (gpio_get_value(MX28_PAD_LCD_D01__GPIO_1_1) ? 1 : 0) << 1; + bootmode |= (gpio_get_value(MX28_PAD_LCD_D02__GPIO_1_2) ? 1 : 0) << 2; + bootmode |= (gpio_get_value(MX28_PAD_LCD_D03__GPIO_1_3) ? 1 : 0) << 3; + bootmode |= (gpio_get_value(MX28_PAD_LCD_D04__GPIO_1_4) ? 1 : 0) << 4; + bootmode |= (gpio_get_value(MX28_PAD_LCD_D05__GPIO_1_5) ? 1 : 0) << 5; +#endif + + for (i = 0; i < ARRAY_SIZE(mxs_boot_modes); i++) { + masked = bootmode & mxs_boot_modes[i].boot_mask; + if (masked == mxs_boot_modes[i].boot_pads) + break; + } + + return i; +} + +static void mxs_spl_fixup_vectors(void) +{ + /* + * Copy our vector table to 0x0, since due to HAB, we cannot + * be loaded to 0x0. We want to have working vectoring though, + * thus this fixup. Our vectoring table is PIC, so copying is + * fine. + */ + extern uint32_t _start; + memcpy(0x0, &_start, 0x60); +} + +static void mxs_spl_console_init(void) +{ +#ifdef CONFIG_SPL_SERIAL_SUPPORT + gd->bd = &bdata; + gd->baudrate = CONFIG_BAUDRATE; + serial_init(); + gd->have_console = 1; +#endif +} + +void mxs_common_spl_init(const uint32_t arg, const uint32_t *resptr, + const iomux_cfg_t *iomux_setup, + const unsigned int iomux_size) +{ + struct mxs_spl_data *data = (struct mxs_spl_data *) + ((CONFIG_SYS_TEXT_BASE - sizeof(struct mxs_spl_data)) & ~0xf); + uint8_t bootmode = mxs_get_bootmode_index(); + gd = &gdata; + + mxs_spl_fixup_vectors(); + + mxs_iomux_setup_multiple_pads(iomux_setup, iomux_size); + + mxs_spl_console_init(); + + mxs_power_init(); + + mxs_mem_init(); + data->mem_dram_size = mxs_mem_get_size(); + + data->boot_mode_idx = bootmode; + + mxs_power_wait_pswitch(); +} + +/* Support aparatus */ +inline void board_init_f(unsigned long bootflag) +{ + for (;;) + ; +} + +inline void board_init_r(gd_t *id, ulong dest_addr) +{ + for (;;) + ; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/spl_lradc_init.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/spl_lradc_init.c new file mode 100644 index 000000000..cdfcddd82 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/spl_lradc_init.c @@ -0,0 +1,70 @@ +/* + * Freescale i.MX28 Battery measurement init + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <config.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> + +#include "mxs_init.h" + +void mxs_lradc_init(void) +{ + struct mxs_lradc_regs *regs = (struct mxs_lradc_regs *)MXS_LRADC_BASE; + + writel(LRADC_CTRL0_SFTRST, ®s->hw_lradc_ctrl0_clr); + writel(LRADC_CTRL0_CLKGATE, ®s->hw_lradc_ctrl0_clr); + writel(LRADC_CTRL0_ONCHIP_GROUNDREF, ®s->hw_lradc_ctrl0_clr); + + clrsetbits_le32(®s->hw_lradc_ctrl3, + LRADC_CTRL3_CYCLE_TIME_MASK, + LRADC_CTRL3_CYCLE_TIME_6MHZ); + + clrsetbits_le32(®s->hw_lradc_ctrl4, + LRADC_CTRL4_LRADC7SELECT_MASK | + LRADC_CTRL4_LRADC6SELECT_MASK, + LRADC_CTRL4_LRADC7SELECT_CHANNEL7 | + LRADC_CTRL4_LRADC6SELECT_CHANNEL10); +} + +void mxs_lradc_enable_batt_measurement(void) +{ + struct mxs_lradc_regs *regs = (struct mxs_lradc_regs *)MXS_LRADC_BASE; + + /* Check if the channel is present at all. */ + if (!(readl(®s->hw_lradc_status) & LRADC_STATUS_CHANNEL7_PRESENT)) + return; + + writel(LRADC_CTRL1_LRADC7_IRQ_EN, ®s->hw_lradc_ctrl1_clr); + writel(LRADC_CTRL1_LRADC7_IRQ, ®s->hw_lradc_ctrl1_clr); + + clrsetbits_le32(®s->hw_lradc_conversion, + LRADC_CONVERSION_SCALE_FACTOR_MASK, + LRADC_CONVERSION_SCALE_FACTOR_LI_ION); + writel(LRADC_CONVERSION_AUTOMATIC, ®s->hw_lradc_conversion_set); + + /* Configure the channel. */ + writel((1 << 7) << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET, + ®s->hw_lradc_ctrl2_clr); + writel(0xffffffff, ®s->hw_lradc_ch7_clr); + clrbits_le32(®s->hw_lradc_ch7, LRADC_CH_NUM_SAMPLES_MASK); + writel(LRADC_CH_ACCUMULATE, ®s->hw_lradc_ch7_clr); + + /* Schedule the channel. */ + writel(1 << 7, ®s->hw_lradc_ctrl0_set); + + /* Start the channel sampling. */ + writel(((1 << 7) << LRADC_DELAY_TRIGGER_LRADCS_OFFSET) | + ((1 << 3) << LRADC_DELAY_TRIGGER_DELAYS_OFFSET) | + 100, ®s->hw_lradc_delay3); + + writel(0xffffffff, ®s->hw_lradc_ch7_clr); + + writel(LRADC_DELAY_KICK, ®s->hw_lradc_delay3_set); +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/spl_mem_init.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/spl_mem_init.c new file mode 100644 index 000000000..3baf4ddef --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/spl_mem_init.c @@ -0,0 +1,331 @@ +/* + * Freescale i.MX28 RAM init + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <config.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/sys_proto.h> +#include <linux/compiler.h> + +#include "mxs_init.h" + +static uint32_t dram_vals[] = { +/* + * i.MX28 DDR2 at 200MHz + */ +#if defined(CONFIG_MX28) + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000100, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00010101, 0x01010101, + 0x000f0f01, 0x0f02020a, 0x00000000, 0x00010101, + 0x00000100, 0x00000100, 0x00000000, 0x00000002, + 0x01010000, 0x07080403, 0x06005003, 0x0a0000c8, + 0x02009c40, 0x0002030c, 0x0036a609, 0x031a0612, + 0x02030202, 0x00c8001c, 0x00000000, 0x00000000, + 0x00012100, 0xffff0303, 0x00012100, 0xffff0303, + 0x00012100, 0xffff0303, 0x00012100, 0xffff0303, + 0x00000003, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000612, 0x01000F02, + 0x06120612, 0x00000200, 0x00020007, 0xf4004a27, + 0xf4004a27, 0xf4004a27, 0xf4004a27, 0x07000300, + 0x07000300, 0x07400300, 0x07400300, 0x00000005, + 0x00000000, 0x00000000, 0x01000000, 0x01020408, + 0x08040201, 0x000f1133, 0x00000000, 0x00001f04, + 0x00001f04, 0x00001f04, 0x00001f04, 0x00001f04, + 0x00001f04, 0x00001f04, 0x00001f04, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00010000, 0x00030404, + 0x00000003, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x01010000, + 0x01000000, 0x03030000, 0x00010303, 0x01020202, + 0x00000000, 0x02040303, 0x21002103, 0x00061200, + 0x06120612, 0x04420442, 0x04420442, 0x00040004, + 0x00040004, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xffffffff + +/* + * i.MX23 DDR at 133MHz + */ +#elif defined(CONFIG_MX23) + 0x01010001, 0x00010100, 0x01000101, 0x00000001, + 0x00000101, 0x00000000, 0x00010000, 0x01000001, + 0x00000000, 0x00000001, 0x07000200, 0x00070202, + 0x02020000, 0x04040a01, 0x00000201, 0x02040000, + 0x02000000, 0x19000f08, 0x0d0d0000, 0x02021313, + 0x02061521, 0x0000000a, 0x00080008, 0x00200020, + 0x00200020, 0x00200020, 0x000003f7, 0x00000000, + 0x00000000, 0x00000020, 0x00000020, 0x00c80000, + 0x000a23cd, 0x000000c8, 0x00006665, 0x00000000, + 0x00000101, 0x00040001, 0x00000000, 0x00000000, + 0x00010000 +#else +#error Unsupported memory initialization +#endif +}; + +__weak void mxs_adjust_memory_params(uint32_t *dram_vals) +{ +} + +#ifdef CONFIG_MX28 +static void initialize_dram_values(void) +{ + int i; + + mxs_adjust_memory_params(dram_vals); + + for (i = 0; i < ARRAY_SIZE(dram_vals); i++) + writel(dram_vals[i], MXS_DRAM_BASE + (4 * i)); +} +#else +static void initialize_dram_values(void) +{ + int i; + + mxs_adjust_memory_params(dram_vals); + + /* + * HW_DRAM_CTL27, HW_DRAM_CTL28 and HW_DRAM_CTL35 are not initialized as + * per FSL bootlets code. + * + * mx23 Reference Manual marks HW_DRAM_CTL27 and HW_DRAM_CTL28 as + * "reserved". + * HW_DRAM_CTL8 is setup as the last element. + * So skip the initialization of these HW_DRAM_CTL registers. + */ + for (i = 0; i < ARRAY_SIZE(dram_vals); i++) { + if (i == 8 || i == 27 || i == 28 || i == 35) + continue; + writel(dram_vals[i], MXS_DRAM_BASE + (4 * i)); + } + + /* + * Enable tRAS lockout in HW_DRAM_CTL08 ; it must be the last + * element to be set + */ + writel((1 << 24), MXS_DRAM_BASE + (4 * 8)); +} +#endif + +static void mxs_mem_init_clock(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; +#if defined(CONFIG_MX23) + /* Fractional divider for ref_emi is 33 ; 480 * 18 / 33 = 266MHz */ + const unsigned char divider = 33; +#elif defined(CONFIG_MX28) + /* Fractional divider for ref_emi is 21 ; 480 * 18 / 21 = 411MHz */ + const unsigned char divider = 21; +#endif + + /* Gate EMI clock */ + writeb(CLKCTRL_FRAC_CLKGATE, + &clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_EMI]); + + /* Set fractional divider for ref_emi */ + writeb(CLKCTRL_FRAC_CLKGATE | (divider & CLKCTRL_FRAC_FRAC_MASK), + &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]); + + /* Ungate EMI clock */ + writeb(CLKCTRL_FRAC_CLKGATE, + &clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_EMI]); + + early_delay(11000); + + /* Set EMI clock divider for EMI clock to 411 / 2 = 205MHz */ + writel((2 << CLKCTRL_EMI_DIV_EMI_OFFSET) | + (1 << CLKCTRL_EMI_DIV_XTAL_OFFSET), + &clkctrl_regs->hw_clkctrl_emi); + + /* Unbypass EMI */ + writel(CLKCTRL_CLKSEQ_BYPASS_EMI, + &clkctrl_regs->hw_clkctrl_clkseq_clr); + + early_delay(10000); +} + +static void mxs_mem_setup_cpu_and_hbus(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + + /* Set fractional divider for ref_cpu to 480 * 18 / 19 = 454MHz + * and ungate CPU clock */ + writeb(19 & CLKCTRL_FRAC_FRAC_MASK, + (uint8_t *)&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]); + + /* Set CPU bypass */ + writel(CLKCTRL_CLKSEQ_BYPASS_CPU, + &clkctrl_regs->hw_clkctrl_clkseq_set); + + /* HBUS = 151MHz */ + writel(CLKCTRL_HBUS_DIV_MASK, &clkctrl_regs->hw_clkctrl_hbus_set); + writel(((~3) << CLKCTRL_HBUS_DIV_OFFSET) & CLKCTRL_HBUS_DIV_MASK, + &clkctrl_regs->hw_clkctrl_hbus_clr); + + early_delay(10000); + + /* CPU clock divider = 1 */ + clrsetbits_le32(&clkctrl_regs->hw_clkctrl_cpu, + CLKCTRL_CPU_DIV_CPU_MASK, 1); + + /* Disable CPU bypass */ + writel(CLKCTRL_CLKSEQ_BYPASS_CPU, + &clkctrl_regs->hw_clkctrl_clkseq_clr); + + early_delay(15000); +} + +static void mxs_mem_setup_vdda(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + writel((0xc << POWER_VDDACTRL_TRG_OFFSET) | + (0x7 << POWER_VDDACTRL_BO_OFFSET_OFFSET) | + POWER_VDDACTRL_LINREG_OFFSET_1STEPS_BELOW, + &power_regs->hw_power_vddactrl); +} + +uint32_t mxs_mem_get_size(void) +{ + uint32_t sz, da; + uint32_t *vt = (uint32_t *)0x20; + /* The following is "subs pc, r14, #4", used as return from DABT. */ + const uint32_t data_abort_memdetect_handler = 0xe25ef004; + + /* Replace the DABT handler. */ + da = vt[4]; + vt[4] = data_abort_memdetect_handler; + + sz = get_ram_size((long *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE); + + /* Restore the old DABT handler. */ + vt[4] = da; + + return sz; +} + +#ifdef CONFIG_MX23 +static void mx23_mem_setup_vddmem(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + clrbits_le32(&power_regs->hw_power_vddmemctrl, + POWER_VDDMEMCTRL_ENABLE_ILIMIT); + +} + +static void mx23_mem_init(void) +{ + /* + * Reset/ungate the EMI block. This is essential, otherwise the system + * suffers from memory instability. This thing is mx23 specific and is + * no longer present on mx28. + */ + mxs_reset_block((struct mxs_register_32 *)MXS_EMI_BASE); + + mx23_mem_setup_vddmem(); + + /* + * Configure the DRAM registers + */ + + /* Clear START and SREFRESH bit from DRAM_CTL8 */ + clrbits_le32(MXS_DRAM_BASE + 0x20, (1 << 16) | (1 << 8)); + + initialize_dram_values(); + + /* Set START bit in DRAM_CTL8 */ + setbits_le32(MXS_DRAM_BASE + 0x20, 1 << 16); + + clrbits_le32(MXS_DRAM_BASE + 0x40, 1 << 17); + early_delay(20000); + + /* Adjust EMI port priority. */ + clrsetbits_le32(0x80020000, 0x1f << 16, 0x2); + early_delay(20000); + + setbits_le32(MXS_DRAM_BASE + 0x40, 1 << 19); + setbits_le32(MXS_DRAM_BASE + 0x40, 1 << 11); +} +#endif + +#ifdef CONFIG_MX28 +static void mx28_mem_init(void) +{ + struct mxs_pinctrl_regs *pinctrl_regs = + (struct mxs_pinctrl_regs *)MXS_PINCTRL_BASE; + + /* Set DDR2 mode */ + writel(PINCTRL_EMI_DS_CTRL_DDR_MODE_DDR2, + &pinctrl_regs->hw_pinctrl_emi_ds_ctrl_set); + + /* + * Configure the DRAM registers + */ + + /* Clear START bit from DRAM_CTL16 */ + clrbits_le32(MXS_DRAM_BASE + 0x40, 1); + + initialize_dram_values(); + + /* Clear SREFRESH bit from DRAM_CTL17 */ + clrbits_le32(MXS_DRAM_BASE + 0x44, 1); + + /* Set START bit in DRAM_CTL16 */ + setbits_le32(MXS_DRAM_BASE + 0x40, 1); + + /* Wait for bit 20 (DRAM init complete) in DRAM_CTL58 */ + while (!(readl(MXS_DRAM_BASE + 0xe8) & (1 << 20))) + ; +} +#endif + +void mxs_mem_init(void) +{ + early_delay(11000); + + mxs_mem_init_clock(); + + mxs_mem_setup_vdda(); + +#if defined(CONFIG_MX23) + mx23_mem_init(); +#elif defined(CONFIG_MX28) + mx28_mem_init(); +#endif + + early_delay(10000); + + mxs_mem_setup_cpu_and_hbus(); +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/spl_power_init.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/spl_power_init.c new file mode 100644 index 000000000..d25019a51 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/spl_power_init.c @@ -0,0 +1,1155 @@ +/* + * Freescale i.MX28 Boot PMIC init + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <config.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> + +#include "mxs_init.h" + +/** + * mxs_power_clock2xtal() - Switch CPU core clock source to 24MHz XTAL + * + * This function switches the CPU core clock from PLL to 24MHz XTAL + * oscilator. This is necessary if the PLL is being reconfigured to + * prevent crash of the CPU core. + */ +static void mxs_power_clock2xtal(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + + /* Set XTAL as CPU reference clock */ + writel(CLKCTRL_CLKSEQ_BYPASS_CPU, + &clkctrl_regs->hw_clkctrl_clkseq_set); +} + +/** + * mxs_power_clock2pll() - Switch CPU core clock source to PLL + * + * This function switches the CPU core clock from 24MHz XTAL oscilator + * to PLL. This can only be called once the PLL has re-locked and once + * the PLL is stable after reconfiguration. + */ +static void mxs_power_clock2pll(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + + setbits_le32(&clkctrl_regs->hw_clkctrl_pll0ctrl0, + CLKCTRL_PLL0CTRL0_POWER); + early_delay(100); + setbits_le32(&clkctrl_regs->hw_clkctrl_clkseq, + CLKCTRL_CLKSEQ_BYPASS_CPU); +} + +/** + * mxs_power_set_auto_restart() - Set the auto-restart bit + * + * This function ungates the RTC block and sets the AUTO_RESTART + * bit to work around a design bug on MX28EVK Rev. A . + */ + +static void mxs_power_set_auto_restart(void) +{ + struct mxs_rtc_regs *rtc_regs = + (struct mxs_rtc_regs *)MXS_RTC_BASE; + + writel(RTC_CTRL_SFTRST, &rtc_regs->hw_rtc_ctrl_clr); + while (readl(&rtc_regs->hw_rtc_ctrl) & RTC_CTRL_SFTRST) + ; + + writel(RTC_CTRL_CLKGATE, &rtc_regs->hw_rtc_ctrl_clr); + while (readl(&rtc_regs->hw_rtc_ctrl) & RTC_CTRL_CLKGATE) + ; + + /* Do nothing if flag already set */ + if (readl(&rtc_regs->hw_rtc_persistent0) & RTC_PERSISTENT0_AUTO_RESTART) + return; + + while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_NEW_REGS_MASK) + ; + + setbits_le32(&rtc_regs->hw_rtc_persistent0, + RTC_PERSISTENT0_AUTO_RESTART); + writel(RTC_CTRL_FORCE_UPDATE, &rtc_regs->hw_rtc_ctrl_set); + writel(RTC_CTRL_FORCE_UPDATE, &rtc_regs->hw_rtc_ctrl_clr); + while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_NEW_REGS_MASK) + ; + while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_STALE_REGS_MASK) + ; +} + +/** + * mxs_power_set_linreg() - Set linear regulators 25mV below DC-DC converter + * + * This function configures the VDDIO, VDDA and VDDD linear regulators output + * to be 25mV below the VDDIO, VDDA and VDDD output from the DC-DC switching + * converter. This is the recommended setting for the case where we use both + * linear regulators and DC-DC converter to power the VDDIO rail. + */ +static void mxs_power_set_linreg(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + /* Set linear regulator 25mV below switching converter */ + clrsetbits_le32(&power_regs->hw_power_vdddctrl, + POWER_VDDDCTRL_LINREG_OFFSET_MASK, + POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW); + + clrsetbits_le32(&power_regs->hw_power_vddactrl, + POWER_VDDACTRL_LINREG_OFFSET_MASK, + POWER_VDDACTRL_LINREG_OFFSET_1STEPS_BELOW); + + clrsetbits_le32(&power_regs->hw_power_vddioctrl, + POWER_VDDIOCTRL_LINREG_OFFSET_MASK, + POWER_VDDIOCTRL_LINREG_OFFSET_1STEPS_BELOW); +} + +/** + * mxs_get_batt_volt() - Measure battery input voltage + * + * This function retrieves the battery input voltage and returns it. + */ +static int mxs_get_batt_volt(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t volt = readl(&power_regs->hw_power_battmonitor); + volt &= POWER_BATTMONITOR_BATT_VAL_MASK; + volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET; + volt *= 8; + return volt; +} + +/** + * mxs_is_batt_ready() - Test if the battery provides enough voltage to boot + * + * This function checks if the battery input voltage is higher than 3.6V and + * therefore allows the system to successfully boot using this power source. + */ +static int mxs_is_batt_ready(void) +{ + return (mxs_get_batt_volt() >= 3600); +} + +/** + * mxs_is_batt_good() - Test if battery is operational at all + * + * This function starts recharging the battery and tests if the input current + * provided by the 5V input recharging the battery is also sufficient to power + * the DC-DC converter. + */ +static int mxs_is_batt_good(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t volt = mxs_get_batt_volt(); + + if ((volt >= 2400) && (volt <= 4300)) + return 1; + + clrsetbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK, + 0x3 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET); + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, + &power_regs->hw_power_5vctrl_clr); + + clrsetbits_le32(&power_regs->hw_power_charge, + POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK, + POWER_CHARGE_STOP_ILIMIT_10MA | 0x3); + + writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_clr); + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, + &power_regs->hw_power_5vctrl_clr); + + early_delay(500000); + + volt = mxs_get_batt_volt(); + + if (volt >= 3500) + return 0; + + if (volt >= 2400) + return 1; + + writel(POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK, + &power_regs->hw_power_charge_clr); + writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_set); + + return 0; +} + +/** + * mxs_power_setup_5v_detect() - Start the 5V input detection comparator + * + * This function enables the 5V detection comparator and sets the 5V valid + * threshold to 4.4V . We use 4.4V threshold here to make sure that even + * under high load, the voltage drop on the 5V input won't be so critical + * to cause undervolt on the 4P2 linear regulator supplying the DC-DC + * converter and thus making the system crash. + */ +static void mxs_power_setup_5v_detect(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + /* Start 5V detection */ + clrsetbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_VBUSVALID_TRSH_MASK, + POWER_5VCTRL_VBUSVALID_TRSH_4V4 | + POWER_5VCTRL_PWRUP_VBUS_CMPS); +} + +/** + * mxs_src_power_init() - Preconfigure the power block + * + * This function configures reasonable values for the DC-DC control loop + * and battery monitor. + */ +static void mxs_src_power_init(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + /* Improve efficieny and reduce transient ripple */ + writel(POWER_LOOPCTRL_TOGGLE_DIF | POWER_LOOPCTRL_EN_CM_HYST | + POWER_LOOPCTRL_EN_DF_HYST, &power_regs->hw_power_loopctrl_set); + + clrsetbits_le32(&power_regs->hw_power_dclimits, + POWER_DCLIMITS_POSLIMIT_BUCK_MASK, + 0x30 << POWER_DCLIMITS_POSLIMIT_BUCK_OFFSET); + + setbits_le32(&power_regs->hw_power_battmonitor, + POWER_BATTMONITOR_EN_BATADJ); + + /* Increase the RCSCALE level for quick DCDC response to dynamic load */ + clrsetbits_le32(&power_regs->hw_power_loopctrl, + POWER_LOOPCTRL_EN_RCSCALE_MASK, + POWER_LOOPCTRL_RCSCALE_THRESH | + POWER_LOOPCTRL_EN_RCSCALE_8X); + + clrsetbits_le32(&power_regs->hw_power_minpwr, + POWER_MINPWR_HALFFETS, POWER_MINPWR_DOUBLE_FETS); + + /* 5V to battery handoff ... FIXME */ + setbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER); + early_delay(30); + clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER); +} + +/** + * mxs_power_init_4p2_params() - Configure the parameters of the 4P2 regulator + * + * This function configures the necessary parameters for the 4P2 linear + * regulator to supply the DC-DC converter from 5V input. + */ +static void mxs_power_init_4p2_params(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + /* Setup 4P2 parameters */ + clrsetbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_CMPTRIP_MASK | POWER_DCDC4P2_TRG_MASK, + POWER_DCDC4P2_TRG_4V2 | (31 << POWER_DCDC4P2_CMPTRIP_OFFSET)); + + clrsetbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_HEADROOM_ADJ_MASK, + 0x4 << POWER_5VCTRL_HEADROOM_ADJ_OFFSET); + + clrsetbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_DROPOUT_CTRL_MASK, + POWER_DCDC4P2_DROPOUT_CTRL_100MV | + POWER_DCDC4P2_DROPOUT_CTRL_SRC_SEL); + + clrsetbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK, + 0x3f << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET); +} + +/** + * mxs_enable_4p2_dcdc_input() - Enable or disable the DCDC input from 4P2 + * @xfer: Select if the input shall be enabled or disabled + * + * This function enables or disables the 4P2 input into the DC-DC converter. + */ +static void mxs_enable_4p2_dcdc_input(int xfer) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t tmp, vbus_thresh, vbus_5vdetect, pwd_bo; + uint32_t prev_5v_brnout, prev_5v_droop; + + prev_5v_brnout = readl(&power_regs->hw_power_5vctrl) & + POWER_5VCTRL_PWDN_5VBRNOUT; + prev_5v_droop = readl(&power_regs->hw_power_ctrl) & + POWER_CTRL_ENIRQ_VDD5V_DROOP; + + clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT); + writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF, + &power_regs->hw_power_reset); + + clrbits_le32(&power_regs->hw_power_ctrl, POWER_CTRL_ENIRQ_VDD5V_DROOP); + + if (xfer && (readl(&power_regs->hw_power_5vctrl) & + POWER_5VCTRL_ENABLE_DCDC)) { + return; + } + + /* + * Recording orignal values that will be modified temporarlily + * to handle a chip bug. See chip errata for CQ ENGR00115837 + */ + tmp = readl(&power_regs->hw_power_5vctrl); + vbus_thresh = tmp & POWER_5VCTRL_VBUSVALID_TRSH_MASK; + vbus_5vdetect = tmp & POWER_5VCTRL_VBUSVALID_5VDETECT; + + pwd_bo = readl(&power_regs->hw_power_minpwr) & POWER_MINPWR_PWD_BO; + + /* + * Disable mechanisms that get erroneously tripped by when setting + * the DCDC4P2 EN_DCDC + */ + clrbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_VBUSVALID_5VDETECT | + POWER_5VCTRL_VBUSVALID_TRSH_MASK); + + writel(POWER_MINPWR_PWD_BO, &power_regs->hw_power_minpwr_set); + + if (xfer) { + setbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_DCDC_XFER); + early_delay(20); + clrbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_DCDC_XFER); + + setbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_ENABLE_DCDC); + } else { + setbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_ENABLE_DCDC); + } + + early_delay(25); + + clrsetbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_VBUSVALID_TRSH_MASK, vbus_thresh); + + if (vbus_5vdetect) + writel(vbus_5vdetect, &power_regs->hw_power_5vctrl_set); + + if (!pwd_bo) + clrbits_le32(&power_regs->hw_power_minpwr, POWER_MINPWR_PWD_BO); + + while (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) + writel(POWER_CTRL_VBUS_VALID_IRQ, + &power_regs->hw_power_ctrl_clr); + + if (prev_5v_brnout) { + writel(POWER_5VCTRL_PWDN_5VBRNOUT, + &power_regs->hw_power_5vctrl_set); + writel(POWER_RESET_UNLOCK_KEY, + &power_regs->hw_power_reset); + } else { + writel(POWER_5VCTRL_PWDN_5VBRNOUT, + &power_regs->hw_power_5vctrl_clr); + writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF, + &power_regs->hw_power_reset); + } + + while (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VDD5V_DROOP_IRQ) + writel(POWER_CTRL_VDD5V_DROOP_IRQ, + &power_regs->hw_power_ctrl_clr); + + if (prev_5v_droop) + clrbits_le32(&power_regs->hw_power_ctrl, + POWER_CTRL_ENIRQ_VDD5V_DROOP); + else + setbits_le32(&power_regs->hw_power_ctrl, + POWER_CTRL_ENIRQ_VDD5V_DROOP); +} + +/** + * mxs_power_init_4p2_regulator() - Start the 4P2 regulator + * + * This function enables the 4P2 regulator and switches the DC-DC converter + * to use the 4P2 input. + */ +static void mxs_power_init_4p2_regulator(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t tmp, tmp2; + + setbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_ENABLE_4P2); + + writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_set); + + writel(POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK, + &power_regs->hw_power_5vctrl_clr); + clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_TRG_MASK); + + /* Power up the 4p2 rail and logic/control */ + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, + &power_regs->hw_power_5vctrl_clr); + + /* + * Start charging up the 4p2 capacitor. We ramp of this charge + * gradually to avoid large inrush current from the 5V cable which can + * cause transients/problems + */ + mxs_enable_4p2_dcdc_input(0); + + if (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) { + /* + * If we arrived here, we were unable to recover from mx23 chip + * errata 5837. 4P2 is disabled and sufficient battery power is + * not present. Exiting to not enable DCDC power during 5V + * connected state. + */ + clrbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_ENABLE_DCDC); + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, + &power_regs->hw_power_5vctrl_set); + hang(); + } + + /* + * Here we set the 4p2 brownout level to something very close to 4.2V. + * We then check the brownout status. If the brownout status is false, + * the voltage is already close to the target voltage of 4.2V so we + * can go ahead and set the 4P2 current limit to our max target limit. + * If the brownout status is true, we need to ramp us the current limit + * so that we don't cause large inrush current issues. We step up the + * current limit until the brownout status is false or until we've + * reached our maximum defined 4p2 current limit. + */ + clrsetbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_BO_MASK, + 22 << POWER_DCDC4P2_BO_OFFSET); /* 4.15V */ + + if (!(readl(&power_regs->hw_power_sts) & POWER_STS_DCDC_4P2_BO)) { + setbits_le32(&power_regs->hw_power_5vctrl, + 0x3f << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET); + } else { + tmp = (readl(&power_regs->hw_power_5vctrl) & + POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK) >> + POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET; + while (tmp < 0x3f) { + if (!(readl(&power_regs->hw_power_sts) & + POWER_STS_DCDC_4P2_BO)) { + tmp = readl(&power_regs->hw_power_5vctrl); + tmp |= POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK; + early_delay(100); + writel(tmp, &power_regs->hw_power_5vctrl); + break; + } else { + tmp++; + tmp2 = readl(&power_regs->hw_power_5vctrl); + tmp2 &= ~POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK; + tmp2 |= tmp << + POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET; + writel(tmp2, &power_regs->hw_power_5vctrl); + early_delay(100); + } + } + } + + clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_BO_MASK); + writel(POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr); +} + +/** + * mxs_power_init_dcdc_4p2_source() - Switch DC-DC converter to 4P2 source + * + * This function configures the DC-DC converter to be supplied from the 4P2 + * linear regulator. + */ +static void mxs_power_init_dcdc_4p2_source(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + if (!(readl(&power_regs->hw_power_dcdc4p2) & + POWER_DCDC4P2_ENABLE_DCDC)) { + hang(); + } + + mxs_enable_4p2_dcdc_input(1); + + if (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) { + clrbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_ENABLE_DCDC); + writel(POWER_5VCTRL_ENABLE_DCDC, + &power_regs->hw_power_5vctrl_clr); + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, + &power_regs->hw_power_5vctrl_set); + } +} + +/** + * mxs_power_enable_4p2() - Power up the 4P2 regulator + * + * This function drives the process of powering up the 4P2 linear regulator + * and switching the DC-DC converter input over to the 4P2 linear regulator. + */ +static void mxs_power_enable_4p2(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t vdddctrl, vddactrl, vddioctrl; + uint32_t tmp; + + vdddctrl = readl(&power_regs->hw_power_vdddctrl); + vddactrl = readl(&power_regs->hw_power_vddactrl); + vddioctrl = readl(&power_regs->hw_power_vddioctrl); + + setbits_le32(&power_regs->hw_power_vdddctrl, + POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG | + POWER_VDDDCTRL_PWDN_BRNOUT); + + setbits_le32(&power_regs->hw_power_vddactrl, + POWER_VDDACTRL_DISABLE_FET | POWER_VDDACTRL_ENABLE_LINREG | + POWER_VDDACTRL_PWDN_BRNOUT); + + setbits_le32(&power_regs->hw_power_vddioctrl, + POWER_VDDIOCTRL_DISABLE_FET | POWER_VDDIOCTRL_PWDN_BRNOUT); + + mxs_power_init_4p2_params(); + mxs_power_init_4p2_regulator(); + + /* Shutdown battery (none present) */ + if (!mxs_is_batt_ready()) { + clrbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_BO_MASK); + writel(POWER_CTRL_DCDC4P2_BO_IRQ, + &power_regs->hw_power_ctrl_clr); + writel(POWER_CTRL_ENIRQ_DCDC4P2_BO, + &power_regs->hw_power_ctrl_clr); + } + + mxs_power_init_dcdc_4p2_source(); + + writel(vdddctrl, &power_regs->hw_power_vdddctrl); + early_delay(20); + writel(vddactrl, &power_regs->hw_power_vddactrl); + early_delay(20); + writel(vddioctrl, &power_regs->hw_power_vddioctrl); + + /* + * Check if FET is enabled on either powerout and if so, + * disable load. + */ + tmp = 0; + tmp |= !(readl(&power_regs->hw_power_vdddctrl) & + POWER_VDDDCTRL_DISABLE_FET); + tmp |= !(readl(&power_regs->hw_power_vddactrl) & + POWER_VDDACTRL_DISABLE_FET); + tmp |= !(readl(&power_regs->hw_power_vddioctrl) & + POWER_VDDIOCTRL_DISABLE_FET); + if (tmp) + writel(POWER_CHARGE_ENABLE_LOAD, + &power_regs->hw_power_charge_clr); +} + +/** + * mxs_boot_valid_5v() - Boot from 5V supply + * + * This function configures the power block to boot from valid 5V input. + * This is called only if the 5V is reliable and can properly supply the + * CPU. This function proceeds to configure the 4P2 converter to be supplied + * from the 5V input. + */ +static void mxs_boot_valid_5v(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + /* + * Use VBUSVALID level instead of VDD5V_GT_VDDIO level to trigger a 5V + * disconnect event. FIXME + */ + writel(POWER_5VCTRL_VBUSVALID_5VDETECT, + &power_regs->hw_power_5vctrl_set); + + /* Configure polarity to check for 5V disconnection. */ + writel(POWER_CTRL_POLARITY_VBUSVALID | + POWER_CTRL_POLARITY_VDD5V_GT_VDDIO, + &power_regs->hw_power_ctrl_clr); + + writel(POWER_CTRL_VBUS_VALID_IRQ | POWER_CTRL_VDD5V_GT_VDDIO_IRQ, + &power_regs->hw_power_ctrl_clr); + + mxs_power_enable_4p2(); +} + +/** + * mxs_powerdown() - Shut down the system + * + * This function powers down the CPU completely. + */ +static void mxs_powerdown(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + writel(POWER_RESET_UNLOCK_KEY, &power_regs->hw_power_reset); + writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF, + &power_regs->hw_power_reset); +} + +/** + * mxs_batt_boot() - Configure the power block to boot from battery input + * + * This function configures the power block to boot from the battery voltage + * supply. + */ +static void mxs_batt_boot(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT); + clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_ENABLE_DCDC); + + clrbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_ENABLE_DCDC | POWER_DCDC4P2_ENABLE_4P2); + writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_clr); + + /* 5V to battery handoff. */ + setbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER); + early_delay(30); + clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER); + + writel(POWER_CTRL_ENIRQ_DCDC4P2_BO, &power_regs->hw_power_ctrl_clr); + + clrsetbits_le32(&power_regs->hw_power_minpwr, + POWER_MINPWR_HALFFETS, POWER_MINPWR_DOUBLE_FETS); + + mxs_power_set_linreg(); + + clrbits_le32(&power_regs->hw_power_vdddctrl, + POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG); + + clrbits_le32(&power_regs->hw_power_vddactrl, + POWER_VDDACTRL_DISABLE_FET | POWER_VDDACTRL_ENABLE_LINREG); + + clrbits_le32(&power_regs->hw_power_vddioctrl, + POWER_VDDIOCTRL_DISABLE_FET); + + setbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_PWD_CHARGE_4P2_MASK); + + setbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_ENABLE_DCDC); + + clrsetbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK, + 0x8 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET); + + mxs_power_enable_4p2(); +} + +/** + * mxs_handle_5v_conflict() - Test if the 5V input is reliable + * + * This function tests if the 5V input can reliably supply the system. If it + * can, then proceed to configuring the system to boot from 5V source, otherwise + * try booting from battery supply. If we can not boot from battery supply + * either, shut down the system. + */ +static void mxs_handle_5v_conflict(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t tmp; + + setbits_le32(&power_regs->hw_power_vddioctrl, + POWER_VDDIOCTRL_BO_OFFSET_MASK); + + for (;;) { + tmp = readl(&power_regs->hw_power_sts); + + if (tmp & POWER_STS_VDDIO_BO) { + /* + * VDDIO has a brownout, then the VDD5V_GT_VDDIO becomes + * unreliable + */ + mxs_powerdown(); + break; + } + + if (tmp & POWER_STS_VDD5V_GT_VDDIO) { + mxs_boot_valid_5v(); + break; + } else { + mxs_powerdown(); + break; + } + + if (tmp & POWER_STS_PSWITCH_MASK) { + mxs_batt_boot(); + break; + } + } +} + +/** + * mxs_5v_boot() - Configure the power block to boot from 5V input + * + * This function handles configuration of the power block when supplied by + * a 5V input. + */ +static void mxs_5v_boot(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + /* + * NOTE: In original IMX-Bootlets, this also checks for VBUSVALID, + * but their implementation always returns 1 so we omit it here. + */ + if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) { + mxs_boot_valid_5v(); + return; + } + + early_delay(1000); + if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) { + mxs_boot_valid_5v(); + return; + } + + mxs_handle_5v_conflict(); +} + +/** + * mxs_init_batt_bo() - Configure battery brownout threshold + * + * This function configures the battery input brownout threshold. The value + * at which the battery brownout happens is configured to 3.0V in the code. + */ +static void mxs_init_batt_bo(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + /* Brownout at 3V */ + clrsetbits_le32(&power_regs->hw_power_battmonitor, + POWER_BATTMONITOR_BRWNOUT_LVL_MASK, + 15 << POWER_BATTMONITOR_BRWNOUT_LVL_OFFSET); + + writel(POWER_CTRL_BATT_BO_IRQ, &power_regs->hw_power_ctrl_clr); + writel(POWER_CTRL_ENIRQ_BATT_BO, &power_regs->hw_power_ctrl_clr); +} + +/** + * mxs_switch_vddd_to_dcdc_source() - Switch VDDD rail to DC-DC converter + * + * This function turns off the VDDD linear regulator and therefore makes + * the VDDD rail be supplied only by the DC-DC converter. + */ +static void mxs_switch_vddd_to_dcdc_source(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + clrsetbits_le32(&power_regs->hw_power_vdddctrl, + POWER_VDDDCTRL_LINREG_OFFSET_MASK, + POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW); + + clrbits_le32(&power_regs->hw_power_vdddctrl, + POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG | + POWER_VDDDCTRL_DISABLE_STEPPING); +} + +/** + * mxs_power_configure_power_source() - Configure power block source + * + * This function is the core of the power configuration logic. The function + * selects the power block input source and configures the whole power block + * accordingly. After the configuration is complete and the system is stable + * again, the function switches the CPU clock source back to PLL. Finally, + * the function switches the voltage rails to DC-DC converter. + */ +static void mxs_power_configure_power_source(void) +{ + int batt_ready, batt_good; + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + struct mxs_lradc_regs *lradc_regs = + (struct mxs_lradc_regs *)MXS_LRADC_BASE; + + mxs_src_power_init(); + + if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) { + batt_ready = mxs_is_batt_ready(); + if (batt_ready) { + /* 5V source detected, good battery detected. */ + mxs_batt_boot(); + } else { + batt_good = mxs_is_batt_good(); + if (!batt_good) { + /* 5V source detected, bad battery detected. */ + writel(LRADC_CONVERSION_AUTOMATIC, + &lradc_regs->hw_lradc_conversion_clr); + clrbits_le32(&power_regs->hw_power_battmonitor, + POWER_BATTMONITOR_BATT_VAL_MASK); + } + mxs_5v_boot(); + } + } else { + /* 5V not detected, booting from battery. */ + mxs_batt_boot(); + } + + mxs_power_clock2pll(); + + mxs_init_batt_bo(); + + mxs_switch_vddd_to_dcdc_source(); + +#ifdef CONFIG_MX23 + /* Fire up the VDDMEM LinReg now that we're all set. */ + writel(POWER_VDDMEMCTRL_ENABLE_LINREG | POWER_VDDMEMCTRL_ENABLE_ILIMIT, + &power_regs->hw_power_vddmemctrl); +#endif +} + +/** + * mxs_enable_output_rail_protection() - Enable power rail protection + * + * This function enables overload protection on the power rails. This is + * triggered if the power rails' voltage drops rapidly due to overload and + * in such case, the supply to the powerrail is cut-off, protecting the + * CPU from damage. Note that under such condition, the system will likely + * crash or misbehave. + */ +static void mxs_enable_output_rail_protection(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ | + POWER_CTRL_VDDIO_BO_IRQ, &power_regs->hw_power_ctrl_clr); + + setbits_le32(&power_regs->hw_power_vdddctrl, + POWER_VDDDCTRL_PWDN_BRNOUT); + + setbits_le32(&power_regs->hw_power_vddactrl, + POWER_VDDACTRL_PWDN_BRNOUT); + + setbits_le32(&power_regs->hw_power_vddioctrl, + POWER_VDDIOCTRL_PWDN_BRNOUT); +} + +/** + * mxs_get_vddio_power_source_off() - Get VDDIO rail power source + * + * This function tests if the VDDIO rail is supplied by linear regulator + * or by the DC-DC converter. Returns 1 if powered by linear regulator, + * returns 0 if powered by the DC-DC converter. + */ +static int mxs_get_vddio_power_source_off(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t tmp; + + if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) { + tmp = readl(&power_regs->hw_power_vddioctrl); + if (tmp & POWER_VDDIOCTRL_DISABLE_FET) { + if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) == + POWER_VDDIOCTRL_LINREG_OFFSET_0STEPS) { + return 1; + } + } + + if (!(readl(&power_regs->hw_power_5vctrl) & + POWER_5VCTRL_ENABLE_DCDC)) { + if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) == + POWER_VDDIOCTRL_LINREG_OFFSET_0STEPS) { + return 1; + } + } + } + + return 0; + +} + +/** + * mxs_get_vddd_power_source_off() - Get VDDD rail power source + * + * This function tests if the VDDD rail is supplied by linear regulator + * or by the DC-DC converter. Returns 1 if powered by linear regulator, + * returns 0 if powered by the DC-DC converter. + */ +static int mxs_get_vddd_power_source_off(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t tmp; + + tmp = readl(&power_regs->hw_power_vdddctrl); + if (tmp & POWER_VDDDCTRL_DISABLE_FET) { + if ((tmp & POWER_VDDDCTRL_LINREG_OFFSET_MASK) == + POWER_VDDDCTRL_LINREG_OFFSET_0STEPS) { + return 1; + } + } + + if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) { + if (!(readl(&power_regs->hw_power_5vctrl) & + POWER_5VCTRL_ENABLE_DCDC)) { + return 1; + } + } + + if (!(tmp & POWER_VDDDCTRL_ENABLE_LINREG)) { + if ((tmp & POWER_VDDDCTRL_LINREG_OFFSET_MASK) == + POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW) { + return 1; + } + } + + return 0; +} + +struct mxs_vddx_cfg { + uint32_t *reg; + uint8_t step_mV; + uint16_t lowest_mV; + int (*powered_by_linreg)(void); + uint32_t trg_mask; + uint32_t bo_irq; + uint32_t bo_enirq; + uint32_t bo_offset_mask; + uint32_t bo_offset_offset; +}; + +static const struct mxs_vddx_cfg mxs_vddio_cfg = { + .reg = &(((struct mxs_power_regs *)MXS_POWER_BASE)-> + hw_power_vddioctrl), +#if defined(CONFIG_MX23) + .step_mV = 25, +#else + .step_mV = 50, +#endif + .lowest_mV = 2800, + .powered_by_linreg = mxs_get_vddio_power_source_off, + .trg_mask = POWER_VDDIOCTRL_TRG_MASK, + .bo_irq = POWER_CTRL_VDDIO_BO_IRQ, + .bo_enirq = POWER_CTRL_ENIRQ_VDDIO_BO, + .bo_offset_mask = POWER_VDDIOCTRL_BO_OFFSET_MASK, + .bo_offset_offset = POWER_VDDIOCTRL_BO_OFFSET_OFFSET, +}; + +static const struct mxs_vddx_cfg mxs_vddd_cfg = { + .reg = &(((struct mxs_power_regs *)MXS_POWER_BASE)-> + hw_power_vdddctrl), + .step_mV = 25, + .lowest_mV = 800, + .powered_by_linreg = mxs_get_vddd_power_source_off, + .trg_mask = POWER_VDDDCTRL_TRG_MASK, + .bo_irq = POWER_CTRL_VDDD_BO_IRQ, + .bo_enirq = POWER_CTRL_ENIRQ_VDDD_BO, + .bo_offset_mask = POWER_VDDDCTRL_BO_OFFSET_MASK, + .bo_offset_offset = POWER_VDDDCTRL_BO_OFFSET_OFFSET, +}; + +#ifdef CONFIG_MX23 +static const struct mxs_vddx_cfg mxs_vddmem_cfg = { + .reg = &(((struct mxs_power_regs *)MXS_POWER_BASE)-> + hw_power_vddmemctrl), + .step_mV = 50, + .lowest_mV = 1700, + .powered_by_linreg = NULL, + .trg_mask = POWER_VDDMEMCTRL_TRG_MASK, + .bo_irq = 0, + .bo_enirq = 0, + .bo_offset_mask = 0, + .bo_offset_offset = 0, +}; +#endif + +/** + * mxs_power_set_vddx() - Configure voltage on DC-DC converter rail + * @cfg: Configuration data of the DC-DC converter rail + * @new_target: New target voltage of the DC-DC converter rail + * @new_brownout: New brownout trigger voltage + * + * This function configures the output voltage on the DC-DC converter rail. + * The rail is selected by the @cfg argument. The new voltage target is + * selected by the @new_target and the voltage is specified in mV. The + * new brownout value is selected by the @new_brownout argument and the + * value is also in mV. + */ +static void mxs_power_set_vddx(const struct mxs_vddx_cfg *cfg, + uint32_t new_target, uint32_t new_brownout) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t cur_target, diff, bo_int = 0; + uint32_t powered_by_linreg = 0; + int adjust_up, tmp; + + new_brownout = DIV_ROUND(new_target - new_brownout, cfg->step_mV); + + cur_target = readl(cfg->reg); + cur_target &= cfg->trg_mask; + cur_target *= cfg->step_mV; + cur_target += cfg->lowest_mV; + + adjust_up = new_target > cur_target; + if (cfg->powered_by_linreg) + powered_by_linreg = cfg->powered_by_linreg(); + + if (adjust_up && cfg->bo_irq) { + if (powered_by_linreg) { + bo_int = readl(cfg->reg); + clrbits_le32(cfg->reg, cfg->bo_enirq); + } + setbits_le32(cfg->reg, cfg->bo_offset_mask); + } + + do { + if (abs(new_target - cur_target) > 100) { + if (adjust_up) + diff = cur_target + 100; + else + diff = cur_target - 100; + } else { + diff = new_target; + } + + diff -= cfg->lowest_mV; + diff /= cfg->step_mV; + + clrsetbits_le32(cfg->reg, cfg->trg_mask, diff); + + if (powered_by_linreg || + (readl(&power_regs->hw_power_sts) & + POWER_STS_VDD5V_GT_VDDIO)) + early_delay(500); + else { + for (;;) { + tmp = readl(&power_regs->hw_power_sts); + if (tmp & POWER_STS_DC_OK) + break; + } + } + + cur_target = readl(cfg->reg); + cur_target &= cfg->trg_mask; + cur_target *= cfg->step_mV; + cur_target += cfg->lowest_mV; + } while (new_target > cur_target); + + if (cfg->bo_irq) { + if (adjust_up && powered_by_linreg) { + writel(cfg->bo_irq, &power_regs->hw_power_ctrl_clr); + if (bo_int & cfg->bo_enirq) + setbits_le32(cfg->reg, cfg->bo_enirq); + } + + clrsetbits_le32(cfg->reg, cfg->bo_offset_mask, + new_brownout << cfg->bo_offset_offset); + } +} + +/** + * mxs_setup_batt_detect() - Start the battery voltage measurement logic + * + * This function starts and configures the LRADC block. This allows the + * power initialization code to measure battery voltage and based on this + * knowledge, decide whether to boot at all, boot from battery or boot + * from 5V input. + */ +static void mxs_setup_batt_detect(void) +{ + mxs_lradc_init(); + mxs_lradc_enable_batt_measurement(); + early_delay(10); +} + +/** + * mxs_ungate_power() - Ungate the POWER block + * + * This function ungates clock to the power block. In case the power block + * was still gated at this point, it will not be possible to configure the + * block and therefore the power initialization would fail. This function + * is only needed on i.MX233, on i.MX28 the power block is always ungated. + */ +static void mxs_ungate_power(void) +{ +#ifdef CONFIG_MX23 + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + writel(POWER_CTRL_CLKGATE, &power_regs->hw_power_ctrl_clr); +#endif +} + +/** + * mxs_power_init() - The power block init main function + * + * This function calls all the power block initialization functions in + * proper sequence to start the power block. + */ +void mxs_power_init(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + mxs_ungate_power(); + + mxs_power_clock2xtal(); + mxs_power_set_auto_restart(); + mxs_power_set_linreg(); + mxs_power_setup_5v_detect(); + + mxs_setup_batt_detect(); + + mxs_power_configure_power_source(); + mxs_enable_output_rail_protection(); + + mxs_power_set_vddx(&mxs_vddio_cfg, 3300, 3150); + mxs_power_set_vddx(&mxs_vddd_cfg, 1500, 1000); +#ifdef CONFIG_MX23 + mxs_power_set_vddx(&mxs_vddmem_cfg, 2500, 1700); +#endif + writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ | + POWER_CTRL_VDDIO_BO_IRQ | POWER_CTRL_VDD5V_DROOP_IRQ | + POWER_CTRL_VBUS_VALID_IRQ | POWER_CTRL_BATT_BO_IRQ | + POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr); + + writel(POWER_5VCTRL_PWDN_5VBRNOUT, &power_regs->hw_power_5vctrl_set); + + early_delay(1000); +} + +#ifdef CONFIG_SPL_MXS_PSWITCH_WAIT +/** + * mxs_power_wait_pswitch() - Wait for power switch to be pressed + * + * This function waits until the power-switch was pressed to start booting + * the board. + */ +void mxs_power_wait_pswitch(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + while (!(readl(&power_regs->hw_power_sts) & POWER_STS_PSWITCH_MASK)) + ; +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/start.S b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/start.S new file mode 100644 index 000000000..34a0fcb46 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/start.S @@ -0,0 +1,185 @@ +/* + * armboot - Startup Code for ARM926EJS CPU-core + * + * Copyright (c) 2003 Texas Instruments + * + * ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------ + * + * Copyright (c) 2001 Marius Groger <mag@sysgo.de> + * Copyright (c) 2002 Alex Zupke <azu@sysgo.de> + * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de> + * Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com> + * Copyright (c) 2003 Kshitij <kshitij@ti.com> + * Copyright (c) 2010 Albert Aribaud <albert.u.boot@aribaud.net> + * + * Change to support call back into iMX28 bootrom + * Copyright (c) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <asm-offsets.h> +#include <config.h> +#include <common.h> +#include <version.h> + +/* + ************************************************************************* + * + * Jump vector table as in table 3.1 in [1] + * + ************************************************************************* + */ + + +.globl _start +_start: + b reset + b undefined_instruction + b software_interrupt + b prefetch_abort + b data_abort + b not_used + b irq + b fiq + +/* + * Vector table, located at address 0x20. + * This table allows the code running AFTER SPL, the U-Boot, to install it's + * interrupt handlers here. The problem is that the U-Boot is loaded into RAM, + * including it's interrupt vectoring table and the table at 0x0 is still the + * SPLs. So if interrupt happens in U-Boot, the SPLs interrupt vectoring table + * is still used. + */ +_vt_reset: + .word _reset +_vt_undefined_instruction: + .word _hang +_vt_software_interrupt: + .word _hang +_vt_prefetch_abort: + .word _hang +_vt_data_abort: + .word _hang +_vt_not_used: + .word _reset +_vt_irq: + .word _hang +_vt_fiq: + .word _hang + +reset: + ldr pc, _vt_reset +undefined_instruction: + ldr pc, _vt_undefined_instruction +software_interrupt: + ldr pc, _vt_software_interrupt +prefetch_abort: + ldr pc, _vt_prefetch_abort +data_abort: + ldr pc, _vt_data_abort +not_used: + ldr pc, _vt_not_used +irq: + ldr pc, _vt_irq +fiq: + ldr pc, _vt_fiq + + .balignl 16,0xdeadbeef + +/* + ************************************************************************* + * + * Startup Code (reset vector) + * + * do important init only if we don't start from memory! + * setup Memory and board specific bits prior to relocation. + * relocate armboot to ram + * setup stack + * + ************************************************************************* + */ + +#ifdef CONFIG_USE_IRQ +/* IRQ stack memory (calculated at run-time) */ +.globl IRQ_STACK_START +IRQ_STACK_START: + .word 0x0badc0de + +/* IRQ stack memory (calculated at run-time) */ +.globl FIQ_STACK_START +FIQ_STACK_START: + .word 0x0badc0de +#endif + +/* IRQ stack memory (calculated at run-time) + 8 bytes */ +.globl IRQ_STACK_START_IN +IRQ_STACK_START_IN: + .word 0x0badc0de + +/* + * the actual reset code + */ + +_reset: + /* + * If the CPU is configured in "Wait JTAG connection mode", the stack + * pointer is not configured and is zero. This will cause crash when + * trying to push data onto stack right below here. Load the SP and make + * it point to the end of OCRAM if the SP is zero. + */ + cmp sp, #0x00000000 + ldreq sp, =CONFIG_SYS_INIT_SP_ADDR + + /* + * Store all registers on old stack pointer, this will allow us later to + * return to the BootROM and let the BootROM load U-Boot into RAM. + * + * WARNING: Register r0 and r1 are used by the BootROM to pass data + * to the called code. Register r0 will contain arbitrary + * data that are set in the BootStream. In case this code + * was started with CALL instruction, register r1 will contain + * pointer to the return value this function can then set. + * The code below MUST NOT CHANGE register r0 and r1 ! + */ + push {r0-r12,r14} + + /* Save control register c1 */ + mrc p15, 0, r2, c1, c0, 0 + push {r2} + + /* Set the cpu to SVC32 mode and store old CPSR register content. */ + mrs r2, cpsr + push {r2} + bic r2, r2, #0x1f + orr r2, r2, #0xd3 + msr cpsr, r2 + + bl board_init_ll + + /* Restore BootROM's CPU mode (especially FIQ). */ + pop {r2} + msr cpsr,r2 + + /* + * Restore c1 register. Especially set exception vector location + * back to BootROM space which is required by bootrom for USB boot. + */ + pop {r2} + mcr p15, 0, r2, c1, c0, 0 + + pop {r0-r12,r14} + + /* + * In case this code was started by the CALL instruction, the register + * r0 is examined by the BootROM after this code returns. The value in + * r0 must be set to 0 to indicate successful return. + */ + mov r0, #0 + + bx lr + +_hang: +1: + bl 1b /* hang and never return */ diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/timer.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/timer.c new file mode 100644 index 000000000..99d3fb873 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/timer.c @@ -0,0 +1,159 @@ +/* + * Freescale i.MX28 timer driver + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * Based on code from LTIB: + * (C) Copyright 2009-2010 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/sys_proto.h> + +/* Maximum fixed count */ +#if defined(CONFIG_MX23) +#define TIMER_LOAD_VAL 0xffff +#elif defined(CONFIG_MX28) +#define TIMER_LOAD_VAL 0xffffffff +#endif + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp (gd->arch.tbl) +#define lastdec (gd->arch.lastinc) + +/* + * This driver uses 1kHz clock source. + */ +#define MXS_INCREMENTER_HZ 1000 + +static inline unsigned long tick_to_time(unsigned long tick) +{ + return tick / (MXS_INCREMENTER_HZ / CONFIG_SYS_HZ); +} + +static inline unsigned long time_to_tick(unsigned long time) +{ + return time * (MXS_INCREMENTER_HZ / CONFIG_SYS_HZ); +} + +/* Calculate how many ticks happen in "us" microseconds */ +static inline unsigned long us_to_tick(unsigned long us) +{ + return (us * MXS_INCREMENTER_HZ) / 1000000; +} + +int timer_init(void) +{ + struct mxs_timrot_regs *timrot_regs = + (struct mxs_timrot_regs *)MXS_TIMROT_BASE; + + /* Reset Timers and Rotary Encoder module */ + mxs_reset_block(&timrot_regs->hw_timrot_rotctrl_reg); + + /* Set fixed_count to 0 */ +#if defined(CONFIG_MX23) + writel(0, &timrot_regs->hw_timrot_timcount0); +#elif defined(CONFIG_MX28) + writel(0, &timrot_regs->hw_timrot_fixed_count0); +#endif + + /* Set UPDATE bit and 1Khz frequency */ + writel(TIMROT_TIMCTRLn_UPDATE | TIMROT_TIMCTRLn_RELOAD | + TIMROT_TIMCTRLn_SELECT_1KHZ_XTAL, + &timrot_regs->hw_timrot_timctrl0); + + /* Set fixed_count to maximal value */ +#if defined(CONFIG_MX23) + writel(TIMER_LOAD_VAL - 1, &timrot_regs->hw_timrot_timcount0); +#elif defined(CONFIG_MX28) + writel(TIMER_LOAD_VAL, &timrot_regs->hw_timrot_fixed_count0); +#endif + + return 0; +} + +unsigned long long get_ticks(void) +{ + struct mxs_timrot_regs *timrot_regs = + (struct mxs_timrot_regs *)MXS_TIMROT_BASE; + uint32_t now; + + /* Current tick value */ +#if defined(CONFIG_MX23) + /* Upper bits are the valid ones. */ + now = readl(&timrot_regs->hw_timrot_timcount0) >> + TIMROT_RUNNING_COUNTn_RUNNING_COUNT_OFFSET; +#elif defined(CONFIG_MX28) + now = readl(&timrot_regs->hw_timrot_running_count0); +#endif + + if (lastdec >= now) { + /* + * normal mode (non roll) + * move stamp forward with absolut diff ticks + */ + timestamp += (lastdec - now); + } else { + /* we have rollover of decrementer */ + timestamp += (TIMER_LOAD_VAL - now) + lastdec; + + } + lastdec = now; + + return timestamp; +} + +ulong get_timer_masked(void) +{ + return tick_to_time(get_ticks()); +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +/* We use the HW_DIGCTL_MICROSECONDS register for sub-millisecond timer. */ +#define MXS_HW_DIGCTL_MICROSECONDS 0x8001c0c0 + +void __udelay(unsigned long usec) +{ + uint32_t old, new, incr; + uint32_t counter = 0; + + old = readl(MXS_HW_DIGCTL_MICROSECONDS); + + while (counter < usec) { + new = readl(MXS_HW_DIGCTL_MICROSECONDS); + + /* Check if the timer wrapped. */ + if (new < old) { + incr = 0xffffffff - old; + incr += new; + } else { + incr = new - old; + } + + /* + * Check if we are close to the maximum time and the counter + * would wrap if incremented. If that's the case, break out + * from the loop as the requested delay time passed. + */ + if (counter + incr < counter) + break; + + counter += incr; + old = new; + } +} + +ulong get_tbclk(void) +{ + return MXS_INCREMENTER_HZ; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/u-boot-imx23.bd b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/u-boot-imx23.bd new file mode 100644 index 000000000..3a51879d5 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/u-boot-imx23.bd @@ -0,0 +1,18 @@ +options { + driveTag = 0x00; + flags = 0x01; +} + +sources { + u_boot_spl="spl/u-boot-spl.bin"; + u_boot="u-boot.bin"; +} + +section (0) { + load u_boot_spl > 0x0000; + load ivt (entry = 0x0014) > 0x8000; + call 0x8000; + + load u_boot > 0x40000100; + call 0x40000100; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/u-boot-imx28.bd b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/u-boot-imx28.bd new file mode 100644 index 000000000..c60615a45 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/u-boot-imx28.bd @@ -0,0 +1,14 @@ +sources { + u_boot_spl="spl/u-boot-spl.bin"; + u_boot="u-boot.bin"; +} + +section (0) { + load u_boot_spl > 0x0000; + load ivt (entry = 0x0014) > 0x8000; + hab call 0x8000; + + load u_boot > 0x40000100; + load ivt (entry = 0x40000100) > 0x8000; + hab call 0x8000; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/u-boot-spl.lds b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/u-boot-spl.lds new file mode 100644 index 000000000..f4bf8ac1d --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/mxs/u-boot-spl.lds @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * January 2004 - Changed to support H4 device + * Copyright (c) 2004-2008 Texas Instruments + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = CONFIG_SPL_TEXT_BASE; + + . = ALIGN(4); + .text : + { + arch/arm/cpu/arm926ejs/mxs/start.o (.text*) + *(.text*) + } + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(4); + .data : { + *(.data*) + } + + . = ALIGN(4); + + .rel.dyn : { + __rel_dyn_start = .; + *(.rel*) + __rel_dyn_end = .; + } + + .bss : { + . = ALIGN(4); + __bss_start = .; + *(.bss*) + . = ALIGN(4); + __bss_end = .; + } + + .end : + { + *(.__end) + } + + _image_binary_end = .; + + .dynsym _image_binary_end : { *(.dynsym) } + .dynbss : { *(.dynbss) } + .dynstr : { *(.dynstr*) } + .dynamic : { *(.dynamic*) } + .hash : { *(.hash*) } + .plt : { *(.plt*) } + .interp : { *(.interp*) } + .gnu : { *(.gnu*) } + .ARM.exidx : { *(.ARM.exidx*) } +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/nomadik/Makefile b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/nomadik/Makefile new file mode 100644 index 000000000..cdf1345d5 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/nomadik/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y = timer.o gpio.o +obj-y += reset.o diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/nomadik/gpio.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/nomadik/gpio.c new file mode 100644 index 000000000..eff5b2b75 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/nomadik/gpio.c @@ -0,0 +1,83 @@ +/* + * (C) Copyright 2009 Alessandro Rubini + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/gpio.h> + +static unsigned long gpio_base[4] = { + NOMADIK_GPIO0_BASE, + NOMADIK_GPIO1_BASE, + NOMADIK_GPIO2_BASE, + NOMADIK_GPIO3_BASE +}; + +enum gpio_registers { + GPIO_DAT = 0x00, /* data register */ + GPIO_DATS = 0x04, /* data set */ + GPIO_DATC = 0x08, /* data clear */ + GPIO_PDIS = 0x0c, /* pull disable */ + GPIO_DIR = 0x10, /* direction */ + GPIO_DIRS = 0x14, /* direction set */ + GPIO_DIRC = 0x18, /* direction clear */ + GPIO_AFSLA = 0x20, /* alternate function select A */ + GPIO_AFSLB = 0x24, /* alternate function select B */ +}; + +static inline unsigned long gpio_to_base(int gpio) +{ + return gpio_base[gpio / 32]; +} + +static inline u32 gpio_to_bit(int gpio) +{ + return 1 << (gpio & 0x1f); +} + +void nmk_gpio_af(int gpio, int alternate_function) +{ + unsigned long base = gpio_to_base(gpio); + u32 bit = gpio_to_bit(gpio); + u32 afunc, bfunc; + + /* alternate function is 0..3, with one bit per register */ + afunc = readl(base + GPIO_AFSLA) & ~bit; + bfunc = readl(base + GPIO_AFSLB) & ~bit; + if (alternate_function & 1) afunc |= bit; + if (alternate_function & 2) bfunc |= bit; + writel(afunc, base + GPIO_AFSLA); + writel(bfunc, base + GPIO_AFSLB); +} + +void nmk_gpio_dir(int gpio, int dir) +{ + unsigned long base = gpio_to_base(gpio); + u32 bit = gpio_to_bit(gpio); + + if (dir) + writel(bit, base + GPIO_DIRS); + else + writel(bit, base + GPIO_DIRC); +} + +void nmk_gpio_set(int gpio, int val) +{ + unsigned long base = gpio_to_base(gpio); + u32 bit = gpio_to_bit(gpio); + + if (val) + writel(bit, base + GPIO_DATS); + else + writel(bit, base + GPIO_DATC); +} + +int nmk_gpio_get(int gpio) +{ + unsigned long base = gpio_to_base(gpio); + u32 bit = gpio_to_bit(gpio); + + return readl(base + GPIO_DAT) & bit; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/nomadik/reset.S b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/nomadik/reset.S new file mode 100644 index 000000000..ec954726a --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/nomadik/reset.S @@ -0,0 +1,14 @@ +#include <config.h> +/* + * Processor reset for Nomadik + */ + + .align 5 +.globl reset_cpu +reset_cpu: + ldr r0, =NOMADIK_SRC_BASE /* System and Reset Controller */ + ldr r1, =0x1 + str r1, [r0, #0x18] + +_loop_forever: + b _loop_forever diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/nomadik/timer.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/nomadik/timer.c new file mode 100644 index 000000000..775d0b748 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/nomadik/timer.c @@ -0,0 +1,71 @@ +/* + * (C) Copyright 2009 Alessandro Rubini + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/mtu.h> + +/* + * The timer is a decrementer, we'll left it free running at 2.4MHz. + * We have 2.4 ticks per microsecond and an overflow in almost 30min + */ +#define TIMER_CLOCK (24 * 100 * 1000) +#define COUNT_TO_USEC(x) ((x) * 5 / 12) /* overflows at 6min */ +#define USEC_TO_COUNT(x) ((x) * 12 / 5) /* overflows at 6min */ +#define TICKS_PER_HZ (TIMER_CLOCK / CONFIG_SYS_HZ) +#define TICKS_TO_HZ(x) ((x) / TICKS_PER_HZ) + +/* macro to read the decrementing 32 bit timer as an increasing count */ +#define READ_TIMER() (0 - readl(CONFIG_SYS_TIMERBASE + MTU_VAL(0))) + +/* Configure a free-running, auto-wrap counter with no prescaler */ +int timer_init(void) +{ + ulong val; + + writel(MTU_CRn_ENA | MTU_CRn_PRESCALE_1 | MTU_CRn_32BITS, + CONFIG_SYS_TIMERBASE + MTU_CR(0)); + + /* Reset the timer */ + writel(0, CONFIG_SYS_TIMERBASE + MTU_LR(0)); + /* + * The load-register isn't really immediate: it changes on clock + * edges, so we must wait for our newly-written value to appear. + * Since we might miss reading 0, wait for any change in value. + */ + val = READ_TIMER(); + while (READ_TIMER() == val) + ; + + return 0; +} + +/* Return how many HZ passed since "base" */ +ulong get_timer(ulong base) +{ + return TICKS_TO_HZ(READ_TIMER()) - base; +} + +/* Delay x useconds */ +void __udelay(unsigned long usec) +{ + ulong ini, end; + + ini = READ_TIMER(); + end = ini + USEC_TO_COUNT(usec); + while ((signed)(end - READ_TIMER()) > 0) + ; +} + +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +ulong get_tbclk(void) +{ + return CONFIG_SYS_HZ; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/omap/Makefile b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/omap/Makefile new file mode 100644 index 000000000..add923276 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/omap/Makefile @@ -0,0 +1,10 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y = timer.o +obj-$(CONFIG_DISPLAY_CPUINFO) += cpuinfo.o +obj-y += reset.o diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/omap/cpuinfo.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/omap/cpuinfo.c new file mode 100644 index 000000000..587d99a2b --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/omap/cpuinfo.c @@ -0,0 +1,242 @@ +/* + * OMAP1 CPU identification code + * + * Copyright (C) 2004 Nokia Corporation + * Written by Tony Lindgren <tony@atomide.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <common.h> +#include <command.h> +#include <linux/compiler.h> + +#if defined(CONFIG_OMAP) + +#define omap_readw(x) *(volatile unsigned short *)(x) +#define omap_readl(x) *(volatile unsigned long *)(x) + +#define OMAP_DIE_ID_0 0xfffe1800 +#define OMAP_DIE_ID_1 0xfffe1804 +#define OMAP_PRODUCTION_ID_0 0xfffe2000 +#define OMAP_PRODUCTION_ID_1 0xfffe2004 +#define OMAP32_ID_0 0xfffed400 +#define OMAP32_ID_1 0xfffed404 + +struct omap_id { + u16 jtag_id; /* Used to determine OMAP type */ + u8 die_rev; /* Processor revision */ + u32 omap_id; /* OMAP revision */ + u32 type; /* Cpu id bits [31:08], cpu class bits [07:00] */ +}; + +/* Register values to detect the OMAP version */ +static struct omap_id omap_ids[] = { + { .jtag_id = 0xb574, .die_rev = 0x2, .omap_id = 0x03310315, .type = 0x03100000}, + { .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100}, + { .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300}, + { .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000}, + { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x16100000}, + { .jtag_id = 0xb576, .die_rev = 0x2, .omap_id = 0x03320100, .type = 0x16110000}, + { .jtag_id = 0xb576, .die_rev = 0x3, .omap_id = 0x03320100, .type = 0x16100c00}, + { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320200, .type = 0x16100d00}, + { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00}, + { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00}, + { .jtag_id = 0xb576, .die_rev = 0x1, .omap_id = 0x03320100, .type = 0x16110000}, + { .jtag_id = 0xb58c, .die_rev = 0x2, .omap_id = 0x03320200, .type = 0x16110b00}, + { .jtag_id = 0xb58c, .die_rev = 0x3, .omap_id = 0x03320200, .type = 0x16110c00}, + { .jtag_id = 0xb65f, .die_rev = 0x0, .omap_id = 0x03320400, .type = 0x16212300}, + { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320400, .type = 0x16212300}, + { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x16212300}, + { .jtag_id = 0xb5f7, .die_rev = 0x0, .omap_id = 0x03330000, .type = 0x17100000}, + { .jtag_id = 0xb5f7, .die_rev = 0x1, .omap_id = 0x03330100, .type = 0x17100000}, + { .jtag_id = 0xb5f7, .die_rev = 0x2, .omap_id = 0x03330100, .type = 0x17100000}, +}; + +/* + * Get OMAP type from PROD_ID. + * 1710 has the PROD_ID in bits 15:00, not in 16:01 as documented in TRM. + * 1510 PROD_ID is empty, and 1610 PROD_ID does not make sense. + * Undocumented register in TEST BLOCK is used as fallback; This seems to + * work on 1510, 1610 & 1710. The official way hopefully will work in future + * processors. + */ +static u16 omap_get_jtag_id(void) +{ + u32 prod_id, omap_id; + + prod_id = omap_readl(OMAP_PRODUCTION_ID_1); + omap_id = omap_readl(OMAP32_ID_1); + + /* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730 */ + if (((prod_id >> 20) == 0) || (prod_id == omap_id)) + prod_id = 0; + else + prod_id &= 0xffff; + + if (prod_id) + return prod_id; + + /* Use OMAP32_ID_1 as fallback */ + prod_id = ((omap_id >> 12) & 0xffff); + + return prod_id; +} + +/* + * Get OMAP revision from DIE_REV. + * Early 1710 processors may have broken OMAP_DIE_ID, it contains PROD_ID. + * Undocumented register in the TEST BLOCK is used as fallback. + * REVISIT: This does not seem to work on 1510 + */ +static u8 omap_get_die_rev(void) +{ + u32 die_rev; + + die_rev = omap_readl(OMAP_DIE_ID_1); + + /* Check for broken OMAP_DIE_ID on early 1710 */ + if (((die_rev >> 12) & 0xffff) == omap_get_jtag_id()) + die_rev = 0; + + die_rev = (die_rev >> 17) & 0xf; + if (die_rev) + return die_rev; + + die_rev = (omap_readl(OMAP32_ID_1) >> 28) & 0xf; + + return die_rev; +} + +static unsigned long dpll1(void) +{ + unsigned short pll_ctl_val = omap_readw(DPLL_CTL_REG); + unsigned long rate; + + rate = CONFIG_SYS_CLK_FREQ; /* Base xtal rate */ + if (pll_ctl_val & 0x10) { + /* PLL enabled, apply multiplier and divisor */ + if (pll_ctl_val & 0xf80) + rate *= (pll_ctl_val & 0xf80) >> 7; + rate /= ((pll_ctl_val & 0x60) >> 5) + 1; + } else { + /* PLL disabled, apply bypass divisor */ + switch (pll_ctl_val & 0xc) { + case 0: + break; + case 0x4: + rate /= 2; + break; + default: + rate /= 4; + break; + } + } + + return rate; +} + +static unsigned long armcore(void) +{ + unsigned short arm_ckctl = omap_readw(ARM_CKCTL); + + return (dpll1() >> ((arm_ckctl & 0x0030) >> 4)); +} + +int print_cpuinfo (void) +{ + int i; + u16 jtag_id; + u8 die_rev; + u32 omap_id; + u8 cpu_type; + __maybe_unused u32 system_serial_high; + __maybe_unused u32 system_serial_low; + u32 system_rev = 0; + + jtag_id = omap_get_jtag_id(); + die_rev = omap_get_die_rev(); + omap_id = omap_readl(OMAP32_ID_0); + +#ifdef DEBUG + printf("OMAP_DIE_ID_0: 0x%08x\n", omap_readl(OMAP_DIE_ID_0)); + printf("OMAP_DIE_ID_1: 0x%08x DIE_REV: %i\n", + omap_readl(OMAP_DIE_ID_1), + (omap_readl(OMAP_DIE_ID_1) >> 17) & 0xf); + printf("OMAP_PRODUCTION_ID_0: 0x%08x\n", omap_readl(OMAP_PRODUCTION_ID_0)); + printf("OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x\n", + omap_readl(OMAP_PRODUCTION_ID_1), + omap_readl(OMAP_PRODUCTION_ID_1) & 0xffff); + printf("OMAP32_ID_0: 0x%08x\n", omap_readl(OMAP32_ID_0)); + printf("OMAP32_ID_1: 0x%08x\n", omap_readl(OMAP32_ID_1)); + printf("JTAG_ID: 0x%04x DIE_REV: %i\n", jtag_id, die_rev); +#endif + + system_serial_high = omap_readl(OMAP_DIE_ID_0); + system_serial_low = omap_readl(OMAP_DIE_ID_1); + + /* First check only the major version in a safe way */ + for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { + if (jtag_id == (omap_ids[i].jtag_id)) { + system_rev = omap_ids[i].type; + break; + } + } + + /* Check if we can find the die revision */ + for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { + if (jtag_id == omap_ids[i].jtag_id && die_rev == omap_ids[i].die_rev) { + system_rev = omap_ids[i].type; + break; + } + } + + /* Finally check also the omap_id */ + for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { + if (jtag_id == omap_ids[i].jtag_id + && die_rev == omap_ids[i].die_rev + && omap_id == omap_ids[i].omap_id) { + system_rev = omap_ids[i].type; + break; + } + } + + /* Add the cpu class info (7xx, 15xx, 16xx, 24xx) */ + cpu_type = system_rev >> 24; + + switch (cpu_type) { + case 0x07: + system_rev |= 0x07; + break; + case 0x03: + case 0x15: + system_rev |= 0x15; + break; + case 0x16: + case 0x17: + system_rev |= 0x16; + break; + case 0x24: + system_rev |= 0x24; + break; + default: + printf("Unknown OMAP cpu type: 0x%02x\n", cpu_type); + } + + printf("CPU: OMAP%04x", system_rev >> 16); + if ((system_rev >> 8) & 0xff) + printf("%x", (system_rev >> 8) & 0xff); +#ifdef DEBUG + printf(" revision %i handled as %02xxx id: %08x%08x", + die_rev, system_rev & 0xff, system_serial_low, system_serial_high); +#endif + printf(" at %ld.%01ld MHz (DPLL1=%ld.%01ld MHz)\n", + armcore() / 1000000, (armcore() / 100000) % 10, + dpll1() / 1000000, (dpll1() / 100000) % 10); + + return 0; +} + +#endif /* #if defined(CONFIG_OMAP) */ diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/omap/reset.S b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/omap/reset.S new file mode 100644 index 000000000..1c557b0d9 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/omap/reset.S @@ -0,0 +1,29 @@ +/* + * armboot - Startup Code for ARM926EJS CPU-core + * + * Copyright (c) 2003 Texas Instruments + * + * ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------ + * + * Copyright (c) 2001 Marius Gröger <mag@sysgo.de> + * Copyright (c) 2002 Alex Züpke <azu@sysgo.de> + * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de> + * Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com> + * Copyright (c) 2003 Kshitij <kshitij@ti.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + + .align 5 +.globl reset_cpu +reset_cpu: + ldr r1, rstctl1 /* get clkm1 reset ctl */ + mov r3, #0x0 + strh r3, [r1] /* clear it */ + mov r3, #0x8 + strh r3, [r1] /* force dsp+arm reset */ +_loop_forever: + b _loop_forever + +rstctl1: + .word 0xfffece10 diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/omap/timer.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/omap/timer.c new file mode 100644 index 000000000..b9715656c --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/omap/timer.c @@ -0,0 +1,152 @@ +/* + * (C) Copyright 2003 + * Texas Instruments <www.ti.com> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002-2004 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * (C) Copyright 2004 + * Philippe Robin, ARM Ltd. <philippe.robin@arm.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> + +#define TIMER_CLOCK (CONFIG_SYS_CLK_FREQ / (2 << CONFIG_SYS_PTV)) +#define TIMER_LOAD_VAL 0xffffffff + +/* macro to read the 32 bit timer */ +#define READ_TIMER readl(CONFIG_SYS_TIMERBASE+8) \ + / (TIMER_CLOCK / CONFIG_SYS_HZ) + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp gd->arch.tbl +#define lastdec gd->arch.lastinc + +int timer_init (void) +{ + int32_t val; + + /* Start the decrementer ticking down from 0xffffffff */ + *((int32_t *) (CONFIG_SYS_TIMERBASE + LOAD_TIM)) = TIMER_LOAD_VAL; + val = MPUTIM_ST | MPUTIM_AR | MPUTIM_CLOCK_ENABLE | (CONFIG_SYS_PTV << MPUTIM_PTV_BIT); + *((int32_t *) (CONFIG_SYS_TIMERBASE + CNTL_TIMER)) = val; + + /* init the timestamp and lastdec value */ + reset_timer_masked(); + + return 0; +} + +/* + * timer without interrupts + */ +ulong get_timer (ulong base) +{ + return get_timer_masked () - base; +} + +/* delay x useconds AND preserve advance timestamp value */ +void __udelay (unsigned long usec) +{ + ulong tmo, tmp; + + if(usec >= 1000){ /* if "big" number, spread normalization to seconds */ + tmo = usec / 1000; /* start to normalize for usec to ticks per sec */ + tmo *= CONFIG_SYS_HZ; /* find number of "ticks" to wait to achieve target */ + tmo /= 1000; /* finish normalize. */ + }else{ /* else small number, don't kill it prior to HZ multiply */ + tmo = usec * CONFIG_SYS_HZ; + tmo /= (1000*1000); + } + + tmp = get_timer (0); /* get current timestamp */ + if( (tmo + tmp + 1) < tmp ) /* if setting this fordward will roll time stamp */ + reset_timer_masked (); /* reset "advancing" timestamp to 0, set lastdec value */ + else + tmo += tmp; /* else, set advancing stamp wake up time */ + + while (get_timer_masked () < tmo)/* loop till event */ + /*NOP*/; +} + +void reset_timer_masked (void) +{ + /* reset time */ + lastdec = READ_TIMER; /* capure current decrementer value time */ + timestamp = 0; /* start "advancing" time stamp from 0 */ +} + +ulong get_timer_masked (void) +{ + ulong now = READ_TIMER; /* current tick value */ + + if (lastdec >= now) { /* normal mode (non roll) */ + /* normal mode */ + timestamp += lastdec - now; /* move stamp fordward with absoulte diff ticks */ + } else { /* we have overflow of the count down timer */ + /* nts = ts + ld + (TLV - now) + * ts=old stamp, ld=time that passed before passing through -1 + * (TLV-now) amount of time after passing though -1 + * nts = new "advancing time stamp"...it could also roll and cause problems. + */ + timestamp += lastdec + (TIMER_LOAD_VAL / (TIMER_CLOCK / + CONFIG_SYS_HZ)) - now; + } + lastdec = now; + + return timestamp; +} + +/* waits specified delay value and resets timestamp */ +void udelay_masked (unsigned long usec) +{ + ulong tmo; + ulong endtime; + signed long diff; + + if (usec >= 1000) { /* if "big" number, spread normalization to seconds */ + tmo = usec / 1000; /* start to normalize for usec to ticks per sec */ + tmo *= CONFIG_SYS_HZ; /* find number of "ticks" to wait to achieve target */ + tmo /= 1000; /* finish normalize. */ + } else { /* else small number, don't kill it prior to HZ multiply */ + tmo = usec * CONFIG_SYS_HZ; + tmo /= (1000*1000); + } + + endtime = get_timer_masked () + tmo; + + do { + ulong now = get_timer_masked (); + diff = endtime - now; + } while (diff >= 0); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk (void) +{ + return CONFIG_SYS_HZ; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/orion5x/Makefile b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/orion5x/Makefile new file mode 100644 index 000000000..546ebcb52 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/orion5x/Makefile @@ -0,0 +1,18 @@ +# +# Copyright (C) 2010 Albert ARIBAUD <albert.u.boot@aribaud.net> +# +# Based on original Kirkwood support which is +# (C) Copyright 2009 +# Marvell Semiconductor <www.marvell.com> +# Written-by: Prafulla Wadaskar <prafulla@marvell.com> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y = cpu.o +obj-y += dram.o +obj-y += timer.o + +ifndef CONFIG_SKIP_LOWLEVEL_INIT +obj-y += lowlevel_init.o +endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/orion5x/cpu.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/orion5x/cpu.c new file mode 100644 index 000000000..b55c5f094 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/orion5x/cpu.c @@ -0,0 +1,295 @@ +/* + * Copyright (C) 2010 Albert ARIBAUD <albert.u.boot@aribaud.net> + * + * Based on original Kirkwood support which is + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <netdev.h> +#include <asm/cache.h> +#include <asm/io.h> +#include <u-boot/md5.h> +#include <asm/arch/cpu.h> +#include <hush.h> + +#define BUFLEN 16 + +void reset_cpu(unsigned long ignored) +{ + struct orion5x_cpu_registers *cpureg = + (struct orion5x_cpu_registers *)ORION5X_CPU_REG_BASE; + + writel(readl(&cpureg->rstoutn_mask) | (1 << 2), + &cpureg->rstoutn_mask); + writel(readl(&cpureg->sys_soft_rst) | 1, + &cpureg->sys_soft_rst); + while (1) + ; +} + +/* + * Compute Window Size field value from size expressed in bytes + * Used with the Base register to set the address window size and location. + * Must be programmed from LSB to MSB as sequence of ones followed by + * sequence of zeros. The number of ones specifies the size of the window in + * 64 KiB granularity (e.g., a value of 0x00FF specifies 256 = 16 MiB). + * NOTES: + * 1) A sizeval equal to 0x0 specifies 4 GiB. + * 2) A return value of 0x0 specifies 64 KiB. + */ +unsigned int orion5x_winctrl_calcsize(unsigned int sizeval) +{ + /* + * Calculate the number of 64 KiB blocks needed minus one (rounding up). + * For sizeval > 0 this is equivalent to: + * sizeval = (u32) ceil((double) sizeval / 65536.0) - 1 + */ + sizeval = (sizeval - 1) >> 16; + + /* + * Propagate 'one' bits to the right by 'oring' them. + * We need only treat bits 15-0. + */ + sizeval |= sizeval >> 1; /* 'Or' bit 15 onto bit 14 */ + sizeval |= sizeval >> 2; /* 'Or' bits 15-14 onto bits 13-12 */ + sizeval |= sizeval >> 4; /* 'Or' bits 15-12 onto bits 11-8 */ + sizeval |= sizeval >> 8; /* 'Or' bits 15-8 onto bits 7-0*/ + + return sizeval; +} + +/* + * orion5x_config_adr_windows - Configure address Windows + * + * There are 8 address windows supported by Orion5x Soc to addess different + * devices. Each window can be configured for size, BAR and remap addr + * Below configuration is standard for most of the cases + * + * If remap function not used, remap_lo must be set as base + * + * NOTES: + * + * 1) in order to avoid windows with inconsistent control and base values + * (which could prevent access to BOOTCS and hence execution from FLASH) + * always disable window before writing the base value then reenable it + * by writing the control value. + * + * 2) in order to avoid losing access to BOOTCS when disabling window 7, + * first configure window 6 for BOOTCS, then configure window 7 for BOOTCS, + * then configure windows 6 for its own target. + * + * Reference Documentation: + * Mbus-L to Mbus Bridge Registers Configuration. + * (Sec 25.1 and 25.3 of Datasheet) + */ +int orion5x_config_adr_windows(void) +{ + struct orion5x_win_registers *winregs = + (struct orion5x_win_registers *)ORION5X_CPU_WIN_BASE; + +/* Disable window 0, configure it for its intended target, enable it. */ + writel(0, &winregs[0].ctrl); + writel(ORION5X_ADR_PCIE_MEM, &winregs[0].base); + writel(ORION5X_ADR_PCIE_MEM_REMAP_LO, &winregs[0].remap_lo); + writel(ORION5X_ADR_PCIE_MEM_REMAP_HI, &winregs[0].remap_hi); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_PCIE_MEM, + ORION5X_TARGET_PCIE, ORION5X_ATTR_PCIE_MEM, + ORION5X_WIN_ENABLE), &winregs[0].ctrl); +/* Disable window 1, configure it for its intended target, enable it. */ + writel(0, &winregs[1].ctrl); + writel(ORION5X_ADR_PCIE_IO, &winregs[1].base); + writel(ORION5X_ADR_PCIE_IO_REMAP_LO, &winregs[1].remap_lo); + writel(ORION5X_ADR_PCIE_IO_REMAP_HI, &winregs[1].remap_hi); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_PCIE_IO, + ORION5X_TARGET_PCIE, ORION5X_ATTR_PCIE_IO, + ORION5X_WIN_ENABLE), &winregs[1].ctrl); +/* Disable window 2, configure it for its intended target, enable it. */ + writel(0, &winregs[2].ctrl); + writel(ORION5X_ADR_PCI_MEM, &winregs[2].base); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_PCI_MEM, + ORION5X_TARGET_PCI, ORION5X_ATTR_PCI_MEM, + ORION5X_WIN_ENABLE), &winregs[2].ctrl); +/* Disable window 3, configure it for its intended target, enable it. */ + writel(0, &winregs[3].ctrl); + writel(ORION5X_ADR_PCI_IO, &winregs[3].base); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_PCI_IO, + ORION5X_TARGET_PCI, ORION5X_ATTR_PCI_IO, + ORION5X_WIN_ENABLE), &winregs[3].ctrl); +/* Disable window 4, configure it for its intended target, enable it. */ + writel(0, &winregs[4].ctrl); + writel(ORION5X_ADR_DEV_CS0, &winregs[4].base); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_DEV_CS0, + ORION5X_TARGET_DEVICE, ORION5X_ATTR_DEV_CS0, + ORION5X_WIN_ENABLE), &winregs[4].ctrl); +/* Disable window 5, configure it for its intended target, enable it. */ + writel(0, &winregs[5].ctrl); + writel(ORION5X_ADR_DEV_CS1, &winregs[5].base); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_DEV_CS1, + ORION5X_TARGET_DEVICE, ORION5X_ATTR_DEV_CS1, + ORION5X_WIN_ENABLE), &winregs[5].ctrl); +/* Disable window 6, configure it for FLASH, enable it. */ + writel(0, &winregs[6].ctrl); + writel(ORION5X_ADR_BOOTROM, &winregs[6].base); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_BOOTROM, + ORION5X_TARGET_DEVICE, ORION5X_ATTR_BOOTROM, + ORION5X_WIN_ENABLE), &winregs[6].ctrl); +/* Disable window 7, configure it for FLASH, enable it. */ + writel(0, &winregs[7].ctrl); + writel(ORION5X_ADR_BOOTROM, &winregs[7].base); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_BOOTROM, + ORION5X_TARGET_DEVICE, ORION5X_ATTR_BOOTROM, + ORION5X_WIN_ENABLE), &winregs[7].ctrl); +/* Disable window 6, configure it for its intended target, enable it. */ + writel(0, &winregs[6].ctrl); + writel(ORION5X_ADR_DEV_CS2, &winregs[6].base); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_DEV_CS2, + ORION5X_TARGET_DEVICE, ORION5X_ATTR_DEV_CS2, + ORION5X_WIN_ENABLE), &winregs[6].ctrl); + + return 0; +} + +/* + * Orion5x identification is done through PCIE space. + */ + +u32 orion5x_device_id(void) +{ + return readl(PCIE_DEV_ID_OFF) >> 16; +} + +u32 orion5x_device_rev(void) +{ + return readl(PCIE_DEV_REV_OFF) & 0xff; +} + +#if defined(CONFIG_DISPLAY_CPUINFO) + +/* Display device and revision IDs. + * This function must cover all known device/revision + * combinations, not only the one for which u-boot is + * compiled; this way, one can identify actual HW in + * case of a mismatch. + */ +int print_cpuinfo(void) +{ + char dev_str[7]; /* room enough for 0x0000 plus null byte */ + char rev_str[5]; /* room enough for 0x00 plus null byte */ + char *dev_name = NULL; + char *rev_name = NULL; + + u32 dev = orion5x_device_id(); + u32 rev = orion5x_device_rev(); + + if (dev == MV88F5181_DEV_ID) { + dev_name = "MV88F5181"; + if (rev == MV88F5181_REV_B1) + rev_name = "B1"; + else if (rev == MV88F5181L_REV_A1) { + dev_name = "MV88F5181L"; + rev_name = "A1"; + } else if (rev == MV88F5181L_REV_A0) { + dev_name = "MV88F5181L"; + rev_name = "A0"; + } + } else if (dev == MV88F5182_DEV_ID) { + dev_name = "MV88F5182"; + if (rev == MV88F5182_REV_A2) + rev_name = "A2"; + } else if (dev == MV88F5281_DEV_ID) { + dev_name = "MV88F5281"; + if (rev == MV88F5281_REV_D2) + rev_name = "D2"; + else if (rev == MV88F5281_REV_D1) + rev_name = "D1"; + else if (rev == MV88F5281_REV_D0) + rev_name = "D0"; + } else if (dev == MV88F6183_DEV_ID) { + dev_name = "MV88F6183"; + if (rev == MV88F6183_REV_B0) + rev_name = "B0"; + } + if (dev_name == NULL) { + sprintf(dev_str, "0x%04x", dev); + dev_name = dev_str; + } + if (rev_name == NULL) { + sprintf(rev_str, "0x%02x", rev); + rev_name = rev_str; + } + + printf("SoC: Orion5x %s-%s\n", dev_name, rev_name); + + return 0; +} +#endif /* CONFIG_DISPLAY_CPUINFO */ + +#ifdef CONFIG_ARCH_CPU_INIT +int arch_cpu_init(void) +{ + /* Enable and invalidate L2 cache in write through mode */ + invalidate_l2_cache(); + + orion5x_config_adr_windows(); + + return 0; +} +#endif /* CONFIG_ARCH_CPU_INIT */ + +/* + * SOC specific misc init + */ +#if defined(CONFIG_ARCH_MISC_INIT) +int arch_misc_init(void) +{ + u32 temp; + + /*CPU streaming & write allocate */ + temp = readfr_extra_feature_reg(); + temp &= ~(1 << 28); /* disable wr alloc */ + writefr_extra_feature_reg(temp); + + temp = readfr_extra_feature_reg(); + temp &= ~(1 << 29); /* streaming disabled */ + writefr_extra_feature_reg(temp); + + /* L2Cache settings */ + temp = readfr_extra_feature_reg(); + /* Disable L2C pre fetch - Set bit 24 */ + temp |= (1 << 24); + /* enable L2C - Set bit 22 */ + temp |= (1 << 22); + writefr_extra_feature_reg(temp); + + icache_enable(); + /* Change reset vector to address 0x0 */ + temp = get_cr(); + set_cr(temp & ~CR_V); + + /* Set CPIOs and MPPs - values provided by board + include file */ + writel(ORION5X_MPP0_7, ORION5X_MPP_BASE+0x00); + writel(ORION5X_MPP8_15, ORION5X_MPP_BASE+0x04); + writel(ORION5X_MPP16_23, ORION5X_MPP_BASE+0x50); + writel(ORION5X_GPIO_OUT_VALUE, ORION5X_GPIO_BASE+0x00); + writel(ORION5X_GPIO_OUT_ENABLE, ORION5X_GPIO_BASE+0x04); + writel(ORION5X_GPIO_IN_POLARITY, ORION5X_GPIO_BASE+0x0c); + + /* initialize timer */ + timer_init_r(); + return 0; +} +#endif /* CONFIG_ARCH_MISC_INIT */ + +#ifdef CONFIG_MVGBE +int cpu_eth_init(bd_t *bis) +{ + mvgbe_initialize(bis); + return 0; +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/orion5x/dram.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/orion5x/dram.c new file mode 100644 index 000000000..9ed93d25b --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/orion5x/dram.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2010 Albert ARIBAUD <albert.u.boot@aribaud.net> + * + * Based on original Kirkwood support which is + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <config.h> +#include <asm/arch/cpu.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * orion5x_sdram_bar - reads SDRAM Base Address Register + */ +u32 orion5x_sdram_bar(enum memory_bank bank) +{ + struct orion5x_ddr_addr_decode_registers *winregs = + (struct orion5x_ddr_addr_decode_registers *) + ORION5X_DRAM_BASE; + + u32 result = 0; + u32 enable = 0x01 & winregs[bank].size; + + if ((!enable) || (bank > BANK3)) + return 0; + + result = winregs[bank].base; + return result; +} +int dram_init (void) +{ + /* dram_init must store complete ramsize in gd->ram_size */ + gd->ram_size = get_ram_size( + (long *) orion5x_sdram_bar(0), + CONFIG_MAX_RAM_BANK_SIZE); + return 0; +} + +void dram_init_banksize (void) +{ + int i; + + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + gd->bd->bi_dram[i].start = orion5x_sdram_bar(i); + gd->bd->bi_dram[i].size = get_ram_size( + (long *) (gd->bd->bi_dram[i].start), + CONFIG_MAX_RAM_BANK_SIZE); + } +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/orion5x/lowlevel_init.S b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/orion5x/lowlevel_init.S new file mode 100644 index 000000000..4dacc296e --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/orion5x/lowlevel_init.S @@ -0,0 +1,277 @@ +/* + * Copyright (C) 2010 Albert ARIBAUD <albert.u.boot@aribaud.net> + * + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> +#include "asm/arch/orion5x.h" + +/* + * Configuration values for SDRAM access setup + */ + +#define SDRAM_CONFIG 0x3148400 +#define SDRAM_MODE 0x62 +#define SDRAM_CONTROL 0x4041000 +#define SDRAM_TIME_CTRL_LOW 0x11602220 +#define SDRAM_TIME_CTRL_HI 0x40c +#define SDRAM_OPEN_PAGE_EN 0x0 +/* DDR 1 2x 32M NANYA NT5DS16M16CS-6K ==> 64MB */ +#define SDRAM_BANK0_SIZE 0x3ff0001 +#define SDRAM_ADDR_CTRL 0x10 + +#define SDRAM_OP_NOP 0x05 +#define SDRAM_OP_SETMODE 0x03 + +#define SDRAM_PAD_CTRL_WR_EN 0x80000000 +#define SDRAM_PAD_CTRL_TUNE_EN 0x00010000 +#define SDRAM_PAD_CTRL_DRVN_MASK 0x0000003f +#define SDRAM_PAD_CTRL_DRVP_MASK 0x00000fc0 + +/* + * For Guideline MEM-3 - Drive Strength value + */ + +#define DDR1_PAD_STRENGTH_DEFAULT 0x00001000 +#define SDRAM_PAD_CTRL_DRV_STR_MASK 0x00003000 + +/* + * For Guideline MEM-4 - DQS Reference Delay Tuning + */ + +#define MSAR_ARMDDRCLCK_MASK 0x000000f0 +#define MSAR_ARMDDRCLCK_H_MASK 0x00000100 + +#define MSAR_ARMDDRCLCK_333_167 0x00000000 +#define MSAR_ARMDDRCLCK_500_167 0x00000030 +#define MSAR_ARMDDRCLCK_667_167 0x00000060 +#define MSAR_ARMDDRCLCK_400_200_1 0x000001E0 +#define MSAR_ARMDDRCLCK_400_200 0x00000010 +#define MSAR_ARMDDRCLCK_600_200 0x00000050 +#define MSAR_ARMDDRCLCK_800_200 0x00000070 + +#define FTDLL_DDR1_166MHZ 0x0047F001 + +#define FTDLL_DDR1_200MHZ 0x0044D001 + +/* + * Low-level init happens right after start.S has switched to SVC32, + * flushed and disabled caches and disabled MMU. We're still running + * from the boot chip select, so the first thing we should do is set + * up RAM for us to relocate into. + */ + +.globl lowlevel_init + +lowlevel_init: + + /* Use 'r4 as the base for internal register accesses */ + ldr r4, =ORION5X_REGS_PHY_BASE + + /* move internal registers from the default 0xD0000000 + * to their intended location, defined by SoC */ + ldr r3, =0xD0000000 + add r3, r3, #0x20000 + str r4, [r3, #0x80] + + /* Use R3 as the base for DRAM registers */ + add r3, r4, #0x01000 + + /*DDR SDRAM Initialization Control */ + ldr r6, =0x00000001 + str r6, [r3, #0x480] + + /* Use R3 as the base for PCI registers */ + add r3, r4, #0x31000 + + /* Disable arbiter */ + ldr r6, =0x00000030 + str r6, [r3, #0xd00] + + /* Use R3 as the base for DRAM registers */ + add r3, r4, #0x01000 + + /* set all dram windows to 0 */ + mov r6, #0 + str r6, [r3, #0x504] + str r6, [r3, #0x50C] + str r6, [r3, #0x514] + str r6, [r3, #0x51C] + + /* 1) Configure SDRAM */ + ldr r6, =SDRAM_CONFIG + str r6, [r3, #0x400] + + /* 2) Set SDRAM Control reg */ + ldr r6, =SDRAM_CONTROL + str r6, [r3, #0x404] + + /* 3) Write SDRAM address control register */ + ldr r6, =SDRAM_ADDR_CTRL + str r6, [r3, #0x410] + + /* 4) Write SDRAM bank 0 size register */ + ldr r6, =SDRAM_BANK0_SIZE + str r6, [r3, #0x504] + /* keep other banks disabled */ + + /* 5) Write SDRAM open pages control register */ + ldr r6, =SDRAM_OPEN_PAGE_EN + str r6, [r3, #0x414] + + /* 6) Write SDRAM timing Low register */ + ldr r6, =SDRAM_TIME_CTRL_LOW + str r6, [r3, #0x408] + + /* 7) Write SDRAM timing High register */ + ldr r6, =SDRAM_TIME_CTRL_HI + str r6, [r3, #0x40C] + + /* 8) Write SDRAM mode register */ + /* The CPU must not attempt to change the SDRAM Mode register setting */ + /* prior to DRAM controller completion of the DRAM initialization */ + /* sequence. To guarantee this restriction, it is recommended that */ + /* the CPU sets the SDRAM Operation register to NOP command, performs */ + /* read polling until the register is back in Normal operation value, */ + /* and then sets SDRAM Mode register to its new value. */ + + /* 8.1 write 'nop' to SDRAM operation */ + ldr r6, =SDRAM_OP_NOP + str r6, [r3, #0x418] + + /* 8.2 poll SDRAM operation until back in 'normal' mode. */ +1: + ldr r6, [r3, #0x418] + cmp r6, #0 + bne 1b + + /* 8.3 Now its safe to write new value to SDRAM Mode register */ + ldr r6, =SDRAM_MODE + str r6, [r3, #0x41C] + + /* 8.4 Set new mode */ + ldr r6, =SDRAM_OP_SETMODE + str r6, [r3, #0x418] + + /* 8.5 poll SDRAM operation until back in 'normal' mode. */ +2: + ldr r6, [r3, #0x418] + cmp r6, #0 + bne 2b + + /* DDR SDRAM Address/Control Pads Calibration */ + ldr r6, [r3, #0x4C0] + + /* Set Bit [31] to make the register writable */ + orr r6, r6, #SDRAM_PAD_CTRL_WR_EN + str r6, [r3, #0x4C0] + + bic r6, r6, #SDRAM_PAD_CTRL_WR_EN + bic r6, r6, #SDRAM_PAD_CTRL_TUNE_EN + bic r6, r6, #SDRAM_PAD_CTRL_DRVN_MASK + bic r6, r6, #SDRAM_PAD_CTRL_DRVP_MASK + + /* Get the final N locked value of driving strength [22:17] */ + mov r1, r6 + mov r1, r1, LSL #9 + mov r1, r1, LSR #26 /* r1[5:0]<DrvN> = r3[22:17]<LockN> */ + orr r1, r1, r1, LSL #6 /* r1[11:6]<DrvP> = r1[5:0]<DrvN> */ + + /* Write to both <DrvN> bits [5:0] and <DrvP> bits [11:6] */ + orr r6, r6, r1 + str r6, [r3, #0x4C0] + + /* DDR SDRAM Data Pads Calibration */ + ldr r6, [r3, #0x4C4] + + /* Set Bit [31] to make the register writable */ + orr r6, r6, #SDRAM_PAD_CTRL_WR_EN + str r6, [r3, #0x4C4] + + bic r6, r6, #SDRAM_PAD_CTRL_WR_EN + bic r6, r6, #SDRAM_PAD_CTRL_TUNE_EN + bic r6, r6, #SDRAM_PAD_CTRL_DRVN_MASK + bic r6, r6, #SDRAM_PAD_CTRL_DRVP_MASK + + /* Get the final N locked value of driving strength [22:17] */ + mov r1, r6 + mov r1, r1, LSL #9 + mov r1, r1, LSR #26 + orr r1, r1, r1, LSL #6 /* r1[5:0] = r3[22:17]<LockN> */ + + /* Write to both <DrvN> bits [5:0] and <DrvP> bits [11:6] */ + orr r6, r6, r1 + + str r6, [r3, #0x4C4] + + /* Implement Guideline (GL# MEM-3) Drive Strength Value */ + /* Relevant for: 88F5181-A1/B0/B1 and 88F5281-A0/B0 */ + + ldr r1, =DDR1_PAD_STRENGTH_DEFAULT + + /* Enable writes to DDR SDRAM Addr/Ctrl Pads Calibration register */ + ldr r6, [r3, #0x4C0] + orr r6, r6, #SDRAM_PAD_CTRL_WR_EN + str r6, [r3, #0x4C0] + + /* Correct strength and disable writes again */ + bic r6, r6, #SDRAM_PAD_CTRL_WR_EN + bic r6, r6, #SDRAM_PAD_CTRL_DRV_STR_MASK + orr r6, r6, r1 + str r6, [r3, #0x4C0] + + /* Enable writes to DDR SDRAM Data Pads Calibration register */ + ldr r6, [r3, #0x4C4] + orr r6, r6, #SDRAM_PAD_CTRL_WR_EN + str r6, [r3, #0x4C4] + + /* Correct strength and disable writes again */ + bic r6, r6, #SDRAM_PAD_CTRL_DRV_STR_MASK + bic r6, r6, #SDRAM_PAD_CTRL_WR_EN + orr r6, r6, r1 + str r6, [r3, #0x4C4] + + /* Implement Guideline (GL# MEM-4) DQS Reference Delay Tuning */ + /* Relevant for: 88F5181-A1/B0/B1 and 88F5281-A0/B0 */ + + /* Get the "sample on reset" register for the DDR frequancy */ + ldr r3, =0x10000 + ldr r6, [r3, #0x010] + ldr r1, =MSAR_ARMDDRCLCK_MASK + and r1, r6, r1 + + ldr r6, =FTDLL_DDR1_166MHZ + cmp r1, #MSAR_ARMDDRCLCK_333_167 + beq 3f + cmp r1, #MSAR_ARMDDRCLCK_500_167 + beq 3f + cmp r1, #MSAR_ARMDDRCLCK_667_167 + beq 3f + + ldr r6, =FTDLL_DDR1_200MHZ + cmp r1, #MSAR_ARMDDRCLCK_400_200_1 + beq 3f + cmp r1, #MSAR_ARMDDRCLCK_400_200 + beq 3f + cmp r1, #MSAR_ARMDDRCLCK_600_200 + beq 3f + cmp r1, #MSAR_ARMDDRCLCK_800_200 + beq 3f + + ldr r6, =0 + +3: + /* Use R3 as the base for DRAM registers */ + add r3, r4, #0x01000 + + ldr r2, [r3, #0x484] + orr r2, r2, r6 + str r2, [r3, #0x484] + + /* Return to U-boot via saved link register */ + mov pc, lr diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/orion5x/timer.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/orion5x/timer.c new file mode 100644 index 000000000..ec4f6bee8 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/orion5x/timer.c @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2010 Albert ARIBAUD <albert.u.boot@aribaud.net> + * + * Based on original Kirkwood support which is + * Copyright (C) Marvell International Ltd. and its affiliates + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> + +#define UBOOT_CNTR 0 /* counter to use for uboot timer */ + +/* Timer reload and current value registers */ +struct orion5x_tmr_val { + u32 reload; /* Timer reload reg */ + u32 val; /* Timer value reg */ +}; + +/* Timer registers */ +struct orion5x_tmr_registers { + u32 ctrl; /* Timer control reg */ + u32 pad[3]; + struct orion5x_tmr_val tmr[2]; + u32 wdt_reload; + u32 wdt_val; +}; + +struct orion5x_tmr_registers *orion5x_tmr_regs = + (struct orion5x_tmr_registers *)ORION5X_TIMER_BASE; + +/* + * ARM Timers Registers Map + */ +#define CNTMR_CTRL_REG (&orion5x_tmr_regs->ctrl) +#define CNTMR_RELOAD_REG(tmrnum) (&orion5x_tmr_regs->tmr[tmrnum].reload) +#define CNTMR_VAL_REG(tmrnum) (&orion5x_tmr_regs->tmr[tmrnum].val) + +/* + * ARM Timers Control Register + * CPU_TIMERS_CTRL_REG (CTCR) + */ +#define CTCR_ARM_TIMER_EN_OFFS(cntr) (cntr * 2) +#define CTCR_ARM_TIMER_EN_MASK(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS) +#define CTCR_ARM_TIMER_EN(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS(cntr)) +#define CTCR_ARM_TIMER_DIS(cntr) (0 << CTCR_ARM_TIMER_EN_OFFS(cntr)) + +#define CTCR_ARM_TIMER_AUTO_OFFS(cntr) ((cntr * 2) + 1) +#define CTCR_ARM_TIMER_AUTO_MASK(cntr) (1 << 1) +#define CTCR_ARM_TIMER_AUTO_EN(cntr) (1 << CTCR_ARM_TIMER_AUTO_OFFS(cntr)) +#define CTCR_ARM_TIMER_AUTO_DIS(cntr) (0 << CTCR_ARM_TIMER_AUTO_OFFS(cntr)) + +/* + * ARM Timer\Watchdog Reload Register + * CNTMR_RELOAD_REG (TRR) + */ +#define TRG_ARM_TIMER_REL_OFFS 0 +#define TRG_ARM_TIMER_REL_MASK 0xffffffff + +/* + * ARM Timer\Watchdog Register + * CNTMR_VAL_REG (TVRG) + */ +#define TVR_ARM_TIMER_OFFS 0 +#define TVR_ARM_TIMER_MASK 0xffffffff +#define TVR_ARM_TIMER_MAX 0xffffffff +#define TIMER_LOAD_VAL 0xffffffff + +static inline ulong read_timer(void) +{ + return readl(CNTMR_VAL_REG(UBOOT_CNTR)) + / (CONFIG_SYS_TCLK / 1000); +} + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp gd->arch.tbl +#define lastdec gd->arch.lastinc + +ulong get_timer_masked(void) +{ + ulong now = read_timer(); + + if (lastdec >= now) { + /* normal mode */ + timestamp += lastdec - now; + } else { + /* we have an overflow ... */ + timestamp += lastdec + + (TIMER_LOAD_VAL / (CONFIG_SYS_TCLK / 1000)) - now; + } + lastdec = now; + + return timestamp; +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +static inline ulong uboot_cntr_val(void) +{ + return readl(CNTMR_VAL_REG(UBOOT_CNTR)); +} + +void __udelay(unsigned long usec) +{ + uint current; + ulong delayticks; + + current = uboot_cntr_val(); + delayticks = (usec * (CONFIG_SYS_TCLK / 1000000)); + + if (current < delayticks) { + delayticks -= current; + while (uboot_cntr_val() < current) + ; + while ((TIMER_LOAD_VAL - delayticks) < uboot_cntr_val()) + ; + } else { + while (uboot_cntr_val() > (current - delayticks)) + ; + } +} + +/* + * init the counter + */ +int timer_init(void) +{ + unsigned int cntmrctrl; + + /* load value into timer */ + writel(TIMER_LOAD_VAL, CNTMR_RELOAD_REG(UBOOT_CNTR)); + writel(TIMER_LOAD_VAL, CNTMR_VAL_REG(UBOOT_CNTR)); + + /* enable timer in auto reload mode */ + cntmrctrl = readl(CNTMR_CTRL_REG); + cntmrctrl |= CTCR_ARM_TIMER_EN(UBOOT_CNTR); + cntmrctrl |= CTCR_ARM_TIMER_AUTO_EN(UBOOT_CNTR); + writel(cntmrctrl, CNTMR_CTRL_REG); + return 0; +} + +void timer_init_r(void) +{ + /* init the timestamp and lastdec value */ + lastdec = read_timer(); + timestamp = 0; +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk (void) +{ + return (ulong)CONFIG_SYS_HZ; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/pantheon/Makefile b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/pantheon/Makefile new file mode 100644 index 000000000..988341f8f --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/pantheon/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2011 +# Marvell Semiconductor <www.marvell.com> +# Written-by: Lei Wen <leiwen@marvell.com> +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y = cpu.o timer.o dram.o diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/pantheon/cpu.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/pantheon/cpu.c new file mode 100644 index 000000000..4e2a177c0 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/pantheon/cpu.c @@ -0,0 +1,85 @@ +/* + * (C) Copyright 2011 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Lei Wen <leiwen@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/pantheon.h> + +#define UARTCLK14745KHZ (APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(1)) +#define SET_MRVL_ID (1<<8) +#define L2C_RAM_SEL (1<<4) + +int arch_cpu_init(void) +{ + u32 val; + struct panthcpu_registers *cpuregs = + (struct panthcpu_registers*) PANTHEON_CPU_BASE; + + struct panthapb_registers *apbclkres = + (struct panthapb_registers*) PANTHEON_APBC_BASE; + + struct panthmpmu_registers *mpmu = + (struct panthmpmu_registers*) PANTHEON_MPMU_BASE; + + struct panthapmu_registers *apmu = + (struct panthapmu_registers *) PANTHEON_APMU_BASE; + + /* set SEL_MRVL_ID bit in PANTHEON_CPU_CONF register */ + val = readl(&cpuregs->cpu_conf); + val = val | SET_MRVL_ID; + writel(val, &cpuregs->cpu_conf); + + /* Turn on clock gating (PMUM_CCGR) */ + writel(0xFFFFFFFF, &mpmu->ccgr); + + /* Turn on clock gating (PMUM_ACGR) */ + writel(0xFFFFFFFF, &mpmu->acgr); + + /* Turn on uart2 clock */ + writel(UARTCLK14745KHZ, &apbclkres->uart0); + + /* Enable GPIO clock */ + writel(APBC_APBCLK, &apbclkres->gpio); + +#ifdef CONFIG_I2C_MV + /* Enable I2C clock */ + writel(APBC_RST | APBC_FNCLK | APBC_APBCLK, &apbclkres->twsi); + writel(APBC_FNCLK | APBC_APBCLK, &apbclkres->twsi); +#endif + +#ifdef CONFIG_MV_SDHCI + /* Enable mmc clock */ + writel(APMU_PERI_CLK | APMU_AXI_CLK | APMU_PERI_RST | APMU_AXI_RST, + &apmu->sd1); + writel(APMU_PERI_CLK | APMU_AXI_CLK | APMU_PERI_RST | APMU_AXI_RST, + &apmu->sd3); +#endif + + icache_enable(); + + return 0; +} + +#if defined(CONFIG_DISPLAY_CPUINFO) +int print_cpuinfo(void) +{ + u32 id; + struct panthcpu_registers *cpuregs = + (struct panthcpu_registers*) PANTHEON_CPU_BASE; + + id = readl(&cpuregs->chip_id); + printf("SoC: PANTHEON 88AP%X-%X\n", (id & 0xFFF), (id >> 0x10)); + return 0; +} +#endif + +#ifdef CONFIG_I2C_MV +void i2c_clk_enable(void) +{ +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/pantheon/dram.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/pantheon/dram.c new file mode 100644 index 000000000..f77e3d0ab --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/pantheon/dram.c @@ -0,0 +1,117 @@ +/* + * (C) Copyright 2011 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Lei Wen <leiwen@marvell.com>, + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/pantheon.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Pantheon DRAM controller supports upto 8 banks + * for chip select 0 and 1 + */ + +/* + * DDR Memory Control Registers + * Refer Datasheet 4.4 + */ +struct panthddr_map_registers { + u32 cs; /* Memory Address Map Register -CS */ + u32 pad[3]; +}; + +struct panthddr_registers { + u8 pad[0x100 - 0x000]; + struct panthddr_map_registers mmap[2]; +}; + +/* + * panth_sdram_base - reads SDRAM Base Address Register + */ +u32 panth_sdram_base(int chip_sel) +{ + struct panthddr_registers *ddr_regs = + (struct panthddr_registers *)PANTHEON_DRAM_BASE; + u32 result = 0; + u32 CS_valid = 0x01 & readl(&ddr_regs->mmap[chip_sel].cs); + + if (!CS_valid) + return 0; + + result = readl(&ddr_regs->mmap[chip_sel].cs) & 0xFF800000; + return result; +} + +/* + * panth_sdram_size - reads SDRAM size + */ +u32 panth_sdram_size(int chip_sel) +{ + struct panthddr_registers *ddr_regs = + (struct panthddr_registers *)PANTHEON_DRAM_BASE; + u32 result = 0; + u32 CS_valid = 0x01 & readl(&ddr_regs->mmap[chip_sel].cs); + + if (!CS_valid) + return 0; + + result = readl(&ddr_regs->mmap[chip_sel].cs); + result = (result >> 16) & 0xF; + if (result < 0x7) { + printf("Unknown DRAM Size\n"); + return -1; + } else { + return ((0x8 << (result - 0x7)) * 1024 * 1024); + } +} + +#ifndef CONFIG_SYS_BOARD_DRAM_INIT +int dram_init(void) +{ + int i; + + gd->ram_size = 0; + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + gd->bd->bi_dram[i].start = panth_sdram_base(i); + gd->bd->bi_dram[i].size = panth_sdram_size(i); + /* + * It is assumed that all memory banks are consecutive + * and without gaps. + * If the gap is found, ram_size will be reported for + * consecutive memory only + */ + if (gd->bd->bi_dram[i].start != gd->ram_size) + break; + + gd->ram_size += gd->bd->bi_dram[i].size; + + } + + for (; i < CONFIG_NR_DRAM_BANKS; i++) { + /* + * If above loop terminated prematurely, we need to set + * remaining banks' start address & size as 0. Otherwise other + * u-boot functions and Linux kernel gets wrong values which + * could result in crash + */ + gd->bd->bi_dram[i].start = 0; + gd->bd->bi_dram[i].size = 0; + } + return 0; +} + +/* + * If this function is not defined here, + * board.c alters dram bank zero configuration defined above. + */ +void dram_init_banksize(void) +{ + dram_init(); +} +#endif /* CONFIG_SYS_BOARD_DRAM_INIT */ diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/pantheon/timer.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/pantheon/timer.c new file mode 100644 index 000000000..6382d3b0c --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/pantheon/timer.c @@ -0,0 +1,201 @@ +/* + * (C) Copyright 2011 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Lei Wen <leiwen@marvell.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/pantheon.h> + +/* + * Timer registers + * Refer 6.2.9 in Datasheet + */ +struct panthtmr_registers { + u32 clk_ctrl; /* Timer clk control reg */ + u32 match[9]; /* Timer match registers */ + u32 count[3]; /* Timer count registers */ + u32 status[3]; + u32 ie[3]; + u32 preload[3]; /* Timer preload value */ + u32 preload_ctrl[3]; + u32 wdt_match_en; + u32 wdt_match_r; + u32 wdt_val; + u32 wdt_sts; + u32 icr[3]; + u32 wdt_icr; + u32 cer; /* Timer count enable reg */ + u32 cmr; + u32 ilr[3]; + u32 wcr; + u32 wfar; + u32 wsar; + u32 cvwr[3]; +}; + +#define TIMER 0 /* Use TIMER 0 */ +/* Each timer has 3 match registers */ +#define MATCH_CMP(x) ((3 * TIMER) + x) +#define TIMER_LOAD_VAL 0xffffffff +#define COUNT_RD_REQ 0x1 + +DECLARE_GLOBAL_DATA_PTR; +/* Using gd->arch.tbu from timestamp and gd->arch.tbl for lastdec */ + +/* + * For preventing risk of instability in reading counter value, + * first set read request to register cvwr and then read same + * register after it captures counter value. + */ +ulong read_timer(void) +{ + struct panthtmr_registers *panthtimers = + (struct panthtmr_registers *) PANTHEON_TIMER_BASE; + volatile int loop=100; + ulong val; + + writel(COUNT_RD_REQ, &panthtimers->cvwr); + while (loop--) + val = readl(&panthtimers->cvwr); + + /* + * This stop gcc complain and prevent loop mistake init to 0 + */ + val = readl(&panthtimers->cvwr); + + return val; +} + +ulong get_timer_masked(void) +{ + ulong now = read_timer(); + + if (now >= gd->arch.tbl) { + /* normal mode */ + gd->arch.tbu += now - gd->arch.tbl; + } else { + /* we have an overflow ... */ + gd->arch.tbu += now + TIMER_LOAD_VAL - gd->arch.tbl; + } + gd->arch.tbl = now; + + return gd->arch.tbu; +} + +ulong get_timer(ulong base) +{ + return ((get_timer_masked() / (CONFIG_SYS_HZ_CLOCK / 1000)) - + base); +} + +void __udelay(unsigned long usec) +{ + ulong delayticks; + ulong endtime; + + delayticks = (usec * (CONFIG_SYS_HZ_CLOCK / 1000000)); + endtime = get_timer_masked() + delayticks; + + while (get_timer_masked() < endtime) + ; +} + +/* + * init the Timer + */ +int timer_init(void) +{ + struct panthapb_registers *apb1clkres = + (struct panthapb_registers *) PANTHEON_APBC_BASE; + struct panthtmr_registers *panthtimers = + (struct panthtmr_registers *) PANTHEON_TIMER_BASE; + + /* Enable Timer clock at 3.25 MHZ */ + writel(APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3), &apb1clkres->timers); + + /* load value into timer */ + writel(0x0, &panthtimers->clk_ctrl); + /* Use Timer 0 Match Resiger 0 */ + writel(TIMER_LOAD_VAL, &panthtimers->match[MATCH_CMP(0)]); + /* Preload value is 0 */ + writel(0x0, &panthtimers->preload[TIMER]); + /* Enable match comparator 0 for Timer 0 */ + writel(0x1, &panthtimers->preload_ctrl[TIMER]); + + /* Enable timer 0 */ + writel(0x1, &panthtimers->cer); + /* init the gd->arch.tbu and gd->arch.tbl value */ + gd->arch.tbl = read_timer(); + gd->arch.tbu = 0; + + return 0; +} + +#define MPMU_APRR_WDTR (1<<4) +#define TMR_WFAR 0xbaba /* WDT Register First key */ +#define TMP_WSAR 0xeb10 /* WDT Register Second key */ + +/* + * This function uses internal Watchdog Timer + * based reset mechanism. + * Steps to write watchdog registers (protected access) + * 1. Write key value to TMR_WFAR reg. + * 2. Write key value to TMP_WSAR reg. + * 3. Perform write operation. + */ +void reset_cpu (unsigned long ignored) +{ + struct panthmpmu_registers *mpmu = + (struct panthmpmu_registers *) PANTHEON_MPMU_BASE; + struct panthtmr_registers *panthtimers = + (struct panthtmr_registers *) PANTHEON_WD_TIMER_BASE; + u32 val; + + /* negate hardware reset to the WDT after system reset */ + val = readl(&mpmu->aprr); + val = val | MPMU_APRR_WDTR; + writel(val, &mpmu->aprr); + + /* reset/enable WDT clock */ + writel(APBC_APBCLK, &mpmu->wdtpcr); + + /* clear previous WDT status */ + writel(TMR_WFAR, &panthtimers->wfar); + writel(TMP_WSAR, &panthtimers->wsar); + writel(0, &panthtimers->wdt_sts); + + /* set match counter */ + writel(TMR_WFAR, &panthtimers->wfar); + writel(TMP_WSAR, &panthtimers->wsar); + writel(0xf, &panthtimers->wdt_match_r); + + /* enable WDT reset */ + writel(TMR_WFAR, &panthtimers->wfar); + writel(TMP_WSAR, &panthtimers->wsar); + writel(0x3, &panthtimers->wdt_match_en); + + /*enable functional WDT clock */ + writel(APBC_APBCLK | APBC_FNCLK, &mpmu->wdtpcr); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk (void) +{ + return (ulong)CONFIG_SYS_HZ; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/Makefile b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/Makefile new file mode 100644 index 000000000..3f190bc0c --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/Makefile @@ -0,0 +1,21 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y := cpu.o \ + reset.o \ + timer.o + +ifdef CONFIG_SPL_BUILD +obj-y += spl.o spl_boot.o +obj-$(CONFIG_SPEAR600) += spear600.o +obj-$(CONFIG_DDR_MT47H64M16) += spr600_mt47h64m16_3_333_cl5_psync.o +obj-$(CONFIG_DDR_MT47H32M16) += spr600_mt47h32m16_333_cl5_psync.o +obj-$(CONFIG_DDR_MT47H32M16) += spr600_mt47h32m16_37e_166_cl4_sync.o +obj-$(CONFIG_DDR_MT47H128M8) += spr600_mt47h128m8_3_266_cl5_async.o +endif + +extra-$(CONFIG_SPL_BUILD) := start.o diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/cpu.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/cpu.c new file mode 100644 index 000000000..3757ffb2c --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/cpu.c @@ -0,0 +1,71 @@ +/* + * (C) Copyright 2010 + * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/spr_misc.h> + +int arch_cpu_init(void) +{ + struct misc_regs *const misc_p = + (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + u32 periph1_clken, periph_clk_cfg; + + periph1_clken = readl(&misc_p->periph1_clken); + +#if defined(CONFIG_SPEAR3XX) + periph1_clken |= MISC_GPT2ENB; +#elif defined(CONFIG_SPEAR600) + periph1_clken |= MISC_GPT3ENB; +#endif + +#if defined(CONFIG_PL011_SERIAL) + periph1_clken |= MISC_UART0ENB; + + periph_clk_cfg = readl(&misc_p->periph_clk_cfg); + periph_clk_cfg &= ~CONFIG_SPEAR_UARTCLKMSK; + periph_clk_cfg |= CONFIG_SPEAR_UART48M; + writel(periph_clk_cfg, &misc_p->periph_clk_cfg); +#endif +#if defined(CONFIG_DESIGNWARE_ETH) + periph1_clken |= MISC_ETHENB; +#endif +#if defined(CONFIG_DW_UDC) + periph1_clken |= MISC_USBDENB; +#endif +#if defined(CONFIG_DW_I2C) + periph1_clken |= MISC_I2CENB; +#endif +#if defined(CONFIG_ST_SMI) + periph1_clken |= MISC_SMIENB; +#endif +#if defined(CONFIG_NAND_FSMC) + periph1_clken |= MISC_FSMCENB; +#endif + + writel(periph1_clken, &misc_p->periph1_clken); + return 0; +} + +#ifdef CONFIG_DISPLAY_CPUINFO +int print_cpuinfo(void) +{ +#ifdef CONFIG_SPEAR300 + printf("CPU: SPEAr300\n"); +#elif defined(CONFIG_SPEAR310) + printf("CPU: SPEAr310\n"); +#elif defined(CONFIG_SPEAR320) + printf("CPU: SPEAr320\n"); +#elif defined(CONFIG_SPEAR600) + printf("CPU: SPEAr600\n"); +#else +#error CPU not supported in spear platform +#endif + return 0; +} +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/reset.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/reset.c new file mode 100644 index 000000000..9546e80bc --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/reset.c @@ -0,0 +1,38 @@ +/* + * (C) Copyright 2009 + * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/spr_syscntl.h> + +void reset_cpu(ulong ignored) +{ + struct syscntl_regs *syscntl_regs_p = + (struct syscntl_regs *)CONFIG_SPEAR_SYSCNTLBASE; + + printf("System is going to reboot ...\n"); + + /* + * This 1 second delay will allow the above message + * to be printed before reset + */ + udelay((1000 * 1000)); + + /* Going into slow mode before resetting SOC */ + writel(0x02, &syscntl_regs_p->scctrl); + + /* + * Writing any value to the system status register will + * reset the SoC + */ + writel(0x00, &syscntl_regs_p->scsysstat); + + /* system will restart */ + while (1) + ; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spear600.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spear600.c new file mode 100644 index 000000000..6474e9d55 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spear600.c @@ -0,0 +1,217 @@ +/* + * (C) Copyright 2000-2009 + * Viresh Kumar, ST Microelectronics, viresh.kumar@st.com + * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/arch/spr_misc.h> +#include <asm/arch/spr_defs.h> + +static void sel_1v8(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + u32 ddr1v8, ddr2v5; + + ddr2v5 = readl(&misc_p->ddr_2v5_compensation); + ddr2v5 &= 0x8080ffc0; + ddr2v5 |= 0x78000003; + writel(ddr2v5, &misc_p->ddr_2v5_compensation); + + ddr1v8 = readl(&misc_p->ddr_1v8_compensation); + ddr1v8 &= 0x8080ffc0; + ddr1v8 |= 0x78000010; + writel(ddr1v8, &misc_p->ddr_1v8_compensation); + + while (!(readl(&misc_p->ddr_1v8_compensation) & DDR_COMP_ACCURATE)) + ; +} + +static void sel_2v5(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + u32 ddr1v8, ddr2v5; + + ddr1v8 = readl(&misc_p->ddr_1v8_compensation); + ddr1v8 &= 0x8080ffc0; + ddr1v8 |= 0x78000003; + writel(ddr1v8, &misc_p->ddr_1v8_compensation); + + ddr2v5 = readl(&misc_p->ddr_2v5_compensation); + ddr2v5 &= 0x8080ffc0; + ddr2v5 |= 0x78000010; + writel(ddr2v5, &misc_p->ddr_2v5_compensation); + + while (!(readl(&misc_p->ddr_2v5_compensation) & DDR_COMP_ACCURATE)) + ; +} + +/* + * plat_ddr_init: + */ +void plat_ddr_init(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + u32 ddrpad; + u32 core3v3, ddr1v8, ddr2v5; + + /* DDR pad register configurations */ + ddrpad = readl(&misc_p->ddr_pad); + ddrpad &= ~DDR_PAD_CNF_MSK; + +#if (CONFIG_DDR_HCLK) + ddrpad |= 0xEAAB; +#elif (CONFIG_DDR_2HCLK) + ddrpad |= 0xEAAD; +#elif (CONFIG_DDR_PLL2) + ddrpad |= 0xEAAD; +#endif + writel(ddrpad, &misc_p->ddr_pad); + + /* Compensation register configurations */ + core3v3 = readl(&misc_p->core_3v3_compensation); + core3v3 &= 0x8080ffe0; + core3v3 |= 0x78000002; + writel(core3v3, &misc_p->core_3v3_compensation); + + ddr1v8 = readl(&misc_p->ddr_1v8_compensation); + ddr1v8 &= 0x8080ffc0; + ddr1v8 |= 0x78000004; + writel(ddr1v8, &misc_p->ddr_1v8_compensation); + + ddr2v5 = readl(&misc_p->ddr_2v5_compensation); + ddr2v5 &= 0x8080ffc0; + ddr2v5 |= 0x78000004; + writel(ddr2v5, &misc_p->ddr_2v5_compensation); + + if ((readl(&misc_p->ddr_pad) & DDR_PAD_SW_CONF) == DDR_PAD_SW_CONF) { + /* Software memory configuration */ + if (readl(&misc_p->ddr_pad) & DDR_PAD_SSTL_SEL) + sel_1v8(); + else + sel_2v5(); + } else { + /* Hardware memory configuration */ + if (readl(&misc_p->ddr_pad) & DDR_PAD_DRAM_TYPE) + sel_1v8(); + else + sel_2v5(); + } +} + +/* + * soc_init: + */ +void soc_init(void) +{ + /* Nothing to be done for SPEAr600 */ +} + +/* + * xxx_boot_selected: + * + * return true if the particular booting option is selected + * return false otherwise + */ +static u32 read_bootstrap(void) +{ + return (readl(CONFIG_SPEAR_BOOTSTRAPCFG) >> CONFIG_SPEAR_BOOTSTRAPSHFT) + & CONFIG_SPEAR_BOOTSTRAPMASK; +} + +int snor_boot_selected(void) +{ + u32 bootstrap = read_bootstrap(); + + if (SNOR_BOOT_SUPPORTED) { + /* Check whether SNOR boot is selected */ + if ((bootstrap & CONFIG_SPEAR_ONLYSNORBOOT) == + CONFIG_SPEAR_ONLYSNORBOOT) + return true; + + if ((bootstrap & CONFIG_SPEAR_NORNANDBOOT) == + CONFIG_SPEAR_NORNAND8BOOT) + return true; + + if ((bootstrap & CONFIG_SPEAR_NORNANDBOOT) == + CONFIG_SPEAR_NORNAND16BOOT) + return true; + } + + return false; +} + +int nand_boot_selected(void) +{ + u32 bootstrap = read_bootstrap(); + + if (NAND_BOOT_SUPPORTED) { + /* Check whether NAND boot is selected */ + if ((bootstrap & CONFIG_SPEAR_NORNANDBOOT) == + CONFIG_SPEAR_NORNAND8BOOT) + return true; + + if ((bootstrap & CONFIG_SPEAR_NORNANDBOOT) == + CONFIG_SPEAR_NORNAND16BOOT) + return true; + } + + return false; +} + +int pnor_boot_selected(void) +{ + /* Parallel NOR boot is not selected in any SPEAr600 revision */ + return false; +} + +int usb_boot_selected(void) +{ + u32 bootstrap = read_bootstrap(); + + if (USB_BOOT_SUPPORTED) { + /* Check whether USB boot is selected */ + if (!(bootstrap & CONFIG_SPEAR_USBBOOT)) + return true; + } + + return false; +} + +int tftp_boot_selected(void) +{ + /* TFTP boot is not selected in any SPEAr600 revision */ + return false; +} + +int uart_boot_selected(void) +{ + /* UART boot is not selected in any SPEAr600 revision */ + return false; +} + +int spi_boot_selected(void) +{ + /* SPI boot is not selected in any SPEAr600 revision */ + return false; +} + +int i2c_boot_selected(void) +{ + /* I2C boot is not selected in any SPEAr600 revision */ + return false; +} + +int mmc_boot_selected(void) +{ + return false; +} + +void plat_late_init(void) +{ + spear_late_init(); +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spl.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spl.c new file mode 100644 index 000000000..b55040435 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spl.c @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2011 + * Heiko Schocher, DENX Software Engineering, hs@denx.de. + * + * Copyright (C) 2012 Stefan Roese <sr@denx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <version.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/spr_defs.h> +#include <asm/arch/spr_misc.h> +#include <asm/arch/spr_syscntl.h> + +static void ddr_clock_init(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + u32 clkenb, ddrpll; + + clkenb = readl(&misc_p->periph1_clken); + clkenb &= ~PERIPH_MPMCMSK; + clkenb |= PERIPH_MPMC_WE; + + /* Intentionally done twice */ + writel(clkenb, &misc_p->periph1_clken); + writel(clkenb, &misc_p->periph1_clken); + + ddrpll = readl(&misc_p->pll_ctr_reg); + ddrpll &= ~MEM_CLK_SEL_MSK; +#if (CONFIG_DDR_HCLK) + ddrpll |= MEM_CLK_HCLK; +#elif (CONFIG_DDR_2HCLK) + ddrpll |= MEM_CLK_2HCLK; +#elif (CONFIG_DDR_PLL2) + ddrpll |= MEM_CLK_PLL2; +#else +#error "please define one of CONFIG_DDR_(HCLK|2HCLK|PLL2)" +#endif + writel(ddrpll, &misc_p->pll_ctr_reg); + + writel(readl(&misc_p->periph1_clken) | PERIPH_MPMC_EN, + &misc_p->periph1_clken); +} + +static void mpmc_init_values(void) +{ + u32 i; + u32 *mpmc_reg_p = (u32 *)CONFIG_SPEAR_MPMCBASE; + u32 *mpmc_val_p = &mpmc_conf_vals[0]; + + for (i = 0; i < CONFIG_SPEAR_MPMCREGS; i++, mpmc_reg_p++, mpmc_val_p++) + writel(*mpmc_val_p, mpmc_reg_p); + + mpmc_reg_p = (u32 *)CONFIG_SPEAR_MPMCBASE; + + /* + * MPMC controller start + * MPMC waiting for DLLLOCKREG high + */ + writel(0x01000100, &mpmc_reg_p[7]); + + while (!(readl(&mpmc_reg_p[3]) & 0x10000)) + ; +} + +static void mpmc_init(void) +{ + /* Clock related settings for DDR */ + ddr_clock_init(); + + /* + * DDR pad register bits are different for different SoCs + * Compensation values are also handled separately + */ + plat_ddr_init(); + + /* Initialize mpmc register values */ + mpmc_init_values(); +} + +static void pll_init(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + + /* Initialize PLLs */ + writel(FREQ_332, &misc_p->pll1_frq); + writel(0x1C0A, &misc_p->pll1_cntl); + writel(0x1C0E, &misc_p->pll1_cntl); + writel(0x1C06, &misc_p->pll1_cntl); + writel(0x1C0E, &misc_p->pll1_cntl); + + writel(FREQ_332, &misc_p->pll2_frq); + writel(0x1C0A, &misc_p->pll2_cntl); + writel(0x1C0E, &misc_p->pll2_cntl); + writel(0x1C06, &misc_p->pll2_cntl); + writel(0x1C0E, &misc_p->pll2_cntl); + + /* wait for pll locks */ + while (!(readl(&misc_p->pll1_cntl) & 0x1)) + ; + while (!(readl(&misc_p->pll2_cntl) & 0x1)) + ; +} + +static void mac_init(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + + writel(readl(&misc_p->periph1_clken) & (~PERIPH_GMAC), + &misc_p->periph1_clken); + + writel(SYNTH23, &misc_p->gmac_synth_clk); + + switch (get_socrev()) { + case SOC_SPEAR600_AA: + case SOC_SPEAR600_AB: + case SOC_SPEAR600_BA: + case SOC_SPEAR600_BB: + case SOC_SPEAR600_BC: + case SOC_SPEAR600_BD: + writel(0x0, &misc_p->gmac_ctr_reg); + break; + + case SOC_SPEAR300: + case SOC_SPEAR310: + case SOC_SPEAR320: + writel(0x4, &misc_p->gmac_ctr_reg); + break; + } + + writel(readl(&misc_p->periph1_clken) | PERIPH_GMAC, + &misc_p->periph1_clken); + + writel(readl(&misc_p->periph1_rst) | PERIPH_GMAC, + &misc_p->periph1_rst); + writel(readl(&misc_p->periph1_rst) & (~PERIPH_GMAC), + &misc_p->periph1_rst); +} + +static void sys_init(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + struct syscntl_regs *syscntl_p = + (struct syscntl_regs *)CONFIG_SPEAR_SYSCNTLBASE; + + /* Set system state to SLOW */ + writel(SLOW, &syscntl_p->scctrl); + writel(PLL_TIM << 3, &syscntl_p->scpllctrl); + + /* Initialize PLLs */ + pll_init(); + + /* + * Ethernet configuration + * To be done only if the tftp boot is not selected already + * Boot code ensures the correct configuration in tftp booting + */ + if (!tftp_boot_selected()) + mac_init(); + + writel(RTC_DISABLE | PLLTIMEEN, &misc_p->periph_clk_cfg); + writel(0x555, &misc_p->amba_clk_cfg); + + writel(NORMAL, &syscntl_p->scctrl); + + /* Wait for system to switch to normal mode */ + while (((readl(&syscntl_p->scctrl) >> MODE_SHIFT) & MODE_MASK) + != NORMAL) + ; +} + +/* + * get_socrev + * + * Get SoC Revision. + * @return SOC_SPEARXXX + */ +int get_socrev(void) +{ +#if defined(CONFIG_SPEAR600) + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + u32 soc_id = readl(&misc_p->soc_core_id); + u32 pri_socid = (soc_id >> SOC_PRI_SHFT) & 0xFF; + u32 sec_socid = (soc_id >> SOC_SEC_SHFT) & 0xFF; + + if ((pri_socid == 'B') && (sec_socid == 'B')) + return SOC_SPEAR600_BB; + else if ((pri_socid == 'B') && (sec_socid == 'C')) + return SOC_SPEAR600_BC; + else if ((pri_socid == 'B') && (sec_socid == 'D')) + return SOC_SPEAR600_BD; + else if (soc_id == 0) + return SOC_SPEAR600_BA; + else + return SOC_SPEAR_NA; +#elif defined(CONFIG_SPEAR300) + return SOC_SPEAR300; +#elif defined(CONFIG_SPEAR310) + return SOC_SPEAR310; +#elif defined(CONFIG_SPEAR320) + return SOC_SPEAR320; +#endif +} + +void lowlevel_init(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + const char *u_boot_rev = U_BOOT_VERSION; + + /* Initialize PLLs */ + sys_init(); + + /* Initialize UART */ + serial_init(); + + /* Print U-Boot SPL version string */ + serial_puts("\nU-Boot SPL "); + /* Avoid a second "U-Boot" coming from this string */ + u_boot_rev = &u_boot_rev[7]; + serial_puts(u_boot_rev); + serial_puts(" ("); + serial_puts(U_BOOT_DATE); + serial_puts(" - "); + serial_puts(U_BOOT_TIME); + serial_puts(")\n"); + +#if defined(CONFIG_OS_BOOT) + writel(readl(&misc_p->periph1_clken) | PERIPH_UART1, + &misc_p->periph1_clken); +#endif + + /* Enable IPs (release reset) */ + writel(PERIPH_RST_ALL, &misc_p->periph1_rst); + + /* Initialize MPMC */ + serial_puts("Configure DDR\n"); + mpmc_init(); + + /* SoC specific initialization */ + soc_init(); +} + +void spear_late_init(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + + writel(0x80000007, &misc_p->arb_icm_ml1); + writel(0x80000007, &misc_p->arb_icm_ml2); + writel(0x80000007, &misc_p->arb_icm_ml3); + writel(0x80000007, &misc_p->arb_icm_ml4); + writel(0x80000007, &misc_p->arb_icm_ml5); + writel(0x80000007, &misc_p->arb_icm_ml6); + writel(0x80000007, &misc_p->arb_icm_ml7); + writel(0x80000007, &misc_p->arb_icm_ml8); + writel(0x80000007, &misc_p->arb_icm_ml9); +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spl_boot.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spl_boot.c new file mode 100644 index 000000000..c846d758c --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spl_boot.c @@ -0,0 +1,181 @@ +/* + * (C) Copyright 2000-2009 + * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com + * + * Copyright (C) 2012 Stefan Roese <sr@denx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <image.h> +#include <linux/compiler.h> +#include <asm/io.h> +#include <asm/arch/spr_defs.h> +#include <linux/mtd/st_smi.h> + +static const char kernel_name[] = "Linux"; +static const char loader_name[] = "U-Boot"; + +int image_check_header(image_header_t *hdr, const char *name) +{ + if (image_check_magic(hdr) && + (!strncmp(image_get_name(hdr), name, strlen(name))) && + image_check_hcrc(hdr)) { + return 1; + } + return 0; +} + +int image_check_data(image_header_t *hdr) +{ + if (image_check_dcrc(hdr)) + return 1; + + return 0; +} + +/* + * SNOR (Serial NOR flash) related functions + */ +void snor_init(void) +{ + struct smi_regs *const smicntl = + (struct smi_regs * const)CONFIG_SYS_SMI_BASE; + + /* Setting the fast mode values. SMI working at 166/4 = 41.5 MHz */ + writel(HOLD1 | FAST_MODE | BANK_EN | DSEL_TIME | PRESCAL4, + &smicntl->smi_cr1); +} + +static int snor_image_load(u8 *load_addr, void (**image_p)(void), + const char *image_name) +{ + image_header_t *header; + + /* + * Since calculating the crc in the SNOR flash does not + * work, we copy the image to the destination address + * minus the header size. And point the header to this + * new destination. This will not work for address 0 + * of course. + */ + header = (image_header_t *)load_addr; + memcpy((ulong *)(image_get_load(header) - sizeof(image_header_t)), + (const ulong *)load_addr, + image_get_data_size(header) + sizeof(image_header_t)); + header = (image_header_t *)(image_get_load(header) - + sizeof(image_header_t)); + + if (image_check_header(header, image_name)) { + if (image_check_data(header)) { + /* Jump to boot image */ + *image_p = (void *)image_get_load(header); + return 1; + } + } + + return 0; +} + +static void boot_image(void (*image)(void)) +{ + void (*funcp)(void) __noreturn = (void *)image; + + (*funcp)(); +} + +/* + * spl_boot: + * + * All supported booting types of all supported SoCs are listed here. + * Generic readback APIs are provided for each supported booting type + * eg. nand_read_skip_bad + */ +u32 spl_boot(void) +{ + void (*image)(void); + +#ifdef CONFIG_SPEAR_USBTTY + plat_late_init(); + return 1; +#endif + + /* + * All the supported booting devices are listed here. Each of + * the booting type supported by the platform would define the + * macro xxx_BOOT_SUPPORTED to true. + */ + + if (SNOR_BOOT_SUPPORTED && snor_boot_selected()) { + /* SNOR-SMI initialization */ + snor_init(); + + serial_puts("Booting via SNOR\n"); + /* Serial NOR booting */ + if (1 == snor_image_load((u8 *)CONFIG_SYS_UBOOT_BASE, + &image, loader_name)) { + /* Platform related late initialasations */ + plat_late_init(); + + /* Jump to boot image */ + serial_puts("Jumping to U-Boot\n"); + boot_image(image); + return 1; + } + } + + if (NAND_BOOT_SUPPORTED && nand_boot_selected()) { + /* NAND booting */ + /* Not ported from XLoader to SPL yet */ + return 0; + } + + if (PNOR_BOOT_SUPPORTED && pnor_boot_selected()) { + /* PNOR booting */ + /* Not ported from XLoader to SPL yet */ + return 0; + } + + if (MMC_BOOT_SUPPORTED && mmc_boot_selected()) { + /* MMC booting */ + /* Not ported from XLoader to SPL yet */ + return 0; + } + + if (SPI_BOOT_SUPPORTED && spi_boot_selected()) { + /* SPI booting */ + /* Not supported for any platform as of now */ + return 0; + } + + if (I2C_BOOT_SUPPORTED && i2c_boot_selected()) { + /* I2C booting */ + /* Not supported for any platform as of now */ + return 0; + } + + /* + * All booting types without memory are listed as below + * Control has to be returned to BootROM in case of all + * the following booting scenarios + */ + + if (USB_BOOT_SUPPORTED && usb_boot_selected()) { + plat_late_init(); + return 1; + } + + if (TFTP_BOOT_SUPPORTED && tftp_boot_selected()) { + plat_late_init(); + return 1; + } + + if (UART_BOOT_SUPPORTED && uart_boot_selected()) { + plat_late_init(); + return 1; + } + + /* Ideally, the control should not reach here. */ + hang(); +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spr600_mt47h128m8_3_266_cl5_async.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spr600_mt47h128m8_3_266_cl5_async.c new file mode 100644 index 000000000..3d6ad04ab --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spr600_mt47h128m8_3_266_cl5_async.c @@ -0,0 +1,114 @@ +/* + * (C) Copyright 2000-2009 + * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> + +#if (CONFIG_DDR_PLL2) + +const u32 mpmc_conf_vals[CONFIG_SPEAR_MPMCREGS] = { + 0x00000001, + 0x00000000, + 0x01000000, + 0x00000101, + 0x00000001, + 0x01000000, + 0x00010001, + 0x00000100, + 0x00010001, + 0x00000003, + 0x01000201, + 0x06000202, + 0x06060106, + 0x03050502, + 0x03040404, + 0x02020503, + 0x02010106, + 0x03000404, + 0x02030202, + 0x03000204, + 0x0707073f, + 0x07070707, + 0x06060607, + 0x06060606, + 0x05050506, + 0x05050505, + 0x04040405, + 0x04040404, + 0x03030304, + 0x03030303, + 0x02020203, + 0x02020202, + 0x01010102, + 0x01010101, + 0x08080a01, + 0x0000023f, + 0x00040800, + 0x00000000, + 0x00000f02, + 0x00001b1b, + 0x7f000000, + 0x005f0000, + 0x1c040b6a, + 0x00640064, + 0x00640064, + 0x00640064, + 0x00000064, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x000007ff, + 0x00000000, + 0x47ec00c8, + 0x00c8001f, + 0x00000000, + 0x0000cd98, + 0x00000000, + 0x03030100, + 0x03030303, + 0x03030303, + 0x03030303, + 0x00270000, + 0x00250027, + 0x00300000, + 0x008900b7, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spr600_mt47h32m16_333_cl5_psync.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spr600_mt47h32m16_333_cl5_psync.c new file mode 100644 index 000000000..105b3058f --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spr600_mt47h32m16_333_cl5_psync.c @@ -0,0 +1,119 @@ +/* + * (C) Copyright 2000-2009 + * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> + +#if (CONFIG_DDR_PLL2 || CONFIG_DDR_2HCLK) + +const u32 mpmc_conf_vals[CONFIG_SPEAR_MPMCREGS] = { +#if (CONFIG_DDR_PLL2) + 0x00000001, + 0x00000000, +#elif (CONFIG_DDR_2HCLK) + 0x02020201, + 0x02020202, +#endif + 0x01000000, + 0x00000101, + 0x00000101, + 0x01000000, + 0x00010001, + 0x00000100, + 0x01010001, + 0x00000201, + 0x01000101, + 0x06000002, + 0x06060106, + 0x03050502, + 0x03040404, + 0x02020503, + 0x02010106, + 0x03000405, + 0x03040202, + 0x04000305, + 0x0707073f, + 0x07070707, + 0x06060607, + 0x06060606, + 0x05050506, + 0x05050505, + 0x04040405, + 0x04040404, + 0x03030304, + 0x03030303, + 0x02020203, + 0x02020202, + 0x01010102, + 0x01010101, + 0x0a0a0a01, + 0x0000023f, + 0x00050a00, + 0x11000000, + 0x00001302, + 0x00000A0A, + 0x72000000, + 0x00550000, + 0x2b050e86, + 0x00640064, + 0x00640064, + 0x00640064, + 0x00000064, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00000a24, + 0x43C20000, + 0x5b1c00c8, + 0x00c8002e, + 0x00000000, + 0x0001046b, + 0x00000000, + 0x03030100, + 0x03030303, + 0x03030303, + 0x03030303, + 0x00210000, + 0x00010021, + 0x00200000, + 0x006c0090, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spr600_mt47h32m16_37e_166_cl4_sync.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spr600_mt47h32m16_37e_166_cl4_sync.c new file mode 100644 index 000000000..00b6b2927 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spr600_mt47h32m16_37e_166_cl4_sync.c @@ -0,0 +1,114 @@ +/* + * (C) Copyright 2000-2009 + * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> + +#if (CONFIG_DDR_HCLK) + +const u32 mpmc_conf_vals[CONFIG_SPEAR_MPMCREGS] = { + 0x03030301, + 0x03030303, + 0x01000000, + 0x00000101, + 0x00000001, + 0x01000000, + 0x00010001, + 0x00000100, + 0x00010001, + 0x00000003, + 0x01000201, + 0x06000202, + 0x06060106, + 0x03050502, + 0x03040404, + 0x02020503, + 0x02010106, + 0x03000404, + 0x02020202, + 0x03000203, + 0x0707073f, + 0x07070707, + 0x06060607, + 0x06060606, + 0x05050506, + 0x05050505, + 0x04040405, + 0x04040404, + 0x03030304, + 0x03030303, + 0x02020203, + 0x02020202, + 0x01010102, + 0x01010101, + 0x08080a01, + 0x0000023f, + 0x00030600, + 0x00000000, + 0x00000a02, + 0x00001c1c, + 0x7f000000, + 0x005f0000, + 0x12030743, + 0x00640064, + 0x00640064, + 0x00640064, + 0x00000064, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x0000050e, + 0x00000000, + 0x2d8900c8, + 0x00c80014, + 0x00000000, + 0x00008236, + 0x00000000, + 0x03030100, + 0x03030303, + 0x03030303, + 0x03030303, + 0x00400000, + 0x003a0040, + 0x00680000, + 0x00d80120, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spr600_mt47h64m16_3_333_cl5_psync.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spr600_mt47h64m16_3_333_cl5_psync.c new file mode 100644 index 000000000..a406c3e8c --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/spr600_mt47h64m16_3_333_cl5_psync.c @@ -0,0 +1,128 @@ +/* + * (C) Copyright 2000-2009 + * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> + +#if (CONFIG_DDR_PLL2 || CONFIG_DDR_2HCLK) + +const u32 mpmc_conf_vals[CONFIG_SPEAR_MPMCREGS] = { +#if (CONFIG_DDR_PLL2) + 0x00000001, + 0x00000000, +#elif (CONFIG_DDR_2HCLK) + 0x02020201, + 0x02020202, +#endif + 0x01000000, + 0x00000101, + 0x00000101, + 0x01000000, + 0x00010001, + 0x00000100, + 0x01010001, + 0x00000201, + 0x01000101, + 0x06000002, + 0x06060106, + 0x03050502, + 0x03040404, + 0x02020503, +#ifdef CONFIG_X600 + 0x02030206, +#else + 0x02010106, +#endif + 0x03000405, + 0x03040202, + 0x04000305, + 0x0707073f, + 0x07070707, + 0x06060607, + 0x06060606, + 0x05050506, + 0x05050505, + 0x04040405, + 0x04040404, + 0x03030304, + 0x03030303, + 0x02020203, + 0x02020202, + 0x01010102, + 0x01010101, + 0x0a0a0a01, + 0x0000023f, + 0x00050a00, + 0x11000000, + 0x00001302, + 0x00000A0A, +#ifdef CONFIG_X600 + 0x7f000000, + 0x005c0000, +#else + 0x72000000, + 0x00550000, +#endif + 0x2b050e86, + 0x00640064, + 0x00640064, + 0x00640064, + 0x00000064, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00000a24, + 0x43C20000, + 0x5b1c00c8, + 0x00c8002e, + 0x00000000, + 0x0001046b, + 0x00000000, + 0x03030100, + 0x03030303, + 0x03030303, + 0x03030303, + 0x00210000, + 0x00010021, + 0x00200000, + 0x006c0090, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; +#endif diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/start.S b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/start.S new file mode 100644 index 000000000..7dbd5dbf9 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/start.S @@ -0,0 +1,106 @@ +/* + * armboot - Startup Code for ARM926EJS CPU-core + * + * Copyright (c) 2003 Texas Instruments + * + * ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------ + * + * Copyright (c) 2001 Marius Gröger <mag@sysgo.de> + * Copyright (c) 2002 Alex Züpke <azu@sysgo.de> + * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de> + * Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com> + * Copyright (c) 2003 Kshitij <kshitij@ti.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + + +#include <config.h> + +.globl _start +_start: + b reset + ldr pc, _undefined_instruction + ldr pc, _software_interrupt + ldr pc, _prefetch_abort + ldr pc, _data_abort + ldr pc, _not_used + ldr pc, _irq + ldr pc, _fiq + +_undefined_instruction: +_software_interrupt: +_prefetch_abort: +_data_abort: +_not_used: +_irq: +_fiq: + .word infinite_loop + +infinite_loop: + b infinite_loop + +/* + ************************************************************************* + * + * Startup Code (reset vector) + * + * Below are the critical initializations already taken place in BootROM. + * So, these are not taken care in Xloader + * 1. Relocation to RAM + * 2. Initializing stacks + * + ************************************************************************* + */ + +/* + * the actual reset code + */ + +reset: +/* + * Xloader has to return back to BootROM in a few cases. + * eg. Ethernet boot, UART boot, USB boot + * Saving registers for returning back + */ + stmdb sp!, {r0-r12,r14} + bl cpu_init_crit +/* + * Clearing bss area is not done in Xloader. + * BSS area lies in the DDR location which is not yet initialized + * bss is assumed to be uninitialized. + */ + bl spl_boot + ldmia sp!, {r0-r12,pc} + +/* + ************************************************************************* + * + * CPU_init_critical registers + * + * setup important registers + * setup memory timing + * + ************************************************************************* + */ +cpu_init_crit: + /* + * flush v4 I/D caches + */ + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ + mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ + + /* + * enable instruction cache + */ + mrc p15, 0, r0, c1, c0, 0 + orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */ + mcr p15, 0, r0, c1, c0, 0 + + /* + * Go setup Memory and board specific bits prior to relocation. + */ + stmdb sp!, {lr} + bl lowlevel_init /* go setup pll,mux,memory */ + ldmia sp!, {pc} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/timer.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/timer.c new file mode 100644 index 000000000..c88e962a3 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/timer.c @@ -0,0 +1,123 @@ +/* + * (C) Copyright 2009 + * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/spr_gpt.h> +#include <asm/arch/spr_misc.h> + +#define GPT_RESOLUTION (CONFIG_SPEAR_HZ_CLOCK / CONFIG_SPEAR_HZ) +#define READ_TIMER() (readl(&gpt_regs_p->count) & GPT_FREE_RUNNING) + +static struct gpt_regs *const gpt_regs_p = + (struct gpt_regs *)CONFIG_SPEAR_TIMERBASE; + +static struct misc_regs *const misc_regs_p = + (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp gd->arch.tbl +#define lastdec gd->arch.lastinc + +int timer_init(void) +{ + u32 synth; + + /* Prescaler setting */ +#if defined(CONFIG_SPEAR3XX) + writel(MISC_PRSC_CFG, &misc_regs_p->prsc2_clk_cfg); + synth = MISC_GPT4SYNTH; +#elif defined(CONFIG_SPEAR600) + writel(MISC_PRSC_CFG, &misc_regs_p->prsc1_clk_cfg); + synth = MISC_GPT3SYNTH; +#else +# error Incorrect config. Can only be spear{600|300|310|320} +#endif + + writel(readl(&misc_regs_p->periph_clk_cfg) | synth, + &misc_regs_p->periph_clk_cfg); + + /* disable timers */ + writel(GPT_PRESCALER_1 | GPT_MODE_AUTO_RELOAD, &gpt_regs_p->control); + + /* load value for free running */ + writel(GPT_FREE_RUNNING, &gpt_regs_p->compare); + + /* auto reload, start timer */ + writel(readl(&gpt_regs_p->control) | GPT_ENABLE, &gpt_regs_p->control); + + /* Reset the timer */ + lastdec = READ_TIMER(); + timestamp = 0; + + return 0; +} + +/* + * timer without interrupts + */ +ulong get_timer(ulong base) +{ + return (get_timer_masked() / GPT_RESOLUTION) - base; +} + +void __udelay(unsigned long usec) +{ + ulong tmo; + ulong start = get_timer_masked(); + ulong tenudelcnt = CONFIG_SPEAR_HZ_CLOCK / (1000 * 100); + ulong rndoff; + + rndoff = (usec % 10) ? 1 : 0; + + /* tenudelcnt timer tick gives 10 microsecconds delay */ + tmo = ((usec / 10) + rndoff) * tenudelcnt; + + while ((ulong) (get_timer_masked() - start) < tmo) + ; +} + +ulong get_timer_masked(void) +{ + ulong now = READ_TIMER(); + + if (now >= lastdec) { + /* normal mode */ + timestamp += now - lastdec; + } else { + /* we have an overflow ... */ + timestamp += now + GPT_FREE_RUNNING - lastdec; + } + lastdec = now; + + return timestamp; +} + +void udelay_masked(unsigned long usec) +{ + return udelay(usec); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + return CONFIG_SPEAR_HZ; +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/u-boot-spl.lds b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/u-boot-spl.lds new file mode 100644 index 000000000..b6d0f65b6 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/spear/u-boot-spl.lds @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * January 2004 - Changed to support H4 device + * Copyright (c) 2004-2008 Texas Instruments + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + + . = ALIGN(4); + .text : + { + arch/arm/cpu/arm926ejs/spear/start.o (.text*) + *(.text*) + } + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(4); + .data : { + *(.data*) + } + + . = ALIGN(4); + + .rel.dyn : { + __rel_dyn_start = .; + *(.rel*) + __rel_dyn_end = .; + } + + .bss : { + . = ALIGN(4); + __bss_start = .; + *(.bss*) + . = ALIGN(4); + __bss_end = .; + } + + .end : + { + *(.__end) + } + + _image_binary_end = .; + + .dynsym _image_binary_end : { *(.dynsym) } + .dynbss : { *(.dynbss) } + .dynstr : { *(.dynstr*) } + .dynamic : { *(.dynamic*) } + .hash : { *(.hash*) } + .plt : { *(.plt*) } + .interp : { *(.interp*) } + .gnu : { *(.gnu*) } + .ARM.exidx : { *(.ARM.exidx*) } +} diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/start.S b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/start.S new file mode 100644 index 000000000..071732705 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/start.S @@ -0,0 +1,372 @@ +/* + * armboot - Startup Code for ARM926EJS CPU-core + * + * Copyright (c) 2003 Texas Instruments + * + * ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------ + * + * Copyright (c) 2001 Marius Gröger <mag@sysgo.de> + * Copyright (c) 2002 Alex Züpke <azu@sysgo.de> + * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de> + * Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com> + * Copyright (c) 2003 Kshitij <kshitij@ti.com> + * Copyright (c) 2010 Albert Aribaud <albert.u.boot@aribaud.net> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <asm-offsets.h> +#include <config.h> +#include <common.h> +#include <version.h> + +/* + ************************************************************************* + * + * Jump vector table as in table 3.1 in [1] + * + ************************************************************************* + */ + + +#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG +.globl _start +_start: +.globl _NOR_BOOT_CFG +_NOR_BOOT_CFG: + .word CONFIG_SYS_DV_NOR_BOOT_CFG + b reset +#else +.globl _start +_start: + b reset +#endif +#ifdef CONFIG_SPL_BUILD +/* No exception handlers in preloader */ + ldr pc, _hang + ldr pc, _hang + ldr pc, _hang + ldr pc, _hang + ldr pc, _hang + ldr pc, _hang + ldr pc, _hang + +_hang: + .word do_hang +/* pad to 64 byte boundary */ + .word 0x12345678 + .word 0x12345678 + .word 0x12345678 + .word 0x12345678 + .word 0x12345678 + .word 0x12345678 + .word 0x12345678 +#else + ldr pc, _undefined_instruction + ldr pc, _software_interrupt + ldr pc, _prefetch_abort + ldr pc, _data_abort + ldr pc, _not_used + ldr pc, _irq + ldr pc, _fiq + +_undefined_instruction: + .word undefined_instruction +_software_interrupt: + .word software_interrupt +_prefetch_abort: + .word prefetch_abort +_data_abort: + .word data_abort +_not_used: + .word not_used +_irq: + .word irq +_fiq: + .word fiq + +#endif /* CONFIG_SPL_BUILD */ + .balignl 16,0xdeadbeef + + +/* + ************************************************************************* + * + * Startup Code (reset vector) + * + * do important init only if we don't start from memory! + * setup Memory and board specific bits prior to relocation. + * relocate armboot to ram + * setup stack + * + ************************************************************************* + */ + +#ifdef CONFIG_USE_IRQ +/* IRQ stack memory (calculated at run-time) */ +.globl IRQ_STACK_START +IRQ_STACK_START: + .word 0x0badc0de + +/* IRQ stack memory (calculated at run-time) */ +.globl FIQ_STACK_START +FIQ_STACK_START: + .word 0x0badc0de +#endif + +/* IRQ stack memory (calculated at run-time) + 8 bytes */ +.globl IRQ_STACK_START_IN +IRQ_STACK_START_IN: + .word 0x0badc0de + +/* + * the actual reset code + */ + +reset: + /* + * set the cpu to SVC32 mode + */ + mrs r0,cpsr + bic r0,r0,#0x1f + orr r0,r0,#0xd3 + msr cpsr,r0 + + /* + * we do sys-critical inits only at reboot, + * not when booting from ram! + */ +#ifndef CONFIG_SKIP_LOWLEVEL_INIT + bl cpu_init_crit +#endif + + bl _main + +/*------------------------------------------------------------------------------*/ + + .globl c_runtime_cpu_setup +c_runtime_cpu_setup: + + bx lr + +/* + ************************************************************************* + * + * CPU_init_critical registers + * + * setup important registers + * setup memory timing + * + ************************************************************************* + */ +#ifndef CONFIG_SKIP_LOWLEVEL_INIT +cpu_init_crit: + /* + * flush D cache before disabling it + */ + mov r0, #0 +flush_dcache: + mrc p15, 0, r15, c7, c10, 3 + bne flush_dcache + + mcr p15, 0, r0, c8, c7, 0 /* invalidate TLB */ + mcr p15, 0, r0, c7, c5, 0 /* invalidate I Cache */ + + /* + * disable MMU and D cache + * enable I cache if CONFIG_SYS_ICACHE_OFF is not defined + */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x00000300 /* clear bits 9:8 (---- --RS) */ + bic r0, r0, #0x00000087 /* clear bits 7, 2:0 (B--- -CAM) */ +#ifdef CONFIG_SYS_EXCEPTION_VECTORS_HIGH + orr r0, r0, #0x00002000 /* set bit 13 (--V- ----) */ +#else + bic r0, r0, #0x00002000 /* clear bit 13 (--V- ----) */ +#endif + orr r0, r0, #0x00000002 /* set bit 2 (A) Align */ +#ifndef CONFIG_SYS_ICACHE_OFF + orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */ +#endif + mcr p15, 0, r0, c1, c0, 0 + + /* + * Go setup Memory and board specific bits prior to relocation. + */ + mov ip, lr /* perserve link reg across call */ + bl lowlevel_init /* go setup pll,mux,memory */ + mov lr, ip /* restore link */ + mov pc, lr /* back to my caller */ +#endif /* CONFIG_SKIP_LOWLEVEL_INIT */ + +#ifndef CONFIG_SPL_BUILD +/* + ************************************************************************* + * + * Interrupt handling + * + ************************************************************************* + */ + +@ +@ IRQ stack frame. +@ +#define S_FRAME_SIZE 72 + +#define S_OLD_R0 68 +#define S_PSR 64 +#define S_PC 60 +#define S_LR 56 +#define S_SP 52 + +#define S_IP 48 +#define S_FP 44 +#define S_R10 40 +#define S_R9 36 +#define S_R8 32 +#define S_R7 28 +#define S_R6 24 +#define S_R5 20 +#define S_R4 16 +#define S_R3 12 +#define S_R2 8 +#define S_R1 4 +#define S_R0 0 + +#define MODE_SVC 0x13 +#define I_BIT 0x80 + +/* + * use bad_save_user_regs for abort/prefetch/undef/swi ... + * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling + */ + + .macro bad_save_user_regs + @ carve out a frame on current user stack + sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ Save user registers (now in svc mode) r0-r12 + ldr r2, IRQ_STACK_START_IN + @ get values for "aborted" pc and cpsr (into parm regs) + ldmia r2, {r2 - r3} + add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack + add r5, sp, #S_SP + mov r1, lr + stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr + mov r0, sp @ save current stack into r0 (param register) + .endm + + .macro irq_save_user_regs + sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ Calling r0-r12 + @ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good. + add r8, sp, #S_PC + stmdb r8, {sp, lr}^ @ Calling SP, LR + str lr, [r8, #0] @ Save calling PC + mrs r6, spsr + str r6, [r8, #4] @ Save CPSR + str r0, [r8, #8] @ Save OLD_R0 + mov r0, sp + .endm + + .macro irq_restore_user_regs + ldmia sp, {r0 - lr}^ @ Calling r0 - lr + mov r0, r0 + ldr lr, [sp, #S_PC] @ Get PC + add sp, sp, #S_FRAME_SIZE + subs pc, lr, #4 @ return & move spsr_svc into cpsr + .endm + + .macro get_bad_stack + ldr r13, IRQ_STACK_START_IN @ setup our mode stack + + str lr, [r13] @ save caller lr in position 0 of saved stack + mrs lr, spsr @ get the spsr + str lr, [r13, #4] @ save spsr in position 1 of saved stack + mov r13, #MODE_SVC @ prepare SVC-Mode + @ msr spsr_c, r13 + msr spsr, r13 @ switch modes, make sure moves will execute + mov lr, pc @ capture return pc + movs pc, lr @ jump to next instruction & switch modes. + .endm + + .macro get_irq_stack @ setup IRQ stack + ldr sp, IRQ_STACK_START + .endm + + .macro get_fiq_stack @ setup FIQ stack + ldr sp, FIQ_STACK_START + .endm +#endif /* CONFIG_SPL_BUILD */ + +/* + * exception handlers + */ +#ifdef CONFIG_SPL_BUILD + .align 5 +do_hang: +1: + bl 1b /* hang and never return */ +#else /* !CONFIG_SPL_BUILD */ + .align 5 +undefined_instruction: + get_bad_stack + bad_save_user_regs + bl do_undefined_instruction + + .align 5 +software_interrupt: + get_bad_stack + bad_save_user_regs + bl do_software_interrupt + + .align 5 +prefetch_abort: + get_bad_stack + bad_save_user_regs + bl do_prefetch_abort + + .align 5 +data_abort: + get_bad_stack + bad_save_user_regs + bl do_data_abort + + .align 5 +not_used: + get_bad_stack + bad_save_user_regs + bl do_not_used + +#ifdef CONFIG_USE_IRQ + + .align 5 +irq: + get_irq_stack + irq_save_user_regs + bl do_irq + irq_restore_user_regs + + .align 5 +fiq: + get_fiq_stack + /* someone ought to write a more effiction fiq_save_user_regs */ + irq_save_user_regs + bl do_fiq + irq_restore_user_regs + +#else + + .align 5 +irq: + get_bad_stack + bad_save_user_regs + bl do_irq + + .align 5 +fiq: + get_bad_stack + bad_save_user_regs + bl do_fiq + +#endif +#endif /* CONFIG_SPL_BUILD */ diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/versatile/Makefile b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/versatile/Makefile new file mode 100644 index 000000000..907f5161a --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/versatile/Makefile @@ -0,0 +1,9 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-y = timer.o +obj-y += reset.o diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/versatile/reset.S b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/versatile/reset.S new file mode 100644 index 000000000..1c557b0d9 --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/versatile/reset.S @@ -0,0 +1,29 @@ +/* + * armboot - Startup Code for ARM926EJS CPU-core + * + * Copyright (c) 2003 Texas Instruments + * + * ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------ + * + * Copyright (c) 2001 Marius Gröger <mag@sysgo.de> + * Copyright (c) 2002 Alex Züpke <azu@sysgo.de> + * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de> + * Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com> + * Copyright (c) 2003 Kshitij <kshitij@ti.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + + .align 5 +.globl reset_cpu +reset_cpu: + ldr r1, rstctl1 /* get clkm1 reset ctl */ + mov r3, #0x0 + strh r3, [r1] /* clear it */ + mov r3, #0x8 + strh r3, [r1] /* force dsp+arm reset */ +_loop_forever: + b _loop_forever + +rstctl1: + .word 0xfffece10 diff --git a/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/versatile/timer.c b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/versatile/timer.c new file mode 100644 index 000000000..5d694d85e --- /dev/null +++ b/qemu/roms/u-boot/arch/arm/cpu/arm926ejs/versatile/timer.c @@ -0,0 +1,64 @@ +/* + * (C) Copyright 2003 + * Texas Instruments <www.ti.com> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002-2004 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * (C) Copyright 2004 + * Philippe Robin, ARM Ltd. <philippe.robin@arm.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> + +#define TIMER_ENABLE (1 << 7) +#define TIMER_MODE_MSK (1 << 6) +#define TIMER_MODE_FR (0 << 6) +#define TIMER_MODE_PD (1 << 6) + +#define TIMER_INT_EN (1 << 5) +#define TIMER_PRS_MSK (3 << 2) +#define TIMER_PRS_8S (1 << 3) +#define TIMER_SIZE_MSK (1 << 2) +#define TIMER_ONE_SHT (1 << 0) + +int timer_init (void) +{ + ulong tmr_ctrl_val; + + /* 1st disable the Timer */ + tmr_ctrl_val = *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8); + tmr_ctrl_val &= ~TIMER_ENABLE; + *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = tmr_ctrl_val; + + /* + * The Timer Control Register has one Undefined/Shouldn't Use Bit + * So we should do read/modify/write Operation + */ + + /* + * Timer Mode : Free Running + * Interrupt : Disabled + * Prescale : 8 Stage, Clk/256 + * Tmr Siz : 16 Bit Counter + * Tmr in Wrapping Mode + */ + tmr_ctrl_val = *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8); + tmr_ctrl_val &= ~(TIMER_MODE_MSK | TIMER_INT_EN | TIMER_PRS_MSK | TIMER_SIZE_MSK | TIMER_ONE_SHT ); + tmr_ctrl_val |= (TIMER_ENABLE | TIMER_PRS_8S); + + *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = tmr_ctrl_val; + + return 0; +} + |