1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2015 Miao Yan <yanmiaobest@gmail.com>
4  * (C) Copyright 2021 Asherah Connor <ashe@kivikakk.ee>
5  */
6 
7 #include <dm.h>
8 #include <dm/uclass.h>
9 #include <qfw.h>
10 #include <stdlib.h>
11 
qfw_get_dev(struct udevice ** devp)12 int qfw_get_dev(struct udevice **devp)
13 {
14 	return uclass_first_device_err(UCLASS_QFW, devp);
15 }
16 
qfw_online_cpus(struct udevice * dev)17 int qfw_online_cpus(struct udevice *dev)
18 {
19 	u16 nb_cpus;
20 
21 	qfw_read_entry(dev, FW_CFG_NB_CPUS, 2, &nb_cpus);
22 
23 	return le16_to_cpu(nb_cpus);
24 }
25 
qfw_read_firmware_list(struct udevice * dev)26 int qfw_read_firmware_list(struct udevice *dev)
27 {
28 	int i;
29 	u32 count;
30 	struct fw_file *file;
31 	struct list_head *entry;
32 
33 	struct qfw_dev *qdev = dev_get_uclass_priv(dev);
34 
35 	/* don't read it twice */
36 	if (!list_empty(&qdev->fw_list))
37 		return 0;
38 
39 	qfw_read_entry(dev, FW_CFG_FILE_DIR, 4, &count);
40 	if (!count)
41 		return 0;
42 
43 	count = be32_to_cpu(count);
44 	for (i = 0; i < count; i++) {
45 		file = malloc(sizeof(*file));
46 		if (!file) {
47 			printf("error: allocating resource\n");
48 			goto err;
49 		}
50 		qfw_read_entry(dev, FW_CFG_INVALID,
51 			       sizeof(struct fw_cfg_file), &file->cfg);
52 		file->addr = 0;
53 		list_add_tail(&file->list, &qdev->fw_list);
54 	}
55 
56 	return 0;
57 
58 err:
59 	list_for_each(entry, &qdev->fw_list) {
60 		file = list_entry(entry, struct fw_file, list);
61 		free(file);
62 	}
63 
64 	return -ENOMEM;
65 }
66 
qfw_find_file(struct udevice * dev,const char * name)67 struct fw_file *qfw_find_file(struct udevice *dev, const char *name)
68 {
69 	struct list_head *entry;
70 	struct fw_file *file;
71 
72 	struct qfw_dev *qdev = dev_get_uclass_priv(dev);
73 
74 	list_for_each(entry, &qdev->fw_list) {
75 		file = list_entry(entry, struct fw_file, list);
76 		if (!strcmp(file->cfg.name, name))
77 			return file;
78 	}
79 
80 	return NULL;
81 }
82 
qfw_file_iter_init(struct udevice * dev,struct fw_cfg_file_iter * iter)83 struct fw_file *qfw_file_iter_init(struct udevice *dev,
84 				   struct fw_cfg_file_iter *iter)
85 {
86 	struct qfw_dev *qdev = dev_get_uclass_priv(dev);
87 
88 	iter->entry = qdev->fw_list.next;
89 	iter->end = &qdev->fw_list;
90 	return list_entry((struct list_head *)iter->entry,
91 			  struct fw_file, list);
92 }
93 
qfw_file_iter_next(struct fw_cfg_file_iter * iter)94 struct fw_file *qfw_file_iter_next(struct fw_cfg_file_iter *iter)
95 {
96 	iter->entry = ((struct list_head *)iter->entry)->next;
97 	return list_entry((struct list_head *)iter->entry,
98 			  struct fw_file, list);
99 }
100 
qfw_file_iter_end(struct fw_cfg_file_iter * iter)101 bool qfw_file_iter_end(struct fw_cfg_file_iter *iter)
102 {
103 	return iter->entry == iter->end;
104 }
105