X60: fix docking
[coreboot.git] / src / mainboard / lenovo / x60 / 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 "southbridge/intel/i82801gx/i82801gx.h"
30 #include "superio/nsc/pc87392/pc87392.h"
31
32 static void dlpc_write_register(int reg, int value)
33 {
34         outb(reg, 0x164e);
35         outb(value, 0x164f);
36 }
37
38 static u8 dlpc_read_register(int reg)
39 {
40         outb(reg, 0x164e);
41         return inb(0x164f);
42 }
43
44 static void dock_write_register(int reg, int value)
45 {
46         outb(reg, 0x2e);
47         outb(value, 0x2f);
48 }
49
50 static u8 dock_read_register(int reg)
51 {
52         outb(reg, 0x2e);
53         return inb(0x2f);
54 }
55
56 static void dlpc_gpio_set_mode(int port, int mode)
57 {
58         dlpc_write_register(0xf0, port);
59         dlpc_write_register(0xf1, mode);
60 }
61
62 static void dock_gpio_set_mode(int port, int mode, int irq)
63 {
64         dock_write_register(0xf0, port);
65         dock_write_register(0xf1, mode);
66         dock_write_register(0xf2, irq);
67 }
68
69 static void dlpc_gpio_init(void)
70 {
71         /* Select GPIO module */
72         dlpc_write_register(0x07, 0x07);
73         /* GPIO Base Address 0x1680 */
74         dlpc_write_register(0x60, 0x16);
75         dlpc_write_register(0x61, 0x80);
76
77         /* Activate GPIO */
78         dlpc_write_register(0x30, 0x01);
79
80         dlpc_gpio_set_mode(0x00, 3);
81         dlpc_gpio_set_mode(0x01, 3);
82         dlpc_gpio_set_mode(0x02, 0);
83         dlpc_gpio_set_mode(0x03, 3);
84         dlpc_gpio_set_mode(0x04, 4);
85         dlpc_gpio_set_mode(0x20, 4);
86         dlpc_gpio_set_mode(0x21, 4);
87         dlpc_gpio_set_mode(0x23, 4);
88 }
89
90 int dlpc_init(void)
91 {
92         int timeout = 1000;
93
94         /* Enable 14.318MHz CLK on CLKIN */
95         dlpc_write_register(0x29, 0xa0);
96         while(!(dlpc_read_register(0x29) & 0x10) && timeout--)
97                 udelay(1000);
98
99         if (!timeout)
100                 return 1;
101
102         /* Select DLPC module */
103         dlpc_write_register(0x07, 0x19);
104         /* DLPC Base Address 0x164c */
105         dlpc_write_register(0x60, 0x16);
106         dlpc_write_register(0x61, 0x4c);
107         /* Activate DLPC */
108         dlpc_write_register(0x30, 0x01);
109
110         dlpc_gpio_init();
111
112         return 0;
113 }
114
115 int dock_connect(void)
116 {
117         int timeout = 1000;
118
119         outb(0x07, 0x164c);
120
121         timeout = 1000;
122
123         while(!(inb(0x164c) & 8) && timeout--)
124                 udelay(1000);
125
126         if (!timeout) {
127                 /* docking failed, disable DLPC switch */
128                 outb(0x00, 0x164c);
129                 dlpc_write_register(0x30, 0x00);
130                 return 1;
131         }
132
133         /* Assert D_PLTRST# */
134         outb(0xfe, 0x1680);
135         udelay(100000);
136         /* Deassert D_PLTRST# */
137         outb(0xff, 0x1680);
138
139         udelay(100000);
140
141         /* startup 14.318MHz Clock */
142         dock_write_register(0x29, 0x06);
143         /* wait until clock is settled */
144         timeout = 1000;
145         while(!(dock_read_register(0x29) & 0x08) && timeout--)
146                 udelay(1000);
147
148         if (!timeout)
149                 return 1;
150
151         /* Pin  6: CLKRUN
152          * Pin 72:  #DR1
153          * Pin 19: #SMI
154          * Pin 73: #MTR
155          */
156         dock_write_register(0x24, 0x37);
157
158         /* PNF active HIGH */
159         dock_write_register(0x25, 0xa0);
160
161         /* disable FDC */
162         dock_write_register(0x26, 0x01);
163
164         /* Enable GPIO IRQ to #SMI */
165         dock_write_register(0x28, 0x02);
166
167         /* select GPIO */
168         dock_write_register(0x07, 0x07);
169
170         /* set base address */
171         dock_write_register(0x60, 0x16);
172         dock_write_register(0x61, 0x20);
173
174         /* init GPIO pins */
175         dock_gpio_set_mode(0x00, PC87392_GPIO_PIN_DEBOUNCE |
176                                  PC87392_GPIO_PIN_PULLUP, 0x00);
177
178         dock_gpio_set_mode(0x01, PC87392_GPIO_PIN_DEBOUNCE |
179                                  PC87392_GPIO_PIN_PULLUP,
180                                  PC87392_GPIO_PIN_TRIGGERS_SMI);
181
182         dock_gpio_set_mode(0x02, PC87392_GPIO_PIN_PULLUP, 0x00);
183         dock_gpio_set_mode(0x03, PC87392_GPIO_PIN_PULLUP, 0x00);
184         dock_gpio_set_mode(0x04, PC87392_GPIO_PIN_PULLUP, 0x00);
185         dock_gpio_set_mode(0x05, PC87392_GPIO_PIN_PULLUP, 0x00);
186         dock_gpio_set_mode(0x06, PC87392_GPIO_PIN_PULLUP, 0x00);
187         dock_gpio_set_mode(0x07, PC87392_GPIO_PIN_PULLUP, 0x02);
188
189         dock_gpio_set_mode(0x10, PC87392_GPIO_PIN_DEBOUNCE |
190                                  PC87392_GPIO_PIN_PULLUP,
191                                  PC87392_GPIO_PIN_TRIGGERS_SMI);
192
193         dock_gpio_set_mode(0x11, PC87392_GPIO_PIN_PULLUP, 0x00);
194         dock_gpio_set_mode(0x12, PC87392_GPIO_PIN_PULLUP, 0x00);
195         dock_gpio_set_mode(0x13, PC87392_GPIO_PIN_PULLUP, 0x00);
196         dock_gpio_set_mode(0x14, PC87392_GPIO_PIN_PULLUP, 0x00);
197         dock_gpio_set_mode(0x15, PC87392_GPIO_PIN_PULLUP, 0x00);
198         dock_gpio_set_mode(0x16, PC87392_GPIO_PIN_PULLUP |
199                                  PC87392_GPIO_PIN_OE , 0x00);
200
201         dock_gpio_set_mode(0x17, PC87392_GPIO_PIN_PULLUP, 0x00);
202
203         dock_gpio_set_mode(0x20, PC87392_GPIO_PIN_TYPE_PUSH_PULL |
204                                  PC87392_GPIO_PIN_OE, 0x00);
205
206         dock_gpio_set_mode(0x21, PC87392_GPIO_PIN_TYPE_PUSH_PULL |
207                                  PC87392_GPIO_PIN_OE, 0x00);
208
209         dock_gpio_set_mode(0x22, PC87392_GPIO_PIN_PULLUP, 0x00);
210         dock_gpio_set_mode(0x23, PC87392_GPIO_PIN_PULLUP, 0x00);
211         dock_gpio_set_mode(0x24, PC87392_GPIO_PIN_PULLUP, 0x00);
212         dock_gpio_set_mode(0x25, PC87392_GPIO_PIN_PULLUP, 0x00);
213         dock_gpio_set_mode(0x26, PC87392_GPIO_PIN_PULLUP, 0x00);
214         dock_gpio_set_mode(0x27, PC87392_GPIO_PIN_PULLUP, 0x00);
215
216         dock_gpio_set_mode(0x30, PC87392_GPIO_PIN_PULLUP, 0x00);
217         dock_gpio_set_mode(0x31, PC87392_GPIO_PIN_PULLUP, 0x00);
218         dock_gpio_set_mode(0x32, PC87392_GPIO_PIN_PULLUP, 0x00);
219         dock_gpio_set_mode(0x33, PC87392_GPIO_PIN_PULLUP, 0x00);
220         dock_gpio_set_mode(0x34, PC87392_GPIO_PIN_PULLUP, 0x00);
221
222         dock_gpio_set_mode(0x35, PC87392_GPIO_PIN_PULLUP |
223                                  PC87392_GPIO_PIN_OE, 0x00);
224
225         dock_gpio_set_mode(0x36, PC87392_GPIO_PIN_PULLUP, 0x00);
226         dock_gpio_set_mode(0x37, PC87392_GPIO_PIN_PULLUP, 0x00);
227
228         /* enable GPIO */
229         dock_write_register(0x30, 0x01);
230
231         outb(0x00, 0x1628);
232         outb(0x00, 0x1623);
233         outb(0x82, 0x1622);
234         outb(0xff, 0x1624);
235
236         /* Enable USB and Ultrabay power */
237         outb(0x03, 0x1628);
238
239         dock_write_register(0x07, 0x03);
240         dock_write_register(0x30, 0x01);
241         console_init();
242         return 0;
243 }
244
245 void dock_disconnect(void)
246 {
247         printk(BIOS_DEBUG, "%s enter\n", __func__);
248         /* disconnect LPC bus */
249         outb(0x00, 0x164c);
250         udelay(10000);
251
252         /* Assert PLTRST and DLPCPD */
253         outb(0xfc, 0x1680);
254         udelay(10000);
255
256         /* disable Ultrabay and USB Power */
257         outb(0x00, 0x1628);
258         udelay(10000);
259
260         printk(BIOS_DEBUG, "%s finish\n", __func__);
261 }
262
263 int dock_present(void)
264 {
265         return !((inb(DEFAULT_GPIOBASE + 0x0c) >> 13) & 1);
266 }
267
268 int dock_ultrabay_device_present(void)
269 {
270         return inb(0x1621) & 0x02 ? 0 : 1;
271 }