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:
Коммит
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;
|
int ret;
|
||||||
|
|
||||||
eemi_ops = zynqmp_pm_get_eemi_ops();
|
eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||||
if (!eemi_ops)
|
if (IS_ERR(eemi_ops))
|
||||||
return -ENXIO;
|
return PTR_ERR(eemi_ops);
|
||||||
|
|
||||||
ret = eemi_ops->query_data(qdata, ret_payload);
|
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;
|
struct device *dev = &pdev->dev;
|
||||||
|
|
||||||
eemi_ops = zynqmp_pm_get_eemi_ops();
|
eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||||
if (!eemi_ops)
|
if (IS_ERR(eemi_ops))
|
||||||
return -ENXIO;
|
return PTR_ERR(eemi_ops);
|
||||||
|
|
||||||
ret = zynqmp_clk_setup(dev->of_node);
|
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;
|
int ret;
|
||||||
struct zynqmp_pm_query_data qdata = {0};
|
struct zynqmp_pm_query_data qdata = {0};
|
||||||
|
|
||||||
if (!eemi_ops)
|
|
||||||
return -ENXIO;
|
|
||||||
|
|
||||||
switch (pm_id) {
|
switch (pm_id) {
|
||||||
case PM_GET_API_VERSION:
|
case PM_GET_API_VERSION:
|
||||||
ret = eemi_ops->get_api_version(&pm_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, "");
|
strcpy(debugfs_buf, "");
|
||||||
|
|
||||||
if (*off != 0 || len == 0)
|
if (*off != 0 || len <= 1 || len > PAGE_SIZE - 1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
kern_buff = kzalloc(len, GFP_KERNEL);
|
kern_buff = memdup_user_nul(ptr, len);
|
||||||
if (!kern_buff)
|
if (IS_ERR(kern_buff))
|
||||||
return -ENOMEM;
|
return PTR_ERR(kern_buff);
|
||||||
|
|
||||||
tmp_buff = 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 */
|
/* Read the API name from a user request */
|
||||||
pm_api_req = strsep(&kern_buff, " ");
|
pm_api_req = strsep(&kern_buff, " ");
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
#include <linux/firmware/xlnx-zynqmp.h>
|
#include <linux/firmware/xlnx-zynqmp.h>
|
||||||
#include "zynqmp-debug.h"
|
#include "zynqmp-debug.h"
|
||||||
|
|
||||||
|
static const struct zynqmp_eemi_ops *eemi_ops_tbl;
|
||||||
|
|
||||||
static const struct mfd_cell firmware_devs[] = {
|
static const struct mfd_cell firmware_devs[] = {
|
||||||
{
|
{
|
||||||
.name = "zynqmp_power_controller",
|
.name = "zynqmp_power_controller",
|
||||||
|
@ -537,6 +539,49 @@ static int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset,
|
||||||
return ret;
|
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
|
* zynqmp_pm_init_finalize() - PM call to inform firmware that the caller
|
||||||
* master has initialized its own power management
|
* 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,
|
.request_node = zynqmp_pm_request_node,
|
||||||
.release_node = zynqmp_pm_release_node,
|
.release_node = zynqmp_pm_release_node,
|
||||||
.set_requirement = zynqmp_pm_set_requirement,
|
.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)
|
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);
|
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__,
|
pr_info("%s Trustzone version v%d.%d\n", __func__,
|
||||||
pm_tz_version >> 16, pm_tz_version & 0xFFFF);
|
pm_tz_version >> 16, pm_tz_version & 0xFFFF);
|
||||||
|
|
||||||
|
/* Assign eemi_ops_table */
|
||||||
|
eemi_ops_tbl = &eemi_ops;
|
||||||
|
|
||||||
zynqmp_pm_api_debugfs_init();
|
zynqmp_pm_api_debugfs_init();
|
||||||
|
|
||||||
ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, firmware_devs,
|
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.
|
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
|
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_TS73XX) += ts73xx-fpga.o
|
||||||
obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o
|
obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o
|
||||||
obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.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) += altera-pr-ip-core.o
|
||||||
obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o
|
obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o
|
||||||
|
|
||||||
|
|
|
@ -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;
|
struct nvmem_device *nvmem;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct zynqmp_eemi_ops *eemi_ops;
|
||||||
|
|
||||||
static int zynqmp_nvmem_read(void *context, unsigned int offset,
|
static int zynqmp_nvmem_read(void *context, unsigned int offset,
|
||||||
void *val, size_t bytes)
|
void *val, size_t bytes)
|
||||||
{
|
{
|
||||||
|
@ -23,9 +25,7 @@ static int zynqmp_nvmem_read(void *context, unsigned int offset,
|
||||||
int idcode, version;
|
int idcode, version;
|
||||||
struct zynqmp_nvmem_data *priv = context;
|
struct zynqmp_nvmem_data *priv = context;
|
||||||
|
|
||||||
const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
|
if (!eemi_ops->get_chipid)
|
||||||
|
|
||||||
if (!eemi_ops || !eemi_ops->get_chipid)
|
|
||||||
return -ENXIO;
|
return -ENXIO;
|
||||||
|
|
||||||
ret = eemi_ops->get_chipid(&idcode, &version);
|
ret = eemi_ops->get_chipid(&idcode, &version);
|
||||||
|
@ -61,6 +61,10 @@ static int zynqmp_nvmem_probe(struct platform_device *pdev)
|
||||||
if (!priv)
|
if (!priv)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||||
|
if (IS_ERR(eemi_ops))
|
||||||
|
return PTR_ERR(eemi_ops);
|
||||||
|
|
||||||
priv->dev = dev;
|
priv->dev = dev;
|
||||||
econfig.dev = dev;
|
econfig.dev = dev;
|
||||||
econfig.reg_read = zynqmp_nvmem_read;
|
econfig.reg_read = zynqmp_nvmem_read;
|
||||||
|
|
|
@ -79,11 +79,11 @@ static int zynqmp_reset_probe(struct platform_device *pdev)
|
||||||
if (!priv)
|
if (!priv)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
platform_set_drvdata(pdev, priv);
|
|
||||||
|
|
||||||
priv->eemi_ops = zynqmp_pm_get_eemi_ops();
|
priv->eemi_ops = zynqmp_pm_get_eemi_ops();
|
||||||
if (!priv->eemi_ops)
|
if (IS_ERR(priv->eemi_ops))
|
||||||
return -ENXIO;
|
return PTR_ERR(priv->eemi_ops);
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, priv);
|
||||||
|
|
||||||
priv->rcdev.ops = &zynqmp_reset_ops;
|
priv->rcdev.ops = &zynqmp_reset_ops;
|
||||||
priv->rcdev.owner = THIS_MODULE;
|
priv->rcdev.owner = THIS_MODULE;
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
/* Flag stating if PM nodes mapped to the PM domain has been requested */
|
/* Flag stating if PM nodes mapped to the PM domain has been requested */
|
||||||
#define ZYNQMP_PM_DOMAIN_REQUESTED BIT(0)
|
#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
|
* struct zynqmp_pm_domain - Wrapper around struct generic_pm_domain
|
||||||
* @gpd: Generic power domain
|
* @gpd: Generic power domain
|
||||||
|
@ -71,9 +73,8 @@ static int zynqmp_gpd_power_on(struct generic_pm_domain *domain)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct zynqmp_pm_domain *pd;
|
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;
|
return -ENXIO;
|
||||||
|
|
||||||
pd = container_of(domain, struct zynqmp_pm_domain, gpd);
|
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;
|
struct zynqmp_pm_domain *pd;
|
||||||
u32 capabilities = 0;
|
u32 capabilities = 0;
|
||||||
bool may_wakeup;
|
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;
|
return -ENXIO;
|
||||||
|
|
||||||
pd = container_of(domain, struct zynqmp_pm_domain, gpd);
|
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;
|
int ret;
|
||||||
struct zynqmp_pm_domain *pd;
|
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;
|
return -ENXIO;
|
||||||
|
|
||||||
pd = container_of(domain, struct zynqmp_pm_domain, gpd);
|
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;
|
int ret;
|
||||||
struct zynqmp_pm_domain *pd;
|
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;
|
return;
|
||||||
|
|
||||||
pd = container_of(domain, struct zynqmp_pm_domain, gpd);
|
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 zynqmp_pm_domain *pd;
|
||||||
struct device *dev = &pdev->dev;
|
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);
|
pd = devm_kcalloc(dev, ZYNQMP_NUM_DOMAINS, sizeof(*pd), GFP_KERNEL);
|
||||||
if (!pd)
|
if (!pd)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
|
@ -31,6 +31,7 @@ static const char *const suspend_modes[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum pm_suspend_mode suspend_mode = PM_SUSPEND_MODE_STD;
|
static enum pm_suspend_mode suspend_mode = PM_SUSPEND_MODE_STD;
|
||||||
|
static const struct zynqmp_eemi_ops *eemi_ops;
|
||||||
|
|
||||||
enum pm_api_cb_id {
|
enum pm_api_cb_id {
|
||||||
PM_INIT_SUSPEND_CB = 30,
|
PM_INIT_SUSPEND_CB = 30,
|
||||||
|
@ -92,9 +93,8 @@ static ssize_t suspend_mode_store(struct device *dev,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
int md, ret = -EINVAL;
|
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;
|
return ret;
|
||||||
|
|
||||||
for (md = PM_SUSPEND_MODE_FIRST; md < ARRAY_SIZE(suspend_modes); md++)
|
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;
|
int ret, irq;
|
||||||
u32 pm_api_version;
|
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;
|
return -ENXIO;
|
||||||
|
|
||||||
eemi_ops->init_finalize();
|
eemi_ops->init_finalize();
|
||||||
|
|
|
@ -138,6 +138,7 @@
|
||||||
|
|
||||||
#define SPI_AUTOSUSPEND_TIMEOUT 3000
|
#define SPI_AUTOSUSPEND_TIMEOUT 3000
|
||||||
enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA};
|
enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA};
|
||||||
|
static const struct zynqmp_eemi_ops *eemi_ops;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct zynqmp_qspi - Defines qspi driver instance
|
* struct zynqmp_qspi - Defines qspi driver instance
|
||||||
|
@ -1021,6 +1022,10 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
struct device *dev = &pdev->dev;
|
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));
|
master = spi_alloc_master(&pdev->dev, sizeof(*xqspi));
|
||||||
if (!master)
|
if (!master)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
|
@ -48,6 +48,14 @@
|
||||||
#define ZYNQMP_PM_CAPABILITY_WAKEUP 0x4U
|
#define ZYNQMP_PM_CAPABILITY_WAKEUP 0x4U
|
||||||
#define ZYNQMP_PM_CAPABILITY_POWER 0x8U
|
#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 {
|
enum pm_api_id {
|
||||||
PM_GET_API_VERSION = 1,
|
PM_GET_API_VERSION = 1,
|
||||||
PM_REQUEST_NODE = 13,
|
PM_REQUEST_NODE = 13,
|
||||||
|
@ -56,6 +64,8 @@ enum pm_api_id {
|
||||||
PM_RESET_ASSERT = 17,
|
PM_RESET_ASSERT = 17,
|
||||||
PM_RESET_GET_STATUS,
|
PM_RESET_GET_STATUS,
|
||||||
PM_PM_INIT_FINALIZE = 21,
|
PM_PM_INIT_FINALIZE = 21,
|
||||||
|
PM_FPGA_LOAD,
|
||||||
|
PM_FPGA_GET_STATUS,
|
||||||
PM_GET_CHIPID = 24,
|
PM_GET_CHIPID = 24,
|
||||||
PM_IOCTL = 34,
|
PM_IOCTL = 34,
|
||||||
PM_QUERY_DATA,
|
PM_QUERY_DATA,
|
||||||
|
@ -258,6 +268,8 @@ struct zynqmp_pm_query_data {
|
||||||
struct zynqmp_eemi_ops {
|
struct zynqmp_eemi_ops {
|
||||||
int (*get_api_version)(u32 *version);
|
int (*get_api_version)(u32 *version);
|
||||||
int (*get_chipid)(u32 *idcode, 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 (*query_data)(struct zynqmp_pm_query_data qdata, u32 *out);
|
||||||
int (*clock_enable)(u32 clock_id);
|
int (*clock_enable)(u32 clock_id);
|
||||||
int (*clock_disable)(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
|
#else
|
||||||
static inline struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
|
static inline struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
|
||||||
{
|
{
|
||||||
return NULL;
|
return ERR_PTR(-ENODEV);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче