1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #define __SIMPLE_DEVICE__
4 #include <console/console.h>
6 #include <device/pnp_ops.h>
7 #include <device/device.h>
8 #include <device/pnp.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>
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
--)
34 static int gpio_init(pnp_devfn_t gpio
, u16 gpio_base
,
35 const struct pin_config pincfg
[], int num_cfgs
)
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);
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 */
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
--)
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
);
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)
101 if (gpio_init(l_gpio
, DLPC_GPIO_BASE
,
102 local_gpio
, ARRAY_SIZE(local_gpio
)) != 0) {
109 static int pc87382_connect(void)
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)
121 /* Assert D_PLTRST# */
123 outb(reg
, DLPC_GPDO0
);
126 /* Deassert D_PLTRST# */
128 outb(reg
, DLPC_GPDO0
);
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)
149 /* Make sure GPIO LDN is configured first ! */
150 id
= (inb(DLPC_GPDI0
) >> 4) & 1;
151 id
|= (inb(DLPC_GPDI2
) & 3) << 1;
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)
179 /* set GPIO pins to Serial/Parallel Port
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)
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);
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
)
223 if (pc87382_connect() != 0 || pc87384_init() != 0) {
224 pc87382_disconnect();
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
);
246 const u8 id
= dock_identify();
248 if (id
!= DOCK_TYPE_NONE
)
249 printk(BIOS_DEBUG
, "DOCK: is present: id=%d\n", id
);
251 printk(BIOS_DEBUG
, "DOCK: not connected\n");