1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2008-2013 Eric Jarrige <eric.jarrige@armadeus.org> 4 * 5 * based on the files by 6 * Sascha Hauer, Pengutronix 7 */ 8 9 #include <common.h> 10 #include <environment.h> 11 #include <jffs2/jffs2.h> 12 #include <nand.h> 13 #include <netdev.h> 14 #include <asm/io.h> 15 #include <asm/arch/imx-regs.h> 16 #include <asm/arch/gpio.h> 17 #include <asm/gpio.h> 18 #include <linux/errno.h> 19 #include "apf27.h" 20 #include "crc.h" 21 #include "fpga.h" 22 23 DECLARE_GLOBAL_DATA_PTR; 24 25 /* 26 * Fuse bank 1 row 8 is "reserved for future use" and therefore available for 27 * customer use. The APF27 board uses this fuse to store the board revision: 28 * 0: initial board revision 29 * 1: first revision - Presence of the second RAM chip on the board is blown in 30 * fuse bank 1 row 9 bit 0 - No hardware change 31 * N: to be defined 32 */ 33 static u32 get_board_rev(void) 34 { 35 struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; 36 37 return readl(&iim->bank[1].fuse_regs[8]); 38 } 39 40 /* 41 * Fuse bank 1 row 9 is "reserved for future use" and therefore available for 42 * customer use. The APF27 board revision 1 uses the bit 0 to permanently store 43 * the presence of the second RAM chip 44 * 0: AFP27 with 1 RAM of 64 MiB 45 * 1: AFP27 with 2 RAM chips of 64 MiB each (128MB) 46 */ 47 static int get_num_ram_bank(void) 48 { 49 struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; 50 int nr_dram_banks = 1; 51 52 if ((get_board_rev() > 0) && (CONFIG_NR_DRAM_BANKS > 1)) 53 nr_dram_banks += readl(&iim->bank[1].fuse_regs[9]) & 0x01; 54 else 55 nr_dram_banks = CONFIG_NR_DRAM_POPULATED; 56 57 return nr_dram_banks; 58 } 59 60 static void apf27_port_init(int port, u32 gpio_dr, u32 ocr1, u32 ocr2, 61 u32 iconfa1, u32 iconfa2, u32 iconfb1, u32 iconfb2, 62 u32 icr1, u32 icr2, u32 imr, u32 gpio_dir, u32 gpr, 63 u32 puen, u32 gius) 64 { 65 struct gpio_port_regs *regs = (struct gpio_port_regs *)IMX_GPIO_BASE; 66 67 writel(gpio_dr, ®s->port[port].gpio_dr); 68 writel(ocr1, ®s->port[port].ocr1); 69 writel(ocr2, ®s->port[port].ocr2); 70 writel(iconfa1, ®s->port[port].iconfa1); 71 writel(iconfa2, ®s->port[port].iconfa2); 72 writel(iconfb1, ®s->port[port].iconfb1); 73 writel(iconfb2, ®s->port[port].iconfb2); 74 writel(icr1, ®s->port[port].icr1); 75 writel(icr2, ®s->port[port].icr2); 76 writel(imr, ®s->port[port].imr); 77 writel(gpio_dir, ®s->port[port].gpio_dir); 78 writel(gpr, ®s->port[port].gpr); 79 writel(puen, ®s->port[port].puen); 80 writel(gius, ®s->port[port].gius); 81 } 82 83 #define APF27_PORT_INIT(n) apf27_port_init(PORT##n, ACFG_DR_##n##_VAL, \ 84 ACFG_OCR1_##n##_VAL, ACFG_OCR2_##n##_VAL, ACFG_ICFA1_##n##_VAL, \ 85 ACFG_ICFA2_##n##_VAL, ACFG_ICFB1_##n##_VAL, ACFG_ICFB2_##n##_VAL, \ 86 ACFG_ICR1_##n##_VAL, ACFG_ICR2_##n##_VAL, ACFG_IMR_##n##_VAL, \ 87 ACFG_DDIR_##n##_VAL, ACFG_GPR_##n##_VAL, ACFG_PUEN_##n##_VAL, \ 88 ACFG_GIUS_##n##_VAL) 89 90 static void apf27_iomux_init(void) 91 { 92 APF27_PORT_INIT(A); 93 APF27_PORT_INIT(B); 94 APF27_PORT_INIT(C); 95 APF27_PORT_INIT(D); 96 APF27_PORT_INIT(E); 97 APF27_PORT_INIT(F); 98 } 99 100 static int apf27_devices_init(void) 101 { 102 int i; 103 unsigned int mode[] = { 104 PC5_PF_I2C2_DATA, 105 PC6_PF_I2C2_CLK, 106 PD17_PF_I2C_DATA, 107 PD18_PF_I2C_CLK, 108 }; 109 110 for (i = 0; i < ARRAY_SIZE(mode); i++) 111 imx_gpio_mode(mode[i]); 112 113 #ifdef CONFIG_MXC_UART 114 mx27_uart1_init_pins(); 115 #endif 116 117 #ifdef CONFIG_FEC_MXC 118 mx27_fec_init_pins(); 119 #endif 120 121 #ifdef CONFIG_MMC_MXC 122 mx27_sd2_init_pins(); 123 imx_gpio_mode((GPIO_PORTF | GPIO_OUT | GPIO_PUEN | GPIO_GPIO | 16)); 124 gpio_request(PC_PWRON, "pc_pwron"); 125 gpio_set_value(PC_PWRON, 1); 126 #endif 127 return 0; 128 } 129 130 static void apf27_setup_csx(void) 131 { 132 struct weim_regs *weim = (struct weim_regs *)IMX_WEIM_BASE; 133 134 writel(ACFG_CS0U_VAL, &weim->cs0u); 135 writel(ACFG_CS0L_VAL, &weim->cs0l); 136 writel(ACFG_CS0A_VAL, &weim->cs0a); 137 138 writel(ACFG_CS1U_VAL, &weim->cs1u); 139 writel(ACFG_CS1L_VAL, &weim->cs1l); 140 writel(ACFG_CS1A_VAL, &weim->cs1a); 141 142 writel(ACFG_CS2U_VAL, &weim->cs2u); 143 writel(ACFG_CS2L_VAL, &weim->cs2l); 144 writel(ACFG_CS2A_VAL, &weim->cs2a); 145 146 writel(ACFG_CS3U_VAL, &weim->cs3u); 147 writel(ACFG_CS3L_VAL, &weim->cs3l); 148 writel(ACFG_CS3A_VAL, &weim->cs3a); 149 150 writel(ACFG_CS4U_VAL, &weim->cs4u); 151 writel(ACFG_CS4L_VAL, &weim->cs4l); 152 writel(ACFG_CS4A_VAL, &weim->cs4a); 153 154 writel(ACFG_CS5U_VAL, &weim->cs5u); 155 writel(ACFG_CS5L_VAL, &weim->cs5l); 156 writel(ACFG_CS5A_VAL, &weim->cs5a); 157 158 writel(ACFG_EIM_VAL, &weim->eim); 159 } 160 161 static void apf27_setup_port(void) 162 { 163 struct system_control_regs *system = 164 (struct system_control_regs *)IMX_SYSTEM_CTL_BASE; 165 166 writel(ACFG_FMCR_VAL, &system->fmcr); 167 } 168 169 int board_init(void) 170 { 171 gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100; 172 173 apf27_setup_csx(); 174 apf27_setup_port(); 175 apf27_iomux_init(); 176 apf27_devices_init(); 177 #if defined(CONFIG_FPGA) 178 APF27_init_fpga(); 179 #endif 180 181 182 return 0; 183 } 184 185 int dram_init(void) 186 { 187 gd->ram_size = get_ram_size((void *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE); 188 if (get_num_ram_bank() > 1) 189 gd->ram_size += get_ram_size((void *)PHYS_SDRAM_2, 190 PHYS_SDRAM_2_SIZE); 191 192 return 0; 193 } 194 195 int dram_init_banksize(void) 196 { 197 gd->bd->bi_dram[0].start = PHYS_SDRAM_1; 198 gd->bd->bi_dram[0].size = get_ram_size((void *)PHYS_SDRAM_1, 199 PHYS_SDRAM_1_SIZE); 200 gd->bd->bi_dram[1].start = PHYS_SDRAM_2; 201 if (get_num_ram_bank() > 1) 202 gd->bd->bi_dram[1].size = get_ram_size((void *)PHYS_SDRAM_2, 203 PHYS_SDRAM_2_SIZE); 204 else 205 gd->bd->bi_dram[1].size = 0; 206 207 return 0; 208 } 209 210 ulong board_get_usable_ram_top(ulong total_size) 211 { 212 ulong ramtop; 213 214 if (get_num_ram_bank() > 1) 215 ramtop = PHYS_SDRAM_2 + get_ram_size((void *)PHYS_SDRAM_2, 216 PHYS_SDRAM_2_SIZE); 217 else 218 ramtop = PHYS_SDRAM_1 + get_ram_size((void *)PHYS_SDRAM_1, 219 PHYS_SDRAM_1_SIZE); 220 221 return ramtop; 222 } 223 224 int checkboard(void) 225 { 226 printf("Board: Armadeus APF27 revision %d\n", get_board_rev()); 227 return 0; 228 } 229 230 #ifdef CONFIG_SPL_BUILD 231 inline void hang(void) 232 { 233 for (;;) 234 ; 235 } 236 237 void board_init_f(ulong bootflag) 238 { 239 /* 240 * copy ourselves from where we are running to where we were 241 * linked at. Use ulong pointers as all addresses involved 242 * are 4-byte-aligned. 243 */ 244 ulong *start_ptr, *end_ptr, *link_ptr, *run_ptr, *dst; 245 asm volatile ("ldr %0, =_start" : "=r"(start_ptr)); 246 asm volatile ("ldr %0, =_end" : "=r"(end_ptr)); 247 asm volatile ("ldr %0, =board_init_f" : "=r"(link_ptr)); 248 asm volatile ("adr %0, board_init_f" : "=r"(run_ptr)); 249 for (dst = start_ptr; dst < end_ptr; dst++) 250 *dst = *(dst+(run_ptr-link_ptr)); 251 252 /* 253 * branch to nand_boot's link-time address. 254 */ 255 asm volatile("ldr pc, =nand_boot"); 256 } 257 #endif /* CONFIG_SPL_BUILD */ 258