2 * Driver/API for AMD Geode Multi-Function General Purpose Timers (MFGPT)
4 * Copyright (C) 2006, Advanced Micro Devices, Inc.
5 * Copyright (C) 2007, Andres Salomon <dilinger@debian.org>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2 of the GNU General Public License
9 * as published by the Free Software Foundation.
11 * The MFGPTs are documented in AMD Geode CS5536 Companion Device Data Book.
15 * We are using the 32Khz input clock - its the only one that has the
16 * ranges we find desirable. The following table lists the suitable
17 * divisors and the associated hz, minimum interval
18 * and the maximum interval:
20 * Divisor Hz Min Delta (S) Max Delta (S)
28 * 128 250 .064 262.144
29 * 256 125 .128 524.288
32 #include <linux/kernel.h>
33 #include <linux/interrupt.h>
34 #include <linux/module.h>
35 #include <asm/geode.h>
39 static struct mfgpt_timer_t {
42 } mfgpt_timers[MFGPT_MAX_TIMERS];
44 /* Selected from the table above */
46 #define MFGPT_DIVISOR 16
47 #define MFGPT_SCALE 4 /* divisor = 2^(scale) */
48 #define MFGPT_HZ (32000 / MFGPT_DIVISOR)
49 #define MFGPT_PERIODIC (MFGPT_HZ / HZ)
51 /* Allow for disabling of MFGPTs */
53 static int __init mfgpt_disable(char *s)
58 __setup("nomfgpt", mfgpt_disable);
61 * Check whether any MFGPTs are available for the kernel to use. In most
62 * cases, firmware that uses AMD's VSA code will claim all timers during
63 * bootup; we certainly don't want to take them if they're already in use.
64 * In other cases (such as with VSAless OpenFirmware), the system firmware
65 * leaves timers available for us to use.
67 int __init geode_mfgpt_detect(void)
73 printk(KERN_INFO "geode-mfgpt: Skipping MFGPT setup\n");
77 for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
78 val = geode_mfgpt_read(i, MFGPT_REG_SETUP);
79 if (!(val & MFGPT_SETUP_SETUP)) {
80 mfgpt_timers[i].flags = F_AVAIL;
88 int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable)
90 u32 msr, mask, value, dummy;
91 int shift = (cmp == MFGPT_CMP1) ? 0 : 8;
93 if (timer < 0 || timer >= MFGPT_MAX_TIMERS)
97 * The register maps for these are described in sections 6.17.1.x of
98 * the AMD Geode CS5536 Companion Device Data Book.
101 case MFGPT_EVENT_RESET:
103 * XXX: According to the docs, we cannot reset timers above
104 * 6; that is, resets for 7 and 8 will be ignored. Is this
105 * a problem? -dilinger
108 mask = 1 << (timer + 24);
111 case MFGPT_EVENT_NMI:
113 mask = 1 << (timer + shift);
116 case MFGPT_EVENT_IRQ:
118 mask = 1 << (timer + shift);
125 rdmsr(msr, value, dummy);
132 wrmsr(msr, value, dummy);
136 int geode_mfgpt_set_irq(int timer, int cmp, int irq, int enable)
141 if (timer < 0 || timer >= MFGPT_MAX_TIMERS)
144 if (geode_mfgpt_toggle_event(timer, cmp, MFGPT_EVENT_IRQ, enable))
147 rdmsr(MSR_PIC_ZSEL_LOW, val, dummy);
149 offset = (timer % 4) * 4;
151 val &= ~((0xF << offset) | (0xF << (offset + 16)));
154 val |= (irq & 0x0F) << (offset);
155 val |= (irq & 0x0F) << (offset + 16);
158 wrmsr(MSR_PIC_ZSEL_LOW, val, dummy);
162 static int mfgpt_get(int timer, struct module *owner)
164 mfgpt_timers[timer].flags &= ~F_AVAIL;
165 mfgpt_timers[timer].owner = owner;
166 printk(KERN_INFO "geode-mfgpt: Registered timer %d\n", timer);
170 int geode_mfgpt_alloc_timer(int timer, int domain, struct module *owner)
174 if (!geode_get_dev_base(GEODE_DEV_MFGPT))
176 if (timer >= MFGPT_MAX_TIMERS)
180 /* Try to find an available timer */
181 for (i = 0; i < MFGPT_MAX_TIMERS; i++) {
182 if (mfgpt_timers[i].flags & F_AVAIL)
183 return mfgpt_get(i, owner);
185 if (i == 5 && domain == MFGPT_DOMAIN_WORKING)
189 /* If they requested a specific timer, try to honor that */
190 if (mfgpt_timers[timer].flags & F_AVAIL)
191 return mfgpt_get(timer, owner);
194 /* No timers available - too bad */