diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2009-12-25 22:11:09 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2009-12-25 22:11:09 +0000 |
commit | c8fc16bdb586df531725f3561028228475d80d4d (patch) | |
tree | 949932e0356f9d17eee51e1656de75ade4f91aed /sys/arch | |
parent | 7ac0ce90fe98c728d104ca49fd8b4745d3cf5a23 (diff) |
By popular demand and peer pressure, check-in work in progress work to support
the Yeelong Lemote mips-based netbook. Kernel bits only for now, needs
polishing; most of this work done during h2k9 last month, although the
porting effort started earlier this year.
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/loongson/dev/glx.c | 761 |
1 files changed, 761 insertions, 0 deletions
diff --git a/sys/arch/loongson/dev/glx.c b/sys/arch/loongson/dev/glx.c new file mode 100644 index 00000000000..ac56891fbce --- /dev/null +++ b/sys/arch/loongson/dev/glx.c @@ -0,0 +1,761 @@ +/* $OpenBSD: glx.c,v 1.1 2009/12/25 22:11:08 miod Exp $ */ + +/* + * Copyright (c) 2009 Miodrag Vallat. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * AMD CS5536 PCI Mess + * XXX too many hardcoded numbers... need to expand glxreg.h + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/bus.h> + +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcidevs.h> + +#include <dev/pci/pciidereg.h> +#include <dev/pci/pciide_amd_reg.h> +#include <dev/usb/ehcireg.h> +#include <dev/usb/ohcireg.h> + +#include <loongson/dev/glxreg.h> +#include <loongson/dev/glxvar.h> + +#include <loongson/dev/bonitovar.h> + +/* + * Since the purpose of this code is to present a different view of the + * PCI configuration space, it can not attach as a real device. + * (well it could, and then we'd have to attach a fake pci to it, + * and fake the configuration space accesses anyways - is it worth doing?) + * + * We just keep the `would-be softc' structure as global variables. + */ + +static pci_chipset_tag_t glxbase_pc; +static pcitag_t glxbase_tag; +static int glxbase_dev; + +/* MSR access through PCI configuration space */ +#define PCI_MSR_CTRL 0x00f0 +#define PCI_MSR_ADDR 0x00f4 +#define PCI_MSR_LO32 0x00f8 +#define PCI_MSR_HI32 0x00fc + +int glx_pci_read_hook(void *, pci_chipset_tag_t, pcitag_t, int, pcireg_t *); +int glx_pci_write_hook(void *, pci_chipset_tag_t, pcitag_t, int, pcireg_t); + +pcireg_t glx_get_status(void); +pcireg_t glx_fn0_read(int); +void glx_fn0_write(int, pcireg_t); +pcireg_t glx_fn2_read(int); +void glx_fn2_write(int, pcireg_t); +pcireg_t glx_fn3_read(int); +void glx_fn3_write(int, pcireg_t); +pcireg_t glx_fn4_read(int); +void glx_fn4_write(int, pcireg_t); +pcireg_t glx_fn5_read(int); +void glx_fn5_write(int, pcireg_t); +pcireg_t glx_fn6_read(int); +void glx_fn6_write(int, pcireg_t); +pcireg_t glx_fn7_read(int); +void glx_fn7_write(int, pcireg_t); + +void +glx_init(pci_chipset_tag_t pc, pcitag_t tag, int dev) +{ + uint64_t msr; + + glxbase_pc = pc; + glxbase_dev = dev; + glxbase_tag = tag; + + /* + * Register PCI configuration hooks to make the various + * embedded devices visible as PCI subfunctions. + */ + + bonito_pci_hook(pc, NULL, glx_pci_read_hook, glx_pci_write_hook); + + /* + * Perform some Geode intialization. + */ + msr = rdmsr(DIVIL_BALL_OPTS); /* 0x71 */ + wrmsr(DIVIL_BALL_OPTS, msr | 0x01); + + /* route usb interrupt */ + msr = rdmsr(PIC_YSEL_LOW); + msr &= ~(0xfUL << 8); + msr |= 11 << 8; + wrmsr(PIC_YSEL_LOW, msr); +} + +uint64_t +rdmsr(uint msr) +{ + uint64_t lo, hi; + + if (glxbase_tag == 0) + panic("rdmsr invoked before glx initialization"); + + pci_conf_write(glxbase_pc, glxbase_tag, PCI_MSR_ADDR, msr); + lo = (uint32_t)pci_conf_read(glxbase_pc, glxbase_tag, PCI_MSR_LO32); + hi = (uint32_t)pci_conf_read(glxbase_pc, glxbase_tag, PCI_MSR_HI32); + return (hi << 32) | lo; +} + +void +wrmsr(uint msr, uint64_t value) +{ + if (glxbase_tag == 0) + panic("rdmsr invoked before glx initialization"); + + pci_conf_write(glxbase_pc, glxbase_tag, PCI_MSR_ADDR, msr); + pci_conf_write(glxbase_pc, glxbase_tag, PCI_MSR_LO32, (uint32_t)value); + pci_conf_write(glxbase_pc, glxbase_tag, PCI_MSR_HI32, value >> 32); +} + +int +glx_pci_read_hook(void *v, pci_chipset_tag_t pc, pcitag_t tag, + int offset, pcireg_t *data) +{ + int bus, dev, fn; + + /* + * Do not get in the way of MSR programming + */ + if (tag == glxbase_tag && offset >= PCI_MSR_CTRL) + return 0; + + pci_decompose_tag(pc, tag, &bus, &dev, &fn); + if (bus != 0 || dev != glxbase_dev) + return 0; + + *data = 0; + + switch (fn) { + case 0: /* PCI-ISA bridge */ + *data = glx_fn0_read(offset); + break; + case 1: /* Flash memory */ + break; + case 2: /* IDE controller */ + *data = glx_fn2_read(offset); + break; + case 3: /* AC97 codec */ + break; + case 4: /* OHCI controller */ + *data = glx_fn4_read(offset); + break; + case 5: /* EHCI controller */ + *data = glx_fn5_read(offset); + break; + case 6: /* UDC */ + break; + case 7: /* OTG */ + break; + } + + return 1; +} + +int +glx_pci_write_hook(void *v, pci_chipset_tag_t pc, pcitag_t tag, + int offset, pcireg_t data) +{ + int bus, dev, fn; + + /* + * Do not get in the way of MSR programming + */ + if (tag == glxbase_tag && offset >= PCI_MSR_CTRL) + return 0; + + pci_decompose_tag(pc, tag, &bus, &dev, &fn); + if (bus != 0 || dev != glxbase_dev) + return 0; + + switch (fn) { + case 0: /* PCI-ISA bridge */ + glx_fn0_write(offset, data); + break; + case 1: /* Flash memory */ + break; + case 2: /* IDE controller */ + glx_fn2_write(offset, data); + break; + case 3: /* AC97 codec */ + break; + case 4: /* OHCI controller */ + glx_fn4_write(offset, data); + break; + case 5: /* EHCI controller */ + glx_fn5_write(offset, data); + break; + case 6: /* USB UDC */ + break; + case 7: /* USB OTG */ + break; + } + + return 1; +} + +pcireg_t +glx_get_status() +{ + uint64_t msr; + pcireg_t data; + + data = 0; + msr = rdmsr(GLPCI_GLD_MSR_ERROR); + if (msr & (1UL << 5)) + data |= PCI_COMMAND_PARITY_ENABLE; + data |= PCI_STATUS_66MHZ_SUPPORT | + PCI_STATUS_BACKTOBACK_SUPPORT | PCI_STATUS_DEVSEL_MEDIUM; + if (msr & (1UL << 21)) + data |= PCI_STATUS_PARITY_DETECT; + if (msr & (1UL << 20)) + data |= PCI_STATUS_TARGET_TARGET_ABORT; + if (msr & (1UL << 17)) + data |= PCI_STATUS_MASTER_TARGET_ABORT; + if (msr & (1UL << 16)) + data |= PCI_STATUS_MASTER_ABORT; + + return data; +} + +/* + * Function 0: PCI-ISA bridge + */ + +static pcireg_t pcib_bar_sizes[(4 + PCI_MAPREG_END - PCI_MAPREG_START) / 4] = { + 0x008, + 0x100, + 0x040, + 0x020, + 0x080, + 0x020 +}; + +static pcireg_t pcib_bar_values[(4 + PCI_MAPREG_END - PCI_MAPREG_START) / 4]; + +static uint64_t pcib_bar_msr[(4 + PCI_MAPREG_END - PCI_MAPREG_START) / 4] = { + DIVIL_LBAR_SMB, + DIVIL_LBAR_GPIO, + DIVIL_LBAR_MFGPT, + DIVIL_LBAR_IRQ, + DIVIL_LBAR_PMS, + DIVIL_LBAR_ACPI +}; + +pcireg_t +glx_fn0_read(int reg) +{ + uint64_t msr; + pcireg_t data; + int index; + + switch (reg) { + case PCI_ID_REG: + case PCI_SUBSYS_ID_REG: + data = PCI_ID_CODE(PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_PCIB); + break; + case PCI_COMMAND_STATUS_REG: + data = glx_get_status(); + data |= PCI_COMMAND_MASTER_ENABLE; + msr = rdmsr(DIVIL_LBAR_SMB); + if (msr & (1UL << 32)) + data |= PCI_COMMAND_IO_ENABLE; + break; + case PCI_CLASS_REG: + msr = rdmsr(GLCP_CHIP_REV_ID); + data = (PCI_CLASS_BRIDGE << PCI_CLASS_SHIFT) | + (PCI_SUBCLASS_BRIDGE_ISA << PCI_SUBCLASS_SHIFT) | + (msr & PCI_REVISION_MASK); + break; + case PCI_BHLC_REG: + msr = rdmsr(GLPCI_CTRL); + data = (0x80 << PCI_HDRTYPE_SHIFT) | + (((msr & 0xff00000000UL) >> 32) << PCI_LATTIMER_SHIFT) | + (0x08 << PCI_CACHELINE_SHIFT); + break; + case PCI_MAPREG_START + 0x00: + case PCI_MAPREG_START + 0x04: + case PCI_MAPREG_START + 0x08: + case PCI_MAPREG_START + 0x0c: + case PCI_MAPREG_START + 0x10: + case PCI_MAPREG_START + 0x14: + case PCI_MAPREG_START + 0x18: + index = (reg - PCI_MAPREG_START) / 4; + if (pcib_bar_msr[index] == 0) + data = 0; + else { + data = pcib_bar_values[index]; + if (data == 0xffffffff) + data = PCI_MAPREG_IO_ADDR_MASK & + ~(pcib_bar_sizes[index] - 1); + else { + msr = rdmsr(pcib_bar_msr[index]); + data = msr & 0xfffff000; + } + if (data != 0) + data |= PCI_MAPREG_TYPE_IO; + } + break; + case PCI_INTERRUPT_REG: + data = (0x40 << PCI_MAX_LAT_SHIFT) | + (PCI_INTERRUPT_PIN_NONE << PCI_INTERRUPT_PIN_SHIFT); + break; + default: + data = 0; + break; + } + + return data; +} + +void +glx_fn0_write(int reg, pcireg_t data) +{ + uint64_t msr; + int index; + + switch (reg) { + case PCI_COMMAND_STATUS_REG: + for (index = 0; index < nitems(pcib_bar_msr); index++) { + if (pcib_bar_msr[index] == 0) + continue; + msr = rdmsr(pcib_bar_msr[index]); + if (data & PCI_COMMAND_IO_ENABLE) + msr |= 1UL << 32; + else + msr &= ~(1UL << 32); + wrmsr(pcib_bar_msr[index], msr); + } + + msr = rdmsr(GLPCI_GLD_MSR_ERROR); + if (data & PCI_COMMAND_PARITY_ENABLE) + msr |= 1UL << 5; + else + msr &= ~(1UL << 5); + wrmsr(GLPCI_GLD_MSR_ERROR, msr); + break; + case PCI_BHLC_REG: + msr = rdmsr(GLPCI_CTRL); + msr &= 0xff00000000UL; + msr |= ((uint64_t)PCI_LATTIMER(data)) << 32; + break; + case PCI_MAPREG_START + 0x00: + case PCI_MAPREG_START + 0x04: + case PCI_MAPREG_START + 0x08: + case PCI_MAPREG_START + 0x0c: + case PCI_MAPREG_START + 0x10: + case PCI_MAPREG_START + 0x14: + case PCI_MAPREG_START + 0x18: + index = (reg - PCI_MAPREG_START) / 4; + if (data == 0xffffffff) { + pcib_bar_values[index] = data; + } else if (pcib_bar_msr[index] != 0) { + if ((data & PCI_MAPREG_TYPE_MASK) == + PCI_MAPREG_TYPE_IO) { + data &= PCI_MAPREG_IO_ADDR_MASK; + data &= 0xfffff000; + wrmsr(pcib_bar_msr[index], + (0x0000f000UL << 32) | (1UL << 32) | data); + } else { + wrmsr(pcib_bar_msr[index], 0UL); + } + pcib_bar_values[index] = 0; + } + break; + } +} + +/* + * Function 2: IDE Controller + */ + +static pcireg_t pciide_bar_size = 0x10; +static pcireg_t pciide_bar_value; + +pcireg_t +glx_fn2_read(int reg) +{ + uint64_t msr; + pcireg_t data; + + switch (reg) { + case PCI_ID_REG: + case PCI_SUBSYS_ID_REG: + data = PCI_ID_CODE(PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_IDE); + break; + case PCI_COMMAND_STATUS_REG: + data = glx_get_status(); + data |= PCI_COMMAND_IO_ENABLE; + msr = rdmsr(GLIU_PAE); + if ((msr & (0x3 << 4)) == 0x03) + data |= PCI_COMMAND_MASTER_ENABLE; + break; + case PCI_CLASS_REG: + msr = rdmsr(IDE_GLD_MSR_CAP); + data = (PCI_CLASS_MASS_STORAGE << PCI_CLASS_SHIFT) | + (PCI_SUBCLASS_MASS_STORAGE_IDE << PCI_SUBCLASS_SHIFT) | + (PCIIDE_INTERFACE_BUS_MASTER_DMA << PCI_INTERFACE_SHIFT) | + (msr & PCI_REVISION_MASK); + break; + case PCI_BHLC_REG: + msr = rdmsr(GLPCI_CTRL); + data = (0x00 << PCI_HDRTYPE_SHIFT) | + (((msr & 0xff00000000UL) >> 32) << PCI_LATTIMER_SHIFT) | + (0x08 << PCI_CACHELINE_SHIFT); + break; + case PCI_MAPREG_START + 0x10: + data = pciide_bar_value; + if (data == 0xffffffff) + data = PCI_MAPREG_IO_ADDR_MASK & ~(pciide_bar_size - 1); + else { + msr = rdmsr(IDE_IO_BAR); + data = msr & 0xfffffff0; + } + if (data != 0) + data |= PCI_MAPREG_TYPE_IO; + break; + case PCI_INTERRUPT_REG: + /* compat mode */ + data = (0x40 << PCI_MAX_LAT_SHIFT) | + (PCI_INTERRUPT_PIN_NONE << PCI_INTERRUPT_PIN_SHIFT); + break; + /* + * The following registers are used by pciide(4) + */ + case AMD756_CHANSTATUS_EN: + data = rdmsr(IDE_CFG); + break; + case AMD756_DATATIM: + data = rdmsr(IDE_DTC); + break; + case AMD756_UDMA: + data = rdmsr(IDE_ETC); + break; + default: + data = 0; + break; + } + + return data; +} + +void +glx_fn2_write(int reg, pcireg_t data) +{ + uint64_t msr; + + switch (reg) { + case PCI_COMMAND_STATUS_REG: + msr = rdmsr(GLIU_PAE); + if (data & PCI_COMMAND_MASTER_ENABLE) + msr |= 0x03 << 4; + else + msr &= ~(0x03 << 4); + wrmsr(GLIU_PAE, msr); + break; + case PCI_BHLC_REG: + msr = rdmsr(GLPCI_CTRL); + msr &= 0xff00000000UL; + msr |= ((uint64_t)PCI_LATTIMER(data)) << 32; + break; + case PCI_MAPREG_START + 0x10: + if (data == 0xffffffff) { + pciide_bar_value = data; + } else { + if ((data & PCI_MAPREG_TYPE_MASK) == + PCI_MAPREG_TYPE_IO) { + data &= PCI_MAPREG_IO_ADDR_MASK; + msr = (uint32_t)data & 0xfffffff0; + wrmsr(IDE_IO_BAR, msr); + } else { + wrmsr(IDE_IO_BAR, 0); + } + pciide_bar_value = 0; + } + break; + /* + * The following registers are used by pciide(4) + */ + case AMD756_CHANSTATUS_EN: + wrmsr(IDE_CFG, (uint32_t)data); + break; + case AMD756_DATATIM: + wrmsr(IDE_DTC, (uint32_t)data); + break; + case AMD756_UDMA: + wrmsr(IDE_ETC, (uint32_t)data); + break; + } +} + +/* + * Function 4: OHCI Controller + */ + +static pcireg_t ohci_bar_size = 0x1000; +static pcireg_t ohci_bar_value; + +pcireg_t +glx_fn4_read(int reg) +{ + uint64_t msr; + pcireg_t data; + + switch (reg) { + case PCI_ID_REG: + case PCI_SUBSYS_ID_REG: + data = PCI_ID_CODE(PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_OHCI); + break; + case PCI_COMMAND_STATUS_REG: + data = glx_get_status(); + msr = rdmsr(USB_MSR_OHCB); + if (msr & (1UL << 34)) + data |= PCI_COMMAND_MASTER_ENABLE; + if (msr & (1UL << 33)) + data |= PCI_COMMAND_MEM_ENABLE; + break; + case PCI_CLASS_REG: + msr = rdmsr(USB_GLD_MSR_CAP); + data = (PCI_CLASS_SERIALBUS << PCI_CLASS_SHIFT) | + (PCI_SUBCLASS_SERIALBUS_USB << PCI_SUBCLASS_SHIFT) | + (PCI_INTERFACE_OHCI << PCI_INTERFACE_SHIFT) | + (msr & PCI_REVISION_MASK); + break; + case PCI_BHLC_REG: + msr = rdmsr(GLPCI_CTRL); + data = (0x00 << PCI_HDRTYPE_SHIFT) | + (((msr & 0xff00000000UL) >> 32) << PCI_LATTIMER_SHIFT) | + (0x08 << PCI_CACHELINE_SHIFT); + break; + case PCI_MAPREG_START + 0x00: + data = ohci_bar_value; + if (data == 0xffffffff) + data = PCI_MAPREG_MEM_ADDR_MASK & ~(ohci_bar_size - 1); + else { + msr = rdmsr(USB_MSR_OHCB); + data = msr & 0xffffff00; + } + if (data != 0) + data |= PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT; + break; + case PCI_CAPLISTPTR_REG: + data = 0x40; + break; + case PCI_INTERRUPT_REG: + data = (0x40 << PCI_MAX_LAT_SHIFT) | + (PCI_INTERRUPT_PIN_A << PCI_INTERRUPT_PIN_SHIFT); + break; + case 0x40: /* USB capability pointer */ + data = 0; + break; + default: + data = 0; + break; + } + + return data; +} + +void +glx_fn4_write(int reg, pcireg_t data) +{ + uint64_t msr; + + switch (reg) { + case PCI_COMMAND_STATUS_REG: + msr = rdmsr(USB_MSR_OHCB); + if (data & PCI_COMMAND_MASTER_ENABLE) + msr |= 1UL << 34; + else + msr &= ~(1UL << 34); + if (data & PCI_COMMAND_MEM_ENABLE) + msr |= 1UL << 33; + else + msr &= ~(1UL << 33); + wrmsr(USB_MSR_OHCB, msr); + break; + case PCI_BHLC_REG: + msr = rdmsr(GLPCI_CTRL); + msr &= 0xff00000000UL; + msr |= ((uint64_t)PCI_LATTIMER(data)) << 32; + break; + case PCI_MAPREG_START + 0x00: + if (data == 0xffffffff) { + ohci_bar_value = data; + } else { + if ((data & PCI_MAPREG_TYPE_MASK) == + PCI_MAPREG_TYPE_MEM) { + data &= PCI_MAPREG_MEM_ADDR_MASK; + msr = rdmsr(GLIU_P2D_BM3); + msr &= 0x0fffff0000000000UL; + msr |= 2UL << 61; /* USB */ + msr |= (((uint64_t)data) >> 12) << 20; + msr |= 0x000fffff; + wrmsr(GLIU_P2D_BM3, msr); + + msr = rdmsr(USB_MSR_OHCB); + msr &= ~0xffffff00UL; + msr |= data; + } else { + msr = rdmsr(USB_MSR_OHCB); + msr &= ~0xffffff00UL; + } + wrmsr(USB_MSR_OHCB, msr); + ohci_bar_value = 0; + } + break; + default: + break; + } +} + +/* + * Function 5: EHCI Controller + */ + +static pcireg_t ehci_bar_size = 0x1000; +static pcireg_t ehci_bar_value; + +pcireg_t +glx_fn5_read(int reg) +{ + uint64_t msr; + pcireg_t data; + + switch (reg) { + case PCI_ID_REG: + case PCI_SUBSYS_ID_REG: + data = PCI_ID_CODE(PCI_VENDOR_AMD, PCI_PRODUCT_AMD_CS5536_EHCI); + break; + case PCI_COMMAND_STATUS_REG: + data = glx_get_status(); + msr = rdmsr(USB_MSR_EHCB); + if (msr & (1UL << 34)) + data |= PCI_COMMAND_MASTER_ENABLE; + if (msr & (1UL << 33)) + data |= PCI_COMMAND_MEM_ENABLE; + break; + case PCI_CLASS_REG: + msr = rdmsr(USB_GLD_MSR_CAP); + data = (PCI_CLASS_SERIALBUS << PCI_CLASS_SHIFT) | + (PCI_SUBCLASS_SERIALBUS_USB << PCI_SUBCLASS_SHIFT) | + (PCI_INTERFACE_EHCI << PCI_INTERFACE_SHIFT) | + (msr & PCI_REVISION_MASK); + break; + case PCI_BHLC_REG: + msr = rdmsr(GLPCI_CTRL); + data = (0x00 << PCI_HDRTYPE_SHIFT) | + (((msr & 0xff00000000UL) >> 32) << PCI_LATTIMER_SHIFT) | + (0x08 << PCI_CACHELINE_SHIFT); + break; + case PCI_MAPREG_START + 0x00: + data = ehci_bar_value; + if (data == 0xffffffff) + data = PCI_MAPREG_MEM_ADDR_MASK & ~(ehci_bar_size - 1); + else { + msr = rdmsr(USB_MSR_EHCB); + data = msr & 0xffffff00; + } + if (data != 0) + data |= PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT; + break; + case PCI_CAPLISTPTR_REG: + data = 0x40; + break; + case PCI_INTERRUPT_REG: + data = (0x40 << PCI_MAX_LAT_SHIFT) | + (PCI_INTERRUPT_PIN_A << PCI_INTERRUPT_PIN_SHIFT); + break; + case 0x40: /* USB capability pointer */ + data = 0; + break; + case PCI_USBREV: + msr = rdmsr(USB_MSR_EHCB); + data = PCI_USBREV_2_0; + data |= ((msr >> 40) & 0x3f) << 8; /* PCI_EHCI_FLADJ */ + break; + default: + data = 0; + break; + } + + return data; +} + +void +glx_fn5_write(int reg, pcireg_t data) +{ + uint64_t msr; + + switch (reg) { + case PCI_COMMAND_STATUS_REG: + msr = rdmsr(USB_MSR_EHCB); + if (data & PCI_COMMAND_MASTER_ENABLE) + msr |= 1UL << 34; + else + msr &= ~(1UL << 34); + if (data & PCI_COMMAND_MEM_ENABLE) + msr |= 1UL << 33; + else + msr &= ~(1UL << 33); + wrmsr(USB_MSR_EHCB, msr); + break; + case PCI_BHLC_REG: + msr = rdmsr(GLPCI_CTRL); + msr &= 0xff00000000UL; + msr |= ((uint64_t)PCI_LATTIMER(data)) << 32; + break; + case PCI_MAPREG_START + 0x00: + if (data == 0xffffffff) { + ehci_bar_value = data; + } else { + if ((data & PCI_MAPREG_TYPE_MASK) == + PCI_MAPREG_TYPE_MEM) { + data &= PCI_MAPREG_MEM_ADDR_MASK; + msr = rdmsr(GLIU_P2D_BM4); + msr &= 0x0fffff0000000000UL; + msr |= 2UL << 61; /* USB */ + msr |= (((uint64_t)data) >> 12) << 20; + msr |= 0x000fffff; + wrmsr(GLIU_P2D_BM4, msr); + + msr = rdmsr(USB_MSR_EHCB); + msr &= ~0xffffff00UL; + msr |= data; + } else { + msr = rdmsr(USB_MSR_EHCB); + msr &= ~0xffffff00UL; + } + wrmsr(USB_MSR_EHCB, msr); + ehci_bar_value = 0; + } + break; + default: + break; + } +} |