mirror of
https://github.com/FEX-Emu/linux.git
synced 2025-01-10 19:43:29 +00:00
arm64: zynqmp: SoC changes for v5.2
- Add support for ZynqMP fpga manager - Defer some probes which depends on firmware driver to be ready - Debugfs fix -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iEYEABECAAYFAly0QlMACgkQykllyylKDCFYngCfZOByHuyiliPv+PSa6KCtCics ccgAn3YC1zEfvh8pmj2t0cvO/EpV2pXC =HBAL -----END PGP SIGNATURE----- Merge tag 'zynqmp-soc-for-v5.2' of https://github.com/Xilinx/linux-xlnx into arm/drivers arm64: zynqmp: SoC changes for v5.2 - Add support for ZynqMP fpga manager - Defer some probes which depends on firmware driver to be ready - Debugfs fix * tag 'zynqmp-soc-for-v5.2' of https://github.com/Xilinx/linux-xlnx: fpga manager: Adding FPGA Manager support for Xilinx zynqmp dt-bindings: fpga: Add bindings for ZynqMP fpga driver firmware: xilinx: Add fpga API's drivers: Defer probe if firmware is not ready firmware: xilinx: fix debugfs write handler Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
commit
b94d3ff97e
@ -0,0 +1,25 @@
|
||||
Devicetree bindings for Zynq Ultrascale MPSoC FPGA Manager.
|
||||
The ZynqMP SoC uses the PCAP (Processor configuration Port) to configure the
|
||||
Programmable Logic (PL). The configuration uses the firmware interface.
|
||||
|
||||
Required properties:
|
||||
- compatible: should contain "xlnx,zynqmp-pcap-fpga"
|
||||
|
||||
Example for full FPGA configuration:
|
||||
|
||||
fpga-region0 {
|
||||
compatible = "fpga-region";
|
||||
fpga-mgr = <&zynqmp_pcap>;
|
||||
#address-cells = <0x1>;
|
||||
#size-cells = <0x1>;
|
||||
};
|
||||
|
||||
firmware {
|
||||
zynqmp_firmware: zynqmp-firmware {
|
||||
compatible = "xlnx,zynqmp-firmware";
|
||||
method = "smc";
|
||||
zynqmp_pcap: pcap {
|
||||
compatible = "xlnx,zynqmp-pcap-fpga";
|
||||
};
|
||||
};
|
||||
};
|
@ -41,8 +41,8 @@ Example of EEMI ops usage:
|
||||
int ret;
|
||||
|
||||
eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
if (!eemi_ops)
|
||||
return -ENXIO;
|
||||
if (IS_ERR(eemi_ops))
|
||||
return PTR_ERR(eemi_ops);
|
||||
|
||||
ret = eemi_ops->query_data(qdata, ret_payload);
|
||||
|
||||
|
@ -695,8 +695,8 @@ static int zynqmp_clock_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
if (!eemi_ops)
|
||||
return -ENXIO;
|
||||
if (IS_ERR(eemi_ops))
|
||||
return PTR_ERR(eemi_ops);
|
||||
|
||||
ret = zynqmp_clk_setup(dev->of_node);
|
||||
|
||||
|
@ -90,9 +90,6 @@ static int process_api_request(u32 pm_id, u64 *pm_api_arg, u32 *pm_api_ret)
|
||||
int ret;
|
||||
struct zynqmp_pm_query_data qdata = {0};
|
||||
|
||||
if (!eemi_ops)
|
||||
return -ENXIO;
|
||||
|
||||
switch (pm_id) {
|
||||
case PM_GET_API_VERSION:
|
||||
ret = eemi_ops->get_api_version(&pm_api_version);
|
||||
@ -163,21 +160,14 @@ static ssize_t zynqmp_pm_debugfs_api_write(struct file *file,
|
||||
|
||||
strcpy(debugfs_buf, "");
|
||||
|
||||
if (*off != 0 || len == 0)
|
||||
if (*off != 0 || len <= 1 || len > PAGE_SIZE - 1)
|
||||
return -EINVAL;
|
||||
|
||||
kern_buff = kzalloc(len, GFP_KERNEL);
|
||||
if (!kern_buff)
|
||||
return -ENOMEM;
|
||||
|
||||
kern_buff = memdup_user_nul(ptr, len);
|
||||
if (IS_ERR(kern_buff))
|
||||
return PTR_ERR(kern_buff);
|
||||
tmp_buff = kern_buff;
|
||||
|
||||
ret = strncpy_from_user(kern_buff, ptr, len);
|
||||
if (ret < 0) {
|
||||
ret = -EFAULT;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Read the API name from a user request */
|
||||
pm_api_req = strsep(&kern_buff, " ");
|
||||
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include <linux/firmware/xlnx-zynqmp.h>
|
||||
#include "zynqmp-debug.h"
|
||||
|
||||
static const struct zynqmp_eemi_ops *eemi_ops_tbl;
|
||||
|
||||
static const struct mfd_cell firmware_devs[] = {
|
||||
{
|
||||
.name = "zynqmp_power_controller",
|
||||
@ -537,6 +539,49 @@ static int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset,
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_fpga_load - Perform the fpga load
|
||||
* @address: Address to write to
|
||||
* @size: pl bitstream size
|
||||
* @flags: Bitstream type
|
||||
* -XILINX_ZYNQMP_PM_FPGA_FULL: FPGA full reconfiguration
|
||||
* -XILINX_ZYNQMP_PM_FPGA_PARTIAL: FPGA partial reconfiguration
|
||||
*
|
||||
* This function provides access to pmufw. To transfer
|
||||
* the required bitstream into PL.
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
static int zynqmp_pm_fpga_load(const u64 address, const u32 size,
|
||||
const u32 flags)
|
||||
{
|
||||
return zynqmp_pm_invoke_fn(PM_FPGA_LOAD, lower_32_bits(address),
|
||||
upper_32_bits(address), size, flags, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_fpga_get_status - Read value from PCAP status register
|
||||
* @value: Value to read
|
||||
*
|
||||
* This function provides access to the pmufw to get the PCAP
|
||||
* status
|
||||
*
|
||||
* Return: Returns status, either success or error+reason
|
||||
*/
|
||||
static int zynqmp_pm_fpga_get_status(u32 *value)
|
||||
{
|
||||
u32 ret_payload[PAYLOAD_ARG_CNT];
|
||||
int ret;
|
||||
|
||||
if (!value)
|
||||
return -EINVAL;
|
||||
|
||||
ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, 0, 0, 0, 0, ret_payload);
|
||||
*value = ret_payload[1];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_pm_init_finalize() - PM call to inform firmware that the caller
|
||||
* master has initialized its own power management
|
||||
@ -640,6 +685,8 @@ static const struct zynqmp_eemi_ops eemi_ops = {
|
||||
.request_node = zynqmp_pm_request_node,
|
||||
.release_node = zynqmp_pm_release_node,
|
||||
.set_requirement = zynqmp_pm_set_requirement,
|
||||
.fpga_load = zynqmp_pm_fpga_load,
|
||||
.fpga_get_status = zynqmp_pm_fpga_get_status,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -649,7 +696,11 @@ static const struct zynqmp_eemi_ops eemi_ops = {
|
||||
*/
|
||||
const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
|
||||
{
|
||||
return &eemi_ops;
|
||||
if (eemi_ops_tbl)
|
||||
return eemi_ops_tbl;
|
||||
else
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops);
|
||||
|
||||
@ -694,6 +745,9 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
|
||||
pr_info("%s Trustzone version v%d.%d\n", __func__,
|
||||
pm_tz_version >> 16, pm_tz_version & 0xFFFF);
|
||||
|
||||
/* Assign eemi_ops_table */
|
||||
eemi_ops_tbl = &eemi_ops;
|
||||
|
||||
zynqmp_pm_api_debugfs_init();
|
||||
|
||||
ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, firmware_devs,
|
||||
|
@ -204,4 +204,13 @@ config FPGA_DFL_PCI
|
||||
|
||||
To compile this as a module, choose M here.
|
||||
|
||||
config FPGA_MGR_ZYNQMP_FPGA
|
||||
tristate "Xilinx ZynqMP FPGA"
|
||||
depends on ARCH_ZYNQMP || COMPILE_TEST
|
||||
help
|
||||
FPGA manager driver support for Xilinx ZynqMP FPGAs.
|
||||
This driver uses the processor configuration port(PCAP)
|
||||
to configure the programmable logic(PL) through PS
|
||||
on ZynqMP SoC.
|
||||
|
||||
endif # FPGA
|
||||
|
@ -17,6 +17,7 @@ obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC) += stratix10-soc.o
|
||||
obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o
|
||||
obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o
|
||||
obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o
|
||||
obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA) += zynqmp-fpga.o
|
||||
obj-$(CONFIG_ALTERA_PR_IP_CORE) += altera-pr-ip-core.o
|
||||
obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o
|
||||
|
||||
|
159
drivers/fpga/zynqmp-fpga.c
Normal file
159
drivers/fpga/zynqmp-fpga.c
Normal file
@ -0,0 +1,159 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2019 Xilinx, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/fpga/fpga-mgr.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/firmware/xlnx-zynqmp.h>
|
||||
|
||||
/* Constant Definitions */
|
||||
#define IXR_FPGA_DONE_MASK BIT(3)
|
||||
|
||||
/**
|
||||
* struct zynqmp_fpga_priv - Private data structure
|
||||
* @dev: Device data structure
|
||||
* @flags: flags which is used to identify the bitfile type
|
||||
*/
|
||||
struct zynqmp_fpga_priv {
|
||||
struct device *dev;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
static int zynqmp_fpga_ops_write_init(struct fpga_manager *mgr,
|
||||
struct fpga_image_info *info,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct zynqmp_fpga_priv *priv;
|
||||
|
||||
priv = mgr->priv;
|
||||
priv->flags = info->flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
struct zynqmp_fpga_priv *priv;
|
||||
dma_addr_t dma_addr;
|
||||
u32 eemi_flags = 0;
|
||||
char *kbuf;
|
||||
int ret;
|
||||
|
||||
if (!eemi_ops || !eemi_ops->fpga_load)
|
||||
return -ENXIO;
|
||||
|
||||
priv = mgr->priv;
|
||||
|
||||
kbuf = dma_alloc_coherent(priv->dev, size, &dma_addr, GFP_KERNEL);
|
||||
if (!kbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(kbuf, buf, size);
|
||||
|
||||
wmb(); /* ensure all writes are done before initiate FW call */
|
||||
|
||||
if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG)
|
||||
eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL;
|
||||
|
||||
ret = eemi_ops->fpga_load(dma_addr, size, eemi_flags);
|
||||
|
||||
dma_free_coherent(priv->dev, size, kbuf, dma_addr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int zynqmp_fpga_ops_write_complete(struct fpga_manager *mgr,
|
||||
struct fpga_image_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum fpga_mgr_states zynqmp_fpga_ops_state(struct fpga_manager *mgr)
|
||||
{
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
u32 status;
|
||||
|
||||
if (!eemi_ops || !eemi_ops->fpga_get_status)
|
||||
return FPGA_MGR_STATE_UNKNOWN;
|
||||
|
||||
eemi_ops->fpga_get_status(&status);
|
||||
if (status & IXR_FPGA_DONE_MASK)
|
||||
return FPGA_MGR_STATE_OPERATING;
|
||||
|
||||
return FPGA_MGR_STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
static const struct fpga_manager_ops zynqmp_fpga_ops = {
|
||||
.state = zynqmp_fpga_ops_state,
|
||||
.write_init = zynqmp_fpga_ops_write_init,
|
||||
.write = zynqmp_fpga_ops_write,
|
||||
.write_complete = zynqmp_fpga_ops_write_complete,
|
||||
};
|
||||
|
||||
static int zynqmp_fpga_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct zynqmp_fpga_priv *priv;
|
||||
struct fpga_manager *mgr;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->dev = dev;
|
||||
|
||||
mgr = devm_fpga_mgr_create(dev, "Xilinx ZynqMP FPGA Manager",
|
||||
&zynqmp_fpga_ops, priv);
|
||||
if (!mgr)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, mgr);
|
||||
|
||||
ret = fpga_mgr_register(mgr);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to register FPGA manager");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zynqmp_fpga_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct fpga_manager *mgr = platform_get_drvdata(pdev);
|
||||
|
||||
fpga_mgr_unregister(mgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id zynqmp_fpga_of_match[] = {
|
||||
{ .compatible = "xlnx,zynqmp-pcap-fpga", },
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, zynqmp_fpga_of_match);
|
||||
|
||||
static struct platform_driver zynqmp_fpga_driver = {
|
||||
.probe = zynqmp_fpga_probe,
|
||||
.remove = zynqmp_fpga_remove,
|
||||
.driver = {
|
||||
.name = "zynqmp_fpga_manager",
|
||||
.of_match_table = of_match_ptr(zynqmp_fpga_of_match),
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver(zynqmp_fpga_driver);
|
||||
|
||||
MODULE_AUTHOR("Nava kishore Manne <navam@xilinx.com>");
|
||||
MODULE_DESCRIPTION("Xilinx ZynqMp FPGA Manager");
|
||||
MODULE_LICENSE("GPL");
|
@ -16,6 +16,8 @@ struct zynqmp_nvmem_data {
|
||||
struct nvmem_device *nvmem;
|
||||
};
|
||||
|
||||
static const struct zynqmp_eemi_ops *eemi_ops;
|
||||
|
||||
static int zynqmp_nvmem_read(void *context, unsigned int offset,
|
||||
void *val, size_t bytes)
|
||||
{
|
||||
@ -23,9 +25,7 @@ static int zynqmp_nvmem_read(void *context, unsigned int offset,
|
||||
int idcode, version;
|
||||
struct zynqmp_nvmem_data *priv = context;
|
||||
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->get_chipid)
|
||||
if (!eemi_ops->get_chipid)
|
||||
return -ENXIO;
|
||||
|
||||
ret = eemi_ops->get_chipid(&idcode, &version);
|
||||
@ -61,6 +61,10 @@ static int zynqmp_nvmem_probe(struct platform_device *pdev)
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
if (IS_ERR(eemi_ops))
|
||||
return PTR_ERR(eemi_ops);
|
||||
|
||||
priv->dev = dev;
|
||||
econfig.dev = dev;
|
||||
econfig.reg_read = zynqmp_nvmem_read;
|
||||
|
@ -79,11 +79,11 @@ static int zynqmp_reset_probe(struct platform_device *pdev)
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
priv->eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
if (!priv->eemi_ops)
|
||||
return -ENXIO;
|
||||
if (IS_ERR(priv->eemi_ops))
|
||||
return PTR_ERR(priv->eemi_ops);
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
priv->rcdev.ops = &zynqmp_reset_ops;
|
||||
priv->rcdev.owner = THIS_MODULE;
|
||||
|
@ -23,6 +23,8 @@
|
||||
/* Flag stating if PM nodes mapped to the PM domain has been requested */
|
||||
#define ZYNQMP_PM_DOMAIN_REQUESTED BIT(0)
|
||||
|
||||
static const struct zynqmp_eemi_ops *eemi_ops;
|
||||
|
||||
/**
|
||||
* struct zynqmp_pm_domain - Wrapper around struct generic_pm_domain
|
||||
* @gpd: Generic power domain
|
||||
@ -71,9 +73,8 @@ static int zynqmp_gpd_power_on(struct generic_pm_domain *domain)
|
||||
{
|
||||
int ret;
|
||||
struct zynqmp_pm_domain *pd;
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->set_requirement)
|
||||
if (!eemi_ops->set_requirement)
|
||||
return -ENXIO;
|
||||
|
||||
pd = container_of(domain, struct zynqmp_pm_domain, gpd);
|
||||
@ -107,9 +108,8 @@ static int zynqmp_gpd_power_off(struct generic_pm_domain *domain)
|
||||
struct zynqmp_pm_domain *pd;
|
||||
u32 capabilities = 0;
|
||||
bool may_wakeup;
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->set_requirement)
|
||||
if (!eemi_ops->set_requirement)
|
||||
return -ENXIO;
|
||||
|
||||
pd = container_of(domain, struct zynqmp_pm_domain, gpd);
|
||||
@ -160,9 +160,8 @@ static int zynqmp_gpd_attach_dev(struct generic_pm_domain *domain,
|
||||
{
|
||||
int ret;
|
||||
struct zynqmp_pm_domain *pd;
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->request_node)
|
||||
if (!eemi_ops->request_node)
|
||||
return -ENXIO;
|
||||
|
||||
pd = container_of(domain, struct zynqmp_pm_domain, gpd);
|
||||
@ -197,9 +196,8 @@ static void zynqmp_gpd_detach_dev(struct generic_pm_domain *domain,
|
||||
{
|
||||
int ret;
|
||||
struct zynqmp_pm_domain *pd;
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->release_node)
|
||||
if (!eemi_ops->release_node)
|
||||
return;
|
||||
|
||||
pd = container_of(domain, struct zynqmp_pm_domain, gpd);
|
||||
@ -266,6 +264,10 @@ static int zynqmp_gpd_probe(struct platform_device *pdev)
|
||||
struct zynqmp_pm_domain *pd;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
if (IS_ERR(eemi_ops))
|
||||
return PTR_ERR(eemi_ops);
|
||||
|
||||
pd = devm_kcalloc(dev, ZYNQMP_NUM_DOMAINS, sizeof(*pd), GFP_KERNEL);
|
||||
if (!pd)
|
||||
return -ENOMEM;
|
||||
|
@ -31,6 +31,7 @@ static const char *const suspend_modes[] = {
|
||||
};
|
||||
|
||||
static enum pm_suspend_mode suspend_mode = PM_SUSPEND_MODE_STD;
|
||||
static const struct zynqmp_eemi_ops *eemi_ops;
|
||||
|
||||
enum pm_api_cb_id {
|
||||
PM_INIT_SUSPEND_CB = 30,
|
||||
@ -92,9 +93,8 @@ static ssize_t suspend_mode_store(struct device *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int md, ret = -EINVAL;
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
|
||||
if (!eemi_ops || !eemi_ops->set_suspend_mode)
|
||||
if (!eemi_ops->set_suspend_mode)
|
||||
return ret;
|
||||
|
||||
for (md = PM_SUSPEND_MODE_FIRST; md < ARRAY_SIZE(suspend_modes); md++)
|
||||
@ -120,9 +120,11 @@ static int zynqmp_pm_probe(struct platform_device *pdev)
|
||||
int ret, irq;
|
||||
u32 pm_api_version;
|
||||
|
||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
if (IS_ERR(eemi_ops))
|
||||
return PTR_ERR(eemi_ops);
|
||||
|
||||
if (!eemi_ops || !eemi_ops->get_api_version || !eemi_ops->init_finalize)
|
||||
if (!eemi_ops->get_api_version || !eemi_ops->init_finalize)
|
||||
return -ENXIO;
|
||||
|
||||
eemi_ops->init_finalize();
|
||||
|
@ -138,6 +138,7 @@
|
||||
|
||||
#define SPI_AUTOSUSPEND_TIMEOUT 3000
|
||||
enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA};
|
||||
static const struct zynqmp_eemi_ops *eemi_ops;
|
||||
|
||||
/**
|
||||
* struct zynqmp_qspi - Defines qspi driver instance
|
||||
@ -1021,6 +1022,10 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||
if (IS_ERR(eemi_ops))
|
||||
return PTR_ERR(eemi_ops);
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(*xqspi));
|
||||
if (!master)
|
||||
return -ENOMEM;
|
||||
|
@ -48,6 +48,14 @@
|
||||
#define ZYNQMP_PM_CAPABILITY_WAKEUP 0x4U
|
||||
#define ZYNQMP_PM_CAPABILITY_POWER 0x8U
|
||||
|
||||
/*
|
||||
* Firmware FPGA Manager flags
|
||||
* XILINX_ZYNQMP_PM_FPGA_FULL: FPGA full reconfiguration
|
||||
* XILINX_ZYNQMP_PM_FPGA_PARTIAL: FPGA partial reconfiguration
|
||||
*/
|
||||
#define XILINX_ZYNQMP_PM_FPGA_FULL 0x0U
|
||||
#define XILINX_ZYNQMP_PM_FPGA_PARTIAL BIT(0)
|
||||
|
||||
enum pm_api_id {
|
||||
PM_GET_API_VERSION = 1,
|
||||
PM_REQUEST_NODE = 13,
|
||||
@ -56,6 +64,8 @@ enum pm_api_id {
|
||||
PM_RESET_ASSERT = 17,
|
||||
PM_RESET_GET_STATUS,
|
||||
PM_PM_INIT_FINALIZE = 21,
|
||||
PM_FPGA_LOAD,
|
||||
PM_FPGA_GET_STATUS,
|
||||
PM_GET_CHIPID = 24,
|
||||
PM_IOCTL = 34,
|
||||
PM_QUERY_DATA,
|
||||
@ -258,6 +268,8 @@ struct zynqmp_pm_query_data {
|
||||
struct zynqmp_eemi_ops {
|
||||
int (*get_api_version)(u32 *version);
|
||||
int (*get_chipid)(u32 *idcode, u32 *version);
|
||||
int (*fpga_load)(const u64 address, const u32 size, const u32 flags);
|
||||
int (*fpga_get_status)(u32 *value);
|
||||
int (*query_data)(struct zynqmp_pm_query_data qdata, u32 *out);
|
||||
int (*clock_enable)(u32 clock_id);
|
||||
int (*clock_disable)(u32 clock_id);
|
||||
@ -293,7 +305,7 @@ const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void);
|
||||
#else
|
||||
static inline struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
|
||||
{
|
||||
return NULL;
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user