Commit | Line | Data |
---|---|---|
f62e5184 AS |
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 | { | |
83d7384f AS |
148 | int timers; |
149 | ||
f62e5184 AS |
150 | if (!is_geode()) |
151 | return -ENODEV; | |
152 | ||
153 | init_lbars(); | |
83d7384f AS |
154 | timers = geode_mfgpt_detect(); |
155 | printk(KERN_INFO "geode: %d MFGPT timers available.\n", timers); | |
f62e5184 AS |
156 | return 0; |
157 | } | |
158 | ||
159 | postcore_initcall(geode_southbridge_init); |