/* SPDX-License-Identifier: GPL-2.0-only */ /* * Include this file into a southbridge ASL block and it will * expose the W83977TF/EF SuperIO and some of its functionality. * * Adapted from winbond/w83627dhg. * * It allows the change of IO ports, IRQs and DMA settings on logical * devices, disabling and reenabling logical devices and controlling power * saving mode on logical devices or the whole chip. * * Controllable through preprocessor defines: * SUPERIO_PNP_BASE I/O address of the first PnP configuration register * SUPERIO_SHOW_UARTA If defined, UARTA will be exposed. * SUPERIO_SHOW_UARTB If defined, UARTB will be exposed. * SUPERIO_SHOW_FDC If defined, floppy controller will be exposed. * SUPERIO_SHOW_LPT If defined, parallel port will be exposed. */ #define SUPERIO_CHIP_NAME W83977TF #include #include /* Mutex for accesses to the configuration ports */ Mutex(CRMX, 1) /* SuperIO configuration ports */ OperationRegion (CREG, SystemIO, SUPERIO_PNP_BASE, 0x02) Field (CREG, ByteAcc, NoLock, Preserve) { PNP_ADDR_REG, 8, PNP_DATA_REG, 8 } IndexField (PNP_ADDR_REG, PNP_DATA_REG, ByteAcc, NoLock, Preserve) { Offset (0x07), PNP_LOGICAL_DEVICE, 8, /* Logical device selector */ Offset (0x20), DID, 8, /* Device ID: TF=0x97, EF=0x52 */ DREV, 8, /* Device revision */ FDPW, 1, , 2, PRPW, 1, UAPW, 1, /* UART A Power Down */ UBPW, 1, /* UART B Power Down */ Offset (0x23), IPD, 1, /* Immediate Chip Power Down */ Offset (0x30), PNP_DEVICE_ACTIVE, 8, Offset (0x60), PNP_IO0_HIGH_BYTE, 8, PNP_IO0_LOW_BYTE, 8, PNP_IO1_HIGH_BYTE, 8, PNP_IO1_LOW_BYTE, 8, PNP_IO2_HIGH_BYTE, 8, PNP_IO2_LOW_BYTE, 8, Offset (0x70), PNP_IRQ0, 8, Offset (0x72), PNP_IRQ1, 8, Offset (0x74), PNP_DMA0, 8, /* MSWK and KBWK are for ACPI logical device, LDN 0xA */ Offset (0xE0), MSWK, 8, Offset (0xE4), KBWK, 8, Offset (0xF0), OPT1, 8, OPT2, 8 } #define PNP_ENTER_MAGIC_1ST 0x87 #define PNP_ENTER_MAGIC_2ND 0x87 #define PNP_EXIT_MAGIC_1ST 0xaa #include /* PM: indicate IPD (Immediate Power Down) bit state as D0/D3 */ Method (_PSC) { ENTER_CONFIG_MODE (PNP_NO_LDN_CHANGE) Local0 = IPD EXIT_CONFIG_MODE () If (Local0) { Return (3) } Else { Return (0) } } #ifdef SUPERIO_SHOW_FDC Device (FDC0) { Name (_HID, EisaId ("PNP0700")) Method (_STA, 0, NotSerialized) { PNP_GENERIC_STA(W83977TF_FDC) } Method (_DIS, 0, NotSerialized) // _DIS: Disable Device { PNP_GENERIC_DIS(W83977TF_FDC) } Method (_CRS, 0) { Name (BUF0, ResourceTemplate () { IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04, IO0) IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01, IO1) IRQ (Edge, ActiveHigh, Exclusive, Y08) {6} DMA (Compatibility, NotBusMaster, Transfer8, Y09) {2} }) CreateWordField (BUF0, IO1._MIN, IO1I) CreateWordField (BUF0, IO1._MAX, IO1A) ENTER_CONFIG_MODE(W83977TF_FDC) /* OEM BIOS does not report actual programmed base port */ /* xx0 is read from superio */ PNP_READ_IO(PNP_IO0, BUF0, IO0) /* Store xx7 range first so the value isn't overwritten * for below */ IO1I += 7 IO1A = IO1I /* Store xx2 range */ IO0I += 2 IO0A = IO0I /* End OEM BIOS deficiency */ PNP_READ_IRQ(PNP_IRQ0, BUF0, Y08) PNP_READ_DMA(PNP_DMA0, BUF0, Y09) EXIT_CONFIG_MODE() Return (BUF0) } Name (_PRS, ResourceTemplate () { IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04, ) IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01, ) IRQ (Edge, ActiveHigh, Exclusive, ) {6} DMA (Compatibility, NotBusMaster, Transfer8, ) {2} }) Method (_SRS, 1, NotSerialized) { CreateByteField (Arg0, 0x02, IOLO) CreateByteField (Arg0, 0x03, IOHI) CreateWordField (Arg0, 0x11, IRQW) CreateByteField (Arg0, 0x15, DMAV) ENTER_CONFIG_MODE(W83977TF_FDC) /* FDC base port on 8-byte boundary. */ PNP_IO0_LOW_BYTE = IOLO & 0xF8 PNP_IO0_HIGH_BYTE = IOHI PNP_IRQ0 = FindSetLeftBit (IRQW) - 1 PNP_DMA0 = FindSetLeftBit (DMAV) - 1 PNP_DEVICE_ACTIVE = 1 EXIT_CONFIG_MODE() } } #endif #ifdef SUPERIO_SHOW_LPT /* Standard LPT Parallel Port */ Device (LPT) { Name (_HID, EisaId ("PNP0400")) Method (_STA, 0, NotSerialized) { ENTER_CONFIG_MODE(W83977TF_PP) Local0 = OPT1 & 0x02 If (IO0H || IO0L) { /* Report device not present if ECP is enabled */ If (Local0 == 0x02) { EXIT_CONFIG_MODE() Return (0x00) } ElseIf (PNP_DEVICE_ACTIVE) { EXIT_CONFIG_MODE() Return (0x0F) } Else { EXIT_CONFIG_MODE() Return (0x0D) } } EXIT_CONFIG_MODE() Return (0) } Method (_DIS, 0, NotSerialized) { PNP_GENERIC_DIS(W83977TF_PP) } Method (_CRS, 0, NotSerialized) { Name (BUF5, ResourceTemplate () { IO (Decode16,0x0378,0x0378,0x00,0x04,Y0A) IRQ (Edge, ActiveHigh, Exclusive, Y0B) {7} }) ENTER_CONFIG_MODE(W83977TF_PP) PNP_READ_IO(PNP_IO0,BUF5,Y0A) PNP_READ_IRQ(PNP_IRQ0,BUF5,Y0B) EXIT_CONFIG_MODE() Return (BUF5) } Name (_PRS, ResourceTemplate () { StartDependentFn (0x01, 0x01) { IO (Decode16,0x0378,0x0378,0x00,0x08,) IRQ (Edge, ActiveHigh, Exclusive, ) {5,7} } StartDependentFn (0x01, 0x01) { IO (Decode16,0x0278,0x0278,0x00,0x08,) IRQ (Edge, ActiveHigh, Exclusive, ) {5,7} } StartDependentFn (0x01, 0x01) { IO (Decode16,0x03BC,0x03BC,0x00,0x04,) IRQ (Edge, ActiveHigh, Exclusive, ) {5,7} } EndDependentFn () }) Method (_SRS, 1, NotSerialized) { CreateByteField (Arg0, 0x02, IOLO) CreateByteField (Arg0, 0x03, IOHI) CreateWordField (Arg0, 0x09, IRQW) ENTER_CONFIG_MODE(W83977TF_PP) PNP_IO0_LOW_BYTE = IOLO PNP_IO0_HIGH_BYTE = IOHI PNP_IRQ0 = FindSetLeftBit (IRQW) - 1 PNP_DEVICE_ACTIVE = 1 EXIT_CONFIG_MODE() } } /* ECP Parallel Port */ Device (ECP) { Name (_HID, EisaId ("PNP0401")) Method (_STA, 0, NotSerialized) { ENTER_CONFIG_MODE(W83977TF_PP) Local0 = OPT1 & 0x02 If (IO0H || IO0L) { If (Local0 == 0x02) { If (PNP_DEVICE_ACTIVE) { EXIT_CONFIG_MODE() Return (0x0F) } Else { EXIT_CONFIG_MODE() Return (0x05) } } } EXIT_CONFIG_MODE() Return (0x00) } Method (_DIS, 0, NotSerialized) { PNP_GENERIC_DIS(W83977TF_PP) } Method (_CRS, 0, NotSerialized) { Name (BUF6, ResourceTemplate () { IO (Decode16,0x0378,0x0378,0,4,IO0) IO (Decode16,0x0778,0x0778,0,4,IO1) IRQ (Edge, ActiveHigh, Exclusive, IR1) {7} DMA (Compatibility, NotBusMaster, Transfer8, Y0F) {1} }) ENTER_CONFIG_MODE(W83977TF_PP) PNP_READ_IO(PNP_IO0, BUF6, IO0) PNP_READ_IO(PNP_IO0, BUF6, IO1) PNP_READ_IRQ(PNP_IRQ0, BUF6, IR1) PNP_READ_DMA(PNP_DMA0, BUF6, Y0F) /* Report a second port range that is 0x400 above base port. */ CreateByteField (BUF6, 0x0B, I2HI) CreateByteField (BUF6, 0x0D, I2RH) I2RH = I2HI + 4 I2HI = I2HI + 4 EXIT_CONFIG_MODE() Return (BUF6) } Name (_PRS, ResourceTemplate () // _PRS: Possible Resource Settings { StartDependentFn (0x01, 0x01) { IO (Decode16,0x0378,0x0378,0,4,) IO (Decode16,0x0778,0x0778,0,4,) IRQ (Edge, ActiveHigh, Exclusive, ) {5,7} DMA (Compatibility, NotBusMaster, Transfer8, ) {0,1,3} } StartDependentFn (0x01, 0x01) { IO (Decode16,0x0278,0x0278,0,4,) IO (Decode16,0x0678,0x0678,0,4,) IRQ (Edge, ActiveHigh, Exclusive, ) {5,7} DMA (Compatibility, NotBusMaster, Transfer8, ) {0,1,3} } StartDependentFn (0x01, 0x01) { IO (Decode16,0x03BC,0x03BC,0,4,) IO (Decode16,0x07BC,0x07BC,0,4,) IRQ (Edge, ActiveHigh, Exclusive, ) {5,7} DMA (Compatibility, NotBusMaster, Transfer8, ) {0,1,3} } EndDependentFn () }) Method (_SRS, 1, NotSerialized) // _SRS: Set Resource Settings { CreateByteField (Arg0, 0x02, IOLO) CreateByteField (Arg0, 0x03, IOHI) CreateWordField (Arg0, 0x11, IRQW) CreateByteField (Arg0, 0x15, DMAC) ENTER_CONFIG_MODE(W83977TF_PP) PNP_IO0_LOW_BYTE = IOLO PNP_IO0_HIGH_BYTE = IOHI PNP_IRQ0 = FindSetLeftBit (IRQW) - 1 PNP_DMA0 = FindSetLeftBit (DMAC) - 1 PNP_DEVICE_ACTIVE = 1 EXIT_CONFIG_MODE() } } #endif #define SUPERIO_UART_PM_VAL 0 #define SUPERIO_UART_PM_LDN PNP_NO_LDN_CHANGE #ifdef SUPERIO_SHOW_UARTA #define SUPERIO_UART_LDN W83977TF_SP1 #define SUPERIO_UART_PM_REG UAPW #include #undef SUPERIO_UART_LDN #undef SUPERIO_UART_PM_REG #endif #ifdef SUPERIO_SHOW_UARTB #define SUPERIO_UART_LDN W83977TF_SP2 #define SUPERIO_UART_PM_REG UBPW #include #undef SUPERIO_UART_LDN #undef SUPERIO_UART_PM_REG #endif /* * TODO: IrDA device; * EF=LDN 3 aka UARTB * Some revisions of TF=LDN 6 */ #define SUPERIO_KBC_LDN W83977TF_KBC #define SUPERIO_KBC_PS2M /* Mouse shares same LDN */ #include