Vadim Bendebury | 476f731 | 2014-04-08 18:45:46 -0700 | [diff] [blame^] | 1 | |
| 2 | /* * Copyright (c) 2012 - 2013 The Linux Foundation. All rights reserved.* */ |
| 3 | |
| 4 | #include <common.h> |
| 5 | #include <linux/mtd/ipq_nand.h> |
| 6 | #include <asm/arch-ipq806x/gpio.h> |
| 7 | #include <asm/global_data.h> |
| 8 | #include <asm/io.h> |
| 9 | #include <asm/arch-ipq806x/clock.h> |
| 10 | #include <asm/arch-ipq806x/ebi2.h> |
| 11 | #include <asm/arch-ipq806x/smem.h> |
| 12 | #include <asm/errno.h> |
| 13 | #include "ipq806x_board_param.h" |
| 14 | #include "ipq806x_cdp.h" |
| 15 | #include <asm/arch-ipq806x/nss/msm_ipq806x_gmac.h> |
| 16 | #include <asm/arch-ipq806x/timer.h> |
| 17 | #include <nand.h> |
| 18 | #include <phy.h> |
| 19 | |
| 20 | DECLARE_GLOBAL_DATA_PTR; |
| 21 | |
| 22 | |
| 23 | /* Watchdog bite time set to default reset value */ |
| 24 | #define RESET_WDT_BITE_TIME 0x31F3 |
| 25 | |
| 26 | /* Watchdog bark time value is ketp larger than the watchdog timeout |
| 27 | * of 0x31F3, effectively disabling the watchdog bark interrupt |
| 28 | */ |
| 29 | #define RESET_WDT_BARK_TIME (5 * RESET_WDT_BITE_TIME) |
| 30 | |
| 31 | /* |
| 32 | * If SMEM is not found, we provide a value, that will prevent the |
| 33 | * environment from being written to random location in the flash. |
| 34 | * |
| 35 | * NAND: In the case of NAND, we do this by setting ENV_RANGE to |
| 36 | * zero. If ENV_RANGE < ENV_SIZE, then environment is not written. |
| 37 | * |
| 38 | * SPI Flash: In the case of SPI Flash, we do this by setting the |
| 39 | * flash_index to -1. |
| 40 | */ |
| 41 | |
| 42 | loff_t board_env_offset; |
| 43 | loff_t board_env_range; |
| 44 | extern int nand_env_device; |
| 45 | |
| 46 | board_ipq806x_params_t *gboard_param; |
| 47 | extern int ipq_gmac_eth_initialize(const char *ethaddr); |
| 48 | uchar ipq_def_enetaddr[6] = {0x00, 0x03, 0x7F, 0xBA, 0xDB, 0xAD}; |
| 49 | |
| 50 | /******************************************************* |
| 51 | Function description: Board specific initialization. |
| 52 | I/P : None |
| 53 | O/P : integer, 0 - no error. |
| 54 | |
| 55 | ********************************************************/ |
| 56 | static board_ipq806x_params_t *get_board_param(unsigned int machid) |
| 57 | { |
| 58 | unsigned int index = 0; |
| 59 | |
| 60 | for (index = 0; index < NUM_IPQ806X_BOARDS; index++) { |
| 61 | if (machid == board_params[index].machid) |
| 62 | return &board_params[index]; |
| 63 | } |
| 64 | BUG_ON(index == NUM_IPQ806X_BOARDS); |
| 65 | printf("cdp: Invalid machine id 0x%x\n", machid); |
| 66 | for (;;); |
| 67 | } |
| 68 | |
| 69 | int board_init() |
| 70 | { |
| 71 | int ret; |
| 72 | uint32_t start_blocks; |
| 73 | uint32_t size_blocks; |
| 74 | loff_t board_env_size; |
| 75 | ipq_smem_flash_info_t *sfi = &ipq_smem_flash_info; |
| 76 | |
| 77 | /* |
| 78 | * after relocation gboard_param is reset to NULL |
| 79 | * initialize again |
| 80 | */ |
| 81 | gd->bd->bi_boot_params = IPQ_BOOT_PARAMS_ADDR; |
| 82 | gd->bd->bi_arch_number = smem_get_board_machtype(); |
| 83 | gboard_param = get_board_param(gd->bd->bi_arch_number); |
| 84 | |
| 85 | /* |
| 86 | * Should be inited, before env_relocate() is called, |
| 87 | * since env. offset is obtained from SMEM. |
| 88 | */ |
| 89 | ret = smem_ptable_init(); |
| 90 | if (ret < 0) { |
| 91 | printf("cdp: SMEM init failed\n"); |
| 92 | return ret; |
| 93 | } |
| 94 | |
| 95 | ret = smem_get_boot_flash(&sfi->flash_type, |
| 96 | &sfi->flash_index, |
| 97 | &sfi->flash_chip_select, |
| 98 | &sfi->flash_block_size); |
| 99 | if (ret < 0) { |
| 100 | printf("cdp: get boot flash failed\n"); |
| 101 | return ret; |
| 102 | } |
| 103 | |
| 104 | if (sfi->flash_type == SMEM_BOOT_NAND_FLASH) { |
| 105 | nand_env_device = CONFIG_IPQ_NAND_NAND_INFO_IDX; |
| 106 | } else if (sfi->flash_type == SMEM_BOOT_SPI_FLASH) { |
| 107 | nand_env_device = CONFIG_IPQ_SPI_NAND_INFO_IDX; |
| 108 | } else { |
| 109 | printf("BUG: unsupported flash type : %d\n", sfi->flash_type); |
| 110 | BUG(); |
| 111 | } |
| 112 | |
| 113 | ret = smem_getpart("0:APPSBLENV", &start_blocks, &size_blocks); |
| 114 | if (ret < 0) { |
| 115 | printf("cdp: get environment part failed\n"); |
| 116 | return ret; |
| 117 | } |
| 118 | |
| 119 | board_env_offset = ((loff_t) sfi->flash_block_size) * start_blocks; |
| 120 | board_env_size = ((loff_t) sfi->flash_block_size) * size_blocks; |
| 121 | board_env_range = CONFIG_ENV_SIZE; |
| 122 | BUG_ON(board_env_size < CONFIG_ENV_SIZE); |
| 123 | |
| 124 | return 0; |
| 125 | } |
| 126 | |
| 127 | void enable_caches(void) |
| 128 | { |
| 129 | icache_enable(); |
| 130 | /* When dcache is enabled it causes the tftp timeout CR is raised CR.No: 513868. |
| 131 | * disabing dcache now to make tftp to work */ |
| 132 | #if (CONFIG_IPQ_CACHE_ENABLE == 1) |
| 133 | dcache_enable(); |
| 134 | #endif |
| 135 | } |
| 136 | |
| 137 | |
| 138 | /******************************************************* |
| 139 | Function description: DRAM initialization. |
| 140 | I/P : None |
| 141 | O/P : integer, 0 - no error. |
| 142 | |
| 143 | ********************************************************/ |
| 144 | |
| 145 | int dram_init(void) |
| 146 | { |
| 147 | struct smem_ram_ptable rtable; |
| 148 | int i; |
| 149 | int mx = ARRAY_SIZE(rtable.parts); |
| 150 | |
| 151 | if (smem_ram_ptable_init(&rtable) > 0) { |
| 152 | gd->ram_size = 0; |
| 153 | for (i = 0; i < mx; i++) { |
| 154 | if (rtable.parts[i].category == RAM_PARTITION_SDRAM |
| 155 | && rtable.parts[i].type == RAM_PARTITION_SYS_MEMORY) { |
| 156 | gd->ram_size += rtable.parts[i].size; |
| 157 | } |
| 158 | } |
| 159 | gboard_param->ddr_size = gd->ram_size; |
| 160 | } else { |
| 161 | gd->ram_size = gboard_param->ddr_size; |
| 162 | } |
| 163 | return 0; |
| 164 | } |
| 165 | |
| 166 | /******************************************************* |
| 167 | Function description: initi Dram Bank size |
| 168 | I/P : None |
| 169 | O/P : integer, 0 - no error. |
| 170 | |
| 171 | ********************************************************/ |
| 172 | |
| 173 | |
| 174 | void dram_init_banksize(void) |
| 175 | { |
| 176 | gd->bd->bi_dram[0].start = IPQ_KERNEL_START_ADDR; |
| 177 | gd->bd->bi_dram[0].size = gboard_param->ddr_size - GENERATED_IPQ_RESERVE_SIZE; |
| 178 | |
| 179 | } |
| 180 | |
| 181 | /********************************************************** |
| 182 | Function description: Display board information on console. |
| 183 | I/P : None |
| 184 | O/P : integer, 0 - no error. |
| 185 | |
| 186 | **********************************************************/ |
| 187 | |
| 188 | #ifdef CONFIG_DISPLAY_BOARDINFO |
| 189 | int checkboard(void) |
| 190 | { |
| 191 | printf("Board: %s\n", sysinfo.board_string); |
| 192 | return 0; |
| 193 | } |
| 194 | #endif /* CONFIG_DISPLAY_BOARDINFO */ |
| 195 | |
| 196 | void reset_cpu(ulong addr) |
| 197 | { |
| 198 | printf("\nResetting with watch dog!\n"); |
| 199 | |
| 200 | writel(0, APCS_WDT0_EN); |
| 201 | writel(1, APCS_WDT0_RST); |
| 202 | writel(RESET_WDT_BARK_TIME, APCS_WDT0_BARK_TIME); |
| 203 | writel(RESET_WDT_BITE_TIME, APCS_WDT0_BITE_TIME); |
| 204 | writel(1, APCS_WDT0_EN); |
| 205 | writel(1, APCS_WDT0_CPU0_WDOG_EXPIRED_ENABLE); |
| 206 | |
| 207 | for(;;); |
| 208 | } |
| 209 | |
| 210 | static void configure_nand_gpio(void) |
| 211 | { |
| 212 | /* EBI2 CS, CLE, ALE, WE, OE */ |
| 213 | gpio_tlmm_config(34, 1, 0, GPIO_NO_PULL, GPIO_10MA, GPIO_DISABLE); |
| 214 | gpio_tlmm_config(35, 1, 0, GPIO_NO_PULL, GPIO_10MA, GPIO_DISABLE); |
| 215 | gpio_tlmm_config(36, 1, 0, GPIO_NO_PULL, GPIO_10MA, GPIO_DISABLE); |
| 216 | gpio_tlmm_config(37, 1, 0, GPIO_NO_PULL, GPIO_10MA, GPIO_DISABLE); |
| 217 | gpio_tlmm_config(38, 1, 0, GPIO_NO_PULL, GPIO_10MA, GPIO_DISABLE); |
| 218 | |
| 219 | /* EBI2 BUSY */ |
| 220 | gpio_tlmm_config(39, 1, 0, GPIO_PULL_UP, GPIO_10MA, GPIO_DISABLE); |
| 221 | |
| 222 | /* EBI2 D7 - D0 */ |
| 223 | gpio_tlmm_config(40, 1, 0, GPIO_KEEPER, GPIO_10MA, GPIO_DISABLE); |
| 224 | gpio_tlmm_config(41, 1, 0, GPIO_KEEPER, GPIO_10MA, GPIO_DISABLE); |
| 225 | gpio_tlmm_config(42, 1, 0, GPIO_KEEPER, GPIO_10MA, GPIO_DISABLE); |
| 226 | gpio_tlmm_config(43, 1, 0, GPIO_KEEPER, GPIO_10MA, GPIO_DISABLE); |
| 227 | gpio_tlmm_config(44, 1, 0, GPIO_KEEPER, GPIO_10MA, GPIO_DISABLE); |
| 228 | gpio_tlmm_config(45, 1, 0, GPIO_KEEPER, GPIO_10MA, GPIO_DISABLE); |
| 229 | gpio_tlmm_config(46, 1, 0, GPIO_KEEPER, GPIO_10MA, GPIO_DISABLE); |
| 230 | gpio_tlmm_config(47, 1, 0, GPIO_KEEPER, GPIO_10MA, GPIO_DISABLE); |
| 231 | } |
| 232 | |
| 233 | void board_nand_init(void) |
| 234 | { |
| 235 | struct ebi2cr_regs *ebi2_regs; |
| 236 | extern int ipq_spi_init(void); |
| 237 | |
| 238 | if (gboard_param->flashdesc != NOR_MMC) { |
| 239 | |
| 240 | ebi2_regs = (struct ebi2cr_regs *) EBI2CR_BASE; |
| 241 | |
| 242 | nand_clock_config(); |
| 243 | configure_nand_gpio(); |
| 244 | |
| 245 | /* NAND Flash is connected to CS0 */ |
| 246 | clrsetbits_le32(&ebi2_regs->chip_select_cfg0, CS0_CFG_MASK, |
| 247 | CS0_CFG_SERIAL_FLASH_DEVICE); |
| 248 | |
| 249 | ipq_nand_init(IPQ_NAND_LAYOUT_LINUX); |
| 250 | } |
| 251 | |
| 252 | ipq_spi_init(); |
| 253 | } |
| 254 | |
| 255 | void ipq_get_part_details(void) |
| 256 | { |
| 257 | int ret, i; |
| 258 | uint32_t start; /* block number */ |
| 259 | uint32_t size; /* no. of blocks */ |
| 260 | |
| 261 | ipq_smem_flash_info_t *smem = &ipq_smem_flash_info; |
| 262 | |
| 263 | struct { char *name; ipq_part_entry_t *part; } entries[] = { |
| 264 | { "0:HLOS", &smem->hlos }, |
| 265 | { "0:NSS0", &smem->nss[0] }, |
| 266 | { "0:NSS1", &smem->nss[1] }, |
| 267 | }; |
| 268 | |
| 269 | for (i = 0; i < ARRAY_SIZE(entries); i++) { |
| 270 | ret = smem_getpart(entries[i].name, &start, &size); |
| 271 | if (ret < 0) { |
| 272 | ipq_part_entry_t *part = entries[i].part; |
| 273 | printf("cdp: get part failed for %s\n", entries[i].name); |
| 274 | part->offset = 0xBAD0FF5E; |
| 275 | part->size = 0xBAD0FF5E; |
| 276 | } |
| 277 | ipq_set_part_entry(smem, entries[i].part, start, size); |
| 278 | } |
| 279 | |
| 280 | return; |
| 281 | } |
| 282 | |
| 283 | /* |
| 284 | * Get the kernel partition details from SMEM and populate the, |
| 285 | * environment with sufficient information for the boot command to |
| 286 | * load and execute the kernel. |
| 287 | */ |
| 288 | int board_late_init(void) |
| 289 | { |
| 290 | unsigned int machid; |
| 291 | |
| 292 | ipq_get_part_details(); |
| 293 | |
| 294 | /* get machine type from SMEM and set in env */ |
| 295 | machid = gd->bd->bi_arch_number; |
| 296 | if (machid != 0) { |
| 297 | setenv_addr("machid", (void *)machid); |
| 298 | gd->bd->bi_arch_number = machid; |
| 299 | } |
| 300 | |
| 301 | return 0; |
| 302 | } |
| 303 | |
| 304 | /* |
| 305 | * This function is called in the very beginning. |
| 306 | * Retreive the machtype info from SMEM and map the board specific |
| 307 | * parameters. Shared memory region at Dram address 0x40400000 |
| 308 | * contains the machine id/ board type data polulated by SBL. |
| 309 | */ |
| 310 | int board_early_init_f(void) |
| 311 | { |
| 312 | gboard_param = get_board_param(smem_get_board_machtype()); |
| 313 | |
| 314 | return 0; |
| 315 | } |
| 316 | |
| 317 | /* |
| 318 | * Gets the ethernet address from the ART partition table and return the value |
| 319 | */ |
| 320 | int get_eth_mac_address(uchar *enetaddr, uint no_of_macs) |
| 321 | { |
| 322 | s32 ret; |
| 323 | u32 start_blocks; |
| 324 | u32 size_blocks; |
| 325 | u32 length = (6 * no_of_macs); |
| 326 | u32 flash_type; |
| 327 | loff_t art_offset; |
| 328 | |
| 329 | if (ipq_smem_flash_info.flash_type == SMEM_BOOT_SPI_FLASH) |
| 330 | flash_type = CONFIG_IPQ_SPI_NAND_INFO_IDX; |
| 331 | else if (ipq_smem_flash_info.flash_type == SMEM_BOOT_NAND_FLASH) |
| 332 | flash_type = CONFIG_IPQ_NAND_NAND_INFO_IDX; |
| 333 | else { |
| 334 | printf("Unknown flash type\n"); |
| 335 | return -EINVAL; |
| 336 | } |
| 337 | |
| 338 | ret = smem_getpart("0:ART", &start_blocks, &size_blocks); |
| 339 | if (ret < 0) { |
| 340 | printf("No ART partition found\n"); |
| 341 | return ret; |
| 342 | } |
| 343 | |
| 344 | /* |
| 345 | * ART partition 0th position (6 * 4) 24 bytes will contain the |
| 346 | * 4 MAC Address. First 0-5 bytes for GMAC0, Second 6-11 bytes |
| 347 | * for GMAC1, 12-17 bytes for GMAC2 and 18-23 bytes for GMAC3 |
| 348 | */ |
| 349 | art_offset = ((loff_t) ipq_smem_flash_info.flash_block_size * start_blocks); |
| 350 | |
| 351 | ret = nand_read(&nand_info[flash_type], art_offset, &length, enetaddr); |
| 352 | if (ret < 0) |
| 353 | printf("ART partition read failed..\n"); |
| 354 | return ret; |
| 355 | } |
| 356 | |
| 357 | void ipq_configure_gpio(gpio_func_data_t *gpio, uint count) |
| 358 | { |
| 359 | int i; |
| 360 | |
| 361 | for (i = 0; i < count; i++) { |
| 362 | gpio_tlmm_config(gpio->gpio, gpio->func, gpio->dir, |
| 363 | gpio->pull, gpio->drvstr, gpio->enable); |
| 364 | gpio++; |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | int board_eth_init(bd_t *bis) |
| 369 | { |
| 370 | int status; |
| 371 | |
| 372 | ipq_gmac_common_init(gboard_param->gmac_cfg); |
| 373 | |
| 374 | ipq_configure_gpio(gboard_param->gmac_gpio, |
| 375 | gboard_param->gmac_gpio_count); |
| 376 | |
| 377 | status = ipq_gmac_init(gboard_param->gmac_cfg); |
| 378 | return status; |
| 379 | } |