1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2019, Linaro Limited
4  */
5 
6 #include <log.h>
7 #include <malloc.h>
8 #include <asm/io.h>
9 #include <dm.h>
10 #include <dt-bindings/reset/ti-syscon.h>
11 #include <reset-uclass.h>
12 #include <linux/bitops.h>
13 
14 struct hisi_reset_priv {
15 	void __iomem *base;
16 };
17 
hisi_reset_deassert(struct reset_ctl * rst)18 static int hisi_reset_deassert(struct reset_ctl *rst)
19 {
20 	struct hisi_reset_priv *priv = dev_get_priv(rst->dev);
21 	u32 val;
22 
23 	val = readl(priv->base + rst->data);
24 	if (rst->polarity & DEASSERT_SET)
25 		val |= BIT(rst->id);
26 	else
27 		val &= ~BIT(rst->id);
28 	writel(val, priv->base + rst->data);
29 
30 	return 0;
31 }
32 
hisi_reset_assert(struct reset_ctl * rst)33 static int hisi_reset_assert(struct reset_ctl *rst)
34 {
35 	struct hisi_reset_priv *priv = dev_get_priv(rst->dev);
36 	u32 val;
37 
38 	val = readl(priv->base + rst->data);
39 	if (rst->polarity & ASSERT_SET)
40 		val |= BIT(rst->id);
41 	else
42 		val &= ~BIT(rst->id);
43 	writel(val, priv->base + rst->data);
44 
45 	return 0;
46 }
47 
hisi_reset_of_xlate(struct reset_ctl * rst,struct ofnode_phandle_args * args)48 static int hisi_reset_of_xlate(struct reset_ctl *rst,
49 			       struct ofnode_phandle_args *args)
50 {
51 	unsigned long polarity;
52 
53 	switch (args->args_count) {
54 	case 2:
55 		polarity = ASSERT_SET;
56 		break;
57 
58 	case 3:
59 		polarity = args->args[2];
60 		break;
61 
62 	default:
63 		debug("Invalid args_count: %d\n", args->args_count);
64 		return -EINVAL;
65 	}
66 
67 	/* Use .data field as register offset and .id field as bit shift */
68 	rst->data = args->args[0];
69 	rst->id = args->args[1];
70 	rst->polarity = polarity;
71 
72 	return 0;
73 }
74 
75 static const struct reset_ops hisi_reset_reset_ops = {
76 	.of_xlate = hisi_reset_of_xlate,
77 	.rst_assert = hisi_reset_assert,
78 	.rst_deassert = hisi_reset_deassert,
79 };
80 
81 static const struct udevice_id hisi_reset_ids[] = {
82 	{ .compatible = "hisilicon,hi3798cv200-reset" },
83 	{ }
84 };
85 
hisi_reset_probe(struct udevice * dev)86 static int hisi_reset_probe(struct udevice *dev)
87 {
88 	struct hisi_reset_priv *priv = dev_get_priv(dev);
89 
90 	priv->base = dev_remap_addr(dev);
91 	if (!priv->base)
92 		return -ENOMEM;
93 
94 	return 0;
95 }
96 
97 U_BOOT_DRIVER(hisi_reset) = {
98 	.name = "hisilicon_reset",
99 	.id = UCLASS_RESET,
100 	.of_match = hisi_reset_ids,
101 	.ops = &hisi_reset_reset_ops,
102 	.probe = hisi_reset_probe,
103 	.priv_auto	= sizeof(struct hisi_reset_priv),
104 };
105