18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * FPGA Bridge Driver for FPGA Management Engine (FME) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2017-2018 Intel Corporation, Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: 88c2ecf20Sopenharmony_ci * Wu Hao <hao.wu@intel.com> 98c2ecf20Sopenharmony_ci * Joseph Grecco <joe.grecco@intel.com> 108c2ecf20Sopenharmony_ci * Enno Luebbers <enno.luebbers@intel.com> 118c2ecf20Sopenharmony_ci * Tim Whisonant <tim.whisonant@intel.com> 128c2ecf20Sopenharmony_ci * Ananda Ravuri <ananda.ravuri@intel.com> 138c2ecf20Sopenharmony_ci * Henry Mitchel <henry.mitchel@intel.com> 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/fpga/fpga-bridge.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "dfl.h" 208c2ecf20Sopenharmony_ci#include "dfl-fme-pr.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistruct fme_br_priv { 238c2ecf20Sopenharmony_ci struct dfl_fme_br_pdata *pdata; 248c2ecf20Sopenharmony_ci struct dfl_fpga_port_ops *port_ops; 258c2ecf20Sopenharmony_ci struct platform_device *port_pdev; 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic int fme_bridge_enable_set(struct fpga_bridge *bridge, bool enable) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci struct fme_br_priv *priv = bridge->priv; 318c2ecf20Sopenharmony_ci struct platform_device *port_pdev; 328c2ecf20Sopenharmony_ci struct dfl_fpga_port_ops *ops; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (!priv->port_pdev) { 358c2ecf20Sopenharmony_ci port_pdev = dfl_fpga_cdev_find_port(priv->pdata->cdev, 368c2ecf20Sopenharmony_ci &priv->pdata->port_id, 378c2ecf20Sopenharmony_ci dfl_fpga_check_port_id); 388c2ecf20Sopenharmony_ci if (!port_pdev) 398c2ecf20Sopenharmony_ci return -ENODEV; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci priv->port_pdev = port_pdev; 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci if (priv->port_pdev && !priv->port_ops) { 458c2ecf20Sopenharmony_ci ops = dfl_fpga_port_ops_get(priv->port_pdev); 468c2ecf20Sopenharmony_ci if (!ops || !ops->enable_set) 478c2ecf20Sopenharmony_ci return -ENOENT; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci priv->port_ops = ops; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return priv->port_ops->enable_set(priv->port_pdev, enable); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic const struct fpga_bridge_ops fme_bridge_ops = { 568c2ecf20Sopenharmony_ci .enable_set = fme_bridge_enable_set, 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int fme_br_probe(struct platform_device *pdev) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 628c2ecf20Sopenharmony_ci struct fme_br_priv *priv; 638c2ecf20Sopenharmony_ci struct fpga_bridge *br; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 668c2ecf20Sopenharmony_ci if (!priv) 678c2ecf20Sopenharmony_ci return -ENOMEM; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci priv->pdata = dev_get_platdata(dev); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci br = devm_fpga_bridge_create(dev, "DFL FPGA FME Bridge", 728c2ecf20Sopenharmony_ci &fme_bridge_ops, priv); 738c2ecf20Sopenharmony_ci if (!br) 748c2ecf20Sopenharmony_ci return -ENOMEM; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, br); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return fpga_bridge_register(br); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic int fme_br_remove(struct platform_device *pdev) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct fpga_bridge *br = platform_get_drvdata(pdev); 848c2ecf20Sopenharmony_ci struct fme_br_priv *priv = br->priv; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci fpga_bridge_unregister(br); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (priv->port_pdev) 898c2ecf20Sopenharmony_ci put_device(&priv->port_pdev->dev); 908c2ecf20Sopenharmony_ci if (priv->port_ops) 918c2ecf20Sopenharmony_ci dfl_fpga_port_ops_put(priv->port_ops); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic struct platform_driver fme_br_driver = { 978c2ecf20Sopenharmony_ci .driver = { 988c2ecf20Sopenharmony_ci .name = DFL_FPGA_FME_BRIDGE, 998c2ecf20Sopenharmony_ci }, 1008c2ecf20Sopenharmony_ci .probe = fme_br_probe, 1018c2ecf20Sopenharmony_ci .remove = fme_br_remove, 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cimodule_platform_driver(fme_br_driver); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("FPGA Bridge for DFL FPGA Management Engine"); 1078c2ecf20Sopenharmony_ciMODULE_AUTHOR("Intel Corporation"); 1088c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1098c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:dfl-fme-bridge"); 110