160 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * processor thermal device mailbox driver for Workload type hints4 * Copyright (c) 2020, Intel Corporation.5 */6 7#include <linux/kernel.h>8#include <linux/module.h>9#include <linux/pci.h>10#include <linux/io-64-nonatomic-lo-hi.h>11#include "processor_thermal_device.h"12 13#define MBOX_OFFSET_DATA 0x581014#define MBOX_OFFSET_INTERFACE 0x581815 16#define MBOX_BUSY_BIT 3117#define MBOX_RETRY_COUNT 10018 19static DEFINE_MUTEX(mbox_lock);20 21static int wait_for_mbox_ready(struct proc_thermal_device *proc_priv)22{23 u32 retries, data;24 int ret;25 26 /* Poll for rb bit == 0 */27 retries = MBOX_RETRY_COUNT;28 do {29 data = readl(proc_priv->mmio_base + MBOX_OFFSET_INTERFACE);30 if (data & BIT_ULL(MBOX_BUSY_BIT)) {31 ret = -EBUSY;32 continue;33 }34 ret = 0;35 break;36 } while (--retries);37 38 return ret;39}40 41static int send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data)42{43 struct proc_thermal_device *proc_priv;44 u32 reg_data;45 int ret;46 47 proc_priv = pci_get_drvdata(pdev);48 ret = wait_for_mbox_ready(proc_priv);49 if (ret)50 return ret;51 52 writel(data, (proc_priv->mmio_base + MBOX_OFFSET_DATA));53 /* Write command register */54 reg_data = BIT_ULL(MBOX_BUSY_BIT) | id;55 writel(reg_data, (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE));56 57 return wait_for_mbox_ready(proc_priv);58}59 60static int send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp)61{62 struct proc_thermal_device *proc_priv;63 u32 reg_data;64 int ret;65 66 proc_priv = pci_get_drvdata(pdev);67 ret = wait_for_mbox_ready(proc_priv);68 if (ret)69 return ret;70 71 /* Write command register */72 reg_data = BIT_ULL(MBOX_BUSY_BIT) | id;73 writel(reg_data, (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE));74 75 ret = wait_for_mbox_ready(proc_priv);76 if (ret)77 return ret;78 79 if (id == MBOX_CMD_WORKLOAD_TYPE_READ)80 *resp = readl(proc_priv->mmio_base + MBOX_OFFSET_DATA);81 else82 *resp = readq(proc_priv->mmio_base + MBOX_OFFSET_DATA);83 84 return 0;85}86 87int processor_thermal_send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp)88{89 int ret;90 91 mutex_lock(&mbox_lock);92 ret = send_mbox_read_cmd(pdev, id, resp);93 mutex_unlock(&mbox_lock);94 95 return ret;96}97EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_read_cmd, INT340X_THERMAL);98 99int processor_thermal_send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data)100{101 int ret;102 103 mutex_lock(&mbox_lock);104 ret = send_mbox_write_cmd(pdev, id, data);105 mutex_unlock(&mbox_lock);106 107 return ret;108}109EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_write_cmd, INT340X_THERMAL);110 111#define MBOX_CAMARILLO_RD_INTR_CONFIG 0x1E112#define MBOX_CAMARILLO_WR_INTR_CONFIG 0x1F113#define WLT_TW_MASK GENMASK_ULL(30, 24)114#define SOC_PREDICTION_TW_SHIFT 24115 116int processor_thermal_mbox_interrupt_config(struct pci_dev *pdev, bool enable,117 int enable_bit, int time_window)118{119 u64 data;120 int ret;121 122 if (!pdev)123 return -ENODEV;124 125 mutex_lock(&mbox_lock);126 127 /* Do read modify write for MBOX_CAMARILLO_RD_INTR_CONFIG */128 129 ret = send_mbox_read_cmd(pdev, MBOX_CAMARILLO_RD_INTR_CONFIG, &data);130 if (ret) {131 dev_err(&pdev->dev, "MBOX_CAMARILLO_RD_INTR_CONFIG failed\n");132 goto unlock;133 }134 135 if (time_window >= 0) {136 data &= ~WLT_TW_MASK;137 138 /* Program notification delay */139 data |= ((u64)time_window << SOC_PREDICTION_TW_SHIFT) & WLT_TW_MASK;140 }141 142 if (enable)143 data |= BIT(enable_bit);144 else145 data &= ~BIT(enable_bit);146 147 ret = send_mbox_write_cmd(pdev, MBOX_CAMARILLO_WR_INTR_CONFIG, data);148 if (ret)149 dev_err(&pdev->dev, "MBOX_CAMARILLO_WR_INTR_CONFIG failed\n");150 151unlock:152 mutex_unlock(&mbox_lock);153 154 return ret;155}156EXPORT_SYMBOL_NS_GPL(processor_thermal_mbox_interrupt_config, INT340X_THERMAL);157 158MODULE_LICENSE("GPL v2");159MODULE_DESCRIPTION("Processor Thermal Mail Box Interface");160