superio/smsc/sch5545: add support for SMSC SCH5545
The SMSC SCH5545 is very similar to the publicly available datasheet for the SCH5627. TEST=use PS2 keyboard and mouse, serial port, runtime registers and Embedded Memory Interface on Dell Optiplex 9010 Signed-off-by: Michał Żygowski <michal.zygowski@3mdeb.com> Change-Id: If8a60d5802675f09b08014ed583d2d8afa29fc04 Reviewed-on: https://review.coreboot.org/c/coreboot/+/40350 Reviewed-by: Felix Held <felix-coreboot@felixheld.de> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
6191b85f87
commit
fba08308f0
|
@ -16,3 +16,4 @@ subdirs-y += mec1308
|
|||
subdirs-y += smscsuperio
|
||||
subdirs-y += sio1036
|
||||
subdirs-y += sch4037
|
||||
subdirs-y += sch5545
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
## SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
config SUPERIO_SMSC_SCH5545
|
||||
bool
|
|
@ -0,0 +1,10 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
bootblock-$(CONFIG_SUPERIO_SMSC_SCH5545) += sch5545_early_init.c
|
||||
romstage-$(CONFIG_SUPERIO_SMSC_SCH5545) += sch5545_early_init.c
|
||||
|
||||
bootblock-$(CONFIG_SUPERIO_SMSC_SCH5545) += sch5545_emi.c
|
||||
romstage-$(CONFIG_SUPERIO_SMSC_SCH5545) += sch5545_emi.c
|
||||
ramstage-$(CONFIG_SUPERIO_SMSC_SCH5545) += sch5545_emi.c
|
||||
|
||||
ramstage-$(CONFIG_SUPERIO_SMSC_SCH5545) += superio.c
|
|
@ -0,0 +1,412 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
/* Helper package for determining IO, DMA, IRQ location according to LDN */
|
||||
Name (DCAT, Package (0x10) {
|
||||
0x07, /* UARTA */
|
||||
0x08, /* UARTB */
|
||||
0x11, /* LPT */
|
||||
0x0B, /* Floppy */
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF,
|
||||
One, /* KBC */
|
||||
0xFF,
|
||||
0xFF,
|
||||
0xFF,
|
||||
One, /* KBC */
|
||||
0xFF
|
||||
})
|
||||
|
||||
Method (CGLD, 1, NotSerialized)
|
||||
{
|
||||
Return (DerefOf (DCAT [Arg0]))
|
||||
}
|
||||
|
||||
/* Return Parallel port mode*/
|
||||
Method (LPTM, 1, NotSerialized)
|
||||
{
|
||||
ENTER_CONFIG_MODE (CGLD (Arg0))
|
||||
Local0 = (OPT0 & 0x02)
|
||||
EXIT_CONFIG_MODE ()
|
||||
Return (Local0)
|
||||
}
|
||||
|
||||
/* Device Status */
|
||||
Method (DSTA, 1, NotSerialized)
|
||||
{
|
||||
ENTER_CONFIG_MODE (CGLD (Arg0))
|
||||
Local0 = PNP_DEVICE_ACTIVE
|
||||
If (Local0 == 0xFF)
|
||||
{
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Local0 &= One
|
||||
If (Arg0 < 0x10)
|
||||
{
|
||||
IOST |= (Local0 << Arg0)
|
||||
}
|
||||
|
||||
If (Local0)
|
||||
{
|
||||
Return (DEVICE_PRESENT_ACTIVE)
|
||||
}
|
||||
ElseIf ((One << Arg0) & IOST)
|
||||
{
|
||||
Return (DEVICE_PRESENT_INACTIVE)
|
||||
}
|
||||
Else
|
||||
{
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
EXIT_CONFIG_MODE ()
|
||||
}
|
||||
|
||||
Method (DCNT, 2, NotSerialized)
|
||||
{
|
||||
ENTER_CONFIG_MODE (CGLD (Arg0))
|
||||
PNP_DEVICE_ACTIVE = Arg1
|
||||
EXIT_CONFIG_MODE ()
|
||||
}
|
||||
|
||||
/* Resource templates for SIO LDNs */
|
||||
Name (CRS1, ResourceTemplate ()
|
||||
{
|
||||
IO (Decode16,
|
||||
0x0000,
|
||||
0x0000,
|
||||
0x01,
|
||||
0x00,
|
||||
_Y16)
|
||||
IRQ (Edge, ActiveHigh, Exclusive, _Y14) {}
|
||||
DMA (Compatibility, NotBusMaster, Transfer8, _Y15) {}
|
||||
})
|
||||
|
||||
CreateWordField (CRS1, \_SB.PCI0.LPCB.SIO1._Y14._INT, IRQM)
|
||||
CreateByteField (CRS1, \_SB.PCI0.LPCB.SIO1._Y15._DMA, DMAM)
|
||||
CreateWordField (CRS1, \_SB.PCI0.LPCB.SIO1._Y16._MIN, IO11)
|
||||
CreateWordField (CRS1, \_SB.PCI0.LPCB.SIO1._Y16._MAX, IO12)
|
||||
CreateByteField (CRS1, \_SB.PCI0.LPCB.SIO1._Y16._LEN, LEN1)
|
||||
|
||||
Name (CRS2, ResourceTemplate ()
|
||||
{
|
||||
IO (Decode16,
|
||||
0x0000,
|
||||
0x0000,
|
||||
0x01,
|
||||
0x00,
|
||||
_Y19)
|
||||
IO (Decode16,
|
||||
0x0000,
|
||||
0x0000,
|
||||
0x01,
|
||||
0x00,
|
||||
_Y1A)
|
||||
IRQ (Edge, ActiveHigh, Exclusive, _Y17) {}
|
||||
DMA (Compatibility, NotBusMaster, Transfer8, _Y18) {}
|
||||
})
|
||||
|
||||
CreateWordField (CRS2, \_SB.PCI0.LPCB.SIO1._Y17._INT, IRQE)
|
||||
CreateByteField (CRS2, \_SB.PCI0.LPCB.SIO1._Y18._DMA, DMAE)
|
||||
CreateWordField (CRS2, \_SB.PCI0.LPCB.SIO1._Y19._MIN, IO21)
|
||||
CreateWordField (CRS2, \_SB.PCI0.LPCB.SIO1._Y19._MAX, IO22)
|
||||
CreateByteField (CRS2, \_SB.PCI0.LPCB.SIO1._Y19._LEN, LEN2)
|
||||
CreateWordField (CRS2, \_SB.PCI0.LPCB.SIO1._Y1A._MIN, IO31)
|
||||
CreateWordField (CRS2, \_SB.PCI0.LPCB.SIO1._Y1A._MAX, IO32)
|
||||
CreateByteField (CRS2, \_SB.PCI0.LPCB.SIO1._Y1A._LEN, LEN3)
|
||||
|
||||
/* Read IO resource */
|
||||
Method (GIOB, 1, NotSerialized)
|
||||
{
|
||||
If (CGLD (Arg0) == 0x07) /* UARTA */
|
||||
{
|
||||
SWITCH_LDN (SUPERIO_LPC_LDN)
|
||||
Local0 = (CR6B << 0x08)
|
||||
Local0 |= CR6A
|
||||
Return (Local0)
|
||||
}
|
||||
|
||||
If (CGLD (Arg0) == 0x08) /* UARTB */
|
||||
{
|
||||
SWITCH_LDN (SUPERIO_LPC_LDN)
|
||||
Local0 = (CR6F << 0x08)
|
||||
Local0 |= CR6E
|
||||
Return (Local0)
|
||||
}
|
||||
|
||||
If (CGLD (Arg0) == 0x11) /* LPT */
|
||||
{
|
||||
SWITCH_LDN (SUPERIO_LPC_LDN)
|
||||
Local0 = (CR83 << 0x08)
|
||||
Local0 |= CR82
|
||||
Return (Local0)
|
||||
}
|
||||
|
||||
If (CGLD (Arg0) == 0x0B) /* Floppy */
|
||||
{
|
||||
SWITCH_LDN (SUPERIO_LPC_LDN)
|
||||
Local0 = (CR7F << 0x08)
|
||||
Local0 |= CR7E
|
||||
Return (Local0)
|
||||
}
|
||||
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
/* Read IRQ resource */
|
||||
Method (GIRQ, 1, NotSerialized)
|
||||
{
|
||||
SWITCH_LDN (SUPERIO_LPC_LDN)
|
||||
Local0 = 0x0F /* 15 IRQ regs, 1 for each IRQ number */
|
||||
While (Local0)
|
||||
{
|
||||
Local1 = (0x40 + Local0) /* IRQ regs begin at offset 0x40 */
|
||||
PNP_ADDR_REG = Local1
|
||||
Local1 = PNP_DATA_REG
|
||||
If (CGLD (Arg0) == Local1)
|
||||
{
|
||||
Local1 = One
|
||||
Local0 = (Local1 << Local0)
|
||||
Return (Local0)
|
||||
}
|
||||
|
||||
Local0--
|
||||
}
|
||||
|
||||
Return (0xFF)
|
||||
}
|
||||
|
||||
/* Read DMA resource */
|
||||
Method (GDMA, 1, NotSerialized)
|
||||
{
|
||||
SWITCH_LDN (SUPERIO_LPC_LDN)
|
||||
Local0 = 0x03 /* Only DMA Channels 0-3 */
|
||||
While (Local0)
|
||||
{
|
||||
Local1 = (Local0 << One)
|
||||
Local1 += 0x51 /* DMA regs begin at offset 0x50 */
|
||||
PNP_ADDR_REG = Local1
|
||||
Local1 = PNP_DATA_REG
|
||||
If ((0x80 | CGLD (Arg0)) == Local1)
|
||||
{
|
||||
Local1 = One
|
||||
Local0 = (Local1 << Local0)
|
||||
Return (Local0)
|
||||
}
|
||||
|
||||
Local0--
|
||||
}
|
||||
|
||||
Return (0xFF)
|
||||
}
|
||||
|
||||
/* Set IO resource */
|
||||
Method (STIO, 2, NotSerialized)
|
||||
{
|
||||
SWITCH_LDN (SUPERIO_LPC_LDN)
|
||||
Local0 = (Arg1 & 0xFF)
|
||||
PNP_ADDR_REG = Arg0
|
||||
PNP_DATA_REG = Local0
|
||||
Local0 = (Arg1 >> 0x08)
|
||||
Local1 = (Arg0 + One)
|
||||
PNP_ADDR_REG = Local1
|
||||
PNP_DATA_REG = Local0
|
||||
}
|
||||
|
||||
/* Set IRQ resource */
|
||||
Method (SIRQ, 2, NotSerialized)
|
||||
{
|
||||
SWITCH_LDN (SUPERIO_LPC_LDN)
|
||||
FindSetRightBit (Arg1, Local0)
|
||||
Local0 -= One
|
||||
Local1 = 0x0F
|
||||
While (Local1)
|
||||
{
|
||||
Local2 = (0x40 + Local1)
|
||||
PNP_ADDR_REG = Local2
|
||||
Local3 = PNP_DATA_REG
|
||||
If (CGLD (Arg0) == Local3)
|
||||
{
|
||||
If (Local0 != Local1)
|
||||
{
|
||||
PNP_ADDR_REG = Local2
|
||||
PNP_DATA_REG = 0xFF
|
||||
Break
|
||||
}
|
||||
Else
|
||||
{
|
||||
Return (Zero)
|
||||
}
|
||||
}
|
||||
|
||||
Local1--
|
||||
}
|
||||
|
||||
Local0 += 0x40
|
||||
PNP_ADDR_REG = Local0
|
||||
PNP_DATA_REG = CGLD (Arg0)
|
||||
Return (0xFF)
|
||||
}
|
||||
|
||||
/* Set DMA resource */
|
||||
Method (SDMA, 2, NotSerialized)
|
||||
{
|
||||
SWITCH_LDN (SUPERIO_LPC_LDN)
|
||||
FindSetRightBit (Arg1, Local0)
|
||||
Local0 -= One
|
||||
Local1 = 0x03
|
||||
While (Local1)
|
||||
{
|
||||
Local2 = (Local1 << One)
|
||||
Local3 = (0x51 + Local2)
|
||||
PNP_ADDR_REG = Local3
|
||||
Local4 = PNP_DATA_REG
|
||||
If ((0x80 | CGLD (Arg0)) == Local4)
|
||||
{
|
||||
If (Local0 != Local1)
|
||||
{
|
||||
PNP_ADDR_REG = Local3
|
||||
PNP_DATA_REG = Zero
|
||||
Break
|
||||
}
|
||||
Else
|
||||
{
|
||||
Return (Zero)
|
||||
}
|
||||
}
|
||||
|
||||
Local1--
|
||||
}
|
||||
|
||||
Local0 <<= One
|
||||
Local0 += 0x51
|
||||
PNP_ADDR_REG = Local0
|
||||
PNP_DATA_REG = (0x80 | CGLD (Arg0))
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
/* Device Current Resource Settings */
|
||||
Method (DCRS, 2, NotSerialized)
|
||||
{
|
||||
If (CGLD (Arg0) == 0x07) /* UARTA resources */
|
||||
{
|
||||
ENTER_CONFIG_MODE (SUPERIO_LPC_LDN)
|
||||
IO11 = GIOB (Arg0)
|
||||
IO12 = IO11
|
||||
LEN1 = 0x08
|
||||
IRQM = GIRQ (Arg0)
|
||||
If ((GDMA (Arg0) > 0x03) || (Arg1 == Zero))
|
||||
{
|
||||
DMAM = Zero
|
||||
}
|
||||
Else
|
||||
{
|
||||
DMAM = GDMA (Arg0)
|
||||
}
|
||||
|
||||
EXIT_CONFIG_MODE ()
|
||||
Return (CRS1)
|
||||
}
|
||||
|
||||
If (CGLD (Arg0) == 0x08) /* UARTB resources */
|
||||
{
|
||||
ENTER_CONFIG_MODE (SUPERIO_LPC_LDN)
|
||||
IO11 = GIOB (Arg0)
|
||||
IO12 = IO11
|
||||
LEN1 = 0x08
|
||||
IRQM = GIRQ (Arg0)
|
||||
If ((GDMA (Arg0) > 0x03) || (Arg1 == Zero))
|
||||
{
|
||||
DMAM = Zero
|
||||
}
|
||||
Else
|
||||
{
|
||||
DMAM = GDMA (Arg0)
|
||||
}
|
||||
|
||||
EXIT_CONFIG_MODE ()
|
||||
Return (CRS1)
|
||||
}
|
||||
|
||||
If (CGLD (Arg0) == 0x11) /* LPT resources */
|
||||
{
|
||||
If (LPTM (Arg0))
|
||||
{
|
||||
ENTER_CONFIG_MODE (SUPERIO_LPC_LDN)
|
||||
IO21 = GIOB (Arg0)
|
||||
IO22 = IO21
|
||||
IO31 = (IO21 + 0x0400)
|
||||
IO32 = IO31
|
||||
If ((IO21 & 0xFF) == 0xBC)
|
||||
{
|
||||
LEN2 = 0x04
|
||||
LEN3 = 0x04
|
||||
}
|
||||
Else
|
||||
{
|
||||
LEN2 = 0x08
|
||||
LEN3 = 0x04
|
||||
}
|
||||
|
||||
IRQE = GIRQ (Arg0)
|
||||
If ((GDMA (Arg0) > 0x03) || (Arg1 == Zero))
|
||||
{
|
||||
DMAM = Zero
|
||||
}
|
||||
Else
|
||||
{
|
||||
DMAE = GDMA (Arg0)
|
||||
}
|
||||
|
||||
EXIT_CONFIG_MODE ()
|
||||
Return (CRS2) /* \_SB_.PCI0.LPCB.SIO1.CRS2 */
|
||||
}
|
||||
Else
|
||||
{
|
||||
ENTER_CONFIG_MODE (SUPERIO_LPC_LDN)
|
||||
IO11 = GIOB (Arg0)
|
||||
IO12 = IO11 /* \_SB_.PCI0.LPCB.SIO1.IO11 */
|
||||
If ((IO11 & 0xFF) == 0xBC)
|
||||
{
|
||||
LEN1 = 0x04
|
||||
}
|
||||
Else
|
||||
{
|
||||
LEN1 = 0x08
|
||||
}
|
||||
|
||||
IRQM = GIRQ (Arg0)
|
||||
EXIT_CONFIG_MODE ()
|
||||
Return (CRS1) /* \_SB_.PCI0.LPCB.SIO1.CRS1 */
|
||||
}
|
||||
}
|
||||
|
||||
If (CGLD (Arg0) == 0x0B) /* Floppy resources */
|
||||
{
|
||||
ENTER_CONFIG_MODE (SUPERIO_LPC_LDN)
|
||||
IO21 = GIOB (Arg0)
|
||||
IO22 = IO21 /* \_SB_.PCI0.LPCB.SIO1.IO21 */
|
||||
LEN2 = 0x06
|
||||
IO31 = (IO21 + 0x07)
|
||||
IO32 = IO31 /* \_SB_.PCI0.LPCB.SIO1.IO31 */
|
||||
LEN3 = One
|
||||
IRQE = GIRQ (Arg0)
|
||||
If ((GDMA (Arg0) > 0x03) || (Arg1 == Zero))
|
||||
{
|
||||
DMAM = Zero
|
||||
}
|
||||
Else
|
||||
{
|
||||
DMAE = GDMA (Arg0)
|
||||
}
|
||||
|
||||
EXIT_CONFIG_MODE ()
|
||||
Return (CRS2) /* \_SB_.PCI0.LPCB.SIO1.CRS2 */
|
||||
}
|
||||
|
||||
Return (CRS1) /* \_SB_.PCI0.LPCB.SIO1.CRS1 */
|
||||
}
|
|
@ -0,0 +1,589 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
/*
|
||||
* Include this file into a mainboard's DSDT _SB device tree and it will
|
||||
* expose the SCH5545 SuperIO and some of its functionality.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* LDN State
|
||||
* 0x0 FDC Not implemented
|
||||
* 0x3 PP Not implemented
|
||||
* 0x4 UARTA Implemented and tested
|
||||
* 0x5 UARTB Implemented
|
||||
* 0x7 KBC Implemented and tested
|
||||
*
|
||||
* Controllable through preprocessor defines:
|
||||
* SUPERIO_PNP_BASE I/O address of the first PnP configuration register
|
||||
* SCH5545_SHOW_UARTA If defined, UARTA will be exposed.
|
||||
* SCH5545_SHOW_UARTB If defined, UARTB will be exposed.
|
||||
* SCH5545_SHOW_KBC If defined, the KBC will be exposed.
|
||||
* SCH5545_EMI_BASE If defined, the Embedded Memory Interface resource will be exposed.
|
||||
* SCH5545_RUNTIME_BASE If defined, The Runtime Registers resource will be exposed.
|
||||
*/
|
||||
|
||||
#undef SUPERIO_CHIP_NAME
|
||||
#define SUPERIO_CHIP_NAME SCH5545
|
||||
#include <superio/acpi/pnp.asl>
|
||||
|
||||
#undef PNP_DEFAULT_PSC
|
||||
#define PNP_DEFAULT_PSC Return (0) /* no power management */
|
||||
|
||||
/*
|
||||
* Common helpers will not work on this chip. IO, DMA and IRQ resources.
|
||||
* These are accessed via LPC interface LDN 0xC.
|
||||
*/
|
||||
#undef PNP_READ_IO
|
||||
#undef PNP_READ_IRQ
|
||||
#undef PNP_READ_DMA
|
||||
#undef PNP_WRITE_IO
|
||||
#undef PNP_WRITE_IRQ
|
||||
#undef PNP_WRITE_DMA
|
||||
|
||||
Device(SIO1) {
|
||||
Name (_HID, EisaId("PNP0A05"))
|
||||
Name (_STR, Unicode("SMSC SCH5545 Super I/O"))
|
||||
Name (_UID, SUPERIO_UID(SIO1,))
|
||||
|
||||
#ifdef SCH5545_EMI_BASE
|
||||
Name (IO1B, SCH5545_EMI_BASE)
|
||||
#endif
|
||||
#ifdef SCH5545_RUNTIME_BASE
|
||||
Name (IO2B, SCH5545_RUNTIME_BASE)
|
||||
#endif
|
||||
Name (IOST, 0x0001) /* IO decoding status */
|
||||
Name (MSFG, One) /* Mouse wake config */
|
||||
Name (KBFG, One) /* Keyboard wake config */
|
||||
Name (PMFG, Zero) /* Wake config */
|
||||
|
||||
/* 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 (0x30),
|
||||
PNP_DEVICE_ACTIVE, 1, /* Logical device activation */
|
||||
|
||||
Offset (0x69),
|
||||
CR69, 8, /* UART1 Base address Registers */
|
||||
CR6A, 8,
|
||||
CR6B, 8,
|
||||
Offset (0x6D),
|
||||
CR6D, 8, /* UART2 Base address Registers */
|
||||
CR6E, 8,
|
||||
CR6F, 8,
|
||||
Offset (0x7D),
|
||||
CR7D, 8, /* FD Base address Registers */
|
||||
CR7E, 8,
|
||||
CR7F, 8,
|
||||
Offset (0x81),
|
||||
CR81, 8, /* LPT Base address Registers */
|
||||
CR82, 8,
|
||||
CR83, 8,
|
||||
Offset (0xF0),
|
||||
OPT0, 8, /* MISC registers */
|
||||
OPT1, 8,
|
||||
OPT2, 8,
|
||||
OPT3, 8,
|
||||
OPT4, 8,
|
||||
OPT5, 8
|
||||
}
|
||||
|
||||
#ifdef SCH5545_RUNTIME_BASE
|
||||
/* Runtime registers */
|
||||
OperationRegion (RNTR, SystemIO, SCH5545_RUNTIME_BASE, 0x40)
|
||||
Field (RNTR, ByteAcc, NoLock, Preserve)
|
||||
{
|
||||
PMES, 1, /* PME Global Status */
|
||||
Offset (0x01),
|
||||
PMEN, 1, /* PME Global Enable */
|
||||
Offset (0x02),
|
||||
PMS1, 8, /* PME Status 1 for KBD and PS2M */
|
||||
PMS2, 8, /* PME Status 2 for EC, WDT, Bat, Intruder */
|
||||
PMS3, 8, /* PME Status 3 for GPIOs */
|
||||
PME1, 8, /* PME Enable 1 for KBD and PS2M */
|
||||
PME2, 8, /* PME Enable 2 for EC, WDT, Bat, Intruder */
|
||||
PME3, 8, /* PME Enable 3 for GPIOs */
|
||||
Offset (0x10),
|
||||
SOIS, 1, /* SMI Global Status*/
|
||||
Offset (0x11),
|
||||
SOIE, 1, /* SMI Global Enable */
|
||||
Offset (0x12),
|
||||
SST1, 8, /* SMI Status 1 for UARTs, LPT, FD, EC, Bat */
|
||||
SST2, 8, /* SMI Status 2 for KBD, PS2M, WDT, Intruder */
|
||||
SST3, 8, /* SMI Status 3 for GPIOs */
|
||||
Offset (0x16),
|
||||
SEN1, 8, /* SMI Enable 1 for UARTs, LPT, FD, EC, Bat */
|
||||
SEN2, 8, /* SMI Enable 2 for KBD, PS2M, WDT, Intruder */
|
||||
SEN3, 8, /* SMI Enable 3 for GPIOs */
|
||||
Offset (0x25),
|
||||
LED1, 8, /* LED control register */
|
||||
Offset (0x28),
|
||||
GPSR, 8, /* GPIO Select Register */
|
||||
GPRR, 8 /* GPIO Read Register */
|
||||
}
|
||||
#endif
|
||||
Name (CRS, ResourceTemplate ()
|
||||
{
|
||||
IO (Decode16,
|
||||
0x0000,
|
||||
0x0000,
|
||||
0x00,
|
||||
0x00,
|
||||
_Y11)
|
||||
#ifdef SCH5545_EMI_BASE
|
||||
IO (Decode16,
|
||||
0x0000,
|
||||
0x0000,
|
||||
0x00,
|
||||
0x00,
|
||||
_Y12)
|
||||
#endif
|
||||
#ifdef SCH5545_RUNTIME_BASE
|
||||
IO (Decode16,
|
||||
0x0000,
|
||||
0x0000,
|
||||
0x00,
|
||||
0x00,
|
||||
_Y13)
|
||||
#endif
|
||||
})
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
If (SUPERIO_PNP_BASE)
|
||||
{
|
||||
CreateWordField (CRS, \_SB.PCI0.LPCB.SIO1._Y11._MIN, GPI0)
|
||||
CreateWordField (CRS, \_SB.PCI0.LPCB.SIO1._Y11._MAX, GPI1)
|
||||
CreateByteField (CRS, \_SB.PCI0.LPCB.SIO1._Y11._LEN, GPIL)
|
||||
GPI0 = SUPERIO_PNP_BASE
|
||||
GPI1 = SUPERIO_PNP_BASE
|
||||
GPIL = 0x02
|
||||
}
|
||||
#ifdef SCH5545_EMI_BASE
|
||||
If (IO1B)
|
||||
{
|
||||
CreateWordField (CRS, \_SB.PCI0.LPCB.SIO1._Y12._MIN, GP10)
|
||||
CreateWordField (CRS, \_SB.PCI0.LPCB.SIO1._Y12._MAX, GP11)
|
||||
CreateByteField (CRS, \_SB.PCI0.LPCB.SIO1._Y12._LEN, GPL1)
|
||||
GP10 = SCH5545_EMI_BASE
|
||||
GP11 = SCH5545_EMI_BASE
|
||||
GPL1 = 0x10
|
||||
}
|
||||
#endif
|
||||
#ifdef SCH5545_RUNTIME_BASE
|
||||
If (IO2B)
|
||||
{
|
||||
CreateWordField (CRS, \_SB.PCI0.LPCB.SIO1._Y13._MIN, GP20)
|
||||
CreateWordField (CRS, \_SB.PCI0.LPCB.SIO1._Y13._MAX, GP21)
|
||||
CreateByteField (CRS, \_SB.PCI0.LPCB.SIO1._Y13._LEN, GPL2)
|
||||
GP20 = SCH5545_RUNTIME_BASE
|
||||
GP21 = SCH5545_RUNTIME_BASE
|
||||
GPL2 = 0x40
|
||||
}
|
||||
#endif
|
||||
Return (CRS)
|
||||
}
|
||||
|
||||
#undef PNP_ENTER_MAGIC_1ST
|
||||
#undef PNP_ENTER_MAGIC_2ND
|
||||
#undef PNP_ENTER_MAGIC_3RD
|
||||
#undef PNP_ENTER_MAGIC_4TH
|
||||
#undef PNP_EXIT_MAGIC_1ST
|
||||
#undef PNP_EXIT_SPECIAL_REG
|
||||
#undef PNP_EXIT_SPECIAL_VAL
|
||||
#define PNP_ENTER_MAGIC_1ST 0x55
|
||||
#define PNP_EXIT_MAGIC_1ST 0xaa
|
||||
#include <superio/acpi/pnp_config.asl>
|
||||
#define SUPERIO_LPC_LDN 0x0C
|
||||
#include "resource_helpers.asl"
|
||||
|
||||
#ifdef SCH5545_SHOW_KBC
|
||||
Device (PS2K)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0303"))
|
||||
Name (_CID, EisaId ("PNP030B"))
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Return (DSTA (0xa))
|
||||
}
|
||||
|
||||
Name (_CRS, ResourceTemplate ()
|
||||
{
|
||||
IO (Decode16,
|
||||
0x0060,
|
||||
0x0060,
|
||||
0x00,
|
||||
0x01,
|
||||
)
|
||||
IO (Decode16,
|
||||
0x0064,
|
||||
0x0064,
|
||||
0x00,
|
||||
0x01,
|
||||
)
|
||||
IRQ (Edge, ActiveHigh, Exclusive) {1}
|
||||
})
|
||||
Name (_PRS, ResourceTemplate ()
|
||||
{
|
||||
StartDependentFn (0x00, 0x00)
|
||||
{
|
||||
FixedIO (
|
||||
0x0060, // Address
|
||||
0x01,
|
||||
)
|
||||
FixedIO (
|
||||
0x0064, // Address
|
||||
0x01,
|
||||
)
|
||||
IRQ (Edge, ActiveHigh, Exclusive) {1}
|
||||
}
|
||||
EndDependentFn ()
|
||||
})
|
||||
Method (_PSW, 1, NotSerialized) // _PSW: Power State Wake
|
||||
{
|
||||
KBFG = Arg0
|
||||
}
|
||||
Name (_PRW, Package() { 8, 3 })
|
||||
}
|
||||
|
||||
Device (PS2M)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0F13"))
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Return (DSTA (0xe))
|
||||
}
|
||||
|
||||
Name (_CRS, ResourceTemplate ()
|
||||
{
|
||||
IRQ (Edge, ActiveHigh, Exclusive) {12}
|
||||
})
|
||||
|
||||
Name (_PRS, ResourceTemplate ()
|
||||
{
|
||||
StartDependentFn (0x00, 0x00)
|
||||
{
|
||||
IRQ (Edge, ActiveHigh, Exclusive) {12}
|
||||
}
|
||||
EndDependentFn ()
|
||||
})
|
||||
|
||||
Method (_PSW, 1, NotSerialized)
|
||||
{
|
||||
MSFG = Arg0
|
||||
}
|
||||
|
||||
Name (_PRW, Package() { 8, 3 })
|
||||
}
|
||||
|
||||
OperationRegion (IOKP, SystemIO, 0x60, 0x05)
|
||||
Field (IOKP, ByteAcc, NoLock, Preserve)
|
||||
{
|
||||
KP60, 8,
|
||||
Offset (0x04),
|
||||
KP64, 8
|
||||
}
|
||||
|
||||
OperationRegion (KB64, SystemIO, 0x64, One)
|
||||
Field (KB64, ByteAcc, NoLock, Preserve)
|
||||
{
|
||||
, 1,
|
||||
KRDY, 1,
|
||||
Offset (0x01)
|
||||
}
|
||||
#ifdef SCH5545_RUNTIME_BASE
|
||||
/* SIO prepare to sleep */
|
||||
Method (SIOS, 1, NotSerialized)
|
||||
{
|
||||
If ((Arg0 == 0x03) | (Arg0 == One))
|
||||
{
|
||||
ENTER_CONFIG_MODE (One)
|
||||
Local0 = OPT0
|
||||
OPT0 = (Local0 | 0x60)
|
||||
EXIT_CONFIG_MODE ()
|
||||
Local0 = PMS1
|
||||
PMS1 = (Local0 | 0x18)
|
||||
Local0 = PMES
|
||||
PMES = (Local0 | One)
|
||||
|
||||
Local0 = PME1
|
||||
If (KBFG)
|
||||
{
|
||||
PME1 = (Local0 | 0x08)
|
||||
}
|
||||
Else
|
||||
{
|
||||
PME1 = (Local0 & 0xF7)
|
||||
}
|
||||
|
||||
Local0 = PME1
|
||||
If (MSFG)
|
||||
{
|
||||
PME1 = (Local0 | 0x10)
|
||||
}
|
||||
Else
|
||||
{
|
||||
PME1 = (Local0 & 0xEF)
|
||||
}
|
||||
|
||||
Local0 = PMEN
|
||||
PMEN = (Local0 | One)
|
||||
|
||||
While (KRDY) {}
|
||||
KP60 = 0xED
|
||||
While (KRDY) {}
|
||||
KP60 = Zero
|
||||
While (KRDY) {}
|
||||
KP60 = 0xF4
|
||||
Sleep (One)
|
||||
}
|
||||
}
|
||||
|
||||
Method (GPKM, 0, NotSerialized)
|
||||
{
|
||||
Local0 = PME1
|
||||
PME1 = (Local0 & 0xE7)
|
||||
Local0 = PMEN
|
||||
PMEN = (Local0 & 0xFE)
|
||||
Local0 = PMS1
|
||||
PMS1 = (Local0 & 0x18)
|
||||
Local0 = PMES
|
||||
PMES = (Local0 & One)
|
||||
}
|
||||
|
||||
/* SIO wake method */
|
||||
Method (SIOW, 1, NotSerialized)
|
||||
{
|
||||
PMFG = PMS1
|
||||
If (Arg0 == One)
|
||||
{
|
||||
GPKM ()
|
||||
ENTER_CONFIG_MODE (One)
|
||||
Local0 = OPT0
|
||||
OPT0 = (Local0 & 0x9F)
|
||||
EXIT_CONFIG_MODE ()
|
||||
}
|
||||
|
||||
If (Arg0 == 0x03)
|
||||
{
|
||||
GPKM ()
|
||||
ENTER_CONFIG_MODE (One)
|
||||
Local0 = OPT0
|
||||
OPT0 = (Local0 & 0x9F)
|
||||
OPT2 |= One
|
||||
OPT2 &= 0xFE
|
||||
EXIT_CONFIG_MODE ()
|
||||
}
|
||||
}
|
||||
|
||||
Method (SIOH, 0, NotSerialized)
|
||||
{
|
||||
If (PMFG & 0x08)
|
||||
{
|
||||
Notify (PS2K, 0x02) // Device Wake
|
||||
}
|
||||
|
||||
If (PMFG & 0x10)
|
||||
{
|
||||
Notify (PS2M, 0x02) // Device Wake
|
||||
}
|
||||
}
|
||||
#endif // SCH5545_RUNTIME_BASE
|
||||
#endif // SCH5545_SHOW_KBC
|
||||
|
||||
#ifdef SCH5545_SHOW_UARTA
|
||||
#define SUPERIO_UARTA_LDN 7
|
||||
Device (UAR1)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0501"))
|
||||
Name (_UID, SUPERIO_UID(SER, SUPERIO_UARTA_LDN))
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Return (DSTA (Zero))
|
||||
}
|
||||
|
||||
Method (_DIS, 0, NotSerialized)
|
||||
{
|
||||
DCNT (Zero, Zero)
|
||||
}
|
||||
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Return (DCRS (Zero, Zero))
|
||||
}
|
||||
|
||||
Method (_SRS, 1, NotSerialized)
|
||||
{
|
||||
CreateWordField (Arg0, 0x02, IO11)
|
||||
CreateWordField (Arg0, 0x09, IRQM)
|
||||
ENTER_CONFIG_MODE (SUPERIO_LPC_LDN)
|
||||
STIO (0x6A, IO11)
|
||||
SIRQ (Zero, IRQM)
|
||||
EXIT_CONFIG_MODE ()
|
||||
DCNT (Zero, One)
|
||||
}
|
||||
|
||||
Name (_PRS, ResourceTemplate ()
|
||||
{
|
||||
StartDependentFn (0x00, 0x00)
|
||||
{
|
||||
IO (Decode16,
|
||||
0x03F8,
|
||||
0x03F8,
|
||||
0x01,
|
||||
0x08,
|
||||
)
|
||||
IRQNoFlags ()
|
||||
{4}
|
||||
DMA (Compatibility, NotBusMaster, Transfer8, )
|
||||
{}
|
||||
}
|
||||
StartDependentFn (0x00, 0x00)
|
||||
{
|
||||
IO (Decode16,
|
||||
0x02F8,
|
||||
0x02F8,
|
||||
0x01,
|
||||
0x08,
|
||||
)
|
||||
IRQNoFlags ()
|
||||
{3}
|
||||
DMA (Compatibility, NotBusMaster, Transfer8, )
|
||||
{}
|
||||
}
|
||||
StartDependentFn (0x00, 0x00)
|
||||
{
|
||||
IO (Decode16,
|
||||
0x03E8,
|
||||
0x03E8,
|
||||
0x01,
|
||||
0x08,
|
||||
)
|
||||
IRQNoFlags ()
|
||||
{4}
|
||||
DMA (Compatibility, NotBusMaster, Transfer8, )
|
||||
{}
|
||||
}
|
||||
StartDependentFn (0x00, 0x00)
|
||||
{
|
||||
IO (Decode16,
|
||||
0x02E8,
|
||||
0x02E8,
|
||||
0x01,
|
||||
0x08,
|
||||
)
|
||||
IRQNoFlags ()
|
||||
{3}
|
||||
DMA (Compatibility, NotBusMaster, Transfer8, )
|
||||
{}
|
||||
}
|
||||
EndDependentFn ()
|
||||
})
|
||||
|
||||
Name (_PRW, Package() { 8, 3 })
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SCH5545_SHOW_UARTB
|
||||
#define SUPERIO_UARTB_LDN 8
|
||||
Device (UAR1)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0501"))
|
||||
Name (_UID, SUPERIO_UID(SER, SUPERIO_UARTB_LDN))
|
||||
Method (_STA, 0, NotSerialized)
|
||||
{
|
||||
Return (DSTA (One))
|
||||
}
|
||||
|
||||
Method (_DIS, 0, NotSerialized)
|
||||
{
|
||||
DCNT (One, Zero)
|
||||
}
|
||||
|
||||
Method (_CRS, 0, NotSerialized)
|
||||
{
|
||||
Return (DCRS (One, Zero))
|
||||
}
|
||||
|
||||
Method (_SRS, 1, NotSerialized)
|
||||
{
|
||||
CreateWordField (Arg0, 0x02, IO11)
|
||||
CreateWordField (Arg0, 0x09, IRQM)
|
||||
ENTER_CONFIG_MODE (SUPERIO_LPC_LDN)
|
||||
STIO (0x6E, IO11)
|
||||
SIRQ (One, IRQM)
|
||||
EXIT_CONFIG_MODE ()
|
||||
DCNT (One, One)
|
||||
}
|
||||
|
||||
Name (_PRS, ResourceTemplate ()
|
||||
{
|
||||
StartDependentFn (0x00, 0x00)
|
||||
{
|
||||
IO (Decode16,
|
||||
0x03F8,
|
||||
0x03F8,
|
||||
0x01,
|
||||
0x08,
|
||||
)
|
||||
IRQNoFlags ()
|
||||
{4}
|
||||
DMA (Compatibility, NotBusMaster, Transfer8, )
|
||||
{}
|
||||
}
|
||||
StartDependentFn (0x00, 0x00)
|
||||
{
|
||||
IO (Decode16,
|
||||
0x02F8,
|
||||
0x02F8,
|
||||
0x01,
|
||||
0x08,
|
||||
)
|
||||
IRQNoFlags ()
|
||||
{3}
|
||||
DMA (Compatibility, NotBusMaster, Transfer8, )
|
||||
{}
|
||||
}
|
||||
StartDependentFn (0x00, 0x00)
|
||||
{
|
||||
IO (Decode16,
|
||||
0x03E8,
|
||||
0x03E8,
|
||||
0x01,
|
||||
0x08,
|
||||
)
|
||||
IRQNoFlags ()
|
||||
{4}
|
||||
DMA (Compatibility, NotBusMaster, Transfer8, )
|
||||
{}
|
||||
}
|
||||
StartDependentFn (0x00, 0x00)
|
||||
{
|
||||
IO (Decode16,
|
||||
0x02E8,
|
||||
0x02E8,
|
||||
0x01,
|
||||
0x08,
|
||||
)
|
||||
IRQNoFlags ()
|
||||
{3}
|
||||
DMA (Compatibility, NotBusMaster, Transfer8, )
|
||||
{}
|
||||
}
|
||||
EndDependentFn ()
|
||||
})
|
||||
|
||||
Name (_PRW, Package() { 8, 3 })
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,299 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
/*
|
||||
* Based on SMSC SCH5627 datahseet:
|
||||
* http://pdf.datasheetcatalog.com/datasheets/microchip/00001996A.pdf
|
||||
*/
|
||||
|
||||
#ifndef SUPERIO_SCH_5545_H
|
||||
#define SUPERIO_SCH_5545_H
|
||||
|
||||
/* LPC I/O space */
|
||||
#define SCH5545_RUNTIME_REG_BASE 0x0a00
|
||||
#define SCH5545_EMI_BASE 0x0a40
|
||||
|
||||
/* logical devices */
|
||||
#define SCH5545_LDN_EMI 0x00
|
||||
#define SCH5545_LDN_KBC 0x01
|
||||
#define SCH5545_LDN_UART1 0x07
|
||||
#define SCH5545_LDN_UART2 0x08
|
||||
#define SCH5545_LDN_RR 0x0a /* Runtime Registers */
|
||||
#define SCH5545_LDN_FDC 0x0b
|
||||
#define SCH5545_LDN_LPC 0x0c /* LPC Interface */
|
||||
#define SCH5545_LDN_PP 0x11
|
||||
#define SCH5545_LDN_GCONF 0x3f /* Global Config */
|
||||
|
||||
/* KBC config registers */
|
||||
#define SCH5545_KRST_GA20 0xf0
|
||||
#define SCH5545_PORT92_EN (1 << 2)
|
||||
#define SCH5545_KBD_INT_LATCH (1 << 3)
|
||||
#define SCH5545_MOUSE_INT_LATCH (1 << 4)
|
||||
#define SCH5545_KBD_ISOLATION (1 << 5)
|
||||
#define SCH5545_MOUSE_ISOLATION (1 << 6)
|
||||
#define SCH5545_KEYBOARD_SELECT 0xf1
|
||||
#define SCH5545_KBD_MOUSE_SWAP (1 << 0)
|
||||
#define SCH5545_8042_RESET 0xf2
|
||||
#define SCH5545_8042_IN_RESET (1 << 0)
|
||||
#define SCH5545_8042_OUT_RESET (0 << 0)
|
||||
|
||||
/* UART config registers */
|
||||
#define SCH5545_UART_CONFIG_SELECT 0xf0
|
||||
#define SCH5545_UART_CLK_64MHZ_RO (0 << 0)
|
||||
#define SCH5545_UART_CLK_96MHZ_PLL (1 << 0)
|
||||
#define SCH5545_UART_POWER_VTR (0 << 1)
|
||||
#define SCH5545_UART_POWER_VCC (1 << 1)
|
||||
#define SCH5545_UART_NO_POLARITY_INVERT (0 << 2)
|
||||
#define SCH5545_UART_INVERT_POLARITY (1 << 2)
|
||||
|
||||
/* RR config registers */
|
||||
#define SCH5545_SPEKEY 0xf0
|
||||
#define SCH5545_SPEKEY_WAKE_EN (0 << 1)
|
||||
#define SCH5545_SPEKEY_WAKE_DIS (1 << 1)
|
||||
|
||||
/* Floppy config registers */
|
||||
#define SCH5545_FDD_MODE 0xf0
|
||||
#define SCH5545_FDD_MODE_NORMAL (0 << 0)
|
||||
#define SCH5545_FDD_MODE_ENHANCED (1 << 0)
|
||||
#define SCH5545_FDC_DMA_MODE_BURST (0 << 1)
|
||||
#define SCH5545_FDC_DMA_MODE_NON_BURST (1 << 1)
|
||||
#define SCH5545_FDD_IF_MODE_AT (3 << 2)
|
||||
#define SCH5545_FDD_IF_MODE_PS2 (1 << 2)
|
||||
#define SCH5545_FDD_IF_MODE_MODEL30 (0 << 2)
|
||||
#define SCH5545_FDC_OUTPUT_TYPE_OPEN_DRAIN (0 << 6)
|
||||
#define SCH5545_FDC_OUTPUT_TYPE_PUSH_PULL (1 << 6)
|
||||
#define SCH5545_FDC_OUTPUT_CTRL_ACTIVE (0 << 7)
|
||||
#define SCH5545_FDC_OUTPUT_CTRL_TRISTATE (1 << 7)
|
||||
#define SCH5545_FDD_OPTION 0xf1
|
||||
#define SCH5545_FDD_FORCED_WP_INACTIVE (0 << 0)
|
||||
#define SCH5545_FDD_FORCED_WP_ACTIVE (1 << 0)
|
||||
#define SCH5545_FDD_DENSITY_NORMAL (0 << 2)
|
||||
#define SCH5545_FDD_DENSITY_NORMAL_USER (1 << 2)
|
||||
#define SCH5545_FDD_DENSITY_LOGIC_ONE (2 << 2)
|
||||
#define SCH5545_FDD_DENSITY_LOGIC_ZERO (3 << 2)
|
||||
#define SCH5545_FDD_TYPE 0xf2
|
||||
#define SCH5545_FDD0 0xf4
|
||||
#define SCH5545_FDD0_TYPE_SEL_DT0 (1 << 0)
|
||||
#define SCH5545_FDD0_TYPE_SEL_DT1 (1 << 1)
|
||||
#define SCH5545_FDD0_DRT_SEL_DRT0 (1 << 3)
|
||||
#define SCH5545_FDD0_USE_PRECOMPENSATION (0 << 6)
|
||||
#define SCH5545_FDD0_NO_PRECOMPENSATION (1 << 6)
|
||||
|
||||
/* Parallel Port config registers */
|
||||
#define SCH5545_PP_INT_SELECT 0x70
|
||||
#define SCH5545_PP_SERIRQ_CHANNEL_MASK 0xf
|
||||
#define SCH5545_PP_DMA_SELECT 0x74
|
||||
#define SCH5545_PP_DMA_CHANNEL_MASK 0x7
|
||||
#define SCH5545_PP_MODE 0xf0
|
||||
#define SCH5545_PP_MODE_PRINTER (4 << 0)
|
||||
#define SCH5545_PP_MODE_SPP (0 << 0)
|
||||
#define SCH5545_PP_MODE_EPP19_SPP (1 << 0)
|
||||
#define SCH5545_PP_MODE_EPP17_SPP (5 << 0)
|
||||
#define SCH5545_PP_MODE_ECP (2 << 0)
|
||||
#define SCH5545_PP_MODE_EPP17_ECP (3 << 0)
|
||||
#define SCH5545_PP_MODE_EPP19_ECP (7 << 0)
|
||||
#define SCH5545_PP_ECP_FIFO_TRESH_MASK (0xf << 3)
|
||||
#define SCH5545_PP_INT_PULSED_LOW (1 << 7)
|
||||
#define SCH5545_PP_INT_FOLLOWS_ACK (0 << 7)
|
||||
#define SCH5545_PP_MODE2 0xf1
|
||||
#define SCH5545_PP_TMOUT_CLEARED_ON_WRITE (0 << 4)
|
||||
#define SCH5545_PP_TMOUT_CLEARED_ON_READ (1 << 4)
|
||||
|
||||
/* LPC IF config registers */
|
||||
#define SCH5545_IRQ_BASE 0x40
|
||||
#define SCH5545_DRQ_BASE 0x50
|
||||
/*
|
||||
* BAR registers are 4 byte
|
||||
* byte 0 0-6 mask, 7 reserved
|
||||
* byte 1 0-5 frame, 6 device, 7 valid
|
||||
* byte 2 LPC address least sig.
|
||||
* byte 3 LPC address most sig.
|
||||
*/
|
||||
#define SCH5545_BAR_LPC_IF 0x60
|
||||
#define SCH5545_BAR_EM_IF 0x64
|
||||
#define SCH5545_BAR_UART1 0x68
|
||||
#define SCH5545_BAR_UART2 0x6c
|
||||
#define SCH5545_BAR_RUNTIME_REG 0x70
|
||||
/* Certain SMSC parts have SPI controller LDN 0xf with BAR rgeister at 0x74 */
|
||||
#define SCH5545_BAR_KBC 0x78
|
||||
#define SCH5545_BAR_FLOPPY 0x7c
|
||||
#define SCH5545_BAR_PARPORT 0x80
|
||||
|
||||
/* IRQ <> device mappings */
|
||||
#define SCH5545_IRQ_KBD 0x01
|
||||
#define SCH5545_IRQ_MOUSE 0x81
|
||||
#define SCH5545_IRQ_UART1 0x07
|
||||
#define SCH5545_IRQ_UART2 0x08
|
||||
#define SCH5545_IRQ_EMI_MAILBOX 0x00
|
||||
#define SCH5545_IRQ_EMI_IRQ_SOURCE 0x80
|
||||
#define SCH5545_IRQ_RUNTIME_REG 0x0a
|
||||
#define SCH5545_IRQ_RUNTIME_REG_SMI 0x8a
|
||||
#define SCH5545_IRQ_FLOPPY 0x0b
|
||||
#define SCH5545_IRQ_PARPORT 0x11
|
||||
#define SCH5545_IRQ_DISABLED 0xff
|
||||
|
||||
|
||||
/* runtime registers */
|
||||
#define SCH5545_RR_PME_STS 0x00
|
||||
#define SCH5545_GLOBAL_PME_STS 0x01
|
||||
#define SCH5545_RR_PME_EN 0x01
|
||||
#define SCH5545_GLOBAL_PME_EN 0x01
|
||||
#define SCH5545_RR_PME_STS1 0x02
|
||||
#define SCH5545_UART2_RI_PME_STS 0x2
|
||||
#define SCH5545_UART1_RI_PME_STS 0x4
|
||||
#define SCH5545_KBD_PME_STS 0x8
|
||||
#define SCH5545_MOUSE_PME_STS 0x10
|
||||
#define SCH5545_SPECIFIC_KEY_PME_STS 0x20
|
||||
#define SCH5545_RR_PME_STS2 0x03
|
||||
#define SCH5545_IO_SMI_EVT_STS 0x1
|
||||
#define SCH5545_WDT_TIMEOUT_EVT_STS 0x2
|
||||
#define SCH5545_EM_EVT1_STS 0x4
|
||||
#define SCH5545_EM_EVT2_STS 0x8
|
||||
#define SCH5545_FW_EVT_STS 0x10
|
||||
#define SCH5545_BAT_LOW_STS 0x20
|
||||
#define SCH5545_INTRUDER_STS 0x40
|
||||
#define SCH5545_RR_PME_STS3 0x04
|
||||
#define SCH5545_GPIO62_PME_STS 0x1
|
||||
#define SCH5545_GPIO54_PME_STS 0x2
|
||||
#define SCH5545_GPIO53_PME_STS 0x4
|
||||
#define SCH5545_GPIO35_PME_STS 0x8
|
||||
#define SCH5545_GPIO31_PME_STS 0x10
|
||||
#define SCH5545_GPIO25_PME_STS 0x20
|
||||
#define SCH5545_GPIO24_PME_STS 0x40
|
||||
#define SCH5545_GPIO21_PME_STS 0x80
|
||||
#define SCH5545_RR_PME_EN1 0x05
|
||||
#define SCH5545_UART2_RI_PME_EN 0x2
|
||||
#define SCH5545_UART1_RI_PME_EN 0x4
|
||||
#define SCH5545_KBD_PME_EN 0x8
|
||||
#define SCH5545_MOUSE_PME_EN 0x10
|
||||
#define SCH5545_SPECIFIC_KEY_PME_EN 0x20
|
||||
#define SCH5545_RR_PME_EN2 0x06
|
||||
#define SCH5545_IO_SMI_EVT_PME_EN 0x1
|
||||
#define SCH5545_WDT_EVT_PME_EN 0x2
|
||||
#define SCH5545_EM_EVT1_PME_EN 0x4
|
||||
#define SCH5545_EM_EVT2_PME_EN 0x8
|
||||
#define SCH5545_FW_EVT_PME_EN 0x10
|
||||
#define SCH5545_BAT_LOW_PME_EN 0x20
|
||||
#define SCH5545_INTRUDER_PME_EN 0x40
|
||||
#define SCH5545_RR_PME_EN3 0x07
|
||||
#define SCH5545_GPIO62_PME_EN 0x1
|
||||
#define SCH5545_GPIO54_PME_EN 0x2
|
||||
#define SCH5545_GPIO53_PME_EN 0x4
|
||||
#define SCH5545_GPIO35_PME_EN 0x8
|
||||
#define SCH5545_GPIO31_PME_EN 0x10
|
||||
#define SCH5545_GPIO25_PME_EN 0x20
|
||||
#define SCH5545_GPIO24_PME_EN 0x40
|
||||
#define SCH5545_GPIO21_PME_EN 0x80
|
||||
#define SCH5545_RR_SMI_STS 0x10
|
||||
#define SCH5545_SMI_GLOBAL_STS 0x1
|
||||
#define SCH5545_RR_SMI_EN 0x11
|
||||
#define SCH5545_SMI_GLOBAL_EN 0x1
|
||||
#define SCH5545_RR_SMI_STS1 0x12
|
||||
#define SCH5545_LOW_BAT_SMI_STS 0x1
|
||||
#define SCH5545_PAR_PORT_SMI_STS 0x2
|
||||
#define SCH5545_UART2_SMI_STS 0x4
|
||||
#define SCH5545_UART1_SMI_STS 0x8
|
||||
#define SCH5545_FLOPPY_SMI_STS 0x10
|
||||
#define SCH5545_EM_EVT1_SMI_STS 0x20
|
||||
#define SCH5545_EM_EVT2_SMI_STS 0x40
|
||||
#define SCH5545_FW_EVT_SMI_STS 0x80
|
||||
#define SCH5545_RR_SMI_STS2 0x13
|
||||
#define SCH5545_MOUSE_SMI_STS 0x1
|
||||
#define SCH5545_KBD_SMI_STS 0x2
|
||||
#define SCH5545_WATCHDOG_EVT_SMI_STS 0x8
|
||||
#define SCH5545_INTRUSION_SMI_STS 0x10
|
||||
#define SCH5545_RR_SMI_STS3 0x14
|
||||
#define SCH5545_GPIO62_SMI_STS 0x1
|
||||
#define SCH5545_GPIO54_SMI_STS 0x2
|
||||
#define SCH5545_GPIO53_SMI_STS 0x4
|
||||
#define SCH5545_GPIO35_SMI_STS 0x8
|
||||
#define SCH5545_GPIO31_SMI_STS 0x10
|
||||
#define SCH5545_GPIO25_SMI_STS 0x20
|
||||
#define SCH5545_GPIO24_SMI_STS 0x40
|
||||
#define SCH5545_GPIO21_SMI_STS 0x80
|
||||
#define SCH5545_RR_SMI_EN1 0x15
|
||||
#define SCH5545_LOW_BAT_SMI_EN 0x1
|
||||
#define SCH5545_PAR_PORT_SMI_EN 0x2
|
||||
#define SCH5545_UART2_SMI_EN 0x4
|
||||
#define SCH5545_UART1_SMI_EN 0x8
|
||||
#define SCH5545_FLOPPY_SMI_EN 0x10
|
||||
#define SCH5545_EM_EVT1_SMI_EN 0x20
|
||||
#define SCH5545_EM_EVT2_SMI_EN 0x40
|
||||
#define SCH5545_FW_EVT_SMI_EN 0x1
|
||||
#define SCH5545_RR_SMI_EN2 0x16
|
||||
#define SCH5545_MOUSE_SMI_EN 0x1
|
||||
#define SCH5545_KBD_SMI_EN 0x2
|
||||
#define SCH5545_WATCHDOG_EVT_SMI_EN 0x8
|
||||
#define SCH5545_INTRUSION_SMI_EN 0x10
|
||||
#define SCH5545_RR_SMI_EN3 0x17
|
||||
#define SCH5545_GPIO62_SMI_EN 0x1
|
||||
#define SCH5545_GPIO54_SMI_EN 0x2
|
||||
#define SCH5545_GPIO53_SMI_EN 0x4
|
||||
#define SCH5545_GPIO35_SMI_EN 0x8
|
||||
#define SCH5545_GPIO31_SMI_EN 0x10
|
||||
#define SCH5545_GPIO25_SMI_EN 0x20
|
||||
#define SCH5545_GPIO24_SMI_EN 0x40
|
||||
#define SCH5545_GPIO21_SMI_EN 0x80
|
||||
#define SCH5545_RR_FORCE_DISK_CH 0x20
|
||||
#define SCH5545_FLOPPY_DISK_CHANGE 0x1
|
||||
#define SCH5545_RR_FLOPPY_DR_SEL 0x21
|
||||
#define SCH5545_DR_SELECT0 0x1
|
||||
#define SCH5545_DR_SELECT1 0x2
|
||||
#define SCH5545_FLOPPY_PRECOMP0 0x4
|
||||
#define SCH5545_FLOPPY_PRECOMP1 0x8
|
||||
#define SCH5545_FLOPPY_PRECOMP2 0x10
|
||||
#define SCH5545_FLOPPY_PWR_DOWN 0x40
|
||||
#define SCH5545_FLOPPY_SOFT_RESET 0x80
|
||||
#define SCH5545_RR_UART1_FIFO_CTRL 0x22
|
||||
#define SCH5545_UART1_FIFO_FE 0x1
|
||||
#define SCH5545_UART1_FIFO_RFR 0x2
|
||||
#define SCH5545_UART1_FIFO_XFR 0x4
|
||||
#define SCH5545_UART1_FIFO_DMS 0x8
|
||||
#define SCH5545_UART1_FIFO_RTL 0x40
|
||||
#define SCH5545_UART1_FIFO_RTM 0x80
|
||||
#define SCH5545_RR_UART2_FIFO_CTRL 0x23
|
||||
#define SCH5545_UART2_FIFO_FE 0x1
|
||||
#define SCH5545_UART2_FIFO_RFR 0x2
|
||||
#define SCH5545_UART2_FIFO_XFR 0x4
|
||||
#define SCH5545_UART2_FIFO_DMS 0x8
|
||||
#define SCH5545_UART2_FIFO_RTL 0x40
|
||||
#define SCH5545_UART2_FIFO_RTM 0x80
|
||||
#define SCH5545_RR_DEV_DISABLE 0x24
|
||||
#define SCH5545_FLOPPY_WP 0x1
|
||||
#define SCH5545_FLOPPY_DIS 0x8
|
||||
#define SCH5545_UART2_DIS 0x20
|
||||
#define SCH5545_UART1_DIS 0x40
|
||||
#define SCH5545_PAR_PORT_DIS 0x80
|
||||
#define SCH5545_RR_LED 0x25
|
||||
#define SCH5545_LED_BLINK_OFF 0x0
|
||||
#define SCH5545_LED_BLINK_1HZ 0x1
|
||||
#define SCH5545_LED_BLINK_ON 0x3
|
||||
#define SCH5545_LED_BLINK_MASK 0x3
|
||||
#define SCH5545_LED_COLOR_YELLOW 0x0
|
||||
#define SCH5545_LED_COLOR_GREEN 0x4
|
||||
#define SCH5545_LED_CODE_FETCH 0x8
|
||||
#define SCH5545_RR_KB_SCAN 0x26
|
||||
#define SCH5545_RR_PWRGOOD 0x27
|
||||
#define SCH5545_PWRGOOD_DELAY 0x1
|
||||
#define SCH5545_PWRGOOD_LOCK 0x2
|
||||
#define SCH5545_PCIRST_OUT4_EN 0x10
|
||||
#define SCH5545_PCIRST_OUT3_EN 0x20
|
||||
#define SCH5545_PCIRST_OUT1_EN 0x40
|
||||
#define SCH5545_PCIRST_OUT2_EN 0x80
|
||||
#define SCH5545_RR_GPIO_SEL 0x28
|
||||
#define SCH5545_RR_GPIO_READ 0x29
|
||||
#define SCH5545_RR_GPIO_WRITE 0x2A
|
||||
#define SCH5545_RR_FW_EVT_STS 0x30
|
||||
#define SCH5545_RR_FW_EVT_EN 0x31
|
||||
#define SCH5545_RR_PWR_REC_MODES 0x32
|
||||
#define SCH5545_PWR_SUPPLY_OFF 0x00
|
||||
#define SCH5545_PWR_SUPPLY_ON 0x80
|
||||
#define SCH5545_RR_INTRUDER 0x34
|
||||
#define SCH5545_INTRUSION_EDGE_STS 0x1
|
||||
#define SCH5545_INTRUDER_PIN_STS 0x2
|
||||
|
||||
void sch5545_early_init(unsigned int port);
|
||||
void sch5545_enable_uart(unsigned int port, unsigned int uart_no);
|
||||
void sch5545_set_led(unsigned int runtime_reg_base, unsigned int color, uint16_t blink);
|
||||
int sch5545_get_gpio(uint8_t sio_port, uint8_t gpio);
|
||||
|
||||
#endif /* SUPERIO_SCH_5545_H */
|
|
@ -0,0 +1,179 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <arch/io.h>
|
||||
#include <device/pnp.h>
|
||||
#include <stdint.h>
|
||||
#include <device/pnp_def.h>
|
||||
#include <device/pnp_ops.h>
|
||||
#include "sch5545.h"
|
||||
|
||||
static void pnp_enter_conf_state(pnp_devfn_t dev)
|
||||
{
|
||||
unsigned int port = dev >> 8;
|
||||
outb(0x55, port);
|
||||
}
|
||||
|
||||
static void pnp_exit_conf_state(pnp_devfn_t dev)
|
||||
{
|
||||
unsigned int port = dev >> 8;
|
||||
outb(0xaa, port);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the BAR / iobase for a specific device.
|
||||
* pnp_devfn_t dev must be in conf state.
|
||||
* LDN LPC IF must be active.
|
||||
*/
|
||||
static void set_iobase(pnp_devfn_t dev, uint16_t device_addr, uint16_t bar_addr)
|
||||
{
|
||||
uint16_t bar;
|
||||
|
||||
/*
|
||||
* Set the BAR. We have to flip the BAR due to different register layout:
|
||||
* - LPC addr LSB on device_addr + 2
|
||||
* - LPC addr MSB on device_addr + 3
|
||||
*/
|
||||
bar = ((bar_addr >> 8) & 0xff) | ((bar_addr & 0xff) << 8);
|
||||
pnp_set_iobase(dev, device_addr + 2, bar);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the IRQ for the specific device.
|
||||
* pnp_devfn_t dev must be in conf state.
|
||||
* LDN LPC IF must be active.
|
||||
*/
|
||||
static void set_irq(pnp_devfn_t dev, uint8_t irq_device, unsigned int irq)
|
||||
{
|
||||
if (irq > 15)
|
||||
return;
|
||||
|
||||
pnp_write_config(dev, SCH5545_IRQ_BASE + irq, irq_device);
|
||||
}
|
||||
|
||||
/*
|
||||
* sch5545 has 2 LEDs which are accessed via color (1 bit), 2 bits for a
|
||||
* pattern blink and 1 bit for "code fetch" which means the cpu/mainboard is
|
||||
* working (always set).
|
||||
*/
|
||||
void sch5545_set_led(unsigned int runtime_reg_base, unsigned int color, uint16_t blink)
|
||||
{
|
||||
uint8_t val = blink & SCH5545_LED_BLINK_MASK;
|
||||
val |= SCH5545_LED_CODE_FETCH;
|
||||
if (color)
|
||||
val |= SCH5545_LED_COLOR_GREEN;
|
||||
outb(val, runtime_reg_base + SCH5545_RR_LED);
|
||||
}
|
||||
|
||||
void sch5545_early_init(unsigned int port)
|
||||
{
|
||||
pnp_devfn_t dev;
|
||||
|
||||
/* Enable SERIRQ */
|
||||
dev = PNP_DEV(port, SCH5545_LDN_GCONF);
|
||||
pnp_enter_conf_state(dev);
|
||||
pnp_set_logical_device(dev);
|
||||
pnp_write_config(dev, 0x24, pnp_read_config(dev, 0x24) | 0x04);
|
||||
|
||||
/* Enable LPC interface */
|
||||
dev = PNP_DEV(port, SCH5545_LDN_LPC);
|
||||
pnp_set_logical_device(dev);
|
||||
pnp_set_enable(dev, 1);
|
||||
/* Set LPC BAR mask */
|
||||
pnp_write_config(dev, SCH5545_BAR_LPC_IF, 0x01);
|
||||
/* BAR valid, Frame/LDN = 0xc */
|
||||
pnp_write_config(dev, SCH5545_BAR_LPC_IF + 1, SCH5545_LDN_LPC | 0x80);
|
||||
set_iobase(dev, SCH5545_BAR_LPC_IF, port);
|
||||
|
||||
/* Enable Runtime Registers */
|
||||
|
||||
/* The Runtime Registers BAR is 0x40 long */
|
||||
pnp_write_config(dev, SCH5545_BAR_RUNTIME_REG, 0x3f);
|
||||
/* BAR valid, Frame/LDN = 0xa */
|
||||
pnp_write_config(dev, SCH5545_BAR_RUNTIME_REG + 1, SCH5545_LDN_RR | 0x80);
|
||||
|
||||
/* Map Runtime Registers */
|
||||
set_iobase(dev, SCH5545_BAR_RUNTIME_REG, SCH5545_RUNTIME_REG_BASE);
|
||||
dev = PNP_DEV(port, SCH5545_LDN_RR);
|
||||
pnp_set_logical_device(dev);
|
||||
pnp_set_enable(dev, 1);
|
||||
|
||||
/* Set LED color and indicate BIOS has reached code fetch phase */
|
||||
sch5545_set_led(SCH5545_RUNTIME_REG_BASE, SCH5545_LED_COLOR_GREEN,
|
||||
SCH5545_LED_BLINK_ON);
|
||||
|
||||
/* Configure EMI */
|
||||
dev = PNP_DEV(port, SCH5545_LDN_LPC);
|
||||
pnp_set_logical_device(dev);
|
||||
/* EMI BAR has 11 registers, but vendor sets the mask to 0xf */
|
||||
pnp_write_config(dev, SCH5545_BAR_EM_IF, 0x0f);
|
||||
/* BAR valid, Frame/LDN = 0x00 */
|
||||
pnp_write_config(dev, SCH5545_BAR_EM_IF + 1, SCH5545_LDN_EMI | 0x80);
|
||||
set_iobase(dev, SCH5545_BAR_EM_IF, SCH5545_EMI_BASE);
|
||||
|
||||
pnp_exit_conf_state(dev);
|
||||
}
|
||||
|
||||
void sch5545_enable_uart(unsigned int port, unsigned int uart_no)
|
||||
{
|
||||
pnp_devfn_t dev;
|
||||
|
||||
if (uart_no > 1)
|
||||
return;
|
||||
|
||||
/* Configure serial port */
|
||||
dev = PNP_DEV(port, SCH5545_LDN_LPC);
|
||||
pnp_enter_conf_state(dev);
|
||||
pnp_set_logical_device(dev);
|
||||
/* Set UART BAR mask to 0x07 (8 registers) */
|
||||
pnp_write_config(dev, SCH5545_BAR_UART1 + (4 * uart_no), 0x07);
|
||||
/* Set BAR valid, Frame/LDN = UART1/2 LDN 0x07/0x08 */
|
||||
pnp_write_config(dev, SCH5545_BAR_UART1 + (4 * uart_no) + 1,
|
||||
(SCH5545_LDN_UART1 + uart_no) | 0x80);
|
||||
set_iobase(dev, SCH5545_BAR_UART1 + (4 * uart_no), (uart_no == 1) ? 0x2f8 : 0x3f8);
|
||||
/* IRQ 3 for UART2, IRQ4 for UART1 */
|
||||
set_irq(dev, SCH5545_LDN_UART1 + uart_no, 4 - uart_no);
|
||||
|
||||
dev = PNP_DEV(port, SCH5545_LDN_UART1 + uart_no);
|
||||
pnp_set_logical_device(dev);
|
||||
pnp_set_enable(dev, 1);
|
||||
pnp_write_config(dev, SCH5545_UART_CONFIG_SELECT, SCH5545_UART_POWER_VCC);
|
||||
|
||||
pnp_exit_conf_state(dev);
|
||||
}
|
||||
|
||||
int sch5545_get_gpio(uint8_t sio_port, uint8_t gpio)
|
||||
{
|
||||
pnp_devfn_t dev;
|
||||
uint16_t runtime_reg_base;
|
||||
uint8_t gpio_bank, gpio_num;
|
||||
|
||||
gpio_bank = gpio / 10;
|
||||
gpio_num = gpio % 10;
|
||||
/*
|
||||
* GPIOs are divided into banks of 8 GPIOs (kind of). Each group starts at decimal
|
||||
* base, i.e. 8 GPIOs from GPIO000, 8 GPIOs from GPIO010, etc., up to GPIO071 and
|
||||
* GPIO072 which are an exception (only two GPIOs in the bank 7).
|
||||
*/
|
||||
if (gpio_num > 7)
|
||||
return -1;
|
||||
else if (gpio_bank == 7 && gpio_num > 1)
|
||||
return -1;
|
||||
else if (gpio_bank > 7)
|
||||
return -1;
|
||||
|
||||
dev = PNP_DEV(sio_port, SCH5545_LDN_LPC);
|
||||
pnp_enter_conf_state(dev);
|
||||
pnp_set_logical_device(dev);
|
||||
|
||||
runtime_reg_base = pnp_read_config(dev, SCH5545_BAR_RUNTIME_REG + 2);
|
||||
runtime_reg_base |= pnp_read_config(dev, SCH5545_BAR_RUNTIME_REG + 3) << 8;
|
||||
|
||||
pnp_exit_conf_state(dev);
|
||||
|
||||
if (runtime_reg_base == 0)
|
||||
return -1;
|
||||
|
||||
outb(gpio_bank * 8 + gpio_num, runtime_reg_base + SCH5545_RR_GPIO_SEL);
|
||||
|
||||
return inb(runtime_reg_base + SCH5545_RR_GPIO_READ) & 1;
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <assert.h>
|
||||
#include <arch/io.h>
|
||||
#include <device/pnp.h>
|
||||
#include <device/pnp_def.h>
|
||||
#include <device/pnp_ops.h>
|
||||
#include <superio/conf_mode.h>
|
||||
|
||||
#include "sch5545.h"
|
||||
#include "sch5545_emi.h"
|
||||
|
||||
static uint16_t emi_bar;
|
||||
|
||||
#ifdef __SIMPLE_DEVICE__
|
||||
static void sch5545_enter_conf_state(pnp_devfn_t dev)
|
||||
{
|
||||
unsigned int port = dev >> 8;
|
||||
outb(0x55, port);
|
||||
}
|
||||
|
||||
static void sch5545_exit_conf_state(pnp_devfn_t dev)
|
||||
{
|
||||
unsigned int port = dev >> 8;
|
||||
outb(0xaa, port);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t sch5545_read_emi_bar(uint8_t sio_port)
|
||||
{
|
||||
uint16_t bar;
|
||||
|
||||
#ifdef __SIMPLE_DEVICE__
|
||||
pnp_devfn_t lpcif = PNP_DEV(sio_port, SCH5545_LDN_LPC);
|
||||
sch5545_enter_conf_state(lpcif);
|
||||
#else
|
||||
struct device *lpcif = dev_find_slot_pnp(sio_port, SCH5545_LDN_LPC);
|
||||
if (!lpcif)
|
||||
return 0;
|
||||
pnp_enter_conf_mode_55(lpcif);
|
||||
#endif
|
||||
pnp_set_logical_device(lpcif);
|
||||
|
||||
bar = pnp_read_config(lpcif, SCH5545_BAR_EM_IF + 2);
|
||||
bar |= pnp_read_config(lpcif, SCH5545_BAR_EM_IF + 3) << 8;
|
||||
|
||||
#ifdef __SIMPLE_DEVICE__
|
||||
sch5545_exit_conf_state(lpcif);
|
||||
#else
|
||||
pnp_exit_conf_mode_aa(lpcif);
|
||||
#endif
|
||||
return bar;
|
||||
}
|
||||
|
||||
void sch5545_emi_init(uint8_t sio_port)
|
||||
{
|
||||
emi_bar = sch5545_read_emi_bar(sio_port);
|
||||
assert(emi_bar != 0);
|
||||
}
|
||||
|
||||
void sch5545_emi_ec2h_mailbox_clear(void)
|
||||
{
|
||||
sch5545_emi_ec2h_mbox_write(sch5545_emi_ec2h_mbox_read());
|
||||
}
|
||||
|
||||
void sch5545_emi_disable_interrupts(void)
|
||||
{
|
||||
sch5545_emi_set_int_mask(0);
|
||||
}
|
||||
|
||||
void sch5545_emi_h2ec_mbox_write(uint8_t mbox_message)
|
||||
{
|
||||
outb(mbox_message, emi_bar + SCH5545_EMI_HOST_TO_EC_MAILBOX);
|
||||
}
|
||||
|
||||
uint8_t sch5545_emi_h2ec_mbox_read(void)
|
||||
{
|
||||
return inb(emi_bar + SCH5545_EMI_HOST_TO_EC_MAILBOX);
|
||||
}
|
||||
|
||||
void sch5545_emi_ec2h_mbox_write(uint8_t mbox_message)
|
||||
{
|
||||
outb(mbox_message, emi_bar + SCH5545_EMI_EC_TO_HOST_MAILBOX);
|
||||
}
|
||||
|
||||
uint8_t sch5545_emi_ec2h_mbox_read(void)
|
||||
{
|
||||
return inb(emi_bar + SCH5545_EMI_EC_TO_HOST_MAILBOX);
|
||||
}
|
||||
|
||||
void sch5545_emi_set_int_mask(uint16_t mask)
|
||||
{
|
||||
outw(mask, emi_bar + SCH5545_EMI_INT_MASK);
|
||||
}
|
||||
|
||||
void sch5545_emi_set_int_mask_low(uint8_t mask)
|
||||
{
|
||||
outb(mask, emi_bar + SCH5545_EMI_INT_MASK);
|
||||
}
|
||||
|
||||
void sch5545_emi_set_int_mask_high(uint8_t mask)
|
||||
{
|
||||
outb(mask, emi_bar + SCH5545_EMI_INT_MASK + 1);
|
||||
}
|
||||
|
||||
uint8_t sch5545_emi_get_int_mask_low(void)
|
||||
{
|
||||
return inb(emi_bar + SCH5545_EMI_INT_MASK);
|
||||
}
|
||||
|
||||
uint8_t sch5545_emi_get_int_mask_high(void)
|
||||
{
|
||||
return inb(emi_bar + SCH5545_EMI_INT_MASK + 1);
|
||||
}
|
||||
|
||||
uint16_t sch5545_emi_get_int_mask(void)
|
||||
{
|
||||
return inw(emi_bar + SCH5545_EMI_INT_MASK);
|
||||
}
|
||||
|
||||
void sch5545_emi_set_int_src_low(uint8_t int_src)
|
||||
{
|
||||
outb(int_src, emi_bar + SCH5545_EMI_INT_SOURCE);
|
||||
}
|
||||
|
||||
void sch5545_emi_set_int_src_high(uint8_t int_src)
|
||||
{
|
||||
outb(int_src, emi_bar + SCH5545_EMI_INT_SOURCE + 1);
|
||||
}
|
||||
|
||||
uint8_t sch5545_emi_get_int_src_low(void)
|
||||
{
|
||||
return inb(emi_bar + SCH5545_EMI_INT_SOURCE);
|
||||
}
|
||||
|
||||
uint8_t sch5545_emi_get_int_src_high(void)
|
||||
{
|
||||
return inb(emi_bar + SCH5545_EMI_INT_SOURCE + 1);
|
||||
}
|
||||
uint16_t sch5545_emi_get_int_src(void)
|
||||
{
|
||||
return inw(emi_bar + SCH5545_EMI_INT_SOURCE);
|
||||
}
|
||||
|
||||
void sch5545_emi_set_int_src(uint16_t int_src)
|
||||
{
|
||||
outw(int_src, emi_bar + SCH5545_EMI_INT_SOURCE);
|
||||
}
|
||||
|
||||
void sch5545_emi_set_ec_addr(uint16_t addr)
|
||||
{
|
||||
outw(addr, emi_bar + SCH5545_EMI_EC_ADDR);
|
||||
}
|
||||
|
||||
uint16_t sch5545_emi_read_ec_addr(void)
|
||||
{
|
||||
return inw(emi_bar + SCH5545_EMI_EC_ADDR);
|
||||
}
|
||||
|
||||
void sch5545_emi_ec_write8(uint16_t addr, uint8_t data)
|
||||
{
|
||||
sch5545_emi_set_ec_addr((addr & 0xfffc) | EMI_EC_8BIT_ACCESS);
|
||||
outb(data, emi_bar + SCH5545_EMI_EC_DATA + (addr & 3));
|
||||
}
|
||||
|
||||
void sch5545_emi_ec_write16(uint16_t addr, uint16_t data)
|
||||
{
|
||||
sch5545_emi_set_ec_addr((addr & 0xfffc) | EMI_EC_16BIT_ACCESS);
|
||||
outw(data, emi_bar + SCH5545_EMI_EC_DATA + (addr & 2));
|
||||
}
|
||||
|
||||
void sch5545_emi_ec_write32(uint16_t addr, uint32_t data)
|
||||
{
|
||||
sch5545_emi_set_ec_addr((addr & 0xfffc) | EMI_EC_32BIT_ACCESS);
|
||||
outl(data, emi_bar + SCH5545_EMI_EC_DATA);
|
||||
}
|
||||
|
||||
void sch5545_emi_ec_write32_bulk(uint16_t addr, const uint32_t *buffer, size_t len)
|
||||
{
|
||||
sch5545_emi_set_ec_addr((addr & 0xfffc) | EMI_EC_32BIT_AUTO_ACCESS);
|
||||
|
||||
while (len > 0) {
|
||||
outl(*(buffer++), emi_bar + SCH5545_EMI_EC_DATA);
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t sch5545_emi_ec_read8(uint16_t addr)
|
||||
{
|
||||
sch5545_emi_set_ec_addr((addr & 0xfffc) | EMI_EC_8BIT_ACCESS);
|
||||
return inb(emi_bar + SCH5545_EMI_EC_DATA + (addr & 3));
|
||||
}
|
||||
|
||||
uint16_t sch5545_emi_ec_read16(uint16_t addr)
|
||||
{
|
||||
sch5545_emi_set_ec_addr((addr & 0xfffc) | EMI_EC_16BIT_ACCESS);
|
||||
return inw(emi_bar + SCH5545_EMI_EC_DATA + (addr & 2));
|
||||
}
|
||||
|
||||
uint32_t sch5545_emi_ec_read32(uint16_t addr)
|
||||
{
|
||||
sch5545_emi_set_ec_addr((addr & 0xfffc) | EMI_EC_32BIT_ACCESS);
|
||||
return inb(emi_bar + SCH5545_EMI_EC_DATA);
|
||||
}
|
||||
|
||||
void sch5545_emi_ec_read32_bulk(uint16_t addr, uint32_t *buffer, size_t len)
|
||||
{
|
||||
sch5545_emi_set_ec_addr((addr & 0xfffc) | EMI_EC_32BIT_AUTO_ACCESS);
|
||||
|
||||
while (len > 0) {
|
||||
*(buffer++) = inl(emi_bar + SCH5545_EMI_EC_DATA);
|
||||
len--;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#ifndef SUPERIO_SCH_5545_EMI_H
|
||||
#define SUPERIO_SCH_5545_EMI_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Embedded Memory Interface registers */
|
||||
#define SCH5545_EMI_HOST_TO_EC_MAILBOX 0x0
|
||||
#define SCH5545_EMI_EC_TO_HOST_MAILBOX 0x1
|
||||
#define SCH5545_EMI_EC_ADDR 0x2
|
||||
#define SCH5545_EMI_EC_DATA 0x4
|
||||
#define SCH5545_EMI_INT_SOURCE 0x8
|
||||
#define SCH5545_EMI_INT_MASK 0xa
|
||||
|
||||
#define EMI_EC_8BIT_ACCESS 0
|
||||
#define EMI_EC_16BIT_ACCESS 1
|
||||
#define EMI_EC_32BIT_ACCESS 2
|
||||
#define EMI_EC_32BIT_AUTO_ACCESS 3
|
||||
|
||||
/**
|
||||
* Reads and returns the base address of EMI from the SuperIO.
|
||||
*/
|
||||
uint16_t sch5545_read_emi_bar(uint8_t sio_port);
|
||||
/**
|
||||
* One must call this function at every stage before using any of the EMI
|
||||
* functions. The base address of EMI interface must not be zero.
|
||||
*/
|
||||
void sch5545_emi_init(uint8_t sio_port);
|
||||
/**
|
||||
* Reads the EC to Host mailbox register and then writes the same content to
|
||||
* clear it.
|
||||
*/
|
||||
void sch5545_emi_ec2h_mailbox_clear(void);
|
||||
/**
|
||||
* Writes the interrupt mask register with 0.
|
||||
*/
|
||||
void sch5545_emi_disable_interrupts(void);
|
||||
/**
|
||||
* Writes the Host to EC mailbox 8bit register with mbox_message.
|
||||
*/
|
||||
void sch5545_emi_h2ec_mbox_write(uint8_t mbox_message);
|
||||
/**
|
||||
* Reads and returns the Host to EC mailbox 8bit register.
|
||||
*/
|
||||
uint8_t sch5545_emi_h2ec_mbox_read(void);
|
||||
/**
|
||||
* Writes the EC to Host mailbox 8bit register with mbox_message.
|
||||
*/
|
||||
void sch5545_emi_ec2h_mbox_write(uint8_t mbox_message);
|
||||
/**
|
||||
* Reads and returns the EC to Host mailbox 8bit register.
|
||||
*/
|
||||
uint8_t sch5545_emi_ec2h_mbox_read(void);
|
||||
/**
|
||||
* Sets the mask for all EC interrupts.
|
||||
*/
|
||||
void sch5545_emi_set_int_mask(uint16_t mask);
|
||||
/**
|
||||
* Sets the EC interrupt mask for LSB in the Interrupt Mask register.
|
||||
*/
|
||||
void sch5545_emi_set_int_mask_low(uint8_t mask);
|
||||
/**
|
||||
* Sets the EC interrupt mask for MSB in the Interrupt Mask register.
|
||||
*/
|
||||
void sch5545_emi_set_int_mask_high(uint8_t mask);
|
||||
/**
|
||||
* Returns LSB of Interrupt mask register.
|
||||
*/
|
||||
uint8_t sch5545_emi_get_int_mask_low(void);
|
||||
/**
|
||||
* Returns MSB of Interrupt mask register.
|
||||
*/
|
||||
uint8_t sch5545_emi_get_int_mask_high(void);
|
||||
/**
|
||||
* Returns the content of interrupt mask register.
|
||||
*/
|
||||
uint16_t sch5545_emi_get_int_mask(void);
|
||||
/**
|
||||
* Clears the interrupt status bits.
|
||||
*/
|
||||
void sch5545_emi_clear_int_src(void);
|
||||
/**
|
||||
* Writes int_src bits to clear the desired interrupt source LSB.
|
||||
*/
|
||||
void sch5545_emi_set_int_src_low(uint8_t int_src);
|
||||
/**
|
||||
* Writes int_src bits to clear the desired interrupt source MSB.
|
||||
*/
|
||||
void sch5545_emi_set_int_src_high(uint8_t int_src);
|
||||
/**
|
||||
* Writes int_src bits to clear the desired interrupt source bits.
|
||||
*/
|
||||
void sch5545_emi_set_int_src(uint16_t int_src);
|
||||
/**
|
||||
* Returns LSB of interrupt source register.
|
||||
*/
|
||||
uint8_t sch5545_emi_get_int_src_low(void);
|
||||
/**
|
||||
* Returns MSB of interrupt source register.
|
||||
*/
|
||||
uint8_t sch5545_emi_get_int_src_high(void);
|
||||
/**
|
||||
* Returns the content of interrupt source register.
|
||||
*/
|
||||
uint16_t sch5545_emi_get_int_src(void);
|
||||
/**
|
||||
* Sets the EC address registers with given addr for indirect access to
|
||||
* Embedded Memory.
|
||||
*/
|
||||
void sch5545_emi_set_ec_addr(uint16_t addr);
|
||||
/**
|
||||
* Return the current EC address used for indirect access to Embedded Memory.
|
||||
*/
|
||||
uint16_t sch5545_emi_read_ec_addr(void);
|
||||
/**
|
||||
* Writes any byte of 4 bytes from the 32bit dword indicated by addr. The
|
||||
* function will automatically align to the matching 32bit dword.
|
||||
*/
|
||||
void sch5545_emi_ec_write8(uint16_t addr, uint8_t data);
|
||||
/**
|
||||
* Writes any word of 2 words from the 32bit dword indicated by addr. The addr
|
||||
* must be aligned to 16bit access, because function programs the right access
|
||||
* mode rounding the address to be written to 16 bit boundary.
|
||||
*/
|
||||
void sch5545_emi_ec_write16(uint16_t addr, uint16_t data);
|
||||
/**
|
||||
* Writes dword of data at the desired address indicated by addr. The addr must
|
||||
* be aligned to 32bit access, because function programs the right access mode
|
||||
* rounding the address to be written to 32 bit boundary.
|
||||
*/
|
||||
void sch5545_emi_ec_write32(uint16_t addr, uint32_t data);
|
||||
/**
|
||||
* Writes an array of dwords at the desired address indicated by addr. The addr
|
||||
* must be aligned to 32bit access, because function programs the right access
|
||||
* mode rounding the address to be written to 32 bit boundary. The address is
|
||||
* autoincremented by each IO write operation automatically.
|
||||
*/
|
||||
void sch5545_emi_ec_write32_bulk(uint16_t addr, const uint32_t *buffer, size_t len);
|
||||
/**
|
||||
* Reads any byte of 4 bytes from the 32bit dword indicated by addr. The
|
||||
* function will automatically align to the matching 32bit dword.
|
||||
*/
|
||||
uint8_t sch5545_emi_ec_read8(uint16_t addr);
|
||||
/**
|
||||
* Reads any word of 2 words from the 32bit dword indicated by addr. The addr
|
||||
* must be aligned to 16bit access, because function programs the right access
|
||||
* mode rounding the address to be read to 16 bit boundary.
|
||||
*/
|
||||
uint16_t sch5545_emi_ec_read16(uint16_t addr);
|
||||
/**
|
||||
* Reads dword of data at the desired address indicated by addr. The addr must
|
||||
* be aligned to 32bit access, because function programs the right access mode
|
||||
* rounding the address to be read to 32 bit boundary.
|
||||
*/
|
||||
uint32_t sch5545_emi_ec_read32(uint16_t addr);
|
||||
/**
|
||||
* Reads a stream of dwords of size len to an array of dwords from the desired
|
||||
* address indicated by addr. The addr must be aligned to 32bit access, because
|
||||
* function programs the right access mode rounding the start address to be
|
||||
* read to 32 bit boundary. The address is autoincremented by each IO read
|
||||
* operation automatically.
|
||||
*/
|
||||
void sch5545_emi_ec_read32_bulk(uint16_t addr, uint32_t *buffer, size_t len);
|
||||
|
||||
#endif /* SUPERIO_SCH_5545_EMI_H */
|
|
@ -0,0 +1,301 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
|
||||
#include <arch/io.h>
|
||||
#include <device/device.h>
|
||||
#include <device/pnp.h>
|
||||
#include <superio/conf_mode.h>
|
||||
#include <console/console.h>
|
||||
#include <pc80/keyboard.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "sch5545.h"
|
||||
|
||||
int sch5545_get_gpio(uint8_t sio_port, uint8_t gpio)
|
||||
{
|
||||
struct device *dev;
|
||||
uint16_t runtime_reg_base;
|
||||
uint8_t gpio_bank, gpio_num;
|
||||
|
||||
gpio_bank = gpio / 10;
|
||||
gpio_num = gpio % 10;
|
||||
/*
|
||||
* GPIOs are divided into banks of 8 GPIOs (kind of). Each group starts
|
||||
* at decimal base, i.e. 8 GPIOs from GPIO000, 8 GPIOs from GPIO010,
|
||||
* etc., up to GPIO071 and GPIO072 which are an exception (only two
|
||||
* gpios in the bank 7).
|
||||
*/
|
||||
if (gpio_num > 7)
|
||||
return -1;
|
||||
else if (gpio_bank == 7 && gpio_num > 1)
|
||||
return -1;
|
||||
else if (gpio_bank > 7)
|
||||
return -1;
|
||||
|
||||
dev = dev_find_slot_pnp(sio_port, SCH5545_LDN_LPC);
|
||||
|
||||
if (!dev) {
|
||||
printk(BIOS_ERR, "%s: ERROR: LPC interface LDN not present."
|
||||
"Check the devicetree!\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pnp_enter_conf_mode(dev);
|
||||
pnp_set_logical_device(dev);
|
||||
|
||||
runtime_reg_base = pnp_read_config(dev, SCH5545_BAR_RUNTIME_REG + 2);
|
||||
runtime_reg_base |= pnp_read_config(dev, SCH5545_BAR_RUNTIME_REG + 3) << 8;
|
||||
|
||||
pnp_exit_conf_mode(dev);
|
||||
|
||||
if (runtime_reg_base == 0)
|
||||
return -1;
|
||||
|
||||
outb(gpio_bank * 8 + gpio_num, runtime_reg_base + SCH5545_RR_GPIO_SEL);
|
||||
|
||||
return inb(runtime_reg_base + SCH5545_RR_GPIO_READ) & 1;
|
||||
}
|
||||
|
||||
static void sch5545_init(struct device *dev)
|
||||
{
|
||||
if (!dev->enabled)
|
||||
return;
|
||||
|
||||
switch (dev->path.pnp.device) {
|
||||
case SCH5545_LDN_KBC:
|
||||
pc_keyboard_init(NO_AUX_DEVICE);
|
||||
break;
|
||||
case SCH5545_LDN_LPC:
|
||||
pnp_enter_conf_mode(dev);
|
||||
pnp_set_logical_device(dev);
|
||||
/* Enable SERIRQ */
|
||||
pnp_write_config(dev, 0x24, pnp_read_config(dev, 0x24) | 0x04);
|
||||
pnp_exit_conf_mode(dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void sch5545_set_iobase(struct device *dev, u8 index, u16 iobase)
|
||||
{
|
||||
u8 val;
|
||||
struct device *lpc_if;
|
||||
u8 iobase_reg = 0;
|
||||
|
||||
lpc_if = dev_find_slot_pnp(dev->path.pnp.port, SCH5545_LDN_LPC);
|
||||
|
||||
if (!lpc_if) {
|
||||
printk(BIOS_ERR, "ERROR: %s LPC interface LDN not present."
|
||||
"Check the devicetree!\n", dev_path(dev));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dev->path.pnp.device) {
|
||||
case SCH5545_LDN_EMI:
|
||||
iobase_reg = SCH5545_BAR_EM_IF;
|
||||
break;
|
||||
case SCH5545_LDN_KBC:
|
||||
iobase_reg = SCH5545_BAR_KBC;
|
||||
break;
|
||||
case SCH5545_LDN_UART1:
|
||||
iobase_reg = SCH5545_BAR_UART1;
|
||||
break;
|
||||
case SCH5545_LDN_UART2:
|
||||
iobase_reg = SCH5545_BAR_UART2;
|
||||
break;
|
||||
case SCH5545_LDN_RR:
|
||||
iobase_reg = SCH5545_BAR_RUNTIME_REG;
|
||||
break;
|
||||
case SCH5545_LDN_FDC:
|
||||
iobase_reg = SCH5545_BAR_FLOPPY;
|
||||
break;
|
||||
case SCH5545_LDN_LPC:
|
||||
iobase_reg = SCH5545_BAR_LPC_IF;
|
||||
break;
|
||||
case SCH5545_LDN_PP:
|
||||
iobase_reg = SCH5545_BAR_PARPORT;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
pnp_set_logical_device(lpc_if);
|
||||
|
||||
/* Flip the bytes in IO base, LSB goes first */
|
||||
pnp_write_config(lpc_if, iobase_reg + 2, iobase & 0xff);
|
||||
pnp_write_config(lpc_if, iobase_reg + 3, (iobase >> 8) & 0xff);
|
||||
|
||||
/* Set valid bit */
|
||||
val = pnp_read_config(lpc_if, iobase_reg + 1);
|
||||
val |= 0x80;
|
||||
pnp_write_config(lpc_if, iobase_reg + 1, val);
|
||||
|
||||
pnp_set_logical_device(dev);
|
||||
}
|
||||
|
||||
static void sch5545_set_irq(struct device *dev, u8 index, u8 irq)
|
||||
{
|
||||
u8 select_bit = 0;
|
||||
struct device *lpc_if;
|
||||
|
||||
/* In case it is not the IRQ, write misc register directly */
|
||||
if (index >= PNP_IDX_MSC0) {
|
||||
pnp_write_config(dev, index, irq);
|
||||
return;
|
||||
}
|
||||
|
||||
lpc_if = dev_find_slot_pnp(dev->path.pnp.port, SCH5545_LDN_LPC);
|
||||
|
||||
if (!lpc_if) {
|
||||
printk(BIOS_ERR, "ERROR: %s LPC interface LDN not present."
|
||||
"Check the devicetree!\n", dev_path(dev));
|
||||
return;
|
||||
}
|
||||
|
||||
pnp_set_logical_device(lpc_if);
|
||||
|
||||
/*
|
||||
* Some LDNs can generate IRQs from two sources, i.e.
|
||||
* - EMI may generate interrupts for Mailbox and INT source register
|
||||
* - KBC may generate separate IRQ for mouse and keyboard,
|
||||
* - RR LDN may generate IRQ for PME and SMI etc.
|
||||
* SELECT bit allows to distinguish IRQ source for single LDN.
|
||||
* Use the standard IRQs for devices.
|
||||
*/
|
||||
switch (dev->path.pnp.device) {
|
||||
case SCH5545_LDN_EMI:
|
||||
case SCH5545_LDN_KBC:
|
||||
case SCH5545_LDN_RR:
|
||||
if (index == 0x72)
|
||||
select_bit = 0x80;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* IRQs are set in a little different manner. Each IRQ number has its
|
||||
* own register which is programmed with LDN number which should use
|
||||
* the IRQ. Ignore the index offset and choose register based on IRQ
|
||||
* number counting from IRQ base.
|
||||
*/
|
||||
pnp_write_config(lpc_if, SCH5545_IRQ_BASE + irq, dev->path.pnp.device | select_bit);
|
||||
pnp_set_logical_device(dev);
|
||||
}
|
||||
|
||||
static void sch5545_set_drq(struct device *dev, u8 index, u8 drq)
|
||||
{
|
||||
struct device *lpc_if;
|
||||
|
||||
if (drq == 4) {
|
||||
printk(BIOS_ERR, "ERROR: %s %02x: Trying to set reserved DMA channel 4!\n",
|
||||
dev_path(dev), index);
|
||||
printk(BIOS_ERR, "This configuration is untested. Trying to continue.\n");
|
||||
}
|
||||
|
||||
/* DMA channel is programmed via LPC LDN */
|
||||
lpc_if = dev_find_slot_pnp(dev->path.pnp.port, SCH5545_LDN_LPC);
|
||||
|
||||
if (!lpc_if) {
|
||||
printk(BIOS_ERR, "ERROR: %s LPC interface LDN not present."
|
||||
"Check the devicetree!\n", dev_path(dev));
|
||||
return;
|
||||
}
|
||||
|
||||
pnp_set_logical_device(lpc_if);
|
||||
|
||||
/*
|
||||
* There are 8 configurable DMA channels. DRQs are set in a little
|
||||
* different manner. Each DMA channel has its own 16-bit register which
|
||||
* is programmed with LDN number (in higher byte) which should use the
|
||||
* IRQ. Ignore the index offset and choose register based on IRQ number
|
||||
* counting from IRQ base. Set valid bit (bit 7) additionally.
|
||||
*/
|
||||
pnp_write_config(dev, SCH5545_DRQ_BASE + (drq * 2) + 1, dev->path.pnp.device | 0x80);
|
||||
|
||||
pnp_set_logical_device(dev);
|
||||
}
|
||||
|
||||
static void sch5545_set_resource(struct device *dev, struct resource *resource)
|
||||
{
|
||||
if (!(resource->flags & IORESOURCE_ASSIGNED)) {
|
||||
/*
|
||||
* The PNP_MSC super IO registers have the IRQ flag set. If no
|
||||
* value is assigned in the devicetree, the corresponding
|
||||
* PNP_MSC register doesn't get written, which should be printed
|
||||
* as warning and not as error.
|
||||
*/
|
||||
if (resource->flags & IORESOURCE_IRQ &&
|
||||
(resource->index != PNP_IDX_IRQ0) &&
|
||||
(resource->index != PNP_IDX_IRQ1))
|
||||
printk(BIOS_WARNING, "WARNING: %s %02lx %s size: "
|
||||
"0x%010llx not assigned\n", dev_path(dev),
|
||||
resource->index, resource_type(resource),
|
||||
resource->size);
|
||||
else
|
||||
printk(BIOS_ERR, "ERROR: %s %02lx %s size: 0x%010llx "
|
||||
"not assigned\n", dev_path(dev), resource->index,
|
||||
resource_type(resource), resource->size);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now store the resource. */
|
||||
if (resource->flags & IORESOURCE_IO) {
|
||||
sch5545_set_iobase(dev, resource->index, resource->base);
|
||||
} else if (resource->flags & IORESOURCE_DRQ) {
|
||||
sch5545_set_drq(dev, resource->index, resource->base);
|
||||
} else if (resource->flags & IORESOURCE_IRQ) {
|
||||
sch5545_set_irq(dev, resource->index, resource->base);
|
||||
} else {
|
||||
printk(BIOS_ERR, "ERROR: %s %02lx unknown resource type\n",
|
||||
dev_path(dev), resource->index);
|
||||
return;
|
||||
}
|
||||
resource->flags |= IORESOURCE_STORED;
|
||||
|
||||
report_resource_stored(dev, resource, "");
|
||||
}
|
||||
|
||||
static void sch5545_set_resources(struct device *dev)
|
||||
{
|
||||
struct resource *res;
|
||||
|
||||
pnp_enter_conf_mode(dev);
|
||||
|
||||
/* Select the logical device (LDN). */
|
||||
pnp_set_logical_device(dev);
|
||||
|
||||
for (res = dev->resource_list; res; res = res->next)
|
||||
sch5545_set_resource(dev, res);
|
||||
|
||||
pnp_exit_conf_mode(dev);
|
||||
}
|
||||
|
||||
static struct device_operations ops = {
|
||||
.read_resources = pnp_read_resources,
|
||||
.set_resources = sch5545_set_resources,
|
||||
.enable_resources = pnp_enable_resources,
|
||||
.enable = pnp_alt_enable,
|
||||
.init = sch5545_init,
|
||||
.ops_pnp_mode = &pnp_conf_mode_55_aa,
|
||||
};
|
||||
|
||||
static struct pnp_info pnp_dev_info[] = {
|
||||
{ NULL, SCH5545_LDN_EMI, PNP_IO0 | PNP_IRQ0 | PNP_IRQ1, 0x0ff0 },
|
||||
{ NULL, SCH5545_LDN_KBC, PNP_IO0 | PNP_IRQ0 | PNP_IRQ1 | PNP_MSC0 | PNP_MSC1, 0x0fff },
|
||||
{ NULL, SCH5545_LDN_UART1, PNP_IO0 | PNP_IRQ0 | PNP_MSC0, 0x0ff8 },
|
||||
{ NULL, SCH5545_LDN_UART2, PNP_IO0 | PNP_IRQ0 | PNP_MSC0, 0x0ff8 },
|
||||
{ NULL, SCH5545_LDN_RR, PNP_IO0 | PNP_IRQ0 | PNP_IRQ1 | PNP_MSC0, 0x0fc0 },
|
||||
{ NULL, SCH5545_LDN_FDC, PNP_IO0 | PNP_IRQ0 | PNP_DRQ0 | PNP_MSC0 | PNP_MSC1 |
|
||||
PNP_MSC2 | PNP_MSC3 | PNP_MSC4 | PNP_MSC5, 0x0ff8, },
|
||||
{ NULL, SCH5545_LDN_LPC, PNP_IO0, 0x0ffe },
|
||||
{ NULL, SCH5545_LDN_PP, PNP_IO0 | PNP_IRQ0 | PNP_DRQ0 | PNP_MSC0 | PNP_MSC1, 0x0ff8 },
|
||||
};
|
||||
|
||||
static void enable_dev(struct device *dev)
|
||||
{
|
||||
pnp_enable_devices(dev, &ops, ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
|
||||
}
|
||||
|
||||
struct chip_operations superio_smsc_sch5545_ops = {
|
||||
CHIP_NAME("SMSC SCH5545 Super I/O")
|
||||
.enable_dev = enable_dev,
|
||||
};
|
Loading…
Reference in New Issue