From 57f0f512b273f60d52568b8c6b77e17f5636edc0 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Wed, 5 Aug 2015 17:04:01 -0300 Subject: Initial import --- drivers/staging/gs_fpgaboot/gs_fpgaboot.c | 389 ++++++++++++++++++++++++++++++ 1 file changed, 389 insertions(+) create mode 100644 drivers/staging/gs_fpgaboot/gs_fpgaboot.c (limited to 'drivers/staging/gs_fpgaboot/gs_fpgaboot.c') diff --git a/drivers/staging/gs_fpgaboot/gs_fpgaboot.c b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c new file mode 100644 index 000000000..a3a10f9a2 --- /dev/null +++ b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c @@ -0,0 +1,389 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gs_fpgaboot.h" +#include "io.h" + +#define DEVICE_NAME "device" +#define CLASS_NAME "fpgaboot" + +static uint8_t bits_magic[] = { + 0x0, 0x9, 0xf, 0xf0, 0xf, 0xf0, + 0xf, 0xf0, 0xf, 0xf0, 0x0, 0x0, 0x1}; + +/* fake device for request_firmware */ +static struct platform_device *firmware_pdev; + +static char *file = "xlinx_fpga_firmware.bit"; +module_param(file, charp, S_IRUGO); +MODULE_PARM_DESC(file, "Xilinx FPGA firmware file."); + +static void read_bitstream(char *bitdata, char *buf, int *offset, int rdsize) +{ + memcpy(buf, bitdata + *offset, rdsize); + *offset += rdsize; +} + +static void readinfo_bitstream(char *bitdata, char *buf, int *offset) +{ + char tbuf[64]; + int32_t len; + + /* read section char */ + read_bitstream(bitdata, tbuf, offset, 1); + + /* read length */ + read_bitstream(bitdata, tbuf, offset, 2); + + len = tbuf[0] << 8 | tbuf[1]; + + read_bitstream(bitdata, buf, offset, len); + buf[len] = '\0'; +} + +/* + * read bitdata length + */ +static int readlength_bitstream(char *bitdata, int *lendata, int *offset) +{ + char tbuf[64]; + + /* read section char */ + read_bitstream(bitdata, tbuf, offset, 1); + + /* make sure it is section 'e' */ + if (tbuf[0] != 'e') { + pr_err("error: length section is not 'e', but %c\n", tbuf[0]); + return -1; + } + + /* read 4bytes length */ + read_bitstream(bitdata, tbuf, offset, 4); + + *lendata = tbuf[0] << 24 | tbuf[1] << 16 | + tbuf[2] << 8 | tbuf[3]; + + return 0; +} + + +/* + * read first 13 bytes to check bitstream magic number + */ +static int readmagic_bitstream(char *bitdata, int *offset) +{ + char buf[13]; + int r; + + read_bitstream(bitdata, buf, offset, 13); + r = memcmp(buf, bits_magic, 13); + if (r) { + pr_err("error: corrupted header"); + return -1; + } + pr_info("bitstream file magic number Ok\n"); + + *offset = 13; /* magic length */ + + return 0; +} + +/* + * NOTE: supports only bitstream format + */ +static enum fmt_image get_imageformat(struct fpgaimage *fimage) +{ + return f_bit; +} + +static void gs_print_header(struct fpgaimage *fimage) +{ + pr_info("file: %s\n", fimage->filename); + pr_info("part: %s\n", fimage->part); + pr_info("date: %s\n", fimage->date); + pr_info("time: %s\n", fimage->time); + pr_info("lendata: %d\n", fimage->lendata); +} + +static void gs_read_bitstream(struct fpgaimage *fimage) +{ + char *bitdata; + int offset; + + offset = 0; + bitdata = (char *)fimage->fw_entry->data; + + readmagic_bitstream(bitdata, &offset); + readinfo_bitstream(bitdata, fimage->filename, &offset); + readinfo_bitstream(bitdata, fimage->part, &offset); + readinfo_bitstream(bitdata, fimage->date, &offset); + readinfo_bitstream(bitdata, fimage->time, &offset); + readlength_bitstream(bitdata, &fimage->lendata, &offset); + + fimage->fpgadata = bitdata + offset; +} + +static int gs_read_image(struct fpgaimage *fimage) +{ + int img_fmt; + + img_fmt = get_imageformat(fimage); + + switch (img_fmt) { + case f_bit: + pr_info("image is bitstream format\n"); + gs_read_bitstream(fimage); + break; + default: + pr_err("unsupported fpga image format\n"); + return -1; + } + + gs_print_header(fimage); + + return 0; +} + +static int gs_load_image(struct fpgaimage *fimage, char *fw_file) +{ + int err; + + pr_info("load fpgaimage %s\n", fw_file); + + err = request_firmware(&fimage->fw_entry, fw_file, &firmware_pdev->dev); + if (err != 0) { + pr_err("firmware %s is missing, cannot continue.\n", fw_file); + return err; + } + + return 0; +} + +static int gs_download_image(struct fpgaimage *fimage, enum wbus bus_bytes) +{ + char *bitdata; + int size, i, cnt; + + cnt = 0; + bitdata = (char *)fimage->fpgadata; + size = fimage->lendata; + +#ifdef DEBUG_FPGA + print_hex_dump_bytes("bitfile sample: ", DUMP_PREFIX_OFFSET, + bitdata, 0x100); +#endif /* DEBUG_FPGA */ + if (!xl_supported_prog_bus_width(bus_bytes)) { + pr_err("unsupported program bus width %d\n", + bus_bytes); + return -1; + } + + /* Bring csi_b, rdwr_b Low and program_b High */ + xl_program_b(1); + xl_rdwr_b(0); + xl_csi_b(0); + + /* Configuration reset */ + xl_program_b(0); + msleep(20); + xl_program_b(1); + + /* Wait for Device Initialization */ + while (xl_get_init_b() == 0) + ; + + pr_info("device init done\n"); + + for (i = 0; i < size; i += bus_bytes) + xl_shift_bytes_out(bus_bytes, bitdata+i); + + pr_info("program done\n"); + + /* Check INIT_B */ + if (xl_get_init_b() == 0) { + pr_err("init_b 0\n"); + return -1; + } + + while (xl_get_done_b() == 0) { + if (cnt++ > MAX_WAIT_DONE) { + pr_err("init_B %d\n", xl_get_init_b()); + break; + } + } + + if (cnt > MAX_WAIT_DONE) { + pr_err("fpga download fail\n"); + return -1; + } + + pr_info("download fpgaimage\n"); + + /* Compensate for Special Startup Conditions */ + xl_shift_cclk(8); + + return 0; +} + +static int gs_release_image(struct fpgaimage *fimage) +{ + release_firmware(fimage->fw_entry); + pr_info("release fpgaimage\n"); + + return 0; +} + +/* + * NOTE: supports systemmap parallel programming + */ +static int gs_set_download_method(struct fpgaimage *fimage) +{ + pr_info("set program method\n"); + + fimage->dmethod = m_systemmap; + + pr_info("systemmap program method\n"); + + return 0; +} + +static int init_driver(void) +{ + firmware_pdev = platform_device_register_simple("fpgaboot", -1, + NULL, 0); + return PTR_ERR_OR_ZERO(firmware_pdev); +} + +static void finish_driver(void) +{ + platform_device_unregister(firmware_pdev); +} + +static int gs_fpgaboot(void) +{ + int err; + struct fpgaimage *fimage; + + fimage = kmalloc(sizeof(struct fpgaimage), GFP_KERNEL); + if (!fimage) + return -ENOMEM; + + err = gs_load_image(fimage, file); + if (err) { + pr_err("gs_load_image error\n"); + goto err_out1; + } + + err = gs_read_image(fimage); + if (err) { + pr_err("gs_read_image error\n"); + goto err_out2; + } + + err = gs_set_download_method(fimage); + if (err) { + pr_err("gs_set_download_method error\n"); + goto err_out2; + } + + err = gs_download_image(fimage, bus_2byte); + if (err) { + pr_err("gs_download_image error\n"); + goto err_out2; + } + + err = gs_release_image(fimage); + if (err) { + pr_err("gs_release_image error\n"); + goto err_out1; + } + + kfree(fimage); + return 0; + +err_out2: + err = gs_release_image(fimage); + if (err) + pr_err("gs_release_image error\n"); +err_out1: + kfree(fimage); + + return -1; + +} + +static int __init gs_fpgaboot_init(void) +{ + int err; + + pr_info("FPGA DOWNLOAD --->\n"); + + pr_info("FPGA image file name: %s\n", file); + + err = init_driver(); + if (err) { + pr_err("FPGA DRIVER INIT FAIL!!\n"); + return err; + } + + err = xl_init_io(); + if (err) { + pr_err("GPIO INIT FAIL!!\n"); + goto errout; + } + + err = gs_fpgaboot(); + if (err) { + pr_err("FPGA DOWNLOAD FAIL!!\n"); + goto errout; + } + + pr_info("FPGA DOWNLOAD DONE <---\n"); + + return 0; + +errout: + finish_driver(); + + return err; +} + +static void __exit gs_fpgaboot_exit(void) +{ + finish_driver(); + pr_info("FPGA image download module removed\n"); +} + +module_init(gs_fpgaboot_init); +module_exit(gs_fpgaboot_exit); + +MODULE_AUTHOR("Insop Song"); +MODULE_DESCRIPTION("Xlinix FPGA firmware download"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-54-g00ecf