diff options
-rw-r--r-- | arch/i386/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/i386/kernel/geode.c | 155 | ||||
-rw-r--r-- | include/asm-i386/geode.h | 159 |
3 files changed, 315 insertions, 0 deletions
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 06da59f6f837..dbe5e87e0d66 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile | |||
@@ -40,6 +40,7 @@ obj-$(CONFIG_VM86) += vm86.o | |||
40 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 40 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
41 | obj-$(CONFIG_HPET_TIMER) += hpet.o | 41 | obj-$(CONFIG_HPET_TIMER) += hpet.o |
42 | obj-$(CONFIG_K8_NB) += k8.o | 42 | obj-$(CONFIG_K8_NB) += k8.o |
43 | obj-$(CONFIG_MGEODE_LX) += geode.o | ||
43 | 44 | ||
44 | obj-$(CONFIG_VMI) += vmi.o vmiclock.o | 45 | obj-$(CONFIG_VMI) += vmi.o vmiclock.o |
45 | obj-$(CONFIG_PARAVIRT) += paravirt.o | 46 | obj-$(CONFIG_PARAVIRT) += paravirt.o |
diff --git a/arch/i386/kernel/geode.c b/arch/i386/kernel/geode.c new file mode 100644 index 000000000000..41e8aec4c61d --- /dev/null +++ b/arch/i386/kernel/geode.c | |||
@@ -0,0 +1,155 @@ | |||
1 | /* | ||
2 | * AMD Geode southbridge support code | ||
3 | * Copyright (C) 2006, Advanced Micro Devices, Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of version 2 of the GNU General Public License | ||
7 | * as published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/ioport.h> | ||
13 | #include <linux/io.h> | ||
14 | #include <asm/msr.h> | ||
15 | #include <asm/geode.h> | ||
16 | |||
17 | static struct { | ||
18 | char *name; | ||
19 | u32 msr; | ||
20 | int size; | ||
21 | u32 base; | ||
22 | } lbars[] = { | ||
23 | { "geode-pms", MSR_LBAR_PMS, LBAR_PMS_SIZE, 0 }, | ||
24 | { "geode-acpi", MSR_LBAR_ACPI, LBAR_ACPI_SIZE, 0 }, | ||
25 | { "geode-gpio", MSR_LBAR_GPIO, LBAR_GPIO_SIZE, 0 }, | ||
26 | { "geode-mfgpt", MSR_LBAR_MFGPT, LBAR_MFGPT_SIZE, 0 } | ||
27 | }; | ||
28 | |||
29 | static void __init init_lbars(void) | ||
30 | { | ||
31 | u32 lo, hi; | ||
32 | int i; | ||
33 | |||
34 | for (i = 0; i < ARRAY_SIZE(lbars); i++) { | ||
35 | rdmsr(lbars[i].msr, lo, hi); | ||
36 | if (hi & 0x01) | ||
37 | lbars[i].base = lo & 0x0000ffff; | ||
38 | |||
39 | if (lbars[i].base == 0) | ||
40 | printk(KERN_ERR "geode: Couldn't initialize '%s'\n", | ||
41 | lbars[i].name); | ||
42 | } | ||
43 | } | ||
44 | |||
45 | int geode_get_dev_base(unsigned int dev) | ||
46 | { | ||
47 | BUG_ON(dev >= ARRAY_SIZE(lbars)); | ||
48 | return lbars[dev].base; | ||
49 | } | ||
50 | EXPORT_SYMBOL_GPL(geode_get_dev_base); | ||
51 | |||
52 | /* === GPIO API === */ | ||
53 | |||
54 | void geode_gpio_set(unsigned int gpio, unsigned int reg) | ||
55 | { | ||
56 | u32 base = geode_get_dev_base(GEODE_DEV_GPIO); | ||
57 | |||
58 | if (!base) | ||
59 | return; | ||
60 | |||
61 | if (gpio < 16) | ||
62 | outl(1 << gpio, base + reg); | ||
63 | else | ||
64 | outl(1 << (gpio - 16), base + 0x80 + reg); | ||
65 | } | ||
66 | EXPORT_SYMBOL_GPL(geode_gpio_set); | ||
67 | |||
68 | void geode_gpio_clear(unsigned int gpio, unsigned int reg) | ||
69 | { | ||
70 | u32 base = geode_get_dev_base(GEODE_DEV_GPIO); | ||
71 | |||
72 | if (!base) | ||
73 | return; | ||
74 | |||
75 | if (gpio < 16) | ||
76 | outl(1 << (gpio + 16), base + reg); | ||
77 | else | ||
78 | outl(1 << gpio, base + 0x80 + reg); | ||
79 | } | ||
80 | EXPORT_SYMBOL_GPL(geode_gpio_clear); | ||
81 | |||
82 | int geode_gpio_isset(unsigned int gpio, unsigned int reg) | ||
83 | { | ||
84 | u32 base = geode_get_dev_base(GEODE_DEV_GPIO); | ||
85 | |||
86 | if (!base) | ||
87 | return 0; | ||
88 | |||
89 | if (gpio < 16) | ||
90 | return (inl(base + reg) & (1 << gpio)) ? 1 : 0; | ||
91 | else | ||
92 | return (inl(base + 0x80 + reg) & (1 << (gpio - 16))) ? 1 : 0; | ||
93 | } | ||
94 | EXPORT_SYMBOL_GPL(geode_gpio_isset); | ||
95 | |||
96 | void geode_gpio_set_irq(unsigned int group, unsigned int irq) | ||
97 | { | ||
98 | u32 lo, hi; | ||
99 | |||
100 | if (group > 7 || irq > 15) | ||
101 | return; | ||
102 | |||
103 | rdmsr(MSR_PIC_ZSEL_HIGH, lo, hi); | ||
104 | |||
105 | lo &= ~(0xF << (group * 4)); | ||
106 | lo |= (irq & 0xF) << (group * 4); | ||
107 | |||
108 | wrmsr(MSR_PIC_ZSEL_HIGH, lo, hi); | ||
109 | } | ||
110 | EXPORT_SYMBOL_GPL(geode_gpio_set_irq); | ||
111 | |||
112 | void geode_gpio_setup_event(unsigned int gpio, int pair, int pme) | ||
113 | { | ||
114 | u32 base = geode_get_dev_base(GEODE_DEV_GPIO); | ||
115 | u32 offset, shift, val; | ||
116 | |||
117 | if (gpio >= 24) | ||
118 | offset = GPIO_MAP_W; | ||
119 | else if (gpio >= 16) | ||
120 | offset = GPIO_MAP_Z; | ||
121 | else if (gpio >= 8) | ||
122 | offset = GPIO_MAP_Y; | ||
123 | else | ||
124 | offset = GPIO_MAP_X; | ||
125 | |||
126 | shift = (gpio % 8) * 4; | ||
127 | |||
128 | val = inl(base + offset); | ||
129 | |||
130 | /* Clear whatever was there before */ | ||
131 | val &= ~(0xF << shift); | ||
132 | |||
133 | /* And set the new value */ | ||
134 | |||
135 | val |= ((pair & 7) << shift); | ||
136 | |||
137 | /* Set the PME bit if this is a PME event */ | ||
138 | |||
139 | if (pme) | ||
140 | val |= (1 << (shift + 3)); | ||
141 | |||
142 | outl(val, base + offset); | ||
143 | } | ||
144 | EXPORT_SYMBOL_GPL(geode_gpio_setup_event); | ||
145 | |||
146 | static int __init geode_southbridge_init(void) | ||
147 | { | ||
148 | if (!is_geode()) | ||
149 | return -ENODEV; | ||
150 | |||
151 | init_lbars(); | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | postcore_initcall(geode_southbridge_init); | ||
diff --git a/include/asm-i386/geode.h b/include/asm-i386/geode.h new file mode 100644 index 000000000000..6da4bbbea3dc --- /dev/null +++ b/include/asm-i386/geode.h | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * AMD Geode definitions | ||
3 | * Copyright (C) 2006, Advanced Micro Devices, Inc. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of version 2 of the GNU General Public License | ||
7 | * as published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #ifndef _ASM_GEODE_H_ | ||
11 | #define _ASM_GEODE_H_ | ||
12 | |||
13 | #include <asm/processor.h> | ||
14 | #include <linux/io.h> | ||
15 | |||
16 | /* Generic southbridge functions */ | ||
17 | |||
18 | #define GEODE_DEV_PMS 0 | ||
19 | #define GEODE_DEV_ACPI 1 | ||
20 | #define GEODE_DEV_GPIO 2 | ||
21 | #define GEODE_DEV_MFGPT 3 | ||
22 | |||
23 | extern int geode_get_dev_base(unsigned int dev); | ||
24 | |||
25 | /* Useful macros */ | ||
26 | #define geode_pms_base() geode_get_dev_base(GEODE_DEV_PMS) | ||
27 | #define geode_acpi_base() geode_get_dev_base(GEODE_DEV_ACPI) | ||
28 | #define geode_gpio_base() geode_get_dev_base(GEODE_DEV_GPIO) | ||
29 | #define geode_mfgpt_base() geode_get_dev_base(GEODE_DEV_MFGPT) | ||
30 | |||
31 | /* MSRS */ | ||
32 | |||
33 | #define GX_GLCP_SYS_RSTPLL 0x4C000014 | ||
34 | |||
35 | #define MSR_LBAR_SMB 0x5140000B | ||
36 | #define MSR_LBAR_GPIO 0x5140000C | ||
37 | #define MSR_LBAR_MFGPT 0x5140000D | ||
38 | #define MSR_LBAR_ACPI 0x5140000E | ||
39 | #define MSR_LBAR_PMS 0x5140000F | ||
40 | |||
41 | #define MSR_PIC_YSEL_LOW 0x51400020 | ||
42 | #define MSR_PIC_YSEL_HIGH 0x51400021 | ||
43 | #define MSR_PIC_ZSEL_LOW 0x51400022 | ||
44 | #define MSR_PIC_ZSEL_HIGH 0x51400023 | ||
45 | |||
46 | #define MFGPT_IRQ_MSR 0x51400028 | ||
47 | #define MFGPT_NR_MSR 0x51400029 | ||
48 | |||
49 | /* Resource Sizes */ | ||
50 | |||
51 | #define LBAR_GPIO_SIZE 0xFF | ||
52 | #define LBAR_MFGPT_SIZE 0x40 | ||
53 | #define LBAR_ACPI_SIZE 0x40 | ||
54 | #define LBAR_PMS_SIZE 0x80 | ||
55 | |||
56 | /* ACPI registers (PMS block) */ | ||
57 | |||
58 | /* | ||
59 | * PM1_EN is only valid when VSA is enabled for 16 bit reads. | ||
60 | * When VSA is not enabled, *always* read both PM1_STS and PM1_EN | ||
61 | * with a 32 bit read at offset 0x0 | ||
62 | */ | ||
63 | |||
64 | #define PM1_STS 0x00 | ||
65 | #define PM1_EN 0x02 | ||
66 | #define PM1_CNT 0x08 | ||
67 | #define PM2_CNT 0x0C | ||
68 | #define PM_TMR 0x10 | ||
69 | #define PM_GPE0_STS 0x18 | ||
70 | #define PM_GPE0_EN 0x1C | ||
71 | |||
72 | /* PMC registers (PMS block) */ | ||
73 | |||
74 | #define PM_SSD 0x00 | ||
75 | #define PM_SCXA 0x04 | ||
76 | #define PM_SCYA 0x08 | ||
77 | #define PM_OUT_SLPCTL 0x0C | ||
78 | #define PM_SCLK 0x10 | ||
79 | #define PM_SED 0x1 | ||
80 | #define PM_SCXD 0x18 | ||
81 | #define PM_SCYD 0x1C | ||
82 | #define PM_IN_SLPCTL 0x20 | ||
83 | #define PM_WKD 0x30 | ||
84 | #define PM_WKXD 0x34 | ||
85 | #define PM_RD 0x38 | ||
86 | #define PM_WKXA 0x3C | ||
87 | #define PM_FSD 0x40 | ||
88 | #define PM_TSD 0x44 | ||
89 | #define PM_PSD 0x48 | ||
90 | #define PM_NWKD 0x4C | ||
91 | #define PM_AWKD 0x50 | ||
92 | #define PM_SSC 0x54 | ||
93 | |||
94 | /* GPIO */ | ||
95 | |||
96 | #define GPIO_OUTPUT_VAL 0x00 | ||
97 | #define GPIO_OUTPUT_ENABLE 0x04 | ||
98 | #define GPIO_OUTPUT_OPEN_DRAIN 0x08 | ||
99 | #define GPIO_OUTPUT_INVERT 0x0C | ||
100 | #define GPIO_OUTPUT_AUX1 0x10 | ||
101 | #define GPIO_OUTPUT_AUX2 0x14 | ||
102 | #define GPIO_PULL_UP 0x18 | ||
103 | #define GPIO_PULL_DOWN 0x1C | ||
104 | #define GPIO_INPUT_ENABLE 0x20 | ||
105 | #define GPIO_INPUT_INVERT 0x24 | ||
106 | #define GPIO_INPUT_FILTER 0x28 | ||
107 | #define GPIO_INPUT_EVENT_COUNT 0x2C | ||
108 | #define GPIO_READ_BACK 0x30 | ||
109 | #define GPIO_INPUT_AUX1 0x34 | ||
110 | #define GPIO_EVENTS_ENABLE 0x38 | ||
111 | #define GPIO_LOCK_ENABLE 0x3C | ||
112 | #define GPIO_POSITIVE_EDGE_EN 0x40 | ||
113 | #define GPIO_NEGATIVE_EDGE_EN 0x44 | ||
114 | #define GPIO_POSITIVE_EDGE_STS 0x48 | ||
115 | #define GPIO_NEGATIVE_EDGE_STS 0x4C | ||
116 | |||
117 | #define GPIO_MAP_X 0xE0 | ||
118 | #define GPIO_MAP_Y 0xE4 | ||
119 | #define GPIO_MAP_Z 0xE8 | ||
120 | #define GPIO_MAP_W 0xEC | ||
121 | |||
122 | extern void geode_gpio_set(unsigned int, unsigned int); | ||
123 | extern void geode_gpio_clear(unsigned int, unsigned int); | ||
124 | extern int geode_gpio_isset(unsigned int, unsigned int); | ||
125 | extern void geode_gpio_setup_event(unsigned int, int, int); | ||
126 | extern void geode_gpio_set_irq(unsigned int, unsigned int); | ||
127 | |||
128 | static inline void geode_gpio_event_irq(unsigned int gpio, int pair) | ||
129 | { | ||
130 | geode_gpio_setup_event(gpio, pair, 0); | ||
131 | } | ||
132 | |||
133 | static inline void geode_gpio_event_pme(unsigned int gpio, int pair) | ||
134 | { | ||
135 | geode_gpio_setup_event(gpio, pair, 1); | ||
136 | } | ||
137 | |||
138 | /* Specific geode tests */ | ||
139 | |||
140 | static inline int is_geode_gx(void) | ||
141 | { | ||
142 | return ((boot_cpu_data.x86_vendor == X86_VENDOR_NSC) && | ||
143 | (boot_cpu_data.x86 == 5) && | ||
144 | (boot_cpu_data.x86_model == 5)); | ||
145 | } | ||
146 | |||
147 | static inline int is_geode_lx(void) | ||
148 | { | ||
149 | return ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && | ||
150 | (boot_cpu_data.x86 == 5) && | ||
151 | (boot_cpu_data.x86_model == 10)); | ||
152 | } | ||
153 | |||
154 | static inline int is_geode(void) | ||
155 | { | ||
156 | return (is_geode_gx() || is_geode_lx()); | ||
157 | } | ||
158 | |||
159 | #endif | ||