diff options
-rw-r--r-- | drivers/soc/Kconfig | 9 | ||||
-rw-r--r-- | drivers/soc/Makefile | 1 | ||||
-rw-r--r-- | drivers/soc/soc-uclass.c | 102 | ||||
-rw-r--r-- | include/dm/uclass-id.h | 1 | ||||
-rw-r--r-- | include/soc.h | 145 |
5 files changed, 258 insertions, 0 deletions
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index 7b4e4d6130..e715dfd017 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -1,5 +1,14 @@ menu "SOC (System On Chip) specific Drivers" +config SOC_DEVICE + bool "Enable SoC Device ID drivers using Driver Model" + help + This allows drivers to be provided for SoCs to help in identifying + the SoC in use and matching SoC attributes for selecting SoC + specific data. This is useful for other device drivers that may + need different parameters or quirks enabled depending on the + specific device variant in use. + source "drivers/soc/ti/Kconfig" endmenu diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index ce253b7aa8..1c09a84656 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -3,3 +3,4 @@ # Makefile for the U-Boot SOC specific device drivers. obj-$(CONFIG_SOC_TI) += ti/ +obj-$(CONFIG_SOC_DEVICE) += soc-uclass.o diff --git a/drivers/soc/soc-uclass.c b/drivers/soc/soc-uclass.c new file mode 100644 index 0000000000..c32d647864 --- /dev/null +++ b/drivers/soc/soc-uclass.c @@ -0,0 +1,102 @@ +// 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", +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 7837d459f1..690a8ed4df 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -97,6 +97,7 @@ enum uclass_id { UCLASS_SERIAL, /* Serial UART */ UCLASS_SIMPLE_BUS, /* Bus with child devices */ UCLASS_SMEM, /* Shared memory interface */ + UCLASS_SOC, /* SOC Device */ UCLASS_SOUND, /* Playing simple sounds */ UCLASS_SPI, /* SPI bus */ UCLASS_SPI_FLASH, /* SPI flash */ diff --git a/include/soc.h b/include/soc.h new file mode 100644 index 0000000000..a55eb1b572 --- /dev/null +++ b/include/soc.h @@ -0,0 +1,145 @@ +/* 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 */ |