1235723Sbapt// SPDX-License-Identifier: GPL-2.0-or-later 2235723Sbapt/* 3235723Sbapt * APM X-Gene SoC Hardware Monitoring Driver 4235723Sbapt * 5235723Sbapt * Copyright (c) 2016, Applied Micro Circuits Corporation 6235723Sbapt * Author: Loc Ho <lho@apm.com> 7235723Sbapt * Hoan Tran <hotran@apm.com> 8235723Sbapt * 9235723Sbapt * This driver provides the following features: 10235723Sbapt * - Retrieve CPU total power (uW) 11235723Sbapt * - Retrieve IO total power (uW) 12235723Sbapt * - Retrieve SoC temperature (milli-degree C) and alarm 13235723Sbapt */ 14235723Sbapt#include <linux/acpi.h> 15235723Sbapt#include <linux/dma-mapping.h> 16235723Sbapt#include <linux/hwmon.h> 17235723Sbapt#include <linux/hwmon-sysfs.h> 18235723Sbapt#include <linux/io.h> 19235723Sbapt#include <linux/interrupt.h> 20235723Sbapt#include <linux/kfifo.h> 21235723Sbapt#include <linux/mailbox_controller.h> 22235723Sbapt#include <linux/mailbox_client.h> 23235723Sbapt#include <linux/module.h> 24235723Sbapt#include <linux/of.h> 25235723Sbapt#include <linux/platform_device.h> 26235723Sbapt 27235723Sbapt#include <acpi/pcc.h> 28235723Sbapt 29235723Sbapt/* SLIMpro message defines */ 30235723Sbapt#define MSG_TYPE_DBG 0 31235723Sbapt#define MSG_TYPE_ERR 7 32235723Sbapt#define MSG_TYPE_PWRMGMT 9 33235723Sbapt 34235723Sbapt#define MSG_TYPE(v) (((v) & 0xF0000000) >> 28) 35235723Sbapt#define MSG_TYPE_SET(v) (((v) << 28) & 0xF0000000) 36235723Sbapt#define MSG_SUBTYPE(v) (((v) & 0x0F000000) >> 24) 37235723Sbapt#define MSG_SUBTYPE_SET(v) (((v) << 24) & 0x0F000000) 38235723Sbapt 39235723Sbapt#define DBG_SUBTYPE_SENSOR_READ 4 40235723Sbapt#define SENSOR_RD_MSG 0x04FFE902 41235723Sbapt#define SENSOR_RD_EN_ADDR(a) ((a) & 0x000FFFFF) 42235723Sbapt#define PMD_PWR_REG 0x20 43235723Sbapt#define PMD_PWR_MW_REG 0x26 44235723Sbapt#define SOC_PWR_REG 0x21 45235723Sbapt#define SOC_PWR_MW_REG 0x27 46235723Sbapt#define SOC_TEMP_REG 0x10 47235723Sbapt 48235723Sbapt#define TEMP_NEGATIVE_BIT 8 49235723Sbapt#define SENSOR_INVALID_DATA BIT(15) 50235723Sbapt 51235723Sbapt#define PWRMGMT_SUBTYPE_TPC 1 52235723Sbapt#define TPC_ALARM 2 53235723Sbapt#define TPC_GET_ALARM 3 54235723Sbapt#define TPC_CMD(v) (((v) & 0x00FF0000) >> 16) 55235723Sbapt#define TPC_CMD_SET(v) (((v) << 16) & 0x00FF0000) 56235723Sbapt#define TPC_EN_MSG(hndl, cmd, type) \ 57235723Sbapt (MSG_TYPE_SET(MSG_TYPE_PWRMGMT) | \ 58235723Sbapt MSG_SUBTYPE_SET(hndl) | TPC_CMD_SET(cmd) | type) 59235723Sbapt 60235723Sbapt/* 61235723Sbapt * Arbitrary retries in case the remote processor is slow to respond 62235723Sbapt * to PCC commands 63235723Sbapt */ 64235723Sbapt#define PCC_NUM_RETRIES 500 65235723Sbapt 66235723Sbapt#define ASYNC_MSG_FIFO_SIZE 16 67235723Sbapt#define MBOX_OP_TIMEOUTMS 1000 68235723Sbapt 69235723Sbapt#define WATT_TO_mWATT(x) ((x) * 1000) 70235723Sbapt#define mWATT_TO_uWATT(x) ((x) * 1000) 71235723Sbapt#define CELSIUS_TO_mCELSIUS(x) ((x) * 1000) 72235723Sbapt 73235723Sbapt#define to_xgene_hwmon_dev(cl) \ 74235723Sbapt container_of(cl, struct xgene_hwmon_dev, mbox_client) 75235723Sbapt 76235723Sbaptenum xgene_hwmon_version { 77235723Sbapt XGENE_HWMON_V1 = 0, 78235723Sbapt XGENE_HWMON_V2 = 1, 79235723Sbapt}; 80235723Sbapt 81235723Sbaptstruct slimpro_resp_msg { 82235723Sbapt u32 msg; 83235723Sbapt u32 param1; 84235723Sbapt u32 param2; 85235723Sbapt} __packed; 86235723Sbapt 87235723Sbaptstruct xgene_hwmon_dev { 88235723Sbapt struct device *dev; 89235723Sbapt struct mbox_chan *mbox_chan; 90235723Sbapt struct pcc_mbox_chan *pcc_chan; 91235723Sbapt struct mbox_client mbox_client; 92235723Sbapt int mbox_idx; 93235723Sbapt 94235723Sbapt spinlock_t kfifo_lock; 95235723Sbapt struct mutex rd_mutex; 96235723Sbapt struct completion rd_complete; 97235723Sbapt int resp_pending; 98235723Sbapt struct slimpro_resp_msg sync_msg; 99235723Sbapt 100235723Sbapt struct work_struct workq; 101235723Sbapt struct kfifo_rec_ptr_1 async_msg_fifo; 102235723Sbapt 103235723Sbapt struct device *hwmon_dev; 104235723Sbapt bool temp_critical_alarm; 105235723Sbapt 106235723Sbapt phys_addr_t comm_base_addr; 107235723Sbapt void *pcc_comm_addr; 108235723Sbapt u64 usecs_lat; 109235723Sbapt}; 110235723Sbapt 111235723Sbapt/* 112235723Sbapt * This function tests and clears a bitmask then returns its old value 113235723Sbapt */ 114235723Sbaptstatic u16 xgene_word_tst_and_clr(u16 *addr, u16 mask) 115235723Sbapt{ 116235723Sbapt u16 ret, val; 117235723Sbapt 118235723Sbapt val = le16_to_cpu(READ_ONCE(*addr)); 119235723Sbapt ret = val & mask; 120235723Sbapt val &= ~mask; 121235723Sbapt WRITE_ONCE(*addr, cpu_to_le16(val)); 122235723Sbapt 123235723Sbapt return ret; 124235723Sbapt} 125235723Sbapt 126235723Sbaptstatic int xgene_hwmon_pcc_rd(struct xgene_hwmon_dev *ctx, u32 *msg) 127235723Sbapt{ 128235723Sbapt struct acpi_pcct_shared_memory *generic_comm_base = ctx->pcc_comm_addr; 129235723Sbapt u32 *ptr = (void *)(generic_comm_base + 1); 130235723Sbapt int rc, i; 131235723Sbapt u16 val; 132235723Sbapt 133235723Sbapt mutex_lock(&ctx->rd_mutex); 134235723Sbapt init_completion(&ctx->rd_complete); 135235723Sbapt ctx->resp_pending = true; 136235723Sbapt 137235723Sbapt /* Write signature for subspace */ 138235723Sbapt WRITE_ONCE(generic_comm_base->signature, 139235723Sbapt cpu_to_le32(PCC_SIGNATURE | ctx->mbox_idx)); 140235723Sbapt 141235723Sbapt /* Write to the shared command region */ 142235723Sbapt WRITE_ONCE(generic_comm_base->command, 143235723Sbapt cpu_to_le16(MSG_TYPE(msg[0]) | PCC_CMD_GENERATE_DB_INTR)); 144235723Sbapt 145235723Sbapt /* Flip CMD COMPLETE bit */ 146235723Sbapt val = le16_to_cpu(READ_ONCE(generic_comm_base->status)); 147235723Sbapt val &= ~PCC_STATUS_CMD_COMPLETE; 148235723Sbapt WRITE_ONCE(generic_comm_base->status, cpu_to_le16(val)); 149235723Sbapt 150235723Sbapt /* Copy the message to the PCC comm space */ 151235723Sbapt for (i = 0; i < sizeof(struct slimpro_resp_msg) / 4; i++) 152235723Sbapt WRITE_ONCE(ptr[i], cpu_to_le32(msg[i])); 153235723Sbapt 154235723Sbapt /* Ring the doorbell */ 155235723Sbapt rc = mbox_send_message(ctx->mbox_chan, msg); 156235723Sbapt if (rc < 0) { 157235723Sbapt dev_err(ctx->dev, "Mailbox send error %d\n", rc); 158235723Sbapt goto err; 159235723Sbapt } 160235723Sbapt if (!wait_for_completion_timeout(&ctx->rd_complete, 161235723Sbapt usecs_to_jiffies(ctx->usecs_lat))) { 162235723Sbapt dev_err(ctx->dev, "Mailbox operation timed out\n"); 163235723Sbapt rc = -ETIMEDOUT; 164235723Sbapt goto err; 165235723Sbapt } 166235723Sbapt 167235723Sbapt /* Check for error message */ 168235723Sbapt if (MSG_TYPE(ctx->sync_msg.msg) == MSG_TYPE_ERR) { 169235723Sbapt rc = -EINVAL; 170235723Sbapt goto err; 171235723Sbapt } 172235723Sbapt 173235723Sbapt msg[0] = ctx->sync_msg.msg; 174235723Sbapt msg[1] = ctx->sync_msg.param1; 175235723Sbapt msg[2] = ctx->sync_msg.param2; 176235723Sbapt 177235723Sbapterr: 178235723Sbapt mbox_chan_txdone(ctx->mbox_chan, 0); 179235723Sbapt ctx->resp_pending = false; 180235723Sbapt mutex_unlock(&ctx->rd_mutex); 181235723Sbapt return rc; 182235723Sbapt} 183235723Sbapt 184235723Sbaptstatic int xgene_hwmon_rd(struct xgene_hwmon_dev *ctx, u32 *msg) 185235723Sbapt{ 186235723Sbapt int rc; 187235723Sbapt 188235723Sbapt mutex_lock(&ctx->rd_mutex); 189235723Sbapt init_completion(&ctx->rd_complete); 190235723Sbapt ctx->resp_pending = true; 191235723Sbapt 192235723Sbapt rc = mbox_send_message(ctx->mbox_chan, msg); 193235723Sbapt if (rc < 0) { 194235723Sbapt dev_err(ctx->dev, "Mailbox send error %d\n", rc); 195235723Sbapt goto err; 196235723Sbapt } 197235723Sbapt 198235723Sbapt if (!wait_for_completion_timeout(&ctx->rd_complete, 199235723Sbapt msecs_to_jiffies(MBOX_OP_TIMEOUTMS))) { 200235723Sbapt dev_err(ctx->dev, "Mailbox operation timed out\n"); 201235723Sbapt rc = -ETIMEDOUT; 202235723Sbapt goto err; 203235723Sbapt } 204235723Sbapt 205235723Sbapt /* Check for error message */ 206235723Sbapt if (MSG_TYPE(ctx->sync_msg.msg) == MSG_TYPE_ERR) { 207235723Sbapt rc = -EINVAL; 208235723Sbapt goto err; 209235723Sbapt } 210235723Sbapt 211235723Sbapt msg[0] = ctx->sync_msg.msg; 212235723Sbapt msg[1] = ctx->sync_msg.param1; 213235723Sbapt msg[2] = ctx->sync_msg.param2; 214235723Sbapt 215235723Sbapterr: 216235723Sbapt ctx->resp_pending = false; 217235723Sbapt mutex_unlock(&ctx->rd_mutex); 218235723Sbapt return rc; 219235723Sbapt} 220235723Sbapt 221235723Sbaptstatic int xgene_hwmon_reg_map_rd(struct xgene_hwmon_dev *ctx, u32 addr, 222235723Sbapt u32 *data) 223235723Sbapt{ 224235723Sbapt u32 msg[3]; 225235723Sbapt int rc; 226235723Sbapt 227235723Sbapt msg[0] = SENSOR_RD_MSG; 228235723Sbapt msg[1] = SENSOR_RD_EN_ADDR(addr); 229235723Sbapt msg[2] = 0; 230235723Sbapt 231235723Sbapt if (acpi_disabled) 232235723Sbapt rc = xgene_hwmon_rd(ctx, msg); 233235723Sbapt else 234235723Sbapt rc = xgene_hwmon_pcc_rd(ctx, msg); 235235723Sbapt 236235723Sbapt if (rc < 0) 237235723Sbapt return rc; 238235723Sbapt 239235723Sbapt /* 240235723Sbapt * Check if sensor data is valid. 241235723Sbapt */ 242235723Sbapt if (msg[1] & SENSOR_INVALID_DATA) 243235723Sbapt return -ENODATA; 244235723Sbapt 245235723Sbapt *data = msg[1]; 246235723Sbapt 247235723Sbapt return rc; 248235723Sbapt} 249235723Sbapt 250235723Sbaptstatic int xgene_hwmon_get_notification_msg(struct xgene_hwmon_dev *ctx, 251235723Sbapt u32 *amsg) 252235723Sbapt{ 253235723Sbapt u32 msg[3]; 254235723Sbapt int rc; 255235723Sbapt 256235723Sbapt msg[0] = TPC_EN_MSG(PWRMGMT_SUBTYPE_TPC, TPC_GET_ALARM, 0); 257235723Sbapt msg[1] = 0; 258235723Sbapt msg[2] = 0; 259235723Sbapt 260235723Sbapt rc = xgene_hwmon_pcc_rd(ctx, msg); 261235723Sbapt if (rc < 0) 262235723Sbapt return rc; 263235723Sbapt 264235723Sbapt amsg[0] = msg[0]; 265235723Sbapt amsg[1] = msg[1]; 266235723Sbapt amsg[2] = msg[2]; 267235723Sbapt 268235723Sbapt return rc; 269235723Sbapt} 270235723Sbapt 271235723Sbaptstatic int xgene_hwmon_get_cpu_pwr(struct xgene_hwmon_dev *ctx, u32 *val) 272235723Sbapt{ 273235723Sbapt u32 watt, mwatt; 274235723Sbapt int rc; 275235723Sbapt 276235723Sbapt rc = xgene_hwmon_reg_map_rd(ctx, PMD_PWR_REG, &watt); 277235723Sbapt if (rc < 0) 278235723Sbapt return rc; 279235723Sbapt 280235723Sbapt rc = xgene_hwmon_reg_map_rd(ctx, PMD_PWR_MW_REG, &mwatt); 281235723Sbapt if (rc < 0) 282235723Sbapt return rc; 283235723Sbapt 284235723Sbapt *val = WATT_TO_mWATT(watt) + mwatt; 285235723Sbapt return 0; 286235723Sbapt} 287235723Sbapt 288235723Sbaptstatic int xgene_hwmon_get_io_pwr(struct xgene_hwmon_dev *ctx, u32 *val) 289235723Sbapt{ 290235723Sbapt u32 watt, mwatt; 291235723Sbapt int rc; 292235723Sbapt 293235723Sbapt rc = xgene_hwmon_reg_map_rd(ctx, SOC_PWR_REG, &watt); 294235723Sbapt if (rc < 0) 295235723Sbapt return rc; 296235723Sbapt 297235723Sbapt rc = xgene_hwmon_reg_map_rd(ctx, SOC_PWR_MW_REG, &mwatt); 298235723Sbapt if (rc < 0) 299235723Sbapt return rc; 300235723Sbapt 301235723Sbapt *val = WATT_TO_mWATT(watt) + mwatt; 302235723Sbapt return 0; 303235723Sbapt} 304235723Sbapt 305235723Sbaptstatic int xgene_hwmon_get_temp(struct xgene_hwmon_dev *ctx, u32 *val) 306235723Sbapt{ 307235723Sbapt return xgene_hwmon_reg_map_rd(ctx, SOC_TEMP_REG, val); 308235723Sbapt} 309235723Sbapt 310235723Sbapt/* 311235723Sbapt * Sensor temperature/power functions 312235723Sbapt */ 313235723Sbaptstatic ssize_t temp1_input_show(struct device *dev, 314235723Sbapt struct device_attribute *attr, 315235723Sbapt char *buf) 316235723Sbapt{ 317235723Sbapt struct xgene_hwmon_dev *ctx = dev_get_drvdata(dev); 318235723Sbapt int rc, temp; 319235723Sbapt u32 val; 320235723Sbapt 321235723Sbapt rc = xgene_hwmon_get_temp(ctx, &val); 322235723Sbapt if (rc < 0) 323235723Sbapt return rc; 324235723Sbapt 325235723Sbapt temp = sign_extend32(val, TEMP_NEGATIVE_BIT); 326235723Sbapt 327235723Sbapt return sysfs_emit(buf, "%d\n", CELSIUS_TO_mCELSIUS(temp)); 328235723Sbapt} 329235723Sbapt 330235723Sbaptstatic ssize_t temp1_label_show(struct device *dev, 331235723Sbapt struct device_attribute *attr, 332235723Sbapt char *buf) 333235723Sbapt{ 334235723Sbapt return sysfs_emit(buf, "SoC Temperature\n"); 335235723Sbapt} 336235723Sbapt 337235723Sbaptstatic ssize_t temp1_critical_alarm_show(struct device *dev, 338235723Sbapt struct device_attribute *devattr, 339235723Sbapt char *buf) 340235723Sbapt{ 341235723Sbapt struct xgene_hwmon_dev *ctx = dev_get_drvdata(dev); 342235723Sbapt 343235723Sbapt return sysfs_emit(buf, "%d\n", ctx->temp_critical_alarm); 344235723Sbapt} 345235723Sbapt 346235723Sbaptstatic ssize_t power1_label_show(struct device *dev, 347235723Sbapt struct device_attribute *attr, 348235723Sbapt char *buf) 349235723Sbapt{ 350235723Sbapt return sysfs_emit(buf, "CPU power\n"); 351235723Sbapt} 352235723Sbapt 353235723Sbaptstatic ssize_t power2_label_show(struct device *dev, 354235723Sbapt struct device_attribute *attr, 355235723Sbapt char *buf) 356235723Sbapt{ 357235723Sbapt return sysfs_emit(buf, "IO power\n"); 358235723Sbapt} 359235723Sbapt 360235723Sbaptstatic ssize_t power1_input_show(struct device *dev, 361235723Sbapt struct device_attribute *attr, 362235723Sbapt char *buf) 363235723Sbapt{ 364235723Sbapt struct xgene_hwmon_dev *ctx = dev_get_drvdata(dev); 365235723Sbapt u32 val; 366235723Sbapt int rc; 367235723Sbapt 368235723Sbapt rc = xgene_hwmon_get_cpu_pwr(ctx, &val); 369235723Sbapt if (rc < 0) 370235723Sbapt return rc; 371235723Sbapt 372235723Sbapt return sysfs_emit(buf, "%u\n", mWATT_TO_uWATT(val)); 373235723Sbapt} 374235723Sbapt 375235723Sbaptstatic ssize_t power2_input_show(struct device *dev, 376235723Sbapt struct device_attribute *attr, 377235723Sbapt char *buf) 378235723Sbapt{ 379235723Sbapt struct xgene_hwmon_dev *ctx = dev_get_drvdata(dev); 380235723Sbapt u32 val; 381235723Sbapt int rc; 382235723Sbapt 383235723Sbapt rc = xgene_hwmon_get_io_pwr(ctx, &val); 384235723Sbapt if (rc < 0) 385235723Sbapt return rc; 386235723Sbapt 387235723Sbapt return sysfs_emit(buf, "%u\n", mWATT_TO_uWATT(val)); 388235723Sbapt} 389235723Sbapt 390235723Sbaptstatic DEVICE_ATTR_RO(temp1_label); 391235723Sbaptstatic DEVICE_ATTR_RO(temp1_input); 392235723Sbaptstatic DEVICE_ATTR_RO(temp1_critical_alarm); 393235723Sbaptstatic DEVICE_ATTR_RO(power1_label); 394235723Sbaptstatic DEVICE_ATTR_RO(power1_input); 395235723Sbaptstatic DEVICE_ATTR_RO(power2_label); 396235723Sbaptstatic DEVICE_ATTR_RO(power2_input); 397235723Sbapt 398235723Sbaptstatic struct attribute *xgene_hwmon_attrs[] = { 399235723Sbapt &dev_attr_temp1_label.attr, 400235723Sbapt &dev_attr_temp1_input.attr, 401235723Sbapt &dev_attr_temp1_critical_alarm.attr, 402235723Sbapt &dev_attr_power1_label.attr, 403235723Sbapt &dev_attr_power1_input.attr, 404235723Sbapt &dev_attr_power2_label.attr, 405235723Sbapt &dev_attr_power2_input.attr, 406235723Sbapt NULL, 407235723Sbapt}; 408235723Sbapt 409235723SbaptATTRIBUTE_GROUPS(xgene_hwmon); 410235723Sbapt 411235723Sbaptstatic int xgene_hwmon_tpc_alarm(struct xgene_hwmon_dev *ctx, 412235723Sbapt struct slimpro_resp_msg *amsg) 413235723Sbapt{ 414235723Sbapt ctx->temp_critical_alarm = !!amsg->param2; 415235723Sbapt sysfs_notify(&ctx->dev->kobj, NULL, "temp1_critical_alarm"); 416235723Sbapt 417235723Sbapt return 0; 418235723Sbapt} 419235723Sbapt 420235723Sbaptstatic void xgene_hwmon_process_pwrmsg(struct xgene_hwmon_dev *ctx, 421235723Sbapt struct slimpro_resp_msg *amsg) 422235723Sbapt{ 423235723Sbapt if ((MSG_SUBTYPE(amsg->msg) == PWRMGMT_SUBTYPE_TPC) && 424235723Sbapt (TPC_CMD(amsg->msg) == TPC_ALARM)) 425235723Sbapt xgene_hwmon_tpc_alarm(ctx, amsg); 426235723Sbapt} 427235723Sbapt 428235723Sbapt/* 429235723Sbapt * This function is called to process async work queue 430235723Sbapt */ 431235723Sbaptstatic void xgene_hwmon_evt_work(struct work_struct *work) 432235723Sbapt{ 433235723Sbapt struct slimpro_resp_msg amsg; 434235723Sbapt struct xgene_hwmon_dev *ctx; 435235723Sbapt int ret; 436235723Sbapt 437235723Sbapt ctx = container_of(work, struct xgene_hwmon_dev, workq); 438235723Sbapt while (kfifo_out_spinlocked(&ctx->async_msg_fifo, &amsg, 439235723Sbapt sizeof(struct slimpro_resp_msg), 440235723Sbapt &ctx->kfifo_lock)) { 441235723Sbapt /* 442235723Sbapt * If PCC, send a consumer command to Platform to get info 443235723Sbapt * If Slimpro Mailbox, get message from specific FIFO 444235723Sbapt */ 445235723Sbapt if (!acpi_disabled) { 446235723Sbapt ret = xgene_hwmon_get_notification_msg(ctx, 447235723Sbapt (u32 *)&amsg); 448235723Sbapt if (ret < 0) 449235723Sbapt continue; 450235723Sbapt } 451235723Sbapt 452235723Sbapt if (MSG_TYPE(amsg.msg) == MSG_TYPE_PWRMGMT) 453235723Sbapt xgene_hwmon_process_pwrmsg(ctx, &amsg); 454235723Sbapt } 455235723Sbapt} 456235723Sbapt 457235723Sbaptstatic int xgene_hwmon_rx_ready(struct xgene_hwmon_dev *ctx, void *msg) 458235723Sbapt{ 459235723Sbapt if (IS_ERR_OR_NULL(ctx->hwmon_dev) && !ctx->resp_pending) { 460235723Sbapt /* Enqueue to the FIFO */ 461235723Sbapt kfifo_in_spinlocked(&ctx->async_msg_fifo, msg, 462235723Sbapt sizeof(struct slimpro_resp_msg), 463235723Sbapt &ctx->kfifo_lock); 464235723Sbapt return -ENODEV; 465235723Sbapt } 466235723Sbapt 467235723Sbapt return 0; 468235723Sbapt} 469235723Sbapt 470235723Sbapt/* 471235723Sbapt * This function is called when the SLIMpro Mailbox received a message 472235723Sbapt */ 473235723Sbaptstatic void xgene_hwmon_rx_cb(struct mbox_client *cl, void *msg) 474235723Sbapt{ 475235723Sbapt struct xgene_hwmon_dev *ctx = to_xgene_hwmon_dev(cl); 476235723Sbapt 477235723Sbapt /* 478235723Sbapt * While the driver registers with the mailbox framework, an interrupt 479235723Sbapt * can be pending before the probe function completes its 480235723Sbapt * initialization. If such condition occurs, just queue up the message 481235723Sbapt * as the driver is not ready for servicing the callback. 482235723Sbapt */ 483235723Sbapt if (xgene_hwmon_rx_ready(ctx, msg) < 0) 484235723Sbapt return; 485235723Sbapt 486235723Sbapt /* 487235723Sbapt * Response message format: 488235723Sbapt * msg[0] is the return code of the operation 489235723Sbapt * msg[1] is the first parameter word 490235723Sbapt * msg[2] is the second parameter word 491235723Sbapt * 492235723Sbapt * As message only supports dword size, just assign it. 493235723Sbapt */ 494235723Sbapt 495235723Sbapt /* Check for sync query */ 496235723Sbapt if (ctx->resp_pending && 497235723Sbapt ((MSG_TYPE(((u32 *)msg)[0]) == MSG_TYPE_ERR) || 498235723Sbapt (MSG_TYPE(((u32 *)msg)[0]) == MSG_TYPE_DBG && 499235723Sbapt MSG_SUBTYPE(((u32 *)msg)[0]) == DBG_SUBTYPE_SENSOR_READ) || 500235723Sbapt (MSG_TYPE(((u32 *)msg)[0]) == MSG_TYPE_PWRMGMT && 501235723Sbapt MSG_SUBTYPE(((u32 *)msg)[0]) == PWRMGMT_SUBTYPE_TPC && 502235723Sbapt TPC_CMD(((u32 *)msg)[0]) == TPC_ALARM))) { 503235723Sbapt ctx->sync_msg.msg = ((u32 *)msg)[0]; 504235723Sbapt ctx->sync_msg.param1 = ((u32 *)msg)[1]; 505235723Sbapt ctx->sync_msg.param2 = ((u32 *)msg)[2]; 506235723Sbapt 507235723Sbapt /* Operation waiting for response */ 508235723Sbapt complete(&ctx->rd_complete); 509235723Sbapt 510235723Sbapt return; 511235723Sbapt } 512235723Sbapt 513235723Sbapt /* Enqueue to the FIFO */ 514235723Sbapt kfifo_in_spinlocked(&ctx->async_msg_fifo, msg, 515235723Sbapt sizeof(struct slimpro_resp_msg), &ctx->kfifo_lock); 516235723Sbapt /* Schedule the bottom handler */ 517235723Sbapt schedule_work(&ctx->workq); 518235723Sbapt} 519235723Sbapt 520235723Sbapt/* 521235723Sbapt * This function is called when the PCC Mailbox received a message 522235723Sbapt */ 523235723Sbaptstatic void xgene_hwmon_pcc_rx_cb(struct mbox_client *cl, void *msg) 524235723Sbapt{ 525235723Sbapt struct xgene_hwmon_dev *ctx = to_xgene_hwmon_dev(cl); 526235723Sbapt struct acpi_pcct_shared_memory *generic_comm_base = ctx->pcc_comm_addr; 527235723Sbapt struct slimpro_resp_msg amsg; 528235723Sbapt 529235723Sbapt /* 530235723Sbapt * While the driver registers with the mailbox framework, an interrupt 531235723Sbapt * can be pending before the probe function completes its 532235723Sbapt * initialization. If such condition occurs, just queue up the message 533235723Sbapt * as the driver is not ready for servicing the callback. 534235723Sbapt */ 535235723Sbapt if (xgene_hwmon_rx_ready(ctx, &amsg) < 0) 536235723Sbapt return; 537235723Sbapt 538235723Sbapt msg = generic_comm_base + 1; 539235723Sbapt /* Check if platform sends interrupt */ 540235723Sbapt if (!xgene_word_tst_and_clr(&generic_comm_base->status, 541235723Sbapt PCC_STATUS_SCI_DOORBELL)) 542235723Sbapt return; 543235723Sbapt 544235723Sbapt /* 545235723Sbapt * Response message format: 546235723Sbapt * msg[0] is the return code of the operation 547235723Sbapt * msg[1] is the first parameter word 548235723Sbapt * msg[2] is the second parameter word 549235723Sbapt * 550235723Sbapt * As message only supports dword size, just assign it. 551235723Sbapt */ 552235723Sbapt 553235723Sbapt /* Check for sync query */ 554235723Sbapt if (ctx->resp_pending && 555235723Sbapt ((MSG_TYPE(((u32 *)msg)[0]) == MSG_TYPE_ERR) || 556235723Sbapt (MSG_TYPE(((u32 *)msg)[0]) == MSG_TYPE_DBG && 557235723Sbapt MSG_SUBTYPE(((u32 *)msg)[0]) == DBG_SUBTYPE_SENSOR_READ) || 558235723Sbapt (MSG_TYPE(((u32 *)msg)[0]) == MSG_TYPE_PWRMGMT && 559235723Sbapt MSG_SUBTYPE(((u32 *)msg)[0]) == PWRMGMT_SUBTYPE_TPC && 560235723Sbapt TPC_CMD(((u32 *)msg)[0]) == TPC_ALARM))) { 561235723Sbapt /* Check if platform completes command */ 562235723Sbapt if (xgene_word_tst_and_clr(&generic_comm_base->status, 563235723Sbapt PCC_STATUS_CMD_COMPLETE)) { 564235723Sbapt ctx->sync_msg.msg = ((u32 *)msg)[0]; 565235723Sbapt ctx->sync_msg.param1 = ((u32 *)msg)[1]; 566235723Sbapt ctx->sync_msg.param2 = ((u32 *)msg)[2]; 567235723Sbapt 568235723Sbapt /* Operation waiting for response */ 569235723Sbapt complete(&ctx->rd_complete); 570235723Sbapt 571235723Sbapt return; 572235723Sbapt } 573235723Sbapt } 574235723Sbapt 575235723Sbapt /* 576235723Sbapt * Platform notifies interrupt to OSPM. 577235723Sbapt * OPSM schedules a consumer command to get this information 578235723Sbapt * in a workqueue. Platform must wait until OSPM has issued 579235723Sbapt * a consumer command that serves this notification. 580235723Sbapt */ 581235723Sbapt 582235723Sbapt /* Enqueue to the FIFO */ 583235723Sbapt kfifo_in_spinlocked(&ctx->async_msg_fifo, &amsg, 584235723Sbapt sizeof(struct slimpro_resp_msg), &ctx->kfifo_lock); 585235723Sbapt /* Schedule the bottom handler */ 586235723Sbapt schedule_work(&ctx->workq); 587235723Sbapt} 588235723Sbapt 589235723Sbaptstatic void xgene_hwmon_tx_done(struct mbox_client *cl, void *msg, int ret) 590235723Sbapt{ 591235723Sbapt if (ret) { 592235723Sbapt dev_dbg(cl->dev, "TX did not complete: CMD sent:%x, ret:%d\n", 593235723Sbapt *(u16 *)msg, ret); 594235723Sbapt } else { 595235723Sbapt dev_dbg(cl->dev, "TX completed. CMD sent:%x, ret:%d\n", 596235723Sbapt *(u16 *)msg, ret); 597235723Sbapt } 598235723Sbapt} 599235723Sbapt 600235723Sbapt#ifdef CONFIG_ACPI 601235723Sbaptstatic const struct acpi_device_id xgene_hwmon_acpi_match[] = { 602235723Sbapt {"APMC0D29", XGENE_HWMON_V1}, 603235723Sbapt {"APMC0D8A", XGENE_HWMON_V2}, 604235723Sbapt {}, 605235723Sbapt}; 606235723SbaptMODULE_DEVICE_TABLE(acpi, xgene_hwmon_acpi_match); 607235723Sbapt#endif 608235723Sbapt 609235723Sbaptstatic int xgene_hwmon_probe(struct platform_device *pdev) 610235723Sbapt{ 611235723Sbapt struct xgene_hwmon_dev *ctx; 612235723Sbapt struct mbox_client *cl; 613235723Sbapt int rc; 614235723Sbapt 615235723Sbapt ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 616235723Sbapt if (!ctx) 617235723Sbapt return -ENOMEM; 618235723Sbapt 619235723Sbapt ctx->dev = &pdev->dev; 620235723Sbapt platform_set_drvdata(pdev, ctx); 621235723Sbapt cl = &ctx->mbox_client; 622235723Sbapt 623235723Sbapt spin_lock_init(&ctx->kfifo_lock); 624235723Sbapt mutex_init(&ctx->rd_mutex); 625235723Sbapt 626235723Sbapt rc = kfifo_alloc(&ctx->async_msg_fifo, 627235723Sbapt sizeof(struct slimpro_resp_msg) * ASYNC_MSG_FIFO_SIZE, 628235723Sbapt GFP_KERNEL); 629235723Sbapt if (rc) 630235723Sbapt return -ENOMEM; 631235723Sbapt 632235723Sbapt INIT_WORK(&ctx->workq, xgene_hwmon_evt_work); 633235723Sbapt 634235723Sbapt /* Request mailbox channel */ 635235723Sbapt cl->dev = &pdev->dev; 636235723Sbapt cl->tx_done = xgene_hwmon_tx_done; 637235723Sbapt cl->tx_block = false; 638235723Sbapt cl->tx_tout = MBOX_OP_TIMEOUTMS; 639235723Sbapt cl->knows_txdone = false; 640235723Sbapt if (acpi_disabled) { 641235723Sbapt cl->rx_callback = xgene_hwmon_rx_cb; 642235723Sbapt ctx->mbox_chan = mbox_request_channel(cl, 0); 643235723Sbapt if (IS_ERR(ctx->mbox_chan)) { 644235723Sbapt dev_err(&pdev->dev, 645235723Sbapt "SLIMpro mailbox channel request failed\n"); 646235723Sbapt rc = -ENODEV; 647235723Sbapt goto out_mbox_free; 648235723Sbapt } 649235723Sbapt } else { 650235723Sbapt struct pcc_mbox_chan *pcc_chan; 651235723Sbapt const struct acpi_device_id *acpi_id; 652235723Sbapt int version; 653235723Sbapt 654235723Sbapt acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table, 655235723Sbapt &pdev->dev); 656235723Sbapt if (!acpi_id) { 657235723Sbapt rc = -EINVAL; 658235723Sbapt goto out_mbox_free; 659235723Sbapt } 660235723Sbapt 661235723Sbapt version = (int)acpi_id->driver_data; 662235723Sbapt 663235723Sbapt if (device_property_read_u32(&pdev->dev, "pcc-channel", 664235723Sbapt &ctx->mbox_idx)) { 665235723Sbapt dev_err(&pdev->dev, "no pcc-channel property\n"); 666235723Sbapt rc = -ENODEV; 667235723Sbapt goto out_mbox_free; 668235723Sbapt } 669235723Sbapt 670235723Sbapt cl->rx_callback = xgene_hwmon_pcc_rx_cb; 671235723Sbapt pcc_chan = pcc_mbox_request_channel(cl, ctx->mbox_idx); 672235723Sbapt if (IS_ERR(pcc_chan)) { 673235723Sbapt dev_err(&pdev->dev, 674235723Sbapt "PPC channel request failed\n"); 675235723Sbapt rc = -ENODEV; 676235723Sbapt goto out_mbox_free; 677235723Sbapt } 678235723Sbapt 679235723Sbapt ctx->pcc_chan = pcc_chan; 680235723Sbapt ctx->mbox_chan = pcc_chan->mchan; 681235723Sbapt 682235723Sbapt if (!ctx->mbox_chan->mbox->txdone_irq) { 683235723Sbapt dev_err(&pdev->dev, "PCC IRQ not supported\n"); 684235723Sbapt rc = -ENODEV; 685235723Sbapt goto out; 686235723Sbapt } 687235723Sbapt 688235723Sbapt /* 689235723Sbapt * This is the shared communication region 690235723Sbapt * for the OS and Platform to communicate over. 691235723Sbapt */ 692235723Sbapt ctx->comm_base_addr = pcc_chan->shmem_base_addr; 693235723Sbapt if (ctx->comm_base_addr) { 694235723Sbapt if (version == XGENE_HWMON_V2) 695235723Sbapt ctx->pcc_comm_addr = (void __force *)devm_ioremap(&pdev->dev, 696235723Sbapt ctx->comm_base_addr, 697235723Sbapt pcc_chan->shmem_size); 698235723Sbapt else 699235723Sbapt ctx->pcc_comm_addr = devm_memremap(&pdev->dev, 700235723Sbapt ctx->comm_base_addr, 701235723Sbapt pcc_chan->shmem_size, 702235723Sbapt MEMREMAP_WB); 703235723Sbapt } else { 704235723Sbapt dev_err(&pdev->dev, "Failed to get PCC comm region\n"); 705235723Sbapt rc = -ENODEV; 706235723Sbapt goto out; 707235723Sbapt } 708235723Sbapt 709235723Sbapt if (!ctx->pcc_comm_addr) { 710235723Sbapt dev_err(&pdev->dev, 711235723Sbapt "Failed to ioremap PCC comm region\n"); 712235723Sbapt rc = -ENOMEM; 713235723Sbapt goto out; 714235723Sbapt } 715235723Sbapt 716235723Sbapt /* 717235723Sbapt * pcc_chan->latency is just a Nominal value. In reality 718235723Sbapt * the remote processor could be much slower to reply. 719235723Sbapt * So add an arbitrary amount of wait on top of Nominal. 720235723Sbapt */ 721235723Sbapt ctx->usecs_lat = PCC_NUM_RETRIES * pcc_chan->latency; 722235723Sbapt } 723235723Sbapt 724235723Sbapt ctx->hwmon_dev = hwmon_device_register_with_groups(ctx->dev, 725235723Sbapt "apm_xgene", 726235723Sbapt ctx, 727235723Sbapt xgene_hwmon_groups); 728235723Sbapt if (IS_ERR(ctx->hwmon_dev)) { 729235723Sbapt dev_err(&pdev->dev, "Failed to register HW monitor device\n"); 730235723Sbapt rc = PTR_ERR(ctx->hwmon_dev); 731235723Sbapt goto out; 732235723Sbapt } 733235723Sbapt 734235723Sbapt /* 735235723Sbapt * Schedule the bottom handler if there is a pending message. 736235723Sbapt */ 737235723Sbapt schedule_work(&ctx->workq); 738235723Sbapt 739235723Sbapt dev_info(&pdev->dev, "APM X-Gene SoC HW monitor driver registered\n"); 740235723Sbapt 741235723Sbapt return 0; 742235723Sbapt 743235723Sbaptout: 744235723Sbapt if (acpi_disabled) 745235723Sbapt mbox_free_channel(ctx->mbox_chan); 746235723Sbapt else 747235723Sbapt pcc_mbox_free_channel(ctx->pcc_chan); 748235723Sbaptout_mbox_free: 749235723Sbapt kfifo_free(&ctx->async_msg_fifo); 750235723Sbapt 751235723Sbapt return rc; 752235723Sbapt} 753235723Sbapt 754235723Sbaptstatic void xgene_hwmon_remove(struct platform_device *pdev) 755235723Sbapt{ 756235723Sbapt struct xgene_hwmon_dev *ctx = platform_get_drvdata(pdev); 757235723Sbapt 758235723Sbapt cancel_work_sync(&ctx->workq); 759235723Sbapt hwmon_device_unregister(ctx->hwmon_dev); 760235723Sbapt kfifo_free(&ctx->async_msg_fifo); 761235723Sbapt if (acpi_disabled) 762235723Sbapt mbox_free_channel(ctx->mbox_chan); 763235723Sbapt else 764235723Sbapt pcc_mbox_free_channel(ctx->pcc_chan); 765235723Sbapt} 766235723Sbapt 767235723Sbaptstatic const struct of_device_id xgene_hwmon_of_match[] = { 768235723Sbapt {.compatible = "apm,xgene-slimpro-hwmon"}, 769235723Sbapt {} 770235723Sbapt}; 771235723SbaptMODULE_DEVICE_TABLE(of, xgene_hwmon_of_match); 772235723Sbapt 773235723Sbaptstatic struct platform_driver xgene_hwmon_driver = { 774235723Sbapt .probe = xgene_hwmon_probe, 775235723Sbapt .remove_new = xgene_hwmon_remove, 776235723Sbapt .driver = { 777235723Sbapt .name = "xgene-slimpro-hwmon", 778235723Sbapt .of_match_table = xgene_hwmon_of_match, 779235723Sbapt .acpi_match_table = ACPI_PTR(xgene_hwmon_acpi_match), 780235723Sbapt }, 781235723Sbapt}; 782235723Sbaptmodule_platform_driver(xgene_hwmon_driver); 783235723Sbapt 784235723SbaptMODULE_DESCRIPTION("APM X-Gene SoC hardware monitor"); 785235723SbaptMODULE_LICENSE("GPL"); 786235723Sbapt