diff options
-rw-r--r-- | src/soc/marvell/armada38x/Kconfig | 27 | ||||
-rw-r--r-- | src/soc/marvell/armada38x/Makefile.inc | 31 | ||||
-rw-r--r-- | src/soc/marvell/armada38x/bootblock.c | 176 | ||||
-rw-r--r-- | src/soc/marvell/armada38x/bootblock_asm.S | 123 | ||||
-rw-r--r-- | src/soc/marvell/armada38x/cbmem.c | 22 | ||||
-rw-r--r-- | src/soc/marvell/armada38x/include/soc/common.h | 128 | ||||
-rw-r--r-- | src/soc/marvell/armada38x/include/soc/memlayout.ld | 34 | ||||
-rw-r--r-- | src/soc/marvell/armada38x/include/soc/soc_services.h | 23 | ||||
-rw-r--r-- | src/soc/marvell/armada38x/monotonic_timer.c | 58 | ||||
-rw-r--r-- | src/soc/marvell/armada38x/soc.c | 55 | ||||
-rw-r--r-- | src/soc/marvell/armada38x/uart.c | 151 |
11 files changed, 828 insertions, 0 deletions
diff --git a/src/soc/marvell/armada38x/Kconfig b/src/soc/marvell/armada38x/Kconfig new file mode 100644 index 0000000000..6754a0f1f6 --- /dev/null +++ b/src/soc/marvell/armada38x/Kconfig @@ -0,0 +1,27 @@ +config SOC_MARVELL_ARMADA38X + bool + default n + select ARCH_BOOTBLOCK_ARMV7 + select ARCH_VERSTAGE_ARMV7 + select ARCH_ROMSTAGE_ARMV7 + select ARCH_RAMSTAGE_ARMV7 + select HAVE_UART_SPECIAL + select BOOTBLOCK_CONSOLE + select RETURN_FROM_VERSTAGE + select BOOTBLOCK_CUSTOM + select GENERIC_UDELAY + +if SOC_MARVELL_ARMADA38X + +config BOOTBLOCK_CPU_INIT + string + default "soc/marvell/armada38x/bootblock.c" + help + CPU/SoC-specific bootblock code. This is useful if the + bootblock must load microcode or copy data from ROM before + searching for the bootblock. + +config CONSOLE_SERIAL_UART_ADDRESS + hex + default 0xf1012000 +endif diff --git a/src/soc/marvell/armada38x/Makefile.inc b/src/soc/marvell/armada38x/Makefile.inc new file mode 100644 index 0000000000..416ad74d87 --- /dev/null +++ b/src/soc/marvell/armada38x/Makefile.inc @@ -0,0 +1,31 @@ +ifeq ($(CONFIG_SOC_MARVELL_ARMADA38X),y) + +bootblock-y += bootblock.c +bootblock-y += bootblock_asm.S +bootblock-y += monotonic_timer.c +ifeq ($(CONFIG_BOOTBLOCK_CONSOLE),y) +bootblock-$(CONFIG_DRIVERS_UART) += uart.c +endif + +verstage-$(CONFIG_DRIVERS_UART) += uart.c +verstage-y += monotonic_timer.c + +romstage-y += cbmem.c +romstage-y += monotonic_timer.c +romstage-$(CONFIG_DRIVERS_UART) += uart.c + +ramstage-y += cbmem.c +ramstage-y += monotonic_timer.c +ramstage-y += soc.c +ramstage-$(CONFIG_DRIVERS_UART) += uart.c + +CPPFLAGS_common += -Isrc/soc/marvell/armada38x/include/ + +BIN_HDR = 3rdparty/blobs/cpu/marvell/armada38x/bin_hdr.bin +DOIMAGE = 3rdparty/blobs/cpu/marvell/armada38x/doimage + +$(objcbfs)/bootblock.bin: $(objcbfs)/bootblock.raw.bin + @chmod a+x $(DOIMAGE) + $(DOIMAGE) -T flash -D 0 -E 0 -G $(BIN_HDR) $< $@ + rm $< +endif diff --git a/src/soc/marvell/armada38x/bootblock.c b/src/soc/marvell/armada38x/bootblock.c new file mode 100644 index 0000000000..8c125b5bb6 --- /dev/null +++ b/src/soc/marvell/armada38x/bootblock.c @@ -0,0 +1,176 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <assert.h> +#include <arch/io.h> +#include <arch/cache.h> +#include <arch/exception.h> +#include <arch/hlt.h> +#include <bootblock_common.h> +#include <cbfs.h> +#include <console/console.h> +#include <delay.h> +#include <arch/stages.h> +#include <symbols.h> +#include <vendorcode/google/chromeos/chromeos.h> +#include <soc/common.h> + +#define CLOCK_BIT_SATA23 BIT30 +#define CLOCK_BIT_PNC BIT29 +#define CLOCK_BIT_TDM BIT25 +#define CLOCK_BIT_CRYPTO0_GATE BIT23 +#define CLOCK_BIT_CRYPTO1_GATE BIT21 +#define CLOCK_BIT_CRYPTO1_Z BIT16 +#define CLOCK_BIT_SATA01 BIT15 +#define CLOCK_BIT_CRYPTO0_Z BIT14 +#define CLOCK_BIT_BM BIT13 +#define CLOCK_BIT_PCIE2 BIT6 +#define CLOCK_BIT_PCIE1 BIT5 +#define CLOCK_BIT_GBE0 BIT4 +#define CLOCK_BIT_GBE1 BIT3 +#define CLOCK_BIT_GBE2 BIT2 +#define CLOCK_BIT_AUDIO BIT0 + +#define A38x_MPP0_7_OFFSET 0x18000 +#define A38x_MPP8_15_OFFSET 0x18004 +#define A38x_MPP16_23_OFFSET 0x18008 +#define A38x_MPP24_31_OFFSET 0x1800c +#define A38x_MPP32_39_OFFSET 0x18010 +#define A38x_MPP40_47_OFFSET 0x18014 +#define A38x_MPP48_55_OFFSET 0x18018 +#define A38x_MPP56_63_OFFSET 0x1801c + +#define A38X_GPP_OUT_ENA_OFFSET_LOW 0x18104 +#define A38X_GPP_OUT_ENA_OFFSET_MID 0x18144 + +#define A38X_GPP_OUT_VALUE_OFFSET_LOW 0x18100 +#define A38X_GPP_OUT_VALUE_OFFSET_MID 0x18140 + +#define A38x_CUBE_BOARD_MPP0_7 0x00001111 +#define A38x_CUBE_BOARD_MPP8_15 0x46200000 +#define A38x_CUBE_BOARD_MPP16_23 0x00400444 +#define A38x_CUBE_BOARD_MPP24_31 0x00043300 +#define A38x_CUBE_BOARD_MPP32_39 0x44400000 +#define A38x_CUBE_BOARD_MPP40_47 0x00000004 +#define A38x_CUBE_BOARD_MPP48_55 0x00444444 +#define A38x_CUBE_BOARD_MPP56_63 0x00004444 + +/* Set bit x to enable GPIO output mode for MPP x */ +#define A38x_CUBE_BOARD_0_GPP_OUT_ENA_LOW ~(BIT4 | BIT6) +/* MID group is for MPP32 ~ MPP63 e.g BIT3 corresponds to MPP35 */ +#define A38x_CUBE_BOARD_0_GPP_OUT_ENA_MID ~(BIT3) + +#define A38x_CUSTOMER_BOARD_0_GPP_OUT_VAL_LOW (BIT4) +/* MID group is for MPP32 ~ MPP63 e.g BIT3 corresponds to MPP35 */ +#define A38x_CUSTOMER_BOARD_0_GPP_OUT_VAL_MID (BIT3) + +#define A38X_POWER_MANAGEMENT_CLOCK_GATING_CONTROL 0x18220 + +#define A38x_SOC_IO_ERR_CTRL_OFFSET 0x20200 +#define A38x_SOC_WIN_CTRL_OFFSET 0x20250 +#define A38x_SOC_WIN_BASE_OFFSET 0x20254 + +#define A38x_CUBE_BOARD_SOC_IO_ERR_CTRL 0x00000000 +#define A38x_CUBE_BOARD_SOC_WIN_CTRL 0x1ff00001 +#define A38x_CUBE_BOARD_SOC_BASE_CTRL 0xe0000000 + +#define DRAM_START ((uintptr_t)_dram / MiB) +#define DRAM_SIZE (CONFIG_DRAM_SIZE_MB) +/* DMA memory for drivers */ +#define DMA_START ((uintptr_t)_dma_coherent / MiB) +#define DMA_SIZE (_dma_coherent_size / MiB) + +static void setup_pinmux(void) +{ + /* Hard coded pin mux configuration */ + mrvl_reg_write(A38x_MPP0_7_OFFSET, A38x_CUBE_BOARD_MPP0_7); + mrvl_reg_write(A38x_MPP8_15_OFFSET, A38x_CUBE_BOARD_MPP8_15); + mrvl_reg_write(A38x_MPP16_23_OFFSET, A38x_CUBE_BOARD_MPP16_23); + mrvl_reg_write(A38x_MPP24_31_OFFSET, A38x_CUBE_BOARD_MPP24_31); + mrvl_reg_write(A38x_MPP32_39_OFFSET, A38x_CUBE_BOARD_MPP32_39); + mrvl_reg_write(A38x_MPP40_47_OFFSET, A38x_CUBE_BOARD_MPP40_47); + mrvl_reg_write(A38x_MPP48_55_OFFSET, A38x_CUBE_BOARD_MPP48_55); + mrvl_reg_write(A38x_MPP56_63_OFFSET, A38x_CUBE_BOARD_MPP56_63); +} + +static void setup_gpp_out_value(void) +{ + mrvl_reg_write( + A38X_GPP_OUT_VALUE_OFFSET_LOW, + A38x_CUSTOMER_BOARD_0_GPP_OUT_VAL_LOW); + mrvl_reg_write( + A38X_GPP_OUT_VALUE_OFFSET_MID, + A38x_CUSTOMER_BOARD_0_GPP_OUT_VAL_MID); +} + +static void setup_gpp_out_enable(void) +{ + mrvl_reg_write( + A38X_GPP_OUT_ENA_OFFSET_LOW, + A38x_CUBE_BOARD_0_GPP_OUT_ENA_LOW); + mrvl_reg_write( + A38X_GPP_OUT_ENA_OFFSET_MID, + A38x_CUBE_BOARD_0_GPP_OUT_ENA_MID); +} + +/* This function disable unused periperal clocks */ +static void setup_peripherals_clocks(void) +{ + mrvl_reg_bit_reset( + A38X_POWER_MANAGEMENT_CLOCK_GATING_CONTROL, ( + CLOCK_BIT_SATA23 | CLOCK_BIT_PNC | CLOCK_BIT_TDM | + CLOCK_BIT_CRYPTO0_GATE | CLOCK_BIT_CRYPTO1_GATE | + CLOCK_BIT_CRYPTO1_Z | CLOCK_BIT_SATA01 | + CLOCK_BIT_CRYPTO0_Z | CLOCK_BIT_BM | + CLOCK_BIT_PCIE2 | CLOCK_BIT_PCIE1 | + CLOCK_BIT_GBE0 | CLOCK_BIT_GBE1 | + CLOCK_BIT_GBE2 | CLOCK_BIT_AUDIO + ) + ); +} + +static void setup_win_regs(void) +{ + mrvl_reg_write(A38x_SOC_IO_ERR_CTRL_OFFSET, + A38x_CUBE_BOARD_SOC_IO_ERR_CTRL); + mrvl_reg_write(A38x_SOC_WIN_CTRL_OFFSET, A38x_CUBE_BOARD_SOC_WIN_CTRL); + mrvl_reg_write(A38x_SOC_WIN_BASE_OFFSET, A38x_CUBE_BOARD_SOC_BASE_CTRL); +} + +void main(void) +{ + if (CONFIG_BOOTBLOCK_CONSOLE) { + console_init(); + exception_init(); + } + + init_timer(); + + /* enable mmu */ + mmu_init(); + mmu_config_range(0, 4096, DCACHE_OFF); + mmu_config_range(DRAM_START, DRAM_SIZE, DCACHE_WRITEBACK); + mmu_config_range(DMA_START, DMA_SIZE, DCACHE_OFF); + dcache_mmu_enable(); + + bootblock_mainboard_init(); + + setup_pinmux(); + setup_gpp_out_value(); + setup_gpp_out_enable(); + setup_win_regs(); + setup_peripherals_clocks(); + run_romstage(); +} diff --git a/src/soc/marvell/armada38x/bootblock_asm.S b/src/soc/marvell/armada38x/bootblock_asm.S new file mode 100644 index 0000000000..640c4ed91e --- /dev/null +++ b/src/soc/marvell/armada38x/bootblock_asm.S @@ -0,0 +1,123 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/asm.h> + +.arm + /* + * Just in case the maskrom or the vendor basic firmware passes on a + * parameter when calling the bootblock, store it here for handling by C + * code. + */ + .section .bss, "aw" @nobits + .global maskrom_param + .align 4 +maskrom_param: + .word 0 + +ENTRY(_start) + /* + * Set the cpu to System mode with IRQ and FIQ disabled. Prefetch/Data + * aborts may happen early and crash before the abort handlers are + * installed, but at least the problem will show up near the code that + * causes it. + */ + msr cpsr_cxf, #0xdf + bl _thumb_start +ENDPROC(_start) + +.thumb +ENTRY(_thumb_start) + + /* Preserve the maskrom passed value, if any */ + mov r10, r0 + + /* Disable L2 Cache */ + ldr r1, =0x0 + ldr r0, =0xD0008100 + str r1, [r0] + + /* Disable windows that overlap with 0xF1000000 */ + /* By default, window #12 overlaps with 0xF1000000 */ + mov r1, #0 + ldr r0, =0xD00200B0 + str r1, [r0] + /* Set Registers Base address. */ + ldr r1, =0xf1000000 + ldr r0, =0xD0020080 + str r1, [r0] + /* Update SCU (peripheral) register Base address with + * correct INTER_REG_BASE + */ + ldr r2, = 0xC000 /* SCU offset = 0xC000 */ + add r1, r1, r2 /* r1 = INTER_REG_BASE + SCU_OFFSET */ + mcr p15, 4, r1, c15, c0, 0 /* Write SCU base register */ + + bl arm_init_caches + + /* + * From Cortex-A Series Programmer's Guide: + * Only CPU 0 performs initialization. Other CPUs go into WFI + * to do this, first work out which CPU this is + * this code typically is run before any other initialization step + */ + mrc p15, 0, r1, c0, c0, 5 @ Read Multiprocessor Affinity Register + and r1, r1, #0x3 @ Extract CPU ID bits + cmp r1, #0 + bne wait_for_interrupt @ If this is not core0, wait + + /* + * Initialize the stack to a known value. This is used to check for + * stack overflow later in the boot process. + */ + ldr r0, =_stack + ldr r1, =_estack + ldr r2, =0xdeadbeef +init_stack_loop: + str r2, [r0] + add r0, #4 + cmp r0, r1 + bne init_stack_loop + + ldr r0, =_bss + ldr r1, =_ebss + mov r2, #0x00000000 /* prepare zero to clear BSS */ +clbss_l: + str r2, [r0] + add r0, #4 + cmp r0, r1 + bne clbss_l + +call_bootblock: + + /* Restore parameter passed in by maskrom/vendor firmware. */ + ldr r0, =maskrom_param + str r10, [r0] + + /* Set stackpointer in internal RAM to call bootblock main() */ + ldr sp, =_estack + ldr r0,=0x00000000 + /* + * The current design of cpu_info places the struct at the top of the + * stack. Free enough space to accommodate for that, but make sure it's + * 8-byte aligned for ABI compliance. + */ + sub sp, sp, #16 + bl main + +wait_for_interrupt: + wfi + mov pc, lr @ back to my caller +ENDPROC(_thumb_start) diff --git a/src/soc/marvell/armada38x/cbmem.c b/src/soc/marvell/armada38x/cbmem.c new file mode 100644 index 0000000000..94719b8ca0 --- /dev/null +++ b/src/soc/marvell/armada38x/cbmem.c @@ -0,0 +1,22 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <cbmem.h> +#include <soc/soc_services.h> + +void *cbmem_top(void) +{ + return (void *)_memlayout_cbmem_top; +} diff --git a/src/soc/marvell/armada38x/include/soc/common.h b/src/soc/marvell/armada38x/include/soc/common.h new file mode 100644 index 0000000000..3a8799cf7e --- /dev/null +++ b/src/soc/marvell/armada38x/include/soc/common.h @@ -0,0 +1,128 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Marvell Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __SOC_MARVELL_ARMADA38X_COMMON_H_ +#define __SOC_MARVELL_ARMADA38X_COMMON_H_ + +#include <types.h> +#include <arch/io.h> + +#define INTER_REGS_BASE 0xF1000000 + +#define MV_TRUE (1) +#define MV_FALSE (0) + +/* The following is a list of Marvell status */ +#define MV_ERROR (-1) +#define MV_OK (0) +#define MV_FAIL (1) +#define MV_BAD_VALUE (2) +#define MV_OUT_OF_RANGE (3) +#define MV_BAD_PARAM (4) +#define MV_BAD_PTR (5) +#define MV_BAD_SIZE (6) +#define MV_BAD_STATE (7) +#define MV_SET_ERROR (8) +#define MV_GET_ERROR (9) +#define MV_CREATE_ERROR (10) +#define MV_NOT_FOUND (11) +#define MV_NO_MORE (12) +#define MV_NO_SUCH (13) +#define MV_TIMEOUT (14) +#define MV_NO_CHANGE (15) +#define MV_NOT_SUPPORTED (16) +#define MV_NOT_IMPLEMENTED (17) +#define MV_NOT_INITIALIZED (18) +#define MV_NO_RESOURCE (19) +#define MV_FULL (20) +#define MV_EMPTY (21) +#define MV_INIT_ERROR (22) +#define MV_HW_ERROR (23) +#define MV_TX_ERROR (24) +#define MV_RX_ERROR (25) +#define MV_NOT_READY (26) +#define MV_ALREADY_EXIST (27) +#define MV_OUT_OF_CPU_MEM (28) +#define MV_NOT_STARTED (29) +#define MV_BUSY (30) +#define MV_TERMINATE (31) +#define MV_NOT_ALIGNED (32) +#define MV_NOT_ALLOWED (33) +#define MV_WRITE_PROTECT (34) +#define MV_DROPPED (35) +#define MV_STOLEN (36) +#define MV_CONTINUE (37) +#define MV_RETRY (38) + +#define MV_INVALID (int)(-1) + +#define MV_BOARD_TCLK_200MHZ 200000000 +#define MV_BOARD_TCLK_250MHZ 250000000 + +#define MPP_SAMPLE_AT_RESET (0x18600) + +#define MV_6810_DEV_ID 0x6810 + +#define BIT0 0x00000001 +#define BIT1 0x00000002 +#define BIT2 0x00000004 +#define BIT3 0x00000008 +#define BIT4 0x00000010 +#define BIT5 0x00000020 +#define BIT6 0x00000040 +#define BIT7 0x00000080 +#define BIT8 0x00000100 +#define BIT9 0x00000200 +#define BIT10 0x00000400 +#define BIT11 0x00000800 +#define BIT12 0x00001000 +#define BIT13 0x00002000 +#define BIT14 0x00004000 +#define BIT15 0x00008000 +#define BIT16 0x00010000 +#define BIT17 0x00020000 +#define BIT18 0x00040000 +#define BIT19 0x00080000 +#define BIT20 0x00100000 +#define BIT21 0x00200000 +#define BIT22 0x00400000 +#define BIT23 0x00800000 +#define BIT24 0x01000000 +#define BIT25 0x02000000 +#define BIT26 0x04000000 +#define BIT27 0x08000000 +#define BIT28 0x10000000 +#define BIT29 0x20000000 +#define BIT30 0x40000000 +#define BIT31 0x80000000 + +static inline uint32_t mrvl_reg_read(uint32_t offset) +{ + return read32((void *)(INTER_REGS_BASE + offset)); +} +static inline void mrvl_reg_write(uint32_t offset, uint32_t val) +{ + write32((void *)(INTER_REGS_BASE + offset), val); +} +static inline void mrvl_reg_bit_set(uint32_t offset, uint32_t bit_mask) +{ + mrvl_reg_write(offset, (mrvl_reg_read(offset) | bit_mask)); +} +static inline void mrvl_reg_bit_reset(uint32_t offset, uint32_t bit_mask) +{ + mrvl_reg_write(offset, (mrvl_reg_read(offset) & (~bit_mask))); +} + +#endif // __SOC_MARVELL_ARMADA38X_COMMON_H__ diff --git a/src/soc/marvell/armada38x/include/soc/memlayout.ld b/src/soc/marvell/armada38x/include/soc/memlayout.ld new file mode 100644 index 0000000000..b7f34eac71 --- /dev/null +++ b/src/soc/marvell/armada38x/include/soc/memlayout.ld @@ -0,0 +1,34 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <memlayout.h> +#include <arch/header.ld> + +SECTIONS +{ + DRAM_START(0x00000000) + BOOTBLOCK(0x00000000, 24K) + RAMSTAGE(0x00800000, 128K) + CBFS_CACHE(0x12006000, 80K) + STACK(0x1201c000, 16K) + + VERSTAGE(0x1202c000, 96K) + ROMSTAGE(0x12044000, 96K) + VBOOT2_WORK(0x1205c000, 16K) + DMA_COHERENT(0x12100000, 2M) + SYMBOL(memlayout_cbmem_top, 0x1F400000) + TTB(0x1FF00000, 16K) + TTB_SUBTABLES(0x1FF04000, 2K) +} diff --git a/src/soc/marvell/armada38x/include/soc/soc_services.h b/src/soc/marvell/armada38x/include/soc/soc_services.h new file mode 100644 index 0000000000..2659961c29 --- /dev/null +++ b/src/soc/marvell/armada38x/include/soc/soc_services.h @@ -0,0 +1,23 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __SOC_MARVELL_ARMADA38X_SOC_SERVICES_H_ +#define __SOC_MARVELL_ARMADA38X_SOC_SERVICES_H_ + +#include <types.h> + +extern u8 _memlayout_cbmem_top[]; + +#endif /*__SOC_MARVELL_ARMADA38X_SOC_SERVICES_H_*/ diff --git a/src/soc/marvell/armada38x/monotonic_timer.c b/src/soc/marvell/armada38x/monotonic_timer.c new file mode 100644 index 0000000000..b314f1185e --- /dev/null +++ b/src/soc/marvell/armada38x/monotonic_timer.c @@ -0,0 +1,58 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/io.h> +#include <timer.h> +#include <delay.h> + +#define TIMER_CTRL_REG 0xf1020300 +#define TIMER_RELOAD_REG 0xf1020310 +#define TIMER_REG 0xf1020314 +#define TIMER_RELOAD_VALUE 0xffffffff + +#define MHZ_NUM 25 + +void init_timer(void) +{ + unsigned int reg; + + /* Set the reload timer */ + write32((void *)TIMER_RELOAD_REG, TIMER_RELOAD_VALUE); + /* Set the initial value to TIMER_RELOAD_VALUE - 1 + * (instead of TIMER_RELOAD_VALUE) to avoid 'fake' + * overflow being detected in timer_monotonic_get + * if it's called close enough with 'this' function */ + write32((void *)TIMER_REG, TIMER_RELOAD_VALUE - 1); + reg = read32((const void *)TIMER_CTRL_REG); + /* Let it start counting */ + reg |= 0x3; + write32((void *)TIMER_CTRL_REG, reg); +} + +void timer_monotonic_get(struct mono_time *mt) +{ + static uint64_t total_ticks = 0; + uint64_t overflow = 0; + uint32_t current_ticks = + TIMER_RELOAD_VALUE - read32((const void *)TIMER_REG); + + /* Assuming at most one overflow happened since last call */ + if (current_ticks <= total_ticks) + overflow = 1ULL << 32; + + total_ticks = (((total_ticks + overflow) >> 32) << 32) + current_ticks; + mono_time_set_usecs(mt, total_ticks / MHZ_NUM); +} + diff --git a/src/soc/marvell/armada38x/soc.c b/src/soc/marvell/armada38x/soc.c new file mode 100644 index 0000000000..d049391b8e --- /dev/null +++ b/src/soc/marvell/armada38x/soc.c @@ -0,0 +1,55 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/io.h> +#include <console/console.h> +#include <device/device.h> +#include <vendorcode/google/chromeos/chromeos.h> +#include <symbols.h> + +#define RESERVED_SIZE_KB (1 * KiB) + +static void soc_enable(device_t dev) +{ + /* Reserve bottom 1M bytes for MMU/TTB */ + reserved_ram_resource(dev, 0, ((uintptr_t)_dram / KiB + + (CONFIG_DRAM_SIZE_MB * KiB - RESERVED_SIZE_KB)), + RESERVED_SIZE_KB); + ram_resource(dev, 0, (uintptr_t)_dram / KiB, + (CONFIG_DRAM_SIZE_MB * KiB) - RESERVED_SIZE_KB); +} + +static void soc_init(device_t dev) +{ + printk(BIOS_INFO, "CPU: Armada 38X\n"); +} + +static struct device_operations soc_ops = { + .read_resources = DEVICE_NOOP, + .set_resources = DEVICE_NOOP, + .enable_resources = soc_enable, + .init = soc_init, + .scan_bus = 0, +}; + +static void enable_armada38x_dev(device_t dev) +{ + dev->ops = &soc_ops; +} + +struct chip_operations soc_marvell_armada38x_ops = { + CHIP_NAME("SOC Marvell Armada 38x") + .enable_dev = enable_armada38x_dev, +}; diff --git a/src/soc/marvell/armada38x/uart.c b/src/soc/marvell/armada38x/uart.c new file mode 100644 index 0000000000..e535aebf67 --- /dev/null +++ b/src/soc/marvell/armada38x/uart.c @@ -0,0 +1,151 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2015 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/io.h> +#include <console/uart.h> +#include <console/console.h> +#include <drivers/uart/uart8250reg.h> +#include <boot/coreboot_tables.h> +#include <stdint.h> +#include <assert.h> +#include <soc/common.h> + +struct armada38x_uart { + union { + uint32_t thr; // Transmit holding register. + uint32_t rbr; // Receive buffer register. + uint32_t dll; // Divisor latch lsb. + }; + union { + uint32_t ier; // Interrupt enable register. + uint32_t dlm; // Divisor latch msb. + }; + union { + uint32_t iir; // Interrupt identification register. + uint32_t fcr; // FIFO control register. + }; + uint32_t lcr; // Line control register. + uint32_t mcr; // Modem control register. + uint32_t lsr; // Line status register. + uint32_t msr; // Modem status register. +} __attribute__ ((packed)); + +static void armada38x_uart_tx_flush(struct armada38x_uart *uart_ptr); +static int armada38x_uart_tst_byte(struct armada38x_uart *uart_ptr); + +static void armada38x_uart_init(struct armada38x_uart *uart_ptr) +{ + const uint8_t line_config = UART8250_LCR_WLS_8; + uint16_t divisor = (u16) uart_baudrate_divisor(default_baudrate(), + uart_platform_refclk(), 16); + + armada38x_uart_tx_flush(uart_ptr); + // Disable interrupts. + write8(&uart_ptr->ier, 0); + // Enable access to divisor latches. + write8(&uart_ptr->lcr, UART8250_LCR_DLAB); + // Set the divisor. + write8(&uart_ptr->dll, divisor & 0xff); + write8(&uart_ptr->dlm, (divisor >> 8) & 0xff); + // Hide divisor latches and program line config. + write8(&uart_ptr->lcr, line_config); + // Enable FIFOs, and clear receive and transmit. + write8(&uart_ptr->fcr, UART8250_FCR_FIFO_EN | UART8250_FCR_CLEAR_RCVR | + UART8250_FCR_CLEAR_XMIT); +} + +static void armada38x_uart_tx_byte(struct armada38x_uart *uart_ptr, + unsigned char data) +{ + while (!(read8(&uart_ptr->lsr) & UART8250_LSR_THRE)) + ; + write8(&uart_ptr->thr, data); +} + +static void armada38x_uart_tx_flush(struct armada38x_uart *uart_ptr) +{ + while (!(read8(&uart_ptr->lsr) & UART8250_LSR_TEMT)) + ; +} + +static unsigned char armada38x_uart_rx_byte(struct armada38x_uart *uart_ptr) +{ + if (!armada38x_uart_tst_byte(uart_ptr)) + return 0; + return read8(&uart_ptr->rbr); +} + +static int armada38x_uart_tst_byte(struct armada38x_uart *uart_ptr) +{ + return (read8(&uart_ptr->lsr) & UART8250_LSR_DR) == UART8250_LSR_DR; +} + +unsigned int uart_platform_refclk(void) +{ + return MV_BOARD_TCLK_250MHZ; +} + +uintptr_t uart_platform_base(int idx) +{ + /* Default to UART 0 */ + unsigned int base = CONFIG_CONSOLE_SERIAL_UART_ADDRESS; + + assert((idx >= 0) && (idx < 2)); + base += idx * 0x100; + return base; +} + +void uart_init(int idx) +{ + struct armada38x_uart *uart_ptr = uart_platform_baseptr(idx); + + armada38x_uart_init(uart_ptr); +} + +void uart_tx_byte(int idx, unsigned char data) +{ + struct armada38x_uart *uart_ptr = uart_platform_baseptr(idx); + + armada38x_uart_tx_byte(uart_ptr, data); +} + +void uart_tx_flush(int idx) +{ + struct armada38x_uart *uart_ptr = uart_platform_baseptr(idx); + + armada38x_uart_tx_flush(uart_ptr); +} + +unsigned char uart_rx_byte(int idx) +{ + struct armada38x_uart *uart_ptr = uart_platform_baseptr(idx); + + return armada38x_uart_rx_byte(uart_ptr); +} + +#if ENV_RAMSTAGE +void uart_fill_lb(void *data) +{ + struct lb_serial serial; + + serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED; + serial.baseaddr = uart_platform_base(CONFIG_UART_FOR_CONSOLE); + serial.baud = default_baudrate(); + serial.regwidth = 1; + lb_add_serial(&serial, data); + + lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data); +} +#endif |