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