Harrie Paijmans has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/87198?usp=email )
Change subject: superio/fintek: Add support for f81966d ......................................................................
superio/fintek: Add support for f81966d
This patch adds support for the Fintek f81966d SuperIO, which is very similar to the fintek/f81866d.
Datasheet: - Name: F81966D/A, Release Date: Oct 2023, Version: V0.21P
BUG=NA TEST=Customer platform with F81966D, verified GPIO configuration.
Change-Id: Ibe3987b6e15eb07b92d7f5a7de2bd511de85e2f7 Signed-off-by: Harrie Paijmans hpaijmans@eltan.com --- M src/superio/fintek/Makefile.mk A src/superio/fintek/f81966d/Kconfig A src/superio/fintek/f81966d/Makefile.mk A src/superio/fintek/f81966d/chip.h A src/superio/fintek/f81966d/f81966d.h A src/superio/fintek/f81966d/f81966d_gpio.c A src/superio/fintek/f81966d/f81966d_hwm.c A src/superio/fintek/f81966d/f81966d_uart.c A src/superio/fintek/f81966d/fintek_internal.h A src/superio/fintek/f81966d/superio.c 10 files changed, 578 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/98/87198/1
diff --git a/src/superio/fintek/Makefile.mk b/src/superio/fintek/Makefile.mk index b9cfe4d..5e9708f 100644 --- a/src/superio/fintek/Makefile.mk +++ b/src/superio/fintek/Makefile.mk @@ -11,3 +11,4 @@ subdirs-y += f81865f subdirs-y += f81866d subdirs-y += f81803a +subdirs-y += f81966d diff --git a/src/superio/fintek/f81966d/Kconfig b/src/superio/fintek/f81966d/Kconfig new file mode 100644 index 0000000..3f66f46 --- /dev/null +++ b/src/superio/fintek/f81966d/Kconfig @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config SUPERIO_FINTEK_F81966D + bool + select SUPERIO_FINTEK_COMMON_PRE_RAM diff --git a/src/superio/fintek/f81966d/Makefile.mk b/src/superio/fintek/f81966d/Makefile.mk new file mode 100644 index 0000000..7016b0c --- /dev/null +++ b/src/superio/fintek/f81966d/Makefile.mk @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +ramstage-$(CONFIG_SUPERIO_FINTEK_F81966D) += f81966d_hwm.c f81966d_uart.c f81966d_gpio.c +ramstage-$(CONFIG_SUPERIO_FINTEK_F81966D) += superio.c diff --git a/src/superio/fintek/f81966d/chip.h b/src/superio/fintek/f81966d/chip.h new file mode 100644 index 0000000..cf7c8e8 --- /dev/null +++ b/src/superio/fintek/f81966d/chip.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef SUPERIO_FINTEK_F81966D_CHIP_H +#define SUPERIO_FINTEK_F81966D_CHIP_H + +#include <stdint.h> + +struct superio_fintek_f81966d_config { + /* AMD TSI */ + uint8_t hwm_amd_tsi_addr; + uint8_t hwm_amd_tsi_control; + + /* Fan control */ + uint8_t hwm_fan_select; + uint8_t hwm_fan_mode; + uint8_t hwm_fan3_control; + uint8_t hwm_fan2_temp_map_select; + + uint8_t hwm_fan2_bound1; + uint8_t hwm_fan2_bound2; + uint8_t hwm_fan2_bound3; + uint8_t hwm_fan2_bound4; + uint8_t hwm_fan2_seg1_speed; + uint8_t hwm_fan2_seg2_speed; + uint8_t hwm_fan2_seg3_speed; + uint8_t hwm_fan2_seg4_speed; + uint8_t hwm_fan2_seg5_speed; + + /* Temp sensor type */ + uint8_t hwm_temp_sens_type; + + /* gpio control, range bits [0:7] map to GPIOx0:GPIOx7 */ + uint8_t use_gpio0; + uint8_t gpio0_enable; + uint8_t gpio0_data; + + uint8_t use_gpio1; + uint8_t gpio1_enable; + uint8_t gpio1_data; + + uint8_t use_gpio2; + uint8_t gpio2_enable; + uint8_t gpio2_data; + + uint8_t use_gpio3; + uint8_t gpio3_enable; + uint8_t gpio3_data; + + uint8_t use_gpio4; + uint8_t gpio4_enable; + uint8_t gpio4_data; + + uint8_t use_gpio5; + uint8_t gpio5_enable; + uint8_t gpio5_data; + + uint8_t use_gpio6; + uint8_t gpio6_enable; + uint8_t gpio6_data; + + uint8_t use_gpio7; + uint8_t gpio7_enable; + uint8_t gpio7_data; + + uint8_t use_gpio8; + uint8_t gpio8_enable; + uint8_t gpio8_data; + uint8_t gpio8_drive; +}; + +#endif /* SUPERIO_FINTEK_F81966D_CHIP_H */ diff --git a/src/superio/fintek/f81966d/f81966d.h b/src/superio/fintek/f81966d/f81966d.h new file mode 100644 index 0000000..15811c5 --- /dev/null +++ b/src/superio/fintek/f81966d/f81966d.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef SUPERIO_FINTEK_F81966_H +#define SUPERIO_FINTEK_F81966_H + +/* + * Datasheet: + * - Name: F81966D/A, Release Date: Oct 2023, Version: V0.21P + */ + +/* General registers */ +#define LDN_REG 0x07 +#define PORT_SELECT_REGISTER 0x27 +#define MULTI_FUNC_SEL1_REG 0x28 +#define MULTI_FUNC_SEL3_REG 0x29 +#define GPIO_FUNC_SEL_REG 0x2a /* differs on bank: 0=11/10 1=13/12 2=15/14 3=17/16 */ +#define MULTI_FUNC_SEL4_REG 0x2b +#define MULTI_FUNC_SEL5_REG 0x2c +#define IRQ_SHARE_REGISTER 0xf0 +#define FIFO_SEL_MODE 0xf6 + +/* Logical Device Numbers (LDN) */ +#define F81966D_SP1 0x10 /* UART1 */ +#define F81966D_SP2 0x11 /* UART2 */ +#define F81966D_SP3 0x12 /* UART3 */ +#define F81966D_SP4 0x13 /* UART4 */ +#define F81966D_SP5 0x14 /* UART5 */ +#define F81966D_SP6 0x15 /* UART6 */ +#define F81966D_PP 0x03 /* Parallel Port */ +#define F81966D_HWM 0x04 /* Hardware Monitor */ +#define F81966D_KBC 0x05 /* Keyboard/Mouse */ +#define F81966D_GPIO 0x06 /* General Purpose I/O (GPIO) */ +#define F81966D_WDT 0x07 /* Watchdog */ +#define F81966D_PME 0x0a /* Power Management Events (PME) */ +#define F81966D_SPI 0x0f /* SPI */ + +/* Register addresses for HWM */ +/* Choose between AMD and Intel */ +#define HWM_AMD_TSI_ADDR 0x08 +#define HWM_AMD_TSI_CONTROL_REG 0x0A +/* Set temp sensors type */ +#define TEMP_SENS_TYPE_REG 0x6B +/* FAN prog sel */ +#define HWM_FAN3_CONTROL 0x9A +#define HWM_FAN_SEL 0x94 +#define HWM_FAN_MODE 0x96 +#define HWM_FAN2_TEMP_MAP_SEL 0xBF +/* Fan 2 - 4 Boundaries */ +#define HWM_FAN2_BOUND1 0xB6 +#define HWM_FAN2_BOUND2 0xB7 +#define HWM_FAN2_BOUND3 0xB8 +#define HWM_FAN2_BOUND4 0xB9 +/* Fan 2 - 5 Segment speeds */ +#define HWM_FAN2_SEG1_SPEED_COUNT 0xBA +#define HWM_FAN2_SEG2_SPEED_COUNT 0xBB +#define HWM_FAN2_SEG3_SPEED_COUNT 0xBC +#define HWM_FAN2_SEG4_SPEED_COUNT 0xBD +#define HWM_FAN2_SEG5_SPEED_COUNT 0xBE + +/* Register addresses for GPIO */ +/* GPIO registers */ +#define GPIO0X_OUTPUT_ENABLE_REGISTER 0xf0 +#define GPIO1X_OUTPUT_ENABLE_REGISTER 0xe0 +#define GPIO2X_OUTPUT_ENABLE_REGISTER 0xd0 +#define GPIO3X_OUTPUT_ENABLE_REGISTER 0xc0 +#define GPIO4X_OUTPUT_ENABLE_REGISTER 0xb0 +#define GPIO5X_OUTPUT_ENABLE_REGISTER 0xa0 +#define GPIO6X_OUTPUT_ENABLE_REGISTER 0x90 +#define GPIO7X_OUTPUT_ENABLE_REGISTER 0x80 +#define GPIO8X_OUTPUT_ENABLE_REGISTER 0x88 +#define GPIO0X_OUTPUT_DATA_REGISTER 0xf1 +#define GPIO1X_OUTPUT_DATA_REGISTER 0xe1 +#define GPIO2X_OUTPUT_DATA_REGISTER 0xd1 +#define GPIO3X_OUTPUT_DATA_REGISTER 0xc1 +#define GPIO4X_OUTPUT_DATA_REGISTER 0xb1 +#define GPIO5X_OUTPUT_DATA_REGISTER 0xa1 +#define GPIO6X_OUTPUT_DATA_REGISTER 0x91 +#define GPIO7X_OUTPUT_DATA_REGISTER 0x81 +#define GPIO8X_OUTPUT_DATA_REGISTER 0x89 +#define GPIO8X_DRIVE_ENABLE_REGISTER 0x8B + +#endif /* SUPERIO_FINTEK_F81966_H */ diff --git a/src/superio/fintek/f81966d/f81966d_gpio.c b/src/superio/fintek/f81966d/f81966d_gpio.c new file mode 100644 index 0000000..844b660 --- /dev/null +++ b/src/superio/fintek/f81966d/f81966d_gpio.c @@ -0,0 +1,204 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pnp.h> +#include "fintek_internal.h" +#include "chip.h" +#include "f81966d.h" + +/* + * Set the values for the register using the mask + * The mask has the writable bits high so the write the bits [3:2] & [0] the mask would be + * 0xd = 0b00001101. +*/ +void setreg(struct device *dev, u8 port, u8 mask, u8 val) +{ + u8 tmp = pnp_read_config(dev, port); + pnp_write_config(dev, port, (tmp & ~mask) | (val & mask)); +} + +/* + * Select a bank as indicated by the spec. + * Write the BANKID and 0 registers in the same call. + */ +u8 selectbank(struct device *dev, u8 bank) +{ + if (bank > 3) { + printk(BIOS_WARNING, "%s: GPIO Bank not in range.\n", __func__); + return -1; + } + /* write 0x27[3:2] = BANKID, 0x27[0] = 0 */ + setreg(dev, PORT_SELECT_REGISTER, 0x0D, (bank << 2)); + return 0; +} + +/* + * F81966D_gpio_init enables all necessary registers for GPIO + * Fintek needs to know if pins are used as GPIO or UART pins + * Share interrupt usage needs to be enabled + */ +void f81966d_gpio_init(struct device *dev) +{ + struct superio_fintek_f81966d_config *conf = dev->chip_info; + struct resource *res = probe_resource(dev, PNP_IDX_IO0); + u8 tmp; + + if (!res) { + printk(BIOS_WARNING, "%s: No GPIO resource found.\n", __func__); + return; + } + + pnp_enter_conf_mode(dev); + + if (conf->use_gpio0) { + selectbank(dev, 0); /* Select BANK0 */ + setreg(dev, MULTI_FUNC_SEL5_REG, 0x01, 0x1); /* 0x2c[0] = 1 */ + + selectbank(dev, 0); /* Select BANK0 */ + setreg(dev, MULTI_FUNC_SEL5_REG, 0x02, 0x2); /* 0x2c[1] = 1 */ + + selectbank(dev, 0); /* Select BANK0 */ + setreg(dev, MULTI_FUNC_SEL5_REG, 0x04, 0x4); /* 0x2c[2] = 1 */ + /* "0x27[3:2] = 01; 0x27[0] = 0" is equivalent to "selectbank(dev, 1);" but kept in line with datasheet */ + setreg(dev, PORT_SELECT_REGISTER, 0x0D, 0x4); /* 0x27[3:2] = 01; 0x27[0] = 0 */ + setreg(dev, MULTI_FUNC_SEL5_REG, 0x04, 0x0); /* 0x2c[2] = 0 */ + + selectbank(dev, 0); /* Select BANK0 */ + setreg(dev, MULTI_FUNC_SEL5_REG, 0x08, 0x8); /* 0x2c[3] = 1 */ + selectbank(dev, 1); /* Select BANK1 */ + setreg(dev, MULTI_FUNC_SEL5_REG, 0x40, 0x0); /* 0x2c[6] = 0 */ + + selectbank(dev, 0); /* Select BANK0 */ + setreg(dev, MULTI_FUNC_SEL5_REG, 0x10, 0x10); /* 0x2c[4] = 1 */ + + selectbank(dev, 0); /* Select BANK0 */ + setreg(dev, MULTI_FUNC_SEL1_REG, 0x0C, 0x00); /* 0x28[3:2] = 00 */ + + setreg(dev, GPIO0X_OUTPUT_ENABLE_REGISTER, 0xFF, conf->gpio0_enable); + setreg(dev, GPIO0X_OUTPUT_DATA_REGISTER, 0xFF, conf->gpio0_data); + } + + if (conf->use_gpio1) { + selectbank(dev, 0); /* Select BANK0 */ + setreg(dev, GPIO_FUNC_SEL_REG, 0x07, 0x000); /* GPIO10_FUNC_SEL = 000 */ + setreg(dev, GPIO_FUNC_SEL_REG, 0x70, 0x000); /* GPIO11_FUNC_SEL = 000 */ + + selectbank(dev, 0); /* Select BANK0 */ + setreg(dev, MULTI_FUNC_SEL1_REG, 0x0C, 0x00); /* 0x28[4] = 0 */ + selectbank(dev, 1); /* Select BANK1 */ + setreg(dev, MULTI_FUNC_SEL5_REG, 0x01, 0x0); /* 0x2c[0] = 0 */ + selectbank(dev, 1); /* Select BANK1 */ + setreg(dev, GPIO_FUNC_SEL_REG, 0x07, 0x000); /* GPIO12_FUNC_SEL = 000 */ + + selectbank(dev, 0); /* Select BANK0 */ + setreg(dev, MULTI_FUNC_SEL5_REG, 0x10, 0x0); /* 0x2c[4] = 0 */ + selectbank(dev, 1); /* Select BANK1 */ + setreg(dev, MULTI_FUNC_SEL1_REG, 0x0C, 0x00); /* 0x28[4] = 0 */ + selectbank(dev, 1); /* Select BANK1 */ + setreg(dev, GPIO_FUNC_SEL_REG, 0X70, 0x000); /* GPIO13_FUNC_SEL = 000 */ + + selectbank(dev, 2); /* Select BANK2 */ + setreg(dev, GPIO_FUNC_SEL_REG, 0x07, 0x000); /* GPIO14_FUNC_SEL = 000 */ + + selectbank(dev, 2); /* Select BANK2 */ + setreg(dev, GPIO_FUNC_SEL_REG, 0x70, 0x000); /* GPIO15_FUNC_SEL = 000 */ + + selectbank(dev, 1); /* Select BANK1 */ + setreg(dev, MULTI_FUNC_SEL5_REG, 0X20, 0x0); /* 0x2c[5] = 0 */ + selectbank(dev, 3); /* Select BANK3 */ + setreg(dev, GPIO_FUNC_SEL_REG, 0x07, 0x000); /* GPIO16_FUNC_SEL = 000 */ + + selectbank(dev, 0); /* Select BANK0 */ + setreg(dev, MULTI_FUNC_SEL1_REG, 0x80, 0x00); /* 0x28[7] = 0 */ + selectbank(dev, 3); /* Select BANK3 */ + setreg(dev, GPIO_FUNC_SEL_REG, 0x70, 0x000); /* GPIO17_FUNC_SEL = 000 */ + + setreg(dev, GPIO1X_OUTPUT_ENABLE_REGISTER, 0xFF, conf->gpio1_enable); + setreg(dev, GPIO1X_OUTPUT_DATA_REGISTER, 0xFF, conf->gpio1_data); + } + + if (conf->use_gpio2) { + selectbank(dev, 2); /* Select BANK2 */ + setreg(dev, MULTI_FUNC_SEL5_REG, 0x01, 0x1); /* 0x2c[0] = 1 */ + selectbank(dev, 1); /* Select BANK1 */ + setreg(dev, MULTI_FUNC_SEL5_REG, 0x02, 0x0); /* 0x2c[1] = 0 */ + + selectbank(dev, 2); /* Select BANK2 */ + setreg(dev, MULTI_FUNC_SEL5_REG, 0xFE, 0xFE); /* 0x2c[7:1] = 1111110 */ + + setreg(dev, GPIO2X_OUTPUT_ENABLE_REGISTER, 0xFF, conf->gpio2_enable); + setreg(dev, GPIO2X_OUTPUT_DATA_REGISTER, 0xFF, conf->gpio2_data); + } + + if (conf->use_gpio3) { + selectbank(dev, 0); /* Select BANK0 */ + setreg(dev, MULTI_FUNC_SEL3_REG, 0x30, 0x00); /* 0x29[5:4] = 00 */ + + setreg(dev, GPIO3X_OUTPUT_ENABLE_REGISTER, 0xFF, conf->gpio3_enable); + setreg(dev, GPIO3X_OUTPUT_DATA_REGISTER, 0xFF, conf->gpio3_data); + } + + if (conf->use_gpio4) { + selectbank(dev, 0); /* Select BANK0 */ + setreg(dev, MULTI_FUNC_SEL3_REG, 0xC0, 0x00); /* 0x29[7:6] = 00 */ + + setreg(dev, GPIO4X_OUTPUT_ENABLE_REGISTER, 0xFF, conf->gpio4_enable); + setreg(dev, GPIO4X_OUTPUT_DATA_REGISTER, 0xFF, conf->gpio4_data); + } + + if (conf->use_gpio5) { + setreg(dev, PORT_SELECT_REGISTER, 0x02, 0x00); /* 0x27[1] = 0 */ + selectbank(dev, 0); /* Select BANK0 */ + setreg(dev, MULTI_FUNC_SEL1_REG, 0x03, 0x00); /* 0x28[1:0] = 00 */ + selectbank(dev, 1); /* Select BANK1 */ + setreg(dev, MULTI_FUNC_SEL1_REG, 0x10, 0x00); /* 0x28[4] = 0 */ + + /* set in/output pins */ + setreg(dev, GPIO5X_OUTPUT_ENABLE_REGISTER, 0xFF, conf->gpio5_enable); + setreg(dev, GPIO5X_OUTPUT_DATA_REGISTER, 0xFF, conf->gpio5_data); + } + + /* Enable gpio 6x */ + if (conf->use_gpio6) { + selectbank(dev, 0); /* Select BANK0 */ + setreg(dev, MULTI_FUNC_SEL1_REG, 0x0C, 0x00); /* 0x28[1:0] = 00 */ + setreg(dev, MULTI_FUNC_SEL4_REG, 0xE0, 0x00); /* 0x2b[0] = 0 */ + + setreg(dev, GPIO6X_OUTPUT_ENABLE_REGISTER, 0xFF, conf->gpio6_enable); + setreg(dev, GPIO6X_OUTPUT_DATA_REGISTER, 0xFF, conf->gpio6_data); + } + + if (conf->use_gpio7) { + selectbank(dev, 0); /* Select BANK0 */ + setreg(dev, MULTI_FUNC_SEL1_REG, 0x20, 0x20); /* 0x28[5] = 1 */ + setreg(dev, MULTI_FUNC_SEL4_REG, 0x01, 0x00); /* 0x2b[0] = 0 */ + + /* set in/output pins */ + setreg(dev, GPIO7X_OUTPUT_ENABLE_REGISTER, 0xFF, conf->gpio7_enable); + setreg(dev, GPIO7X_OUTPUT_DATA_REGISTER, 0xFF, conf->gpio7_data); + } + + if (conf->use_gpio8) { + selectbank(dev, 0); /* Select BANK0 */ + setreg(dev, MULTI_FUNC_SEL1_REG, 0x20, 0x20); /* 0x28[5] = 1 */ + setreg(dev, MULTI_FUNC_SEL4_REG, 0x40, 0x00); /* 0x2b[6] = 0 */ + + /* set in/output pins */ + setreg(dev, GPIO8X_OUTPUT_ENABLE_REGISTER, 0xFF, conf->gpio8_enable); + setreg(dev, GPIO8X_OUTPUT_DATA_REGISTER, 0xFF, conf->gpio8_data); + + /* set Drive Enable */ + setreg(dev, GPIO8X_DRIVE_ENABLE_REGISTER, 0xFF, conf->gpio8_drive); + } + + /* Select GPIO in LDN register */ + pnp_write_config(dev, LDN_REG, dev->path.pnp.device & 0xFF); + /* Set IRQ trigger mode from active low to high (Bit 3) */ + tmp = pnp_read_config(dev, FIFO_SEL_MODE); + pnp_write_config(dev, FIFO_SEL_MODE, tmp | 0x8); + /* Enable share interrupt (Bit 0) */ + pnp_write_config(dev, IRQ_SHARE_REGISTER, 0x01); + + pnp_exit_conf_mode(dev); +} diff --git a/src/superio/fintek/f81966d/f81966d_hwm.c b/src/superio/fintek/f81966d/f81966d_hwm.c new file mode 100644 index 0000000..b3e7e28 --- /dev/null +++ b/src/superio/fintek/f81966d/f81966d_hwm.c @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* Setup only for Fan2 + * TODO: Add support for Fan1 and Fan3 + */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pnp.h> +#include "fintek_internal.h" +#include "chip.h" +#include "f81966d.h" + +void f81966d_hwm_init(struct device *dev) +{ + struct resource *res = probe_resource(dev, PNP_IDX_IO0); + + if (!res) { + printk(BIOS_WARNING, "Super I/O HWM: No HWM resource found.\n"); + return; + } + + const struct superio_fintek_f81966d_config *reg = dev->chip_info; + u16 port = res->base; + + pnp_enter_conf_mode(dev); + + /* Use AMD TSI */ + pnp_write_index(port, HWM_AMD_TSI_ADDR, reg->hwm_amd_tsi_addr); + pnp_write_index(port, HWM_AMD_TSI_CONTROL_REG, reg->hwm_amd_tsi_control); + + /* Set temp1 sensor to thermistor */ + pnp_write_index(port, TEMP_SENS_TYPE_REG, reg->hwm_temp_sens_type); + + /* Select FAN Type */ + pnp_write_index(port, HWM_FAN_SEL, reg->hwm_fan_select); + + /* Select FAN Mode*/ + pnp_write_index(port, HWM_FAN_MODE, reg->hwm_fan_mode); + + /* Set Boundaries */ + pnp_write_index(port, HWM_FAN2_BOUND1, reg->hwm_fan2_bound1); + pnp_write_index(port, HWM_FAN2_BOUND2, reg->hwm_fan2_bound2); + pnp_write_index(port, HWM_FAN2_BOUND3, reg->hwm_fan2_bound3); + pnp_write_index(port, HWM_FAN2_BOUND4, reg->hwm_fan2_bound4); + + /* Set Speed */ + pnp_write_index(port, HWM_FAN2_SEG1_SPEED_COUNT, reg->hwm_fan2_seg1_speed); + pnp_write_index(port, HWM_FAN2_SEG2_SPEED_COUNT, reg->hwm_fan2_seg2_speed); + pnp_write_index(port, HWM_FAN2_SEG3_SPEED_COUNT, reg->hwm_fan2_seg3_speed); + pnp_write_index(port, HWM_FAN2_SEG4_SPEED_COUNT, reg->hwm_fan2_seg4_speed); + pnp_write_index(port, HWM_FAN2_SEG5_SPEED_COUNT, reg->hwm_fan2_seg5_speed); + + /* Set Fan control freq */ + pnp_write_index(port, HWM_FAN3_CONTROL, reg->hwm_fan3_control); + pnp_write_index(port, HWM_FAN2_TEMP_MAP_SEL, reg->hwm_fan2_temp_map_select); + + pnp_exit_conf_mode(dev); +} diff --git a/src/superio/fintek/f81966d/f81966d_uart.c b/src/superio/fintek/f81966d/f81966d_uart.c new file mode 100644 index 0000000..8c2b697 --- /dev/null +++ b/src/superio/fintek/f81966d/f81966d_uart.c @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <console/console.h> +#include <device/device.h> +#include <device/pnp.h> +#include "fintek_internal.h" +#include "chip.h" +#include "f81966d.h" + +/* + * F81966D_uart_init enables all necessary registers for UART 3/4 + * Fintek needs to know if pins are used as GPIO or UART pins + * Share interrupt usage needs to be enabled + */ +void f81966d_uart_init(struct device *dev) +{ + struct resource *res = probe_resource(dev, PNP_IDX_IO0); + u8 tmp; + + if (!res) { + printk(BIOS_WARNING, "%s: No UART resource found.\n", __func__); + return; + } + + pnp_enter_conf_mode(dev); + + /* + * Set Port Select Register (Bit 0) = 0 + * before accessing Multi Function Select 3 Register + */ + tmp = pnp_read_config(dev, PORT_SELECT_REGISTER); + pnp_write_config(dev, PORT_SELECT_REGISTER, tmp & 0xFE); + + /* Set UART 3 function (Bit 4/5), otherwise pin 36-43 are GPIO */ + if (dev->path.pnp.device == F81966D_SP3) { + tmp = pnp_read_config(dev, MULTI_FUNC_SEL3_REG); + pnp_write_config(dev, MULTI_FUNC_SEL3_REG, tmp | 0x30); + } + + /* Set UART 4 function (Bit 6/7), otherwise pin 44-51 are GPIO */ + if (dev->path.pnp.device == F81966D_SP4) { + tmp = pnp_read_config(dev, MULTI_FUNC_SEL3_REG); + pnp_write_config(dev, MULTI_FUNC_SEL3_REG, tmp | 0xC0); + } + + /* Select UART X in LDN register */ + pnp_write_config(dev, LDN_REG, dev->path.pnp.device & 0xff); + /* Set IRQ trigger mode from active low to high (Bit 3) */ + tmp = pnp_read_config(dev, FIFO_SEL_MODE); + pnp_write_config(dev, FIFO_SEL_MODE, tmp | 0x8); + /* Enable share interrupt (Bit 0) */ + pnp_write_config(dev, IRQ_SHARE_REGISTER, 0x01); + + pnp_exit_conf_mode(dev); +} diff --git a/src/superio/fintek/f81966d/fintek_internal.h b/src/superio/fintek/f81966d/fintek_internal.h new file mode 100644 index 0000000..3f13c68 --- /dev/null +++ b/src/superio/fintek/f81966d/fintek_internal.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef SUPERIO_FINTEK_F81966D_INTERNAL_H +#define SUPERIO_FINTEK_F81966D_INTERNAL_H + +#include <device/pnp.h> + +void f81966d_hwm_init(struct device *dev); +void f81966d_uart_init(struct device *dev); +void f81966d_gpio_init(struct device *dev); + +u8 selectbank(struct device *dev, u8 bank); +void setreg(struct device *dev, u8 port, u8 mask, u8 val); + +#endif /* SUPERIO_FINTEK_F81966D_INTERNAL_H */ diff --git a/src/superio/fintek/f81966d/superio.c b/src/superio/fintek/f81966d/superio.c new file mode 100644 index 0000000..952f3d0 --- /dev/null +++ b/src/superio/fintek/f81966d/superio.c @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include <device/device.h> +#include <device/pnp.h> +#include <superio/conf_mode.h> +#include <pc80/keyboard.h> + +#include "chip.h" +#include "fintek_internal.h" +#include "f81966d.h" + +static void f81966d_init(struct device *dev) +{ + if (!dev->enabled) + return; + + switch (dev->path.pnp.device) { + case F81966D_KBC: + pc_keyboard_init(NO_AUX_DEVICE); + break; + case F81966D_HWM: + /* Fixing temp sensor read out and init Fan control */ + f81966d_hwm_init(dev); + break; + case F81966D_SP1: + /* Enable Uart1 and IRQ share register */ + f81966d_uart_init(dev); + break; + case F81966D_SP2: + /* Enable Uart2 and IRQ share register */ + f81966d_uart_init(dev); + break; + case F81966D_SP3: + /* Enable Uart3 and IRQ share register */ + f81966d_uart_init(dev); + break; + case F81966D_SP4: + /* Enable Uart4 and IRQ share register */ + f81966d_uart_init(dev); + break; + case F81966D_GPIO: + /* Enable GPIO */ + f81966d_gpio_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 = f81966d_init, + .ops_pnp_mode = &pnp_conf_mode_8787_aa, +}; + +static struct pnp_info pnp_dev_info[] = { + /* Some of the 0x7f8 values may need to be corrected. */ + { NULL, F81966D_SP1, PNP_IO0 | PNP_IRQ0, 0x7f8, }, + { NULL, F81966D_SP2, PNP_IO0 | PNP_IRQ0, 0x7f8, }, + { NULL, F81966D_SP3, PNP_IO0 | PNP_IRQ0, 0x7f8, }, + { NULL, F81966D_SP4, PNP_IO0 | PNP_IRQ0, 0x7f8, }, + { NULL, F81966D_SP5, PNP_IO0 | PNP_IRQ0, 0x7f8, }, + { NULL, F81966D_SP6, PNP_IO0 | PNP_IRQ0, 0x7f8, }, + { NULL, F81966D_KBC, PNP_IO0 | PNP_IRQ0 | PNP_IRQ1, 0x07ff, }, + { NULL, F81966D_PP, PNP_IO0 | PNP_IRQ0 | PNP_DRQ0, 0x07f8, }, + { NULL, F81966D_HWM, PNP_IO0 | PNP_IRQ0, 0xff8, }, + { NULL, F81966D_GPIO, PNP_IO0, 0xff8, }, + { NULL, F81966D_PME, }, + { NULL, F81966D_WDT, }, + { NULL, F81966D_SPI, }, +}; + +static void enable_dev(struct device *dev) +{ + pnp_enable_devices(dev, &ops, ARRAY_SIZE(pnp_dev_info), pnp_dev_info); +} + +struct chip_operations superio_fintek_f81966d_ops = { + .name = "Fintek F81966D-I Super I/O", + .enable_dev = enable_dev +};