1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2024 Samsung Electronics Co., Ltd.
4 * Author: Michal Wilczynski <m.wilczynski@samsung.com>
5 */
6
7 #include <linux/of.h>
8 #include <linux/platform_device.h>
9 #include <linux/reset-controller.h>
10 #include <linux/regmap.h>
11
12 #include <dt-bindings/reset/thead,th1520-reset.h>
13
14 /* register offset in VOSYS_REGMAP */
15 #define TH1520_GPU_RST_CFG 0x0
16 #define TH1520_GPU_RST_CFG_MASK GENMASK(1, 0)
17
18 /* register values */
19 #define TH1520_GPU_SW_GPU_RST BIT(0)
20 #define TH1520_GPU_SW_CLKGEN_RST BIT(1)
21
22 struct th1520_reset_priv {
23 struct reset_controller_dev rcdev;
24 struct regmap *map;
25 };
26
27 struct th1520_reset_map {
28 u32 bit;
29 u32 reg;
30 };
31
32 static const struct th1520_reset_map th1520_resets[] = {
33 [TH1520_RESET_ID_GPU] = {
34 .bit = TH1520_GPU_SW_GPU_RST,
35 .reg = TH1520_GPU_RST_CFG,
36 },
37 [TH1520_RESET_ID_GPU_CLKGEN] = {
38 .bit = TH1520_GPU_SW_CLKGEN_RST,
39 .reg = TH1520_GPU_RST_CFG,
40 }
41 };
42
43 static inline struct th1520_reset_priv *
to_th1520_reset(struct reset_controller_dev * rcdev)44 to_th1520_reset(struct reset_controller_dev *rcdev)
45 {
46 return container_of(rcdev, struct th1520_reset_priv, rcdev);
47 }
48
th1520_reset_assert(struct reset_controller_dev * rcdev,unsigned long id)49 static int th1520_reset_assert(struct reset_controller_dev *rcdev,
50 unsigned long id)
51 {
52 struct th1520_reset_priv *priv = to_th1520_reset(rcdev);
53 const struct th1520_reset_map *reset;
54
55 reset = &th1520_resets[id];
56
57 return regmap_update_bits(priv->map, reset->reg, reset->bit, 0);
58 }
59
th1520_reset_deassert(struct reset_controller_dev * rcdev,unsigned long id)60 static int th1520_reset_deassert(struct reset_controller_dev *rcdev,
61 unsigned long id)
62 {
63 struct th1520_reset_priv *priv = to_th1520_reset(rcdev);
64 const struct th1520_reset_map *reset;
65
66 reset = &th1520_resets[id];
67
68 return regmap_update_bits(priv->map, reset->reg, reset->bit,
69 reset->bit);
70 }
71
72 static const struct reset_control_ops th1520_reset_ops = {
73 .assert = th1520_reset_assert,
74 .deassert = th1520_reset_deassert,
75 };
76
77 static const struct regmap_config th1520_reset_regmap_config = {
78 .reg_bits = 32,
79 .val_bits = 32,
80 .reg_stride = 4,
81 .fast_io = true,
82 };
83
th1520_reset_probe(struct platform_device * pdev)84 static int th1520_reset_probe(struct platform_device *pdev)
85 {
86 struct device *dev = &pdev->dev;
87 struct th1520_reset_priv *priv;
88 void __iomem *base;
89 int ret;
90
91 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
92 if (!priv)
93 return -ENOMEM;
94
95 base = devm_platform_ioremap_resource(pdev, 0);
96 if (IS_ERR(base))
97 return PTR_ERR(base);
98
99 priv->map = devm_regmap_init_mmio(dev, base,
100 &th1520_reset_regmap_config);
101 if (IS_ERR(priv->map))
102 return PTR_ERR(priv->map);
103
104 /* Initialize GPU resets to asserted state */
105 ret = regmap_update_bits(priv->map, TH1520_GPU_RST_CFG,
106 TH1520_GPU_RST_CFG_MASK, 0);
107 if (ret)
108 return ret;
109
110 priv->rcdev.owner = THIS_MODULE;
111 priv->rcdev.nr_resets = ARRAY_SIZE(th1520_resets);
112 priv->rcdev.ops = &th1520_reset_ops;
113 priv->rcdev.of_node = dev->of_node;
114
115 return devm_reset_controller_register(dev, &priv->rcdev);
116 }
117
118 static const struct of_device_id th1520_reset_match[] = {
119 { .compatible = "thead,th1520-reset" },
120 { /* sentinel */ }
121 };
122 MODULE_DEVICE_TABLE(of, th1520_reset_match);
123
124 static struct platform_driver th1520_reset_driver = {
125 .driver = {
126 .name = "th1520-reset",
127 .of_match_table = th1520_reset_match,
128 },
129 .probe = th1520_reset_probe,
130 };
131 module_platform_driver(th1520_reset_driver);
132
133 MODULE_AUTHOR("Michal Wilczynski <m.wilczynski@samsung.com>");
134 MODULE_DESCRIPTION("T-HEAD TH1520 SoC reset controller");
135 MODULE_LICENSE("GPL");
136