1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2019 Rockchip Electronics Co., Ltd
4 */
5
6#include <common.h>
7#include <dm.h>
8#include <log.h>
9#include <dm/pinctrl.h>
10#include <regmap.h>
11#include <syscon.h>
12#include <linux/bitops.h>
13
14#include "pinctrl-rockchip.h"
15
16static struct rockchip_mux_recalced_data rk3328_mux_recalced_data[] = {
17	{
18		.num = 2,
19		.pin = 12,
20		.reg = 0x24,
21		.bit = 8,
22		.mask = 0x3
23	}, {
24		.num = 2,
25		.pin = 15,
26		.reg = 0x28,
27		.bit = 0,
28		.mask = 0x7
29	}, {
30		.num = 2,
31		.pin = 23,
32		.reg = 0x30,
33		.bit = 14,
34		.mask = 0x3
35	},
36};
37
38static struct rockchip_mux_route_data rk3328_mux_route_data[] = {
39	{
40		/* uart2dbg_rxm0 */
41		.bank_num = 1,
42		.pin = 1,
43		.func = 2,
44		.route_offset = 0x50,
45		.route_val = BIT(16) | BIT(16 + 1),
46	}, {
47		/* uart2dbg_rxm1 */
48		.bank_num = 2,
49		.pin = 1,
50		.func = 1,
51		.route_offset = 0x50,
52		.route_val = BIT(16) | BIT(16 + 1) | BIT(0),
53	}, {
54		/* gmac-m1_rxd0 */
55		.bank_num = 1,
56		.pin = 11,
57		.func = 2,
58		.route_offset = 0x50,
59		.route_val = BIT(16 + 2) | BIT(2),
60	}, {
61		/* gmac-m1-optimized_rxd3 */
62		.bank_num = 1,
63		.pin = 14,
64		.func = 2,
65		.route_offset = 0x50,
66		.route_val = BIT(16 + 10) | BIT(10),
67	}, {
68		/* pdm_sdi0m0 */
69		.bank_num = 2,
70		.pin = 19,
71		.func = 2,
72		.route_offset = 0x50,
73		.route_val = BIT(16 + 3),
74	}, {
75		/* pdm_sdi0m1 */
76		.bank_num = 1,
77		.pin = 23,
78		.func = 3,
79		.route_offset = 0x50,
80		.route_val =  BIT(16 + 3) | BIT(3),
81	}, {
82		/* spi_rxdm2 */
83		.bank_num = 3,
84		.pin = 2,
85		.func = 4,
86		.route_offset = 0x50,
87		.route_val =  BIT(16 + 4) | BIT(16 + 5) | BIT(5),
88	}, {
89		/* i2s2_sdim0 */
90		.bank_num = 1,
91		.pin = 24,
92		.func = 1,
93		.route_offset = 0x50,
94		.route_val = BIT(16 + 6),
95	}, {
96		/* i2s2_sdim1 */
97		.bank_num = 3,
98		.pin = 2,
99		.func = 6,
100		.route_offset = 0x50,
101		.route_val =  BIT(16 + 6) | BIT(6),
102	}, {
103		/* card_iom1 */
104		.bank_num = 2,
105		.pin = 22,
106		.func = 3,
107		.route_offset = 0x50,
108		.route_val =  BIT(16 + 7) | BIT(7),
109	}, {
110		/* tsp_d5m1 */
111		.bank_num = 2,
112		.pin = 16,
113		.func = 3,
114		.route_offset = 0x50,
115		.route_val =  BIT(16 + 8) | BIT(8),
116	}, {
117		/* cif_data5m1 */
118		.bank_num = 2,
119		.pin = 16,
120		.func = 4,
121		.route_offset = 0x50,
122		.route_val =  BIT(16 + 9) | BIT(9),
123	},
124};
125
126static int rk3328_set_mux(struct rockchip_pin_bank *bank, int pin, int mux)
127{
128	struct rockchip_pinctrl_priv *priv = bank->priv;
129	int iomux_num = (pin / 8);
130	struct regmap *regmap;
131	int reg, ret, mask, mux_type;
132	u8 bit;
133	u32 data;
134
135	regmap = (bank->iomux[iomux_num].type & IOMUX_SOURCE_PMU)
136				? priv->regmap_pmu : priv->regmap_base;
137
138	/* get basic quadrupel of mux registers and the correct reg inside */
139	mux_type = bank->iomux[iomux_num].type;
140	reg = bank->iomux[iomux_num].offset;
141	reg += rockchip_get_mux_data(mux_type, pin, &bit, &mask);
142
143	if (bank->recalced_mask & BIT(pin))
144		rockchip_get_recalced_mux(bank, pin, &reg, &bit, &mask);
145
146	data = (mask << (bit + 16));
147	data |= (mux & mask) << bit;
148	ret = regmap_write(regmap, reg, data);
149
150	return ret;
151}
152
153#define RK3328_PULL_OFFSET		0x100
154
155static void rk3328_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
156					 int pin_num, struct regmap **regmap,
157					 int *reg, u8 *bit)
158{
159	struct rockchip_pinctrl_priv *priv = bank->priv;
160
161	*regmap = priv->regmap_base;
162	*reg = RK3328_PULL_OFFSET;
163	*reg += bank->bank_num * ROCKCHIP_PULL_BANK_STRIDE;
164	*reg += ((pin_num / ROCKCHIP_PULL_PINS_PER_REG) * 4);
165
166	*bit = (pin_num % ROCKCHIP_PULL_PINS_PER_REG);
167	*bit *= ROCKCHIP_PULL_BITS_PER_PIN;
168}
169
170static int rk3328_set_pull(struct rockchip_pin_bank *bank,
171			   int pin_num, int pull)
172{
173	struct regmap *regmap;
174	int reg, ret;
175	u8 bit, type;
176	u32 data;
177
178	if (pull == PIN_CONFIG_BIAS_PULL_PIN_DEFAULT)
179		return -ENOTSUPP;
180
181	rk3328_calc_pull_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
182	type = bank->pull_type[pin_num / 8];
183	ret = rockchip_translate_pull_value(type, pull);
184	if (ret < 0) {
185		debug("unsupported pull setting %d\n", pull);
186		return ret;
187	}
188
189	/* enable the write to the equivalent lower bits */
190	data = ((1 << ROCKCHIP_PULL_BITS_PER_PIN) - 1) << (bit + 16);
191	data |= (ret << bit);
192	ret = regmap_write(regmap, reg, data);
193
194	return ret;
195}
196
197#define RK3328_DRV_GRF_OFFSET		0x200
198
199static void rk3328_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
200					int pin_num, struct regmap **regmap,
201					int *reg, u8 *bit)
202{
203	struct rockchip_pinctrl_priv *priv = bank->priv;
204
205	*regmap = priv->regmap_base;
206	*reg = RK3328_DRV_GRF_OFFSET;
207	*reg += bank->bank_num * ROCKCHIP_DRV_BANK_STRIDE;
208	*reg += ((pin_num / ROCKCHIP_DRV_PINS_PER_REG) * 4);
209
210	*bit = (pin_num % ROCKCHIP_DRV_PINS_PER_REG);
211	*bit *= ROCKCHIP_DRV_BITS_PER_PIN;
212}
213
214static int rk3328_set_drive(struct rockchip_pin_bank *bank,
215			    int pin_num, int strength)
216{
217	struct regmap *regmap;
218	int reg, ret;
219	u32 data;
220	u8 bit;
221	int type = bank->drv[pin_num / 8].drv_type;
222
223	rk3328_calc_drv_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
224	ret = rockchip_translate_drive_value(type, strength);
225	if (ret < 0) {
226		debug("unsupported driver strength %d\n", strength);
227		return ret;
228	}
229
230	/* enable the write to the equivalent lower bits */
231	data = ((1 << ROCKCHIP_DRV_BITS_PER_PIN) - 1) << (bit + 16);
232	data |= (ret << bit);
233	ret = regmap_write(regmap, reg, data);
234
235	return ret;
236}
237
238#define RK3328_SCHMITT_BITS_PER_PIN		1
239#define RK3328_SCHMITT_PINS_PER_REG		16
240#define RK3328_SCHMITT_BANK_STRIDE		8
241#define RK3328_SCHMITT_GRF_OFFSET		0x380
242
243static int rk3328_calc_schmitt_reg_and_bit(struct rockchip_pin_bank *bank,
244					   int pin_num,
245					   struct regmap **regmap,
246					   int *reg, u8 *bit)
247{
248	struct rockchip_pinctrl_priv *priv = bank->priv;
249
250	*regmap = priv->regmap_base;
251	*reg = RK3328_SCHMITT_GRF_OFFSET;
252
253	*reg += bank->bank_num * RK3328_SCHMITT_BANK_STRIDE;
254	*reg += ((pin_num / RK3328_SCHMITT_PINS_PER_REG) * 4);
255	*bit = pin_num % RK3328_SCHMITT_PINS_PER_REG;
256
257	return 0;
258}
259
260static int rk3328_set_schmitt(struct rockchip_pin_bank *bank,
261			      int pin_num, int enable)
262{
263	struct regmap *regmap;
264	int reg;
265	u8 bit;
266	u32 data;
267
268	rk3328_calc_schmitt_reg_and_bit(bank, pin_num, &regmap, &reg, &bit);
269	/* enable the write to the equivalent lower bits */
270	data = BIT(bit + 16) | (enable << bit);
271
272	return regmap_write(regmap, reg, data);
273}
274
275static struct rockchip_pin_bank rk3328_pin_banks[] = {
276	PIN_BANK_IOMUX_FLAGS(0, 32, "gpio0", 0, 0, 0, 0),
277	PIN_BANK_IOMUX_FLAGS(1, 32, "gpio1", 0, 0, 0, 0),
278	PIN_BANK_IOMUX_FLAGS(2, 32, "gpio2", 0,
279			     IOMUX_WIDTH_3BIT,
280			     IOMUX_WIDTH_3BIT,
281			     0),
282	PIN_BANK_IOMUX_FLAGS(3, 32, "gpio3",
283			     IOMUX_WIDTH_3BIT,
284			     IOMUX_WIDTH_3BIT,
285			     0,
286			     0),
287};
288
289static struct rockchip_pin_ctrl rk3328_pin_ctrl = {
290	.pin_banks		= rk3328_pin_banks,
291	.nr_banks		= ARRAY_SIZE(rk3328_pin_banks),
292	.grf_mux_offset		= 0x0,
293	.iomux_recalced		= rk3328_mux_recalced_data,
294	.niomux_recalced	= ARRAY_SIZE(rk3328_mux_recalced_data),
295	.iomux_routes		= rk3328_mux_route_data,
296	.niomux_routes		= ARRAY_SIZE(rk3328_mux_route_data),
297	.set_mux		= rk3328_set_mux,
298	.set_pull		= rk3328_set_pull,
299	.set_drive		= rk3328_set_drive,
300	.set_schmitt		= rk3328_set_schmitt,
301};
302
303static const struct udevice_id rk3328_pinctrl_ids[] = {
304	{
305		.compatible = "rockchip,rk3328-pinctrl",
306		.data = (ulong)&rk3328_pin_ctrl
307	},
308	{ }
309};
310
311U_BOOT_DRIVER(rockchip_rk3328_pinctrl) = {
312	.name		= "rockchip_rk3328_pinctrl",
313	.id		= UCLASS_PINCTRL,
314	.of_match	= rk3328_pinctrl_ids,
315	.priv_auto	= sizeof(struct rockchip_pinctrl_priv),
316	.ops		= &rockchip_pinctrl_ops,
317#if CONFIG_IS_ENABLED(OF_REAL)
318	.bind		= dm_scan_fdt_dev,
319#endif
320	.probe		= rockchip_pinctrl_probe,
321};
322