blob: a3c5cb7e57cc8c0f32bffab4fb763b55e1d1dc7a [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2021 Linaro Limited
* Author: AKASHI Takahiro
*/
#include <malloc.h>
#include <asm/global_data.h>
#include <dm/root.h>
#include <dm/tag.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/types.h>
struct udevice;
DECLARE_GLOBAL_DATA_PTR;
static const char *const tag_name[] = {
[DM_TAG_PLAT] = "plat",
[DM_TAG_PARENT_PLAT] = "parent_plat",
[DM_TAG_UC_PLAT] = "uclass_plat",
[DM_TAG_PRIV] = "priv",
[DM_TAG_PARENT_PRIV] = "parent_priv",
[DM_TAG_UC_PRIV] = "uclass_priv",
[DM_TAG_DRIVER_DATA] = "driver_data",
[DM_TAG_EFI] = "efi",
};
const char *tag_get_name(enum dm_tag_t tag)
{
return tag_name[tag];
}
int dev_tag_set_ptr(struct udevice *dev, enum dm_tag_t tag, void *ptr)
{
struct dmtag_node *node;
if (!dev || tag >= DM_TAG_COUNT)
return -EINVAL;
list_for_each_entry(node, &gd->dmtag_list, sibling) {
if (node->dev == dev && node->tag == tag)
return -EEXIST;
}
node = calloc(sizeof(*node), 1);
if (!node)
return -ENOMEM;
node->dev = dev;
node->tag = tag;
node->ptr = ptr;
list_add_tail(&node->sibling, (struct list_head *)&gd->dmtag_list);
return 0;
}
int dev_tag_set_val(struct udevice *dev, enum dm_tag_t tag, ulong val)
{
struct dmtag_node *node;
if (!dev || tag >= DM_TAG_COUNT)
return -EINVAL;
list_for_each_entry(node, &gd->dmtag_list, sibling) {
if (node->dev == dev && node->tag == tag)
return -EEXIST;
}
node = calloc(sizeof(*node), 1);
if (!node)
return -ENOMEM;
node->dev = dev;
node->tag = tag;
node->val = val;
list_add_tail(&node->sibling, (struct list_head *)&gd->dmtag_list);
return 0;
}
int dev_tag_get_ptr(struct udevice *dev, enum dm_tag_t tag, void **ptrp)
{
struct dmtag_node *node;
if (!dev || tag >= DM_TAG_COUNT)
return -EINVAL;
list_for_each_entry(node, &gd->dmtag_list, sibling) {
if (node->dev == dev && node->tag == tag) {
*ptrp = node->ptr;
return 0;
}
}
return -ENOENT;
}
int dev_tag_get_val(struct udevice *dev, enum dm_tag_t tag, ulong *valp)
{
struct dmtag_node *node;
if (!dev || tag >= DM_TAG_COUNT)
return -EINVAL;
list_for_each_entry(node, &gd->dmtag_list, sibling) {
if (node->dev == dev && node->tag == tag) {
*valp = node->val;
return 0;
}
}
return -ENOENT;
}
int dev_tag_del(struct udevice *dev, enum dm_tag_t tag)
{
struct dmtag_node *node, *tmp;
if (!dev || tag >= DM_TAG_COUNT)
return -EINVAL;
list_for_each_entry_safe(node, tmp, &gd->dmtag_list, sibling) {
if (node->dev == dev && node->tag == tag) {
list_del(&node->sibling);
free(node);
return 0;
}
}
return -ENOENT;
}
int dev_tag_del_all(struct udevice *dev)
{
struct dmtag_node *node, *tmp;
bool found = false;
if (!dev)
return -EINVAL;
list_for_each_entry_safe(node, tmp, &gd->dmtag_list, sibling) {
if (node->dev == dev) {
list_del(&node->sibling);
free(node);
found = true;
}
}
if (found)
return 0;
return -ENOENT;
}
void dev_tag_collect_stats(struct dm_stats *stats)
{
struct dmtag_node *node;
list_for_each_entry(node, &gd->dmtag_list, sibling) {
stats->tag_count++;
stats->tag_size += sizeof(struct dmtag_node);
}
}