superio/fintek: Add f81803A
Add f81803A plus the capability to control the fan with any fintek SIO. This will be done through a common API, though currently only F81803A will have it implemented. BUG=none. TEST=Tested later with padmelon board. Change-Id: I3d336e76bccc38452b1b1aefef5d4a4f7ee129a8 Signed-off-by: Richard Spiegel <richard.spiegel@silverbackltd.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/33623 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Felix Held <felix-coreboot@felixheld.de>
This commit is contained in:
		
				
					committed by
					
						 Felix Held
						Felix Held
					
				
			
			
				
	
			
			
			
						parent
						
							150a61e103
						
					
				
				
					commit
					ae5b3671b3
				
			| @@ -26,3 +26,4 @@ subdirs-y += f71872 | ||||
| subdirs-y += f81216h | ||||
| subdirs-y += f81865f | ||||
| subdirs-y += f81866d | ||||
| subdirs-y += f81803a | ||||
|   | ||||
							
								
								
									
										63
									
								
								src/superio/fintek/common/fan_api_call.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/superio/fintek/common/fan_api_call.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,63 @@ | ||||
| /* | ||||
|  * 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 <console/console.h> | ||||
| #include "fan_control.h" | ||||
|  | ||||
| static int check_status(int status) | ||||
| { | ||||
| 	if (status < HWM_STATUS_SUCCESS) | ||||
| 		return status; | ||||
| 	return HWM_STATUS_SUCCESS;	/* positive values are warnings only */ | ||||
| } | ||||
|  | ||||
| int set_fan(struct fintek_fan *fan_init) | ||||
| { | ||||
| 	int s; | ||||
|  | ||||
| 	s = set_sensor_type(CONFIG_HWM_PORT, fan_init->sensor, fan_init->stype); | ||||
| 	if (check_status(s) != HWM_STATUS_SUCCESS) | ||||
| 		return s; | ||||
|  | ||||
| 	s = set_fan_temperature_source(CONFIG_HWM_PORT, fan_init->fan, fan_init->temp_source); | ||||
| 	if (check_status(s) != HWM_STATUS_SUCCESS) | ||||
| 		return s; | ||||
|  | ||||
| 	s = set_fan_type_mode(CONFIG_HWM_PORT, fan_init->fan, fan_init->ftype, fan_init->fmode); | ||||
| 	if (check_status(s) != HWM_STATUS_SUCCESS) | ||||
| 		return s; | ||||
|  | ||||
| 	s = set_pwm_frequency(CONFIG_HWM_PORT, fan_init->fan, fan_init->fan_freq); | ||||
| 	if (check_status(s) != HWM_STATUS_SUCCESS) | ||||
| 		return s; | ||||
|  | ||||
| 	s = set_fan_speed_change_rate(CONFIG_HWM_PORT, fan_init->fan, fan_init->rate_up, | ||||
| 				fan_init->rate_down); | ||||
| 	if (check_status(s) != HWM_STATUS_SUCCESS) | ||||
| 		return s; | ||||
|  | ||||
| 	s = set_fan_follow(CONFIG_HWM_PORT, fan_init->fan, fan_init->follow); | ||||
| 	if (check_status(s) != HWM_STATUS_SUCCESS) | ||||
| 		return s; | ||||
|  | ||||
| 	s = set_sections(CONFIG_HWM_PORT, fan_init->fan, fan_init->boundaries, | ||||
| 				fan_init->sections); | ||||
| 	if (check_status(s) != HWM_STATUS_SUCCESS) | ||||
| 		return s; | ||||
|  | ||||
| 	printk(BIOS_DEBUG, "Fan %d completed\n", fan_init->fan); | ||||
| 	return HWM_STATUS_SUCCESS; | ||||
| } | ||||
							
								
								
									
										199
									
								
								src/superio/fintek/common/fan_control.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										199
									
								
								src/superio/fintek/common/fan_control.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,199 @@ | ||||
| /* | ||||
|  * 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> | ||||
|  | ||||
| typedef enum { | ||||
| 	IGNORE_SENSOR = 0, | ||||
| 	EXTERNAL_SENSOR1, | ||||
| 	EXTERNAL_SENSOR2, | ||||
| 	EXTERNAL_SENSOR3, | ||||
| 	EXTERNAL_SENSOR4 | ||||
| } external_sensor; | ||||
|  | ||||
| typedef enum { | ||||
| 	TEMP_SENSOR_THERMISTOR = 0, | ||||
| 	TEMP_SENSOR_BJT, | ||||
| 	TEMP_SENSOR_DEFAULT | ||||
| } temp_sensor_type; | ||||
|  | ||||
| typedef enum { | ||||
| 	FAN_TYPE_PWM_PUSH_PULL = 0, | ||||
| 	FAN_TYPE_DAC_POWER, | ||||
| 	FAN_TYPE_PWM_OPEN_DRAIN, | ||||
| 	FAN_TYPE_RESERVED | ||||
| } fan_type; | ||||
| #define FAN_TYPE_PWM_CHECK			1 /* bit 0 must be 0 for PWM */ | ||||
|  | ||||
| typedef enum { | ||||
| 	FAN_MODE_AUTO_RPM = 0, | ||||
| 	FAN_MODE_AUTO_PWM_DAC, | ||||
| 	FAN_MODE_MANUAL_RPM, | ||||
| 	FAN_MODE_MANUAL_PWM_DAC, | ||||
| 	FAN_MODE_DEFAULT | ||||
| } fan_mode; | ||||
|  | ||||
| typedef enum { | ||||
| 	FAN_PWM_FREQ_23500 = 0, | ||||
| 	FAN_PWM_FREQ_11750, | ||||
| 	FAN_PWM_FREQ_5875, | ||||
| 	FAN_PWM_FREQ_220 | ||||
| } fan_pwm_freq; | ||||
|  | ||||
| typedef enum { | ||||
| 	FAN_TEMP_PECI = 0, | ||||
| 	FAN_TEMP_EXTERNAL_1, | ||||
| 	FAN_TEMP_EXTERNAL_2, | ||||
| 	FAN_TEMP_TSI = 4, | ||||
| 	FAN_TEMP_MXM, | ||||
| } fan_temp_source; | ||||
|  | ||||
| typedef enum { | ||||
| 	FAN_UP_RATE_2HZ = 0, | ||||
| 	FAN_UP_RATE_5HZ, | ||||
| 	FAN_UP_RATE_10HZ, | ||||
| 	FAN_UP_RATE_20HZ, | ||||
| 	FAN_UP_RATE_DEFAULT, | ||||
| 	FAN_UP_RATE_JUMP = 8 | ||||
| } fan_rate_up; | ||||
|  | ||||
| typedef enum { | ||||
| 	FAN_DOWN_RATE_2HZ = 0, | ||||
| 	FAN_DOWN_RATE_5HZ, | ||||
| 	FAN_DOWN_RATE_10HZ, | ||||
| 	FAN_DOWN_RATE_20HZ, | ||||
| 	FAN_DOWN_RATE_DEFAULT, | ||||
| 	FAN_DOWN_RATE_SAME_AS_UP, | ||||
| 	FAN_DOWN_RATE_JUMP = 8 | ||||
| } fan_rate_down; | ||||
|  | ||||
| typedef enum { | ||||
| 	FAN_FOLLOW_STEP = 0, | ||||
| 	FAN_FOLLOW_INTERPOLATION | ||||
| } fan_follow; | ||||
|  | ||||
| struct fintek_fan { | ||||
| 	uint8_t fan; | ||||
| 	external_sensor sensor; | ||||
| 	temp_sensor_type stype; | ||||
| 	fan_temp_source temp_source; | ||||
| 	fan_type ftype; | ||||
| 	fan_mode fmode; | ||||
| 	fan_pwm_freq fan_freq; | ||||
| 	fan_rate_up rate_up; | ||||
| 	fan_rate_down rate_down; | ||||
| 	fan_follow follow; | ||||
| 	uint8_t *boundaries; | ||||
| 	uint8_t *sections; | ||||
| }; | ||||
|  | ||||
| #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		-10 | ||||
| #define HWM_STATUS_SECTIONS_WRONG_ORDER		-11 | ||||
| #define HWM_STATUS_WARNING_SENSOR_DISCONECTED	1 | ||||
| #define HWM_STATUS_WARNING_FAN_NOT_PWM		2 | ||||
|  | ||||
| #define CPU_DAMAGE_TEMP				110 | ||||
|  | ||||
| /* | ||||
|  * 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 | ||||
|  | ||||
| /* | ||||
|  * When using external sensor, its type must be defined. When using PECI, | ||||
|  * TSI or MXM use IGNORE_SENSOR to indicate so. | ||||
|  */ | ||||
| int set_sensor_type(u16 base_address, external_sensor sensor, | ||||
| 						temp_sensor_type type); | ||||
|  | ||||
| /* | ||||
|  * Define the temperature source used to control a fan. | ||||
|  */ | ||||
| int set_fan_temperature_source(u16 base_address, u8 fan, | ||||
| 						fan_temp_source source); | ||||
|  | ||||
| /* | ||||
|  * Define if fan is controlled through PWM or absolute voltage powering it | ||||
|  * (DAC). Then, under mode, define if control is automatic (SIO) or manual | ||||
|  * (CPU, through ACPI). Notice there needs to be a match between type and | ||||
|  * mode (PWM with PWM or DAC with DAC). | ||||
|  */ | ||||
| int set_fan_type_mode(u16 base_address, u8 fan, fan_type type, fan_mode mode); | ||||
|  | ||||
| /* | ||||
|  * For fans controlled through pulse width, define the base frequency used. | ||||
|  */ | ||||
| int set_pwm_frequency(u16 base_address, u8 fan, fan_pwm_freq frequency); | ||||
|  | ||||
| /* | ||||
|  * For fintek SIO HWM there are 4 (temperature) boundaries points, defining | ||||
|  * 5 sections (1 fan speed per section). Start with the highest temperature/ | ||||
|  * speed. Temperature is in Celsius, speed is in percentile of max speed. The | ||||
|  * highest speed should be 100%, no requirements for minimum speed, could be | ||||
|  * 0 or above 0. | ||||
|  */ | ||||
| int set_sections(u16 base_address, u8 fan, u8 *boundaries, u8 *sections); | ||||
|  | ||||
| /* | ||||
|  * Define how often temperature is measured to change fan speed. | ||||
|  */ | ||||
| int set_fan_speed_change_rate(u16 base_address, u8 fan, fan_rate_up rate_up, | ||||
| 						fan_rate_down rate_down); | ||||
|  | ||||
| /* | ||||
|  * There a 2 ways a fan can be controlled: A single speed per section, or | ||||
|  * interpolation. Under interpolation, the section speed is the speed at the | ||||
|  * lowest temperature of the section (0 Celsius for the lowest section), and | ||||
|  * it's the speed of the next section at the boundary to the next section. | ||||
|  * In between these 2 points, it's a linear function. For example, midway | ||||
|  * between temperature points it'll have a speed that is midway between the | ||||
|  * section speed and next section speed. Obviously, there's no variation for | ||||
|  * the highest section, reason why it must be 100% max speed. | ||||
|  */ | ||||
| int set_fan_follow(u16 base_address, u8 fan, fan_follow follow); | ||||
|  | ||||
| /* | ||||
|  * This is an upper level API which calls all the above APIs in the | ||||
|  * appropriate order. Any API failure will be displayed. Alerts will | ||||
|  * also be displayed, but will not interrupt the sequence, while errors | ||||
|  * will interrupt the sequence. | ||||
|  */ | ||||
| int set_fan(struct fintek_fan *fan_init); | ||||
|  | ||||
| #endif /* SUPERIO_FINTEK_FAN_CONTROL_H */ | ||||
							
								
								
									
										28
									
								
								src/superio/fintek/f81803a/Kconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/superio/fintek/f81803a/Kconfig
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| ## | ||||
| ## 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_FAN_CONTROL | ||||
| 	bool | ||||
| 	default n | ||||
|  | ||||
| config SUPERIO_FINTEK_FAN_API_CALL | ||||
| 	depends on SUPERIO_FINTEK_FAN_CONTROL | ||||
| 	bool | ||||
| 	default n | ||||
							
								
								
									
										30
									
								
								src/superio/fintek/f81803a/Makefile.inc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/superio/fintek/f81803a/Makefile.inc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| ## | ||||
| ## 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 | ||||
|  | ||||
| ## Notice: For fan control at romstage, HWM must be initialized before | ||||
| ## the API is called. Ramstage can use devicetree to initialize it. | ||||
|  | ||||
| romstage-$(CONFIG_SUPERIO_FINTEK_F81803A) += ../common/early_serial.c | ||||
| romstage-$(CONFIG_SUPERIO_FINTEK_FAN_CONTROL) += fan_control.c | ||||
| romstage-$(CONFIG_SUPERIO_FINTEK_FAN_API_CALL) += ../common/fan_api_call.c | ||||
|  | ||||
| ramstage-$(CONFIG_SUPERIO_FINTEK_F81803A) += superio.c | ||||
| ramstage-$(CONFIG_SUPERIO_FINTEK_FAN_CONTROL) += fan_control.c | ||||
| ramstage-$(CONFIG_SUPERIO_FINTEK_FAN_API_CALL) += ../common/fan_api_call.c | ||||
							
								
								
									
										266
									
								
								src/superio/fintek/f81803a/acpi/superio.asl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										266
									
								
								src/superio/fintek/f81803a/acpi/superio.asl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,266 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  * 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 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			Implemented, partially tested | ||||
|  * 0x4 HWM			Not implemented | ||||
|  * 0x5 KBC			Not implemented | ||||
|  * 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_HWMON	If defined, the hardware monitor will be exposed. | ||||
|  * F81803A_SHOW_PME 	If defined, the PME/EARP/ACPI  will be exposed. | ||||
|  * | ||||
|  * Known issue: | ||||
|  * Do not enable UARTA and UARTB simultaneously, Linux boot will crash. | ||||
|  * Select one or the other. | ||||
|  */ | ||||
| #undef SUPERIO_CHIP_NAME | ||||
| #define SUPERIO_CHIP_NAME F81803A | ||||
| #include <superio/acpi/pnp.asl> | ||||
|  | ||||
| #undef PNP_DEFAULT_PSC | ||||
| #define PNP_DEFAULT_PSC Return (0) /* no power management */ | ||||
|  | ||||
| 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_PM_REG | ||||
| 	#undef SUPERIO_UART_PM_VAL | ||||
| 	#undef SUPERIO_UART_PM_LDN | ||||
| 	#define SUPERIO_UART_LDN 1 | ||||
|  | ||||
| 	Device (SUPERIO_ID(SER, SUPERIO_UART_LDN)) { | ||||
| 		Name (_HID, EisaId ("PNP0501")) | ||||
| 		Name (_UID, SUPERIO_UID(SER, SUPERIO_UART_LDN)) | ||||
|  | ||||
| 		Method (_STA) | ||||
| 		{ | ||||
| 			PNP_GENERIC_STA(SUPERIO_UART_LDN) | ||||
| 		} | ||||
|  | ||||
| 		Method (_CRS, 0, Serialized) | ||||
| 		{ | ||||
| 			Name (CRS, ResourceTemplate () { | ||||
| 				IO (Decode16, 0x0000, 0x0000, 0x08, 0x08, IO0) | ||||
| 				IRQNoFlags (IR0) {} | ||||
| 			}) | ||||
| 			ENTER_CONFIG_MODE (SUPERIO_UART_LDN) | ||||
| 			  PNP_READ_IO(PNP_IO0, CRS, IO0) | ||||
| 			  PNP_READ_IRQ(PNP_IRQ0, CRS, IR0) | ||||
| 			EXIT_CONFIG_MODE () | ||||
| 			Return (CRS) | ||||
| 		} | ||||
|  | ||||
| 		Name (_PRS, ResourceTemplate () | ||||
| 		{ | ||||
| 			StartDependentFn (0,0) { | ||||
| 				IO (Decode16, 0x03f8, 0x03f8, 0x08, 0x08) | ||||
| 				IRQNoFlags () {3,4,5,7,9,10,11,12} | ||||
| 			} | ||||
| 			StartDependentFn (0,0) { | ||||
| 				IO (Decode16, 0x02f8, 0x02f8, 0x08, 0x08) | ||||
| 				IRQNoFlags () {3,4,5,7,9,10,11,12} | ||||
| 			} | ||||
| 			StartDependentFn (1,0) { | ||||
| 				IO (Decode16, 0x03e8, 0x03e8, 0x08, 0x08) | ||||
| 				IRQNoFlags () {3,4,5,7,9,10,11,12} | ||||
| 			} | ||||
| 			StartDependentFn (1,0) { | ||||
| 				IO (Decode16, 0x02e8, 0x02e8, 0x08, 0x08) | ||||
| 				IRQNoFlags () {3,4,5,7,9,10,11,12} | ||||
| 			} | ||||
| 			StartDependentFn (2,0) { | ||||
| 				IO (Decode16, 0x0100, 0x0ff8, 0x08, 0x08) | ||||
| 				IRQNoFlags () {3,4,5,7,9,10,11,12} | ||||
| 			} | ||||
| 			EndDependentFn() | ||||
| 		}) | ||||
|  | ||||
| 		Method (_SRS, 1, Serialized) | ||||
| 		{ | ||||
| 			Name (TMPL, ResourceTemplate () { | ||||
| 				IO (Decode16, 0x0000, 0x0000, 0x00, 0x00, IO0) | ||||
| 				IRQNoFlags (IR0) {} | ||||
| 			}) | ||||
| 			ENTER_CONFIG_MODE (SUPERIO_UART_LDN) | ||||
| 			  PNP_WRITE_IO(PNP_IO0, Arg0, IO0) | ||||
| 			  PNP_WRITE_IRQ(PNP_IRQ0, Arg0, IR0) | ||||
| 			  Store (One, PNP_DEVICE_ACTIVE) | ||||
| 			EXIT_CONFIG_MODE () | ||||
| 		} | ||||
| 	} | ||||
| #endif | ||||
|  | ||||
| #ifdef F81803A_SHOW_UARTB | ||||
| 	#undef SUPERIO_UART_LDN | ||||
| 	#undef SUPERIO_UART_PM_REG | ||||
| 	#undef SUPERIO_UART_PM_VAL | ||||
| 	#undef SUPERIO_UART_PM_LDN | ||||
| 	#define SUPERIO_UART_LDN 2 | ||||
|  | ||||
| 	Device (SUPERIO_ID(SER, SUPERIO_UART_LDN)) { | ||||
| 		Name (_HID, EisaId ("PNP0501")) | ||||
| 		Name (_UID, SUPERIO_UID(SER, SUPERIO_UART_LDN)) | ||||
|  | ||||
| 		Method (_STA) | ||||
| 		{ | ||||
| 			PNP_GENERIC_STA(SUPERIO_UART_LDN) | ||||
| 		} | ||||
|  | ||||
| 		Method (_CRS, 0, Serialized) | ||||
| 		{ | ||||
| 			Name (CRS, ResourceTemplate () { | ||||
| 				IO (Decode16, 0x0000, 0x0000, 0x08, 0x08, IO0) | ||||
| 				IRQNoFlags (IR0) {} | ||||
| 			}) | ||||
| 			ENTER_CONFIG_MODE (SUPERIO_UART_LDN) | ||||
| 			  PNP_READ_IO(PNP_IO0, CRS, IO0) | ||||
| 			  PNP_READ_IRQ(PNP_IRQ0, CRS, IR0) | ||||
| 			EXIT_CONFIG_MODE () | ||||
| 			Return (CRS) | ||||
| 		} | ||||
|  | ||||
| 		Name (_PRS, ResourceTemplate () | ||||
| 		{ | ||||
| 			StartDependentFn (0,0) { | ||||
| 				IO (Decode16, 0x03f8, 0x03f8, 0x08, 0x08) | ||||
| 				IRQNoFlags () {3,4,5,7,9,10,11,12} | ||||
| 			} | ||||
| 			StartDependentFn (0,0) { | ||||
| 				IO (Decode16, 0x02f8, 0x02f8, 0x08, 0x08) | ||||
| 				IRQNoFlags () {3,4,5,7,9,10,11,12} | ||||
| 			} | ||||
| 			StartDependentFn (1,0) { | ||||
| 				IO (Decode16, 0x03e8, 0x03e8, 0x08, 0x08) | ||||
| 				IRQNoFlags () {3,4,5,7,9,10,11,12} | ||||
| 			} | ||||
| 			StartDependentFn (1,0) { | ||||
| 				IO (Decode16, 0x02e8, 0x02e8, 0x08, 0x08) | ||||
| 				IRQNoFlags () {3,4,5,7,9,10,11,12} | ||||
| 			} | ||||
| 			StartDependentFn (2,0) { | ||||
| 				IO (Decode16, 0x0100, 0x0ff8, 0x08, 0x08) | ||||
| 				IRQNoFlags () {3,4,5,7,9,10,11,12} | ||||
| 			} | ||||
| 			EndDependentFn() | ||||
| 		}) | ||||
|  | ||||
| 		Method (_SRS, 1, Serialized) | ||||
| 		{ | ||||
| 			Name (TMPL, ResourceTemplate () { | ||||
| 				IO (Decode16, 0x0000, 0x0000, 0x00, 0x00, IO0) | ||||
| 				IRQNoFlags (IR0) {} | ||||
| 			}) | ||||
| 			ENTER_CONFIG_MODE (SUPERIO_UART_LDN) | ||||
| 			  PNP_WRITE_IO(PNP_IO0, Arg0, IO0) | ||||
| 			  PNP_WRITE_IRQ(PNP_IRQ0, Arg0, IR0) | ||||
| 			  Store (One, PNP_DEVICE_ACTIVE) | ||||
| 			EXIT_CONFIG_MODE () | ||||
| 		} | ||||
| 	} | ||||
| #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 | ||||
| } | ||||
							
								
								
									
										71
									
								
								src/superio/fintek/f81803a/f81803a.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								src/superio/fintek/f81803a/f81803a.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| /* | ||||
|  * 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 | ||||
|  | ||||
| #define LDN_REG				0x07	/* Not defined under PNP */ | ||||
| /* 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) */ | ||||
|  | ||||
| /*  Global Control Registers */ | ||||
| #define CLOCK_SELECT_REG		0x26 | ||||
| #define   FUNC_PROG_SELECT		(1<<3) | ||||
| #define 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 */ | ||||
							
								
								
									
										72
									
								
								src/superio/fintek/f81803a/f81803a_hwm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/superio/fintek/f81803a/f81803a_hwm.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| /* | ||||
|  * 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   FAN_TYPE_SHIFT(fan)			((fan - 1) * 2) | ||||
| #define   FAN_TYPE_MASK				0x03 | ||||
| #define FAN_MODE_REG				0x96 | ||||
| 	/* FUNC_PROG_SEL = 0 */ | ||||
| #define   FAN_MODE_SHIFT(fan)			((fan - 1) * 4) | ||||
| #define   FAN_MODE_MASK				0x07 | ||||
| 	/* FUNC_PROG_SEL = 1 */ | ||||
| #define   FAN1_ADJ_SEL_SHIFT			0 | ||||
| #define   FAN1_ADJ_SEL_MASK			0x07 | ||||
| #define   FAN_FREQ_SEL_ADD_SHIFT(fan)		(fan + 2) | ||||
| #define FAN_UP_RATE_REG				0x9a | ||||
| #define   FAN_RATE_SHIFT(fan)			((fan - 1) * 2) | ||||
| #define   FAN_RATE_MASK				0x03 | ||||
| #define FAN_DOWN_RATE_REG			0x9b | ||||
| #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 FAN_BOUND_TEMP				0xa6	/* 4 temperatures */ | ||||
| #define FAN_SECTION_SPEED			0xaa	/* 5 sections */ | ||||
| #define FAN_TMP_MAPPING				0xaf | ||||
| #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 FAN_ADJUST(fan, start)			(((fan - 1) * 0x10) + start) | ||||
|  | ||||
| #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 */ | ||||
							
								
								
									
										362
									
								
								src/superio/fintek/f81803a/fan_control.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										362
									
								
								src/superio/fintek/f81803a/fan_control.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,362 @@ | ||||
| /* | ||||
|  * 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 <console/console.h> | ||||
| #include "../common/fan_control.h" | ||||
| #include "f81803a_hwm.h" | ||||
|  | ||||
| static const char msg_err_invalid[] = "Error: invalid"; | ||||
| static const char msg_err_wrong_order[] = "Error: wrong order,"; | ||||
| static const char msg_err_fan[] = "fan"; | ||||
| static const char msg_err_temp_source[] = "temperature source"; | ||||
| static const char msg_err_type[] = "type"; | ||||
| static const char msg_err_mode[] = "mode"; | ||||
| static const char msg_err_rate[] = "change rate"; | ||||
| static const char msg_err_frequency[] = "frequency"; | ||||
| static const char msg_err_temp_sensor[] = "temperature sensor"; | ||||
| static const char msg_err_bondary[] = "boundary"; | ||||
| static const char msg_err_section[] = "section"; | ||||
| static const char no_msg[] = ""; | ||||
|  | ||||
| struct cross_ref { | ||||
| 	int selection; | ||||
| 	const char *message; | ||||
| }; | ||||
| static struct cross_ref msg_table[] = { | ||||
| 	{HWM_STATUS_INVALID_FAN,		msg_err_fan}, | ||||
| 	{HWM_STATUS_INVALID_TEMP_SOURCE,	msg_err_temp_source}, | ||||
| 	{HWM_STATUS_INVALID_TYPE,		msg_err_type}, | ||||
| 	{HWM_STATUS_INVALID_MODE,		msg_err_mode}, | ||||
| 	{HWM_STATUS_INVALID_RATE,		msg_err_rate}, | ||||
| 	{HWM_STATUS_INVALID_FREQUENCY,		msg_err_frequency}, | ||||
| 	{HWM_STATUS_INVALID_TEMP_SENSOR,	msg_err_temp_sensor}, | ||||
| 	{0, NULL}, | ||||
| }; | ||||
|  | ||||
| static const char *get_msg(int err) | ||||
| { | ||||
| 	int i = 0; | ||||
| 	while (msg_table[i].selection) { | ||||
| 		if (msg_table[i].selection == err) | ||||
| 			return msg_table[i].message; | ||||
| 		i++; | ||||
| 	} | ||||
| 	return no_msg; | ||||
| } | ||||
|  | ||||
| static int message_invalid_1(int err, u8 fan) | ||||
| { | ||||
| 	if (err == HWM_STATUS_INVALID_FAN) | ||||
| 		printk(BIOS_ERR, "%s %s %d!\n", msg_err_invalid, get_msg(err), fan); | ||||
| 	else | ||||
| 		printk(BIOS_ERR, "%s Fan %d %s!\n", msg_err_invalid, fan, get_msg(err)); | ||||
| 	return err; | ||||
| } | ||||
|  | ||||
| static int message_invalid_2(int err, u8 fan) | ||||
| { | ||||
| 	switch (err) { | ||||
| 	case HWM_STATUS_INVALID_BOUNDARY_VALUE: | ||||
| 		printk(BIOS_ERR, "%s fan %d %s value!\n", msg_err_invalid, fan, | ||||
| 					msg_err_bondary); | ||||
| 		break; | ||||
| 	case HWM_STATUS_INVALID_SECTION_VALUE: | ||||
| 		printk(BIOS_ERR, "%s fan %d %s value!\n", msg_err_invalid, fan, | ||||
| 					msg_err_section); | ||||
| 		break; | ||||
| 	case HWM_STATUS_BOUNDARY_WRONG_ORDER: | ||||
| 		printk(BIOS_ERR, "%s fan %d %s!\n", msg_err_wrong_order, fan, msg_err_bondary); | ||||
| 		break; | ||||
| 	case HWM_STATUS_SECTIONS_WRONG_ORDER: | ||||
| 		printk(BIOS_ERR, "%s fan %d %s!\n", msg_err_wrong_order, fan, msg_err_section); | ||||
| 		break; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
| 	return err; | ||||
| } | ||||
|  | ||||
| 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 hwm_reg_modify(u16 address, u8 index, u8 shift, u8 mask, | ||||
| 								u8 value) | ||||
| { | ||||
| 	u8 use_mask = mask << shift; | ||||
| 	u8 use_value = (value & mask) << shift; | ||||
| 	u8 temp = read_hwm_reg(address, index); | ||||
|  | ||||
| 	temp &= ~use_mask; | ||||
| 	temp |= use_value; | ||||
| 	write_hwm_reg(address, index, temp); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Registers 0x94,0x95, 0x96 and 0x9b have 2 versions (banks) selected through | ||||
|  * bit 7 of register 0x9f. | ||||
|  */ | ||||
| static inline void select_hwm_bank(u16 address, u8 value) | ||||
| { | ||||
| 	hwm_reg_modify(address, FAN_FAULT_TIME_REG, FAN_FUNC_PROG_SEL_SHIFT, | ||||
| 				FAN_BIT_MASK, value); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Boundaries and sections must be presented in the same order as in the HWM | ||||
|  * registers, that is, from highest value to lowest. This procedure checks for | ||||
|  * the correct order. | ||||
|  */ | ||||
| static int check_value_seq(u8 *values, u8 count) | ||||
| { | ||||
| 	u8 last_value = CPU_DAMAGE_TEMP; | ||||
| 	u8 current_value, i; | ||||
| 	for (i = 0; i < count; i++) { | ||||
| 		current_value = values[i]; | ||||
| 		if (current_value  > CPU_DAMAGE_TEMP) | ||||
| 			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, external_sensor sensor, | ||||
| 						temp_sensor_type type) | ||||
| { | ||||
| 	u8 sensor_status = read_hwm_reg(base_address, TP_DIODE_STATUS); | ||||
|  | ||||
| 	printk(BIOS_DEBUG, "%s\n", __func__); | ||||
| 	switch (sensor) { | ||||
| 	case EXTERNAL_SENSOR1: | ||||
| 		if (sensor_status & TP_EXTERNAL_SENSOR1_OPEN) { | ||||
| 			printk(BIOS_WARNING, "Sensor 1 disconected!\n"); | ||||
| 			return HWM_STATUS_WARNING_SENSOR_DISCONECTED; | ||||
| 		} | ||||
| 		hwm_reg_modify(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) { | ||||
| 			printk(BIOS_WARNING, "Sensor 2 disconected!\n"); | ||||
| 			return HWM_STATUS_WARNING_SENSOR_DISCONECTED; | ||||
| 		} | ||||
| 		hwm_reg_modify(base_address, TP_SENSOR_TYPE, | ||||
| 			TP_SENSOR2_TYPE_SHIFT, TP_SENSOR_TYPE_MASK, type); | ||||
| 		break; | ||||
| 	case IGNORE_SENSOR: | ||||
| 		break; | ||||
| 	default: | ||||
| 		return message_invalid_1(HWM_STATUS_INVALID_TEMP_SENSOR, 0); | ||||
| 	} | ||||
| 	return HWM_STATUS_SUCCESS; | ||||
| } | ||||
|  | ||||
| int set_fan_temperature_source(u16 base_address, u8 fan, | ||||
| 						fan_temp_source source) | ||||
| { | ||||
| 	u8 index, high_value, low_value; | ||||
|  | ||||
| 	printk(BIOS_DEBUG, "%s\n", __func__); | ||||
| 	if ((fan < FIRST_FAN) || (fan > LAST_FAN)) | ||||
| 		return message_invalid_1(HWM_STATUS_INVALID_FAN, fan); | ||||
| 	index = FAN_ADJUST(fan, FAN_TMP_MAPPING); | ||||
| 	high_value = (source >> 2) & FAN_BIT_MASK; | ||||
| 	low_value = source & FAN_TEMP_SEL_LOW_MASK; | ||||
| 	hwm_reg_modify(base_address, index, FAN_TEMP_SEL_HIGH_SHIFT, | ||||
| 				FAN_BIT_MASK, high_value); | ||||
| 	hwm_reg_modify(base_address, index, FAN_TEMP_SEL_LOW_SHIFT, | ||||
| 				FAN_TEMP_SEL_LOW_MASK, low_value); | ||||
| 	/* | ||||
| 	 * Fan 1 has a weight mechanism for adjusting for next fan speed. Basically the idea is | ||||
| 	 * to react more aggressively (normally CPU fan) based on how high another temperature | ||||
| 	 * (system, thermistor near the CPU, anything) is. This would be highly platform | ||||
| 	 * dependent, and by setting the weight temperature same as the control temperature. | ||||
| 	 * This code cancels the weight mechanism and make it work with any board. If a board | ||||
| 	 * wants to use the weight mechanism, OEM should implement it after calling the main | ||||
| 	 * HWM programming. | ||||
| 	 */ | ||||
| 	if (fan == FIRST_FAN) { | ||||
| 		select_hwm_bank(base_address, 1); | ||||
| 		hwm_reg_modify(base_address, FAN_MODE_REG, | ||||
| 				FAN1_ADJ_SEL_SHIFT, FAN1_ADJ_SEL_MASK, source); | ||||
| 		select_hwm_bank(base_address, 0); | ||||
| 	} | ||||
| 	return HWM_STATUS_SUCCESS; | ||||
| } | ||||
|  | ||||
| int set_fan_type_mode(u16 base_address, u8 fan, fan_type type, fan_mode mode) | ||||
| { | ||||
| 	u8 shift; | ||||
|  | ||||
| 	printk(BIOS_DEBUG, "%s\n", __func__); | ||||
| 	if ((fan < FIRST_FAN) || (fan > LAST_FAN)) | ||||
| 		return message_invalid_1(HWM_STATUS_INVALID_FAN, fan); | ||||
| 	select_hwm_bank(base_address, 0); | ||||
| 	if (type < FAN_TYPE_RESERVED) { | ||||
| 		shift = FAN_TYPE_SHIFT(fan); | ||||
| 		hwm_reg_modify(base_address, FAN_TYPE_REG, shift, | ||||
| 						FAN_TYPE_MASK, type); | ||||
| 	} | ||||
| 	if (mode < FAN_MODE_DEFAULT) { | ||||
| 		shift = FAN_MODE_SHIFT(fan); | ||||
| 		hwm_reg_modify(base_address, FAN_MODE_REG, shift, | ||||
| 						FAN_MODE_MASK, mode); | ||||
| 	} | ||||
| 	return HWM_STATUS_SUCCESS; | ||||
| } | ||||
|  | ||||
| int set_pwm_frequency(u16 base_address, u8 fan, fan_pwm_freq frequency) | ||||
| { | ||||
| 	u8 shift, index, byte; | ||||
|  | ||||
| 	printk(BIOS_DEBUG, "%s\n", __func__); | ||||
| 	if ((fan < FIRST_FAN) || (fan > LAST_FAN)) | ||||
| 		return message_invalid_1(HWM_STATUS_INVALID_FAN, fan); | ||||
| 	byte = read_hwm_reg(base_address, FAN_TYPE_REG); | ||||
| 	shift = FAN_TYPE_SHIFT(fan); | ||||
| 	if (((byte >> shift) & FAN_TYPE_PWM_CHECK) == FAN_TYPE_PWM_CHECK) { | ||||
| 		printk(BIOS_WARNING, "Fan %d not programmed as PWM!\n", fan); | ||||
| 		return HWM_STATUS_WARNING_FAN_NOT_PWM; | ||||
| 	} | ||||
| 	select_hwm_bank(base_address, 1); | ||||
| 	shift = FAN_FREQ_SEL_ADD_SHIFT(fan); | ||||
| 	byte = (frequency >> 1) & FAN_BIT_MASK; | ||||
| 	hwm_reg_modify(base_address, FAN_MODE_REG, shift, FAN_BIT_MASK, | ||||
| 									byte); | ||||
| 	select_hwm_bank(base_address, 0); | ||||
| 	index = FAN_ADJUST(fan, FAN_TMP_MAPPING); | ||||
| 	byte = frequency & FAN_BIT_MASK; | ||||
| 	hwm_reg_modify(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; | ||||
|  | ||||
| 	printk(BIOS_DEBUG, "%s\n", __func__); | ||||
| 	if ((fan < FIRST_FAN) || (fan > LAST_FAN)) | ||||
| 		return message_invalid_1(HWM_STATUS_INVALID_FAN, fan); | ||||
| 	status = check_value_seq(boundaries, | ||||
| 				FINTEK_BOUNDARIES_SIZE); | ||||
| 	if (status != HWM_STATUS_SUCCESS) { | ||||
| 		if (status == STATUS_INVALID_VALUE) | ||||
| 			return message_invalid_2(HWM_STATUS_INVALID_BOUNDARY_VALUE, fan); | ||||
| 		return message_invalid_2(HWM_STATUS_BOUNDARY_WRONG_ORDER, fan); | ||||
| 	} | ||||
| 	status = check_value_seq(sections, | ||||
| 				FINTEK_SECTIONS_SIZE); | ||||
| 	if (status != HWM_STATUS_SUCCESS) { | ||||
| 		if (status == STATUS_INVALID_VALUE) | ||||
| 			return message_invalid_2(HWM_STATUS_INVALID_SECTION_VALUE, fan); | ||||
| 		return message_invalid_2(HWM_STATUS_SECTIONS_WRONG_ORDER, fan); | ||||
| 	} | ||||
| 	index = FAN_ADJUST(fan, FAN_BOUND_TEMP); | ||||
| 	for (i = 0; i < FINTEK_BOUNDARIES_SIZE; i++) { | ||||
| 		value = boundaries[i]; | ||||
| 		write_hwm_reg(base_address, index, value); | ||||
| 		index++; | ||||
| 	} | ||||
| 	index = FAN_ADJUST(fan, FAN_SECTION_SPEED); | ||||
| 	for (i = 0; i < FINTEK_SECTIONS_SIZE; i++) { | ||||
| 		value = sections[i]; | ||||
| 		if (value > 100) | ||||
| 			return message_invalid_2(HWM_STATUS_INVALID_SECTION_VALUE, fan); | ||||
| 		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, fan_rate_up rate_up, | ||||
| 						fan_rate_down rate_down) | ||||
| { | ||||
| 	u8 shift, index; | ||||
|  | ||||
| 	printk(BIOS_DEBUG, "%s\n", __func__); | ||||
| 	if ((fan < FIRST_FAN) || (fan > LAST_FAN)) | ||||
| 		return message_invalid_1(HWM_STATUS_INVALID_FAN, fan); | ||||
|  | ||||
| 	index = FAN_ADJUST(fan, FAN_TMP_MAPPING); | ||||
| 	shift = FAN_RATE_SHIFT(fan); | ||||
|  | ||||
| 	if (rate_up == FAN_UP_RATE_JUMP) { | ||||
| 		hwm_reg_modify(base_address, index, FAN_JUMP_UP_SHIFT, | ||||
| 							FAN_BIT_MASK, 1); | ||||
| 	} else { | ||||
| 		hwm_reg_modify(base_address, index, FAN_JUMP_UP_SHIFT, | ||||
| 							FAN_BIT_MASK, 0); | ||||
| 		if (rate_up < FAN_UP_RATE_DEFAULT) { | ||||
| 			hwm_reg_modify(base_address,	FAN_UP_RATE_REG, | ||||
| 					shift, FAN_RATE_MASK, rate_up); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (rate_down == FAN_DOWN_RATE_JUMP) { | ||||
| 		hwm_reg_modify(base_address, index, FAN_JUMP_DOWN_SHIFT, | ||||
| 							FAN_BIT_MASK, 1); | ||||
| 	} else { | ||||
| 		hwm_reg_modify(base_address, index, FAN_JUMP_UP_SHIFT, | ||||
| 							FAN_BIT_MASK, 0); | ||||
| 		select_hwm_bank(base_address, 0); | ||||
| 		if (rate_down < FAN_DOWN_RATE_DEFAULT) { | ||||
| 			hwm_reg_modify(base_address,	FAN_DOWN_RATE_REG, | ||||
| 					shift, FAN_RATE_MASK, rate_down); | ||||
| 			hwm_reg_modify(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) { | ||||
| 			hwm_reg_modify(base_address, FAN_DOWN_RATE_REG, | ||||
| 					FAN_DOWN_RATE_DIFF_FROM_UP_SHIFT, | ||||
| 					FAN_BIT_MASK, 1); | ||||
| 		} | ||||
| 	} | ||||
| 	return HWM_STATUS_SUCCESS; | ||||
| } | ||||
|  | ||||
| int set_fan_follow(u16 base_address, u8 fan, fan_follow follow) | ||||
| { | ||||
| 	u8 index; | ||||
|  | ||||
| 	printk(BIOS_DEBUG, "%s\n", __func__); | ||||
| 	if ((fan < FIRST_FAN) || (fan > LAST_FAN)) | ||||
| 		return message_invalid_1(HWM_STATUS_INVALID_FAN, fan); | ||||
| 	index = FAN_ADJUST(fan, FAN_TMP_MAPPING); | ||||
| 	hwm_reg_modify(base_address, index, FAN_INTERPOLATION_SHIFT, | ||||
| 				FAN_BIT_MASK, follow); | ||||
| 	return HWM_STATUS_SUCCESS; | ||||
| } | ||||
							
								
								
									
										78
									
								
								src/superio/fintek/f81803a/superio.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								src/superio/fintek/f81803a/superio.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| /* | ||||
|  * 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 <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 GPIO or WDT. */ | ||||
| 	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[] = { | ||||
| 	{ &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, 0x07f8, }, | ||||
| 	{ &ops, F81803A_GPIO, PNP_IO0 | PNP_IRQ0, 0x7f8, }, | ||||
| 	{ &ops, F81803A_WDT,  PNP_IO0, 0x7f8 }, | ||||
| 	{ &ops, F81803A_PME, }, | ||||
| }; | ||||
|  | ||||
| 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_f81803a_ops = { | ||||
| 	CHIP_NAME("Fintek F81803A Super I/O") | ||||
| 	.enable_dev = enable_dev | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user