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 */