This source file includes following definitions.
- elansc_match
- elansc_attach
- elansc_tc_read
- elansc_wdogctl
- elansc_wdogctl_cb
- elansc_update_cpuspeed
- elansc_setperf
- elansc_cpuspeed
- elansc_gpio_pin_read
- elansc_gpio_pin_write
- elansc_gpio_pin_ctl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/device.h>
49 #include <sys/gpio.h>
50 #include <sys/sysctl.h>
51 #include <sys/time.h>
52 #include <sys/timetc.h>
53
54 #include <machine/bus.h>
55
56 #include <dev/pci/pcivar.h>
57 #include <dev/pci/pcidevs.h>
58
59 #include <dev/gpio/gpiovar.h>
60
61 #include <arch/i386/pci/elan520reg.h>
62
63 struct elansc_softc {
64 struct device sc_dev;
65 bus_space_tag_t sc_memt;
66 bus_space_handle_t sc_memh;
67
68
69 struct gpio_chipset_tag sc_gpio_gc;
70 gpio_pin_t sc_gpio_pins[ELANSC_PIO_NPINS];
71
72
73 struct timecounter sc_tc;
74 } *elansc;
75
76 int elansc_match(struct device *, void *, void *);
77 void elansc_attach(struct device *, struct device *, void *);
78 void elansc_update_cpuspeed(void);
79 void elansc_setperf(int);
80 int elansc_cpuspeed(int *);
81
82 void elansc_wdogctl(struct elansc_softc *, int, uint16_t);
83 #define elansc_wdogctl_reset(sc) elansc_wdogctl(sc, 1, 0)
84 #define elansc_wdogctl_write(sc, val) elansc_wdogctl(sc, 0, val)
85 int elansc_wdogctl_cb(void *, int);
86
87 int elansc_gpio_pin_read(void *, int);
88 void elansc_gpio_pin_write(void *, int, int);
89 void elansc_gpio_pin_ctl(void *, int, int);
90
91 u_int elansc_tc_read(struct timecounter *);
92
93 struct cfattach elansc_ca = {
94 sizeof(struct elansc_softc), elansc_match, elansc_attach
95 };
96
97 struct cfdriver elansc_cd = {
98 NULL, "elansc", DV_DULL
99 };
100
101 static int cpuspeed;
102
103 int
104 elansc_match(struct device *parent, void *match, void *aux)
105 {
106 struct pci_attach_args *pa = aux;
107
108 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_AMD &&
109 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_AMD_ELANSC520)
110 return (10);
111
112 return (0);
113 }
114
115 static const char *elansc_speeds[] = {
116 "(reserved 00)",
117 "100MHz",
118 "133MHz",
119 "(reserved 11)",
120 };
121
122 #define RSTBITS "\20\x07SCP\x06HRST\x05SRST\x04WDT\x03SD\x02PRGRST\x01PWRGOOD"
123
124 void
125 elansc_attach(struct device *parent, struct device *self, void *aux)
126 {
127 struct elansc_softc *sc = (void *) self;
128 struct pci_attach_args *pa = aux;
129 struct gpiobus_attach_args gba;
130 struct timecounter *tc;
131 uint16_t rev, data;
132 uint8_t ressta, cpuctl, tmr;
133 int pin, reg, shift;
134
135 sc->sc_memt = pa->pa_memt;
136 if (bus_space_map(sc->sc_memt, MMCR_BASE_ADDR, NBPG, 0,
137 &sc->sc_memh) != 0) {
138 printf(": unable to map registers\n");
139 return;
140 }
141
142 rev = bus_space_read_2(sc->sc_memt, sc->sc_memh, MMCR_REVID);
143 cpuctl = bus_space_read_1(sc->sc_memt, sc->sc_memh, MMCR_CPUCTL);
144 ressta = bus_space_read_1(sc->sc_memt, sc->sc_memh, MMCR_RESSTA);
145
146 printf(": product %d stepping %d.%d, CPU clock %s, reset %b\n",
147 (rev & REVID_PRODID) >> REVID_PRODID_SHIFT,
148 (rev & REVID_MAJSTEP) >> REVID_MAJSTEP_SHIFT,
149 (rev & REVID_MINSTEP),
150 elansc_speeds[cpuctl & CPUCTL_CPU_CLK_SPD_MASK],
151 ressta, RSTBITS);
152
153
154
155
156
157 if (ressta & RESSTA_WDT_RST_DET)
158 printf("%s: WARNING: LAST RESET DUE TO WATCHDOG EXPIRATION!\n",
159 sc->sc_dev.dv_xname);
160 bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_RESSTA, ressta);
161
162
163 elansc_wdogctl_write(sc, WDTMRCTL_WRST_ENB | WDTMRCTL_EXP_SEL30);
164
165
166 elansc_wdogctl_reset(sc);
167
168 wdog_register(sc, elansc_wdogctl_cb);
169 elansc = sc;
170 cpu_setperf = elansc_setperf;
171 cpu_cpuspeed = elansc_cpuspeed;
172 elansc_update_cpuspeed();
173
174
175 for (pin = 0; pin < ELANSC_PIO_NPINS; pin++) {
176 sc->sc_gpio_pins[pin].pin_num = pin;
177 sc->sc_gpio_pins[pin].pin_caps = GPIO_PIN_INPUT |
178 GPIO_PIN_OUTPUT;
179
180
181 reg = (pin < 16 ? MMCR_PIODIR15_0 : MMCR_PIODIR31_16);
182 shift = pin % 16;
183 data = bus_space_read_2(sc->sc_memt, sc->sc_memh, reg);
184 if ((data & (1 << shift)) == 0)
185 sc->sc_gpio_pins[pin].pin_flags = GPIO_PIN_INPUT;
186 else
187 sc->sc_gpio_pins[pin].pin_flags = GPIO_PIN_OUTPUT;
188 if (elansc_gpio_pin_read(sc, pin) == 0)
189 sc->sc_gpio_pins[pin].pin_state = GPIO_PIN_LOW;
190 else
191 sc->sc_gpio_pins[pin].pin_state = GPIO_PIN_HIGH;
192 }
193
194
195 sc->sc_gpio_gc.gp_cookie = sc;
196 sc->sc_gpio_gc.gp_pin_read = elansc_gpio_pin_read;
197 sc->sc_gpio_gc.gp_pin_write = elansc_gpio_pin_write;
198 sc->sc_gpio_gc.gp_pin_ctl = elansc_gpio_pin_ctl;
199
200 gba.gba_name = "gpio";
201 gba.gba_gc = &sc->sc_gpio_gc;
202 gba.gba_pins = sc->sc_gpio_pins;
203 gba.gba_npins = ELANSC_PIO_NPINS;
204
205
206 config_found(&sc->sc_dev, &gba, gpiobus_print);
207
208
209 bus_space_write_2(sc->sc_memt, sc->sc_memh, GPTMR1CTL,
210 GPTMRCTL_ENB_WR | GPTMRCTL_CONT_CMP |
211 GPTMRCTL_PSC_SEL | GPTMRCTL_RTG);
212 bus_space_write_2(sc->sc_memt, sc->sc_memh, GPTMR1CNT, 0);
213 bus_space_write_2(sc->sc_memt, sc->sc_memh, GPTMR1MAXCMPA, 0);
214
215 bus_space_write_2(sc->sc_memt, sc->sc_memh, GPTMR2CTL,
216 GPTMRCTL_ENB_WR | GPTMRCTL_CONT_CMP);
217 bus_space_write_2(sc->sc_memt, sc->sc_memh, GPTMR2CNT, 0);
218 bus_space_write_2(sc->sc_memt, sc->sc_memh, GPTMR2MAXCMPA, 0);
219
220 tmr = bus_space_read_1(sc->sc_memt, sc->sc_memh, SWTMRCFG);
221
222
223 bus_space_write_2(sc->sc_memt, sc->sc_memh, GPTMR1CTL,
224 GPTMRCTL_ENB | GPTMRCTL_ENB_WR | GPTMRCTL_CONT_CMP |
225 GPTMRCTL_PSC_SEL | GPTMRCTL_RTG);
226 bus_space_write_2(sc->sc_memt, sc->sc_memh, GPTMR2CTL,
227 GPTMRCTL_ENB | GPTMRCTL_ENB_WR | GPTMRCTL_CONT_CMP);
228
229
230 tc = &sc->sc_tc;
231 tc->tc_get_timecount = elansc_tc_read;
232 tc->tc_poll_pps = NULL;
233 tc->tc_counter_mask = ~0;
234 tc->tc_frequency = (tmr & 1) ? (33000000 / 4) : (33333333 / 4);
235 tc->tc_name = sc->sc_dev.dv_xname;
236 tc->tc_quality = 1000;
237 tc->tc_priv = sc;
238 tc_init(tc);
239 }
240
241 u_int
242 elansc_tc_read(struct timecounter *tc)
243 {
244 struct elansc_softc *sc = tc->tc_priv;
245 u_int32_t m1, m2, l;
246
247 do {
248 m1 = bus_space_read_2(sc->sc_memt, sc->sc_memh, GPTMR1CNT);
249 l = bus_space_read_2(sc->sc_memt, sc->sc_memh, GPTMR2CNT);
250 m2 = bus_space_read_2(sc->sc_memt, sc->sc_memh, GPTMR1CNT);
251 } while (m1 != m2);
252
253 return ((m1 << 16) | l);
254 }
255
256 void
257 elansc_wdogctl(struct elansc_softc *sc, int do_reset, uint16_t val)
258 {
259 int s;
260 uint8_t echo_mode;
261
262 s = splhigh();
263
264
265 echo_mode = bus_space_read_1(sc->sc_memt, sc->sc_memh, MMCR_GPECHO);
266 bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_GPECHO,
267 echo_mode & ~GPECHO_GP_ECHO_ENB);
268
269 if (do_reset) {
270
271 bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WDTMRCTL,
272 WDTMRCTL_RESET1);
273 bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WDTMRCTL,
274 WDTMRCTL_RESET2);
275 } else {
276
277 bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WDTMRCTL,
278 WDTMRCTL_UNLOCK1);
279 bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WDTMRCTL,
280 WDTMRCTL_UNLOCK2);
281
282
283 bus_space_write_2(sc->sc_memt, sc->sc_memh, MMCR_WDTMRCTL,
284 val);
285 }
286
287
288 bus_space_write_1(sc->sc_memt, sc->sc_memh, MMCR_GPECHO, echo_mode);
289
290 splx(s);
291 }
292
293 static const struct {
294 int period;
295 uint16_t exp;
296 } elansc_wdog_periods[] = {
297 { 1, WDTMRCTL_EXP_SEL25 },
298 { 2, WDTMRCTL_EXP_SEL26 },
299 { 4, WDTMRCTL_EXP_SEL27 },
300 { 8, WDTMRCTL_EXP_SEL28 },
301 { 16, WDTMRCTL_EXP_SEL29 },
302 { 32, WDTMRCTL_EXP_SEL30 },
303 };
304
305 int
306 elansc_wdogctl_cb(void *self, int period)
307 {
308 struct elansc_softc *sc = self;
309 int i;
310
311 if (period == 0) {
312 elansc_wdogctl_write(sc,
313 WDTMRCTL_WRST_ENB | WDTMRCTL_EXP_SEL30);
314 } else {
315 for (i = 0; i < (sizeof(elansc_wdog_periods) /
316 sizeof(elansc_wdog_periods[0])) - 1; i++)
317 if (elansc_wdog_periods[i].period >= period)
318 break;
319 period = elansc_wdog_periods[i].period;
320 elansc_wdogctl_write(sc, WDTMRCTL_ENB |
321 WDTMRCTL_WRST_ENB | elansc_wdog_periods[i].exp);
322 elansc_wdogctl_reset(sc);
323 }
324 return (period);
325 }
326
327 void
328 elansc_update_cpuspeed(void)
329 {
330 #ifdef I586_CPU
331 static const int elansc_mhz[] = { 0, 100, 133, 999 };
332 #endif
333 uint8_t cpuctl;
334
335 cpuctl = bus_space_read_1(elansc->sc_memt, elansc->sc_memh,
336 MMCR_CPUCTL);
337 #ifdef I586_CPU
338 cpuspeed = elansc_mhz[cpuctl & CPUCTL_CPU_CLK_SPD_MASK];
339 #endif
340 }
341
342 void
343 elansc_setperf(int level)
344 {
345 uint32_t eflags;
346 uint8_t cpuctl, speed;
347
348 level = (level > 50) ? 100 : 0;
349
350 cpuctl = bus_space_read_1(elansc->sc_memt, elansc->sc_memh,
351 MMCR_CPUCTL);
352 speed = (level == 100) ? 2 : 1;
353 if ((cpuctl & CPUCTL_CPU_CLK_SPD_MASK) == speed)
354 return;
355
356 eflags = read_eflags();
357 disable_intr();
358 bus_space_write_1(elansc->sc_memt, elansc->sc_memh, MMCR_CPUCTL,
359 (cpuctl & ~CPUCTL_CPU_CLK_SPD_MASK) | speed);
360 enable_intr();
361 write_eflags(eflags);
362
363 elansc_update_cpuspeed();
364 }
365
366 int
367 elansc_cpuspeed(int *freq)
368 {
369 *freq = cpuspeed;
370 return (0);
371 }
372
373 int
374 elansc_gpio_pin_read(void *arg, int pin)
375 {
376 struct elansc_softc *sc = arg;
377 int reg, shift;
378 u_int16_t data;
379
380 reg = (pin < 16 ? MMCR_PIODATA15_0 : MMCR_PIODATA31_16);
381 shift = pin % 16;
382 data = bus_space_read_2(sc->sc_memt, sc->sc_memh, reg);
383
384 return ((data >> shift) & 0x1);
385 }
386
387 void
388 elansc_gpio_pin_write(void *arg, int pin, int value)
389 {
390 struct elansc_softc *sc = arg;
391 int reg, shift;
392 u_int16_t data;
393
394 reg = (pin < 16 ? MMCR_PIODATA15_0 : MMCR_PIODATA31_16);
395 shift = pin % 16;
396 data = bus_space_read_2(sc->sc_memt, sc->sc_memh, reg);
397 if (value == 0)
398 data &= ~(1 << shift);
399 else if (value == 1)
400 data |= (1 << shift);
401
402 bus_space_write_2(sc->sc_memt, sc->sc_memh, reg, data);
403 }
404
405 void
406 elansc_gpio_pin_ctl(void *arg, int pin, int flags)
407 {
408 struct elansc_softc *sc = arg;
409 int reg, shift;
410 u_int16_t data;
411
412 reg = (pin < 16 ? MMCR_PIODIR15_0 : MMCR_PIODIR31_16);
413 shift = pin % 16;
414 data = bus_space_read_2(sc->sc_memt, sc->sc_memh, reg);
415 if (flags & GPIO_PIN_INPUT)
416 data &= ~(1 << shift);
417 if (flags & GPIO_PIN_OUTPUT)
418 data |= (1 << shift);
419
420 bus_space_write_2(sc->sc_memt, sc->sc_memh, reg, data);
421 }