diff --git a/drivers/fpga/altera-cvp.c b/drivers/fpga/altera-cvp.c index 070c025ee215..507e29d3a79f 100644 --- a/drivers/fpga/altera-cvp.c +++ b/drivers/fpga/altera-cvp.c @@ -280,6 +280,16 @@ static int altera_cvp_send_block(struct altera_cvp_conf *conf, return 0; } +static void altera_cvp_disable_cvp_mode(struct altera_cvp_conf *conf) +{ + u32 val; + + altera_read_config_dword(conf, VSE_CVP_MODE_CTRL, &val); + val &= ~VSE_CVP_MODE_CTRL_HIP_CLK_SEL; + val &= ~VSE_CVP_MODE_CTRL_CVP_MODE; + altera_write_config_dword(conf, VSE_CVP_MODE_CTRL, val); +} + static int altera_cvp_teardown(struct fpga_manager *mgr, struct fpga_image_info *info) { @@ -308,7 +318,29 @@ static int altera_cvp_teardown(struct fpga_manager *mgr, ret = altera_cvp_wait_status(conf, VSE_CVP_STATUS_CFG_RDY, 0, conf->priv->poll_time_us); if (ret) - dev_err(&mgr->dev, "CFG_RDY == 0 timeout\n"); + dev_warn(&mgr->dev, "CFG_RDY == 0 timeout\n"); + + return ret; +} + +static int altera_cvp_recovery(struct fpga_manager *mgr, + struct fpga_image_info *info) +{ + struct altera_cvp_conf *conf = mgr->priv; + int ret; + + ret = altera_cvp_teardown(mgr, info); + if (ret) { + /* + * CVP_STATUS may get stuck if the device left user mode + * before the poll. Exit CvP mode to switch back the clock + * feeding CVP_STATUS, then try the teardown again. + */ + altera_cvp_disable_cvp_mode(conf); + ret = altera_cvp_teardown(mgr, info); + if (ret) + dev_err(&mgr->dev, "Tear-down failed\n"); + } return ret; } @@ -345,7 +377,7 @@ static int altera_cvp_write_init(struct fpga_manager *mgr, if (val & VSE_CVP_STATUS_CFG_RDY) { dev_warn(&mgr->dev, "CvP already started, tear down first\n"); - ret = altera_cvp_teardown(mgr, info); + ret = altera_cvp_recovery(mgr, info); if (ret) return ret; } @@ -486,7 +518,7 @@ static int altera_cvp_write_complete(struct fpga_manager *mgr, u32 mask, val; int ret; - ret = altera_cvp_teardown(mgr, info); + ret = altera_cvp_recovery(mgr, info); if (ret) return ret; @@ -498,10 +530,7 @@ static int altera_cvp_write_complete(struct fpga_manager *mgr, } /* STEP 17 - reset CVP_MODE and HIP_CLK_SEL bit */ - altera_read_config_dword(conf, VSE_CVP_MODE_CTRL, &val); - val &= ~VSE_CVP_MODE_CTRL_HIP_CLK_SEL; - val &= ~VSE_CVP_MODE_CTRL_CVP_MODE; - altera_write_config_dword(conf, VSE_CVP_MODE_CTRL, val); + altera_cvp_disable_cvp_mode(conf); /* STEP 18 - poll PLD_CLK_IN_USE and USER_MODE bits */ mask = VSE_CVP_STATUS_PLD_CLK_IN_USE | VSE_CVP_STATUS_USERMODE; diff --git a/drivers/fpga/dfl.h b/drivers/fpga/dfl.h index 9549f63b00eb..9a65617bb870 100644 --- a/drivers/fpga/dfl.h +++ b/drivers/fpga/dfl.h @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c index 2672070ced02..5a0b7780b335 100644 --- a/drivers/fpga/fpga-mgr.c +++ b/drivers/fpga/fpga-mgr.c @@ -744,7 +744,7 @@ EXPORT_SYMBOL_GPL(fpga_mgr_put); * @mgr: fpga manager * * Given a pointer to FPGA Manager (from fpga_mgr_get() or - * of_fpga_mgr_put()) attempt to get the mutex. The user should call + * of_fpga_mgr_get()) attempt to get the mutex. The user should call * fpga_mgr_lock() and verify that it returns 0 before attempting to * program the FPGA. Likewise, the user should call fpga_mgr_unlock * when done programming the FPGA. diff --git a/drivers/fpga/stratix10-soc.c b/drivers/fpga/stratix10-soc.c index b8ec2e6f615f..5aed560050c2 100644 --- a/drivers/fpga/stratix10-soc.c +++ b/drivers/fpga/stratix10-soc.c @@ -286,7 +286,7 @@ static int s10_ops_write(struct fpga_manager *mgr, const char *buf, /* * Loop waiting for buffers to be returned. When a buffer is returned, - * reuse it to send more data or free if if all data has been sent. + * reuse it to send more data or free it if all data has been sent. */ while (count > 0 || s10_free_buffer_count(mgr) != NUM_SVC_BUFS) { reinit_completion(&priv->status_return_completion); diff --git a/drivers/fpga/xilinx-selectmap.c b/drivers/fpga/xilinx-selectmap.c index d0cbb5fdfe3a..ff167b23fded 100644 --- a/drivers/fpga/xilinx-selectmap.c +++ b/drivers/fpga/xilinx-selectmap.c @@ -19,6 +19,8 @@ struct xilinx_selectmap_conf { struct xilinx_fpga_core core; void __iomem *base; + struct gpio_desc *csi_b; + struct gpio_desc *rdwr_b; }; #define to_xilinx_selectmap_conf(obj) \ @@ -30,16 +32,28 @@ static int xilinx_selectmap_write(struct xilinx_fpga_core *core, struct xilinx_selectmap_conf *conf = to_xilinx_selectmap_conf(core); size_t i; + /* + * Select this device and put its SelectMAP port into write mode. + * + * RDWR_B is set before CSI_B. UG470 describes in chapter + * "SelectMAP ABORT" that changing RDWR_B while the device is + * selected aborts the configuration on the next CCLK. + */ + gpiod_set_value(conf->rdwr_b, 1); + gpiod_set_value(conf->csi_b, 1); + for (i = 0; i < count; ++i) writeb(buf[i], conf->base); + gpiod_set_value(conf->csi_b, 0); + gpiod_set_value(conf->rdwr_b, 0); + return 0; } static int xilinx_selectmap_probe(struct platform_device *pdev) { struct xilinx_selectmap_conf *conf; - struct gpio_desc *gpio; void __iomem *base; conf = devm_kzalloc(&pdev->dev, sizeof(*conf), GFP_KERNEL); @@ -55,16 +69,23 @@ static int xilinx_selectmap_probe(struct platform_device *pdev) "ioremap error\n"); conf->base = base; - /* CSI_B is active low */ - gpio = devm_gpiod_get_optional(&pdev->dev, "csi", GPIOD_OUT_HIGH); - if (IS_ERR(gpio)) - return dev_err_probe(&pdev->dev, PTR_ERR(gpio), + /* + * Request both signals deasserted, so a device sharing the SelectMAP + * bus with others stays off that bus until its bitstream is written. + * + * The value in the gpiod flags is logical, gpiolib drives the line + * high for GPIOD_OUT_LOW when the firmware describes it active low. + */ + conf->csi_b = devm_gpiod_get_optional(&pdev->dev, "csi", + GPIOD_OUT_LOW); + if (IS_ERR(conf->csi_b)) + return dev_err_probe(&pdev->dev, PTR_ERR(conf->csi_b), "Failed to get CSI_B gpio\n"); - /* RDWR_B is active low */ - gpio = devm_gpiod_get_optional(&pdev->dev, "rdwr", GPIOD_OUT_HIGH); - if (IS_ERR(gpio)) - return dev_err_probe(&pdev->dev, PTR_ERR(gpio), + conf->rdwr_b = devm_gpiod_get_optional(&pdev->dev, "rdwr", + GPIOD_OUT_LOW); + if (IS_ERR(conf->rdwr_b)) + return dev_err_probe(&pdev->dev, PTR_ERR(conf->rdwr_b), "Failed to get RDWR_B gpio\n"); return xilinx_core_probe(&conf->core);