mb/google/nissa/var/rull: Add 6W and 15W DPTF parameters
[coreboot2.git] / src / mainboard / lenovo / t400 / dock.c
blobb8163e710be5005856a9be96433b0e963a1226f0
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #define __SIMPLE_DEVICE__
4 #include <console/console.h>
5 #include <arch/io.h>
6 #include <device/pnp_ops.h>
7 #include <device/device.h>
8 #include <device/pnp.h>
9 #include <delay.h>
10 #include "dock.h"
11 #include <superio/nsc/pc87382/pc87382.h>
13 #include <southbridge/intel/i82801ix/i82801ix.h>
14 #include <ec/lenovo/h8/h8.h>
15 #include <ec/acpi/ec.h>
17 struct pin_config {
18 u8 port;
19 u8 mode;
22 static int poll_clk_stable(pnp_devfn_t dev, int timeout)
24 /* Enable 14.318MHz CLK on CLKIN */
25 pnp_write_config(dev, 0x29, 0xa0);
26 while (!(pnp_read_config(dev, 0x29) & 0x10) && timeout--)
27 udelay(1000);
28 if (!timeout)
29 return 1;
31 return 0;
34 static int gpio_init(pnp_devfn_t gpio, u16 gpio_base,
35 const struct pin_config pincfg[], int num_cfgs)
37 int i;
39 /* Enable GPIO LDN. */
40 pnp_set_logical_device(gpio);
41 pnp_set_iobase(gpio, PNP_IDX_IO0, gpio_base);
42 pnp_set_enable(gpio, 1);
44 for (i = 0; i < num_cfgs; i++) {
45 pnp_write_config(gpio, 0xf0, pincfg[i].port);
46 pnp_write_config(gpio, 0xf1, pincfg[i].mode);
47 pnp_write_config(gpio, 0xf2, 0x0);
49 return 0;
52 static const pnp_devfn_t l_dlpc = PNP_DEV(0x164e, PC87382_DOCK);
53 static const pnp_devfn_t l_gpio = PNP_DEV(0x164e, PC87382_GPIO);
55 static int pc87382_init(pnp_devfn_t dlpc, u16 dlpc_base)
57 /* Maximum 3300 LCLKs at 14.318MHz */
58 int timeout = 230;
60 /* Enable LPC bridge LDN. */
61 pnp_set_logical_device(dlpc);
62 pnp_set_iobase(dlpc, PNP_IDX_IO0, dlpc_base);
63 pnp_set_enable(dlpc, 1);
65 /* Reset docking state */
66 outb(0x00, dlpc_base);
67 outb(0x07, dlpc_base);
68 while (!(inb(dlpc_base) & 8) && timeout--)
69 udelay(1);
70 if (!timeout)
71 return 1;
73 return 0;
76 static void pc87382_close(pnp_devfn_t dlpc)
78 pnp_set_logical_device(dlpc);
80 /* Disconnect LPC bus */
81 u16 dlpc_base = pnp_read_iobase(dlpc, PNP_IDX_IO0);
82 if (dlpc_base) {
83 outb(0x00, dlpc_base);
84 pnp_set_enable(dlpc, 0);
88 static const struct pin_config local_gpio[] = {
89 {0x00, 3}, {0x01, 3}, {0x02, 0}, {0x03, 3},
90 {0x04, 4}, {0x20, 4}, {0x21, 4}, {0x23, 4},
93 /* Enable internal clock and configure GPIO LDN */
94 int pc87382_early(void)
96 /* Wake-up time is 33 msec (maximum). */
97 if (poll_clk_stable(l_gpio, 33) != 0)
98 return 1;
100 /* Set up GPIOs */
101 if (gpio_init(l_gpio, DLPC_GPIO_BASE,
102 local_gpio, ARRAY_SIZE(local_gpio)) != 0) {
103 return 1;
106 return 0;
109 static int pc87382_connect(void)
111 u8 reg;
113 reg = inb(DLPC_GPDO0);
114 reg |= D_PLTRST | D_LPCPD;
115 /* Deassert D_PLTRST# and D_LPCPD# */
116 outb(reg, DLPC_GPDO0);
118 if (pc87382_init(l_dlpc, DLPC_CONTROL) != 0)
119 return 1;
121 /* Assert D_PLTRST# */
122 reg &= ~D_PLTRST;
123 outb(reg, DLPC_GPDO0);
124 udelay(1000);
126 /* Deassert D_PLTRST# */
127 reg |= D_PLTRST;
128 outb(reg, DLPC_GPDO0);
129 mdelay(10);
131 return 0;
134 static void pc87382_disconnect(void)
136 pc87382_close(l_dlpc);
138 /* Assert D_PLTRST# and D_LPCPD# */
139 u8 reg = inb(DLPC_GPDO0);
140 reg &= ~(D_PLTRST | D_LPCPD);
141 outb(reg, DLPC_GPDO0);
144 /* Returns 3bit dock id */
145 static u8 dock_identify(void)
147 u8 id;
149 /* Make sure GPIO LDN is configured first ! */
150 id = (inb(DLPC_GPDI0) >> 4) & 1;
151 id |= (inb(DLPC_GPDI2) & 3) << 1;
153 return id;
156 /* Docking station side. */
158 #include <superio/nsc/pc87384/pc87384.h>
160 static const pnp_devfn_t r_gpio = PNP_DEV(SUPERIO_DEV, PC87384_GPIO);
161 static const pnp_devfn_t r_serial = PNP_DEV(SUPERIO_DEV, PC87384_SP1);
163 static const struct pin_config remote_gpio[] = {
164 {0x00, PC87384_GPIO_PIN_DEBOUNCE | PC87384_GPIO_PIN_PULLUP},
165 {0x01, PC87384_GPIO_PIN_TYPE_PUSH_PULL | PC87384_GPIO_PIN_OE},
166 {0x02, PC87384_GPIO_PIN_TYPE_PUSH_PULL | PC87384_GPIO_PIN_OE},
167 {0x03, PC87384_GPIO_PIN_DEBOUNCE | PC87384_GPIO_PIN_PULLUP},
168 {0x04, PC87384_GPIO_PIN_DEBOUNCE | PC87384_GPIO_PIN_PULLUP},
169 {0x05, PC87384_GPIO_PIN_DEBOUNCE | PC87384_GPIO_PIN_PULLUP},
170 {0x06, PC87384_GPIO_PIN_DEBOUNCE | PC87384_GPIO_PIN_PULLUP},
171 {0x07, PC87384_GPIO_PIN_DEBOUNCE | PC87384_GPIO_PIN_PULLUP},
174 static int pc87384_init(void)
176 if (poll_clk_stable(r_gpio, 1000) != 0)
177 return 1;
179 /* set GPIO pins to Serial/Parallel Port
180 * functions
182 pnp_write_config(r_gpio, 0x22, 0xa9);
184 /* enable serial port */
186 if (CONFIG_TTYS0_BASE > 0) {
187 pnp_set_logical_device(r_serial);
188 pnp_set_iobase(r_serial, PNP_IDX_IO0, CONFIG_TTYS0_BASE);
189 pnp_set_enable(r_serial, 1);
192 if (gpio_init(r_gpio, DOCK_GPIO_BASE,
193 remote_gpio, ARRAY_SIZE(remote_gpio)) != 0)
194 return 1;
196 /* no GPIO events enabled for PORT0 */
197 outb(0x00, DOCK_GPIO_BASE + 0x02);
198 /* clear GPIO events on PORT0 */
199 outb(0xff, DOCK_GPIO_BASE + 0x03);
200 outb(0xff, DOCK_GPIO_BASE + 0x04);
202 /* no GPIO events enabled for PORT1 */
203 outb(0x00, DOCK_GPIO_BASE + 0x06);
204 /* clear GPIO events on PORT1*/
205 outb(0xff, DOCK_GPIO_BASE + 0x07);
206 outb(0x1f, DOCK_GPIO_BASE + 0x08);
208 outb(0xfd, DOCK_GPIO_BASE + 0x00);
210 return 0;
213 /* Mainboard */
215 void dock_connect(void)
217 const u8 id = dock_identify();
219 /* Dock type 2505 doesn't have serial, LPT port or LEDs */
220 if (id == DOCK_TYPE_NONE || id == DOCK_TYPE_2505)
221 return;
223 if (pc87382_connect() != 0 || pc87384_init() != 0) {
224 pc87382_disconnect();
225 return;
228 ec_write(H8_LED_CONTROL,
229 H8_LED_CONTROL_OFF | H8_LED_CONTROL_DOCK_LED1);
230 ec_write(H8_LED_CONTROL,
231 H8_LED_CONTROL_ON | H8_LED_CONTROL_DOCK_LED2);
234 void dock_disconnect(void)
236 pc87382_disconnect();
238 ec_write(H8_LED_CONTROL,
239 H8_LED_CONTROL_OFF | H8_LED_CONTROL_DOCK_LED1);
240 ec_write(H8_LED_CONTROL,
241 H8_LED_CONTROL_OFF | H8_LED_CONTROL_DOCK_LED2);
244 void dock_info(void)
246 const u8 id = dock_identify();
248 if (id != DOCK_TYPE_NONE)
249 printk(BIOS_DEBUG, "DOCK: is present: id=%d\n", id);
250 else
251 printk(BIOS_DEBUG, "DOCK: not connected\n");