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