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