drivers: Defer probe if firmware is not ready

Driver needs ZynqMP firmware interface to call EEMI
APIs. In case firmware is not ready, dependent drivers
should wait until the firmware is ready.

Signed-off-by: Rajan Vaja <rajan.vaja@xilinx.com>
Signed-off-by: Jolly Shah <jollys@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
This commit is contained in:
Rajan Vaja 2019-03-04 15:18:08 -08:00 коммит произвёл Michal Simek
Родитель b9472f7d82
Коммит 3d03137864
10 изменённых файлов: 47 добавлений и 28 удалений

Просмотреть файл

@ -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);

Просмотреть файл

@ -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",
@ -649,7 +651,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 +700,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,

Просмотреть файл

@ -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;

Просмотреть файл

@ -293,7 +293,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