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

soc: Add Amlogic SoC Information driver

Amlogic SoCs have a SoC information register for SoC type, package type and
revision information.
This patchs adds support for this register decoding and exposing with the
SoC bus infrastructure.

Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>
Signed-off-by: Kevin Hilman <khilman@baylibre.com>

authored by

Neil Armstrong and committed by
Kevin Hilman
a9daaba2 9833eb16

+192
+1
drivers/soc/Kconfig
··· 1 1 menu "SOC (System On Chip) specific Drivers" 2 2 3 3 source "drivers/soc/actions/Kconfig" 4 + source "drivers/soc/amlogic/Kconfig" 4 5 source "drivers/soc/atmel/Kconfig" 5 6 source "drivers/soc/bcm/Kconfig" 6 7 source "drivers/soc/fsl/Kconfig"
+1
drivers/soc/Makefile
··· 10 10 obj-y += fsl/ 11 11 obj-$(CONFIG_ARCH_MXC) += imx/ 12 12 obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ 13 + obj-$(CONFIG_ARCH_MESON) += amlogic/ 13 14 obj-$(CONFIG_ARCH_QCOM) += qcom/ 14 15 obj-y += renesas/ 15 16 obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
+12
drivers/soc/amlogic/Kconfig
··· 1 + menu "Amlogic SoC drivers" 2 + 3 + config MESON_GX_SOCINFO 4 + bool "Amlogic Meson GX SoC Information driver" 5 + depends on ARCH_MESON || COMPILE_TEST 6 + default ARCH_MESON 7 + select SOC_BUS 8 + help 9 + Say yes to support decoding of Amlogic Meson GX SoC family 10 + information about the type, package and version. 11 + 12 + endmenu
+1
drivers/soc/amlogic/Makefile
··· 1 + obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o
+177
drivers/soc/amlogic/meson-gx-socinfo.c
··· 1 + /* 2 + * Copyright (c) 2017 BayLibre, SAS 3 + * Author: Neil Armstrong <narmstrong@baylibre.com> 4 + * 5 + * SPDX-License-Identifier: GPL-2.0+ 6 + */ 7 + 8 + #include <linux/io.h> 9 + #include <linux/of.h> 10 + #include <linux/of_address.h> 11 + #include <linux/of_platform.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/slab.h> 14 + #include <linux/sys_soc.h> 15 + #include <linux/bitfield.h> 16 + #include <linux/regmap.h> 17 + #include <linux/mfd/syscon.h> 18 + 19 + #define AO_SEC_SD_CFG8 0xe0 20 + #define AO_SEC_SOCINFO_OFFSET AO_SEC_SD_CFG8 21 + 22 + #define SOCINFO_MAJOR GENMASK(31, 24) 23 + #define SOCINFO_MINOR GENMASK(23, 16) 24 + #define SOCINFO_PACK GENMASK(15, 8) 25 + #define SOCINFO_MISC GENMASK(7, 0) 26 + 27 + static const struct meson_gx_soc_id { 28 + const char *name; 29 + unsigned int id; 30 + } soc_ids[] = { 31 + { "GXBB", 0x1f }, 32 + { "GXTVBB", 0x20 }, 33 + { "GXL", 0x21 }, 34 + { "GXM", 0x22 }, 35 + { "TXL", 0x23 }, 36 + }; 37 + 38 + static const struct meson_gx_package_id { 39 + const char *name; 40 + unsigned int major_id; 41 + unsigned int pack_id; 42 + } soc_packages[] = { 43 + { "S905", 0x1f, 0 }, 44 + { "S905M", 0x1f, 0x20 }, 45 + { "S905D", 0x21, 0 }, 46 + { "S905X", 0x21, 0x80 }, 47 + { "S905L", 0x21, 0xc0 }, 48 + { "S905M2", 0x21, 0xe0 }, 49 + { "S912", 0x22, 0 }, 50 + }; 51 + 52 + static inline unsigned int socinfo_to_major(u32 socinfo) 53 + { 54 + return FIELD_GET(SOCINFO_MAJOR, socinfo); 55 + } 56 + 57 + static inline unsigned int socinfo_to_minor(u32 socinfo) 58 + { 59 + return FIELD_GET(SOCINFO_MINOR, socinfo); 60 + } 61 + 62 + static inline unsigned int socinfo_to_pack(u32 socinfo) 63 + { 64 + return FIELD_GET(SOCINFO_PACK, socinfo); 65 + } 66 + 67 + static inline unsigned int socinfo_to_misc(u32 socinfo) 68 + { 69 + return FIELD_GET(SOCINFO_MISC, socinfo); 70 + } 71 + 72 + static const char *socinfo_to_package_id(u32 socinfo) 73 + { 74 + unsigned int pack = socinfo_to_pack(socinfo) & 0xf0; 75 + unsigned int major = socinfo_to_major(socinfo); 76 + int i; 77 + 78 + for (i = 0 ; i < ARRAY_SIZE(soc_packages) ; ++i) { 79 + if (soc_packages[i].major_id == major && 80 + soc_packages[i].pack_id == pack) 81 + return soc_packages[i].name; 82 + } 83 + 84 + return "Unknown"; 85 + } 86 + 87 + static const char *socinfo_to_soc_id(u32 socinfo) 88 + { 89 + unsigned int id = socinfo_to_major(socinfo); 90 + int i; 91 + 92 + for (i = 0 ; i < ARRAY_SIZE(soc_ids) ; ++i) { 93 + if (soc_ids[i].id == id) 94 + return soc_ids[i].name; 95 + } 96 + 97 + return "Unknown"; 98 + } 99 + 100 + int __init meson_gx_socinfo_init(void) 101 + { 102 + struct soc_device_attribute *soc_dev_attr; 103 + struct soc_device *soc_dev; 104 + struct device_node *np; 105 + struct regmap *regmap; 106 + unsigned int socinfo; 107 + struct device *dev; 108 + int ret; 109 + 110 + /* look up for chipid node */ 111 + np = of_find_compatible_node(NULL, NULL, "amlogic,meson-gx-ao-secure"); 112 + if (!np) 113 + return -ENODEV; 114 + 115 + /* check if interface is enabled */ 116 + if (!of_device_is_available(np)) 117 + return -ENODEV; 118 + 119 + /* check if chip-id is available */ 120 + if (!of_property_read_bool(np, "amlogic,has-chip-id")) 121 + return -ENODEV; 122 + 123 + /* node should be a syscon */ 124 + regmap = syscon_node_to_regmap(np); 125 + of_node_put(np); 126 + if (IS_ERR(regmap)) { 127 + pr_err("%s: failed to get regmap\n", __func__); 128 + return -ENODEV; 129 + } 130 + 131 + ret = regmap_read(regmap, AO_SEC_SOCINFO_OFFSET, &socinfo); 132 + if (ret < 0) 133 + return ret; 134 + 135 + if (!socinfo) { 136 + pr_err("%s: invalid chipid value\n", __func__); 137 + return -EINVAL; 138 + } 139 + 140 + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 141 + if (!soc_dev_attr) 142 + return -ENODEV; 143 + 144 + soc_dev_attr->family = "Amlogic Meson"; 145 + 146 + np = of_find_node_by_path("/"); 147 + of_property_read_string(np, "model", &soc_dev_attr->machine); 148 + of_node_put(np); 149 + 150 + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%x:%x - %x:%x", 151 + socinfo_to_major(socinfo), 152 + socinfo_to_minor(socinfo), 153 + socinfo_to_pack(socinfo), 154 + socinfo_to_misc(socinfo)); 155 + soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%s (%s)", 156 + socinfo_to_soc_id(socinfo), 157 + socinfo_to_package_id(socinfo)); 158 + 159 + soc_dev = soc_device_register(soc_dev_attr); 160 + if (IS_ERR(soc_dev)) { 161 + kfree(soc_dev_attr->revision); 162 + kfree_const(soc_dev_attr->soc_id); 163 + kfree(soc_dev_attr); 164 + return PTR_ERR(soc_dev); 165 + } 166 + dev = soc_device_to_device(soc_dev); 167 + 168 + dev_info(dev, "Amlogic Meson %s Revision %x:%x (%x:%x) Detected\n", 169 + soc_dev_attr->soc_id, 170 + socinfo_to_major(socinfo), 171 + socinfo_to_minor(socinfo), 172 + socinfo_to_pack(socinfo), 173 + socinfo_to_misc(socinfo)); 174 + 175 + return 0; 176 + } 177 + device_initcall(meson_gx_socinfo_init);