[PATCH] ipmi: use completions, not semaphores, in powerdown code
[linux-2.6/mini2440.git] / drivers / macintosh / smu.c
blobfb535737d17d114244481fea4ba7421a768ce1ed
1 /*
2 * PowerMac G5 SMU driver
4 * Copyright 2004 J. Mayer <l_indien@magic.fr>
5 * Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
7 * Released under the term of the GNU GPL v2.
8 */
11 * For now, this driver includes:
12 * - RTC get & set
13 * - reboot & shutdown commands
14 * all synchronous with IRQ disabled (ugh)
16 * TODO:
17 * rework in a way the PMU driver works, that is asynchronous
18 * with a queue of commands. I'll do that as soon as I have an
19 * SMU based machine at hand. Some more cleanup is needed too,
20 * like maybe fitting it into a platform device, etc...
21 * Also check what's up with cache coherency, and if we really
22 * can't do better than flushing the cache, maybe build a table
23 * of command len/reply len like the PMU driver to only flush
24 * what is actually necessary.
25 * --BenH.
28 #include <linux/config.h>
29 #include <linux/types.h>
30 #include <linux/kernel.h>
31 #include <linux/device.h>
32 #include <linux/dmapool.h>
33 #include <linux/bootmem.h>
34 #include <linux/vmalloc.h>
35 #include <linux/highmem.h>
36 #include <linux/jiffies.h>
37 #include <linux/interrupt.h>
38 #include <linux/rtc.h>
40 #include <asm/byteorder.h>
41 #include <asm/io.h>
42 #include <asm/prom.h>
43 #include <asm/machdep.h>
44 #include <asm/pmac_feature.h>
45 #include <asm/smu.h>
46 #include <asm/sections.h>
47 #include <asm/abs_addr.h>
49 #define DEBUG_SMU 1
51 #ifdef DEBUG_SMU
52 #define DPRINTK(fmt, args...) do { printk(KERN_DEBUG fmt , ##args); } while (0)
53 #else
54 #define DPRINTK(fmt, args...) do { } while (0)
55 #endif
58 * This is the command buffer passed to the SMU hardware
60 struct smu_cmd_buf {
61 u8 cmd;
62 u8 length;
63 u8 data[0x0FFE];
66 struct smu_device {
67 spinlock_t lock;
68 struct device_node *of_node;
69 int db_ack; /* doorbell ack GPIO */
70 int db_req; /* doorbell req GPIO */
71 u32 __iomem *db_buf; /* doorbell buffer */
72 struct smu_cmd_buf *cmd_buf; /* command buffer virtual */
73 u32 cmd_buf_abs; /* command buffer absolute */
77 * I don't think there will ever be more than one SMU, so
78 * for now, just hard code that
80 static struct smu_device *smu;
83 * SMU low level communication stuff
85 static inline int smu_cmd_stat(struct smu_cmd_buf *cmd_buf, u8 cmd_ack)
87 rmb();
88 return cmd_buf->cmd == cmd_ack && cmd_buf->length != 0;
91 static inline u8 smu_save_ack_cmd(struct smu_cmd_buf *cmd_buf)
93 return (~cmd_buf->cmd) & 0xff;
96 static void smu_send_cmd(struct smu_device *dev)
98 /* SMU command buf is currently cacheable, we need a physical
99 * address. This isn't exactly a DMA mapping here, I suspect
100 * the SMU is actually communicating with us via i2c to the
101 * northbridge or the CPU to access RAM.
103 writel(dev->cmd_buf_abs, dev->db_buf);
105 /* Ring the SMU doorbell */
106 pmac_do_feature_call(PMAC_FTR_WRITE_GPIO, NULL, dev->db_req, 4);
107 pmac_do_feature_call(PMAC_FTR_READ_GPIO, NULL, dev->db_req, 4);
110 static int smu_cmd_done(struct smu_device *dev)
112 unsigned long wait = 0;
113 int gpio;
115 /* Check the SMU doorbell */
116 do {
117 gpio = pmac_do_feature_call(PMAC_FTR_READ_GPIO,
118 NULL, dev->db_ack);
119 if ((gpio & 7) == 7)
120 return 0;
121 udelay(100);
122 } while(++wait < 10000);
124 printk(KERN_ERR "SMU timeout !\n");
125 return -ENXIO;
128 static int smu_do_cmd(struct smu_device *dev)
130 int rc;
131 u8 cmd_ack;
133 DPRINTK("SMU do_cmd %02x len=%d %02x\n",
134 dev->cmd_buf->cmd, dev->cmd_buf->length,
135 dev->cmd_buf->data[0]);
137 cmd_ack = smu_save_ack_cmd(dev->cmd_buf);
139 /* Clear cmd_buf cache lines */
140 flush_inval_dcache_range((unsigned long)dev->cmd_buf,
141 ((unsigned long)dev->cmd_buf) +
142 sizeof(struct smu_cmd_buf));
143 smu_send_cmd(dev);
144 rc = smu_cmd_done(dev);
145 if (rc == 0)
146 rc = smu_cmd_stat(dev->cmd_buf, cmd_ack) ? 0 : -1;
148 DPRINTK("SMU do_cmd %02x len=%d %02x => %d (%02x)\n",
149 dev->cmd_buf->cmd, dev->cmd_buf->length,
150 dev->cmd_buf->data[0], rc, cmd_ack);
152 return rc;
155 /* RTC low level commands */
156 static inline int bcd2hex (int n)
158 return (((n & 0xf0) >> 4) * 10) + (n & 0xf);
161 static inline int hex2bcd (int n)
163 return ((n / 10) << 4) + (n % 10);
166 #if 0
167 static inline void smu_fill_set_pwrup_timer_cmd(struct smu_cmd_buf *cmd_buf)
169 cmd_buf->cmd = 0x8e;
170 cmd_buf->length = 8;
171 cmd_buf->data[0] = 0x00;
172 memset(cmd_buf->data + 1, 0, 7);
175 static inline void smu_fill_get_pwrup_timer_cmd(struct smu_cmd_buf *cmd_buf)
177 cmd_buf->cmd = 0x8e;
178 cmd_buf->length = 1;
179 cmd_buf->data[0] = 0x01;
182 static inline void smu_fill_dis_pwrup_timer_cmd(struct smu_cmd_buf *cmd_buf)
184 cmd_buf->cmd = 0x8e;
185 cmd_buf->length = 1;
186 cmd_buf->data[0] = 0x02;
188 #endif
190 static inline void smu_fill_set_rtc_cmd(struct smu_cmd_buf *cmd_buf,
191 struct rtc_time *time)
193 cmd_buf->cmd = 0x8e;
194 cmd_buf->length = 8;
195 cmd_buf->data[0] = 0x80;
196 cmd_buf->data[1] = hex2bcd(time->tm_sec);
197 cmd_buf->data[2] = hex2bcd(time->tm_min);
198 cmd_buf->data[3] = hex2bcd(time->tm_hour);
199 cmd_buf->data[4] = time->tm_wday;
200 cmd_buf->data[5] = hex2bcd(time->tm_mday);
201 cmd_buf->data[6] = hex2bcd(time->tm_mon) + 1;
202 cmd_buf->data[7] = hex2bcd(time->tm_year - 100);
205 static inline void smu_fill_get_rtc_cmd(struct smu_cmd_buf *cmd_buf)
207 cmd_buf->cmd = 0x8e;
208 cmd_buf->length = 1;
209 cmd_buf->data[0] = 0x81;
212 static void smu_parse_get_rtc_reply(struct smu_cmd_buf *cmd_buf,
213 struct rtc_time *time)
215 time->tm_sec = bcd2hex(cmd_buf->data[0]);
216 time->tm_min = bcd2hex(cmd_buf->data[1]);
217 time->tm_hour = bcd2hex(cmd_buf->data[2]);
218 time->tm_wday = bcd2hex(cmd_buf->data[3]);
219 time->tm_mday = bcd2hex(cmd_buf->data[4]);
220 time->tm_mon = bcd2hex(cmd_buf->data[5]) - 1;
221 time->tm_year = bcd2hex(cmd_buf->data[6]) + 100;
224 int smu_get_rtc_time(struct rtc_time *time)
226 unsigned long flags;
227 int rc;
229 if (smu == NULL)
230 return -ENODEV;
232 memset(time, 0, sizeof(struct rtc_time));
233 spin_lock_irqsave(&smu->lock, flags);
234 smu_fill_get_rtc_cmd(smu->cmd_buf);
235 rc = smu_do_cmd(smu);
236 if (rc == 0)
237 smu_parse_get_rtc_reply(smu->cmd_buf, time);
238 spin_unlock_irqrestore(&smu->lock, flags);
240 return rc;
243 int smu_set_rtc_time(struct rtc_time *time)
245 unsigned long flags;
246 int rc;
248 if (smu == NULL)
249 return -ENODEV;
251 spin_lock_irqsave(&smu->lock, flags);
252 smu_fill_set_rtc_cmd(smu->cmd_buf, time);
253 rc = smu_do_cmd(smu);
254 spin_unlock_irqrestore(&smu->lock, flags);
256 return rc;
259 void smu_shutdown(void)
261 const unsigned char *command = "SHUTDOWN";
262 unsigned long flags;
264 if (smu == NULL)
265 return;
267 spin_lock_irqsave(&smu->lock, flags);
268 smu->cmd_buf->cmd = 0xaa;
269 smu->cmd_buf->length = strlen(command);
270 strcpy(smu->cmd_buf->data, command);
271 smu_do_cmd(smu);
272 for (;;)
274 spin_unlock_irqrestore(&smu->lock, flags);
277 void smu_restart(void)
279 const unsigned char *command = "RESTART";
280 unsigned long flags;
282 if (smu == NULL)
283 return;
285 spin_lock_irqsave(&smu->lock, flags);
286 smu->cmd_buf->cmd = 0xaa;
287 smu->cmd_buf->length = strlen(command);
288 strcpy(smu->cmd_buf->data, command);
289 smu_do_cmd(smu);
290 for (;;)
292 spin_unlock_irqrestore(&smu->lock, flags);
295 int smu_present(void)
297 return smu != NULL;
301 int smu_init (void)
303 struct device_node *np;
304 u32 *data;
306 np = of_find_node_by_type(NULL, "smu");
307 if (np == NULL)
308 return -ENODEV;
310 if (smu_cmdbuf_abs == 0) {
311 printk(KERN_ERR "SMU: Command buffer not allocated !\n");
312 return -EINVAL;
315 smu = alloc_bootmem(sizeof(struct smu_device));
316 if (smu == NULL)
317 return -ENOMEM;
318 memset(smu, 0, sizeof(*smu));
320 spin_lock_init(&smu->lock);
321 smu->of_node = np;
322 /* smu_cmdbuf_abs is in the low 2G of RAM, can be converted to a
323 * 32 bits value safely
325 smu->cmd_buf_abs = (u32)smu_cmdbuf_abs;
326 smu->cmd_buf = (struct smu_cmd_buf *)abs_to_virt(smu_cmdbuf_abs);
328 np = of_find_node_by_name(NULL, "smu-doorbell");
329 if (np == NULL) {
330 printk(KERN_ERR "SMU: Can't find doorbell GPIO !\n");
331 goto fail;
333 data = (u32 *)get_property(np, "reg", NULL);
334 of_node_put(np);
335 if (data == NULL) {
336 printk(KERN_ERR "SMU: Can't find doorbell GPIO address !\n");
337 goto fail;
340 /* Current setup has one doorbell GPIO that does both doorbell
341 * and ack. GPIOs are at 0x50, best would be to find that out
342 * in the device-tree though.
344 smu->db_req = 0x50 + *data;
345 smu->db_ack = 0x50 + *data;
347 /* Doorbell buffer is currently hard-coded, I didn't find a proper
348 * device-tree entry giving the address. Best would probably to use
349 * an offset for K2 base though, but let's do it that way for now.
351 smu->db_buf = ioremap(0x8000860c, 0x1000);
352 if (smu->db_buf == NULL) {
353 printk(KERN_ERR "SMU: Can't map doorbell buffer pointer !\n");
354 goto fail;
357 sys_ctrler = SYS_CTRLER_SMU;
358 return 0;
360 fail:
361 smu = NULL;
362 return -ENXIO;