• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
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>
12 
13 #include <southbridge/intel/i82801ix/i82801ix.h>
14 #include <ec/lenovo/h8/h8.h>
15 #include <ec/acpi/ec.h>
16 
17 struct pin_config {
18 	u8 port;
19 	u8 mode;
20 };
21 
poll_clk_stable(pnp_devfn_t dev,int timeout)22 static int poll_clk_stable(pnp_devfn_t dev, int timeout)
23 {
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;
30 
31 	return 0;
32 }
33 
gpio_init(pnp_devfn_t gpio,u16 gpio_base,const struct pin_config pincfg[],int num_cfgs)34 static int gpio_init(pnp_devfn_t gpio, u16 gpio_base,
35 	const struct pin_config pincfg[], int num_cfgs)
36 {
37 	int i;
38 
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);
43 
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);
48 	}
49 	return 0;
50 }
51 
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);
54 
pc87382_init(pnp_devfn_t dlpc,u16 dlpc_base)55 static int pc87382_init(pnp_devfn_t dlpc, u16 dlpc_base)
56 {
57 	/* Maximum 3300 LCLKs at 14.318MHz */
58 	int timeout = 230;
59 
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);
64 
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;
72 
73 	return 0;
74 }
75 
pc87382_close(pnp_devfn_t dlpc)76 static void pc87382_close(pnp_devfn_t dlpc)
77 {
78 	pnp_set_logical_device(dlpc);
79 
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);
85 	}
86 }
87 
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},
91 };
92 
93 /* Enable internal clock and configure GPIO LDN */
pc87382_early(void)94 int pc87382_early(void)
95 {
96 	/* Wake-up time is 33 msec (maximum). */
97 	if (poll_clk_stable(l_gpio, 33) != 0)
98 		return 1;
99 
100 	/* Set up GPIOs */
101 	if (gpio_init(l_gpio, DLPC_GPIO_BASE,
102 		local_gpio, ARRAY_SIZE(local_gpio)) != 0) {
103 		return 1;
104 	}
105 
106 	return 0;
107 }
108 
pc87382_connect(void)109 static int pc87382_connect(void)
110 {
111 	u8 reg;
112 
113 	reg = inb(DLPC_GPDO0);
114 	reg |= D_PLTRST | D_LPCPD;
115 	/* Deassert D_PLTRST# and D_LPCPD# */
116 	outb(reg, DLPC_GPDO0);
117 
118 	if (pc87382_init(l_dlpc, DLPC_CONTROL) != 0)
119 		return 1;
120 
121 	/* Assert D_PLTRST# */
122 	reg &= ~D_PLTRST;
123 	outb(reg, DLPC_GPDO0);
124 	udelay(1000);
125 
126 	/* Deassert D_PLTRST# */
127 	reg |= D_PLTRST;
128 	outb(reg, DLPC_GPDO0);
129 	mdelay(10);
130 
131 	return 0;
132 }
133 
pc87382_disconnect(void)134 static void pc87382_disconnect(void)
135 {
136 	pc87382_close(l_dlpc);
137 
138 	/* Assert D_PLTRST# and D_LPCPD# */
139 	u8 reg = inb(DLPC_GPDO0);
140 	reg &= ~(D_PLTRST | D_LPCPD);
141 	outb(reg, DLPC_GPDO0);
142 }
143 
144 /* Returns 3bit dock id */
dock_identify(void)145 static u8 dock_identify(void)
146 {
147 	u8 id;
148 
149 	/* Make sure GPIO LDN is configured first ! */
150 	id = (inb(DLPC_GPDI0) >> 4) & 1;
151 	id |= (inb(DLPC_GPDI2) & 3) << 1;
152 
153 	return id;
154 }
155 
156 /* Docking station side. */
157 
158 #include <superio/nsc/pc87384/pc87384.h>
159 
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);
162 
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},
172 };
173 
pc87384_init(void)174 static int pc87384_init(void)
175 {
176 	if (poll_clk_stable(r_gpio, 1000) != 0)
177 		return 1;
178 
179 	/* set GPIO pins to Serial/Parallel Port
180 	 * functions
181 	 */
182 	pnp_write_config(r_gpio, 0x22, 0xa9);
183 
184 	/* enable serial port */
185 
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);
190 	}
191 
192 	if (gpio_init(r_gpio, DOCK_GPIO_BASE,
193 		remote_gpio, ARRAY_SIZE(remote_gpio)) != 0)
194 		return 1;
195 
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);
201 
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);
207 
208 	outb(0xfd, DOCK_GPIO_BASE + 0x00);
209 
210 	return 0;
211 }
212 
213 /* Mainboard */
214 
dock_connect(void)215 void dock_connect(void)
216 {
217 	const u8 id = dock_identify();
218 
219 	/* Dock type 2505 doesn't have serial, LPT port or LEDs */
220 	if (id == DOCK_TYPE_NONE || id == DOCK_TYPE_2505)
221 		return;
222 
223 	if (pc87382_connect() != 0 || pc87384_init() != 0) {
224 		pc87382_disconnect();
225 		return;
226 	}
227 
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);
232 }
233 
dock_disconnect(void)234 void dock_disconnect(void)
235 {
236 	pc87382_disconnect();
237 
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);
242 }
243 
dock_info(void)244 void dock_info(void)
245 {
246 	const u8 id = dock_identify();
247 
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");
252 }
253