18e8e69d6SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
234d1dc17SAnatolij Gustschin /*
334d1dc17SAnatolij Gustschin * FPGA Manager Driver for Altera Arria/Cyclone/Stratix CvP
434d1dc17SAnatolij Gustschin *
534d1dc17SAnatolij Gustschin * Copyright (C) 2017 DENX Software Engineering
634d1dc17SAnatolij Gustschin *
734d1dc17SAnatolij Gustschin * Anatolij Gustschin <agust@denx.de>
834d1dc17SAnatolij Gustschin *
934d1dc17SAnatolij Gustschin * Manage Altera FPGA firmware using PCIe CvP.
1034d1dc17SAnatolij Gustschin * Firmware must be in binary "rbf" format.
1134d1dc17SAnatolij Gustschin */
1234d1dc17SAnatolij Gustschin
1334d1dc17SAnatolij Gustschin #include <linux/delay.h>
1434d1dc17SAnatolij Gustschin #include <linux/device.h>
1534d1dc17SAnatolij Gustschin #include <linux/fpga/fpga-mgr.h>
1634d1dc17SAnatolij Gustschin #include <linux/module.h>
1734d1dc17SAnatolij Gustschin #include <linux/pci.h>
1834d1dc17SAnatolij Gustschin #include <linux/sizes.h>
1934d1dc17SAnatolij Gustschin
2034d1dc17SAnatolij Gustschin #define CVP_BAR 0 /* BAR used for data transfer in memory mode */
2134d1dc17SAnatolij Gustschin #define CVP_DUMMY_WR 244 /* dummy writes to clear CvP state machine */
2234d1dc17SAnatolij Gustschin #define TIMEOUT_US 2000 /* CVP STATUS timeout for USERMODE polling */
2334d1dc17SAnatolij Gustschin
2434d1dc17SAnatolij Gustschin /* Vendor Specific Extended Capability Registers */
25eb12511fSThor Thayer #define VSE_PCIE_EXT_CAP_ID 0x0
2634d1dc17SAnatolij Gustschin #define VSE_PCIE_EXT_CAP_ID_VAL 0x000b /* 16bit */
2734d1dc17SAnatolij Gustschin
28eb12511fSThor Thayer #define VSE_CVP_STATUS 0x1c /* 32bit */
2934d1dc17SAnatolij Gustschin #define VSE_CVP_STATUS_CFG_RDY BIT(18) /* CVP_CONFIG_READY */
3034d1dc17SAnatolij Gustschin #define VSE_CVP_STATUS_CFG_ERR BIT(19) /* CVP_CONFIG_ERROR */
3134d1dc17SAnatolij Gustschin #define VSE_CVP_STATUS_CVP_EN BIT(20) /* ctrl block is enabling CVP */
3234d1dc17SAnatolij Gustschin #define VSE_CVP_STATUS_USERMODE BIT(21) /* USERMODE */
3334d1dc17SAnatolij Gustschin #define VSE_CVP_STATUS_CFG_DONE BIT(23) /* CVP_CONFIG_DONE */
3434d1dc17SAnatolij Gustschin #define VSE_CVP_STATUS_PLD_CLK_IN_USE BIT(24) /* PLD_CLK_IN_USE */
3534d1dc17SAnatolij Gustschin
36eb12511fSThor Thayer #define VSE_CVP_MODE_CTRL 0x20 /* 32bit */
3734d1dc17SAnatolij Gustschin #define VSE_CVP_MODE_CTRL_CVP_MODE BIT(0) /* CVP (1) or normal mode (0) */
3834d1dc17SAnatolij Gustschin #define VSE_CVP_MODE_CTRL_HIP_CLK_SEL BIT(1) /* PMA (1) or fabric clock (0) */
3934d1dc17SAnatolij Gustschin #define VSE_CVP_MODE_CTRL_NUMCLKS_OFF 8 /* NUMCLKS bits offset */
4034d1dc17SAnatolij Gustschin #define VSE_CVP_MODE_CTRL_NUMCLKS_MASK GENMASK(15, 8)
4134d1dc17SAnatolij Gustschin
42eb12511fSThor Thayer #define VSE_CVP_DATA 0x28 /* 32bit */
43eb12511fSThor Thayer #define VSE_CVP_PROG_CTRL 0x2c /* 32bit */
4434d1dc17SAnatolij Gustschin #define VSE_CVP_PROG_CTRL_CONFIG BIT(0)
4534d1dc17SAnatolij Gustschin #define VSE_CVP_PROG_CTRL_START_XFER BIT(1)
46e5891517SThor Thayer #define VSE_CVP_PROG_CTRL_MASK GENMASK(1, 0)
4734d1dc17SAnatolij Gustschin
48eb12511fSThor Thayer #define VSE_UNCOR_ERR_STATUS 0x34 /* 32bit */
4934d1dc17SAnatolij Gustschin #define VSE_UNCOR_ERR_CVP_CFG_ERR BIT(5) /* CVP_CONFIG_ERROR_LATCHED */
5034d1dc17SAnatolij Gustschin
51e5891517SThor Thayer #define V1_VSEC_OFFSET 0x200 /* Vendor Specific Offset V1 */
52e5891517SThor Thayer /* V2 Defines */
53e5891517SThor Thayer #define VSE_CVP_TX_CREDITS 0x49 /* 8bit */
54e5891517SThor Thayer
55e5891517SThor Thayer #define V2_CREDIT_TIMEOUT_US 20000
56e5891517SThor Thayer #define V2_CHECK_CREDIT_US 10
57e5891517SThor Thayer #define V2_POLL_TIMEOUT_US 1000000
58e5891517SThor Thayer #define V2_USER_TIMEOUT_US 500000
59e5891517SThor Thayer
60e5891517SThor Thayer #define V1_POLL_TIMEOUT_US 10
61e5891517SThor Thayer
6234d1dc17SAnatolij Gustschin #define DRV_NAME "altera-cvp"
6334d1dc17SAnatolij Gustschin #define ALTERA_CVP_MGR_NAME "Altera CvP FPGA Manager"
6434d1dc17SAnatolij Gustschin
65e5891517SThor Thayer /* Write block sizes */
66e5891517SThor Thayer #define ALTERA_CVP_V1_SIZE 4
67e5891517SThor Thayer #define ALTERA_CVP_V2_SIZE 4096
68e5891517SThor Thayer
6934d1dc17SAnatolij Gustschin /* Optional CvP config error status check for debugging */
7034d1dc17SAnatolij Gustschin static bool altera_cvp_chkcfg;
7134d1dc17SAnatolij Gustschin
72e5891517SThor Thayer struct cvp_priv;
73e5891517SThor Thayer
7434d1dc17SAnatolij Gustschin struct altera_cvp_conf {
7534d1dc17SAnatolij Gustschin struct fpga_manager *mgr;
7634d1dc17SAnatolij Gustschin struct pci_dev *pci_dev;
7734d1dc17SAnatolij Gustschin void __iomem *map;
78998c1de5SCarlos A Petry void (*write_data)(struct altera_cvp_conf *conf,
79998c1de5SCarlos A Petry u32 data);
8034d1dc17SAnatolij Gustschin char mgr_name[64];
8134d1dc17SAnatolij Gustschin u8 numclks;
82e5891517SThor Thayer u32 sent_packets;
83eb12511fSThor Thayer u32 vsec_offset;
84e5891517SThor Thayer const struct cvp_priv *priv;
8534d1dc17SAnatolij Gustschin };
8634d1dc17SAnatolij Gustschin
87e5891517SThor Thayer struct cvp_priv {
88e5891517SThor Thayer void (*switch_clk)(struct altera_cvp_conf *conf);
89e5891517SThor Thayer int (*clear_state)(struct altera_cvp_conf *conf);
90e5891517SThor Thayer int (*wait_credit)(struct fpga_manager *mgr, u32 blocks);
91e5891517SThor Thayer size_t block_size;
92e5891517SThor Thayer int poll_time_us;
93e5891517SThor Thayer int user_time_us;
94e5891517SThor Thayer };
95e5891517SThor Thayer
altera_read_config_byte(struct altera_cvp_conf * conf,int where,u8 * val)96e5891517SThor Thayer static int altera_read_config_byte(struct altera_cvp_conf *conf,
97e5891517SThor Thayer int where, u8 *val)
98e5891517SThor Thayer {
99e5891517SThor Thayer return pci_read_config_byte(conf->pci_dev, conf->vsec_offset + where,
100e5891517SThor Thayer val);
101e5891517SThor Thayer }
102e5891517SThor Thayer
altera_read_config_dword(struct altera_cvp_conf * conf,int where,u32 * val)103eb12511fSThor Thayer static int altera_read_config_dword(struct altera_cvp_conf *conf,
104eb12511fSThor Thayer int where, u32 *val)
105eb12511fSThor Thayer {
106eb12511fSThor Thayer return pci_read_config_dword(conf->pci_dev, conf->vsec_offset + where,
107eb12511fSThor Thayer val);
108eb12511fSThor Thayer }
109eb12511fSThor Thayer
altera_write_config_dword(struct altera_cvp_conf * conf,int where,u32 val)110eb12511fSThor Thayer static int altera_write_config_dword(struct altera_cvp_conf *conf,
111eb12511fSThor Thayer int where, u32 val)
112eb12511fSThor Thayer {
113eb12511fSThor Thayer return pci_write_config_dword(conf->pci_dev, conf->vsec_offset + where,
114eb12511fSThor Thayer val);
115eb12511fSThor Thayer }
116eb12511fSThor Thayer
altera_cvp_state(struct fpga_manager * mgr)11734d1dc17SAnatolij Gustschin static enum fpga_mgr_states altera_cvp_state(struct fpga_manager *mgr)
11834d1dc17SAnatolij Gustschin {
11934d1dc17SAnatolij Gustschin struct altera_cvp_conf *conf = mgr->priv;
12034d1dc17SAnatolij Gustschin u32 status;
12134d1dc17SAnatolij Gustschin
122eb12511fSThor Thayer altera_read_config_dword(conf, VSE_CVP_STATUS, &status);
12334d1dc17SAnatolij Gustschin
12434d1dc17SAnatolij Gustschin if (status & VSE_CVP_STATUS_CFG_DONE)
12534d1dc17SAnatolij Gustschin return FPGA_MGR_STATE_OPERATING;
12634d1dc17SAnatolij Gustschin
12734d1dc17SAnatolij Gustschin if (status & VSE_CVP_STATUS_CVP_EN)
12834d1dc17SAnatolij Gustschin return FPGA_MGR_STATE_POWER_UP;
12934d1dc17SAnatolij Gustschin
13034d1dc17SAnatolij Gustschin return FPGA_MGR_STATE_UNKNOWN;
13134d1dc17SAnatolij Gustschin }
13234d1dc17SAnatolij Gustschin
altera_cvp_write_data_iomem(struct altera_cvp_conf * conf,u32 val)13334d1dc17SAnatolij Gustschin static void altera_cvp_write_data_iomem(struct altera_cvp_conf *conf, u32 val)
13434d1dc17SAnatolij Gustschin {
13534d1dc17SAnatolij Gustschin writel(val, conf->map);
13634d1dc17SAnatolij Gustschin }
13734d1dc17SAnatolij Gustschin
altera_cvp_write_data_config(struct altera_cvp_conf * conf,u32 val)13834d1dc17SAnatolij Gustschin static void altera_cvp_write_data_config(struct altera_cvp_conf *conf, u32 val)
13934d1dc17SAnatolij Gustschin {
140eb12511fSThor Thayer pci_write_config_dword(conf->pci_dev, conf->vsec_offset + VSE_CVP_DATA,
141eb12511fSThor Thayer val);
14234d1dc17SAnatolij Gustschin }
14334d1dc17SAnatolij Gustschin
14434d1dc17SAnatolij Gustschin /* switches between CvP clock and internal clock */
altera_cvp_dummy_write(struct altera_cvp_conf * conf)14534d1dc17SAnatolij Gustschin static void altera_cvp_dummy_write(struct altera_cvp_conf *conf)
14634d1dc17SAnatolij Gustschin {
14734d1dc17SAnatolij Gustschin unsigned int i;
14834d1dc17SAnatolij Gustschin u32 val;
14934d1dc17SAnatolij Gustschin
15034d1dc17SAnatolij Gustschin /* set 1 CVP clock cycle for every CVP Data Register Write */
151eb12511fSThor Thayer altera_read_config_dword(conf, VSE_CVP_MODE_CTRL, &val);
15234d1dc17SAnatolij Gustschin val &= ~VSE_CVP_MODE_CTRL_NUMCLKS_MASK;
15334d1dc17SAnatolij Gustschin val |= 1 << VSE_CVP_MODE_CTRL_NUMCLKS_OFF;
154eb12511fSThor Thayer altera_write_config_dword(conf, VSE_CVP_MODE_CTRL, val);
15534d1dc17SAnatolij Gustschin
15634d1dc17SAnatolij Gustschin for (i = 0; i < CVP_DUMMY_WR; i++)
15734d1dc17SAnatolij Gustschin conf->write_data(conf, 0); /* dummy data, could be any value */
15834d1dc17SAnatolij Gustschin }
15934d1dc17SAnatolij Gustschin
altera_cvp_wait_status(struct altera_cvp_conf * conf,u32 status_mask,u32 status_val,int timeout_us)16034d1dc17SAnatolij Gustschin static int altera_cvp_wait_status(struct altera_cvp_conf *conf, u32 status_mask,
16134d1dc17SAnatolij Gustschin u32 status_val, int timeout_us)
16234d1dc17SAnatolij Gustschin {
16334d1dc17SAnatolij Gustschin unsigned int retries;
16434d1dc17SAnatolij Gustschin u32 val;
16534d1dc17SAnatolij Gustschin
16634d1dc17SAnatolij Gustschin retries = timeout_us / 10;
16734d1dc17SAnatolij Gustschin if (timeout_us % 10)
16834d1dc17SAnatolij Gustschin retries++;
16934d1dc17SAnatolij Gustschin
17034d1dc17SAnatolij Gustschin do {
171eb12511fSThor Thayer altera_read_config_dword(conf, VSE_CVP_STATUS, &val);
17234d1dc17SAnatolij Gustschin if ((val & status_mask) == status_val)
17334d1dc17SAnatolij Gustschin return 0;
17434d1dc17SAnatolij Gustschin
17534d1dc17SAnatolij Gustschin /* use small usleep value to re-check and break early */
17634d1dc17SAnatolij Gustschin usleep_range(10, 11);
17734d1dc17SAnatolij Gustschin } while (--retries);
17834d1dc17SAnatolij Gustschin
17934d1dc17SAnatolij Gustschin return -ETIMEDOUT;
18034d1dc17SAnatolij Gustschin }
18134d1dc17SAnatolij Gustschin
altera_cvp_chk_error(struct fpga_manager * mgr,size_t bytes)182d2083d04SThor Thayer static int altera_cvp_chk_error(struct fpga_manager *mgr, size_t bytes)
183d2083d04SThor Thayer {
184d2083d04SThor Thayer struct altera_cvp_conf *conf = mgr->priv;
185d2083d04SThor Thayer u32 val;
186d2083d04SThor Thayer int ret;
187d2083d04SThor Thayer
188d2083d04SThor Thayer /* STEP 10 (optional) - check CVP_CONFIG_ERROR flag */
189d2083d04SThor Thayer ret = altera_read_config_dword(conf, VSE_CVP_STATUS, &val);
190d2083d04SThor Thayer if (ret || (val & VSE_CVP_STATUS_CFG_ERR)) {
191d2083d04SThor Thayer dev_err(&mgr->dev, "CVP_CONFIG_ERROR after %zu bytes!\n",
192d2083d04SThor Thayer bytes);
193d2083d04SThor Thayer return -EPROTO;
194d2083d04SThor Thayer }
195d2083d04SThor Thayer return 0;
196d2083d04SThor Thayer }
197d2083d04SThor Thayer
198e5891517SThor Thayer /*
199e5891517SThor Thayer * CvP Version2 Functions
200e5891517SThor Thayer * Recent Intel FPGAs use a credit mechanism to throttle incoming
201e5891517SThor Thayer * bitstreams and a different method of clearing the state.
202e5891517SThor Thayer */
203e5891517SThor Thayer
altera_cvp_v2_clear_state(struct altera_cvp_conf * conf)204e5891517SThor Thayer static int altera_cvp_v2_clear_state(struct altera_cvp_conf *conf)
205e5891517SThor Thayer {
206e5891517SThor Thayer u32 val;
207e5891517SThor Thayer int ret;
208e5891517SThor Thayer
209e5891517SThor Thayer /* Clear the START_XFER and CVP_CONFIG bits */
210e5891517SThor Thayer ret = altera_read_config_dword(conf, VSE_CVP_PROG_CTRL, &val);
211e5891517SThor Thayer if (ret) {
212e5891517SThor Thayer dev_err(&conf->pci_dev->dev,
213e5891517SThor Thayer "Error reading CVP Program Control Register\n");
214e5891517SThor Thayer return ret;
215e5891517SThor Thayer }
216e5891517SThor Thayer
217e5891517SThor Thayer val &= ~VSE_CVP_PROG_CTRL_MASK;
218e5891517SThor Thayer ret = altera_write_config_dword(conf, VSE_CVP_PROG_CTRL, val);
219e5891517SThor Thayer if (ret) {
220e5891517SThor Thayer dev_err(&conf->pci_dev->dev,
221e5891517SThor Thayer "Error writing CVP Program Control Register\n");
222e5891517SThor Thayer return ret;
223e5891517SThor Thayer }
224e5891517SThor Thayer
225e5891517SThor Thayer return altera_cvp_wait_status(conf, VSE_CVP_STATUS_CFG_RDY, 0,
226e5891517SThor Thayer conf->priv->poll_time_us);
227e5891517SThor Thayer }
228e5891517SThor Thayer
altera_cvp_v2_wait_for_credit(struct fpga_manager * mgr,u32 blocks)229e5891517SThor Thayer static int altera_cvp_v2_wait_for_credit(struct fpga_manager *mgr,
230e5891517SThor Thayer u32 blocks)
231e5891517SThor Thayer {
232e5891517SThor Thayer u32 timeout = V2_CREDIT_TIMEOUT_US / V2_CHECK_CREDIT_US;
233e5891517SThor Thayer struct altera_cvp_conf *conf = mgr->priv;
234e5891517SThor Thayer int ret;
235e5891517SThor Thayer u8 val;
236e5891517SThor Thayer
237e5891517SThor Thayer do {
238e5891517SThor Thayer ret = altera_read_config_byte(conf, VSE_CVP_TX_CREDITS, &val);
239e5891517SThor Thayer if (ret) {
240e5891517SThor Thayer dev_err(&conf->pci_dev->dev,
241e5891517SThor Thayer "Error reading CVP Credit Register\n");
242e5891517SThor Thayer return ret;
243e5891517SThor Thayer }
244e5891517SThor Thayer
245e5891517SThor Thayer /* Return if there is space in FIFO */
246e5891517SThor Thayer if (val - (u8)conf->sent_packets)
247e5891517SThor Thayer return 0;
248e5891517SThor Thayer
249e5891517SThor Thayer ret = altera_cvp_chk_error(mgr, blocks * ALTERA_CVP_V2_SIZE);
250e5891517SThor Thayer if (ret) {
251e5891517SThor Thayer dev_err(&conf->pci_dev->dev,
252e5891517SThor Thayer "CE Bit error credit reg[0x%x]:sent[0x%x]\n",
253e5891517SThor Thayer val, conf->sent_packets);
254e5891517SThor Thayer return -EAGAIN;
255e5891517SThor Thayer }
256e5891517SThor Thayer
257e5891517SThor Thayer /* Limit the check credit byte traffic */
258e5891517SThor Thayer usleep_range(V2_CHECK_CREDIT_US, V2_CHECK_CREDIT_US + 1);
259e5891517SThor Thayer } while (timeout--);
260e5891517SThor Thayer
261e5891517SThor Thayer dev_err(&conf->pci_dev->dev, "Timeout waiting for credit\n");
262e5891517SThor Thayer return -ETIMEDOUT;
263e5891517SThor Thayer }
264e5891517SThor Thayer
altera_cvp_send_block(struct altera_cvp_conf * conf,const u32 * data,size_t len)265d2083d04SThor Thayer static int altera_cvp_send_block(struct altera_cvp_conf *conf,
266d2083d04SThor Thayer const u32 *data, size_t len)
267d2083d04SThor Thayer {
268d2083d04SThor Thayer u32 mask, words = len / sizeof(u32);
269d2083d04SThor Thayer int i, remainder;
270d2083d04SThor Thayer
271d2083d04SThor Thayer for (i = 0; i < words; i++)
272d2083d04SThor Thayer conf->write_data(conf, *data++);
273d2083d04SThor Thayer
274d2083d04SThor Thayer /* write up to 3 trailing bytes, if any */
275d2083d04SThor Thayer remainder = len % sizeof(u32);
276d2083d04SThor Thayer if (remainder) {
277d2083d04SThor Thayer mask = BIT(remainder * 8) - 1;
278d2083d04SThor Thayer if (mask)
279d2083d04SThor Thayer conf->write_data(conf, *data & mask);
280d2083d04SThor Thayer }
281d2083d04SThor Thayer
282d2083d04SThor Thayer return 0;
283d2083d04SThor Thayer }
284d2083d04SThor Thayer
altera_cvp_teardown(struct fpga_manager * mgr,struct fpga_image_info * info)28534d1dc17SAnatolij Gustschin static int altera_cvp_teardown(struct fpga_manager *mgr,
28634d1dc17SAnatolij Gustschin struct fpga_image_info *info)
28734d1dc17SAnatolij Gustschin {
28834d1dc17SAnatolij Gustschin struct altera_cvp_conf *conf = mgr->priv;
28934d1dc17SAnatolij Gustschin int ret;
29034d1dc17SAnatolij Gustschin u32 val;
29134d1dc17SAnatolij Gustschin
29234d1dc17SAnatolij Gustschin /* STEP 12 - reset START_XFER bit */
293eb12511fSThor Thayer altera_read_config_dword(conf, VSE_CVP_PROG_CTRL, &val);
29434d1dc17SAnatolij Gustschin val &= ~VSE_CVP_PROG_CTRL_START_XFER;
295eb12511fSThor Thayer altera_write_config_dword(conf, VSE_CVP_PROG_CTRL, val);
29634d1dc17SAnatolij Gustschin
29734d1dc17SAnatolij Gustschin /* STEP 13 - reset CVP_CONFIG bit */
29834d1dc17SAnatolij Gustschin val &= ~VSE_CVP_PROG_CTRL_CONFIG;
299eb12511fSThor Thayer altera_write_config_dword(conf, VSE_CVP_PROG_CTRL, val);
30034d1dc17SAnatolij Gustschin
30134d1dc17SAnatolij Gustschin /*
30234d1dc17SAnatolij Gustschin * STEP 14
30334d1dc17SAnatolij Gustschin * - set CVP_NUMCLKS to 1 and then issue CVP_DUMMY_WR dummy
30434d1dc17SAnatolij Gustschin * writes to the HIP
30534d1dc17SAnatolij Gustschin */
306e5891517SThor Thayer if (conf->priv->switch_clk)
307e5891517SThor Thayer conf->priv->switch_clk(conf);
30834d1dc17SAnatolij Gustschin
30934d1dc17SAnatolij Gustschin /* STEP 15 - poll CVP_CONFIG_READY bit for 0 with 10us timeout */
310e5891517SThor Thayer ret = altera_cvp_wait_status(conf, VSE_CVP_STATUS_CFG_RDY, 0,
311e5891517SThor Thayer conf->priv->poll_time_us);
31234d1dc17SAnatolij Gustschin if (ret)
31334d1dc17SAnatolij Gustschin dev_err(&mgr->dev, "CFG_RDY == 0 timeout\n");
31434d1dc17SAnatolij Gustschin
31534d1dc17SAnatolij Gustschin return ret;
31634d1dc17SAnatolij Gustschin }
31734d1dc17SAnatolij Gustschin
altera_cvp_write_init(struct fpga_manager * mgr,struct fpga_image_info * info,const char * buf,size_t count)31834d1dc17SAnatolij Gustschin static int altera_cvp_write_init(struct fpga_manager *mgr,
31934d1dc17SAnatolij Gustschin struct fpga_image_info *info,
32034d1dc17SAnatolij Gustschin const char *buf, size_t count)
32134d1dc17SAnatolij Gustschin {
32234d1dc17SAnatolij Gustschin struct altera_cvp_conf *conf = mgr->priv;
32334d1dc17SAnatolij Gustschin u32 iflags, val;
32434d1dc17SAnatolij Gustschin int ret;
32534d1dc17SAnatolij Gustschin
32634d1dc17SAnatolij Gustschin iflags = info ? info->flags : 0;
32734d1dc17SAnatolij Gustschin
32834d1dc17SAnatolij Gustschin if (iflags & FPGA_MGR_PARTIAL_RECONFIG) {
32934d1dc17SAnatolij Gustschin dev_err(&mgr->dev, "Partial reconfiguration not supported.\n");
33034d1dc17SAnatolij Gustschin return -EINVAL;
33134d1dc17SAnatolij Gustschin }
33234d1dc17SAnatolij Gustschin
33334d1dc17SAnatolij Gustschin /* Determine allowed clock to data ratio */
33434d1dc17SAnatolij Gustschin if (iflags & FPGA_MGR_COMPRESSED_BITSTREAM)
33534d1dc17SAnatolij Gustschin conf->numclks = 8; /* ratio for all compressed images */
33634d1dc17SAnatolij Gustschin else if (iflags & FPGA_MGR_ENCRYPTED_BITSTREAM)
33734d1dc17SAnatolij Gustschin conf->numclks = 4; /* for uncompressed and encrypted images */
33834d1dc17SAnatolij Gustschin else
33934d1dc17SAnatolij Gustschin conf->numclks = 1; /* for uncompressed and unencrypted images */
34034d1dc17SAnatolij Gustschin
34134d1dc17SAnatolij Gustschin /* STEP 1 - read CVP status and check CVP_EN flag */
342eb12511fSThor Thayer altera_read_config_dword(conf, VSE_CVP_STATUS, &val);
34334d1dc17SAnatolij Gustschin if (!(val & VSE_CVP_STATUS_CVP_EN)) {
34434d1dc17SAnatolij Gustschin dev_err(&mgr->dev, "CVP mode off: 0x%04x\n", val);
34534d1dc17SAnatolij Gustschin return -ENODEV;
34634d1dc17SAnatolij Gustschin }
34734d1dc17SAnatolij Gustschin
34834d1dc17SAnatolij Gustschin if (val & VSE_CVP_STATUS_CFG_RDY) {
34934d1dc17SAnatolij Gustschin dev_warn(&mgr->dev, "CvP already started, tear down first\n");
35034d1dc17SAnatolij Gustschin ret = altera_cvp_teardown(mgr, info);
35134d1dc17SAnatolij Gustschin if (ret)
35234d1dc17SAnatolij Gustschin return ret;
35334d1dc17SAnatolij Gustschin }
35434d1dc17SAnatolij Gustschin
35534d1dc17SAnatolij Gustschin /*
35634d1dc17SAnatolij Gustschin * STEP 2
35734d1dc17SAnatolij Gustschin * - set HIP_CLK_SEL and CVP_MODE (must be set in the order mentioned)
35834d1dc17SAnatolij Gustschin */
35934d1dc17SAnatolij Gustschin /* switch from fabric to PMA clock */
360eb12511fSThor Thayer altera_read_config_dword(conf, VSE_CVP_MODE_CTRL, &val);
36134d1dc17SAnatolij Gustschin val |= VSE_CVP_MODE_CTRL_HIP_CLK_SEL;
362eb12511fSThor Thayer altera_write_config_dword(conf, VSE_CVP_MODE_CTRL, val);
36334d1dc17SAnatolij Gustschin
36434d1dc17SAnatolij Gustschin /* set CVP mode */
365eb12511fSThor Thayer altera_read_config_dword(conf, VSE_CVP_MODE_CTRL, &val);
36634d1dc17SAnatolij Gustschin val |= VSE_CVP_MODE_CTRL_CVP_MODE;
367eb12511fSThor Thayer altera_write_config_dword(conf, VSE_CVP_MODE_CTRL, val);
36834d1dc17SAnatolij Gustschin
36934d1dc17SAnatolij Gustschin /*
37034d1dc17SAnatolij Gustschin * STEP 3
37134d1dc17SAnatolij Gustschin * - set CVP_NUMCLKS to 1 and issue CVP_DUMMY_WR dummy writes to the HIP
37234d1dc17SAnatolij Gustschin */
373e5891517SThor Thayer if (conf->priv->switch_clk)
374e5891517SThor Thayer conf->priv->switch_clk(conf);
375e5891517SThor Thayer
376e5891517SThor Thayer if (conf->priv->clear_state) {
377e5891517SThor Thayer ret = conf->priv->clear_state(conf);
378e5891517SThor Thayer if (ret) {
379e5891517SThor Thayer dev_err(&mgr->dev, "Problem clearing out state\n");
380e5891517SThor Thayer return ret;
381e5891517SThor Thayer }
382e5891517SThor Thayer }
383e5891517SThor Thayer
384e5891517SThor Thayer conf->sent_packets = 0;
38534d1dc17SAnatolij Gustschin
38634d1dc17SAnatolij Gustschin /* STEP 4 - set CVP_CONFIG bit */
387eb12511fSThor Thayer altera_read_config_dword(conf, VSE_CVP_PROG_CTRL, &val);
38834d1dc17SAnatolij Gustschin /* request control block to begin transfer using CVP */
38934d1dc17SAnatolij Gustschin val |= VSE_CVP_PROG_CTRL_CONFIG;
390eb12511fSThor Thayer altera_write_config_dword(conf, VSE_CVP_PROG_CTRL, val);
39134d1dc17SAnatolij Gustschin
392e5891517SThor Thayer /* STEP 5 - poll CVP_CONFIG READY for 1 with timeout */
39334d1dc17SAnatolij Gustschin ret = altera_cvp_wait_status(conf, VSE_CVP_STATUS_CFG_RDY,
394e5891517SThor Thayer VSE_CVP_STATUS_CFG_RDY,
395e5891517SThor Thayer conf->priv->poll_time_us);
39634d1dc17SAnatolij Gustschin if (ret) {
39734d1dc17SAnatolij Gustschin dev_warn(&mgr->dev, "CFG_RDY == 1 timeout\n");
39834d1dc17SAnatolij Gustschin return ret;
39934d1dc17SAnatolij Gustschin }
40034d1dc17SAnatolij Gustschin
40134d1dc17SAnatolij Gustschin /*
40234d1dc17SAnatolij Gustschin * STEP 6
40334d1dc17SAnatolij Gustschin * - set CVP_NUMCLKS to 1 and issue CVP_DUMMY_WR dummy writes to the HIP
40434d1dc17SAnatolij Gustschin */
405e5891517SThor Thayer if (conf->priv->switch_clk)
406e5891517SThor Thayer conf->priv->switch_clk(conf);
407e5891517SThor Thayer
408e5891517SThor Thayer if (altera_cvp_chkcfg) {
409e5891517SThor Thayer ret = altera_cvp_chk_error(mgr, 0);
410e5891517SThor Thayer if (ret) {
411e5891517SThor Thayer dev_warn(&mgr->dev, "CFG_RDY == 1 timeout\n");
412e5891517SThor Thayer return ret;
413e5891517SThor Thayer }
414e5891517SThor Thayer }
41534d1dc17SAnatolij Gustschin
41634d1dc17SAnatolij Gustschin /* STEP 7 - set START_XFER */
417eb12511fSThor Thayer altera_read_config_dword(conf, VSE_CVP_PROG_CTRL, &val);
41834d1dc17SAnatolij Gustschin val |= VSE_CVP_PROG_CTRL_START_XFER;
419eb12511fSThor Thayer altera_write_config_dword(conf, VSE_CVP_PROG_CTRL, val);
42034d1dc17SAnatolij Gustschin
42134d1dc17SAnatolij Gustschin /* STEP 8 - start transfer (set CVP_NUMCLKS for bitstream) */
422e5891517SThor Thayer if (conf->priv->switch_clk) {
423eb12511fSThor Thayer altera_read_config_dword(conf, VSE_CVP_MODE_CTRL, &val);
42434d1dc17SAnatolij Gustschin val &= ~VSE_CVP_MODE_CTRL_NUMCLKS_MASK;
42534d1dc17SAnatolij Gustschin val |= conf->numclks << VSE_CVP_MODE_CTRL_NUMCLKS_OFF;
426eb12511fSThor Thayer altera_write_config_dword(conf, VSE_CVP_MODE_CTRL, val);
427e5891517SThor Thayer }
42834d1dc17SAnatolij Gustschin return 0;
42934d1dc17SAnatolij Gustschin }
43034d1dc17SAnatolij Gustschin
altera_cvp_write(struct fpga_manager * mgr,const char * buf,size_t count)43134d1dc17SAnatolij Gustschin static int altera_cvp_write(struct fpga_manager *mgr, const char *buf,
43234d1dc17SAnatolij Gustschin size_t count)
43334d1dc17SAnatolij Gustschin {
43434d1dc17SAnatolij Gustschin struct altera_cvp_conf *conf = mgr->priv;
435d2083d04SThor Thayer size_t done, remaining, len;
43634d1dc17SAnatolij Gustschin const u32 *data;
43734d1dc17SAnatolij Gustschin int status = 0;
43834d1dc17SAnatolij Gustschin
43934d1dc17SAnatolij Gustschin /* STEP 9 - write 32-bit data from RBF file to CVP data register */
44034d1dc17SAnatolij Gustschin data = (u32 *)buf;
44134d1dc17SAnatolij Gustschin remaining = count;
44234d1dc17SAnatolij Gustschin done = 0;
44334d1dc17SAnatolij Gustschin
444d2083d04SThor Thayer while (remaining) {
445e5891517SThor Thayer /* Use credit throttling if available */
446e5891517SThor Thayer if (conf->priv->wait_credit) {
447e5891517SThor Thayer status = conf->priv->wait_credit(mgr, done);
448e5891517SThor Thayer if (status) {
449e5891517SThor Thayer dev_err(&conf->pci_dev->dev,
450e5891517SThor Thayer "Wait Credit ERR: 0x%x\n", status);
451e5891517SThor Thayer return status;
452e5891517SThor Thayer }
453e5891517SThor Thayer }
454e5891517SThor Thayer
455e5891517SThor Thayer len = min(conf->priv->block_size, remaining);
456d2083d04SThor Thayer altera_cvp_send_block(conf, data, len);
457e5891517SThor Thayer data += len / sizeof(u32);
458d2083d04SThor Thayer done += len;
459d2083d04SThor Thayer remaining -= len;
460e5891517SThor Thayer conf->sent_packets++;
46134d1dc17SAnatolij Gustschin
46234d1dc17SAnatolij Gustschin /*
46334d1dc17SAnatolij Gustschin * STEP 10 (optional) and STEP 11
46434d1dc17SAnatolij Gustschin * - check error flag
46534d1dc17SAnatolij Gustschin * - loop until data transfer completed
46634d1dc17SAnatolij Gustschin * Config images can be huge (more than 40 MiB), so
46734d1dc17SAnatolij Gustschin * only check after a new 4k data block has been written.
46834d1dc17SAnatolij Gustschin * This reduces the number of checks and speeds up the
46934d1dc17SAnatolij Gustschin * configuration process.
47034d1dc17SAnatolij Gustschin */
47134d1dc17SAnatolij Gustschin if (altera_cvp_chkcfg && !(done % SZ_4K)) {
47234d1dc17SAnatolij Gustschin status = altera_cvp_chk_error(mgr, done);
47334d1dc17SAnatolij Gustschin if (status < 0)
47434d1dc17SAnatolij Gustschin return status;
47534d1dc17SAnatolij Gustschin }
47634d1dc17SAnatolij Gustschin }
47734d1dc17SAnatolij Gustschin
47834d1dc17SAnatolij Gustschin if (altera_cvp_chkcfg)
47934d1dc17SAnatolij Gustschin status = altera_cvp_chk_error(mgr, count);
48034d1dc17SAnatolij Gustschin
48134d1dc17SAnatolij Gustschin return status;
48234d1dc17SAnatolij Gustschin }
48334d1dc17SAnatolij Gustschin
altera_cvp_write_complete(struct fpga_manager * mgr,struct fpga_image_info * info)48434d1dc17SAnatolij Gustschin static int altera_cvp_write_complete(struct fpga_manager *mgr,
48534d1dc17SAnatolij Gustschin struct fpga_image_info *info)
48634d1dc17SAnatolij Gustschin {
48734d1dc17SAnatolij Gustschin struct altera_cvp_conf *conf = mgr->priv;
488eb12511fSThor Thayer u32 mask, val;
48934d1dc17SAnatolij Gustschin int ret;
49034d1dc17SAnatolij Gustschin
49134d1dc17SAnatolij Gustschin ret = altera_cvp_teardown(mgr, info);
49234d1dc17SAnatolij Gustschin if (ret)
49334d1dc17SAnatolij Gustschin return ret;
49434d1dc17SAnatolij Gustschin
49534d1dc17SAnatolij Gustschin /* STEP 16 - check CVP_CONFIG_ERROR_LATCHED bit */
496eb12511fSThor Thayer altera_read_config_dword(conf, VSE_UNCOR_ERR_STATUS, &val);
49734d1dc17SAnatolij Gustschin if (val & VSE_UNCOR_ERR_CVP_CFG_ERR) {
49834d1dc17SAnatolij Gustschin dev_err(&mgr->dev, "detected CVP_CONFIG_ERROR_LATCHED!\n");
49934d1dc17SAnatolij Gustschin return -EPROTO;
50034d1dc17SAnatolij Gustschin }
50134d1dc17SAnatolij Gustschin
50234d1dc17SAnatolij Gustschin /* STEP 17 - reset CVP_MODE and HIP_CLK_SEL bit */
503eb12511fSThor Thayer altera_read_config_dword(conf, VSE_CVP_MODE_CTRL, &val);
50434d1dc17SAnatolij Gustschin val &= ~VSE_CVP_MODE_CTRL_HIP_CLK_SEL;
50534d1dc17SAnatolij Gustschin val &= ~VSE_CVP_MODE_CTRL_CVP_MODE;
506eb12511fSThor Thayer altera_write_config_dword(conf, VSE_CVP_MODE_CTRL, val);
50734d1dc17SAnatolij Gustschin
50834d1dc17SAnatolij Gustschin /* STEP 18 - poll PLD_CLK_IN_USE and USER_MODE bits */
50934d1dc17SAnatolij Gustschin mask = VSE_CVP_STATUS_PLD_CLK_IN_USE | VSE_CVP_STATUS_USERMODE;
510e5891517SThor Thayer ret = altera_cvp_wait_status(conf, mask, mask,
511e5891517SThor Thayer conf->priv->user_time_us);
51234d1dc17SAnatolij Gustschin if (ret)
51334d1dc17SAnatolij Gustschin dev_err(&mgr->dev, "PLD_CLK_IN_USE|USERMODE timeout\n");
51434d1dc17SAnatolij Gustschin
51534d1dc17SAnatolij Gustschin return ret;
51634d1dc17SAnatolij Gustschin }
51734d1dc17SAnatolij Gustschin
51834d1dc17SAnatolij Gustschin static const struct fpga_manager_ops altera_cvp_ops = {
51934d1dc17SAnatolij Gustschin .state = altera_cvp_state,
52034d1dc17SAnatolij Gustschin .write_init = altera_cvp_write_init,
52134d1dc17SAnatolij Gustschin .write = altera_cvp_write,
52234d1dc17SAnatolij Gustschin .write_complete = altera_cvp_write_complete,
52334d1dc17SAnatolij Gustschin };
52434d1dc17SAnatolij Gustschin
525e5891517SThor Thayer static const struct cvp_priv cvp_priv_v1 = {
526e5891517SThor Thayer .switch_clk = altera_cvp_dummy_write,
527e5891517SThor Thayer .block_size = ALTERA_CVP_V1_SIZE,
528e5891517SThor Thayer .poll_time_us = V1_POLL_TIMEOUT_US,
529e5891517SThor Thayer .user_time_us = TIMEOUT_US,
530e5891517SThor Thayer };
531e5891517SThor Thayer
532e5891517SThor Thayer static const struct cvp_priv cvp_priv_v2 = {
533e5891517SThor Thayer .clear_state = altera_cvp_v2_clear_state,
534e5891517SThor Thayer .wait_credit = altera_cvp_v2_wait_for_credit,
535e5891517SThor Thayer .block_size = ALTERA_CVP_V2_SIZE,
536e5891517SThor Thayer .poll_time_us = V2_POLL_TIMEOUT_US,
537e5891517SThor Thayer .user_time_us = V2_USER_TIMEOUT_US,
538e5891517SThor Thayer };
539e5891517SThor Thayer
chkcfg_show(struct device_driver * dev,char * buf)54055e001aaSGreg Kroah-Hartman static ssize_t chkcfg_show(struct device_driver *dev, char *buf)
54134d1dc17SAnatolij Gustschin {
54234d1dc17SAnatolij Gustschin return snprintf(buf, 3, "%d\n", altera_cvp_chkcfg);
54334d1dc17SAnatolij Gustschin }
54434d1dc17SAnatolij Gustschin
chkcfg_store(struct device_driver * drv,const char * buf,size_t count)54555e001aaSGreg Kroah-Hartman static ssize_t chkcfg_store(struct device_driver *drv, const char *buf,
54634d1dc17SAnatolij Gustschin size_t count)
54734d1dc17SAnatolij Gustschin {
54834d1dc17SAnatolij Gustschin int ret;
54934d1dc17SAnatolij Gustschin
55034d1dc17SAnatolij Gustschin ret = kstrtobool(buf, &altera_cvp_chkcfg);
55134d1dc17SAnatolij Gustschin if (ret)
55234d1dc17SAnatolij Gustschin return ret;
55334d1dc17SAnatolij Gustschin
55434d1dc17SAnatolij Gustschin return count;
55534d1dc17SAnatolij Gustschin }
55634d1dc17SAnatolij Gustschin
55755e001aaSGreg Kroah-Hartman static DRIVER_ATTR_RW(chkcfg);
55834d1dc17SAnatolij Gustschin
55934d1dc17SAnatolij Gustschin static int altera_cvp_probe(struct pci_dev *pdev,
56034d1dc17SAnatolij Gustschin const struct pci_device_id *dev_id);
56134d1dc17SAnatolij Gustschin static void altera_cvp_remove(struct pci_dev *pdev);
56234d1dc17SAnatolij Gustschin
56334d1dc17SAnatolij Gustschin static struct pci_device_id altera_cvp_id_tbl[] = {
56434d1dc17SAnatolij Gustschin { PCI_VDEVICE(ALTERA, PCI_ANY_ID) },
56534d1dc17SAnatolij Gustschin { }
56634d1dc17SAnatolij Gustschin };
56734d1dc17SAnatolij Gustschin MODULE_DEVICE_TABLE(pci, altera_cvp_id_tbl);
56834d1dc17SAnatolij Gustschin
56934d1dc17SAnatolij Gustschin static struct pci_driver altera_cvp_driver = {
57034d1dc17SAnatolij Gustschin .name = DRV_NAME,
57134d1dc17SAnatolij Gustschin .id_table = altera_cvp_id_tbl,
57234d1dc17SAnatolij Gustschin .probe = altera_cvp_probe,
57334d1dc17SAnatolij Gustschin .remove = altera_cvp_remove,
57434d1dc17SAnatolij Gustschin };
57534d1dc17SAnatolij Gustschin
altera_cvp_probe(struct pci_dev * pdev,const struct pci_device_id * dev_id)57634d1dc17SAnatolij Gustschin static int altera_cvp_probe(struct pci_dev *pdev,
57734d1dc17SAnatolij Gustschin const struct pci_device_id *dev_id)
57834d1dc17SAnatolij Gustschin {
57934d1dc17SAnatolij Gustschin struct altera_cvp_conf *conf;
5807085e2a9SAlan Tull struct fpga_manager *mgr;
581eb12511fSThor Thayer int ret, offset;
58234d1dc17SAnatolij Gustschin u16 cmd, val;
58368f60538SAndreas Puhm u32 regval;
584eb12511fSThor Thayer
585eb12511fSThor Thayer /* Discover the Vendor Specific Offset for this device */
586eb12511fSThor Thayer offset = pci_find_next_ext_capability(pdev, 0, PCI_EXT_CAP_ID_VNDR);
587eb12511fSThor Thayer if (!offset) {
588eb12511fSThor Thayer dev_err(&pdev->dev, "No Vendor Specific Offset.\n");
589eb12511fSThor Thayer return -ENODEV;
590eb12511fSThor Thayer }
59134d1dc17SAnatolij Gustschin
59234d1dc17SAnatolij Gustschin /*
59334d1dc17SAnatolij Gustschin * First check if this is the expected FPGA device. PCI config
59434d1dc17SAnatolij Gustschin * space access works without enabling the PCI device, memory
59534d1dc17SAnatolij Gustschin * space access is enabled further down.
59634d1dc17SAnatolij Gustschin */
597eb12511fSThor Thayer pci_read_config_word(pdev, offset + VSE_PCIE_EXT_CAP_ID, &val);
59834d1dc17SAnatolij Gustschin if (val != VSE_PCIE_EXT_CAP_ID_VAL) {
59934d1dc17SAnatolij Gustschin dev_err(&pdev->dev, "Wrong EXT_CAP_ID value 0x%x\n", val);
60034d1dc17SAnatolij Gustschin return -ENODEV;
60134d1dc17SAnatolij Gustschin }
60234d1dc17SAnatolij Gustschin
603eb12511fSThor Thayer pci_read_config_dword(pdev, offset + VSE_CVP_STATUS, ®val);
60468f60538SAndreas Puhm if (!(regval & VSE_CVP_STATUS_CVP_EN)) {
60568f60538SAndreas Puhm dev_err(&pdev->dev,
60668f60538SAndreas Puhm "CVP is disabled for this device: CVP_STATUS Reg 0x%x\n",
60768f60538SAndreas Puhm regval);
60868f60538SAndreas Puhm return -ENODEV;
60968f60538SAndreas Puhm }
61068f60538SAndreas Puhm
61134d1dc17SAnatolij Gustschin conf = devm_kzalloc(&pdev->dev, sizeof(*conf), GFP_KERNEL);
61234d1dc17SAnatolij Gustschin if (!conf)
61334d1dc17SAnatolij Gustschin return -ENOMEM;
61434d1dc17SAnatolij Gustschin
615eb12511fSThor Thayer conf->vsec_offset = offset;
616eb12511fSThor Thayer
61734d1dc17SAnatolij Gustschin /*
61834d1dc17SAnatolij Gustschin * Enable memory BAR access. We cannot use pci_enable_device() here
61934d1dc17SAnatolij Gustschin * because it will make the driver unusable with FPGA devices that
62034d1dc17SAnatolij Gustschin * have additional big IOMEM resources (e.g. 4GiB BARs) on 32-bit
62134d1dc17SAnatolij Gustschin * platform. Such BARs will not have an assigned address range and
62234d1dc17SAnatolij Gustschin * pci_enable_device() will fail, complaining about not claimed BAR,
62334d1dc17SAnatolij Gustschin * even if the concerned BAR is not needed for FPGA configuration
62434d1dc17SAnatolij Gustschin * at all. Thus, enable the device via PCI config space command.
62534d1dc17SAnatolij Gustschin */
62634d1dc17SAnatolij Gustschin pci_read_config_word(pdev, PCI_COMMAND, &cmd);
62734d1dc17SAnatolij Gustschin if (!(cmd & PCI_COMMAND_MEMORY)) {
62834d1dc17SAnatolij Gustschin cmd |= PCI_COMMAND_MEMORY;
62934d1dc17SAnatolij Gustschin pci_write_config_word(pdev, PCI_COMMAND, cmd);
63034d1dc17SAnatolij Gustschin }
63134d1dc17SAnatolij Gustschin
63234d1dc17SAnatolij Gustschin ret = pci_request_region(pdev, CVP_BAR, "CVP");
63334d1dc17SAnatolij Gustschin if (ret) {
63434d1dc17SAnatolij Gustschin dev_err(&pdev->dev, "Requesting CVP BAR region failed\n");
63534d1dc17SAnatolij Gustschin goto err_disable;
63634d1dc17SAnatolij Gustschin }
63734d1dc17SAnatolij Gustschin
63834d1dc17SAnatolij Gustschin conf->pci_dev = pdev;
63934d1dc17SAnatolij Gustschin conf->write_data = altera_cvp_write_data_iomem;
64034d1dc17SAnatolij Gustschin
641e5891517SThor Thayer if (conf->vsec_offset == V1_VSEC_OFFSET)
642e5891517SThor Thayer conf->priv = &cvp_priv_v1;
643e5891517SThor Thayer else
644e5891517SThor Thayer conf->priv = &cvp_priv_v2;
645e5891517SThor Thayer
64634d1dc17SAnatolij Gustschin conf->map = pci_iomap(pdev, CVP_BAR, 0);
64734d1dc17SAnatolij Gustschin if (!conf->map) {
64834d1dc17SAnatolij Gustschin dev_warn(&pdev->dev, "Mapping CVP BAR failed\n");
64934d1dc17SAnatolij Gustschin conf->write_data = altera_cvp_write_data_config;
65034d1dc17SAnatolij Gustschin }
65134d1dc17SAnatolij Gustschin
65234d1dc17SAnatolij Gustschin snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s @%s",
65334d1dc17SAnatolij Gustschin ALTERA_CVP_MGR_NAME, pci_name(pdev));
65434d1dc17SAnatolij Gustschin
655*4ba0b2c2SRuss Weight mgr = fpga_mgr_register(&pdev->dev, conf->mgr_name,
65634d1dc17SAnatolij Gustschin &altera_cvp_ops, conf);
657*4ba0b2c2SRuss Weight if (IS_ERR(mgr)) {
658*4ba0b2c2SRuss Weight ret = PTR_ERR(mgr);
659122c5770SChristophe Jaillet goto err_unmap;
660122c5770SChristophe Jaillet }
6617085e2a9SAlan Tull
6627085e2a9SAlan Tull pci_set_drvdata(pdev, mgr);
6637085e2a9SAlan Tull
66434d1dc17SAnatolij Gustschin return 0;
66534d1dc17SAnatolij Gustschin
66634d1dc17SAnatolij Gustschin err_unmap:
667187fade8SAnatolij Gustschin if (conf->map)
66834d1dc17SAnatolij Gustschin pci_iounmap(pdev, conf->map);
66934d1dc17SAnatolij Gustschin pci_release_region(pdev, CVP_BAR);
67034d1dc17SAnatolij Gustschin err_disable:
67134d1dc17SAnatolij Gustschin cmd &= ~PCI_COMMAND_MEMORY;
67234d1dc17SAnatolij Gustschin pci_write_config_word(pdev, PCI_COMMAND, cmd);
67334d1dc17SAnatolij Gustschin return ret;
67434d1dc17SAnatolij Gustschin }
67534d1dc17SAnatolij Gustschin
altera_cvp_remove(struct pci_dev * pdev)67634d1dc17SAnatolij Gustschin static void altera_cvp_remove(struct pci_dev *pdev)
67734d1dc17SAnatolij Gustschin {
67834d1dc17SAnatolij Gustschin struct fpga_manager *mgr = pci_get_drvdata(pdev);
67934d1dc17SAnatolij Gustschin struct altera_cvp_conf *conf = mgr->priv;
68034d1dc17SAnatolij Gustschin u16 cmd;
68134d1dc17SAnatolij Gustschin
6827085e2a9SAlan Tull fpga_mgr_unregister(mgr);
683187fade8SAnatolij Gustschin if (conf->map)
68434d1dc17SAnatolij Gustschin pci_iounmap(pdev, conf->map);
68534d1dc17SAnatolij Gustschin pci_release_region(pdev, CVP_BAR);
68634d1dc17SAnatolij Gustschin pci_read_config_word(pdev, PCI_COMMAND, &cmd);
68734d1dc17SAnatolij Gustschin cmd &= ~PCI_COMMAND_MEMORY;
68834d1dc17SAnatolij Gustschin pci_write_config_word(pdev, PCI_COMMAND, cmd);
68934d1dc17SAnatolij Gustschin }
69034d1dc17SAnatolij Gustschin
altera_cvp_init(void)69130522a95SAnatolij Gustschin static int __init altera_cvp_init(void)
69230522a95SAnatolij Gustschin {
69330522a95SAnatolij Gustschin int ret;
69430522a95SAnatolij Gustschin
69530522a95SAnatolij Gustschin ret = pci_register_driver(&altera_cvp_driver);
69630522a95SAnatolij Gustschin if (ret)
69730522a95SAnatolij Gustschin return ret;
69830522a95SAnatolij Gustschin
69930522a95SAnatolij Gustschin ret = driver_create_file(&altera_cvp_driver.driver,
70030522a95SAnatolij Gustschin &driver_attr_chkcfg);
70130522a95SAnatolij Gustschin if (ret)
70230522a95SAnatolij Gustschin pr_warn("Can't create sysfs chkcfg file\n");
70330522a95SAnatolij Gustschin
70430522a95SAnatolij Gustschin return 0;
70530522a95SAnatolij Gustschin }
70630522a95SAnatolij Gustschin
altera_cvp_exit(void)70730522a95SAnatolij Gustschin static void __exit altera_cvp_exit(void)
70830522a95SAnatolij Gustschin {
70930522a95SAnatolij Gustschin driver_remove_file(&altera_cvp_driver.driver, &driver_attr_chkcfg);
71030522a95SAnatolij Gustschin pci_unregister_driver(&altera_cvp_driver);
71130522a95SAnatolij Gustschin }
71230522a95SAnatolij Gustschin
71330522a95SAnatolij Gustschin module_init(altera_cvp_init);
71430522a95SAnatolij Gustschin module_exit(altera_cvp_exit);
71534d1dc17SAnatolij Gustschin
71634d1dc17SAnatolij Gustschin MODULE_LICENSE("GPL v2");
71734d1dc17SAnatolij Gustschin MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");
71834d1dc17SAnatolij Gustschin MODULE_DESCRIPTION("Module to load Altera FPGA over CvP");
719