kernel: Generate miidevs.h, pccarddevs.h and pcidevs.h on the fly.
[dragonfly.git] / sys / platform / pc32 / i386 / geode.c
1 /*
2  * Copyright (c) 2003 Markus Friedl <markus@openbsd.org>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  *
16  *
17  * Copyright (c) 2009 The DragonFly Project.  All rights reserved.
18  *
19  * This code is derived from software contributed to The DragonFly Project
20  * by Alex Hornung <ahornung@gmail.com>
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions
24  * are met:
25  *
26  * 1. Redistributions of source code must retain the above copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in
30  *    the documentation and/or other materials provided with the
31  *    distribution.
32  * 3. Neither the name of The DragonFly Project nor the names of its
33  *    contributors may be used to endorse or promote products derived
34  *    from this software without specific, prior written permission.
35  *
36  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
37  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
38  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
39  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
40  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
41  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
42  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
44  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  *
49  */
50
51 #include <sys/param.h>
52 #include <sys/systm.h>
53 #include <sys/systimer.h>
54 #include <sys/bus.h>
55 #include <sys/kernel.h>
56 #include <sys/module.h>
57 #include <sys/wdog.h>
58 #include <bus/pci/pcireg.h>
59 #include <bus/pci/pcivar.h>
60 #include "pcidevs.h"
61 #include <bus/pci/pcib_private.h>
62 #include <machine/pc/bios.h>
63
64 /*
65  * Geode SC1100 Information Appliance On a Chip
66  * http://www.national.com/ds.cgi/SC/SC1100.pdf
67  */
68
69 /* Configuration Space Register Map */
70
71 #define SC1100_F5_SCRATCHPAD    0x64
72
73 #define GCB_WDTO        0x0000  /* WATCHDOG Timeout */
74 #define GCB_WDCNFG      0x0002  /* WATCHDOG Configuration */
75 #define GCB_WDSTS       0x0004  /* WATCHDOG Status */
76 #define GCB_TSC         0x0008  /* Cyclecounter at 27MHz */
77 #define GCB_TSCNFG      0x000c  /* config for the above */
78 #define GCB_IID         0x003c  /* IA On a Chip ID */
79 #define GCB_REV         0x003d  /* Revision */
80 #define GCB_CBA         0x003e  /* Configuration Base Address */
81
82 /* Watchdog */
83
84 #define WD32KPD_ENABLE  0x0000
85 #define WD32KPD_DISABLE 0x0100
86 #define WDTYPE1_RESET   0x0030
87 #define WDTYPE2_RESET   0x00c0
88 #define WDPRES_DIV_512  0x0009
89 #define WDPRES_DIV_8192 0x000d
90 #define WDCNFG_MASK     0x00ff
91 #define WDOVF_CLEAR     0x0001
92
93 /* cyclecounter */
94 #define TSC_ENABLE      0x0200
95 #define GEODE_TIMER_FREQ        27000000
96
97 struct geode_softc {
98         bus_space_tag_t         sc_iot;
99         bus_space_handle_t      sc_ioh;
100 };
101
102 static struct geode_softc geode_sc;
103 static sysclock_t geode_get_timecount(void);
104
105 static void
106 geode_cputimer_construct(struct cputimer *timer, sysclock_t oldclock)
107 {
108         timer->base = 0;
109         timer->base = oldclock - geode_get_timecount();
110 }
111
112 static struct cputimer geode_timer = {
113         SLIST_ENTRY_INITIALIZER,
114         "Geode",
115         CPUTIMER_PRI_GEODE,
116         CPUTIMER_GEODE,
117         geode_get_timecount,
118         cputimer_default_fromhz,
119         cputimer_default_fromus,
120         geode_cputimer_construct,
121         cputimer_default_destruct,
122         GEODE_TIMER_FREQ,
123         0, 0, 0
124 };
125
126 static sysclock_t
127 geode_get_timecount(void)
128 {
129
130         return (geode_timer.base +
131                 bus_space_read_4(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_TSC));
132 }
133
134 static int
135 geode_watchdog(void *unused, int period)
136 {
137         if (period > 0x03ff)
138                 period = 0x03ff;
139
140         bus_space_write_2(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_WDTO, period * 64);
141
142         return period;
143 }
144
145 static struct watchdog  geode_wdog = {
146         .name           =       "Geode SC1100",
147         .wdog_fn        =       geode_watchdog,
148         .arg            =       NULL,
149         .period_max     =       0x03ff,
150 };
151
152 static int
153 geode_probe(device_t self)
154 {
155         if (pci_get_vendor(self) == PCI_VENDOR_NS &&
156                 (pci_get_device(self) == PCI_PRODUCT_NS_SC1100_XBUS ||
157                 pci_get_device(self) == PCI_PRODUCT_NS_SCx200_XBUS)) {
158                 /* device_set_desc(self, ...) */
159                 return 0;
160         }
161
162         return ENXIO;
163 }
164 static int
165 geode_attach(device_t self)
166 {
167         u_int32_t       reg;
168         u_int16_t       cnfg, cba;
169         u_int8_t        sts, rev, iid;
170
171         /*
172          * The address of the CBA is written to this register
173          * by the bios, see p161 in data sheet.
174          */
175         reg = pci_read_config(self, SC1100_F5_SCRATCHPAD, 4);
176         if (reg == 0)
177                 return ENODEV;
178
179         /* bus_space_map(sc->sc_iot, reg, 64, 0, &sc->sc_ioh)) */
180         geode_sc.sc_iot = I386_BUS_SPACE_IO;
181         geode_sc.sc_ioh = reg;
182
183         cba = bus_space_read_2(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_CBA);
184         if (cba != reg) {
185                 kprintf("Geode LX: cba mismatch: cba 0x%x != reg 0x%x\n", cba, reg);
186                 return ENODEV;
187         }
188
189         /* outl(cba + 0x0d, 2); ??? */
190         sts = bus_space_read_1(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_WDSTS);
191         cnfg = bus_space_read_2(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_WDCNFG);
192         iid = bus_space_read_1(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_IID);
193         rev = bus_space_read_1(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_REV);
194 #define WDSTSBITS "\20\x04WDRST\x03WDSMI\x02WDINT\x01WDOVF"
195         kprintf("Geode LX: iid %d revision %d wdstatus %b\n", iid, rev, sts, WDSTSBITS);
196
197         /* enable timer */
198         bus_space_write_4(geode_sc.sc_iot, geode_sc.sc_iot, GCB_TSCNFG, TSC_ENABLE);
199         cputimer_register(&geode_timer);
200         cputimer_select(&geode_timer, 0);
201
202         /* enable watchdog and configure */
203         bus_space_write_2(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_WDTO, 0);
204         sts |= WDOVF_CLEAR;
205         bus_space_write_1(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_WDSTS, sts);
206         cnfg &= ~WDCNFG_MASK;
207         cnfg |= WDTYPE1_RESET | WDPRES_DIV_512;
208         bus_space_write_2(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_WDCNFG, cnfg);
209         wdog_register(&geode_wdog);
210
211         return 0;
212 }
213
214 static device_method_t geode_methods[] = {
215         /* Device interface */
216         DEVMETHOD(device_probe,         geode_probe),
217         DEVMETHOD(device_attach,        geode_attach),
218         DEVMETHOD(device_suspend,       bus_generic_suspend),
219         DEVMETHOD(device_resume,        bus_generic_resume),
220         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
221         DEVMETHOD_END
222 };
223
224 static driver_t geode_driver = {
225         "geode",
226         geode_methods,
227         0,
228 };
229
230 static devclass_t geode_devclass;
231
232 DRIVER_MODULE(geode, pci, geode_driver, geode_devclass, NULL, NULL);