1 // SPDX-License-Identifier: GPL-2.0-only
3 * processor thermal device mailbox driver for Workload type hints
4 * Copyright (c) 2020, Intel Corporation.
7 #include <linux/kernel.h>
8 #include <linux/module.h>
10 #include <linux/io-64-nonatomic-lo-hi.h>
11 #include "processor_thermal_device.h"
13 #define MBOX_OFFSET_DATA 0x5810
14 #define MBOX_OFFSET_INTERFACE 0x5818
16 #define MBOX_BUSY_BIT 31
17 #define MBOX_RETRY_COUNT 100
19 static DEFINE_MUTEX(mbox_lock);
21 static int wait_for_mbox_ready(struct proc_thermal_device *proc_priv)
26 /* Poll for rb bit == 0 */
27 retries = MBOX_RETRY_COUNT;
29 data = readl(proc_priv->mmio_base + MBOX_OFFSET_INTERFACE);
30 if (data & BIT_ULL(MBOX_BUSY_BIT)) {
41 static int send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data)
43 struct proc_thermal_device *proc_priv;
47 proc_priv = pci_get_drvdata(pdev);
48 ret = wait_for_mbox_ready(proc_priv);
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));
57 return wait_for_mbox_ready(proc_priv);
60 static int send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp)
62 struct proc_thermal_device *proc_priv;
66 proc_priv = pci_get_drvdata(pdev);
67 ret = wait_for_mbox_ready(proc_priv);
71 /* Write command register */
72 reg_data = BIT_ULL(MBOX_BUSY_BIT) | id;
73 writel(reg_data, (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE));
75 ret = wait_for_mbox_ready(proc_priv);
79 if (id == MBOX_CMD_WORKLOAD_TYPE_READ)
80 *resp = readl(proc_priv->mmio_base + MBOX_OFFSET_DATA);
82 *resp = readq(proc_priv->mmio_base + MBOX_OFFSET_DATA);
87 int processor_thermal_send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp)
91 mutex_lock(&mbox_lock);
92 ret = send_mbox_read_cmd(pdev, id, resp);
93 mutex_unlock(&mbox_lock);
97 EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_read_cmd, "INT340X_THERMAL");
99 int processor_thermal_send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data)
103 mutex_lock(&mbox_lock);
104 ret = send_mbox_write_cmd(pdev, id, data);
105 mutex_unlock(&mbox_lock);
109 EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_write_cmd, "INT340X_THERMAL");
111 #define MBOX_CAMARILLO_RD_INTR_CONFIG 0x1E
112 #define MBOX_CAMARILLO_WR_INTR_CONFIG 0x1F
113 #define WLT_TW_MASK GENMASK_ULL(30, 24)
114 #define SOC_PREDICTION_TW_SHIFT 24
116 int processor_thermal_mbox_interrupt_config(struct pci_dev *pdev, bool enable,
117 int enable_bit, int time_window)
125 mutex_lock(&mbox_lock);
127 /* Do read modify write for MBOX_CAMARILLO_RD_INTR_CONFIG */
129 ret = send_mbox_read_cmd(pdev, MBOX_CAMARILLO_RD_INTR_CONFIG, &data);
131 dev_err(&pdev->dev, "MBOX_CAMARILLO_RD_INTR_CONFIG failed\n");
135 if (time_window >= 0) {
136 data &= ~WLT_TW_MASK;
138 /* Program notification delay */
139 data |= ((u64)time_window << SOC_PREDICTION_TW_SHIFT) & WLT_TW_MASK;
143 data |= BIT(enable_bit);
145 data &= ~BIT(enable_bit);
147 ret = send_mbox_write_cmd(pdev, MBOX_CAMARILLO_WR_INTR_CONFIG, data);
149 dev_err(&pdev->dev, "MBOX_CAMARILLO_WR_INTR_CONFIG failed\n");
152 mutex_unlock(&mbox_lock);
156 EXPORT_SYMBOL_NS_GPL(processor_thermal_mbox_interrupt_config, "INT340X_THERMAL");
158 MODULE_LICENSE("GPL v2");
159 MODULE_DESCRIPTION("Processor Thermal Mail Box Interface");