diff options
| author | Andres Salomon <dilinger@collabora.co.uk> | 2009-12-14 21:00:41 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-15 11:53:28 -0500 |
| commit | c95d1e53ed89b75a4d7b68d1cbae4607b1479243 (patch) | |
| tree | b82d2ef1e349a3da948fe4c7dbd56ebed0ad0e84 | |
| parent | f3a57a60d3e107d17aebb9e52b61c503e5bc14f9 (diff) | |
cs5535: drop the Geode-specific MFGPT/GPIO code
With generic modular drivers handling all of this stuff, the
geode-specific code can go away. The cs5535-gpio, cs5535-mfgpt, and
cs5535-clockevt drivers now handle this.
Signed-off-by: Andres Salomon <dilinger@collabora.co.uk>
Cc: Jordan Crouse <jordan@cosmicpenguin.net>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: john stultz <johnstul@us.ibm.com>
Cc: Chris Ball <cjb@laptop.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | arch/x86/Kconfig | 10 | ||||
| -rw-r--r-- | arch/x86/include/asm/geode.h | 117 | ||||
| -rw-r--r-- | arch/x86/kernel/Makefile | 1 | ||||
| -rw-r--r-- | arch/x86/kernel/geode_32.c | 174 | ||||
| -rw-r--r-- | arch/x86/kernel/mfgpt_32.c | 410 | ||||
| -rw-r--r-- | drivers/gpio/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/misc/Kconfig | 2 |
7 files changed, 2 insertions, 714 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 6ad0985e8d76..3b2a5aca4edb 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -2012,16 +2012,6 @@ config SCx200HR_TIMER | |||
| 2012 | processor goes idle (as is done by the scheduler). The | 2012 | processor goes idle (as is done by the scheduler). The |
| 2013 | other workaround is idle=poll boot option. | 2013 | other workaround is idle=poll boot option. |
| 2014 | 2014 | ||
| 2015 | config GEODE_MFGPT_TIMER | ||
| 2016 | def_bool y | ||
| 2017 | prompt "Geode Multi-Function General Purpose Timer (MFGPT) events" | ||
| 2018 | depends on MGEODE_LX && GENERIC_TIME && GENERIC_CLOCKEVENTS | ||
| 2019 | ---help--- | ||
| 2020 | This driver provides a clock event source based on the MFGPT | ||
| 2021 | timer(s) in the CS5535 and CS5536 companion chip for the geode. | ||
| 2022 | MFGPTs have a better resolution and max interval than the | ||
| 2023 | generic PIT, and are suitable for use as high-res timers. | ||
| 2024 | |||
| 2025 | config OLPC | 2015 | config OLPC |
| 2026 | bool "One Laptop Per Child support" | 2016 | bool "One Laptop Per Child support" |
| 2027 | select GPIOLIB | 2017 | select GPIOLIB |
diff --git a/arch/x86/include/asm/geode.h b/arch/x86/include/asm/geode.h index ae104da6ad5a..7cd73552a4e8 100644 --- a/arch/x86/include/asm/geode.h +++ b/arch/x86/include/asm/geode.h | |||
| @@ -14,98 +14,6 @@ | |||
| 14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
| 15 | #include <linux/cs5535.h> | 15 | #include <linux/cs5535.h> |
| 16 | 16 | ||
| 17 | /* Generic southbridge functions */ | ||
| 18 | |||
| 19 | #define GEODE_DEV_PMS 0 | ||
| 20 | #define GEODE_DEV_ACPI 1 | ||
| 21 | #define GEODE_DEV_GPIO 2 | ||
| 22 | #define GEODE_DEV_MFGPT 3 | ||
| 23 | |||
| 24 | extern int geode_get_dev_base(unsigned int dev); | ||
| 25 | |||
| 26 | /* Useful macros */ | ||
| 27 | #define geode_pms_base() geode_get_dev_base(GEODE_DEV_PMS) | ||
| 28 | #define geode_acpi_base() geode_get_dev_base(GEODE_DEV_ACPI) | ||
| 29 | #define geode_gpio_base() geode_get_dev_base(GEODE_DEV_GPIO) | ||
| 30 | #define geode_mfgpt_base() geode_get_dev_base(GEODE_DEV_MFGPT) | ||
| 31 | |||
| 32 | /* MSRS */ | ||
| 33 | |||
| 34 | #define MSR_LBAR_SMB 0x5140000B | ||
| 35 | #define MSR_LBAR_GPIO 0x5140000C | ||
| 36 | #define MSR_LBAR_MFGPT 0x5140000D | ||
| 37 | #define MSR_LBAR_ACPI 0x5140000E | ||
| 38 | #define MSR_LBAR_PMS 0x5140000F | ||
| 39 | |||
| 40 | /* Resource Sizes */ | ||
| 41 | |||
| 42 | #define LBAR_GPIO_SIZE 0xFF | ||
| 43 | #define LBAR_MFGPT_SIZE 0x40 | ||
| 44 | #define LBAR_ACPI_SIZE 0x40 | ||
| 45 | #define LBAR_PMS_SIZE 0x80 | ||
| 46 | |||
| 47 | /* ACPI registers (PMS block) */ | ||
| 48 | |||
| 49 | /* | ||
| 50 | * PM1_EN is only valid when VSA is enabled for 16 bit reads. | ||
| 51 | * When VSA is not enabled, *always* read both PM1_STS and PM1_EN | ||
| 52 | * with a 32 bit read at offset 0x0 | ||
| 53 | */ | ||
| 54 | |||
| 55 | #define PM1_STS 0x00 | ||
| 56 | #define PM1_EN 0x02 | ||
| 57 | #define PM1_CNT 0x08 | ||
| 58 | #define PM2_CNT 0x0C | ||
| 59 | #define PM_TMR 0x10 | ||
| 60 | #define PM_GPE0_STS 0x18 | ||
| 61 | #define PM_GPE0_EN 0x1C | ||
| 62 | |||
| 63 | /* PMC registers (PMS block) */ | ||
| 64 | |||
| 65 | #define PM_SSD 0x00 | ||
| 66 | #define PM_SCXA 0x04 | ||
| 67 | #define PM_SCYA 0x08 | ||
| 68 | #define PM_OUT_SLPCTL 0x0C | ||
| 69 | #define PM_SCLK 0x10 | ||
| 70 | #define PM_SED 0x1 | ||
| 71 | #define PM_SCXD 0x18 | ||
| 72 | #define PM_SCYD 0x1C | ||
| 73 | #define PM_IN_SLPCTL 0x20 | ||
| 74 | #define PM_WKD 0x30 | ||
| 75 | #define PM_WKXD 0x34 | ||
| 76 | #define PM_RD 0x38 | ||
| 77 | #define PM_WKXA 0x3C | ||
| 78 | #define PM_FSD 0x40 | ||
| 79 | #define PM_TSD 0x44 | ||
| 80 | #define PM_PSD 0x48 | ||
| 81 | #define PM_NWKD 0x4C | ||
| 82 | #define PM_AWKD 0x50 | ||
| 83 | #define PM_SSC 0x54 | ||
| 84 | |||
| 85 | static inline u32 geode_gpio(unsigned int nr) | ||
| 86 | { | ||
| 87 | BUG_ON(nr > 28); | ||
| 88 | return 1 << nr; | ||
| 89 | } | ||
| 90 | |||
| 91 | extern void geode_gpio_set(u32, unsigned int); | ||
| 92 | extern void geode_gpio_clear(u32, unsigned int); | ||
| 93 | extern int geode_gpio_isset(u32, unsigned int); | ||
| 94 | extern void geode_gpio_setup_event(unsigned int, int, int); | ||
| 95 | extern void geode_gpio_set_irq(unsigned int, unsigned int); | ||
| 96 | |||
| 97 | static inline void geode_gpio_event_irq(unsigned int gpio, int pair) | ||
| 98 | { | ||
| 99 | geode_gpio_setup_event(gpio, pair, 0); | ||
| 100 | } | ||
| 101 | |||
| 102 | static inline void geode_gpio_event_pme(unsigned int gpio, int pair) | ||
| 103 | { | ||
| 104 | geode_gpio_setup_event(gpio, pair, 1); | ||
| 105 | } | ||
| 106 | |||
| 107 | /* Specific geode tests */ | ||
| 108 | |||
| 109 | static inline int is_geode_gx(void) | 17 | static inline int is_geode_gx(void) |
| 110 | { | 18 | { |
| 111 | return ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC) && | 19 | return ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC) && |
| @@ -125,29 +33,4 @@ static inline int is_geode(void) | |||
| 125 | return (is_geode_gx() || is_geode_lx()); | 33 | return (is_geode_gx() || is_geode_lx()); |
| 126 | } | 34 | } |
| 127 | 35 | ||
| 128 | static inline void geode_mfgpt_write(int timer, u16 reg, u16 value) | ||
| 129 | { | ||
| 130 | u32 base = geode_get_dev_base(GEODE_DEV_MFGPT); | ||
| 131 | outw(value, base + reg + (timer * 8)); | ||
| 132 | } | ||
| 133 | |||
| 134 | static inline u16 geode_mfgpt_read(int timer, u16 reg) | ||
| 135 | { | ||
| 136 | u32 base = geode_get_dev_base(GEODE_DEV_MFGPT); | ||
| 137 | return inw(base + reg + (timer * 8)); | ||
| 138 | } | ||
| 139 | |||
| 140 | extern int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable); | ||
| 141 | extern int geode_mfgpt_set_irq(int timer, int cmp, int *irq, int enable); | ||
| 142 | extern int geode_mfgpt_alloc_timer(int timer, int domain); | ||
| 143 | |||
| 144 | #define geode_mfgpt_setup_irq(t, c, i) geode_mfgpt_set_irq((t), (c), (i), 1) | ||
| 145 | #define geode_mfgpt_release_irq(t, c, i) geode_mfgpt_set_irq((t), (c), (i), 0) | ||
| 146 | |||
| 147 | #ifdef CONFIG_GEODE_MFGPT_TIMER | ||
| 148 | extern int __init mfgpt_timer_setup(void); | ||
| 149 | #else | ||
| 150 | static inline int mfgpt_timer_setup(void) { return 0; } | ||
| 151 | #endif | ||
| 152 | |||
| 153 | #endif /* _ASM_X86_GEODE_H */ | 36 | #endif /* _ASM_X86_GEODE_H */ |
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 4f2e66e29ecc..d87f09bc5a52 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
| @@ -89,7 +89,6 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | |||
| 89 | obj-$(CONFIG_HPET_TIMER) += hpet.o | 89 | obj-$(CONFIG_HPET_TIMER) += hpet.o |
| 90 | 90 | ||
| 91 | obj-$(CONFIG_K8_NB) += k8.o | 91 | obj-$(CONFIG_K8_NB) += k8.o |
| 92 | obj-$(CONFIG_MGEODE_LX) += geode_32.o mfgpt_32.o | ||
| 93 | obj-$(CONFIG_DEBUG_RODATA_TEST) += test_rodata.o | 92 | obj-$(CONFIG_DEBUG_RODATA_TEST) += test_rodata.o |
| 94 | obj-$(CONFIG_DEBUG_NX_TEST) += test_nx.o | 93 | obj-$(CONFIG_DEBUG_NX_TEST) += test_nx.o |
| 95 | 94 | ||
diff --git a/arch/x86/kernel/geode_32.c b/arch/x86/kernel/geode_32.c deleted file mode 100644 index 9dad6ca6cd70..000000000000 --- a/arch/x86/kernel/geode_32.c +++ /dev/null | |||
| @@ -1,174 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * AMD Geode southbridge support code | ||
| 3 | * Copyright (C) 2006, Advanced Micro Devices, Inc. | ||
| 4 | * Copyright (C) 2007, Andres Salomon <dilinger@debian.org> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of version 2 of the GNU General Public License | ||
| 8 | * as published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/ioport.h> | ||
| 14 | #include <linux/io.h> | ||
| 15 | #include <asm/msr.h> | ||
| 16 | #include <asm/geode.h> | ||
| 17 | |||
| 18 | static struct { | ||
| 19 | char *name; | ||
| 20 | u32 msr; | ||
| 21 | int size; | ||
| 22 | u32 base; | ||
| 23 | } lbars[] = { | ||
| 24 | { "geode-pms", MSR_LBAR_PMS, LBAR_PMS_SIZE, 0 }, | ||
| 25 | { "geode-acpi", MSR_LBAR_ACPI, LBAR_ACPI_SIZE, 0 }, | ||
| 26 | { "geode-gpio", MSR_LBAR_GPIO, LBAR_GPIO_SIZE, 0 }, | ||
| 27 | { "geode-mfgpt", MSR_LBAR_MFGPT, LBAR_MFGPT_SIZE, 0 } | ||
| 28 | }; | ||
| 29 | |||
| 30 | static void __init init_lbars(void) | ||
| 31 | { | ||
| 32 | u32 lo, hi; | ||
| 33 | int i; | ||
| 34 | |||
| 35 | for (i = 0; i < ARRAY_SIZE(lbars); i++) { | ||
| 36 | rdmsr(lbars[i].msr, lo, hi); | ||
| 37 | if (hi & 0x01) | ||
| 38 | lbars[i].base = lo & 0x0000ffff; | ||
| 39 | |||
| 40 | if (lbars[i].base == 0) | ||
| 41 | printk(KERN_ERR "geode: Couldn't initialize '%s'\n", | ||
| 42 | lbars[i].name); | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | int geode_get_dev_base(unsigned int dev) | ||
| 47 | { | ||
| 48 | BUG_ON(dev >= ARRAY_SIZE(lbars)); | ||
| 49 | return lbars[dev].base; | ||
| 50 | } | ||
| 51 | EXPORT_SYMBOL_GPL(geode_get_dev_base); | ||
| 52 | |||
| 53 | /* === GPIO API === */ | ||
| 54 | |||
| 55 | void geode_gpio_set(u32 gpio, unsigned int reg) | ||
| 56 | { | ||
| 57 | u32 base = geode_get_dev_base(GEODE_DEV_GPIO); | ||
| 58 | |||
| 59 | if (!base) | ||
| 60 | return; | ||
| 61 | |||
| 62 | /* low bank register */ | ||
| 63 | if (gpio & 0xFFFF) | ||
| 64 | outl(gpio & 0xFFFF, base + reg); | ||
| 65 | /* high bank register */ | ||
| 66 | gpio >>= 16; | ||
| 67 | if (gpio) | ||
| 68 | outl(gpio, base + 0x80 + reg); | ||
| 69 | } | ||
| 70 | EXPORT_SYMBOL_GPL(geode_gpio_set); | ||
| 71 | |||
| 72 | void geode_gpio_clear(u32 gpio, unsigned int reg) | ||
| 73 | { | ||
| 74 | u32 base = geode_get_dev_base(GEODE_DEV_GPIO); | ||
| 75 | |||
| 76 | if (!base) | ||
| 77 | return; | ||
| 78 | |||
| 79 | /* low bank register */ | ||
| 80 | if (gpio & 0xFFFF) | ||
| 81 | outl((gpio & 0xFFFF) << 16, base + reg); | ||
| 82 | /* high bank register */ | ||
| 83 | gpio &= (0xFFFF << 16); | ||
| 84 | if (gpio) | ||
| 85 | outl(gpio, base + 0x80 + reg); | ||
| 86 | } | ||
| 87 | EXPORT_SYMBOL_GPL(geode_gpio_clear); | ||
| 88 | |||
| 89 | int geode_gpio_isset(u32 gpio, unsigned int reg) | ||
| 90 | { | ||
| 91 | u32 base = geode_get_dev_base(GEODE_DEV_GPIO); | ||
| 92 | u32 val; | ||
| 93 | |||
| 94 | if (!base) | ||
| 95 | return 0; | ||
| 96 | |||
| 97 | /* low bank register */ | ||
| 98 | if (gpio & 0xFFFF) { | ||
| 99 | val = inl(base + reg) & (gpio & 0xFFFF); | ||
| 100 | if ((gpio & 0xFFFF) == val) | ||
| 101 | return 1; | ||
| 102 | } | ||
| 103 | /* high bank register */ | ||
| 104 | gpio >>= 16; | ||
| 105 | if (gpio) { | ||
| 106 | val = inl(base + 0x80 + reg) & gpio; | ||
| 107 | if (gpio == val) | ||
| 108 | return 1; | ||
| 109 | } | ||
| 110 | return 0; | ||
| 111 | } | ||
| 112 | EXPORT_SYMBOL_GPL(geode_gpio_isset); | ||
| 113 | |||
| 114 | void geode_gpio_set_irq(unsigned int group, unsigned int irq) | ||
| 115 | { | ||
| 116 | u32 lo, hi; | ||
| 117 | |||
| 118 | if (group > 7 || irq > 15) | ||
| 119 | return; | ||
| 120 | |||
| 121 | rdmsr(MSR_PIC_ZSEL_HIGH, lo, hi); | ||
| 122 | |||
| 123 | lo &= ~(0xF << (group * 4)); | ||
| 124 | lo |= (irq & 0xF) << (group * 4); | ||
| 125 | |||
| 126 | wrmsr(MSR_PIC_ZSEL_HIGH, lo, hi); | ||
| 127 | } | ||
| 128 | EXPORT_SYMBOL_GPL(geode_gpio_set_irq); | ||
| 129 | |||
| 130 | void geode_gpio_setup_event(unsigned int gpio, int pair, int pme) | ||
| 131 | { | ||
| 132 | u32 base = geode_get_dev_base(GEODE_DEV_GPIO); | ||
| 133 | u32 offset, shift, val; | ||
| 134 | |||
| 135 | if (gpio >= 24) | ||
| 136 | offset = GPIO_MAP_W; | ||
| 137 | else if (gpio >= 16) | ||
| 138 | offset = GPIO_MAP_Z; | ||
| 139 | else if (gpio >= 8) | ||
| 140 | offset = GPIO_MAP_Y; | ||
| 141 | else | ||
| 142 | offset = GPIO_MAP_X; | ||
| 143 | |||
| 144 | shift = (gpio % 8) * 4; | ||
| 145 | |||
| 146 | val = inl(base + offset); | ||
| 147 | |||
| 148 | /* Clear whatever was there before */ | ||
| 149 | val &= ~(0xF << shift); | ||
| 150 | |||
| 151 | /* And set the new value */ | ||
| 152 | |||
| 153 | val |= ((pair & 7) << shift); | ||
| 154 | |||
| 155 | /* Set the PME bit if this is a PME event */ | ||
| 156 | |||
| 157 | if (pme) | ||
| 158 | val |= (1 << (shift + 3)); | ||
| 159 | |||
| 160 | outl(val, base + offset); | ||
| 161 | } | ||
| 162 | EXPORT_SYMBOL_GPL(geode_gpio_setup_event); | ||
| 163 | |||
| 164 | static int __init geode_southbridge_init(void) | ||
| 165 | { | ||
| 166 | if (!is_geode()) | ||
| 167 | return -ENODEV; | ||
| 168 | |||
| 169 | init_lbars(); | ||
| 170 | (void) mfgpt_timer_setup(); | ||
| 171 | return 0; | ||
| 172 | } | ||
| 173 | |||
| 174 | postcore_initcall(geode_southbridge_init); | ||
diff --git a/arch/x86/kernel/mfgpt_32.c b/arch/x86/kernel/mfgpt_32.c deleted file mode 100644 index 2a62d843f015..000000000000 --- a/arch/x86/kernel/mfgpt_32.c +++ /dev/null | |||
| @@ -1,410 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Driver/API for AMD Geode Multi-Function General Purpose Timers (MFGPT) | ||
| 3 | * | ||
| 4 | * Copyright (C) 2006, Advanced Micro Devices, Inc. | ||
| 5 | * Copyright (C) 2007, Andres Salomon <dilinger@debian.org> | ||
| 6 | * | ||
| 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. | ||
| 10 | * | ||
| 11 | * The MFGPTs are documented in AMD Geode CS5536 Companion Device Data Book. | ||
| 12 | */ | ||
| 13 | |||
| 14 | /* | ||
| 15 | * We are using the 32.768kHz input clock - it's 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 and the maximum interval: | ||
| 18 | * | ||
| 19 | * Divisor Hz Min Delta (s) Max Delta (s) | ||
| 20 | * 1 32768 .00048828125 2.000 | ||
| 21 | * 2 16384 .0009765625 4.000 | ||
| 22 | * 4 8192 .001953125 8.000 | ||
| 23 | * 8 4096 .00390625 16.000 | ||
| 24 | * 16 2048 .0078125 32.000 | ||
| 25 | * 32 1024 .015625 64.000 | ||
| 26 | * 64 512 .03125 128.000 | ||
| 27 | * 128 256 .0625 256.000 | ||
| 28 | * 256 128 .125 512.000 | ||
| 29 | */ | ||
| 30 | |||
| 31 | #include <linux/kernel.h> | ||
| 32 | #include <linux/interrupt.h> | ||
| 33 | #include <linux/module.h> | ||
| 34 | #include <asm/geode.h> | ||
| 35 | |||
| 36 | #define MFGPT_DEFAULT_IRQ 7 | ||
| 37 | |||
| 38 | static struct mfgpt_timer_t { | ||
| 39 | unsigned int avail:1; | ||
| 40 | } mfgpt_timers[MFGPT_MAX_TIMERS]; | ||
| 41 | |||
| 42 | /* Selected from the table above */ | ||
| 43 | |||
| 44 | #define MFGPT_DIVISOR 16 | ||
| 45 | #define MFGPT_SCALE 4 /* divisor = 2^(scale) */ | ||
| 46 | #define MFGPT_HZ (32768 / MFGPT_DIVISOR) | ||
| 47 | #define MFGPT_PERIODIC (MFGPT_HZ / HZ) | ||
| 48 | |||
| 49 | /* Allow for disabling of MFGPTs */ | ||
| 50 | static int disable; | ||
| 51 | static int __init mfgpt_disable(char *s) | ||
| 52 | { | ||
| 53 | disable = 1; | ||
| 54 | return 1; | ||
| 55 | } | ||
| 56 | __setup("nomfgpt", mfgpt_disable); | ||
| 57 | |||
| 58 | /* Reset the MFGPT timers. This is required by some broken BIOSes which already | ||
| 59 | * do the same and leave the system in an unstable state. TinyBIOS 0.98 is | ||
| 60 | * affected at least (0.99 is OK with MFGPT workaround left to off). | ||
| 61 | */ | ||
| 62 | static int __init mfgpt_fix(char *s) | ||
| 63 | { | ||
| 64 | u32 val, dummy; | ||
| 65 | |||
| 66 | /* The following udocumented bit resets the MFGPT timers */ | ||
| 67 | val = 0xFF; dummy = 0; | ||
| 68 | wrmsr(MSR_MFGPT_SETUP, val, dummy); | ||
| 69 | return 1; | ||
| 70 | } | ||
| 71 | __setup("mfgptfix", mfgpt_fix); | ||
| 72 | |||
| 73 | /* | ||
| 74 | * Check whether any MFGPTs are available for the kernel to use. In most | ||
| 75 | * cases, firmware that uses AMD's VSA code will claim all timers during | ||
| 76 | * bootup; we certainly don't want to take them if they're already in use. | ||
| 77 | * In other cases (such as with VSAless OpenFirmware), the system firmware | ||
| 78 | * leaves timers available for us to use. | ||
| 79 | */ | ||
| 80 | |||
| 81 | |||
| 82 | static int timers = -1; | ||
| 83 | |||
| 84 | static void geode_mfgpt_detect(void) | ||
| 85 | { | ||
| 86 | int i; | ||
| 87 | u16 val; | ||
| 88 | |||
| 89 | timers = 0; | ||
| 90 | |||
| 91 | if (disable) { | ||
| 92 | printk(KERN_INFO "geode-mfgpt: MFGPT support is disabled\n"); | ||
| 93 | goto done; | ||
| 94 | } | ||
| 95 | |||
| 96 | if (!geode_get_dev_base(GEODE_DEV_MFGPT)) { | ||
| 97 | printk(KERN_INFO "geode-mfgpt: MFGPT LBAR is not set up\n"); | ||
| 98 | goto done; | ||
| 99 | } | ||
| 100 | |||
| 101 | for (i = 0; i < MFGPT_MAX_TIMERS; i++) { | ||
| 102 | val = geode_mfgpt_read(i, MFGPT_REG_SETUP); | ||
| 103 | if (!(val & MFGPT_SETUP_SETUP)) { | ||
| 104 | mfgpt_timers[i].avail = 1; | ||
| 105 | timers++; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | done: | ||
| 110 | printk(KERN_INFO "geode-mfgpt: %d MFGPT timers available.\n", timers); | ||
| 111 | } | ||
| 112 | |||
| 113 | int geode_mfgpt_toggle_event(int timer, int cmp, int event, int enable) | ||
| 114 | { | ||
| 115 | u32 msr, mask, value, dummy; | ||
| 116 | int shift = (cmp == MFGPT_CMP1) ? 0 : 8; | ||
| 117 | |||
| 118 | if (timer < 0 || timer >= MFGPT_MAX_TIMERS) | ||
| 119 | return -EIO; | ||
| 120 | |||
| 121 | /* | ||
| 122 | * The register maps for these are described in sections 6.17.1.x of | ||
| 123 | * the AMD Geode CS5536 Companion Device Data Book. | ||
| 124 | */ | ||
| 125 | switch (event) { | ||
| 126 | case MFGPT_EVENT_RESET: | ||
| 127 | /* | ||
| 128 | * XXX: According to the docs, we cannot reset timers above | ||
| 129 | * 6; that is, resets for 7 and 8 will be ignored. Is this | ||
| 130 | * a problem? -dilinger | ||
| 131 | */ | ||
| 132 | msr = MSR_MFGPT_NR; | ||
| 133 | mask = 1 << (timer + 24); | ||
| 134 | break; | ||
| 135 | |||
| 136 | case MFGPT_EVENT_NMI: | ||
| 137 | msr = MSR_MFGPT_NR; | ||
| 138 | mask = 1 << (timer + shift); | ||
| 139 | break; | ||
| 140 | |||
| 141 | case MFGPT_EVENT_IRQ: | ||
| 142 | msr = MSR_MFGPT_IRQ; | ||
| 143 | mask = 1 << (timer + shift); | ||
| 144 | break; | ||
| 145 | |||
| 146 | default: | ||
| 147 | return -EIO; | ||
| 148 | } | ||
| 149 | |||
| 150 | rdmsr(msr, value, dummy); | ||
| 151 | |||
| 152 | if (enable) | ||
| 153 | value |= mask; | ||
| 154 | else | ||
| 155 | value &= ~mask; | ||
| 156 | |||
| 157 | wrmsr(msr, value, dummy); | ||
| 158 | return 0; | ||
| 159 | } | ||
| 160 | EXPORT_SYMBOL_GPL(geode_mfgpt_toggle_event); | ||
| 161 | |||
| 162 | int geode_mfgpt_set_irq(int timer, int cmp, int *irq, int enable) | ||
| 163 | { | ||
| 164 | u32 zsel, lpc, dummy; | ||
| 165 | int shift; | ||
| 166 | |||
| 167 | if (timer < 0 || timer >= MFGPT_MAX_TIMERS) | ||
| 168 | return -EIO; | ||
| 169 | |||
| 170 | /* | ||
| 171 | * Unfortunately, MFGPTs come in pairs sharing their IRQ lines. If VSA | ||
| 172 | * is using the same CMP of the timer's Siamese twin, the IRQ is set to | ||
| 173 | * 2, and we mustn't use nor change it. | ||
| 174 | * XXX: Likewise, 2 Linux drivers might clash if the 2nd overwrites the | ||
| 175 | * IRQ of the 1st. This can only happen if forcing an IRQ, calling this | ||
| 176 | * with *irq==0 is safe. Currently there _are_ no 2 drivers. | ||
| 177 | */ | ||
| 178 | rdmsr(MSR_PIC_ZSEL_LOW, zsel, dummy); | ||
| 179 | shift = ((cmp == MFGPT_CMP1 ? 0 : 4) + timer % 4) * 4; | ||
| 180 | if (((zsel >> shift) & 0xF) == 2) | ||
| 181 | return -EIO; | ||
| 182 | |||
| 183 | /* Choose IRQ: if none supplied, keep IRQ already set or use default */ | ||
| 184 | if (!*irq) | ||
| 185 | *irq = (zsel >> shift) & 0xF; | ||
| 186 | if (!*irq) | ||
| 187 | *irq = MFGPT_DEFAULT_IRQ; | ||
| 188 | |||
| 189 | /* Can't use IRQ if it's 0 (=disabled), 2, or routed to LPC */ | ||
| 190 | if (*irq < 1 || *irq == 2 || *irq > 15) | ||
| 191 | return -EIO; | ||
| 192 | rdmsr(MSR_PIC_IRQM_LPC, lpc, dummy); | ||
| 193 | if (lpc & (1 << *irq)) | ||
| 194 | return -EIO; | ||
| 195 | |||
| 196 | /* All chosen and checked - go for it */ | ||
| 197 | if (geode_mfgpt_toggle_event(timer, cmp, MFGPT_EVENT_IRQ, enable)) | ||
| 198 | return -EIO; | ||
| 199 | if (enable) { | ||
| 200 | zsel = (zsel & ~(0xF << shift)) | (*irq << shift); | ||
| 201 | wrmsr(MSR_PIC_ZSEL_LOW, zsel, dummy); | ||
| 202 | } | ||
| 203 | |||
| 204 | return 0; | ||
| 205 | } | ||
| 206 | |||
| 207 | static int mfgpt_get(int timer) | ||
| 208 | { | ||
| 209 | mfgpt_timers[timer].avail = 0; | ||
| 210 | printk(KERN_INFO "geode-mfgpt: Registered timer %d\n", timer); | ||
| 211 | return timer; | ||
| 212 | } | ||
| 213 | |||
| 214 | int geode_mfgpt_alloc_timer(int timer, int domain) | ||
| 215 | { | ||
| 216 | int i; | ||
| 217 | |||
| 218 | if (timers == -1) { | ||
| 219 | /* timers haven't been detected yet */ | ||
| 220 | geode_mfgpt_detect(); | ||
| 221 | } | ||
| 222 | |||
| 223 | if (!timers) | ||
| 224 | return -1; | ||
| 225 | |||
| 226 | if (timer >= MFGPT_MAX_TIMERS) | ||
| 227 | return -1; | ||
| 228 | |||
| 229 | if (timer < 0) { | ||
| 230 | /* Try to find an available timer */ | ||
| 231 | for (i = 0; i < MFGPT_MAX_TIMERS; i++) { | ||
| 232 | if (mfgpt_timers[i].avail) | ||
| 233 | return mfgpt_get(i); | ||
| 234 | |||
| 235 | if (i == 5 && domain == MFGPT_DOMAIN_WORKING) | ||
| 236 | break; | ||
| 237 | } | ||
| 238 | } else { | ||
| 239 | /* If they requested a specific timer, try to honor that */ | ||
| 240 | if (mfgpt_timers[timer].avail) | ||
| 241 | return mfgpt_get(timer); | ||
| 242 | } | ||
| 243 | |||
| 244 | /* No timers available - too bad */ | ||
| 245 | return -1; | ||
| 246 | } | ||
| 247 | EXPORT_SYMBOL_GPL(geode_mfgpt_alloc_timer); | ||
| 248 | |||
| 249 | |||
| 250 | #ifdef CONFIG_GEODE_MFGPT_TIMER | ||
| 251 | |||
| 252 | /* | ||
| 253 | * The MFPGT timers on the CS5536 provide us with suitable timers to use | ||
| 254 | * as clock event sources - not as good as a HPET or APIC, but certainly | ||
| 255 | * better than the PIT. This isn't a general purpose MFGPT driver, but | ||
| 256 | * a simplified one designed specifically to act as a clock event source. | ||
| 257 | * For full details about the MFGPT, please consult the CS5536 data sheet. | ||
| 258 | */ | ||
| 259 | |||
| 260 | #include <linux/clocksource.h> | ||
| 261 | #include <linux/clockchips.h> | ||
| 262 | |||
| 263 | static unsigned int mfgpt_tick_mode = CLOCK_EVT_MODE_SHUTDOWN; | ||
| 264 | static u16 mfgpt_event_clock; | ||
| 265 | |||
| 266 | static int irq; | ||
| 267 | static int __init mfgpt_setup(char *str) | ||
| 268 | { | ||
| 269 | get_option(&str, &irq); | ||
| 270 | return 1; | ||
| 271 | } | ||
| 272 | __setup("mfgpt_irq=", mfgpt_setup); | ||
| 273 | |||
| 274 | static void mfgpt_disable_timer(u16 clock) | ||
| 275 | { | ||
| 276 | /* avoid races by clearing CMP1 and CMP2 unconditionally */ | ||
| 277 | geode_mfgpt_write(clock, MFGPT_REG_SETUP, (u16) ~MFGPT_SETUP_CNTEN | | ||
| 278 | MFGPT_SETUP_CMP1 | MFGPT_SETUP_CMP2); | ||
| 279 | } | ||
| 280 | |||
| 281 | static int mfgpt_next_event(unsigned long, struct clock_event_device *); | ||
| 282 | static void mfgpt_set_mode(enum clock_event_mode, struct clock_event_device *); | ||
| 283 | |||
| 284 | static struct clock_event_device mfgpt_clockevent = { | ||
| 285 | .name = "mfgpt-timer", | ||
| 286 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
| 287 | .set_mode = mfgpt_set_mode, | ||
| 288 | .set_next_event = mfgpt_next_event, | ||
| 289 | .rating = 250, | ||
| 290 | .cpumask = cpu_all_mask, | ||
| 291 | .shift = 32 | ||
| 292 | }; | ||
| 293 | |||
| 294 | static void mfgpt_start_timer(u16 delta) | ||
| 295 | { | ||
| 296 | geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_CMP2, (u16) delta); | ||
| 297 | geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0); | ||
| 298 | |||
| 299 | geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, | ||
| 300 | MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); | ||
| 301 | } | ||
| 302 | |||
| 303 | static void mfgpt_set_mode(enum clock_event_mode mode, | ||
| 304 | struct clock_event_device *evt) | ||
| 305 | { | ||
| 306 | mfgpt_disable_timer(mfgpt_event_clock); | ||
| 307 | |||
| 308 | if (mode == CLOCK_EVT_MODE_PERIODIC) | ||
| 309 | mfgpt_start_timer(MFGPT_PERIODIC); | ||
| 310 | |||
| 311 | mfgpt_tick_mode = mode; | ||
| 312 | } | ||
| 313 | |||
| 314 | static int mfgpt_next_event(unsigned long delta, struct clock_event_device *evt) | ||
| 315 | { | ||
| 316 | mfgpt_start_timer(delta); | ||
| 317 | return 0; | ||
| 318 | } | ||
| 319 | |||
| 320 | static irqreturn_t mfgpt_tick(int irq, void *dev_id) | ||
| 321 | { | ||
| 322 | u16 val = geode_mfgpt_read(mfgpt_event_clock, MFGPT_REG_SETUP); | ||
| 323 | |||
| 324 | /* See if the interrupt was for us */ | ||
| 325 | if (!(val & (MFGPT_SETUP_SETUP | MFGPT_SETUP_CMP2 | MFGPT_SETUP_CMP1))) | ||
| 326 | return IRQ_NONE; | ||
| 327 | |||
| 328 | /* Turn off the clock (and clear the event) */ | ||
| 329 | mfgpt_disable_timer(mfgpt_event_clock); | ||
| 330 | |||
| 331 | if (mfgpt_tick_mode == CLOCK_EVT_MODE_SHUTDOWN) | ||
| 332 | return IRQ_HANDLED; | ||
| 333 | |||
| 334 | /* Clear the counter */ | ||
| 335 | geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0); | ||
| 336 | |||
| 337 | /* Restart the clock in periodic mode */ | ||
| 338 | |||
| 339 | if (mfgpt_tick_mode == CLOCK_EVT_MODE_PERIODIC) { | ||
| 340 | geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, | ||
| 341 | MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2); | ||
| 342 | } | ||
| 343 | |||
| 344 | mfgpt_clockevent.event_handler(&mfgpt_clockevent); | ||
| 345 | return IRQ_HANDLED; | ||
| 346 | } | ||
| 347 | |||
| 348 | static struct irqaction mfgptirq = { | ||
| 349 | .handler = mfgpt_tick, | ||
| 350 | .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER, | ||
| 351 | .name = "mfgpt-timer" | ||
| 352 | }; | ||
| 353 | |||
| 354 | int __init mfgpt_timer_setup(void) | ||
| 355 | { | ||
| 356 | int timer, ret; | ||
| 357 | u16 val; | ||
| 358 | |||
| 359 | timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING); | ||
| 360 | if (timer < 0) { | ||
| 361 | printk(KERN_ERR | ||
| 362 | "mfgpt-timer: Could not allocate a MFPGT timer\n"); | ||
| 363 | return -ENODEV; | ||
| 364 | } | ||
| 365 | |||
| 366 | mfgpt_event_clock = timer; | ||
| 367 | |||
| 368 | /* Set up the IRQ on the MFGPT side */ | ||
| 369 | if (geode_mfgpt_setup_irq(mfgpt_event_clock, MFGPT_CMP2, &irq)) { | ||
| 370 | printk(KERN_ERR "mfgpt-timer: Could not set up IRQ %d\n", irq); | ||
| 371 | return -EIO; | ||
| 372 | } | ||
| 373 | |||
| 374 | /* And register it with the kernel */ | ||
| 375 | ret = setup_irq(irq, &mfgptirq); | ||
| 376 | |||
| 377 | if (ret) { | ||
| 378 | printk(KERN_ERR | ||
| 379 | "mfgpt-timer: Unable to set up the interrupt.\n"); | ||
| 380 | goto err; | ||
| 381 | } | ||
| 382 | |||
| 383 | /* Set the clock scale and enable the event mode for CMP2 */ | ||
| 384 | val = MFGPT_SCALE | (3 << 8); | ||
| 385 | |||
| 386 | geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val); | ||
| 387 | |||
| 388 | /* Set up the clock event */ | ||
| 389 | mfgpt_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC, | ||
| 390 | mfgpt_clockevent.shift); | ||
| 391 | mfgpt_clockevent.min_delta_ns = clockevent_delta2ns(0xF, | ||
| 392 | &mfgpt_clockevent); | ||
| 393 | mfgpt_clockevent.max_delta_ns = clockevent_delta2ns(0xFFFE, | ||
| 394 | &mfgpt_clockevent); | ||
| 395 | |||
| 396 | printk(KERN_INFO | ||
| 397 | "mfgpt-timer: Registering MFGPT timer %d as a clock event, using IRQ %d\n", | ||
| 398 | timer, irq); | ||
| 399 | clockevents_register_device(&mfgpt_clockevent); | ||
| 400 | |||
| 401 | return 0; | ||
| 402 | |||
| 403 | err: | ||
| 404 | geode_mfgpt_release_irq(mfgpt_event_clock, MFGPT_CMP2, &irq); | ||
| 405 | printk(KERN_ERR | ||
| 406 | "mfgpt-timer: Unable to set up the MFGPT clock source\n"); | ||
| 407 | return -EIO; | ||
| 408 | } | ||
| 409 | |||
| 410 | #endif | ||
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index df4b82d1348e..57ca339924ef 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
| @@ -176,7 +176,7 @@ comment "PCI GPIO expanders:" | |||
| 176 | 176 | ||
| 177 | config GPIO_CS5535 | 177 | config GPIO_CS5535 |
| 178 | tristate "AMD CS5535/CS5536 GPIO support" | 178 | tristate "AMD CS5535/CS5536 GPIO support" |
| 179 | depends on PCI && !CS5535_GPIO && !MGEODE_LX | 179 | depends on PCI && !CS5535_GPIO |
| 180 | help | 180 | help |
| 181 | The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that | 181 | The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that |
| 182 | can be used for quite a number of things. The CS5535/6 is found on | 182 | can be used for quite a number of things. The CS5535/6 is found on |
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index d6d6d846f0d6..59f4ba1b7034 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
| @@ -189,7 +189,7 @@ config SGI_XP | |||
| 189 | 189 | ||
| 190 | config CS5535_MFGPT | 190 | config CS5535_MFGPT |
| 191 | tristate "CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support" | 191 | tristate "CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support" |
| 192 | depends on PCI && !MGEODE_LX | 192 | depends on PCI |
| 193 | depends on X86 | 193 | depends on X86 |
| 194 | default n | 194 | default n |
| 195 | help | 195 | help |
