/*
 * alt_epcs_flash_init
 *
 */
int alt_epcs_flash_init(alt_flash_epcs_dev* flash)
{
  int ret_code = 0;

  /* Set up function pointers and/or data structures as needed. */
  ret_code = alt_epcs_flash_query(flash);

  /* The following function pointers:
   *
   * alt_epcs_flash_write
   * alt_epcs_flash_read
   * alt_epcs_flash_get_info
   *
   * are already filled in in the device struct.
   * Fill in any other function pointers here, if necessary.
  */

  /*
  *  Register this device as a valid flash device type
  */
  if (!ret_code)
    ret_code = alt_flash_device_register(&(flash->dev));

  return ret_code;
}
/**
 * altera_epcq_controller_init
 *
 * alt_sys_init.c will call this function automatically through macro
 *
 * Information in system.h is checked against expected values that are determined by the silicon_id.
 * If the information doesn't match then this system is configured incorrectly. Most likely the wrong
 * type of EPCS or EPCQ device was selected when instantiating the soft IP.
 *
 * Arguments:
 * - *flash: Pointer to EPCQ flash device structure.
 *
 * Returns:
 * 0 -> success
 * -EINVAL -> Invalid arguments.
 * -ENODEV -> System is configured incorrectly.
**/
alt_32 altera_epcq_controller_init(alt_epcq_controller_dev *flash)
{
	alt_u32 silicon_id = 0;
	alt_u32 size_in_bytes = 0;
	alt_u32 number_of_sectors = 0;

    /* return -EINVAL if flash is NULL */
	if(NULL == flash)
    {
    	return -EINVAL;
    }
	
	/* return -ENODEV if CSR slave is not attached */
	if(NULL == (void *)flash->csr_base)
	{
		return -ENODEV;
	}


	/*
	 * If flash is an EPCQ device, we read the EPCQ_RD_RDID register for the ID
	 * If flash is an EPCS device, we read the EPCQ_RD_SID register for the ID
	 *
	 * Whether or not the flash is a EPCQ or EPCS is indicated in the system.h. The system.h gets
	 * this value from the hw.tcl of the IP. If this value is set incorrectly, then things will go
	 * badly.
	 *
	 * In both cases, we can determine the number of sectors, which we can use
	 * to calculate a size. We compare that size to the system.h value to make sure
	 * the EPCQ soft IP was configured correctly.
	 */
	if(0 == flash->is_epcs)
	{
		/* If we're an EPCQ, we read EPCQ_RD_RDID for the silicon ID */
		silicon_id = IORD_ALTERA_EPCQ_CONTROLLER_RDID(flash->csr_base);
		silicon_id &= ALTERA_EPCQ_CONTROLLER_RDID_MASK;

		/* Determine which EPCQ device so we can figure out the number of sectors */
		/* EPCQ share the same ID for the same capacity*/
		switch(silicon_id)
		{
			case ALTERA_EPCQ_CONTROLLER_RDID_EPCQ16:
			{
				number_of_sectors = 32;
				break;
			}
			case ALTERA_EPCQ_CONTROLLER_RDID_EPCQ32:
			{
				number_of_sectors = 64;
				break;
			}
			case ALTERA_EPCQ_CONTROLLER_RDID_EPCQ64:
			{
				number_of_sectors = 128;
				break;
			}
			case ALTERA_EPCQ_CONTROLLER_RDID_EPCQ128:
			{
				number_of_sectors = 256;
				break;
			}
			case ALTERA_EPCQ_CONTROLLER_RDID_EPCQ256:
			{
				number_of_sectors = 512;
				break;
			}
			case ALTERA_EPCQ_CONTROLLER_RDID_EPCQ512:
			{
				number_of_sectors = 1024;
				break;
			}
			case ALTERA_EPCQ_CONTROLLER_RDID_EPCQ1024:
			{
				number_of_sectors = 2048;
				break;
			}
			default:
			{
				return -ENODEV;
			}
		}
	}
	else {
		/* If we're an EPCS, we read EPCQ_RD_SID for the silicon ID */
		silicon_id = IORD_ALTERA_EPCQ_CONTROLLER_SID(flash->csr_base);
		silicon_id &= ALTERA_EPCQ_CONTROLLER_SID_MASK;

		/* Determine which EPCS device so we can figure out various properties */
		switch(silicon_id)
		{
			case ALTERA_EPCQ_CONTROLLER_SID_EPCS16:
			{
				number_of_sectors = 32;
				break;
			}
			case ALTERA_EPCQ_CONTROLLER_SID_EPCS64:
			{
				number_of_sectors = 128;
				break;
			}
			case ALTERA_EPCQ_CONTROLLER_SID_EPCS128:
			{
				number_of_sectors = 256;
				break;
			}
			default:
			{
				return -ENODEV;
			}
		}
	}

	/* Calculate size of flash based on number of sectors */
	size_in_bytes = number_of_sectors * flash->sector_size;

	/*
	 * Make sure calculated size is the same size given in system.h
	 * Also check number of sectors is the same number given in system.h
	 * Otherwise the EPCQ IP was not configured correctly
	 */
	if(	size_in_bytes != flash->size_in_bytes ||
			number_of_sectors != flash->number_of_sectors)
	{
		flash->dev.number_of_regions = 0;
		return -ENODEV;
	}
	else
	{
		flash->silicon_id = silicon_id;
		flash->number_of_sectors = number_of_sectors;

		/*
		 * populate fields of region_info required to conform to HAL API
		 * create 1 region that composed of "number_of_sectors" blocks
		 */
		flash->dev.number_of_regions = 1;
		flash->dev.region_info[0].offset = 0;
		flash->dev.region_info[0].region_size = size_in_bytes;
		flash->dev.region_info[0].number_of_blocks = number_of_sectors;
		flash->dev.region_info[0].block_size = flash->sector_size;
	}


    /*
     * Register this device as a valid flash device type
     *
     * Only register the device if it's configured correctly.
     */
		alt_flash_device_register(&(flash->dev));


    return 0;
}