Update DEP-5 uri
[debian/omnibook.git] / compal.c
1 /*
2  * compal.c -- EC PIO Command/Data/Index mode low-level access code
3  * 
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2, or (at your option) any
7  * later version.
8  * 
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * Written by Mathieu BĂ©rard <mathieu.berard@crans.org>, 2006
15  *
16  */
17
18 #include "omnibook.h"
19
20 #include <linux/delay.h>
21 #include <linux/ioport.h>
22 #include <linux/pci.h>
23 #include <linux/kref.h>
24
25 #include <asm/io.h>
26 #include "hardware.h"
27
28 /*
29  * ATI's IXP PCI-LPC bridge
30  */
31 #define PCI_DEVICE_ID_ATI_SB400 0x4377
32
33 /* 
34  * PCI Config space regiser
35  * Laptop with Intel ICH Chipset
36  * See ICH6M and ICH7M spec
37  */
38 #define INTEL_LPC_GEN1_DEC      0x84
39 #define INTEL_LPC_GEN4_DEC      0x90
40 #define INTEL_IOPORT_BASE       0xff2c
41
42 /* 
43  * PCI Config space regiser
44  * Laptop with ATI Chipset
45  * FIXME Untested, name unknown
46  */
47 #define ATI_LPC_REG             0x4a
48 #define ATI_IOPORT_BASE         0xfd60
49
50 /* 
51  *This interface uses 2 ports for command and 1 port for data
52  *These are relative to the ioport_base address
53  */
54
55 #define PIO_PORT_COMMAND1       0x1
56 #define PIO_PORT_COMMAND2       0x2
57 #define PIO_PORT_DATA           0x3
58
59 /*
60  * Private data of this backend
61  */
62 static struct pci_dev *lpc_bridge;      /* Southbridge chip ISA bridge/LPC interface PCI device */
63 static u32 ioport_base;         /* PIO base adress */
64 static union {
65         u16 word;
66         u32 dword;
67 } pci_reg_state;                /* Saved state of register in PCI config spave */
68
69 /*
70  * Possible list of supported southbridges
71  * Here mostly to implement a more or less clean PCI probing
72  * Works only because of previous DMI probing.
73  * Shared with nbsmi backend
74  */
75 const struct pci_device_id lpc_bridge_table[] = {
76         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
77         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
78         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
79         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
80         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
81         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
82         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
83         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
84         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
85         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
86         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
87         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
88         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
89         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
90         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
91         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
92         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_30, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
93         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
94         {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_4, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
95         {PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SB400, PCI_ANY_ID, PCI_ANY_ID, 0, 0,},
96         {0,},                   /* End of list */
97 };
98
99 /*
100  * Low-level Read function:
101  * Write a 2-bytes wide command to the COMMAND ports
102  * Read the result in the DATA port
103  */
104 static unsigned char lowlevel_read(u16 command)
105 {
106         unsigned char data;
107         outb((command & 0xff00) >> 8, ioport_base + PIO_PORT_COMMAND1);
108         outb(command & 0x00ff, ioport_base + PIO_PORT_COMMAND2);
109         data = inb(ioport_base + PIO_PORT_DATA);
110         return data;
111 }
112
113 /*
114  * Low-level Write function:
115  * Write a 2-bytes wide command to the COMMAND ports
116  * Write the result in the DATA port
117  */
118 static void lowlevel_write(u16 command, u8 data)
119 {
120         outb((command & 0xff00) >> 8, ioport_base + PIO_PORT_COMMAND1);
121         outb(command & 0x00ff, ioport_base + PIO_PORT_COMMAND2);
122         outb(data, ioport_base + PIO_PORT_DATA);
123 }
124
125 /*
126  * Probe for a state of the PIO Command/Data/Index interface
127  * Give some time for the controler to settle in the desired state
128  * mode significance:
129  * 0: Waiting for command
130  * 1,2,3: I am confused FIXME
131  */
132 static int check_cdimode_flag(unsigned int mode)
133 {
134         int i;
135         int retval;
136
137         /*dprintk("Index mode:");*/
138         for (i = 1; i <= 250; i++) {
139                 retval = lowlevel_read(0xfbfc);
140                 /*dprintk_simple(" [%i]", retval);*/
141                 if (retval == mode) {
142                         /*dprintk_simple(".\n");
143                         dprintk("Index Mode Ok (%i) after %i iter\n", mode, i);*/
144                         return 0;
145                 }
146                 udelay(100);
147         }
148         printk(O_ERR "check_cdimode_flag timeout.\n");
149         return -ETIME;
150 }
151
152 /*
153  * Check for conventional default (0xf432) state in Commad ports
154  */
155 static int check_default_state(void)
156 {
157         int i;
158
159         for (i = 1; i <= 250; i++) {
160                 if ((inb(ioport_base + PIO_PORT_COMMAND1) == 0xf4)
161                     && (inb(ioport_base + PIO_PORT_COMMAND2) == 0x32))
162                         return 0;
163                 udelay(100);
164         }
165         printk(O_ERR "check_default_state timeout.\n");
166         return -ETIME;
167 }
168
169 /*
170  * Enable EC Command/Data/Index PIO Access and then check EC state.
171  * Enabling is done in PCI config space of the LPC bridge.
172  *
173  * Just after Enabling, the EC should be in a precisly defined state:
174  * - PIO should be in a conventional default state (0xf432 in the Command ports)
175  * - Command/Data/Index interface waiting for command
176  * The EC is expected to be in that state prior to any attempt to use the interface.
177  *
178  */
179 static int enable_cdimode(void)
180 {
181         union {
182                 u16 word;
183                 u32 dword;
184         } value;
185
186         switch (lpc_bridge->vendor) {
187         case PCI_VENDOR_ID_INTEL:
188                 switch (lpc_bridge->device) {
189                 case PCI_DEVICE_ID_INTEL_ICH7_0:        /* ICH7 */
190                 case PCI_DEVICE_ID_INTEL_ICH7_1:
191                 case PCI_DEVICE_ID_INTEL_ICH7_30:
192                 case PCI_DEVICE_ID_INTEL_ICH7_31:
193                 case PCI_DEVICE_ID_INTEL_ICH8_4:        /* ICH8 */
194                         pci_read_config_dword(lpc_bridge, INTEL_LPC_GEN4_DEC, &(value.dword));
195                         pci_reg_state.dword = value.dword;
196                         value.dword = 0x3CFF21;
197                         pci_write_config_dword(lpc_bridge, INTEL_LPC_GEN4_DEC, value.dword);
198                         break;
199                 default:        /* All other Intel chipset */
200                         pci_read_config_word(lpc_bridge, INTEL_LPC_GEN1_DEC, &(value.word));
201                         pci_reg_state.word = value.word;
202                         value.word = (INTEL_IOPORT_BASE & 0xfff1) | 0x1;
203                         pci_write_config_word(lpc_bridge, INTEL_LPC_GEN1_DEC, value.word);
204                 }
205                 break;
206         case PCI_VENDOR_ID_ATI:
207                 pci_read_config_dword(lpc_bridge, ATI_LPC_REG, &(value.dword));
208                 pci_reg_state.dword = value.dword;
209                 value.dword = ((pci_reg_state.dword & 0x7f) | 0x80) << 0x10;
210                 pci_write_config_dword(lpc_bridge, ATI_LPC_REG, value.dword);
211                 break;
212         default:
213                 BUG();
214         }
215         dprintk("Saved state of PCI register: [%x].\n", pci_reg_state.dword);
216
217         if (check_default_state() || check_cdimode_flag(0)) {
218                 printk(O_ERR "EC state check failure, please report.\n");
219                 return -EIO;
220         }
221
222         return 0;
223
224 }
225
226 /*
227  * Send a write command and associated data code to be written
228  * Known commands an associated code significance:
229  * 0xfbfd: Select Index with 'code' ordinal
230  * 0xfbfe: Set to 'code' a previously selected Index
231  * 0xfbfc: Set CDI mode flag
232  */
233 static int send_ec_cmd(unsigned int command, u8 code)
234 {
235         lowlevel_write(0xfbfc, 0x2);
236         lowlevel_write(command, code);
237         lowlevel_write(0xfbfc, 0x1);
238         if (check_cdimode_flag(2))
239                 return -ETIME;
240         return 0;
241 }
242
243 /*
244  * Send a read command
245  * Known commands an associated code significance:
246  * 0xfbfe: Read a previously selected Index
247  * 0xfbfc: Set CDI mode flag
248  */
249 static int read_ec_cmd(unsigned int command, u8 * value)
250 {
251         *value = lowlevel_read(command);
252         lowlevel_write(0xfbfc, 0x1);
253         if (check_cdimode_flag(2))
254                 return -ETIME;
255         return 0;
256 }
257
258 /*
259  * Disable EC Command/Data/Index PIO Access 
260  * Step 1: clear_cdimode
261  * Send Disable command
262  * Revert PIO interface to conventional default state (0xf432 in the Command ports)
263  * Step 2: clear_cdimode_pci
264  * Disable the interface in the PCI config space of the Southbridge
265  * These steps are separated due to constrains in error path treatement
266  */
267 static void clear_cdimode(void)
268 {
269         lowlevel_write(0xfbfc, 0x0);
270         outb(0xf4, ioport_base + PIO_PORT_COMMAND1);
271         outb(0x32, ioport_base + PIO_PORT_COMMAND2);
272 }
273
274 static void clear_cdimode_pci(void)
275 {
276         switch (lpc_bridge->vendor) {
277         case PCI_VENDOR_ID_INTEL:
278                 switch (lpc_bridge->device) {
279                 case PCI_DEVICE_ID_INTEL_ICH7_0:        /* ICH7 */
280                 case PCI_DEVICE_ID_INTEL_ICH7_1:
281                 case PCI_DEVICE_ID_INTEL_ICH7_30:
282                 case PCI_DEVICE_ID_INTEL_ICH7_31:
283                 case PCI_DEVICE_ID_INTEL_ICH8_4:        /* ICH8 */
284                         pci_write_config_dword(lpc_bridge, INTEL_LPC_GEN4_DEC, pci_reg_state.dword);
285                         break;
286                 default:        /* All other Intel chipset */
287                         pci_write_config_word(lpc_bridge, INTEL_LPC_GEN1_DEC, pci_reg_state.word);
288                 }
289                 break;
290         case PCI_VENDOR_ID_ATI:
291                 pci_write_config_dword(lpc_bridge, ATI_LPC_REG, pci_reg_state.dword);
292                 break;
293         default:
294                 BUG();
295         }
296 }
297
298 /*
299  * Try to init the backend
300  * This function can be called blindly as it use a kref
301  * to check if the init sequence was already done.
302  */
303 static int omnibook_cdimode_init(const struct omnibook_operation *io_op)
304 {
305         int retval = 0;
306         int i;
307
308         /* ectypes other than TSM70 have no business with this backend */
309         if (!(omnibook_ectype & (TSM70 | TSX205)))
310                 return -ENODEV;
311
312         if (io_op->backend->already_failed) {
313                 dprintk("CDI backend init already failed, skipping.\n");
314                 return -ENODEV;
315         }
316
317         if (!lpc_bridge) {
318                 /* Fist use of the backend */
319                 dprintk("Try to init cdimode\n");
320                 mutex_init(&io_op->backend->mutex);
321                 mutex_lock(&io_op->backend->mutex);
322                 kref_init(&io_op->backend->kref);
323
324                 /* PCI probing: find the LPC Super I/O bridge PCI device */
325                 for (i = 0; !lpc_bridge && lpc_bridge_table[i].vendor; ++i)
326                         lpc_bridge =
327                             pci_get_device(lpc_bridge_table[i].vendor, lpc_bridge_table[i].device,
328                                            NULL);
329
330                 if (!lpc_bridge) {
331                         printk(O_ERR "Fail to find a supported LPC I/O bridge, please report\n");
332                         retval = -ENODEV;
333                         goto error1;
334                 }
335
336                 if ((retval = pci_enable_device(lpc_bridge))) {
337                         printk(O_ERR "Unable to enable PCI device.\n");
338                         goto error2;
339                 }
340
341                 switch (lpc_bridge->vendor) {
342                 case PCI_VENDOR_ID_INTEL:
343                         ioport_base = INTEL_IOPORT_BASE;
344                         break;
345                 case PCI_VENDOR_ID_ATI:
346                         ioport_base = ATI_IOPORT_BASE;
347                         break;
348                 default:
349                         BUG();
350                 }
351
352                 if (!request_region(ioport_base, 4, OMNIBOOK_MODULE_NAME)) {
353                         printk(O_ERR "Request I/O region error\n");
354                         retval = -ENODEV;
355                         goto error2;
356                 }
357
358                 /*
359                  * Make an enable-check disable cycle for testing purpose
360                  */
361
362                 retval = enable_cdimode();
363                 if (retval)
364                         goto error3;
365
366                 clear_cdimode();
367                 clear_cdimode_pci();
368
369                 dprintk("Cdimode init ok\n");
370                 mutex_unlock(&io_op->backend->mutex);
371                 return 0;
372         } else {
373                 dprintk("Cdimode has already been initialized\n");
374                 kref_get(&io_op->backend->kref);
375                 return 0;
376         }
377
378       error3:
379         clear_cdimode_pci();
380         release_region(ioport_base, 4);
381       error2:
382         pci_dev_put(lpc_bridge);
383         lpc_bridge = NULL;
384       error1:
385         io_op->backend->already_failed = 1;
386         mutex_unlock(&io_op->backend->mutex);
387         mutex_destroy(&io_op->backend->mutex);
388         return retval;
389 }
390
391 static void cdimode_free(struct kref *ref)
392 {
393         struct omnibook_backend *backend;
394         
395         dprintk("Cdimode not used anymore: disposing\n");
396
397         backend = container_of(ref, struct omnibook_backend, kref);
398
399         mutex_lock(&backend->mutex);
400         pci_dev_put(lpc_bridge);
401         release_region(ioport_base, 4);
402         lpc_bridge = NULL;
403         mutex_unlock(&backend->mutex);
404         mutex_destroy(&backend->mutex);
405 }
406
407 static void omnibook_cdimode_exit(const struct omnibook_operation *io_op)
408 {
409         /* ectypes other than TSM70 have no business with this backend */
410         BUG_ON(!(omnibook_ectype & (TSM70 | TSX205)));
411         dprintk("Trying to dispose cdimode\n");
412         kref_put(&io_op->backend->kref, cdimode_free);
413 }
414
415 /* 
416  * Read EC index and write result to value 
417  * 'EC index' here is unrelated to an index in the EC registers
418  */
419 static int omnibook_cdimode_read(const struct omnibook_operation *io_op, u8 * value)
420 {
421         int retval = 0;
422
423         if (!lpc_bridge)
424                 return -ENODEV;
425
426         retval = enable_cdimode();
427         if (retval)
428                 goto out;
429         retval = send_ec_cmd(0xfbfd, (unsigned int)io_op->read_addr);
430         if (retval)
431                 goto error;
432         retval = read_ec_cmd(0xfbfe, value);
433
434         if (io_op->read_mask)
435                 *value &= io_op->read_mask;
436
437       error:
438         clear_cdimode();
439       out:
440         clear_cdimode_pci();
441         return retval;
442 }
443
444 /* 
445  * Write value 
446  * 'EC index' here is unrelated to an index in the EC registers
447  */
448 static int omnibook_cdimode_write(const struct omnibook_operation *io_op, u8 value)
449 {
450         int retval = 0;
451
452         if (!lpc_bridge)
453                 return -ENODEV;
454
455         retval = enable_cdimode();
456         if (retval)
457                 goto out;
458         retval = send_ec_cmd(0xfbfd, (unsigned int)io_op->write_addr);
459         if (retval)
460                 goto error;
461         retval = send_ec_cmd(0xfbfe, value);
462       error:
463         clear_cdimode();
464       out:
465         clear_cdimode_pci();
466         return retval;
467
468 }
469
470 /*
471  * Fn+foo and multimedia hotkeys handling
472  */
473 static int omnibook_cdimode_hotkeys(const struct omnibook_operation *io_op, unsigned int state)
474 {
475         int retval;
476
477         struct omnibook_operation hotkeys_op = 
478                 { CDI, 0, TSM70_FN_INDEX, 0, TSM70_FN_ENABLE, TSM70_FN_DISABLE};
479
480         /* Fn+foo handling */
481         retval = __omnibook_toggle(&hotkeys_op, !!(state & HKEY_FN));
482         if (retval < 0)
483                 return retval;
484
485         /* Multimedia keys handling */
486         hotkeys_op.write_addr = TSM70_HOTKEYS_INDEX;
487         hotkeys_op.on_mask = TSM70_HOTKEYS_ENABLE;
488         hotkeys_op.off_mask = TSM70_HOTKEYS_DISABLE;
489         retval = __omnibook_toggle(&hotkeys_op, !!(state & HKEY_MULTIMEDIA));
490
491         return retval;
492 }
493
494 /* Scan index space, this hard locks my machine */
495 #if 0
496 static int compal_scan(char *buffer)
497 {
498         int len = 0;
499         int i, j;
500         u8 v;
501
502         for (i = 0; i < 255; i += 16) {
503                 for (j = 0; j < 16; j++) {
504                         omnibook_compal_read(i + j, &v);
505                         len += sprintf(buffer + len, "Read index %02x: %02x\n", i + j, v);
506                         mdelay(500);
507                 }
508                 if (j != 16)
509                         break;
510         }
511
512         return len;
513 }
514 #endif
515
516 struct omnibook_backend compal_backend = {
517         .name = "compal",
518         .hotkeys_write_cap = HKEY_MULTIMEDIA | HKEY_FN,
519         .init = omnibook_cdimode_init,
520         .exit = omnibook_cdimode_exit,
521         .byte_read = omnibook_cdimode_read,
522         .byte_write = omnibook_cdimode_write,
523         .hotkeys_set = omnibook_cdimode_hotkeys,
524 };
525
526 /* End of file */