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 */
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 0x5810
14 #define MBOX_OFFSET_INTERFACE 0x5818
15
16 #define MBOX_BUSY_BIT 31
17 #define MBOX_RETRY_COUNT 100
18
19 static DEFINE_MUTEX(mbox_lock);
20
wait_for_mbox_ready(struct proc_thermal_device * proc_priv)21 static 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
send_mbox_write_cmd(struct pci_dev * pdev,u16 id,u32 data)41 static 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
send_mbox_read_cmd(struct pci_dev * pdev,u16 id,u64 * resp)60 static 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 else
82 *resp = readq(proc_priv->mmio_base + MBOX_OFFSET_DATA);
83
84 return 0;
85 }
86
processor_thermal_send_mbox_read_cmd(struct pci_dev * pdev,u16 id,u64 * resp)87 int 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 }
97 EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_read_cmd, INT340X_THERMAL);
98
processor_thermal_send_mbox_write_cmd(struct pci_dev * pdev,u16 id,u32 data)99 int 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 }
109 EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_write_cmd, INT340X_THERMAL);
110
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
115
processor_thermal_mbox_interrupt_config(struct pci_dev * pdev,bool enable,int enable_bit,int time_window)116 int 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 else
145 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
151 unlock:
152 mutex_unlock(&mbox_lock);
153
154 return ret;
155 }
156 EXPORT_SYMBOL_NS_GPL(processor_thermal_mbox_interrupt_config, INT340X_THERMAL);
157
158 MODULE_LICENSE("GPL v2");
159 MODULE_DESCRIPTION("Processor Thermal Mail Box Interface");
160