This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / macintosh / smu.c
1 /*
2  * PowerMac G5 SMU driver
3  *
4  * Copyright 2004 J. Mayer <l_indien@magic.fr>
5  * Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
6  *
7  * Released under the term of the GNU GPL v2.
8  */
9
10 /*
11  * For now, this driver includes:
12  * - RTC get & set
13  * - reboot & shutdown commands
14  * all synchronous with IRQ disabled (ugh)
15  *
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.
26  */
27
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>
39
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>
48
49 #define DEBUG_SMU 1
50
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
56
57 /*
58  * This is the command buffer passed to the SMU hardware
59  */
60 struct smu_cmd_buf {
61         u8 cmd;
62         u8 length;
63         u8 data[0x0FFE];
64 };
65
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 */
74 };
75
76 /*
77  * I don't think there will ever be more than one SMU, so
78  * for now, just hard code that
79  */
80 static struct smu_device        *smu;
81
82 /*
83  * SMU low level communication stuff
84  */
85 static inline int smu_cmd_stat(struct smu_cmd_buf *cmd_buf, u8 cmd_ack)
86 {
87         rmb();
88         return cmd_buf->cmd == cmd_ack && cmd_buf->length != 0;
89 }
90
91 static inline u8 smu_save_ack_cmd(struct smu_cmd_buf *cmd_buf)
92 {
93         return (~cmd_buf->cmd) & 0xff;
94 }
95
96 static void smu_send_cmd(struct smu_device *dev)
97 {
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.
102          */
103         writel(dev->cmd_buf_abs, dev->db_buf);
104
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);
108 }
109
110 static int smu_cmd_done(struct smu_device *dev)
111 {
112         unsigned long wait = 0;
113         int gpio;
114
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);
123
124         printk(KERN_ERR "SMU timeout !\n");
125         return -ENXIO;
126 }
127
128 static int smu_do_cmd(struct smu_device *dev)
129 {
130         int rc;
131         u8 cmd_ack;
132
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]);
136
137         cmd_ack = smu_save_ack_cmd(dev->cmd_buf);
138
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;
147
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);
151
152         return rc;
153 }
154
155 /* RTC low level commands */
156 static inline int bcd2hex (int n)
157 {
158         return (((n & 0xf0) >> 4) * 10) + (n & 0xf);
159 }
160
161 static inline int hex2bcd (int n)
162 {
163         return ((n / 10) << 4) + (n % 10);
164 }
165
166 #if 0
167 static inline void smu_fill_set_pwrup_timer_cmd(struct smu_cmd_buf *cmd_buf)
168 {
169         cmd_buf->cmd = 0x8e;
170         cmd_buf->length = 8;
171         cmd_buf->data[0] = 0x00;
172         memset(cmd_buf->data + 1, 0, 7);
173 }
174
175 static inline void smu_fill_get_pwrup_timer_cmd(struct smu_cmd_buf *cmd_buf)
176 {
177         cmd_buf->cmd = 0x8e;
178         cmd_buf->length = 1;
179         cmd_buf->data[0] = 0x01;
180 }
181
182 static inline void smu_fill_dis_pwrup_timer_cmd(struct smu_cmd_buf *cmd_buf)
183 {
184         cmd_buf->cmd = 0x8e;
185         cmd_buf->length = 1;
186         cmd_buf->data[0] = 0x02;
187 }
188 #endif
189
190 static inline void smu_fill_set_rtc_cmd(struct smu_cmd_buf *cmd_buf,
191                                         struct rtc_time *time)
192 {
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);
203 }
204
205 static inline void smu_fill_get_rtc_cmd(struct smu_cmd_buf *cmd_buf)
206 {
207         cmd_buf->cmd = 0x8e;
208         cmd_buf->length = 1;
209         cmd_buf->data[0] = 0x81;
210 }
211
212 static void smu_parse_get_rtc_reply(struct smu_cmd_buf *cmd_buf,
213                                     struct rtc_time *time)
214 {
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;
222 }
223
224 int smu_get_rtc_time(struct rtc_time *time)
225 {
226         unsigned long flags;
227         int rc;
228
229         if (smu == NULL)
230                 return -ENODEV;
231
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);
239
240         return rc;
241 }
242
243 int smu_set_rtc_time(struct rtc_time *time)
244 {
245         unsigned long flags;
246         int rc;
247
248         if (smu == NULL)
249                 return -ENODEV;
250
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);
255
256         return rc;
257 }
258
259 void smu_shutdown(void)
260 {
261         const unsigned char *command = "SHUTDOWN";
262         unsigned long flags;
263
264         if (smu == NULL)
265                 return;
266
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 (;;)
273                 ;
274         spin_unlock_irqrestore(&smu->lock, flags);
275 }
276
277 void smu_restart(void)
278 {
279         const unsigned char *command = "RESTART";
280         unsigned long flags;
281
282         if (smu == NULL)
283                 return;
284
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 (;;)
291                 ;
292         spin_unlock_irqrestore(&smu->lock, flags);
293 }
294
295 int smu_present(void)
296 {
297         return smu != NULL;
298 }
299
300
301 int smu_init (void)
302 {
303         struct device_node *np;
304         u32 *data;
305
306         np = of_find_node_by_type(NULL, "smu");
307         if (np == NULL)
308                 return -ENODEV;
309
310         if (smu_cmdbuf_abs == 0) {
311                 printk(KERN_ERR "SMU: Command buffer not allocated !\n");
312                 return -EINVAL;
313         }
314
315         smu = alloc_bootmem(sizeof(struct smu_device));
316         if (smu == NULL)
317                 return -ENOMEM;
318         memset(smu, 0, sizeof(*smu));
319
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
324          */
325         smu->cmd_buf_abs = (u32)smu_cmdbuf_abs;
326         smu->cmd_buf = (struct smu_cmd_buf *)abs_to_virt(smu_cmdbuf_abs);
327
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;
332         }
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;
338         }
339
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.
343          */
344         smu->db_req = 0x50 + *data;
345         smu->db_ack = 0x50 + *data;
346
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.
350          */
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;
355         }
356
357         sys_ctrler = SYS_CTRLER_SMU;
358         return 0;
359
360  fail:
361         smu = NULL;
362         return -ENXIO;
363
364 }