linux: move fan autoservo to fan.c

This commit is contained in:
Andy Nguyen
2026-07-05 09:34:17 +02:00
parent c445e9adf3
commit 1926418e4e

View File

@@ -5626,10 +5626,10 @@ index 000000000000..f48ad6f92534
+MODULE_LICENSE("GPL");
diff --git a/drivers/ps5/fan.c b/drivers/ps5/fan.c
new file mode 100644
index 000000000000..33a48c664f73
index 000000000000..040c08ad1a7b
--- /dev/null
+++ b/drivers/ps5/fan.c
@@ -0,0 +1,193 @@
@@ -0,0 +1,368 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/module.h>
@@ -5638,7 +5638,184 @@ index 000000000000..33a48c664f73
+#include <linux/err.h>
+#include <linux/unaligned.h>
+#include <linux/ps5.h>
+#include <linux/io.h>
+#include "ps5-fan.h"
+#include "autoservo_param.h"
+
+#define PS5_FAN_BOOT_TARGET_TEMP 75
+
+#define GDDR6_SAMSUNG 0x01
+#define GDDR6_HYNIX 0x06
+#define GDDR6_MICRON 0x0f
+
+#define BOARD_MASK_A 0xffffffffffffff00
+#define BOARD_MASK_B 0xffffffffff00ff00
+
+#define BOARD_SANCARLO_1 0x2001010104010400
+#define BOARD_SANCARLO_2 0x2001010104010500
+#define BOARD_A_EIGER_1 0x3002010104010400
+#define BOARD_A_EIGER_2 0x3002010104010500
+#define BOARD_A_DENALI_1 0x3002010104030400
+#define BOARD_A_DENALI_2 0x3002010104030500
+#define BOARD_B_EIGER_DENALI_1 0x3002020101000400
+#define BOARD_B_EIGER_DENALI_2 0x3002020101000500
+#define BOARD_D_EIGER_DENALI_1 0x3002040101000400
+#define BOARD_D_EIGER_DENALI_2 0x3002040101000500
+
+static void bootparam_get_config_board_id(u64 *board_id)
+{
+ void __iomem *bootparam = ioremap(0x9b000, 0x2000);
+ *board_id = readq(bootparam + 0x328);
+ iounmap(bootparam);
+}
+
+static void bootparam_get_config_gddr6_id(u16 *gddr6_id)
+{
+ void __iomem *bootparam = ioremap(0x9b000, 0x2000);
+ *gddr6_id = readw(bootparam + 0x1184);
+ iounmap(bootparam);
+}
+
+int icc_fan_update_param(const u8 *param)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+
+ msg->service_id = ICC_SERVICE_ID_FAN;
+ msg->msg_type = 0xe;
+ msg->length = sizeof(*msg) + 0x6ae;
+ memcpy(msg->data, param, 0x6ae);
+
+ return icc_query(buf, buf);
+}
+EXPORT_SYMBOL(icc_fan_update_param);
+
+int icc_fan_update_autoservo_param(void)
+{
+ u64 board_id, board_mask_a, board_mask_b;
+ u16 gddr6_id;
+ u8 gddr6_vendor, gddr6_revision;
+ const char *board_name = NULL;
+ const char *gddr6_name = NULL;
+ const u8 *param = NULL;
+ int ret;
+
+ bootparam_get_config_board_id(&board_id);
+ board_id = be64_to_cpu(board_id);
+ board_mask_a = board_id & BOARD_MASK_A;
+ board_mask_b = board_id & BOARD_MASK_B;
+
+ bootparam_get_config_gddr6_id(&gddr6_id);
+ gddr6_vendor = gddr6_id & 0xf;
+ gddr6_revision = gddr6_id >> 4;
+
+ if (board_mask_a == BOARD_SANCARLO_1 || board_mask_a == BOARD_SANCARLO_2) {
+ board_name = "Sancarlo";
+ param = autoservo_param_sancarlo;
+ } else if (board_mask_a == BOARD_A_EIGER_1 || board_mask_a == BOARD_A_EIGER_2) {
+ board_name = "A-Eiger";
+ switch (gddr6_vendor) {
+ case GDDR6_SAMSUNG:
+ gddr6_name = "Samsung";
+ param = autoservo_param_a_eiger_samsung;
+ break;
+ case GDDR6_HYNIX:
+ gddr6_name = "Hynix";
+ param = autoservo_param_a_eiger_hynix;
+ break;
+ case GDDR6_MICRON:
+ gddr6_name = "Micron";
+ param = autoservo_param_a_eiger_micron;
+ break;
+ default:
+ pr_info("FanServo: %s Unknown Vendor 0x%x\n", board_name, gddr6_vendor);
+ goto not_updated;
+ }
+ } else if (board_mask_a == BOARD_A_DENALI_1 || board_mask_a == BOARD_A_DENALI_2) {
+ board_name = "A-Denali";
+ switch (gddr6_vendor) {
+ case GDDR6_SAMSUNG:
+ gddr6_name = "Samsung";
+ param = autoservo_param_a_denali_samsung;
+ break;
+ case GDDR6_HYNIX:
+ gddr6_name = "Hynix";
+ param = autoservo_param_a_denali_hynix;
+ break;
+ case GDDR6_MICRON:
+ gddr6_name = "Micron";
+ param = autoservo_param_a_denali_micron;
+ break;
+ default:
+ pr_info("FanServo: %s Unknown Vendor 0x%x\n", board_name, gddr6_vendor);
+ goto not_updated;
+ }
+ } else if (board_mask_b == BOARD_B_EIGER_DENALI_1 || board_mask_b == BOARD_B_EIGER_DENALI_2) {
+ board_name = "B-Eiger/Denali";
+ if (gddr6_vendor == GDDR6_SAMSUNG && gddr6_revision == 8) {
+ gddr6_name = "Samsung D1x";
+ param = autoservo_param_b_eiger_denali_samsung_d1x;
+ } else if (gddr6_vendor == GDDR6_SAMSUNG && gddr6_revision == 9) {
+ gddr6_name = "Samsung D1z";
+ param = NULL;
+ } else if (gddr6_vendor == GDDR6_HYNIX && gddr6_revision == 0) {
+ gddr6_name = "Hynix 1x";
+ param = autoservo_param_b_eiger_denali_hynix_1x_micron_120s;
+ } else if (gddr6_vendor == GDDR6_HYNIX && gddr6_revision == 1) {
+ gddr6_name = "Hynix 1y";
+ param = autoservo_param_b_eiger_denali_hynix_1y_micron_130s;
+ } else if (gddr6_vendor == GDDR6_MICRON && gddr6_revision == 0) {
+ gddr6_name = "Micron 120s";
+ param = autoservo_param_b_eiger_denali_hynix_1x_micron_120s;
+ } else if (gddr6_vendor == GDDR6_MICRON && gddr6_revision == 1) {
+ gddr6_name = "Micron 130s";
+ param = autoservo_param_b_eiger_denali_hynix_1y_micron_130s;
+ } else {
+ pr_info("FanServo: %s Unknown Vendor/Revision 0x%x/0x%x\n", board_name, gddr6_vendor, gddr6_revision);
+ goto not_updated;
+ }
+ } else if (board_mask_b == BOARD_D_EIGER_DENALI_1 || board_mask_b == BOARD_D_EIGER_DENALI_2) {
+ board_name = "D-Eiger/Denali";
+ if (gddr6_vendor == GDDR6_SAMSUNG && gddr6_revision == 9) {
+ gddr6_name = "Samsung D1z";
+ param = autoservo_param_d_eiger_denali_samsung_d1z;
+ } else if (gddr6_vendor == GDDR6_HYNIX && gddr6_revision == 1) {
+ gddr6_name = "Hynix 1y";
+ param = autoservo_param_d_eiger_denali_hynix_1y;
+ } else if (gddr6_vendor == GDDR6_MICRON && gddr6_revision == 1) {
+ gddr6_name = "Micron 130s";
+ param = autoservo_param_d_eiger_denali_micron_130s_y31j;
+ } else if (gddr6_vendor == GDDR6_MICRON && gddr6_revision == 2) {
+ gddr6_name = "Micron Y31J";
+ param = autoservo_param_d_eiger_denali_micron_130s_y31j;
+ } else {
+ pr_info("FanServo: %s Unknown Vendor/Revision 0x%x/0x%x\n", board_name, gddr6_vendor, gddr6_revision);
+ goto not_updated;
+ }
+ } else {
+ pr_info("FanServo: 0x%016llX\n", board_id);
+ goto not_updated;
+ }
+
+ if (gddr6_name)
+ pr_info("FanServo: %s %s\n", board_name, gddr6_name);
+ else
+ pr_info("FanServo: %s\n", board_name);
+
+ if (!param)
+ goto not_updated;
+
+ ret = icc_fan_update_param(param);
+ if (ret)
+ pr_err("Error: %s: %d\n", __func__, ret);
+
+ return ret;
+
+not_updated:
+ pr_info("FanServo: Not update\n");
+ return 0;
+}
+EXPORT_SYMBOL(icc_fan_update_autoservo_param);
+
+static int icc_fan_txn(u8 svc, u16 mt, u16 len,
+ const u8 *data, size_t dlen,
@@ -5767,8 +5944,6 @@ index 000000000000..33a48c664f73
+};
+ATTRIBUTE_GROUPS(ps5_fan);
+
+#define PS5_FAN_BOOT_TARGET_TEMP 75
+
+static int ps5_fan_probe(struct platform_device *pdev)
+{
+ int ret = icc_fan_update_autoservo_param();
@@ -8140,10 +8315,10 @@ index 000000000000..5ea1519823c3
+#endif /* _PS5_FAN_H */
diff --git a/drivers/ps5/spcie.c b/drivers/ps5/spcie.c
new file mode 100644
index 000000000000..7e2be5605399
index 000000000000..547b1457ac62
--- /dev/null
+++ b/drivers/ps5/spcie.c
@@ -0,0 +1,1148 @@
@@ -0,0 +1,974 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -8156,7 +8331,6 @@ index 000000000000..7e2be5605399
+#include <linux/dmi.h>
+#include <linux/delay.h>
+#include <linux/kfifo.h>
+#include "autoservo_param.h"
+
+#define PCI_DEVICE_ID_SPCIE 0x9107
+#define SPCIE_SUBFUNC_ICC 12
@@ -8188,24 +8362,6 @@ index 000000000000..7e2be5605399
+
+#define ICC_FAN_CHANGE_SERVO_PATTERN _IOW(ICC_IOC_MAGIC, 1, u8)
+
+#define GDDR6_SAMSUNG 0x01
+#define GDDR6_HYNIX 0x06
+#define GDDR6_MICRON 0x0f
+
+#define BOARD_MASK_A 0xffffffffffffff00
+#define BOARD_MASK_B 0xffffffffff00ff00
+
+#define BOARD_SANCARLO_1 0x2001010104010400
+#define BOARD_SANCARLO_2 0x2001010104010500
+#define BOARD_A_EIGER_1 0x3002010104010400
+#define BOARD_A_EIGER_2 0x3002010104010500
+#define BOARD_A_DENALI_1 0x3002010104030400
+#define BOARD_A_DENALI_2 0x3002010104030500
+#define BOARD_B_EIGER_DENALI_1 0x3002020101000400
+#define BOARD_B_EIGER_DENALI_2 0x3002020101000500
+#define BOARD_D_EIGER_DENALI_1 0x3002040101000400
+#define BOARD_D_EIGER_DENALI_2 0x3002040101000500
+
+struct spcie_dev;
+
+struct spcie_icc_dev {
@@ -8265,20 +8421,6 @@ index 000000000000..7e2be5605399
+ 0x00
+};
+
+static void bootparam_get_config_board_id(u64 *board_id)
+{
+ void __iomem *bootparam = ioremap(0x9b000, 0x2000);
+ *board_id = readq(bootparam + 0x328);
+ iounmap(bootparam);
+}
+
+static void bootparam_get_config_gddr6_id(u16 *gddr6_id)
+{
+ void __iomem *bootparam = ioremap(0x9b000, 0x2000);
+ *gddr6_id = readw(bootparam + 0x1184);
+ iounmap(bootparam);
+}
+
+static u16 icc_checksum(struct icc_msg *msg)
+{
+ u16 i;
@@ -8644,147 +8786,6 @@ index 000000000000..7e2be5605399
+}
+EXPORT_SYMBOL(icc_fan_change_servo_pattern);
+
+int icc_fan_update_param(const u8 *param)
+{
+ u8 buf[ICC_MSG_MAX_SIZE] = {};
+ struct icc_msg *msg = (struct icc_msg *)buf;
+
+ msg->service_id = ICC_SERVICE_ID_FAN;
+ msg->msg_type = 0xe;
+ msg->length = sizeof(*msg) + 0x6ae;
+ memcpy(msg->data, param, 0x6ae);
+
+ return icc_query(buf, buf);
+}
+EXPORT_SYMBOL(icc_fan_update_param);
+
+int icc_fan_update_autoservo_param(void)
+{
+ u64 board_id, board_mask_a, board_mask_b;
+ u16 gddr6_id;
+ u8 gddr6_vendor, gddr6_revision;
+ const char *board_name = NULL;
+ const char *gddr6_name = NULL;
+ const u8 *param = NULL;
+ int ret;
+
+ bootparam_get_config_board_id(&board_id);
+ board_id = be64_to_cpu(board_id);
+ board_mask_a = board_id & BOARD_MASK_A;
+ board_mask_b = board_id & BOARD_MASK_B;
+
+ bootparam_get_config_gddr6_id(&gddr6_id);
+ gddr6_vendor = gddr6_id & 0xf;
+ gddr6_revision = gddr6_id >> 4;
+
+ if (board_mask_a == BOARD_SANCARLO_1 || board_mask_a == BOARD_SANCARLO_2) {
+ board_name = "Sancarlo";
+ param = autoservo_param_sancarlo;
+ } else if (board_mask_a == BOARD_A_EIGER_1 || board_mask_a == BOARD_A_EIGER_2) {
+ board_name = "A-Eiger";
+ switch (gddr6_vendor) {
+ case GDDR6_SAMSUNG:
+ gddr6_name = "Samsung";
+ param = autoservo_param_a_eiger_samsung;
+ break;
+ case GDDR6_HYNIX:
+ gddr6_name = "Hynix";
+ param = autoservo_param_a_eiger_hynix;
+ break;
+ case GDDR6_MICRON:
+ gddr6_name = "Micron";
+ param = autoservo_param_a_eiger_micron;
+ break;
+ default:
+ pr_info("FanServo: %s Unknown Vendor 0x%x\n", board_name, gddr6_vendor);
+ goto not_updated;
+ }
+ } else if (board_mask_a == BOARD_A_DENALI_1 || board_mask_a == BOARD_A_DENALI_2) {
+ board_name = "A-Denali";
+ switch (gddr6_vendor) {
+ case GDDR6_SAMSUNG:
+ gddr6_name = "Samsung";
+ param = autoservo_param_a_denali_samsung;
+ break;
+ case GDDR6_HYNIX:
+ gddr6_name = "Hynix";
+ param = autoservo_param_a_denali_hynix;
+ break;
+ case GDDR6_MICRON:
+ gddr6_name = "Micron";
+ param = autoservo_param_a_denali_micron;
+ break;
+ default:
+ pr_info("FanServo: %s Unknown Vendor 0x%x\n", board_name, gddr6_vendor);
+ goto not_updated;
+ }
+ } else if (board_mask_b == BOARD_B_EIGER_DENALI_1 || board_mask_b == BOARD_B_EIGER_DENALI_2) {
+ board_name = "B-Eiger/Denali";
+ if (gddr6_vendor == GDDR6_SAMSUNG && gddr6_revision == 8) {
+ gddr6_name = "Samsung D1x";
+ param = autoservo_param_b_eiger_denali_samsung_d1x;
+ } else if (gddr6_vendor == GDDR6_SAMSUNG && gddr6_revision == 9) {
+ gddr6_name = "Samsung D1z";
+ param = NULL;
+ } else if (gddr6_vendor == GDDR6_HYNIX && gddr6_revision == 0) {
+ gddr6_name = "Hynix 1x";
+ param = autoservo_param_b_eiger_denali_hynix_1x_micron_120s;
+ } else if (gddr6_vendor == GDDR6_HYNIX && gddr6_revision == 1) {
+ gddr6_name = "Hynix 1y";
+ param = autoservo_param_b_eiger_denali_hynix_1y_micron_130s;
+ } else if (gddr6_vendor == GDDR6_MICRON && gddr6_revision == 0) {
+ gddr6_name = "Micron 120s";
+ param = autoservo_param_b_eiger_denali_hynix_1x_micron_120s;
+ } else if (gddr6_vendor == GDDR6_MICRON && gddr6_revision == 1) {
+ gddr6_name = "Micron 130s";
+ param = autoservo_param_b_eiger_denali_hynix_1y_micron_130s;
+ } else {
+ pr_info("FanServo: %s Unknown Vendor/Revision 0x%x/0x%x\n", board_name, gddr6_vendor, gddr6_revision);
+ goto not_updated;
+ }
+ } else if (board_mask_b == BOARD_D_EIGER_DENALI_1 || board_mask_b == BOARD_D_EIGER_DENALI_2) {
+ board_name = "D-Eiger/Denali";
+ if (gddr6_vendor == GDDR6_SAMSUNG && gddr6_revision == 9) {
+ gddr6_name = "Samsung D1z";
+ param = autoservo_param_d_eiger_denali_samsung_d1z;
+ } else if (gddr6_vendor == GDDR6_HYNIX && gddr6_revision == 1) {
+ gddr6_name = "Hynix 1y";
+ param = autoservo_param_d_eiger_denali_hynix_1y;
+ } else if (gddr6_vendor == GDDR6_MICRON && gddr6_revision == 1) {
+ gddr6_name = "Micron 130s";
+ param = autoservo_param_d_eiger_denali_micron_130s_y31j;
+ } else if (gddr6_vendor == GDDR6_MICRON && gddr6_revision == 2) {
+ gddr6_name = "Micron Y31J";
+ param = autoservo_param_d_eiger_denali_micron_130s_y31j;
+ } else {
+ pr_info("FanServo: %s Unknown Vendor/Revision 0x%x/0x%x\n", board_name, gddr6_vendor, gddr6_revision);
+ goto not_updated;
+ }
+ } else {
+ pr_info("FanServo: 0x%016llX\n", board_id);
+ goto not_updated;
+ }
+
+ if (gddr6_name)
+ pr_info("FanServo: %s %s\n", board_name, gddr6_name);
+ else
+ pr_info("FanServo: %s\n", board_name);
+
+ if (!param)
+ goto not_updated;
+
+ ret = icc_fan_update_param(param);
+ if (ret)
+ pr_err("Error: %s: %d\n", __func__, ret);
+
+ return ret;
+
+not_updated:
+ pr_info("FanServo: Not update\n");
+ return 0;
+}
+EXPORT_SYMBOL(icc_fan_update_autoservo_param);
+
+static void button_notification_handler(struct icc_msg *msg)
+{
+ if (msg->msg_type == 0x8010) { // power button down