1 /* $OpenBSD: octgpio.c,v 1.2 2019/09/29 04:28:52 visa Exp $ */ 2 3 /* 4 * Copyright (c) 2019 Visa Hankala 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * Driver for OCTEON GPIO controller. 21 */ 22 23 #include <sys/param.h> 24 #include <sys/systm.h> 25 #include <sys/device.h> 26 #include <sys/malloc.h> 27 28 #include <dev/ofw/fdt.h> 29 #include <dev/ofw/ofw_gpio.h> 30 #include <dev/ofw/openfirm.h> 31 32 #include <machine/fdt.h> 33 #include <machine/octeonvar.h> 34 #include <machine/octeon_model.h> 35 36 #define GPIO_BIT_CFG(x) (0x0000u + (x) * 8) 37 #define GPIO_BIT_CFG_OUTPUT_SEL_M 0x00000000001f0000ull 38 #define GPIO_BIT_CFG_OUTPUT_SEL_S 16 39 #define GPIO_BIT_CFG_INT_EN 0x0000000000000004ull 40 #define GPIO_BIT_CFG_RX_XOR 0x0000000000000002ull 41 #define GPIO_BIT_CFG_TX_OE 0x0000000000000001ull 42 #define GPIO_XBIT_CFG(x) (0x0100u + (x) * 8) 43 #define GPIO_RX_DAT 0x0080u 44 #define GPIO_TX_SET 0x0088u 45 #define GPIO_TX_CLR 0x0090u 46 47 #define GPIO_RD_8(sc, reg) \ 48 bus_space_read_8((sc)->sc_iot, (sc)->sc_ioh, (reg)) 49 #define GPIO_WR_8(sc, reg, val) \ 50 bus_space_write_8((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 51 52 struct octgpio_softc { 53 struct device sc_dev; 54 bus_space_tag_t sc_iot; 55 bus_space_handle_t sc_ioh; 56 struct gpio_controller sc_gc; 57 uint32_t sc_npins; 58 uint32_t sc_xbit; 59 }; 60 61 int octgpio_match(struct device *, void *, void *); 62 void octgpio_attach(struct device *, struct device *, void *); 63 64 void octgpio_config_pin(void *, uint32_t *, int); 65 int octgpio_get_pin(void *, uint32_t *); 66 void octgpio_set_pin(void *, uint32_t *, int); 67 68 const struct cfattach octgpio_ca = { 69 sizeof(struct octgpio_softc), octgpio_match, octgpio_attach 70 }; 71 72 struct cfdriver octgpio_cd = { 73 NULL, "octgpio", DV_DULL 74 }; 75 76 int 77 octgpio_match(struct device *parent, void *match, void *aux) 78 { 79 struct fdt_attach_args *faa = aux; 80 81 return OF_is_compatible(faa->fa_node, "cavium,octeon-3860-gpio") || 82 OF_is_compatible(faa->fa_node, "cavium,octeon-7890-gpio"); 83 } 84 85 void 86 octgpio_attach(struct device *parent, struct device *self, void *aux) 87 { 88 struct fdt_attach_args *faa = aux; 89 struct octgpio_softc *sc = (struct octgpio_softc *)self; 90 uint32_t chipid; 91 92 if (faa->fa_nreg != 1) { 93 printf(": no registers\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, faa->fa_reg[0].size, 99 0, &sc->sc_ioh)) { 100 printf(": can't map registers\n"); 101 return; 102 } 103 104 chipid = octeon_get_chipid(); 105 switch (octeon_model_family(chipid)) { 106 case OCTEON_MODEL_FAMILY_CN61XX: 107 case OCTEON_MODEL_FAMILY_CN63XX: 108 case OCTEON_MODEL_FAMILY_CN66XX: 109 case OCTEON_MODEL_FAMILY_CN68XX: 110 case OCTEON_MODEL_FAMILY_CN71XX: 111 sc->sc_npins = 20; 112 sc->sc_xbit = 16; 113 break; 114 case OCTEON_MODEL_FAMILY_CN73XX: 115 sc->sc_npins = 32; 116 sc->sc_xbit = 0; 117 break; 118 case OCTEON_MODEL_FAMILY_CN78XX: 119 sc->sc_npins = 20; 120 sc->sc_xbit = 0; 121 break; 122 default: 123 sc->sc_npins = 24; 124 sc->sc_xbit = 16; 125 break; 126 } 127 128 sc->sc_gc.gc_node = faa->fa_node; 129 sc->sc_gc.gc_cookie = sc; 130 sc->sc_gc.gc_config_pin = octgpio_config_pin; 131 sc->sc_gc.gc_get_pin = octgpio_get_pin; 132 sc->sc_gc.gc_set_pin = octgpio_set_pin; 133 gpio_controller_register(&sc->sc_gc); 134 135 printf(": %u pins, xbit %u\n", sc->sc_npins, sc->sc_xbit); 136 } 137 138 void 139 octgpio_config_pin(void *cookie, uint32_t *cells, int config) 140 { 141 struct octgpio_softc *sc = cookie; 142 uint64_t output_sel, reg, value; 143 uint32_t pin = cells[0]; 144 145 if (pin >= sc->sc_npins) 146 return; 147 if (pin >= sc->sc_xbit) 148 reg = GPIO_XBIT_CFG(pin - sc->sc_xbit); 149 else 150 reg = GPIO_BIT_CFG(pin); 151 152 value = GPIO_RD_8(sc, reg); 153 if (config & GPIO_CONFIG_OUTPUT) { 154 value |= GPIO_BIT_CFG_TX_OE; 155 156 switch (config & GPIO_CONFIG_MD_OUTPUT_SEL_MASK) { 157 case GPIO_CONFIG_MD_USB0_VBUS_CTRL: 158 output_sel = 0x14; 159 break; 160 case GPIO_CONFIG_MD_USB1_VBUS_CTRL: 161 output_sel = 0x19; 162 break; 163 default: 164 output_sel = 0; 165 break; 166 } 167 value &= ~GPIO_BIT_CFG_OUTPUT_SEL_M; 168 value |= output_sel << GPIO_BIT_CFG_OUTPUT_SEL_S; 169 } else 170 value &= ~(GPIO_BIT_CFG_TX_OE | GPIO_BIT_CFG_RX_XOR); 171 /* There is no INT_EN bit on true XBIT pins. */ 172 value &= ~GPIO_BIT_CFG_INT_EN; 173 GPIO_WR_8(sc, reg, value); 174 } 175 176 int 177 octgpio_get_pin(void *cookie, uint32_t *cells) 178 { 179 struct octgpio_softc *sc = cookie; 180 uint32_t pin = cells[0]; 181 uint32_t flags = cells[1]; 182 int value; 183 184 if (pin >= sc->sc_npins) 185 return 0; 186 187 value = (GPIO_RD_8(sc, GPIO_RX_DAT) >> pin) & 1; 188 if (flags & GPIO_ACTIVE_LOW) 189 value = !value; 190 return value; 191 } 192 193 void 194 octgpio_set_pin(void *cookie, uint32_t *cells, int value) 195 { 196 struct octgpio_softc *sc = cookie; 197 uint32_t pin = cells[0]; 198 uint32_t flags = cells[1]; 199 200 if (pin >= sc->sc_npins) 201 return; 202 203 if (flags & GPIO_ACTIVE_LOW) 204 value = !value; 205 if (value) 206 GPIO_WR_8(sc, GPIO_TX_SET, 1ul << pin); 207 else 208 GPIO_WR_8(sc, GPIO_TX_CLR, 1ul << pin); 209 } 210