diff options
author | Paul Mackerras <paulus@samba.org> | 2005-10-22 02:02:39 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2005-10-22 02:02:39 -0400 |
commit | 35499c0195e46f479cf6ac16ad8d3f394b5fcc10 (patch) | |
tree | 25660acd2425de5236a1eff7a25dc931e6f86492 /arch/powerpc/platforms/powermac/time.c | |
parent | b6ba92819dc1304a4e5a0bf06b297c657b58168a (diff) |
powerpc: Merge in 64-bit powermac support.
This brings in a lot of changes from arch/ppc64/kernel/pmac_*.c to
arch/powerpc/platforms/powermac/*.c and makes various minor tweaks
elsewhere. On the powermac we now initialize ppc_md by copying
the whole pmac_md structure into it, which required some changes in
the ordering of initializations of individual fields of it.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/powermac/time.c')
-rw-r--r-- | arch/powerpc/platforms/powermac/time.c | 250 |
1 files changed, 152 insertions, 98 deletions
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c index a6d2d231d5a0..82982bf6453c 100644 --- a/arch/powerpc/platforms/powermac/time.c +++ b/arch/powerpc/platforms/powermac/time.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <asm/machdep.h> | 33 | #include <asm/machdep.h> |
34 | #include <asm/time.h> | 34 | #include <asm/time.h> |
35 | #include <asm/nvram.h> | 35 | #include <asm/nvram.h> |
36 | #include <asm/smu.h> | ||
36 | 37 | ||
37 | #undef DEBUG | 38 | #undef DEBUG |
38 | 39 | ||
@@ -68,8 +69,8 @@ | |||
68 | 69 | ||
69 | long __init pmac_time_init(void) | 70 | long __init pmac_time_init(void) |
70 | { | 71 | { |
71 | #ifdef CONFIG_NVRAM | ||
72 | s32 delta = 0; | 72 | s32 delta = 0; |
73 | #ifdef CONFIG_NVRAM | ||
73 | int dst; | 74 | int dst; |
74 | 75 | ||
75 | delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16; | 76 | delta = ((s32)pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x9)) << 16; |
@@ -80,110 +81,181 @@ long __init pmac_time_init(void) | |||
80 | dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); | 81 | dst = ((pmac_xpram_read(PMAC_XPRAM_MACHINE_LOC + 0x8) & 0x80) != 0); |
81 | printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, | 82 | printk("GMT Delta read from XPRAM: %d minutes, DST: %s\n", delta/60, |
82 | dst ? "on" : "off"); | 83 | dst ? "on" : "off"); |
83 | return delta; | ||
84 | #else | ||
85 | return 0; | ||
86 | #endif | 84 | #endif |
85 | return delta; | ||
87 | } | 86 | } |
88 | 87 | ||
89 | unsigned long pmac_get_boot_time(void) | 88 | static void to_rtc_time(unsigned long now, struct rtc_time *tm) |
89 | { | ||
90 | to_tm(now, tm); | ||
91 | tm->tm_year -= 1900; | ||
92 | tm->tm_mon -= 1; | ||
93 | } | ||
94 | |||
95 | static unsigned long from_rtc_time(struct rtc_time *tm) | ||
96 | { | ||
97 | return mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, | ||
98 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
99 | } | ||
100 | |||
101 | #ifdef CONFIG_ADB_CUDA | ||
102 | static unsigned long cuda_get_time(void) | ||
90 | { | 103 | { |
91 | #if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) | ||
92 | struct adb_request req; | 104 | struct adb_request req; |
93 | unsigned long now; | 105 | unsigned long now; |
94 | #endif | ||
95 | 106 | ||
96 | /* Get the time from the RTC */ | 107 | if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0) |
97 | switch (sys_ctrler) { | 108 | return 0; |
98 | #ifdef CONFIG_ADB_CUDA | 109 | while (!req.complete) |
99 | case SYS_CTRLER_CUDA: | 110 | cuda_poll(); |
100 | if (cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_GET_TIME) < 0) | 111 | if (req.reply_len != 7) |
101 | return 0; | 112 | printk(KERN_ERR "cuda_get_time: got %d byte reply\n", |
102 | while (!req.complete) | 113 | req.reply_len); |
103 | cuda_poll(); | 114 | now = (req.reply[3] << 24) + (req.reply[4] << 16) |
104 | if (req.reply_len != 7) | 115 | + (req.reply[5] << 8) + req.reply[6]; |
105 | printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", | 116 | if (now < RTC_OFFSET) |
106 | req.reply_len); | 117 | return 0; |
107 | now = (req.reply[3] << 24) + (req.reply[4] << 16) | 118 | return now - RTC_OFFSET; |
108 | + (req.reply[5] << 8) + req.reply[6]; | 119 | } |
109 | return now - RTC_OFFSET; | 120 | |
110 | #endif /* CONFIG_ADB_CUDA */ | 121 | #define cuda_get_rtc_time(tm) to_rtc_time(cuda_get_time(), (tm)) |
111 | #ifdef CONFIG_ADB_PMU | 122 | |
112 | case SYS_CTRLER_PMU: | 123 | static int cuda_set_rtc_time(struct rtc_time *tm) |
113 | if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) | 124 | { |
114 | return 0; | 125 | unsigned int nowtime; |
115 | while (!req.complete) | 126 | struct adb_request req; |
116 | pmu_poll(); | 127 | |
117 | if (req.reply_len != 4) | 128 | nowtime = from_rtc_time(tm) + RTC_OFFSET; |
118 | printk(KERN_ERR "pmac_get_rtc_time: got %d byte reply\n", | 129 | if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, |
119 | req.reply_len); | 130 | nowtime >> 24, nowtime >> 16, nowtime >> 8, |
120 | now = (req.reply[0] << 24) + (req.reply[1] << 16) | 131 | nowtime) < 0) |
121 | + (req.reply[2] << 8) + req.reply[3]; | 132 | return -ENXIO; |
122 | return now - RTC_OFFSET; | 133 | while (!req.complete) |
123 | #endif /* CONFIG_ADB_PMU */ | 134 | cuda_poll(); |
124 | default: ; | 135 | if ((req.reply_len != 3) && (req.reply_len != 7)) |
125 | } | 136 | printk(KERN_ERR "cuda_set_rtc_time: got %d byte reply\n", |
137 | req.reply_len); | ||
126 | return 0; | 138 | return 0; |
127 | } | 139 | } |
128 | 140 | ||
129 | void pmac_get_rtc_time(struct rtc_time *tm) | 141 | #else |
142 | #define cuda_get_time() 0 | ||
143 | #define cuda_get_rtc_time(tm) | ||
144 | #define cuda_set_rtc_time(tm) 0 | ||
145 | #endif | ||
146 | |||
147 | #ifdef CONFIG_ADB_PMU | ||
148 | static unsigned long pmu_get_time(void) | ||
130 | { | 149 | { |
150 | struct adb_request req; | ||
131 | unsigned long now; | 151 | unsigned long now; |
132 | 152 | ||
133 | now = pmac_get_boot_time(); | 153 | if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0) |
134 | to_tm(now, tm); | 154 | return 0; |
135 | tm->tm_year -= 1900; | 155 | pmu_wait_complete(&req); |
136 | tm->tm_mon -= 1; /* month is 0-based */ | 156 | if (req.reply_len != 4) |
157 | printk(KERN_ERR "pmu_get_time: got %d byte reply from PMU\n", | ||
158 | req.reply_len); | ||
159 | now = (req.reply[0] << 24) + (req.reply[1] << 16) | ||
160 | + (req.reply[2] << 8) + req.reply[3]; | ||
161 | if (now < RTC_OFFSET) | ||
162 | return 0; | ||
163 | return now - RTC_OFFSET; | ||
137 | } | 164 | } |
138 | 165 | ||
139 | int pmac_set_rtc_time(struct rtc_time *tm) | 166 | #define pmu_get_rtc_time(tm) to_rtc_time(pmu_get_time(), (tm)) |
167 | |||
168 | static int pmu_set_rtc_time(struct rtc_time *tm) | ||
140 | { | 169 | { |
141 | unsigned long nowtime; | 170 | unsigned int nowtime; |
142 | #if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) | ||
143 | struct adb_request req; | 171 | struct adb_request req; |
172 | |||
173 | nowtime = from_rtc_time(tm) + RTC_OFFSET; | ||
174 | if (pmu_request(&req, NULL, 5, PMU_SET_RTC, nowtime >> 24, | ||
175 | nowtime >> 16, nowtime >> 8, nowtime) < 0) | ||
176 | return -ENXIO; | ||
177 | pmu_wait_complete(&req); | ||
178 | if (req.reply_len != 0) | ||
179 | printk(KERN_ERR "pmu_set_rtc_time: %d byte reply from PMU\n", | ||
180 | req.reply_len); | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | #else | ||
185 | #define pmu_get_time() 0 | ||
186 | #define pmu_get_rtc_time(tm) | ||
187 | #define pmu_set_rtc_time(tm) 0 | ||
144 | #endif | 188 | #endif |
145 | 189 | ||
146 | nowtime = mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, | 190 | #ifdef CONFIG_PMAC_SMU |
147 | tm->tm_hour, tm->tm_min, tm->tm_sec); | 191 | static unsigned long smu_get_time(void) |
148 | nowtime += RTC_OFFSET; | 192 | { |
193 | struct rtc_time tm; | ||
194 | |||
195 | if (smu_get_rtc_time(&tm, 1)) | ||
196 | return 0; | ||
197 | return from_rtc_time(&tm); | ||
198 | } | ||
199 | |||
200 | #else | ||
201 | #define smu_get_time() 0 | ||
202 | #define smu_get_rtc_time(tm, spin) | ||
203 | #define smu_set_rtc_time(tm, spin) 0 | ||
204 | #endif | ||
149 | 205 | ||
206 | unsigned long pmac_get_boot_time(void) | ||
207 | { | ||
208 | /* Get the time from the RTC, used only at boot time */ | ||
150 | switch (sys_ctrler) { | 209 | switch (sys_ctrler) { |
151 | #ifdef CONFIG_ADB_CUDA | ||
152 | case SYS_CTRLER_CUDA: | 210 | case SYS_CTRLER_CUDA: |
153 | if (cuda_request(&req, NULL, 6, CUDA_PACKET, CUDA_SET_TIME, | 211 | return cuda_get_time(); |
154 | nowtime >> 24, nowtime >> 16, nowtime >> 8, | ||
155 | nowtime) < 0) | ||
156 | return 0; | ||
157 | while (!req.complete) | ||
158 | cuda_poll(); | ||
159 | if ((req.reply_len != 3) && (req.reply_len != 7)) | ||
160 | printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", | ||
161 | req.reply_len); | ||
162 | return 1; | ||
163 | #endif /* CONFIG_ADB_CUDA */ | ||
164 | #ifdef CONFIG_ADB_PMU | ||
165 | case SYS_CTRLER_PMU: | 212 | case SYS_CTRLER_PMU: |
166 | if (pmu_request(&req, NULL, 5, PMU_SET_RTC, | 213 | return pmu_get_time(); |
167 | nowtime >> 24, nowtime >> 16, nowtime >> 8, nowtime) < 0) | 214 | case SYS_CTRLER_SMU: |
168 | return 0; | 215 | return smu_get_time(); |
169 | while (!req.complete) | ||
170 | pmu_poll(); | ||
171 | if (req.reply_len != 0) | ||
172 | printk(KERN_ERR "pmac_set_rtc_time: got %d byte reply\n", | ||
173 | req.reply_len); | ||
174 | return 1; | ||
175 | #endif /* CONFIG_ADB_PMU */ | ||
176 | default: | 216 | default: |
177 | return 0; | 217 | return 0; |
178 | } | 218 | } |
179 | } | 219 | } |
180 | 220 | ||
221 | void pmac_get_rtc_time(struct rtc_time *tm) | ||
222 | { | ||
223 | /* Get the time from the RTC, used only at boot time */ | ||
224 | switch (sys_ctrler) { | ||
225 | case SYS_CTRLER_CUDA: | ||
226 | cuda_get_rtc_time(tm); | ||
227 | break; | ||
228 | case SYS_CTRLER_PMU: | ||
229 | pmu_get_rtc_time(tm); | ||
230 | break; | ||
231 | case SYS_CTRLER_SMU: | ||
232 | smu_get_rtc_time(tm, 1); | ||
233 | break; | ||
234 | default: | ||
235 | ; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | int pmac_set_rtc_time(struct rtc_time *tm) | ||
240 | { | ||
241 | switch (sys_ctrler) { | ||
242 | case SYS_CTRLER_CUDA: | ||
243 | return cuda_set_rtc_time(tm); | ||
244 | case SYS_CTRLER_PMU: | ||
245 | return pmu_set_rtc_time(tm); | ||
246 | case SYS_CTRLER_SMU: | ||
247 | return smu_set_rtc_time(tm, 1); | ||
248 | default: | ||
249 | return -ENODEV; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | #ifdef CONFIG_PPC32 | ||
181 | /* | 254 | /* |
182 | * Calibrate the decrementer register using VIA timer 1. | 255 | * Calibrate the decrementer register using VIA timer 1. |
183 | * This is used both on powermacs and CHRP machines. | 256 | * This is used both on powermacs and CHRP machines. |
184 | */ | 257 | */ |
185 | int __init | 258 | int __init via_calibrate_decr(void) |
186 | via_calibrate_decr(void) | ||
187 | { | 259 | { |
188 | struct device_node *vias; | 260 | struct device_node *vias; |
189 | volatile unsigned char __iomem *via; | 261 | volatile unsigned char __iomem *via; |
@@ -217,15 +289,12 @@ via_calibrate_decr(void) | |||
217 | dend = get_dec(); | 289 | dend = get_dec(); |
218 | 290 | ||
219 | ppc_tb_freq = (dstart - dend) * 100 / 6; | 291 | ppc_tb_freq = (dstart - dend) * 100 / 6; |
220 | tb_ticks_per_jiffy = (dstart - dend) / ((6 * HZ)/100); | ||
221 | |||
222 | printk(KERN_INFO "via_calibrate_decr: ticks per jiffy = %lu (%u ticks)\n", | ||
223 | tb_ticks_per_jiffy, dstart - dend); | ||
224 | 292 | ||
225 | iounmap(via); | 293 | iounmap(via); |
226 | 294 | ||
227 | return 1; | 295 | return 1; |
228 | } | 296 | } |
297 | #endif | ||
229 | 298 | ||
230 | #ifdef CONFIG_PM | 299 | #ifdef CONFIG_PM |
231 | /* | 300 | /* |
@@ -262,19 +331,17 @@ static struct pmu_sleep_notifier time_sleep_notifier = { | |||
262 | 331 | ||
263 | /* | 332 | /* |
264 | * Query the OF and get the decr frequency. | 333 | * Query the OF and get the decr frequency. |
265 | * This was taken from the pmac time_init() when merging the prep/pmac | ||
266 | * time functions. | ||
267 | */ | 334 | */ |
268 | void __init | 335 | void __init pmac_calibrate_decr(void) |
269 | pmac_calibrate_decr(void) | ||
270 | { | 336 | { |
271 | struct device_node *cpu; | ||
272 | unsigned int freq, *fp; | ||
273 | |||
274 | #ifdef CONFIG_PM | 337 | #ifdef CONFIG_PM |
338 | /* XXX why here? */ | ||
275 | pmu_register_sleep_notifier(&time_sleep_notifier); | 339 | pmu_register_sleep_notifier(&time_sleep_notifier); |
276 | #endif /* CONFIG_PM */ | 340 | #endif /* CONFIG_PM */ |
277 | 341 | ||
342 | generic_calibrate_decr(); | ||
343 | |||
344 | #ifdef CONFIG_PPC32 | ||
278 | /* We assume MacRISC2 machines have correct device-tree | 345 | /* We assume MacRISC2 machines have correct device-tree |
279 | * calibration. That's better since the VIA itself seems | 346 | * calibration. That's better since the VIA itself seems |
280 | * to be slightly off. --BenH | 347 | * to be slightly off. --BenH |
@@ -293,18 +360,5 @@ pmac_calibrate_decr(void) | |||
293 | if (machine_is_compatible("PowerMac3,5")) | 360 | if (machine_is_compatible("PowerMac3,5")) |
294 | if (via_calibrate_decr()) | 361 | if (via_calibrate_decr()) |
295 | return; | 362 | return; |
296 | /* | 363 | #endif |
297 | * The cpu node should have a timebase-frequency property | ||
298 | * to tell us the rate at which the decrementer counts. | ||
299 | */ | ||
300 | cpu = find_type_devices("cpu"); | ||
301 | if (cpu == 0) | ||
302 | panic("can't find cpu node in time_init"); | ||
303 | fp = (unsigned int *) get_property(cpu, "timebase-frequency", NULL); | ||
304 | if (fp == 0) | ||
305 | panic("can't get cpu timebase frequency"); | ||
306 | freq = *fp; | ||
307 | printk("time_init: decrementer frequency = %u.%.6u MHz\n", | ||
308 | freq/1000000, freq%1000000); | ||
309 | ppc_tb_freq = freq; | ||
310 | } | 364 | } |