/**************************************************************************** ; ; MODULE attosetup.c ; ; DESCRIPTION This module supports Atto's dual-boot functionality for and ; FPGA image in the context of U-Boot. ; ; ; THIS PROGRAM AND THE INFORMATION CONTAINED HEREIN IS THE PROPERTY OF ; ATTO TECHNOLOGY, INC. AND SHALL NOT BE REPRODUCED, COPIED, OR USED IN ; WHOLE OR IN PART OTHER THAN AS PROVIDED FOR IN THE LICENSE AGREEMENT ; PURSUANT TO WHICH IT WAS FURNISHED. ; ; COPYRIGHT (c) ATTO TECHNOLOGY, INC. 2016 ; ALL RIGHTS RESERVED. ; *****************************************************************************/ #include #include #include #include int atto_image = IMAGE_NA; static void atto_store_reset_reason(uint32_t * store_addr); void atto_qspi_get_data(uint32_t block_num, uint32_t offset, uint32_t data_size, uint32_t * pdata); int atto_dual_boot_get_image(void); int atto_image_get(void); void atto_qspi_get_data(uint32_t block_num, uint32_t offset, uint32_t data_size, uint32_t * pdata) { struct spi_flash * pflash; uint32_t read_addr = (block_num * ATTO_QSPI_BLOCK_SIZE) + offset; /* first we need an instance of the flash to use * This is eqivalent to doing an "sf probe" at the U-Boot prompt */ pflash = spi_flash_probe(CONFIG_SF_DEFAULT_BUS, CONFIG_SF_DEFAULT_CS, CONFIG_SF_DEFAULT_SPEED, CONFIG_SF_DEFAULT_MODE); if(!pflash) { puts("attosetup: Could not get an instance of the flash. " "Spin Forever\r\n"); STALL_HERE } spi_flash_read(pflash, read_addr, data_size, pdata); } int atto_dual_boot_get_image(void) { int image_valid_a = FALSE; int image_valid_b = FALSE; FLSH_BLK flash_blk_a; FLSH_BLK flash_blk_b; PFLSH_BLK pflash_block_a = &flash_blk_a; PFLSH_BLK pflash_block_b = &flash_blk_b; uint32_t * preg_boot_oldest_image = (uint32_t *)ARRIA10_HPS_SYSMGR_ROM_ISWHANDOFF_7; atto_qspi_get_data(ATTO_IMA_COOKIE_BLOCK_NUM_A, ATTO_QSPI_BLOCK_SIZE - sizeof(FLSH_BLK), sizeof(FLSH_BLK), (uint32_t *)pflash_block_a); atto_qspi_get_data(ATTO_IMA_COOKIE_BLOCK_NUM_B, ATTO_QSPI_BLOCK_SIZE - sizeof(FLSH_BLK), sizeof(FLSH_BLK), (uint32_t *)pflash_block_b); /* Verify Cookies */ if( (pflash_block_a->wCookie == 0xCAFE) && (pflash_block_b->wCookie == 0xCAFE)) { puts("attosetup: Both cookies good.\r\n"); image_valid_a = TRUE; image_valid_b = TRUE; /* Both images are good, check the dates. */ if(pflash_block_a->dwDate < pflash_block_b->dwDate) { /* image b is newer */ puts("attosetup: Image B is newer.\r\n"); atto_image = IMAGE_B; } else if(pflash_block_b->dwDate < pflash_block_a->dwDate) { /* image a is newer */ puts("attosetup: Image A is newer.\r\n"); atto_image = IMAGE_A; } else { /* dates are the same, check the times */ if(pflash_block_a->dwTime < pflash_block_b->dwTime) { /* image b is newer */ puts("attosetup: Image B is newer.\r\n"); atto_image = IMAGE_B; } else { /* image a is newer, or we flashed both images at the same * exact time O_o */ puts("attosetup: Image A is newer.\r\n"); atto_image = IMAGE_A; } } } else if(pflash_block_a->wCookie == 0xCAFE) { /* only image a is good */ puts("attosetup: Image A's cookie is good.\r\n"); image_valid_a = TRUE; atto_image = IMAGE_A; } else if(pflash_block_b->wCookie == 0xCAFE) { /* only image b is good */ puts("attosetup: Image B's cookie is good.\r\n"); image_valid_b = TRUE; atto_image = IMAGE_B; } else { /* no good images */ atto_image = IMAGE_NA; } /* Boot oldest image support */ if((*preg_boot_oldest_image & ISWGRP_7_BOOT_OLDESTIMAGE_MASK) == ISWGRP_7_BOOT_OLDESTIMAGE_MASK) { puts("attosetup: Boot the oldest image.\r\n"); if((image_valid_a == TRUE) && (image_valid_b == TRUE)) { /* Both images are valid so change the image we plan to boot. */ if(atto_image == IMAGE_A) { atto_image = IMAGE_B; } else if(atto_image == IMAGE_B) { atto_image = IMAGE_A; } } } return atto_image; } int atto_image_get(void) { if(atto_image == IMAGE_NA) { /* we haven't already figured out which image we're booting */ puts("attosetup: Dynamically find the FPGA image.\r\n"); return atto_dual_boot_get_image(); } else if((atto_image == IMAGE_A) || (atto_image == IMAGE_B)) { /* we've done this before so just return what we already learned */ puts("attosetup: Already found the FPGA image.\r\n"); return atto_image; } else { /* we're in some weird state and should never get to this */ return IMAGE_NA; } } uint32_t atto_fpga_get_address(void) { int image_validation_success; int validation_count = FALSE; uint32_t fpga_block_number, fpga_addr; image_header_t fpga_header; puts("attosetup: Start\r\n"); atto_image_get(); if(atto_image == IMAGE_A) { puts("attosetup: Image A selected.\r\n"); fpga_block_number = ATTO_FPGA_BLOCK_NUBMER_A; } else if(atto_image == IMAGE_B) { puts("attosetup: Image B selected.\r\n"); fpga_block_number = ATTO_FPGA_BLOCK_NUBMER_B; } else { /* Neither image is good, which means we're somewhat hosed. Maybe we * have a good fpga and can get to attoboot at least. Just try A * first. */ puts("attosetup: No good IMA in flash.\r\n"); fpga_block_number = ATTO_FPGA_BLOCK_NUBMER_A; } do { /* Start with a clean slate */ puts("attosetup: Validate FPGA Image\r\n"); image_validation_success = TRUE; /* get the mkimage head off the top of the fpga */ atto_qspi_get_data(fpga_block_number, 0, sizeof(image_header_t), (uint32_t *)&fpga_header); /* Check the magic number if we're still in our pursuit of success */ if( (image_validation_success == TRUE) && !image_check_magic(&fpga_header)) { puts("attosetup: magic number check failed\r\n"); image_validation_success = FALSE; } /* Check the header crc */ if( (image_validation_success == TRUE) && !image_check_hcrc(&fpga_header)) { puts("attosetup: header crc check failed\r\n"); image_validation_success = FALSE; } if(image_validation_success == FALSE) { puts("attosetup: Failed image validation: "); memset(&fpga_header, FALSE, sizeof(image_header_t)); if(fpga_block_number == ATTO_FPGA_BLOCK_NUBMER_A) { puts("Image A\r\n"); fpga_block_number = ATTO_FPGA_BLOCK_NUBMER_B; } else if(fpga_block_number == ATTO_FPGA_BLOCK_NUBMER_B) { puts("Image B\r\n"); fpga_block_number = ATTO_FPGA_BLOCK_NUBMER_A; } else { puts("attosetup: No fpga block number configured\r\n"); } } /* only want to do this twice because we only have 2 images */ ++validation_count; } while((image_validation_success == FALSE) && (validation_count < 2)); if(image_validation_success == TRUE) { if(fpga_block_number == ATTO_FPGA_BLOCK_NUBMER_A) { atto_image = IMAGE_A; puts("attosetup: Configuring FPGA A\r\n"); } else { atto_image = IMAGE_B; puts("attosetup: Configuring FPGA B\r\n"); } fpga_addr = fpga_block_number * ATTO_QSPI_BLOCK_SIZE; } else { atto_image = IMAGE_NA; puts("attosetup: No valid FPGA image to boot\r\n"); fpga_addr = -1; } return fpga_addr; } int atto_setup(void) { atto_store_reset_reason((uint32_t *)ARRIA10_HPS_SYSMGR_ROM_ISWHANDOFF_5); return 0; } static void atto_store_reset_reason(uint32_t * store_addr) { extern unsigned long rst_mgr_status; puts("attosetup: storing reset manager status.\n"); if(store_addr == NULL) { return; } *store_addr = rst_mgr_status; }