linux/drivers/hwmon/xgene-hwmon.c
<<
>>
Prefs
   1/*
   2 * APM X-Gene SoC Hardware Monitoring Driver
   3 *
   4 * Copyright (c) 2016, Applied Micro Circuits Corporation
   5 * Author: Loc Ho <lho@apm.com>
   6 *         Hoan Tran <hotran@apm.com>
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License as
  10 * published by the Free Software Foundation; either version 2 of
  11 * the License, or (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
  20 *
  21 * This driver provides the following features:
  22 *  - Retrieve CPU total power (uW)
  23 *  - Retrieve IO total power (uW)
  24 *  - Retrieve SoC temperature (milli-degree C) and alarm
  25 */
  26#include <linux/acpi.h>
  27#include <linux/dma-mapping.h>
  28#include <linux/hwmon.h>
  29#include <linux/hwmon-sysfs.h>
  30#include <linux/io.h>
  31#include <linux/interrupt.h>
  32#include <linux/kfifo.h>
  33#include <linux/mailbox_controller.h>
  34#include <linux/mailbox_client.h>
  35#include <linux/module.h>
  36#include <linux/of.h>
  37#include <linux/platform_device.h>
  38
  39#include <acpi/pcc.h>
  40
  41/* SLIMpro message defines */
  42#define MSG_TYPE_DBG                    0
  43#define MSG_TYPE_ERR                    7
  44#define MSG_TYPE_PWRMGMT                9
  45
  46#define MSG_TYPE(v)                     (((v) & 0xF0000000) >> 28)
  47#define MSG_TYPE_SET(v)                 (((v) << 28) & 0xF0000000)
  48#define MSG_SUBTYPE(v)                  (((v) & 0x0F000000) >> 24)
  49#define MSG_SUBTYPE_SET(v)              (((v) << 24) & 0x0F000000)
  50
  51#define DBG_SUBTYPE_SENSOR_READ         4
  52#define SENSOR_RD_MSG                   0x04FFE902
  53#define SENSOR_RD_EN_ADDR(a)            ((a) & 0x000FFFFF)
  54#define PMD_PWR_REG                     0x20
  55#define PMD_PWR_MW_REG                  0x26
  56#define SOC_PWR_REG                     0x21
  57#define SOC_PWR_MW_REG                  0x27
  58#define SOC_TEMP_REG                    0x10
  59
  60#define TEMP_NEGATIVE_BIT               8
  61#define SENSOR_INVALID_DATA             BIT(15)
  62
  63#define PWRMGMT_SUBTYPE_TPC             1
  64#define TPC_ALARM                       2
  65#define TPC_GET_ALARM                   3
  66#define TPC_CMD(v)                      (((v) & 0x00FF0000) >> 16)
  67#define TPC_CMD_SET(v)                  (((v) << 16) & 0x00FF0000)
  68#define TPC_EN_MSG(hndl, cmd, type) \
  69        (MSG_TYPE_SET(MSG_TYPE_PWRMGMT) | \
  70        MSG_SUBTYPE_SET(hndl) | TPC_CMD_SET(cmd) | type)
  71
  72/* PCC defines */
  73#define PCC_SIGNATURE_MASK              0x50424300
  74#define PCCC_GENERATE_DB_INT            BIT(15)
  75#define PCCS_CMD_COMPLETE               BIT(0)
  76#define PCCS_SCI_DOORBEL                BIT(1)
  77#define PCCS_PLATFORM_NOTIFICATION      BIT(3)
  78/*
  79 * Arbitrary retries in case the remote processor is slow to respond
  80 * to PCC commands
  81 */
  82#define PCC_NUM_RETRIES                 500
  83
  84#define ASYNC_MSG_FIFO_SIZE             16
  85#define MBOX_OP_TIMEOUTMS               1000
  86
  87#define WATT_TO_mWATT(x)                ((x) * 1000)
  88#define mWATT_TO_uWATT(x)               ((x) * 1000)
  89#define CELSIUS_TO_mCELSIUS(x)          ((x) * 1000)
  90
  91#define to_xgene_hwmon_dev(cl)          \
  92        container_of(cl, struct xgene_hwmon_dev, mbox_client)
  93
  94enum xgene_hwmon_version {
  95        XGENE_HWMON_V1 = 0,
  96        XGENE_HWMON_V2 = 1,
  97};
  98
  99struct slimpro_resp_msg {
 100        u32 msg;
 101        u32 param1;
 102        u32 param2;
 103} __packed;
 104
 105struct xgene_hwmon_dev {
 106        struct device           *dev;
 107        struct mbox_chan        *mbox_chan;
 108        struct mbox_client      mbox_client;
 109        int                     mbox_idx;
 110
 111        spinlock_t              kfifo_lock;
 112        struct mutex            rd_mutex;
 113        struct completion       rd_complete;
 114        int                     resp_pending;
 115        struct slimpro_resp_msg sync_msg;
 116
 117        struct work_struct      workq;
 118        struct kfifo_rec_ptr_1  async_msg_fifo;
 119
 120        struct device           *hwmon_dev;
 121        bool                    temp_critical_alarm;
 122
 123        phys_addr_t             comm_base_addr;
 124        void                    *pcc_comm_addr;
 125        u64                     usecs_lat;
 126};
 127
 128/*
 129 * This function tests and clears a bitmask then returns its old value
 130 */
 131static u16 xgene_word_tst_and_clr(u16 *addr, u16 mask)
 132{
 133        u16 ret, val;
 134
 135        val = le16_to_cpu(READ_ONCE(*addr));
 136        ret = val & mask;
 137        val &= ~mask;
 138        WRITE_ONCE(*addr, cpu_to_le16(val));
 139
 140        return ret;
 141}
 142
 143static int xgene_hwmon_pcc_rd(struct xgene_hwmon_dev *ctx, u32 *msg)
 144{
 145        struct acpi_pcct_shared_memory *generic_comm_base = ctx->pcc_comm_addr;
 146        u32 *ptr = (void *)(generic_comm_base + 1);
 147        int rc, i;
 148        u16 val;
 149
 150        mutex_lock(&ctx->rd_mutex);
 151        init_completion(&ctx->rd_complete);
 152        ctx->resp_pending = true;
 153
 154        /* Write signature for subspace */
 155        WRITE_ONCE(generic_comm_base->signature,
 156                   cpu_to_le32(PCC_SIGNATURE_MASK | ctx->mbox_idx));
 157
 158        /* Write to the shared command region */
 159        WRITE_ONCE(generic_comm_base->command,
 160                   cpu_to_le16(MSG_TYPE(msg[0]) | PCCC_GENERATE_DB_INT));
 161
 162        /* Flip CMD COMPLETE bit */
 163        val = le16_to_cpu(READ_ONCE(generic_comm_base->status));
 164        val &= ~PCCS_CMD_COMPLETE;
 165        WRITE_ONCE(generic_comm_base->status, cpu_to_le16(val));
 166
 167        /* Copy the message to the PCC comm space */
 168        for (i = 0; i < sizeof(struct slimpro_resp_msg) / 4; i++)
 169                WRITE_ONCE(ptr[i], cpu_to_le32(msg[i]));
 170
 171        /* Ring the doorbell */
 172        rc = mbox_send_message(ctx->mbox_chan, msg);
 173        if (rc < 0) {
 174                dev_err(ctx->dev, "Mailbox send error %d\n", rc);
 175                goto err;
 176        }
 177        if (!wait_for_completion_timeout(&ctx->rd_complete,
 178                                         usecs_to_jiffies(ctx->usecs_lat))) {
 179                dev_err(ctx->dev, "Mailbox operation timed out\n");
 180                rc = -ETIMEDOUT;
 181                goto err;
 182        }
 183
 184        /* Check for error message */
 185        if (MSG_TYPE(ctx->sync_msg.msg) == MSG_TYPE_ERR) {
 186                rc = -EINVAL;
 187                goto err;
 188        }
 189
 190        msg[0] = ctx->sync_msg.msg;
 191        msg[1] = ctx->sync_msg.param1;
 192        msg[2] = ctx->sync_msg.param2;
 193
 194err:
 195        mbox_chan_txdone(ctx->mbox_chan, 0);
 196        ctx->resp_pending = false;
 197        mutex_unlock(&ctx->rd_mutex);
 198        return rc;
 199}
 200
 201static int xgene_hwmon_rd(struct xgene_hwmon_dev *ctx, u32 *msg)
 202{
 203        int rc;
 204
 205        mutex_lock(&ctx->rd_mutex);
 206        init_completion(&ctx->rd_complete);
 207        ctx->resp_pending = true;
 208
 209        rc = mbox_send_message(ctx->mbox_chan, msg);
 210        if (rc < 0) {
 211                dev_err(ctx->dev, "Mailbox send error %d\n", rc);
 212                goto err;
 213        }
 214
 215        if (!wait_for_completion_timeout(&ctx->rd_complete,
 216                                         msecs_to_jiffies(MBOX_OP_TIMEOUTMS))) {
 217                dev_err(ctx->dev, "Mailbox operation timed out\n");
 218                rc = -ETIMEDOUT;
 219                goto err;
 220        }
 221
 222        /* Check for error message */
 223        if (MSG_TYPE(ctx->sync_msg.msg) == MSG_TYPE_ERR) {
 224                rc = -EINVAL;
 225                goto err;
 226        }
 227
 228        msg[0] = ctx->sync_msg.msg;
 229        msg[1] = ctx->sync_msg.param1;
 230        msg[2] = ctx->sync_msg.param2;
 231
 232err:
 233        ctx->resp_pending = false;
 234        mutex_unlock(&ctx->rd_mutex);
 235        return rc;
 236}
 237
 238static int xgene_hwmon_reg_map_rd(struct xgene_hwmon_dev *ctx, u32 addr,
 239                                  u32 *data)
 240{
 241        u32 msg[3];
 242        int rc;
 243
 244        msg[0] = SENSOR_RD_MSG;
 245        msg[1] = SENSOR_RD_EN_ADDR(addr);
 246        msg[2] = 0;
 247
 248        if (acpi_disabled)
 249                rc = xgene_hwmon_rd(ctx, msg);
 250        else
 251                rc = xgene_hwmon_pcc_rd(ctx, msg);
 252
 253        if (rc < 0)
 254                return rc;
 255
 256        /*
 257         * Check if sensor data is valid.
 258         */
 259        if (msg[1] & SENSOR_INVALID_DATA)
 260                return -ENODATA;
 261
 262        *data = msg[1];
 263
 264        return rc;
 265}
 266
 267static int xgene_hwmon_get_notification_msg(struct xgene_hwmon_dev *ctx,
 268                                            u32 *amsg)
 269{
 270        u32 msg[3];
 271        int rc;
 272
 273        msg[0] = TPC_EN_MSG(PWRMGMT_SUBTYPE_TPC, TPC_GET_ALARM, 0);
 274        msg[1] = 0;
 275        msg[2] = 0;
 276
 277        rc = xgene_hwmon_pcc_rd(ctx, msg);
 278        if (rc < 0)
 279                return rc;
 280
 281        amsg[0] = msg[0];
 282        amsg[1] = msg[1];
 283        amsg[2] = msg[2];
 284
 285        return rc;
 286}
 287
 288static int xgene_hwmon_get_cpu_pwr(struct xgene_hwmon_dev *ctx, u32 *val)
 289{
 290        u32 watt, mwatt;
 291        int rc;
 292
 293        rc = xgene_hwmon_reg_map_rd(ctx, PMD_PWR_REG, &watt);
 294        if (rc < 0)
 295                return rc;
 296
 297        rc = xgene_hwmon_reg_map_rd(ctx, PMD_PWR_MW_REG, &mwatt);
 298        if (rc < 0)
 299                return rc;
 300
 301        *val = WATT_TO_mWATT(watt) + mwatt;
 302        return 0;
 303}
 304
 305static int xgene_hwmon_get_io_pwr(struct xgene_hwmon_dev *ctx, u32 *val)
 306{
 307        u32 watt, mwatt;
 308        int rc;
 309
 310        rc = xgene_hwmon_reg_map_rd(ctx, SOC_PWR_REG, &watt);
 311        if (rc < 0)
 312                return rc;
 313
 314        rc = xgene_hwmon_reg_map_rd(ctx, SOC_PWR_MW_REG, &mwatt);
 315        if (rc < 0)
 316                return rc;
 317
 318        *val = WATT_TO_mWATT(watt) + mwatt;
 319        return 0;
 320}
 321
 322static int xgene_hwmon_get_temp(struct xgene_hwmon_dev *ctx, u32 *val)
 323{
 324        return xgene_hwmon_reg_map_rd(ctx, SOC_TEMP_REG, val);
 325}
 326
 327/*
 328 * Sensor temperature/power functions
 329 */
 330static ssize_t temp1_input_show(struct device *dev,
 331                                struct device_attribute *attr,
 332                                char *buf)
 333{
 334        struct xgene_hwmon_dev *ctx = dev_get_drvdata(dev);
 335        int rc, temp;
 336        u32 val;
 337
 338        rc = xgene_hwmon_get_temp(ctx, &val);
 339        if (rc < 0)
 340                return rc;
 341
 342        temp = sign_extend32(val, TEMP_NEGATIVE_BIT);
 343
 344        return snprintf(buf, PAGE_SIZE, "%d\n", CELSIUS_TO_mCELSIUS(temp));
 345}
 346
 347static ssize_t temp1_label_show(struct device *dev,
 348                                struct device_attribute *attr,
 349                                char *buf)
 350{
 351        return snprintf(buf, PAGE_SIZE, "SoC Temperature\n");
 352}
 353
 354static ssize_t temp1_critical_alarm_show(struct device *dev,
 355                                         struct device_attribute *devattr,
 356                                         char *buf)
 357{
 358        struct xgene_hwmon_dev *ctx = dev_get_drvdata(dev);
 359
 360        return snprintf(buf, PAGE_SIZE, "%d\n", ctx->temp_critical_alarm);
 361}
 362
 363static ssize_t power1_label_show(struct device *dev,
 364                                 struct device_attribute *attr,
 365                                 char *buf)
 366{
 367        return snprintf(buf, PAGE_SIZE, "CPU power\n");
 368}
 369
 370static ssize_t power2_label_show(struct device *dev,
 371                                 struct device_attribute *attr,
 372                                 char *buf)
 373{
 374        return snprintf(buf, PAGE_SIZE, "IO power\n");
 375}
 376
 377static ssize_t power1_input_show(struct device *dev,
 378                                 struct device_attribute *attr,
 379                                 char *buf)
 380{
 381        struct xgene_hwmon_dev *ctx = dev_get_drvdata(dev);
 382        u32 val;
 383        int rc;
 384
 385        rc = xgene_hwmon_get_cpu_pwr(ctx, &val);
 386        if (rc < 0)
 387                return rc;
 388
 389        return snprintf(buf, PAGE_SIZE, "%u\n", mWATT_TO_uWATT(val));
 390}
 391
 392static ssize_t power2_input_show(struct device *dev,
 393                                 struct device_attribute *attr,
 394                                 char *buf)
 395{
 396        struct xgene_hwmon_dev *ctx = dev_get_drvdata(dev);
 397        u32 val;
 398        int rc;
 399
 400        rc = xgene_hwmon_get_io_pwr(ctx, &val);
 401        if (rc < 0)
 402                return rc;
 403
 404        return snprintf(buf, PAGE_SIZE, "%u\n", mWATT_TO_uWATT(val));
 405}
 406
 407static DEVICE_ATTR_RO(temp1_label);
 408static DEVICE_ATTR_RO(temp1_input);
 409static DEVICE_ATTR_RO(temp1_critical_alarm);
 410static DEVICE_ATTR_RO(power1_label);
 411static DEVICE_ATTR_RO(power1_input);
 412static DEVICE_ATTR_RO(power2_label);
 413static DEVICE_ATTR_RO(power2_input);
 414
 415static struct attribute *xgene_hwmon_attrs[] = {
 416        &dev_attr_temp1_label.attr,
 417        &dev_attr_temp1_input.attr,
 418        &dev_attr_temp1_critical_alarm.attr,
 419        &dev_attr_power1_label.attr,
 420        &dev_attr_power1_input.attr,
 421        &dev_attr_power2_label.attr,
 422        &dev_attr_power2_input.attr,
 423        NULL,
 424};
 425
 426ATTRIBUTE_GROUPS(xgene_hwmon);
 427
 428static int xgene_hwmon_tpc_alarm(struct xgene_hwmon_dev *ctx,
 429                                 struct slimpro_resp_msg *amsg)
 430{
 431        ctx->temp_critical_alarm = !!amsg->param2;
 432        sysfs_notify(&ctx->dev->kobj, NULL, "temp1_critical_alarm");
 433
 434        return 0;
 435}
 436
 437static void xgene_hwmon_process_pwrmsg(struct xgene_hwmon_dev *ctx,
 438                                       struct slimpro_resp_msg *amsg)
 439{
 440        if ((MSG_SUBTYPE(amsg->msg) == PWRMGMT_SUBTYPE_TPC) &&
 441            (TPC_CMD(amsg->msg) == TPC_ALARM))
 442                xgene_hwmon_tpc_alarm(ctx, amsg);
 443}
 444
 445/*
 446 * This function is called to process async work queue
 447 */
 448static void xgene_hwmon_evt_work(struct work_struct *work)
 449{
 450        struct slimpro_resp_msg amsg;
 451        struct xgene_hwmon_dev *ctx;
 452        int ret;
 453
 454        ctx = container_of(work, struct xgene_hwmon_dev, workq);
 455        while (kfifo_out_spinlocked(&ctx->async_msg_fifo, &amsg,
 456                                    sizeof(struct slimpro_resp_msg),
 457                                    &ctx->kfifo_lock)) {
 458                /*
 459                 * If PCC, send a consumer command to Platform to get info
 460                 * If Slimpro Mailbox, get message from specific FIFO
 461                 */
 462                if (!acpi_disabled) {
 463                        ret = xgene_hwmon_get_notification_msg(ctx,
 464                                                               (u32 *)&amsg);
 465                        if (ret < 0)
 466                                continue;
 467                }
 468
 469                if (MSG_TYPE(amsg.msg) == MSG_TYPE_PWRMGMT)
 470                        xgene_hwmon_process_pwrmsg(ctx, &amsg);
 471        }
 472}
 473
 474static int xgene_hwmon_rx_ready(struct xgene_hwmon_dev *ctx, void *msg)
 475{
 476        if (IS_ERR_OR_NULL(ctx->hwmon_dev) && !ctx->resp_pending) {
 477                /* Enqueue to the FIFO */
 478                kfifo_in_spinlocked(&ctx->async_msg_fifo, msg,
 479                                    sizeof(struct slimpro_resp_msg),
 480                                    &ctx->kfifo_lock);
 481                return -ENODEV;
 482        }
 483
 484        return 0;
 485}
 486
 487/*
 488 * This function is called when the SLIMpro Mailbox received a message
 489 */
 490static void xgene_hwmon_rx_cb(struct mbox_client *cl, void *msg)
 491{
 492        struct xgene_hwmon_dev *ctx = to_xgene_hwmon_dev(cl);
 493
 494        /*
 495         * While the driver registers with the mailbox framework, an interrupt
 496         * can be pending before the probe function completes its
 497         * initialization. If such condition occurs, just queue up the message
 498         * as the driver is not ready for servicing the callback.
 499         */
 500        if (xgene_hwmon_rx_ready(ctx, msg) < 0)
 501                return;
 502
 503        /*
 504         * Response message format:
 505         * msg[0] is the return code of the operation
 506         * msg[1] is the first parameter word
 507         * msg[2] is the second parameter word
 508         *
 509         * As message only supports dword size, just assign it.
 510         */
 511
 512        /* Check for sync query */
 513        if (ctx->resp_pending &&
 514            ((MSG_TYPE(((u32 *)msg)[0]) == MSG_TYPE_ERR) ||
 515             (MSG_TYPE(((u32 *)msg)[0]) == MSG_TYPE_DBG &&
 516              MSG_SUBTYPE(((u32 *)msg)[0]) == DBG_SUBTYPE_SENSOR_READ) ||
 517             (MSG_TYPE(((u32 *)msg)[0]) == MSG_TYPE_PWRMGMT &&
 518              MSG_SUBTYPE(((u32 *)msg)[0]) == PWRMGMT_SUBTYPE_TPC &&
 519              TPC_CMD(((u32 *)msg)[0]) == TPC_ALARM))) {
 520                ctx->sync_msg.msg = ((u32 *)msg)[0];
 521                ctx->sync_msg.param1 = ((u32 *)msg)[1];
 522                ctx->sync_msg.param2 = ((u32 *)msg)[2];
 523
 524                /* Operation waiting for response */
 525                complete(&ctx->rd_complete);
 526
 527                return;
 528        }
 529
 530        /* Enqueue to the FIFO */
 531        kfifo_in_spinlocked(&ctx->async_msg_fifo, msg,
 532                            sizeof(struct slimpro_resp_msg), &ctx->kfifo_lock);
 533        /* Schedule the bottom handler */
 534        schedule_work(&ctx->workq);
 535}
 536
 537/*
 538 * This function is called when the PCC Mailbox received a message
 539 */
 540static void xgene_hwmon_pcc_rx_cb(struct mbox_client *cl, void *msg)
 541{
 542        struct xgene_hwmon_dev *ctx = to_xgene_hwmon_dev(cl);
 543        struct acpi_pcct_shared_memory *generic_comm_base = ctx->pcc_comm_addr;
 544        struct slimpro_resp_msg amsg;
 545
 546        /*
 547         * While the driver registers with the mailbox framework, an interrupt
 548         * can be pending before the probe function completes its
 549         * initialization. If such condition occurs, just queue up the message
 550         * as the driver is not ready for servicing the callback.
 551         */
 552        if (xgene_hwmon_rx_ready(ctx, &amsg) < 0)
 553                return;
 554
 555        msg = generic_comm_base + 1;
 556        /* Check if platform sends interrupt */
 557        if (!xgene_word_tst_and_clr(&generic_comm_base->status,
 558                                    PCCS_SCI_DOORBEL))
 559                return;
 560
 561        /*
 562         * Response message format:
 563         * msg[0] is the return code of the operation
 564         * msg[1] is the first parameter word
 565         * msg[2] is the second parameter word
 566         *
 567         * As message only supports dword size, just assign it.
 568         */
 569
 570        /* Check for sync query */
 571        if (ctx->resp_pending &&
 572            ((MSG_TYPE(((u32 *)msg)[0]) == MSG_TYPE_ERR) ||
 573             (MSG_TYPE(((u32 *)msg)[0]) == MSG_TYPE_DBG &&
 574              MSG_SUBTYPE(((u32 *)msg)[0]) == DBG_SUBTYPE_SENSOR_READ) ||
 575             (MSG_TYPE(((u32 *)msg)[0]) == MSG_TYPE_PWRMGMT &&
 576              MSG_SUBTYPE(((u32 *)msg)[0]) == PWRMGMT_SUBTYPE_TPC &&
 577              TPC_CMD(((u32 *)msg)[0]) == TPC_ALARM))) {
 578                /* Check if platform completes command */
 579                if (xgene_word_tst_and_clr(&generic_comm_base->status,
 580                                           PCCS_CMD_COMPLETE)) {
 581                        ctx->sync_msg.msg = ((u32 *)msg)[0];
 582                        ctx->sync_msg.param1 = ((u32 *)msg)[1];
 583                        ctx->sync_msg.param2 = ((u32 *)msg)[2];
 584
 585                        /* Operation waiting for response */
 586                        complete(&ctx->rd_complete);
 587
 588                        return;
 589                }
 590        }
 591
 592        /*
 593         * Platform notifies interrupt to OSPM.
 594         * OPSM schedules a consumer command to get this information
 595         * in a workqueue. Platform must wait until OSPM has issued
 596         * a consumer command that serves this notification.
 597         */
 598
 599        /* Enqueue to the FIFO */
 600        kfifo_in_spinlocked(&ctx->async_msg_fifo, &amsg,
 601                            sizeof(struct slimpro_resp_msg), &ctx->kfifo_lock);
 602        /* Schedule the bottom handler */
 603        schedule_work(&ctx->workq);
 604}
 605
 606static void xgene_hwmon_tx_done(struct mbox_client *cl, void *msg, int ret)
 607{
 608        if (ret) {
 609                dev_dbg(cl->dev, "TX did not complete: CMD sent:%x, ret:%d\n",
 610                        *(u16 *)msg, ret);
 611        } else {
 612                dev_dbg(cl->dev, "TX completed. CMD sent:%x, ret:%d\n",
 613                        *(u16 *)msg, ret);
 614        }
 615}
 616
 617#ifdef CONFIG_ACPI
 618static const struct acpi_device_id xgene_hwmon_acpi_match[] = {
 619        {"APMC0D29", XGENE_HWMON_V1},
 620        {"APMC0D8A", XGENE_HWMON_V2},
 621        {},
 622};
 623MODULE_DEVICE_TABLE(acpi, xgene_hwmon_acpi_match);
 624#endif
 625
 626static int xgene_hwmon_probe(struct platform_device *pdev)
 627{
 628        struct xgene_hwmon_dev *ctx;
 629        struct mbox_client *cl;
 630        int rc;
 631
 632        ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 633        if (!ctx)
 634                return -ENOMEM;
 635
 636        ctx->dev = &pdev->dev;
 637        platform_set_drvdata(pdev, ctx);
 638        cl = &ctx->mbox_client;
 639
 640        spin_lock_init(&ctx->kfifo_lock);
 641        mutex_init(&ctx->rd_mutex);
 642
 643        rc = kfifo_alloc(&ctx->async_msg_fifo,
 644                         sizeof(struct slimpro_resp_msg) * ASYNC_MSG_FIFO_SIZE,
 645                         GFP_KERNEL);
 646        if (rc)
 647                return -ENOMEM;
 648
 649        INIT_WORK(&ctx->workq, xgene_hwmon_evt_work);
 650
 651        /* Request mailbox channel */
 652        cl->dev = &pdev->dev;
 653        cl->tx_done = xgene_hwmon_tx_done;
 654        cl->tx_block = false;
 655        cl->tx_tout = MBOX_OP_TIMEOUTMS;
 656        cl->knows_txdone = false;
 657        if (acpi_disabled) {
 658                cl->rx_callback = xgene_hwmon_rx_cb;
 659                ctx->mbox_chan = mbox_request_channel(cl, 0);
 660                if (IS_ERR(ctx->mbox_chan)) {
 661                        dev_err(&pdev->dev,
 662                                "SLIMpro mailbox channel request failed\n");
 663                        rc = -ENODEV;
 664                        goto out_mbox_free;
 665                }
 666        } else {
 667                struct acpi_pcct_hw_reduced *cppc_ss;
 668                const struct acpi_device_id *acpi_id;
 669                int version;
 670
 671                acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table,
 672                                            &pdev->dev);
 673                if (!acpi_id)
 674                        return -EINVAL;
 675
 676                version = (int)acpi_id->driver_data;
 677
 678                if (device_property_read_u32(&pdev->dev, "pcc-channel",
 679                                             &ctx->mbox_idx)) {
 680                        dev_err(&pdev->dev, "no pcc-channel property\n");
 681                        rc = -ENODEV;
 682                        goto out_mbox_free;
 683                }
 684
 685                cl->rx_callback = xgene_hwmon_pcc_rx_cb;
 686                ctx->mbox_chan = pcc_mbox_request_channel(cl, ctx->mbox_idx);
 687                if (IS_ERR(ctx->mbox_chan)) {
 688                        dev_err(&pdev->dev,
 689                                "PPC channel request failed\n");
 690                        rc = -ENODEV;
 691                        goto out_mbox_free;
 692                }
 693
 694                /*
 695                 * The PCC mailbox controller driver should
 696                 * have parsed the PCCT (global table of all
 697                 * PCC channels) and stored pointers to the
 698                 * subspace communication region in con_priv.
 699                 */
 700                cppc_ss = ctx->mbox_chan->con_priv;
 701                if (!cppc_ss) {
 702                        dev_err(&pdev->dev, "PPC subspace not found\n");
 703                        rc = -ENODEV;
 704                        goto out;
 705                }
 706
 707                if (!ctx->mbox_chan->mbox->txdone_irq) {
 708                        dev_err(&pdev->dev, "PCC IRQ not supported\n");
 709                        rc = -ENODEV;
 710                        goto out;
 711                }
 712
 713                /*
 714                 * This is the shared communication region
 715                 * for the OS and Platform to communicate over.
 716                 */
 717                ctx->comm_base_addr = cppc_ss->base_address;
 718                if (ctx->comm_base_addr) {
 719                        if (version == XGENE_HWMON_V2)
 720                                ctx->pcc_comm_addr = (void __force *)ioremap(
 721                                                        ctx->comm_base_addr,
 722                                                        cppc_ss->length);
 723                        else
 724                                ctx->pcc_comm_addr = memremap(
 725                                                        ctx->comm_base_addr,
 726                                                        cppc_ss->length,
 727                                                        MEMREMAP_WB);
 728                } else {
 729                        dev_err(&pdev->dev, "Failed to get PCC comm region\n");
 730                        rc = -ENODEV;
 731                        goto out;
 732                }
 733
 734                if (!ctx->pcc_comm_addr) {
 735                        dev_err(&pdev->dev,
 736                                "Failed to ioremap PCC comm region\n");
 737                        rc = -ENOMEM;
 738                        goto out;
 739                }
 740
 741                /*
 742                 * cppc_ss->latency is just a Nominal value. In reality
 743                 * the remote processor could be much slower to reply.
 744                 * So add an arbitrary amount of wait on top of Nominal.
 745                 */
 746                ctx->usecs_lat = PCC_NUM_RETRIES * cppc_ss->latency;
 747        }
 748
 749        ctx->hwmon_dev = hwmon_device_register_with_groups(ctx->dev,
 750                                                           "apm_xgene",
 751                                                           ctx,
 752                                                           xgene_hwmon_groups);
 753        if (IS_ERR(ctx->hwmon_dev)) {
 754                dev_err(&pdev->dev, "Failed to register HW monitor device\n");
 755                rc = PTR_ERR(ctx->hwmon_dev);
 756                goto out;
 757        }
 758
 759        /*
 760         * Schedule the bottom handler if there is a pending message.
 761         */
 762        schedule_work(&ctx->workq);
 763
 764        dev_info(&pdev->dev, "APM X-Gene SoC HW monitor driver registered\n");
 765
 766        return 0;
 767
 768out:
 769        if (acpi_disabled)
 770                mbox_free_channel(ctx->mbox_chan);
 771        else
 772                pcc_mbox_free_channel(ctx->mbox_chan);
 773out_mbox_free:
 774        kfifo_free(&ctx->async_msg_fifo);
 775
 776        return rc;
 777}
 778
 779static int xgene_hwmon_remove(struct platform_device *pdev)
 780{
 781        struct xgene_hwmon_dev *ctx = platform_get_drvdata(pdev);
 782
 783        hwmon_device_unregister(ctx->hwmon_dev);
 784        kfifo_free(&ctx->async_msg_fifo);
 785        if (acpi_disabled)
 786                mbox_free_channel(ctx->mbox_chan);
 787        else
 788                pcc_mbox_free_channel(ctx->mbox_chan);
 789
 790        return 0;
 791}
 792
 793static const struct of_device_id xgene_hwmon_of_match[] = {
 794        {.compatible = "apm,xgene-slimpro-hwmon"},
 795        {}
 796};
 797MODULE_DEVICE_TABLE(of, xgene_hwmon_of_match);
 798
 799static struct platform_driver xgene_hwmon_driver __refdata = {
 800        .probe = xgene_hwmon_probe,
 801        .remove = xgene_hwmon_remove,
 802        .driver = {
 803                .name = "xgene-slimpro-hwmon",
 804                .of_match_table = xgene_hwmon_of_match,
 805                .acpi_match_table = ACPI_PTR(xgene_hwmon_acpi_match),
 806        },
 807};
 808module_platform_driver(xgene_hwmon_driver);
 809
 810MODULE_DESCRIPTION("APM X-Gene SoC hardware monitor");
 811MODULE_LICENSE("GPL");
 812