Commit f3e69db2 authored by Arnd Bergmann's avatar Arnd Bergmann
Browse files

Merge tag 'amlogic-drivers' of...

Merge tag 'amlogic-drivers' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic into next/drivers

Pull "Amlogic drivers for v4.15" from Kevin Hilman:

- add SoC info driver for 32-bit Amlogic SoCs

* tag 'amlogic-drivers' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic:
  soc: amlogic: Add Meson6/Meson8/Meson8b/Meson8m2 SoC Information driver
parents ae1d77fc 5e68c0fc
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -9,4 +9,14 @@ config MESON_GX_SOCINFO
	  Say yes to support decoding of Amlogic Meson GX SoC family
	  Say yes to support decoding of Amlogic Meson GX SoC family
	  information about the type, package and version.
	  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
endmenu
+1 −0
Original line number Original line Diff line number Diff line
obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o
obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o
obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o
+175 −0
Original line number Original line Diff line number Diff line
/*
 * 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);