xref: /openbmc/linux/drivers/fpga/altera-cvp.c (revision 4ba0b2c2)
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, &regval);
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