--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2020 - Texas Instruments Incorporated - http://www.ti.com/
+ * Dave Gerlach <d-gerlach@ti.com>
+ */
+
+#include <common.h>
+#include <soc.h>
+#include <dm.h>
+#include <errno.h>
+#include <dm/lists.h>
+#include <dm/root.h>
+
+int soc_get(struct udevice **devp)
+{
+ return uclass_first_device_err(UCLASS_SOC, devp);
+}
+
+int soc_get_machine(struct udevice *dev, char *buf, int size)
+{
+ struct soc_ops *ops = soc_get_ops(dev);
+
+ if (!ops->get_machine)
+ return -ENOSYS;
+
+ return ops->get_machine(dev, buf, size);
+}
+
+int soc_get_family(struct udevice *dev, char *buf, int size)
+{
+ struct soc_ops *ops = soc_get_ops(dev);
+
+ if (!ops->get_family)
+ return -ENOSYS;
+
+ return ops->get_family(dev, buf, size);
+}
+
+int soc_get_revision(struct udevice *dev, char *buf, int size)
+{
+ struct soc_ops *ops = soc_get_ops(dev);
+
+ if (!ops->get_revision)
+ return -ENOSYS;
+
+ return ops->get_revision(dev, buf, size);
+}
+
+const struct soc_attr *
+soc_device_match(const struct soc_attr *matches)
+{
+ bool match;
+ struct udevice *soc;
+ char str[SOC_MAX_STR_SIZE];
+
+ if (!matches)
+ return NULL;
+
+ if (soc_get(&soc))
+ return NULL;
+
+ while (1) {
+ if (!(matches->machine || matches->family ||
+ matches->revision))
+ break;
+
+ match = true;
+
+ if (matches->machine) {
+ if (!soc_get_machine(soc, str, SOC_MAX_STR_SIZE)) {
+ if (strcmp(matches->machine, str))
+ match = false;
+ }
+ }
+
+ if (matches->family) {
+ if (!soc_get_family(soc, str, SOC_MAX_STR_SIZE)) {
+ if (strcmp(matches->family, str))
+ match = false;
+ }
+ }
+
+ if (matches->revision) {
+ if (!soc_get_revision(soc, str, SOC_MAX_STR_SIZE)) {
+ if (strcmp(matches->revision, str))
+ match = false;
+ }
+ }
+
+ if (match)
+ return matches;
+
+ matches++;
+ }
+
+ return NULL;
+}
+
+UCLASS_DRIVER(soc) = {
+ .id = UCLASS_SOC,
+ .name = "soc",
+};
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2020 - Texas Instruments Incorporated - http://www.ti.com/
+ * Dave Gerlach <d-gerlach@ti.com>
+ */
+
+#ifndef __SOC_H
+#define __SOC_H
+
+#define SOC_MAX_STR_SIZE 128
+
+/**
+ * struct soc_attr - Contains SoC identify information to be used in
+ * SoC matching. An array of these structs
+ * representing different SoCs can be passed to
+ * soc_device_match and the struct matching the SoC
+ * in use will be returned.
+ *
+ * @family - Name of SoC family that can include multiple related SoC
+ * variants. Example: am33
+ * @machine - Name of a specific SoC. Example: am3352
+ * @revision - Name of a specific SoC revision. Example: SR1.1
+ * @data - A pointer to user data for the SoC variant
+ */
+struct soc_attr {
+ const char *family;
+ const char *machine;
+ const char *revision;
+ const void *data;
+};
+
+struct soc_ops {
+ /**
+ * get_machine() - Get machine name of an SOC
+ *
+ * @dev: Device to check (UCLASS_SOC)
+ * @buf: Buffer to place string
+ * @size: Size of string space
+ * @return 0 if OK, -ENOSPC if buffer is too small, other -ve on error
+ */
+ int (*get_machine)(struct udevice *dev, char *buf, int size);
+
+ /**
+ * get_revision() - Get revision name of a SOC
+ *
+ * @dev: Device to check (UCLASS_SOC)
+ * @buf: Buffer to place string
+ * @size: Size of string space
+ * @return 0 if OK, -ENOSPC if buffer is too small, other -ve on error
+ */
+ int (*get_revision)(struct udevice *dev, char *buf, int size);
+
+ /**
+ * get_family() - Get family name of an SOC
+ *
+ * @dev: Device to check (UCLASS_SOC)
+ * @buf: Buffer to place string
+ * @size: Size of string space
+ * @return 0 if OK, -ENOSPC if buffer is too small, other -ve on error
+ */
+ int (*get_family)(struct udevice *dev, char *buf, int size);
+};
+
+#define soc_get_ops(dev) ((struct soc_ops *)(dev)->driver->ops)
+
+#ifdef CONFIG_SOC_DEVICE
+/**
+ * soc_get() - Return the soc device for the soc in use.
+ * @devp: Pointer to structure to receive the soc device.
+ *
+ * Since there can only be at most one SOC instance, the API can supply a
+ * function that returns the unique device.
+ *
+ * Return: 0 if OK, -ve on error.
+ */
+int soc_get(struct udevice **devp);
+
+/**
+ * soc_get_machine() - Get machine name of an SOC
+ * @dev: Device to check (UCLASS_SOC)
+ * @buf: Buffer to place string
+ * @size: Size of string space
+ *
+ * Return: 0 if OK, -ENOSPC if buffer is too small, other -ve on error
+ */
+int soc_get_machine(struct udevice *dev, char *buf, int size);
+
+/**
+ * soc_get_revision() - Get revision name of an SOC
+ * @dev: Device to check (UCLASS_SOC)
+ * @buf: Buffer to place string
+ * @size: Size of string space
+ *
+ * Return: 0 if OK, -ENOSPC if buffer is too small, other -ve on error
+ */
+int soc_get_revision(struct udevice *dev, char *buf, int size);
+
+/**
+ * soc_get_family() - Get family name of an SOC
+ * @dev: Device to check (UCLASS_SOC)
+ * @buf: Buffer to place string
+ * @size: Size of string space
+ *
+ * Return: 0 if OK, -ENOSPC if buffer is too small, other -ve on error
+ */
+int soc_get_family(struct udevice *dev, char *buf, int size);
+
+/**
+ * soc_device_match() - Return match from an array of soc_attr
+ * @matches: Array with any combination of family, revision or machine set
+ *
+ * Return: Pointer to struct from matches array with set attributes matching
+ * those provided by the soc device, or NULL if no match found.
+ */
+const struct soc_attr *
+soc_device_match(const struct soc_attr *matches);
+
+#else
+static inline int soc_get(struct udevice **devp)
+{
+ return -ENOSYS;
+}
+
+static inline int soc_get_machine(struct udevice *dev, char *buf, int size)
+{
+ return -ENOSYS;
+}
+
+static inline int soc_get_revision(struct udevice *dev, char *buf, int size)
+{
+ return -ENOSYS;
+}
+
+static inline int soc_get_family(struct udevice *dev, char *buf, int size)
+{
+ return -ENOSYS;
+}
+
+static inline const struct soc_attr *
+soc_device_match(const struct soc_attr *matches)
+{
+ return NULL;
+}
+#endif
+#endif /* _SOC_H */