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
octgpio_match(struct device * parent,void * match,void * aux)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
octgpio_attach(struct device * parent,struct device * self,void * aux)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
octgpio_config_pin(void * cookie,uint32_t * cells,int config)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
octgpio_get_pin(void * cookie,uint32_t * cells)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
octgpio_set_pin(void * cookie,uint32_t * cells,int value)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