[U-Boot] [PATCH 0/5] Virtex2 FPGA enhancements

Robert Hancock hancock at sedsystems.ca
Thu Jun 20 22:11:21 UTC 2019


On 2019-06-20 5:55 a.m., Michal Simek wrote:
> On 19. 06. 19 17:43, Robert Hancock wrote:
>> On 2019-06-19 6:10 a.m., Michal Simek wrote:
>>> On 18. 06. 19 17:47, Robert Hancock wrote:
>>>> These changes add support for slave serial mode, in addition to the
>>>> existing slave SelectMAP mode, for programming Xilinx Virtex2 (and later)
>>>> FPGAs, as well as fixing up code style and an issue with the programming
>>>> sequence.
>>>>
>>>> Robert Hancock (5):
>>>>   fpga: virtex2: cosmetic: Cleanup code style
>>>>   fpga: virtex2: added Kconfig option
>>>>   fpga: virtex2: Split out image writing from pre/post operations
>>>>   fpga: virtex2: Add additional clock cycles after DONE assertion
>>>>   fpga: virtex2: Add slave serial programming support
>>>>
>>>>  drivers/fpga/Kconfig   |   8 +
>>>>  drivers/fpga/virtex2.c | 503 +++++++++++++++++++++++++++++--------------------
>>>>  include/virtex2.h      |  13 +-
>>>>  3 files changed, 313 insertions(+), 211 deletions(-)
>>>>
>>>
>>> I have not a problem with this code but my question is what's your plan
>>> about it? Right now none is really calling/building this code.
>>> Are you going to push any platform which will enable this driver?
>>
>> This is being used on an internal platform that hasn't been upstreamed
>> yet. There is some more cleanup that needs to happen in the board code
>> before that can happen but I think we could potentially do that.
>>
>> However, now that there is a Kconfig option for this it would be a lot
>> easier for those code to be built for other platforms that will use it.
> 
> It will be useful to have this code available because of fpga functions
> needs to be implemented based on your connection. Do you have this in
> any internal repo or also available in your u-boot clone somewhere like
> github?

If it helps, here is part of our board file that does the FPGA GPIO and
SPI initialization and initializes the FPGA callbacks. We are using an
ITB image that has the FPGA .bit file as one of the entries and which
gets loaded as part of the bootm command.

static struct gpio_desc fpga_done;
static struct gpio_desc fpga_prog;
static struct gpio_desc fpga_init_in;

static struct spi_slave *fpga_slave;

...

/*
 * Initialize before download
 */
static int fpga_pre_fn(int cookie)
{
	/* Initialize GPIO pins */
	dm_gpio_set_dir_flags(&fpga_prog, GPIOD_IS_OUT);
	dm_gpio_set_value(&fpga_prog, 1);

	return cookie;
}

/*
 * Set the FPGA's active-low program line to the specified level
 */
static int fpga_pgm_fn(int assert, int flush, int cookie)
{
	dm_gpio_set_value(&fpga_prog, !assert);
	return assert;
}

/*
 * Test the state of the active-low FPGA INIT line.  Return 1 on INIT
 * asserted (low).
 */
static int fpga_init_fn(int cookie)
{
	return !dm_gpio_get_value(&fpga_init_in);
}

/*
 * Test the state of the active-high FPGA DONE pin
 */
static int fpga_done_fn(int cookie)
{
	return dm_gpio_get_value(&fpga_done) ? FPGA_SUCCESS : FPGA_FAIL;
}

static int fpga_wbulkdata_fn(void *buf, size_t len, int flush, int cookie)
{
	int ret = spi_xfer(fpga_slave, len * 8, buf, NULL,
			   SPI_XFER_BEGIN | SPI_XFER_END);
	if (ret) {
		printf("Failed to transfer %zu bytes of SPI data: %d\n",
		       len, ret);
	}
	return cookie;
}

static int fpga_post_fn(int cookie)
{
	return cookie;
}

static int fpga_abort_fn(int cookie)
{
	return fpga_post_fn(cookie);
}

static int fpga_busy_fn(int cookie)
{
	return 0;
}

static xilinx_virtex2_slave_fns fpga_fns = {
	.pre = fpga_pre_fn,
	.pgm = fpga_pgm_fn,
	.init = fpga_init_fn,
	.done = fpga_done_fn,
	.wbulkdata = fpga_wbulkdata_fn,
	.busy = fpga_busy_fn,
	.abort = fpga_abort_fn,
	.post = fpga_post_fn,
};

static xilinx_desc fpga = {
	.family = xilinx_virtex2,
	.iface = slave_serial,
	.size = 6692572,
	.iface_fns = &fpga_fns,
	.cookie = 0,
	.operations = &virtex2_op,
	.name = "7k160tffg676"
};

int board_late_init(void)
{
	struct udevice *dev;
	int ret, i;

...

	/* Bind SPI generic driver to the device */
	ret = spi_get_bus_and_cs(2, 0, 50000000, SPI_MODE_0, "spi_generic_drv",
				 "fpga_spi", &dev, &fpga_slave);
	if (ret) {
		printf("Failed to bind SPI generic device (err=%d)\n", ret);
		return 1;
	}

	/* Claim SPI bus */
	ret = spi_claim_bus(fpga_slave);
	if (ret) {
		printf("Failed to claim SPI generic device (err=%d)\n", ret);
		return 1;
	}

	/* Claim FPGA GPIOs */
	ret = dm_gpio_lookup_name("GPIO6_5", &fpga_done);
	if (ret) {
		printf("Unable to lookup GPIO6_5\n");
		return 1;
	}

	ret = dm_gpio_request(&fpga_done, "fpga_done");
	if (ret) {
		printf("Unable to request fpga_done\n");
		return 1;
	}

	dm_gpio_set_dir_flags(&fpga_done, GPIOD_IS_IN);

	ret = dm_gpio_lookup_name("GPIO6_3", &fpga_prog);
	if (ret) {
		printf("Unable to lookup GPIO6_3\n");
		return 1;
	}

	ret = dm_gpio_request(&fpga_prog, "fpga_prog");
	if (ret) {
		printf("Unable to request fpga_prog\n");
		return 1;
	}

	ret = dm_gpio_lookup_name("GPIO6_2", &fpga_init_in);
	if (ret) {
		printf("Unable to lookup GPIO6_2\n");
		return 1;
	}

	ret = dm_gpio_request(&fpga_init_in, "fpga_init_in");
	if (ret) {
		printf("Unable to request fpga_init_in\n");
		return 1;
	}

	dm_gpio_set_dir_flags(&fpga_init_in, GPIOD_IS_IN);

	fpga_init();

	fpga_add(fpga_xilinx, &fpga);

...

	return 0;
}

-- 
Robert Hancock
Senior Software Developer
SED Systems, a division of Calian Ltd.
Email: hancock at sedsystems.ca


More information about the U-Boot mailing list