Files
OpenBMC/meta-luxshare/meta-bhs/recipes-kernel/linux/linux-aspeed/0001-soc-aspeed-abr-Add-sysfs-attrs-for-flash-toggle.patch
2026-04-23 17:07:55 +08:00

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