| /* |
| * Minimal bootblock for Cubieboard |
| * It sets up CPU clock, and enables the bootblock console. |
| * |
| * Copyright (C) 2013 Alexandru Gagniuc <mr.nuke.me@gmail.com> |
| * Subject to the GNU GPL v2, or (at your option) any later version. |
| */ |
| |
| #include <arch/io.h> |
| #include <bootblock_common.h> |
| #include <console/uart.h> |
| #include <console/console.h> |
| #include <delay.h> |
| #include <cpu/allwinner/a10/gpio.h> |
| #include <cpu/allwinner/a10/clock.h> |
| #include <cpu/allwinner/a10/dramc.h> |
| |
| #define CPU_AHB_APB0_DEFAULT \ |
| CPU_CLK_SRC_OSC24M \ |
| | APB0_DIV_1 \ |
| | AHB_DIV_2 \ |
| | AXI_DIV_1 |
| |
| #define GPH_STATUS_LEDS (1 << 20) | (1 << 21) |
| #define GPH_LED1_PIN_NO 21 |
| #define GPH_LED2_PIN_NO 20 |
| |
| #define GPB_UART0_FUNC 2 |
| #define GPB_UART0_PINS ((1 << 22) | (1 << 23)) |
| |
| #define GPF_SD0_FUNC 2 |
| #define GPF_SD0_PINS 0x3f /* PF0 thru PF5 */ |
| #define GPH1_SD0_DET_FUNC 5 |
| |
| static void cubieboard_set_sys_clock(void) |
| { |
| u32 reg32; |
| struct a10_ccm *ccm = (void *)A1X_CCM_BASE; |
| |
| /* Switch CPU clock to main oscillator */ |
| write32(&ccm->cpu_ahb_apb0_cfg, CPU_AHB_APB0_DEFAULT); |
| |
| /* Configure the PLL1. The value is the same one used by u-boot |
| * P = 1, N = 16, K = 1, M = 1 --> Output = 384 MHz |
| */ |
| write32(&ccm->pll1_cfg, 0xa1005000); |
| |
| /* FIXME: Delay to wait for PLL to lock */ |
| u32 wait = 1000; |
| while (--wait); |
| |
| /* Switch CPU to PLL clock */ |
| reg32 = read32(&ccm->cpu_ahb_apb0_cfg); |
| reg32 &= ~CPU_CLK_SRC_MASK; |
| reg32 |= CPU_CLK_SRC_PLL1; |
| write32(&ccm->cpu_ahb_apb0_cfg, reg32); |
| } |
| |
| static void cubieboard_setup_clocks(void) |
| { |
| struct a10_ccm *ccm = (void *)A1X_CCM_BASE; |
| |
| cubieboard_set_sys_clock(); |
| /* Configure the clock source for APB1. This drives our UART */ |
| write32(&ccm->apb1_clk_div_cfg, |
| APB1_CLK_SRC_OSC24M | APB1_RAT_N(0) | APB1_RAT_M(0)); |
| |
| /* Configure the clock for SD0 */ |
| write32(&ccm->sd0_clk_cfg, |
| SDx_CLK_GATE | SDx_CLK_SRC_OSC24M | SDx_RAT_EXP_N(0) | SDx_RAT_M(1)); |
| |
| /* Enable clock to SD0 */ |
| a1x_periph_clock_enable(A1X_CLKEN_MMC0); |
| |
| } |
| |
| static void cubieboard_setup_gpios(void) |
| { |
| /* Mux Status LED pins */ |
| gpio_set_multipin_func(GPH, GPH_STATUS_LEDS, GPIO_PIN_FUNC_OUTPUT); |
| /* Turn on green LED to let user know we're executing coreboot code */ |
| gpio_set(GPH, GPH_LED2_PIN_NO); |
| |
| /* Mux UART pins */ |
| gpio_set_multipin_func(GPB, GPB_UART0_PINS, GPB_UART0_FUNC); |
| |
| /* Mux SD pins */ |
| gpio_set_multipin_func(GPF, GPF_SD0_PINS, GPF_SD0_FUNC); |
| gpio_set_pin_func(GPH, 1, GPH1_SD0_DET_FUNC); |
| } |
| |
| static void cubieboard_enable_uart(void) |
| { |
| a1x_periph_clock_enable(A1X_CLKEN_UART0); |
| } |
| |
| static void cubieboard_raminit(void) |
| { |
| struct dram_para dram_para = { |
| .clock = 480, |
| .type = 3, |
| .rank_num = 1, |
| .density = 4096, |
| .io_width = 16, |
| .bus_width = 32, |
| .cas = 6, |
| .zq = 123, |
| .odt_en = 0, |
| .size = 1024, |
| .tpr0 = 0x30926692, |
| .tpr1 = 0x1090, |
| .tpr2 = 0x1a0c8, |
| .tpr3 = 0, |
| .tpr4 = 0, |
| .tpr5 = 0, |
| .emr1 = 0, |
| .emr2 = 0, |
| .emr3 = 0, |
| }; |
| |
| dramc_init(&dram_para); |
| |
| /* FIXME: ram_check does not compile for ARM, |
| * and we didn't init console yet |
| */ |
| ////void *const test_base = (void *)A1X_DRAM_BASE; |
| ////ram_check((u32)test_base, (u32)test_base + 0x1000); |
| } |
| |
| void bootblock_mainboard_init(void) |
| { |
| /* A10 Timer init uses the 24MHz clock, not PLLs, so we can init it very |
| * early on to get udelay, which is used almost everywhere else. |
| */ |
| init_timer(); |
| |
| cubieboard_setup_clocks(); |
| cubieboard_setup_gpios(); |
| cubieboard_enable_uart(); |
| |
| cubieboard_raminit(); |
| } |