diff mbox series

rtc: sun6i: Add NVMEM provider

Message ID 20210419014549.26900-1-samuel@sholland.org (mailing list archive)
State New
Headers show
Series rtc: sun6i: Add NVMEM provider | expand

Commit Message

Samuel Holland April 19, 2021, 1:45 a.m. UTC
The sun6i RTC provides 32 bytes of general-purpose data registers.
They can be used to save data in the always-on RTC power domain.
The registers are writable via 32-bit MMIO accesses only.

Expose the region as a NVMEM provider so it can be used by userspace and
other drivers.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 drivers/rtc/rtc-sun6i.c | 42 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

Comments

Maxime Ripard April 30, 2021, 9:02 a.m. UTC | #1
Hi,

On Sun, Apr 18, 2021 at 08:45:49PM -0500, Samuel Holland wrote:
> The sun6i RTC provides 32 bytes of general-purpose data registers.
> They can be used to save data in the always-on RTC power domain.
> The registers are writable via 32-bit MMIO accesses only.
> 
> Expose the region as a NVMEM provider so it can be used by userspace and
> other drivers.
> 
> Signed-off-by: Samuel Holland <samuel@sholland.org>

As far as I understood, you want to use those registers to implement
super-standby? If so, while it makes sense for the kernel to be able to
be able to write to those registers, I guess it would be a bit unwise to
allow the userspace to access it?

Maxime
Alexandre Belloni May 4, 2021, 3:33 p.m. UTC | #2
On 30/04/2021 11:02:06+0200, Maxime Ripard wrote:
> Hi,
> 
> On Sun, Apr 18, 2021 at 08:45:49PM -0500, Samuel Holland wrote:
> > The sun6i RTC provides 32 bytes of general-purpose data registers.
> > They can be used to save data in the always-on RTC power domain.
> > The registers are writable via 32-bit MMIO accesses only.
> > 
> > Expose the region as a NVMEM provider so it can be used by userspace and
> > other drivers.
> > 
> > Signed-off-by: Samuel Holland <samuel@sholland.org>
> 
> As far as I understood, you want to use those registers to implement
> super-standby? If so, while it makes sense for the kernel to be able to
> be able to write to those registers, I guess it would be a bit unwise to
> allow the userspace to access it?

I would think nvmem is still the proper subsystem. I guess maybe we
should have a version of __nvmem_device_get that would ensure exclusive
access to a cell, thus preventing userspace accessing it as long a the
kernel is using it.
Samuel Holland May 10, 2021, 3:39 a.m. UTC | #3
On 4/30/21 4:02 AM, Maxime Ripard wrote:
> Hi,
> 
> On Sun, Apr 18, 2021 at 08:45:49PM -0500, Samuel Holland wrote:
>> The sun6i RTC provides 32 bytes of general-purpose data registers.
>> They can be used to save data in the always-on RTC power domain.
>> The registers are writable via 32-bit MMIO accesses only.
>>
>> Expose the region as a NVMEM provider so it can be used by userspace and
>> other drivers.
>>
>> Signed-off-by: Samuel Holland <samuel@sholland.org>
> 
> As far as I understood, you want to use those registers to implement
> super-standby? If so, while it makes sense for the kernel to be able to
> be able to write to those registers, I guess it would be a bit unwise to
> allow the userspace to access it?

I want the user to be able to pass information to the bootloader (to
select a boot device, e.g. reboot to FEL). I also want the user to be
able to read data stored to these registers by system firmware (e.g.
crust writes exception information there). It's not really related to
standby.

I would want to stack a nvmem-reboot-mode on top to give friendlier
names to some of the numbers, but I don't see a problem with root having
direct access to the registers. It's no different from /dev/nvram
providing access to the PC CMOS RAM.

Regards,
Samuel
Alexandre Belloni May 10, 2021, 8 a.m. UTC | #4
On 09/05/2021 22:39:30-0500, Samuel Holland wrote:
> On 4/30/21 4:02 AM, Maxime Ripard wrote:
> > Hi,
> > 
> > On Sun, Apr 18, 2021 at 08:45:49PM -0500, Samuel Holland wrote:
> >> The sun6i RTC provides 32 bytes of general-purpose data registers.
> >> They can be used to save data in the always-on RTC power domain.
> >> The registers are writable via 32-bit MMIO accesses only.
> >>
> >> Expose the region as a NVMEM provider so it can be used by userspace and
> >> other drivers.
> >>
> >> Signed-off-by: Samuel Holland <samuel@sholland.org>
> > 
> > As far as I understood, you want to use those registers to implement
> > super-standby? If so, while it makes sense for the kernel to be able to
> > be able to write to those registers, I guess it would be a bit unwise to
> > allow the userspace to access it?
> 
> I want the user to be able to pass information to the bootloader (to
> select a boot device, e.g. reboot to FEL). I also want the user to be
> able to read data stored to these registers by system firmware (e.g.
> crust writes exception information there). It's not really related to
> standby.
> 
> I would want to stack a nvmem-reboot-mode on top to give friendlier
> names to some of the numbers, but I don't see a problem with root having
> direct access to the registers. It's no different from /dev/nvram
> providing access to the PC CMOS RAM.
> 

(which is deprecated in favor of nvmem)
diff mbox series

Patch

diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c
index e75020ab8024..f4a5e7465148 100644
--- a/drivers/rtc/rtc-sun6i.c
+++ b/drivers/rtc/rtc-sun6i.c
@@ -69,6 +69,10 @@ 
 #define SUN6I_LOSC_OUT_GATING			0x0060
 #define SUN6I_LOSC_OUT_GATING_EN_OFFSET		0
 
+/* General-purpose data */
+#define SUN6I_GP_DATA				0x0100
+#define SUN6I_GP_DATA_SIZE			0x20
+
 /*
  * Get date values
  */
@@ -641,6 +645,39 @@  static const struct rtc_class_ops sun6i_rtc_ops = {
 	.alarm_irq_enable	= sun6i_rtc_alarm_irq_enable
 };
 
+static int sun6i_rtc_nvmem_read(void *priv, unsigned int offset, void *_val, size_t bytes)
+{
+	struct sun6i_rtc_dev *chip = priv;
+	u32 *val = _val;
+	int i;
+
+	for (i = 0; i < bytes / 4; ++i)
+		val[i] = readl(chip->base + SUN6I_GP_DATA + offset + 4 * i);
+
+	return 0;
+}
+
+static int sun6i_rtc_nvmem_write(void *priv, unsigned int offset, void *_val, size_t bytes)
+{
+	struct sun6i_rtc_dev *chip = priv;
+	u32 *val = _val;
+	int i;
+
+	for (i = 0; i < bytes / 4; ++i)
+		writel(val[i], chip->base + SUN6I_GP_DATA + offset + 4 * i);
+
+	return 0;
+}
+
+static struct nvmem_config sun6i_rtc_nvmem_cfg = {
+	.type		= NVMEM_TYPE_BATTERY_BACKED,
+	.reg_read	= sun6i_rtc_nvmem_read,
+	.reg_write	= sun6i_rtc_nvmem_write,
+	.size		= SUN6I_GP_DATA_SIZE,
+	.word_size	= 4,
+	.stride		= 4,
+};
+
 /* Enable IRQ wake on suspend, to wake up from RTC. */
 static int sun6i_rtc_suspend(struct device *dev)
 {
@@ -728,6 +765,11 @@  static int sun6i_rtc_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	sun6i_rtc_nvmem_cfg.priv = chip;
+	ret = devm_rtc_nvmem_register(chip->rtc, &sun6i_rtc_nvmem_cfg);
+	if (ret)
+		return ret;
+
 	dev_info(&pdev->dev, "RTC enabled\n");
 
 	return 0;