powerpc/powermac: New windfarm driver for PowerMac G5 (AGP) and Xserve G5

This replaces the old therm_pm72 using the same windfarm infrastructure
that was used for other PowerMac G5 models. The fan speeds and sensors
should now be visible in the same location in sysfs.

The driver is split into separate core modules for PowerMac7,2 (and 7,3)
and RackMac3,1, with a lot of the shared code now in the separate sensor
and control modules.
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent a78a4a03
......@@ -204,11 +204,14 @@ config THERM_ADT746X
better fan behaviour by default, and some manual control.
config THERM_PM72
tristate "Support for thermal management on PowerMac G5"
tristate "Support for thermal management on PowerMac G5 (AGP)"
depends on I2C && I2C_POWERMAC && PPC_PMAC64
default n
help
This driver provides thermostat and fan control for the desktop
G5 machines.
G5 machines.
This is deprecated, use windfarm instead.
config WINDFARM
tristate "New PowerMac thermal control infrastructure"
......@@ -221,6 +224,22 @@ config WINDFARM_PM81
help
This driver provides thermal control for the iMacG5
config WINDFARM_PM72
tristate "Support for thermal management on PowerMac G5 (AGP)"
depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && ADB_PMU
select I2C_POWERMAC
help
This driver provides thermal control for the PowerMac G5
"AGP" variants (PowerMac 7,2 and 7,3)
config WINDFARM_RM31
tristate "Support for thermal management on Xserve G5"
depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && ADB_PMU
select I2C_POWERMAC
help
This driver provides thermal control for the Xserve G5
(RackMac3,1)
config WINDFARM_PM91
tristate "Support for thermal management on PowerMac9,1"
depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU
......
......@@ -29,6 +29,20 @@ obj-$(CONFIG_THERM_PM72) += therm_pm72.o
obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o
obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o
obj-$(CONFIG_WINDFARM) += windfarm_core.o
obj-$(CONFIG_WINDFARM_PM72) += windfarm_fcu_controls.o \
windfarm_ad7417_sensor.o \
windfarm_lm75_sensor.o \
windfarm_max6690_sensor.o \
windfarm_pid.o \
windfarm_cpufreq_clamp.o \
windfarm_pm72.o
obj-$(CONFIG_WINDFARM_RM31) += windfarm_fcu_controls.o \
windfarm_ad7417_sensor.o \
windfarm_lm75_sensor.o \
windfarm_lm87_sensor.o \
windfarm_pid.o \
windfarm_cpufreq_clamp.o \
windfarm_rm31.o
obj-$(CONFIG_WINDFARM_PM81) += windfarm_smu_controls.o \
windfarm_smu_sensors.o \
windfarm_lm75_sensor.o windfarm_pid.o \
......
......@@ -17,7 +17,7 @@
#include <linux/device.h>
/* Display a 16.16 fixed point value */
#define FIX32TOPRINT(f) ((f) >> 16),((((f) & 0xffff) * 1000) >> 16)
#define FIX32TOPRINT(f) (((s32)(f)) >> 16),(((((s32)(f)) & 0xffff) * 1000) >> 16)
/*
* Control objects
......@@ -41,6 +41,7 @@ struct wf_control {
int type;
struct kref ref;
struct device_attribute attr;
void *priv;
};
#define WF_CONTROL_TYPE_GENERIC 0
......
......@@ -169,8 +169,11 @@ static ssize_t wf_show_control(struct device *dev,
int err;
err = ctrl->ops->get_value(ctrl, &val);
if (err < 0)
if (err < 0) {
if (err == -EFAULT)
return sprintf(buf, "<HW FAULT>\n");
return err;
}
switch(ctrl->type) {
case WF_CONTROL_RPM_FAN:
typestr = " RPM";
......@@ -481,11 +484,6 @@ static int __init windfarm_core_init(void)
{
DBG("wf: core loaded\n");
/* Don't register on old machines that use therm_pm72 for now */
if (of_machine_is_compatible("PowerMac7,2") ||
of_machine_is_compatible("PowerMac7,3") ||
of_machine_is_compatible("RackMac3,1"))
return -ENODEV;
platform_device_register(&wf_platform_device);
return 0;
}
......
......@@ -75,12 +75,6 @@ static int __init wf_cpufreq_clamp_init(void)
{
struct wf_control *clamp;
/* Don't register on old machines that use therm_pm72 for now */
if (of_machine_is_compatible("PowerMac7,2") ||
of_machine_is_compatible("PowerMac7,3") ||
of_machine_is_compatible("RackMac3,1"))
return -ENODEV;
clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL);
if (clamp == NULL)
return -ENOMEM;
......
......@@ -41,10 +41,10 @@
* applied to the setpoint RPM speed, that is basically the
* speed we proviously "asked" for.
*
* I'm not sure which of these Apple's algorithm is supposed
* to use
* I'm using 0 for now which is what therm_pm72 used to do and
* what Darwin -apparently- does based on observed behaviour.
*/
#define RPM_PID_USE_ACTUAL_SPEED 1
#define RPM_PID_USE_ACTUAL_SPEED 0
/* Default min/max for pumps */
#define CPU_PUMP_OUTPUT_MAX 3200
......@@ -154,8 +154,6 @@ static int wf_fcu_fan_set_rpm(struct wf_control *ct, s32 value)
if (value > fan->max)
value = fan->max;
if (fan->target && fan->target == value)
return 0;
fan->target = value;
buf[0] = value >> (8 - shift);
......@@ -213,8 +211,6 @@ static int wf_fcu_fan_set_pwm(struct wf_control *ct, s32 value)
if (value > fan->max)
value = fan->max;
if (fan->target && fan->target == value)
return 0;
fan->target = value;
value = (value * 2559) / 1000;
......
/*
* Windfarm PowerMac thermal control
*
* Copyright 2012 Benjamin Herrenschmidt, IBM Corp.
*
* Released under the term of the GNU GPL v2.
*/
#ifndef __WINDFARM_MPU_H
#define __WINDFARM_MPU_H
typedef unsigned short fu16;
typedef int fs32;
typedef short fs16;
/* Definition of the MPU data structure which contains per CPU
* calibration information (among others) for the G5 machines
*/
struct mpu_data
{
u8 signature; /* 0x00 - EEPROM sig. */
u8 bytes_used; /* 0x01 - Bytes used in eeprom (160 ?) */
u8 size; /* 0x02 - EEPROM size (256 ?) */
u8 version; /* 0x03 - EEPROM version */
u32 data_revision; /* 0x04 - Dataset revision */
u8 processor_bin_code[3]; /* 0x08 - Processor BIN code */
u8 bin_code_expansion; /* 0x0b - ??? (padding ?) */
u8 processor_num; /* 0x0c - Number of CPUs on this MPU */
u8 input_mul_bus_div; /* 0x0d - Clock input multiplier/bus divider */
u8 reserved1[2]; /* 0x0e - */
u32 input_clk_freq_high; /* 0x10 - Input clock frequency high */
u8 cpu_nb_target_cycles; /* 0x14 - ??? */
u8 cpu_statlat; /* 0x15 - ??? */
u8 cpu_snooplat; /* 0x16 - ??? */
u8 cpu_snoopacc; /* 0x17 - ??? */
u8 nb_paamwin; /* 0x18 - ??? */
u8 nb_statlat; /* 0x19 - ??? */
u8 nb_snooplat; /* 0x1a - ??? */
u8 nb_snoopwin; /* 0x1b - ??? */
u8 api_bus_mode; /* 0x1c - ??? */
u8 reserved2[3]; /* 0x1d - */
u32 input_clk_freq_low; /* 0x20 - Input clock frequency low */
u8 processor_card_slot; /* 0x24 - Processor card slot number */
u8 reserved3[2]; /* 0x25 - */
u8 padjmax; /* 0x27 - Max power adjustment (Not in OF!) */
u8 ttarget; /* 0x28 - Target temperature */
u8 tmax; /* 0x29 - Max temperature */
u8 pmaxh; /* 0x2a - Max power */
u8 tguardband; /* 0x2b - Guardband temp ??? Hist. len in OSX */
fs32 pid_gp; /* 0x2c - PID proportional gain */
fs32 pid_gr; /* 0x30 - PID reset gain */
fs32 pid_gd; /* 0x34 - PID derivative gain */
fu16 voph; /* 0x38 - Vop High */
fu16 vopl; /* 0x3a - Vop Low */
fs16 nactual_die; /* 0x3c - nActual Die */
fs16 nactual_heatsink; /* 0x3e - nActual Heatsink */
fs16 nactual_system; /* 0x40 - nActual System */
u16 calibration_flags; /* 0x42 - Calibration flags */
fu16 mdiode; /* 0x44 - Diode M value (scaling factor) */
fs16 bdiode; /* 0x46 - Diode B value (offset) */
fs32 theta_heat_sink; /* 0x48 - Theta heat sink */
u16 rminn_intake_fan; /* 0x4c - Intake fan min RPM */
u16 rmaxn_intake_fan; /* 0x4e - Intake fan max RPM */
u16 rminn_exhaust_fan; /* 0x50 - Exhaust fan min RPM */
u16 rmaxn_exhaust_fan; /* 0x52 - Exhaust fan max RPM */
u8 processor_part_num[8]; /* 0x54 - Processor part number XX pumps min/max */
u32 processor_lot_num; /* 0x5c - Processor lot number */
u8 orig_card_sernum[0x10]; /* 0x60 - Card original serial number */
u8 curr_card_sernum[0x10]; /* 0x70 - Card current serial number */
u8 mlb_sernum[0x18]; /* 0x80 - MLB serial number */
u32 checksum1; /* 0x98 - */
u32 checksum2; /* 0x9c - */
}; /* Total size = 0xa0 */
static inline const struct mpu_data *wf_get_mpu(int cpu)
{
struct device_node *np;
char nodename[64];
const void *data;
int len;
/*
* prom.c routine for finding a node by path is a bit brain dead
* and requires exact @xxx unit numbers. This is a bit ugly but
* will work for these machines
*/
sprintf(nodename, "/u3@0,f8000000/i2c@f8001000/cpuid@a%d", cpu ? 2 : 0);
np = of_find_node_by_path(nodename);
if (!np)
return NULL;
data = of_get_property(np, "cpuid", &len);
of_node_put(np);
if (!data)
return NULL;
/*
* We are naughty, we have dropped the reference to the device
* node and still return a pointer to the content. We know we
* can do that though as this is only ever called on PowerMac
* which cannot remove those nodes
*/
return data;
}
#endif /* __WINDFARM_MPU_H */
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment