]> Git Repo - J-linux.git/blob - drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c
Merge tag 'amd-drm-next-6.5-2023-06-09' of https://gitlab.freedesktop.org/agd5f/linux...
[J-linux.git] / drivers / thermal / intel / int340x_thermal / processor_thermal_mbox.c
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_CMD_WORKLOAD_TYPE_READ     0x0E
14 #define MBOX_CMD_WORKLOAD_TYPE_WRITE    0x0F
15
16 #define MBOX_OFFSET_DATA                0x5810
17 #define MBOX_OFFSET_INTERFACE           0x5818
18
19 #define MBOX_BUSY_BIT                   31
20 #define MBOX_RETRY_COUNT                100
21
22 #define MBOX_DATA_BIT_VALID             31
23 #define MBOX_DATA_BIT_AC_DC             30
24
25 static DEFINE_MUTEX(mbox_lock);
26
27 static int wait_for_mbox_ready(struct proc_thermal_device *proc_priv)
28 {
29         u32 retries, data;
30         int ret;
31
32         /* Poll for rb bit == 0 */
33         retries = MBOX_RETRY_COUNT;
34         do {
35                 data = readl(proc_priv->mmio_base + MBOX_OFFSET_INTERFACE);
36                 if (data & BIT_ULL(MBOX_BUSY_BIT)) {
37                         ret = -EBUSY;
38                         continue;
39                 }
40                 ret = 0;
41                 break;
42         } while (--retries);
43
44         return ret;
45 }
46
47 static int send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data)
48 {
49         struct proc_thermal_device *proc_priv;
50         u32 reg_data;
51         int ret;
52
53         proc_priv = pci_get_drvdata(pdev);
54
55         mutex_lock(&mbox_lock);
56
57         ret = wait_for_mbox_ready(proc_priv);
58         if (ret)
59                 goto unlock_mbox;
60
61         writel(data, (proc_priv->mmio_base + MBOX_OFFSET_DATA));
62         /* Write command register */
63         reg_data = BIT_ULL(MBOX_BUSY_BIT) | id;
64         writel(reg_data, (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE));
65
66         ret = wait_for_mbox_ready(proc_priv);
67
68 unlock_mbox:
69         mutex_unlock(&mbox_lock);
70         return ret;
71 }
72
73 static int send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp)
74 {
75         struct proc_thermal_device *proc_priv;
76         u32 reg_data;
77         int ret;
78
79         proc_priv = pci_get_drvdata(pdev);
80
81         mutex_lock(&mbox_lock);
82
83         ret = wait_for_mbox_ready(proc_priv);
84         if (ret)
85                 goto unlock_mbox;
86
87         /* Write command register */
88         reg_data = BIT_ULL(MBOX_BUSY_BIT) | id;
89         writel(reg_data, (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE));
90
91         ret = wait_for_mbox_ready(proc_priv);
92         if (ret)
93                 goto unlock_mbox;
94
95         if (id == MBOX_CMD_WORKLOAD_TYPE_READ)
96                 *resp = readl(proc_priv->mmio_base + MBOX_OFFSET_DATA);
97         else
98                 *resp = readq(proc_priv->mmio_base + MBOX_OFFSET_DATA);
99
100 unlock_mbox:
101         mutex_unlock(&mbox_lock);
102         return ret;
103 }
104
105 int processor_thermal_send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp)
106 {
107         return send_mbox_read_cmd(pdev, id, resp);
108 }
109 EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_read_cmd, INT340X_THERMAL);
110
111 int processor_thermal_send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data)
112 {
113         return send_mbox_write_cmd(pdev, id, data);
114 }
115 EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_write_cmd, INT340X_THERMAL);
116
117 /* List of workload types */
118 static const char * const workload_types[] = {
119         "none",
120         "idle",
121         "semi_active",
122         "bursty",
123         "sustained",
124         "battery_life",
125         NULL
126 };
127
128 static ssize_t workload_available_types_show(struct device *dev,
129                                                struct device_attribute *attr,
130                                                char *buf)
131 {
132         int i = 0;
133         int ret = 0;
134
135         while (workload_types[i] != NULL)
136                 ret += sprintf(&buf[ret], "%s ", workload_types[i++]);
137
138         ret += sprintf(&buf[ret], "\n");
139
140         return ret;
141 }
142
143 static DEVICE_ATTR_RO(workload_available_types);
144
145 static ssize_t workload_type_store(struct device *dev,
146                                     struct device_attribute *attr,
147                                     const char *buf, size_t count)
148 {
149         struct pci_dev *pdev = to_pci_dev(dev);
150         char str_preference[15];
151         u32 data = 0;
152         ssize_t ret;
153
154         ret = sscanf(buf, "%14s", str_preference);
155         if (ret != 1)
156                 return -EINVAL;
157
158         ret = match_string(workload_types, -1, str_preference);
159         if (ret < 0)
160                 return ret;
161
162         ret &= 0xff;
163
164         if (ret)
165                 data = BIT(MBOX_DATA_BIT_VALID) | BIT(MBOX_DATA_BIT_AC_DC);
166
167         data |= ret;
168
169         ret = send_mbox_write_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_WRITE, data);
170         if (ret)
171                 return false;
172
173         return count;
174 }
175
176 static ssize_t workload_type_show(struct device *dev,
177                                    struct device_attribute *attr,
178                                    char *buf)
179 {
180         struct pci_dev *pdev = to_pci_dev(dev);
181         u64 cmd_resp;
182         int ret;
183
184         ret = send_mbox_read_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, &cmd_resp);
185         if (ret)
186                 return false;
187
188         cmd_resp &= 0xff;
189
190         if (cmd_resp > ARRAY_SIZE(workload_types) - 1)
191                 return -EINVAL;
192
193         return sprintf(buf, "%s\n", workload_types[cmd_resp]);
194 }
195
196 static DEVICE_ATTR_RW(workload_type);
197
198 static struct attribute *workload_req_attrs[] = {
199         &dev_attr_workload_available_types.attr,
200         &dev_attr_workload_type.attr,
201         NULL
202 };
203
204 static const struct attribute_group workload_req_attribute_group = {
205         .attrs = workload_req_attrs,
206         .name = "workload_request"
207 };
208
209 static bool workload_req_created;
210
211 int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
212 {
213         u64 cmd_resp;
214         int ret;
215
216         /* Check if there is a mailbox support, if fails return success */
217         ret = send_mbox_read_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, &cmd_resp);
218         if (ret)
219                 return 0;
220
221         ret = sysfs_create_group(&pdev->dev.kobj, &workload_req_attribute_group);
222         if (ret)
223                 return ret;
224
225         workload_req_created = true;
226
227         return 0;
228 }
229 EXPORT_SYMBOL_GPL(proc_thermal_mbox_add);
230
231 void proc_thermal_mbox_remove(struct pci_dev *pdev)
232 {
233         if (workload_req_created)
234                 sysfs_remove_group(&pdev->dev.kobj, &workload_req_attribute_group);
235
236         workload_req_created = false;
237
238 }
239 EXPORT_SYMBOL_GPL(proc_thermal_mbox_remove);
240
241 MODULE_LICENSE("GPL v2");
This page took 0.043136 seconds and 4 git commands to generate.