linux-rtc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] rtc: add imx rpmsg rtc support
@ 2021-08-05  3:35 Dong Aisheng
  2021-08-05  3:35 ` [PATCH 1/2] ARM: dts: imx7ulp: add cm4 support Dong Aisheng
  2021-08-05  3:35 ` [PATCH 2/2] rtc: imx-rpmsg: Add i.MX RPMSG RTC support Dong Aisheng
  0 siblings, 2 replies; 6+ messages in thread
From: Dong Aisheng @ 2021-08-05  3:35 UTC (permalink / raw)
  To: linux-arm-kernel, linux-rtc
  Cc: devicetree, linux-imx, kernel, aisheng.dong, dongas86, robh+dt,
	shawnguo, peng.fan

Add imx rpmsg rtc driver support

The driver needs cowork with pm rpmsg on imx7ulp but no compilation
dependency.

Dong Aisheng (2):
  ARM: dts: imx7ulp: add cm4 support
  rtc: imx-rpmsg: Add i.MX RPMSG RTC support

 arch/arm/boot/dts/imx7ulp-evk-m4.dtsi |  48 ++++
 arch/arm/boot/dts/imx7ulp-evk.dts     |   1 +
 arch/arm/boot/dts/imx7ulp.dtsi        |   7 +
 drivers/rtc/Kconfig                   |  10 +
 drivers/rtc/Makefile                  |   1 +
 drivers/rtc/rtc-imx-rpmsg.c           | 301 ++++++++++++++++++++++++++
 include/linux/firmware/imx/rpmsg.h    |  37 ++++
 7 files changed, 405 insertions(+)
 create mode 100644 arch/arm/boot/dts/imx7ulp-evk-m4.dtsi
 create mode 100644 drivers/rtc/rtc-imx-rpmsg.c
 create mode 100644 include/linux/firmware/imx/rpmsg.h

-- 
2.25.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2] ARM: dts: imx7ulp: add cm4 support
  2021-08-05  3:35 [PATCH 0/2] rtc: add imx rpmsg rtc support Dong Aisheng
@ 2021-08-05  3:35 ` Dong Aisheng
  2021-08-05  3:35 ` [PATCH 2/2] rtc: imx-rpmsg: Add i.MX RPMSG RTC support Dong Aisheng
  1 sibling, 0 replies; 6+ messages in thread
From: Dong Aisheng @ 2021-08-05  3:35 UTC (permalink / raw)
  To: linux-arm-kernel, linux-rtc
  Cc: devicetree, linux-imx, kernel, aisheng.dong, dongas86, robh+dt,
	shawnguo, peng.fan, Alessandro Zummo, Alexandre Belloni

Add cm4 remoteproc which supports rpmsg naming service with
two vdevs and two pairs of vrings. The vdevbuffer region is
not required.

Cc: Rob Herring <robh+dt@kernel.org>
Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
---
 arch/arm/boot/dts/imx7ulp-evk-m4.dtsi | 48 +++++++++++++++++++++++++++
 arch/arm/boot/dts/imx7ulp-evk.dts     |  1 +
 arch/arm/boot/dts/imx7ulp.dtsi        |  7 ++++
 3 files changed, 56 insertions(+)
 create mode 100644 arch/arm/boot/dts/imx7ulp-evk-m4.dtsi

diff --git a/arch/arm/boot/dts/imx7ulp-evk-m4.dtsi b/arch/arm/boot/dts/imx7ulp-evk-m4.dtsi
new file mode 100644
index 000000000000..abef0e6a2f25
--- /dev/null
+++ b/arch/arm/boot/dts/imx7ulp-evk-m4.dtsi
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 NXP
+ *   Dong Aisheng <aisheng.dong@nxp.com>
+ */
+
+/ {
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		vdev0vring0: vdev0vring0@9ff00000 {
+			reg = <0x9ff00000 0x8000>;
+			no-map;
+		};
+
+		vdev0vring1: vdev0vring1@9ff08000 {
+			reg = <0x9ff08000 0x8000>;
+			no-map;
+		};
+
+		vdev1vring0: vdev1vring0@9ff10000 {
+			reg = <0x9ff10000 0x8000>;
+			no-map;
+		};
+
+		vdev1vring1: vdev1vring1@9ff18000 {
+			reg = <0x9ff18000 0x8000>;
+			no-map;
+		};
+
+		rsc_table: rsc-table@1fff8000{
+			reg = <0x1fff8000 0x1000>;
+			no-map;
+		};
+	};
+
+	imx7ulp-cm4 {
+		compatible = "fsl,imx7ulp-cm4";
+		mbox-names = "tx", "rx", "rxdb";
+		mboxes = <&mu 0 1
+			  &mu 1 1
+			  &mu 3 1>;
+		memory-region = <&vdev0vring0>, <&vdev0vring1>,
+				<&vdev1vring0>, <&vdev1vring1>, <&rsc_table>;
+	};
+};
diff --git a/arch/arm/boot/dts/imx7ulp-evk.dts b/arch/arm/boot/dts/imx7ulp-evk.dts
index eff51e113db4..5d08bdad4c07 100644
--- a/arch/arm/boot/dts/imx7ulp-evk.dts
+++ b/arch/arm/boot/dts/imx7ulp-evk.dts
@@ -8,6 +8,7 @@
 /dts-v1/;
 
 #include "imx7ulp.dtsi"
+#include "imx7ulp-evk-m4.dtsi"
 
 / {
 	model = "NXP i.MX7ULP EVK";
diff --git a/arch/arm/boot/dts/imx7ulp.dtsi b/arch/arm/boot/dts/imx7ulp.dtsi
index a917b363da25..b4568eb49f2c 100644
--- a/arch/arm/boot/dts/imx7ulp.dtsi
+++ b/arch/arm/boot/dts/imx7ulp.dtsi
@@ -122,6 +122,13 @@ edma1: dma-controller@40080000 {
 				 <&pcc2 IMX7ULP_CLK_DMA_MUX1>;
 		};
 
+		mu: mailbox@40220000 {
+			compatible = "fsl,imx7ulp-mu";
+			reg = <0x40220000 0x1000>;
+			interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
+			#mbox-cells = <2>;
+		};
+
 		crypto: crypto@40240000 {
 			compatible = "fsl,sec-v4.0";
 			#address-cells = <1>;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] rtc: imx-rpmsg: Add i.MX RPMSG RTC support
  2021-08-05  3:35 [PATCH 0/2] rtc: add imx rpmsg rtc support Dong Aisheng
  2021-08-05  3:35 ` [PATCH 1/2] ARM: dts: imx7ulp: add cm4 support Dong Aisheng
@ 2021-08-05  3:35 ` Dong Aisheng
  2021-08-05  8:13   ` Alexandre Belloni
  2021-09-25 21:53   ` Alexandre Belloni
  1 sibling, 2 replies; 6+ messages in thread
From: Dong Aisheng @ 2021-08-05  3:35 UTC (permalink / raw)
  To: linux-arm-kernel, linux-rtc
  Cc: devicetree, linux-imx, kernel, aisheng.dong, dongas86, robh+dt,
	shawnguo, peng.fan, Alessandro Zummo, Alexandre Belloni

Add i.MX RPMSG RTC support.

Cc: Alessandro Zummo <a.zummo@towertech.it>
Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
Cc: Shawn Guo <shawnguo@kernel.org>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
---
 drivers/rtc/Kconfig                |  10 +
 drivers/rtc/Makefile               |   1 +
 drivers/rtc/rtc-imx-rpmsg.c        | 301 +++++++++++++++++++++++++++++
 include/linux/firmware/imx/rpmsg.h |  37 ++++
 4 files changed, 349 insertions(+)
 create mode 100644 drivers/rtc/rtc-imx-rpmsg.c
 create mode 100644 include/linux/firmware/imx/rpmsg.h

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 12153d5801ce..f0e6c4dd8965 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1763,6 +1763,16 @@ config RTC_DRV_SNVS
 	   This driver can also be built as a module, if so, the module
 	   will be called "rtc-snvs".
 
+config RTC_DRV_IMX_RPMSG
+	tristate "NXP RPMSG RTC support"
+	select RPMSG_VIRTIO
+	depends on ARCH_MXC || COMPILE_TEST
+	depends on IMX_REMOTEPROC
+	depends on OF
+	help
+	   If you say yes here you get support for the NXP RPMSG
+	   RTC module.
+
 config RTC_DRV_IMX_SC
 	depends on IMX_SCU
 	depends on HAVE_ARM_SMCCC
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 2dd0dd956b0e..9cebfddcc245 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_RTC_DRV_GOLDFISH)	+= rtc-goldfish.o
 obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o
 obj-$(CONFIG_RTC_DRV_HYM8563)	+= rtc-hym8563.o
 obj-$(CONFIG_RTC_DRV_IMXDI)	+= rtc-imxdi.o
+obj-$(CONFIG_RTC_DRV_IMX_RPMSG)	+= rtc-imx-rpmsg.o
 obj-$(CONFIG_RTC_DRV_IMX_SC)	+= rtc-imx-sc.o
 obj-$(CONFIG_RTC_DRV_ISL12022)	+= rtc-isl12022.o
 obj-$(CONFIG_RTC_DRV_ISL12026)	+= rtc-isl12026.o
diff --git a/drivers/rtc/rtc-imx-rpmsg.c b/drivers/rtc/rtc-imx-rpmsg.c
new file mode 100644
index 000000000000..0d6d4b18159e
--- /dev/null
+++ b/drivers/rtc/rtc-imx-rpmsg.c
@@ -0,0 +1,301 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2017-2021 NXP
+ */
+
+#include <linux/firmware/imx/rpmsg.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_qos.h>
+#include <linux/rpmsg.h>
+#include <linux/rtc.h>
+
+#define RPMSG_TIMEOUT 1000
+
+#define RTC_RPMSG_SEND		0x0
+#define RTC_RPMSG_RECEIVE	0x1
+#define RTC_RPMSG_NOTIFY	0x2
+
+enum rtc_rpmsg_cmd {
+	RTC_RPMSG_SET_TIME,
+	RTC_RPMSG_GET_TIME,
+	RTC_RPMSG_SET_ALARM,
+	RTC_RPMSG_GET_ALARM,
+	RTC_RPMSG_ENABLE_ALARM,
+};
+
+struct rtc_rpmsg_data {
+	struct imx_rpmsg_head header;
+	u8 reserved0;
+	union {
+		u8 reserved1;
+		u8 ret;
+	};
+	union {
+		u32 reserved2;
+		u32 sec;
+	};
+	union {
+		u8 enable;
+		u8 reserved3;
+	};
+	union {
+		u8 pending;
+		u8 reserved4;
+	};
+} __packed;
+
+struct rtc_rpmsg_info {
+	struct rpmsg_device *rpdev;
+	struct rtc_rpmsg_data *msg;
+	struct pm_qos_request pm_qos_req;
+	struct completion cmd_complete;
+	struct mutex lock;
+	struct rtc_device *rtc;
+};
+
+static int rtc_send_message(struct rtc_rpmsg_info *info,
+			    struct rtc_rpmsg_data *msg, bool ack)
+{
+	struct device *dev = &info->rpdev->dev;
+	int err;
+
+	mutex_lock(&info->lock);
+
+	cpu_latency_qos_add_request(&info->pm_qos_req, 0);
+	reinit_completion(&info->cmd_complete);
+
+	err = rpmsg_send(info->rpdev->ept, (void *)msg, sizeof(*msg));
+	if (err) {
+		dev_err(dev, "rpmsg send failed: %d\n", err);
+		goto err_out;
+	}
+
+	if (ack) {
+		err = wait_for_completion_timeout(&info->cmd_complete,
+						  msecs_to_jiffies(RPMSG_TIMEOUT));
+		if (!err) {
+			dev_err(dev, "rpmsg send timeout\n");
+			err = -ETIMEDOUT;
+			goto err_out;
+		}
+
+		if (info->msg->ret != 0) {
+			dev_err(dev, "rpmsg not ack %d\n", info->msg->ret);
+			err = -EINVAL;
+			goto err_out;
+		}
+
+		err = 0;
+	}
+
+err_out:
+	cpu_latency_qos_remove_request(&info->pm_qos_req);
+	mutex_unlock(&info->lock);
+
+	return err;
+}
+
+static int imx_rpmsg_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
+	struct rtc_rpmsg_data msg;
+	int ret;
+
+	msg.header.cate = IMX_RPMSG_RTC;
+	msg.header.major = IMX_RMPSG_MAJOR;
+	msg.header.minor = IMX_RMPSG_MINOR;
+	msg.header.type = RTC_RPMSG_SEND;
+	msg.header.cmd = RTC_RPMSG_GET_TIME;
+
+	ret = rtc_send_message(rtc_rpmsg, &msg, true);
+	if (ret)
+		return ret;
+
+	rtc_time64_to_tm(rtc_rpmsg->msg->sec, tm);
+
+	return 0;
+}
+
+static int imx_rpmsg_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
+	struct rtc_rpmsg_data msg;
+	unsigned long time;
+	int ret;
+
+	time = rtc_tm_to_time64(tm);
+
+	msg.header.cate = IMX_RPMSG_RTC;
+	msg.header.major = IMX_RMPSG_MAJOR;
+	msg.header.minor = IMX_RMPSG_MINOR;
+	msg.header.type = RTC_RPMSG_SEND;
+	msg.header.cmd = RTC_RPMSG_SET_TIME;
+	msg.sec = time;
+
+	ret = rtc_send_message(rtc_rpmsg, &msg, true);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int imx_rpmsg_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
+	struct rtc_rpmsg_data msg;
+	int ret;
+
+	msg.header.cate = IMX_RPMSG_RTC;
+	msg.header.major = IMX_RMPSG_MAJOR;
+	msg.header.minor = IMX_RMPSG_MINOR;
+	msg.header.type = RTC_RPMSG_SEND;
+	msg.header.cmd = RTC_RPMSG_GET_ALARM;
+
+	ret = rtc_send_message(rtc_rpmsg, &msg, true);
+	if (ret)
+		return ret;
+
+	rtc_time64_to_tm(rtc_rpmsg->msg->sec, &alrm->time);
+	alrm->pending = rtc_rpmsg->msg->pending;
+
+	return 0;
+}
+
+static int imx_rpmsg_rtc_alarm_irq_enable(struct device *dev,
+	unsigned int enable)
+{
+	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
+	struct rtc_rpmsg_data msg;
+	int ret;
+
+	msg.header.cate = IMX_RPMSG_RTC;
+	msg.header.major = IMX_RMPSG_MAJOR;
+	msg.header.minor = IMX_RMPSG_MINOR;
+	msg.header.type = RTC_RPMSG_SEND;
+	msg.header.cmd = RTC_RPMSG_ENABLE_ALARM;
+	msg.enable = enable;
+
+	ret = rtc_send_message(rtc_rpmsg, &msg, true);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int imx_rpmsg_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
+	struct rtc_rpmsg_data msg;
+	unsigned long time;
+	int ret;
+
+	time = rtc_tm_to_time64(&alrm->time);
+
+	msg.header.cate = IMX_RPMSG_RTC;
+	msg.header.major = IMX_RMPSG_MAJOR;
+	msg.header.minor = IMX_RMPSG_MINOR;
+	msg.header.type = RTC_RPMSG_SEND;
+	msg.header.cmd = RTC_RPMSG_SET_ALARM;
+	msg.sec = time;
+	msg.enable = alrm->enabled;
+
+	ret = rtc_send_message(rtc_rpmsg, &msg, true);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct rtc_class_ops imx_rpmsg_rtc_ops = {
+	.read_time = imx_rpmsg_rtc_read_time,
+	.set_time = imx_rpmsg_rtc_set_time,
+	.read_alarm = imx_rpmsg_rtc_read_alarm,
+	.set_alarm = imx_rpmsg_rtc_set_alarm,
+	.alarm_irq_enable = imx_rpmsg_rtc_alarm_irq_enable,
+};
+
+static int rtc_rpmsg_probe(struct rpmsg_device *rpdev)
+{
+	struct device *dev = &rpdev->dev;
+	struct rtc_rpmsg_info *rtc_rpmsg;
+
+	dev_info(dev, "new channel: 0x%x -> 0x%x\n", rpdev->src, rpdev->dst);
+
+	rtc_rpmsg = devm_kzalloc(dev, sizeof(*rtc_rpmsg), GFP_KERNEL);
+	if (!rtc_rpmsg)
+		return -ENOMEM;
+
+	rtc_rpmsg->rpdev = rpdev;
+	mutex_init(&rtc_rpmsg->lock);
+	init_completion(&rtc_rpmsg->cmd_complete);
+
+	dev_set_drvdata(dev, rtc_rpmsg);
+
+	device_init_wakeup(dev, true);
+
+	rtc_rpmsg->rtc = devm_rtc_device_register(dev, "rtc-rpmsg",
+						  &imx_rpmsg_rtc_ops,
+						  THIS_MODULE);
+	if (IS_ERR(rtc_rpmsg->rtc)) {
+		dev_err(dev, "failed to register rtc rpmsg: %ld\n", PTR_ERR(rtc_rpmsg->rtc));
+		return PTR_ERR(rtc_rpmsg->rtc);
+	}
+
+	return 0;
+}
+
+static void rtc_rpmsg_remove(struct rpmsg_device *rpdev)
+{
+	dev_info(&rpdev->dev, "rtc rpmsg driver is removed\n");
+}
+
+static int rtc_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
+			void *priv, u32 src)
+{
+	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(&rpdev->dev);
+	struct rtc_rpmsg_data *msg = (struct rtc_rpmsg_data *)data;
+
+	rtc_rpmsg->msg = msg;
+
+	if (msg->header.type == RTC_RPMSG_RECEIVE)
+		complete(&rtc_rpmsg->cmd_complete);
+	else if (msg->header.type == RTC_RPMSG_NOTIFY)
+		rtc_update_irq(rtc_rpmsg->rtc, 1, RTC_IRQF);
+	else
+		dev_err(&rpdev->dev, "wrong command type!\n");
+
+	return 0;
+}
+
+static const struct rpmsg_device_id rtc_rpmsg_id_table[] = {
+	{ .name	= "rpmsg-rtc-channel" },
+	{ },
+};
+
+static struct rpmsg_driver rtc_rpmsg_driver = {
+	.drv.name	= "imx_rtc_rpmsg",
+	.probe		= rtc_rpmsg_probe,
+	.remove		= rtc_rpmsg_remove,
+	.callback	= rtc_rpmsg_cb,
+	.id_table	= rtc_rpmsg_id_table,
+};
+
+/*
+ * imx m4 has a limitation that we can't read data during ns process.
+ * So register rtc a little bit late as rtc core will read data during
+ * register process
+ */
+static int __init rtc_rpmsg_init(void)
+{
+	return register_rpmsg_driver(&rtc_rpmsg_driver);
+}
+late_initcall(rtc_rpmsg_init);
+
+MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");
+MODULE_DESCRIPTION("NXP i.MX RPMSG RTC Driver");
+MODULE_ALIAS("platform:imx_rtc_rpmsg");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/firmware/imx/rpmsg.h b/include/linux/firmware/imx/rpmsg.h
new file mode 100644
index 000000000000..20bcce23c917
--- /dev/null
+++ b/include/linux/firmware/imx/rpmsg.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2019-2021 NXP.
+ */
+
+#ifndef __LINUX_IMX_RPMSG_H__
+#define __LINUX_IMX_RPMSG_H__
+
+#include <linux/types.h>
+
+/*
+ * Global header file for iMX RPMSG
+ */
+
+/* Category define */
+#define IMX_RMPSG_LIFECYCLE     1
+#define IMX_RPMSG_PMIC          2
+#define IMX_RPMSG_AUDIO         3
+#define IMX_RPMSG_KEY           4
+#define IMX_RPMSG_GPIO          5
+#define IMX_RPMSG_RTC           6
+#define IMX_RPMSG_SENSOR        7
+
+/* rpmsg version */
+#define IMX_RMPSG_MAJOR         1
+#define IMX_RMPSG_MINOR         0
+
+struct imx_rpmsg_head {
+	u8 cate;
+	u8 major;
+	u8 minor;
+	u8 type;
+	u8 cmd;
+	u8 reserved[5];
+} __packed;
+
+#endif /* __LINUX_IMX_RPMSG_H__ */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] rtc: imx-rpmsg: Add i.MX RPMSG RTC support
  2021-08-05  3:35 ` [PATCH 2/2] rtc: imx-rpmsg: Add i.MX RPMSG RTC support Dong Aisheng
@ 2021-08-05  8:13   ` Alexandre Belloni
  2021-08-05  8:48     ` Dong Aisheng
  2021-09-25 21:53   ` Alexandre Belloni
  1 sibling, 1 reply; 6+ messages in thread
From: Alexandre Belloni @ 2021-08-05  8:13 UTC (permalink / raw)
  To: Dong Aisheng
  Cc: linux-arm-kernel, linux-rtc, devicetree, linux-imx, kernel,
	dongas86, robh+dt, shawnguo, peng.fan, Alessandro Zummo

Hello,

On 05/08/2021 11:35:46+0800, Dong Aisheng wrote:
> Add i.MX RPMSG RTC support.
> 

You definitively need to elaborate why this is necessary and why
rtc-imx-sc.c has not been reused. I'm not going to take a new driver for
each version of the CM4 firmware.

> Cc: Alessandro Zummo <a.zummo@towertech.it>
> Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
> Cc: Shawn Guo <shawnguo@kernel.org>
> Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
> ---
>  drivers/rtc/Kconfig                |  10 +
>  drivers/rtc/Makefile               |   1 +
>  drivers/rtc/rtc-imx-rpmsg.c        | 301 +++++++++++++++++++++++++++++
>  include/linux/firmware/imx/rpmsg.h |  37 ++++
>  4 files changed, 349 insertions(+)
>  create mode 100644 drivers/rtc/rtc-imx-rpmsg.c
>  create mode 100644 include/linux/firmware/imx/rpmsg.h
> 
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 12153d5801ce..f0e6c4dd8965 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -1763,6 +1763,16 @@ config RTC_DRV_SNVS
>  	   This driver can also be built as a module, if so, the module
>  	   will be called "rtc-snvs".
>  
> +config RTC_DRV_IMX_RPMSG
> +	tristate "NXP RPMSG RTC support"
> +	select RPMSG_VIRTIO
> +	depends on ARCH_MXC || COMPILE_TEST
> +	depends on IMX_REMOTEPROC
> +	depends on OF
> +	help
> +	   If you say yes here you get support for the NXP RPMSG
> +	   RTC module.
> +
>  config RTC_DRV_IMX_SC
>  	depends on IMX_SCU
>  	depends on HAVE_ARM_SMCCC
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 2dd0dd956b0e..9cebfddcc245 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -72,6 +72,7 @@ obj-$(CONFIG_RTC_DRV_GOLDFISH)	+= rtc-goldfish.o
>  obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o
>  obj-$(CONFIG_RTC_DRV_HYM8563)	+= rtc-hym8563.o
>  obj-$(CONFIG_RTC_DRV_IMXDI)	+= rtc-imxdi.o
> +obj-$(CONFIG_RTC_DRV_IMX_RPMSG)	+= rtc-imx-rpmsg.o
>  obj-$(CONFIG_RTC_DRV_IMX_SC)	+= rtc-imx-sc.o
>  obj-$(CONFIG_RTC_DRV_ISL12022)	+= rtc-isl12022.o
>  obj-$(CONFIG_RTC_DRV_ISL12026)	+= rtc-isl12026.o
> diff --git a/drivers/rtc/rtc-imx-rpmsg.c b/drivers/rtc/rtc-imx-rpmsg.c
> new file mode 100644
> index 000000000000..0d6d4b18159e
> --- /dev/null
> +++ b/drivers/rtc/rtc-imx-rpmsg.c
> @@ -0,0 +1,301 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright 2017-2021 NXP
> + */
> +
> +#include <linux/firmware/imx/rpmsg.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/pm_qos.h>
> +#include <linux/rpmsg.h>
> +#include <linux/rtc.h>
> +
> +#define RPMSG_TIMEOUT 1000
> +
> +#define RTC_RPMSG_SEND		0x0
> +#define RTC_RPMSG_RECEIVE	0x1
> +#define RTC_RPMSG_NOTIFY	0x2
> +
> +enum rtc_rpmsg_cmd {
> +	RTC_RPMSG_SET_TIME,
> +	RTC_RPMSG_GET_TIME,
> +	RTC_RPMSG_SET_ALARM,
> +	RTC_RPMSG_GET_ALARM,
> +	RTC_RPMSG_ENABLE_ALARM,
> +};
> +
> +struct rtc_rpmsg_data {
> +	struct imx_rpmsg_head header;
> +	u8 reserved0;
> +	union {
> +		u8 reserved1;
> +		u8 ret;
> +	};
> +	union {
> +		u32 reserved2;
> +		u32 sec;
> +	};
> +	union {
> +		u8 enable;
> +		u8 reserved3;
> +	};
> +	union {
> +		u8 pending;
> +		u8 reserved4;
> +	};
> +} __packed;
> +
> +struct rtc_rpmsg_info {
> +	struct rpmsg_device *rpdev;
> +	struct rtc_rpmsg_data *msg;
> +	struct pm_qos_request pm_qos_req;
> +	struct completion cmd_complete;
> +	struct mutex lock;
> +	struct rtc_device *rtc;
> +};
> +
> +static int rtc_send_message(struct rtc_rpmsg_info *info,
> +			    struct rtc_rpmsg_data *msg, bool ack)
> +{
> +	struct device *dev = &info->rpdev->dev;
> +	int err;
> +
> +	mutex_lock(&info->lock);
> +
> +	cpu_latency_qos_add_request(&info->pm_qos_req, 0);
> +	reinit_completion(&info->cmd_complete);
> +
> +	err = rpmsg_send(info->rpdev->ept, (void *)msg, sizeof(*msg));
> +	if (err) {
> +		dev_err(dev, "rpmsg send failed: %d\n", err);
> +		goto err_out;
> +	}
> +
> +	if (ack) {
> +		err = wait_for_completion_timeout(&info->cmd_complete,
> +						  msecs_to_jiffies(RPMSG_TIMEOUT));
> +		if (!err) {
> +			dev_err(dev, "rpmsg send timeout\n");
> +			err = -ETIMEDOUT;
> +			goto err_out;
> +		}
> +
> +		if (info->msg->ret != 0) {
> +			dev_err(dev, "rpmsg not ack %d\n", info->msg->ret);
> +			err = -EINVAL;
> +			goto err_out;
> +		}
> +
> +		err = 0;
> +	}
> +
> +err_out:
> +	cpu_latency_qos_remove_request(&info->pm_qos_req);
> +	mutex_unlock(&info->lock);
> +
> +	return err;
> +}
> +
> +static int imx_rpmsg_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
> +	struct rtc_rpmsg_data msg;
> +	int ret;
> +
> +	msg.header.cate = IMX_RPMSG_RTC;
> +	msg.header.major = IMX_RMPSG_MAJOR;
> +	msg.header.minor = IMX_RMPSG_MINOR;
> +	msg.header.type = RTC_RPMSG_SEND;
> +	msg.header.cmd = RTC_RPMSG_GET_TIME;
> +
> +	ret = rtc_send_message(rtc_rpmsg, &msg, true);
> +	if (ret)
> +		return ret;
> +
> +	rtc_time64_to_tm(rtc_rpmsg->msg->sec, tm);
> +
> +	return 0;
> +}
> +
> +static int imx_rpmsg_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
> +	struct rtc_rpmsg_data msg;
> +	unsigned long time;
> +	int ret;
> +
> +	time = rtc_tm_to_time64(tm);
> +
> +	msg.header.cate = IMX_RPMSG_RTC;
> +	msg.header.major = IMX_RMPSG_MAJOR;
> +	msg.header.minor = IMX_RMPSG_MINOR;
> +	msg.header.type = RTC_RPMSG_SEND;
> +	msg.header.cmd = RTC_RPMSG_SET_TIME;
> +	msg.sec = time;
> +
> +	ret = rtc_send_message(rtc_rpmsg, &msg, true);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int imx_rpmsg_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
> +	struct rtc_rpmsg_data msg;
> +	int ret;
> +
> +	msg.header.cate = IMX_RPMSG_RTC;
> +	msg.header.major = IMX_RMPSG_MAJOR;
> +	msg.header.minor = IMX_RMPSG_MINOR;
> +	msg.header.type = RTC_RPMSG_SEND;
> +	msg.header.cmd = RTC_RPMSG_GET_ALARM;
> +
> +	ret = rtc_send_message(rtc_rpmsg, &msg, true);
> +	if (ret)
> +		return ret;
> +
> +	rtc_time64_to_tm(rtc_rpmsg->msg->sec, &alrm->time);
> +	alrm->pending = rtc_rpmsg->msg->pending;
> +
> +	return 0;
> +}
> +
> +static int imx_rpmsg_rtc_alarm_irq_enable(struct device *dev,
> +	unsigned int enable)
> +{
> +	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
> +	struct rtc_rpmsg_data msg;
> +	int ret;
> +
> +	msg.header.cate = IMX_RPMSG_RTC;
> +	msg.header.major = IMX_RMPSG_MAJOR;
> +	msg.header.minor = IMX_RMPSG_MINOR;
> +	msg.header.type = RTC_RPMSG_SEND;
> +	msg.header.cmd = RTC_RPMSG_ENABLE_ALARM;
> +	msg.enable = enable;
> +
> +	ret = rtc_send_message(rtc_rpmsg, &msg, true);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int imx_rpmsg_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
> +	struct rtc_rpmsg_data msg;
> +	unsigned long time;
> +	int ret;
> +
> +	time = rtc_tm_to_time64(&alrm->time);
> +
> +	msg.header.cate = IMX_RPMSG_RTC;
> +	msg.header.major = IMX_RMPSG_MAJOR;
> +	msg.header.minor = IMX_RMPSG_MINOR;
> +	msg.header.type = RTC_RPMSG_SEND;
> +	msg.header.cmd = RTC_RPMSG_SET_ALARM;
> +	msg.sec = time;
> +	msg.enable = alrm->enabled;
> +
> +	ret = rtc_send_message(rtc_rpmsg, &msg, true);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static const struct rtc_class_ops imx_rpmsg_rtc_ops = {
> +	.read_time = imx_rpmsg_rtc_read_time,
> +	.set_time = imx_rpmsg_rtc_set_time,
> +	.read_alarm = imx_rpmsg_rtc_read_alarm,
> +	.set_alarm = imx_rpmsg_rtc_set_alarm,
> +	.alarm_irq_enable = imx_rpmsg_rtc_alarm_irq_enable,
> +};
> +
> +static int rtc_rpmsg_probe(struct rpmsg_device *rpdev)
> +{
> +	struct device *dev = &rpdev->dev;
> +	struct rtc_rpmsg_info *rtc_rpmsg;
> +
> +	dev_info(dev, "new channel: 0x%x -> 0x%x\n", rpdev->src, rpdev->dst);
> +
> +	rtc_rpmsg = devm_kzalloc(dev, sizeof(*rtc_rpmsg), GFP_KERNEL);
> +	if (!rtc_rpmsg)
> +		return -ENOMEM;
> +
> +	rtc_rpmsg->rpdev = rpdev;
> +	mutex_init(&rtc_rpmsg->lock);
> +	init_completion(&rtc_rpmsg->cmd_complete);
> +
> +	dev_set_drvdata(dev, rtc_rpmsg);
> +
> +	device_init_wakeup(dev, true);
> +
> +	rtc_rpmsg->rtc = devm_rtc_device_register(dev, "rtc-rpmsg",
> +						  &imx_rpmsg_rtc_ops,
> +						  THIS_MODULE);
> +	if (IS_ERR(rtc_rpmsg->rtc)) {
> +		dev_err(dev, "failed to register rtc rpmsg: %ld\n", PTR_ERR(rtc_rpmsg->rtc));
> +		return PTR_ERR(rtc_rpmsg->rtc);
> +	}
> +
> +	return 0;
> +}
> +
> +static void rtc_rpmsg_remove(struct rpmsg_device *rpdev)
> +{
> +	dev_info(&rpdev->dev, "rtc rpmsg driver is removed\n");
> +}
> +
> +static int rtc_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
> +			void *priv, u32 src)
> +{
> +	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(&rpdev->dev);
> +	struct rtc_rpmsg_data *msg = (struct rtc_rpmsg_data *)data;
> +
> +	rtc_rpmsg->msg = msg;
> +
> +	if (msg->header.type == RTC_RPMSG_RECEIVE)
> +		complete(&rtc_rpmsg->cmd_complete);
> +	else if (msg->header.type == RTC_RPMSG_NOTIFY)
> +		rtc_update_irq(rtc_rpmsg->rtc, 1, RTC_IRQF);
> +	else
> +		dev_err(&rpdev->dev, "wrong command type!\n");
> +
> +	return 0;
> +}
> +
> +static const struct rpmsg_device_id rtc_rpmsg_id_table[] = {
> +	{ .name	= "rpmsg-rtc-channel" },
> +	{ },
> +};
> +
> +static struct rpmsg_driver rtc_rpmsg_driver = {
> +	.drv.name	= "imx_rtc_rpmsg",
> +	.probe		= rtc_rpmsg_probe,
> +	.remove		= rtc_rpmsg_remove,
> +	.callback	= rtc_rpmsg_cb,
> +	.id_table	= rtc_rpmsg_id_table,
> +};
> +
> +/*
> + * imx m4 has a limitation that we can't read data during ns process.
> + * So register rtc a little bit late as rtc core will read data during
> + * register process
> + */
> +static int __init rtc_rpmsg_init(void)
> +{
> +	return register_rpmsg_driver(&rtc_rpmsg_driver);
> +}
> +late_initcall(rtc_rpmsg_init);
> +
> +MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");
> +MODULE_DESCRIPTION("NXP i.MX RPMSG RTC Driver");
> +MODULE_ALIAS("platform:imx_rtc_rpmsg");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/firmware/imx/rpmsg.h b/include/linux/firmware/imx/rpmsg.h
> new file mode 100644
> index 000000000000..20bcce23c917
> --- /dev/null
> +++ b/include/linux/firmware/imx/rpmsg.h
> @@ -0,0 +1,37 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2019-2021 NXP.
> + */
> +
> +#ifndef __LINUX_IMX_RPMSG_H__
> +#define __LINUX_IMX_RPMSG_H__
> +
> +#include <linux/types.h>
> +
> +/*
> + * Global header file for iMX RPMSG
> + */
> +
> +/* Category define */
> +#define IMX_RMPSG_LIFECYCLE     1
> +#define IMX_RPMSG_PMIC          2
> +#define IMX_RPMSG_AUDIO         3
> +#define IMX_RPMSG_KEY           4
> +#define IMX_RPMSG_GPIO          5
> +#define IMX_RPMSG_RTC           6
> +#define IMX_RPMSG_SENSOR        7
> +
> +/* rpmsg version */
> +#define IMX_RMPSG_MAJOR         1
> +#define IMX_RMPSG_MINOR         0
> +
> +struct imx_rpmsg_head {
> +	u8 cate;
> +	u8 major;
> +	u8 minor;
> +	u8 type;
> +	u8 cmd;
> +	u8 reserved[5];
> +} __packed;
> +
> +#endif /* __LINUX_IMX_RPMSG_H__ */
> -- 
> 2.25.1
> 

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] rtc: imx-rpmsg: Add i.MX RPMSG RTC support
  2021-08-05  8:13   ` Alexandre Belloni
@ 2021-08-05  8:48     ` Dong Aisheng
  0 siblings, 0 replies; 6+ messages in thread
From: Dong Aisheng @ 2021-08-05  8:48 UTC (permalink / raw)
  To: Alexandre Belloni
  Cc: Dong Aisheng,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
	linux-rtc, devicetree, dl-linux-imx, Sascha Hauer, Rob Herring,
	Shawn Guo, Peng Fan, Alessandro Zummo

Hi Alexandre,

On Thu, Aug 5, 2021 at 4:13 PM Alexandre Belloni
<alexandre.belloni@bootlin.com> wrote:
>
> Hello,
>
> On 05/08/2021 11:35:46+0800, Dong Aisheng wrote:
> > Add i.MX RPMSG RTC support.
> >
>
> You definitively need to elaborate why this is necessary and why
> rtc-imx-sc.c has not been reused. I'm not going to take a new driver for
> each version of the CM4 firmware.

rtc-imx-sc is based on SCU protocol and only used on SCU firmware
based platforms
like mx8qm/qxp platforms.

rtc-imx-rpmsg is based on rpmsg/virtio and could be used on the rest
of the imx platforms
with MCore firmware like mx6/mx7ulp/imx8m/imx8ulp.

They're totally different protocols and based on different frameworks.

Regards
Aisheng

>
> > Cc: Alessandro Zummo <a.zummo@towertech.it>
> > Cc: Alexandre Belloni <alexandre.belloni@bootlin.com>
> > Cc: Shawn Guo <shawnguo@kernel.org>
> > Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
> > ---
> >  drivers/rtc/Kconfig                |  10 +
> >  drivers/rtc/Makefile               |   1 +
> >  drivers/rtc/rtc-imx-rpmsg.c        | 301 +++++++++++++++++++++++++++++
> >  include/linux/firmware/imx/rpmsg.h |  37 ++++
> >  4 files changed, 349 insertions(+)
> >  create mode 100644 drivers/rtc/rtc-imx-rpmsg.c
> >  create mode 100644 include/linux/firmware/imx/rpmsg.h
> >
> > diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> > index 12153d5801ce..f0e6c4dd8965 100644
> > --- a/drivers/rtc/Kconfig
> > +++ b/drivers/rtc/Kconfig
> > @@ -1763,6 +1763,16 @@ config RTC_DRV_SNVS
> >          This driver can also be built as a module, if so, the module
> >          will be called "rtc-snvs".
> >
> > +config RTC_DRV_IMX_RPMSG
> > +     tristate "NXP RPMSG RTC support"
> > +     select RPMSG_VIRTIO
> > +     depends on ARCH_MXC || COMPILE_TEST
> > +     depends on IMX_REMOTEPROC
> > +     depends on OF
> > +     help
> > +        If you say yes here you get support for the NXP RPMSG
> > +        RTC module.
> > +
> >  config RTC_DRV_IMX_SC
> >       depends on IMX_SCU
> >       depends on HAVE_ARM_SMCCC
> > diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> > index 2dd0dd956b0e..9cebfddcc245 100644
> > --- a/drivers/rtc/Makefile
> > +++ b/drivers/rtc/Makefile
> > @@ -72,6 +72,7 @@ obj-$(CONFIG_RTC_DRV_GOLDFISH)      += rtc-goldfish.o
> >  obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o
> >  obj-$(CONFIG_RTC_DRV_HYM8563)        += rtc-hym8563.o
> >  obj-$(CONFIG_RTC_DRV_IMXDI)  += rtc-imxdi.o
> > +obj-$(CONFIG_RTC_DRV_IMX_RPMSG)      += rtc-imx-rpmsg.o
> >  obj-$(CONFIG_RTC_DRV_IMX_SC) += rtc-imx-sc.o
> >  obj-$(CONFIG_RTC_DRV_ISL12022)       += rtc-isl12022.o
> >  obj-$(CONFIG_RTC_DRV_ISL12026)       += rtc-isl12026.o
> > diff --git a/drivers/rtc/rtc-imx-rpmsg.c b/drivers/rtc/rtc-imx-rpmsg.c
> > new file mode 100644
> > index 000000000000..0d6d4b18159e
> > --- /dev/null
> > +++ b/drivers/rtc/rtc-imx-rpmsg.c
> > @@ -0,0 +1,301 @@
> > +// SPDX-License-Identifier: GPL-2.0-only
> > +/*
> > + * Copyright 2017-2021 NXP
> > + */
> > +
> > +#include <linux/firmware/imx/rpmsg.h>
> > +#include <linux/init.h>
> > +#include <linux/io.h>
> > +#include <linux/kernel.h>
> > +#include <linux/module.h>
> > +#include <linux/of.h>
> > +#include <linux/pm_qos.h>
> > +#include <linux/rpmsg.h>
> > +#include <linux/rtc.h>
> > +
> > +#define RPMSG_TIMEOUT 1000
> > +
> > +#define RTC_RPMSG_SEND               0x0
> > +#define RTC_RPMSG_RECEIVE    0x1
> > +#define RTC_RPMSG_NOTIFY     0x2
> > +
> > +enum rtc_rpmsg_cmd {
> > +     RTC_RPMSG_SET_TIME,
> > +     RTC_RPMSG_GET_TIME,
> > +     RTC_RPMSG_SET_ALARM,
> > +     RTC_RPMSG_GET_ALARM,
> > +     RTC_RPMSG_ENABLE_ALARM,
> > +};
> > +
> > +struct rtc_rpmsg_data {
> > +     struct imx_rpmsg_head header;
> > +     u8 reserved0;
> > +     union {
> > +             u8 reserved1;
> > +             u8 ret;
> > +     };
> > +     union {
> > +             u32 reserved2;
> > +             u32 sec;
> > +     };
> > +     union {
> > +             u8 enable;
> > +             u8 reserved3;
> > +     };
> > +     union {
> > +             u8 pending;
> > +             u8 reserved4;
> > +     };
> > +} __packed;
> > +
> > +struct rtc_rpmsg_info {
> > +     struct rpmsg_device *rpdev;
> > +     struct rtc_rpmsg_data *msg;
> > +     struct pm_qos_request pm_qos_req;
> > +     struct completion cmd_complete;
> > +     struct mutex lock;
> > +     struct rtc_device *rtc;
> > +};
> > +
> > +static int rtc_send_message(struct rtc_rpmsg_info *info,
> > +                         struct rtc_rpmsg_data *msg, bool ack)
> > +{
> > +     struct device *dev = &info->rpdev->dev;
> > +     int err;
> > +
> > +     mutex_lock(&info->lock);
> > +
> > +     cpu_latency_qos_add_request(&info->pm_qos_req, 0);
> > +     reinit_completion(&info->cmd_complete);
> > +
> > +     err = rpmsg_send(info->rpdev->ept, (void *)msg, sizeof(*msg));
> > +     if (err) {
> > +             dev_err(dev, "rpmsg send failed: %d\n", err);
> > +             goto err_out;
> > +     }
> > +
> > +     if (ack) {
> > +             err = wait_for_completion_timeout(&info->cmd_complete,
> > +                                               msecs_to_jiffies(RPMSG_TIMEOUT));
> > +             if (!err) {
> > +                     dev_err(dev, "rpmsg send timeout\n");
> > +                     err = -ETIMEDOUT;
> > +                     goto err_out;
> > +             }
> > +
> > +             if (info->msg->ret != 0) {
> > +                     dev_err(dev, "rpmsg not ack %d\n", info->msg->ret);
> > +                     err = -EINVAL;
> > +                     goto err_out;
> > +             }
> > +
> > +             err = 0;
> > +     }
> > +
> > +err_out:
> > +     cpu_latency_qos_remove_request(&info->pm_qos_req);
> > +     mutex_unlock(&info->lock);
> > +
> > +     return err;
> > +}
> > +
> > +static int imx_rpmsg_rtc_read_time(struct device *dev, struct rtc_time *tm)
> > +{
> > +     struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
> > +     struct rtc_rpmsg_data msg;
> > +     int ret;
> > +
> > +     msg.header.cate = IMX_RPMSG_RTC;
> > +     msg.header.major = IMX_RMPSG_MAJOR;
> > +     msg.header.minor = IMX_RMPSG_MINOR;
> > +     msg.header.type = RTC_RPMSG_SEND;
> > +     msg.header.cmd = RTC_RPMSG_GET_TIME;
> > +
> > +     ret = rtc_send_message(rtc_rpmsg, &msg, true);
> > +     if (ret)
> > +             return ret;
> > +
> > +     rtc_time64_to_tm(rtc_rpmsg->msg->sec, tm);
> > +
> > +     return 0;
> > +}
> > +
> > +static int imx_rpmsg_rtc_set_time(struct device *dev, struct rtc_time *tm)
> > +{
> > +     struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
> > +     struct rtc_rpmsg_data msg;
> > +     unsigned long time;
> > +     int ret;
> > +
> > +     time = rtc_tm_to_time64(tm);
> > +
> > +     msg.header.cate = IMX_RPMSG_RTC;
> > +     msg.header.major = IMX_RMPSG_MAJOR;
> > +     msg.header.minor = IMX_RMPSG_MINOR;
> > +     msg.header.type = RTC_RPMSG_SEND;
> > +     msg.header.cmd = RTC_RPMSG_SET_TIME;
> > +     msg.sec = time;
> > +
> > +     ret = rtc_send_message(rtc_rpmsg, &msg, true);
> > +     if (ret)
> > +             return ret;
> > +
> > +     return 0;
> > +}
> > +
> > +static int imx_rpmsg_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> > +{
> > +     struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
> > +     struct rtc_rpmsg_data msg;
> > +     int ret;
> > +
> > +     msg.header.cate = IMX_RPMSG_RTC;
> > +     msg.header.major = IMX_RMPSG_MAJOR;
> > +     msg.header.minor = IMX_RMPSG_MINOR;
> > +     msg.header.type = RTC_RPMSG_SEND;
> > +     msg.header.cmd = RTC_RPMSG_GET_ALARM;
> > +
> > +     ret = rtc_send_message(rtc_rpmsg, &msg, true);
> > +     if (ret)
> > +             return ret;
> > +
> > +     rtc_time64_to_tm(rtc_rpmsg->msg->sec, &alrm->time);
> > +     alrm->pending = rtc_rpmsg->msg->pending;
> > +
> > +     return 0;
> > +}
> > +
> > +static int imx_rpmsg_rtc_alarm_irq_enable(struct device *dev,
> > +     unsigned int enable)
> > +{
> > +     struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
> > +     struct rtc_rpmsg_data msg;
> > +     int ret;
> > +
> > +     msg.header.cate = IMX_RPMSG_RTC;
> > +     msg.header.major = IMX_RMPSG_MAJOR;
> > +     msg.header.minor = IMX_RMPSG_MINOR;
> > +     msg.header.type = RTC_RPMSG_SEND;
> > +     msg.header.cmd = RTC_RPMSG_ENABLE_ALARM;
> > +     msg.enable = enable;
> > +
> > +     ret = rtc_send_message(rtc_rpmsg, &msg, true);
> > +     if (ret)
> > +             return ret;
> > +
> > +     return 0;
> > +}
> > +
> > +static int imx_rpmsg_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> > +{
> > +     struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
> > +     struct rtc_rpmsg_data msg;
> > +     unsigned long time;
> > +     int ret;
> > +
> > +     time = rtc_tm_to_time64(&alrm->time);
> > +
> > +     msg.header.cate = IMX_RPMSG_RTC;
> > +     msg.header.major = IMX_RMPSG_MAJOR;
> > +     msg.header.minor = IMX_RMPSG_MINOR;
> > +     msg.header.type = RTC_RPMSG_SEND;
> > +     msg.header.cmd = RTC_RPMSG_SET_ALARM;
> > +     msg.sec = time;
> > +     msg.enable = alrm->enabled;
> > +
> > +     ret = rtc_send_message(rtc_rpmsg, &msg, true);
> > +     if (ret)
> > +             return ret;
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct rtc_class_ops imx_rpmsg_rtc_ops = {
> > +     .read_time = imx_rpmsg_rtc_read_time,
> > +     .set_time = imx_rpmsg_rtc_set_time,
> > +     .read_alarm = imx_rpmsg_rtc_read_alarm,
> > +     .set_alarm = imx_rpmsg_rtc_set_alarm,
> > +     .alarm_irq_enable = imx_rpmsg_rtc_alarm_irq_enable,
> > +};
> > +
> > +static int rtc_rpmsg_probe(struct rpmsg_device *rpdev)
> > +{
> > +     struct device *dev = &rpdev->dev;
> > +     struct rtc_rpmsg_info *rtc_rpmsg;
> > +
> > +     dev_info(dev, "new channel: 0x%x -> 0x%x\n", rpdev->src, rpdev->dst);
> > +
> > +     rtc_rpmsg = devm_kzalloc(dev, sizeof(*rtc_rpmsg), GFP_KERNEL);
> > +     if (!rtc_rpmsg)
> > +             return -ENOMEM;
> > +
> > +     rtc_rpmsg->rpdev = rpdev;
> > +     mutex_init(&rtc_rpmsg->lock);
> > +     init_completion(&rtc_rpmsg->cmd_complete);
> > +
> > +     dev_set_drvdata(dev, rtc_rpmsg);
> > +
> > +     device_init_wakeup(dev, true);
> > +
> > +     rtc_rpmsg->rtc = devm_rtc_device_register(dev, "rtc-rpmsg",
> > +                                               &imx_rpmsg_rtc_ops,
> > +                                               THIS_MODULE);
> > +     if (IS_ERR(rtc_rpmsg->rtc)) {
> > +             dev_err(dev, "failed to register rtc rpmsg: %ld\n", PTR_ERR(rtc_rpmsg->rtc));
> > +             return PTR_ERR(rtc_rpmsg->rtc);
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static void rtc_rpmsg_remove(struct rpmsg_device *rpdev)
> > +{
> > +     dev_info(&rpdev->dev, "rtc rpmsg driver is removed\n");
> > +}
> > +
> > +static int rtc_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
> > +                     void *priv, u32 src)
> > +{
> > +     struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(&rpdev->dev);
> > +     struct rtc_rpmsg_data *msg = (struct rtc_rpmsg_data *)data;
> > +
> > +     rtc_rpmsg->msg = msg;
> > +
> > +     if (msg->header.type == RTC_RPMSG_RECEIVE)
> > +             complete(&rtc_rpmsg->cmd_complete);
> > +     else if (msg->header.type == RTC_RPMSG_NOTIFY)
> > +             rtc_update_irq(rtc_rpmsg->rtc, 1, RTC_IRQF);
> > +     else
> > +             dev_err(&rpdev->dev, "wrong command type!\n");
> > +
> > +     return 0;
> > +}
> > +
> > +static const struct rpmsg_device_id rtc_rpmsg_id_table[] = {
> > +     { .name = "rpmsg-rtc-channel" },
> > +     { },
> > +};
> > +
> > +static struct rpmsg_driver rtc_rpmsg_driver = {
> > +     .drv.name       = "imx_rtc_rpmsg",
> > +     .probe          = rtc_rpmsg_probe,
> > +     .remove         = rtc_rpmsg_remove,
> > +     .callback       = rtc_rpmsg_cb,
> > +     .id_table       = rtc_rpmsg_id_table,
> > +};
> > +
> > +/*
> > + * imx m4 has a limitation that we can't read data during ns process.
> > + * So register rtc a little bit late as rtc core will read data during
> > + * register process
> > + */
> > +static int __init rtc_rpmsg_init(void)
> > +{
> > +     return register_rpmsg_driver(&rtc_rpmsg_driver);
> > +}
> > +late_initcall(rtc_rpmsg_init);
> > +
> > +MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");
> > +MODULE_DESCRIPTION("NXP i.MX RPMSG RTC Driver");
> > +MODULE_ALIAS("platform:imx_rtc_rpmsg");
> > +MODULE_LICENSE("GPL");
> > diff --git a/include/linux/firmware/imx/rpmsg.h b/include/linux/firmware/imx/rpmsg.h
> > new file mode 100644
> > index 000000000000..20bcce23c917
> > --- /dev/null
> > +++ b/include/linux/firmware/imx/rpmsg.h
> > @@ -0,0 +1,37 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +/*
> > + * Copyright (C) 2019-2021 NXP.
> > + */
> > +
> > +#ifndef __LINUX_IMX_RPMSG_H__
> > +#define __LINUX_IMX_RPMSG_H__
> > +
> > +#include <linux/types.h>
> > +
> > +/*
> > + * Global header file for iMX RPMSG
> > + */
> > +
> > +/* Category define */
> > +#define IMX_RMPSG_LIFECYCLE     1
> > +#define IMX_RPMSG_PMIC          2
> > +#define IMX_RPMSG_AUDIO         3
> > +#define IMX_RPMSG_KEY           4
> > +#define IMX_RPMSG_GPIO          5
> > +#define IMX_RPMSG_RTC           6
> > +#define IMX_RPMSG_SENSOR        7
> > +
> > +/* rpmsg version */
> > +#define IMX_RMPSG_MAJOR         1
> > +#define IMX_RMPSG_MINOR         0
> > +
> > +struct imx_rpmsg_head {
> > +     u8 cate;
> > +     u8 major;
> > +     u8 minor;
> > +     u8 type;
> > +     u8 cmd;
> > +     u8 reserved[5];
> > +} __packed;
> > +
> > +#endif /* __LINUX_IMX_RPMSG_H__ */
> > --
> > 2.25.1
> >
>
> --
> Alexandre Belloni, co-owner and COO, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] rtc: imx-rpmsg: Add i.MX RPMSG RTC support
  2021-08-05  3:35 ` [PATCH 2/2] rtc: imx-rpmsg: Add i.MX RPMSG RTC support Dong Aisheng
  2021-08-05  8:13   ` Alexandre Belloni
@ 2021-09-25 21:53   ` Alexandre Belloni
  1 sibling, 0 replies; 6+ messages in thread
From: Alexandre Belloni @ 2021-09-25 21:53 UTC (permalink / raw)
  To: Dong Aisheng
  Cc: linux-arm-kernel, linux-rtc, devicetree, linux-imx, kernel,
	dongas86, robh+dt, shawnguo, peng.fan, Alessandro Zummo

Hello,

On 05/08/2021 11:35:46+0800, Dong Aisheng wrote:
> +static int rtc_send_message(struct rtc_rpmsg_info *info,
> +			    struct rtc_rpmsg_data *msg, bool ack)
> +{
> +	struct device *dev = &info->rpdev->dev;
> +	int err;
> +
> +	mutex_lock(&info->lock);
> +
> +	cpu_latency_qos_add_request(&info->pm_qos_req, 0);
> +	reinit_completion(&info->cmd_complete);
> +
> +	err = rpmsg_send(info->rpdev->ept, (void *)msg, sizeof(*msg));
> +	if (err) {
> +		dev_err(dev, "rpmsg send failed: %d\n", err);
> +		goto err_out;
> +	}
> +
> +	if (ack) {
> +		err = wait_for_completion_timeout(&info->cmd_complete,
> +						  msecs_to_jiffies(RPMSG_TIMEOUT));
> +		if (!err) {
> +			dev_err(dev, "rpmsg send timeout\n");
> +			err = -ETIMEDOUT;
> +			goto err_out;
> +		}
> +
> +		if (info->msg->ret != 0) {
> +			dev_err(dev, "rpmsg not ack %d\n", info->msg->ret);

This is very verbose and I guess nobody will ever read those, maybe use
dev_dbg?

> +			err = -EINVAL;
> +			goto err_out;
> +		}
> +
> +		err = 0;
> +	}
> +
> +err_out:
> +	cpu_latency_qos_remove_request(&info->pm_qos_req);
> +	mutex_unlock(&info->lock);
> +
> +	return err;
> +}
> +
> +static int imx_rpmsg_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
> +	struct rtc_rpmsg_data msg;
> +	int ret;
> +
> +	msg.header.cate = IMX_RPMSG_RTC;
> +	msg.header.major = IMX_RMPSG_MAJOR;
> +	msg.header.minor = IMX_RMPSG_MINOR;
> +	msg.header.type = RTC_RPMSG_SEND;
> +	msg.header.cmd = RTC_RPMSG_GET_TIME;
> +
> +	ret = rtc_send_message(rtc_rpmsg, &msg, true);
> +	if (ret)
> +		return ret;
> +

Is there a way to know when the time is invalid (e.g. it has not been
set yet)?

> +	rtc_time64_to_tm(rtc_rpmsg->msg->sec, tm);
> +
> +	return 0;
> +}
> +
> +static int imx_rpmsg_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
> +	struct rtc_rpmsg_data msg;
> +	unsigned long time;
> +	int ret;
> +
> +	time = rtc_tm_to_time64(tm);
> +
> +	msg.header.cate = IMX_RPMSG_RTC;
> +	msg.header.major = IMX_RMPSG_MAJOR;
> +	msg.header.minor = IMX_RMPSG_MINOR;
> +	msg.header.type = RTC_RPMSG_SEND;
> +	msg.header.cmd = RTC_RPMSG_SET_TIME;
> +	msg.sec = time;
> +
> +	ret = rtc_send_message(rtc_rpmsg, &msg, true);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int imx_rpmsg_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
> +	struct rtc_rpmsg_data msg;
> +	int ret;
> +
> +	msg.header.cate = IMX_RPMSG_RTC;
> +	msg.header.major = IMX_RMPSG_MAJOR;
> +	msg.header.minor = IMX_RMPSG_MINOR;
> +	msg.header.type = RTC_RPMSG_SEND;
> +	msg.header.cmd = RTC_RPMSG_GET_ALARM;
> +
> +	ret = rtc_send_message(rtc_rpmsg, &msg, true);
> +	if (ret)
> +		return ret;
> +
> +	rtc_time64_to_tm(rtc_rpmsg->msg->sec, &alrm->time);
> +	alrm->pending = rtc_rpmsg->msg->pending;
> +
> +	return 0;
> +}
> +
> +static int imx_rpmsg_rtc_alarm_irq_enable(struct device *dev,
> +	unsigned int enable)
> +{
> +	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
> +	struct rtc_rpmsg_data msg;
> +	int ret;
> +
> +	msg.header.cate = IMX_RPMSG_RTC;
> +	msg.header.major = IMX_RMPSG_MAJOR;
> +	msg.header.minor = IMX_RMPSG_MINOR;
> +	msg.header.type = RTC_RPMSG_SEND;
> +	msg.header.cmd = RTC_RPMSG_ENABLE_ALARM;
> +	msg.enable = enable;
> +
> +	ret = rtc_send_message(rtc_rpmsg, &msg, true);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static int imx_rpmsg_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(dev);
> +	struct rtc_rpmsg_data msg;
> +	unsigned long time;
> +	int ret;
> +
> +	time = rtc_tm_to_time64(&alrm->time);
> +
> +	msg.header.cate = IMX_RPMSG_RTC;
> +	msg.header.major = IMX_RMPSG_MAJOR;
> +	msg.header.minor = IMX_RMPSG_MINOR;
> +	msg.header.type = RTC_RPMSG_SEND;
> +	msg.header.cmd = RTC_RPMSG_SET_ALARM;
> +	msg.sec = time;
> +	msg.enable = alrm->enabled;
> +
> +	ret = rtc_send_message(rtc_rpmsg, &msg, true);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
> +static const struct rtc_class_ops imx_rpmsg_rtc_ops = {
> +	.read_time = imx_rpmsg_rtc_read_time,
> +	.set_time = imx_rpmsg_rtc_set_time,
> +	.read_alarm = imx_rpmsg_rtc_read_alarm,
> +	.set_alarm = imx_rpmsg_rtc_set_alarm,
> +	.alarm_irq_enable = imx_rpmsg_rtc_alarm_irq_enable,
> +};
> +
> +static int rtc_rpmsg_probe(struct rpmsg_device *rpdev)
> +{
> +	struct device *dev = &rpdev->dev;
> +	struct rtc_rpmsg_info *rtc_rpmsg;
> +
> +	dev_info(dev, "new channel: 0x%x -> 0x%x\n", rpdev->src, rpdev->dst);
> +

Same comment, please try to cut down on the number of strings in the
driver, your customers will thank you.

> +	rtc_rpmsg = devm_kzalloc(dev, sizeof(*rtc_rpmsg), GFP_KERNEL);
> +	if (!rtc_rpmsg)
> +		return -ENOMEM;
> +
> +	rtc_rpmsg->rpdev = rpdev;
> +	mutex_init(&rtc_rpmsg->lock);
> +	init_completion(&rtc_rpmsg->cmd_complete);
> +
> +	dev_set_drvdata(dev, rtc_rpmsg);
> +
> +	device_init_wakeup(dev, true);
> +
> +	rtc_rpmsg->rtc = devm_rtc_device_register(dev, "rtc-rpmsg",
> +						  &imx_rpmsg_rtc_ops,
> +						  THIS_MODULE);
> +	if (IS_ERR(rtc_rpmsg->rtc)) {
> +		dev_err(dev, "failed to register rtc rpmsg: %ld\n", PTR_ERR(rtc_rpmsg->rtc));
> +		return PTR_ERR(rtc_rpmsg->rtc);
> +	}

Please use devm_rtc_allocate_device/devm_rtc_register_device. Also, it
would be nice to set .range_min and .range_max if you actually know what
the underlying RTC supports.

> +
> +	return 0;
> +}
> +
> +static void rtc_rpmsg_remove(struct rpmsg_device *rpdev)
> +{
> +	dev_info(&rpdev->dev, "rtc rpmsg driver is removed\n");

Seriously, drop this function...

> +}
> +
> +static int rtc_rpmsg_cb(struct rpmsg_device *rpdev, void *data, int len,
> +			void *priv, u32 src)
> +{
> +	struct rtc_rpmsg_info *rtc_rpmsg = dev_get_drvdata(&rpdev->dev);
> +	struct rtc_rpmsg_data *msg = (struct rtc_rpmsg_data *)data;
> +
> +	rtc_rpmsg->msg = msg;
> +
> +	if (msg->header.type == RTC_RPMSG_RECEIVE)
> +		complete(&rtc_rpmsg->cmd_complete);
> +	else if (msg->header.type == RTC_RPMSG_NOTIFY)
> +		rtc_update_irq(rtc_rpmsg->rtc, 1, RTC_IRQF);
> +	else
> +		dev_err(&rpdev->dev, "wrong command type!\n");
> +
> +	return 0;
> +}
> +
> +static const struct rpmsg_device_id rtc_rpmsg_id_table[] = {
> +	{ .name	= "rpmsg-rtc-channel" },
> +	{ },
> +};
> +
> +static struct rpmsg_driver rtc_rpmsg_driver = {
> +	.drv.name	= "imx_rtc_rpmsg",
> +	.probe		= rtc_rpmsg_probe,
> +	.remove		= rtc_rpmsg_remove,
> +	.callback	= rtc_rpmsg_cb,
> +	.id_table	= rtc_rpmsg_id_table,
> +};
> +
> +/*
> + * imx m4 has a limitation that we can't read data during ns process.
> + * So register rtc a little bit late as rtc core will read data during
> + * register process
> + */
> +static int __init rtc_rpmsg_init(void)
> +{
> +	return register_rpmsg_driver(&rtc_rpmsg_driver);
> +}
> +late_initcall(rtc_rpmsg_init);
> +
> +MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");
> +MODULE_DESCRIPTION("NXP i.MX RPMSG RTC Driver");
> +MODULE_ALIAS("platform:imx_rtc_rpmsg");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/firmware/imx/rpmsg.h b/include/linux/firmware/imx/rpmsg.h
> new file mode 100644
> index 000000000000..20bcce23c917
> --- /dev/null
> +++ b/include/linux/firmware/imx/rpmsg.h
> @@ -0,0 +1,37 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2019-2021 NXP.
> + */
> +
> +#ifndef __LINUX_IMX_RPMSG_H__
> +#define __LINUX_IMX_RPMSG_H__
> +
> +#include <linux/types.h>
> +
> +/*
> + * Global header file for iMX RPMSG
> + */
> +
> +/* Category define */
> +#define IMX_RMPSG_LIFECYCLE     1
> +#define IMX_RPMSG_PMIC          2
> +#define IMX_RPMSG_AUDIO         3
> +#define IMX_RPMSG_KEY           4
> +#define IMX_RPMSG_GPIO          5
> +#define IMX_RPMSG_RTC           6
> +#define IMX_RPMSG_SENSOR        7
> +
> +/* rpmsg version */
> +#define IMX_RMPSG_MAJOR         1
> +#define IMX_RMPSG_MINOR         0
> +
> +struct imx_rpmsg_head {
> +	u8 cate;
> +	u8 major;
> +	u8 minor;
> +	u8 type;
> +	u8 cmd;
> +	u8 reserved[5];
> +} __packed;
> +
> +#endif /* __LINUX_IMX_RPMSG_H__ */
> -- 
> 2.25.1
> 

-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-09-25 21:53 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-05  3:35 [PATCH 0/2] rtc: add imx rpmsg rtc support Dong Aisheng
2021-08-05  3:35 ` [PATCH 1/2] ARM: dts: imx7ulp: add cm4 support Dong Aisheng
2021-08-05  3:35 ` [PATCH 2/2] rtc: imx-rpmsg: Add i.MX RPMSG RTC support Dong Aisheng
2021-08-05  8:13   ` Alexandre Belloni
2021-08-05  8:48     ` Dong Aisheng
2021-09-25 21:53   ` Alexandre Belloni

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).