コード例 #1
0
int early_board_init(void)
{
	const int cpu_ref = DEFAULT_CPU_REF_FREQUENCY_MHZ;
	int i;

	gd->arch.ddr_ref_hertz = 50000000;
	gd->arch.tlv_addr = CONFIG_SYS_I2C_EEPROM_ADDR;

	for (i = 0; i < ARRAY_SIZE(tuple_addresses); i++) {
		gd->arch.tlv_addr = tuple_addresses[i];
		debug("%s: Trying TLV EEPROM at address 0x%x\n",
		      __func__, tuple_addresses[i]);
		octeon_board_get_descriptor(CVMX_BOARD_TYPE_GENERIC, 1, 0);
		if (gd->board_type != CVMX_BOARD_TYPE_GENERIC)
			break;
	}
	if (i == ARRAY_SIZE(tuple_addresses) ||
	    gd->board_type == CVMX_BOARD_TYPE_GENERIC) {
		puts("ERROR: Board TLV descriptor not found!  Cannot continue!\n"
		     "Use the tlv_eeprom command to program the board type.\n");
		return -1;
	}

	octeon_board_get_clock_info(DEFAULT_DDR3_CLOCK_FREQ_MHZ);

	printf("Board type: %s\n",
	       cvmx_board_type_to_string(gd->board_type));

	/* Read CPU clock multiplier */
	gd->cpu_clk = octeon_get_cpu_multiplier() * cpu_ref * 1000000;

	return 0;
}
コード例 #2
0
void __octeon_board_get_descriptor(enum cvmx_board_types_enum type,
				   int rev_major, int rev_minor)
{
	struct bootloader_header *header;

	gd->arch.board_desc.board_type = CVMX_BOARD_TYPE_NULL;
	debug("%s(%s, %d, %d)\n", __func__, cvmx_board_type_to_string(type),
	      rev_major, rev_minor);

	if (type == CVMX_BOARD_TYPE_NULL) {
		debug("NULL board type passed, extracting board type from header\n");
		header = CASTPTR(struct bootloader_header, CONFIG_SYS_TEXT_BASE);
		if (validate_bootloader_header(header)) {
			gd->flags |= GD_FLG_BOARD_DESC_MISSING;
			gd->arch.board_desc.rev_major = header->maj_rev;
			gd->arch.board_desc.rev_minor = header->min_rev;
			gd->arch.board_desc.board_type = header->board_type;
			strncpy((char *)(gd->arch.board_desc.serial_str),
				"unknown", SERIAL_LEN);
			debug("header board type: %s, revision %d.%d\n",
			      cvmx_board_type_to_string(header->board_type),
			      header->maj_rev, header->min_rev);
		}
	}
コード例 #3
0
ファイル: hal.c プロジェクト: nighthawk149/fvs318g-cfw
/**
 * Return the board name as a constant string
 *
 * @return board name
 */
const char *octeon_board_type_string(void)
{
    return cvmx_board_type_to_string(octeon_bootinfo->board_type);
}
コード例 #4
0
ファイル: octeon_machdep.c プロジェクト: 2trill2spill/freebsd
void
platform_start(__register_t a0, __register_t a1, __register_t a2 __unused,
    __register_t a3)
{
	const struct octeon_feature_description *ofd;
	uint64_t platform_counter_freq;
	int rv;

	mips_postboot_fixup();

	/*
	 * Initialize boot parameters so that we can determine things like
	 * which console we shoud use, etc.
	 */
	octeon_boot_params_init(a3);

	/* Initialize pcpu stuff */
	mips_pcpu0_init();
	mips_timer_early_init(cvmx_sysinfo_get()->cpu_clock_hz);

	/* Initialize console.  */
	cninit();

	/*
	 * Display information about the CPU.
	 */
#if !defined(OCTEON_MODEL)
	printf("Using runtime CPU model checks.\n");
#else
	printf("Compiled for CPU model: " __XSTRING(OCTEON_MODEL) "\n");
#endif
	strcpy(cpu_model, octeon_model_get_string(cvmx_get_proc_id()));
	printf("CPU Model: %s\n", cpu_model);
	printf("CPU clock: %uMHz  Core Mask: %#x\n",
	       cvmx_sysinfo_get()->cpu_clock_hz / 1000000,
	       cvmx_sysinfo_get()->core_mask);
	rv = octeon_model_version_check(cvmx_get_proc_id());
	if (rv == -1)
		panic("%s: kernel not compatible with this processor.", __func__);

	/*
	 * Display information about the board.
	 */
#if defined(OCTEON_BOARD_CAPK_0100ND)
	strcpy(cpu_board, "CAPK-0100ND");
	if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_CN3010_EVB_HS5) {
		panic("Compiled for %s, but board type is %s.", cpu_board,
		       cvmx_board_type_to_string(cvmx_sysinfo_get()->board_type));
	}
#else
	strcpy(cpu_board,
	       cvmx_board_type_to_string(cvmx_sysinfo_get()->board_type));
#endif
	printf("Board: %s\n", cpu_board);
	printf("Board Type: %u  Revision: %u/%u\n",
	       cvmx_sysinfo_get()->board_type,
	       cvmx_sysinfo_get()->board_rev_major,
	       cvmx_sysinfo_get()->board_rev_minor);
	printf("Serial number: %s\n", cvmx_sysinfo_get()->board_serial_number);

	/*
	 * Additional on-chip hardware/settings.
	 *
	 * XXX Display PCI host/target?  What else?
	 */
	printf("MAC address base: %6D (%u configured)\n",
	       cvmx_sysinfo_get()->mac_addr_base, ":",
	       cvmx_sysinfo_get()->mac_addr_count);


	octeon_ciu_reset();
	/*
	 * Convert U-Boot 'bootoctlinux' loader command line arguments into
	 * boot flags and kernel environment variables.
	 */
	bootverbose = 1;
	octeon_init_kenv(a3);

	/*
	 * For some reason on the cn38xx simulator ebase register is set to
	 * 0x80001000 at bootup time.  Move it back to the default, but
	 * when we move to having support for multiple executives, we need
	 * to rethink this.
	 */
	mips_wr_ebase(0x80000000);

	octeon_memory_init();
	init_param1();
	init_param2(physmem);
	mips_cpu_init();
	pmap_bootstrap();
	mips_proc0_init();
	mutex_init();
	kdb_init();
#ifdef KDB
	if (boothowto & RB_KDB)
		kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger");
#endif
	cpu_clock = cvmx_sysinfo_get()->cpu_clock_hz;
	platform_counter_freq = cpu_clock;
	octeon_timecounter.tc_frequency = cpu_clock;
	platform_timecounter = &octeon_timecounter;
	mips_timer_init_params(platform_counter_freq, 0);
	set_cputicker(octeon_get_ticks, cpu_clock, 0);

#ifdef SMP
	/*
	 * Clear any pending IPIs.
	 */
	cvmx_write_csr(CVMX_CIU_MBOX_CLRX(0), 0xffffffff);
#endif

	printf("Octeon SDK: %s\n", OCTEON_SDK_VERSION_STRING);
	printf("Available Octeon features:");
	for (ofd = octeon_feature_descriptions; ofd->ofd_string != NULL; ofd++)
		if (octeon_has_feature(ofd->ofd_feature))
			printf(" %s", ofd->ofd_string);
	printf("\n");
}
コード例 #5
0
int cvmx_llm_initialize_desc(llm_descriptor_t *llm_desc_ptr)
{
    cvmx_sysinfo_t *sys_ptr;
    sys_ptr = cvmx_sysinfo_get();
    llm_descriptor_t default_llm_desc;

    memset(&default_llm_desc, 0, sizeof(default_llm_desc));
    if (sys_ptr->board_type == CVMX_BOARD_TYPE_SIM)
    {
        cvmx_dprintf("Skipping llm configuration for simulator.\n");
        return 0;
    }

    if (sys_ptr->board_type == CVMX_BOARD_TYPE_EBH3100)
    {
        /* CN31xx DFA memory is DDR based, so it is completely different from the CN38XX DFA memory
        ** config descriptors are not supported yet.*/
        cvmx_dprintf("Warning: preliminary DFA memory configuration\n");
        cn31xx_dfa_memory_init();
        return(256*1024*1024);
    }

    /* If no descriptor passed, generate default descriptor based on board type.
    ** Fail if no default available for given board type
    */
    if (!llm_desc_ptr)
    {
        /* Get default descriptor */
        if (0 > cvmx_llm_get_default_descriptor(&default_llm_desc))
            return -1;

        /* Disable second port depending on CVMX config */
        if (CVMX_LLM_NUM_PORTS == 1)
	  default_llm_desc.rld0_bunks = 0;        // For single port: Force RLD0(P1) to appear EMPTY

        cvmx_dprintf("Using default LLM configuration for board %s (%d)\n", cvmx_board_type_to_string(sys_ptr->board_type),  sys_ptr->board_type);

        llm_desc_ptr = &default_llm_desc;
    }



    rldram_csr_config_t ebt3000_rld_cfg;
    if (!rld_csr_config_generate(llm_desc_ptr, &ebt3000_rld_cfg))
    {
        cvmx_dprintf("Configuring %d llm port(s).\n", !!llm_desc_ptr->rld0_bunks + !!llm_desc_ptr->rld1_bunks);
        write_rld_cfg(&ebt3000_rld_cfg);
    }
    else
    {
        cvmx_dprintf("Error creating rldram configuration\n");
        return(-1);
    }

    /* Compute how much memory is configured
    ** Memory is interleaved, so if one port has more than the other some memory is not usable */

    /* If both ports are enabled, handle the case where one port has more than the other.
    ** This is an unusual and not recommended configuration that exists on the ebt3000 board */
    if (!!llm_desc_ptr->rld0_bunks && !!llm_desc_ptr->rld1_bunks)
        llm_desc_ptr->rld0_mbytes = llm_desc_ptr->rld1_mbytes = MIN(llm_desc_ptr->rld0_mbytes, llm_desc_ptr->rld1_mbytes);

    return(((!!llm_desc_ptr->rld0_bunks) * llm_desc_ptr->rld0_mbytes
          + (!!llm_desc_ptr->rld1_bunks) * llm_desc_ptr->rld1_mbytes) * 1024*1024);
}
コード例 #6
0
int cvmx_llm_get_default_descriptor(llm_descriptor_t *llm_desc_ptr)
{
    cvmx_sysinfo_t *sys_ptr;
    sys_ptr = cvmx_sysinfo_get();

    if (!llm_desc_ptr)
        return -1;

    memset(llm_desc_ptr, 0, sizeof(llm_descriptor_t));

    llm_desc_ptr->cpu_hz = cvmx_clock_get_rate(CVMX_CLOCK_CORE);

    if (sys_ptr->board_type == CVMX_BOARD_TYPE_EBT3000)
    { // N3K->RLD0 Address Swizzle
        strcpy(llm_desc_ptr->addr_rld0_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
        strcpy(llm_desc_ptr->addr_rld0_bb_str, "22 21 19 20 08 07 06 05 04 03 02 01 00 09 18 17 16 15 14 13 12 11 10");
        // N3K->RLD1 Address Swizzle
        strcpy(llm_desc_ptr->addr_rld1_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
        strcpy(llm_desc_ptr->addr_rld1_bb_str, "22 21 20 00 08 07 06 05 04 13 02 01 03 09 18 17 16 15 14 10 12 11 19");
        /* NOTE: The ebt3000 has a strange RLDRAM configuration for validation purposes.  It is not recommended to have
        ** different amounts of memory on different ports as that renders some memory unusable */
        llm_desc_ptr->rld0_bunks = 2;
        llm_desc_ptr->rld1_bunks = 2;
        llm_desc_ptr->rld0_mbytes = 128;          // RLD0: 4x 32Mx9
        llm_desc_ptr->rld1_mbytes = 64;           // RLD1: 2x 16Mx18
    }
    else if (sys_ptr->board_type == CVMX_BOARD_TYPE_EBT5800)
    {
        strcpy(llm_desc_ptr->addr_rld0_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
        strcpy(llm_desc_ptr->addr_rld0_bb_str, "22 21 20 00 08 07 06 05 04 13 02 01 03 09 18 17 16 15 14 10 12 11 19");
        strcpy(llm_desc_ptr->addr_rld1_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
        strcpy(llm_desc_ptr->addr_rld1_bb_str, "22 21 20 00 08 07 06 05 04 13 02 01 03 09 18 17 16 15 14 10 12 11 19");
        llm_desc_ptr->rld0_bunks = 2;
        llm_desc_ptr->rld1_bunks = 2;
        llm_desc_ptr->rld0_mbytes = 128;
        llm_desc_ptr->rld1_mbytes = 128;
        llm_desc_ptr->max_rld_clock_mhz = 400;  /* CN58XX needs a max clock speed for selecting optimal divisor */
    }
    else if (sys_ptr->board_type == CVMX_BOARD_TYPE_EBH3000)
    {
        strcpy(llm_desc_ptr->addr_rld0_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
        strcpy(llm_desc_ptr->addr_rld0_bb_str, "22 21 19 20 08 07 06 05 04 03 02 01 00 09 18 17 16 15 14 13 12 11 10");
        strcpy(llm_desc_ptr->addr_rld1_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
        strcpy(llm_desc_ptr->addr_rld1_bb_str, "22 21 19 20 08 07 06 05 04 03 02 01 00 09 18 17 16 15 14 13 12 11 10");
        llm_desc_ptr->rld0_bunks = 2;
        llm_desc_ptr->rld1_bunks = 2;
        llm_desc_ptr->rld0_mbytes = 128;
        llm_desc_ptr->rld1_mbytes = 128;
    }
    else if (sys_ptr->board_type == CVMX_BOARD_TYPE_THUNDER)
    {

        if (sys_ptr->board_rev_major >= 4)
        {
            strcpy(llm_desc_ptr->addr_rld0_fb_str, "22 21 13 11 01 02 07 19 03 18 10 12 20 06 04 08 17 05 14 16 00 09 15");
            strcpy(llm_desc_ptr->addr_rld0_bb_str, "22 21 11 13 04 08 17 05 14 16 00 09 15 06 01 02 07 19 03 18 10 12 20");
            strcpy(llm_desc_ptr->addr_rld1_fb_str, "22 21 02 19 18 17 16 09 14 13 20 11 10 01 08 03 06 15 04 07 05 12 00");
            strcpy(llm_desc_ptr->addr_rld1_bb_str, "22 21 19 02 08 03 06 15 04 07 05 12 00 01 18 17 16 09 14 13 20 11 10");
        }
        else
        {
            strcpy(llm_desc_ptr->addr_rld0_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
            strcpy(llm_desc_ptr->addr_rld0_bb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
            strcpy(llm_desc_ptr->addr_rld1_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
            strcpy(llm_desc_ptr->addr_rld1_bb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
        }

        llm_desc_ptr->rld0_bunks = 2;
        llm_desc_ptr->rld1_bunks = 2;
        llm_desc_ptr->rld0_mbytes = 128;
        llm_desc_ptr->rld1_mbytes = 128;
    }
    else if (sys_ptr->board_type == CVMX_BOARD_TYPE_NICPRO2)
    {
        strcpy(llm_desc_ptr->addr_rld0_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
        strcpy(llm_desc_ptr->addr_rld0_bb_str, "22 21 19 20 08 07 06 05 04 03 02 01 00 09 18 17 16 15 14 13 12 11 10");
        strcpy(llm_desc_ptr->addr_rld1_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
        strcpy(llm_desc_ptr->addr_rld1_bb_str, "22 21 19 20 08 07 06 05 04 03 02 01 00 09 18 17 16 15 14 13 12 11 10");
        llm_desc_ptr->rld0_bunks = 2;
        llm_desc_ptr->rld1_bunks = 2;
        llm_desc_ptr->rld0_mbytes = 256;
        llm_desc_ptr->rld1_mbytes = 256;
        llm_desc_ptr->max_rld_clock_mhz = 400;  /* CN58XX needs a max clock speed for selecting optimal divisor */
    }
    else if (sys_ptr->board_type == CVMX_BOARD_TYPE_EBH3100)
    {
        /* CN31xx DFA memory is DDR based, so it is completely different from the CN38XX DFA memory */
        llm_desc_ptr->rld0_bunks = 1;
        llm_desc_ptr->rld0_mbytes = 256;
    }
    else if (sys_ptr->board_type == CVMX_BOARD_TYPE_KBP)
    {
        strcpy(llm_desc_ptr->addr_rld0_fb_str, "");
        strcpy(llm_desc_ptr->addr_rld0_bb_str, "");
        llm_desc_ptr->rld0_bunks = 0;
        llm_desc_ptr->rld0_mbytes = 0;
        strcpy(llm_desc_ptr->addr_rld1_fb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
        strcpy(llm_desc_ptr->addr_rld1_bb_str, "22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00");
        llm_desc_ptr->rld1_bunks = 2;
        llm_desc_ptr->rld1_mbytes = 64;
    }
    else
    {
        cvmx_dprintf("No default LLM configuration available for board %s (%d)\n", cvmx_board_type_to_string(sys_ptr->board_type),  sys_ptr->board_type);
        return -1;
    }

    return(0);
}
コード例 #7
0
/**
 * Command for updating a bootloader image in flash.  This function
 * parses the arguments, and validates the header (if header exists.)
 * Actual flash updating is done by flash type specific functions.
 *
 * @return 0 on success
 *         1 on failure
 */
int do_bootloader_update(cmd_tbl_t * cmdtp, int flag, int argc,
			 char *const argv[])
{
	uint32_t image_addr = 0;
	uint32_t image_len = 0;
	uint32_t burn_addr = 0;
	int failsafe = 0;
	const bootloader_header_t *header;
	int force_nand = 0;
	int force_spi = 0;

	if (argc >= 2) {
		if (!strcmp(argv[1], "nand")) {
			debug("Forced NAND bootloader update\n");
			force_nand = 1;
			argc--;
			argv++;
		} else if (!strcmp(argv[1], "spi")) {
			debug("Forced SPI bootloader update\n");
			force_spi = 1;
			argc--;
			argv++;
			if (!strcmp(argv[1], "failsafe")) {
				failsafe = 1;
				argc--;
				argv++;
			}
		}
	}
	if (argc >= 2)
		image_addr = simple_strtoul(argv[1], NULL, 16);
	if (argc >= 3)
		image_len = simple_strtoul(argv[2], NULL, 16);
	if (argc >= 4) {
		if (force_spi || force_nand) {
			if (!strcmp("failsafe", argv[3]))
				failsafe = 1;
		} else {
			burn_addr = simple_strtoul(argv[3], NULL, 16);
		}
	}
	if ((argc >= 5) && (strcmp("failsafe", argv[4]) == 0))
		failsafe = 1;

	/* If we don't support failsafe images, we need to put the image at the
	 * base of flash, so we treat all images like failsafe image in this
	 * case.
	 */
#ifdef CONFIG_OCTEON_NO_FAILSAFE
	failsafe = 1;
	burn_addr = 0x1fc00000;
#endif

	if (!burn_addr)
		burn_addr = getenv_hex("burnaddr", 0);

	if (!image_addr) {
		image_addr = getenv_hex("fileaddr", load_addr);
		if (!image_addr) {
			puts("ERROR: Unable to get image address from "
			     "'fileaddr' environment variable\n");
			return 1;
		}
	}

	DBGUPD("%s: burn address: 0x%x, image address: 0x%x\n",
	      __func__, burn_addr, image_addr);

	/* Figure out what kind of flash we are going to update.  This will
	 * typically come from the bootloader header.  If the bootloader does
	 * not have a header, then it is assumed to be a legacy NOR image, and
	 * a destination NOR flash address must be supplied.  NAND images
	 * _must_ have a header.
	 */
	header = (void *)image_addr;

	if (header->magic != BOOTLOADER_HEADER_MAGIC) {
		/* No header, assume headerless NOR bootloader image */
		puts("No valid bootloader header found.  Assuming old headerless image\n"
		     "Image checks cannot be performed\n");

		if (!burn_addr) {
			burn_addr = CONFIG_SYS_NORMAL_BOOTLOADER_BASE;
			DBGUPD("Unable to get burn address from 'burnaddr' environment variable,\n");
			DBGUPD(" using default 0x%x\n", burn_addr);
		}
		/* We only need image length for the headerless case */
		if (!image_len) {
			image_len = getenv_hex("filesize", 0);
			if (!image_len) {
				puts("ERROR: Unable to get image size from "
				     "'filesize' environment variable\n");
				return 1;
			}
		}

		return do_bootloader_update_nor(image_addr, image_len,
						burn_addr, failsafe);
	}

	/* We have a header, so validate image */
	if (validate_header(header)) {
		puts("ERROR: Image header has invalid CRC.\n");
		return 1;
	}
	if (validate_data(header))	/* Errors printed */
		return 1;

	/* We now have a valid image, so determine what to do with it. */
	puts("Valid bootloader image found.\n");

	/* Check to see that it is for the board we are running on */
	if (header->board_type != cvmx_sysinfo_get()->board_type) {
		printf("Current board type: %s (%d), image board type: %s (%d)\n",
		       cvmx_board_type_to_string(cvmx_sysinfo_get()->board_type),
		       cvmx_sysinfo_get()->board_type,
		       cvmx_board_type_to_string(header->board_type),
		       header->board_type);
		if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_GENERIC
		    && header->board_type != CVMX_BOARD_TYPE_GENERIC) {
			puts("ERROR: Bootloader image is not for this board type.\n");
			return 1;
		} else {
			puts("Loading mismatched image since current "
			     "or new bootloader is generic.\n");
		}
	}

	/* SDK 1.9.0 NOR images have rev of 1.1 and unkown image_type */
	if (((header->image_type == BL_HEADER_IMAGE_NOR)
	     || (header->image_type == BL_HEADER_IMAGE_UNKNOWN
		 && header->maj_rev == 1 && header->min_rev == 1))
	    && !force_nand && !force_spi) {
		debug("Updating NOR bootloader\n");
		return do_bootloader_update_nor(image_addr, 0, burn_addr,
						failsafe);
#if defined(CONFIG_CMD_OCTEON_NAND) || defined(CONFIG_OCTEON_NAND_BOOT_END)
	} else if (!force_spi &&
		   (header->image_type == BL_HEADER_IMAGE_STAGE2 ||
		    header->image_type == BL_HEADER_IMAGE_STAGE3 ||
		    force_nand)) {
		debug("Updating NAND bootloader\n");
		return (do_bootloader_update_nand(image_addr));
#endif
#if defined(CONFIG_OCTEON_SPI_BOOT_END)
	} else if (!force_nand &&
		   (header->image_type == BL_HEADER_IMAGE_STAGE2 ||
		    header->image_type == BL_HEADER_IMAGE_STAGE3 ||
		    force_spi)) {
		debug("Updating SPI bootloader\n");
		return do_bootloader_update_spi(image_addr,
						header->dlen + header->hlen,
						failsafe, false);
#else
	} else {
		puts("ERROR: This bootloader not compiled for this medium\n");
		return 1;
#endif
	}

	return 1;
}
コード例 #8
0
ファイル: cmd_octeon_nand.c プロジェクト: ryanSie/Advantech
int do_oct_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
    u64 buf_storage[CVMX_NAND_MAX_PAGE_AND_OOB_SIZE / 8];
    unsigned char *buf = (unsigned char *)buf_storage;
    int rc;

    const char *cmd;

    if (argc < 2)
        goto usage;

    cmd = argv[1];

    if (!strcmp("probe", cmd)) {
        rc = oct_nand_probe();
        if (rc < 0) {
            printf("NAND flash not found\n");
        } else {
            printf("probe found NAND flash on boot bus %d.\n", rc);
        }
        return 0;
    } else if (!strcmp("dump", cmd)) {
        /* Only dump full pages.... */
        u64 page, end;
        u64 start_addr, len;
        int page_size = cvmx_nand_get_page_size(chip);
        int oob_size = cvmx_nand_get_oob_size(chip);
        if (argc < 3)
            goto usage;
        start_addr = simple_strtoull(argv[2], NULL, 16);
        if (argc == 4)
            len = simple_strtoull(argv[3], NULL, 16);
        else
            len = 0;

        if (!page_size) {
            printf("ERROR: No NAND configured (run probe)\n");
            return 1;
        }

        /* Convert from addresses to pages */
        page = start_addr / page_size;
        if (!len)
            end = page;
        else
            end = (start_addr + len) / page_size;

        while (page <= end) {
            /* Read the next block */
            int i;
            int read_size = page_size + oob_size;
            /* Read more than required in cases when total read size
             * is not a multiple of 8.
             */
            read_size = (read_size + 7) & ~0x7;

            int bytes = cvmx_nand_page_read(chip, page_size * page,
                                            cvmx_ptr_to_phys(buf),
                                            read_size);
            int pages_per_block =
                cvmx_nand_get_pages_per_block(chip);
            if (bytes != read_size) {
                printf("Error reading page %llu, "
                       "bytes read: %d\n", page, bytes);
                return 1;
            }
            /* Dump page data */
            printf("Address 0x%llx, (Block 0x%llx, page 0x%llx) "
                   "data:\n",
                   page * page_size, page / pages_per_block,
                   page % pages_per_block);
            for (i = 0; i < page_size; i++) {
                if (i % 16 == 0)
                    printf("0x%04llx:",
                           page * page_size + i);
                printf(" %02x", buf[i]);
                if (i % 16 == 15)
                    printf("\n");

            }
            /* Dump OOB data */
            printf("Address 0x%llx, (Block 0x%llx, page 0x%llx) OOB:\n",
                   page * page_size, page / pages_per_block,
                   page % pages_per_block);
            for (i = 0; i < oob_size; i++) {
                if (i % 16 == 0)
                    printf("0x%04x:", i);
                printf(" %02x", buf[page_size + i]);
                if (i % 16 == 15)
                    printf("\n");
            }
            printf("\n");

            page++;
        }
        return 0;
    } else if (!strcmp("erase", cmd)) {
        u64 start_addr, length;
        int force = 0;
        u64 i;
        int page_size = cvmx_nand_get_page_size(chip);
        int pages_per_block = cvmx_nand_get_pages_per_block(chip);
        if (argc < 3 || argc > 5)
            goto usage;
        start_addr = simple_strtoull(argv[2], NULL, 16);
        if (argc >= 4)
            length = simple_strtoull(argv[3], NULL, 16);
        else
            length = page_size * pages_per_block;

        if (argc == 5) {
            if (strcmp(argv[4], "force"))
                goto usage;
            printf("WARNING: Forced erase: erasing bad blocks.\n");
            force = 1;
        }
        if (!page_size) {
            printf("ERROR: No NAND configured (run probe)\n");
            return 1;
        }

        if (start_addr & ((u64) page_size * pages_per_block - 1)) {
            printf("ERROR: erase start not at block boundary "
                   "(maybe want: 0x%llx or 0x%llx)\n",
                   start_addr & ~((u64) page_size *
                                  pages_per_block - 1),
                   (start_addr +
                    page_size *
                    pages_per_block) & ~((u64) page_size *
                                         pages_per_block - 1));
            return 1;
        }
        if ((length & (page_size * pages_per_block - 1))) {
            printf
            ("ERROR: erase length not multiple of block size "
             "(maybe want: 0x%llx)\n",
             (length +
              (page_size * pages_per_block -
               1)) & ~(page_size * pages_per_block - 1));
            return 1;
        }

        for (i = start_addr; i < start_addr + length;
                i += page_size * pages_per_block) {
            if (oct_nand_block_is_bad(chip, i, 1)) {
                if (force) {
                    printf("WARNING: Erasing bad bock at "
                           "address 0x%llx\n", i);
                } else {
                    printf("Not erasing bad block at "
                           "address 0x%llx\n", i);
                    continue;
                }
            }
            if (cvmx_nand_block_erase(chip, i)) {
                printf("cvmx_nand_block_erase() failed, "
                       "addr 0x%08llx\n", i);
                return 1;
            }
        }

        return 0;
    } else if (!strcmp("write", cmd)) {
        u64 nand_addr;
        u32 dram_addr, length;
        int page_size = cvmx_nand_get_page_size(chip);

        if (!page_size) {
            printf("ERROR: No NAND configured (run probe)\n");
            return 1;
        }
        if (argc != 3 && argc != 5)
            goto usage;

        nand_addr = simple_strtoull(argv[2], NULL, 16);
        if (argc == 5) {
            dram_addr = simple_strtoul(argv[3], NULL, 16);
            length = simple_strtoul(argv[4], NULL, 16);
        } else {
            /* We look up the length/address from environment
             * variables....
             * filesize=3410
             * fileaddr=20000000
             */
            if (getenv("filesize") && getenv("fileaddr")) {
                dram_addr = simple_strtoul(getenv("fileaddr"),
                                           NULL, 16);
                length = simple_strtoul(getenv("filesize"),
                                        NULL, 16);

                /* Round length up to pagesize */
                length =
                    (length + page_size - 1) & ~(page_size - 1);
            } else {
                printf("ERROR: filesize and fileaddr "
                       "environment variables\n"
                       "must be set if address and size "
                       "are not given\n");
                goto usage;
            }
        }
        unsigned char *data_ptr = (void *)dram_addr;

        if (nand_addr & (page_size - 1)) {
            printf("ERROR: write address not at page boundary "
                   "(maybe want: 0x%08llx)\n",
                   nand_addr & ~(page_size - 1));
            return 1;
        }

        return oct_nand_boot_write(nand_addr, data_ptr, length, 0);
    } else if (!strcmp("scan", cmd)) {
        u64 nand_addr;
        bootloader_header_t header_copy;
        int page_size = cvmx_nand_get_page_size(chip);
        int pages_per_block = cvmx_nand_get_pages_per_block(chip);
        int block_size = page_size * pages_per_block;
        int errors = 0;
        int read_size = CVMX_NAND_BOOT_ECC_BLOCK_SIZE +
                        CVMX_NAND_BOOT_ECC_ECC_SIZE;
        if (!page_size) {
            printf("ERROR: No NAND configured (run probe)\n");
            return 1;
        }

        printf("Scanning NAND for recognized images\n");
        for (nand_addr = 0; nand_addr < MAX_NAND_SEARCH_ADDR;
                nand_addr += page_size) {
            /* Adjust the read address based on location in page */
            int offset = ((nand_addr & (page_size - 1)) /
                          CVMX_NAND_BOOT_ECC_BLOCK_SIZE) *
                         CVMX_NAND_BOOT_ECC_ECC_SIZE;
            int bytes = cvmx_nand_page_read(chip,
                                            nand_addr + offset,
                                            cvmx_ptr_to_phys(buf),
                                            read_size);
            if (bytes != read_size) {
                printf("Error reading NAND addr 0x%08llx "
                       "(bytes_read: %d, expected: %d)\n",
                       nand_addr, bytes, read_size);
                return 1;
            }
            errors = cvmx_nand_correct_boot_ecc(buf);
            if (errors <= 1) {
                const bootloader_header_t *header =
                    (const bootloader_header_t *)buf;

                /* Block is good, see if it contains a
                 * bootloader image header
                 */
                if ((header->magic == BOOTLOADER_HEADER_MAGIC)) {
                    int rval;

                    /* Check the CRC of the header */
                    u32 crc;
                    crc = crc32(0, (void *)header, 12);
                    crc = crc32(crc, (void *)header + 16,
                                header->hlen - 16);

                    if (crc != header->hcrc) {
                        printf("ERROR: 0x%llx Header "
                               "CRC mismatch, expected:"
                               " 0x%08x, found:"
                               " 0x%08x\n",
                               nand_addr,
                               header->hcrc, crc);
                    } else {
                        header_copy = *header;
                        printf("\nImage header at addr:"
                               "0x%llx, size: 0x%x, "
                               "crc: 0x%x ", nand_addr,
                               header->dlen,
                               header->dcrc);
                        if ((rval =
                                    oct_nand_validate_image(nand_addr)) < 0) {
                            printf("Invalid image(%d).\n",
                                   rval);
                        } else {
                            printf
                            ("Valid image.\n");
                            if (header_copy.flags &
                                    BL_HEADER_FLAG_FAILSAFE)
                                printf("Failsafe");
                            else
                                printf("Normal");
                            if (header_copy.image_type ==
                                    BL_HEADER_IMAGE_STAGE2)
                                printf("NAND stage2 ");
                            else if
                            (header_copy.image_type ==
                                    BL_HEADER_IMAGE_STAGE3)
                                printf("NAND stage3 ");
                            else if
                            (header_copy.image_type ==
                                    BL_HEADER_IMAGE_UBOOT_ENV)
                                printf("U-boot environment (version: %d)\n",
                                       (int)header_copy.address);

                            if (header_copy.board_type)
                                printf("image for %s board\n",
                                       cvmx_board_type_to_string(header_copy.board_type));
                            else
                                printf("\n");
                            /* Skip the image, as we
                             * have validated it
                             */
                            nand_addr +=
                                ((header->dlen +
                                  page_size -
                                  1) & ~(page_size -
                                         1)) -
                                page_size;
                        }
                    }
                }
            } else {
                /* Uncorrectable errors detected. */

                /* Check to see if we have a bad block */
                if (oct_nand_block_is_bad(chip, nand_addr, 1)) {
                    printf
                    ("Bad NAND block at addr: 0x%llx\n",
                     nand_addr & ~(block_size - 1));
                    /* Skip rest of block */
                    nand_addr += block_size -
                                 (nand_addr & (block_size - 1)) -
                                 page_size;
                }
            }
        }
        printf("\n");
        return 0;
    }

usage:
    printf("Usage:\n%s\n", cmdtp->usage);
    return 1;
}