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 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 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 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