]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
soc: amlogic: Add Meson6/Meson8/Meson8b/Meson8m2 SoC Information driver
authorMartin Blumenstingl <martin.blumenstingl@googlemail.com>
Sat, 23 Sep 2017 14:14:02 +0000 (16:14 +0200)
committerKevin Hilman <khilman@baylibre.com>
Fri, 6 Oct 2017 22:36:17 +0000 (15:36 -0700)
Amlogic SoCs have an information register which contains the SoC type
and revision information.
This patchs adds support for decoding those registers and exposing the
resulting information via the SoC bus infrastructure.

Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Signed-off-by: Kevin Hilman <khilman@baylibre.com>
drivers/soc/amlogic/Kconfig
drivers/soc/amlogic/Makefile
drivers/soc/amlogic/meson-mx-socinfo.c [new file with mode: 0644]

index 22acf064531ff4f2f48146b3a49187ef614e77ea..ef0b8f6c53e0f449ef4c0c6faf96a8e0cf8cadc3 100644 (file)
@@ -9,4 +9,14 @@ config MESON_GX_SOCINFO
          Say yes to support decoding of Amlogic Meson GX SoC family
          information about the type, package and version.
 
+config MESON_MX_SOCINFO
+       bool "Amlogic Meson MX SoC Information driver"
+       depends on ARCH_MESON || COMPILE_TEST
+       default ARCH_MESON
+       select SOC_BUS
+       help
+         Say yes to support decoding of Amlogic Meson6, Meson8,
+         Meson8b and Meson8m2 SoC family information about the type
+         and version.
+
 endmenu
index 3e85fc462c2131813f9fdef9512025b4b8fae438..1f5df50ebd73303abd66907af6857623b9087cc7 100644 (file)
@@ -1 +1,2 @@
 obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o
+obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o
diff --git a/drivers/soc/amlogic/meson-mx-socinfo.c b/drivers/soc/amlogic/meson-mx-socinfo.c
new file mode 100644 (file)
index 0000000..7bfff5f
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+#include <linux/bitfield.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#define MESON_SOCINFO_MAJOR_VER_MESON6         0x16
+#define MESON_SOCINFO_MAJOR_VER_MESON8         0x19
+#define MESON_SOCINFO_MAJOR_VER_MESON8B                0x1b
+
+#define MESON_MX_ASSIST_HW_REV                 0x14c
+
+#define MESON_MX_ANALOG_TOP_METAL_REVISION     0x0
+
+#define MESON_MX_BOOTROM_MISC_VER              0x4
+
+static const char *meson_mx_socinfo_revision(unsigned int major_ver,
+                                            unsigned int misc_ver,
+                                            unsigned int metal_rev)
+{
+       unsigned int minor_ver;
+
+       switch (major_ver) {
+       case MESON_SOCINFO_MAJOR_VER_MESON6:
+               minor_ver = 0xa;
+               break;
+
+       case MESON_SOCINFO_MAJOR_VER_MESON8:
+               if (metal_rev == 0x11111112)
+                       major_ver = 0x1d;
+
+               if (metal_rev == 0x11111111 || metal_rev == 0x11111112)
+                       minor_ver = 0xa;
+               else if (metal_rev == 0x11111113)
+                       minor_ver = 0xb;
+               else if (metal_rev == 0x11111133)
+                       minor_ver = 0xc;
+               else
+                       minor_ver = 0xd;
+
+               break;
+
+       case MESON_SOCINFO_MAJOR_VER_MESON8B:
+               if (metal_rev == 0x11111111)
+                       minor_ver = 0xa;
+               else
+                       minor_ver = 0xb;
+
+               break;
+
+       default:
+               minor_ver = 0x0;
+               break;
+       }
+
+       return kasprintf(GFP_KERNEL, "Rev%X (%x - 0:%X)", minor_ver, major_ver,
+                        misc_ver);
+}
+
+static const char *meson_mx_socinfo_soc_id(unsigned int major_ver,
+                                          unsigned int metal_rev)
+{
+       const char *soc_id;
+
+       switch (major_ver) {
+       case MESON_SOCINFO_MAJOR_VER_MESON6:
+               soc_id = "Meson6 (AML8726-MX)";
+               break;
+
+       case MESON_SOCINFO_MAJOR_VER_MESON8:
+               if (metal_rev == 0x11111112)
+                       soc_id = "Meson8m2 (S812)";
+               else
+                       soc_id = "Meson8 (S802)";
+
+               break;
+
+       case MESON_SOCINFO_MAJOR_VER_MESON8B:
+               soc_id = "Meson8b (S805)";
+               break;
+
+       default:
+               soc_id = "Unknown";
+               break;
+       }
+
+       return kstrdup_const(soc_id, GFP_KERNEL);
+}
+
+static const struct of_device_id meson_mx_socinfo_analog_top_ids[] = {
+       { .compatible = "amlogic,meson8-analog-top", },
+       { .compatible = "amlogic,meson8b-analog-top", },
+       { /* sentinel */ }
+};
+
+int __init meson_mx_socinfo_init(void)
+{
+       struct soc_device_attribute *soc_dev_attr;
+       struct soc_device *soc_dev;
+       struct device_node *np;
+       struct regmap *assist_regmap, *bootrom_regmap, *analog_top_regmap;
+       unsigned int major_ver, misc_ver, metal_rev = 0;
+       int ret;
+
+       assist_regmap =
+               syscon_regmap_lookup_by_compatible("amlogic,meson-mx-assist");
+       if (IS_ERR(assist_regmap))
+               return PTR_ERR(assist_regmap);
+
+       bootrom_regmap =
+               syscon_regmap_lookup_by_compatible("amlogic,meson-mx-bootrom");
+       if (IS_ERR(bootrom_regmap))
+               return PTR_ERR(bootrom_regmap);
+
+       np = of_find_matching_node(NULL, meson_mx_socinfo_analog_top_ids);
+       if (np) {
+               analog_top_regmap = syscon_node_to_regmap(np);
+               if (IS_ERR(analog_top_regmap))
+                       return PTR_ERR(analog_top_regmap);
+
+               ret = regmap_read(analog_top_regmap,
+                                 MESON_MX_ANALOG_TOP_METAL_REVISION,
+                                 &metal_rev);
+               if (ret)
+                       return ret;
+       }
+
+       ret = regmap_read(assist_regmap, MESON_MX_ASSIST_HW_REV, &major_ver);
+       if (ret < 0)
+               return ret;
+
+       ret = regmap_read(bootrom_regmap, MESON_MX_BOOTROM_MISC_VER,
+                         &misc_ver);
+       if (ret < 0)
+               return ret;
+
+       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return -ENODEV;
+
+       soc_dev_attr->family = "Amlogic Meson";
+
+       np = of_find_node_by_path("/");
+       of_property_read_string(np, "model", &soc_dev_attr->machine);
+       of_node_put(np);
+
+       soc_dev_attr->revision = meson_mx_socinfo_revision(major_ver, misc_ver,
+                                                          metal_rev);
+       soc_dev_attr->soc_id = meson_mx_socinfo_soc_id(major_ver, metal_rev);
+
+       soc_dev = soc_device_register(soc_dev_attr);
+       if (IS_ERR(soc_dev)) {
+               kfree_const(soc_dev_attr->revision);
+               kfree_const(soc_dev_attr->soc_id);
+               kfree(soc_dev_attr);
+               return PTR_ERR(soc_dev);
+       }
+
+       dev_info(soc_device_to_device(soc_dev), "Amlogic %s %s detected\n",
+                soc_dev_attr->soc_id, soc_dev_attr->revision);
+
+       return 0;
+}
+device_initcall(meson_mx_socinfo_init);