Add Lenovo ThinkPad T60
[coreboot.git] / src / mainboard / lenovo / t60 / dock.c
1 /*
2  * This file is part of the coreboot project.
3  *
4  * Copyright (C) 2011 Sven Schnelle <svens@stackframe.org>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; version 2 of
9  * the License.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
19  * MA 02110-1301 USA
20  */
21
22 #include <console/console.h>
23 #include <device/device.h>
24 #include <arch/io.h>
25 #include <boot/tables.h>
26 #include <delay.h>
27 #include <arch/io.h>
28 #include "dock.h"
29 #include "superio/nsc/pc87384/pc87384.h"
30 #include "ec/acpi/ec.h"
31 #include "southbridge/intel/i82801gx/i82801gx.h"
32
33 static void dlpc_write_register(int reg, int value)
34 {
35         outb(reg, 0x164e);
36         outb(value, 0x164f);
37 }
38
39 static u8 dlpc_read_register(int reg)
40 {
41         outb(reg, 0x164e);
42         return inb(0x164f);
43 }
44
45 static void dock_write_register(int reg, int value)
46 {
47         outb(reg, 0x2e);
48         outb(value, 0x2f);
49 }
50
51 static u8 dock_read_register(int reg)
52 {
53         outb(reg, 0x2e);
54         return inb(0x2f);
55 }
56
57 static void dlpc_gpio_set_mode(int port, int mode)
58 {
59         dlpc_write_register(0xf0, port);
60         dlpc_write_register(0xf1, mode);
61 }
62
63 static void dock_gpio_set_mode(int port, int mode, int irq)
64 {
65         dock_write_register(0xf0, port);
66         dock_write_register(0xf1, mode);
67         dock_write_register(0xf2, irq);
68 }
69
70 static void dlpc_gpio_init(void)
71 {
72         /* Select GPIO module */
73         dlpc_write_register(0x07, 0x07);
74         /* GPIO Base Address 0x1680 */
75         dlpc_write_register(0x60, 0x16);
76         dlpc_write_register(0x61, 0x80);
77
78         /* Activate GPIO */
79         dlpc_write_register(0x30, 0x01);
80
81         dlpc_gpio_set_mode(0x00, 3);
82         dlpc_gpio_set_mode(0x01, 3);
83         dlpc_gpio_set_mode(0x02, 0);
84         dlpc_gpio_set_mode(0x03, 3);
85         dlpc_gpio_set_mode(0x04, 4);
86         dlpc_gpio_set_mode(0x20, 4);
87         dlpc_gpio_set_mode(0x21, 4);
88         dlpc_gpio_set_mode(0x23, 4);
89 }
90
91 int dlpc_init(void)
92 {
93         int timeout = 1000;
94
95         /* Enable 14.318MHz CLK on CLKIN */
96         dlpc_write_register(0x29, 0xa0);
97         while(!(dlpc_read_register(0x29) & 0x10) && timeout--)
98                 udelay(1000);
99
100         if (!timeout)
101                 return 1;
102
103         /* Select DLPC module */
104         dlpc_write_register(0x07, 0x19);
105         /* DLPC Base Address 0x164c */
106         dlpc_write_register(0x60, 0x16);
107         dlpc_write_register(0x61, 0x4c);
108         /* Activate DLPC */
109         dlpc_write_register(0x30, 0x01);
110
111         dlpc_gpio_init();
112         return 0;
113 }
114
115 static int dock_superio_init(void)
116 {
117         int timeout = 1000;
118         /* startup 14.318MHz Clock */
119         dock_write_register(0x29, 0xa0);
120         /* wait until clock is settled */
121         while(!(dock_read_register(0x29) & 0x10) && timeout--)
122                 udelay(1000);
123
124         if (!timeout)
125                 return 1;
126
127         /* set GPIO pins to Serial/Parallel Port
128          * functions
129          */
130         dock_write_register(0x22, 0xeb);
131
132         dock_write_register(0x07, PC87384_GPIO);
133         dock_write_register(0x60, 0x16);
134         dock_write_register(0x61, 0x20);
135
136         dock_gpio_set_mode(0x00, PC87384_GPIO_PIN_DEBOUNCE |
137                            PC87384_GPIO_PIN_PULLUP, 0x00);
138
139         dock_gpio_set_mode(0x01, PC87384_GPIO_PIN_TYPE_PUSH_PULL |
140                            PC87384_GPIO_PIN_OE, 0x00);
141
142         dock_gpio_set_mode(0x02, PC87384_GPIO_PIN_TYPE_PUSH_PULL |
143                            PC87384_GPIO_PIN_OE, 0x00);
144
145         dock_gpio_set_mode(0x03, PC87384_GPIO_PIN_DEBOUNCE |
146                            PC87384_GPIO_PIN_PULLUP, 0x00);
147
148         dock_gpio_set_mode(0x04, PC87384_GPIO_PIN_DEBOUNCE |
149                            PC87384_GPIO_PIN_PULLUP, 0x00);
150
151         dock_gpio_set_mode(0x05, PC87384_GPIO_PIN_DEBOUNCE |
152                            PC87384_GPIO_PIN_PULLUP, 0x00);
153
154         dock_gpio_set_mode(0x06, PC87384_GPIO_PIN_DEBOUNCE |
155                            PC87384_GPIO_PIN_PULLUP, 0x00);
156
157         dock_gpio_set_mode(0x07, PC87384_GPIO_PIN_DEBOUNCE |
158                            PC87384_GPIO_PIN_PULLUP, 0x00);
159
160         outb(0xfd, 0x1620);
161
162         /* no GPIO events enabled for PORT0 */
163         outb(0x00, 0x1622);
164         /* clear GPIO events on PORT0 */
165         outb(0xff, 0x1623);
166         outb(0xff, 0x1624);
167         /* no GPIO events enabled for PORT1 */
168         outb(0x00, 0x1626);
169
170         /* clear GPIO events on PORT1*/
171         outb(0xff, 0x1627);
172         outb(0x1F, 0x1628);
173         /* enable GPIO */
174         dock_write_register(0x30, 0x01);
175         return 0;
176 }
177
178 int dock_connect(void)
179 {
180         int timeout = 1000;
181
182         outb(0x07, 0x164c);
183
184         timeout = 1000;
185
186         while(!(inb(0x164c) & 8) && timeout--)
187                 udelay(1000);
188
189         if (!timeout) {
190                 /* docking failed, disable DLPC switch */
191                 outb(0x00, 0x164c);
192                 dlpc_write_register(0x30, 0x00);
193                 return 1;
194         }
195
196         /* Assert D_PLTRST# */
197         outb(0xfe, 0x1680);
198         udelay(1000);
199         /* Deassert D_PLTRST# */
200         outb(0xff, 0x1680);
201         udelay(10000);
202
203         return dock_superio_init();
204 }
205
206 void dock_disconnect(void)
207 {
208         /* disconnect LPC bus */
209         outb(0x00, 0x164c);
210         /* Assert PLTRST and DLPCPD */
211         outb(0xfc, 0x1680);
212 }
213
214 int dock_present(void)
215 {
216         outb(0x61, 0x15ec);
217         return inb(0x15ee) & 1;
218 }
219