xref: /netbsd-src/sys/arch/evbmips/loongson/dev/glx.c (revision e61202360d5611414dd6f6115934a96aa1f50b1a)
1 /*	$NetBSD: glx.c,v 1.4 2012/03/11 00:02:04 mrg Exp $	*/
2 /*	$OpenBSD: glx.c,v 1.6 2010/10/14 21:23:04 pirofti Exp $	*/
3 
4 /*
5  * Copyright (c) 2009 Miodrag Vallat.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*
21  * AMD CS5536 PCI Mess
22  * XXX too many hardcoded numbers... need to expand glxreg.h
23  */
24 #include <sys/cdefs.h>
25 __KERNEL_RCSID(0, "$NetBSD: glx.c,v 1.4 2012/03/11 00:02:04 mrg Exp $");
26 
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/device.h>
30 
31 #include <evbmips/loongson/autoconf.h>
32 
33 #include <dev/pci/pcireg.h>
34 #include <dev/pci/pcivar.h>
35 #include <dev/pci/pcidevs.h>
36 
37 #include <dev/pci/pciidereg.h>
38 #include <dev/usb/usb.h>
39 #include <dev/usb/ohcireg.h>
40 #include <dev/usb/ehcireg.h>
41 
42 #include <mips/bonito/bonitoreg.h>
43 #include <mips/bonito/bonitovar.h>
44 
45 #include <evbmips/loongson/dev/glxreg.h>
46 #include <evbmips/loongson/dev/glxvar.h>
47 
48 #ifdef GLX_DEBUG
49 #define DPRINTF(x) printf x
50 #else
51 #define DPRINTF(x)
52 #endif
53 
54 /*
55  * Since the purpose of this code is to present a different view of the
56  * PCI configuration space, it can not attach as a real device.
57  * (well it could, and then we'd have to attach a fake pci to it,
58  * and fake the configuration space accesses anyways - is it worth doing?)
59  *
60  * We just keep the `would-be softc' structure as global variables.
61  */
62 
63 static pci_chipset_tag_t	glxbase_pc;
64 static pcitag_t			glxbase_tag;
65 static int			glxbase_dev;
66 
67 /* MSR access through PCI configuration space */
68 #define	PCI_MSR_CTRL		0x00f0
69 #define	PCI_MSR_ADDR		0x00f4
70 #define	PCI_MSR_LO32		0x00f8
71 #define	PCI_MSR_HI32		0x00fc
72 
73 /* access to the MSR through the PCI mailbox needs the same transformation
74  * as done by hardware when a MSR request reaches the CS5536.
75  */
76 #define GLX_MSR_ADDR_TARGET	0x00003fff
77 #define GLX_MSR_ADDR_RF		0xffffc000
78 #define GLX_MSR_ADDR_RF_SHIFT	9
79 
80 static uint glx_msra2mbxa(uint);
81 static uint
82 glx_msra2mbxa(uint msr)
83 {
84 	uint rf = (msr & GLX_MSR_ADDR_RF);
85 	return ((rf << GLX_MSR_ADDR_RF_SHIFT) | (msr & GLX_MSR_ADDR_TARGET));
86 }
87 
88 pcireg_t glx_pci_read_hook(void *, pcitag_t, int);
89 void	glx_pci_write_hook(void *, pcitag_t, int, pcireg_t);
90 
91 pcireg_t glx_get_status(void);
92 pcireg_t glx_fn0_read(int);
93 void	glx_fn0_write(int, pcireg_t);
94 pcireg_t glx_fn2_read(int);
95 void	glx_fn2_write(int, pcireg_t);
96 pcireg_t glx_fn3_read(int);
97 void	glx_fn3_write(int, pcireg_t);
98 pcireg_t glx_fn4_read(int);
99 void	glx_fn4_write(int, pcireg_t);
100 pcireg_t glx_fn5_read(int);
101 void	glx_fn5_write(int, pcireg_t);
102 pcireg_t glx_fn6_read(int);
103 void	glx_fn6_write(int, pcireg_t);
104 pcireg_t glx_fn7_read(int);
105 void	glx_fn7_write(int, pcireg_t);
106 
107 pcireg_t (*gen_pci_conf_read)(void *, pcitag_t, int);
108 void (*gen_pci_conf_write)(void *, pcitag_t, int, pcireg_t);
109 
110 void
111 glx_init(pci_chipset_tag_t pc, pcitag_t tag, int dev)
112 {
113 	uint64_t msr;
114 
115 	glxbase_pc = pc;
116 	glxbase_dev = dev;
117 	glxbase_tag = tag;
118 
119 	/*
120 	 * Register PCI configuration hooks to make the various
121 	 * embedded devices visible as PCI subfunctions.
122 	 */
123 
124 	gen_pci_conf_read = pc->pc_conf_read;
125 	pc->pc_conf_read = glx_pci_read_hook;
126 	gen_pci_conf_write = pc->pc_conf_write;
127 	pc->pc_conf_write = glx_pci_write_hook;
128 
129 	/*
130 	 * Perform some Geode intialization.
131 	 */
132 
133 	msr = rdmsr(GCSC_DIVIL_BALL_OPTS);	/* 0x71 */
134 	wrmsr(GCSC_DIVIL_BALL_OPTS, msr | 0x01);
135 
136 	/*
137 	 * Route usb and audio
138 	 */
139 	msr = 0;
140 	msr |= 11 << 8;
141 	msr |= 9 << 16;
142 	wrmsr(GCSC_PIC_YSEL_LOW, msr);
143 
144 	/*
145 	 * serial interrupts
146 	 */
147 	msr = 0;
148 	msr |= 4 << 24;
149 	msr |= 3 << 28;
150 	wrmsr(GCSC_PIC_YSEL_HIGH, msr);
151 
152 	/*
153 	 * and IDE
154 	 */
155 	msr = 0;
156 	msr |= 1 << 14;
157 	wrmsr(GCSC_PIC_IRQM_PRIM, msr);
158 
159 	/*
160 	 * keyboard and mouse interrupts
161 	 */
162 	msr = 0;
163 	msr |= 1 << 1;	/* keyboard */
164 	msr |= 1 << 12;	/* mouse */
165 	wrmsr(GCSC_PIC_IRQM_LPC, msr);
166 
167 	/* no interrupts from theses */
168 	wrmsr(GCSC_PIC_ZSEL_LOW, 0);
169 	wrmsr(GCSC_PIC_ZSEL_HIGH, 0);
170 
171 	DPRINTF(("IO space 0x%" PRIx64 "\n", rdmsr(0x80000014)));
172 }
173 
174 uint64_t
175 rdmsr(uint msr)
176 {
177 	uint64_t lo, hi;
178 	int s;
179 
180 #ifdef DIAGNOSTIC
181 	if (glxbase_tag == 0)
182 		panic("rdmsr invoked before glx initialization");
183 #endif
184 
185 	s = splhigh();
186 	pci_conf_write(glxbase_pc, glxbase_tag, PCI_MSR_ADDR,
187 	    glx_msra2mbxa(msr));
188 	lo = (uint32_t)pci_conf_read(glxbase_pc, glxbase_tag, PCI_MSR_LO32);
189 	hi = (uint32_t)pci_conf_read(glxbase_pc, glxbase_tag, PCI_MSR_HI32);
190 	splx(s);
191 	return (hi << 32) | lo;
192 }
193 
194 void
195 wrmsr(uint msr, uint64_t value)
196 {
197 	int s;
198 
199 #ifdef DIAGNOSTIC
200 	if (glxbase_tag == 0)
201 		panic("wrmsr invoked before glx initialization");
202 #endif
203 
204 	s = splhigh();
205 	pci_conf_write(glxbase_pc, glxbase_tag, PCI_MSR_ADDR,
206 	    glx_msra2mbxa(msr));
207 	pci_conf_write(glxbase_pc, glxbase_tag, PCI_MSR_LO32, (uint32_t)value);
208 	pci_conf_write(glxbase_pc, glxbase_tag, PCI_MSR_HI32, value >> 32);
209 	splx(s);
210 }
211 
212 pcireg_t
213 glx_pci_read_hook(void *v, pcitag_t tag, int offset)
214 {
215 	int bus, dev, fn;
216 	pcireg_t data;
217 
218 	/*
219 	 * Do not get in the way of MSR programming
220 	 */
221 	if (tag == glxbase_tag && offset >= PCI_MSR_CTRL)
222 		return gen_pci_conf_read(v, tag, offset);
223 
224 	pci_decompose_tag(glxbase_pc, tag, &bus, &dev, &fn);
225 	if (bus != 0 || dev != glxbase_dev)
226 		return gen_pci_conf_read(v, tag, offset);
227 
228 	data = 0;
229 
230 	switch (fn) {
231 	case 0:	/* PCI-ISA bridge */
232 		data = glx_fn0_read(offset);
233 		break;
234 	case 1:	/* Flash memory */
235 		break;
236 	case 2:	/* IDE controller */
237 		data = glx_fn2_read(offset);
238 		break;
239 	case 3:	/* AC97 codec */
240 		data = glx_fn3_read(offset);
241 		break;
242 	case 4:	/* OHCI controller */
243 		data = glx_fn4_read(offset);
244 		break;
245 	case 5:	/* EHCI controller */
246 		data = glx_fn5_read(offset);
247 		break;
248 	case 6:	/* UDC */
249 		break;
250 	case 7:	/* OTG */
251 		break;
252 	}
253 
254 	return data;
255 }
256 
257 void
258 glx_pci_write_hook(void *v, pcitag_t tag,
259     int offset, pcireg_t data)
260 {
261 	int bus, dev, fn;
262 
263 	/*
264 	 * Do not get in the way of MSR programming
265 	 */
266 	if (tag == glxbase_tag && offset >= PCI_MSR_CTRL) {
267 		gen_pci_conf_write(v, tag, offset, data);
268 		return;
269 	}
270 
271 
272 	pci_decompose_tag(glxbase_pc, tag, &bus, &dev, &fn);
273 	if (bus != 0 || dev != glxbase_dev) {
274 		gen_pci_conf_write(v, tag, offset, data);
275 		return;
276 	}
277 
278 	switch (fn) {
279 	case 0:	/* PCI-ISA bridge */
280 		glx_fn0_write(offset, data);
281 		break;
282 	case 1:	/* Flash memory */
283 		break;
284 	case 2:	/* IDE controller */
285 		glx_fn2_write(offset, data);
286 		break;
287 	case 3:	/* AC97 codec */
288 		glx_fn3_write(offset, data);
289 		break;
290 	case 4:	/* OHCI controller */
291 		glx_fn4_write(offset, data);
292 		break;
293 	case 5:	/* EHCI controller */
294 		glx_fn5_write(offset, data);
295 		break;
296 	case 6:	/* USB UDC */
297 		break;
298 	case 7:	/* USB OTG */
299 		break;
300 	}
301 }
302 
303 pcireg_t
304 glx_get_status(void)
305 {
306 	uint64_t msr;
307 	pcireg_t data;
308 
309 	data = 0;
310 	msr = rdmsr(GCSC_GLPCI_GLD_MSR_ERROR);
311 	if (msr & (1UL << 5))
312 		data |= PCI_COMMAND_PARITY_ENABLE;
313 	data |= PCI_STATUS_66MHZ_SUPPORT |
314 	    PCI_STATUS_BACKTOBACK_SUPPORT | PCI_STATUS_DEVSEL_MEDIUM;
315 	if (msr & (1UL << 21))
316 		data |= PCI_STATUS_PARITY_DETECT;
317 	if (msr & (1UL << 20))
318 		data |= PCI_STATUS_TARGET_TARGET_ABORT;
319 	if (msr & (1UL << 17))
320 		data |= PCI_STATUS_MASTER_TARGET_ABORT;
321 	if (msr & (1UL << 16))
322 		data |= PCI_STATUS_MASTER_ABORT;
323 
324 	return data;
325 }
326 
327 /*
328  * Function 0: PCI-ISA bridge
329  */
330 
331 static const pcireg_t pcib_bar_sizes[(4 + PCI_MAPREG_END - PCI_MAPREG_START) / 4] = {
332 	0x008,
333 	0x100,
334 	0x040,
335 	0x020,
336 	0x080,
337 	0x020
338 };
339 
340 static pcireg_t pcib_bar_values[(4 + PCI_MAPREG_END - PCI_MAPREG_START) / 4];
341 
342 static const uint64_t pcib_bar_msr[(4 + PCI_MAPREG_END - PCI_MAPREG_START) / 4] = {
343 	GCSC_DIVIL_LBAR_SMB,
344 	GCSC_DIVIL_LBAR_GPIO,
345 	GCSC_DIVIL_LBAR_MFGPT,
346 	GCSC_DIVIL_LBAR_IRQ,
347 	GCSC_DIVIL_LBAR_PMS,
348 	GCSC_DIVIL_LBAR_ACPI
349 };
350 
351 pcireg_t
352 glx_fn0_read(int reg)
353 {
354 	uint64_t msr;
355 	pcireg_t data;
356 	int index;
357 
358 	switch (reg) {
359 	case PCI_ID_REG:
360 	case PCI_SUBSYS_ID_REG:
361 		data = PCI_ID_CODE(PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_PCIB);
362 		break;
363 	case PCI_COMMAND_STATUS_REG:
364 		data = glx_get_status();
365 		data |= PCI_COMMAND_MASTER_ENABLE;
366 		msr = rdmsr(GCSC_DIVIL_LBAR_SMB);
367 		if (msr & (1ULL << 32))
368 			data |= PCI_COMMAND_IO_ENABLE;
369 		break;
370 	case PCI_CLASS_REG:
371 		msr = rdmsr(GCSC_GLCP_CHIP_REV_ID);
372 		data = (PCI_CLASS_BRIDGE << PCI_CLASS_SHIFT) |
373 		    (PCI_SUBCLASS_BRIDGE_ISA << PCI_SUBCLASS_SHIFT) |
374 		    (msr & PCI_REVISION_MASK);
375 		break;
376 	case PCI_BHLC_REG:
377 		msr = rdmsr(GCSC_GLPCI_CTRL);
378 		data = (0x80 << PCI_HDRTYPE_SHIFT) |
379 		    (((msr & 0xff00000000UL) >> 32) << PCI_LATTIMER_SHIFT) |
380 		    (0x08 << PCI_CACHELINE_SHIFT);
381 		break;
382 	case PCI_MAPREG_START + 0x00:
383 	case PCI_MAPREG_START + 0x04:
384 	case PCI_MAPREG_START + 0x08:
385 	case PCI_MAPREG_START + 0x0c:
386 	case PCI_MAPREG_START + 0x10:
387 	case PCI_MAPREG_START + 0x14:
388 	case PCI_MAPREG_START + 0x18:
389 		index = (reg - PCI_MAPREG_START) / 4;
390 		if (pcib_bar_msr[index] == 0)
391 			data = 0;
392 		else {
393 			data = pcib_bar_values[index];
394 			if (data == 0xffffffff)
395 				data = PCI_MAPREG_IO_ADDR_MASK;
396 			else
397 				data = (pcireg_t)rdmsr(pcib_bar_msr[index]);
398 			data &= ~(pcib_bar_sizes[index] - 1);
399 			if (data != 0)
400 				data |= PCI_MAPREG_TYPE_IO;
401 		}
402 		break;
403 	case PCI_INTERRUPT_REG:
404 		data = (0x40 << PCI_MAX_LAT_SHIFT) |
405 		    (PCI_INTERRUPT_PIN_NONE << PCI_INTERRUPT_PIN_SHIFT);
406 		break;
407 	default:
408 		data = 0;
409 		break;
410 	}
411 
412 	return data;
413 }
414 
415 void
416 glx_fn0_write(int reg, pcireg_t data)
417 {
418 	uint64_t msr;
419 	int index;
420 
421 	switch (reg) {
422 	case PCI_COMMAND_STATUS_REG:
423 		for (index = 0; index < __arraycount(pcib_bar_msr); index++) {
424 			if (pcib_bar_msr[index] == 0)
425 				continue;
426 			msr = rdmsr(pcib_bar_msr[index]);
427 			if (data & PCI_COMMAND_IO_ENABLE)
428 				msr |= 1ULL << 32;
429 			else
430 				msr &= ~(1ULL << 32);
431 			wrmsr(pcib_bar_msr[index], msr);
432 		}
433 
434 		msr = rdmsr(GCSC_GLPCI_GLD_MSR_ERROR);
435 		if (data & PCI_COMMAND_PARITY_ENABLE)
436 			msr |= 1ULL << 5;
437 		else
438 			msr &= ~(1ULL << 5);
439 		wrmsr(GCSC_GLPCI_GLD_MSR_ERROR, msr);
440 		break;
441 	case PCI_BHLC_REG:
442 		msr = rdmsr(GCSC_GLPCI_CTRL);
443 		msr &= 0xff00000000ULL;
444 		msr |= ((uint64_t)PCI_LATTIMER(data)) << 32;
445 		break;
446 	case PCI_MAPREG_START + 0x00:
447 	case PCI_MAPREG_START + 0x04:
448 	case PCI_MAPREG_START + 0x08:
449 	case PCI_MAPREG_START + 0x0c:
450 	case PCI_MAPREG_START + 0x10:
451 	case PCI_MAPREG_START + 0x14:
452 	case PCI_MAPREG_START + 0x18:
453 		index = (reg - PCI_MAPREG_START) / 4;
454 		if (data == 0xffffffff) {
455 			pcib_bar_values[index] = data;
456 		} else if (pcib_bar_msr[index] != 0) {
457 			if ((data & PCI_MAPREG_TYPE_MASK) ==
458 			    PCI_MAPREG_TYPE_IO) {
459 				data &= PCI_MAPREG_IO_ADDR_MASK;
460 				data &= ~(pcib_bar_sizes[index] - 1);
461 				wrmsr(pcib_bar_msr[index],
462 				    (0x0000f000ULL << 32) | (1ULL << 32) | data);
463 			} else {
464 				wrmsr(pcib_bar_msr[index], 0ULL);
465 			}
466 			pcib_bar_values[index] = 0;
467 		}
468 		break;
469 	}
470 }
471 
472 /*
473  * Function 2: IDE Controller
474  */
475 
476 static pcireg_t pciide_bar_size = 0x10;
477 static pcireg_t pciide_bar_value;
478 
479 pcireg_t
480 glx_fn2_read(int reg)
481 {
482 	uint64_t msr;
483 	pcireg_t data;
484 
485 	switch (reg) {
486 	case PCI_ID_REG:
487 	case PCI_SUBSYS_ID_REG:
488 		data = PCI_ID_CODE(PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_IDE);
489 		break;
490 	case PCI_COMMAND_STATUS_REG:
491 		data = glx_get_status();
492 		data |= PCI_COMMAND_IO_ENABLE;
493 		msr = rdmsr(GCSC_GLIU_PAE);
494 		if ((msr & (0x3 << 4)) == (0x3 << 4))
495 			data |= PCI_COMMAND_MASTER_ENABLE;
496 		break;
497 	case PCI_CLASS_REG:
498 		msr = rdmsr(GCSC_IDE_GLD_MSR_CAP);
499 		data = (PCI_CLASS_MASS_STORAGE << PCI_CLASS_SHIFT) |
500 		    (PCI_SUBCLASS_MASS_STORAGE_IDE << PCI_SUBCLASS_SHIFT) |
501 		    (PCIIDE_INTERFACE_BUS_MASTER_DMA << PCI_INTERFACE_SHIFT) |
502 		    (msr & PCI_REVISION_MASK);
503 		break;
504 	case PCI_BHLC_REG:
505 		msr = rdmsr(GCSC_GLPCI_CTRL);
506 		data = (0x00 << PCI_HDRTYPE_SHIFT) |
507 		    (((msr & 0xff00000000ULL) >> 32) << PCI_LATTIMER_SHIFT) |
508 		    (0x08 << PCI_CACHELINE_SHIFT);
509 		break;
510 	case PCI_MAPREG_START + 0x10:
511 		data = pciide_bar_value;
512 		if (data == 0xffffffff)
513 			data = PCI_MAPREG_IO_ADDR_MASK & ~(pciide_bar_size - 1);
514 		else {
515 			msr = rdmsr(GCSC_IDE_IO_BAR);
516 			data = msr & 0xfffffff0;
517 		}
518 		if (data != 0)
519 			data |= PCI_MAPREG_TYPE_IO;
520 		break;
521 	case PCI_INTERRUPT_REG:
522 		/* compat mode */
523 		data = (0x40 << PCI_MAX_LAT_SHIFT) |
524 		    (PCI_INTERRUPT_PIN_NONE << PCI_INTERRUPT_PIN_SHIFT);
525 		break;
526 	/*
527 	 * The following registers are used by pciide(4)
528 	 */
529 	case PCIIDE_CHANSTATUS_EN:
530 		data = rdmsr(GCSC_IDE_CFG);
531 		break;
532 	case /* AMD756_DATATIM XXX */ 0x48:
533 		data = rdmsr(GCSC_IDE_DTC);
534 		break;
535 	case /* AMD756_UDMA XXX*/ 0x50:
536 		data = rdmsr(GCSC_IDE_ETC);
537 		break;
538 	default:
539 		DPRINTF(("unimplemented pciide reg 0x%x\n", reg));
540 		data = 0;
541 		break;
542 	}
543 
544 	return data;
545 }
546 
547 void
548 glx_fn2_write(int reg, pcireg_t data)
549 {
550 	uint64_t msr;
551 
552 	switch (reg) {
553 	case PCI_COMMAND_STATUS_REG:
554 		msr = rdmsr(GCSC_GLIU_PAE);
555 		if (data & PCI_COMMAND_MASTER_ENABLE)
556 			msr |= 0x03 << 4;
557 		else
558 			msr &= ~(0x03 << 4);
559 		wrmsr(GCSC_GLIU_PAE, msr);
560 		break;
561 	case PCI_BHLC_REG:
562 		msr = rdmsr(GCSC_GLPCI_CTRL);
563 		msr &= 0xff00000000ULL;
564 		msr |= ((uint64_t)PCI_LATTIMER(data)) << 32;
565 		break;
566 	case PCI_MAPREG_START + 0x10:
567 		if (data == 0xffffffff) {
568 			pciide_bar_value = data;
569 		} else {
570 			if ((data & PCI_MAPREG_TYPE_MASK) ==
571 			    PCI_MAPREG_TYPE_IO) {
572 				data &= PCI_MAPREG_IO_ADDR_MASK;
573 				msr = (uint32_t)data & 0xfffffff0;
574 				wrmsr(GCSC_IDE_IO_BAR, msr);
575 			} else {
576 				wrmsr(GCSC_IDE_IO_BAR, 0);
577 			}
578 			pciide_bar_value = 0;
579 		}
580 		break;
581 	/*
582 	 * The following registers are used by pciide(4)
583 	 */
584 	case PCIIDE_CHANSTATUS_EN:
585 		wrmsr(GCSC_IDE_CFG, (uint32_t)data);
586 		break;
587 	case /* AMD756_DATATIM XXX */ 0x48:
588 		wrmsr(GCSC_IDE_DTC, (uint32_t)data);
589 		break;
590 	case /* AMD756_UDMA XXX*/ 0x50:
591 		wrmsr(GCSC_IDE_ETC, (uint32_t)data);
592 		break;
593 	default:
594 		DPRINTF(("unimplemented pciide reg 0x%x\n", reg));
595 	}
596 }
597 
598 /*
599  * Function 3: AC97 Codec
600  */
601 
602 static pcireg_t ac97_bar_size = 0x80;
603 static pcireg_t ac97_bar_value;
604 
605 pcireg_t
606 glx_fn3_read(int reg)
607 {
608 	uint64_t msr;
609 	pcireg_t data;
610 
611 	switch (reg) {
612 	case PCI_ID_REG:
613 	case PCI_SUBSYS_ID_REG:
614 		data = PCI_ID_CODE(PCI_VENDOR_AMD,
615 		    PCI_PRODUCT_AMD_CS5536_AUDIO);
616 		break;
617 	case PCI_COMMAND_STATUS_REG:
618 		data = glx_get_status();
619 		data |= PCI_COMMAND_IO_ENABLE;
620 		msr = rdmsr(GCSC_GLIU_PAE);
621 		if ((msr & (0x3 << 8)) == (0x3 << 8))
622 			data |= PCI_COMMAND_MASTER_ENABLE;
623 		break;
624 	case PCI_CLASS_REG:
625 		msr = rdmsr(GCSC_ACC_GLD_MSR_CAP);
626 		data = (PCI_CLASS_MULTIMEDIA << PCI_CLASS_SHIFT) |
627 		    (PCI_SUBCLASS_MULTIMEDIA_AUDIO << PCI_SUBCLASS_SHIFT) |
628 		    (msr & PCI_REVISION_MASK);
629 		break;
630 	case PCI_BHLC_REG:
631 		msr = rdmsr(GCSC_GLPCI_CTRL);
632 		data = (0x00 << PCI_HDRTYPE_SHIFT) |
633 		    (((msr & 0xff00000000ULL) >> 32) << PCI_LATTIMER_SHIFT) |
634 		    (0x08 << PCI_CACHELINE_SHIFT);
635 		break;
636 	case PCI_MAPREG_START:
637 		data = ac97_bar_value;
638 		if (data == 0xffffffff)
639 			data = PCI_MAPREG_IO_ADDR_MASK & ~(ac97_bar_size - 1);
640 		else {
641 			msr = rdmsr(GCSC_GLIU_IOD_BM1);
642 			data = (msr >> 20) & 0x000fffff;
643 			data &= (msr & 0x000fffff);
644 		}
645 		if (data != 0)
646 			data |= PCI_MAPREG_TYPE_IO;
647 		break;
648 	case PCI_INTERRUPT_REG:
649 		data = (0x40 << PCI_MAX_LAT_SHIFT) |
650 		    (PCI_INTERRUPT_PIN_A << PCI_INTERRUPT_PIN_SHIFT);
651 		break;
652 	default:
653 		data = 0;
654 		break;
655 	}
656 
657 	return data;
658 }
659 
660 void
661 glx_fn3_write(int reg, pcireg_t data)
662 {
663 	uint64_t msr;
664 
665 	switch (reg) {
666 	case PCI_COMMAND_STATUS_REG:
667 		msr = rdmsr(GCSC_GLIU_PAE);
668 		if (data & PCI_COMMAND_MASTER_ENABLE)
669 			msr |= 0x03 << 8;
670 		else
671 			msr &= ~(0x03 << 8);
672 		wrmsr(GCSC_GLIU_PAE, msr);
673 		break;
674 	case PCI_BHLC_REG:
675 		msr = rdmsr(GCSC_GLPCI_CTRL);
676 		msr &= 0xff00000000ULL;
677 		msr |= ((uint64_t)PCI_LATTIMER(data)) << 32;
678 		break;
679 	case PCI_MAPREG_START:
680 		if (data == 0xffffffff) {
681 			ac97_bar_value = data;
682 		} else {
683 			if ((data & PCI_MAPREG_TYPE_MASK) ==
684 			    PCI_MAPREG_TYPE_IO) {
685 				data &= PCI_MAPREG_IO_ADDR_MASK;
686 				msr = rdmsr(GCSC_GLIU_IOD_BM1);
687 				msr &= 0x0fffff0000000000ULL;
688 				msr |= 5ULL << 61;	/* AC97 */
689 				msr |= ((uint64_t)data & 0xfffff) << 20;
690 				msr |= 0x000fffff & ~(ac97_bar_size - 1);
691 				wrmsr(GCSC_GLIU_IOD_BM1, msr);
692 			} else {
693 				wrmsr(GCSC_GLIU_IOD_BM1, 0);
694 			}
695 			ac97_bar_value = 0;
696 		}
697 		break;
698 	}
699 }
700 
701 /*
702  * Function 4: OHCI Controller
703  */
704 
705 static pcireg_t ohci_bar_size = 0x1000;
706 static pcireg_t ohci_bar_value;
707 
708 pcireg_t
709 glx_fn4_read(int reg)
710 {
711 	uint64_t msr;
712 	pcireg_t data;
713 
714 	switch (reg) {
715 	case PCI_ID_REG:
716 	case PCI_SUBSYS_ID_REG:
717 		data = PCI_ID_CODE(PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_OHCI);
718 		break;
719 	case PCI_COMMAND_STATUS_REG:
720 		data = glx_get_status();
721 		msr = rdmsr(GCSC_USB_MSR_OHCB);
722 		if (msr & (1ULL << 34))
723 			data |= PCI_COMMAND_MASTER_ENABLE;
724 		if (msr & (1ULL << 33))
725 			data |= PCI_COMMAND_MEM_ENABLE;
726 		break;
727 	case PCI_CLASS_REG:
728 		msr = rdmsr(GCSC_USB_GLD_MSR_CAP);
729 		data = (PCI_CLASS_SERIALBUS << PCI_CLASS_SHIFT) |
730 		    (PCI_SUBCLASS_SERIALBUS_USB << PCI_SUBCLASS_SHIFT) |
731 		    (PCI_INTERFACE_OHCI << PCI_INTERFACE_SHIFT) |
732 		    (msr & PCI_REVISION_MASK);
733 		break;
734 	case PCI_BHLC_REG:
735 		msr = rdmsr(GCSC_GLPCI_CTRL);
736 		data = (0x00 << PCI_HDRTYPE_SHIFT) |
737 		    (((msr & 0xff00000000ULL) >> 32) << PCI_LATTIMER_SHIFT) |
738 		    (0x08 << PCI_CACHELINE_SHIFT);
739 		break;
740 	case PCI_MAPREG_START + 0x00:
741 		data = ohci_bar_value;
742 		if (data == 0xffffffff)
743 			data = PCI_MAPREG_MEM_ADDR_MASK & ~(ohci_bar_size - 1);
744 		else {
745 			msr = rdmsr(GCSC_USB_MSR_OHCB);
746 			data = msr & 0xffffff00;
747 		}
748 		if (data != 0)
749 			data |= PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT;
750 		break;
751 	case PCI_CAPLISTPTR_REG:
752 		data = 0x40;
753 		break;
754 	case PCI_INTERRUPT_REG:
755 		data = (0x40 << PCI_MAX_LAT_SHIFT) |
756 		    (PCI_INTERRUPT_PIN_A << PCI_INTERRUPT_PIN_SHIFT);
757 		break;
758 	case 0x40:	/* USB capability pointer */
759 		data = 0;
760 		break;
761 	default:
762 		data = 0;
763 		break;
764 	}
765 
766 	return data;
767 }
768 
769 void
770 glx_fn4_write(int reg, pcireg_t data)
771 {
772 	uint64_t msr;
773 
774 	switch (reg) {
775 	case PCI_COMMAND_STATUS_REG:
776 		msr = rdmsr(GCSC_USB_MSR_OHCB);
777 		if (data & PCI_COMMAND_MASTER_ENABLE)
778 			msr |= 1ULL << 34;
779 		else
780 			msr &= ~(1ULL << 34);
781 		if (data & PCI_COMMAND_MEM_ENABLE)
782 			msr |= 1ULL << 33;
783 		else
784 			msr &= ~(1ULL << 33);
785 		wrmsr(GCSC_USB_MSR_OHCB, msr);
786 		break;
787 	case PCI_BHLC_REG:
788 		msr = rdmsr(GCSC_GLPCI_CTRL);
789 		msr &= 0xff00000000ULL;
790 		msr |= ((uint64_t)PCI_LATTIMER(data)) << 32;
791 		break;
792 	case PCI_MAPREG_START + 0x00:
793 		if (data == 0xffffffff) {
794 			ohci_bar_value = data;
795 		} else {
796 			if ((data & PCI_MAPREG_TYPE_MASK) ==
797 			    PCI_MAPREG_TYPE_MEM) {
798 				data &= PCI_MAPREG_MEM_ADDR_MASK;
799 				msr = rdmsr(GCSC_GLIU_P2D_BM3);
800 				msr &= 0x0fffff0000000000ULL;
801 				msr |= 2ULL << 61;	/* USB */
802 				msr |= (((uint64_t)data) >> 12) << 20;
803 				msr |= 0x000fffff;
804 				wrmsr(GCSC_GLIU_P2D_BM3, msr);
805 
806 				msr = rdmsr(GCSC_USB_MSR_OHCB);
807 				msr &= ~0xffffff00ULL;
808 				msr |= data;
809 			} else {
810 				msr = rdmsr(GCSC_USB_MSR_OHCB);
811 				msr &= ~0xffffff00ULL;
812 			}
813 			wrmsr(GCSC_USB_MSR_OHCB, msr);
814 			ohci_bar_value = 0;
815 		}
816 		break;
817 	default:
818 		break;
819 	}
820 }
821 
822 /*
823  * Function 5: EHCI Controller
824  */
825 
826 static pcireg_t ehci_bar_size = 0x1000;
827 static pcireg_t ehci_bar_value;
828 
829 pcireg_t
830 glx_fn5_read(int reg)
831 {
832 	uint64_t msr;
833 	pcireg_t data;
834 
835 	switch (reg) {
836 	case PCI_ID_REG:
837 	case PCI_SUBSYS_ID_REG:
838 		data = PCI_ID_CODE(PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_EHCI);
839 		break;
840 	case PCI_COMMAND_STATUS_REG:
841 		data = glx_get_status();
842 		msr = rdmsr(GCSC_USB_MSR_EHCB);
843 		if (msr & (1ULL << 34))
844 			data |= PCI_COMMAND_MASTER_ENABLE;
845 		if (msr & (1ULL << 33))
846 			data |= PCI_COMMAND_MEM_ENABLE;
847 		break;
848 	case PCI_CLASS_REG:
849 		msr = rdmsr(GCSC_USB_GLD_MSR_CAP);
850 		data = (PCI_CLASS_SERIALBUS << PCI_CLASS_SHIFT) |
851 		    (PCI_SUBCLASS_SERIALBUS_USB << PCI_SUBCLASS_SHIFT) |
852 		    (PCI_INTERFACE_EHCI << PCI_INTERFACE_SHIFT) |
853 		    (msr & PCI_REVISION_MASK);
854 		break;
855 	case PCI_BHLC_REG:
856 		msr = rdmsr(GCSC_GLPCI_CTRL);
857 		data = (0x00 << PCI_HDRTYPE_SHIFT) |
858 		    (((msr & 0xff00000000ULL) >> 32) << PCI_LATTIMER_SHIFT) |
859 		    (0x08 << PCI_CACHELINE_SHIFT);
860 		break;
861 	case PCI_MAPREG_START + 0x00:
862 		data = ehci_bar_value;
863 		if (data == 0xffffffff)
864 			data = PCI_MAPREG_MEM_ADDR_MASK & ~(ehci_bar_size - 1);
865 		else {
866 			msr = rdmsr(GCSC_USB_MSR_EHCB);
867 			data = msr & 0xffffff00;
868 		}
869 		if (data != 0)
870 			data |= PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT;
871 		break;
872 	case PCI_CAPLISTPTR_REG:
873 		data = 0x40;
874 		break;
875 	case PCI_INTERRUPT_REG:
876 		data = (0x40 << PCI_MAX_LAT_SHIFT) |
877 		    (PCI_INTERRUPT_PIN_A << PCI_INTERRUPT_PIN_SHIFT);
878 		break;
879 	case 0x40:	/* USB capability pointer */
880 		data = 0;
881 		break;
882 	case PCI_USBREV:
883 		msr = rdmsr(GCSC_USB_MSR_EHCB);
884 		data = PCI_USBREV_2_0;
885 		data |= ((msr >> 40) & 0x3f) << 8;	/* PCI_EHCI_FLADJ */
886 		break;
887 	default:
888 		data = 0;
889 		break;
890 	}
891 
892 	return data;
893 }
894 
895 void
896 glx_fn5_write(int reg, pcireg_t data)
897 {
898 	uint64_t msr;
899 
900 	switch (reg) {
901 	case PCI_COMMAND_STATUS_REG:
902 		msr = rdmsr(GCSC_USB_MSR_EHCB);
903 		if (data & PCI_COMMAND_MASTER_ENABLE)
904 			msr |= 1ULL << 34;
905 		else
906 			msr &= ~(1ULL << 34);
907 		if (data & PCI_COMMAND_MEM_ENABLE)
908 			msr |= 1ULL << 33;
909 		else
910 			msr &= ~(1ULL << 33);
911 		wrmsr(GCSC_USB_MSR_EHCB, msr);
912 		break;
913 	case PCI_BHLC_REG:
914 		msr = rdmsr(GCSC_GLPCI_CTRL);
915 		msr &= 0xff00000000ULL;
916 		msr |= ((uint64_t)PCI_LATTIMER(data)) << 32;
917 		break;
918 	case PCI_MAPREG_START + 0x00:
919 		if (data == 0xffffffff) {
920 			ehci_bar_value = data;
921 		} else {
922 			if ((data & PCI_MAPREG_TYPE_MASK) ==
923 			    PCI_MAPREG_TYPE_MEM) {
924 				data &= PCI_MAPREG_MEM_ADDR_MASK;
925 				msr = rdmsr(GCSC_GLIU_P2D_BM4);
926 				msr &= 0x0fffff0000000000ULL;
927 				msr |= 2ULL << 61;	/* USB */
928 				msr |= (((uint64_t)data) >> 12) << 20;
929 				msr |= 0x000fffff;
930 				wrmsr(GCSC_GLIU_P2D_BM4, msr);
931 
932 				msr = rdmsr(GCSC_USB_MSR_EHCB);
933 				msr &= ~0xffffff00ULL;
934 				msr |= data;
935 			} else {
936 				msr = rdmsr(GCSC_USB_MSR_EHCB);
937 				msr &= ~0xffffff00ULL;
938 			}
939 			wrmsr(GCSC_USB_MSR_EHCB, msr);
940 			ehci_bar_value = 0;
941 		}
942 		break;
943 	default:
944 		break;
945 	}
946 }
947