18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * FPGA Manager Driver for FPGA Management Engine (FME) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2017-2018 Intel Corporation, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: 88c2ecf20Sopenharmony_ci * Kang Luwei <luwei.kang@intel.com> 98c2ecf20Sopenharmony_ci * Xiao Guangrong <guangrong.xiao@linux.intel.com> 108c2ecf20Sopenharmony_ci * Wu Hao <hao.wu@intel.com> 118c2ecf20Sopenharmony_ci * Joseph Grecco <joe.grecco@intel.com> 128c2ecf20Sopenharmony_ci * Enno Luebbers <enno.luebbers@intel.com> 138c2ecf20Sopenharmony_ci * Tim Whisonant <tim.whisonant@intel.com> 148c2ecf20Sopenharmony_ci * Ananda Ravuri <ananda.ravuri@intel.com> 158c2ecf20Sopenharmony_ci * Christopher Rauer <christopher.rauer@intel.com> 168c2ecf20Sopenharmony_ci * Henry Mitchel <henry.mitchel@intel.com> 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 208c2ecf20Sopenharmony_ci#include <linux/module.h> 218c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 228c2ecf20Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h> 238c2ecf20Sopenharmony_ci#include <linux/fpga/fpga-mgr.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "dfl-fme-pr.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* FME Partial Reconfiguration Sub Feature Register Set */ 288c2ecf20Sopenharmony_ci#define FME_PR_DFH 0x0 298c2ecf20Sopenharmony_ci#define FME_PR_CTRL 0x8 308c2ecf20Sopenharmony_ci#define FME_PR_STS 0x10 318c2ecf20Sopenharmony_ci#define FME_PR_DATA 0x18 328c2ecf20Sopenharmony_ci#define FME_PR_ERR 0x20 338c2ecf20Sopenharmony_ci#define FME_PR_INTFC_ID_L 0xA8 348c2ecf20Sopenharmony_ci#define FME_PR_INTFC_ID_H 0xB0 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* FME PR Control Register Bitfield */ 378c2ecf20Sopenharmony_ci#define FME_PR_CTRL_PR_RST BIT_ULL(0) /* Reset PR engine */ 388c2ecf20Sopenharmony_ci#define FME_PR_CTRL_PR_RSTACK BIT_ULL(4) /* Ack for PR engine reset */ 398c2ecf20Sopenharmony_ci#define FME_PR_CTRL_PR_RGN_ID GENMASK_ULL(9, 7) /* PR Region ID */ 408c2ecf20Sopenharmony_ci#define FME_PR_CTRL_PR_START BIT_ULL(12) /* Start to request PR service */ 418c2ecf20Sopenharmony_ci#define FME_PR_CTRL_PR_COMPLETE BIT_ULL(13) /* PR data push completion */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* FME PR Status Register Bitfield */ 448c2ecf20Sopenharmony_ci/* Number of available entries in HW queue inside the PR engine. */ 458c2ecf20Sopenharmony_ci#define FME_PR_STS_PR_CREDIT GENMASK_ULL(8, 0) 468c2ecf20Sopenharmony_ci#define FME_PR_STS_PR_STS BIT_ULL(16) /* PR operation status */ 478c2ecf20Sopenharmony_ci#define FME_PR_STS_PR_STS_IDLE 0 488c2ecf20Sopenharmony_ci#define FME_PR_STS_PR_CTRLR_STS GENMASK_ULL(22, 20) /* Controller status */ 498c2ecf20Sopenharmony_ci#define FME_PR_STS_PR_HOST_STS GENMASK_ULL(27, 24) /* PR host status */ 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* FME PR Data Register Bitfield */ 528c2ecf20Sopenharmony_ci/* PR data from the raw-binary file. */ 538c2ecf20Sopenharmony_ci#define FME_PR_DATA_PR_DATA_RAW GENMASK_ULL(32, 0) 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* FME PR Error Register */ 568c2ecf20Sopenharmony_ci/* PR Operation errors detected. */ 578c2ecf20Sopenharmony_ci#define FME_PR_ERR_OPERATION_ERR BIT_ULL(0) 588c2ecf20Sopenharmony_ci/* CRC error detected. */ 598c2ecf20Sopenharmony_ci#define FME_PR_ERR_CRC_ERR BIT_ULL(1) 608c2ecf20Sopenharmony_ci/* Incompatible PR bitstream detected. */ 618c2ecf20Sopenharmony_ci#define FME_PR_ERR_INCOMPATIBLE_BS BIT_ULL(2) 628c2ecf20Sopenharmony_ci/* PR data push protocol violated. */ 638c2ecf20Sopenharmony_ci#define FME_PR_ERR_PROTOCOL_ERR BIT_ULL(3) 648c2ecf20Sopenharmony_ci/* PR data fifo overflow error detected */ 658c2ecf20Sopenharmony_ci#define FME_PR_ERR_FIFO_OVERFLOW BIT_ULL(4) 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define PR_WAIT_TIMEOUT 8000000 688c2ecf20Sopenharmony_ci#define PR_HOST_STATUS_IDLE 0 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistruct fme_mgr_priv { 718c2ecf20Sopenharmony_ci void __iomem *ioaddr; 728c2ecf20Sopenharmony_ci u64 pr_error; 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic u64 pr_error_to_mgr_status(u64 err) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci u64 status = 0; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (err & FME_PR_ERR_OPERATION_ERR) 808c2ecf20Sopenharmony_ci status |= FPGA_MGR_STATUS_OPERATION_ERR; 818c2ecf20Sopenharmony_ci if (err & FME_PR_ERR_CRC_ERR) 828c2ecf20Sopenharmony_ci status |= FPGA_MGR_STATUS_CRC_ERR; 838c2ecf20Sopenharmony_ci if (err & FME_PR_ERR_INCOMPATIBLE_BS) 848c2ecf20Sopenharmony_ci status |= FPGA_MGR_STATUS_INCOMPATIBLE_IMAGE_ERR; 858c2ecf20Sopenharmony_ci if (err & FME_PR_ERR_PROTOCOL_ERR) 868c2ecf20Sopenharmony_ci status |= FPGA_MGR_STATUS_IP_PROTOCOL_ERR; 878c2ecf20Sopenharmony_ci if (err & FME_PR_ERR_FIFO_OVERFLOW) 888c2ecf20Sopenharmony_ci status |= FPGA_MGR_STATUS_FIFO_OVERFLOW_ERR; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci return status; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic u64 fme_mgr_pr_error_handle(void __iomem *fme_pr) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci u64 pr_status, pr_error; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci pr_status = readq(fme_pr + FME_PR_STS); 988c2ecf20Sopenharmony_ci if (!(pr_status & FME_PR_STS_PR_STS)) 998c2ecf20Sopenharmony_ci return 0; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci pr_error = readq(fme_pr + FME_PR_ERR); 1028c2ecf20Sopenharmony_ci writeq(pr_error, fme_pr + FME_PR_ERR); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return pr_error; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic int fme_mgr_write_init(struct fpga_manager *mgr, 1088c2ecf20Sopenharmony_ci struct fpga_image_info *info, 1098c2ecf20Sopenharmony_ci const char *buf, size_t count) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct device *dev = &mgr->dev; 1128c2ecf20Sopenharmony_ci struct fme_mgr_priv *priv = mgr->priv; 1138c2ecf20Sopenharmony_ci void __iomem *fme_pr = priv->ioaddr; 1148c2ecf20Sopenharmony_ci u64 pr_ctrl, pr_status; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) { 1178c2ecf20Sopenharmony_ci dev_err(dev, "only supports partial reconfiguration.\n"); 1188c2ecf20Sopenharmony_ci return -EINVAL; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci dev_dbg(dev, "resetting PR before initiated PR\n"); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci pr_ctrl = readq(fme_pr + FME_PR_CTRL); 1248c2ecf20Sopenharmony_ci pr_ctrl |= FME_PR_CTRL_PR_RST; 1258c2ecf20Sopenharmony_ci writeq(pr_ctrl, fme_pr + FME_PR_CTRL); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (readq_poll_timeout(fme_pr + FME_PR_CTRL, pr_ctrl, 1288c2ecf20Sopenharmony_ci pr_ctrl & FME_PR_CTRL_PR_RSTACK, 1, 1298c2ecf20Sopenharmony_ci PR_WAIT_TIMEOUT)) { 1308c2ecf20Sopenharmony_ci dev_err(dev, "PR Reset ACK timeout\n"); 1318c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci pr_ctrl = readq(fme_pr + FME_PR_CTRL); 1358c2ecf20Sopenharmony_ci pr_ctrl &= ~FME_PR_CTRL_PR_RST; 1368c2ecf20Sopenharmony_ci writeq(pr_ctrl, fme_pr + FME_PR_CTRL); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci dev_dbg(dev, 1398c2ecf20Sopenharmony_ci "waiting for PR resource in HW to be initialized and ready\n"); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (readq_poll_timeout(fme_pr + FME_PR_STS, pr_status, 1428c2ecf20Sopenharmony_ci (pr_status & FME_PR_STS_PR_STS) == 1438c2ecf20Sopenharmony_ci FME_PR_STS_PR_STS_IDLE, 1, PR_WAIT_TIMEOUT)) { 1448c2ecf20Sopenharmony_ci dev_err(dev, "PR Status timeout\n"); 1458c2ecf20Sopenharmony_ci priv->pr_error = fme_mgr_pr_error_handle(fme_pr); 1468c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci dev_dbg(dev, "check and clear previous PR error\n"); 1508c2ecf20Sopenharmony_ci priv->pr_error = fme_mgr_pr_error_handle(fme_pr); 1518c2ecf20Sopenharmony_ci if (priv->pr_error) 1528c2ecf20Sopenharmony_ci dev_dbg(dev, "previous PR error detected %llx\n", 1538c2ecf20Sopenharmony_ci (unsigned long long)priv->pr_error); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci dev_dbg(dev, "set PR port ID\n"); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci pr_ctrl = readq(fme_pr + FME_PR_CTRL); 1588c2ecf20Sopenharmony_ci pr_ctrl &= ~FME_PR_CTRL_PR_RGN_ID; 1598c2ecf20Sopenharmony_ci pr_ctrl |= FIELD_PREP(FME_PR_CTRL_PR_RGN_ID, info->region_id); 1608c2ecf20Sopenharmony_ci writeq(pr_ctrl, fme_pr + FME_PR_CTRL); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic int fme_mgr_write(struct fpga_manager *mgr, 1668c2ecf20Sopenharmony_ci const char *buf, size_t count) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct device *dev = &mgr->dev; 1698c2ecf20Sopenharmony_ci struct fme_mgr_priv *priv = mgr->priv; 1708c2ecf20Sopenharmony_ci void __iomem *fme_pr = priv->ioaddr; 1718c2ecf20Sopenharmony_ci u64 pr_ctrl, pr_status, pr_data; 1728c2ecf20Sopenharmony_ci int delay = 0, pr_credit, i = 0; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci dev_dbg(dev, "start request\n"); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci pr_ctrl = readq(fme_pr + FME_PR_CTRL); 1778c2ecf20Sopenharmony_ci pr_ctrl |= FME_PR_CTRL_PR_START; 1788c2ecf20Sopenharmony_ci writeq(pr_ctrl, fme_pr + FME_PR_CTRL); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci dev_dbg(dev, "pushing data from bitstream to HW\n"); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* 1838c2ecf20Sopenharmony_ci * driver can push data to PR hardware using PR_DATA register once HW 1848c2ecf20Sopenharmony_ci * has enough pr_credit (> 1), pr_credit reduces one for every 32bit 1858c2ecf20Sopenharmony_ci * pr data write to PR_DATA register. If pr_credit <= 1, driver needs 1868c2ecf20Sopenharmony_ci * to wait for enough pr_credit from hardware by polling. 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_ci pr_status = readq(fme_pr + FME_PR_STS); 1898c2ecf20Sopenharmony_ci pr_credit = FIELD_GET(FME_PR_STS_PR_CREDIT, pr_status); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci while (count > 0) { 1928c2ecf20Sopenharmony_ci while (pr_credit <= 1) { 1938c2ecf20Sopenharmony_ci if (delay++ > PR_WAIT_TIMEOUT) { 1948c2ecf20Sopenharmony_ci dev_err(dev, "PR_CREDIT timeout\n"); 1958c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci udelay(1); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci pr_status = readq(fme_pr + FME_PR_STS); 2008c2ecf20Sopenharmony_ci pr_credit = FIELD_GET(FME_PR_STS_PR_CREDIT, pr_status); 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (count < 4) { 2048c2ecf20Sopenharmony_ci dev_err(dev, "Invalid PR bitstream size\n"); 2058c2ecf20Sopenharmony_ci return -EINVAL; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci pr_data = 0; 2098c2ecf20Sopenharmony_ci pr_data |= FIELD_PREP(FME_PR_DATA_PR_DATA_RAW, 2108c2ecf20Sopenharmony_ci *(((u32 *)buf) + i)); 2118c2ecf20Sopenharmony_ci writeq(pr_data, fme_pr + FME_PR_DATA); 2128c2ecf20Sopenharmony_ci count -= 4; 2138c2ecf20Sopenharmony_ci pr_credit--; 2148c2ecf20Sopenharmony_ci i++; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return 0; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_cistatic int fme_mgr_write_complete(struct fpga_manager *mgr, 2218c2ecf20Sopenharmony_ci struct fpga_image_info *info) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct device *dev = &mgr->dev; 2248c2ecf20Sopenharmony_ci struct fme_mgr_priv *priv = mgr->priv; 2258c2ecf20Sopenharmony_ci void __iomem *fme_pr = priv->ioaddr; 2268c2ecf20Sopenharmony_ci u64 pr_ctrl; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci pr_ctrl = readq(fme_pr + FME_PR_CTRL); 2298c2ecf20Sopenharmony_ci pr_ctrl |= FME_PR_CTRL_PR_COMPLETE; 2308c2ecf20Sopenharmony_ci writeq(pr_ctrl, fme_pr + FME_PR_CTRL); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci dev_dbg(dev, "green bitstream push complete\n"); 2338c2ecf20Sopenharmony_ci dev_dbg(dev, "waiting for HW to release PR resource\n"); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (readq_poll_timeout(fme_pr + FME_PR_CTRL, pr_ctrl, 2368c2ecf20Sopenharmony_ci !(pr_ctrl & FME_PR_CTRL_PR_START), 1, 2378c2ecf20Sopenharmony_ci PR_WAIT_TIMEOUT)) { 2388c2ecf20Sopenharmony_ci dev_err(dev, "PR Completion ACK timeout.\n"); 2398c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci dev_dbg(dev, "PR operation complete, checking status\n"); 2438c2ecf20Sopenharmony_ci priv->pr_error = fme_mgr_pr_error_handle(fme_pr); 2448c2ecf20Sopenharmony_ci if (priv->pr_error) { 2458c2ecf20Sopenharmony_ci dev_dbg(dev, "PR error detected %llx\n", 2468c2ecf20Sopenharmony_ci (unsigned long long)priv->pr_error); 2478c2ecf20Sopenharmony_ci return -EIO; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci dev_dbg(dev, "PR done successfully\n"); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return 0; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic enum fpga_mgr_states fme_mgr_state(struct fpga_manager *mgr) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci return FPGA_MGR_STATE_UNKNOWN; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic u64 fme_mgr_status(struct fpga_manager *mgr) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct fme_mgr_priv *priv = mgr->priv; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci return pr_error_to_mgr_status(priv->pr_error); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic const struct fpga_manager_ops fme_mgr_ops = { 2688c2ecf20Sopenharmony_ci .write_init = fme_mgr_write_init, 2698c2ecf20Sopenharmony_ci .write = fme_mgr_write, 2708c2ecf20Sopenharmony_ci .write_complete = fme_mgr_write_complete, 2718c2ecf20Sopenharmony_ci .state = fme_mgr_state, 2728c2ecf20Sopenharmony_ci .status = fme_mgr_status, 2738c2ecf20Sopenharmony_ci}; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic void fme_mgr_get_compat_id(void __iomem *fme_pr, 2768c2ecf20Sopenharmony_ci struct fpga_compat_id *id) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci id->id_l = readq(fme_pr + FME_PR_INTFC_ID_L); 2798c2ecf20Sopenharmony_ci id->id_h = readq(fme_pr + FME_PR_INTFC_ID_H); 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic int fme_mgr_probe(struct platform_device *pdev) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct dfl_fme_mgr_pdata *pdata = dev_get_platdata(&pdev->dev); 2858c2ecf20Sopenharmony_ci struct fpga_compat_id *compat_id; 2868c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 2878c2ecf20Sopenharmony_ci struct fme_mgr_priv *priv; 2888c2ecf20Sopenharmony_ci struct fpga_manager *mgr; 2898c2ecf20Sopenharmony_ci struct resource *res; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 2928c2ecf20Sopenharmony_ci if (!priv) 2938c2ecf20Sopenharmony_ci return -ENOMEM; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci if (pdata->ioaddr) 2968c2ecf20Sopenharmony_ci priv->ioaddr = pdata->ioaddr; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (!priv->ioaddr) { 2998c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3008c2ecf20Sopenharmony_ci priv->ioaddr = devm_ioremap_resource(dev, res); 3018c2ecf20Sopenharmony_ci if (IS_ERR(priv->ioaddr)) 3028c2ecf20Sopenharmony_ci return PTR_ERR(priv->ioaddr); 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci compat_id = devm_kzalloc(dev, sizeof(*compat_id), GFP_KERNEL); 3068c2ecf20Sopenharmony_ci if (!compat_id) 3078c2ecf20Sopenharmony_ci return -ENOMEM; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci fme_mgr_get_compat_id(priv->ioaddr, compat_id); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci mgr = devm_fpga_mgr_create(dev, "DFL FME FPGA Manager", 3128c2ecf20Sopenharmony_ci &fme_mgr_ops, priv); 3138c2ecf20Sopenharmony_ci if (!mgr) 3148c2ecf20Sopenharmony_ci return -ENOMEM; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci mgr->compat_id = compat_id; 3178c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, mgr); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci return fpga_mgr_register(mgr); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic int fme_mgr_remove(struct platform_device *pdev) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci struct fpga_manager *mgr = platform_get_drvdata(pdev); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci fpga_mgr_unregister(mgr); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic struct platform_driver fme_mgr_driver = { 3328c2ecf20Sopenharmony_ci .driver = { 3338c2ecf20Sopenharmony_ci .name = DFL_FPGA_FME_MGR, 3348c2ecf20Sopenharmony_ci }, 3358c2ecf20Sopenharmony_ci .probe = fme_mgr_probe, 3368c2ecf20Sopenharmony_ci .remove = fme_mgr_remove, 3378c2ecf20Sopenharmony_ci}; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cimodule_platform_driver(fme_mgr_driver); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("FPGA Manager for DFL FPGA Management Engine"); 3428c2ecf20Sopenharmony_ciMODULE_AUTHOR("Intel Corporation"); 3438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 3448c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:dfl-fme-mgr"); 345