xref: /rk3399_rockchip-uboot/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c (revision 510454db045143e374a7d64e6bb043799d0023d7)
1 /*
2  * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <mapmem.h>
9 #include <linux/io.h>
10 #include <linux/err.h>
11 #include <linux/sizes.h>
12 #include <dm/device.h>
13 #include <dm/pinctrl.h>
14 
15 #include "pinctrl-uniphier.h"
16 
17 static int uniphier_pinctrl_get_groups_count(struct udevice *dev)
18 {
19 	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
20 
21 	return priv->socdata->groups_count;
22 }
23 
24 static const char *uniphier_pinctrl_get_group_name(struct udevice *dev,
25 						   unsigned selector)
26 {
27 	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
28 
29 	return priv->socdata->groups[selector].name;
30 }
31 
32 static int uniphier_pinmux_get_functions_count(struct udevice *dev)
33 {
34 	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
35 
36 	return priv->socdata->functions_count;
37 }
38 
39 static const char *uniphier_pinmux_get_function_name(struct udevice *dev,
40 						     unsigned selector)
41 {
42 	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
43 
44 	return priv->socdata->functions[selector];
45 }
46 
47 static void uniphier_pinconf_input_enable(struct udevice *dev, unsigned pin)
48 {
49 	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
50 	int pins_count = priv->socdata->pins_count;
51 	const struct uniphier_pinctrl_pin *pins = priv->socdata->pins;
52 	int i;
53 
54 	for (i = 0; i < pins_count; i++) {
55 		if (pins[i].number == pin) {
56 			unsigned int iectrl;
57 			u32 tmp;
58 
59 			iectrl = uniphier_pin_get_iectrl(pins[i].data);
60 			tmp = readl(priv->base + UNIPHIER_PINCTRL_IECTRL);
61 			tmp |= 1 << iectrl;
62 			writel(tmp, priv->base + UNIPHIER_PINCTRL_IECTRL);
63 		}
64 	}
65 }
66 
67 static void uniphier_pinmux_set_one(struct udevice *dev, unsigned pin,
68 				    unsigned muxval)
69 {
70 	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
71 	unsigned mux_bits = priv->socdata->mux_bits;
72 	unsigned reg_stride = priv->socdata->reg_stride;
73 	unsigned reg, reg_end, shift, mask;
74 	u32 tmp;
75 
76 	/* some pins need input-enabling */
77 	uniphier_pinconf_input_enable(dev, pin);
78 
79 	reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride;
80 	reg_end = reg + reg_stride;
81 	shift = pin * mux_bits % 32;
82 	mask = (1U << mux_bits) - 1;
83 
84 	/*
85 	 * If reg_stride is greater than 4, the MSB of each pinsel shall be
86 	 * stored in the offset+4.
87 	 */
88 	for (; reg < reg_end; reg += 4) {
89 		tmp = readl(priv->base + reg);
90 		tmp &= ~(mask << shift);
91 		tmp |= (mask & muxval) << shift;
92 		writel(tmp, priv->base + reg);
93 
94 		muxval >>= mux_bits;
95 	}
96 
97 	if (priv->socdata->load_pinctrl)
98 		writel(1, priv->base + UNIPHIER_PINCTRL_LOAD_PINMUX);
99 }
100 
101 static int uniphier_pinmux_group_set(struct udevice *dev,
102 				     unsigned group_selector,
103 				     unsigned func_selector)
104 {
105 	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
106 	const struct uniphier_pinctrl_group *grp =
107 					&priv->socdata->groups[group_selector];
108 	int i;
109 
110 	for (i = 0; i < grp->num_pins; i++)
111 		uniphier_pinmux_set_one(dev, grp->pins[i], grp->muxvals[i]);
112 
113 	return 0;
114 }
115 
116 const struct pinctrl_ops uniphier_pinctrl_ops = {
117 	.get_groups_count = uniphier_pinctrl_get_groups_count,
118 	.get_group_name = uniphier_pinctrl_get_group_name,
119 	.get_functions_count = uniphier_pinmux_get_functions_count,
120 	.get_function_name = uniphier_pinmux_get_function_name,
121 	.pinmux_group_set = uniphier_pinmux_group_set,
122 	.set_state = pinctrl_generic_set_state,
123 };
124 
125 int uniphier_pinctrl_probe(struct udevice *dev,
126 			   struct uniphier_pinctrl_socdata *socdata)
127 {
128 	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
129 	fdt_addr_t addr;
130 
131 	addr = dev_get_addr(dev);
132 	if (addr == FDT_ADDR_T_NONE)
133 		return -EINVAL;
134 
135 	priv->base = map_sysmem(addr, SZ_4K);
136 	if (!priv->base)
137 		return -ENOMEM;
138 
139 	priv->socdata = socdata;
140 
141 	return 0;
142 }
143 
144 int uniphier_pinctrl_remove(struct udevice *dev)
145 {
146 	struct uniphier_pinctrl_priv *priv = dev_get_priv(dev);
147 
148 	unmap_sysmem(priv->base);
149 
150 	return 0;
151 }
152