1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2020, Linaro Limited
4  */
5 
6 #define LOG_CATEGORY UCLASS_MISC
7 
8 #include <common.h>
9 #include <clk.h>
10 #include <dm.h>
11 #include <malloc.h>
12 #include <reset.h>
13 #include <asm/io.h>
14 #include <asm/scmi_test.h>
15 #include <dm/device_compat.h>
16 
17 /*
18  * Simulate to some extent a SCMI exchange.
19  * This drivers gets SCMI resources and offers API function to the
20  * SCMI test sequence manipulate the resources, currently clock
21  * and reset controllers.
22  */
23 
24 #define SCMI_TEST_DEVICES_CLK_COUNT		3
25 #define SCMI_TEST_DEVICES_RD_COUNT		1
26 
27 /*
28  * struct sandbox_scmi_device_priv - Storage for device handles used by test
29  * @clk:		Array of clock instances used by tests
30  * @reset_clt:		Array of the reset controller instances used by tests
31  * @devices:		Resources exposed by sandbox_scmi_devices_ctx()
32  */
33 struct sandbox_scmi_device_priv {
34 	struct clk clk[SCMI_TEST_DEVICES_CLK_COUNT];
35 	struct reset_ctl reset_ctl[SCMI_TEST_DEVICES_RD_COUNT];
36 	struct sandbox_scmi_devices devices;
37 };
38 
sandbox_scmi_devices_ctx(struct udevice * dev)39 struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(struct udevice *dev)
40 {
41 	struct sandbox_scmi_device_priv *priv = dev_get_priv(dev);
42 
43 	if (priv)
44 		return &priv->devices;
45 
46 	return NULL;
47 }
48 
sandbox_scmi_devices_remove(struct udevice * dev)49 static int sandbox_scmi_devices_remove(struct udevice *dev)
50 {
51 	struct sandbox_scmi_devices *devices = sandbox_scmi_devices_ctx(dev);
52 	int ret = 0;
53 	size_t n;
54 
55 	if (!devices)
56 		return 0;
57 
58 	for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) {
59 		int ret2 = reset_free(devices->reset + n);
60 
61 		if (ret2 && !ret)
62 			ret = ret2;
63 	}
64 
65 	return ret;
66 }
67 
sandbox_scmi_devices_probe(struct udevice * dev)68 static int sandbox_scmi_devices_probe(struct udevice *dev)
69 {
70 	struct sandbox_scmi_device_priv *priv = dev_get_priv(dev);
71 	int ret;
72 	size_t n;
73 
74 	priv->devices = (struct sandbox_scmi_devices){
75 		.clk = priv->clk,
76 		.clk_count = SCMI_TEST_DEVICES_CLK_COUNT,
77 		.reset = priv->reset_ctl,
78 		.reset_count = SCMI_TEST_DEVICES_RD_COUNT,
79 	};
80 
81 	for (n = 0; n < SCMI_TEST_DEVICES_CLK_COUNT; n++) {
82 		ret = clk_get_by_index(dev, n, priv->devices.clk + n);
83 		if (ret) {
84 			dev_err(dev, "%s: Failed on clk %zu\n", __func__, n);
85 			return ret;
86 		}
87 	}
88 
89 	for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) {
90 		ret = reset_get_by_index(dev, n, priv->devices.reset + n);
91 		if (ret) {
92 			dev_err(dev, "%s: Failed on reset %zu\n", __func__, n);
93 			goto err_reset;
94 		}
95 	}
96 
97 	return 0;
98 
99 err_reset:
100 	for (; n > 0; n--)
101 		reset_free(priv->devices.reset + n - 1);
102 
103 	return ret;
104 }
105 
106 static const struct udevice_id sandbox_scmi_devices_ids[] = {
107 	{ .compatible = "sandbox,scmi-devices" },
108 	{ }
109 };
110 
111 U_BOOT_DRIVER(sandbox_scmi_devices) = {
112 	.name = "sandbox-scmi_devices",
113 	.id = UCLASS_MISC,
114 	.of_match = sandbox_scmi_devices_ids,
115 	.priv_auto	= sizeof(struct sandbox_scmi_device_priv),
116 	.remove = sandbox_scmi_devices_remove,
117 	.probe = sandbox_scmi_devices_probe,
118 };
119