1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
4  */
5 
6 #include <dm.h>
7 #include <log.h>
8 #include <malloc.h>
9 #include <reset-uclass.h>
10 #include <linux/bitops.h>
11 #include <linux/io.h>
12 #include <asm/arch-rockchip/hardware.h>
13 #include <dm/device-internal.h>
14 #include <dm/lists.h>
15 /*
16  * Each reg has 16 bits reset signal for devices
17  * Note: Not including rk2818 and older SoCs
18  */
19 #define ROCKCHIP_RESET_NUM_IN_REG	16
20 
21 struct rockchip_reset_priv {
22 	void __iomem *base;
23 	const int *lut;
24 	/* Rockchip reset reg locate at cru controller */
25 	u32 reset_reg_offset;
26 	/* Rockchip reset reg number */
27 	u32 reset_reg_num;
28 };
29 
rockchip_reset_request(struct reset_ctl * reset_ctl)30 static int rockchip_reset_request(struct reset_ctl *reset_ctl)
31 {
32 	struct rockchip_reset_priv *priv = dev_get_priv(reset_ctl->dev);
33 	unsigned long id = reset_ctl->id;
34 
35 	if (priv->lut)
36 		id = priv->lut[id];
37 
38 	debug("%s(reset_ctl=%p) (dev=%p, id=%lu) (reg_num=%d)\n", __func__,
39 	      reset_ctl, reset_ctl->dev, id, priv->reset_reg_num);
40 
41 	if (id / ROCKCHIP_RESET_NUM_IN_REG >= priv->reset_reg_num)
42 		return -EINVAL;
43 
44 	return 0;
45 }
46 
rockchip_reset_assert(struct reset_ctl * reset_ctl)47 static int rockchip_reset_assert(struct reset_ctl *reset_ctl)
48 {
49 	struct rockchip_reset_priv *priv = dev_get_priv(reset_ctl->dev);
50 	unsigned long id = reset_ctl->id;
51 	int bank, offset;
52 
53 	if (priv->lut)
54 		id = priv->lut[id];
55 
56 	bank = id / ROCKCHIP_RESET_NUM_IN_REG;
57 	offset = id % ROCKCHIP_RESET_NUM_IN_REG;
58 
59 	debug("%s(reset_ctl=%p) (dev=%p, id=%lu) (reg_addr=%p)\n", __func__,
60 	      reset_ctl, reset_ctl->dev, id, priv->base + (bank * 4));
61 
62 	rk_setreg(priv->base + (bank * 4), BIT(offset));
63 
64 	return 0;
65 }
66 
rockchip_reset_deassert(struct reset_ctl * reset_ctl)67 static int rockchip_reset_deassert(struct reset_ctl *reset_ctl)
68 {
69 	struct rockchip_reset_priv *priv = dev_get_priv(reset_ctl->dev);
70 	unsigned long id = reset_ctl->id;
71 	int bank, offset;
72 
73 	if (priv->lut)
74 		id = priv->lut[id];
75 
76 	bank = id / ROCKCHIP_RESET_NUM_IN_REG;
77 	offset = id % ROCKCHIP_RESET_NUM_IN_REG;
78 
79 	debug("%s(reset_ctl=%p) (dev=%p, id=%lu) (reg_addr=%p)\n", __func__,
80 	      reset_ctl, reset_ctl->dev, id, priv->base + (bank * 4));
81 
82 	rk_clrreg(priv->base + (bank * 4), BIT(offset));
83 
84 	return 0;
85 }
86 
87 struct reset_ops rockchip_reset_ops = {
88 	.request = rockchip_reset_request,
89 	.rst_assert = rockchip_reset_assert,
90 	.rst_deassert = rockchip_reset_deassert,
91 };
92 
rockchip_reset_probe(struct udevice * dev)93 static int rockchip_reset_probe(struct udevice *dev)
94 {
95 	struct rockchip_reset_priv *priv = dev_get_priv(dev);
96 	fdt_addr_t addr;
97 	fdt_size_t size;
98 
99 	addr = dev_read_addr_size(dev, &size);
100 	if (addr == FDT_ADDR_T_NONE)
101 		return -EINVAL;
102 
103 	if ((priv->reset_reg_offset == 0) && (priv->reset_reg_num == 0))
104 		return -EINVAL;
105 
106 	addr += priv->reset_reg_offset;
107 	priv->base = ioremap(addr, size);
108 
109 	debug("%s(base=%p) (reg_offset=%x, reg_num=%d)\n", __func__,
110 	      priv->base, priv->reset_reg_offset, priv->reset_reg_num);
111 
112 	return 0;
113 }
114 
rockchip_reset_bind_lut(struct udevice * pdev,const int * lookup_table,u32 reg_offset,u32 reg_number)115 int rockchip_reset_bind_lut(struct udevice *pdev,
116 			    const int *lookup_table,
117 			    u32 reg_offset,
118 			    u32 reg_number)
119 {
120 	struct udevice *rst_dev;
121 	struct rockchip_reset_priv *priv;
122 	int ret;
123 
124 	ret = device_bind_driver_to_node(pdev, "rockchip_reset", "reset",
125 					 dev_ofnode(pdev), &rst_dev);
126 	if (ret) {
127 		debug("Warning: No rockchip reset driver: ret=%d\n", ret);
128 		return ret;
129 	}
130 	priv = malloc(sizeof(struct rockchip_reset_priv));
131 	priv->reset_reg_offset = reg_offset;
132 	priv->reset_reg_num = reg_number;
133 	priv->lut = lookup_table;
134 	dev_set_priv(rst_dev, priv);
135 
136 	return 0;
137 }
138 
rockchip_reset_bind(struct udevice * pdev,u32 reg_offset,u32 reg_number)139 int rockchip_reset_bind(struct udevice *pdev, u32 reg_offset, u32 reg_number)
140 {
141 	return rockchip_reset_bind_lut(pdev, NULL, reg_offset, reg_number);
142 }
143 
144 U_BOOT_DRIVER(rockchip_reset) = {
145 	.name = "rockchip_reset",
146 	.id = UCLASS_RESET,
147 	.probe = rockchip_reset_probe,
148 	.ops = &rockchip_reset_ops,
149 	.priv_auto	= sizeof(struct rockchip_reset_priv),
150 };
151