224 lines
6.3 KiB
Diff
Executable File
224 lines
6.3 KiB
Diff
Executable File
From 674e059d34193930cd48df8fe1f2f5bf49c83469 Mon Sep 17 00:00:00 2001
|
|
From: roly <Rolyli.Li@luxshare-ict.com>
|
|
Date: Thu, 9 Jan 2025 08:54:00 +0800
|
|
Subject: [PATCH] soc aspeed abr Add sysfs attrs for flash toggle
|
|
|
|
---
|
|
drivers/spi/spi-aspeed-smc.c | 60 +++++++++++++
|
|
include/linux/soc/aspeed/aspeed-abr.h | 118 ++++++++++++++++++++++++++
|
|
2 files changed, 178 insertions(+)
|
|
create mode 100644 include/linux/soc/aspeed/aspeed-abr.h
|
|
|
|
diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
|
|
index 70c4e6e3e2e8..8a819f8f65ba 100644
|
|
--- a/drivers/spi/spi-aspeed-smc.c
|
|
+++ b/drivers/spi/spi-aspeed-smc.c
|
|
@@ -13,6 +13,7 @@
|
|
#include <linux/platform_device.h>
|
|
#include <linux/spi/spi.h>
|
|
#include <linux/spi/spi-mem.h>
|
|
+#include <linux/soc/aspeed/aspeed-abr.h>
|
|
|
|
#define DEVICE_NAME "spi-aspeed-smc"
|
|
|
|
@@ -110,6 +111,53 @@ struct aspeed_spi {
|
|
u8 *op_buf;
|
|
};
|
|
|
|
+static ssize_t access_primary_show(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ struct aspeed_spi *aspi = dev_get_drvdata(dev);
|
|
+
|
|
+ return _access_primary_show(aspi->regs, attr, buf);
|
|
+}
|
|
+
|
|
+static ssize_t access_primary_store(struct device *dev,
|
|
+ struct device_attribute *attr,
|
|
+ const char *buf, size_t size)
|
|
+{
|
|
+ struct aspeed_spi *aspi = dev_get_drvdata(dev);
|
|
+
|
|
+ return _access_primary_store(aspi->regs, attr, buf, size);
|
|
+}
|
|
+
|
|
+static ssize_t access_backup_show(struct device *dev,
|
|
+ struct device_attribute *attr, char *buf)
|
|
+{
|
|
+ struct aspeed_spi *aspi = dev_get_drvdata(dev);
|
|
+
|
|
+ return _access_backup_show(aspi->regs, attr, buf);
|
|
+}
|
|
+
|
|
+static ssize_t access_backup_store(struct device *dev,
|
|
+ struct device_attribute *attr,
|
|
+ const char *buf, size_t size)
|
|
+{
|
|
+ struct aspeed_spi *aspi = dev_get_drvdata(dev);
|
|
+
|
|
+ return _access_backup_store(aspi->regs, attr, buf, size);
|
|
+}
|
|
+
|
|
+static DEVICE_ATTR_RW(access_primary);
|
|
+static DEVICE_ATTR_RW(access_backup);
|
|
+
|
|
+static struct attribute *bswitch_primary_attrs[] = {
|
|
+ &dev_attr_access_primary.attr, NULL
|
|
+};
|
|
+
|
|
+static struct attribute *bswitch_backup_attrs[] = {
|
|
+ &dev_attr_access_backup.attr, NULL
|
|
+};
|
|
+
|
|
+ATTRIBUTE_GROUPS(bswitch_primary);
|
|
+ATTRIBUTE_GROUPS(bswitch_backup);
|
|
static u32 aspeed_spi_get_io_mode(const struct spi_mem_op *op)
|
|
{
|
|
switch (op->data.buswidth) {
|
|
@@ -908,6 +956,18 @@ static int aspeed_spi_probe(struct platform_device *pdev)
|
|
ctlr->num_chipselect = data->max_cs;
|
|
ctlr->dev.of_node = dev->of_node;
|
|
|
|
+ if (of_device_is_compatible(dev->of_node, "aspeed,ast2600-fmc")) {
|
|
+ /* if boot from alt source, show access_primary, otherwise show access_backup */
|
|
+ if (readl(aspi->regs + OFFSET_ABR_CTRL_STATUS) &
|
|
+ ABR_BOOT_SRC_INDICATE) {
|
|
+ if (devm_device_add_groups(dev, bswitch_primary_groups))
|
|
+ dev_warn(dev, "Could not add access_primary\n");
|
|
+ } else {
|
|
+ if (devm_device_add_groups(dev, bswitch_backup_groups))
|
|
+ dev_warn(dev, "Could not add access_backup\n");
|
|
+ }
|
|
+ }
|
|
+
|
|
ret = devm_spi_register_controller(dev, ctlr);
|
|
if (ret) {
|
|
dev_err(&pdev->dev, "spi_register_controller failed\n");
|
|
diff --git a/include/linux/soc/aspeed/aspeed-abr.h b/include/linux/soc/aspeed/aspeed-abr.h
|
|
new file mode 100644
|
|
index 000000000000..144f43dff1ac
|
|
--- /dev/null
|
|
+++ b/include/linux/soc/aspeed/aspeed-abr.h
|
|
@@ -0,0 +1,118 @@
|
|
+/* SPDX-License-Identifier: GPL-2.0+ */
|
|
+
|
|
+#ifndef __ASPEED_ABR_H__
|
|
+#define __ASPEED_ABR_H__
|
|
+
|
|
+#include <linux/device.h>
|
|
+#include <linux/sysfs.h>
|
|
+#include <linux/io.h>
|
|
+
|
|
+#define OFFSET_ABR_CTRL_STATUS 0x64
|
|
+#define OFFSET_ABR_TIMER_RELOAD 0x68
|
|
+#define OFFSET_ABR_TIMER_RESTART 0x6c
|
|
+
|
|
+#define ABR_WDT_ENABLE BIT(0)
|
|
+#define ABR_BOOT_SRC_INDICATE BIT(4)
|
|
+#define ABR_RESTART_MAGIC 0x4755
|
|
+#define ABR_CLEAR_BOOT_SRC_MAGIC (0xEA << 16)
|
|
+#define ABR_RELOAD_MAX_VALUE 0x1fff
|
|
+
|
|
+static inline ssize_t _access_primary_show(void __iomem *regs,
|
|
+ struct device_attribute *attr,
|
|
+ char *buf)
|
|
+{
|
|
+ u32 status = readl(regs + OFFSET_ABR_CTRL_STATUS);
|
|
+
|
|
+ return sysfs_emit(buf, "%u\n", !(status & ABR_BOOT_SRC_INDICATE));
|
|
+}
|
|
+
|
|
+static inline ssize_t _access_primary_store(void __iomem *regs,
|
|
+ struct device_attribute *attr,
|
|
+ const char *buf, size_t size)
|
|
+{
|
|
+ unsigned long val;
|
|
+
|
|
+ if (kstrtoul(buf, 10, &val))
|
|
+ return -EINVAL;
|
|
+
|
|
+ /* disable watchdog */
|
|
+ if (val == 0) {
|
|
+ writel(0, regs + OFFSET_ABR_CTRL_STATUS);
|
|
+ return size;
|
|
+ }
|
|
+
|
|
+ /* val is the microsecond, convert to reload count(0.1s) */
|
|
+ val /= (100 * 1000);
|
|
+
|
|
+ /*
|
|
+ * bit[12:0] : Reload value of expire time
|
|
+ * The time unit is 0.1 second. Default set at 22 seconds
|
|
+ * 0: Immediately timeout
|
|
+ */
|
|
+ val = val < ABR_RELOAD_MAX_VALUE ? val : ABR_RELOAD_MAX_VALUE;
|
|
+
|
|
+ writel(0, regs + OFFSET_ABR_CTRL_STATUS);
|
|
+ writel(val, regs + OFFSET_ABR_TIMER_RELOAD);
|
|
+
|
|
+ /* Write 0x4755 value to load the reload value into watchdog counter */
|
|
+ writel(ABR_RESTART_MAGIC, regs + OFFSET_ABR_TIMER_RESTART);
|
|
+
|
|
+ /* Enable watchdog */
|
|
+ writel(ABR_WDT_ENABLE, regs + OFFSET_ABR_CTRL_STATUS);
|
|
+ return size;
|
|
+}
|
|
+
|
|
+static inline ssize_t _access_backup_show(void __iomem *regs,
|
|
+ struct device_attribute *attr,
|
|
+ char *buf)
|
|
+{
|
|
+ u32 status = readl(regs + OFFSET_ABR_CTRL_STATUS);
|
|
+ u32 timer_reload = readl(regs + OFFSET_ABR_TIMER_RELOAD);
|
|
+
|
|
+ if (!(status & ABR_WDT_ENABLE))
|
|
+ return sysfs_emit(buf, "%u\n", 0);
|
|
+
|
|
+ /*
|
|
+ * [31:16] Counter value status
|
|
+ * timeout unit is 0.1s, convert to microseconds
|
|
+ */
|
|
+ return sysfs_emit(buf, "%u\n", (timer_reload >> 16) * 100 * 1000);
|
|
+}
|
|
+
|
|
+static inline ssize_t _access_backup_store(void __iomem *regs,
|
|
+ struct device_attribute *attr,
|
|
+ const char *buf, size_t size)
|
|
+{
|
|
+ unsigned long val;
|
|
+
|
|
+ if (kstrtoul(buf, 10, &val))
|
|
+ return -EINVAL;
|
|
+
|
|
+ /* disable watchdog */
|
|
+ if (val == 0) {
|
|
+ writel(0, regs + OFFSET_ABR_CTRL_STATUS);
|
|
+ return size;
|
|
+ }
|
|
+
|
|
+ /* val is the microsecond, convert to reload count(0.1s) */
|
|
+ val /= (100 * 1000);
|
|
+
|
|
+ /*
|
|
+ * bit[12:0] : Reload value of expire time
|
|
+ * The time unit is 0.1 second. Default set at 22 seconds
|
|
+ * 0: Immediately timeout
|
|
+ */
|
|
+ val = val < ABR_RELOAD_MAX_VALUE ? val : ABR_RELOAD_MAX_VALUE;
|
|
+
|
|
+ writel(0, regs + OFFSET_ABR_CTRL_STATUS);
|
|
+ writel(val, regs + OFFSET_ABR_TIMER_RELOAD);
|
|
+
|
|
+ /* Write 0x4755 value to load the reload value into watchdog counter */
|
|
+ writel(ABR_RESTART_MAGIC, regs + OFFSET_ABR_TIMER_RESTART);
|
|
+
|
|
+ /* Enable watchdog */
|
|
+ writel(ABR_WDT_ENABLE, regs + OFFSET_ABR_CTRL_STATUS);
|
|
+ return size;
|
|
+}
|
|
+
|
|
+#endif
|
|
--
|
|
2.25.1
|
|
|