xref: /optee_os/core/drivers/pinctrl/atmel_pio.c (revision 12fc37711783247b0d05fdc271ef007f4930767b)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright 2019 Microchip.
4  */
5 #include <assert.h>
6 #include <drivers/clk.h>
7 #include <drivers/clk_dt.h>
8 #include <drivers/pinctrl.h>
9 #include <initcall.h>
10 #include <io.h>
11 #include <kernel/dt.h>
12 #include <libfdt.h>
13 #include <malloc.h>
14 #include <matrix.h>
15 #include <platform_config.h>
16 #include <trace.h>
17 #include <util.h>
18 
19 #define PIO_GROUP_COUNT		4
20 #define PIO_GROUP_OFFSET	0x40
21 #define PIO_REG(reg, group)	((reg) + ((group) * PIO_GROUP_OFFSET))
22 /* Mask register */
23 #define PIO_MSKR(group)		PIO_REG(0x0, (group))
24 /* Configuration register */
25 #define PIO_CFGR(group)		PIO_REG(0x4, (group))
26 #define PIO_CFGR_FUNC		GENMASK(2, 0)
27 #define PIO_CFGR_PUEN		BIT(9)
28 #define PIO_CFGR_PDEN		BIT(10)
29 
30 /* Non-Secure configuration register */
31 #define PIO_SIONR(group)	PIO_REG(0x30, (group))
32 /* Secure configuration register */
33 #define PIO_SIOSR(group)	PIO_REG(0x34, (group))
34 
35 #define DT_GET_PIN_NO(val)	((val) & 0xFF)
36 #define DT_GET_FUNC(val)	(((val) >> 16) & 0xF)
37 
38 struct atmel_pio {
39 	vaddr_t base;
40 };
41 
42 struct atmel_pio_pin_conf {
43 	uint32_t pin_mask;
44 	uint32_t pin_cfg;
45 	uint8_t pio_group;
46 	struct atmel_pio *pio;
47 };
48 
49 static void pio_write(struct atmel_pio *pio, unsigned int offset, uint32_t val)
50 {
51 	io_write32(pio->base + offset, val);
52 }
53 
54 static TEE_Result pio_conf_apply(struct pinconf *conf)
55 {
56 	struct atmel_pio_pin_conf *pio_conf = conf->priv;
57 	struct atmel_pio *pio = pio_conf->pio;
58 
59 	DMSG("Apply cfg %#" PRIx32 " on group %" PRIu8 ", pins %#" PRIx32,
60 	     pio_conf->pin_cfg, pio_conf->pio_group, pio_conf->pin_mask);
61 
62 	pio_write(pio, PIO_SIOSR(pio_conf->pio_group), pio_conf->pin_mask);
63 	pio_write(pio, PIO_MSKR(pio_conf->pio_group), pio_conf->pin_mask);
64 	pio_write(pio, PIO_CFGR(pio_conf->pio_group), pio_conf->pin_cfg);
65 
66 	return TEE_SUCCESS;
67 }
68 
69 static void pio_conf_free(struct pinconf *conf)
70 {
71 	free(conf);
72 }
73 
74 static const struct pinctrl_ops pio_pinctrl_ops = {
75 	.conf_apply = pio_conf_apply,
76 	.conf_free = pio_conf_free,
77 };
78 
79 static struct pinconf *pio_pinctrl_dt_get(struct dt_pargs *pargs,
80 					  void *data, TEE_Result *res)
81 {
82 	int i = 0;
83 	int func = 0;
84 	int group = 0;
85 	int pin_no = 0;
86 	uint32_t cfg = 0;
87 	int prop_count = 0;
88 	int pio_group = -1;
89 	uint32_t pinmux = 0;
90 	uint32_t pin_mask = 0;
91 	bitstr_t *cfg_modes = NULL;
92 	const uint32_t *prop = NULL;
93 	struct pinconf *pinconf = NULL;
94 	struct atmel_pio *atmel_pio = data;
95 	struct atmel_pio_pin_conf *pio_conf = NULL;
96 
97 	prop = fdt_getprop(pargs->fdt, pargs->phandle_node, "pinmux",
98 			   &prop_count);
99 	if (!prop) {
100 		*res = TEE_ERROR_ITEM_NOT_FOUND;
101 		return NULL;
102 	}
103 
104 	prop_count /= sizeof(uint32_t);
105 	for (i = 0; i < prop_count; i++) {
106 		pinmux = fdt32_to_cpu(prop[i]);
107 
108 		pin_no = DT_GET_PIN_NO(pinmux);
109 		func = DT_GET_FUNC(pinmux);
110 
111 		group = pin_no / 32;
112 		if (pio_group == -1) {
113 			pio_group = group;
114 		} else {
115 			if (group != pio_group) {
116 				EMSG("Unexpected group %d vs %d", group,
117 				     pio_group);
118 				*res = TEE_ERROR_GENERIC;
119 				return NULL;
120 			}
121 		}
122 
123 		pin_mask |= BIT(pin_no % 32);
124 	}
125 
126 	cfg = func;
127 
128 	*res = pinctrl_parse_dt_pin_modes(pargs->fdt, pargs->phandle_node,
129 					  &cfg_modes);
130 	if (*res)
131 		return NULL;
132 
133 	for (i = 0; i < PINCTRL_DT_PROP_MAX; i++) {
134 		if (!bit_test(cfg_modes, i))
135 			continue;
136 
137 		switch (i) {
138 		case PINCTRL_DT_PROP_BIAS_PULL_UP:
139 			cfg |= PIO_CFGR_PUEN;
140 			cfg &= ~PIO_CFGR_PDEN;
141 			break;
142 		case PINCTRL_DT_PROP_BIAS_PULL_DOWN:
143 			cfg |= PIO_CFGR_PDEN;
144 			cfg &= ~PIO_CFGR_PUEN;
145 			break;
146 		case PINCTRL_DT_PROP_BIAS_DISABLE:
147 			break;
148 		default:
149 			EMSG("Unhandled config %u", i);
150 			break;
151 		}
152 	}
153 
154 	free(cfg_modes);
155 
156 	pinconf = calloc(1, sizeof(*pinconf) + sizeof(*pio_conf));
157 	if (!pinconf) {
158 		*res = TEE_ERROR_OUT_OF_MEMORY;
159 		return NULL;
160 	}
161 
162 	pio_conf = (struct atmel_pio_pin_conf *)(pinconf + 1);
163 
164 	pio_conf->pin_mask = pin_mask;
165 	pio_conf->pin_cfg = cfg;
166 	pio_conf->pio = atmel_pio;
167 	pio_conf->pio_group = pio_group;
168 	pinconf->priv = pio_conf;
169 	pinconf->ops = &pio_pinctrl_ops;
170 
171 	*res = TEE_SUCCESS;
172 
173 	return pinconf;
174 }
175 
176 static void pio_init_hw(struct atmel_pio *pio)
177 {
178 	int i = 0;
179 
180 	/* Set all IOs as non-secure */
181 	for (i = 0; i < PIO_GROUP_COUNT; i++)
182 		pio_write(pio, PIO_SIONR(PIO_GROUP_COUNT), GENMASK_32(31, 0));
183 }
184 
185 static TEE_Result pio_node_probe(const void *fdt, int node,
186 				 const void *compat_data __unused)
187 {
188 	size_t size = 0;
189 	struct clk *clk = NULL;
190 	struct atmel_pio *pio = NULL;
191 	TEE_Result res = TEE_ERROR_GENERIC;
192 
193 	if (fdt_get_status(fdt, node) != DT_STATUS_OK_SEC)
194 		return TEE_ERROR_BAD_STATE;
195 
196 	pio = calloc(1, sizeof(*pio));
197 	if (!pio)
198 		return TEE_ERROR_OUT_OF_MEMORY;
199 
200 	res = clk_dt_get_by_index(fdt, node, 0, &clk);
201 	if (res)
202 		goto free_pio;
203 
204 	if (dt_map_dev(fdt, node, &pio->base, &size, DT_MAP_AUTO) < 0)
205 		goto free_pio;
206 
207 	res = clk_enable(clk);
208 	if (res)
209 		goto free_pio;
210 
211 	matrix_configure_periph_secure(AT91C_ID_PIOA);
212 	matrix_configure_periph_secure(AT91C_ID_PIOB);
213 	matrix_configure_periph_secure(AT91C_ID_PIOC);
214 	matrix_configure_periph_secure(AT91C_ID_PIOD);
215 
216 	pio_init_hw(pio);
217 
218 	res = pinctrl_register_provider(fdt, node, pio_pinctrl_dt_get, pio);
219 	if (res)
220 		goto disable_clock;
221 
222 	return TEE_SUCCESS;
223 
224 disable_clock:
225 	clk_disable(clk);
226 free_pio:
227 	free(pio);
228 
229 	return res;
230 }
231 
232 static const struct dt_device_match atmel_pio_match_table[] = {
233 	{ .compatible = "atmel,sama5d2-pinctrl" },
234 	{ }
235 };
236 
237 DEFINE_DT_DRIVER(atmel_pio_dt_driver) = {
238 	.name = "atmel_pio",
239 	.type = DT_DRIVER_PINCTRL,
240 	.match_table = atmel_pio_match_table,
241 	.probe = pio_node_probe,
242 };
243