| /* |
| * Copyright (C) 2008-2013 Eric Jarrige <eric.jarrige@armadeus.org> |
| * |
| * based on the files by |
| * Sascha Hauer, Pengutronix |
| * |
| * SPDX-License-Identifier: GPL-2.0+ |
| */ |
| |
| #include <common.h> |
| #include <environment.h> |
| #include <jffs2/jffs2.h> |
| #include <nand.h> |
| #include <netdev.h> |
| #include <asm/io.h> |
| #include <asm/arch/imx-regs.h> |
| #include <asm/arch/gpio.h> |
| #include <asm/gpio.h> |
| #include <linux/errno.h> |
| #include "apf27.h" |
| #include "crc.h" |
| #include "fpga.h" |
| |
| DECLARE_GLOBAL_DATA_PTR; |
| |
| /* |
| * Fuse bank 1 row 8 is "reserved for future use" and therefore available for |
| * customer use. The APF27 board uses this fuse to store the board revision: |
| * 0: initial board revision |
| * 1: first revision - Presence of the second RAM chip on the board is blown in |
| * fuse bank 1 row 9 bit 0 - No hardware change |
| * N: to be defined |
| */ |
| static u32 get_board_rev(void) |
| { |
| struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; |
| |
| return readl(&iim->bank[1].fuse_regs[8]); |
| } |
| |
| /* |
| * Fuse bank 1 row 9 is "reserved for future use" and therefore available for |
| * customer use. The APF27 board revision 1 uses the bit 0 to permanently store |
| * the presence of the second RAM chip |
| * 0: AFP27 with 1 RAM of 64 MiB |
| * 1: AFP27 with 2 RAM chips of 64 MiB each (128MB) |
| */ |
| static int get_num_ram_bank(void) |
| { |
| struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; |
| int nr_dram_banks = 1; |
| |
| if ((get_board_rev() > 0) && (CONFIG_NR_DRAM_BANKS > 1)) |
| nr_dram_banks += readl(&iim->bank[1].fuse_regs[9]) & 0x01; |
| else |
| nr_dram_banks = CONFIG_NR_DRAM_POPULATED; |
| |
| return nr_dram_banks; |
| } |
| |
| static void apf27_port_init(int port, u32 gpio_dr, u32 ocr1, u32 ocr2, |
| u32 iconfa1, u32 iconfa2, u32 iconfb1, u32 iconfb2, |
| u32 icr1, u32 icr2, u32 imr, u32 gpio_dir, u32 gpr, |
| u32 puen, u32 gius) |
| { |
| struct gpio_port_regs *regs = (struct gpio_port_regs *)IMX_GPIO_BASE; |
| |
| writel(gpio_dr, ®s->port[port].gpio_dr); |
| writel(ocr1, ®s->port[port].ocr1); |
| writel(ocr2, ®s->port[port].ocr2); |
| writel(iconfa1, ®s->port[port].iconfa1); |
| writel(iconfa2, ®s->port[port].iconfa2); |
| writel(iconfb1, ®s->port[port].iconfb1); |
| writel(iconfb2, ®s->port[port].iconfb2); |
| writel(icr1, ®s->port[port].icr1); |
| writel(icr2, ®s->port[port].icr2); |
| writel(imr, ®s->port[port].imr); |
| writel(gpio_dir, ®s->port[port].gpio_dir); |
| writel(gpr, ®s->port[port].gpr); |
| writel(puen, ®s->port[port].puen); |
| writel(gius, ®s->port[port].gius); |
| } |
| |
| #define APF27_PORT_INIT(n) apf27_port_init(PORT##n, ACFG_DR_##n##_VAL, \ |
| ACFG_OCR1_##n##_VAL, ACFG_OCR2_##n##_VAL, ACFG_ICFA1_##n##_VAL, \ |
| ACFG_ICFA2_##n##_VAL, ACFG_ICFB1_##n##_VAL, ACFG_ICFB2_##n##_VAL, \ |
| ACFG_ICR1_##n##_VAL, ACFG_ICR2_##n##_VAL, ACFG_IMR_##n##_VAL, \ |
| ACFG_DDIR_##n##_VAL, ACFG_GPR_##n##_VAL, ACFG_PUEN_##n##_VAL, \ |
| ACFG_GIUS_##n##_VAL) |
| |
| static void apf27_iomux_init(void) |
| { |
| APF27_PORT_INIT(A); |
| APF27_PORT_INIT(B); |
| APF27_PORT_INIT(C); |
| APF27_PORT_INIT(D); |
| APF27_PORT_INIT(E); |
| APF27_PORT_INIT(F); |
| } |
| |
| static int apf27_devices_init(void) |
| { |
| int i; |
| unsigned int mode[] = { |
| PC5_PF_I2C2_DATA, |
| PC6_PF_I2C2_CLK, |
| PD17_PF_I2C_DATA, |
| PD18_PF_I2C_CLK, |
| }; |
| |
| for (i = 0; i < ARRAY_SIZE(mode); i++) |
| imx_gpio_mode(mode[i]); |
| |
| #ifdef CONFIG_MXC_UART |
| mx27_uart1_init_pins(); |
| #endif |
| |
| #ifdef CONFIG_FEC_MXC |
| mx27_fec_init_pins(); |
| #endif |
| |
| #ifdef CONFIG_MMC_MXC |
| mx27_sd2_init_pins(); |
| imx_gpio_mode((GPIO_PORTF | GPIO_OUT | GPIO_PUEN | GPIO_GPIO | 16)); |
| gpio_request(PC_PWRON, "pc_pwron"); |
| gpio_set_value(PC_PWRON, 1); |
| #endif |
| return 0; |
| } |
| |
| static void apf27_setup_csx(void) |
| { |
| struct weim_regs *weim = (struct weim_regs *)IMX_WEIM_BASE; |
| |
| writel(ACFG_CS0U_VAL, &weim->cs0u); |
| writel(ACFG_CS0L_VAL, &weim->cs0l); |
| writel(ACFG_CS0A_VAL, &weim->cs0a); |
| |
| writel(ACFG_CS1U_VAL, &weim->cs1u); |
| writel(ACFG_CS1L_VAL, &weim->cs1l); |
| writel(ACFG_CS1A_VAL, &weim->cs1a); |
| |
| writel(ACFG_CS2U_VAL, &weim->cs2u); |
| writel(ACFG_CS2L_VAL, &weim->cs2l); |
| writel(ACFG_CS2A_VAL, &weim->cs2a); |
| |
| writel(ACFG_CS3U_VAL, &weim->cs3u); |
| writel(ACFG_CS3L_VAL, &weim->cs3l); |
| writel(ACFG_CS3A_VAL, &weim->cs3a); |
| |
| writel(ACFG_CS4U_VAL, &weim->cs4u); |
| writel(ACFG_CS4L_VAL, &weim->cs4l); |
| writel(ACFG_CS4A_VAL, &weim->cs4a); |
| |
| writel(ACFG_CS5U_VAL, &weim->cs5u); |
| writel(ACFG_CS5L_VAL, &weim->cs5l); |
| writel(ACFG_CS5A_VAL, &weim->cs5a); |
| |
| writel(ACFG_EIM_VAL, &weim->eim); |
| } |
| |
| static void apf27_setup_port(void) |
| { |
| struct system_control_regs *system = |
| (struct system_control_regs *)IMX_SYSTEM_CTL_BASE; |
| |
| writel(ACFG_FMCR_VAL, &system->fmcr); |
| } |
| |
| int board_init(void) |
| { |
| gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100; |
| |
| apf27_setup_csx(); |
| apf27_setup_port(); |
| apf27_iomux_init(); |
| apf27_devices_init(); |
| #if defined(CONFIG_FPGA) |
| APF27_init_fpga(); |
| #endif |
| |
| |
| return 0; |
| } |
| |
| int dram_init(void) |
| { |
| gd->ram_size = get_ram_size((void *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE); |
| if (get_num_ram_bank() > 1) |
| gd->ram_size += get_ram_size((void *)PHYS_SDRAM_2, |
| PHYS_SDRAM_2_SIZE); |
| |
| return 0; |
| } |
| |
| int dram_init_banksize(void) |
| { |
| gd->bd->bi_dram[0].start = PHYS_SDRAM_1; |
| gd->bd->bi_dram[0].size = get_ram_size((void *)PHYS_SDRAM_1, |
| PHYS_SDRAM_1_SIZE); |
| gd->bd->bi_dram[1].start = PHYS_SDRAM_2; |
| if (get_num_ram_bank() > 1) |
| gd->bd->bi_dram[1].size = get_ram_size((void *)PHYS_SDRAM_2, |
| PHYS_SDRAM_2_SIZE); |
| else |
| gd->bd->bi_dram[1].size = 0; |
| |
| return 0; |
| } |
| |
| ulong board_get_usable_ram_top(ulong total_size) |
| { |
| ulong ramtop; |
| |
| if (get_num_ram_bank() > 1) |
| ramtop = PHYS_SDRAM_2 + get_ram_size((void *)PHYS_SDRAM_2, |
| PHYS_SDRAM_2_SIZE); |
| else |
| ramtop = PHYS_SDRAM_1 + get_ram_size((void *)PHYS_SDRAM_1, |
| PHYS_SDRAM_1_SIZE); |
| |
| return ramtop; |
| } |
| |
| int checkboard(void) |
| { |
| printf("Board: Armadeus APF27 revision %d\n", get_board_rev()); |
| return 0; |
| } |
| |
| #ifdef CONFIG_SPL_BUILD |
| inline void hang(void) |
| { |
| for (;;) |
| ; |
| } |
| |
| void board_init_f(ulong bootflag) |
| { |
| /* |
| * copy ourselves from where we are running to where we were |
| * linked at. Use ulong pointers as all addresses involved |
| * are 4-byte-aligned. |
| */ |
| ulong *start_ptr, *end_ptr, *link_ptr, *run_ptr, *dst; |
| asm volatile ("ldr %0, =_start" : "=r"(start_ptr)); |
| asm volatile ("ldr %0, =_end" : "=r"(end_ptr)); |
| asm volatile ("ldr %0, =board_init_f" : "=r"(link_ptr)); |
| asm volatile ("adr %0, board_init_f" : "=r"(run_ptr)); |
| for (dst = start_ptr; dst < end_ptr; dst++) |
| *dst = *(dst+(run_ptr-link_ptr)); |
| |
| /* |
| * branch to nand_boot's link-time address. |
| */ |
| asm volatile("ldr pc, =nand_boot"); |
| } |
| #endif /* CONFIG_SPL_BUILD */ |