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
pio_write(struct atmel_pio * pio,unsigned int offset,uint32_t val)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
pio_conf_apply(struct pinconf * conf)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
pio_conf_free(struct pinconf * conf)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
pio_pinctrl_dt_get(struct dt_pargs * pargs,void * data,struct pinconf ** out_pinconf)79 static TEE_Result pio_pinctrl_dt_get(struct dt_pargs *pargs, void *data,
80 struct pinconf **out_pinconf)
81 {
82 TEE_Result res = TEE_ERROR_GENERIC;
83 int i = 0;
84 int func = 0;
85 int group = 0;
86 int pin_no = 0;
87 uint32_t cfg = 0;
88 int prop_count = 0;
89 int pio_group = -1;
90 uint32_t pinmux = 0;
91 uint32_t pin_mask = 0;
92 bitstr_t *cfg_modes = NULL;
93 const uint32_t *prop = NULL;
94 struct pinconf *pinconf = NULL;
95 struct atmel_pio *atmel_pio = data;
96 struct atmel_pio_pin_conf *pio_conf = NULL;
97
98 prop = fdt_getprop(pargs->fdt, pargs->phandle_node, "pinmux",
99 &prop_count);
100 if (!prop)
101 return TEE_ERROR_ITEM_NOT_FOUND;
102
103 prop_count /= sizeof(uint32_t);
104 for (i = 0; i < prop_count; i++) {
105 pinmux = fdt32_to_cpu(prop[i]);
106
107 pin_no = DT_GET_PIN_NO(pinmux);
108 func = DT_GET_FUNC(pinmux);
109
110 group = pin_no / 32;
111 if (pio_group == -1) {
112 pio_group = group;
113 } else {
114 if (group != pio_group) {
115 EMSG("Unexpected group %d vs %d", group,
116 pio_group);
117 return TEE_ERROR_GENERIC;
118 }
119 }
120
121 pin_mask |= BIT(pin_no % 32);
122 }
123
124 cfg = func;
125
126 res = pinctrl_parse_dt_pin_modes(pargs->fdt, pargs->phandle_node,
127 &cfg_modes);
128 if (res)
129 return res;
130
131 for (i = 0; i < PINCTRL_DT_PROP_MAX; i++) {
132 if (!bit_test(cfg_modes, i))
133 continue;
134
135 switch (i) {
136 case PINCTRL_DT_PROP_BIAS_PULL_UP:
137 cfg |= PIO_CFGR_PUEN;
138 cfg &= ~PIO_CFGR_PDEN;
139 break;
140 case PINCTRL_DT_PROP_BIAS_PULL_DOWN:
141 cfg |= PIO_CFGR_PDEN;
142 cfg &= ~PIO_CFGR_PUEN;
143 break;
144 case PINCTRL_DT_PROP_BIAS_DISABLE:
145 break;
146 default:
147 EMSG("Unhandled config %u", i);
148 break;
149 }
150 }
151
152 free(cfg_modes);
153
154 pinconf = calloc(1, sizeof(*pinconf) + sizeof(*pio_conf));
155 if (!pinconf)
156 return TEE_ERROR_OUT_OF_MEMORY;
157
158 pio_conf = (struct atmel_pio_pin_conf *)(pinconf + 1);
159
160 pio_conf->pin_mask = pin_mask;
161 pio_conf->pin_cfg = cfg;
162 pio_conf->pio = atmel_pio;
163 pio_conf->pio_group = pio_group;
164 pinconf->priv = pio_conf;
165 pinconf->ops = &pio_pinctrl_ops;
166
167 *out_pinconf = pinconf;
168
169 return TEE_SUCCESS;
170 }
171
pio_init_hw(struct atmel_pio * pio)172 static void pio_init_hw(struct atmel_pio *pio)
173 {
174 int i = 0;
175
176 /* Set all IOs as non-secure */
177 for (i = 0; i < PIO_GROUP_COUNT; i++)
178 pio_write(pio, PIO_SIONR(PIO_GROUP_COUNT), GENMASK_32(31, 0));
179 }
180
181 /* Non-null reference for compat data */
182 static const uint8_t has_pioe;
183
pio_node_probe(const void * fdt,int node,const void * compat_data)184 static TEE_Result pio_node_probe(const void *fdt, int node,
185 const void *compat_data)
186 {
187 size_t size = 0;
188 struct clk *clk = NULL;
189 struct atmel_pio *pio = NULL;
190 TEE_Result res = TEE_ERROR_GENERIC;
191
192 if (fdt_get_status(fdt, node) != DT_STATUS_OK_SEC)
193 return TEE_ERROR_BAD_STATE;
194
195 pio = calloc(1, sizeof(*pio));
196 if (!pio)
197 return TEE_ERROR_OUT_OF_MEMORY;
198
199 res = clk_dt_get_by_index(fdt, node, 0, &clk);
200 if (res)
201 goto free_pio;
202
203 if (dt_map_dev(fdt, node, &pio->base, &size, DT_MAP_AUTO) < 0)
204 goto free_pio;
205
206 res = clk_enable(clk);
207 if (res)
208 goto free_pio;
209
210 matrix_configure_periph_secure(AT91C_ID_PIOA);
211 matrix_configure_periph_secure(AT91C_ID_PIOB);
212 matrix_configure_periph_secure(AT91C_ID_PIOC);
213 matrix_configure_periph_secure(AT91C_ID_PIOD);
214
215 if (compat_data == &has_pioe)
216 matrix_configure_periph_secure(AT91C_ID_PIOD + 1);
217
218 pio_init_hw(pio);
219
220 res = pinctrl_register_provider(fdt, node, pio_pinctrl_dt_get, pio);
221 if (res)
222 goto disable_clock;
223
224 return TEE_SUCCESS;
225
226 disable_clock:
227 clk_disable(clk);
228 free_pio:
229 free(pio);
230
231 return res;
232 }
233
234 static const struct dt_device_match atmel_pio_match_table[] = {
235 { .compatible = "atmel,sama5d2-pinctrl" },
236 {
237 .compatible = "microchip,sama7g5-pinctrl",
238 .compat_data = &has_pioe,
239 },
240 { }
241 };
242
243 DEFINE_DT_DRIVER(atmel_pio_dt_driver) = {
244 .name = "atmel_pio",
245 .type = DT_DRIVER_PINCTRL,
246 .match_table = atmel_pio_match_table,
247 .probe = pio_node_probe,
248 };
249