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:
parent
150a61e103
commit
ae5b3671b3
|
@ -26,3 +26,4 @@ subdirs-y += f71872
|
||||||
subdirs-y += f81216h
|
subdirs-y += f81216h
|
||||||
subdirs-y += f81865f
|
subdirs-y += f81865f
|
||||||
subdirs-y += f81866d
|
subdirs-y += f81866d
|
||||||
|
subdirs-y += f81803a
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||||
|
}
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
||||||
|
};
|
Loading…
Reference in New Issue