18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * FPGA Manager Driver for Altera SOCFPGA
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2013-2015 Altera Corporation
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/completion.h>
88c2ecf20Sopenharmony_ci#include <linux/delay.h>
98c2ecf20Sopenharmony_ci#include <linux/fpga/fpga-mgr.h>
108c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
118c2ecf20Sopenharmony_ci#include <linux/io.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/of_address.h>
148c2ecf20Sopenharmony_ci#include <linux/of_irq.h>
158c2ecf20Sopenharmony_ci#include <linux/pm.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/* Register offsets */
188c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_STAT_OFST				0x0
198c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_CTL_OFST					0x4
208c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_DCLKCNT_OFST				0x8
218c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_DCLKSTAT_OFST				0xc
228c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_GPIO_INTEN_OFST				0x830
238c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_GPIO_INTMSK_OFST				0x834
248c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_GPIO_INTTYPE_LEVEL_OFST			0x838
258c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_GPIO_INT_POL_OFST			0x83c
268c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_GPIO_INTSTAT_OFST			0x840
278c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_GPIO_RAW_INTSTAT_OFST			0x844
288c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_GPIO_PORTA_EOI_OFST			0x84c
298c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_GPIO_EXT_PORTA_OFST			0x850
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/* Register bit defines */
328c2ecf20Sopenharmony_ci/* SOCFPGA_FPGMGR_STAT register mode field values */
338c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_STAT_POWER_UP				0x0 /*ramping*/
348c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_STAT_RESET				0x1
358c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_STAT_CFG					0x2
368c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_STAT_INIT				0x3
378c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_STAT_USER_MODE				0x4
388c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_STAT_UNKNOWN				0x5
398c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_STAT_STATE_MASK				0x7
408c2ecf20Sopenharmony_ci/* This is a flag value that doesn't really happen in this register field */
418c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_STAT_POWER_OFF				0x0
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci#define MSEL_PP16_FAST_NOAES_NODC				0x0
448c2ecf20Sopenharmony_ci#define MSEL_PP16_FAST_AES_NODC					0x1
458c2ecf20Sopenharmony_ci#define MSEL_PP16_FAST_AESOPT_DC				0x2
468c2ecf20Sopenharmony_ci#define MSEL_PP16_SLOW_NOAES_NODC				0x4
478c2ecf20Sopenharmony_ci#define MSEL_PP16_SLOW_AES_NODC					0x5
488c2ecf20Sopenharmony_ci#define MSEL_PP16_SLOW_AESOPT_DC				0x6
498c2ecf20Sopenharmony_ci#define MSEL_PP32_FAST_NOAES_NODC				0x8
508c2ecf20Sopenharmony_ci#define MSEL_PP32_FAST_AES_NODC					0x9
518c2ecf20Sopenharmony_ci#define MSEL_PP32_FAST_AESOPT_DC				0xa
528c2ecf20Sopenharmony_ci#define MSEL_PP32_SLOW_NOAES_NODC				0xc
538c2ecf20Sopenharmony_ci#define MSEL_PP32_SLOW_AES_NODC					0xd
548c2ecf20Sopenharmony_ci#define MSEL_PP32_SLOW_AESOPT_DC				0xe
558c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_STAT_MSEL_MASK				0x000000f8
568c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_STAT_MSEL_SHIFT				3
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/* SOCFPGA_FPGMGR_CTL register */
598c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_CTL_EN					0x00000001
608c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_CTL_NCE					0x00000002
618c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_CTL_NCFGPULL				0x00000004
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci#define CDRATIO_X1						0x00000000
648c2ecf20Sopenharmony_ci#define CDRATIO_X2						0x00000040
658c2ecf20Sopenharmony_ci#define CDRATIO_X4						0x00000080
668c2ecf20Sopenharmony_ci#define CDRATIO_X8						0x000000c0
678c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_CTL_CDRATIO_MASK				0x000000c0
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_CTL_AXICFGEN				0x00000100
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#define CFGWDTH_16						0x00000000
728c2ecf20Sopenharmony_ci#define CFGWDTH_32						0x00000200
738c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_CTL_CFGWDTH_MASK				0x00000200
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/* SOCFPGA_FPGMGR_DCLKSTAT register */
768c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_DCLKSTAT_DCNTDONE_E_DONE			0x1
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci/* SOCFPGA_FPGMGR_GPIO_* registers share the same bit positions */
798c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_MON_NSTATUS				0x0001
808c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_MON_CONF_DONE				0x0002
818c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_MON_INIT_DONE				0x0004
828c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_MON_CRC_ERROR				0x0008
838c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_MON_CVP_CONF_DONE			0x0010
848c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_MON_PR_READY				0x0020
858c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_MON_PR_ERROR				0x0040
868c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_MON_PR_DONE				0x0080
878c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_MON_NCONFIG_PIN				0x0100
888c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_MON_NSTATUS_PIN				0x0200
898c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_MON_CONF_DONE_PIN			0x0400
908c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_MON_FPGA_POWER_ON			0x0800
918c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_MON_STATUS_MASK				0x0fff
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#define SOCFPGA_FPGMGR_NUM_SUPPLIES 3
948c2ecf20Sopenharmony_ci#define SOCFPGA_RESUME_TIMEOUT 3
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/* In power-up order. Reverse for power-down. */
978c2ecf20Sopenharmony_cistatic const char *supply_names[SOCFPGA_FPGMGR_NUM_SUPPLIES] __maybe_unused = {
988c2ecf20Sopenharmony_ci	"FPGA-1.5V",
998c2ecf20Sopenharmony_ci	"FPGA-1.1V",
1008c2ecf20Sopenharmony_ci	"FPGA-2.5V",
1018c2ecf20Sopenharmony_ci};
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistruct socfpga_fpga_priv {
1048c2ecf20Sopenharmony_ci	void __iomem *fpga_base_addr;
1058c2ecf20Sopenharmony_ci	void __iomem *fpga_data_addr;
1068c2ecf20Sopenharmony_ci	struct completion status_complete;
1078c2ecf20Sopenharmony_ci	int irq;
1088c2ecf20Sopenharmony_ci};
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistruct cfgmgr_mode {
1118c2ecf20Sopenharmony_ci	/* Values to set in the CTRL register */
1128c2ecf20Sopenharmony_ci	u32 ctrl;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	/* flag that this table entry is a valid mode */
1158c2ecf20Sopenharmony_ci	bool valid;
1168c2ecf20Sopenharmony_ci};
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci/* For SOCFPGA_FPGMGR_STAT_MSEL field */
1198c2ecf20Sopenharmony_cistatic struct cfgmgr_mode cfgmgr_modes[] = {
1208c2ecf20Sopenharmony_ci	[MSEL_PP16_FAST_NOAES_NODC] = { CFGWDTH_16 | CDRATIO_X1, 1 },
1218c2ecf20Sopenharmony_ci	[MSEL_PP16_FAST_AES_NODC] =   { CFGWDTH_16 | CDRATIO_X2, 1 },
1228c2ecf20Sopenharmony_ci	[MSEL_PP16_FAST_AESOPT_DC] =  { CFGWDTH_16 | CDRATIO_X4, 1 },
1238c2ecf20Sopenharmony_ci	[MSEL_PP16_SLOW_NOAES_NODC] = { CFGWDTH_16 | CDRATIO_X1, 1 },
1248c2ecf20Sopenharmony_ci	[MSEL_PP16_SLOW_AES_NODC] =   { CFGWDTH_16 | CDRATIO_X2, 1 },
1258c2ecf20Sopenharmony_ci	[MSEL_PP16_SLOW_AESOPT_DC] =  { CFGWDTH_16 | CDRATIO_X4, 1 },
1268c2ecf20Sopenharmony_ci	[MSEL_PP32_FAST_NOAES_NODC] = { CFGWDTH_32 | CDRATIO_X1, 1 },
1278c2ecf20Sopenharmony_ci	[MSEL_PP32_FAST_AES_NODC] =   { CFGWDTH_32 | CDRATIO_X4, 1 },
1288c2ecf20Sopenharmony_ci	[MSEL_PP32_FAST_AESOPT_DC] =  { CFGWDTH_32 | CDRATIO_X8, 1 },
1298c2ecf20Sopenharmony_ci	[MSEL_PP32_SLOW_NOAES_NODC] = { CFGWDTH_32 | CDRATIO_X1, 1 },
1308c2ecf20Sopenharmony_ci	[MSEL_PP32_SLOW_AES_NODC] =   { CFGWDTH_32 | CDRATIO_X4, 1 },
1318c2ecf20Sopenharmony_ci	[MSEL_PP32_SLOW_AESOPT_DC] =  { CFGWDTH_32 | CDRATIO_X8, 1 },
1328c2ecf20Sopenharmony_ci};
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic u32 socfpga_fpga_readl(struct socfpga_fpga_priv *priv, u32 reg_offset)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	return readl(priv->fpga_base_addr + reg_offset);
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic void socfpga_fpga_writel(struct socfpga_fpga_priv *priv, u32 reg_offset,
1408c2ecf20Sopenharmony_ci				u32 value)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	writel(value, priv->fpga_base_addr + reg_offset);
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic u32 socfpga_fpga_raw_readl(struct socfpga_fpga_priv *priv,
1468c2ecf20Sopenharmony_ci				  u32 reg_offset)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	return __raw_readl(priv->fpga_base_addr + reg_offset);
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_cistatic void socfpga_fpga_raw_writel(struct socfpga_fpga_priv *priv,
1528c2ecf20Sopenharmony_ci				    u32 reg_offset, u32 value)
1538c2ecf20Sopenharmony_ci{
1548c2ecf20Sopenharmony_ci	__raw_writel(value, priv->fpga_base_addr + reg_offset);
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_cistatic void socfpga_fpga_data_writel(struct socfpga_fpga_priv *priv, u32 value)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	writel(value, priv->fpga_data_addr);
1608c2ecf20Sopenharmony_ci}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_cistatic inline void socfpga_fpga_set_bitsl(struct socfpga_fpga_priv *priv,
1638c2ecf20Sopenharmony_ci					  u32 offset, u32 bits)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	u32 val;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	val = socfpga_fpga_readl(priv, offset);
1688c2ecf20Sopenharmony_ci	val |= bits;
1698c2ecf20Sopenharmony_ci	socfpga_fpga_writel(priv, offset, val);
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic inline void socfpga_fpga_clr_bitsl(struct socfpga_fpga_priv *priv,
1738c2ecf20Sopenharmony_ci					  u32 offset, u32 bits)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	u32 val;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	val = socfpga_fpga_readl(priv, offset);
1788c2ecf20Sopenharmony_ci	val &= ~bits;
1798c2ecf20Sopenharmony_ci	socfpga_fpga_writel(priv, offset, val);
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_cistatic u32 socfpga_fpga_mon_status_get(struct socfpga_fpga_priv *priv)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	return socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_GPIO_EXT_PORTA_OFST) &
1858c2ecf20Sopenharmony_ci		SOCFPGA_FPGMGR_MON_STATUS_MASK;
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic u32 socfpga_fpga_state_get(struct socfpga_fpga_priv *priv)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	u32 status = socfpga_fpga_mon_status_get(priv);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if ((status & SOCFPGA_FPGMGR_MON_FPGA_POWER_ON) == 0)
1938c2ecf20Sopenharmony_ci		return SOCFPGA_FPGMGR_STAT_POWER_OFF;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	return socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_STAT_OFST) &
1968c2ecf20Sopenharmony_ci		SOCFPGA_FPGMGR_STAT_STATE_MASK;
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic void socfpga_fpga_clear_done_status(struct socfpga_fpga_priv *priv)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_DCLKSTAT_OFST,
2028c2ecf20Sopenharmony_ci			    SOCFPGA_FPGMGR_DCLKSTAT_DCNTDONE_E_DONE);
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci/*
2068c2ecf20Sopenharmony_ci * Set the DCLKCNT, wait for DCLKSTAT to report the count completed, and clear
2078c2ecf20Sopenharmony_ci * the complete status.
2088c2ecf20Sopenharmony_ci */
2098c2ecf20Sopenharmony_cistatic int socfpga_fpga_dclk_set_and_wait_clear(struct socfpga_fpga_priv *priv,
2108c2ecf20Sopenharmony_ci						u32 count)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	int timeout = 2;
2138c2ecf20Sopenharmony_ci	u32 done;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	/* Clear any existing DONE status. */
2168c2ecf20Sopenharmony_ci	if (socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_DCLKSTAT_OFST))
2178c2ecf20Sopenharmony_ci		socfpga_fpga_clear_done_status(priv);
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	/* Issue the DCLK count. */
2208c2ecf20Sopenharmony_ci	socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_DCLKCNT_OFST, count);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	/* Poll DCLKSTAT to see if it completed in the timeout period. */
2238c2ecf20Sopenharmony_ci	do {
2248c2ecf20Sopenharmony_ci		done = socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_DCLKSTAT_OFST);
2258c2ecf20Sopenharmony_ci		if (done == SOCFPGA_FPGMGR_DCLKSTAT_DCNTDONE_E_DONE) {
2268c2ecf20Sopenharmony_ci			socfpga_fpga_clear_done_status(priv);
2278c2ecf20Sopenharmony_ci			return 0;
2288c2ecf20Sopenharmony_ci		}
2298c2ecf20Sopenharmony_ci		udelay(1);
2308c2ecf20Sopenharmony_ci	} while (timeout--);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
2338c2ecf20Sopenharmony_ci}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_cistatic int socfpga_fpga_wait_for_state(struct socfpga_fpga_priv *priv,
2368c2ecf20Sopenharmony_ci				       u32 state)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	int timeout = 2;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	/*
2418c2ecf20Sopenharmony_ci	 * HW doesn't support an interrupt for changes in state, so poll to see
2428c2ecf20Sopenharmony_ci	 * if it matches the requested state within the timeout period.
2438c2ecf20Sopenharmony_ci	 */
2448c2ecf20Sopenharmony_ci	do {
2458c2ecf20Sopenharmony_ci		if ((socfpga_fpga_state_get(priv) & state) != 0)
2468c2ecf20Sopenharmony_ci			return 0;
2478c2ecf20Sopenharmony_ci		msleep(20);
2488c2ecf20Sopenharmony_ci	} while (timeout--);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic void socfpga_fpga_enable_irqs(struct socfpga_fpga_priv *priv, u32 irqs)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	/* set irqs to level sensitive */
2568c2ecf20Sopenharmony_ci	socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_INTTYPE_LEVEL_OFST, 0);
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	/* set interrupt polarity */
2598c2ecf20Sopenharmony_ci	socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_INT_POL_OFST, irqs);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	/* clear irqs */
2628c2ecf20Sopenharmony_ci	socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_PORTA_EOI_OFST, irqs);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	/* unmask interrupts */
2658c2ecf20Sopenharmony_ci	socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_INTMSK_OFST, 0);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	/* enable interrupts */
2688c2ecf20Sopenharmony_ci	socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_INTEN_OFST, irqs);
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_cistatic void socfpga_fpga_disable_irqs(struct socfpga_fpga_priv *priv)
2728c2ecf20Sopenharmony_ci{
2738c2ecf20Sopenharmony_ci	socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_INTEN_OFST, 0);
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic irqreturn_t socfpga_fpga_isr(int irq, void *dev_id)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	struct socfpga_fpga_priv *priv = dev_id;
2798c2ecf20Sopenharmony_ci	u32 irqs, st;
2808c2ecf20Sopenharmony_ci	bool conf_done, nstatus;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	/* clear irqs */
2838c2ecf20Sopenharmony_ci	irqs = socfpga_fpga_raw_readl(priv, SOCFPGA_FPGMGR_GPIO_INTSTAT_OFST);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	socfpga_fpga_raw_writel(priv, SOCFPGA_FPGMGR_GPIO_PORTA_EOI_OFST, irqs);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	st = socfpga_fpga_raw_readl(priv, SOCFPGA_FPGMGR_GPIO_EXT_PORTA_OFST);
2888c2ecf20Sopenharmony_ci	conf_done = (st & SOCFPGA_FPGMGR_MON_CONF_DONE) != 0;
2898c2ecf20Sopenharmony_ci	nstatus = (st & SOCFPGA_FPGMGR_MON_NSTATUS) != 0;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	/* success */
2928c2ecf20Sopenharmony_ci	if (conf_done && nstatus) {
2938c2ecf20Sopenharmony_ci		/* disable irqs */
2948c2ecf20Sopenharmony_ci		socfpga_fpga_raw_writel(priv,
2958c2ecf20Sopenharmony_ci					SOCFPGA_FPGMGR_GPIO_INTEN_OFST, 0);
2968c2ecf20Sopenharmony_ci		complete(&priv->status_complete);
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic int socfpga_fpga_wait_for_config_done(struct socfpga_fpga_priv *priv)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	int timeout, ret = 0;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	socfpga_fpga_disable_irqs(priv);
3078c2ecf20Sopenharmony_ci	init_completion(&priv->status_complete);
3088c2ecf20Sopenharmony_ci	socfpga_fpga_enable_irqs(priv, SOCFPGA_FPGMGR_MON_CONF_DONE);
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	timeout = wait_for_completion_interruptible_timeout(
3118c2ecf20Sopenharmony_ci						&priv->status_complete,
3128c2ecf20Sopenharmony_ci						msecs_to_jiffies(10));
3138c2ecf20Sopenharmony_ci	if (timeout == 0)
3148c2ecf20Sopenharmony_ci		ret = -ETIMEDOUT;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	socfpga_fpga_disable_irqs(priv);
3178c2ecf20Sopenharmony_ci	return ret;
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic int socfpga_fpga_cfg_mode_get(struct socfpga_fpga_priv *priv)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	u32 msel;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	msel = socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_STAT_OFST);
3258c2ecf20Sopenharmony_ci	msel &= SOCFPGA_FPGMGR_STAT_MSEL_MASK;
3268c2ecf20Sopenharmony_ci	msel >>= SOCFPGA_FPGMGR_STAT_MSEL_SHIFT;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	/* Check that this MSEL setting is supported */
3298c2ecf20Sopenharmony_ci	if ((msel >= ARRAY_SIZE(cfgmgr_modes)) || !cfgmgr_modes[msel].valid)
3308c2ecf20Sopenharmony_ci		return -EINVAL;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	return msel;
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic int socfpga_fpga_cfg_mode_set(struct socfpga_fpga_priv *priv)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	u32 ctrl_reg;
3388c2ecf20Sopenharmony_ci	int mode;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	/* get value from MSEL pins */
3418c2ecf20Sopenharmony_ci	mode = socfpga_fpga_cfg_mode_get(priv);
3428c2ecf20Sopenharmony_ci	if (mode < 0)
3438c2ecf20Sopenharmony_ci		return mode;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	/* Adjust CTRL for the CDRATIO */
3468c2ecf20Sopenharmony_ci	ctrl_reg = socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_CTL_OFST);
3478c2ecf20Sopenharmony_ci	ctrl_reg &= ~SOCFPGA_FPGMGR_CTL_CDRATIO_MASK;
3488c2ecf20Sopenharmony_ci	ctrl_reg &= ~SOCFPGA_FPGMGR_CTL_CFGWDTH_MASK;
3498c2ecf20Sopenharmony_ci	ctrl_reg |= cfgmgr_modes[mode].ctrl;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	/* Set NCE to 0. */
3528c2ecf20Sopenharmony_ci	ctrl_reg &= ~SOCFPGA_FPGMGR_CTL_NCE;
3538c2ecf20Sopenharmony_ci	socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_CTL_OFST, ctrl_reg);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	return 0;
3568c2ecf20Sopenharmony_ci}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_cistatic int socfpga_fpga_reset(struct fpga_manager *mgr)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	struct socfpga_fpga_priv *priv = mgr->priv;
3618c2ecf20Sopenharmony_ci	u32 ctrl_reg, status;
3628c2ecf20Sopenharmony_ci	int ret;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	/*
3658c2ecf20Sopenharmony_ci	 * Step 1:
3668c2ecf20Sopenharmony_ci	 *  - Set CTRL.CFGWDTH, CTRL.CDRATIO to match cfg mode
3678c2ecf20Sopenharmony_ci	 *  - Set CTRL.NCE to 0
3688c2ecf20Sopenharmony_ci	 */
3698c2ecf20Sopenharmony_ci	ret = socfpga_fpga_cfg_mode_set(priv);
3708c2ecf20Sopenharmony_ci	if (ret)
3718c2ecf20Sopenharmony_ci		return ret;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	/* Step 2: Set CTRL.EN to 1 */
3748c2ecf20Sopenharmony_ci	socfpga_fpga_set_bitsl(priv, SOCFPGA_FPGMGR_CTL_OFST,
3758c2ecf20Sopenharmony_ci			       SOCFPGA_FPGMGR_CTL_EN);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	/* Step 3: Set CTRL.NCONFIGPULL to 1 to put FPGA in reset */
3788c2ecf20Sopenharmony_ci	ctrl_reg = socfpga_fpga_readl(priv, SOCFPGA_FPGMGR_CTL_OFST);
3798c2ecf20Sopenharmony_ci	ctrl_reg |= SOCFPGA_FPGMGR_CTL_NCFGPULL;
3808c2ecf20Sopenharmony_ci	socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_CTL_OFST, ctrl_reg);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	/* Step 4: Wait for STATUS.MODE to report FPGA is in reset phase */
3838c2ecf20Sopenharmony_ci	status = socfpga_fpga_wait_for_state(priv, SOCFPGA_FPGMGR_STAT_RESET);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	/* Step 5: Set CONTROL.NCONFIGPULL to 0 to release FPGA from reset */
3868c2ecf20Sopenharmony_ci	ctrl_reg &= ~SOCFPGA_FPGMGR_CTL_NCFGPULL;
3878c2ecf20Sopenharmony_ci	socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_CTL_OFST, ctrl_reg);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	/* Timeout waiting for reset */
3908c2ecf20Sopenharmony_ci	if (status)
3918c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	return 0;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci/*
3978c2ecf20Sopenharmony_ci * Prepare the FPGA to receive the configuration data.
3988c2ecf20Sopenharmony_ci */
3998c2ecf20Sopenharmony_cistatic int socfpga_fpga_ops_configure_init(struct fpga_manager *mgr,
4008c2ecf20Sopenharmony_ci					   struct fpga_image_info *info,
4018c2ecf20Sopenharmony_ci					   const char *buf, size_t count)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	struct socfpga_fpga_priv *priv = mgr->priv;
4048c2ecf20Sopenharmony_ci	int ret;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
4078c2ecf20Sopenharmony_ci		dev_err(&mgr->dev, "Partial reconfiguration not supported.\n");
4088c2ecf20Sopenharmony_ci		return -EINVAL;
4098c2ecf20Sopenharmony_ci	}
4108c2ecf20Sopenharmony_ci	/* Steps 1 - 5: Reset the FPGA */
4118c2ecf20Sopenharmony_ci	ret = socfpga_fpga_reset(mgr);
4128c2ecf20Sopenharmony_ci	if (ret)
4138c2ecf20Sopenharmony_ci		return ret;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci	/* Step 6: Wait for FPGA to enter configuration phase */
4168c2ecf20Sopenharmony_ci	if (socfpga_fpga_wait_for_state(priv, SOCFPGA_FPGMGR_STAT_CFG))
4178c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	/* Step 7: Clear nSTATUS interrupt */
4208c2ecf20Sopenharmony_ci	socfpga_fpga_writel(priv, SOCFPGA_FPGMGR_GPIO_PORTA_EOI_OFST,
4218c2ecf20Sopenharmony_ci			    SOCFPGA_FPGMGR_MON_NSTATUS);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	/* Step 8: Set CTRL.AXICFGEN to 1 to enable transfer of config data */
4248c2ecf20Sopenharmony_ci	socfpga_fpga_set_bitsl(priv, SOCFPGA_FPGMGR_CTL_OFST,
4258c2ecf20Sopenharmony_ci			       SOCFPGA_FPGMGR_CTL_AXICFGEN);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	return 0;
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci/*
4318c2ecf20Sopenharmony_ci * Step 9: write data to the FPGA data register
4328c2ecf20Sopenharmony_ci */
4338c2ecf20Sopenharmony_cistatic int socfpga_fpga_ops_configure_write(struct fpga_manager *mgr,
4348c2ecf20Sopenharmony_ci					    const char *buf, size_t count)
4358c2ecf20Sopenharmony_ci{
4368c2ecf20Sopenharmony_ci	struct socfpga_fpga_priv *priv = mgr->priv;
4378c2ecf20Sopenharmony_ci	u32 *buffer_32 = (u32 *)buf;
4388c2ecf20Sopenharmony_ci	size_t i = 0;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	if (count <= 0)
4418c2ecf20Sopenharmony_ci		return -EINVAL;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	/* Write out the complete 32-bit chunks. */
4448c2ecf20Sopenharmony_ci	while (count >= sizeof(u32)) {
4458c2ecf20Sopenharmony_ci		socfpga_fpga_data_writel(priv, buffer_32[i++]);
4468c2ecf20Sopenharmony_ci		count -= sizeof(u32);
4478c2ecf20Sopenharmony_ci	}
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	/* Write out remaining non 32-bit chunks. */
4508c2ecf20Sopenharmony_ci	switch (count) {
4518c2ecf20Sopenharmony_ci	case 3:
4528c2ecf20Sopenharmony_ci		socfpga_fpga_data_writel(priv, buffer_32[i++] & 0x00ffffff);
4538c2ecf20Sopenharmony_ci		break;
4548c2ecf20Sopenharmony_ci	case 2:
4558c2ecf20Sopenharmony_ci		socfpga_fpga_data_writel(priv, buffer_32[i++] & 0x0000ffff);
4568c2ecf20Sopenharmony_ci		break;
4578c2ecf20Sopenharmony_ci	case 1:
4588c2ecf20Sopenharmony_ci		socfpga_fpga_data_writel(priv, buffer_32[i++] & 0x000000ff);
4598c2ecf20Sopenharmony_ci		break;
4608c2ecf20Sopenharmony_ci	case 0:
4618c2ecf20Sopenharmony_ci		break;
4628c2ecf20Sopenharmony_ci	default:
4638c2ecf20Sopenharmony_ci		/* This will never happen. */
4648c2ecf20Sopenharmony_ci		return -EFAULT;
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	return 0;
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cistatic int socfpga_fpga_ops_configure_complete(struct fpga_manager *mgr,
4718c2ecf20Sopenharmony_ci					       struct fpga_image_info *info)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	struct socfpga_fpga_priv *priv = mgr->priv;
4748c2ecf20Sopenharmony_ci	u32 status;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	/*
4778c2ecf20Sopenharmony_ci	 * Step 10:
4788c2ecf20Sopenharmony_ci	 *  - Observe CONF_DONE and nSTATUS (active low)
4798c2ecf20Sopenharmony_ci	 *  - if CONF_DONE = 1 and nSTATUS = 1, configuration was successful
4808c2ecf20Sopenharmony_ci	 *  - if CONF_DONE = 0 and nSTATUS = 0, configuration failed
4818c2ecf20Sopenharmony_ci	 */
4828c2ecf20Sopenharmony_ci	status = socfpga_fpga_wait_for_config_done(priv);
4838c2ecf20Sopenharmony_ci	if (status)
4848c2ecf20Sopenharmony_ci		return status;
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	/* Step 11: Clear CTRL.AXICFGEN to disable transfer of config data */
4878c2ecf20Sopenharmony_ci	socfpga_fpga_clr_bitsl(priv, SOCFPGA_FPGMGR_CTL_OFST,
4888c2ecf20Sopenharmony_ci			       SOCFPGA_FPGMGR_CTL_AXICFGEN);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	/*
4918c2ecf20Sopenharmony_ci	 * Step 12:
4928c2ecf20Sopenharmony_ci	 *  - Write 4 to DCLKCNT
4938c2ecf20Sopenharmony_ci	 *  - Wait for STATUS.DCNTDONE = 1
4948c2ecf20Sopenharmony_ci	 *  - Clear W1C bit in STATUS.DCNTDONE
4958c2ecf20Sopenharmony_ci	 */
4968c2ecf20Sopenharmony_ci	if (socfpga_fpga_dclk_set_and_wait_clear(priv, 4))
4978c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	/* Step 13: Wait for STATUS.MODE to report USER MODE */
5008c2ecf20Sopenharmony_ci	if (socfpga_fpga_wait_for_state(priv, SOCFPGA_FPGMGR_STAT_USER_MODE))
5018c2ecf20Sopenharmony_ci		return -ETIMEDOUT;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	/* Step 14: Set CTRL.EN to 0 */
5048c2ecf20Sopenharmony_ci	socfpga_fpga_clr_bitsl(priv, SOCFPGA_FPGMGR_CTL_OFST,
5058c2ecf20Sopenharmony_ci			       SOCFPGA_FPGMGR_CTL_EN);
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	return 0;
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci/* Translate state register values to FPGA framework state */
5118c2ecf20Sopenharmony_cistatic const enum fpga_mgr_states socfpga_state_to_framework_state[] = {
5128c2ecf20Sopenharmony_ci	[SOCFPGA_FPGMGR_STAT_POWER_OFF] = FPGA_MGR_STATE_POWER_OFF,
5138c2ecf20Sopenharmony_ci	[SOCFPGA_FPGMGR_STAT_RESET] = FPGA_MGR_STATE_RESET,
5148c2ecf20Sopenharmony_ci	[SOCFPGA_FPGMGR_STAT_CFG] = FPGA_MGR_STATE_WRITE_INIT,
5158c2ecf20Sopenharmony_ci	[SOCFPGA_FPGMGR_STAT_INIT] = FPGA_MGR_STATE_WRITE_INIT,
5168c2ecf20Sopenharmony_ci	[SOCFPGA_FPGMGR_STAT_USER_MODE] = FPGA_MGR_STATE_OPERATING,
5178c2ecf20Sopenharmony_ci	[SOCFPGA_FPGMGR_STAT_UNKNOWN] = FPGA_MGR_STATE_UNKNOWN,
5188c2ecf20Sopenharmony_ci};
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_cistatic enum fpga_mgr_states socfpga_fpga_ops_state(struct fpga_manager *mgr)
5218c2ecf20Sopenharmony_ci{
5228c2ecf20Sopenharmony_ci	struct socfpga_fpga_priv *priv = mgr->priv;
5238c2ecf20Sopenharmony_ci	enum fpga_mgr_states ret;
5248c2ecf20Sopenharmony_ci	u32 state;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	state = socfpga_fpga_state_get(priv);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	if (state < ARRAY_SIZE(socfpga_state_to_framework_state))
5298c2ecf20Sopenharmony_ci		ret = socfpga_state_to_framework_state[state];
5308c2ecf20Sopenharmony_ci	else
5318c2ecf20Sopenharmony_ci		ret = FPGA_MGR_STATE_UNKNOWN;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	return ret;
5348c2ecf20Sopenharmony_ci}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_cistatic const struct fpga_manager_ops socfpga_fpga_ops = {
5378c2ecf20Sopenharmony_ci	.state = socfpga_fpga_ops_state,
5388c2ecf20Sopenharmony_ci	.write_init = socfpga_fpga_ops_configure_init,
5398c2ecf20Sopenharmony_ci	.write = socfpga_fpga_ops_configure_write,
5408c2ecf20Sopenharmony_ci	.write_complete = socfpga_fpga_ops_configure_complete,
5418c2ecf20Sopenharmony_ci};
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_cistatic int socfpga_fpga_probe(struct platform_device *pdev)
5448c2ecf20Sopenharmony_ci{
5458c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
5468c2ecf20Sopenharmony_ci	struct socfpga_fpga_priv *priv;
5478c2ecf20Sopenharmony_ci	struct fpga_manager *mgr;
5488c2ecf20Sopenharmony_ci	struct resource *res;
5498c2ecf20Sopenharmony_ci	int ret;
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
5528c2ecf20Sopenharmony_ci	if (!priv)
5538c2ecf20Sopenharmony_ci		return -ENOMEM;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
5568c2ecf20Sopenharmony_ci	priv->fpga_base_addr = devm_ioremap_resource(dev, res);
5578c2ecf20Sopenharmony_ci	if (IS_ERR(priv->fpga_base_addr))
5588c2ecf20Sopenharmony_ci		return PTR_ERR(priv->fpga_base_addr);
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
5618c2ecf20Sopenharmony_ci	priv->fpga_data_addr = devm_ioremap_resource(dev, res);
5628c2ecf20Sopenharmony_ci	if (IS_ERR(priv->fpga_data_addr))
5638c2ecf20Sopenharmony_ci		return PTR_ERR(priv->fpga_data_addr);
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	priv->irq = platform_get_irq(pdev, 0);
5668c2ecf20Sopenharmony_ci	if (priv->irq < 0)
5678c2ecf20Sopenharmony_ci		return priv->irq;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	ret = devm_request_irq(dev, priv->irq, socfpga_fpga_isr, 0,
5708c2ecf20Sopenharmony_ci			       dev_name(dev), priv);
5718c2ecf20Sopenharmony_ci	if (ret)
5728c2ecf20Sopenharmony_ci		return ret;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	mgr = devm_fpga_mgr_create(dev, "Altera SOCFPGA FPGA Manager",
5758c2ecf20Sopenharmony_ci				   &socfpga_fpga_ops, priv);
5768c2ecf20Sopenharmony_ci	if (!mgr)
5778c2ecf20Sopenharmony_ci		return -ENOMEM;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, mgr);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	return fpga_mgr_register(mgr);
5828c2ecf20Sopenharmony_ci}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_cistatic int socfpga_fpga_remove(struct platform_device *pdev)
5858c2ecf20Sopenharmony_ci{
5868c2ecf20Sopenharmony_ci	struct fpga_manager *mgr = platform_get_drvdata(pdev);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	fpga_mgr_unregister(mgr);
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	return 0;
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci#ifdef CONFIG_OF
5948c2ecf20Sopenharmony_cistatic const struct of_device_id socfpga_fpga_of_match[] = {
5958c2ecf20Sopenharmony_ci	{ .compatible = "altr,socfpga-fpga-mgr", },
5968c2ecf20Sopenharmony_ci	{},
5978c2ecf20Sopenharmony_ci};
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, socfpga_fpga_of_match);
6008c2ecf20Sopenharmony_ci#endif
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_cistatic struct platform_driver socfpga_fpga_driver = {
6038c2ecf20Sopenharmony_ci	.probe = socfpga_fpga_probe,
6048c2ecf20Sopenharmony_ci	.remove = socfpga_fpga_remove,
6058c2ecf20Sopenharmony_ci	.driver = {
6068c2ecf20Sopenharmony_ci		.name	= "socfpga_fpga_manager",
6078c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(socfpga_fpga_of_match),
6088c2ecf20Sopenharmony_ci	},
6098c2ecf20Sopenharmony_ci};
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_cimodule_platform_driver(socfpga_fpga_driver);
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ciMODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>");
6148c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Altera SOCFPGA FPGA Manager");
6158c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
616