RE: [PATCH v3 2/4] soc: qcom: Introduce APCS IPC driver
From: Loic PALLARDY
Date: Wed May 03 2017 - 05:29:30 EST
> -----Original Message-----
> From: linux-remoteproc-owner@xxxxxxxxxxxxxxx [mailto:linux-remoteproc-
> owner@xxxxxxxxxxxxxxx] On Behalf Of Bjorn Andersson
> Sent: Wednesday, May 03, 2017 7:29 AM
> To: Andy Gross <andy.gross@xxxxxxxxxx>; Rob Herring
> <robh+dt@xxxxxxxxxx>; Mark Rutland <mark.rutland@xxxxxxx>; Ohad Ben-
> Cohen <ohad@xxxxxxxxxx>
> Cc: linux-arm-msm@xxxxxxxxxxxxxxx; linux-soc@xxxxxxxxxxxxxxx;
> devicetree@xxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx; linux-
> remoteproc@xxxxxxxxxxxxxxx
> Subject: [PATCH v3 2/4] soc: qcom: Introduce APCS IPC driver
>
> This implements a driver that exposes the IPC bits found in the APCS Global
> block in various Qualcomm platforms. The bits are used to signal inter-
> processor communication signals from the application CPU to other masters.
>
> The driver implements the "doorbell" binding and could be used as basis for a
> new Linux framework, if found useful outside Qualcomm.
>
Hi Bjorn,
Even if Qualcom APCS IPC is limited, why don't you rely on existing mailbox framework.
It is there to gather all IPC management under the same interface.
No need to create a new one from my pov.
If you don't provide message data, mailbox framework behaves as doorbell.
Regards,
Loic
> Signed-off-by: Bjorn Andersson <bjorn.andersson@xxxxxxxxxx>
> ---
>
> Changes since v2:
> - New driver
>
> drivers/soc/qcom/Kconfig | 8 ++
> drivers/soc/qcom/Makefile | 1 +
> drivers/soc/qcom/apcs-ipc.c | 182
> ++++++++++++++++++++++++++++++++++++++
> include/linux/soc/qcom/apcs_ipc.h | 26 ++++++
> 4 files changed, 217 insertions(+)
> create mode 100644 drivers/soc/qcom/apcs-ipc.c create mode 100644
> include/linux/soc/qcom/apcs_ipc.h
>
> diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index
> 78b1bb7bcf20..4113da81d18b 100644
> --- a/drivers/soc/qcom/Kconfig
> +++ b/drivers/soc/qcom/Kconfig
> @@ -1,6 +1,14 @@
> #
> # QCOM Soc drivers
> #
> +config QCOM_APCS_IPC
> + tristate "Qualcomm APCS IPC driver"
> + depends on ARCH_QCOM
> + help
> + Say y here to enable support for the APCS IPC doorbell driver,
> + providing an interface for invoking the inter-process communication
> + signals from the application processor to other masters.
> +
> config QCOM_GSBI
> tristate "QCOM General Serial Bus Interface"
> depends on ARCH_QCOM
> diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index
> 1f30260b06b8..e15b33e5a630 100644
> --- a/drivers/soc/qcom/Makefile
> +++ b/drivers/soc/qcom/Makefile
> @@ -1,3 +1,4 @@
> +obj-$(CONFIG_QCOM_APCS_IPC) += apcs-ipc.o
> obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
> obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o
> obj-$(CONFIG_QCOM_PM) += spm.o
> diff --git a/drivers/soc/qcom/apcs-ipc.c b/drivers/soc/qcom/apcs-ipc.c new
> file mode 100644 index 000000000000..ea835cb08657
> --- /dev/null
> +++ b/drivers/soc/qcom/apcs-ipc.c
> @@ -0,0 +1,182 @@
> +/*
> + * Copyright (c) 2017, Linaro Ltd
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/io.h>
> +#include <linux/slab.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +
> +static struct platform_driver qcom_apcs_ipc_driver;
> +
> +struct qcom_apcs_ipc {
> + struct device *dev;
> +
> + void __iomem *base;
> + unsigned long offset;
> +};
> +
> +struct qcom_apcs_ipc_bell {
> + struct qcom_apcs_ipc *apcs;
> + unsigned int bit;
> +};
> +
> +static void qcom_apcs_ipc_release(struct device *dev, void *res) {
> + struct qcom_apcs_ipc_bell *bell = res;
> + struct qcom_apcs_ipc *apcs = bell->apcs;
> +
> + put_device(apcs->dev);
> +}
> +
> +/**
> + * qcom_apcs_ipc_get() - acquire a handle to a doorbell
> + * @dev: client device handle
> + * @id: identifier of the doorbell
> + *
> + * Returns a doorbell reference, or negative errno on failure.
> + */
> +struct qcom_apcs_ipc_bell *devm_qcom_apcs_ipc_get(struct device *dev,
> + const char *id)
> +{
> + struct qcom_apcs_ipc_bell *bell;
> + struct platform_device *pdev;
> + struct of_phandle_args args;
> + int index = 0;
> + int ret;
> +
> + if (id) {
> + index = of_property_match_string(dev->of_node,
> + "doorbell-names", id);
> + if (index < 0)
> + return ERR_PTR(index);
> + }
> +
> + ret = of_parse_phandle_with_args(dev->of_node, "doorbells",
> + "#doorbell-cells", index, &args);
> + if (ret) {
> + dev_err(dev, "unable to resolve doorbell\n");
> + return ERR_PTR(-ENODEV);
> + }
> +
> + pdev = of_find_device_by_node(args.np);
> + of_node_put(args.np);
> +
> + if (!pdev)
> + return ERR_PTR(-EPROBE_DEFER);
> +
> + if (args.args[0] >= 32) {
> + dev_err(dev, "invalid doorbell requested\n");
> + ret = -EINVAL;
> + goto release_device;
> + }
> +
> + if (pdev->dev.driver != &qcom_apcs_ipc_driver.driver) {
> + dev_err(dev, "failed to acquire apcs ipc driver\n");
> + ret = -EINVAL;
> + goto release_device;
> + }
> +
> + bell = devres_alloc(qcom_apcs_ipc_release, sizeof(*bell),
> GFP_KERNEL);
> + if (!bell) {
> + ret = -ENOMEM;
> + goto release_device;
> + }
> +
> + bell->apcs = platform_get_drvdata(pdev);
> + bell->bit = args.args[0];
> +
> + devres_add(dev, bell);
> +
> + return bell;
> +
> +release_device:
> + put_device(&pdev->dev);
> +
> + return ERR_PTR(ret);
> +
> +}
> +EXPORT_SYMBOL_GPL(devm_qcom_apcs_ipc_get);
> +
> +/**
> + * qcom_apcs_ipc_ring() - ring the doorbell
> + * @bell: doorbell to ring
> + */
> +void qcom_apcs_ipc_ring(struct qcom_apcs_ipc_bell *bell) {
> + struct qcom_apcs_ipc *apcs = bell->apcs;
> +
> + writel(BIT(bell->bit), apcs->base + apcs->offset); }
> +EXPORT_SYMBOL_GPL(qcom_apcs_ipc_ring);
> +
> +static int qcom_apcs_ipc_probe(struct platform_device *pdev) {
> + struct qcom_apcs_ipc *apcs;
> + struct resource *res;
> +
> + apcs = devm_kzalloc(&pdev->dev, sizeof(*apcs), GFP_KERNEL);
> + if (!apcs)
> + return -ENOMEM;
> +
> + apcs->dev = &pdev->dev;
> + apcs->offset = (unsigned long)of_device_get_match_data(&pdev-
> >dev);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + apcs->base = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(apcs->base))
> + return PTR_ERR(apcs->base);
> +
> + platform_set_drvdata(pdev, apcs);
> +
> + return 0;
> +}
> +
> +static int qcom_apcs_ipc_remove(struct platform_device *pdev) {
> + return 0;
> +}
> +
> +/* .data is the offset of the ipc register within the global block */
> +static const struct of_device_id qcom_apcs_ipc_of_match[] = {
> + { .compatible = "qcom,msm8916-apcs-kpss-global", .data = (void *)8
> },
> + { .compatible = "qcom,msm8996-apcs-hmss-global", .data = (void
> *)16 },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, qcom_apcs_ipc_of_match);
> +
> +static struct platform_driver qcom_apcs_ipc_driver = {
> + .probe = qcom_apcs_ipc_probe,
> + .remove = qcom_apcs_ipc_remove,
> + .driver = {
> + .name = "qcom_apcs_ipc",
> + .of_match_table = qcom_apcs_ipc_of_match,
> + },
> +};
> +
> +static int __init qcom_apcs_ipc_init(void) {
> + return platform_driver_register(&qcom_apcs_ipc_driver);
> +}
> +postcore_initcall(qcom_apcs_ipc_init);
> +
> +static void __exit qcom_apcs_ipc_exit(void) {
> + platform_driver_unregister(&qcom_apcs_ipc_driver);
> +}
> +module_exit(qcom_apcs_ipc_exit);
> +
> +MODULE_LICENSE("GPL v2");
> +MODULE_DESCRIPTION("Qualcomm APCS IPC driver");
> diff --git a/include/linux/soc/qcom/apcs_ipc.h
> b/include/linux/soc/qcom/apcs_ipc.h
> new file mode 100644
> index 000000000000..72be77555261
> --- /dev/null
> +++ b/include/linux/soc/qcom/apcs_ipc.h
> @@ -0,0 +1,26 @@
> +#ifndef __QCOM_APCS_IPC_H__
> +#define __QCOM_APCS_IPC_H__
> +
> +#include <linux/err.h>
> +
> +struct device;
> +struct qcom_apcs_ipc_bell;
> +
> +#if IS_ENABLED(CONFIG_QCOM_APCS_IPC)
> +
> +struct qcom_apcs_ipc_bell *devm_qcom_apcs_ipc_get(struct device *dev,
> + const char *id);
> +void qcom_apcs_ipc_ring(struct qcom_apcs_ipc_bell *bell);
> +
> +#else
> +
> +static inline struct qcom_apcs_ipc_bell *devm_qcom_apcs_ipc_get(struct
> device *dev,
> + const char
> *id)
> +{
> + return ERR_PTR(-EINVAL);
> +}
> +
> +static inline void qcom_apcs_ipc_ring(struct qcom_apcs_ipc_bell *bell)
> +{}
> +
> +#endif
> +#endif
> --
> 2.12.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-remoteproc" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo
> info at http://vger.kernel.org/majordomo-info.html