18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * FPGA Manager Driver for Altera Arria10 SoCFPGA 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2015-2016 Altera Corporation 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/clk.h> 88c2ecf20Sopenharmony_ci#include <linux/device.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/fpga/fpga-mgr.h> 118c2ecf20Sopenharmony_ci#include <linux/io.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/of_address.h> 148c2ecf20Sopenharmony_ci#include <linux/regmap.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#define A10_FPGAMGR_DCLKCNT_OFST 0x08 178c2ecf20Sopenharmony_ci#define A10_FPGAMGR_DCLKSTAT_OFST 0x0c 188c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_00_OFST 0x70 198c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_01_OFST 0x74 208c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_02_OFST 0x78 218c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_STAT_OFST 0x80 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define A10_FPGAMGR_DCLKSTAT_DCLKDONE BIT(0) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NCONFIG BIT(0) 268c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NSTATUS BIT(1) 278c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_CONDONE BIT(2) 288c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG BIT(8) 298c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_NSTATUS_OE BIT(16) 308c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_00_S2F_CONDONE_OE BIT(24) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG BIT(0) 338c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST BIT(16) 348c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_01_S2F_NCE BIT(24) 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL BIT(0) 378c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_02_CDRATIO_MASK (BIT(16) | BIT(17)) 388c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SHIFT 16 398c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH BIT(24) 408c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH_SHIFT 24 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_STAT_F2S_CRC_ERROR BIT(0) 438c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_STAT_F2S_EARLY_USERMODE BIT(1) 448c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_STAT_F2S_USERMODE BIT(2) 458c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN BIT(4) 468c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN BIT(6) 478c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_STAT_F2S_PR_READY BIT(9) 488c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_STAT_F2S_PR_DONE BIT(10) 498c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_STAT_F2S_PR_ERROR BIT(11) 508c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_STAT_F2S_NCONFIG_PIN BIT(12) 518c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_STAT_F2S_MSEL_MASK (BIT(16) | BIT(17) | BIT(18)) 528c2ecf20Sopenharmony_ci#define A10_FPGAMGR_IMGCFG_STAT_F2S_MSEL_SHIFT 16 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* FPGA CD Ratio Value */ 558c2ecf20Sopenharmony_ci#define CDRATIO_x1 0x0 568c2ecf20Sopenharmony_ci#define CDRATIO_x2 0x1 578c2ecf20Sopenharmony_ci#define CDRATIO_x4 0x2 588c2ecf20Sopenharmony_ci#define CDRATIO_x8 0x3 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* Configuration width 16/32 bit */ 618c2ecf20Sopenharmony_ci#define CFGWDTH_32 1 628c2ecf20Sopenharmony_ci#define CFGWDTH_16 0 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* 658c2ecf20Sopenharmony_ci * struct a10_fpga_priv - private data for fpga manager 668c2ecf20Sopenharmony_ci * @regmap: regmap for register access 678c2ecf20Sopenharmony_ci * @fpga_data_addr: iomap for single address data register to FPGA 688c2ecf20Sopenharmony_ci * @clk: clock 698c2ecf20Sopenharmony_ci */ 708c2ecf20Sopenharmony_cistruct a10_fpga_priv { 718c2ecf20Sopenharmony_ci struct regmap *regmap; 728c2ecf20Sopenharmony_ci void __iomem *fpga_data_addr; 738c2ecf20Sopenharmony_ci struct clk *clk; 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic bool socfpga_a10_fpga_writeable_reg(struct device *dev, unsigned int reg) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci switch (reg) { 798c2ecf20Sopenharmony_ci case A10_FPGAMGR_DCLKCNT_OFST: 808c2ecf20Sopenharmony_ci case A10_FPGAMGR_DCLKSTAT_OFST: 818c2ecf20Sopenharmony_ci case A10_FPGAMGR_IMGCFG_CTL_00_OFST: 828c2ecf20Sopenharmony_ci case A10_FPGAMGR_IMGCFG_CTL_01_OFST: 838c2ecf20Sopenharmony_ci case A10_FPGAMGR_IMGCFG_CTL_02_OFST: 848c2ecf20Sopenharmony_ci return true; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci return false; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic bool socfpga_a10_fpga_readable_reg(struct device *dev, unsigned int reg) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci switch (reg) { 928c2ecf20Sopenharmony_ci case A10_FPGAMGR_DCLKCNT_OFST: 938c2ecf20Sopenharmony_ci case A10_FPGAMGR_DCLKSTAT_OFST: 948c2ecf20Sopenharmony_ci case A10_FPGAMGR_IMGCFG_CTL_00_OFST: 958c2ecf20Sopenharmony_ci case A10_FPGAMGR_IMGCFG_CTL_01_OFST: 968c2ecf20Sopenharmony_ci case A10_FPGAMGR_IMGCFG_CTL_02_OFST: 978c2ecf20Sopenharmony_ci case A10_FPGAMGR_IMGCFG_STAT_OFST: 988c2ecf20Sopenharmony_ci return true; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci return false; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic const struct regmap_config socfpga_a10_fpga_regmap_config = { 1048c2ecf20Sopenharmony_ci .reg_bits = 32, 1058c2ecf20Sopenharmony_ci .reg_stride = 4, 1068c2ecf20Sopenharmony_ci .val_bits = 32, 1078c2ecf20Sopenharmony_ci .writeable_reg = socfpga_a10_fpga_writeable_reg, 1088c2ecf20Sopenharmony_ci .readable_reg = socfpga_a10_fpga_readable_reg, 1098c2ecf20Sopenharmony_ci .max_register = A10_FPGAMGR_IMGCFG_STAT_OFST, 1108c2ecf20Sopenharmony_ci .cache_type = REGCACHE_NONE, 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/* 1148c2ecf20Sopenharmony_ci * from the register map description of cdratio in imgcfg_ctrl_02: 1158c2ecf20Sopenharmony_ci * Normal Configuration : 32bit Passive Parallel 1168c2ecf20Sopenharmony_ci * Partial Reconfiguration : 16bit Passive Parallel 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_cistatic void socfpga_a10_fpga_set_cfg_width(struct a10_fpga_priv *priv, 1198c2ecf20Sopenharmony_ci int width) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci width <<= A10_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH_SHIFT; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST, 1248c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_02_CFGWIDTH, width); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic void socfpga_a10_fpga_generate_dclks(struct a10_fpga_priv *priv, 1288c2ecf20Sopenharmony_ci u32 count) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci u32 val; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* Clear any existing DONE status. */ 1338c2ecf20Sopenharmony_ci regmap_write(priv->regmap, A10_FPGAMGR_DCLKSTAT_OFST, 1348c2ecf20Sopenharmony_ci A10_FPGAMGR_DCLKSTAT_DCLKDONE); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* Issue the DCLK regmap. */ 1378c2ecf20Sopenharmony_ci regmap_write(priv->regmap, A10_FPGAMGR_DCLKCNT_OFST, count); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* wait till the dclkcnt done */ 1408c2ecf20Sopenharmony_ci regmap_read_poll_timeout(priv->regmap, A10_FPGAMGR_DCLKSTAT_OFST, val, 1418c2ecf20Sopenharmony_ci val, 1, 100); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* Clear DONE status. */ 1448c2ecf20Sopenharmony_ci regmap_write(priv->regmap, A10_FPGAMGR_DCLKSTAT_OFST, 1458c2ecf20Sopenharmony_ci A10_FPGAMGR_DCLKSTAT_DCLKDONE); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci#define RBF_ENCRYPTION_MODE_OFFSET 69 1498c2ecf20Sopenharmony_ci#define RBF_DECOMPRESS_OFFSET 229 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic int socfpga_a10_fpga_encrypted(u32 *buf32, size_t buf32_size) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci if (buf32_size < RBF_ENCRYPTION_MODE_OFFSET + 1) 1548c2ecf20Sopenharmony_ci return -EINVAL; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* Is the bitstream encrypted? */ 1578c2ecf20Sopenharmony_ci return ((buf32[RBF_ENCRYPTION_MODE_OFFSET] >> 2) & 3) != 0; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic int socfpga_a10_fpga_compressed(u32 *buf32, size_t buf32_size) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci if (buf32_size < RBF_DECOMPRESS_OFFSET + 1) 1638c2ecf20Sopenharmony_ci return -EINVAL; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* Is the bitstream compressed? */ 1668c2ecf20Sopenharmony_ci return !((buf32[RBF_DECOMPRESS_OFFSET] >> 1) & 1); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic unsigned int socfpga_a10_fpga_get_cd_ratio(unsigned int cfg_width, 1708c2ecf20Sopenharmony_ci bool encrypt, bool compress) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci unsigned int cd_ratio; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* 1758c2ecf20Sopenharmony_ci * cd ratio is dependent on cfg width and whether the bitstream 1768c2ecf20Sopenharmony_ci * is encrypted and/or compressed. 1778c2ecf20Sopenharmony_ci * 1788c2ecf20Sopenharmony_ci * | width | encr. | compr. | cd ratio | 1798c2ecf20Sopenharmony_ci * | 16 | 0 | 0 | 1 | 1808c2ecf20Sopenharmony_ci * | 16 | 0 | 1 | 4 | 1818c2ecf20Sopenharmony_ci * | 16 | 1 | 0 | 2 | 1828c2ecf20Sopenharmony_ci * | 16 | 1 | 1 | 4 | 1838c2ecf20Sopenharmony_ci * | 32 | 0 | 0 | 1 | 1848c2ecf20Sopenharmony_ci * | 32 | 0 | 1 | 8 | 1858c2ecf20Sopenharmony_ci * | 32 | 1 | 0 | 4 | 1868c2ecf20Sopenharmony_ci * | 32 | 1 | 1 | 8 | 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_ci if (!compress && !encrypt) 1898c2ecf20Sopenharmony_ci return CDRATIO_x1; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (compress) 1928c2ecf20Sopenharmony_ci cd_ratio = CDRATIO_x4; 1938c2ecf20Sopenharmony_ci else 1948c2ecf20Sopenharmony_ci cd_ratio = CDRATIO_x2; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* If 32 bit, double the cd ratio by incrementing the field */ 1978c2ecf20Sopenharmony_ci if (cfg_width == CFGWDTH_32) 1988c2ecf20Sopenharmony_ci cd_ratio += 1; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return cd_ratio; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int socfpga_a10_fpga_set_cdratio(struct fpga_manager *mgr, 2048c2ecf20Sopenharmony_ci unsigned int cfg_width, 2058c2ecf20Sopenharmony_ci const char *buf, size_t count) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci struct a10_fpga_priv *priv = mgr->priv; 2088c2ecf20Sopenharmony_ci unsigned int cd_ratio; 2098c2ecf20Sopenharmony_ci int encrypt, compress; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci encrypt = socfpga_a10_fpga_encrypted((u32 *)buf, count / 4); 2128c2ecf20Sopenharmony_ci if (encrypt < 0) 2138c2ecf20Sopenharmony_ci return -EINVAL; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci compress = socfpga_a10_fpga_compressed((u32 *)buf, count / 4); 2168c2ecf20Sopenharmony_ci if (compress < 0) 2178c2ecf20Sopenharmony_ci return -EINVAL; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci cd_ratio = socfpga_a10_fpga_get_cd_ratio(cfg_width, encrypt, compress); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST, 2228c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_02_CDRATIO_MASK, 2238c2ecf20Sopenharmony_ci cd_ratio << A10_FPGAMGR_IMGCFG_CTL_02_CDRATIO_SHIFT); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return 0; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic u32 socfpga_a10_fpga_read_stat(struct a10_fpga_priv *priv) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci u32 val; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci regmap_read(priv->regmap, A10_FPGAMGR_IMGCFG_STAT_OFST, &val); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return val; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int socfpga_a10_fpga_wait_for_pr_ready(struct a10_fpga_priv *priv) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci u32 reg, i; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci for (i = 0; i < 10 ; i++) { 2428c2ecf20Sopenharmony_ci reg = socfpga_a10_fpga_read_stat(priv); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_ERROR) 2458c2ecf20Sopenharmony_ci return -EINVAL; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_READY) 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int socfpga_a10_fpga_wait_for_pr_done(struct a10_fpga_priv *priv) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci u32 reg, i; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci for (i = 0; i < 10 ; i++) { 2598c2ecf20Sopenharmony_ci reg = socfpga_a10_fpga_read_stat(priv); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_ERROR) 2628c2ecf20Sopenharmony_ci return -EINVAL; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_DONE) 2658c2ecf20Sopenharmony_ci return 0; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci/* Start the FPGA programming by initialize the FPGA Manager */ 2728c2ecf20Sopenharmony_cistatic int socfpga_a10_fpga_write_init(struct fpga_manager *mgr, 2738c2ecf20Sopenharmony_ci struct fpga_image_info *info, 2748c2ecf20Sopenharmony_ci const char *buf, size_t count) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci struct a10_fpga_priv *priv = mgr->priv; 2778c2ecf20Sopenharmony_ci unsigned int cfg_width; 2788c2ecf20Sopenharmony_ci u32 msel, stat, mask; 2798c2ecf20Sopenharmony_ci int ret; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) 2828c2ecf20Sopenharmony_ci cfg_width = CFGWDTH_16; 2838c2ecf20Sopenharmony_ci else 2848c2ecf20Sopenharmony_ci return -EINVAL; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* Check for passive parallel (msel == 000 or 001) */ 2878c2ecf20Sopenharmony_ci msel = socfpga_a10_fpga_read_stat(priv); 2888c2ecf20Sopenharmony_ci msel &= A10_FPGAMGR_IMGCFG_STAT_F2S_MSEL_MASK; 2898c2ecf20Sopenharmony_ci msel >>= A10_FPGAMGR_IMGCFG_STAT_F2S_MSEL_SHIFT; 2908c2ecf20Sopenharmony_ci if ((msel != 0) && (msel != 1)) { 2918c2ecf20Sopenharmony_ci dev_dbg(&mgr->dev, "Fail: invalid msel=%d\n", msel); 2928c2ecf20Sopenharmony_ci return -EINVAL; 2938c2ecf20Sopenharmony_ci } 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* Make sure no external devices are interfering */ 2968c2ecf20Sopenharmony_ci stat = socfpga_a10_fpga_read_stat(priv); 2978c2ecf20Sopenharmony_ci mask = A10_FPGAMGR_IMGCFG_STAT_F2S_NCONFIG_PIN | 2988c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN; 2998c2ecf20Sopenharmony_ci if ((stat & mask) != mask) 3008c2ecf20Sopenharmony_ci return -EINVAL; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* Set cfg width */ 3038c2ecf20Sopenharmony_ci socfpga_a10_fpga_set_cfg_width(priv, cfg_width); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* Determine cd ratio from bitstream header and set cd ratio */ 3068c2ecf20Sopenharmony_ci ret = socfpga_a10_fpga_set_cdratio(mgr, cfg_width, buf, count); 3078c2ecf20Sopenharmony_ci if (ret) 3088c2ecf20Sopenharmony_ci return ret; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* 3118c2ecf20Sopenharmony_ci * Clear s2f_nce to enable chip select. Leave pr_request 3128c2ecf20Sopenharmony_ci * unasserted and override disabled. 3138c2ecf20Sopenharmony_ci */ 3148c2ecf20Sopenharmony_ci regmap_write(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, 3158c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* Set cfg_ctrl to enable s2f dclk and data */ 3188c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST, 3198c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL, 3208c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci /* 3238c2ecf20Sopenharmony_ci * Disable overrides not needed for pr. 3248c2ecf20Sopenharmony_ci * s2f_config==1 leaves reset deasseted. 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_ci regmap_write(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_00_OFST, 3278c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NCONFIG | 3288c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_NSTATUS | 3298c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_00_S2F_NENABLE_CONDONE | 3308c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_00_S2F_NCONFIG); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Enable override for data, dclk, nce, and pr_request to CSS */ 3338c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, 3348c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG, 0); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci /* Send some clocks to clear out any errors */ 3378c2ecf20Sopenharmony_ci socfpga_a10_fpga_generate_dclks(priv, 256); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* Assert pr_request */ 3408c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, 3418c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST, 3428c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci /* Provide 2048 DCLKs before starting the config data streaming. */ 3458c2ecf20Sopenharmony_ci socfpga_a10_fpga_generate_dclks(priv, 0x7ff); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* Wait for pr_ready */ 3488c2ecf20Sopenharmony_ci return socfpga_a10_fpga_wait_for_pr_ready(priv); 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci/* 3528c2ecf20Sopenharmony_ci * write data to the FPGA data register 3538c2ecf20Sopenharmony_ci */ 3548c2ecf20Sopenharmony_cistatic int socfpga_a10_fpga_write(struct fpga_manager *mgr, const char *buf, 3558c2ecf20Sopenharmony_ci size_t count) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci struct a10_fpga_priv *priv = mgr->priv; 3588c2ecf20Sopenharmony_ci u32 *buffer_32 = (u32 *)buf; 3598c2ecf20Sopenharmony_ci size_t i = 0; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (count <= 0) 3628c2ecf20Sopenharmony_ci return -EINVAL; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci /* Write out the complete 32-bit chunks */ 3658c2ecf20Sopenharmony_ci while (count >= sizeof(u32)) { 3668c2ecf20Sopenharmony_ci writel(buffer_32[i++], priv->fpga_data_addr); 3678c2ecf20Sopenharmony_ci count -= sizeof(u32); 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* Write out remaining non 32-bit chunks */ 3718c2ecf20Sopenharmony_ci switch (count) { 3728c2ecf20Sopenharmony_ci case 3: 3738c2ecf20Sopenharmony_ci writel(buffer_32[i++] & 0x00ffffff, priv->fpga_data_addr); 3748c2ecf20Sopenharmony_ci break; 3758c2ecf20Sopenharmony_ci case 2: 3768c2ecf20Sopenharmony_ci writel(buffer_32[i++] & 0x0000ffff, priv->fpga_data_addr); 3778c2ecf20Sopenharmony_ci break; 3788c2ecf20Sopenharmony_ci case 1: 3798c2ecf20Sopenharmony_ci writel(buffer_32[i++] & 0x000000ff, priv->fpga_data_addr); 3808c2ecf20Sopenharmony_ci break; 3818c2ecf20Sopenharmony_ci case 0: 3828c2ecf20Sopenharmony_ci break; 3838c2ecf20Sopenharmony_ci default: 3848c2ecf20Sopenharmony_ci /* This will never happen */ 3858c2ecf20Sopenharmony_ci return -EFAULT; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci return 0; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_cistatic int socfpga_a10_fpga_write_complete(struct fpga_manager *mgr, 3928c2ecf20Sopenharmony_ci struct fpga_image_info *info) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct a10_fpga_priv *priv = mgr->priv; 3958c2ecf20Sopenharmony_ci u32 reg; 3968c2ecf20Sopenharmony_ci int ret; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* Wait for pr_done */ 3998c2ecf20Sopenharmony_ci ret = socfpga_a10_fpga_wait_for_pr_done(priv); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* Clear pr_request */ 4028c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, 4038c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_01_S2F_PR_REQUEST, 0); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci /* Send some clocks to clear out any errors */ 4068c2ecf20Sopenharmony_ci socfpga_a10_fpga_generate_dclks(priv, 256); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* Disable s2f dclk and data */ 4098c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_02_OFST, 4108c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_02_EN_CFG_CTRL, 0); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci /* Deassert chip select */ 4138c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, 4148c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_01_S2F_NCE, 4158c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_01_S2F_NCE); 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci /* Disable data, dclk, nce, and pr_request override to CSS */ 4188c2ecf20Sopenharmony_ci regmap_update_bits(priv->regmap, A10_FPGAMGR_IMGCFG_CTL_01_OFST, 4198c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG, 4208c2ecf20Sopenharmony_ci A10_FPGAMGR_IMGCFG_CTL_01_S2F_NENABLE_CONFIG); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* Return any errors regarding pr_done or pr_error */ 4238c2ecf20Sopenharmony_ci if (ret) 4248c2ecf20Sopenharmony_ci return ret; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* Final check */ 4278c2ecf20Sopenharmony_ci reg = socfpga_a10_fpga_read_stat(priv); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_USERMODE) == 0) || 4308c2ecf20Sopenharmony_ci ((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_CONDONE_PIN) == 0) || 4318c2ecf20Sopenharmony_ci ((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN) == 0)) { 4328c2ecf20Sopenharmony_ci dev_dbg(&mgr->dev, 4338c2ecf20Sopenharmony_ci "Timeout in final check. Status=%08xf\n", reg); 4348c2ecf20Sopenharmony_ci return -ETIMEDOUT; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci return 0; 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_cistatic enum fpga_mgr_states socfpga_a10_fpga_state(struct fpga_manager *mgr) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct a10_fpga_priv *priv = mgr->priv; 4438c2ecf20Sopenharmony_ci u32 reg = socfpga_a10_fpga_read_stat(priv); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_USERMODE) 4468c2ecf20Sopenharmony_ci return FPGA_MGR_STATE_OPERATING; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_PR_READY) 4498c2ecf20Sopenharmony_ci return FPGA_MGR_STATE_WRITE; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (reg & A10_FPGAMGR_IMGCFG_STAT_F2S_CRC_ERROR) 4528c2ecf20Sopenharmony_ci return FPGA_MGR_STATE_WRITE_COMPLETE_ERR; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if ((reg & A10_FPGAMGR_IMGCFG_STAT_F2S_NSTATUS_PIN) == 0) 4558c2ecf20Sopenharmony_ci return FPGA_MGR_STATE_RESET; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci return FPGA_MGR_STATE_UNKNOWN; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic const struct fpga_manager_ops socfpga_a10_fpga_mgr_ops = { 4618c2ecf20Sopenharmony_ci .initial_header_size = (RBF_DECOMPRESS_OFFSET + 1) * 4, 4628c2ecf20Sopenharmony_ci .state = socfpga_a10_fpga_state, 4638c2ecf20Sopenharmony_ci .write_init = socfpga_a10_fpga_write_init, 4648c2ecf20Sopenharmony_ci .write = socfpga_a10_fpga_write, 4658c2ecf20Sopenharmony_ci .write_complete = socfpga_a10_fpga_write_complete, 4668c2ecf20Sopenharmony_ci}; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic int socfpga_a10_fpga_probe(struct platform_device *pdev) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 4718c2ecf20Sopenharmony_ci struct a10_fpga_priv *priv; 4728c2ecf20Sopenharmony_ci void __iomem *reg_base; 4738c2ecf20Sopenharmony_ci struct fpga_manager *mgr; 4748c2ecf20Sopenharmony_ci struct resource *res; 4758c2ecf20Sopenharmony_ci int ret; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 4788c2ecf20Sopenharmony_ci if (!priv) 4798c2ecf20Sopenharmony_ci return -ENOMEM; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* First mmio base is for register access */ 4828c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 4838c2ecf20Sopenharmony_ci reg_base = devm_ioremap_resource(dev, res); 4848c2ecf20Sopenharmony_ci if (IS_ERR(reg_base)) 4858c2ecf20Sopenharmony_ci return PTR_ERR(reg_base); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* Second mmio base is for writing FPGA image data */ 4888c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 4898c2ecf20Sopenharmony_ci priv->fpga_data_addr = devm_ioremap_resource(dev, res); 4908c2ecf20Sopenharmony_ci if (IS_ERR(priv->fpga_data_addr)) 4918c2ecf20Sopenharmony_ci return PTR_ERR(priv->fpga_data_addr); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* regmap for register access */ 4948c2ecf20Sopenharmony_ci priv->regmap = devm_regmap_init_mmio(dev, reg_base, 4958c2ecf20Sopenharmony_ci &socfpga_a10_fpga_regmap_config); 4968c2ecf20Sopenharmony_ci if (IS_ERR(priv->regmap)) 4978c2ecf20Sopenharmony_ci return -ENODEV; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci priv->clk = devm_clk_get(dev, NULL); 5008c2ecf20Sopenharmony_ci if (IS_ERR(priv->clk)) { 5018c2ecf20Sopenharmony_ci dev_err(dev, "no clock specified\n"); 5028c2ecf20Sopenharmony_ci return PTR_ERR(priv->clk); 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 5068c2ecf20Sopenharmony_ci if (ret) { 5078c2ecf20Sopenharmony_ci dev_err(dev, "could not enable clock\n"); 5088c2ecf20Sopenharmony_ci return -EBUSY; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci mgr = devm_fpga_mgr_create(dev, "SoCFPGA Arria10 FPGA Manager", 5128c2ecf20Sopenharmony_ci &socfpga_a10_fpga_mgr_ops, priv); 5138c2ecf20Sopenharmony_ci if (!mgr) 5148c2ecf20Sopenharmony_ci return -ENOMEM; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, mgr); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci ret = fpga_mgr_register(mgr); 5198c2ecf20Sopenharmony_ci if (ret) { 5208c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 5218c2ecf20Sopenharmony_ci return ret; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci return 0; 5258c2ecf20Sopenharmony_ci} 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_cistatic int socfpga_a10_fpga_remove(struct platform_device *pdev) 5288c2ecf20Sopenharmony_ci{ 5298c2ecf20Sopenharmony_ci struct fpga_manager *mgr = platform_get_drvdata(pdev); 5308c2ecf20Sopenharmony_ci struct a10_fpga_priv *priv = mgr->priv; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci fpga_mgr_unregister(mgr); 5338c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci return 0; 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic const struct of_device_id socfpga_a10_fpga_of_match[] = { 5398c2ecf20Sopenharmony_ci { .compatible = "altr,socfpga-a10-fpga-mgr", }, 5408c2ecf20Sopenharmony_ci {}, 5418c2ecf20Sopenharmony_ci}; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, socfpga_a10_fpga_of_match); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic struct platform_driver socfpga_a10_fpga_driver = { 5468c2ecf20Sopenharmony_ci .probe = socfpga_a10_fpga_probe, 5478c2ecf20Sopenharmony_ci .remove = socfpga_a10_fpga_remove, 5488c2ecf20Sopenharmony_ci .driver = { 5498c2ecf20Sopenharmony_ci .name = "socfpga_a10_fpga_manager", 5508c2ecf20Sopenharmony_ci .of_match_table = socfpga_a10_fpga_of_match, 5518c2ecf20Sopenharmony_ci }, 5528c2ecf20Sopenharmony_ci}; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cimodule_platform_driver(socfpga_a10_fpga_driver); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>"); 5578c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SoCFPGA Arria10 FPGA Manager"); 5588c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 559