1 /* $OpenBSD: pinctrl.c,v 1.2 2018/08/27 10:03:35 jsg Exp $ */ 2 /* 3 * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/malloc.h> 22 23 #include <machine/intr.h> 24 #include <machine/bus.h> 25 #include <machine/fdt.h> 26 27 #include <dev/ofw/openfirm.h> 28 #include <dev/ofw/ofw_misc.h> 29 #include <dev/ofw/ofw_pinctrl.h> 30 #include <dev/ofw/fdt.h> 31 32 #define HREAD2(sc, reg) \ 33 (bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, (reg))) 34 #define HWRITE2(sc, reg, val) \ 35 bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 36 #define HREAD4(sc, reg) \ 37 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 38 #define HWRITE4(sc, reg, val) \ 39 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 40 41 struct pinctrl_softc { 42 struct device sc_dev; 43 bus_space_tag_t sc_iot; 44 bus_space_handle_t sc_ioh; 45 46 uint32_t sc_reg_width; 47 uint32_t sc_func_mask; 48 }; 49 50 int pinctrl_match(struct device *, void *, void *); 51 void pinctrl_attach(struct device *, struct device *, void *); 52 53 struct cfattach pinctrl_ca = { 54 sizeof (struct pinctrl_softc), pinctrl_match, pinctrl_attach 55 }; 56 57 struct cfdriver pinctrl_cd = { 58 NULL, "pinctrl", DV_DULL 59 }; 60 61 int pinctrl_pinctrl(uint32_t, void *); 62 63 int 64 pinctrl_match(struct device *parent, void *match, void *aux) 65 { 66 struct fdt_attach_args *faa = aux; 67 68 return OF_is_compatible(faa->fa_node, "pinctrl-single"); 69 } 70 71 void 72 pinctrl_attach(struct device *parent, struct device *self, void *aux) 73 { 74 struct pinctrl_softc *sc = (struct pinctrl_softc *)self; 75 struct fdt_attach_args *faa = aux; 76 77 if (faa->fa_nreg < 1) { 78 printf(": no registers\n"); 79 return; 80 } 81 82 sc->sc_reg_width = OF_getpropint(faa->fa_node, 83 "pinctrl-single,register-width", 0); 84 if (sc->sc_reg_width != 16 && 85 sc->sc_reg_width != 32) { 86 printf(": unsupported register width\n"); 87 return; 88 } 89 90 sc->sc_func_mask = OF_getpropint(faa->fa_node, 91 "pinctrl-single,function-mask", 0); 92 if (sc->sc_func_mask == 0) { 93 printf(": bogus function mask\n"); 94 return; 95 } 96 97 sc->sc_iot = faa->fa_iot; 98 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 99 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 100 printf(": can't map registers\n"); 101 return; 102 } 103 104 pinctrl_register(faa->fa_node, pinctrl_pinctrl, sc); 105 106 printf("\n"); 107 } 108 109 int 110 pinctrl_pinctrl(uint32_t phandle, void *cookie) 111 { 112 struct pinctrl_softc *sc = cookie; 113 uint32_t *pins; 114 int node, len, i; 115 116 node = OF_getnodebyphandle(phandle); 117 if (node == 0) 118 return -1; 119 120 len = OF_getproplen(node, "pinctrl-single,pins"); 121 if (len <= 0) 122 return -1; 123 124 pins = malloc(len, M_TEMP, M_WAITOK); 125 OF_getpropintarray(node, "pinctrl-single,pins", pins, len); 126 127 for (i = 0; i < len / sizeof(uint32_t); i += 2) { 128 if (sc->sc_reg_width == 16) { 129 uint16_t reg = pins[i]; 130 uint16_t func = pins[i + 1]; 131 uint16_t val; 132 133 val = HREAD2(sc, reg); 134 val &= ~sc->sc_func_mask; 135 val |= (func & sc->sc_func_mask); 136 HWRITE2(sc, reg, val); 137 break; 138 } else if (sc->sc_reg_width == 32) { 139 uint32_t reg = pins[i]; 140 uint32_t func = pins[i + 1]; 141 uint32_t val; 142 143 val = HREAD4(sc, reg); 144 val &= ~sc->sc_func_mask; 145 val |= (func & sc->sc_func_mask); 146 HWRITE4(sc, reg, val); 147 break; 148 } 149 } 150 151 free(pins, M_TEMP, len); 152 return 0; 153 } 154