windfarm_fcu_controls.c (14476B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Windfarm PowerMac thermal control. FCU fan control 4 * 5 * Copyright 2012 Benjamin Herrenschmidt, IBM Corp. 6 */ 7#undef DEBUG 8 9#include <linux/types.h> 10#include <linux/errno.h> 11#include <linux/kernel.h> 12#include <linux/delay.h> 13#include <linux/slab.h> 14#include <linux/init.h> 15#include <linux/wait.h> 16#include <linux/i2c.h> 17 18#include <asm/machdep.h> 19#include <asm/io.h> 20#include <asm/sections.h> 21 22#include "windfarm.h" 23#include "windfarm_mpu.h" 24 25#define VERSION "1.0" 26 27#ifdef DEBUG 28#define DBG(args...) printk(args) 29#else 30#define DBG(args...) do { } while(0) 31#endif 32 33/* 34 * This option is "weird" :) Basically, if you define this to 1 35 * the control loop for the RPMs fans (not PWMs) will apply the 36 * correction factor obtained from the PID to the actual RPM 37 * speed read from the FCU. 38 * 39 * If you define the below constant to 0, then it will be 40 * applied to the setpoint RPM speed, that is basically the 41 * speed we proviously "asked" for. 42 * 43 * I'm using 0 for now which is what therm_pm72 used to do and 44 * what Darwin -apparently- does based on observed behaviour. 45 */ 46#define RPM_PID_USE_ACTUAL_SPEED 0 47 48/* Default min/max for pumps */ 49#define CPU_PUMP_OUTPUT_MAX 3200 50#define CPU_PUMP_OUTPUT_MIN 1250 51 52#define FCU_FAN_RPM 0 53#define FCU_FAN_PWM 1 54 55struct wf_fcu_priv { 56 struct kref ref; 57 struct i2c_client *i2c; 58 struct mutex lock; 59 struct list_head fan_list; 60 int rpm_shift; 61}; 62 63struct wf_fcu_fan { 64 struct list_head link; 65 int id; 66 s32 min, max, target; 67 struct wf_fcu_priv *fcu_priv; 68 struct wf_control ctrl; 69}; 70 71static void wf_fcu_release(struct kref *ref) 72{ 73 struct wf_fcu_priv *pv = container_of(ref, struct wf_fcu_priv, ref); 74 75 kfree(pv); 76} 77 78static void wf_fcu_fan_release(struct wf_control *ct) 79{ 80 struct wf_fcu_fan *fan = ct->priv; 81 82 kref_put(&fan->fcu_priv->ref, wf_fcu_release); 83 kfree(fan); 84} 85 86static int wf_fcu_read_reg(struct wf_fcu_priv *pv, int reg, 87 unsigned char *buf, int nb) 88{ 89 int tries, nr, nw; 90 91 mutex_lock(&pv->lock); 92 93 buf[0] = reg; 94 tries = 0; 95 for (;;) { 96 nw = i2c_master_send(pv->i2c, buf, 1); 97 if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100) 98 break; 99 msleep(10); 100 ++tries; 101 } 102 if (nw <= 0) { 103 pr_err("Failure writing address to FCU: %d", nw); 104 nr = nw; 105 goto bail; 106 } 107 tries = 0; 108 for (;;) { 109 nr = i2c_master_recv(pv->i2c, buf, nb); 110 if (nr > 0 || (nr < 0 && nr != -ENODEV) || tries >= 100) 111 break; 112 msleep(10); 113 ++tries; 114 } 115 if (nr <= 0) 116 pr_err("wf_fcu: Failure reading data from FCU: %d", nw); 117 bail: 118 mutex_unlock(&pv->lock); 119 return nr; 120} 121 122static int wf_fcu_write_reg(struct wf_fcu_priv *pv, int reg, 123 const unsigned char *ptr, int nb) 124{ 125 int tries, nw; 126 unsigned char buf[16]; 127 128 buf[0] = reg; 129 memcpy(buf+1, ptr, nb); 130 ++nb; 131 tries = 0; 132 for (;;) { 133 nw = i2c_master_send(pv->i2c, buf, nb); 134 if (nw > 0 || (nw < 0 && nw != -EIO) || tries >= 100) 135 break; 136 msleep(10); 137 ++tries; 138 } 139 if (nw < 0) 140 pr_err("wf_fcu: Failure writing to FCU: %d", nw); 141 return nw; 142} 143 144static int wf_fcu_fan_set_rpm(struct wf_control *ct, s32 value) 145{ 146 struct wf_fcu_fan *fan = ct->priv; 147 struct wf_fcu_priv *pv = fan->fcu_priv; 148 int rc, shift = pv->rpm_shift; 149 unsigned char buf[2]; 150 151 if (value < fan->min) 152 value = fan->min; 153 if (value > fan->max) 154 value = fan->max; 155 156 fan->target = value; 157 158 buf[0] = value >> (8 - shift); 159 buf[1] = value << shift; 160 rc = wf_fcu_write_reg(pv, 0x10 + (fan->id * 2), buf, 2); 161 if (rc < 0) 162 return -EIO; 163 return 0; 164} 165 166static int wf_fcu_fan_get_rpm(struct wf_control *ct, s32 *value) 167{ 168 struct wf_fcu_fan *fan = ct->priv; 169 struct wf_fcu_priv *pv = fan->fcu_priv; 170 int rc, reg_base, shift = pv->rpm_shift; 171 unsigned char failure; 172 unsigned char active; 173 unsigned char buf[2]; 174 175 rc = wf_fcu_read_reg(pv, 0xb, &failure, 1); 176 if (rc != 1) 177 return -EIO; 178 if ((failure & (1 << fan->id)) != 0) 179 return -EFAULT; 180 rc = wf_fcu_read_reg(pv, 0xd, &active, 1); 181 if (rc != 1) 182 return -EIO; 183 if ((active & (1 << fan->id)) == 0) 184 return -ENXIO; 185 186 /* Programmed value or real current speed */ 187#if RPM_PID_USE_ACTUAL_SPEED 188 reg_base = 0x11; 189#else 190 reg_base = 0x10; 191#endif 192 rc = wf_fcu_read_reg(pv, reg_base + (fan->id * 2), buf, 2); 193 if (rc != 2) 194 return -EIO; 195 196 *value = (buf[0] << (8 - shift)) | buf[1] >> shift; 197 198 return 0; 199} 200 201static int wf_fcu_fan_set_pwm(struct wf_control *ct, s32 value) 202{ 203 struct wf_fcu_fan *fan = ct->priv; 204 struct wf_fcu_priv *pv = fan->fcu_priv; 205 unsigned char buf[2]; 206 int rc; 207 208 if (value < fan->min) 209 value = fan->min; 210 if (value > fan->max) 211 value = fan->max; 212 213 fan->target = value; 214 215 value = (value * 2559) / 1000; 216 buf[0] = value; 217 rc = wf_fcu_write_reg(pv, 0x30 + (fan->id * 2), buf, 1); 218 if (rc < 0) 219 return -EIO; 220 return 0; 221} 222 223static int wf_fcu_fan_get_pwm(struct wf_control *ct, s32 *value) 224{ 225 struct wf_fcu_fan *fan = ct->priv; 226 struct wf_fcu_priv *pv = fan->fcu_priv; 227 unsigned char failure; 228 unsigned char active; 229 unsigned char buf[2]; 230 int rc; 231 232 rc = wf_fcu_read_reg(pv, 0x2b, &failure, 1); 233 if (rc != 1) 234 return -EIO; 235 if ((failure & (1 << fan->id)) != 0) 236 return -EFAULT; 237 rc = wf_fcu_read_reg(pv, 0x2d, &active, 1); 238 if (rc != 1) 239 return -EIO; 240 if ((active & (1 << fan->id)) == 0) 241 return -ENXIO; 242 243 rc = wf_fcu_read_reg(pv, 0x30 + (fan->id * 2), buf, 1); 244 if (rc != 1) 245 return -EIO; 246 247 *value = (((s32)buf[0]) * 1000) / 2559; 248 249 return 0; 250} 251 252static s32 wf_fcu_fan_min(struct wf_control *ct) 253{ 254 struct wf_fcu_fan *fan = ct->priv; 255 256 return fan->min; 257} 258 259static s32 wf_fcu_fan_max(struct wf_control *ct) 260{ 261 struct wf_fcu_fan *fan = ct->priv; 262 263 return fan->max; 264} 265 266static const struct wf_control_ops wf_fcu_fan_rpm_ops = { 267 .set_value = wf_fcu_fan_set_rpm, 268 .get_value = wf_fcu_fan_get_rpm, 269 .get_min = wf_fcu_fan_min, 270 .get_max = wf_fcu_fan_max, 271 .release = wf_fcu_fan_release, 272 .owner = THIS_MODULE, 273}; 274 275static const struct wf_control_ops wf_fcu_fan_pwm_ops = { 276 .set_value = wf_fcu_fan_set_pwm, 277 .get_value = wf_fcu_fan_get_pwm, 278 .get_min = wf_fcu_fan_min, 279 .get_max = wf_fcu_fan_max, 280 .release = wf_fcu_fan_release, 281 .owner = THIS_MODULE, 282}; 283 284static void wf_fcu_get_pump_minmax(struct wf_fcu_fan *fan) 285{ 286 const struct mpu_data *mpu = wf_get_mpu(0); 287 u16 pump_min = 0, pump_max = 0xffff; 288 u16 tmp[4]; 289 290 /* Try to fetch pumps min/max infos from eeprom */ 291 if (mpu) { 292 memcpy(&tmp, mpu->processor_part_num, 8); 293 if (tmp[0] != 0xffff && tmp[1] != 0xffff) { 294 pump_min = max(pump_min, tmp[0]); 295 pump_max = min(pump_max, tmp[1]); 296 } 297 if (tmp[2] != 0xffff && tmp[3] != 0xffff) { 298 pump_min = max(pump_min, tmp[2]); 299 pump_max = min(pump_max, tmp[3]); 300 } 301 } 302 303 /* Double check the values, this _IS_ needed as the EEPROM on 304 * some dual 2.5Ghz G5s seem, at least, to have both min & max 305 * same to the same value ... (grrrr) 306 */ 307 if (pump_min == pump_max || pump_min == 0 || pump_max == 0xffff) { 308 pump_min = CPU_PUMP_OUTPUT_MIN; 309 pump_max = CPU_PUMP_OUTPUT_MAX; 310 } 311 312 fan->min = pump_min; 313 fan->max = pump_max; 314 315 DBG("wf_fcu: pump min/max for %s set to: [%d..%d] RPM\n", 316 fan->ctrl.name, pump_min, pump_max); 317} 318 319static void wf_fcu_get_rpmfan_minmax(struct wf_fcu_fan *fan) 320{ 321 struct wf_fcu_priv *pv = fan->fcu_priv; 322 const struct mpu_data *mpu0 = wf_get_mpu(0); 323 const struct mpu_data *mpu1 = wf_get_mpu(1); 324 325 /* Default */ 326 fan->min = 2400 >> pv->rpm_shift; 327 fan->max = 56000 >> pv->rpm_shift; 328 329 /* CPU fans have min/max in MPU */ 330 if (mpu0 && !strcmp(fan->ctrl.name, "cpu-front-fan-0")) { 331 fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan); 332 fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan); 333 goto bail; 334 } 335 if (mpu1 && !strcmp(fan->ctrl.name, "cpu-front-fan-1")) { 336 fan->min = max(fan->min, (s32)mpu1->rminn_intake_fan); 337 fan->max = min(fan->max, (s32)mpu1->rmaxn_intake_fan); 338 goto bail; 339 } 340 if (mpu0 && !strcmp(fan->ctrl.name, "cpu-rear-fan-0")) { 341 fan->min = max(fan->min, (s32)mpu0->rminn_exhaust_fan); 342 fan->max = min(fan->max, (s32)mpu0->rmaxn_exhaust_fan); 343 goto bail; 344 } 345 if (mpu1 && !strcmp(fan->ctrl.name, "cpu-rear-fan-1")) { 346 fan->min = max(fan->min, (s32)mpu1->rminn_exhaust_fan); 347 fan->max = min(fan->max, (s32)mpu1->rmaxn_exhaust_fan); 348 goto bail; 349 } 350 /* Rackmac variants, we just use mpu0 intake */ 351 if (!strncmp(fan->ctrl.name, "cpu-fan", 7)) { 352 fan->min = max(fan->min, (s32)mpu0->rminn_intake_fan); 353 fan->max = min(fan->max, (s32)mpu0->rmaxn_intake_fan); 354 goto bail; 355 } 356 bail: 357 DBG("wf_fcu: fan min/max for %s set to: [%d..%d] RPM\n", 358 fan->ctrl.name, fan->min, fan->max); 359} 360 361static void wf_fcu_add_fan(struct wf_fcu_priv *pv, const char *name, 362 int type, int id) 363{ 364 struct wf_fcu_fan *fan; 365 366 fan = kzalloc(sizeof(*fan), GFP_KERNEL); 367 if (!fan) 368 return; 369 fan->fcu_priv = pv; 370 fan->id = id; 371 fan->ctrl.name = name; 372 fan->ctrl.priv = fan; 373 374 /* min/max is oddball but the code comes from 375 * therm_pm72 which seems to work so ... 376 */ 377 if (type == FCU_FAN_RPM) { 378 if (!strncmp(name, "cpu-pump", strlen("cpu-pump"))) 379 wf_fcu_get_pump_minmax(fan); 380 else 381 wf_fcu_get_rpmfan_minmax(fan); 382 fan->ctrl.type = WF_CONTROL_RPM_FAN; 383 fan->ctrl.ops = &wf_fcu_fan_rpm_ops; 384 } else { 385 fan->min = 10; 386 fan->max = 100; 387 fan->ctrl.type = WF_CONTROL_PWM_FAN; 388 fan->ctrl.ops = &wf_fcu_fan_pwm_ops; 389 } 390 391 if (wf_register_control(&fan->ctrl)) { 392 pr_err("wf_fcu: Failed to register fan %s\n", name); 393 kfree(fan); 394 return; 395 } 396 list_add(&fan->link, &pv->fan_list); 397 kref_get(&pv->ref); 398} 399 400static void wf_fcu_lookup_fans(struct wf_fcu_priv *pv) 401{ 402 /* Translation of device-tree location properties to 403 * windfarm fan names 404 */ 405 static const struct { 406 const char *dt_name; /* Device-tree name */ 407 const char *ct_name; /* Control name */ 408 } loc_trans[] = { 409 { "BACKSIDE", "backside-fan", }, 410 { "SYS CTRLR FAN", "backside-fan", }, 411 { "DRIVE BAY", "drive-bay-fan", }, 412 { "SLOT", "slots-fan", }, 413 { "PCI FAN", "slots-fan", }, 414 { "CPU A INTAKE", "cpu-front-fan-0", }, 415 { "CPU A EXHAUST", "cpu-rear-fan-0", }, 416 { "CPU B INTAKE", "cpu-front-fan-1", }, 417 { "CPU B EXHAUST", "cpu-rear-fan-1", }, 418 { "CPU A PUMP", "cpu-pump-0", }, 419 { "CPU B PUMP", "cpu-pump-1", }, 420 { "CPU A 1", "cpu-fan-a-0", }, 421 { "CPU A 2", "cpu-fan-b-0", }, 422 { "CPU A 3", "cpu-fan-c-0", }, 423 { "CPU B 1", "cpu-fan-a-1", }, 424 { "CPU B 2", "cpu-fan-b-1", }, 425 { "CPU B 3", "cpu-fan-c-1", }, 426 }; 427 struct device_node *np, *fcu = pv->i2c->dev.of_node; 428 int i; 429 430 DBG("Looking up FCU controls in device-tree...\n"); 431 432 for_each_child_of_node(fcu, np) { 433 int id, type = -1; 434 const char *loc; 435 const char *name; 436 const u32 *reg; 437 438 DBG(" control: %pOFn, type: %s\n", np, of_node_get_device_type(np)); 439 440 /* Detect control type */ 441 if (of_node_is_type(np, "fan-rpm-control") || 442 of_node_is_type(np, "fan-rpm")) 443 type = FCU_FAN_RPM; 444 if (of_node_is_type(np, "fan-pwm-control") || 445 of_node_is_type(np, "fan-pwm")) 446 type = FCU_FAN_PWM; 447 /* Only care about fans for now */ 448 if (type == -1) 449 continue; 450 451 /* Lookup for a matching location */ 452 loc = of_get_property(np, "location", NULL); 453 reg = of_get_property(np, "reg", NULL); 454 if (loc == NULL || reg == NULL) 455 continue; 456 DBG(" matching location: %s, reg: 0x%08x\n", loc, *reg); 457 458 for (i = 0; i < ARRAY_SIZE(loc_trans); i++) { 459 if (strncmp(loc, loc_trans[i].dt_name, 460 strlen(loc_trans[i].dt_name))) 461 continue; 462 name = loc_trans[i].ct_name; 463 464 DBG(" location match, name: %s\n", name); 465 466 if (type == FCU_FAN_RPM) 467 id = ((*reg) - 0x10) / 2; 468 else 469 id = ((*reg) - 0x30) / 2; 470 if (id > 7) { 471 pr_warn("wf_fcu: Can't parse fan ID in device-tree for %pOF\n", np); 472 break; 473 } 474 wf_fcu_add_fan(pv, name, type, id); 475 break; 476 } 477 } 478} 479 480static void wf_fcu_default_fans(struct wf_fcu_priv *pv) 481{ 482 /* We only support the default fans for PowerMac7,2 */ 483 if (!of_machine_is_compatible("PowerMac7,2")) 484 return; 485 486 wf_fcu_add_fan(pv, "backside-fan", FCU_FAN_PWM, 1); 487 wf_fcu_add_fan(pv, "drive-bay-fan", FCU_FAN_RPM, 2); 488 wf_fcu_add_fan(pv, "slots-fan", FCU_FAN_PWM, 2); 489 wf_fcu_add_fan(pv, "cpu-front-fan-0", FCU_FAN_RPM, 3); 490 wf_fcu_add_fan(pv, "cpu-rear-fan-0", FCU_FAN_RPM, 4); 491 wf_fcu_add_fan(pv, "cpu-front-fan-1", FCU_FAN_RPM, 5); 492 wf_fcu_add_fan(pv, "cpu-rear-fan-1", FCU_FAN_RPM, 6); 493} 494 495static int wf_fcu_init_chip(struct wf_fcu_priv *pv) 496{ 497 unsigned char buf = 0xff; 498 int rc; 499 500 rc = wf_fcu_write_reg(pv, 0xe, &buf, 1); 501 if (rc < 0) 502 return -EIO; 503 rc = wf_fcu_write_reg(pv, 0x2e, &buf, 1); 504 if (rc < 0) 505 return -EIO; 506 rc = wf_fcu_read_reg(pv, 0, &buf, 1); 507 if (rc < 0) 508 return -EIO; 509 pv->rpm_shift = (buf == 1) ? 2 : 3; 510 511 pr_debug("wf_fcu: FCU Initialized, RPM fan shift is %d\n", 512 pv->rpm_shift); 513 514 return 0; 515} 516 517static int wf_fcu_probe(struct i2c_client *client, 518 const struct i2c_device_id *id) 519{ 520 struct wf_fcu_priv *pv; 521 522 pv = kzalloc(sizeof(*pv), GFP_KERNEL); 523 if (!pv) 524 return -ENOMEM; 525 526 kref_init(&pv->ref); 527 mutex_init(&pv->lock); 528 INIT_LIST_HEAD(&pv->fan_list); 529 pv->i2c = client; 530 531 /* 532 * First we must start the FCU which will query the 533 * shift value to apply to RPMs 534 */ 535 if (wf_fcu_init_chip(pv)) { 536 pr_err("wf_fcu: Initialization failed !\n"); 537 kfree(pv); 538 return -ENXIO; 539 } 540 541 /* First lookup fans in the device-tree */ 542 wf_fcu_lookup_fans(pv); 543 544 /* 545 * Older machines don't have the device-tree entries 546 * we are looking for, just hard code the list 547 */ 548 if (list_empty(&pv->fan_list)) 549 wf_fcu_default_fans(pv); 550 551 /* Still no fans ? FAIL */ 552 if (list_empty(&pv->fan_list)) { 553 pr_err("wf_fcu: Failed to find fans for your machine\n"); 554 kfree(pv); 555 return -ENODEV; 556 } 557 558 dev_set_drvdata(&client->dev, pv); 559 560 return 0; 561} 562 563static int wf_fcu_remove(struct i2c_client *client) 564{ 565 struct wf_fcu_priv *pv = dev_get_drvdata(&client->dev); 566 struct wf_fcu_fan *fan; 567 568 while (!list_empty(&pv->fan_list)) { 569 fan = list_first_entry(&pv->fan_list, struct wf_fcu_fan, link); 570 list_del(&fan->link); 571 wf_unregister_control(&fan->ctrl); 572 } 573 kref_put(&pv->ref, wf_fcu_release); 574 return 0; 575} 576 577static const struct i2c_device_id wf_fcu_id[] = { 578 { "MAC,fcu", 0 }, 579 { } 580}; 581MODULE_DEVICE_TABLE(i2c, wf_fcu_id); 582 583static const struct of_device_id wf_fcu_of_id[] = { 584 { .compatible = "fcu", }, 585 { } 586}; 587MODULE_DEVICE_TABLE(of, wf_fcu_of_id); 588 589static struct i2c_driver wf_fcu_driver = { 590 .driver = { 591 .name = "wf_fcu", 592 .of_match_table = wf_fcu_of_id, 593 }, 594 .probe = wf_fcu_probe, 595 .remove = wf_fcu_remove, 596 .id_table = wf_fcu_id, 597}; 598 599module_i2c_driver(wf_fcu_driver); 600 601MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); 602MODULE_DESCRIPTION("FCU control objects for PowerMacs thermal control"); 603MODULE_LICENSE("GPL"); 604