/*
 * This file is part of the coreboot project.
 *
 * Copyright (C) 2007-2009 coresystems GmbH
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; version 2 of
 * the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
 * MA 02110-1301 USA
 */

/* SMSC LPC47N227 */

Device (SIO1)
{
	Name (_HID, EISAID("PNP0A05"))
	Name (_UID, 1)

	OperationRegion(SIOR, SystemIO, 0x2e, 0x02)
	Field (SIOR, ByteAcc, Nolock, Preserve)
	{
		INDX,	8,
		DATA,	8
	}

	Mutex (SIOM, 0x00)

	Method (READ, 3)
	{
		Acquire (SIOM, 0xffff)
		If (LEqual(Arg0, 0)) {
			Store (0x55, INDX)
			Store (Arg1, INDX)
			Store (DATA, Local1)
			Store (0xaa, INDX)
		}
		And (Local1, Arg2, Local1)
		Release(SIOM)
		Return(Local1)
	}

	Method (WRIT, 3)
	{
		Acquire (SIOM, 0xffff)
		If (LEqual(Arg0, 0)) {
			Store (0x55, INDX)
			Store (Arg1, INDX)
			Store (Arg2, DATA)
			Store (0xaa, INDX)
		}
		Release(SIOM)
	}

	Device (COMA)
	{
		Name(_HID, EISAID("PNP0501"))
		Name(_UID, 1)
		Name(_PRW, Package() { 0x08, 0x03 })

		/* Device Status */
		Method (_STA, 0)
		{
			// Device disabled by coreboot?
			If (LEqual(CMAP, 0)) {
				Return (0)
			}

			// Is the hardware enabled?
			Store (READ(0, 0x24, 0xff), Local0)
			If (LEqual(Local0, 0)) {
				Return (0xd)
			} Else {
				// Power Enabled?
				Store (READ(0, 0x02, 0x08), Local0)
				If (LEqual(Local0, 0)) {
					Return (0x0d)
				} Else {
					Return (0x0f)
				}
			}
		}

		/* Device Disable */
		Method (_DIS, 0)
		{
			WRIT(0, 0x24, 0x00)

			Store(READ(0, 0x28, 0x0f), Local0)
			WRIT(0, 0x28, Local0)

			Store(READ(0, 0x02, 0xff), Local0)
			Not(0x08, Local1)
			And(Local0, Local1, Local0)
			WRIT(0, 0x02, Local0)
		}

		/* Possible Resource Settings */
		Name(_PRS, ResourceTemplate() {
			StartDependentFn(0, 1) {
				IO(Decode16, 0x3f8, 0x3f8, 0x8, 0x8)
				IRQNoFlags() { 4 }
			} EndDependentFn()
		})

		/* Current Resource Settings */
		Method(_CRS, 0)
		{
			Name(NONE, ResourceTemplate() {
				IO(Decode16, 0x000, 0x000, 0x0, 0x0)
				IRQNoFlags() { }
			})

			Name(RSRC, ResourceTemplate() {
				IO(Decode16, 0x3f8, 0x3f8, 0x8, 0x8, _IOA)
				IRQNoFlags(_IRA) { 4 }
			})

			And (_STA(), 0x02, Local0)
			If (LEqual(Local0, 0)) {
				Return(NONE)
			}

			CreateByteField(RSRC,
				\_SB.PCI0.LPCB.SIO1.COMA._CRS._IOA._MIN, IOLO)
			CreateByteField(RSRC, 0x03, IOHI) // Why?
			CreateByteField(RSRC,
				\_SB.PCI0.LPCB.SIO1.COMA._CRS._IOA._MAX, IORL)
			CreateByteField(RSRC, 0x05, IORH) // Why?
			CreateByteField(RSRC,
				\_SB.PCI0.LPCB.SIO1.COMA._CRS._IRA._INT, IRQL)
			
			Store (READ(0, 0x24, 0xff), Local0)
			And (Local0, 0xc0, Local1)
			ShiftRight(Local1, 0x06, Local1)
			ShiftLeft(Local0, 0x02, Local0)
			Store(Local0, IOLO)
			Store(Local1, IOHI)
			Store(IOLO, IORL)
			Store(IOHI, IORH)

			/* Interrupt */
			Store(READ(0, 0x28, 0xf0), Local0)
			ShiftRight(Local0, 4, Local0)
			ShiftLeft(1, Local0, IRQL)
			Return(RSRC)
		}

		/* Set Resource Settings */
		Method(_SRS, 1)
		{
			CreateByteField(Arg0, 0x02, IOLO)
			CreateByteField(Arg0, 0x03, IOHI)
			CreateByteField(Arg0, 0x09, IRQL)

			WRIT(0, 0x24, 0)
			FindSetRightBit(IRQL, Local0)
			Decrement(Local0)
			ShiftLeft(Local0, 4, Local0)

			Store(READ(0, 0x28, 0x0f), Local1)
			Or(Local0, Local1, Local0)
			WRIT(0, 0x28, Local0)

			Store(IOLO, Local0)
			ShiftRight(Local0, 2, Local0)
			And(Local0, 0xfe, Local0)

			Store(IOHI, Local1)
			ShiftLeft(Local1, 6, Local1)
			Or (Local0, Local1, Local0)
			WRIT(0, 0x24, Local0)

			Store(READ(0, 0x02, 0xff), Local0)
			Or(Local0, 0x08, Local0)
			WRIT(0, 0x02, Local0)

			Store(READ(0, 0x07, 0xff), Local0)
			Not(0x40, Local1)
			And (Local0, Local1, Local0)
			WRIT(0, 0x07, Local0)
		}


		/* D0 state - Line drivers are on */
		Method (_PS0, 0)
		{
			Store(READ(0, 0x02, 0xff), Local0)
			Or(Local0, 0x08, Local0)
			WRIT(0, 0x02, Local0)

			Store (READ(0, 0x07, 0xff), Local0)
			Not(0x40, Local1)
			And(Local0, Local1, Local0)
			WRIT(0, 0x07, Local0)
		}

		/* D3 State - Line drivers are off */
		Method(_PS3, 0)
		{
			Store(READ(0, 0x02, 0xff), Local0)
			Not(0x08, Local1)
			And(Local0, Local1, Local0)
			WRIT(0, 0x02, Local0)
		}
	}

	Device (COMB)
	{
		Name(_HID, EISAID("PNP0501"))
		Name(_UID, 2)
		Name(_PRW, Package() { 0x08, 0x03 })

		/* Device Status */
		Method (_STA, 0)
		{
			// Device disabled by coreboot?
			If (LEqual(CMBP, 0)) {
				Return (0)
			}

			/* IRDA? */
			Store(READ(0, 0x0c, 0x38), Local0)
			If (LNotEqual(Local0, Zero)) {
				Return (0)
			}

			// Is the hardware enabled?
			Store (READ(0, 0x25, 0xff), Local0)
			If (LEqual(Local0, 0)) {
				Return (0xd)
			} Else {
				// Power Enabled?
				Store (READ(0, 0x02, 0x80), Local0)
				If (LEqual(Local0, 0)) {
					Return (0x0d)
				} Else {
					Return (0x0f)
				}
			}
		}

		/* Device Disable */
		Method (_DIS, 0)
		{
			WRIT(0, 0x25, 0x00)

			Store(READ(0, 0x28, 0xf0), Local0)
			WRIT(0, 0x28, Local0)

			Store(READ(0, 0x02, 0xff), Local0)
			Not(0x80, Local1)
			And(Local0, Local1, Local0)
			WRIT(0, 0x02, Local0)
		}

		/* Possible Resource Settings */
		Name(_PRS, ResourceTemplate() {
			StartDependentFn(0, 1) {
				IO(Decode16, 0x2f8, 0x2f8, 0x8, 0x8)
				IRQNoFlags() { 3 }
			} EndDependentFn()
		})

		/* Current Resource Settings */
		Method(_CRS, 0)
		{
			Name(NONE, ResourceTemplate() {
				IO(Decode16, 0x000, 0x000, 0x0, 0x0)
				IRQNoFlags() { }
			})

			Name(RSRC, ResourceTemplate() {
				IO(Decode16, 0x2f8, 0x2f8, 0x8, 0x8, _IOB)
				IRQNoFlags(_IRB) { 3 }
			})

			And (_STA(), 0x02, Local0)
			If (LEqual(Local0, 0)) {
				Return(NONE)
			}

			CreateByteField(RSRC,
				\_SB.PCI0.LPCB.SIO1.COMB._CRS._IOB._MIN, IOLO)
			CreateByteField(RSRC, 0x03, IOHI)
			CreateByteField(RSRC,
				\_SB.PCI0.LPCB.SIO1.COMB._CRS._IOB._MAX, IORL)
			CreateByteField(RSRC, 0x05, IORH)
			CreateByteField(RSRC,
				\_SB.PCI0.LPCB.SIO1.COMB._CRS._IRB._INT, IRQL)
			
			Store (READ(0, 0x25, 0xff), Local0)
			And (Local0, 0xc0, Local1)
			ShiftRight(Local1, 0x06, Local1)
			ShiftLeft(Local0, 0x02, Local0)
			Store(Local0, IOLO)
			Store(Local1, IOHI)
			Store(IOLO, IORL)
			Store(IOHI, IORH)

			/* Interrupt */
			Store(READ(0, 0x28, 0x0f), Local0)
			ShiftRight(Local0, 4, Local0)
			ShiftLeft(1, Local0, IRQL)
			Return(RSRC)
		}

		/* Set Resource Settings */
		Method(_SRS, 1)
		{
			CreateByteField(Arg0, 0x02, IOLO)
			CreateByteField(Arg0, 0x03, IOHI)
			CreateByteField(Arg0, 0x09, IRQL)

			WRIT(0, 0x25, 0)
			FindSetRightBit(IRQL, Local0)
			Decrement(Local0)

			Store(READ(0, 0x28, 0xf0), Local1)
			Or(Local0, Local1, Local0)
			WRIT(0, 0x28, Local0)

			Store(IOLO, Local0)
			ShiftRight(Local0, 2, Local0)
			And(Local0, 0xfe, Local0)

			Store(IOHI, Local1)
			ShiftLeft(Local1, 6, Local1)
			Or (Local0, Local1, Local0)
			WRIT(0, 0x25, Local0)

			Store(READ(0, 0x0c, 0xff), Local0)
			Not(0x38, Local1)
			And(Local0, Local1, Local0)
			WRIT(0, 0x0c, Local0)

			Store(READ(0, 0x02, 0xff), Local0)
			Or(Local0, 0x80, Local0)
			WRIT(0, 0x02, Local0)

			Store(READ(0, 0x07, 0xff), Local0)
			Not(0x20, Local1)
			And (Local0, Local1, Local0)
			WRIT(0, 0x07, Local0)
		}

		/* D0 state - Line drivers are on */
		Method (_PS0, 0)
		{
			Store(READ(0, 0x02, 0xff), Local0)
			Or(Local0, 0x80, Local0)
			WRIT(0, 0x02, Local0)

			Store (READ(0, 0x07, 0xff), Local0)
			Not(0x20, Local1)
			And(Local0, Local1, Local0)
			WRIT(0, 0x07, Local0)
		}

		/* D3 State - Line drivers are off */
		Method(_PS3, 0)
		{
			Store(READ(0, 0x02, 0xff), Local0)
			Not(0x80, Local1)
			And(Local0, Local1, Local0)
			WRIT(0, 0x02, Local0)
		}
	}
}

