static int socfpga_a10_fpga_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct a10_fpga_priv *priv; void __iomem *reg_base; struct fpga_manager *mgr; struct resource *res; int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; /* First mmio base is for register access */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); reg_base = devm_ioremap_resource(dev, res); if (IS_ERR(reg_base)) return PTR_ERR(reg_base); /* Second mmio base is for writing FPGA image data */ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); priv->fpga_data_addr = devm_ioremap_resource(dev, res); if (IS_ERR(priv->fpga_data_addr)) return PTR_ERR(priv->fpga_data_addr); /* regmap for register access */ priv->regmap = devm_regmap_init_mmio(dev, reg_base, &socfpga_a10_fpga_regmap_config); if (IS_ERR(priv->regmap)) return -ENODEV; priv->clk = devm_clk_get(dev, NULL); if (IS_ERR(priv->clk)) { dev_err(dev, "no clock specified\n"); return PTR_ERR(priv->clk); } ret = clk_prepare_enable(priv->clk); if (ret) { dev_err(dev, "could not enable clock\n"); return -EBUSY; } mgr = fpga_mgr_create(dev, "SoCFPGA Arria10 FPGA Manager", &socfpga_a10_fpga_mgr_ops, priv); if (!mgr) return -ENOMEM; platform_set_drvdata(pdev, mgr); ret = fpga_mgr_register(mgr); if (ret) { fpga_mgr_free(mgr); clk_disable_unprepare(priv->clk); return ret; } return 0; }
static int altera_cvp_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) { struct altera_cvp_conf *conf; u16 cmd, val; int ret; /* * First check if this is the expected FPGA device. PCI config * space access works without enabling the PCI device, memory * space access is enabled further down. */ pci_read_config_word(pdev, VSE_PCIE_EXT_CAP_ID, &val); if (val != VSE_PCIE_EXT_CAP_ID_VAL) { dev_err(&pdev->dev, "Wrong EXT_CAP_ID value 0x%x\n", val); return -ENODEV; } conf = devm_kzalloc(&pdev->dev, sizeof(*conf), GFP_KERNEL); if (!conf) return -ENOMEM; /* * Enable memory BAR access. We cannot use pci_enable_device() here * because it will make the driver unusable with FPGA devices that * have additional big IOMEM resources (e.g. 4GiB BARs) on 32-bit * platform. Such BARs will not have an assigned address range and * pci_enable_device() will fail, complaining about not claimed BAR, * even if the concerned BAR is not needed for FPGA configuration * at all. Thus, enable the device via PCI config space command. */ pci_read_config_word(pdev, PCI_COMMAND, &cmd); if (!(cmd & PCI_COMMAND_MEMORY)) { cmd |= PCI_COMMAND_MEMORY; pci_write_config_word(pdev, PCI_COMMAND, cmd); } ret = pci_request_region(pdev, CVP_BAR, "CVP"); if (ret) { dev_err(&pdev->dev, "Requesting CVP BAR region failed\n"); goto err_disable; } conf->pci_dev = pdev; conf->write_data = altera_cvp_write_data_iomem; conf->map = pci_iomap(pdev, CVP_BAR, 0); if (!conf->map) { dev_warn(&pdev->dev, "Mapping CVP BAR failed\n"); conf->write_data = altera_cvp_write_data_config; } snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s @%s", ALTERA_CVP_MGR_NAME, pci_name(pdev)); ret = fpga_mgr_register(&pdev->dev, conf->mgr_name, &altera_cvp_ops, conf); if (ret) goto err_unmap; ret = driver_create_file(&altera_cvp_driver.driver, &driver_attr_chkcfg); if (ret) { dev_err(&pdev->dev, "Can't create sysfs chkcfg file\n"); fpga_mgr_unregister(&pdev->dev); goto err_unmap; } return 0; err_unmap: pci_iounmap(pdev, conf->map); pci_release_region(pdev, CVP_BAR); err_disable: cmd &= ~PCI_COMMAND_MEMORY; pci_write_config_word(pdev, PCI_COMMAND, cmd); return ret; }
static int ice40_fpga_ops_write_init(struct fpga_manager *mgr, struct fpga_image_info *info, const char *buf, size_t count) { struct ice40_fpga_priv *priv = mgr->priv; struct spi_device *dev = priv->dev; struct spi_message message; struct spi_transfer assert_cs_then_reset_delay = { .cs_change = 1, .delay_usecs = ICE40_SPI_RESET_DELAY }; struct spi_transfer housekeeping_delay_then_release_cs = { .delay_usecs = ICE40_SPI_HOUSEKEEPING_DELAY }; int ret; if ((info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { dev_err(&dev->dev, "Partial reconfiguration is not supported\n"); return -ENOTSUPP; } /* Lock the bus, assert CRESET_B and SS_B and delay >200ns */ spi_bus_lock(dev->master); gpiod_set_value(priv->reset, 1); spi_message_init(&message); spi_message_add_tail(&assert_cs_then_reset_delay, &message); ret = spi_sync_locked(dev, &message); /* Come out of reset */ gpiod_set_value(priv->reset, 0); /* Abort if the chip-select failed */ if (ret) goto fail; /* Check CDONE is de-asserted i.e. the FPGA is reset */ if (gpiod_get_value(priv->cdone)) { dev_err(&dev->dev, "Device reset failed, CDONE is asserted\n"); ret = -EIO; goto fail; } /* Wait for the housekeeping to complete, and release SS_B */ spi_message_init(&message); spi_message_add_tail(&housekeeping_delay_then_release_cs, &message); ret = spi_sync_locked(dev, &message); fail: spi_bus_unlock(dev->master); return ret; } static int ice40_fpga_ops_write(struct fpga_manager *mgr, const char *buf, size_t count) { struct ice40_fpga_priv *priv = mgr->priv; return spi_write(priv->dev, buf, count); } static int ice40_fpga_ops_write_complete(struct fpga_manager *mgr, struct fpga_image_info *info) { struct ice40_fpga_priv *priv = mgr->priv; struct spi_device *dev = priv->dev; const u8 padding[ICE40_SPI_NUM_ACTIVATION_BYTES] = {0}; /* Check CDONE is asserted */ if (!gpiod_get_value(priv->cdone)) { dev_err(&dev->dev, "CDONE was not asserted after firmware transfer\n"); return -EIO; } /* Send of zero-padding to activate the firmware */ return spi_write(dev, padding, sizeof(padding)); } static const struct fpga_manager_ops ice40_fpga_ops = { .state = ice40_fpga_ops_state, .write_init = ice40_fpga_ops_write_init, .write = ice40_fpga_ops_write, .write_complete = ice40_fpga_ops_write_complete, }; static int ice40_fpga_probe(struct spi_device *spi) { struct device *dev = &spi->dev; struct ice40_fpga_priv *priv; struct fpga_manager *mgr; int ret; priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; priv->dev = spi; /* Check board setup data. */ if (spi->max_speed_hz > ICE40_SPI_MAX_SPEED) { dev_err(dev, "SPI speed is too high, maximum speed is " __stringify(ICE40_SPI_MAX_SPEED) "\n"); return -EINVAL; } if (spi->max_speed_hz < ICE40_SPI_MIN_SPEED) { dev_err(dev, "SPI speed is too low, minimum speed is " __stringify(ICE40_SPI_MIN_SPEED) "\n"); return -EINVAL; } if (spi->mode & SPI_CPHA) { dev_err(dev, "Bad SPI mode, CPHA not supported\n"); return -EINVAL; } /* Set up the GPIOs */ priv->cdone = devm_gpiod_get(dev, "cdone", GPIOD_IN); if (IS_ERR(priv->cdone)) { ret = PTR_ERR(priv->cdone); dev_err(dev, "Failed to get CDONE GPIO: %d\n", ret); return ret; } priv->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(priv->reset)) { ret = PTR_ERR(priv->reset); dev_err(dev, "Failed to get CRESET_B GPIO: %d\n", ret); return ret; } mgr = fpga_mgr_create(dev, "Lattice iCE40 FPGA Manager", &ice40_fpga_ops, priv); if (!mgr) return -ENOMEM; spi_set_drvdata(spi, mgr); ret = fpga_mgr_register(mgr); if (ret) fpga_mgr_free(mgr); return ret; } static int ice40_fpga_remove(struct spi_device *spi) { struct fpga_manager *mgr = spi_get_drvdata(spi); fpga_mgr_unregister(mgr); return 0; } static const struct of_device_id ice40_fpga_of_match[] = { { .compatible = "lattice,ice40-fpga-mgr", }, {}, };