3afa49b7a73b849df0ab855c7810f95c4e0611e3
[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 #include "opt_cpu.h"
51 #include <sys/cdefs.h>
52
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/systimer.h>
56 #include <sys/bus.h>
57 #include <sys/kernel.h>
58 #include <sys/module.h>
59 #include <sys/wdog.h>
60 #include <bus/pci/pcireg.h>
61 #include <bus/pci/pcivar.h>
62 #include <bus/pci/pcidevs.h>
63 #include <bus/pci/pcib_private.h>
64 #include <machine/pc/bios.h>
65
66 /*
67  * Geode SC1100 Information Appliance On a Chip
68  * http://www.national.com/ds.cgi/SC/SC1100.pdf
69  */
70
71 /* Configuration Space Register Map */
72
73 #define SC1100_F5_SCRATCHPAD    0x64
74
75 #define GCB_WDTO        0x0000  /* WATCHDOG Timeout */
76 #define GCB_WDCNFG      0x0002  /* WATCHDOG Configuration */
77 #define GCB_WDSTS       0x0004  /* WATCHDOG Status */
78 #define GCB_TSC         0x0008  /* Cyclecounter at 27MHz */
79 #define GCB_TSCNFG      0x000c  /* config for the above */
80 #define GCB_IID         0x003c  /* IA On a Chip ID */
81 #define GCB_REV         0x003d  /* Revision */
82 #define GCB_CBA         0x003e  /* Configuration Base Address */
83
84 /* Watchdog */
85
86 #define WD32KPD_ENABLE  0x0000
87 #define WD32KPD_DISABLE 0x0100
88 #define WDTYPE1_RESET   0x0030
89 #define WDTYPE2_RESET   0x00c0
90 #define WDPRES_DIV_512  0x0009
91 #define WDPRES_DIV_8192 0x000d
92 #define WDCNFG_MASK     0x00ff
93 #define WDOVF_CLEAR     0x0001
94
95 /* cyclecounter */
96 #define TSC_ENABLE      0x0200
97 #define GEODE_TIMER_FREQ        27000000
98
99 struct geode_softc {
100         bus_space_tag_t         sc_iot;
101         bus_space_handle_t      sc_ioh;
102 };
103
104 static struct geode_softc geode_sc;
105 static sysclock_t geode_get_timecount(void);
106
107 static void
108 geode_cputimer_construct(struct cputimer *timer, sysclock_t oldclock)
109 {
110         timer->base = 0;
111         timer->base = oldclock - geode_get_timecount();
112 }
113
114 static struct cputimer geode_timer = {
115         SLIST_ENTRY_INITIALIZER,
116         "Geode",
117         CPUTIMER_PRI_GEODE,
118         CPUTIMER_GEODE,
119         geode_get_timecount,
120         cputimer_default_fromhz,
121         cputimer_default_fromus,
122         geode_cputimer_construct,
123         cputimer_default_destruct,
124         GEODE_TIMER_FREQ,
125         0, 0, 0
126 };
127
128 static sysclock_t
129 geode_get_timecount(void)
130 {
131
132         return (geode_timer.base +
133                 bus_space_read_4(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_TSC));
134 }
135
136
137 #ifdef WATCHDOG_ENABLE
138 static int
139 geode_watchdog(void *unused, int period)
140 {
141         uint32_t data;
142         uint16_t port;
143         int     reg;
144
145         if (period > 0x03ff)
146                 period = 0x03ff;
147
148         bus_space_write_2(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_WDTO, period * 64);
149
150         return period;
151 }
152
153 static struct watchdog  geode_wdog = {
154         .name           =       "Geode SC1100",
155         .wdog_fn        =       geode_watchdog,
156         .arg            =       NULL,
157         .period_max     =       0x03ff,
158 };
159 #endif /* WATCHDOG_ENABLE */
160
161 static int
162 geode_probe(device_t self)
163 {
164         if (pci_get_vendor(self) == PCI_VENDOR_NS &&
165                 (pci_get_device(self) == PCI_PRODUCT_NS_SC1100_XBUS ||
166                 pci_get_device(self) == PCI_PRODUCT_NS_SCx200_XBUS)) {
167                 /* device_set_desc(self, ...) */
168                 return 0;
169         }
170
171         return ENXIO;
172 }
173 static int
174 geode_attach(device_t self)
175 {
176         u_int32_t       reg;
177         u_int16_t       cnfg, cba;
178         u_int8_t        sts, rev, iid;
179
180         /*
181          * The address of the CBA is written to this register
182          * by the bios, see p161 in data sheet.
183          */
184         reg = pci_read_config(self, SC1100_F5_SCRATCHPAD, 4);
185         if (reg == 0)
186                 return ENODEV;
187
188         /* bus_space_map(sc->sc_iot, reg, 64, 0, &sc->sc_ioh)) */
189         geode_sc.sc_iot = I386_BUS_SPACE_IO;
190         geode_sc.sc_ioh = reg;
191
192         cba = bus_space_read_2(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_CBA);
193         if (cba != reg) {
194                 kprintf("Geode LX: cba mismatch: cba 0x%x != reg 0x%x\n", cba, reg);
195                 return ENODEV;
196         }
197
198         /* outl(cba + 0x0d, 2); ??? */
199         sts = bus_space_read_1(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_WDSTS);
200         cnfg = bus_space_read_2(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_WDCNFG);
201         iid = bus_space_read_1(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_IID);
202         rev = bus_space_read_1(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_REV);
203 #define WDSTSBITS "\20\x04WDRST\x03WDSMI\x02WDINT\x01WDOVF"
204         kprintf("Geode LX: iid %d revision %d wdstatus %b\n", iid, rev, sts, WDSTSBITS);
205
206         /* enable timer */
207         bus_space_write_4(geode_sc.sc_iot, geode_sc.sc_iot, GCB_TSCNFG, TSC_ENABLE);
208         cputimer_register(&geode_timer);
209         cputimer_select(&geode_timer, 0);
210
211 #ifdef WATCHDOG_ENABLE
212         /* enable watchdog and configure */
213         bus_space_write_2(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_WDTO, 0);
214         sts |= WDOVF_CLEAR;
215         bus_space_write_1(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_WDSTS, sts);
216         cnfg &= ~WDCNFG_MASK;
217         cnfg |= WDTYPE1_RESET | WDPRES_DIV_512;
218         bus_space_write_2(geode_sc.sc_iot, geode_sc.sc_ioh, GCB_WDCNFG, cnfg);
219         wdog_register(&geode_wdog);
220 #endif /* WATCHDOG_ENABLE */
221
222         return 0;
223 }
224
225 static device_method_t geode_methods[] = {
226         /* Device interface */
227         DEVMETHOD(device_probe,         geode_probe),
228         DEVMETHOD(device_attach,        geode_attach),
229         DEVMETHOD(device_suspend,       bus_generic_suspend),
230         DEVMETHOD(device_resume,        bus_generic_resume),
231         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
232         {0, 0}
233 };
234
235 static driver_t geode_driver = {
236         "geode",
237         geode_methods,
238         0,
239 };
240
241 static devclass_t geode_devclass;
242
243 DRIVER_MODULE(geode, pci, geode_driver, geode_devclass, 0, 0);