Richard Spiegel has uploaded this change for review.

View Change

superio/fintek: Add code for superio f81803a

In preparation to add padmelon to coreboot, add the the code for the f81803a
superio. This code will also include ways to program fan control.

TEST=To be tested later with padmelon board.

Change-Id: I1d9a79f681be795dbd07fd0f0f179b06915e07ab
Signed-off-by: Richard Spiegel <richard.spiegel@silverbackltd.com>
---
M src/superio/fintek/Makefile.inc
A src/superio/fintek/common/fan_control.h
A src/superio/fintek/f81803a/Kconfig
A src/superio/fintek/f81803a/Makefile.inc
A src/superio/fintek/f81803a/acpi/superio.asl
A src/superio/fintek/f81803a/f81803a.h
A src/superio/fintek/f81803a/f81803a_hwm.h
A src/superio/fintek/f81803a/fan_control.c
A src/superio/fintek/f81803a/superio.c
9 files changed, 822 insertions(+), 0 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/74/31374/1
diff --git a/src/superio/fintek/Makefile.inc b/src/superio/fintek/Makefile.inc
index 796e519..db683fd 100644
--- a/src/superio/fintek/Makefile.inc
+++ b/src/superio/fintek/Makefile.inc
@@ -26,3 +26,4 @@
subdirs-y += f81216h
subdirs-y += f81865f
subdirs-y += f81866d
+subdirs-y += f81803a
diff --git a/src/superio/fintek/common/fan_control.h b/src/superio/fintek/common/fan_control.h
new file mode 100644
index 0000000..8828c4b
--- /dev/null
+++ b/src/superio/fintek/common/fan_control.h
@@ -0,0 +1,109 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2019 Richard Spiegel <richard.spiegel@silverbackltd.com>
+ * Copyright (C) 2019 Silverback ltd.
+ *
+ * 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.
+ */
+
+#ifndef SUPERIO_FINTEK_FAN_CONTROL_H
+#define SUPERIO_FINTEK_FAN_CONTROL_H
+
+#include <stdint.h>
+#include <arch/io.h>
+
+#define EXTERNAL_SENSOR1 1
+#define EXTERNAL_SENSOR2 2
+#define EXTERNAL_SENSOR3 3
+#define EXTERNAL_SENSOR_4 4
+#define TEMP_SENSOR_THERMISTOR 0
+#define TEMP_SENSOR_BJT 1
+#define TEMP_SENSOR_DEFAULT 2
+
+#define FAN_TYPE_PWM_PUSH_PULL 0
+#define FAN_TYPE_DAC_POWER 1
+#define FAN_TYPE_PWM_OPEN_DRAIN 2
+#define FAN_TYPE_SET_BY_STRAP 3
+#define FAN_TYPE_PWM_CHECK 1 /* bit 0 must be 0 for PWM */
+
+#define FAN_MODE_AUTO_RPM 0
+#define FAN_MODE_AUTO_PWM_DAC 1
+#define FAN_MODE_MANUAL_RPM 2
+#define FAN_MODE_MANUAL_PWM_DAC 3
+#define FAN_MODE_DEFAULT 4
+
+#define FAN_PWM_FREQ_23500 0
+#define FAN_PWM_FREQ_11750 1
+#define FAN_PWM_FREQ_5875 2
+#define FAN_PWM_FREQ_220 3
+
+#define FAN_TEMP_PECI 0
+#define FAN_TEMP_EXTERNAL_1 1
+#define FAN_TEMP_EXTERNAL_2 2
+#define FAN_TEMP_TSI 4
+#define FAN_TEMP_MXM 5
+
+#define FAN_UP_RATE_2HZ 0
+#define FAN_UP_RATE_5HZ 1
+#define FAN_UP_RATE_10HZ 2
+#define FAN_UP_RATE_20HZ 3
+#define FAN_UP_RATE_DEFAULT 4
+#define FAN_UP_RATE_JUMP 8
+
+#define FAN_DOWN_RATE_2HZ 0
+#define FAN_DOWN_RATE_5HZ 1
+#define FAN_DOWN_RATE_10HZ 2
+#define FAN_DOWN_RATE_20HZ 3
+#define FAN_DOWN_RATE_DEFAULT 4
+#define FAN_DOWN_RATE_SAME_AS_UP 5
+#define FAN_DOWN_RATE_JUMP 8
+
+#define FAN_FOLLOW_STEP 0
+#define FAN_FOLLOW_INTERPOLATION 1
+
+#define HWM_STATUS_SUCCESS 0
+#define HWM_STATUS_INVALID_FAN -1
+#define HWM_STATUS_INVALID_TEMP_SOURCE -2
+#define HWM_STATUS_INVALID_TYPE -3
+#define HWM_STATUS_INVALID_MODE -4
+#define HWM_STATUS_INVALID_RATE -5
+#define HWM_STATUS_INVALID_FREQUENCY -6
+#define HWM_STATUS_INVALID_TEMP_SENSOR -7
+#define HWM_STATUS_INVALID_BOUNDARY_VALUE -8
+#define HWM_STATUS_INVALID_SECTION_VALUE -9
+#define HWM_STATUS_BOUNDARY_WRONG_ORDER -20
+#define HWM_STATUS_SECTIONS_WRONG_ORDER -21
+#define HWM_STATUS_WARNING_SENSOR_DISCONECTED 1
+#define HWM_STATUS_WARNING_FAN_NOT_PWM 2
+
+/*
+ * Boundaries order is from highest temp. to lowest. Values from 0 to 127.
+ * Boundaries should be defined as u8 boundaries[fintek_boundaries_size].
+ */
+#define fintek_boundaries_size 4
+/*
+ * Section defines the duty_cycle/voltage to be used based on where the
+ * temperature lies with respect to the boundaries. There are 5 sections
+ * (4 boundaries) and the order must be from highest to lowest. Values
+ * from 0% to 100%, will be converted internally to percent of 255.
+ * Sections should be defined as u8 sections[fintek_sections_size].
+ */
+#define fintek_sections_size 5
+
+int set_sensor_type(u16 base_address, u8 sensor, u8 type);
+int set_fan_temperature_source(u16 base_address, u8 fan, u8 source);
+int set_fan_type_mode(u16 base_address, u8 fan, u8 type, u8 mode);
+int set_pwm_frequency(u16 base_address, u8 fan, u8 frequency);
+int set_sections(u16 base_address, u8 fan, u8 *boundaries, u8 *sections);
+int set_fan_speed_change_rate(u16 base_address, u8 fan, u8 rate_up,
+ u8 rate_down);
+
+#endif /* SUPERIO_FINTEK_FAN_CONTROL_H */
diff --git a/src/superio/fintek/f81803a/Kconfig b/src/superio/fintek/f81803a/Kconfig
new file mode 100644
index 0000000..f1f6ef3
--- /dev/null
+++ b/src/superio/fintek/f81803a/Kconfig
@@ -0,0 +1,24 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2009 Ronald G. Minnich
+## Copyright (C) 2014 Edward O'Callaghan <eocallaghan@alterapraxis.com>
+##
+## 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.
+##
+
+config SUPERIO_FINTEK_F81803A
+ bool
+ select SUPERIO_FINTEK_COMMON_PRE_RAM
+
+config SUPERIO_FINTEK_F81803A_FAN_CONTROL
+ bool
+ depends on SUPERIO_FINTEK_COMMON_PRE_RAM
+ default n
diff --git a/src/superio/fintek/f81803a/Makefile.inc b/src/superio/fintek/f81803a/Makefile.inc
new file mode 100644
index 0000000..a953b4a
--- /dev/null
+++ b/src/superio/fintek/f81803a/Makefile.inc
@@ -0,0 +1,24 @@
+##
+## This file is part of the coreboot project.
+##
+## Copyright (C) 2011 Advanced Micro Devices, Inc.
+##
+## 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; either version 2 of the License, or
+## (at your option) any later version.
+##
+## 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.
+##
+
+ifeq ($(CONFIG_BOOTBLOCK_CONSOLE),y)
+bootblock-$(CONFIG_SUPERIO_FINTEK_F81803A) += ../common/early_serial.c
+endif
+
+romstage-$(CONFIG_SUPERIO_FINTEK_F81803A) += ../common/early_serial.c
+
+ramstage-$(CONFIG_SUPERIO_FINTEK_F81803A) += superio.c
+ramstage-$(CONFIG_SUPERIO_FINTEK_F81803A_FAN_CONTROL) += fan_control.c
diff --git a/src/superio/fintek/f81803a/acpi/superio.asl b/src/superio/fintek/f81803a/acpi/superio.asl
new file mode 100644
index 0000000..7568131
--- /dev/null
+++ b/src/superio/fintek/f81803a/acpi/superio.asl
@@ -0,0 +1,155 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Christoph Grenz <christophg+cb@grenz-bonn.de>
+ * Copyright (C) 2013 secunet Security Networks AG
+ *
+ * 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.
+ */
+
+/*
+ * Include this file into a mainboard's DSDT _SB device tree and it will
+ * expose the F81803A 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
+ * 0x1 UARTA Implemented, partially tested
+ * 0x2 UARTB UART only, partially tested
+ * 0x4 HWM Not implemented
+ * 0x5 KBC Implemented, untested
+ * 0x6 GPIO6 Not implemented
+ * 0x7 WDT0&PLED Not implemented
+ * 0xa ACPI/PME/ERP Partially implemented
+ *
+ * Controllable through preprocessor defines:
+ * SUPERIO_DEV Device identifier for this SIO (e.g. SIO0)
+ * SUPERIO_PNP_BASE I/o address of the first PnP configuration register
+ * F81803A_SHOW_UARTA If defined, UARTA will be exposed.
+ * F81803A_SHOW_UARTB If defined, UARTB will be exposed.
+ * F81803A_SHOW_KBC If defined, the KBC will be exposed.
+ * F81803A_SHOW_PS2M If defined, PS/2 mouse support will be exposed.
+ * F81803A_SHOW_HWMON If defined, the hardware monitor will be exposed.
+ * F81803A_SHOW_PME If defined, the PME/EARP/ACPI will be exposed.
+ */
+#undef SUPERIO_DEV
+#define SUPERIO_DEV SIO0
+#undef SUPERIO_CHIP_NAME
+#define SUPERIO_CHIP_NAME F81803A
+#define SUPERIO_PNP_BASE 0x4E
+#define F81803A_SHOW_PME
+#include <superio/acpi/pnp.asl>
+
+
+
+Device(SUPERIO_DEV) {
+ Name (_HID, EisaId("PNP0A05"))
+ Name (_STR, Unicode("Fintek F81803A Super I/O"))
+ Name (_UID, SUPERIO_UID(SUPERIO_DEV,))
+
+ /* 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 (ADDR, DATA, ByteAcc, NoLock, Preserve)
+ {
+ Offset (0x07),
+ PNP_LOGICAL_DEVICE, 8, /* Logical device selector */
+ Offset (0x30),
+ PNP_DEVICE_ACTIVE, 1, /* Logical device activation */
+ Offset (0x60),
+ PNP_IO0_HIGH_BYTE, 8, /* First I/O port base - high byte */
+ PNP_IO0_LOW_BYTE, 8, /* First I/O port base - low byte */
+ Offset (0x62),
+ PNP_IO1_HIGH_BYTE, 8, /* Second I/O port base - high byte */
+ PNP_IO1_LOW_BYTE, 8, /* Second I/O port base - low byte */
+ Offset (0x70),
+ PNP_IRQ0, 8, /* First IRQ */
+ offset(0xFB),
+ APC5, 8, /* PME ACPI Control Register 5 */
+ }
+
+ Method(_CRS)
+ {
+ /* Announce the used i/o ports to the OS */
+ Return (ResourceTemplate () {
+ IO (Decode16, SUPERIO_PNP_BASE, SUPERIO_PNP_BASE, 0x01, 0x02)
+ })
+ }
+
+ #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 0x87
+ #define PNP_ENTER_MAGIC_2ND 0x87
+ #define PNP_EXIT_MAGIC_1ST 0xaa
+ #include <superio/acpi/pnp_config.asl>
+
+#ifdef F81803A_SHOW_UARTA
+ #undef SUPERIO_UART_LDN
+ #undef SUPERIO_UART_DDN
+ #undef SUPERIO_UART_PM_REG
+ #undef SUPERIO_UART_PM_VAL
+ #undef SUPERIO_UART_PM_LDN
+ #define SUPERIO_UART_LDN 1
+ #define SUPERIO_UART_PM_REG UAPW
+ #define SUPERIO_UART_PM_VAL 0
+ #define SUPERIO_UART_PM_LDN PNP_NO_LDN_CHANGE
+ #include <superio/acpi/pnp_uart.asl>
+#endif
+
+#ifdef F81803A_SHOW_UARTB
+ #undef SUPERIO_UART_LDN
+ #undef SUPERIO_UART_DDN
+ #undef SUPERIO_UART_PM_REG
+ #undef SUPERIO_UART_PM_VAL
+ #undef SUPERIO_UART_PM_LDN
+ #define SUPERIO_UART_LDN 2
+ #define SUPERIO_UART_PM_REG UBPW
+ #define SUPERIO_UART_PM_VAL 0
+ #define SUPERIO_UART_PM_LDN PNP_NO_LDN_CHANGE
+ #include <superio/acpi/pnp_uart.asl>
+#endif
+
+#ifdef F81803A_SHOW_PME
+ #undef SUPERIO_PME_LDN
+ #define SUPERIO_PME_LDN 0x0A
+
+ OperationRegion(APCx, SystemIO, APC5, 0x01)
+ Field(APCx, ByteAcc, Nolock, Preserve) /* bits in PME ACPI CONTROL Reg 5*/
+ {
+ Offset(0x00), /*Control Reg 5 */
+ , 7,
+ PSIN, 1 /* PSIN_FLAG */
+ }
+
+ /* routine to clear PSIN_FLAG in ACPI_CONTROL_REG_5 of SIO */
+ Method(CPSI, 0, Serialized)
+ {
+ /* DBG0("SIO CPSI")*/
+ ENTER_CONFIG_MODE(SUPERIO_PME_LDN)
+ Store(1, PSIN)
+ EXIT_CONFIG_MODE()
+ }
+#endif
+
+}
diff --git a/src/superio/fintek/f81803a/f81803a.h b/src/superio/fintek/f81803a/f81803a.h
new file mode 100644
index 0000000..15361f3
--- /dev/null
+++ b/src/superio/fintek/f81803a/f81803a.h
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Advanced Micro Devices, Inc.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+/*
+ * Datasheet:
+ * - Name: F81803A
+ */
+
+#ifndef SUPERIO_FINTEK_F81803_H
+#define SUPERIO_FINTEK_F81803_H
+
+/* Logical Device Numbers (LDN) */
+#define F81803A_SP1 0x01 /* UART1 */
+#define F81803A_SP2 0x02 /* UART2 */
+#define F81803A_HWM 0x04 /* Hardware Monitor */
+#define F81803A_KBC 0x05 /* Keyboard/Mouse */
+#define F81803A_GPIO 0x06 /* General Purpose I/O (GPIO) */
+#define F81803A_WDT 0x07 /* Watch Dog Timer */
+#define F81803A_PME 0x0a /* Power Management Events (PME) */
+
+/* registers in Fintek F81803A */
+#define LDN_REG 0x07
+
+/* Global Control Registers */
+#define CLOCK_SELECT_REG 0x26
+#define FUNC_PROG_SELECT (1<<3)
+#define CONFIG_PORT_SELECT_REG 0x27
+
+#define TSI_LEVEL_SELECT_REG 0x28 /* FUNC_PROG_SEL = 0 */
+#define TSI_PIN_SELECT_REG 0x28 /* FUNC_PROG_SEL = 1 */
+#define MULTI_FUNC_SEL_REG1 0x29
+#define MULTI_FUNC_SEL_REG2 0x2A
+#define MULTI_FUNC_SEL_REG3 0x2B
+#define MULTI_FUNC_SEL_REG 0x2C
+#define WAKEUP_CONTROL_REG 0x2d
+
+/* LUN A - PME, ACPI, ERP */
+#define PME_DEVICE_ENABLE_REG 0x30
+#define PME_ENABLE (1<<0)
+#define PME_ERP_ENABLE_REG 0xE0
+#define ERP_ENABLE (1<<7)
+#define ERP_PME_EN (1<<1)
+#define ERP_PSOUT_EN (1<<0)
+#define PME_ERP_CONTROL_1_REG 0xE1
+#define PME_ERP_CONTROL_2_REG 0xE2
+#define PME_ERP_PSIN_DEBOUNCE_REG 0xE3
+#define PME_ERP_WAKEUP_ENABLE_REG 0xE8
+#define PME_ERP_MODE_SELECT_REG 0xEC
+#define PME_EVENT_ENABLE_1_REG 0xF0
+#define PME_EVENT_STATUS_1_REG 0xF1
+#define PME_EVENT_ENABLE_2_REG 0xF2
+#define PME_EVENT_STATUS_2_REG 0xF3
+#define PME_ACPI_CONTROL_1_REG 0xF4
+#define PME_ACPI_CONTROL_2_REG 0xF5
+#define PME_ACPI_CONTROL_3_REG 0xF6
+#define PME_ACPI_CONTROL_4_REG 0xF7
+#define PME_ACPI_CONTROL_5_REG 0xFB
+#define PME_ACPI_CONTROL_6_REG 0xFC
+
+#endif /* SUPERIO_FINTEK_F81803_H */
+
diff --git a/src/superio/fintek/f81803a/f81803a_hwm.h b/src/superio/fintek/f81803a/f81803a_hwm.h
new file mode 100644
index 0000000..2fba52b
--- /dev/null
+++ b/src/superio/fintek/f81803a/f81803a_hwm.h
@@ -0,0 +1,92 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2019 Richard Spiegel <richard.spiegel@silverbackltd.com>
+ * Copyright (C) 2019 Silverback ltd.
+ *
+ * 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.
+ */
+
+#ifndef SUPERIO_FINTEK_F81803_HWM_H
+#define SUPERIO_FINTEK_F81803_HWM_H
+
+#define TP_SENSOR_TYPE 0x6b
+#define TP_SENSOR1_TYPE_SHIFT 1
+#define TP_SENSOR2_TYPE_SHIFT 2
+#define TP_SENSOR_TYPE_MASK 0x01
+#define TP_DIODE_STATUS 0x6f
+#define TP_MMX_OPEN 0x40
+#define TP_PECI_OPEN 0x20
+#define TP_TSI_OPEN 0x10
+#define TP_EXTERNAL_SENSOR2_OPEN 0x04
+#define TP_EXTERNAL_SENSOR1_OPEN 0x02
+
+#define FAN_TYPE_REG 0x94
+#define FAN1_TYPE_SHIFT 0
+#define FAN2_TYPE_SHIFT 2
+#define FAN_TYPE_MASK 0x03
+#define FAN_MODE_REG 0x96
+#define FAN1_MODE_SHIFT 0
+#define FAN2_MODE_SHIFT 4
+#define FAN_MODE_MASK 0x07
+#define FAN1_FREQ_SEL_ADD_SHIFT 3 /* FUNC_PROG_SEL = 1 */
+#define FAN2_FREQ_SEL_ADD_SHIFT 4 /* FUNC_PROG_SEL = 1 */
+#define FAN_UP_RATE_REG 0x9a
+#define FAN1_UP_RATE_SHIFT 0
+#define FAN2_UP_RATE_SHIFT 2
+#define FAN_UP_RATE_MASK 0x03
+#define FAN_DOWN_RATE_REG 0x9b
+#define FAN1_DOWN_RATE_SHIFT 0
+#define FAN2_DOWN_RATE_SHIFT 2
+#define FAN_DOWN_RATE_MASK 0x03
+#define FAN_DOWN_RATE_DIFF_FROM_UP_SHIFT 7 /* FUNC_PROG_SEL = 1 */
+#define FAN_DIRECT_LOAD_EN_SHIFT 6 /* FUNC_PROG_SEL = 1 */
+#define FAN_FAULT_TIME_REG 0x9f
+#define FAN_FUNC_PROG_SEL_SHIFT 7
+
+#define FAN1_BOUND_TEMP1 0xa6
+#define FAN1_BOUND_TEMP2 0xa7
+#define FAN1_BOUND_TEMP3 0xa8
+#define FAN1_BOUND_TEMP4 0xa9
+#define FAN1_SECTION_SPEED1 0xaa
+#define FAN1_SECTION_SPEED2 0xab
+#define FAN1_SECTION_SPEED3 0xac
+#define FAN1_SECTION_SPEED4 0xad
+#define FAN1_SECTION_SPEED5 0xae
+#define FAN2_BOUND_TEMP1 0xb6
+#define FAN2_BOUND_TEMP2 0xb7
+#define FAN2_BOUND_TEMP3 0xb8
+#define FAN2_BOUND_TEMP4 0xb9
+#define FAN2_SECTION_SPEED1 0xba
+#define FAN2_SECTION_SPEED2 0xbb
+#define FAN2_SECTION_SPEED3 0xbc
+#define FAN2_SECTION_SPEED4 0xbd
+#define FAN2_SECTION_SPEED5 0xbe
+#define FAN_DETAIL_SKIP (FAN2_BOUND_TEMP1 - FAN1_BOUND_TEMP1)
+
+#define FAN1_TMP_MAPPING 0xaf
+#define FAN2_TMP_MAPPING 0xbf
+#define FAN_TEMP_SEL_HIGH_SHIFT 7
+#define FAN_PWM_FREQ_SEL_SHIFT 6
+#define FAN_INTERPOLATION_SHIFT 4
+#define FAN_JUMP_UP_SHIFT 3
+#define FAN_JUMP_DOWN_SHIFT 2
+#define FAN_TEMP_SEL_LOW_SHIFT 0
+#define FAN_TEMP_SEL_LOW_MASK 0x03
+#define FAN_BIT_MASK 0x01
+
+#define STATUS_INVALID_VALUE -1
+#define STATUS_INVALID_ORDER -2
+
+#define FIRST_FAN 1
+#define LAST_FAN 2
+#define MAX_DUTY 100
+
+#endif /* SUPERIO_FINTEK_F81803_HWM_H */
diff --git a/src/superio/fintek/f81803a/fan_control.c b/src/superio/fintek/f81803a/fan_control.c
new file mode 100644
index 0000000..47c8086
--- /dev/null
+++ b/src/superio/fintek/f81803a/fan_control.c
@@ -0,0 +1,263 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2019 Richard Spiegel <richard.spiegel@silverbackltd.com>
+ * Copyright (C) 2019 Silverback ltd.
+ *
+ * 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.
+ */
+
+#include "../common/fan_control.h"
+#include "f81803a_hwm.h"
+
+static void write_hwm_reg(u16 address, u8 index, u8 value)
+{
+ u16 index_add, data_add;
+ index_add = address | 0x0001; /* force odd address */
+ data_add = index_add + 1;
+ outb(index, index_add);
+ outb(value, data_add);
+}
+
+static u8 read_hwm_reg(u16 address, u8 index)
+{
+ u16 index_add, data_add;
+ index_add = address | 0x0001; /* force odd address */
+ data_add = index_add + 1;
+ outb(index, index_add);
+ return inb(data_add);
+}
+
+static void read_and_or_write(u16 address, u8 index, u8 shift, u8 mask,
+ u8 value)
+{
+ u8 use_mask, use_value;
+ u8 temp = read_hwm_reg(address, index);
+
+ use_mask = mask << shift;
+ use_value = (value & mask) << shift;
+ temp &= ~use_mask;
+ temp |= use_value;
+ write_hwm_reg(address, index, temp);
+}
+
+static inline void set_prog_sel(u16 address, u8 value)
+{
+ read_and_or_write(address, FAN_FAULT_TIME_REG, FAN_FUNC_PROG_SEL_SHIFT,
+ FAN_BIT_MASK, value);
+}
+
+static int check_value_seq(u8 *values, u8 count)
+{
+ u8 last_value = 128; /* max value is 127 */
+ u8 current_value, i;
+ for (i = 0; i < count; i++) {
+ current_value = values[i];
+ if (current_value > 127)
+ return STATUS_INVALID_VALUE;
+ if (current_value >= last_value)
+ return STATUS_INVALID_ORDER;
+ last_value = current_value;
+ }
+ return HWM_STATUS_SUCCESS;
+}
+
+int set_sensor_type(u16 base_address, u8 sensor, u8 type)
+{
+ u8 sensor_status = read_hwm_reg(base_address, TP_DIODE_STATUS);
+ if (sensor == TEMP_SENSOR_DEFAULT)
+ return HWM_STATUS_SUCCESS;
+ switch (sensor) {
+ case EXTERNAL_SENSOR1:
+ if (sensor_status & TP_EXTERNAL_SENSOR1_OPEN)
+ return HWM_STATUS_WARNING_SENSOR_DISCONECTED;
+ read_and_or_write(base_address, TP_SENSOR_TYPE,
+ TP_SENSOR1_TYPE_SHIFT, TP_SENSOR_TYPE_MASK, type);
+ break;
+ case EXTERNAL_SENSOR2:
+ if (sensor_status & TP_EXTERNAL_SENSOR2_OPEN)
+ return HWM_STATUS_WARNING_SENSOR_DISCONECTED;
+ read_and_or_write(base_address, TP_SENSOR_TYPE,
+ TP_SENSOR2_TYPE_SHIFT, TP_SENSOR_TYPE_MASK, type);
+ break;
+ default:
+ return HWM_STATUS_INVALID_TEMP_SENSOR;
+ }
+ return HWM_STATUS_SUCCESS;
+}
+
+int set_fan_temperature_source(u16 base_address, u8 fan, u8 source)
+{
+ u8 index, high_value, low_value;
+
+ if ((fan < FIRST_FAN) || (fan > LAST_FAN))
+ return HWM_STATUS_INVALID_FAN;
+ index = FAN1_TMP_MAPPING;
+ if (fan == LAST_FAN)
+ index += FAN_DETAIL_SKIP;
+ high_value = (source >> 2) & FAN_BIT_MASK;
+ low_value = source & FAN_TEMP_SEL_LOW_MASK;
+ read_and_or_write(base_address, index, FAN_TEMP_SEL_HIGH_SHIFT,
+ FAN_BIT_MASK, high_value);
+ read_and_or_write(base_address, index, FAN_TEMP_SEL_LOW_SHIFT,
+ FAN_TEMP_SEL_LOW_MASK, low_value);
+ return HWM_STATUS_SUCCESS;
+}
+
+int set_fan_type_mode(u16 base_address, u8 fan, u8 type, u8 mode)
+{
+ u8 shift;
+
+ if ((fan < FIRST_FAN) || (fan > LAST_FAN))
+ return HWM_STATUS_INVALID_FAN;
+ set_prog_sel(base_address, 0);
+ if (type < FAN_TYPE_SET_BY_STRAP) {
+ shift = FAN1_TYPE_SHIFT;
+ if (fan == LAST_FAN)
+ shift = FAN2_TYPE_SHIFT;
+ read_and_or_write(base_address, FAN_TYPE_REG, shift,
+ FAN_TYPE_MASK, type);
+ }
+ if (mode < FAN_MODE_DEFAULT) {
+ shift = FAN1_MODE_SHIFT;
+ if (fan == LAST_FAN)
+ shift = FAN2_MODE_SHIFT;
+ read_and_or_write(base_address, FAN_MODE_REG, shift,
+ FAN_MODE_MASK, mode);
+ }
+ return HWM_STATUS_SUCCESS;
+}
+
+int set_pwm_frequency(u16 base_address, u8 fan, u8 frequency)
+{
+ u8 shift, index, byte;
+
+ if ((fan < FIRST_FAN) || (fan > LAST_FAN))
+ return HWM_STATUS_INVALID_FAN;
+ byte = read_hwm_reg(base_address, FAN_TYPE_REG);
+ shift = FAN1_TYPE_SHIFT;
+ if (fan == LAST_FAN)
+ shift = FAN2_TYPE_SHIFT;
+ if (((byte >> shift) & FAN_TYPE_PWM_CHECK) == FAN_TYPE_PWM_CHECK)
+ return HWM_STATUS_WARNING_FAN_NOT_PWM;
+ set_prog_sel(base_address, 1);
+ shift = FAN1_FREQ_SEL_ADD_SHIFT;
+ if (fan == LAST_FAN)
+ shift = FAN2_FREQ_SEL_ADD_SHIFT;
+ byte = (frequency >> 1) & FAN_BIT_MASK;
+ read_and_or_write(base_address, FAN_MODE_REG, shift, FAN_BIT_MASK,
+ byte);
+ set_prog_sel(base_address, 0);
+ index = FAN1_TMP_MAPPING;
+ if (fan == LAST_FAN)
+ index += FAN_DETAIL_SKIP;
+ byte = frequency & FAN_BIT_MASK;
+ read_and_or_write(base_address, index, FAN_PWM_FREQ_SEL_SHIFT,
+ FAN_BIT_MASK, byte);
+ return HWM_STATUS_SUCCESS;
+}
+
+int set_sections(u16 base_address, u8 fan, u8 *boundaries, u8 *sections)
+{
+ int status, temp;
+ u8 i, index, value;
+
+ if ((fan < FIRST_FAN) || (fan > LAST_FAN))
+ return HWM_STATUS_INVALID_FAN;
+ status = check_value_seq(boundaries,
+ fintek_boundaries_size);
+ if (status != HWM_STATUS_SUCCESS) {
+ if (status == STATUS_INVALID_VALUE)
+ return HWM_STATUS_INVALID_BOUNDARY_VALUE;
+ return HWM_STATUS_BOUNDARY_WRONG_ORDER;
+ }
+ status = check_value_seq(sections,
+ fintek_sections_size);
+ if (status != HWM_STATUS_SUCCESS) {
+ if (status == STATUS_INVALID_VALUE)
+ return HWM_STATUS_INVALID_SECTION_VALUE;
+ return HWM_STATUS_SECTIONS_WRONG_ORDER;
+ }
+ index = FAN1_BOUND_TEMP1;
+ if (fan == LAST_FAN)
+ index += FAN_DETAIL_SKIP;
+ for (i = 0; i < fintek_boundaries_size; i++) {
+ value = boundaries[i];
+ write_hwm_reg(base_address, index, value);
+ index++;
+ }
+ index = FAN1_SECTION_SPEED1;
+ if (fan == LAST_FAN)
+ index += FAN_DETAIL_SKIP;
+ for (i = 0; i < fintek_sections_size; i++) {
+ value = sections[i];
+ if (value > 100)
+ return HWM_STATUS_INVALID_SECTION_VALUE;
+ temp = (255 * value) / 100;
+ value = (u8) (temp & 0x00ff);
+ write_hwm_reg(base_address, index, value);
+ index++;
+ }
+ return HWM_STATUS_SUCCESS;
+}
+
+int set_fan_speed_change_rate(u16 base_address, u8 fan, u8 rate_up,
+ u8 rate_down)
+{
+ u8 shift, index;
+
+ if ((fan < FIRST_FAN) || (fan > LAST_FAN))
+ return HWM_STATUS_INVALID_FAN;
+
+ index = FAN1_TMP_MAPPING;
+ if (fan == LAST_FAN)
+ index += FAN_DETAIL_SKIP;
+ shift = FAN1_UP_RATE_SHIFT;
+ if (fan == LAST_FAN)
+ shift = FAN2_UP_RATE_SHIFT;
+
+ if (rate_up == FAN_UP_RATE_JUMP) {
+ read_and_or_write(base_address, index, FAN_JUMP_UP_SHIFT,
+ FAN_BIT_MASK, 1);
+ } else {
+ read_and_or_write(base_address, index, FAN_JUMP_UP_SHIFT,
+ FAN_BIT_MASK, 0);
+ if (rate_up < FAN_UP_RATE_DEFAULT) {
+ read_and_or_write(base_address, FAN_UP_RATE_REG,
+ shift, FAN_UP_RATE_MASK, rate_up);
+ }
+ }
+
+ shift = FAN1_DOWN_RATE_SHIFT;
+ if (fan == LAST_FAN)
+ shift = FAN2_DOWN_RATE_SHIFT;
+ if (rate_down == FAN_DOWN_RATE_JUMP) {
+ read_and_or_write(base_address, index, FAN_JUMP_DOWN_SHIFT,
+ FAN_BIT_MASK, 1);
+ } else {
+ read_and_or_write(base_address, index, FAN_JUMP_UP_SHIFT,
+ FAN_BIT_MASK, 0);
+ set_prog_sel(base_address, 1);
+ if (rate_down < FAN_DOWN_RATE_DEFAULT) {
+ read_and_or_write(base_address, FAN_DOWN_RATE_REG,
+ shift, FAN_DOWN_RATE_MASK, rate_down);
+ read_and_or_write(base_address, FAN_DOWN_RATE_REG,
+ FAN_DOWN_RATE_DIFF_FROM_UP_SHIFT,
+ FAN_BIT_MASK, 0);
+ }
+ if (rate_down == FAN_DOWN_RATE_SAME_AS_UP) {
+ read_and_or_write(base_address, FAN_DOWN_RATE_REG,
+ FAN_DOWN_RATE_DIFF_FROM_UP_SHIFT,
+ FAN_BIT_MASK, 1);
+ }
+ set_prog_sel(base_address, 0);
+ }
+ return HWM_STATUS_SUCCESS;
+}
diff --git a/src/superio/fintek/f81803a/superio.c b/src/superio/fintek/f81803a/superio.c
new file mode 100644
index 0000000..bc4cbba
--- /dev/null
+++ b/src/superio/fintek/f81803a/superio.c
@@ -0,0 +1,80 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2011 Advanced Micro Devices, Inc.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#include <arch/io.h>
+#include <device/device.h>
+#include <device/pnp.h>
+#include <superio/conf_mode.h>
+#include <console/console.h>
+#include <stdlib.h>
+#include <pc80/keyboard.h>
+#include "f81803a.h"
+
+static void f81803a_pme_init(struct device *dev)
+{
+ pnp_enter_conf_mode(dev);
+ pnp_write_config(dev, LDN_REG, F81803A_PME);
+ /* enable ERP function*/
+ /* also set PSIN to generate PSOUT*/
+ pnp_write_config(dev, PME_ERP_ENABLE_REG, ERP_ENABLE | ERP_PSOUT_EN);
+ pnp_exit_conf_mode(dev);
+}
+
+static void f81803a_init(struct device *dev)
+{
+ if (!dev->enabled)
+ return;
+ switch (dev->path.pnp.device) {
+ /* TODO: Might potentially need code for HWM or FDC etc. */
+ case F81803A_KBC:
+ pc_keyboard_init(NO_AUX_DEVICE);
+ break;
+ case F81803A_PME:
+ f81803a_pme_init(dev);
+ break;
+ }
+
+}
+
+static struct device_operations ops = {
+ .read_resources = pnp_read_resources,
+ .set_resources = pnp_set_resources,
+ .enable_resources = pnp_enable_resources,
+ .enable = pnp_alt_enable,
+ .init = f81803a_init,
+ .ops_pnp_mode = &pnp_conf_mode_8787_aa,
+};
+
+static struct pnp_info pnp_dev_info[] = {
+ /* TODO: Some of the 0x7f8 etc. values may not be correct. */
+ { &ops, F81803A_SP1, PNP_IO0 | PNP_IRQ0, 0x7f8, },
+ { &ops, F81803A_SP2, PNP_IO0 | PNP_IRQ0, 0x7f8, },
+ { &ops, F81803A_HWM, PNP_IO0 | PNP_IRQ0, 0xff8, },
+ { &ops, F81803A_KBC, PNP_IO0 | PNP_IRQ0 | PNP_IRQ1, 0x07ff, },
+ { &ops, F81803A_GPIO, PNP_IO0 | PNP_IRQ0, 0x7f8, },
+ //{ &ops, F81803A_WDT, PNP_IO0, 0x7f8 },
+ { &ops, F81803A_PME, },
+};
+
+static void enable_dev(struct device *dev)
+{
+ printk(BIOS_INFO, "F81803A : %s\n", __func__);
+ pnp_enable_devices(dev, &ops, ARRAY_SIZE(pnp_dev_info), pnp_dev_info);
+}
+
+struct chip_operations superio_fintek_f81803a_ops = {
+ .enable_dev = enable_dev
+};

To view, visit change 31374. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: I1d9a79f681be795dbd07fd0f0f179b06915e07ab
Gerrit-Change-Number: 31374
Gerrit-PatchSet: 1
Gerrit-Owner: Richard Spiegel <richard.spiegel@silverbackltd.com>
Gerrit-MessageType: newchange