File indexing completed on 2025-05-11 08:23:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052 #include <sys/param.h>
0053 #ifndef __rtems__
0054 #include <sys/systm.h>
0055 #include <sys/bus.h>
0056 #include <sys/kernel.h>
0057 #include <sys/module.h>
0058 #include <sys/malloc.h>
0059 #include <sys/rman.h>
0060
0061 #include <machine/bus.h>
0062
0063 #include <dev/ofw/openfirm.h>
0064 #include <dev/ofw/ofw_bus.h>
0065 #include <dev/ofw/ofw_bus_subr.h>
0066 #include <dev/fdt/fdt_pinctrl.h>
0067 #endif
0068
0069 #include <arm/freescale/imx/imx_iomuxvar.h>
0070 #ifndef __rtems__
0071 #include <arm/freescale/imx/imx_machdep.h>
0072 #else
0073 #include <bsp.h>
0074 #include <bsp/fdt.h>
0075 #include <bsp/imx-iomux.h>
0076 #include <rtems/sysinit.h>
0077 #include <errno.h>
0078 #include <libfdt.h>
0079 #include <stdlib.h>
0080
0081 typedef size_t bus_size_t;
0082 typedef int phandle_t;
0083 #endif
0084
0085 struct iomux_softc {
0086 #ifndef __rtems__
0087 device_t dev;
0088 struct resource *mem_res;
0089 u_int last_gpregaddr;
0090 #else
0091 volatile uint32_t *regs;
0092 #endif
0093 };
0094
0095 #ifndef __rtems__
0096 static struct iomux_softc *iomux_sc;
0097
0098 static struct ofw_compat_data compat_data[] = {
0099 {"fsl,imx6dl-iomuxc", true},
0100 {"fsl,imx6q-iomuxc", true},
0101 {"fsl,imx6sl-iomuxc", true},
0102 {"fsl,imx6ul-iomuxc", true},
0103 {"fsl,imx6sx-iomuxc", true},
0104 {"fsl,imx53-iomuxc", true},
0105 {"fsl,imx51-iomuxc", true},
0106 {NULL, false},
0107 };
0108 #else
0109 static struct iomux_softc iomux_sc_instance;
0110
0111 #define iomux_sc (&iomux_sc_instance);
0112
0113
0114 static bool
0115 imx_fdt_node_status_okay(const void *fdt, int node)
0116 {
0117 const void *status;
0118 int len;
0119
0120 status = fdt_getprop(fdt, node, "status", &len);
0121 if ((status == NULL) ||
0122 (strncmp(status, "okay", MIN(5, len)) == 0) ||
0123 (strncmp(status, "ok", MIN(3, len)) == 0)) {
0124 return true;
0125 }
0126
0127 return false;
0128 }
0129
0130
0131
0132
0133
0134
0135 static void
0136 imx_pinctrl_configure_children(const void *fdt, int parent)
0137 {
0138 int node;
0139 const uint32_t *phandle;
0140 int len;
0141
0142 fdt_for_each_subnode(node, fdt, parent) {
0143 if (imx_fdt_node_status_okay(fdt, node)) {
0144 imx_pinctrl_configure_children(fdt, node);
0145 phandle = fdt_getprop(fdt, node, "pinctrl-0", &len);
0146 if (phandle != NULL && len == sizeof(*phandle)) {
0147 imx_iomux_configure_pins(fdt,
0148 fdt32_to_cpu(*phandle));
0149 }
0150 }
0151 }
0152 }
0153
0154 static void
0155 imx_iomux_init(void)
0156 {
0157 const void *fdt;
0158 int node;
0159 struct iomux_softc *sc;
0160
0161 fdt = bsp_fdt_get();
0162 node = fdt_node_offset_by_compatible(fdt, -1, "fsl,imx7d-iomuxc");
0163 if (node < 0) {
0164 node = fdt_node_offset_by_compatible(fdt, -1,
0165 "fsl,imx6ul-iomuxc");
0166 }
0167 if (node < 0) {
0168 node = fdt_node_offset_by_compatible(fdt, -1,
0169 "nxp,imxrt1050-iomuxc");
0170 }
0171 sc = iomux_sc;
0172 sc->regs = imx_get_reg_of_node(fdt, node);
0173
0174 node = fdt_path_offset(fdt, "/");
0175 imx_pinctrl_configure_children(fdt, node);
0176 }
0177
0178 RTEMS_SYSINIT_ITEM(imx_iomux_init, RTEMS_SYSINIT_BSP_START,
0179 RTEMS_SYSINIT_ORDER_MIDDLE);
0180
0181 #define OF_node_from_xref(phandle) fdt_node_offset_by_phandle(fdt, phandle)
0182
0183 static int
0184 imx_iomux_getencprop_alloc(const char *fdt, int node, const char *name,
0185 size_t elsz, void **buf)
0186 {
0187 int len;
0188 const uint32_t *val;
0189 int i;
0190 uint32_t *cell;
0191
0192 val = fdt_getprop(fdt, node, "fsl,pins", &len);
0193 if (val == NULL || len < 0 || len % elsz != 0) {
0194 return (-1);
0195 }
0196
0197 cell = malloc((size_t)len);
0198 *buf = cell;
0199 if (cell == NULL) {
0200 return (-1);
0201 }
0202
0203 for (i = 0; i < len / 4; ++i) {
0204 cell[i] = fdt32_to_cpu(val[i]);
0205 }
0206
0207 return (len / (int)elsz);
0208 }
0209
0210 #define OF_getencprop_alloc(node, name, elsz, buf) \
0211 imx_iomux_getencprop_alloc(fdt, node, name, elsz, buf)
0212
0213 #define OF_prop_free(buf) free(buf)
0214 #endif
0215
0216
0217
0218
0219 struct pincfg {
0220 uint32_t mux_reg;
0221 uint32_t padconf_reg;
0222 uint32_t input_reg;
0223 uint32_t mux_val;
0224 uint32_t input_val;
0225 uint32_t padconf_val;
0226 };
0227
0228 #define PADCONF_NONE (1U << 31)
0229 #define PADCONF_SION (1U << 30)
0230 #define PADMUX_SION (1U << 4)
0231
0232 static inline uint32_t
0233 RD4(struct iomux_softc *sc, bus_size_t off)
0234 {
0235
0236 #ifndef __rtems__
0237 return (bus_read_4(sc->mem_res, off));
0238 #else
0239 return (sc->regs[off / 4]);
0240 #endif
0241 }
0242
0243 static inline void
0244 WR4(struct iomux_softc *sc, bus_size_t off, uint32_t val)
0245 {
0246
0247 #ifndef __rtems__
0248 bus_write_4(sc->mem_res, off, val);
0249 #else
0250 sc->regs[off / 4] = val;
0251 #endif
0252 }
0253
0254 static void
0255 iomux_configure_input(struct iomux_softc *sc, uint32_t reg, uint32_t val)
0256 {
0257 u_int select, mask, shift, width;
0258
0259
0260 if (reg == 0 && val == 0)
0261 return;
0262
0263
0264
0265
0266
0267
0268
0269
0270 if ((val & 0xff000000) == 0xff000000) {
0271 select = val & 0x000000ff;
0272 width = (val & 0x0000ff00) >> 8;
0273 shift = (val & 0x00ff0000) >> 16;
0274 mask = ((1u << width) - 1) << shift;
0275 val = (RD4(sc, reg) & ~mask) | (select << shift);
0276 }
0277 WR4(sc, reg, val);
0278 }
0279
0280 #ifndef __rtems__
0281 static int
0282 iomux_configure_pins(device_t dev, phandle_t cfgxref)
0283 #else
0284 int imx_iomux_configure_pins(const void *fdt, uint32_t cfgxref)
0285 #endif
0286 {
0287 struct iomux_softc *sc;
0288 struct pincfg *cfgtuples, *cfg;
0289 phandle_t cfgnode;
0290 int i, ntuples;
0291 uint32_t sion;
0292
0293 #ifndef __rtems__
0294 sc = device_get_softc(dev);
0295 #else
0296 sc = iomux_sc;
0297 #endif
0298 cfgnode = OF_node_from_xref(cfgxref);
0299 ntuples = OF_getencprop_alloc(cfgnode, "fsl,pins", sizeof(*cfgtuples),
0300 (void **)&cfgtuples);
0301 if (ntuples < 0)
0302 return (ENOENT);
0303 if (ntuples == 0)
0304 return (0);
0305 for (i = 0, cfg = cfgtuples; i < ntuples; i++, cfg++) {
0306 sion = (cfg->padconf_val & PADCONF_SION) ? PADMUX_SION : 0;
0307 WR4(sc, cfg->mux_reg, cfg->mux_val | sion);
0308 iomux_configure_input(sc, cfg->input_reg, cfg->input_val);
0309 if ((cfg->padconf_val & PADCONF_NONE) == 0)
0310 #ifndef __rtems__
0311 WR4(sc, cfg->padconf_reg, cfg->padconf_val);
0312 #else
0313
0314
0315
0316
0317
0318 WR4(sc, cfg->padconf_reg, cfg->padconf_val
0319 & ~(PADCONF_SION | PADCONF_NONE));
0320 #endif
0321 #ifndef __rtems__
0322 if (bootverbose) {
0323 char name[32];
0324 OF_getprop(cfgnode, "name", &name, sizeof(name));
0325 printf("%16s: muxreg 0x%04x muxval 0x%02x "
0326 "inpreg 0x%04x inpval 0x%02x "
0327 "padreg 0x%04x padval 0x%08x\n",
0328 name, cfg->mux_reg, cfg->mux_val | sion,
0329 cfg->input_reg, cfg->input_val,
0330 cfg->padconf_reg, cfg->padconf_val);
0331 }
0332 #endif
0333 }
0334 OF_prop_free(cfgtuples);
0335 return (0);
0336 }
0337
0338 #ifndef __rtems__
0339 static int
0340 iomux_probe(device_t dev)
0341 {
0342
0343 if (!ofw_bus_status_okay(dev))
0344 return (ENXIO);
0345
0346 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
0347 return (ENXIO);
0348
0349 device_set_desc(dev, "Freescale i.MX pin configuration");
0350 return (BUS_PROBE_DEFAULT);
0351 }
0352
0353 static int
0354 iomux_detach(device_t dev)
0355 {
0356
0357
0358 return (EBUSY);
0359 }
0360
0361 static int
0362 iomux_attach(device_t dev)
0363 {
0364 struct iomux_softc * sc;
0365 int rid;
0366
0367 sc = device_get_softc(dev);
0368 sc->dev = dev;
0369
0370 switch (imx_soc_type()) {
0371 case IMXSOC_51:
0372 sc->last_gpregaddr = 1 * sizeof(uint32_t);
0373 break;
0374 case IMXSOC_53:
0375 sc->last_gpregaddr = 2 * sizeof(uint32_t);
0376 break;
0377 case IMXSOC_6DL:
0378 case IMXSOC_6S:
0379 case IMXSOC_6SL:
0380 case IMXSOC_6Q:
0381 sc->last_gpregaddr = 13 * sizeof(uint32_t);
0382 break;
0383 case IMXSOC_6UL:
0384 sc->last_gpregaddr = 14 * sizeof(uint32_t);
0385 break;
0386 default:
0387 device_printf(dev, "Unknown SoC type\n");
0388 return (ENXIO);
0389 }
0390
0391 rid = 0;
0392 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
0393 RF_ACTIVE);
0394 if (sc->mem_res == NULL) {
0395 device_printf(dev, "Cannot allocate memory resources\n");
0396 return (ENXIO);
0397 }
0398
0399 iomux_sc = sc;
0400
0401
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413 fdt_pinctrl_register(dev, "fsl,pins");
0414 fdt_pinctrl_configure_tree(dev);
0415
0416 return (0);
0417 }
0418
0419 uint32_t
0420 imx_iomux_gpr_get(u_int regaddr)
0421 {
0422 struct iomux_softc * sc;
0423
0424 sc = iomux_sc;
0425 KASSERT(sc != NULL, ("%s called before attach", __FUNCTION__));
0426 KASSERT(regaddr >= 0 && regaddr <= sc->last_gpregaddr,
0427 ("%s bad regaddr %u, max %u", __FUNCTION__, regaddr,
0428 sc->last_gpregaddr));
0429
0430 return (RD4(iomux_sc, regaddr));
0431 }
0432
0433 void
0434 imx_iomux_gpr_set(u_int regaddr, uint32_t val)
0435 {
0436 struct iomux_softc * sc;
0437
0438 sc = iomux_sc;
0439 KASSERT(sc != NULL, ("%s called before attach", __FUNCTION__));
0440 KASSERT(regaddr >= 0 && regaddr <= sc->last_gpregaddr,
0441 ("%s bad regaddr %u, max %u", __FUNCTION__, regaddr,
0442 sc->last_gpregaddr));
0443
0444 WR4(iomux_sc, regaddr, val);
0445 }
0446
0447 void
0448 imx_iomux_gpr_set_masked(u_int regaddr, uint32_t clrbits, uint32_t setbits)
0449 {
0450 struct iomux_softc * sc;
0451 uint32_t val;
0452
0453 sc = iomux_sc;
0454 KASSERT(sc != NULL, ("%s called before attach", __FUNCTION__));
0455 KASSERT(regaddr >= 0 && regaddr <= sc->last_gpregaddr,
0456 ("%s bad regaddr %u, max %u", __FUNCTION__, regaddr,
0457 sc->last_gpregaddr));
0458
0459 val = RD4(iomux_sc, regaddr * 4);
0460 val = (val & ~clrbits) | setbits;
0461 WR4(iomux_sc, regaddr, val);
0462 }
0463
0464 static device_method_t imx_iomux_methods[] = {
0465
0466 DEVMETHOD(device_probe, iomux_probe),
0467 DEVMETHOD(device_attach, iomux_attach),
0468 DEVMETHOD(device_detach, iomux_detach),
0469
0470
0471 DEVMETHOD(fdt_pinctrl_configure,iomux_configure_pins),
0472
0473 DEVMETHOD_END
0474 };
0475
0476 static driver_t imx_iomux_driver = {
0477 "imx_iomux",
0478 imx_iomux_methods,
0479 sizeof(struct iomux_softc),
0480 };
0481
0482 static devclass_t imx_iomux_devclass;
0483
0484 EARLY_DRIVER_MODULE(imx_iomux, simplebus, imx_iomux_driver,
0485 imx_iomux_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_LATE);
0486
0487 #endif