1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (c) 2021 Linaro Limited
4 * Author: AKASHI Takahiro
5 */
6
7 #include <malloc.h>
8 #include <asm/global_data.h>
9 #include <dm/root.h>
10 #include <dm/tag.h>
11 #include <linux/err.h>
12 #include <linux/list.h>
13 #include <linux/types.h>
14
15 struct udevice;
16
17 DECLARE_GLOBAL_DATA_PTR;
18
19 static const char *const tag_name[] = {
20 [DM_TAG_PLAT] = "plat",
21 [DM_TAG_PARENT_PLAT] = "parent_plat",
22 [DM_TAG_UC_PLAT] = "uclass_plat",
23
24 [DM_TAG_PRIV] = "priv",
25 [DM_TAG_PARENT_PRIV] = "parent_priv",
26 [DM_TAG_UC_PRIV] = "uclass_priv",
27 [DM_TAG_DRIVER_DATA] = "driver_data",
28
29 [DM_TAG_EFI] = "efi",
30 };
31
tag_get_name(enum dm_tag_t tag)32 const char *tag_get_name(enum dm_tag_t tag)
33 {
34 return tag_name[tag];
35 }
36
dev_tag_set_ptr(struct udevice * dev,enum dm_tag_t tag,void * ptr)37 int dev_tag_set_ptr(struct udevice *dev, enum dm_tag_t tag, void *ptr)
38 {
39 struct dmtag_node *node;
40
41 if (!dev || tag >= DM_TAG_COUNT)
42 return -EINVAL;
43
44 list_for_each_entry(node, &gd->dmtag_list, sibling) {
45 if (node->dev == dev && node->tag == tag)
46 return -EEXIST;
47 }
48
49 node = calloc(sizeof(*node), 1);
50 if (!node)
51 return -ENOMEM;
52
53 node->dev = dev;
54 node->tag = tag;
55 node->ptr = ptr;
56 list_add_tail(&node->sibling, (struct list_head *)&gd->dmtag_list);
57
58 return 0;
59 }
60
dev_tag_set_val(struct udevice * dev,enum dm_tag_t tag,ulong val)61 int dev_tag_set_val(struct udevice *dev, enum dm_tag_t tag, ulong val)
62 {
63 struct dmtag_node *node;
64
65 if (!dev || tag >= DM_TAG_COUNT)
66 return -EINVAL;
67
68 list_for_each_entry(node, &gd->dmtag_list, sibling) {
69 if (node->dev == dev && node->tag == tag)
70 return -EEXIST;
71 }
72
73 node = calloc(sizeof(*node), 1);
74 if (!node)
75 return -ENOMEM;
76
77 node->dev = dev;
78 node->tag = tag;
79 node->val = val;
80 list_add_tail(&node->sibling, (struct list_head *)&gd->dmtag_list);
81
82 return 0;
83 }
84
dev_tag_get_ptr(struct udevice * dev,enum dm_tag_t tag,void ** ptrp)85 int dev_tag_get_ptr(struct udevice *dev, enum dm_tag_t tag, void **ptrp)
86 {
87 struct dmtag_node *node;
88
89 if (!dev || tag >= DM_TAG_COUNT)
90 return -EINVAL;
91
92 list_for_each_entry(node, &gd->dmtag_list, sibling) {
93 if (node->dev == dev && node->tag == tag) {
94 *ptrp = node->ptr;
95 return 0;
96 }
97 }
98
99 return -ENOENT;
100 }
101
dev_tag_get_val(struct udevice * dev,enum dm_tag_t tag,ulong * valp)102 int dev_tag_get_val(struct udevice *dev, enum dm_tag_t tag, ulong *valp)
103 {
104 struct dmtag_node *node;
105
106 if (!dev || tag >= DM_TAG_COUNT)
107 return -EINVAL;
108
109 list_for_each_entry(node, &gd->dmtag_list, sibling) {
110 if (node->dev == dev && node->tag == tag) {
111 *valp = node->val;
112 return 0;
113 }
114 }
115
116 return -ENOENT;
117 }
118
dev_tag_del(struct udevice * dev,enum dm_tag_t tag)119 int dev_tag_del(struct udevice *dev, enum dm_tag_t tag)
120 {
121 struct dmtag_node *node, *tmp;
122
123 if (!dev || tag >= DM_TAG_COUNT)
124 return -EINVAL;
125
126 list_for_each_entry_safe(node, tmp, &gd->dmtag_list, sibling) {
127 if (node->dev == dev && node->tag == tag) {
128 list_del(&node->sibling);
129 free(node);
130
131 return 0;
132 }
133 }
134
135 return -ENOENT;
136 }
137
dev_tag_del_all(struct udevice * dev)138 int dev_tag_del_all(struct udevice *dev)
139 {
140 struct dmtag_node *node, *tmp;
141 bool found = false;
142
143 if (!dev)
144 return -EINVAL;
145
146 list_for_each_entry_safe(node, tmp, &gd->dmtag_list, sibling) {
147 if (node->dev == dev) {
148 list_del(&node->sibling);
149 free(node);
150 found = true;
151 }
152 }
153
154 if (found)
155 return 0;
156
157 return -ENOENT;
158 }
159
dev_tag_collect_stats(struct dm_stats * stats)160 void dev_tag_collect_stats(struct dm_stats *stats)
161 {
162 struct dmtag_node *node;
163
164 list_for_each_entry(node, &gd->dmtag_list, sibling) {
165 stats->tag_count++;
166 stats->tag_size += sizeof(struct dmtag_node);
167 }
168 }
169