brintos

brintos / linux-shallow public Read only

0
0
Text · 3.6 KiB · af2ec0b Raw
160 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * processor thermal device mailbox driver for Workload type hints4 * 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		0x581014#define MBOX_OFFSET_INTERFACE		0x581815 16#define MBOX_BUSY_BIT			3117#define MBOX_RETRY_COUNT		10018 19static DEFINE_MUTEX(mbox_lock);20 21static 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 41static 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 60static 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	else82		*resp = readq(proc_priv->mmio_base + MBOX_OFFSET_DATA);83 84	return 0;85}86 87int 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}97EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_read_cmd, INT340X_THERMAL);98 99int 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}109EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_write_cmd, INT340X_THERMAL);110 111#define MBOX_CAMARILLO_RD_INTR_CONFIG	0x1E112#define MBOX_CAMARILLO_WR_INTR_CONFIG	0x1F113#define WLT_TW_MASK			GENMASK_ULL(30, 24)114#define SOC_PREDICTION_TW_SHIFT		24115 116int 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	else145		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 151unlock:152	mutex_unlock(&mbox_lock);153 154	return ret;155}156EXPORT_SYMBOL_NS_GPL(processor_thermal_mbox_interrupt_config, INT340X_THERMAL);157 158MODULE_LICENSE("GPL v2");159MODULE_DESCRIPTION("Processor Thermal Mail Box Interface");160