xref: /linux/drivers/thermal/intel/int340x_thermal/processor_thermal_mbox.c (revision cdd30ebb1b9f36159d66f088b61aee264e649d7a)
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