Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soc: amlogic: Add Meson6/Meson8/Meson8b/Meson8m2 SoC Information driver

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>

authored by

Martin Blumenstingl and committed by
Kevin Hilman
5e68c0fc 2bd6bf03

+186
+10
drivers/soc/amlogic/Kconfig
··· 9 9 Say yes to support decoding of Amlogic Meson GX SoC family 10 10 information about the type, package and version. 11 11 12 + config MESON_MX_SOCINFO 13 + bool "Amlogic Meson MX SoC Information driver" 14 + depends on ARCH_MESON || COMPILE_TEST 15 + default ARCH_MESON 16 + select SOC_BUS 17 + help 18 + Say yes to support decoding of Amlogic Meson6, Meson8, 19 + Meson8b and Meson8m2 SoC family information about the type 20 + and version. 21 + 12 22 endmenu
+1
drivers/soc/amlogic/Makefile
··· 1 1 obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o 2 + obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o
+175
drivers/soc/amlogic/meson-mx-socinfo.c
··· 1 + /* 2 + * Copyright (c) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com> 3 + * 4 + * SPDX-License-Identifier: GPL-2.0+ 5 + */ 6 + 7 + #include <linux/io.h> 8 + #include <linux/of.h> 9 + #include <linux/of_address.h> 10 + #include <linux/of_platform.h> 11 + #include <linux/platform_device.h> 12 + #include <linux/slab.h> 13 + #include <linux/sys_soc.h> 14 + #include <linux/bitfield.h> 15 + #include <linux/regmap.h> 16 + #include <linux/mfd/syscon.h> 17 + 18 + #define MESON_SOCINFO_MAJOR_VER_MESON6 0x16 19 + #define MESON_SOCINFO_MAJOR_VER_MESON8 0x19 20 + #define MESON_SOCINFO_MAJOR_VER_MESON8B 0x1b 21 + 22 + #define MESON_MX_ASSIST_HW_REV 0x14c 23 + 24 + #define MESON_MX_ANALOG_TOP_METAL_REVISION 0x0 25 + 26 + #define MESON_MX_BOOTROM_MISC_VER 0x4 27 + 28 + static const char *meson_mx_socinfo_revision(unsigned int major_ver, 29 + unsigned int misc_ver, 30 + unsigned int metal_rev) 31 + { 32 + unsigned int minor_ver; 33 + 34 + switch (major_ver) { 35 + case MESON_SOCINFO_MAJOR_VER_MESON6: 36 + minor_ver = 0xa; 37 + break; 38 + 39 + case MESON_SOCINFO_MAJOR_VER_MESON8: 40 + if (metal_rev == 0x11111112) 41 + major_ver = 0x1d; 42 + 43 + if (metal_rev == 0x11111111 || metal_rev == 0x11111112) 44 + minor_ver = 0xa; 45 + else if (metal_rev == 0x11111113) 46 + minor_ver = 0xb; 47 + else if (metal_rev == 0x11111133) 48 + minor_ver = 0xc; 49 + else 50 + minor_ver = 0xd; 51 + 52 + break; 53 + 54 + case MESON_SOCINFO_MAJOR_VER_MESON8B: 55 + if (metal_rev == 0x11111111) 56 + minor_ver = 0xa; 57 + else 58 + minor_ver = 0xb; 59 + 60 + break; 61 + 62 + default: 63 + minor_ver = 0x0; 64 + break; 65 + } 66 + 67 + return kasprintf(GFP_KERNEL, "Rev%X (%x - 0:%X)", minor_ver, major_ver, 68 + misc_ver); 69 + } 70 + 71 + static const char *meson_mx_socinfo_soc_id(unsigned int major_ver, 72 + unsigned int metal_rev) 73 + { 74 + const char *soc_id; 75 + 76 + switch (major_ver) { 77 + case MESON_SOCINFO_MAJOR_VER_MESON6: 78 + soc_id = "Meson6 (AML8726-MX)"; 79 + break; 80 + 81 + case MESON_SOCINFO_MAJOR_VER_MESON8: 82 + if (metal_rev == 0x11111112) 83 + soc_id = "Meson8m2 (S812)"; 84 + else 85 + soc_id = "Meson8 (S802)"; 86 + 87 + break; 88 + 89 + case MESON_SOCINFO_MAJOR_VER_MESON8B: 90 + soc_id = "Meson8b (S805)"; 91 + break; 92 + 93 + default: 94 + soc_id = "Unknown"; 95 + break; 96 + } 97 + 98 + return kstrdup_const(soc_id, GFP_KERNEL); 99 + } 100 + 101 + static const struct of_device_id meson_mx_socinfo_analog_top_ids[] = { 102 + { .compatible = "amlogic,meson8-analog-top", }, 103 + { .compatible = "amlogic,meson8b-analog-top", }, 104 + { /* sentinel */ } 105 + }; 106 + 107 + int __init meson_mx_socinfo_init(void) 108 + { 109 + struct soc_device_attribute *soc_dev_attr; 110 + struct soc_device *soc_dev; 111 + struct device_node *np; 112 + struct regmap *assist_regmap, *bootrom_regmap, *analog_top_regmap; 113 + unsigned int major_ver, misc_ver, metal_rev = 0; 114 + int ret; 115 + 116 + assist_regmap = 117 + syscon_regmap_lookup_by_compatible("amlogic,meson-mx-assist"); 118 + if (IS_ERR(assist_regmap)) 119 + return PTR_ERR(assist_regmap); 120 + 121 + bootrom_regmap = 122 + syscon_regmap_lookup_by_compatible("amlogic,meson-mx-bootrom"); 123 + if (IS_ERR(bootrom_regmap)) 124 + return PTR_ERR(bootrom_regmap); 125 + 126 + np = of_find_matching_node(NULL, meson_mx_socinfo_analog_top_ids); 127 + if (np) { 128 + analog_top_regmap = syscon_node_to_regmap(np); 129 + if (IS_ERR(analog_top_regmap)) 130 + return PTR_ERR(analog_top_regmap); 131 + 132 + ret = regmap_read(analog_top_regmap, 133 + MESON_MX_ANALOG_TOP_METAL_REVISION, 134 + &metal_rev); 135 + if (ret) 136 + return ret; 137 + } 138 + 139 + ret = regmap_read(assist_regmap, MESON_MX_ASSIST_HW_REV, &major_ver); 140 + if (ret < 0) 141 + return ret; 142 + 143 + ret = regmap_read(bootrom_regmap, MESON_MX_BOOTROM_MISC_VER, 144 + &misc_ver); 145 + if (ret < 0) 146 + return ret; 147 + 148 + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 149 + if (!soc_dev_attr) 150 + return -ENODEV; 151 + 152 + soc_dev_attr->family = "Amlogic Meson"; 153 + 154 + np = of_find_node_by_path("/"); 155 + of_property_read_string(np, "model", &soc_dev_attr->machine); 156 + of_node_put(np); 157 + 158 + soc_dev_attr->revision = meson_mx_socinfo_revision(major_ver, misc_ver, 159 + metal_rev); 160 + soc_dev_attr->soc_id = meson_mx_socinfo_soc_id(major_ver, metal_rev); 161 + 162 + soc_dev = soc_device_register(soc_dev_attr); 163 + if (IS_ERR(soc_dev)) { 164 + kfree_const(soc_dev_attr->revision); 165 + kfree_const(soc_dev_attr->soc_id); 166 + kfree(soc_dev_attr); 167 + return PTR_ERR(soc_dev); 168 + } 169 + 170 + dev_info(soc_device_to_device(soc_dev), "Amlogic %s %s detected\n", 171 + soc_dev_attr->soc_id, soc_dev_attr->revision); 172 + 173 + return 0; 174 + } 175 + device_initcall(meson_mx_socinfo_init);