linux/drivers/macintosh/windfarm_fcu_controls.c
<<
>>
Prefs
   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#include <asm/prom.h>
  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
 605