Merge tag 'clk-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux.git] / drivers / thermal / intel / int340x_thermal / processor_thermal_mbox.c
blobb1d531ef440f1db0e36a84c671741f47fcd6e954
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * processor thermal device mailbox driver for Workload type hints
4 * Copyright (c) 2020, Intel Corporation.
5 */
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"
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)
23 u32 retries, data;
24 int ret;
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;
34 ret = 0;
35 break;
36 } while (--retries);
38 return ret;
41 static int send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data)
43 struct proc_thermal_device *proc_priv;
44 u32 reg_data;
45 int ret;
47 proc_priv = pci_get_drvdata(pdev);
48 ret = wait_for_mbox_ready(proc_priv);
49 if (ret)
50 return ret;
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;
63 u32 reg_data;
64 int ret;
66 proc_priv = pci_get_drvdata(pdev);
67 ret = wait_for_mbox_ready(proc_priv);
68 if (ret)
69 return ret;
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);
76 if (ret)
77 return ret;
79 if (id == MBOX_CMD_WORKLOAD_TYPE_READ)
80 *resp = readl(proc_priv->mmio_base + MBOX_OFFSET_DATA);
81 else
82 *resp = readq(proc_priv->mmio_base + MBOX_OFFSET_DATA);
84 return 0;
87 int processor_thermal_send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp)
89 int ret;
91 mutex_lock(&mbox_lock);
92 ret = send_mbox_read_cmd(pdev, id, resp);
93 mutex_unlock(&mbox_lock);
95 return ret;
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)
101 int ret;
103 mutex_lock(&mbox_lock);
104 ret = send_mbox_write_cmd(pdev, id, data);
105 mutex_unlock(&mbox_lock);
107 return ret;
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)
119 u64 data;
120 int ret;
122 if (!pdev)
123 return -ENODEV;
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);
130 if (ret) {
131 dev_err(&pdev->dev, "MBOX_CAMARILLO_RD_INTR_CONFIG failed\n");
132 goto unlock;
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;
142 if (enable)
143 data |= BIT(enable_bit);
144 else
145 data &= ~BIT(enable_bit);
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");
151 unlock:
152 mutex_unlock(&mbox_lock);
154 return ret;
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");